Skip to content

Commit bcdca8e

Browse files
author
Leo
committed
Integration tests working as expected
1 parent 949a109 commit bcdca8e

File tree

7 files changed

+141
-41
lines changed

7 files changed

+141
-41
lines changed

FirebaseAdmin/FirebaseAdmin.IntegrationTests/FirebaseMessagingTest.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
// limitations under the License.
1414

1515
using System;
16+
using System.Collections.Generic;
1617
using System.Text.RegularExpressions;
1718
using System.Threading.Tasks;
1819
using FirebaseAdmin.Messaging;
@@ -120,5 +121,21 @@ public async Task SendMulticast()
120121
Assert.NotNull(response.Responses[0].Exception);
121122
Assert.NotNull(response.Responses[1].Exception);
122123
}
124+
125+
[Fact]
126+
public async Task SubscribeToTopic()
127+
{
128+
var response = await FirebaseMessaging.DefaultInstance.SubscribeToTopicAsync("test-topic", new List<string> { "token1", "token2" });
129+
Assert.NotNull(response);
130+
Assert.Equal(2, response.FailureCount);
131+
}
132+
133+
[Fact]
134+
public async Task UnsubscribeFromTopic()
135+
{
136+
var response = await FirebaseMessaging.DefaultInstance.UnsubscribeFromTopicAsync("test-topic", new List<string> { "token1", "token2" });
137+
Assert.NotNull(response);
138+
Assert.Equal(2, response.FailureCount);
139+
}
123140
}
124141
}

FirebaseAdmin/FirebaseAdmin.Tests/Messaging/FirebaseMessagingTest.cs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
// limitations under the License.
1414

1515
using System;
16+
using System.Collections.Generic;
1617
using System.Threading;
1718
using System.Threading.Tasks;
1819
using FirebaseAdmin.Tests;
@@ -118,6 +119,56 @@ await Assert.ThrowsAsync<OperationCanceledException>(
118119
new Message() { Topic = "test-topic" }, canceller.Token));
119120
}
120121

122+
[Fact]
123+
public async Task SubscribeWithClientFactory()
124+
{
125+
var handler = new MockMessageHandler()
126+
{
127+
Response = @"{""results"":[{}]}",
128+
};
129+
var factory = new MockHttpClientFactory(handler);
130+
131+
var app = FirebaseApp.Create(new AppOptions()
132+
{
133+
Credential = GoogleCredential.FromAccessToken("test-token"),
134+
HttpClientFactory = factory,
135+
ProjectId = "test-project",
136+
});
137+
FirebaseMessaging messaging = FirebaseMessaging.GetMessaging(app);
138+
Assert.NotNull(messaging);
139+
Assert.Same(messaging, FirebaseMessaging.GetMessaging(app));
140+
141+
var response = await messaging.SubscribeToTopicAsync("test-topic", new List<string> { "test-token" });
142+
Assert.Equal(0, response.FailureCount);
143+
Assert.Equal(1, response.SuccessCount);
144+
app.Delete();
145+
}
146+
147+
[Fact]
148+
public async Task UnsubscribeWithClientFactory()
149+
{
150+
var handler = new MockMessageHandler()
151+
{
152+
Response = @"{""results"":[{}]}",
153+
};
154+
var factory = new MockHttpClientFactory(handler);
155+
156+
var app = FirebaseApp.Create(new AppOptions()
157+
{
158+
Credential = GoogleCredential.FromAccessToken("test-token"),
159+
HttpClientFactory = factory,
160+
ProjectId = "test-project",
161+
});
162+
FirebaseMessaging messaging = FirebaseMessaging.GetMessaging(app);
163+
Assert.NotNull(messaging);
164+
Assert.Same(messaging, FirebaseMessaging.GetMessaging(app));
165+
166+
var response = await messaging.UnsubscribeFromTopicAsync("test-topic", new List<string> { "test-token" });
167+
Assert.Equal(0, response.FailureCount);
168+
Assert.Equal(1, response.SuccessCount);
169+
app.Delete();
170+
}
171+
121172
public void Dispose()
122173
{
123174
FirebaseApp.DeleteAll();

FirebaseAdmin/FirebaseAdmin.Tests/Messaging/InstanceIdClientTest.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public async Task InstanceIdClientSubscribesToTopic()
4949

5050
var client = new InstanceIdClient(factory, MockCredential, "test-project");
5151

52-
var result = await client.SubscribeToTopic("test-topic", new List<string> { "abc123" });
52+
var result = await client.SubscribeToTopicAsync("test-topic", new List<string> { "abc123" });
5353

5454
Assert.Equal(1, result.GetSuccessCount());
5555
}
@@ -65,7 +65,7 @@ public async Task InstanceIdClientUnsubscribesFromTopic()
6565

6666
var client = new InstanceIdClient(factory, MockCredential, "test-project");
6767

68-
var result = await client.UnsubscribeFromTopic("test-topic", new List<string> { "abc123" });
68+
var result = await client.UnsubscribeFromTopicAsync("test-topic", new List<string> { "abc123" });
6969

7070
Assert.Equal(1, result.GetSuccessCount());
7171
}

FirebaseAdmin/FirebaseAdmin.Tests/Messaging/TopicManagementResponseTest.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,5 +59,27 @@ public void TopicManagementResponseHandlesUnknownErrors()
5959
Assert.Equal(1, response.GetFailureCount());
6060
Assert.Equal(0, response.GetSuccessCount());
6161
}
62+
63+
[Fact]
64+
public void TopicManagementResponseHandlesUnexpectedResponse()
65+
{
66+
var json = @"[{""unexpected"":""NOT_A_REAL_CODE""}]";
67+
var jObjects = JArray.Parse(json).ToObject<List<JObject>>();
68+
var response = new TopicManagementResponse(jObjects);
69+
70+
Assert.Equal(0, response.GetFailureCount());
71+
Assert.Equal(1, response.GetSuccessCount());
72+
}
73+
74+
[Fact]
75+
public void TopicManagementResponseCountsSuccessAndErrors()
76+
{
77+
var json = @"[{""error"": ""NOT_FOUND""}, {}, {""error"": ""NOT_FOUND""}, {}, {}]";
78+
var jObjects = JArray.Parse(json).ToObject<List<JObject>>();
79+
var response = new TopicManagementResponse(jObjects);
80+
81+
Assert.Equal(2, response.GetFailureCount());
82+
Assert.Equal(3, response.GetSuccessCount());
83+
}
6284
}
6385
}

FirebaseAdmin/FirebaseAdmin/Messaging/FirebaseMessaging.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,15 @@ namespace FirebaseAdmin.Messaging
2727
public sealed class FirebaseMessaging : IFirebaseService
2828
{
2929
private readonly FirebaseMessagingClient messagingClient;
30+
private readonly InstanceIdClient instanceIdClient;
3031

3132
private FirebaseMessaging(FirebaseApp app)
3233
{
3334
this.messagingClient = new FirebaseMessagingClient(
3435
app.Options.HttpClientFactory, app.Options.Credential, app.GetProjectId());
36+
37+
this.instanceIdClient = new InstanceIdClient(
38+
app.Options.HttpClientFactory, app.Options.Credential, app.GetProjectId());
3539
}
3640

3741
/// <summary>
@@ -310,6 +314,28 @@ public async Task<BatchResponse> SendMulticastAsync(
310314
message.GetMessageList(), dryRun, cancellationToken).ConfigureAwait(false);
311315
}
312316

317+
/// <summary>
318+
/// Subscribes a list of registration tokens to a topic.
319+
/// </summary>
320+
/// <param name="topic">The topic name to subscribe to. /topics/ will be prepended to the topic name provided if absent.</param>
321+
/// <param name="registrationTokens">A list of registration tokens to subscribe.</param>
322+
/// <returns>The response produced by FCM topic management operations.</returns>
323+
public async Task<TopicManagementResponse> SubscribeToTopicAsync(string topic, List<string> registrationTokens)
324+
{
325+
return await this.instanceIdClient.SubscribeToTopicAsync(topic, registrationTokens);
326+
}
327+
328+
/// <summary>
329+
/// Unsubscribes a list of registration tokens from a topic.
330+
/// </summary>
331+
/// <param name="topic">The topic name to unsubscribe from. /topics/ will be prepended to the topic name provided if absent.</param>
332+
/// <param name="registrationTokens">A list of registration tokens to unsubscribe.</param>
333+
/// <returns>The response produced by FCM topic management operations.</returns>
334+
public async Task<TopicManagementResponse> UnsubscribeFromTopicAsync(string topic, List<string> registrationTokens)
335+
{
336+
return await this.instanceIdClient.UnsubscribeFromTopicAsync(topic, registrationTokens);
337+
}
338+
313339
/// <summary>
314340
/// Deletes this <see cref="FirebaseMessaging"/> service instance.
315341
/// </summary>

FirebaseAdmin/FirebaseAdmin/Messaging/InstanceIdClient.cs

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,18 @@
2525
using Google.Apis.Json;
2626
using Google.Apis.Util;
2727
using Newtonsoft.Json;
28-
using Newtonsoft.Json.Linq;
2928

3029
/// <summary>
3130
/// A helper class for interacting with the Firebase Instance ID service.Implements the FCM
3231
/// topic management functionality.
3332
/// </summary>
34-
public sealed class InstanceIdClient
33+
public sealed class InstanceIdClient : IDisposable
3534
{
36-
private readonly string iidHost = "https://iid.googleapis.com";
35+
private const string IidHost = "https://iid.googleapis.com";
3736

38-
private readonly string iidSubscriberPath = "iid/v1:batchAdd";
37+
private const string IidSubscriberPath = "iid/v1:batchAdd";
3938

40-
private readonly string iidUnsubscribePath = "iid/v1:batchRemove";
39+
private const string IidUnsubscribePath = "iid/v1:batchRemove";
4140

4241
private readonly ConfigurableHttpClient httpClient;
4342

@@ -67,16 +66,16 @@ public InstanceIdClient(HttpClientFactory clientFactory, GoogleCredential creden
6766
}
6867

6968
/// <summary>
70-
/// Index of the registration token to which this error is related to.
69+
/// Subscribes a list of registration tokens to a topic.
7170
/// </summary>
7271
/// <param name="topic">The topic name to subscribe to. /topics/ will be prepended to the topic name provided if absent.</param>
7372
/// <param name="registrationTokens">A list of registration tokens to subscribe.</param>
7473
/// <returns>The response produced by FCM topic management operations.</returns>
75-
public async Task<TopicManagementResponse> SubscribeToTopic(string topic, List<string> registrationTokens)
74+
public async Task<TopicManagementResponse> SubscribeToTopicAsync(string topic, List<string> registrationTokens)
7675
{
7776
try
7877
{
79-
return await this.SendInstanceIdRequest(topic, registrationTokens, this.iidSubscriberPath).ConfigureAwait(false);
78+
return await this.SendInstanceIdRequest(topic, registrationTokens, IidSubscriberPath).ConfigureAwait(false);
8079
}
8180
catch (HttpRequestException e)
8281
{
@@ -89,16 +88,16 @@ public async Task<TopicManagementResponse> SubscribeToTopic(string topic, List<s
8988
}
9089

9190
/// <summary>
92-
/// Index of the registration token to which this error is related to.
91+
/// Unsubscribes a list of registration tokens from a topic.
9392
/// </summary>
9493
/// <param name="topic">The topic name to unsubscribe from. /topics/ will be prepended to the topic name provided if absent.</param>
9594
/// <param name="registrationTokens">A list of registration tokens to unsubscribe.</param>
9695
/// <returns>The response produced by FCM topic management operations.</returns>
97-
public async Task<TopicManagementResponse> UnsubscribeFromTopic(string topic, List<string> registrationTokens)
96+
public async Task<TopicManagementResponse> UnsubscribeFromTopicAsync(string topic, List<string> registrationTokens)
9897
{
9998
try
10099
{
101-
return await this.SendInstanceIdRequest(topic, registrationTokens, this.iidUnsubscribePath).ConfigureAwait(false);
100+
return await this.SendInstanceIdRequest(topic, registrationTokens, IidUnsubscribePath).ConfigureAwait(false);
102101
}
103102
catch (HttpRequestException e)
104103
{
@@ -110,9 +109,17 @@ public async Task<TopicManagementResponse> UnsubscribeFromTopic(string topic, Li
110109
}
111110
}
112111

112+
/// <summary>
113+
/// Dispose the HttpClient.
114+
/// </summary>
115+
public void Dispose()
116+
{
117+
this.httpClient.Dispose();
118+
}
119+
113120
private async Task<TopicManagementResponse> SendInstanceIdRequest(string topic, List<string> registrationTokens, string path)
114121
{
115-
string url = $"{this.iidHost}/{path}";
122+
string url = $"{IidHost}/{path}";
116123
var body = new InstanceIdServiceRequest
117124
{
118125
Topic = this.GetPrefixedTopic(topic),
@@ -171,18 +178,4 @@ private class InstanceIdServiceRequest
171178
[JsonProperty("registration_tokens")]
172179
public List<string> RegistrationTokens { get; set; }
173180
}
174-
175-
/*
176-
private class InstanceIdServiceErrorResponse
177-
{
178-
[JsonProperty("error")]
179-
public string Error { get; set; }
180-
}
181-
182-
private class InstanceIdServiceResponse
183-
{
184-
[JsonProperty("results")]
185-
public List<JObject> Results { get; set; }
186-
}
187-
*/
188181
}

FirebaseAdmin/FirebaseAdmin/Messaging/TopicManagementResponse.cs

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public TopicManagementResponse(List<JObject> results)
3838
var resultErrors = new List<Error>();
3939
for (var i = 0; i < results.Count; i++)
4040
{
41-
if (results[i].HasValues)
41+
if (results[i].HasValues && results[i].Value<string>("error") != null)
4242
{
4343
resultErrors.Add(new Error(i, results[i].Value<string>("error")));
4444
}
@@ -55,28 +55,19 @@ public TopicManagementResponse(List<JObject> results)
5555
/// Gets the number of registration tokens that were successfully subscribed or unsubscribed.
5656
/// </summary>
5757
/// <returns>The number of registration tokens that were successfully subscribed or unsubscribed.</returns>
58-
public int GetSuccessCount()
59-
{
60-
return this.successCount;
61-
}
58+
public int SuccessCount => this.successCount;
6259

6360
/// <summary>
6461
/// Gets the number of registration tokens that could not be subscribed or unsubscribed, and resulted in an error.
6562
/// </summary>
6663
/// <returns>The number of failures.</returns>
67-
public int GetFailureCount()
68-
{
69-
return this.errors.Count;
70-
}
64+
public int FailureCount => this.errors.Count;
7165

7266
/// <summary>
7367
/// Gets a list of errors encountered while executing the topic management operation.
7468
/// </summary>
7569
/// <returns>A non-null list.</returns>
76-
public IReadOnlyList<Error> GetErrors()
77-
{
78-
return this.errors;
79-
}
70+
public IReadOnlyList<Error> Errors => this.errors;
8071

8172
/// <summary>
8273
/// A topic management error.

0 commit comments

Comments
 (0)