Files
git.stella-ops.org/src/Notify/__Tests/StellaOps.Notify.Connectors.Teams.Tests/TeamsChannelTestProviderTests.cs
2025-10-28 15:10:40 +02:00

136 lines
5.5 KiB
C#

using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using StellaOps.Notify.Engine;
using StellaOps.Notify.Models;
using Xunit;
namespace StellaOps.Notify.Connectors.Teams.Tests;
public sealed class TeamsChannelTestProviderTests
{
[Fact]
public async Task BuildPreviewAsync_EmitsFallbackMetadata()
{
var provider = new TeamsChannelTestProvider();
var channel = CreateChannel(
endpoint: "https://contoso.webhook.office.com/webhookb2/tenant@uuid/IncomingWebhook/abcdef0123456789",
properties: new Dictionary<string, string>
{
["team"] = "secops",
["webhookKey"] = "s3cr3t-value-with-key-fragment",
["tenant"] = "contoso.onmicrosoft.com"
});
var request = new ChannelTestPreviewRequest(
TargetOverride: null,
TemplateId: null,
Title: "Notify Critical Finding",
Summary: "Critical container vulnerability detected.",
Body: "CVSS 9.8 vulnerability detected in ubuntu:22.04 base layer.",
TextBody: null,
Locale: "en-US",
Metadata: new Dictionary<string, string>(),
Attachments: new List<string>());
var context = new ChannelTestPreviewContext(
channel.TenantId,
channel,
channel.Config.Endpoint!,
request,
new DateTimeOffset(2025, 10, 20, 10, 0, 0, TimeSpan.Zero),
TraceId: "trace-teams-001");
var result = await provider.BuildPreviewAsync(context, CancellationToken.None);
Assert.Equal(NotifyChannelType.Teams, result.Preview.ChannelType);
Assert.Equal(channel.Config.Endpoint, result.Preview.Target);
Assert.Equal("Critical container vulnerability detected.", result.Preview.Summary);
Assert.NotNull(result.Metadata);
Assert.Equal(channel.Config.Endpoint, result.Metadata["teams.webhook"]);
Assert.Equal("1.5", result.Metadata["teams.card.version"]);
var fallback = result.Metadata["teams.fallbackText"];
Assert.Equal(result.Preview.TextBody, fallback);
Assert.Equal("Critical container vulnerability detected.", fallback);
Assert.Equal(ComputeSecretHash(channel.Config.SecretRef), result.Metadata["teams.secretRef.hash"]);
Assert.Equal("***", result.Metadata["teams.config.webhookKey"]);
Assert.Equal("contoso.onmicrosoft.com", result.Metadata["teams.config.tenant"]);
Assert.Equal(channel.Config.Endpoint, result.Metadata["teams.config.endpoint"]);
using var payload = JsonDocument.Parse(result.Preview.Body);
Assert.Equal("message", payload.RootElement.GetProperty("type").GetString());
Assert.Equal(result.Preview.TextBody, payload.RootElement.GetProperty("text").GetString());
Assert.Equal(result.Preview.Summary, payload.RootElement.GetProperty("summary").GetString());
var attachments = payload.RootElement.GetProperty("attachments");
Assert.True(attachments.GetArrayLength() > 0);
Assert.Equal(
"AdaptiveCard",
attachments[0].GetProperty("content").GetProperty("type").GetString());
}
[Fact]
public async Task BuildPreviewAsync_TruncatesLongFallback()
{
var provider = new TeamsChannelTestProvider();
var channel = CreateChannel(
endpoint: "https://contoso.webhook.office.com/webhookb2/tenant@uuid/IncomingWebhook/abcdef0123456789",
properties: new Dictionary<string, string>());
var longText = new string('A', 600);
var request = new ChannelTestPreviewRequest(
TargetOverride: null,
TemplateId: null,
Title: null,
Summary: null,
Body: null,
TextBody: longText,
Locale: null,
Metadata: new Dictionary<string, string>(),
Attachments: new List<string>());
var context = new ChannelTestPreviewContext(
channel.TenantId,
channel,
channel.Config.Endpoint!,
request,
DateTimeOffset.UtcNow,
TraceId: "trace-teams-002");
var result = await provider.BuildPreviewAsync(context, CancellationToken.None);
var metadata = Assert.IsAssignableFrom<IReadOnlyDictionary<string, string>>(result.Metadata);
var fallback = Assert.IsType<string>(result.Preview.TextBody);
Assert.Equal(512, fallback.Length);
Assert.Equal(fallback, metadata["teams.fallbackText"]);
Assert.StartsWith(new string('A', 512), fallback);
}
private static NotifyChannel CreateChannel(string endpoint, IDictionary<string, string> properties)
{
return NotifyChannel.Create(
channelId: "channel-teams-sec-ops",
tenantId: "tenant-sec",
name: "teams:sec-ops",
type: NotifyChannelType.Teams,
config: NotifyChannelConfig.Create(
secretRef: "ref://notify/channels/teams/sec-ops",
target: null,
endpoint: endpoint,
properties: properties));
}
private static string ComputeSecretHash(string secretRef)
{
var bytes = System.Text.Encoding.UTF8.GetBytes(secretRef.Trim());
var hash = System.Security.Cryptography.SHA256.HashData(bytes);
return Convert.ToHexString(hash.AsSpan(0, 8)).ToLowerInvariant();
}
}