Add unit tests and implementations for MongoDB index models and OpenAPI metadata

- Implemented `MongoIndexModelTests` to verify index models for various stores.
- Created `OpenApiMetadataFactory` with methods to generate OpenAPI metadata.
- Added tests for `OpenApiMetadataFactory` to ensure expected defaults and URL overrides.
- Introduced `ObserverSurfaceSecrets` and `WebhookSurfaceSecrets` for managing secrets.
- Developed `RuntimeSurfaceFsClient` and `WebhookSurfaceFsClient` for manifest retrieval.
- Added dependency injection tests for `SurfaceEnvironmentRegistration` in both Observer and Webhook contexts.
- Implemented tests for secret resolution in `ObserverSurfaceSecretsTests` and `WebhookSurfaceSecretsTests`.
- Created `EnsureLinkNotMergeCollectionsMigrationTests` to validate MongoDB migration logic.
- Added project files for MongoDB tests and NuGet package mirroring.
This commit is contained in:
master
2025-11-17 21:21:56 +02:00
parent d3128aec24
commit 9075bad2d9
146 changed files with 152183 additions and 82 deletions

View File

@@ -0,0 +1,49 @@
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
namespace StellaOps.Notify.Storage.Mongo.Documents;
public sealed class PackApprovalDocument
{
[BsonId]
public ObjectId Id { get; init; }
[BsonElement("tenantId")]
public required string TenantId { get; init; }
[BsonElement("eventId")]
public required Guid EventId { get; init; }
[BsonElement("packId")]
public required string PackId { get; init; }
[BsonElement("kind")]
public required string Kind { get; init; }
[BsonElement("decision")]
public required string Decision { get; init; }
[BsonElement("actor")]
public required string Actor { get; init; }
[BsonElement("issuedAt")]
public required DateTimeOffset IssuedAt { get; init; }
[BsonElement("policyId")]
public string? PolicyId { get; init; }
[BsonElement("policyVersion")]
public string? PolicyVersion { get; init; }
[BsonElement("resumeToken")]
public string? ResumeToken { get; init; }
[BsonElement("summary")]
public string? Summary { get; init; }
[BsonElement("labels")]
public Dictionary<string, string>? Labels { get; init; }
[BsonElement("createdAt")]
public required DateTimeOffset CreatedAt { get; init; }
}

View File

@@ -0,0 +1,34 @@
using Microsoft.Extensions.Logging;
using StellaOps.Notify.Storage.Mongo.Internal;
namespace StellaOps.Notify.Storage.Mongo.Migrations;
internal sealed class EnsurePackApprovalsCollectionMigration : INotifyMongoMigration
{
private readonly ILogger<EnsurePackApprovalsCollectionMigration> _logger;
public EnsurePackApprovalsCollectionMigration(ILogger<EnsurePackApprovalsCollectionMigration> logger)
=> _logger = logger ?? throw new ArgumentNullException(nameof(logger));
public string Id => "20251117_pack_approvals_collection_v1";
public async ValueTask ExecuteAsync(NotifyMongoContext context, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(context);
var target = context.Options.PackApprovalsCollection;
var cursor = await context.Database
.ListCollectionNamesAsync(cancellationToken: cancellationToken)
.ConfigureAwait(false);
var existing = await cursor.ToListAsync(cancellationToken).ConfigureAwait(false);
if (existing.Contains(target, StringComparer.Ordinal))
{
return;
}
_logger.LogInformation("Creating pack approvals collection '{Collection}'.", target);
await context.Database.CreateCollectionAsync(target, cancellationToken: cancellationToken).ConfigureAwait(false);
}
}

View File

@@ -0,0 +1,41 @@
using MongoDB.Bson;
using MongoDB.Driver;
using StellaOps.Notify.Storage.Mongo.Internal;
namespace StellaOps.Notify.Storage.Mongo.Migrations;
internal sealed class EnsurePackApprovalsIndexesMigration : INotifyMongoMigration
{
public string Id => "20251117_pack_approvals_indexes_v1";
public async ValueTask ExecuteAsync(NotifyMongoContext context, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(context);
var collection = context.Database.GetCollection<BsonDocument>(context.Options.PackApprovalsCollection);
var unique = new CreateIndexModel<BsonDocument>(
Builders<BsonDocument>.IndexKeys
.Ascending("tenantId")
.Ascending("packId")
.Ascending("eventId"),
new CreateIndexOptions
{
Name = "tenant_pack_event",
Unique = true
});
await collection.Indexes.CreateOneAsync(unique, cancellationToken: cancellationToken).ConfigureAwait(false);
var issuedAt = new CreateIndexModel<BsonDocument>(
Builders<BsonDocument>.IndexKeys
.Ascending("tenantId")
.Descending("issuedAt"),
new CreateIndexOptions
{
Name = "tenant_issuedAt"
});
await collection.Indexes.CreateOneAsync(issuedAt, cancellationToken: cancellationToken).ConfigureAwait(false);
}
}

View File

@@ -0,0 +1,8 @@
using StellaOps.Notify.Storage.Mongo.Documents;
namespace StellaOps.Notify.Storage.Mongo.Repositories;
public interface INotifyPackApprovalRepository
{
Task UpsertAsync(PackApprovalDocument document, CancellationToken cancellationToken = default);
}

View File

@@ -0,0 +1,29 @@
using MongoDB.Driver;
using StellaOps.Notify.Storage.Mongo.Documents;
using StellaOps.Notify.Storage.Mongo.Internal;
namespace StellaOps.Notify.Storage.Mongo.Repositories;
internal sealed class NotifyPackApprovalRepository : INotifyPackApprovalRepository
{
private readonly IMongoCollection<PackApprovalDocument> _collection;
public NotifyPackApprovalRepository(NotifyMongoContext context)
{
ArgumentNullException.ThrowIfNull(context);
_collection = context.Database.GetCollection<PackApprovalDocument>(context.Options.PackApprovalsCollection);
}
public async Task UpsertAsync(PackApprovalDocument document, CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(document);
var filter = Builders<PackApprovalDocument>.Filter.And(
Builders<PackApprovalDocument>.Filter.Eq(x => x.TenantId, document.TenantId),
Builders<PackApprovalDocument>.Filter.Eq(x => x.PackId, document.PackId),
Builders<PackApprovalDocument>.Filter.Eq(x => x.EventId, document.EventId));
var options = new ReplaceOptions { IsUpsert = true };
await _collection.ReplaceOneAsync(filter, document, options, cancellationToken).ConfigureAwait(false);
}
}