Skip to content

Commit

Permalink
Tests of Rx
Browse files Browse the repository at this point in the history
  • Loading branch information
helto4real committed May 17, 2020
1 parent b7bf500 commit 57ddd5e
Show file tree
Hide file tree
Showing 8 changed files with 463 additions and 177 deletions.
81 changes: 50 additions & 31 deletions src/App/NetDaemon.App/Common/Reactive/AppDaemonRxApp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@
using System.Linq;
using System.Reactive.Concurrency;
using System.Reactive.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;

// For mocking
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

namespace JoySoftware.HomeAssistant.NetDaemon.Common.Reactive
{
/// <summary>
Expand Down Expand Up @@ -143,34 +147,7 @@ public IDisposable RunDaily(string time, Action action)
/// <inheritdoc/>
public IDisposable RunEvery(TimeSpan timespan, Action action)
{
var result = new DisposableTimerResult(_cancelTimers.Token);

Observable.Interval(timespan, TaskPoolScheduler.Default)
.Subscribe(
s =>
{
try
{
if (this.IsEnabled)
action();
}
catch (OperationCanceledException)
{
// Do nothing
}
catch (Exception e)
{
LogError(e, "Error, RunEvery APP: {app}", Id ?? "unknown");
}
},
ex =>
{
LogError(ex, "Error, RunEvery_ex APP: {app}", Id ?? "unknown");
},
() => Log("Exiting RunEvery for app {app}, {trigger}:{span}", Id!, timespan)
, result.Token);

return result;
return CreateObservableIntervall(timespan, action);
}

/// <inheritdoc/>
Expand Down Expand Up @@ -279,7 +256,51 @@ public async override Task StartUpAsync(INetDaemon daemon)
/// <inheritdoc/>
public EntityState? State(string entityId) => _daemon?.GetState(entityId);

private IDisposable CreateObservableTimer(DateTime timeOfDayToTrigger, TimeSpan interval, Action action)
/// <summary>
/// Creates an observable intervall
/// </summary>
/// <param name="timespan">Time span for intervall</param>
/// <param name="action">The action to call</param>
internal virtual IDisposable CreateObservableIntervall(TimeSpan timespan, Action action)
{
var result = new DisposableTimerResult(_cancelTimers.Token);

Observable.Interval(timespan, TaskPoolScheduler.Default)
.Subscribe(
s =>
{
try
{
if (this.IsEnabled)
action();
}
catch (OperationCanceledException)
{
// Do nothing
}
catch (Exception e)
{
LogError(e, "Error, RunEvery APP: {app}", Id ?? "unknown");
}
},
ex =>
{
LogError(ex, "Error, RunEvery_ex APP: {app}", Id ?? "unknown");
},
() => Log("Exiting RunEvery for app {app}, {trigger}:{span}", Id!, timespan)
, result.Token);

return result;
}

/// <summary>
/// Creates a observable timer that are tracked for errors
/// </summary>
/// <param name="timeOfDayToTrigger">When to start the timer</param>
/// <param name="interval">The intervall</param>
/// <param name="action">Action to call each intervall</param>
/// <returns></returns>
internal virtual IDisposable CreateObservableTimer(DateTime timeOfDayToTrigger, TimeSpan interval, Action action)
{
var result = new DisposableTimerResult(_cancelTimers.Token);

Expand Down Expand Up @@ -316,6 +337,4 @@ private IDisposable CreateObservableTimer(DateTime timeOfDayToTrigger, TimeSpan
return result;
}
}


}
5 changes: 4 additions & 1 deletion src/Daemon/NetDaemon.Daemon/Daemon/NetDaemonHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public class NetDaemonHost : INetDaemonHost, IAsyncDisposable
private readonly IHttpHandler? _httpHandler;

private readonly IDataRepository? _repository;

private readonly ConcurrentDictionary<string, INetDaemonAppBase> _runningAppInstances =
new ConcurrentDictionary<string, INetDaemonAppBase>();

Expand Down Expand Up @@ -286,6 +287,7 @@ public async Task Initialize()
await LoadAllApps().ConfigureAwait(false);
EnableApplicationDiscoveryServiceAsync();
}

/// <inheritdoc/>
public IFluentInputSelect InputSelect(INetDaemonApp app, params string[] inputSelectParams)
{
Expand Down Expand Up @@ -316,7 +318,7 @@ public void ListenCompanionServiceCall(string service, Func<dynamic?, Task> acti
}

public void ListenServiceCall(string domain, string service, Func<dynamic?, Task> action)
=> _daemonServiceCallFunctions.Add((domain.ToLowerInvariant(), service.ToLowerInvariant(), action));
=> _daemonServiceCallFunctions.Add((domain.ToLowerInvariant(), service.ToLowerInvariant(), action));

/// <inheritdoc/>
public IMediaPlayer MediaPlayer(INetDaemonApp app, params string[] entityIds)
Expand Down Expand Up @@ -1250,6 +1252,7 @@ async Task SetStateOnDaemonAppSwitch(string state, dynamic? data)
await SetStateAsync(entityId, state).ConfigureAwait(false);
}
}

private async Task<bool> RestoreAppState(INetDaemonAppBase appInstance)
{
try
Expand Down
29 changes: 24 additions & 5 deletions tests/NetDaemon.Daemon.Tests/DaemonHostTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using JoySoftware.HomeAssistant.NetDaemon.Daemon.Storage;
using Moq;
using NetDaemon.Daemon.Tests.Daemon;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Dynamic;
Expand All @@ -23,6 +24,7 @@ public partial class DaemonHostTestBase : IAsyncLifetime
private readonly Mock<IDataRepository> _defaultDataRepositoryMock;
private readonly HassClientMock _defaultHassClientMock;
private readonly HttpHandlerMock _defaultHttpHandlerMock;
private readonly Mock<JoySoftware.HomeAssistant.NetDaemon.Common.Reactive.NetDaemonRxApp> _defaultMockedRxApp;
private readonly LoggerMock _loggerMock;
private readonly NetDaemonHost _notConnectedDaemonHost;

Expand All @@ -42,28 +44,32 @@ internal DaemonHostTestBase()

_defaultDaemonApp = new BaseTestApp();
_defaultDaemonApp.Id = "app_id";
_defaultDaemonApp.IsEnabled = true;

_defaultDaemonHost.InternalRunningAppInstances[_defaultDaemonApp.Id!] = _defaultDaemonApp;

_defaultDaemonRxApp = new BaseTestRxApp();
_defaultDaemonRxApp.Id = "app_rx_id";
_defaultDaemonRxApp.IsEnabled = true;
_defaultDaemonHost.InternalRunningAppInstances[_defaultDaemonRxApp.Id!] = _defaultDaemonRxApp;

_defaultMockedRxApp = new Mock<JoySoftware.HomeAssistant.NetDaemon.Common.Reactive.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.InternalRunningAppInstances[_defaultMockedRxApp.Object.Id!] = _defaultMockedRxApp.Object;

_notConnectedDaemonHost = new NetDaemonHost(new Mock<IInstanceDaemonApp>().Object, HassClientMock.MockConnectFalse.Object, _defaultDataRepositoryMock.Object, _loggerMock.LoggerFactory);
}

public JoySoftware.HomeAssistant.NetDaemon.Common.NetDaemonApp DefaultDaemonApp => _defaultDaemonApp;

public NetDaemonHost DefaultDaemonHost => _defaultDaemonHost;

public BaseTestRxApp DefaultDaemonRxApp => _defaultDaemonRxApp;

public Mock<IDataRepository> DefaultDataRepositoryMock => _defaultDataRepositoryMock;

public HassClientMock DefaultHassClientMock => _defaultHassClientMock;

public HttpHandlerMock DefaultHttpHandlerMock => _defaultHttpHandlerMock;

public Mock<JoySoftware.HomeAssistant.NetDaemon.Common.Reactive.NetDaemonRxApp> DefaultMockedRxApp => _defaultMockedRxApp;
public string HelloWorldData => "Hello world!";

public LoggerMock LoggerMock => _loggerMock;
Expand All @@ -75,6 +81,7 @@ async Task IAsyncLifetime.DisposeAsync()
await _defaultDaemonApp.DisposeAsync().ConfigureAwait(false);
await _defaultDaemonRxApp.DisposeAsync().ConfigureAwait(false);
await _defaultDaemonHost.DisposeAsync().ConfigureAwait(false);
await _defaultMockedRxApp.Object.DisposeAsync().ConfigureAwait(false);
}

public dynamic GetDynamicDataObject(string testData = "testdata")
Expand All @@ -101,6 +108,7 @@ public async Task InitializeAsync()
{
await _defaultDaemonApp.StartUpAsync(_defaultDaemonHost).ConfigureAwait(false);
await _defaultDaemonRxApp.StartUpAsync(_defaultDaemonHost).ConfigureAwait(false);
await _defaultMockedRxApp.Object.StartUpAsync(_defaultDaemonHost).ConfigureAwait(false);
}

public (Task, CancellationTokenSource) ReturnRunningDefauldDaemonHostTask(short milliSeconds = 100, bool overrideDebugNotCancel = false)
Expand Down Expand Up @@ -146,6 +154,17 @@ public async Task WaitUntilCanceled(Task task)
}
}

protected async Task<Task> GetConnectedNetDaemonTask(short milliSeconds = 100, bool overrideDebugNotCancel = false)
{
var cancelSource = Debugger.IsAttached && !overrideDebugNotCancel
? new CancellationTokenSource()
: new CancellationTokenSource(milliSeconds);

var daemonTask = _defaultDaemonHost.Run("host", 8123, false, "token", cancelSource.Token);
await WaitForDefaultDaemonToConnect(DefaultDaemonHost, cancelSource.Token);
return daemonTask;
}

protected async Task WaitForDefaultDaemonToConnect(NetDaemonHost daemonHost, CancellationToken stoppingToken)
{
var nrOfTimesCheckForConnectedState = 0;
Expand Down
6 changes: 4 additions & 2 deletions tests/NetDaemon.Daemon.Tests/Demon/NetDaemonHostTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -363,8 +363,8 @@ public async Task CallServiceEventShouldCallCorrectFunction()
{
// ARRANGE
var dynObject = GetDynamicDataObject(HelloWorldData);
var daemonTask = await GetConnectedNetDaemonTask();

DefaultHassClientMock.AddCallServiceEvent("custom_domain", "any_service", dynObject);

var isCalled = false;
string? message = "";
Expand All @@ -377,7 +377,9 @@ public async Task CallServiceEventShouldCallCorrectFunction()
return Task.CompletedTask;
});

await RunDefauldDaemonUntilCanceled();
DefaultHassClientMock.AddCallServiceEvent("custom_domain", "any_service", dynObject);

await daemonTask;

// ASSERT
Assert.True(isCalled);
Expand Down

0 comments on commit 57ddd5e

Please sign in to comment.