1+ using System . Collections . Generic ;
2+ using System . Threading ;
3+ using System . Threading . Tasks ;
4+ using Azure . Messaging . ServiceBus ;
5+ using Ev . ServiceBus . Abstractions ;
6+ using Ev . ServiceBus . Abstractions . MessageReception ;
7+ using Ev . ServiceBus . Reception ;
8+ using Ev . ServiceBus . TestHelpers ;
9+ using Ev . ServiceBus . UnitTests . Helpers ;
10+ using FluentAssertions ;
11+ using Microsoft . Extensions . DependencyInjection ;
12+ using Xunit ;
13+
14+ namespace Ev . ServiceBus . UnitTests ;
15+
16+ public class MessageMetadataAccessorDecoratorTests
17+ {
18+ [ Fact ]
19+ public async Task DecoratorSetDataIsCalledDuringReception ( )
20+ {
21+ var composer = new Composer ( ) ;
22+
23+ composer . WithAdditionalServices ( services =>
24+ {
25+ services . AddSingleton < DecoratorCallTracker > ( ) ;
26+ services . Decorate < IMessageMetadataAccessor , TrackingMetadataAccessorDecorator > ( ) ;
27+ services . RegisterServiceBusReception ( ) . FromQueue ( "testQueue" , builder =>
28+ {
29+ builder . RegisterReception < Payload , NoopHandler > ( ) ;
30+ } ) ;
31+ } ) ;
32+
33+ var provider = await composer . Compose ( ) ;
34+ var clientMock = provider . GetProcessorMock ( "testQueue" ) ;
35+
36+ await TriggerReception ( clientMock ) ;
37+
38+ var tracker = provider . GetRequiredService < DecoratorCallTracker > ( ) ;
39+ tracker . SetDataCallCount . Should ( ) . Be ( 1 ) ;
40+ }
41+
42+ [ Fact ]
43+ public async Task DecoratorMetadataIsAccessibleFromHandler ( )
44+ {
45+ var composer = new Composer ( ) ;
46+
47+ composer . WithAdditionalServices ( services =>
48+ {
49+ services . AddSingleton < DecoratorCallTracker > ( ) ;
50+ services . AddSingleton < List < IMessageMetadata ? > > ( ) ;
51+ services . Decorate < IMessageMetadataAccessor , TrackingMetadataAccessorDecorator > ( ) ;
52+ services . RegisterServiceBusReception ( ) . FromQueue ( "testQueue" , builder =>
53+ {
54+ builder . RegisterReception < Payload , MetadataCaptureHandler > ( ) ;
55+ } ) ;
56+ } ) ;
57+
58+ var provider = await composer . Compose ( ) ;
59+ var clientMock = provider . GetProcessorMock ( "testQueue" ) ;
60+
61+ await TriggerReception ( clientMock ) ;
62+
63+ var captured = provider . GetRequiredService < List < IMessageMetadata ? > > ( ) ;
64+ captured . Count . Should ( ) . Be ( 1 ) ;
65+ captured [ 0 ] . Should ( ) . NotBeNull ( ) ;
66+ captured [ 0 ] ! . Subject . Should ( ) . Be ( "test subject" ) ;
67+ }
68+
69+ [ Fact ]
70+ public async Task DecoratorSetDataIsCalledDuringSessionReception ( )
71+ {
72+ var composer = new Composer ( ) ;
73+
74+ composer . WithAdditionalServices ( services =>
75+ {
76+ services . AddSingleton < DecoratorCallTracker > ( ) ;
77+ services . Decorate < IMessageMetadataAccessor , TrackingMetadataAccessorDecorator > ( ) ;
78+ services . RegisterServiceBusReception ( ) . FromQueue ( "testQueue" , builder =>
79+ {
80+ builder . EnableSessionHandling ( options => { } ) ;
81+ builder . RegisterReception < Payload , NoopHandler > ( ) ;
82+ } ) ;
83+ } ) ;
84+
85+ var provider = await composer . Compose ( ) ;
86+ var clientMock = provider . GetSessionProcessorMock ( "testQueue" ) ;
87+
88+ await TriggerSessionReception ( clientMock ) ;
89+
90+ var tracker = provider . GetRequiredService < DecoratorCallTracker > ( ) ;
91+ tracker . SetDataCallCount . Should ( ) . Be ( 1 ) ;
92+ }
93+
94+ private static async Task TriggerReception ( ProcessorMock client , CancellationToken cancellationToken = default )
95+ {
96+ var serializer = new TextJsonPayloadSerializer ( ) ;
97+ var body = serializer . SerializeBody ( new { } ) ;
98+ var message = new ServiceBusMessage ( body . Body )
99+ {
100+ ContentType = body . ContentType ,
101+ Subject = "test subject" ,
102+ ApplicationProperties =
103+ {
104+ { UserProperties . MessageTypeProperty , "IntegrationEvent" } ,
105+ { UserProperties . PayloadTypeIdProperty , "Payload" }
106+ }
107+ } ;
108+ await client . TriggerMessageReception ( message , cancellationToken ) ;
109+ }
110+
111+ private static async Task TriggerSessionReception ( SessionProcessorMock client , CancellationToken cancellationToken = default )
112+ {
113+ var serializer = new TextJsonPayloadSerializer ( ) ;
114+ var body = serializer . SerializeBody ( new { } ) ;
115+ var message = new ServiceBusMessage ( body . Body )
116+ {
117+ ContentType = body . ContentType ,
118+ Subject = "test subject" ,
119+ ApplicationProperties =
120+ {
121+ { UserProperties . MessageTypeProperty , "IntegrationEvent" } ,
122+ { UserProperties . PayloadTypeIdProperty , "Payload" }
123+ }
124+ } ;
125+ await client . TriggerMessageReception ( message , cancellationToken ) ;
126+ }
127+
128+ internal class Payload { }
129+
130+ private class NoopHandler : IMessageReceptionHandler < Payload >
131+ {
132+ public Task Handle ( Payload @event , CancellationToken cancellationToken ) => Task . CompletedTask ;
133+ }
134+
135+ private class MetadataCaptureHandler : IMessageReceptionHandler < Payload >
136+ {
137+ private readonly IMessageMetadataAccessor _accessor ;
138+ private readonly List < IMessageMetadata ? > _captured ;
139+
140+ public MetadataCaptureHandler ( IMessageMetadataAccessor accessor , List < IMessageMetadata ? > captured )
141+ {
142+ _accessor = accessor ;
143+ _captured = captured ;
144+ }
145+
146+ public Task Handle ( Payload @event , CancellationToken cancellationToken )
147+ {
148+ _captured . Add ( _accessor . Metadata ) ;
149+ return Task . CompletedTask ;
150+ }
151+ }
152+
153+ internal class DecoratorCallTracker
154+ {
155+ public int SetDataCallCount { get ; private set ; }
156+ public void RecordSetData ( ) => SetDataCallCount ++ ;
157+ }
158+
159+ private class TrackingMetadataAccessorDecorator : IMessageMetadataAccessor
160+ {
161+ private readonly IMessageMetadataAccessor _inner ;
162+ private readonly DecoratorCallTracker _tracker ;
163+
164+ public TrackingMetadataAccessorDecorator ( IMessageMetadataAccessor inner , DecoratorCallTracker tracker )
165+ {
166+ _inner = inner ;
167+ _tracker = tracker ;
168+ }
169+
170+ public IMessageMetadata ? Metadata => _inner . Metadata ;
171+
172+ public void SetData ( MessageContext context )
173+ {
174+ _tracker . RecordSetData ( ) ;
175+ _inner . SetData ( context ) ;
176+ }
177+ }
178+ }
0 commit comments