LEFT | RIGHT |
1 /* | 1 /* |
2 Copyright 2013 Google Inc | 2 Copyright 2013 Google Inc |
3 | 3 |
4 Licensed under the Apache License, Version 2.0 (the "License"); | 4 Licensed under the Apache License, Version 2.0 (the "License"); |
5 you may not use this file except in compliance with the License. | 5 you may not use this file except in compliance with the License. |
6 You may obtain a copy of the License at | 6 You may obtain a copy of the License at |
7 | 7 |
8 http://www.apache.org/licenses/LICENSE-2.0 | 8 http://www.apache.org/licenses/LICENSE-2.0 |
9 | 9 |
10 Unless required by applicable law or agreed to in writing, software | 10 Unless required by applicable law or agreed to in writing, software |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
50 { | 50 { |
51 // ClientSecrets are missing. | 51 // ClientSecrets are missing. |
52 try | 52 try |
53 { | 53 { |
54 new AuthorizationCodeFlow(new AuthorizationCodeFlow.Initializer( | 54 new AuthorizationCodeFlow(new AuthorizationCodeFlow.Initializer( |
55 "https://authorization_code.com", "https://token.com")); | 55 "https://authorization_code.com", "https://token.com")); |
56 Assert.Fail(); | 56 Assert.Fail(); |
57 } | 57 } |
58 catch (ArgumentException ex) | 58 catch (ArgumentException ex) |
59 { | 59 { |
60 Assert.True(ex.Message.Contains("client secret or client secret
stream MUST be set"), | 60 Assert.True(ex.Message.Contains("You MUST set ClientSecret or Cl
ientSecretStream")); |
61 "User MUST specify client secrets!"); | |
62 } | 61 } |
63 } | 62 } |
64 | 63 |
65 [Test] | 64 [Test] |
66 public void TestConstructor_DefaultValues() | 65 public void TestConstructor_DefaultValues() |
67 { | 66 { |
68 var flow = CreateFlow(); | 67 var flow = CreateFlow(); |
69 Assert.NotNull(flow.AccessMethod); | 68 Assert.NotNull(flow.AccessMethod); |
70 Assert.That(flow.AccessMethod, Is.InstanceOf<BearerToken.Authorizati
onHeaderAccessMethod>()); | 69 Assert.That(flow.AccessMethod, Is.InstanceOf<BearerToken.Authorizati
onHeaderAccessMethod>()); |
71 Assert.That(flow.AuthorizationServerUrl, Is.EqualTo("https://authori
zation.com")); | 70 Assert.That(flow.AuthorizationServerUrl, Is.EqualTo("https://authori
zation.com")); |
72 Assert.NotNull(flow.ClientSecrets); | 71 Assert.NotNull(flow.ClientSecrets); |
73 Assert.That(flow.ClientSecrets.ClientId, Is.EqualTo("id")); | 72 Assert.That(flow.ClientSecrets.ClientId, Is.EqualTo("id")); |
74 Assert.That(flow.ClientSecrets.ClientSecret, Is.EqualTo("secret")); | 73 Assert.That(flow.ClientSecrets.ClientSecret, Is.EqualTo("secret")); |
75 Assert.That(flow.Clock, Is.InstanceOf<SystemClock>()); | 74 Assert.That(flow.Clock, Is.InstanceOf<SystemClock>()); |
76 Assert.Null(flow.DataStore); | 75 Assert.Null(flow.DataStore); |
77 Assert.NotNull(flow.HttpClient); | 76 Assert.NotNull(flow.HttpClient); |
78 Assert.NotNull(flow.Scopes); | 77 Assert.NotNull(flow.Scopes); |
79 Assert.That(flow.TokenServerEncodedUrl, Is.EqualTo("https://token.co
m")); | 78 Assert.That(flow.TokenServerUrl, Is.EqualTo("https://token.com")); |
80 | 79 |
81 Assert.That(flow.HttpClient.MessageHandler.UnsuccessfulResponseHandl
ers.Count(), Is.EqualTo(1)); | 80 Assert.That(flow.HttpClient.MessageHandler.UnsuccessfulResponseHandl
ers.Count(), Is.EqualTo(1)); |
82 Assert.That(flow.HttpClient.MessageHandler.UnsuccessfulResponseHandl
ers.First(), | 81 Assert.That(flow.HttpClient.MessageHandler.UnsuccessfulResponseHandl
ers.First(), |
83 Is.InstanceOf<BackOffHandler>()); | 82 Is.InstanceOf<BackOffHandler>()); |
84 } | 83 } |
85 | 84 |
86 #endregion | 85 #endregion |
87 | 86 |
88 #region LoadToken | 87 #region LoadToken |
89 | 88 |
90 [Test] | 89 [Test] |
91 public void LoadToken_NoDataStore() | 90 public void LoadTokenAsync_NoDataStore() |
92 { | 91 { |
93 var flow = CreateFlow(); | 92 var flow = CreateFlow(); |
94 Assert.Null(flow.LoadToken("user", CancellationToken.None).Result); | 93 Assert.Null(flow.LoadTokenAsync("user", CancellationToken.None).Resu
lt); |
95 } | 94 } |
96 | 95 |
97 [Test] | 96 [Test] |
98 public void LoadToken_NullResponse() | 97 public void LoadTokenAsync_NullResponse() |
99 { | 98 { |
100 TaskCompletionSource<TokenResponse> tcs = new TaskCompletionSource<T
okenResponse>(); | 99 TaskCompletionSource<TokenResponse> tcs = new TaskCompletionSource<T
okenResponse>(); |
101 tcs.SetResult(null); | 100 tcs.SetResult(null); |
102 Assert.Null(SubtestLoadToken(tcs)); | 101 Assert.Null(SubtestLoadTokenAsync(tcs)); |
103 } | 102 } |
104 | 103 |
105 [Test] | 104 [Test] |
106 public void LoadToken_TokenResponse() | 105 public void LoadTokenAsync_TokenResponse() |
107 { | 106 { |
108 TokenResponse response = new TokenResponse | 107 TokenResponse response = new TokenResponse |
109 { | 108 { |
110 AccessToken = "access" | 109 AccessToken = "access" |
111 }; | 110 }; |
112 | 111 |
113 TaskCompletionSource<TokenResponse> tcs = new TaskCompletionSource<T
okenResponse>(); | 112 TaskCompletionSource<TokenResponse> tcs = new TaskCompletionSource<T
okenResponse>(); |
114 tcs.SetResult(response); | 113 tcs.SetResult(response); |
115 var result = SubtestLoadToken(tcs); | 114 var result = SubtestLoadTokenAsync(tcs); |
116 Assert.That(result, Is.EqualTo(response)); | 115 Assert.That(result, Is.EqualTo(response)); |
117 } | 116 } |
118 | 117 |
119 private TokenResponse SubtestLoadToken(TaskCompletionSource<TokenRespons
e> tcs) | 118 private TokenResponse SubtestLoadTokenAsync(TaskCompletionSource<TokenRe
sponse> tcs) |
120 { | 119 { |
121 var mock = new Mock<IDataStore>(); | 120 var mock = new Mock<IDataStore>(); |
122 mock.Setup(ds => ds.Get<TokenResponse>("user")).Returns(tcs.Task); | 121 mock.Setup(ds => ds.GetAsync<TokenResponse>("user")).Returns(tcs.Tas
k); |
123 var flow = CreateFlow(dataStore: mock.Object); | 122 var flow = CreateFlow(dataStore: mock.Object); |
124 var result = flow.LoadToken("user", CancellationToken.None).Result; | 123 var result = flow.LoadTokenAsync("user", CancellationToken.None).Res
ult; |
125 // Verify Get("user") was called. | 124 mock.Verify(ds => ds.GetAsync<TokenResponse>("user")); |
126 mock.Verify(ds => ds.Get<TokenResponse>("user")); | |
127 return result; | 125 return result; |
128 } | 126 } |
129 | 127 |
130 #endregion | 128 #endregion |
131 | 129 |
132 #region CreateAuthorizationCodeRequest | 130 #region CreateAuthorizationCodeRequest |
133 | 131 |
134 [Test] | 132 [Test] |
135 public void TestCreateAuthorizationCodeRequest() | 133 public void TestCreateAuthorizationCodeRequest() |
136 { | 134 { |
137 var request = CreateFlow(scopes: new[] { "a", "b" }).CreateAuthoriza
tionCodeRequest("redirect"); | 135 var request = CreateFlow(scopes: new[] { "a", "b" }).CreateAuthoriza
tionCodeRequest("redirect"); |
138 Assert.That(request.AuthorizationServerUrl, Is.EqualTo(new Uri(Autho
rizationCodeUrl))); | 136 Assert.That(request.AuthorizationServerUrl, Is.EqualTo(new Uri(Autho
rizationCodeUrl))); |
139 Assert.That(request.ClientId, Is.EqualTo("id")); | 137 Assert.That(request.ClientId, Is.EqualTo("id")); |
140 Assert.That(request.RedirectUri, Is.EqualTo("redirect")); | 138 Assert.That(request.RedirectUri, Is.EqualTo("redirect")); |
141 Assert.That(request.ResponseType, Is.EqualTo("code")); | 139 Assert.That(request.ResponseType, Is.EqualTo("code")); |
142 Assert.That(request.Scope, Is.EqualTo("a b")); | 140 Assert.That(request.Scope, Is.EqualTo("a b")); |
143 Assert.Null(request.State); | 141 Assert.Null(request.State); |
144 } | 142 } |
145 | 143 |
146 #endregion | 144 #endregion |
147 | 145 |
148 [Test] | 146 [Test] |
149 public void TestExchangeCodeForToken() | 147 public void TestExchangeCodeForTokenAsync() |
150 { | 148 { |
151 var mock = new Mock<IDataStore>(); | 149 var mock = new Mock<IDataStore>(); |
152 var handler = new FetchTokenMessageHandler(); | 150 var handler = new FetchTokenMessageHandler(); |
153 handler.AuthorizationCodeTokenRequest = new AuthorizationCodeTokenRe
quest() | 151 handler.AuthorizationCodeTokenRequest = new AuthorizationCodeTokenRe
quest() |
154 { | 152 { |
155 Code = "c0de", | 153 Code = "c0de", |
156 RedirectUri = "redIrect", | 154 RedirectUri = "redIrect", |
157 Scope = "a" | 155 Scope = "a" |
158 }; | 156 }; |
159 MockHttpClientFactory mockFactory = new MockHttpClientFactory(handle
r); | 157 MockHttpClientFactory mockFactory = new MockHttpClientFactory(handle
r); |
160 | 158 |
161 TaskCompletionSource<object> tcs = new TaskCompletionSource<object>(
); | 159 TaskCompletionSource<object> tcs = new TaskCompletionSource<object>(
); |
162 tcs.SetResult(null); | 160 tcs.SetResult(null); |
163 mock.Setup(ds => ds.Store("uSer", It.IsAny<TokenResponse>())).Return
s(tcs.Task); | 161 mock.Setup(ds => ds.StoreAsync("uSer", It.IsAny<TokenResponse>())).R
eturns(tcs.Task); |
164 | 162 |
165 var flow = CreateFlow(httpClientFactory: mockFactory, scopes: new[]
{ "a" }, dataStore: mock.Object); | 163 var flow = CreateFlow(httpClientFactory: mockFactory, scopes: new[]
{ "a" }, dataStore: mock.Object); |
166 var response = flow.ExchangeCodeForToken("uSer", "c0de", "redIrect",
CancellationToken.None).Result; | 164 var response = flow.ExchangeCodeForTokenAsync("uSer", "c0de", "redIr
ect", CancellationToken.None).Result; |
167 SubtestTokenResponse(response); | 165 SubtestTokenResponse(response); |
168 | 166 |
169 mock.Verify(ds => ds.Store("uSer", It.IsAny<TokenResponse>())); | 167 mock.Verify(ds => ds.StoreAsync("uSer", It.IsAny<TokenResponse>())); |
170 } | 168 } |
171 | 169 |
172 [Test] | 170 [Test] |
173 public void TestRefreshToken() | 171 public void TestRefreshTokenAsync() |
174 { | 172 { |
175 var mock = new Mock<IDataStore>(); | 173 var mock = new Mock<IDataStore>(); |
176 var handler = new FetchTokenMessageHandler(); | 174 var handler = new FetchTokenMessageHandler(); |
177 handler.RefreshTokenRequest = new RefreshTokenRequest() | 175 handler.RefreshTokenRequest = new RefreshTokenRequest() |
178 { | 176 { |
179 RefreshToken = "REFRESH", | 177 RefreshToken = "REFRESH", |
180 Scope = "a" | 178 Scope = "a" |
181 }; | 179 }; |
182 MockHttpClientFactory mockFactory = new MockHttpClientFactory(handle
r); | 180 MockHttpClientFactory mockFactory = new MockHttpClientFactory(handle
r); |
183 | 181 |
184 TaskCompletionSource<object> tcs = new TaskCompletionSource<object>(
); | 182 TaskCompletionSource<object> tcs = new TaskCompletionSource<object>(
); |
185 tcs.SetResult(null); | 183 tcs.SetResult(null); |
186 mock.Setup(ds => ds.Store("uSer", It.IsAny<TokenResponse>())).Return
s(tcs.Task); | 184 mock.Setup(ds => ds.StoreAsync("uSer", It.IsAny<TokenResponse>())).R
eturns(tcs.Task); |
187 | 185 |
188 var flow = CreateFlow(httpClientFactory: mockFactory, scopes: new[]
{ "a" }, dataStore: mock.Object); | 186 var flow = CreateFlow(httpClientFactory: mockFactory, scopes: new[]
{ "a" }, dataStore: mock.Object); |
189 var response = flow.RefreshToken("uSer", "REFRESH", CancellationToke
n.None).Result; | 187 var response = flow.RefreshTokenAsync("uSer", "REFRESH", Cancellatio
nToken.None).Result; |
190 SubtestTokenResponse(response); | 188 SubtestTokenResponse(response); |
191 | 189 |
192 | 190 |
193 mock.Verify(ds => ds.Store("uSer", It.IsAny<TokenResponse>())); | 191 mock.Verify(ds => ds.StoreAsync("uSer", It.IsAny<TokenResponse>())); |
194 } | 192 } |
195 | 193 |
196 #region FetchToken | 194 #region FetchToken |
197 | 195 |
198 /// <summary> | 196 /// <summary> |
199 /// Fetch token message handler, which expects an authorization code tok
en request or a refresh token request. | 197 /// Fetch token message handler, which expects an authorization code tok
en request or a refresh token request. |
200 /// It verifies all the query parameters are valid and return an error r
esponse in case <see cref="Error"/>· | 198 /// It verifies all the query parameters are valid and return an error r
esponse in case <see cref="Error"/>· |
201 /// is <c>true</c>. | 199 /// is <c>true</c>. |
202 /// </summary> | 200 /// </summary> |
203 public class FetchTokenMessageHandler : CountableMessageHandler | 201 public class FetchTokenMessageHandler : CountableMessageHandler |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
295 Scope = "b", | 293 Scope = "b", |
296 }); | 294 }); |
297 response.Content = new StringContent(serializedObject, Encod
ing.UTF8); | 295 response.Content = new StringContent(serializedObject, Encod
ing.UTF8); |
298 } | 296 } |
299 | 297 |
300 return response; | 298 return response; |
301 } | 299 } |
302 } | 300 } |
303 | 301 |
304 [Test] | 302 [Test] |
305 public void TestFetchToken_AuthorizationCodeRequest() | 303 public void TestFetchTokenAsync_AuthorizationCodeRequest() |
306 { | 304 { |
307 var handler = new FetchTokenMessageHandler(); | 305 var handler = new FetchTokenMessageHandler(); |
308 handler.AuthorizationCodeTokenRequest = new AuthorizationCodeTokenRe
quest() | 306 handler.AuthorizationCodeTokenRequest = new AuthorizationCodeTokenRe
quest() |
309 { | 307 { |
310 Code = "c0de", | 308 Code = "c0de", |
311 RedirectUri = "redIrect", | 309 RedirectUri = "redIrect", |
312 Scope = "a" | 310 Scope = "a" |
313 }; | 311 }; |
314 MockHttpClientFactory mockFactory = new MockHttpClientFactory(handle
r); | 312 MockHttpClientFactory mockFactory = new MockHttpClientFactory(handle
r); |
315 | 313 |
316 var flow = CreateFlow(httpClientFactory: mockFactory); | 314 var flow = CreateFlow(httpClientFactory: mockFactory); |
317 var response = flow.FetchToken("user", handler.AuthorizationCodeToke
nRequest, | 315 var response = flow.FetchTokenAsync("user", handler.AuthorizationCod
eTokenRequest, |
318 CancellationToken.None).Result; | 316 CancellationToken.None).Result; |
319 SubtestTokenResponse(response); | 317 SubtestTokenResponse(response); |
320 } | 318 } |
321 | 319 |
322 [Test] | 320 [Test] |
323 public void TestFetchToken_RefreshTokenRequest() | 321 public void TestFetchTokenAsync_RefreshTokenRequest() |
324 { | 322 { |
325 var handler = new FetchTokenMessageHandler(); | 323 var handler = new FetchTokenMessageHandler(); |
326 handler.RefreshTokenRequest = new RefreshTokenRequest() | 324 handler.RefreshTokenRequest = new RefreshTokenRequest() |
327 { | 325 { |
328 RefreshToken = "REFRESH", | 326 RefreshToken = "REFRESH", |
329 Scope = "a" | 327 Scope = "a" |
330 }; | 328 }; |
331 | 329 |
332 MockHttpClientFactory mockFactory = new MockHttpClientFactory(handle
r); | 330 MockHttpClientFactory mockFactory = new MockHttpClientFactory(handle
r); |
333 | 331 |
334 var flow = CreateFlow(httpClientFactory: mockFactory); | 332 var flow = CreateFlow(httpClientFactory: mockFactory); |
335 var response = flow.FetchToken("user", handler.RefreshTokenRequest,
CancellationToken.None).Result; | 333 var response = flow.FetchTokenAsync("user", handler.RefreshTokenRequ
est, CancellationToken.None).Result; |
336 SubtestTokenResponse(response); | 334 SubtestTokenResponse(response); |
337 } | 335 } |
338 | 336 |
339 [Test] | 337 [Test] |
340 public void TestFetchToken_AuthorizationCodeRequest_Error() | 338 public void TestFetchTokenAsync_AuthorizationCodeRequest_Error() |
341 { | 339 { |
342 var handler = new FetchTokenMessageHandler(); | 340 var handler = new FetchTokenMessageHandler(); |
343 handler.AuthorizationCodeTokenRequest = new AuthorizationCodeTokenRe
quest() | 341 handler.AuthorizationCodeTokenRequest = new AuthorizationCodeTokenRe
quest() |
344 { | 342 { |
345 Code = "c0de", | 343 Code = "c0de", |
346 RedirectUri = "redIrect", | 344 RedirectUri = "redIrect", |
347 Scope = "a" | 345 Scope = "a" |
348 }; | 346 }; |
349 handler.Error = true; | 347 handler.Error = true; |
350 SubtestFetchToken_Error(handler); | 348 SubtestFetchTokenAsync_Error(handler); |
351 } | 349 } |
352 | 350 |
353 [Test] | 351 [Test] |
354 public void TestFetchToken_RefreshTokenRequest_Error() | 352 public void TestFetchTokenAsync_RefreshTokenRequest_Error() |
355 { | 353 { |
356 var handler = new FetchTokenMessageHandler(); | 354 var handler = new FetchTokenMessageHandler(); |
357 handler.RefreshTokenRequest = new RefreshTokenRequest() | 355 handler.RefreshTokenRequest = new RefreshTokenRequest() |
358 { | 356 { |
359 RefreshToken = "REFRESH", | 357 RefreshToken = "REFRESH", |
360 Scope = "a" | 358 Scope = "a" |
361 }; | 359 }; |
362 handler.Error = true; | 360 handler.Error = true; |
363 SubtestFetchToken_Error(handler); | 361 SubtestFetchTokenAsync_Error(handler); |
364 } | 362 } |
365 | 363 |
366 /// <summary>Subtest for receiving an error token response.</summary> | 364 /// <summary>Subtest for receiving an error token response.</summary> |
367 /// <param name="handler">The message handler</param> | 365 /// <param name="handler">The message handler.</param> |
368 private void SubtestFetchToken_Error(FetchTokenMessageHandler handler) | 366 private void SubtestFetchTokenAsync_Error(FetchTokenMessageHandler handl
er) |
369 { | 367 { |
370 MockHttpClientFactory mockFactory = new MockHttpClientFactory(handle
r); | 368 MockHttpClientFactory mockFactory = new MockHttpClientFactory(handle
r); |
371 var flow = CreateFlow(httpClientFactory: mockFactory); | 369 var flow = CreateFlow(httpClientFactory: mockFactory); |
372 try | 370 try |
373 { | 371 { |
374 var request = | 372 var request = |
375 (TokenRequest)handler.AuthorizationCodeTokenRequest ?? (Toke
nRequest)handler.RefreshTokenRequest; | 373 (TokenRequest)handler.AuthorizationCodeTokenRequest ?? (Toke
nRequest)handler.RefreshTokenRequest; |
376 var result = flow.FetchToken("user", request, CancellationToken.
None).Result; | 374 var result = flow.FetchTokenAsync("user", request, CancellationT
oken.None).Result; |
377 Assert.Fail(); | 375 Assert.Fail(); |
378 } | 376 } |
379 catch (AggregateException aex) | 377 catch (AggregateException aex) |
380 { | 378 { |
381 var ex = aex.InnerException as TokenResponseException; | 379 var ex = aex.InnerException as TokenResponseException; |
382 Assert.IsNotNull(ex); | 380 Assert.IsNotNull(ex); |
383 var result = ex.Error; | 381 var result = ex.Error; |
384 Assert.That(result.Error, Is.EqualTo("error")); | 382 Assert.That(result.Error, Is.EqualTo("error")); |
385 Assert.That(result.ErrorDescription, Is.EqualTo("desc")); | 383 Assert.That(result.ErrorDescription, Is.EqualTo("desc")); |
386 Assert.That(result.ErrorUri, Is.EqualTo("uri")); | 384 Assert.That(result.ErrorUri, Is.EqualTo("uri")); |
387 } | 385 } |
388 } | 386 } |
389 | 387 |
390 #endregion | 388 #endregion |
391 | 389 |
392 /// <summary>Creates an authorization code flow with the given parameter
s.</summary> | 390 /// <summary>Creates an authorization code flow with the given parameter
s.</summary> |
393 /// <param name="dataStore">The data store.</param> | 391 /// <param name="dataStore">The data store.</param> |
394 /// <param name="scopes">The Scopes</param> | 392 /// <param name="scopes">The Scopes.</param> |
395 /// <param name="httpClientFactory">The HTTP client factory. If not set
the default will be used</param> | 393 /// <param name="httpClientFactory">The HTTP client factory. If not set
the default will be used.</param> |
396 /// <returns>Authorization code flow</returns> | 394 /// <returns>Authorization code flow</returns> |
397 private AuthorizationCodeFlow CreateFlow(IDataStore dataStore = null, IE
numerable<string> scopes = null, | 395 private AuthorizationCodeFlow CreateFlow(IDataStore dataStore = null, IE
numerable<string> scopes = null, |
398 IHttpClientFactory httpClientFactory = null) | 396 IHttpClientFactory httpClientFactory = null) |
399 { | 397 { |
400 var secrets = new ClientSecrets() { ClientId = "id", ClientSecret =
"secret" }; | 398 var secrets = new ClientSecrets() { ClientId = "id", ClientSecret =
"secret" }; |
401 var initializer = new AuthorizationCodeFlow.Initializer(Authorizatio
nCodeUrl, TokenUrl) | 399 var initializer = new AuthorizationCodeFlow.Initializer(Authorizatio
nCodeUrl, TokenUrl) |
402 { | 400 { |
403 ClientSecrets = secrets, | 401 ClientSecrets = secrets, |
404 HttpClientFactory = httpClientFactory | 402 HttpClientFactory = httpClientFactory |
405 }; | 403 }; |
(...skipping 12 matching lines...) Expand all Loading... |
418 /// <summary>Verifies that the token response contains the expected data
.</summary> | 416 /// <summary>Verifies that the token response contains the expected data
.</summary> |
419 /// <param name="response">The token response</param> | 417 /// <param name="response">The token response</param> |
420 private void SubtestTokenResponse(TokenResponse response) | 418 private void SubtestTokenResponse(TokenResponse response) |
421 { | 419 { |
422 Assert.That(response.RefreshToken, Is.EqualTo("r")); | 420 Assert.That(response.RefreshToken, Is.EqualTo("r")); |
423 Assert.That(response.ExpiresInSeconds, Is.EqualTo(100)); | 421 Assert.That(response.ExpiresInSeconds, Is.EqualTo(100)); |
424 Assert.That(response.Scope, Is.EqualTo("b")); | 422 Assert.That(response.Scope, Is.EqualTo("b")); |
425 } | 423 } |
426 } | 424 } |
427 } | 425 } |
LEFT | RIGHT |