public async Task StartAsync(CancellationToken cancellationToken)
        {
            if (IsRunning)
            {
                await
                    Log.ReportWarningAsync("Cannot start plugin manager because it is already running!",
                        cancellationToken);
                return;
            }
            IsRunning = true;

            using (var context = new ZvsContext(EntityContextConnection))
            {
                // Iterate the plugins found in dlls
                foreach (var plugin in Plugins)
                {
                    //keeps this plugin in scope 
                    var zvsPlugin = plugin;

                    //Check Database for this plugin
                    var dbPlugin = await context.Plugins
                        .FirstOrDefaultAsync(p => p.PluginGuid == zvsPlugin.PluginGuid, cancellationToken);

                    var changed = false;
                    if (dbPlugin == null)
                    {
                        dbPlugin = new Plugin { PluginGuid = zvsPlugin.PluginGuid };
                        context.Plugins.Add(dbPlugin);
                        changed = true;
                    }

                    //Update Name and Description
                    zvsPlugin.IsEnabled = dbPlugin.IsEnabled;

                    if (dbPlugin.Name != zvsPlugin.Name)
                    {
                        dbPlugin.Name = zvsPlugin.Name;
                        changed = true;
                    }

                    if (dbPlugin.Description != zvsPlugin.Description)
                    {
                        dbPlugin.Description = zvsPlugin.Description;
                        changed = true;
                    }

                    if (changed)
                    {
                        var result = await context.TrySaveChangesAsync(cancellationToken);
                        if (result.HasError)
                        {
                            await
                                Log.ReportErrorFormatAsync(cancellationToken,
                                    "Plugin not loaded. Error while saving loaded '{0}' plugin to database. {1}", zvsPlugin.Name, result.Message);
                            break;
                        }
                    }

                    await Log.ReportInfoFormatAsync(cancellationToken, "Initializing '{0}'", zvsPlugin.Name);

                    //Plug-in need access to the zvsEngine in order to use the Logger
                    var log = new DatabaseFeedback(EntityContextConnection) { Source = zvsPlugin.Name };
                    await zvsPlugin.Initialize(log, EntityContextConnection, AdapterManager);

                    //Reload just installed settings
                    var pluginSettings = await context.PluginSettings
                        .Include(o => o.Plugin)
                        .Where(p => p.Plugin.PluginGuid == zvsPlugin.PluginGuid)
                        .ToListAsync(cancellationToken);

                    //Set plug-in settings from database values
                    foreach (var setting in pluginSettings)
                        await SetPluginProperty(plugin, setting.UniqueIdentifier, setting.Value, CancellationToken.None);

                    if (dbPlugin.IsEnabled)
                        await zvsPlugin.StartAsync();

                    if (!_pluginIdToGuid.ContainsKey(dbPlugin.Id))
                        _pluginIdToGuid.Add(dbPlugin.Id, dbPlugin.PluginGuid);
                }
            }
            NotifyEntityChangeContext.ChangeNotifications<PluginSetting>.OnEntityUpdated += PluginManager_OnEntityUpdated;
        }
        public async Task TestPropertyUpdatingOnDatabaseSettingChange()
        {
            //Arrange 
            var dbConnection = new UnitTestDbConnection();
            Database.SetInitializer(new CreateFreshDbInitializer());

            var log = new StubIFeedback<LogEntry>
            {
                ReportAsyncT0CancellationToken = (e, c) =>
                {
                    Console.WriteLine(e.ToString());
                    return Task.FromResult(0);
                }
            };
            var unitTestingPlugin = new StubUnitTestPlugin
            {
                PluginGuidGet = () => Guid.Parse("a0f912a6-b8bb-406a-360f-1eb13f50aae4"),
                NameGet = () => "Unit Testing Plugin",
                DescriptionGet = () => "",
                OnSettingsCreatingPluginSettingBuilder = s => Task.FromResult(0),
                OnDeviceSettingsCreatingDeviceSettingBuilder = s => Task.FromResult(0),
                OnSceneSettingsCreatingSceneSettingBuilder = s => Task.FromResult(0),
            };

            var plugin = new Plugin
            {
                PluginGuid = Guid.Parse("a0f912a6-b8bb-406a-360f-1eb13f50aae4"),
                Name = "Unit Testing Plugin",
                Description = ""
            };
            plugin.Settings.Add(new PluginSetting
            {
                UniqueIdentifier = "PropertyTest",
                Value = "2",
                ValueType = DataType.INTEGER
            });

            using (var context = new ZvsContext(dbConnection))
            {
                context.Plugins.Add(plugin);
                await context.SaveChangesAsync(CancellationToken.None);
            }

            var pluginManager = new PluginManager(new List<ZvsPlugin> { unitTestingPlugin }, dbConnection, log, new StubIAdapterManager());
            await pluginManager.StartAsync(CancellationToken.None);
            //act
            using (var context = new ZvsContext(dbConnection))
            {
                context.PluginSettings.First().Value = "55";
                await context.SaveChangesAsync(CancellationToken.None);
            }

            //assert 
            Assert.IsTrue(unitTestingPlugin.PropertyTest == 55, "The property test property on the zvsPlugin did not properly update when the database value was changed.");
        }
        public async Task LoadPluginsAsyncAutoStartTest()
        {
            //Arrange 
            var dbConnection = new UnitTestDbConnection();
            Database.SetInitializer(new CreateFreshDbInitializer());

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

            var plugin = new Plugin()
            {
                PluginGuid = Guid.Parse("a0f912a6-b8bb-406a-360f-1eb13f50aae4"),
                IsEnabled = true
            };
            using (var context = new ZvsContext(dbConnection))
            {
                context.Plugins.Add(plugin);
                await context.SaveChangesAsync(CancellationToken.None);
            }
            var isStarted = false;
            var unitTestingPlugin = new StubUnitTestPlugin
            {
                PluginGuidGet = () => Guid.Parse("a0f912a6-b8bb-406a-360f-1eb13f50aae4"),
                NameGet = () => "Unit Testing Plugin",
                DescriptionGet = () => "",
                OnSettingsCreatingPluginSettingBuilder = s => Task.FromResult(0),
                OnDeviceSettingsCreatingDeviceSettingBuilder = s => Task.FromResult(0),
                OnSceneSettingsCreatingSceneSettingBuilder = s => Task.FromResult(0),
                StartAsync01 = () =>
                {
                    isStarted = true;
                    return Task.FromResult(0);
                }
            };
            unitTestingPlugin.OnSettingsCreatingPluginSettingBuilder = async settingBuilder =>
            {
                var testSetting = new PluginSetting
                {
                    Name = "Test setting",
                    Value = 360.ToString(CultureInfo.InvariantCulture),
                    ValueType = DataType.INTEGER,
                    Description = "Unit testing only"
                };

                await
                    settingBuilder.Plugin(unitTestingPlugin)
                        .RegisterPluginSettingAsync(testSetting, o => o.PropertyTest);
            };

            var pluginManager = new PluginManager(new List<ZvsPlugin> { unitTestingPlugin }, dbConnection, log, new StubIAdapterManager());

            //act
            await pluginManager.StartAsync(CancellationToken.None);

            //assert 
            Assert.IsTrue(isStarted, "Plugin not started!");
        }
        public async Task DisablePluginAsyncTest()
        {
            //Arrange 
            var dbConnection = new UnitTestDbConnection();
            Database.SetInitializer(new CreateFreshDbInitializer());

            var log = new StubIFeedback<LogEntry>();
            var hasStopped = false;
            var unitTestingPlugin = new StubUnitTestPlugin
            {
                PluginGuidGet = () => Guid.Parse("a0f912a6-b8bb-406a-360f-1eb13f50aae4"),
                NameGet = () => "Unit Testing Plugin",
                DescriptionGet = () => "",
                OnSettingsCreatingPluginSettingBuilder = s => Task.FromResult(0),
                OnDeviceSettingsCreatingDeviceSettingBuilder = s => Task.FromResult(0),
                OnSceneSettingsCreatingSceneSettingBuilder = s => Task.FromResult(0),
                StopAsync01 = async () => hasStopped = true
            };

            var pluginManager = new PluginManager(new List<ZvsPlugin> { unitTestingPlugin }, dbConnection, log, new StubIAdapterManager());

            var plugin = new Plugin
            {
                PluginGuid = Guid.Parse("a0f912a6-b8bb-406a-360f-1eb13f50aae4"),
            };
            using (var context = new ZvsContext(dbConnection))
            {
                context.Plugins.Add(plugin);
                await context.SaveChangesAsync(CancellationToken.None);
            }

            //act
            var result = await pluginManager.DisablePluginAsync(Guid.Parse("a0f912a6-b8bb-406a-360f-1eb13f50aae4"), CancellationToken.None);

            //assert 
            Assert.IsFalse(result.HasError, result.Message);
            Assert.IsTrue(hasStopped, "Expected plugin StopAsync to be called.");
        }
        public async Task StopWhenNotStartedTest()
        {
            //Arrange 
            var dbConnection = new UnitTestDbConnection();
            Database.SetInitializer(new CreateFreshDbInitializer());
            var logEntries = new List<LogEntry>();
            var log = new StubIFeedback<LogEntry>
            {
                ReportAsyncT0CancellationToken = (e, c) =>
                {
                    logEntries.Add(e);
                    Console.WriteLine(e.ToString());
                    return Task.FromResult(0);
                }
            };

            var plugin = new Plugin()
            {
                PluginGuid = Guid.Parse("a0f912a6-b8bb-406a-360f-1eb13f50aae4"),
                IsEnabled = true
            };
            using (var context = new ZvsContext(dbConnection))
            {
                context.Plugins.Add(plugin);
                await context.SaveChangesAsync(CancellationToken.None);
            }
            var unitTestingPlugin = new StubUnitTestPlugin
            {
                PluginGuidGet = () => Guid.Parse("a0f912a6-b8bb-406a-360f-1eb13f50aae4"),
                NameGet = () => "Unit Testing Plugin",
                DescriptionGet = () => "",
                OnSettingsCreatingPluginSettingBuilder = s => Task.FromResult(0),
                OnDeviceSettingsCreatingDeviceSettingBuilder = s => Task.FromResult(0),
                OnSceneSettingsCreatingSceneSettingBuilder = s => Task.FromResult(0)
            };
           
            var pluginManager = new PluginManager(new List<ZvsPlugin> { unitTestingPlugin }, dbConnection, log, new StubIAdapterManager());

            //act
            await pluginManager.StopAsync(CancellationToken.None);

            //assert 
            Assert.IsTrue(logEntries.Count(o => o.Level == LogEntryLevel.Warn) == 1);
        }
        public async Task StopTest()
        {
            //Arrange 
            var dbConnection = new StubIEntityContextConnection { NameOrConnectionStringGet = () => "am-StopTest" };
            Database.SetInitializer(new CreateFreshDbInitializer());
            var logEntries = new List<LogEntry>();
            var log = new StubIFeedback<LogEntry>
            {
                ReportAsyncT0CancellationToken = (e, c) =>
                {
                    logEntries.Add(e);
                    Console.WriteLine(e.ToString());
                    return Task.FromResult(0);
                }
            };

            var plugin = new Plugin()
            {
                PluginGuid = Guid.Parse("a0f912a6-b8bb-406a-360f-1eb13f50aae4"),
                IsEnabled = true
            };
            using (var context = new ZvsContext(dbConnection))
            {
                context.Plugins.Add(plugin);
                await context.SaveChangesAsync(CancellationToken.None);
            }
            var isStartedCount = 0;
            var isStoppedCount = 0;
            var unitTestingPlugin = new StubUnitTestPlugin
            {
                PluginGuidGet = () => Guid.Parse("a0f912a6-b8bb-406a-360f-1eb13f50aae4"),
                NameGet = () => "Unit Testing Plugin",
                DescriptionGet = () => "",
                OnSettingsCreatingPluginSettingBuilder = (s) => Task.FromResult(0),
                OnDeviceSettingsCreatingDeviceSettingBuilder = (s) => Task.FromResult(0),
                OnSceneSettingsCreatingSceneSettingBuilder = (s) => Task.FromResult(0),
                StartAsync01 = () =>
                {
                    isStartedCount++;
                    return Task.FromResult(0);
                },
                StopAsync01 = () =>
                {
                    isStoppedCount++;
                    return Task.FromResult(0);
                }
            };
            unitTestingPlugin.OnSettingsCreatingPluginSettingBuilder = async (settingBuilder) =>
            {
                var testSetting = new PluginSetting
                {
                    Name = "Test setting",
                    Value = 360.ToString(CultureInfo.InvariantCulture),
                    ValueType = DataType.INTEGER,
                    Description = "Unit testing only"
                };

                await
                    settingBuilder.Plugin(unitTestingPlugin)
                        .RegisterPluginSettingAsync(testSetting, o => o.PropertyTest);
            };

            var pluginManager = new PluginManager(new List<ZvsPlugin> { unitTestingPlugin }, dbConnection, log, new StubIAdapterManager());

            //act
            await pluginManager.StartAsync(CancellationToken.None);
            await pluginManager.StopAsync(CancellationToken.None);

            //assert 
            Assert.IsTrue(logEntries.All(o => o.Level == LogEntryLevel.Info), "Not all log entries are info level");
            Assert.IsTrue(isStartedCount == 1, "Plugin started too many or too few times");
            Assert.IsTrue(isStoppedCount == 1, "Plugin stopped too many or too few times");
        }