public async Task LogEntrySingleContextLimitTest()
        {
            //Arrange 
            var dbConnection = new StubIEntityContextConnection { NameOrConnectionStringGet = () => "LogEntrySingleContextLimitTest" };
            Database.SetInitializer(new DropCreateDatabaseAlways<ZvsContext>());

            using (var context = new ZvsContext(dbConnection))
            {
                for (var i = 0; i < 2023; i++)
                {
                    context.LogEntries.Add(new LogEntry
                    {
                        Datetime = DateTime.Now,
                        Level = LogEntryLevel.Info,
                        Message = string.Format("hello world {0}", i),
                        Source = "Source"
                    });
                }
                await context.SaveChangesAsync(CancellationToken.None);
            }

            using (var context = new ZvsContext(dbConnection))
            {
                var currentLogEntryCount = context.LogEntries.Count();
                var firstentry = await context.LogEntries.OrderBy(o => o.Datetime).FirstAsync();
                var lastEntry = await context.LogEntries.OrderByDescending(o => o.Datetime).FirstAsync();
                //Aseert
                Assert.IsTrue(currentLogEntryCount == 2000, "Expected 2000 entries and got " + currentLogEntryCount);
                Assert.IsTrue(firstentry.Message == "hello world 24", "Expected first entry to start with 24");
                Assert.IsTrue(lastEntry.Message == "hello world 2022", "Expected last entry to start with 2002");
            }
        }
        public async Task RegisterAsyncNewDeviceTypeTest()
        {
            //arrange 
            var dbConnection = new StubIEntityContextConnection { NameOrConnectionStringGet = () => "dtb-RegisterAsyncNewDeviceTypeTest" };
            Database.SetInitializer(new CreateFreshDbInitializer());

            var dtb = new DeviceTypeBuilder( dbConnection);
            var adapter = UnitTesting.CreateFakeAdapter();
            using (var context = new ZvsContext(dbConnection))
            {
                context.Adapters.Add(adapter);
                await context.SaveChangesAsync();
            }

            var dt = new DeviceType
            {
                AdapterId = adapter.Id,
                UniqueIdentifier = "UNIT_TEST_DEVICE_TYPE1",
                Name = "Unit Test Device Type"
            };

            //act
            var result = await dtb.RegisterAsync(adapter.AdapterGuid, dt, CancellationToken.None);

            //assert 
            Console.WriteLine(result.Message);
            Assert.IsFalse(result.HasError);
            Assert.IsTrue(dt.Id > 0, "Expected device type to have a database generated Id");
        }
        public async Task RegisterAsyncNewTest()
        {
            //arrange 
            var dbConnection = new StubIEntityContextConnection { NameOrConnectionStringGet = () => "bcb-RegisterAsyncNewTest" };
            Database.SetInitializer(new CreateFreshDbInitializer());
            var bcb = new BuiltinCommandBuilder(dbConnection);

            var builtinCommand = new BuiltinCommand
            {
                Name = "Unit Test Builtin Command",
                UniqueIdentifier = "BUILTIN_COMMAND1"
            };

            //act
            var result = await bcb.RegisterAsync(builtinCommand, CancellationToken.None);

            BuiltinCommand setting;
            using (var context = new ZvsContext(dbConnection))
            {
                setting =
                    await
                        context.BuiltinCommands.FirstOrDefaultAsync(
                            o => o.UniqueIdentifier == builtinCommand.UniqueIdentifier);

            }

            //assert 
            Console.WriteLine(result.Message);
            Assert.IsFalse(result.HasError, result.Message);
            Assert.IsNotNull(setting, "Expected new builtin command setting saved to DB");
        }
        public async Task RegisterAsyncNewTest()
        {
            //arrange 
            var dbConnection = new StubIEntityContextConnection { NameOrConnectionStringGet = () => "dsb-RegisterAsyncNewTest" };
            Database.SetInitializer(new CreateFreshDbInitializer());
            var dsb = new DeviceSettingBuilder(dbConnection);

            var deviceSetting = new DeviceSetting
            {
                Name = "Unit Test Device Setting",
                UniqueIdentifier = "DEVICE_SETTING1"
            };

            //act
            var result = await dsb.RegisterAsync(deviceSetting, CancellationToken.None);

            DeviceSetting setting;
            using (var context = new ZvsContext(dbConnection))
            {
                setting =
                    await
                        context.DeviceSettings.FirstOrDefaultAsync(
                            o => o.UniqueIdentifier == deviceSetting.UniqueIdentifier);

            }

            //assert 
            Console.WriteLine(result.Message);
            Assert.IsFalse(result.HasError, result.Message);
            Assert.IsNotNull(setting, "Expected new device setting saved to DB");
        }
        public async Task LoadAdaptersNameTooLongAsyncTest()
        {
            //Arrange 
            var dbConnection = new StubIEntityContextConnection { NameOrConnectionStringGet = () => "am-LoadAdaptersNameTooLongAsyncTest" };
            Database.SetInitializer(new CreateFreshDbInitializer());

            var logEntries = new List<LogEntry>();
            var log = new StubIFeedback<LogEntry>
            {
                ReportAsyncT0CancellationToken = (e, c) =>
                {
                    Console.WriteLine(e.ToString());
                    logEntries.Add(e);
                    return Task.FromResult(0);
                }
            };

            var longNameAdapter = new StubZvsAdapter
            {
                AdapterGuidGet = () => Guid.Parse("a0f912a6-b8bb-406a-360f-1eb13f50aae4"),
                NameGet = () => "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque magna diam, pellentesque et orci eget, pellentesque iaculis odio. Ut ultrices est sapien, ac pellentesque odio malesuada a. Etiam in neque ullamcorper massa gravida ullamcorper vel a posuere.",
                DescriptionGet = () => "",
                OnSettingsCreatingAdapterSettingBuilder = (s) => Task.FromResult(0),
                OnDeviceTypesCreatingDeviceTypeBuilder = (s) => Task.FromResult(0)
            };

            var adapterManager = new AdapterManager(new List<ZvsAdapter>() { longNameAdapter }, dbConnection, log);
            //act
            await adapterManager.StartAsync(CancellationToken.None);

            //assert 
            Assert.IsTrue(logEntries.Count(o => o.Level == LogEntryLevel.Error) == 1, "Expected 1 error");
        }
        public async Task RegisterAsyncNewDeviceValueTest()
        {
            //arrange 
            var dbConnection = new StubIEntityContextConnection { NameOrConnectionStringGet = () => "dvb-RegisterAsyncNewDeviceValueTest" };
            Database.SetInitializer(new CreateFreshDbInitializer());

            var dvb = new DeviceValueBuilder( dbConnection);

            var device = UnitTesting.CreateFakeDevice();
            using (var context = new ZvsContext(dbConnection))
            {
                context.Devices.Add(device);
                await context.SaveChangesAsync();

                var deviceValue = new DeviceValue
                {
                    Description = "Testing Value Description Here",
                    Name = "Test Value",
                    ValueType = DataType.BOOL,
                    Value = true.ToString(),
                    DeviceId = device.Id
                };

                //act
                var result = await dvb.RegisterAsync(deviceValue, device, CancellationToken.None);
                var dv = await context.DeviceValues.FirstOrDefaultAsync(o => o.Name == deviceValue.Name);


                //assert 
                Assert.IsFalse(result.HasError, result.Message);
                Assert.IsNotNull(dv, "Registered device value count not be found in database.");
                Console.WriteLine(result.Message);
            }
        }
 public void ConstructorNullArg1Test()
 {
     //arrange 
     var dbConnection = new StubIEntityContextConnection();
     //act
     new DeviceValueBuilder(null);
     //assert - throws exception
 }
 public void ConstructorNullArg1Test()
 {
     var dbConnection = new StubIEntityContextConnection { NameOrConnectionStringGet = () => "MultilpleTriggersTest" };
     Database.SetInitializer(new CreateFreshDbInitializer());
     //arrange 
     //act
     new TriggerRunner(null, new StubICommandProcessor(), new ZvsEntityContextConnection());
     //assert - throws exception
 }
 public void ConstructorTest()
 {
     //arrange 
     var dbConnection = new StubIEntityContextConnection();
     //act
     var bcb = new BuiltinCommandBuilder(dbConnection);
     //assert 
     Assert.IsNotNull(bcb);
 }
 public void ConstructorTest()
 {
     //arrange 
     var dbConnection = new StubIEntityContextConnection();
     //act
     var ssb = new SceneSettingBuilder(dbConnection);
     //assert 
     Assert.IsNotNull(ssb);
 }
 public void ConstructorTest()
 {
     //arrange 
     var dbConnection = new StubIEntityContextConnection();
     //act
     var dvb = new DeviceValueBuilder(dbConnection);
     //assert 
     Assert.IsNotNull(dvb);
 }
        public async Task RegisterAsyncNullDeviceValueTest()
        {
            //arrange 
            var dbConnection = new StubIEntityContextConnection();
            var dvb = new DeviceValueBuilder( dbConnection);

            //act
            var result = await dvb.RegisterAsync(null, new Device(), CancellationToken.None);

            //assert 
            Assert.IsTrue(result.HasError);
        }
        public async Task RegisterAsyncNullBuiltinCommandTest()
        {
            //arrange 
            var dbConnection = new StubIEntityContextConnection();
            var bcb = new BuiltinCommandBuilder(dbConnection);

            //act
            var result = await bcb.RegisterAsync(null, CancellationToken.None);

            //assert 
            Console.WriteLine(result.Message);
            Assert.IsTrue(result.HasError, result.Message);
        }
        public async Task RegisterAsyncNullDeviceValueTest()
        {
            //arrange 
            var dbConnection = new StubIEntityContextConnection();
            var dvb = new DeviceCommandBuilder( dbConnection);

            //act
            var result = await dvb.RegisterAsync(1, null, CancellationToken.None);

            //assert 
            Assert.IsTrue(result.HasError);
            Console.WriteLine(result.Message);
        }
        public void ConstructorNullArg3Test()
        {
            //arrange 
            var fb = new StubIFeedback<LogEntry>();
            var am = new StubIAdapterManager();
            var connection = new StubIEntityContextConnection();
            var tr = new TriggerRunner(fb, new StubICommandProcessor(), connection);
            var st = new StubScheduledTaskRunner(fb, new StubICommandProcessor(), connection, new StubITimeProvider());

            //act
            new ZvsEngine(fb, am, null, connection, tr, st);
            //assert - throws exception
        }
        public async Task LogEntryLimitMultiThreadedTest()
        {
            //Arrange 
            var dbConnection = new StubIEntityContextConnection { NameOrConnectionStringGet = () => "LogEntryLimitMultiThreadedTest" };
            Database.SetInitializer(new DropCreateDatabaseAlways<ZvsContext>());

            var log = new DatabaseFeedback(dbConnection);

            var task1 = Task.Run(async () =>
            {
                for (var i = 0; i < 1500; i++)
                {
                    await log.ReportInfoFormatAsync(CancellationToken.None, "loop1 {0}", i);
                }
            });

            var task2 = Task.Run(async () =>
            {
                for (var i = 0; i < 400; i++)
                {
                    await log.ReportInfoFormatAsync(CancellationToken.None, "loop2 {0}", i);
                }
            });

            var task3 = Task.Run(async () =>
            {
                using (var context = new ZvsContext(dbConnection))
                {
                    for (var i = 0; i < 700; i++)
                    {
                        context.LogEntries.Add(new LogEntry
                        {
                            Datetime = DateTime.Now,
                            Level = LogEntryLevel.Info,
                            Message = string.Format("loop3 {0}", i),
                            Source = "Source"
                        });
                    }
                    await context.SaveChangesAsync(CancellationToken.None);
                }
            });

            await Task.WhenAll(task1, task2, task3);

            using (var context = new ZvsContext(dbConnection))
            {
                var currentLogEntryCount = context.LogEntries.Count();
                //Assert
                Assert.IsTrue(currentLogEntryCount == 2000, "Expected 2000 entries and got " + currentLogEntryCount);
            }
        }
        public async Task RegisterAsyncInvalidAdapterTest()
        {
            //arrange 
            var dbConnection = new StubIEntityContextConnection { NameOrConnectionStringGet = () => "dtb-RegisterAsyncInvalidAdapterTest" };
            Database.SetInitializer(new CreateFreshDbInitializer());

            var dtb = new DeviceTypeBuilder( dbConnection);

            //act
            var result = await dtb.RegisterAsync(new Guid(), new DeviceType(), CancellationToken.None);

            //assert 
            Assert.IsTrue(result.HasError);
            Console.WriteLine(result.Message);
        }
        public async Task RegisterAdapterSettingNullAdapterTest()
        {
            //Arrange 
            var dbConnection = new StubIEntityContextConnection { NameOrConnectionStringGet = () => "asb-RegisterAdapterSettingNullAdapterTest" };
            Database.SetInitializer(new CreateFreshDbInitializer());
            var adapterBuilder = new AdapterSettingBuilder( dbConnection, CancellationToken.None);
            var adapter = new StubUnitTestAdapter();

            //act
            var result = await adapterBuilder.Adapter(adapter).RegisterAdapterSettingAsync(new AdapterSetting(), o => o.PropertyTest);

            //assert 
            Console.WriteLine(result.Message);
            Assert.IsTrue(result.HasError);
        }
        public async Task RegisterAsyncInvalidDeviceIdTest()
        {
            //arrange 
            var dbConnection = new StubIEntityContextConnection { NameOrConnectionStringGet = () => "dcb-RegisterAsyncInvalidDeviceIdTest" };
            Database.SetInitializer(new CreateFreshDbInitializer());
            var dvb = new DeviceCommandBuilder(dbConnection);

            var deviceCommand = new DeviceCommand();

            //act
            var result = await dvb.RegisterAsync(3, deviceCommand, CancellationToken.None);

            //assert 
            Assert.IsTrue(result.HasError);
            Console.WriteLine(result.Message);
        }
        public async Task RegisterAdapterSettingAdapterTest()
        {
            //Arrange 
            var dbConnection = new StubIEntityContextConnection { NameOrConnectionStringGet = () => "asb-RegisterAdapterSettingAdapterTest" };
            Database.SetInitializer(new CreateFreshDbInitializer());
            var adapterBuilder = new AdapterSettingBuilder(dbConnection, CancellationToken.None);
            var dbAdapter = UnitTesting.CreateFakeAdapter();
            using (var context = new ZvsContext(dbConnection))
            {
                context.Adapters.Add(dbAdapter);
                await context.SaveChangesAsync();
            }
            var adapter = new StubUnitTestAdapter
            {
                AdapterGuidGet = () => dbAdapter.AdapterGuid
            };

            var adapterSetting = new AdapterSetting
            {
                Name = "Adapter Setting 1",
                ValueType = DataType.STRING,
                Value = "Hello World"
            };
               
            //act
            var result = await adapterBuilder.Adapter(adapter).RegisterAdapterSettingAsync(adapterSetting, o => o.PropertyTest);

            Adapter a;
            using (var context = new ZvsContext(dbConnection))
            {
                a = await context.Adapters
                    .Include(o=> o.Settings)
                    .FirstOrDefaultAsync(o => o.AdapterGuid == dbAdapter.AdapterGuid);
            }

            //assert 
            Console.WriteLine(result.Message);
            Assert.IsFalse(result.HasError);
            Assert.IsTrue(a.Settings.Count == 1, "Expected 1 adapter setting");
            Assert.IsTrue(a.Settings[0].Name == adapterSetting.Name, "Adapter setting name mismatch");
        }
        public async Task ExecuteDeviceCommandAsyncInvalidIdTest()
        {
            //Arrange 
            var dbConnection = new StubIEntityContextConnection { NameOrConnectionStringGet = () => "CP-ExecuteDeviceCommandAsyncInvalidIdTest" };
            Database.SetInitializer(new CreateFreshDbInitializer());

            var adapterManager = new StubIAdapterManager();
            var ranstoredCommands = new List<int>();
            var log = new StubIFeedback<LogEntry>();
            var cts = new CancellationTokenSource();
            var commmandProcessor = new CommandProcessor(adapterManager, dbConnection, log);

            //Act
            var result = await commmandProcessor.ExecuteDeviceCommandAsync(new DeviceCommand(), "", "", cts.Token);
            Console.WriteLine(result.Message);

            //Assert
            Assert.IsTrue(result.HasError);
            Assert.IsTrue(ranstoredCommands.Count == 0, "Process did not run the correct amount of commands.");
            Assert.IsTrue(result.Message.Contains("Cannot locate"), "Expect error message to contain 'Cannot locate'");
        }
        public async Task RunSceneAsyncInvalidSceneTest()
        {
            //Arrange 
            var dbConnection = new StubIEntityContextConnection { NameOrConnectionStringGet = () => "Scene-RunSceneAsyncInvalidSceneTest" };
            Database.SetInitializer(new CreateFreshDbInitializer());

            var logEntries = new List<LogEntry>();
            var ranstoredCommands = new List<int>();

            var log = new StubIFeedback<LogEntry>
            {
                ReportAsyncT0CancellationToken = (e, c) =>
                {
                    Console.WriteLine(e.ToString());
                    logEntries.Add(e);
                    return Task.FromResult(0);
                }
            };

            var commandProcessor = new StubICommandProcessor
            {
                RunCommandAsyncNullableOfInt32StringStringCancellationToken = (commandId, argument, argument2, cancellationToken) =>
                {
                    if (commandId.HasValue) ranstoredCommands.Add(commandId.Value);
                    return Task.FromResult(Result.ReportSuccess());
                }
            };

            var cts = new CancellationTokenSource();
            var sceneRunner = new SceneRunner(log, commandProcessor, dbConnection);

            //Act
            var result = await sceneRunner.RunSceneAsync(-1, cts.Token);

            //Assert
            Assert.IsTrue(result.HasError);
            Assert.IsTrue(logEntries.All(o => o.Level == LogEntryLevel.Warn), "Expected only info type log entries");
            Assert.IsTrue(ranstoredCommands.Count == 0, "Scene runner did not run the correct amount of commands.");
        }
        public async Task RegisterAsyncAddNewCommandTest()
        {
            //arrange 
            var dbConnection = new StubIEntityContextConnection { NameOrConnectionStringGet = () => "dcb-RegisterAsyncAddNewCommandTest" };
            Database.SetInitializer(new CreateFreshDbInitializer());
            var dvb = new DeviceCommandBuilder( dbConnection);

            var device = UnitTesting.CreateFakeDevice();
            using (var context = new ZvsContext(dbConnection))
            {
                context.Devices.Add(device);
                await context.SaveChangesAsync();
            }

            var deviceCommand = new DeviceCommand()
            {
                Name = "Unit Testing Command"
            };
            
            //act
            var result = await dvb.RegisterAsync(device.Id, deviceCommand, CancellationToken.None);
            Console.WriteLine(result.Message);

            Device d;
            using (var context = new ZvsContext(dbConnection))
            {
                d = await context.Devices
                    .Include(o=> o.Commands)
                    .FirstOrDefaultAsync(o => o.Id == device.Id);
            }

            //assert 
            Assert.IsFalse(result.HasError, result.Message);
            Assert.IsNotNull(d, "device not found!");
            Assert.IsTrue(d.Commands.Count == 1, "Device has an unexpected number of commands");
            Assert.IsTrue(d.Commands[0].Name == deviceCommand.Name, "Device command did not save correctly");
        }
        public async Task LogEntryMultipleContextLimitTest()
        {
            //Arrange 
            var dbConnection = new StubIEntityContextConnection { NameOrConnectionStringGet = () => "LogEntrySingleContextLimitTest" };
            Database.SetInitializer(new DropCreateDatabaseAlways<ZvsContext>());

            var log = new DatabaseFeedback(dbConnection);

            for (var i = 0; i < 2003; i++)
            {
                await log.ReportInfoFormatAsync(CancellationToken.None, "hello world {0}", i);
            }

            using (var context = new ZvsContext(dbConnection))
            {
                var currentLogEntryCount = context.LogEntries.Count();
                var firstentry = await context.LogEntries.OrderBy(o => o.Datetime).FirstAsync();
                var lastEntry = await context.LogEntries.OrderByDescending(o => o.Datetime).FirstAsync();
                //Aseert
                Assert.IsTrue(currentLogEntryCount == 2000, "Expected 2000 entries and got " + currentLogEntryCount);
                Assert.IsTrue(firstentry.Message == "hello world 3", "Expected first entry to start with 3");
                Assert.IsTrue(lastEntry.Message == "hello world 2002", "Expected last entry to start with 2002");
            }
        }
        public async Task RegisterAsyncNothingToUpdateTest()
        {
            //arrange 
            var dbConnection = new StubIEntityContextConnection { NameOrConnectionStringGet = () => "dvb-RegisterAsyncNothingToUpdateTest" };
            Database.SetInitializer(new CreateFreshDbInitializer());

            var dvb = new DeviceValueBuilder(dbConnection);

            var device = UnitTesting.CreateFakeDevice();
            using (var context = new ZvsContext(dbConnection))
            {
                context.Devices.Add(device);
                var deviceValue = new DeviceValue
                {
                    UniqueIdentifier = "UNIT_TESTING_VALUE1",
                    CommandClass = "Command Class 1",
                    CustomData1 = "Custom Data 1",
                    CustomData2 = "Custom Data 2",
                    Description = "Testing Value Description Here",
                    Name = "Test Value",
                    ValueType = DataType.BOOL,
                    Value = true.ToString(),
                    Genre = "Genre",
                    Index = "Index",
                    IsReadOnly = true
                };
                device.Values.Add(deviceValue);
                await context.SaveChangesAsync();

                //act
                var result = await dvb.RegisterAsync(deviceValue, device, CancellationToken.None);
                var dv = await context.DeviceValues.FirstOrDefaultAsync(o => o.Name == deviceValue.Name);

                //assert 
                Assert.IsFalse(result.HasError, result.Message);
                Assert.IsNotNull(dv, "Registered device value count not be found in database.");
                Console.WriteLine(result.Message);
            }

        }
        public async Task StartAsyncTest()
        {
            //arrange 
            var dbConnection = new StubIEntityContextConnection { NameOrConnectionStringGet = () => "engine-StartAsyncTest" };
            Database.SetInitializer(new CreateFreshDbInitializer());

            var logEntries = new List<LogEntry>();
            var log = new StubIFeedback<LogEntry>
            {
                ReportAsyncT0CancellationToken = (e, c) =>
                {
                    Console.WriteLine(e.ToString());
                    logEntries.Add(e);
                    return Task.FromResult(0);
                }
            };
            var isAdapterManagerInitialized = false;
            var isPluginManagerInitialized = false;
           

            var am = new StubIAdapterManager { StartAsyncCancellationToken = async (ct) =>isAdapterManagerInitialized = true };
            var pm = new StubIPluginManager { StartAsyncCancellationToken = async (ct) => isPluginManagerInitialized = true };
            var tr = new TriggerRunner(log, new StubICommandProcessor(), dbConnection);
            var st = new ScheduledTaskRunner(log, new StubICommandProcessor(), dbConnection,new CurrentTimeProvider());

            var engine = new ZvsEngine(log, am, pm, dbConnection, tr, st);

            //Act 
            await engine.StartAsync(CancellationToken.None);


            //assert 
            Assert.IsNotNull(engine);
            Assert.IsTrue(isAdapterManagerInitialized, "Adapter manager was not started!");
            Assert.IsTrue(isPluginManagerInitialized, "Plugin manager was not started!");
            Assert.IsTrue(engine.ScheduledTaskRunner.IsRunning, "Scheduled Task Runner was not started!");
            Assert.IsTrue(engine.TriggerRunner.IsRunning, "Trigger Runner was not started!");
        }
        public void ConstructorTest()
        {
            //arrange 
            var fb = new StubIFeedback<LogEntry>();
            var am = new StubIAdapterManager();
            var pm = new StubIPluginManager();
            var connection = new StubIEntityContextConnection();
            var tr = new TriggerRunner(fb, new StubICommandProcessor(), connection);
            var st = new StubScheduledTaskRunner(fb, new StubICommandProcessor(), connection, new StubITimeProvider());

            //act
            var engine = new ZvsEngine(fb, am, pm, connection, tr, st);
            
            //assert 
            Assert.IsNotNull(engine);
        }
        public void ConstructorNullArg6Test()
        {
            //arrange 
            var fb = new StubIFeedback<LogEntry>();
            var am = new StubIAdapterManager();
            var pm = new StubIPluginManager();
            var connection = new StubIEntityContextConnection();
            var tr = new TriggerRunner(fb, new StubICommandProcessor(), connection);

            //act
            new ZvsEngine(fb, am, pm, connection, tr, null);
            //assert - throws exception
        }
        public async Task LessThanInvalidValuesTest()
        {
            //Arrange 
            var dbConnection = new StubIEntityContextConnection { NameOrConnectionStringGet = () => "Trigger-LessThanInvalidValuesTest" };
            Database.SetInitializer(new CreateFreshDbInitializer());

            var logEntries = new List<LogEntry>();
            var ranstoredCommands = new List<int>();
            var log = new StubIFeedback<LogEntry>
            {
                ReportAsyncT0CancellationToken = (e, c) =>
                {
                    Console.WriteLine(e.ToString());
                    logEntries.Add(e);
                    return Task.FromResult(0);
                }
            };

            var commandProcessor = new StubICommandProcessor
            {
                RunCommandAsyncNullableOfInt32StringStringCancellationToken = ( commandId, argument, argument2, cancellationToken) =>
                {
                    if (commandId.HasValue) ranstoredCommands.Add(commandId.Value);
                    return Task.FromResult(Result.ReportSuccess());
                }
            };


            Database.SetInitializer(new CreateFreshDbInitializer());

            var cts = new CancellationTokenSource();
            var triggerManager = new TriggerRunner(log, commandProcessor, dbConnection);
            await triggerManager.StartAsync(cts.Token);

            var cmd = new Command();
            var dv = new DeviceValue
            {
                Value = "first value",
                ValueType = DataType.STRING,
                Triggers = new ObservableCollection<DeviceValueTrigger> { 
                    new DeviceValueTrigger
                {
                     Name = "trigger1",
                     IsEnabled = true,
                     Operator = TriggerOperator.LessThan,
                     Value = "a",
                     Command = cmd
                } }
            };

            var device = UnitTesting.CreateFakeDevice();
            device.Values.Add(dv);

            using (var context = new ZvsContext(dbConnection))
            {
                context.Devices.Add(device);
                var r = await context.TrySaveChangesAsync(cts.Token);
                Assert.IsFalse(r.HasError, r.Message);
                dv.Value = "3";

                //Act
                var r2 = await context.TrySaveChangesAsync(cts.Token);
                Assert.IsFalse(r2.HasError, r2.Message);
            }

            await Task.Delay(700, cts.Token);
            await triggerManager.StopAsync(cts.Token);

            //Assert
            Assert.IsTrue(logEntries.Any(o => o.Level == LogEntryLevel.Warn), "Expected some warning log entries");
            Assert.IsTrue(ranstoredCommands.Count == 0, "Trigger runner did not run the correct amount of commands.");
        }
        public async Task StopPath2()
        {
            var dbConnection = new StubIEntityContextConnection { NameOrConnectionStringGet = () => "TriggerStopPath2" };
            Database.SetInitializer(new CreateFreshDbInitializer());

            //Arrange 
            LogEntry logEntry = null;
            var log = new StubIFeedback<LogEntry>
            {
                ReportAsyncT0CancellationToken = (e, c) =>
                {
                    Console.WriteLine(e.ToString());
                    logEntry = e;
                    return Task.FromResult(0);
                }
            };
            var cts = new CancellationTokenSource();
            var tm = new TriggerRunner(log, new StubICommandProcessor(), dbConnection);

            //Act
            await tm.StopAsync(cts.Token);

            //Assert
            Assert.AreEqual(logEntry.Level, LogEntryLevel.Warn);
        }