Skip to content

Commit

Permalink
Big refactor of tests
Browse files Browse the repository at this point in the history
  • Loading branch information
helto4real committed Dec 13, 2020
1 parent d9d7a6e commit bb1568c
Show file tree
Hide file tree
Showing 24 changed files with 1,289 additions and 1,017 deletions.
212 changes: 163 additions & 49 deletions src/Fakes/NetDaemon.Fakes/DaemonHostTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using JoySoftware.HomeAssistant.Client;
using Moq;
using NetDaemon.Common;
using NetDaemon.Common.Fluent;
using NetDaemon.Common.Reactive;
using NetDaemon.Daemon.Storage;
using Xunit;
Expand All @@ -24,6 +25,7 @@ public partial class DaemonHostTestBase : IAsyncLifetime
private readonly HassClientMock _defaultHassClientMock;
private readonly HttpHandlerMock _defaultHttpHandlerMock;
private readonly LoggerMock _loggerMock;
private Task? _fakeConnectedDaemon;

/// <summary>
/// Default contructor
Expand All @@ -41,6 +43,7 @@ public DaemonHostTestBase()
_loggerMock.LoggerFactory,
_defaultHttpHandlerMock.Object);

_defaultDaemonHost.InternalDelayTimeForTts = 0; // Allow no extra waittime
}

/// <summary>
Expand All @@ -64,7 +67,10 @@ public DaemonHostTestBase()
/// </summary>
public LoggerMock LoggerMock => _loggerMock;

Task IAsyncLifetime.DisposeAsync()
/// <summary>
/// Cleans up test
/// </summary>
public Task DisposeAsync()
{
return Task.CompletedTask;
}
Expand All @@ -84,9 +90,9 @@ public dynamic GetDynamicDataObject(string testData = "testdata")
/// <summary>
/// Converts parameters to dynamics
/// </summary>
public (dynamic, ExpandoObject) GetDynamicObject(params (string, object)[] dynamicParameters)
public (dynamic, FluentExpandoObject) GetDynamicObject(params (string, object)[] dynamicParameters)
{
var expandoObject = new ExpandoObject();
var expandoObject = new FluentExpandoObject();
var dict = expandoObject as IDictionary<string, object>;

foreach (var (name, value) in dynamicParameters)
Expand All @@ -104,16 +110,44 @@ public virtual Task InitializeAsync()
return Task.CompletedTask;
}

/// <summary>
/// Sets fake current state of entity, adds it if entity not exists
/// </summary>
/// <param name="state">The state to sett</param>
public void SetEntityState(HassState state)
{
DefaultHassClientMock.FakeStates[state.EntityId] = state;
}

/// <summary>
/// Sets fake current state of entity, adds it if entity not exists
/// </summary>
/// <param name="entityId">Unique id of entity</param>
/// <param name="state">State to set</param>
/// <param name="area">Area of entity</param>
public void SetEntityState(string entityId, dynamic? state = null, string? area = null)
{
var entity = new EntityState
{
EntityId = entityId,
Area = area,
State = state
};

DefaultDaemonHost.InternalState[entityId] = entity;
}

/// <summary>
/// Adds an new instance of app
/// </summary>
/// <param name="app">The instance of the app to add</param>
public void AddAppInstance(INetDaemonAppBase app)
public async Task AddAppInstance(INetDaemonAppBase app)
{
if (string.IsNullOrEmpty(app.Id))
throw new ArgumentException("Application needs an unique id, please provide it!");
app.Id = Guid.NewGuid().ToString();
DefaultDaemonHost.InternalAllAppInstances[app.Id] = app;
DefaultDaemonHost.InternalRunningAppInstances[app.Id] = app;
await app.StartUpAsync(DefaultDaemonHost);
}

/// <summary>
Expand All @@ -136,6 +170,19 @@ public void AddChangedEvent(HassEvent hassEvent)
DefaultHassClientMock.FakeEvents.Enqueue(hassEvent);
}

/// <summary>
/// Adds an simple state change event to NetDaemon to trigger apps
/// </summary>
/// <param name="entityId">Unique id of the entity</param>
/// <param name="fromState">From state</param>
/// <param name="toState">To state</param>
/// <param name="lastUpdated">Last updated time</param>
/// <param name="lastChanged">Last changed time</param>
public void AddChangedEvent(string entityId, object fromState, object toState, DateTime lastUpdated, DateTime lastChanged)
{
DefaultHassClientMock.AddChangedEvent(entityId, fromState, toState, lastUpdated, lastChanged);
}

/// <summary>
/// Add a fake event
/// </summary>
Expand All @@ -156,76 +203,105 @@ public void AddCustomEvent(string eventType, dynamic? data)
/// <param name="domain">Domain of event</param>
/// <param name="service">Service to call</param>
/// <param name="data">Custom data</param>
public void AddCallServiceEvent(string domain, string service, dynamic data)
public void AddCallServiceEvent(string domain, string service, dynamic? data = null)
{
DefaultHassClientMock.AddCallServiceEvent(domain, service, data);
}

/// <summary>
/// Verifies that a custom event are sent
/// </summary>
/// <param name="ev">Name of event</param>
public void VerifyEventSent(string ev)
{
DefaultHassClientMock.Verify(n => n.SendEvent(ev, It.IsAny<object>()));
}

/// <summary>
/// Verifies that a custom event are sent
/// </summary>
/// <param name="ev">Name of event</param>
/// <param name="eventData">Data sent by event</param>
public void VerifyEventSent(string ev, object? eventData)
{
DefaultHassClientMock.Verify(n => n.SendEvent(ev, eventData));
}

/// <summary>
/// Verify that a service has been called
/// </summary>
/// <param name="domain">Domain of service</param>
/// <param name="service">The service name</param>
/// <param name="attributesTuples">Attributes</param>
public void VerifyCallService(string domain, string service,
public void VerifyCallServiceTuple(string domain, string service,
params (string attribute, object value)[] attributesTuples)
{
DefaultHassClientMock.VerifyCallService(domain, service, attributesTuples);
DefaultHassClientMock.VerifyCallServiceTuple(domain, service, attributesTuples);
}

/// <summary>
/// Verify that a service been called specific number of times
/// Verifies that call_service is called
/// </summary>
/// <param name="service">Service name</param>
/// <param name="times">Times called</param>
public void VerifyCallServiceTimes(string service, Times times)
/// <param name="domain">Service domain</param>
/// <param name="service">Service to verify</param>
/// <param name="data">Data sent by service</param>
/// <param name="waitForResponse">If service was waiting for response</param>
/// <param name="times">Number of times called</param>
public void VerifyCallService(string domain, string service, object? data = null, bool waitForResponse = false, Moq.Times? times = null)
{
DefaultHassClientMock.VerifyCallServiceTimes(service, times);
DefaultHassClientMock.VerifyCallService(domain, service, data, waitForResponse, times);
}

/// <summary>
/// Returns default DaemonHost
/// Verifies that call_service is called
/// </summary>
/// <param name="milliSeconds">Timeout in ms</param>
/// <param name="overrideDebugNotCancel">True if use timeout while debug test</param>
public async Task<(Task, CancellationTokenSource)> ReturnRunningDefauldDaemonHostTask(short milliSeconds = 100, bool overrideDebugNotCancel = false)
/// <param name="domain">Service domain</param>
/// <param name="service">Service to verify</param>
/// <param name="entityId">EntityId to verify</param>
/// <param name="data">Data sent by service</param>
/// <param name="waitForResponse">If service was waiting for response</param>
/// <param name="times">Number of times called</param>
/// <param name="attributesTuples">Attributes to verify</param>
public void VerifyCallService(string domain, string service, string entityId, object? data = null, bool waitForResponse = false, Moq.Times? times = null,
params (string attribute, object value)[] attributesTuples)
{
await InitApps();
var cancelSource = Debugger.IsAttached && !overrideDebugNotCancel
? new CancellationTokenSource()
: new CancellationTokenSource(milliSeconds);
return (_defaultDaemonHost.Run("host", 8123, false, "token", cancelSource.Token), cancelSource);
var serviceObject = new FluentExpandoObject();
serviceObject["entity_id"] = entityId;
foreach (var (attr, val) in attributesTuples)
{
serviceObject[attr] = val;
}

DefaultHassClientMock.VerifyCallService(domain, service, serviceObject, waitForResponse, times);
}

/// <summary>
/// Verifies that call_service is called
/// </summary>
/// <param name="domain">Service domain</param>
/// <param name="service">Service to verify</param>
/// <param name="waitForResponse">If service was waiting for response</param>
public void VerifyCallService(string domain, string service, bool waitForResponse = false)
{
DefaultHassClientMock.VerifyCallService(domain, service, waitForResponse);
}

/// <summary>
/// Runs the default daemon to process messages until canceled
/// Verify that a service been called specific number of times
/// </summary>
/// <param name="milliSeconds">Timeout time</param>
/// <param name="overrideDebugNotCancel">True if debugging should cancel</param>
/// <returns></returns>
public async Task RunDefaultDaemonUntilCanceled(short milliSeconds = 100, bool overrideDebugNotCancel = false)
/// <param name="service">Service name</param>
/// <param name="times">Times called</param>
public void VerifyCallServiceTimes(string service, Times times)
{
var cancelSource = Debugger.IsAttached && !overrideDebugNotCancel
? new CancellationTokenSource()
: new CancellationTokenSource(milliSeconds);
try
{
await InitApps();
await _defaultDaemonHost.Run("host", 8123, false, "token", cancelSource.Token).ConfigureAwait(false);
}
catch (TaskCanceledException)
{
// Expected behaviour
}
DefaultHassClientMock.VerifyCallServiceTimes(service, times);
}

/// <summary>
/// Wait for task until canceled
/// </summary>
/// <param name="task">Task to wait for</param>
/// <returns></returns>
public async Task WaitUntilCanceled(Task task)
private async Task WaitUntilCanceled(Task task)
{
try
{
Expand All @@ -240,7 +316,7 @@ public async Task WaitUntilCanceled(Task task)
/// <summary>
/// Initialize applications
/// </summary>
public async Task InitApps()
private async Task InitApps()
{
foreach (var inst in DefaultDaemonHost.InternalAllAppInstances)
{
Expand All @@ -254,13 +330,57 @@ public async Task InitApps()
}
}

/// <summary>
/// Verifies that a state is set
/// </summary>
/// <param name="entityId">Unique identifier of the entity</param>
/// <param name="state">State being set</param>
/// <param name="attributesTuples">Attributes being set</param>
public void VerifySetState(string entityId, string state,
params (string attribute, object value)[] attributesTuples)
{
DefaultHassClientMock.VerifySetState(entityId, state, attributesTuples);
}

/// <summary>
/// Verifies that state being set
/// </summary>
/// <param name="entityId">Unique identifier of the entity</param>
/// <param name="times">How many times it being set</param>
public void VerifySetStateTimes(string entityId, Times times)
{
DefaultHassClientMock.VerifySetStateTimes(entityId, times);
}

/// <summary>
/// Initialize the fake netdaemon core, must be run in most cases starting a test
/// </summary>
/// <param name="timeout">Timeout (ms) of how long fake daemon will stay connected and process events</param>
/// <param name="overrideDebugNotCancel">True if running debug mode should not cancel on timeout</param>
protected async Task FakeDaemonInit(short timeout = 200, bool overrideDebugNotCancel = false)
{
_fakeConnectedDaemon = await GetConnectedNetDaemonTask(timeout, overrideDebugNotCancel);
}

/// <summary>
///
/// </summary>
/// <returns></returns>
protected async Task FakeRunDaemonCoreUntilTimeout()
{
_ = _fakeConnectedDaemon ??
throw new NullReferenceException("No task to process, did you forget to run InitFakeDaemon at the beginning of the test?");

await WaitUntilCanceled(_fakeConnectedDaemon).ConfigureAwait(false);
}

/// <summary>
/// Get already pre-connected mock NetDaemon object
/// </summary>
/// <param name="milliSeconds">Timeout in milliseconds</param>
/// <param name="overrideDebugNotCancel">True to use timeout while debugging</param>
/// <returns></returns>
protected async Task<Task> GetConnectedNetDaemonTask(short milliSeconds = 100, bool overrideDebugNotCancel = false)
private async Task<Task> GetConnectedNetDaemonTask(short milliSeconds = 100, bool overrideDebugNotCancel = false)
{
var cancelSource = Debugger.IsAttached && !overrideDebugNotCancel
? new CancellationTokenSource()
Expand All @@ -273,13 +393,7 @@ protected async Task<Task> GetConnectedNetDaemonTask(short milliSeconds = 100, b
return daemonTask;
}

/// <summary>
/// Wait until default NetDaemon has connected
/// </summary>
/// <param name="daemonHost">Daemon object</param>
/// <param name="cancellationToken">Cancellation token</param>
/// <returns></returns>
protected async Task WaitForDefaultDaemonToConnect(NetDaemonHost daemonHost, CancellationToken cancellationToken)
private async Task WaitForDefaultDaemonToConnect(NetDaemonHost daemonHost, CancellationToken cancellationToken)
{
var nrOfTimesCheckForConnectedState = 0;

Expand Down
Loading

0 comments on commit bb1568c

Please sign in to comment.