public async Task ACustomEventShouldUsingSelectorUsingDataNotExisstFuncNotCall() { // ARRANGE var hcMock = HassClientMock.DefaultMock; var daemonHost = new NetDaemonHost(hcMock.Object, new Mock <IDataRepository>().Object); dynamic dynObject = new ExpandoObject(); dynObject.Test = "Hello World!"; hcMock.AddCustomEvent("CUSTOM_EVENT", dynObject); var cancelSource = hcMock.GetSourceWithTimeout(); var isCalled = false; string?message = ""; daemonHost .Events(n => n.EventId == "CUSTOM_EVENT" && n?.Data?.NotExist == "Hello Test!") .Call((ev, data) => { isCalled = true; message = data?.Test; return(Task.CompletedTask); }).Execute(); try { await daemonHost.Run("host", 8123, false, "token", cancelSource.Token).ConfigureAwait(false); } catch (TaskCanceledException) { // Expected behaviour } Assert.False(isCalled); }
public CoreDaemonHostTestBase() : base() { DefaultDaemonApp = new BaseTestApp { Id = "app_id", IsEnabled = true }; DefaultDaemonHost.AddRunningApp(DefaultDaemonApp); DefaultDaemonRxApp = new BaseTestRxApp { Id = "app_rx_id", IsEnabled = true }; DefaultDaemonHost.AddRunningApp(DefaultDaemonRxApp); DefaultMockedRxApp = new Mock <NetDaemonRxApp>() { CallBase = true }; DefaultMockedRxApp.Object.Id = "app_rx_mock_id"; DefaultMockedRxApp.Object.IsEnabled = true; DefaultMockedRxApp.Setup(n => n.CreateObservableIntervall(It.IsAny <TimeSpan>(), It.IsAny <Action>())).Returns(new Mock <IDisposable>().Object); DefaultDaemonHost.AddRunningApp(DefaultMockedRxApp.Object); var notConnectedHassClientFactoryMock = new HassClientFactoryMock(HassClientMock.MockConnectFalse); _notConnectedDaemonHost = new NetDaemonHost(notConnectedHassClientFactoryMock.Object, DefaultDataRepositoryMock.Object, LoggerMock.LoggerFactory); SetupFakeData(); }
private async Task GenerateEntities(NetDaemonHost daemonHost, string sourceFolder) { if (!_netDaemonSettings.GenerateEntities.GetValueOrDefault()) { return; } if (_entitiesGenerated) { return; } _logger.LogTrace("Generating entities from Home Assistant instance .."); _entitiesGenerated = true; var services = await daemonHost.GetAllServices().ConfigureAwait(false); var sourceRx = CodeGenerator.GenerateCodeRx( "Netdaemon.Generated.Reactive", daemonHost.State.Select(n => n.EntityId).Distinct(), services ); await File.WriteAllTextAsync(Path.Combine(sourceFolder !, "_EntityExtensionsRx.cs.gen"), sourceRx).ConfigureAwait(false); }
public void RunNullReferenceToHassClientShouldThrowException() { // ARRANGE // ACT and ASSERT Assert.Throws <ArgumentNullException>(() => { var DefaultDaemonHost = new NetDaemonHost(null, null); }); }
internal DaemonHostTestaBase() { _loggerMock = new LoggerMock(); _defaultHassClientMock = HassClientMock.DefaultMock; _defaultDataRepositoryMock = new Mock <IDataRepository>(); _defaultDaemonHost = new NetDaemonHost(_defaultHassClientMock.Object, _defaultDataRepositoryMock.Object, _loggerMock.LoggerFactory); _notConnectedDaemonHost = new NetDaemonHost(HassClientMock.MockConnectFalse.Object, _defaultDataRepositoryMock.Object, _loggerMock.LoggerFactory); }
public void ACustomEventNullValueCallThrowsNullReferenceException() { // ARRANGE var hcMock = HassClientMock.DefaultMock; var daemonHost = new NetDaemonHost(hcMock.Object, new Mock <IDataRepository>().Object); var cancelSource = hcMock.GetSourceWithTimeout(); Assert.Throws <NullReferenceException>(() => daemonHost .Event("CUSTOM_EVENT") .Call(null).Execute()); }
/// <inheritdoc/> public Task GenerateEntitiesAsync(NetDaemonHost daemonHost, string sourceFolder) { if (daemonHost == null) { throw new ArgumentNullException(nameof(daemonHost)); } if (sourceFolder == null) { throw new ArgumentNullException(nameof(sourceFolder)); } return(GenerateEntitiesAsyncInternal(daemonHost, sourceFolder)); }
private async Task WaitForDaemonToConnect(NetDaemonHost daemonHost, CancellationToken stoppingToken) { var nrOfTimesCheckForConnectedState = 0; while (!daemonHost.Connected && !stoppingToken.IsCancellationRequested) { await Task.Delay(1000, stoppingToken).ConfigureAwait(false); if (nrOfTimesCheckForConnectedState++ > 5) { break; } } }
private async Task GenerateEntitiesAsyncInternal(NetDaemonHost daemonHost, string sourceFolder) { var services = await daemonHost.GetAllServices().ConfigureAwait(false); var entityIds = daemonHost.State.Distinct().ToList(); var sourceRx = _codeGenerator.GenerateCodeRx( "NetDaemon.Generated.Reactive.Services", entityIds, services.ToList() ); await File.WriteAllTextAsync(Path.Combine(sourceFolder, "_EntityExtensionsRx.cs.gen"), sourceRx).ConfigureAwait(false); }
/// <summary> /// Default contructor /// </summary> public DaemonHostTestBase() { _loggerMock = new LoggerMock(); _defaultHassClientMock = HassClientMock.DefaultMock; _defaultDataRepositoryMock = new Mock <IDataRepository>(); _defaultHttpHandlerMock = new HttpHandlerMock(); _defaultDaemonHost = new NetDaemonHost( _defaultHassClientMock.Object, _defaultDataRepositoryMock.Object, _loggerMock.LoggerFactory, _defaultHttpHandlerMock.Object); _defaultDaemonHost.InternalDelayTimeForTts = 0; // Allow no extra waittime }
public ApiFakeStartup(IConfiguration configuration) { Configuration = configuration; _loggerMock = new LoggerMock(); _defaultHassClientMock = HassClientMock.DefaultMock; _defaultDataRepositoryMock = new Mock <IDataRepository>(); _defaultHttpHandlerMock = new HttpHandlerMock(); var hassClientFactoryMock = new HassClientFactoryMock(_defaultHassClientMock); _defaultDaemonHost = new NetDaemonHost( hassClientFactoryMock.Object, _defaultDataRepositoryMock.Object, _loggerMock.LoggerFactory, _defaultHttpHandlerMock.Object); _defaultDaemonApp = new BaseTestApp { Id = "app_id", IsEnabled = true }; _defaultDaemonHost.AddRunningApp(_defaultDaemonApp); _defaultDaemonApp2 = new BaseTestApp { Id = "app_id2" }; _defaultDaemonApp2.RuntimeInfo.NextScheduledEvent = DateTime.Now; _defaultDaemonApp2.IsEnabled = false; _defaultDaemonHost.AddRunningApp(_defaultDaemonApp2); _defaultDaemonRxApp = new BaseTestRxApp { Id = "app_rx_id", IsEnabled = true }; _defaultDaemonRxApp.RuntimeInfo.NextScheduledEvent = DateTime.Now; _defaultDaemonHost.AddRunningApp(_defaultDaemonRxApp); _defaultMockedRxApp = new Mock <NetDaemonRxApp>() { CallBase = true }; _defaultMockedRxApp.Object.Id = "app_rx_mock_id"; _defaultMockedRxApp.Object.IsEnabled = true; _defaultMockedRxApp.Setup(n => n.CreateObservableIntervall(It.IsAny <TimeSpan>(), It.IsAny <Action>())).Returns(new Mock <IDisposable>().Object); _defaultDaemonHost.AddRunningApp(_defaultMockedRxApp.Object); }
public ApiFakeStartup(IConfiguration configuration) { Configuration = configuration; _loggerMock = new LoggerMock(); _defaultHassClientMock = HassClientMock.DefaultMock; _defaultDataRepositoryMock = new Mock <IDataRepository>(); _defaultHttpHandlerMock = new HttpHandlerMock(); _defaultDaemonHost = new NetDaemonHost( _defaultHassClientMock.Object, _defaultDataRepositoryMock.Object, _loggerMock.LoggerFactory, _defaultHttpHandlerMock.Object); _defaultDaemonApp = new BaseTestApp(); _defaultDaemonApp.Id = "app_id"; _defaultDaemonApp.IsEnabled = true; _defaultDaemonHost.InternalRunningAppInstances[_defaultDaemonApp.Id !] = _defaultDaemonApp;
public async Task ACustomEventShouldDoCorrectCall() { // ARRANGE var hcMock = HassClientMock.DefaultMock; await using var daemonHost = new NetDaemonHost(hcMock.Object, new Mock <IDataRepository>().Object); var app = new FluentTestApp(); app.Id = "id"; daemonHost.InternalRunningAppInstances[app.Id] = app; await app.StartUpAsync(daemonHost); dynamic dynObject = new ExpandoObject(); dynObject.Test = "Hello World!"; hcMock.AddCustomEvent("CUSTOM_EVENT", dynObject); var cancelSource = hcMock.GetSourceWithTimeout(); var isCalled = false; string?message = ""; app .Event("CUSTOM_EVENT") .Call((ev, data) => { isCalled = true; message = data?.Test; return(Task.CompletedTask); }).Execute(); try { await daemonHost.Run("host", 8123, false, "token", cancelSource.Token).ConfigureAwait(false); } catch (TaskCanceledException) { // Expected behaviour } Assert.True(isCalled); Assert.Equal("Hello World!", message); }
public async Task GenerateEntitiesAsync(NetDaemonHost daemonHost, string sourceFolder) { if (!_netDaemonSettings.GenerateEntities.GetValueOrDefault()) { return; } if (_entitiesGenerated) { return; } _logger.LogTrace("Generating entities from Home Assistant instance .."); _entitiesGenerated = true; await _codeGenerationHandler.GenerateEntitiesAsync(daemonHost, sourceFolder).ConfigureAwait(false); }
public void FixStateTypesShouldReturnCorrectValues( bool result, object?newState, object?oldState, object?expectedNewState, object?expectedOldState) { var newEntityState = new EntityState { State = newState }; var oldEntityState = new EntityState { State = oldState }; bool res = NetDaemonHost.FixStateTypes(ref oldEntityState, ref newEntityState); Assert.Equal(result, res); Assert.Equal(expectedNewState, newEntityState.State); Assert.Equal(expectedOldState, oldEntityState.State); }
/// <summary> /// Default contructor /// </summary> public DaemonHostTestBase() { LoggerMock = new LoggerMock(); DefaultHassClientMock = HassClientMock.DefaultMock; DefaultDataRepositoryMock = new Mock <IDataRepository>(); DefaultHttpHandlerMock = new HttpHandlerMock(); var hassClientFactoryMock = new HassClientFactoryMock(DefaultHassClientMock); DefaultDaemonHost = new NetDaemonHost( hassClientFactoryMock.Object, DefaultDataRepositoryMock.Object, LoggerMock.LoggerFactory, DefaultHttpHandlerMock.Object, DefaultServiceProviderMock.Object ) { InternalDelayTimeForTts = 0 // Allow no extra waittime }; }
public async Task ACustomEventNullValueCallThrowsNullReferenceException() { // ARRANGE var hcMock = HassClientMock.DefaultMock; await using var daemonHost = new NetDaemonHost(hcMock.Object, new Mock <IDataRepository>().Object); var app = new FluentTestApp(); app.Id = "id"; daemonHost.InternalRunningAppInstances[app.Id] = app; await app.StartUpAsync(daemonHost); var cancelSource = hcMock.GetSourceWithTimeout(); Assert.Throws <NullReferenceException>(() => app .Event("CUSTOM_EVENT") .Call(null).Execute()); }
public TestCases(NetDaemonHost daemonHost, CancellationToken stoppingToken) { _daemonHost = daemonHost; _stoppingToken = stoppingToken; }
private async Task Run(NetDaemonHost daemonHost, CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { try { if (_hasConnectedBefore) { // This is due to re-connect, it must be a re-connect // so delay before retry connect again await Task.Delay(ReconnectInterval, stoppingToken).ConfigureAwait(false); // Wait x seconds _logger.LogInformation($"Restarting NeDaemon service (version {Version})..."); } var daemonHostTask = daemonHost.Run( _homeAssistantSettings.Host, _homeAssistantSettings.Port, _homeAssistantSettings.Ssl, _homeAssistantSettings.Token, stoppingToken ); if (!await WaitForDaemonToConnect(daemonHost, stoppingToken).ConfigureAwait(false)) { continue; } if (!stoppingToken.IsCancellationRequested) { if (daemonHost.IsConnected) { try { // Generate code if requested if (_sourcePath is string) { await GenerateEntities(daemonHost, _sourcePath).ConfigureAwait(false); } if (_loadedDaemonApps is null) { _loadedDaemonApps = _daemonAppCompiler.GetApps(); } if (_loadedDaemonApps?.Any() != true) { _logger.LogError("No NetDaemon apps could be found, exiting..."); return; } IInstanceDaemonApp?codeManager = new CodeManager(_loadedDaemonApps, _logger, _yamlConfig); await daemonHost.Initialize(codeManager).ConfigureAwait(false); // Wait until daemon stops await daemonHostTask.ConfigureAwait(false); } catch (TaskCanceledException) { _logger.LogTrace("Canceling NetDaemon service..."); } catch (Exception e) { _logger.LogError(e, "Failed to load applications"); } } else { _logger.LogWarning($"Home Assistant Core still unavailable, retrying in {ReconnectInterval / 1000} seconds..."); } } } catch (OperationCanceledException) { if (!stoppingToken.IsCancellationRequested) { _logger.LogWarning($"Home assistant is disconnected, retrying in {ReconnectInterval / 1000} seconds..."); } } catch (Exception e) { _logger.LogError("Error in NetDaemon service!, set trace log level to see details."); _logger.LogTrace(e, "Error in NetDaemon service!"); } finally { try { await daemonHost.Stop().ConfigureAwait(false); } catch (Exception e) { _logger.LogError("Error stopping NetDaemonInstance, enable trace level logging for details"); _logger.LogTrace(e, "Error stopping NetDaemonInstance"); } } // If we reached here it could be a re-connect _hasConnectedBefore = true; } }
protected override async Task ExecuteAsync(CancellationToken stoppingToken) { try { _logger.LogInformation($"Starting NeDaemon (version {_version})..."); var config = await ReadConfigAsync().ConfigureAwait(false); if (config == null) { _logger.LogError("No config specified, file or environment variables! Exiting..."); return; } EnsureApplicationDirectoryExists(config); var sourceFolder = config.SourceFolder; var storageFolder = Path.Combine(config.SourceFolder !, ".storage"); sourceFolder = Path.Combine(config.SourceFolder !, "apps"); // Automatically create source directories if (!System.IO.Directory.Exists(sourceFolder)) { System.IO.Directory.CreateDirectory(sourceFolder); } bool hasConnectedBefore = false; bool generatedEntities = false; while (!stoppingToken.IsCancellationRequested) { try { if (hasConnectedBefore) { // This is due to re-connect, it must be a re-connect // so delay before retry connect again await Task.Delay(_reconnectIntervall, stoppingToken).ConfigureAwait(false); // Wait x seconds } await using var _daemonHost = new NetDaemonHost(new HassClient(_loggerFactory), new DataRepository(storageFolder), _loggerFactory); var daemonHostTask = _daemonHost.Run(config.Host, config.Port, config.Ssl, config.Token, stoppingToken); await WaitForDaemonToConnect(_daemonHost, stoppingToken).ConfigureAwait(false); if (!stoppingToken.IsCancellationRequested) { if (_daemonHost.Connected) { try { // Generate code if requested var envGenEntities = Environment.GetEnvironmentVariable("HASS_GEN_ENTITIES") ?? config.GenerateEntitiesOnStartup?.ToString(); if (envGenEntities is object) { if (envGenEntities == "True" && !generatedEntities) { generatedEntities = true; var codeGen = new CodeGenerator(); var source = codeGen.GenerateCode("Netdaemon.Generated.Extensions", _daemonHost.State.Select(n => n.EntityId).Distinct()); System.IO.File.WriteAllText(System.IO.Path.Combine(sourceFolder !, "_EntityExtensions.cs"), source); } } using (var codeManager = new CodeManager(sourceFolder !, _daemonHost.Logger)) { await codeManager.EnableApplicationDiscoveryServiceAsync(_daemonHost, discoverServicesOnStartup : true).ConfigureAwait(false); // Wait until daemon stops await daemonHostTask.ConfigureAwait(false); if (!stoppingToken.IsCancellationRequested) { // It is disconnet, wait _logger.LogWarning($"Home assistant is unavailable, retrying in {_reconnectIntervall / 1000} seconds..."); } } } catch (TaskCanceledException) { _logger.LogInformation("Canceling NetDaemon service..."); } catch (Exception e) { _logger.LogError(e, "Failed to load applications"); } } else { _logger.LogWarning($"Home Assistant Core still unavailable, retrying in {_reconnectIntervall / 1000} seconds..."); } } } catch (OperationCanceledException) { if (!stoppingToken.IsCancellationRequested) { _logger.LogWarning($"Home assistant is disconnected, retrying in {_reconnectIntervall / 1000} seconds..."); } } // If we reached here it could be a re-connect hasConnectedBefore = true; } } catch (OperationCanceledException) { } // Normal exit catch (Exception e) { _logger.LogError(e, "NetDaemon had unhandled exception, closing..."); } _logger.LogInformation("Netdaemon exited!"); }