Skip to content

Commit 926d6e1

Browse files
Aschenscottinet
authored andcommitted
Unit tests kuzzle class (#17)
## What does this PR do ? :warning: Do not merge this PR, I based the PR on the previous branch for better diff readability Adds unit tests for Kuzzle class ### How should this be manually tested? - Step 1 : Run `dotnet test` ### Other changes - Change some methods or attribute visibility to `internal`
1 parent 6372c3b commit 926d6e1

File tree

3 files changed

+229
-4
lines changed

3 files changed

+229
-4
lines changed

Kuzzle.Tests/KuzzleTest.cs

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
using Xunit;
2+
using Newtonsoft.Json.Linq;
3+
using KuzzleSdk.Exceptions;
4+
using KuzzleSdk.Protocol;
5+
using KuzzleSdk.API;
6+
using KuzzleSdk.API.Controllers;
7+
using System;
8+
using System.Threading.Tasks;
9+
using Moq;
10+
11+
namespace Kuzzle.Tests {
12+
public class KuzzleTest {
13+
private readonly KuzzleSdk.Kuzzle _kuzzle;
14+
private readonly Mock<AbstractProtocol> _protocol;
15+
16+
public KuzzleTest() {
17+
_protocol = new Mock<AbstractProtocol>();
18+
_kuzzle = new KuzzleSdk.Kuzzle(_protocol.Object);
19+
}
20+
21+
[Fact]
22+
public void DispatchTokenExpiredTest() {
23+
_kuzzle.AuthenticationToken = "token";
24+
bool eventDispatched = false;
25+
_kuzzle.TokenExpired += delegate() {
26+
eventDispatched = true;
27+
};
28+
29+
_kuzzle.DispatchTokenExpired();
30+
31+
Assert.Null(_kuzzle.AuthenticationToken);
32+
Assert.True(eventDispatched);
33+
}
34+
35+
[Fact]
36+
public void KuzzleConstructorTest() {
37+
KuzzleSdk.Kuzzle kuzzle2 = new KuzzleSdk.Kuzzle(_protocol.Object);
38+
39+
Assert.IsType<AuthController>(_kuzzle.Auth);
40+
Assert.IsType<CollectionController>(_kuzzle.Collection);
41+
Assert.IsType<DocumentController>(_kuzzle.Document);
42+
Assert.IsType<RealtimeController>(_kuzzle.Realtime);
43+
Assert.IsType<ServerController>(_kuzzle.Server);
44+
Assert.NotEqual(_kuzzle.InstanceId, kuzzle2.InstanceId);
45+
}
46+
47+
[Fact]
48+
public async void ConnectAsyncTest() {
49+
await _kuzzle.ConnectAsync();
50+
51+
_protocol.Verify(m => m.ConnectAsync(), Times.Once);
52+
}
53+
54+
[Fact]
55+
public void DisconnectTest() {
56+
_kuzzle.Disconnect();
57+
58+
_protocol.Verify(m => m.Disconnect(), Times.Once);
59+
}
60+
61+
62+
[Fact]
63+
public async void QueryAsyncNullTest() {
64+
JObject request = null;
65+
_protocol.Setup(protocol => protocol.Send(It.IsAny<JObject>()));
66+
67+
await Assert.ThrowsAsync<InternalException>(async () => {
68+
await _kuzzle.QueryAsync(request);
69+
});
70+
}
71+
72+
[Fact]
73+
public async void QueryAsyncWrongVolatileTest() {
74+
JObject request = new JObject {
75+
{ "volatile", "not a JObject" }
76+
};
77+
78+
_protocol.Setup(protocol => protocol.Send(It.IsAny<JObject>()));
79+
80+
await Assert.ThrowsAsync<InternalException>(async () => {
81+
await _kuzzle.QueryAsync(request);
82+
});
83+
}
84+
85+
[Fact]
86+
public void QueryAsyncTest() {
87+
JObject request = new JObject {
88+
{ "controller", "test" },
89+
{ "action", "testAction" }
90+
};
91+
_kuzzle.AuthenticationToken = "jwt auth token";
92+
_protocol.Setup(protocol => protocol.Send(It.IsAny<JObject>()));
93+
94+
_kuzzle.QueryAsync(request);
95+
96+
_protocol.Verify(
97+
protocol => protocol.Send(It.Is<JObject>(o => testSendArg(o))));
98+
99+
Assert.Single(_kuzzle.requests);
100+
}
101+
private bool testSendArg (JObject request) {
102+
Assert.Equal("test", request["controller"]);
103+
Assert.Equal("testAction", request["action"]);
104+
Assert.Equal("jwt auth token", request["jwt"]);
105+
Assert.Equal(request["volatile"], new JObject {
106+
{ "sdkVersion", _kuzzle.Version },
107+
{ "sdkInstanceId", _kuzzle.InstanceId }
108+
}, new JTokenEqualityComparer());
109+
110+
return true;
111+
}
112+
113+
[Fact]
114+
public async void ResponseListenerTest() {
115+
TaskCompletionSource<Response> responseTask =
116+
new TaskCompletionSource<Response>();
117+
string requestId = "uniq-id";
118+
JObject apiResponse = new JObject {
119+
{ "requestId", requestId },
120+
{ "room", requestId },
121+
{ "status", 200 },
122+
{ "result", "i am the result" }
123+
};
124+
_kuzzle.requests[requestId] = responseTask;
125+
126+
_kuzzle.ResponsesListener(_kuzzle, apiResponse.ToString());
127+
Response response = await responseTask.Task;
128+
129+
Assert.False(_kuzzle.requests.ContainsKey(requestId));
130+
Assert.Equal("i am the result", response.Result);
131+
Assert.Equal(200, response.Status);
132+
}
133+
134+
[Fact]
135+
public async void ResponseListenerTokenExpiredTest() {
136+
bool eventDispatched = false;
137+
_kuzzle.TokenExpired += delegate() {
138+
eventDispatched = true;
139+
};
140+
TaskCompletionSource<Response> responseTask =
141+
new TaskCompletionSource<Response>();
142+
string requestId = "uniq-id";
143+
JObject apiResponse = new JObject {
144+
{ "requestId", requestId },
145+
{ "room", requestId },
146+
{ "status", 401 },
147+
{ "error", new JObject {
148+
{ "message", "Token expired"}
149+
}}
150+
};
151+
_kuzzle.requests[requestId] = responseTask;
152+
153+
154+
_kuzzle.ResponsesListener(_kuzzle, apiResponse.ToString());
155+
ApiErrorException ex =
156+
await Assert.ThrowsAsync<ApiErrorException>(async () => {
157+
await responseTask.Task;
158+
});
159+
160+
Assert.True(eventDispatched);
161+
Assert.Equal(401, ex.Status);
162+
Assert.Equal("Token expired", ex.Message);
163+
}
164+
165+
[Fact]
166+
public void ResponseListenerUnhandledTest() {
167+
bool eventDispatched = false;
168+
_kuzzle.UnhandledResponse += delegate(object sender, Response response) {
169+
eventDispatched = true;
170+
171+
Assert.Equal("i am the result", response.Result);
172+
};
173+
string requestId = "uniq-id";
174+
JObject apiResponse = new JObject {
175+
{ "requestId", requestId },
176+
{ "room", requestId },
177+
{ "status", 200 },
178+
{ "result", "i am the result" }
179+
};
180+
181+
_kuzzle.ResponsesListener(_kuzzle, apiResponse.ToString());
182+
183+
Assert.True(eventDispatched);
184+
}
185+
186+
[Fact]
187+
public async void StateChangeListenerTest () {
188+
TaskCompletionSource<Response> responseTask1 =
189+
new TaskCompletionSource<Response>();
190+
TaskCompletionSource<Response> responseTask2 =
191+
new TaskCompletionSource<Response>();
192+
_kuzzle.requests["request-id-1"] = responseTask1;
193+
_kuzzle.requests["request-id-2"] = responseTask2;
194+
195+
_kuzzle.StateChangeListener(_kuzzle, ProtocolState.Closed);
196+
197+
await Assert.ThrowsAsync<ConnectionLostException>(async () => {
198+
await responseTask1.Task;
199+
});
200+
await Assert.ThrowsAsync<ConnectionLostException>(async () => {
201+
await responseTask2.Task;
202+
});
203+
Assert.Empty(_kuzzle.requests.Keys);
204+
}
205+
}
206+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
namespace KuzzleSdk.Exceptions {
2+
/// <summary>
3+
/// Passed to async tasks when an API request returns an error.
4+
/// </summary>
5+
public class InternalException : KuzzleException {
6+
/// <summary>
7+
/// Initializes a new instance of the <see cref="T:Kuzzle.Exceptions.Internal"/> class
8+
/// </summary>
9+
/// <param name="response">Kuzzle API Response.</param>
10+
public InternalException(string message, int status)
11+
: base(message, status) {
12+
}
13+
}
14+
}

Kuzzle/Kuzzle.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public interface IKuzzleApi {
5959
public sealed class Kuzzle : IKuzzleApi {
6060
private AbstractProtocol networkProtocol;
6161

62-
private readonly Dictionary<string, TaskCompletionSource<Response>>
62+
internal readonly Dictionary<string, TaskCompletionSource<Response>>
6363
requests = new Dictionary<string, TaskCompletionSource<Response>>();
6464

6565
// General informations
@@ -151,7 +151,7 @@ public AbstractProtocol NetworkProtocol {
151151
/// </summary>
152152
/// <param name="sender">Network Protocol instance</param>
153153
/// <param name="payload">raw API Response</param>
154-
private void ResponsesListener(object sender, string payload) {
154+
internal void ResponsesListener(object sender, string payload) {
155155
Response response = Response.FromString(payload);
156156

157157
if (requests.ContainsKey(response.Room)) {
@@ -174,7 +174,7 @@ private void ResponsesListener(object sender, string payload) {
174174
}
175175
}
176176

177-
private void StateChangeListener(object sender, ProtocolState state) {
177+
internal void StateChangeListener(object sender, ProtocolState state) {
178178
// If not connected anymore: close tasks and clean up the requests buffer
179179
if (state == ProtocolState.Closed) {
180180
lock (requests) {
@@ -244,6 +244,10 @@ public void Disconnect() {
244244
/// <returns>API response</returns>
245245
/// <param name="query">Kuzzle API query</param>
246246
public Task<Response> QueryAsync(JObject query) {
247+
if (query == null){
248+
throw new Exceptions.InternalException("You must provide a query", 400);
249+
}
250+
247251
if (NetworkProtocol.State != ProtocolState.Open) {
248252
throw new Exceptions.NotConnectedException();
249253
}
@@ -255,9 +259,10 @@ public Task<Response> QueryAsync(JObject query) {
255259
string requestId = Guid.NewGuid().ToString();
256260
query["requestId"] = requestId;
257261

258-
// Injecting SDK version + instance ID
259262
if (query["volatile"] == null) {
260263
query["volatile"] = new JObject();
264+
} else if (!(query["volatile"] is JObject)) {
265+
throw new Exceptions.InternalException("Volatile data must be a JObject", 400);
261266
}
262267

263268
query["volatile"]["sdkVersion"] = Version;

0 commit comments

Comments
 (0)