@@ -3,10 +3,10 @@ import { fromIni } from "@aws-sdk/credential-provider-ini";
33import { fromProcess } from "@aws-sdk/credential-provider-process" ;
44import { fromSSO } from "@aws-sdk/credential-provider-sso" ;
55import { fromTokenFile } from "@aws-sdk/credential-provider-web-identity" ;
6- import { CredentialsProviderError } from "@smithy/property-provider" ;
6+ import { chain , CredentialsProviderError , memoize } from "@smithy/property-provider" ;
77import { ENV_PROFILE , loadSharedConfigFiles } from "@smithy/shared-ini-file-loader" ;
88
9- import { credentialsTreatedAsExpired , credentialsWillNeedRefresh , defaultProvider } from "./defaultProvider" ;
9+ import { defaultProvider } from "./defaultProvider" ;
1010import { remoteProvider } from "./remoteProvider" ;
1111
1212jest . mock ( "@aws-sdk/credential-provider-env" ) ;
@@ -15,6 +15,7 @@ jest.mock("@aws-sdk/credential-provider-ini");
1515jest . mock ( "@aws-sdk/credential-provider-process" ) ;
1616jest . mock ( "@aws-sdk/credential-provider-sso" ) ;
1717jest . mock ( "@aws-sdk/credential-provider-web-identity" ) ;
18+ jest . mock ( "@smithy/property-provider" ) ;
1819jest . mock ( "@smithy/shared-ini-file-loader" ) ;
1920jest . mock ( "./remoteProvider" ) ;
2021
@@ -24,24 +25,19 @@ describe(defaultProvider.name, () => {
2425 secretAccessKey : "mockSecretAccessKey" ,
2526 } ;
2627
27- const credentials = ( ) => {
28- throw new CredentialsProviderError ( "test" , true ) ;
29- } ;
30-
31- const finalCredentials = ( ) => {
32- return mockCreds ;
33- } ;
34-
3528 const mockInit = {
3629 profile : "mockProfile" ,
3730 } ;
3831
39- const mockEnvFn = jest . fn ( ) . mockImplementation ( ( ) => credentials ( ) ) ;
40- const mockSsoFn = jest . fn ( ) . mockImplementation ( ( ) => credentials ( ) ) ;
41- const mockIniFn = jest . fn ( ) . mockImplementation ( ( ) => credentials ( ) ) ;
42- const mockProcessFn = jest . fn ( ) . mockImplementation ( ( ) => credentials ( ) ) ;
43- const mockTokenFileFn = jest . fn ( ) . mockImplementation ( ( ) => credentials ( ) ) ;
44- const mockRemoteProviderFn = jest . fn ( ) . mockImplementation ( ( ) => finalCredentials ( ) ) ;
32+ const mockEnvFn = jest . fn ( ) ;
33+ const mockSsoFn = jest . fn ( ) ;
34+ const mockIniFn = jest . fn ( ) ;
35+ const mockProcessFn = jest . fn ( ) ;
36+ const mockTokenFileFn = jest . fn ( ) ;
37+ const mockRemoteProviderFn = jest . fn ( ) ;
38+
39+ const mockChainFn = jest . fn ( ) ;
40+ const mockMemoizeFn = jest . fn ( ) . mockResolvedValue ( mockCreds ) ;
4541
4642 beforeEach ( ( ) => {
4743 [
@@ -51,48 +47,51 @@ describe(defaultProvider.name, () => {
5147 [ fromProcess , mockProcessFn ] ,
5248 [ fromTokenFile , mockTokenFileFn ] ,
5349 [ remoteProvider , mockRemoteProviderFn ] ,
50+ [ chain , mockChainFn ] ,
51+ [ memoize , mockMemoizeFn ] ,
5452 ] . forEach ( ( [ fromFn , mockFn ] ) => {
5553 ( fromFn as jest . Mock ) . mockReturnValue ( mockFn ) ;
5654 } ) ;
5755 } ) ;
5856
5957 afterEach ( async ( ) => {
58+ const errorFnIndex = ( chain as jest . Mock ) . mock . calls [ 0 ] . length ;
59+ const errorFn = ( chain as jest . Mock ) . mock . calls [ 0 ] [ errorFnIndex - 1 ] ;
60+ const expectedError = new CredentialsProviderError ( "Could not load credentials from any providers" , false ) ;
61+ try {
62+ await errorFn ( ) ;
63+ fail ( `expected ${ expectedError } ` ) ;
64+ } catch ( error ) {
65+ expect ( error . toString ( ) ) . toStrictEqual ( expectedError . toString ( ) ) ;
66+ }
67+
68+ expect ( memoize ) . toHaveBeenCalledWith ( mockChainFn , expect . any ( Function ) , expect . any ( Function ) ) ;
69+
6070 jest . clearAllMocks ( ) ;
6171 } ) ;
6272
6373 describe ( "without fromEnv" , ( ) => {
64- it ( "creates provider chain and memoizes it" , async ( ) => {
65- const provider = defaultProvider ( mockInit ) ;
66-
67- // initial call proceeds through the chain.
68- {
69- const receivedCreds = await provider ( ) ;
70- expect ( receivedCreds ) . toEqual ( mockCreds ) ;
74+ afterEach ( ( ) => {
75+ expect ( chain ) . toHaveBeenCalledWith (
76+ mockSsoFn ,
77+ mockIniFn ,
78+ mockProcessFn ,
79+ mockTokenFileFn ,
80+ mockRemoteProviderFn ,
81+ expect . any ( Function )
82+ ) ;
83+ } ) ;
7184
72- expect ( fromEnv ) . not . toHaveBeenCalled ( ) ;
73- expect ( fromSSO ) . toHaveBeenCalledWith ( mockInit ) ;
74- expect ( fromIni ) . toHaveBeenCalledWith ( mockInit ) ;
75- expect ( fromProcess ) . toHaveBeenCalledWith ( mockInit ) ;
76- expect ( fromTokenFile ) . toHaveBeenCalledWith ( mockInit ) ;
77- expect ( remoteProvider ) . toHaveBeenCalledWith ( mockInit ) ;
85+ it ( "creates provider chain and memoizes it" , async ( ) => {
86+ const receivedCreds = await defaultProvider ( mockInit ) ( ) ;
87+ expect ( receivedCreds ) . toStrictEqual ( mockCreds ) ;
7888
79- expect ( loadSharedConfigFiles ) . not . toHaveBeenCalled ( ) ;
89+ expect ( fromEnv ) . not . toHaveBeenCalled ( ) ;
90+ for ( const fromFn of [ fromSSO , fromIni , fromProcess , fromTokenFile , remoteProvider ] ) {
91+ expect ( fromFn ) . toHaveBeenCalledWith ( mockInit ) ;
8092 }
8193
82- jest . clearAllMocks ( ) ;
83-
84- // subsequent call does not enter the chain.
85- {
86- const receivedCreds = await provider ( ) ;
87- expect ( receivedCreds ) . toEqual ( mockCreds ) ;
88-
89- expect ( fromEnv ) . not . toHaveBeenCalled ( ) ;
90- expect ( fromSSO ) . not . toHaveBeenCalledWith ( mockInit ) ;
91- expect ( fromIni ) . not . toHaveBeenCalledWith ( mockInit ) ;
92- expect ( fromProcess ) . not . toHaveBeenCalledWith ( mockInit ) ;
93- expect ( fromTokenFile ) . not . toHaveBeenCalledWith ( mockInit ) ;
94- expect ( remoteProvider ) . not . toHaveBeenCalledWith ( mockInit ) ;
95- }
94+ expect ( loadSharedConfigFiles ) . not . toHaveBeenCalled ( ) ;
9695 } ) ;
9796
9897 it ( `if env['${ ENV_PROFILE } '] is set` , async ( ) => {
@@ -124,42 +123,63 @@ describe(defaultProvider.name, () => {
124123 for ( const fromFn of [ fromSSO , fromIni , fromProcess , fromTokenFile , remoteProvider ] ) {
125124 expect ( fromFn ) . toHaveBeenCalledWith ( mockInitWithoutProfile ) ;
126125 }
126+
127+ expect ( chain ) . toHaveBeenCalledWith (
128+ mockEnvFn ,
129+ mockSsoFn ,
130+ mockIniFn ,
131+ mockProcessFn ,
132+ mockTokenFileFn ,
133+ mockRemoteProviderFn ,
134+ expect . any ( Function )
135+ ) ;
127136 } ) ;
128137
129- describe ( credentialsTreatedAsExpired . name , ( ) => {
138+ describe ( "memoize isExpired" , ( ) => {
130139 const mockDateNow = Date . now ( ) ;
131140 beforeEach ( async ( ) => {
132141 jest . spyOn ( Date , "now" ) . mockReturnValueOnce ( mockDateNow ) ;
142+ await defaultProvider ( mockInit ) ( ) ;
133143 } ) ;
134144
135145 it ( "returns true if expiration is defined, and creds have expired" , ( ) => {
146+ const memoizeExpiredFn = ( memoize as jest . Mock ) . mock . calls [ 0 ] [ 1 ] ;
136147 const expiration = new Date ( mockDateNow - 24 * 60 * 60 * 1000 ) ;
137- expect ( credentialsTreatedAsExpired ( { ... mockCreds , expiration } ) ) . toEqual ( true ) ;
148+ expect ( memoizeExpiredFn ( { expiration } ) ) . toEqual ( true ) ;
138149 } ) ;
139150
140151 it ( "returns true if expiration is defined, and creds expire in <5 mins" , ( ) => {
152+ const memoizeExpiredFn = ( memoize as jest . Mock ) . mock . calls [ 0 ] [ 1 ] ;
141153 const expiration = new Date ( mockDateNow + 299 * 1000 ) ;
142- expect ( credentialsTreatedAsExpired ( { ... mockCreds , expiration } ) ) . toEqual ( true ) ;
154+ expect ( memoizeExpiredFn ( { expiration } ) ) . toEqual ( true ) ;
143155 } ) ;
144156
145157 it ( "returns false if expiration is defined, but creds expire in >5 mins" , ( ) => {
158+ const memoizeExpiredFn = ( memoize as jest . Mock ) . mock . calls [ 0 ] [ 1 ] ;
146159 const expiration = new Date ( mockDateNow + 301 * 1000 ) ;
147- expect ( credentialsTreatedAsExpired ( { ... mockCreds , expiration } ) ) . toEqual ( false ) ;
160+ expect ( memoizeExpiredFn ( { expiration } ) ) . toEqual ( false ) ;
148161 } ) ;
149162
150163 it ( "returns false if expiration is not defined" , ( ) => {
151- expect ( credentialsTreatedAsExpired ( { ...mockCreds } ) ) . toEqual ( false ) ;
164+ const memoizeExpiredFn = ( memoize as jest . Mock ) . mock . calls [ 0 ] [ 1 ] ;
165+ expect ( memoizeExpiredFn ( { } ) ) . toEqual ( false ) ;
152166 } ) ;
153167 } ) ;
154168
155- describe ( credentialsWillNeedRefresh . name , ( ) => {
169+ describe ( "memoize requiresRefresh" , ( ) => {
170+ beforeEach ( async ( ) => {
171+ await defaultProvider ( mockInit ) ( ) ;
172+ } ) ;
173+
156174 it ( "returns true if expiration is not defined" , ( ) => {
157- const expiration = new Date ( ) ;
158- expect ( credentialsWillNeedRefresh ( { ...mockCreds , expiration } ) ) . toEqual ( true ) ;
175+ const memoizeRefreshFn = ( memoize as jest . Mock ) . mock . calls [ 0 ] [ 2 ] ;
176+ const expiration = Date . now ( ) ;
177+ expect ( memoizeRefreshFn ( { expiration } ) ) . toEqual ( true ) ;
159178 } ) ;
160179
161180 it ( "returns false if expiration is not defined" , ( ) => {
162- expect ( credentialsWillNeedRefresh ( { ...mockCreds } ) ) . toEqual ( false ) ;
181+ const memoizeRefreshFn = ( memoize as jest . Mock ) . mock . calls [ 0 ] [ 2 ] ;
182+ expect ( memoizeRefreshFn ( { } ) ) . toEqual ( false ) ;
163183 } ) ;
164184 } ) ;
165185} ) ;
0 commit comments