@@ -133,6 +133,212 @@ public async Task SendDryRunAsync()
133133 this . CheckHeaders ( handler . LastRequestHeaders ) ;
134134 }
135135
136+ [ Fact ]
137+ public async Task SendEachAsync ( )
138+ {
139+ var handler = new MockMessageHandler ( )
140+ {
141+ GenerateResponse = ( incomingRequest ) =>
142+ {
143+ string name ;
144+ if ( incomingRequest . Body . Contains ( "test-token1" ) )
145+ {
146+ name = "projects/fir-adminintegrationtests/messages/8580920590356323124" ;
147+ }
148+ else
149+ {
150+ name = "projects/fir-adminintegrationtests/messages/5903525881088369386" ;
151+ }
152+
153+ return new FirebaseMessagingClient . SingleMessageResponse ( )
154+ {
155+ Name = name ,
156+ } ;
157+ } ,
158+ } ;
159+ var factory = new MockHttpClientFactory ( handler ) ;
160+ var client = this . CreateMessagingClient ( factory ) ;
161+ var message1 = new Message ( )
162+ {
163+ Token = "test-token1" ,
164+ } ;
165+ var message2 = new Message ( )
166+ {
167+ Token = "test-token2" ,
168+ } ;
169+
170+ var response = await client . SendEachAsync ( new [ ] { message1 , message2 } ) ;
171+
172+ Assert . Equal ( 2 , response . SuccessCount ) ;
173+ Assert . Equal ( "projects/fir-adminintegrationtests/messages/8580920590356323124" , response . Responses [ 0 ] . MessageId ) ;
174+ Assert . Equal ( "projects/fir-adminintegrationtests/messages/5903525881088369386" , response . Responses [ 1 ] . MessageId ) ;
175+ Assert . Equal ( 2 , handler . Calls ) ;
176+ }
177+
178+ [ Fact ]
179+ public async Task SendEachAsyncWithError ( )
180+ {
181+ // Return a success for `message1` and an error for `message2`
182+ var handler = new MockMessageHandler ( )
183+ {
184+ GenerateResponse = ( incomingRequest ) =>
185+ {
186+ string name ;
187+ if ( incomingRequest . Body . Contains ( "test-token1" ) )
188+ {
189+ name = "projects/fir-adminintegrationtests/messages/8580920590356323124" ;
190+ return new FirebaseMessagingClient . SingleMessageResponse ( )
191+ {
192+ Name = name ,
193+ } ;
194+ }
195+ else
196+ {
197+ return @"{
198+ ""error"": {
199+ ""status"": ""INVALID_ARGUMENT"",
200+ ""message"": ""The registration token is not a valid FCM registration token"",
201+ ""details"": [
202+ {
203+ ""@type"": ""type.googleapis.com/google.firebase.fcm.v1.FcmError"",
204+ ""errorCode"": ""UNREGISTERED""
205+ }
206+ ]
207+ }
208+ }" ;
209+ }
210+ } ,
211+ GenerateStatusCode = ( incomingRequest ) =>
212+ {
213+ if ( incomingRequest . Body . Contains ( "test-token1" ) )
214+ {
215+ return HttpStatusCode . OK ;
216+ }
217+ else
218+ {
219+ return HttpStatusCode . InternalServerError ;
220+ }
221+ } ,
222+ } ;
223+ var factory = new MockHttpClientFactory ( handler ) ;
224+ var client = this . CreateMessagingClient ( factory ) ;
225+ var message1 = new Message ( )
226+ {
227+ Token = "test-token1" ,
228+ } ;
229+ var message2 = new Message ( )
230+ {
231+ Token = "test-token2" ,
232+ } ;
233+
234+ var response = await client . SendEachAsync ( new [ ] { message1 , message2 } ) ;
235+
236+ Assert . Equal ( 1 , response . SuccessCount ) ;
237+ Assert . Equal ( 1 , response . FailureCount ) ;
238+ Assert . Equal ( "projects/fir-adminintegrationtests/messages/8580920590356323124" , response . Responses [ 0 ] . MessageId ) ;
239+
240+ var exception = response . Responses [ 1 ] . Exception ;
241+ Assert . NotNull ( exception ) ;
242+ Assert . Equal ( ErrorCode . InvalidArgument , exception . ErrorCode ) ;
243+ Assert . Equal ( "The registration token is not a valid FCM registration token" , exception . Message ) ;
244+ Assert . Equal ( MessagingErrorCode . Unregistered , exception . MessagingErrorCode ) ;
245+ Assert . NotNull ( exception . HttpResponse ) ;
246+
247+ Assert . Equal ( 2 , handler . Calls ) ;
248+ }
249+
250+ [ Fact ]
251+ public async Task SendEachAsyncWithErrorNoDetail ( )
252+ {
253+ // Return a success for `message1` and an error for `message2`
254+ var handler = new MockMessageHandler ( )
255+ {
256+ GenerateResponse = ( incomingRequest ) =>
257+ {
258+ string name ;
259+ if ( incomingRequest . Body . Contains ( "test-token1" ) )
260+ {
261+ name = "projects/fir-adminintegrationtests/messages/8580920590356323124" ;
262+ return new FirebaseMessagingClient . SingleMessageResponse ( )
263+ {
264+ Name = name ,
265+ } ;
266+ }
267+ else
268+ {
269+ return @"{
270+ ""error"": {
271+ ""status"": ""INVALID_ARGUMENT"",
272+ ""message"": ""The registration token is not a valid FCM registration token"",
273+ }
274+ }" ;
275+ }
276+ } ,
277+ GenerateStatusCode = ( incomingRequest ) =>
278+ {
279+ if ( incomingRequest . Body . Contains ( "test-token1" ) )
280+ {
281+ return HttpStatusCode . OK ;
282+ }
283+ else
284+ {
285+ return HttpStatusCode . InternalServerError ;
286+ }
287+ } ,
288+ } ;
289+ var factory = new MockHttpClientFactory ( handler ) ;
290+ var client = this . CreateMessagingClient ( factory ) ;
291+ var message1 = new Message ( )
292+ {
293+ Token = "test-token1" ,
294+ } ;
295+ var message2 = new Message ( )
296+ {
297+ Token = "test-token2" ,
298+ } ;
299+
300+ var response = await client . SendEachAsync ( new [ ] { message1 , message2 } ) ;
301+
302+ Assert . Equal ( 1 , response . SuccessCount ) ;
303+ Assert . Equal ( 1 , response . FailureCount ) ;
304+ Assert . Equal ( "projects/fir-adminintegrationtests/messages/8580920590356323124" , response . Responses [ 0 ] . MessageId ) ;
305+
306+ var exception = response . Responses [ 1 ] . Exception ;
307+ Assert . NotNull ( exception ) ;
308+ Assert . Equal ( ErrorCode . InvalidArgument , exception . ErrorCode ) ;
309+ Assert . Equal ( "The registration token is not a valid FCM registration token" , exception . Message ) ;
310+ Assert . Null ( exception . MessagingErrorCode ) ;
311+ Assert . NotNull ( exception . HttpResponse ) ;
312+
313+ Assert . Equal ( 2 , handler . Calls ) ;
314+ }
315+
316+ [ Fact ]
317+ public async Task SendEachAsyncNullList ( )
318+ {
319+ var factory = new MockHttpClientFactory ( new MockMessageHandler ( ) ) ;
320+ var client = this . CreateMessagingClient ( factory ) ;
321+
322+ await Assert . ThrowsAsync < ArgumentNullException > ( ( ) => client . SendEachAsync ( null ) ) ;
323+ }
324+
325+ [ Fact ]
326+ public async Task SendEachAsyncWithNoMessages ( )
327+ {
328+ var factory = new MockHttpClientFactory ( new MockMessageHandler ( ) ) ;
329+ var client = this . CreateMessagingClient ( factory ) ;
330+ await Assert . ThrowsAsync < ArgumentException > ( ( ) => client . SendEachAsync ( Enumerable . Empty < Message > ( ) ) ) ;
331+ }
332+
333+ [ Fact ]
334+ public async Task SendEachAsyncWithTooManyMessages ( )
335+ {
336+ var factory = new MockHttpClientFactory ( new MockMessageHandler ( ) ) ;
337+ var client = this . CreateMessagingClient ( factory ) ;
338+ var messages = Enumerable . Range ( 0 , 501 ) . Select ( _ => new Message { Topic = "test-topic" } ) ;
339+ await Assert . ThrowsAsync < ArgumentException > ( ( ) => client . SendEachAsync ( messages ) ) ;
340+ }
341+
136342 [ Fact ]
137343 public async Task SendAllAsync ( )
138344 {
0 commit comments