Tau.Acuvim/console/tests/Tau.Acuvim.Console.Tests/DeviceServiceTests.cs
Renier Forster 84a0668c54 Initial commit: Tau Acuvim IoT monitoring system
Complete IoT monitoring platform for Acuvim II power meters via ESP32.

Firmware (Phases 1-7):
- ESP32-WROVER-B (TTGO T-Call v1.4) with RS485 Modbus RTU
- WiFi STA+AP concurrent mode with GSM/GPRS failover
- Transport abstraction layer with 4 priority modes
- MQTT protocol with 20 commands, LWT, QoS, exponential backoff
- SD card offline buffering with JSONL rotation and non-blocking drain
- OTA firmware updates with dual partition rollback protection
- Watchdog timer, crash loop detection, Acuvim health monitoring
- Captive portal provisioning with AP mode

Console backend (Phase 8):
- .NET 10 minimal API with PostgreSQL + EF Core
- JWT authentication, SignalR real-time updates
- MQTTnet 5.x bridge service with health monitoring
- Device, telemetry, firmware, alert, group management
- Rate limiting, security headers, Swagger/OpenAPI

Frontend (Phase 9):
- React 18 + TypeScript + Vite with Ant Design 5
- ECharts telemetry visualization, TanStack Query
- SignalR live updates, device management UI
- Dashboard, fleet management, firmware deployment

Testing & Production (Phase 10):
- 28 firmware unit tests (Modbus, JSON, config, version)
- 23 xUnit backend tests (device, telemetry, command, alert)
- Docker Compose with nginx, TLS MQTT, PostgreSQL
- Production deployment, commissioning, and troubleshooting docs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-16 19:05:32 +02:00

130 lines
4.0 KiB
C#

using System.Text.Json;
using Tau.Acuvim.Console.DTOs;
using Tau.Acuvim.Console.Models;
using Tau.Acuvim.Console.Services;
namespace Tau.Acuvim.Console.Tests;
public class DeviceServiceTests
{
private DeviceService CreateService(Data.AppDbContext db)
=> new(db, TestHelpers.CreateLogger<DeviceService>());
[Fact]
public async Task RegisterAsync_CreatesNewDevice()
{
using var db = TestHelpers.CreateDbContext();
var svc = CreateService(db);
var payload = JsonSerializer.Serialize(new
{
device_id = "DEV-001",
mac = "AA:BB:CC:DD:EE:FF",
firmware = "1.0.0",
hardware = "rev-A",
imei = "123456789012345",
ts = 1700000000L
});
var device = await svc.RegisterAsync(payload);
Assert.Equal("DEV-001", device.DeviceId);
Assert.Equal("AA:BB:CC:DD:EE:FF", device.MacAddress);
Assert.Equal("1.0.0", device.FirmwareVersion);
Assert.Equal("rev-A", device.Hardware);
Assert.Equal("123456789012345", device.Imei);
Assert.Equal("online", device.Status);
Assert.Single(db.Devices);
}
[Fact]
public async Task RegisterAsync_UpdatesExistingDevice()
{
using var db = TestHelpers.CreateDbContext();
var svc = CreateService(db);
var payload1 = JsonSerializer.Serialize(new { device_id = "DEV-001", firmware = "1.0.0" });
await svc.RegisterAsync(payload1);
var payload2 = JsonSerializer.Serialize(new { device_id = "DEV-001", firmware = "2.0.0" });
var device = await svc.RegisterAsync(payload2);
Assert.Equal("2.0.0", device.FirmwareVersion);
Assert.Single(db.Devices);
}
[Fact]
public async Task GetAllAsync_FiltersByStatus()
{
using var db = TestHelpers.CreateDbContext();
var svc = CreateService(db);
db.Devices.AddRange(
new Device { Id = Guid.NewGuid(), DeviceId = "D1", Status = "online" },
new Device { Id = Guid.NewGuid(), DeviceId = "D2", Status = "offline" },
new Device { Id = Guid.NewGuid(), DeviceId = "D3", Status = "online" }
);
await db.SaveChangesAsync();
var result = await svc.GetAllAsync(status: "online", search: null, page: 1, pageSize: 10);
Assert.Equal(2, result.Count);
Assert.All(result, r => Assert.Equal("online", r.Status));
}
[Fact]
public async Task GetAllAsync_SearchesByName()
{
using var db = TestHelpers.CreateDbContext();
var svc = CreateService(db);
db.Devices.AddRange(
new Device { Id = Guid.NewGuid(), DeviceId = "D1", Name = "Sensor Alpha" },
new Device { Id = Guid.NewGuid(), DeviceId = "D2", Name = "Sensor Beta" },
new Device { Id = Guid.NewGuid(), DeviceId = "D3", Name = "Motor Gamma" }
);
await db.SaveChangesAsync();
var result = await svc.GetAllAsync(status: null, search: "Sensor", page: 1, pageSize: 10);
Assert.Equal(2, result.Count);
}
[Fact]
public async Task GetByDeviceIdAsync_ReturnsNull_WhenNotFound()
{
using var db = TestHelpers.CreateDbContext();
var svc = CreateService(db);
var result = await svc.GetByDeviceIdAsync("NONEXISTENT");
Assert.Null(result);
}
[Fact]
public async Task DeleteAsync_RemovesDevice()
{
using var db = TestHelpers.CreateDbContext();
var svc = CreateService(db);
db.Devices.Add(new Device { Id = Guid.NewGuid(), DeviceId = "DEV-DEL" });
await db.SaveChangesAsync();
var result = await svc.DeleteAsync("DEV-DEL");
Assert.True(result);
Assert.Empty(db.Devices);
}
[Fact]
public async Task DeleteAsync_ReturnsFalse_WhenNotFound()
{
using var db = TestHelpers.CreateDbContext();
var svc = CreateService(db);
var result = await svc.DeleteAsync("NONEXISTENT");
Assert.False(result);
}
}