Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
201 changes: 121 additions & 80 deletions src/Runtime/NetDaemon.Runtime.Tests/Internal/AppStateManagerTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Net;
using System.Reactive.Subjects;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using NetDaemon.AppModel;
using NetDaemon.Client.Internal.Exceptions;
using NetDaemon.HassModel;
Expand All @@ -21,6 +22,7 @@ public async Task TestGetStateAsyncReturnsCorrectStateEnabled()

var provider = new ServiceCollection()
.AddSingleton(haRunnerMock.Object)
.AddSingleton(new Mock<IHostEnvironment>().Object)
.AddNetDaemonStateManager()
.BuildServiceProvider();
using var scopedProvider = provider.CreateScope();
Expand All @@ -44,17 +46,9 @@ public async Task TestGetStateAsyncReturnsCorrectStateEnabled()
public async Task TestGetStateAsyncReturnsCorrectStateDisabled()
{
// ARRANGE
var haConnectionMock = new Mock<IHomeAssistantConnection>();
var haRunnerMock = new Mock<IHomeAssistantRunner>();
haRunnerMock.SetupGet(n => n.CurrentConnection).Returns(haConnectionMock.Object);

var provider = new ServiceCollection()
.AddSingleton(haRunnerMock.Object)
.AddNetDaemonStateManager()
.BuildServiceProvider();
using var scopedProvider = provider.CreateScope();
var (haConnectionMock, provider) = SetupProviderAndMocks();

var appStateManager = scopedProvider.ServiceProvider.GetRequiredService<IAppStateManager>();
var appStateManager = provider.GetRequiredService<IAppStateManager>();

// ACT
// ASSERT
Expand All @@ -73,16 +67,9 @@ public async Task TestGetStateAsyncReturnsCorrectStateDisabled()
public async Task TestSaveStateAsyncReturnsCorrectStateDisabled()
{
// ARRANGE
var haConnectionMock = new Mock<IHomeAssistantConnection>();
var haRunnerMock = new Mock<IHomeAssistantRunner>();
haRunnerMock.SetupGet(n => n.CurrentConnection).Returns(haConnectionMock.Object);

var provider = new ServiceCollection()
.AddSingleton(haRunnerMock.Object)
.AddNetDaemonStateManager()
.BuildServiceProvider();
var (haConnectionMock, scopedProvider) = SetupProviderAndMocks();

var appStateManager = provider.GetRequiredService<IAppStateManager>();
var appStateManager = scopedProvider.GetRequiredService<IAppStateManager>();
haConnectionMock.Setup(n => n.GetApiCallAsync<HassState>(It.IsAny<string>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(
new HassState
Expand All @@ -106,14 +93,7 @@ public async Task TestSaveStateAsyncReturnsCorrectStateDisabled()
public async Task TestGetStateAsyncNotExistReturnsCorrectStateEnabled()
{
// ARRANGE
var haConnectionMock = new Mock<IHomeAssistantConnection>();
var haRunnerMock = new Mock<IHomeAssistantRunner>();
haRunnerMock.SetupGet(n => n.CurrentConnection).Returns(haConnectionMock.Object);

var provider = new ServiceCollection()
.AddSingleton(haRunnerMock.Object)
.AddNetDaemonStateManager()
.BuildServiceProvider();
var (haConnectionMock, provider) = SetupProviderAndMocks();

var appStateManager = provider.GetRequiredService<IAppStateManager>();
haConnectionMock.Setup(n => n.GetApiCallAsync<HassState>(It.IsAny<string>(), It.IsAny<CancellationToken>()))
Expand All @@ -134,17 +114,34 @@ public async Task TestGetStateAsyncNotExistReturnsCorrectStateEnabled()
}

[Fact]
public async Task TestSetStateAsyncEnabled()
public async Task TestGetStateAsyncNotExistReturnsCorrectStateEnabledInDevelopment()
{
// ARRANGE
var haConnectionMock = new Mock<IHomeAssistantConnection>();
var haRunnerMock = new Mock<IHomeAssistantRunner>();
haRunnerMock.SetupGet(n => n.CurrentConnection).Returns(haConnectionMock.Object);
var (haConnectionMock, provider) = SetupProviderAndMocksDevelopment();

var provider = new ServiceCollection()
.AddSingleton(haRunnerMock.Object)
.AddNetDaemonStateManager()
.BuildServiceProvider();
var appStateManager = provider.GetRequiredService<IAppStateManager>();
haConnectionMock.Setup(n => n.GetApiCallAsync<HassState>(It.IsAny<string>(), It.IsAny<CancellationToken>()))
.ThrowsAsync(
new HomeAssistantApiCallException("ohh no", HttpStatusCode.NotFound));
// ACT
_ = await appStateManager.GetStateAsync("helloapp");
// ASSERT
haConnectionMock.Verify(n =>
n.GetApiCallAsync<HassState>("states/input_boolean.dev_netdaemon_helloapp", It.IsAny<CancellationToken>()));
// It exists so it should turn it on
haConnectionMock.Verify(n =>
n.SendCommandAndReturnResponseAsync<CreateInputBooleanHelperCommand, InputBooleanHelper>(
It.IsAny<CreateInputBooleanHelperCommand>(), It.IsAny<CancellationToken>()));
haConnectionMock.Verify(n =>
n.SendCommandAndReturnResponseAsync<CallServiceCommand, object>(It.IsAny<CallServiceCommand>(),
It.IsAny<CancellationToken>()));
}

[Fact]
public async Task TestSetStateAsyncEnabled()
{
// ARRANGE
var (haConnectionMock, provider) = SetupProviderAndMocks();

var appStateManager = provider.GetRequiredService<IAppStateManager>();
haConnectionMock.Setup(n => n.GetApiCallAsync<HassState>(It.IsAny<string>(), It.IsAny<CancellationToken>()))
Expand All @@ -170,14 +167,7 @@ public async Task TestSetStateAsyncEnabled()
public async Task TestSetStateAsyncRunning()
{
// ARRANGE
var haConnectionMock = new Mock<IHomeAssistantConnection>();
var haRunnerMock = new Mock<IHomeAssistantRunner>();
haRunnerMock.SetupGet(n => n.CurrentConnection).Returns(haConnectionMock.Object);

var provider = new ServiceCollection()
.AddSingleton(haRunnerMock.Object)
.AddNetDaemonStateManager()
.BuildServiceProvider();
var (haConnectionMock, provider) = SetupProviderAndMocks();

var appStateManager = provider.GetRequiredService<IAppStateManager>();
haConnectionMock.Setup(n => n.GetApiCallAsync<HassState>(It.IsAny<string>(), It.IsAny<CancellationToken>()))
Expand All @@ -200,17 +190,9 @@ public async Task TestSetStateAsyncRunning()
public async Task TestSetStateAsyncError()
{
// ARRANGE
var haConnectionMock = new Mock<IHomeAssistantConnection>();
var haRunnerMock = new Mock<IHomeAssistantRunner>();
haRunnerMock.SetupGet(n => n.CurrentConnection).Returns(haConnectionMock.Object);
var (haConnectionMock, provider) = SetupProviderAndMocks();

var provider = new ServiceCollection()
.AddSingleton(haRunnerMock.Object)
.AddNetDaemonStateManager()
.BuildServiceProvider();
using var scopedProvider = provider.CreateScope();

var appStateManager = scopedProvider.ServiceProvider.GetRequiredService<IAppStateManager>();
var appStateManager = provider.GetRequiredService<IAppStateManager>();

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good to have these cleaned up 👍

haConnectionMock.Setup(n => n.GetApiCallAsync<HassState>(It.IsAny<string>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(
Expand All @@ -233,15 +215,22 @@ public async Task TestInitialize()
// ARRANGE
var haContextMock = new Mock<IHaContext>();
var appModelContextMock = new Mock<IAppModelContext>();
appModelContextMock.SetupGet(n => n.Applications).Returns(new List<IApplication>());
appModelContextMock.SetupGet(n => n.Applications)
.Returns(new List<IApplication>() {new Mock<IApplication>().Object});

var haConnectionMock = new Mock<IHomeAssistantConnection>();

var haRunnerMock = new Mock<IHomeAssistantRunner>();
haRunnerMock.SetupGet(n => n.CurrentConnection).Returns(haConnectionMock.Object);

var repositoryMock = new Mock<IAppStateRepository>();

var provider = new ServiceCollection()
.AddSingleton(haRunnerMock.Object)
.AddScoped(_ => haContextMock.Object)
.AddSingleton(new Mock<IHostEnvironment>().Object)
.AddNetDaemonStateManager()
.AddSingleton(repositoryMock.Object)
.BuildServiceProvider();
using var scopedProvider = provider.CreateScope();

Expand All @@ -255,29 +244,58 @@ await homeAssistantStateUpdater.InitializeAsync(haConnectionMock.Object, appMode
.ConfigureAwait(false);
// ASSERT
hassEvent.HasObservers.Should().BeTrue();
repositoryMock.Verify(n => n.RemoveNotUsedStatesAsync(It.IsAny<IReadOnlyCollection<string>>(), It.IsAny<CancellationToken>()), Times.Once);
}

[Fact]
public async Task TestAppDisabledShouldCallSetStateAsyncEnabled()
public async Task InitializeShouldNeverTryDeleteUnusedInputBooleanHelpersWhenInDevelopmentEnvironment()
{
// ARRANGE
var haContextMock = new Mock<IHaContext>();
var appModelContextMock = new Mock<IAppModelContext>();
appModelContextMock.SetupGet(n => n.Applications).Returns(new List<IApplication>());
var appMock = new Mock<IApplication>();
// Make sure we have at least one application for this scenario
appModelContextMock.SetupGet(n => n.Applications)
.Returns(new List<IApplication>(){new Mock<IApplication>().Object});
var haConnectionMock = new Mock<IHomeAssistantConnection>();
haConnectionMock.SetupGet(n => n.OnHomeAssistantEvent).Returns(new Subject<HassEvent>());
var haRunnerMock = new Mock<IHomeAssistantRunner>();
haRunnerMock.SetupGet(n => n.CurrentConnection).Returns(haConnectionMock.Object);

var environmentMock = new Mock<IHostEnvironment>();
environmentMock.Setup(n => n.EnvironmentName).Returns("Development");
var repositoryMock = new Mock<IAppStateRepository>();

var provider = new ServiceCollection()
.AddSingleton(haRunnerMock.Object)
.AddScoped(_ => haContextMock.Object)
.AddSingleton(environmentMock.Object)
.AddNetDaemonStateManager()
.AddSingleton(repositoryMock.Object)
.BuildServiceProvider();
using var scopedProvider = provider.CreateScope();

var homeAssistantStateUpdater =
scopedProvider.ServiceProvider.GetRequiredService<IHandleHomeAssistantAppStateUpdates>();

// ACT
await homeAssistantStateUpdater.InitializeAsync(haConnectionMock.Object, appModelContextMock.Object)
.ConfigureAwait(false);
// ASSERT
repositoryMock.Verify(n => n.RemoveNotUsedStatesAsync(It.IsAny<IReadOnlyCollection<string>>(), It.IsAny<CancellationToken>()), Times.Never);

}

[Fact]
public async Task TestAppDisabledShouldCallSetStateAsyncEnabled()
{
// ARRANGE
var (haConnectionMock, provider) = SetupProviderAndMocks();
var appModelContextMock = new Mock<IAppModelContext>();
appModelContextMock.SetupGet(n => n.Applications).Returns(new List<IApplication>());
var appMock = new Mock<IApplication>();

var homeAssistantStateUpdater =
provider.GetRequiredService<IHandleHomeAssistantAppStateUpdates>();
Subject<HassEvent> hassEvent = new();
haConnectionMock.SetupGet(n => n.OnHomeAssistantEvent).Returns(hassEvent);
appMock.SetupGet(n => n.Id).Returns("app");
Expand Down Expand Up @@ -317,24 +335,18 @@ await homeAssistantStateUpdater.InitializeAsync(haConnectionMock.Object, appMode
public async Task TestAppNoChangeShouldNotCallSetStateAsync()
{
// ARRANGE
var haContextMock = new Mock<IHaContext>();
var (haConnectionMock, provider) = SetupProviderAndMocks();

var homeAssistantStateUpdater =
provider.GetRequiredService<IHandleHomeAssistantAppStateUpdates>();

Subject<HassEvent> hassEvent = new();

var appModelContextMock = new Mock<IAppModelContext>();
appModelContextMock.SetupGet(n => n.Applications).Returns(new List<IApplication>());
var appMock = new Mock<IApplication>();
var haConnectionMock = new Mock<IHomeAssistantConnection>();
var haRunnerMock = new Mock<IHomeAssistantRunner>();
haRunnerMock.SetupGet(n => n.CurrentConnection).Returns(haConnectionMock.Object);

var provider = new ServiceCollection()
.AddSingleton(haRunnerMock.Object)
.AddScoped(_ => haContextMock.Object)
.AddNetDaemonStateManager()
.BuildServiceProvider();
using var scopedProvider = provider.CreateScope();
var appMock = new Mock<IApplication>();

var homeAssistantStateUpdater =
scopedProvider.ServiceProvider.GetRequiredService<IHandleHomeAssistantAppStateUpdates>();
Subject<HassEvent> hassEvent = new();
haConnectionMock.SetupGet(n => n.OnHomeAssistantEvent).Returns(hassEvent);
appMock.SetupGet(n => n.Id).Returns("app");
appModelContextMock.SetupGet(n => n.Applications).Returns(
Expand Down Expand Up @@ -374,23 +386,19 @@ await homeAssistantStateUpdater.InitializeAsync(haConnectionMock.Object, appMode
public async Task TestAppOneStateIsNullShouldNotCallSetStateAsync()
{
// ARRANGE
var haContextMock = new Mock<IHaContext>();
var (haConnectionMock, provider) = SetupProviderAndMocks();

var appModelContextMock = new Mock<IAppModelContext>();
appModelContextMock.SetupGet(n => n.Applications).Returns(new List<IApplication>());

var appMock = new Mock<IApplication>();
var haConnectionMock = new Mock<IHomeAssistantConnection>();

var haRunnerMock = new Mock<IHomeAssistantRunner>();
haRunnerMock.SetupGet(n => n.CurrentConnection).Returns(haConnectionMock.Object);

var provider = new ServiceCollection()
.AddSingleton(haRunnerMock.Object)
.AddScoped(_ => haContextMock.Object)
.AddNetDaemonStateManager()
.BuildServiceProvider();
using var scopedProvider = provider.CreateScope();

var homeAssistantStateUpdater =
scopedProvider.ServiceProvider.GetRequiredService<IHandleHomeAssistantAppStateUpdates>();
provider.GetRequiredService<IHandleHomeAssistantAppStateUpdates>();
Subject<HassEvent> hassEvent = new();
haConnectionMock.SetupGet(n => n.OnHomeAssistantEvent).Returns(hassEvent);
appMock.SetupGet(n => n.Id).Returns("app");
Expand Down Expand Up @@ -419,4 +427,37 @@ public async Task TestAppOneStateIsNullShouldNotCallSetStateAsync()
// ASSERT
appMock.Verify(n => n.SetStateAsync(ApplicationState.Disabled), Times.Never);
}

private (Mock<IHomeAssistantConnection> connection, IServiceProvider serviceProvider) SetupProviderAndMocks()
{
var haConnectionMock = new Mock<IHomeAssistantConnection>();
var haRunnerMock = new Mock<IHomeAssistantRunner>();
haRunnerMock.SetupGet(n => n.CurrentConnection).Returns(haConnectionMock.Object);

var provider = new ServiceCollection()
.AddSingleton(haRunnerMock.Object)
.AddSingleton(new Mock<IHostEnvironment>().Object)
.AddNetDaemonStateManager()
.BuildServiceProvider();
var scopedProvider = provider.CreateScope();

return (haConnectionMock, scopedProvider.ServiceProvider);
}

private (Mock<IHomeAssistantConnection> connection, IServiceProvider serviceProvider) SetupProviderAndMocksDevelopment()
{
var haConnectionMock = new Mock<IHomeAssistantConnection>();
var haRunnerMock = new Mock<IHomeAssistantRunner>();
haRunnerMock.SetupGet(n => n.CurrentConnection).Returns(haConnectionMock.Object);
var environmentMock = new Mock<IHostEnvironment>();
environmentMock.Setup(n => n.EnvironmentName).Returns("Development");
var provider = new ServiceCollection()
.AddSingleton(haRunnerMock.Object)
.AddSingleton(environmentMock.Object)
.AddNetDaemonStateManager()
.BuildServiceProvider();
var scopedProvider = provider.CreateScope();

return (haConnectionMock, scopedProvider.ServiceProvider);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Net;
using Microsoft.Extensions.Hosting;
using NetDaemon.Client.Internal.Exceptions;
using NetDaemon.Runtime.Internal;
using NetDaemon.Runtime.Internal.Model;
Expand All @@ -10,11 +11,13 @@ public class AppStateRepositoryTests
private readonly Mock<IHomeAssistantConnection> _connectionMock = new();
private readonly AppStateRepository _repository;
private readonly Mock<IHomeAssistantRunner> _runnerMock = new();
private readonly Mock<IHostEnvironment> _hostEnvironment = new();

public AppStateRepositoryTests()
{
_runnerMock.SetupGet(x => x.CurrentConnection).Returns(_connectionMock.Object);
_repository = new AppStateRepository(_runnerMock.Object);
_hostEnvironment.Setup(n => n.EnvironmentName).Returns("");
_repository = new AppStateRepository(_runnerMock.Object, _hostEnvironment.Object);
}

[Fact]
Expand Down Expand Up @@ -89,7 +92,6 @@ public async Task RemoveNotUsedStatesAsyncShouldRemoveEntitiesThatDoesNotCorresp
var applicationIds = new[] {"some_app_id"};
await _repository.RemoveNotUsedStatesAsync(applicationIds, CancellationToken.None);

// var command = new DeleteInputBooleanHelperCommand() {InputBooleanId = "some_app_id2", Type = "input_boolean/list""};
_connectionMock.Verify(
n => n.SendCommandAndReturnResponseAsync<DeleteInputBooleanHelperCommand, object?>(
It.Is<DeleteInputBooleanHelperCommand>(n => n.InputBooleanId == "netdaemon_some_app_id2"),
Expand All @@ -112,7 +114,6 @@ public async Task RemoveNotUsedStatesAsyncShouldRemoveAllHelpersIfNoAppsPresent(
var applicationIds = new List<string>();
await _repository.RemoveNotUsedStatesAsync(applicationIds, CancellationToken.None);

// var command = new DeleteInputBooleanHelperCommand() {InputBooleanId = "some_app_id2", Type = "input_boolean/list""};
_connectionMock.Verify(
n => n.SendCommandAndReturnResponseAsync<DeleteInputBooleanHelperCommand, object?>(
It.Is<DeleteInputBooleanHelperCommand>(n => n.InputBooleanId == "netdaemon_some_app_id"),
Expand All @@ -131,6 +132,7 @@ public async Task RemoveNotUsedStatesAsyncShouldNotRemoveNonNetDaemonInputBoolea
{
new InputBooleanHelper {Id = "netdaemon_some_app_id", Name = "netdaemon_some_app_id"},
new InputBooleanHelper {Id = "netdaemon_some_app_id2", Name = "netdaemon_some_app_id2"},
new InputBooleanHelper {Id = "dev_netdaemon_some_app_id2", Name = "dev_netdaemon_some_app_id2"},
new InputBooleanHelper {Id = "non_netdaemon_input_boolean", Name = "non_netdaemon_input_boolean"}
};
_connectionMock.Setup(n =>
Expand All @@ -141,10 +143,14 @@ public async Task RemoveNotUsedStatesAsyncShouldNotRemoveNonNetDaemonInputBoolea
var applicationIds = new[] {"some_app_id"};
await _repository.RemoveNotUsedStatesAsync(applicationIds, CancellationToken.None);

// var command = new DeleteInputBooleanHelperCommand() {InputBooleanId = "some_app_id2", Type = "input_boolean/list""};
_connectionMock.Verify(
n => n.SendCommandAndReturnResponseAsync<DeleteInputBooleanHelperCommand, object?>(
It.Is<DeleteInputBooleanHelperCommand>(n => n.InputBooleanId == "non_netdaemon_input_boolean"),
It.IsAny<CancellationToken>()), Times.Never);

_connectionMock.Verify(
n => n.SendCommandAndReturnResponseAsync<DeleteInputBooleanHelperCommand, object?>(
It.IsAny<DeleteInputBooleanHelperCommand>(),
It.IsAny<CancellationToken>()), Times.Exactly(2));
}
}
Loading