Skip to content

Commit 916a681

Browse files
authored
Add support for storage queue subscribers (#211)
* Add support for storage queue subscribers * Remove Newtonsoft.Json * Support topic level auth * Improve test coverage * Add seq to docker compose file * Remove Mediatr dependency
1 parent 0d79487 commit 916a681

83 files changed

Lines changed: 5565 additions & 637 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

AGENTS.md

Lines changed: 401 additions & 0 deletions
Large diffs are not rendered by default.

DOCKER.md

Lines changed: 761 additions & 0 deletions
Large diffs are not rendered by default.

docker-compose.yml

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,13 @@ services:
1616
- ASPNETCORE_Kestrel__Certificates__Default__Path=/aegs/azureEventGridSimulator.pfx
1717
- ASPNETCORE_Kestrel__Certificates__Default__Password=Y0urSup3rCrypt1cPa55w0rd!
1818

19-
# you could also define topics/subscribers via via a configfile
19+
# topics, subscribers, and logging config
2020
- AEGS_ConfigFile=/aegs/appsettings.docker.json
2121

22-
# logging configuration
23-
- AEGS_Serilog__MinimumLevel__Default=Verbose
24-
2522
depends_on:
2623
- servicebus-emulator
24+
- azurite
25+
- seq
2726

2827
networks:
2928
- aegs-network
@@ -32,6 +31,37 @@ services:
3231
context: .
3332
dockerfile: ./Dockerfile
3433

34+
# Seq - Structured Log Server
35+
# See: https://docs.datalust.co/docs/getting-started-with-docker
36+
seq:
37+
container_name: seq
38+
image: datalust/seq:latest
39+
ports:
40+
- "5341:5341" # Ingestion API
41+
- "8081:80" # Web UI
42+
environment:
43+
- ACCEPT_EULA=Y
44+
- SEQ_FIRSTRUN_NOAUTHENTICATION=true
45+
networks:
46+
aegs-network:
47+
aliases:
48+
- seq
49+
50+
# Azurite - Azure Storage Emulator
51+
# See: https://learn.microsoft.com/en-us/azure/storage/common/storage-use-azurite
52+
azurite:
53+
container_name: azurite
54+
image: mcr.microsoft.com/azure-storage/azurite:latest
55+
ports:
56+
- "10000:10000" # Blob service
57+
- "10001:10001" # Queue service
58+
- "10002:10002" # Table service
59+
command: "azurite --blobHost 0.0.0.0 --queueHost 0.0.0.0 --tableHost 0.0.0.0"
60+
networks:
61+
aegs-network:
62+
aliases:
63+
- azurite
64+
3565
# Azure Service Bus Emulator
3666
# See: https://learn.microsoft.com/en-us/azure/service-bus-messaging/test-locally-with-service-bus-emulator
3767
servicebus-emulator:

docker/appsettings.docker.json

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,22 @@
11
{
2+
"Serilog": {
3+
"Using": [
4+
"Serilog.Sinks.Console",
5+
"Serilog.Sinks.Seq"
6+
],
7+
"MinimumLevel": {
8+
"Default": "Verbose"
9+
},
10+
"WriteTo": [
11+
{ "Name": "Console" },
12+
{
13+
"Name": "Seq",
14+
"Args": {
15+
"serverUrl": "http://seq:5341"
16+
}
17+
}
18+
]
19+
},
220
"topics": [
321
{
422
"name": "ExampleTopic",
@@ -43,6 +61,13 @@
4361
}
4462
}
4563
}
64+
],
65+
"storageQueue": [
66+
{
67+
"name": "StorageQueueSubscription",
68+
"connectionString": "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;QueueEndpoint=http://azurite:10001/devstoreaccount1;",
69+
"queueName": "eventgrid-events"
70+
}
4671
]
4772
}
4873
}

src/AzureEventGridSimulator.Tests/ActualSimulatorTests/AzureMessagingEventGridTest.cs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,10 @@ namespace AzureEventGridSimulator.Tests.ActualSimulatorTests;
1616
/// </summary>
1717
[Collection(nameof(ActualSimulatorFixtureCollection))]
1818
[Trait("Category", "integration-actual")]
19-
public class AzureMessagingEventGridTest
19+
public class AzureMessagingEventGridTest(ActualSimulatorFixture actualSimulatorFixture)
2020
{
2121
// ReSharper disable once NotAccessedField.Local
22-
private readonly ActualSimulatorFixture _actualSimulatorFixture;
23-
24-
public AzureMessagingEventGridTest(ActualSimulatorFixture actualSimulatorFixture)
25-
{
26-
_actualSimulatorFixture = actualSimulatorFixture;
27-
}
22+
private readonly ActualSimulatorFixture _actualSimulatorFixture = actualSimulatorFixture;
2823

2924
[Fact]
3025
public async Task GivenValidEvent_WhenUriContainsNonStandardPort_ThenItShouldBeAccepted()

src/AzureEventGridSimulator.Tests/AzureEventGridSimulator.Tests.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<ItemGroup>
88
<PackageReference Include="Azure.Messaging.EventGrid" />
99
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" />
10-
<PackageReference Include="Newtonsoft.Json" />
10+
<PackageReference Include="NSubstitute" />
1111
<PackageReference Include="Shouldly" />
1212
<PackageReference Include="Microsoft.NET.Test.Sdk" />
1313
<PackageReference Include="xunit" />

src/AzureEventGridSimulator.Tests/IntegrationTests/BasicTests.cs

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
using System.Net;
33
using System.Net.Http;
44
using System.Text;
5+
using System.Text.Json;
56
using System.Threading.Tasks;
67
using Azure.Messaging.EventGrid;
78
using AzureEventGridSimulator.Domain;
89
using Microsoft.AspNetCore.Mvc.Testing;
9-
using Newtonsoft.Json;
1010
using Shouldly;
1111
using Xunit;
1212

@@ -18,20 +18,14 @@ namespace AzureEventGridSimulator.Tests.IntegrationTests;
1818
/// Note: this is a WIP.
1919
/// </summary>
2020
[Trait("Category", "integration")]
21-
public class BasicTests : IClassFixture<IntegrationContextFixture>
21+
public class BasicTests(IntegrationContextFixture factory)
22+
: IClassFixture<IntegrationContextFixture>
2223
{
23-
private readonly IntegrationContextFixture _factory;
24-
25-
public BasicTests(IntegrationContextFixture factory)
26-
{
27-
_factory = factory;
28-
}
29-
3024
[Fact]
3125
public async Task GivenAValidEvent_WhenPublished_ThenItShouldBeAccepted()
3226
{
3327
// Arrange
34-
var client = _factory.CreateClient(
28+
var client = factory.CreateClient(
3529
new WebApplicationFactoryClientOptions
3630
{
3731
BaseAddress = new Uri("https://localhost:60101"),
@@ -45,7 +39,10 @@ public async Task GivenAValidEvent_WhenPublished_ThenItShouldBeAccepted()
4539
);
4640

4741
var testEvent = new EventGridEvent("subject", "eventType", "1.0", new { Blah = 1 });
48-
var json = JsonConvert.SerializeObject(new[] { testEvent }, Formatting.Indented);
42+
var json = JsonSerializer.Serialize(
43+
new[] { testEvent },
44+
new JsonSerializerOptions { WriteIndented = true }
45+
);
4946

5047
// Act
5148
var jsonContent = new StringContent(json, Encoding.UTF8, "application/json");
@@ -60,7 +57,7 @@ public async Task GivenAValidEvent_WhenPublished_ThenItShouldBeAccepted()
6057
public async Task GivenAHealthRequest_ThenItShouldRespondWithOk()
6158
{
6259
// Arrange
63-
var client = _factory.CreateClient(
60+
var client = factory.CreateClient(
6461
new WebApplicationFactoryClientOptions
6562
{
6663
BaseAddress = new Uri("https://localhost:60101"),

src/AzureEventGridSimulator.Tests/UnitTests/CloudEvents/CloudEventSchemaFormatterTests.cs

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
using System.Text.Json;
12
using AzureEventGridSimulator.Domain.Entities;
23
using AzureEventGridSimulator.Domain.Services;
3-
using Newtonsoft.Json.Linq;
44
using Shouldly;
55
using Xunit;
66

@@ -26,13 +26,14 @@ public void GivenCloudEvent_WhenSerialized_ThenJsonContainsAllRequiredFields()
2626
var json = _formatter.Serialize(simulatorEvent);
2727

2828
// Azure Event Grid sends events "in an array that has a single event"
29-
var array = JArray.Parse(json);
30-
array.Count.ShouldBe(1);
29+
using var doc = JsonDocument.Parse(json);
30+
var array = doc.RootElement;
31+
array.GetArrayLength().ShouldBe(1);
3132
var parsed = array[0];
32-
parsed["specversion"]?.ToString().ShouldBe("1.0");
33-
parsed["type"]?.ToString().ShouldBe("com.example.test");
34-
parsed["source"]?.ToString().ShouldBe("/test/source");
35-
parsed["id"]?.ToString().ShouldBe("test-id-123");
33+
parsed.GetProperty("specversion").GetString().ShouldBe("1.0");
34+
parsed.GetProperty("type").GetString().ShouldBe("com.example.test");
35+
parsed.GetProperty("source").GetString().ShouldBe("/test/source");
36+
parsed.GetProperty("id").GetString().ShouldBe("test-id-123");
3637
}
3738

3839
[Fact]
@@ -52,12 +53,13 @@ public void GivenCloudEventWithOptionalFields_WhenSerialized_ThenJsonContainsOpt
5253
var simulatorEvent = SimulatorEvent.FromCloudEvent(cloudEvent);
5354
var json = _formatter.Serialize(simulatorEvent);
5455

55-
var array = JArray.Parse(json);
56-
array.Count.ShouldBe(1);
56+
using var doc = JsonDocument.Parse(json);
57+
var array = doc.RootElement;
58+
array.GetArrayLength().ShouldBe(1);
5759
var parsed = array[0];
58-
parsed["subject"]?.ToString().ShouldBe("/test/subject");
59-
parsed["time"].ShouldNotBeNull(); // Time format may vary by locale
60-
parsed["data"].ShouldNotBeNull();
60+
parsed.GetProperty("subject").GetString().ShouldBe("/test/subject");
61+
parsed.TryGetProperty("time", out _).ShouldBeTrue(); // Time format may vary by locale
62+
parsed.TryGetProperty("data", out _).ShouldBeTrue();
6163
}
6264

6365
[Fact]
@@ -76,15 +78,16 @@ public void GivenEventGridEvent_WhenSerializedAsCloudEvent_ThenConvertedCorrectl
7678
var simulatorEvent = SimulatorEvent.FromEventGridEvent(eventGridEvent);
7779
var json = _formatter.Serialize(simulatorEvent);
7880

79-
var array = JArray.Parse(json);
80-
array.Count.ShouldBe(1);
81+
using var doc = JsonDocument.Parse(json);
82+
var array = doc.RootElement;
83+
array.GetArrayLength().ShouldBe(1);
8184
var parsed = array[0];
82-
parsed["specversion"]?.ToString().ShouldBe("1.0");
83-
parsed["type"]?.ToString().ShouldBe("Test.Event.Type");
84-
parsed["source"]?.ToString().ShouldBe("/test/topic");
85-
parsed["id"]?.ToString().ShouldBe("event-123");
86-
parsed["subject"]?.ToString().ShouldBe("/test/subject");
87-
parsed["time"].ShouldNotBeNull(); // Time format may vary by locale
85+
parsed.GetProperty("specversion").GetString().ShouldBe("1.0");
86+
parsed.GetProperty("type").GetString().ShouldBe("Test.Event.Type");
87+
parsed.GetProperty("source").GetString().ShouldBe("/test/topic");
88+
parsed.GetProperty("id").GetString().ShouldBe("event-123");
89+
parsed.GetProperty("subject").GetString().ShouldBe("/test/subject");
90+
parsed.TryGetProperty("time", out _).ShouldBeTrue(); // Time format may vary by locale
8891
}
8992

9093
[Fact]

0 commit comments

Comments
 (0)