Skip to content

Commit 78714da

Browse files
authored
Merge pull request #94 from dataglotlimited/master
Implementation of InstanceIdClient to allow subscribe/unsubscribe to topic
2 parents 60f5a2b + ea9e351 commit 78714da

File tree

9 files changed

+713
-0
lines changed

9 files changed

+713
-0
lines changed

FirebaseAdmin/FirebaseAdmin.IntegrationTests/FirebaseMessagingTest.cs

Lines changed: 25 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,29 @@ 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+
Assert.Equal("invalid-argument", response.Errors[0].Reason);
132+
Assert.Equal(0, response.Errors[0].Index);
133+
Assert.Equal("invalid-argument", response.Errors[1].Reason);
134+
Assert.Equal(1, response.Errors[1].Index);
135+
}
136+
137+
[Fact]
138+
public async Task UnsubscribeFromTopic()
139+
{
140+
var response = await FirebaseMessaging.DefaultInstance.UnsubscribeFromTopicAsync("test-topic", new List<string> { "token1", "token2" });
141+
Assert.NotNull(response);
142+
Assert.Equal(2, response.FailureCount);
143+
Assert.Equal("invalid-argument", response.Errors[0].Reason);
144+
Assert.Equal(0, response.Errors[0].Index);
145+
Assert.Equal("invalid-argument", response.Errors[1].Reason);
146+
Assert.Equal(1, response.Errors[1].Index);
147+
}
123148
}
124149
}

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();
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Net;
4+
using System.Threading.Tasks;
5+
using FirebaseAdmin.Messaging;
6+
using Google.Apis.Auth.OAuth2;
7+
using Google.Apis.Http;
8+
using Xunit;
9+
10+
namespace FirebaseAdmin.Tests.Messaging
11+
{
12+
public class InstanceIdClientTest
13+
{
14+
private static readonly GoogleCredential MockCredential =
15+
GoogleCredential.FromAccessToken("test-token");
16+
17+
[Fact]
18+
public void NoCredential()
19+
{
20+
var clientFactory = new HttpClientFactory();
21+
Assert.Throws<ArgumentNullException>(
22+
() => new InstanceIdClient(clientFactory, null));
23+
}
24+
25+
[Fact]
26+
public void NoClientFactory()
27+
{
28+
var clientFactory = new HttpClientFactory();
29+
Assert.Throws<ArgumentNullException>(
30+
() => new InstanceIdClient(null, MockCredential));
31+
}
32+
33+
[Fact]
34+
public async Task SubscribeToTopicAsync()
35+
{
36+
var handler = new MockMessageHandler()
37+
{
38+
Response = @"{""results"":[{}]}",
39+
};
40+
var factory = new MockHttpClientFactory(handler);
41+
42+
var client = new InstanceIdClient(factory, MockCredential);
43+
44+
var result = await client.SubscribeToTopicAsync("test-topic", new List<string> { "abc123" });
45+
46+
Assert.Equal(1, result.SuccessCount);
47+
}
48+
49+
[Fact]
50+
public async Task UnsubscribeFromTopicAsync()
51+
{
52+
var handler = new MockMessageHandler()
53+
{
54+
Response = @"{""results"":[{}]}",
55+
};
56+
var factory = new MockHttpClientFactory(handler);
57+
58+
var client = new InstanceIdClient(factory, MockCredential);
59+
60+
var result = await client.UnsubscribeFromTopicAsync("test-topic", new List<string> { "abc123" });
61+
62+
Assert.Equal(1, result.SuccessCount);
63+
}
64+
65+
[Fact]
66+
public async Task BadRequest()
67+
{
68+
var handler = new MockMessageHandler()
69+
{
70+
StatusCode = HttpStatusCode.BadRequest,
71+
Response = "BadRequest",
72+
};
73+
var factory = new MockHttpClientFactory(handler);
74+
75+
var client = new InstanceIdClient(factory, MockCredential);
76+
77+
var exception = await Assert.ThrowsAsync<FirebaseMessagingException>(
78+
() => client.SubscribeToTopicAsync("test-topic", new List<string> { "abc123" }));
79+
80+
Assert.Equal(ErrorCode.InvalidArgument, exception.ErrorCode);
81+
Assert.Equal("Unexpected HTTP response with status: 400 (BadRequest)\nBadRequest", exception.Message);
82+
Assert.Null(exception.MessagingErrorCode);
83+
Assert.NotNull(exception.HttpResponse);
84+
Assert.Null(exception.InnerException);
85+
}
86+
87+
[Fact]
88+
public async Task Unauthorized()
89+
{
90+
var handler = new MockMessageHandler()
91+
{
92+
StatusCode = HttpStatusCode.Unauthorized,
93+
Response = "Unauthorized",
94+
};
95+
var factory = new MockHttpClientFactory(handler);
96+
97+
var client = new InstanceIdClient(factory, MockCredential);
98+
99+
var exception = await Assert.ThrowsAsync<FirebaseMessagingException>(
100+
() => client.SubscribeToTopicAsync("test-topic", new List<string> { "abc123" }));
101+
102+
Assert.Equal(ErrorCode.Unauthenticated, exception.ErrorCode);
103+
Assert.Equal("Unexpected HTTP response with status: 401 (Unauthorized)\nUnauthorized", exception.Message);
104+
Assert.Null(exception.MessagingErrorCode);
105+
Assert.NotNull(exception.HttpResponse);
106+
Assert.Null(exception.InnerException);
107+
}
108+
109+
[Fact]
110+
public async Task Forbidden()
111+
{
112+
var handler = new MockMessageHandler()
113+
{
114+
StatusCode = HttpStatusCode.Forbidden,
115+
Response = "Forbidden",
116+
};
117+
var factory = new MockHttpClientFactory(handler);
118+
119+
var client = new InstanceIdClient(factory, MockCredential);
120+
121+
var exception = await Assert.ThrowsAsync<FirebaseMessagingException>(
122+
() => client.SubscribeToTopicAsync("test-topic", new List<string> { "abc123" }));
123+
124+
Assert.Equal(ErrorCode.PermissionDenied, exception.ErrorCode);
125+
Assert.Equal("Unexpected HTTP response with status: 403 (Forbidden)\nForbidden", exception.Message);
126+
Assert.Null(exception.MessagingErrorCode);
127+
Assert.NotNull(exception.HttpResponse);
128+
Assert.Null(exception.InnerException);
129+
}
130+
131+
[Fact]
132+
public async Task NotFound()
133+
{
134+
var handler = new MockMessageHandler()
135+
{
136+
StatusCode = HttpStatusCode.NotFound,
137+
Response = "NotFound",
138+
};
139+
var factory = new MockHttpClientFactory(handler);
140+
141+
var client = new InstanceIdClient(factory, MockCredential);
142+
143+
var exception = await Assert.ThrowsAsync<FirebaseMessagingException>(
144+
() => client.SubscribeToTopicAsync("test-topic", new List<string> { "abc123" }));
145+
146+
Assert.Equal(ErrorCode.NotFound, exception.ErrorCode);
147+
Assert.Equal("Unexpected HTTP response with status: 404 (NotFound)\nNotFound", exception.Message);
148+
Assert.Null(exception.MessagingErrorCode);
149+
Assert.NotNull(exception.HttpResponse);
150+
Assert.Null(exception.InnerException);
151+
}
152+
153+
[Fact]
154+
public async Task ServiceUnavailable()
155+
{
156+
var handler = new MockMessageHandler()
157+
{
158+
StatusCode = HttpStatusCode.ServiceUnavailable,
159+
Response = "ServiceUnavailable",
160+
};
161+
var factory = new MockHttpClientFactory(handler);
162+
163+
var client = new InstanceIdClient(factory, MockCredential);
164+
165+
var exception = await Assert.ThrowsAsync<FirebaseMessagingException>(
166+
() => client.SubscribeToTopicAsync("test-topic", new List<string> { "abc123" }));
167+
168+
Assert.Equal(ErrorCode.Unavailable, exception.ErrorCode);
169+
Assert.Equal("Unexpected HTTP response with status: 503 (ServiceUnavailable)\nServiceUnavailable", exception.Message);
170+
Assert.Null(exception.MessagingErrorCode);
171+
Assert.NotNull(exception.HttpResponse);
172+
Assert.Null(exception.InnerException);
173+
}
174+
}
175+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using FirebaseAdmin.Messaging;
4+
using Newtonsoft.Json;
5+
using Xunit;
6+
7+
namespace FirebaseAdmin.Tests.Messaging
8+
{
9+
public class TopicManagementResponseTest
10+
{
11+
[Fact]
12+
public void SuccessfulReponse()
13+
{
14+
var json = @"{""results"": [{}, {}]}";
15+
var instanceIdServiceResponse = JsonConvert.DeserializeObject<InstanceIdServiceResponse>(json);
16+
var response = new TopicManagementResponse(instanceIdServiceResponse);
17+
18+
Assert.Equal(0, response.FailureCount);
19+
Assert.Equal(2, response.SuccessCount);
20+
}
21+
22+
[Fact]
23+
public void UnsuccessfulResponse()
24+
{
25+
var json = @"{""results"": [{}, {""error"":""NOT_FOUND""}]}";
26+
var instanceIdServiceResponse = JsonConvert.DeserializeObject<InstanceIdServiceResponse>(json);
27+
var response = new TopicManagementResponse(instanceIdServiceResponse);
28+
29+
Assert.Equal(1, response.FailureCount);
30+
Assert.Equal(1, response.SuccessCount);
31+
Assert.NotEmpty(response.Errors);
32+
Assert.Equal("registration-token-not-registered", response.Errors[0].Reason);
33+
Assert.Equal(1, response.Errors[0].Index);
34+
}
35+
36+
[Fact]
37+
public void NullResponse()
38+
{
39+
Assert.Throws<ArgumentNullException>(() =>
40+
{
41+
new TopicManagementResponse(null);
42+
});
43+
}
44+
45+
[Fact]
46+
public void EmptyResponse()
47+
{
48+
Assert.Throws<ArgumentNullException>(() =>
49+
{
50+
var instanceIdServiceResponse = new InstanceIdServiceResponse();
51+
new TopicManagementResponse(instanceIdServiceResponse);
52+
});
53+
}
54+
55+
[Fact]
56+
public void UnregisteredToken()
57+
{
58+
var json = @"{""results"": [{}, {""error"":""NOT_FOUND""}]}";
59+
var instanceIdServiceResponse = JsonConvert.DeserializeObject<InstanceIdServiceResponse>(json);
60+
var response = new TopicManagementResponse(instanceIdServiceResponse);
61+
62+
Assert.Single(response.Errors);
63+
Assert.Equal("registration-token-not-registered", response.Errors[0].Reason);
64+
Assert.Equal(1, response.Errors[0].Index);
65+
}
66+
67+
[Fact]
68+
public void CountsSuccessAndErrors()
69+
{
70+
var json = @"{""results"": [{""error"": ""NOT_FOUND""}, {}, {""error"": ""INVALID_ARGUMENT""}, {}, {}]}";
71+
var instanceIdServiceResponse = JsonConvert.DeserializeObject<InstanceIdServiceResponse>(json);
72+
var response = new TopicManagementResponse(instanceIdServiceResponse);
73+
74+
Assert.Equal(2, response.FailureCount);
75+
Assert.Equal(3, response.SuccessCount);
76+
Assert.Equal("registration-token-not-registered", response.Errors[0].Reason);
77+
Assert.NotEmpty(response.Errors);
78+
Assert.Equal(0, response.Errors[0].Index);
79+
Assert.Equal("invalid-argument", response.Errors[1].Reason);
80+
Assert.Equal(2, response.Errors[1].Index);
81+
}
82+
}
83+
}

0 commit comments

Comments
 (0)