Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
api-governance / spectral-lint (push) Has been cancelled
oas-ci / oas-validate (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Policy Simulation / policy-simulate (push) Has been cancelled
SDK Publish & Sign / sdk-publish (push) Has been cancelled
255 lines
7.9 KiB
C#
255 lines
7.9 KiB
C#
using FluentAssertions;
|
|
using Microsoft.Extensions.Logging.Abstractions;
|
|
using Microsoft.Extensions.Time.Testing;
|
|
using StellaOps.Notifier.Worker.Escalation;
|
|
using Xunit;
|
|
|
|
namespace StellaOps.Notifier.WebService.Tests.Escalation;
|
|
|
|
/// <summary>
|
|
/// Tests for escalation policy service.
|
|
/// </summary>
|
|
public sealed class EscalationPolicyServiceTests
|
|
{
|
|
private readonly FakeTimeProvider _timeProvider;
|
|
private readonly InMemoryEscalationPolicyService _service;
|
|
|
|
public EscalationPolicyServiceTests()
|
|
{
|
|
_timeProvider = new FakeTimeProvider(new DateTimeOffset(2025, 1, 15, 10, 0, 0, TimeSpan.Zero));
|
|
_service = new InMemoryEscalationPolicyService(
|
|
null,
|
|
_timeProvider,
|
|
NullLogger<InMemoryEscalationPolicyService>.Instance);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ListPolicies_WhenEmpty_ReturnsEmptyList()
|
|
{
|
|
var result = await _service.ListPoliciesAsync("tenant-1");
|
|
|
|
result.Should().BeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task UpsertPolicy_CreatesNewPolicy()
|
|
{
|
|
var policy = CreateTestPolicy("tenant-1", "policy-1");
|
|
|
|
var result = await _service.UpsertPolicyAsync(policy, "admin");
|
|
|
|
result.PolicyId.Should().Be("policy-1");
|
|
result.TenantId.Should().Be("tenant-1");
|
|
result.Name.Should().Be("Default Escalation");
|
|
result.Levels.Should().HaveCount(2);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task UpsertPolicy_UpdatesExistingPolicy()
|
|
{
|
|
var policy = CreateTestPolicy("tenant-1", "policy-1");
|
|
await _service.UpsertPolicyAsync(policy, "admin");
|
|
|
|
var updated = policy with { Name = "Updated Policy" };
|
|
var result = await _service.UpsertPolicyAsync(updated, "admin");
|
|
|
|
result.Name.Should().Be("Updated Policy");
|
|
|
|
var retrieved = await _service.GetPolicyAsync("tenant-1", "policy-1");
|
|
retrieved!.Name.Should().Be("Updated Policy");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetPolicy_WhenExists_ReturnsPolicy()
|
|
{
|
|
var policy = CreateTestPolicy("tenant-1", "policy-1");
|
|
await _service.UpsertPolicyAsync(policy, "admin");
|
|
|
|
var result = await _service.GetPolicyAsync("tenant-1", "policy-1");
|
|
|
|
result.Should().NotBeNull();
|
|
result!.PolicyId.Should().Be("policy-1");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetPolicy_WhenNotExists_ReturnsNull()
|
|
{
|
|
var result = await _service.GetPolicyAsync("tenant-1", "nonexistent");
|
|
|
|
result.Should().BeNull();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task DeletePolicy_WhenExists_ReturnsTrue()
|
|
{
|
|
var policy = CreateTestPolicy("tenant-1", "policy-1");
|
|
await _service.UpsertPolicyAsync(policy, "admin");
|
|
|
|
var result = await _service.DeletePolicyAsync("tenant-1", "policy-1", "admin");
|
|
|
|
result.Should().BeTrue();
|
|
|
|
var retrieved = await _service.GetPolicyAsync("tenant-1", "policy-1");
|
|
retrieved.Should().BeNull();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task DeletePolicy_WhenNotExists_ReturnsFalse()
|
|
{
|
|
var result = await _service.DeletePolicyAsync("tenant-1", "nonexistent", "admin");
|
|
|
|
result.Should().BeFalse();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetDefaultPolicy_ReturnsFirstDefaultPolicy()
|
|
{
|
|
var policy1 = CreateTestPolicy("tenant-1", "policy-1") with { IsDefault = false };
|
|
var policy2 = CreateTestPolicy("tenant-1", "policy-2") with { IsDefault = true };
|
|
var policy3 = CreateTestPolicy("tenant-1", "policy-3") with { IsDefault = true };
|
|
|
|
await _service.UpsertPolicyAsync(policy1, "admin");
|
|
await _service.UpsertPolicyAsync(policy2, "admin");
|
|
await _service.UpsertPolicyAsync(policy3, "admin");
|
|
|
|
var result = await _service.GetDefaultPolicyAsync("tenant-1");
|
|
|
|
result.Should().NotBeNull();
|
|
result!.IsDefault.Should().BeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetDefaultPolicy_WhenNoneDefault_ReturnsNull()
|
|
{
|
|
var policy = CreateTestPolicy("tenant-1", "policy-1") with { IsDefault = false };
|
|
await _service.UpsertPolicyAsync(policy, "admin");
|
|
|
|
var result = await _service.GetDefaultPolicyAsync("tenant-1");
|
|
|
|
result.Should().BeNull();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task FindMatchingPolicies_FiltersByEventKind()
|
|
{
|
|
var policy1 = CreateTestPolicy("tenant-1", "policy-1") with
|
|
{
|
|
EventKindFilter = ["scan.*", "vulnerability.*"]
|
|
};
|
|
var policy2 = CreateTestPolicy("tenant-1", "policy-2") with
|
|
{
|
|
EventKindFilter = ["compliance.*"]
|
|
};
|
|
|
|
await _service.UpsertPolicyAsync(policy1, "admin");
|
|
await _service.UpsertPolicyAsync(policy2, "admin");
|
|
|
|
var result = await _service.FindMatchingPoliciesAsync("tenant-1", "scan.completed", null);
|
|
|
|
result.Should().HaveCount(1);
|
|
result[0].PolicyId.Should().Be("policy-1");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task FindMatchingPolicies_FiltersBySeverity()
|
|
{
|
|
var policy1 = CreateTestPolicy("tenant-1", "policy-1") with
|
|
{
|
|
SeverityFilter = ["critical", "high"]
|
|
};
|
|
var policy2 = CreateTestPolicy("tenant-1", "policy-2") with
|
|
{
|
|
SeverityFilter = ["low"]
|
|
};
|
|
|
|
await _service.UpsertPolicyAsync(policy1, "admin");
|
|
await _service.UpsertPolicyAsync(policy2, "admin");
|
|
|
|
var result = await _service.FindMatchingPoliciesAsync("tenant-1", "incident.created", "critical");
|
|
|
|
result.Should().HaveCount(1);
|
|
result[0].PolicyId.Should().Be("policy-1");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task FindMatchingPolicies_ReturnsAllWhenNoFilters()
|
|
{
|
|
var policy1 = CreateTestPolicy("tenant-1", "policy-1");
|
|
var policy2 = CreateTestPolicy("tenant-1", "policy-2");
|
|
|
|
await _service.UpsertPolicyAsync(policy1, "admin");
|
|
await _service.UpsertPolicyAsync(policy2, "admin");
|
|
|
|
var result = await _service.FindMatchingPoliciesAsync("tenant-1", "any.event", null);
|
|
|
|
result.Should().HaveCount(2);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ListPolicies_IsolatesByTenant()
|
|
{
|
|
var policy1 = CreateTestPolicy("tenant-1", "policy-1");
|
|
var policy2 = CreateTestPolicy("tenant-2", "policy-2");
|
|
|
|
await _service.UpsertPolicyAsync(policy1, "admin");
|
|
await _service.UpsertPolicyAsync(policy2, "admin");
|
|
|
|
var tenant1Policies = await _service.ListPoliciesAsync("tenant-1");
|
|
var tenant2Policies = await _service.ListPoliciesAsync("tenant-2");
|
|
|
|
tenant1Policies.Should().HaveCount(1);
|
|
tenant1Policies[0].PolicyId.Should().Be("policy-1");
|
|
|
|
tenant2Policies.Should().HaveCount(1);
|
|
tenant2Policies[0].PolicyId.Should().Be("policy-2");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task UpsertPolicy_SetsTimestamps()
|
|
{
|
|
var policy = CreateTestPolicy("tenant-1", "policy-1");
|
|
|
|
var result = await _service.UpsertPolicyAsync(policy, "admin");
|
|
|
|
result.CreatedAt.Should().Be(_timeProvider.GetUtcNow());
|
|
result.UpdatedAt.Should().Be(_timeProvider.GetUtcNow());
|
|
}
|
|
|
|
private static EscalationPolicy CreateTestPolicy(string tenantId, string policyId) => new()
|
|
{
|
|
PolicyId = policyId,
|
|
TenantId = tenantId,
|
|
Name = "Default Escalation",
|
|
IsDefault = true,
|
|
Levels =
|
|
[
|
|
new EscalationLevel
|
|
{
|
|
Order = 1,
|
|
DelayMinutes = 5,
|
|
Targets =
|
|
[
|
|
new EscalationTarget
|
|
{
|
|
TargetType = EscalationTargetType.OnCallSchedule,
|
|
TargetId = "schedule-1"
|
|
}
|
|
]
|
|
},
|
|
new EscalationLevel
|
|
{
|
|
Order = 2,
|
|
DelayMinutes = 15,
|
|
Targets =
|
|
[
|
|
new EscalationTarget
|
|
{
|
|
TargetType = EscalationTargetType.User,
|
|
TargetId = "manager-1"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
};
|
|
}
|