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