using Application.ATG_Classic_App; using Application.ATG_Classic_App.Model; using AutoMapper; using Edge.Core.Processor; using Edge.Core.IndustryStandardInterface.Pump; using Edge.Core.IndustryStandardInterface.ATG; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.VisualStudio.TestTools.UnitTesting; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Text.Json; using System.Threading.Tasks; using Edge.Core.UniversalApi; namespace Application.ATG_Classic_App_Test { [TestClass] public class ATG { static int TankCount = 6; //ServiceProvider serviceProvider; static List probeHandlers; static ATG_Classic_App.App atg; static List sharedTankProfileDatas; static IEnumerable tankConfigs; static TankOverallConfig tankOverallConfig; static int InventorySamplingInterval = 5000; [ClassInitialize] public static void ClassInit(TestContext context) { var services = new ServiceCollection(); services.AddSingleton(NullLoggerFactory.Instance); #region AutoMapper, resolve all assemblies under entry folder. var applicationAssFileInfos = new DirectoryInfo(Directory.GetCurrentDirectory()) .GetFiles().Where(f => //f.Name.ToLower().StartsWith("application") && f.Extension != null && (f.Extension.ToLower() == ".dll" || f.Extension.ToLower() == ".exe")); var assembliesWithAutoMapperProfileDefined = new List(); foreach (var ai in applicationAssFileInfos) { try { var ass = Assembly.LoadFrom(ai.FullName); if (ass.GetTypes().Any(t => typeof(Profile).IsAssignableFrom(t))) assembliesWithAutoMapperProfileDefined.Add(ass); } catch { } } services.AddAutoMapper(assembliesWithAutoMapperProfileDefined); services.AddSingleton(new UniversalApiHub(null, null)); #endregion var serviceProvider = services.BuildServiceProvider(); probeHandlers = Enumerable.Range(1, TankCount).Select(i => new MockProbeHandler(i, i * 1000)).ToList(); sharedTankProfileDatas = Enumerable.Range(0, 2001).Select(i => new TankProfileData() { BatchLabel = "shitday", Height = i, Volume = i * 2 }).ToList(); tankConfigs = Enumerable.Range(1, TankCount).Select(i => new TankConfig() { TankNumber = (byte)i, Label = "I'm Tank with Number " + i, Diameter = i * 1000, ProbeConfig = new ProbeConfig() { DeviceId = i }, ProductConfig = new ProductConfig() { ProductCode = (i + 90).ToString(), ProductLabel = (i + 90).ToString() + "#" }, TankLimitConfig = new TankLimitConfig() { FullVolume = 1200 * i, MaxVolume = 1100 * i, HighProduct = 900 * i, LowProduct = 100 * i, HighWaterWarning = 10 * i, HighWaterAlarm = 40 * i, FuelTemperatureLowLimit = i, FuelTemperatureHighLimit = 2 * i }, }); tankOverallConfig = new TankOverallConfig() { TcReference = 25, InventorySamplingInterval = InventorySamplingInterval }; var dbContextFactory = new DefaultDbContextFactory(); dbContextFactory.AddProvider(new InMemoryDbContextProvider()); atg = new ATG_Classic_App.App(serviceProvider, 1, true); atg.DbContextFactory = dbContextFactory; atg.Init(probeHandlers.Cast()); var _ = atg.UpsertConfigAsync(tankOverallConfig).Result; foreach (var tc in tankConfigs) { var xx = atg.UpsertConfigAsync(tc).Result; } foreach (var tc in tankConfigs) { var xx = atg.AddTankProfileDataAsync( tc.TankNumber, sharedTankProfileDatas.Select(d => d.Height.ToString() + ":" + d.Volume.ToString()).Aggregate((n, acc) => n + ", " + acc) ).Result; } atg.Start().Wait(); } class InMemoryDbContextProvider : IDbContextProvider { public T CreateDbContext() where T : DbContext { //var options = new DbContextOptionsBuilder() // .UseInMemoryDatabase(databaseName: "Test") // .Options; return new InMemoryDbContext() as T; } public void Dispose() { //throw new NotImplementedException(); } } [TestInitialize] public void TestMethodInit() { } [TestMethod] public async Task TankReading_TestMethod1() { var tanks = atg.Tanks; var mockReading = new Edge.Core.IndustryStandardInterface.ATG.ProbeReading() { Height = 1322, Water = 123, Temperature = new[] { (double)41 } }; probeHandlers.ForEach(ph => ph.Mock_SetProbeReadingValueProducer((_) => mockReading)); Assert.AreEqual(true, atg.Tanks != null); Assert.AreEqual(true, atg.Tanks.Count() == TankCount); await Task.Delay(atg.polling_fast_TankReadingTimer_Internval); var volumeCaculatorTester = new HeightToVolumeCaculator(sharedTankProfileDatas); foreach (var tank in atg.Tanks) { var tankConfig = tankConfigs.First(tc => tc.TankNumber == tank.TankNumber); var tcCaculator = new TemperatureCompensationCaculator(tankConfig.ThermalCoefficient); var tankReading = await atg.GetTankReadingAsync(tank.TankNumber); Assert.AreEqual(true, tankReading != null); Assert.AreEqual(true, tankReading.Height == mockReading.Height); Assert.AreEqual(true, tankReading.Water == mockReading.Water); Assert.AreEqual(true, tankReading.Temperature.Value == mockReading.Temperature.First()); Assert.AreEqual(tankReading.TcVolume, tcCaculator.CaculateCompensatedVolume(tankOverallConfig.TcReference, tankReading.Volume.Value, tankReading.Temperature.Value)); Assert.AreEqual(true, tankReading.WaterVolume == volumeCaculatorTester.GetVolume(tankReading.Water.Value)); Assert.AreEqual(true, tankReading.Volume == volumeCaculatorTester.GetVolume(tankReading.Height.Value) - tankReading.WaterVolume); Assert.AreEqual(tankReading.Ullage, volumeCaculatorTester.GetVolume(sharedTankProfileDatas.Max(p => p.Height)) - tankReading.Volume - tankReading.WaterVolume); } } [TestMethod] public async Task TankReading_TestMethod2() { var tanks = atg.Tanks; Func mockReadingProducer = (ph) => new ProbeReading() { Height = ph.Probe.ProbeLength * 0.8, Water = ph.Probe.ProbeLength * 0.1, Temperature = new[] { (double)(49 + ph.Probe.ProbeLength) } }; probeHandlers.ForEach(ph => ph.Mock_SetProbeReadingValueProducer(mockReadingProducer)); Assert.AreEqual(true, atg.Tanks != null); Assert.AreEqual(true, atg.Tanks.Count() == TankCount); await Task.Delay(atg.polling_fast_TankReadingTimer_Internval * 2); var volumeCaculatorTester = new HeightToVolumeCaculator(sharedTankProfileDatas); foreach (var tank in atg.Tanks) { var tankConfig = tankConfigs.First(tc => tc.TankNumber == tank.TankNumber); var tcCaculator = new TemperatureCompensationCaculator(tankConfig.ThermalCoefficient); var tankReading = await atg.GetTankReadingAsync(tank.TankNumber); Assert.AreEqual(true, tankReading != null); Assert.AreEqual(true, tankReading.Height == tank.Probe.ProbeLength * 0.8); Assert.AreEqual(true, tankReading.Water == tank.Probe.ProbeLength * 0.1); Assert.AreEqual(true, tankReading.Temperature.Value == (double)(49 + tank.Probe.ProbeLength)); Assert.AreEqual(tankReading.TcVolume, tcCaculator.CaculateCompensatedVolume(tankOverallConfig.TcReference, tankReading.Volume.Value, tankReading.Temperature.Value)); Assert.AreEqual(true, tankReading.WaterVolume == volumeCaculatorTester.GetVolume(tankReading.Water.Value)); Assert.AreEqual(true, tankReading.Volume == volumeCaculatorTester.GetVolume(tankReading.Height.Value) - tankReading.WaterVolume); Assert.AreEqual(tankReading.Ullage, volumeCaculatorTester.GetVolume(sharedTankProfileDatas.Max(p => p.Height)) - tankReading.Volume - tankReading.WaterVolume); } } [TestMethod] public async Task Inventory_TestMethod1() { var tanks = atg.Tanks; Func mockReadingProducer = (ph) => new ProbeReading() { Height = ph.Probe.ProbeLength * 0.8, Water = ph.Probe.ProbeLength * 0.1, Temperature = new[] { (double)(49 + ph.Probe.ProbeLength) } }; probeHandlers.ForEach(ph => ph.Mock_SetProbeReadingValueProducer(mockReadingProducer)); Assert.AreEqual(true, atg.Tanks != null); Assert.AreEqual(true, atg.Tanks.Count() == TankCount); await Task.Delay(InventorySamplingInterval * 3); var volumeCaculatorTester = new HeightToVolumeCaculator(sharedTankProfileDatas); foreach (var tank in atg.Tanks) { var tankConfig = tankConfigs.First(tc => tc.TankNumber == tank.TankNumber); var tcCaculator = new TemperatureCompensationCaculator(tankConfig.ThermalCoefficient); var tankReading = await atg.GetTankReadingAsync(tank.TankNumber); Assert.AreEqual(true, tankReading != null); Assert.AreEqual(true, tankReading.Height == tank.Probe.ProbeLength * 0.8); Assert.AreEqual(true, tankReading.Water == tank.Probe.ProbeLength * 0.1); Assert.AreEqual(true, tankReading.Temperature.Value == (double)(49 + tank.Probe.ProbeLength)); Assert.AreEqual(tankReading.TcVolume, tcCaculator.CaculateCompensatedVolume(tankOverallConfig.TcReference, tankReading.Volume.Value, tankReading.Temperature.Value)); Assert.AreEqual(true, tankReading.WaterVolume == volumeCaculatorTester.GetVolume(tankReading.Water.Value)); Assert.AreEqual(true, tankReading.Volume == volumeCaculatorTester.GetVolume(tankReading.Height.Value) - tankReading.WaterVolume); Assert.AreEqual(tankReading.Ullage, volumeCaculatorTester.GetVolume(sharedTankProfileDatas.Max(p => p.Height)) - tankReading.Volume - tankReading.WaterVolume); var inventories = await atg.GetTankInventoryAsync(tank.TankNumber, 1000); Assert.AreEqual(true, inventories != null && inventories.Any()); Assert.AreEqual(true, inventories.Count() >= 2, "Tank with tankNumber: " + tank.TankNumber + " does not has inventory records >=2"); } } [TestMethod] public async Task Delivery_Manual_TestMethod1() { var tanks = atg.Tanks; var probeReading_OnStart = new ProbeReading() { Height = 1000, Water = 10, Temperature = new[] { (double)50 } }; var probeReading_OnStop = new ProbeReading() { Height = 5000, Water = 30, Temperature = new[] { (double)55 } }; Func mockReadingProducer_OnStart_Delivery = (ph) => probeReading_OnStart; Func mockReadingProducer_OnStop_Delivery = (ph) => probeReading_OnStop; probeHandlers.ForEach(ph => ph.Mock_SetProbeReadingValueProducer(mockReadingProducer_OnStart_Delivery)); Assert.AreEqual(true, atg.Tanks != null); Assert.AreEqual(true, atg.Tanks.Count() == TankCount); await Task.Delay(atg.polling_fast_TankReadingTimer_Internval * 2); var volumeCaculatorTester = new HeightToVolumeCaculator(sharedTankProfileDatas); foreach (var tank in atg.Tanks) { var tankConfig = tankConfigs.First(tc => tc.TankNumber == tank.TankNumber); var tcCaculator = new TemperatureCompensationCaculator(tankConfig.ThermalCoefficient); var tankReading_startDelivery = await atg.StartOrStopManualDeliveryAsync(tank.TankNumber, "start"); Assert.AreEqual(true, tankReading_startDelivery != null); Assert.AreEqual(true, tankReading_startDelivery.Height == probeReading_OnStart.Height, $"for tankNumber: {tank.TankNumber}, expect: {probeReading_OnStart.Height}, but actual: {tankReading_startDelivery.Height}"); Assert.AreEqual(true, tankReading_startDelivery.Water == probeReading_OnStart.Water); Assert.AreEqual(true, tankReading_startDelivery.Temperature.Value == probeReading_OnStart.Temperature.First()); } probeHandlers.ForEach(ph => ph.Mock_SetProbeReadingValueProducer(mockReadingProducer_OnStop_Delivery)); await Task.Delay(atg.polling_fast_TankReadingTimer_Internval * 2); foreach (var tank in atg.Tanks) { var tankReading_endDelivery = await atg.StartOrStopManualDeliveryAsync(tank.TankNumber, "stop"); Assert.AreEqual(true, tankReading_endDelivery.Height == probeReading_OnStop.Height); Assert.AreEqual(true, tankReading_endDelivery.Water == probeReading_OnStop.Water); Assert.AreEqual(true, tankReading_endDelivery.Temperature.Value == probeReading_OnStop.Temperature.First()); } foreach (var tank in atg.Tanks) { var tankDeliveries = await atg.GetTankDeliveryAsync(tank.TankNumber, 100); Assert.AreEqual(true, tankDeliveries != null && tankDeliveries.Any()); var latestTankDelivery = tankDeliveries.First(); Assert.AreEqual(true, latestTankDelivery.TankNumber == tank.TankNumber); // it just happened //Assert.AreEqual(true, DateTime.Now.Subtract(latestTankDelivery.StartingDateTime).TotalSeconds <= 2); //Assert.AreEqual(true, DateTime.Now.Subtract(latestTankDelivery.EndingDateTime).TotalSeconds <= InventorySamplingInterval * 4); //Assert.AreEqual(tankReading_startDelivery.TcVolume, // tcCaculator.CaculateCompensatedVolume(tankOverallConfig.TcReference, tankReading_startDelivery.Volume.Value, tankReading_startDelivery.Temperature.Value)); //Assert.AreEqual(true, tankReading_startDelivery.WaterVolume == volumeCaculatorTester.GetVolume(tankReading_startDelivery.Water.Value)); //Assert.AreEqual(true, tankReading_startDelivery.Volume == volumeCaculatorTester.GetVolume(tankReading_startDelivery.Height.Value) - tankReading_startDelivery.WaterVolume); //Assert.AreEqual(tankReading_startDelivery.Ullage, // volumeCaculatorTester.GetVolume(sharedTankProfileDatas.Max(p => p.Height)) - tankReading_startDelivery.Volume - tankReading_startDelivery.WaterVolume); await Task.Delay(atg.polling_fast_TankReadingTimer_Internval * 2); } } [TestMethod] public async Task Alarm_TestMethod1() { var receivedAlarms = new List(); atg.OnAlarm += (s, alEvtArg) => { receivedAlarms.AddRange(alEvtArg.Alarms); }; var tanks = atg.Tanks; var probeReading_OnStart = new ProbeReading() { Height = 1000, Water = 10, Temperature = new[] { (double)50 } }; var probeReading_OnStop = new ProbeReading() { Height = 5000, Water = 30, Temperature = new[] { (double)55 } }; Func mockReadingProducer_OnStart_Delivery = (ph) => probeReading_OnStart; Func mockReadingProducer_OnStop_Delivery = (ph) => probeReading_OnStop; probeHandlers.ForEach(ph => ph.Mock_SetProbeReadingValueProducer(mockReadingProducer_OnStart_Delivery)); Assert.AreEqual(true, atg.Tanks != null); Assert.AreEqual(true, atg.Tanks.Count() == TankCount); await Task.Delay(atg.polling_fast_TankReadingTimer_Internval * 2); var volumeCaculatorTester = new HeightToVolumeCaculator(sharedTankProfileDatas); foreach (var tank in atg.Tanks) { var tankConfig = tankConfigs.First(tc => tc.TankNumber == tank.TankNumber); var tcCaculator = new TemperatureCompensationCaculator(tankConfig.ThermalCoefficient); var tankReading_startDelivery = await atg.StartOrStopManualDeliveryAsync(tank.TankNumber, "start"); Assert.AreEqual(true, tankReading_startDelivery != null); Assert.AreEqual(true, tankReading_startDelivery.Height == probeReading_OnStart.Height, $"for tankNumber: {tank.TankNumber}, expect: {probeReading_OnStart.Height}, but actual: {tankReading_startDelivery.Height}"); Assert.AreEqual(true, tankReading_startDelivery.Water == probeReading_OnStart.Water); Assert.AreEqual(true, tankReading_startDelivery.Temperature.Value == probeReading_OnStart.Temperature.First()); } probeHandlers.ForEach(ph => ph.Mock_SetProbeReadingValueProducer(mockReadingProducer_OnStop_Delivery)); await Task.Delay(atg.polling_fast_TankReadingTimer_Internval * 2); foreach (var tank in atg.Tanks) { var tankReading_endDelivery = await atg.StartOrStopManualDeliveryAsync(tank.TankNumber, "stop"); Assert.AreEqual(true, tankReading_endDelivery.Height == probeReading_OnStop.Height); Assert.AreEqual(true, tankReading_endDelivery.Water == probeReading_OnStop.Water); Assert.AreEqual(true, tankReading_endDelivery.Temperature.Value == probeReading_OnStop.Temperature.First()); } foreach (var tank in atg.Tanks) { var tankDeliveries = await atg.GetTankDeliveryAsync(tank.TankNumber, 100); Assert.AreEqual(true, tankDeliveries != null && tankDeliveries.Any()); var latestTankDelivery = tankDeliveries.First(); Assert.AreEqual(true, latestTankDelivery.TankNumber == tank.TankNumber); // it just happened //Assert.AreEqual(true, DateTime.Now.Subtract(latestTankDelivery.StartingDateTime).TotalSeconds <= 2); //Assert.AreEqual(true, DateTime.Now.Subtract(latestTankDelivery.EndingDateTime).TotalSeconds <= InventorySamplingInterval * 4); //Assert.AreEqual(tankReading_startDelivery.TcVolume, // tcCaculator.CaculateCompensatedVolume(tankOverallConfig.TcReference, tankReading_startDelivery.Volume.Value, tankReading_startDelivery.Temperature.Value)); //Assert.AreEqual(true, tankReading_startDelivery.WaterVolume == volumeCaculatorTester.GetVolume(tankReading_startDelivery.Water.Value)); //Assert.AreEqual(true, tankReading_startDelivery.Volume == volumeCaculatorTester.GetVolume(tankReading_startDelivery.Height.Value) - tankReading_startDelivery.WaterVolume); //Assert.AreEqual(tankReading_startDelivery.Ullage, // volumeCaculatorTester.GetVolume(sharedTankProfileDatas.Max(p => p.Height)) - tankReading_startDelivery.Volume - tankReading_startDelivery.WaterVolume); await Task.Delay(atg.polling_fast_TankReadingTimer_Internval * 2); } } } }