22// Licensed under the MIT license.
33
44import { assert } from "chai" ;
5- import Sinon , { fake , createSandbox } from "sinon" ;
5+ import { fake , createSandbox } from "sinon" ;
66import { OperationSpec } from "../../src/operationSpec" ;
77import { TokenCredential , GetTokenOptions , AccessToken } from "@azure/core-auth" ;
88import { RequestPolicy , RequestPolicyOptions } from "../../src/policies/requestPolicy" ;
@@ -11,15 +11,12 @@ import { HttpOperationResponse } from "../../src/httpOperationResponse";
1111import { HttpHeaders } from "../../src/httpHeaders" ;
1212import { WebResource } from "../../src/webResource" ;
1313import { BearerTokenAuthenticationPolicy } from "../../src/policies/bearerTokenAuthenticationPolicy" ;
14- import { ExpiringAccessTokenCache } from "../../src/credentials/accessTokenCache" ;
14+ import {
15+ ExpiringAccessTokenCache ,
16+ TokenRefreshBufferMs
17+ } from "../../src/credentials/accessTokenCache" ;
1518import { AccessTokenRefresher } from "../../src/credentials/accessTokenRefresher" ;
1619
17- // Token is refreshed one millisecond BEFORE it expires.
18- const beforeTokenExpiresInMs = 1000 ;
19-
20- // To avoid many refresh requests, we make new refresh requests only after:
21- const tokenRefreshIntervalInMs = 500 ;
22-
2320describe ( "BearerTokenAuthenticationPolicy" , function ( ) {
2421 const mockPolicy : RequestPolicy = {
2522 sendRequest ( request : WebResource ) : Promise < HttpOperationResponse > {
@@ -31,15 +28,6 @@ describe("BearerTokenAuthenticationPolicy", function() {
3128 }
3229 } ;
3330
34- let clock : Sinon . SinonFakeTimers ;
35-
36- beforeEach ( ( ) => {
37- clock = Sinon . useFakeTimers ( Date . now ( ) ) ;
38- } ) ;
39- afterEach ( ( ) => {
40- clock . restore ( ) ;
41- } ) ;
42-
4331 it ( "correctly adds an Authentication header with the Bearer token" , async function ( ) {
4432 const mockToken = "token" ;
4533 const tokenScopes = [ "scope1" , "scope2" ] ;
@@ -65,11 +53,32 @@ describe("BearerTokenAuthenticationPolicy", function() {
6553 ) ;
6654 } ) ;
6755
56+ it ( "refreshes access tokens when they expire" , async ( ) => {
57+ const now = Date . now ( ) ;
58+ const refreshCred1 = new MockRefreshAzureCredential ( now ) ;
59+ const refreshCred2 = new MockRefreshAzureCredential ( now + TokenRefreshBufferMs ) ;
60+ const notRefreshCred1 = new MockRefreshAzureCredential ( now + TokenRefreshBufferMs + 5000 ) ;
61+
62+ const credentialsToTest : [ MockRefreshAzureCredential , number , string ] [ ] = [
63+ [ refreshCred1 , 2 , "Refresh credential 1" ] ,
64+ [ refreshCred2 , 2 , "Refresh credential 2" ] ,
65+ [ notRefreshCred1 , 1 , "Not refresh credential 1" ]
66+ ] ;
67+
68+ const request = createRequest ( ) ;
69+ for ( const [ credentialToTest , expectedCalls , message ] of credentialsToTest ) {
70+ const policy = createBearerTokenPolicy ( "testscope" , credentialToTest ) ;
71+ await policy . sendRequest ( request ) ;
72+ await policy . sendRequest ( request ) ;
73+ assert . strictEqual ( credentialToTest . authCount , expectedCalls , `${ message } failed` ) ;
74+ }
75+ } ) ;
76+
6877 it ( "tests that AccessTokenRefresher is working" , async function ( ) {
6978 const now = Date . now ( ) ;
7079 const credentialToTest = new MockRefreshAzureCredential ( now ) ;
7180 const request = createRequest ( ) ;
72- const policy = createBearerTokenPolicy ( "test-scope " , credentialToTest ) ;
81+ const policy = createBearerTokenPolicy ( "testscope " , credentialToTest ) ;
7382 await policy . sendRequest ( request ) ;
7483
7584 const sandbox = createSandbox ( ) ;
@@ -79,66 +88,6 @@ describe("BearerTokenAuthenticationPolicy", function() {
7988 assert . strictEqual ( credentialToTest . authCount , 2 ) ;
8089 } ) ;
8190
82- it ( "refreshes the token on initial request" , async ( ) => {
83- const expiresOn = Date . now ( ) + 1000 * 60 ; // One minute later.
84- const credential = new MockRefreshAzureCredential ( expiresOn ) ;
85- const request = createRequest ( ) ;
86- const policy = createBearerTokenPolicy ( "test-scope" , credential ) ;
87-
88- await policy . sendRequest ( request ) ;
89- assert . strictEqual ( credential . authCount , 1 ) ;
90- } ) ;
91-
92- it ( "refreshes the token again only once it expired" , async ( ) => {
93- const expireDelayMs = 5000 ;
94- let tokenExpiration = Date . now ( ) + expireDelayMs ;
95- const credential = new MockRefreshAzureCredential ( tokenExpiration ) ;
96- const request = createRequest ( ) ;
97- const policy = createBearerTokenPolicy ( "test-scope" , credential ) ;
98-
99- // The token is cached and remains cached for a bit.
100- await policy . sendRequest ( request ) ;
101- await policy . sendRequest ( request ) ;
102- assert . strictEqual ( credential . authCount , 1 ) ;
103-
104- // The token will remain cached until tokenExpiration - testTokenRefreshBufferMs, so in (5000 - 1000) milliseconds.
105-
106- // For safe measure, we test the token is still cached a second earlier than the refresh expectation.
107- clock . tick ( expireDelayMs - beforeTokenExpiresInMs - 1000 ) ;
108- await policy . sendRequest ( request ) ;
109- assert . strictEqual ( credential . authCount , 1 ) ;
110-
111- // The new token will last 5 seconds again.
112- tokenExpiration = Date . now ( ) + expireDelayMs ;
113- credential . setExpiresOnTimestamp ( tokenExpiration ) ;
114-
115- // Now we wait until it expires:
116- clock . tick ( 1000 ) ;
117- await policy . sendRequest ( request ) ;
118- assert . strictEqual ( credential . authCount , 2 ) ;
119- } ) ;
120-
121- it ( "access token refresher should prevent refreshers to happen too fast" , async ( ) => {
122- const expiresOn = Date . now ( ) ; // Already expired
123- const credential = new MockRefreshAzureCredential ( expiresOn ) ;
124- const request = createRequest ( ) ;
125- const policy = createBearerTokenPolicy ( "test-scope" , credential ) ;
126-
127- await policy . sendRequest ( request ) ;
128- assert . strictEqual ( credential . authCount , 1 ) ;
129- credential . setExpiresOnTimestamp ( Date . now ( ) ) ;
130-
131- await policy . sendRequest ( request ) ;
132- assert . strictEqual ( credential . authCount , 1 ) ;
133- credential . setExpiresOnTimestamp ( Date . now ( ) ) ;
134-
135- clock . tick ( tokenRefreshIntervalInMs ) ;
136-
137- await policy . sendRequest ( request ) ;
138- assert . strictEqual ( credential . authCount , 2 ) ;
139- credential . setExpiresOnTimestamp ( Date . now ( ) ) ;
140- } ) ;
141-
14291 function createRequest ( operationSpec ?: OperationSpec ) : WebResource {
14392 const request = new WebResource ( ) ;
14493 request . operationSpec = operationSpec ;
@@ -152,8 +101,8 @@ describe("BearerTokenAuthenticationPolicy", function() {
152101 return new BearerTokenAuthenticationPolicy (
153102 mockPolicy ,
154103 new RequestPolicyOptions ( ) ,
155- new ExpiringAccessTokenCache ( beforeTokenExpiresInMs ) ,
156- new AccessTokenRefresher ( credential , scopes , tokenRefreshIntervalInMs )
104+ new ExpiringAccessTokenCache ( ) ,
105+ new AccessTokenRefresher ( credential , scopes )
157106 ) ;
158107 }
159108} ) ;
@@ -166,15 +115,11 @@ class MockRefreshAzureCredential implements TokenCredential {
166115 this . _expiresOnTimestamp = expiresOnTimestamp ;
167116 }
168117
169- public setExpiresOnTimestamp ( expiresOnTimestamp : number ) : void {
170- this . _expiresOnTimestamp = expiresOnTimestamp ;
171- }
172-
173- public async getToken (
118+ public getToken (
174119 _scopes : string | string [ ] ,
175120 _options ?: GetTokenOptions
176121 ) : Promise < AccessToken | null > {
177122 this . authCount ++ ;
178- return { token : "mock-token " , expiresOnTimestamp : this . _expiresOnTimestamp } ;
123+ return Promise . resolve ( { token : "mocktoken " , expiresOnTimestamp : this . _expiresOnTimestamp } ) ;
179124 }
180125}
0 commit comments