1+ namespace SWEN3 . Paperless . RabbitMq . Tests . Integration ;
2+
3+ public class GenAIIntegrationTests : IAsyncLifetime
4+ {
5+ private readonly RabbitMqContainer _container = new RabbitMqBuilder ( ) . Build ( ) ;
6+ private IHost _host = null ! ;
7+ private IServiceProvider _serviceProvider = null ! ;
8+
9+ private IRabbitMqPublisher Publisher => _serviceProvider . GetRequiredService < IRabbitMqPublisher > ( ) ;
10+ private IRabbitMqConsumerFactory ConsumerFactory => _serviceProvider . GetRequiredService < IRabbitMqConsumerFactory > ( ) ;
11+ private IConnection Connection => _serviceProvider . GetRequiredService < IConnection > ( ) ;
12+
13+ public async ValueTask InitializeAsync ( )
14+ {
15+ await _container . StartAsync ( ) ;
16+ var hostBuilder = Host . CreateDefaultBuilder ( ) . ConfigureAppConfiguration ( ( _ , config ) =>
17+ {
18+ config . AddInMemoryCollection ( new Dictionary < string , string ? >
19+ {
20+ [ "RabbitMQ:Uri" ] = _container . GetConnectionString ( )
21+ } ) ;
22+ } ) . ConfigureServices ( ( context , services ) =>
23+ {
24+ services . AddPaperlessRabbitMq ( context . Configuration ) ;
25+ services . AddLogging ( ) ;
26+ } ) ;
27+ _host = hostBuilder . Build ( ) ;
28+ _serviceProvider = _host . Services ;
29+ await _host . StartAsync ( ) ;
30+ await Task . Delay ( TimeSpan . FromSeconds ( 2 ) ) ;
31+ }
32+
33+ public async ValueTask DisposeAsync ( )
34+ {
35+ await _host . StopAsync ( ) ;
36+ _host . Dispose ( ) ;
37+ await _container . DisposeAsync ( ) ;
38+ }
39+
40+ [ Fact ]
41+ public async Task GenAIEvent_ShouldPublishAndConsume_Successfully ( )
42+ {
43+ var testEvent = new GenAIEvent ( Guid . NewGuid ( ) , "This is a test summary for integration testing" ,
44+ DateTimeOffset . UtcNow ) ;
45+ await Publisher . PublishGenAIEventAsync ( testEvent ) ;
46+ await Task . Delay ( TimeSpan . FromMilliseconds ( 500 ) , TestContext . Current . CancellationToken ) ;
47+
48+ GenAIEvent ? receivedEvent = null ;
49+ await using var consumer = await ConsumerFactory . CreateConsumerAsync < GenAIEvent > ( ) ;
50+ var cts = new CancellationTokenSource ( TimeSpan . FromSeconds ( 5 ) ) ;
51+ await foreach ( var message in consumer . ConsumeAsync ( cts . Token ) )
52+ {
53+ receivedEvent = message ;
54+ await consumer . AckAsync ( ) ;
55+ break ;
56+ }
57+
58+ receivedEvent . Should ( ) . NotBeNull ( ) ;
59+ receivedEvent . DocumentId . Should ( ) . Be ( testEvent . DocumentId ) ;
60+ receivedEvent . Summary . Should ( ) . Be ( testEvent . Summary ) ;
61+ receivedEvent . GeneratedAt . Should ( ) . BeCloseTo ( testEvent . GeneratedAt , TimeSpan . FromSeconds ( 1 ) ) ;
62+ receivedEvent . ErrorMessage . Should ( ) . BeNull ( ) ;
63+ }
64+
65+ [ Fact ]
66+ public async Task GenAIEvent_WithError_ShouldPublishAndConsume_Successfully ( )
67+ {
68+ var testEvent = new GenAIEvent ( Guid . NewGuid ( ) , string . Empty , DateTimeOffset . UtcNow ,
69+ "Failed to generate summary: API rate limit exceeded" ) ;
70+ await Publisher . PublishGenAIEventAsync ( testEvent ) ;
71+ await Task . Delay ( TimeSpan . FromMilliseconds ( 500 ) , TestContext . Current . CancellationToken ) ;
72+
73+ GenAIEvent ? receivedEvent = null ;
74+ await using var consumer = await ConsumerFactory . CreateConsumerAsync < GenAIEvent > ( ) ;
75+ var cts = new CancellationTokenSource ( TimeSpan . FromSeconds ( 5 ) ) ;
76+ await foreach ( var message in consumer . ConsumeAsync ( cts . Token ) )
77+ {
78+ receivedEvent = message ;
79+ await consumer . AckAsync ( ) ;
80+ break ;
81+ }
82+
83+ receivedEvent . Should ( ) . NotBeNull ( ) ;
84+ receivedEvent . DocumentId . Should ( ) . Be ( testEvent . DocumentId ) ;
85+ receivedEvent . Summary . Should ( ) . BeEmpty ( ) ;
86+ receivedEvent . ErrorMessage . Should ( ) . Be ( testEvent . ErrorMessage ) ;
87+ }
88+
89+ [ Fact ]
90+ public async Task GenAIEvent_MultipleEvents_ShouldProcessInOrder ( )
91+ {
92+ var events = Enumerable . Range ( 1 , 3 ) . Select ( i => new GenAIEvent ( Guid . NewGuid ( ) ,
93+ $ "Summary { i } ", DateTimeOffset . UtcNow . AddMinutes ( i ) ) ) . ToList ( ) ;
94+
95+ await using var consumer = await ConsumerFactory . CreateConsumerAsync < GenAIEvent > ( ) ;
96+ foreach ( var evt in events )
97+ await Publisher . PublishGenAIEventAsync ( evt ) ;
98+
99+ var receivedEvents = new List < GenAIEvent > ( ) ;
100+ using var cts = CancellationTokenSource . CreateLinkedTokenSource ( TestContext . Current . CancellationToken ) ;
101+ cts . CancelAfter ( TimeSpan . FromSeconds ( 10 ) ) ;
102+ await foreach ( var message in consumer . ConsumeAsync ( cts . Token ) )
103+ {
104+ receivedEvents . Add ( message ) ;
105+ await consumer . AckAsync ( ) ;
106+ if ( receivedEvents . Count >= 3 )
107+ break ;
108+ }
109+
110+ receivedEvents . Should ( ) . HaveCount ( 3 ) ;
111+ receivedEvents . Should ( )
112+ . BeEquivalentTo ( events , options => options . WithStrictOrdering ( ) . ComparingByMembers < GenAIEvent > ( ) ) ;
113+ }
114+
115+ [ Fact ]
116+ public async Task GenAIQueue_ShouldExistInTopology ( )
117+ {
118+ await using var channel =
119+ await Connection . CreateChannelAsync ( cancellationToken : TestContext . Current . CancellationToken ) ;
120+ var result = await channel . QueueDeclarePassiveAsync ( RabbitMqSchema . GenAIEventQueue ,
121+ TestContext . Current . CancellationToken ) ;
122+
123+ result . Should ( ) . NotBeNull ( ) ;
124+ result . QueueName . Should ( ) . Be ( RabbitMqSchema . GenAIEventQueue ) ;
125+ }
126+
127+ [ Fact ]
128+ public async Task GenAIEvent_Nack_ShouldRequeue ( )
129+ {
130+ var testEvent = new GenAIEvent ( Guid . NewGuid ( ) , "Nack test" , DateTimeOffset . UtcNow ) ;
131+ await Publisher . PublishGenAIEventAsync ( testEvent ) ;
132+ await Task . Delay ( TimeSpan . FromMilliseconds ( 500 ) , TestContext . Current . CancellationToken ) ;
133+
134+ await using ( var consumer1 = await ConsumerFactory . CreateConsumerAsync < GenAIEvent > ( ) )
135+ {
136+ var cts = new CancellationTokenSource ( TimeSpan . FromSeconds ( 5 ) ) ;
137+ await foreach ( var _ in consumer1 . ConsumeAsync ( cts . Token ) )
138+ {
139+ await consumer1 . NackAsync ( ) ;
140+ break ;
141+ }
142+ }
143+
144+ GenAIEvent ? redeliveredEvent = null ;
145+ await using ( var consumer2 = await ConsumerFactory . CreateConsumerAsync < GenAIEvent > ( ) )
146+ {
147+ var cts = new CancellationTokenSource ( TimeSpan . FromSeconds ( 5 ) ) ;
148+ await foreach ( var message in consumer2 . ConsumeAsync ( cts . Token ) )
149+ {
150+ redeliveredEvent = message ;
151+ await consumer2 . AckAsync ( ) ;
152+ break ;
153+ }
154+ }
155+
156+ redeliveredEvent . Should ( ) . NotBeNull ( ) ;
157+ redeliveredEvent . DocumentId . Should ( ) . Be ( testEvent . DocumentId ) ;
158+ redeliveredEvent . Summary . Should ( ) . Be ( testEvent . Summary ) ;
159+ }
160+ }
0 commit comments