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
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@ public async Task TestGetStateAsyncReturnsCorrectStateEnabled()
{
// ARRANGE
var haConnectionMock = new Mock<IHomeAssistantConnection>();
var haRunnerMock = new Mock<IHomeAssistantRunner>();
haRunnerMock.SetupGet(n => n.CurrentConnection).Returns(haConnectionMock.Object);

var provider = new ServiceCollection()
.AddTransient(_ => haConnectionMock.Object)
.AddSingleton(haRunnerMock.Object)
.AddNetDaemonStateManager()
.BuildServiceProvider();
using var scopedProvider = provider.CreateScope();
Expand All @@ -42,8 +45,11 @@ 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()
.AddTransient(_ => haConnectionMock.Object)
.AddSingleton(haRunnerMock.Object)
.AddNetDaemonStateManager()
.BuildServiceProvider();
using var scopedProvider = provider.CreateScope();
Expand All @@ -68,8 +74,11 @@ 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()
.AddTransient(_ => haConnectionMock.Object)
.AddSingleton(haRunnerMock.Object)
.AddNetDaemonStateManager()
.BuildServiceProvider();

Expand Down Expand Up @@ -98,8 +107,11 @@ 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()
.AddTransient(_ => haConnectionMock.Object)
.AddSingleton(haRunnerMock.Object)
.AddNetDaemonStateManager()
.BuildServiceProvider();

Expand All @@ -126,8 +138,11 @@ public async Task TestSetStateAsyncEnabled()
{
// ARRANGE
var haConnectionMock = new Mock<IHomeAssistantConnection>();
var haRunnerMock = new Mock<IHomeAssistantRunner>();
haRunnerMock.SetupGet(n => n.CurrentConnection).Returns(haConnectionMock.Object);

var provider = new ServiceCollection()
.AddTransient(_ => haConnectionMock.Object)
.AddSingleton(haRunnerMock.Object)
.AddNetDaemonStateManager()
.BuildServiceProvider();

Expand Down Expand Up @@ -156,8 +171,11 @@ 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()
.AddTransient(_ => haConnectionMock.Object)
.AddSingleton(haRunnerMock.Object)
.AddNetDaemonStateManager()
.BuildServiceProvider();

Expand All @@ -183,8 +201,11 @@ public async Task TestSetStateAsyncError()
{
// ARRANGE
var haConnectionMock = new Mock<IHomeAssistantConnection>();
var haRunnerMock = new Mock<IHomeAssistantRunner>();
haRunnerMock.SetupGet(n => n.CurrentConnection).Returns(haConnectionMock.Object);

var provider = new ServiceCollection()
.AddTransient(_ => haConnectionMock.Object)
.AddSingleton(haRunnerMock.Object)
.AddNetDaemonStateManager()
.BuildServiceProvider();
using var scopedProvider = provider.CreateScope();
Expand All @@ -207,15 +228,19 @@ public async Task TestSetStateAsyncError()
}

[Fact]
public void TestInitialize()
public async Task TestInitialize()
{
// ARRANGE
var haContextMock = new Mock<IHaContext>();
var appModelContextMock = new Mock<IAppModelContext>();
appModelContextMock.SetupGet(n => n.Applications).Returns(new List<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)
.AddTransient(_ => haConnectionMock.Object)
.AddNetDaemonStateManager()
.BuildServiceProvider();
using var scopedProvider = provider.CreateScope();
Expand All @@ -226,22 +251,27 @@ public void TestInitialize()
haConnectionMock.SetupGet(n => n.OnHomeAssistantEvent).Returns(hassEvent);

// ACT
homeAssistantStateUpdater.Initialize(haConnectionMock.Object, appModelContextMock.Object);
await homeAssistantStateUpdater.InitializeAsync(haConnectionMock.Object, appModelContextMock.Object)
.ConfigureAwait(false);
// ASSERT
hassEvent.HasObservers.Should().BeTrue();
}

[Fact]
public void TestAppDisabledShouldCallSetStateAsyncEnabled()
public async Task TestAppDisabledShouldCallSetStateAsyncEnabled()
{
// 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>();
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)
.AddTransient(_ => haConnectionMock.Object)
.AddNetDaemonStateManager()
.BuildServiceProvider();
using var scopedProvider = provider.CreateScope();
Expand All @@ -258,7 +288,9 @@ public void TestAppDisabledShouldCallSetStateAsyncEnabled()
});

// ACT
homeAssistantStateUpdater.Initialize(haConnectionMock.Object, appModelContextMock.Object);
await homeAssistantStateUpdater.InitializeAsync(haConnectionMock.Object, appModelContextMock.Object)
.ConfigureAwait(false);

hassEvent.OnNext(new HassEvent
{
EventType = "state_changed",
Expand All @@ -282,16 +314,20 @@ public void TestAppDisabledShouldCallSetStateAsyncEnabled()
}

[Fact]
public void TestAppNoChangeShouldNotCallSetStateAsync()
public async Task TestAppNoChangeShouldNotCallSetStateAsync()
{
// 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>();
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)
.AddTransient(_ => haConnectionMock.Object)
.AddNetDaemonStateManager()
.BuildServiceProvider();
using var scopedProvider = provider.CreateScope();
Expand All @@ -308,7 +344,9 @@ public void TestAppNoChangeShouldNotCallSetStateAsync()
});

// ACT
homeAssistantStateUpdater.Initialize(haConnectionMock.Object, appModelContextMock.Object);
await homeAssistantStateUpdater.InitializeAsync(haConnectionMock.Object, appModelContextMock.Object)
.ConfigureAwait(false);

hassEvent.OnNext(new HassEvent
{
EventType = "state_changed",
Expand All @@ -333,16 +371,20 @@ public void TestAppNoChangeShouldNotCallSetStateAsync()
}

[Fact]
public void TestAppOneStateIsNullShouldNotCallSetStateAsync()
public async Task TestAppOneStateIsNullShouldNotCallSetStateAsync()
{
// 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>();
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)
.AddTransient(_ => haConnectionMock.Object)
.AddNetDaemonStateManager()
.BuildServiceProvider();
using var scopedProvider = provider.CreateScope();
Expand All @@ -359,7 +401,7 @@ public void TestAppOneStateIsNullShouldNotCallSetStateAsync()
});

// ACT
homeAssistantStateUpdater.Initialize(haConnectionMock.Object, appModelContextMock.Object);
await homeAssistantStateUpdater.InitializeAsync(haConnectionMock.Object, appModelContextMock.Object);
hassEvent.OnNext(new HassEvent
{
EventType = "state_changed",
Expand All @@ -377,21 +419,4 @@ public void TestAppOneStateIsNullShouldNotCallSetStateAsync()
// ASSERT
appMock.Verify(n => n.SetStateAsync(ApplicationState.Disabled), Times.Never);
}

[Theory]
[InlineData("lowercase", "lowercase")]
[InlineData("lower.namespace.lowercase", "lower_namespace_lowercase")]
[InlineData("Namespace.Class", "namespace_class")]
[InlineData("Namespace.ClassNameWithUpperAndLower", "namespace_class_name_with_upper_and_lower")]
[InlineData("ALLUPPERCASE", "alluppercase")]
[InlineData("DIClass", "diclass")]
[InlineData("DiClass", "di_class")]
[InlineData("Di_Class", "di_class")]
[InlineData("di_class", "di_class")]
[InlineData("di__class", "di_class")]
public void TestToSafeHomeAssistantEntityIdFromApplicationIdShouldGiveCorrectName(string fromId, string toId)
{
var expected = $"input_boolean.netdaemon_{toId}";
AppStateManager.ToSafeHomeAssistantEntityIdFromApplicationId(fromId).Should().Be(expected);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
using System.Net;
using NetDaemon.Client.Internal.Exceptions;
using NetDaemon.Runtime.Internal;
using NetDaemon.Runtime.Internal.Model;

namespace NetDaemon.Runtime.Tests.Internal;

public class AppStateRepositoryTests
{
private readonly Mock<IHomeAssistantConnection> _connectionMock = new();
private readonly AppStateRepository _repository;
private readonly Mock<IHomeAssistantRunner> _runnerMock = new();

public AppStateRepositoryTests()
{
_runnerMock.SetupGet(x => x.CurrentConnection).Returns(_connectionMock.Object);
_repository = new AppStateRepository(_runnerMock.Object);
}

[Fact]
public async Task GetOrCreateAsyncShouldSendCreateInputBooleanCommandIfEntityNotExists()
{
_connectionMock
.Setup(n => n.GetApiCallAsync<HassState>("states/input_boolean.netdaemon_some_app_id",
It.IsAny<CancellationToken>()))
.ThrowsAsync(new HomeAssistantApiCallException("", HttpStatusCode.NotFound));

var result = await _repository.GetOrCreateAsync("some_app_id", CancellationToken.None);

_connectionMock.Verify(
n => n.SendCommandAndReturnResponseAsync<CreateInputBooleanHelperCommand, InputBooleanHelper>(
It.IsAny<CreateInputBooleanHelperCommand>(), It.IsAny<CancellationToken>()), Times.Once);

result.Should().BeTrue();
}

[Fact]
public async Task GetOrCreateAsyncShouldNotSendCreateInputBooleanCommandIfEntityExists()
{
_connectionMock
.Setup(n => n.GetApiCallAsync<HassState>("states/input_boolean.netdaemon_some_app_id",
It.IsAny<CancellationToken>()))
.ReturnsAsync(new HassState
{
EntityId = "input_boolean.netdaemon_some_app_id",
State = "on"
});

_ = await _repository.GetOrCreateAsync("some_app_id", CancellationToken.None);
_connectionMock.Verify(
n => n.SendCommandAndReturnResponseAsync<CreateInputBooleanHelperCommand, InputBooleanHelper>(
It.IsAny<CreateInputBooleanHelperCommand>(), It.IsAny<CancellationToken>()), Times.Never);
}

[Theory]
[InlineData("on", true)]
[InlineData("off", false)]
public async Task GetOrCreateAsyncShouldReturnCorrectEnabledStateForAppDependingOnStateOfInputBooleanHelper(
string entityState, bool isEnabled)
{
_connectionMock
.Setup(n => n.GetApiCallAsync<HassState>("states/input_boolean.netdaemon_some_app_id",
It.IsAny<CancellationToken>()))
.ReturnsAsync(new HassState
{
EntityId = "input_boolean.netdaemon_some_app_id",
State = entityState
});


var result = await _repository.GetOrCreateAsync("some_app_id", CancellationToken.None);

result.Should().Be(isEnabled);
}

[Fact]
public async Task RemoveNotUsedStatesAsyncShouldRemoveEntitiesThatDoesNotCorrespondToAnAppId()
{
var resultList = new[]
{
new InputBooleanHelper {Id = "netdaemon_some_app_id", Name = "netdaemon_some_app_id"},
new InputBooleanHelper {Id = "netdaemon_some_app_id2", Name = "netdaemon_some_app_id2"}
};
_connectionMock.Setup(n =>
n.SendCommandAndReturnResponseAsync<ListInputBooleanHelperCommand,
IReadOnlyCollection<InputBooleanHelper>>(It.IsAny<ListInputBooleanHelperCommand>(),
It.IsAny<CancellationToken>())).ReturnsAsync(resultList.ToList());

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"),
It.IsAny<CancellationToken>()), Times.Once);
}

[Fact]
public async Task RemoveNotUsedStatesAsyncShouldRemoveAllHelpersIfNoAppsPresent()
{
var resultList = new[]
{
new InputBooleanHelper {Id = "netdaemon_some_app_id", Name = "netdaemon_some_app_id"},
new InputBooleanHelper {Id = "netdaemon_some_app_id2", Name = "netdaemon_some_app_id2"}
};
_connectionMock.Setup(n =>
n.SendCommandAndReturnResponseAsync<ListInputBooleanHelperCommand,
IReadOnlyCollection<InputBooleanHelper>>(It.IsAny<ListInputBooleanHelperCommand>(),
It.IsAny<CancellationToken>())).ReturnsAsync(resultList.ToList());

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"),
It.IsAny<CancellationToken>()), Times.Once);

_connectionMock.Verify(
n => n.SendCommandAndReturnResponseAsync<DeleteInputBooleanHelperCommand, object?>(
It.Is<DeleteInputBooleanHelperCommand>(n => n.InputBooleanId == "netdaemon_some_app_id2"),
It.IsAny<CancellationToken>()), Times.Once);
}

[Fact]
public async Task RemoveNotUsedStatesAsyncShouldNotRemoveNonNetDaemonInputBooleans()
{
var resultList = new[]
{
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 = "non_netdaemon_input_boolean", Name = "non_netdaemon_input_boolean"}
};
_connectionMock.Setup(n =>
n.SendCommandAndReturnResponseAsync<ListInputBooleanHelperCommand,
IReadOnlyCollection<InputBooleanHelper>>(It.IsAny<ListInputBooleanHelperCommand>(),
It.IsAny<CancellationToken>())).ReturnsAsync(resultList.ToList());

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);
}
}
Loading