@@ -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 { chain , CredentialsProviderError , memoize } from "@smithy/property-provider" ;
6+ import { CredentialsProviderError } from "@smithy/property-provider" ;
77import { ENV_PROFILE , loadSharedConfigFiles } from "@smithy/shared-ini-file-loader" ;
88
9- import { defaultProvider } from "./defaultProvider" ;
9+ import { credentialsTreatedAsExpired , credentialsWillNeedRefresh , defaultProvider } from "./defaultProvider" ;
1010import { remoteProvider } from "./remoteProvider" ;
1111
1212jest . mock ( "@aws-sdk/credential-provider-env" ) ;
@@ -15,7 +15,6 @@ 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" ) ;
1918jest . mock ( "@smithy/shared-ini-file-loader" ) ;
2019jest . mock ( "./remoteProvider" ) ;
2120
@@ -25,19 +24,24 @@ describe(defaultProvider.name, () => {
2524 secretAccessKey : "mockSecretAccessKey" ,
2625 } ;
2726
27+ const credentials = ( ) => {
28+ throw new CredentialsProviderError ( "test" , true ) ;
29+ } ;
30+
31+ const finalCredentials = ( ) => {
32+ return mockCreds ;
33+ } ;
34+
2835 const mockInit = {
2936 profile : "mockProfile" ,
3037 } ;
3138
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 ) ;
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 ( ) ) ;
4145
4246 beforeEach ( ( ) => {
4347 [
@@ -47,51 +51,48 @@ describe(defaultProvider.name, () => {
4751 [ fromProcess , mockProcessFn ] ,
4852 [ fromTokenFile , mockTokenFileFn ] ,
4953 [ remoteProvider , mockRemoteProviderFn ] ,
50- [ chain , mockChainFn ] ,
51- [ memoize , mockMemoizeFn ] ,
5254 ] . forEach ( ( [ fromFn , mockFn ] ) => {
5355 ( fromFn as jest . Mock ) . mockReturnValue ( mockFn ) ;
5456 } ) ;
5557 } ) ;
5658
5759 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-
7060 jest . clearAllMocks ( ) ;
7161 } ) ;
7262
7363 describe ( "without fromEnv" , ( ) => {
74- afterEach ( ( ) => {
75- expect ( chain ) . toHaveBeenCalledWith (
76- mockSsoFn ,
77- mockIniFn ,
78- mockProcessFn ,
79- mockTokenFileFn ,
80- mockRemoteProviderFn ,
81- expect . any ( Function )
82- ) ;
83- } ) ;
84-
8564 it ( "creates provider chain and memoizes it" , async ( ) => {
86- const receivedCreds = await defaultProvider ( mockInit ) ( ) ;
87- expect ( receivedCreds ) . toStrictEqual ( mockCreds ) ;
65+ const provider = defaultProvider ( mockInit ) ;
8866
89- expect ( fromEnv ) . not . toHaveBeenCalled ( ) ;
90- for ( const fromFn of [ fromSSO , fromIni , fromProcess , fromTokenFile , remoteProvider ] ) {
91- expect ( fromFn ) . toHaveBeenCalledWith ( mockInit ) ;
67+ // initial call proceeds through the chain.
68+ {
69+ const receivedCreds = await provider ( ) ;
70+ expect ( receivedCreds ) . toEqual ( mockCreds ) ;
71+
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 ) ;
78+
79+ expect ( loadSharedConfigFiles ) . not . toHaveBeenCalled ( ) ;
9280 }
9381
94- expect ( loadSharedConfigFiles ) . not . toHaveBeenCalled ( ) ;
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+ }
9596 } ) ;
9697
9798 it ( `if env['${ ENV_PROFILE } '] is set` , async ( ) => {
@@ -123,63 +124,42 @@ describe(defaultProvider.name, () => {
123124 for ( const fromFn of [ fromSSO , fromIni , fromProcess , fromTokenFile , remoteProvider ] ) {
124125 expect ( fromFn ) . toHaveBeenCalledWith ( mockInitWithoutProfile ) ;
125126 }
126-
127- expect ( chain ) . toHaveBeenCalledWith (
128- mockEnvFn ,
129- mockSsoFn ,
130- mockIniFn ,
131- mockProcessFn ,
132- mockTokenFileFn ,
133- mockRemoteProviderFn ,
134- expect . any ( Function )
135- ) ;
136127 } ) ;
137128
138- describe ( "memoize isExpired" , ( ) => {
129+ describe ( credentialsTreatedAsExpired . name , ( ) => {
139130 const mockDateNow = Date . now ( ) ;
140131 beforeEach ( async ( ) => {
141132 jest . spyOn ( Date , "now" ) . mockReturnValueOnce ( mockDateNow ) ;
142- await defaultProvider ( mockInit ) ( ) ;
143133 } ) ;
144134
145135 it ( "returns true if expiration is defined, and creds have expired" , ( ) => {
146- const memoizeExpiredFn = ( memoize as jest . Mock ) . mock . calls [ 0 ] [ 1 ] ;
147136 const expiration = new Date ( mockDateNow - 24 * 60 * 60 * 1000 ) ;
148- expect ( memoizeExpiredFn ( { expiration } ) ) . toEqual ( true ) ;
137+ expect ( credentialsTreatedAsExpired ( { ... mockCreds , expiration } ) ) . toEqual ( true ) ;
149138 } ) ;
150139
151140 it ( "returns true if expiration is defined, and creds expire in <5 mins" , ( ) => {
152- const memoizeExpiredFn = ( memoize as jest . Mock ) . mock . calls [ 0 ] [ 1 ] ;
153141 const expiration = new Date ( mockDateNow + 299 * 1000 ) ;
154- expect ( memoizeExpiredFn ( { expiration } ) ) . toEqual ( true ) ;
142+ expect ( credentialsTreatedAsExpired ( { ... mockCreds , expiration } ) ) . toEqual ( true ) ;
155143 } ) ;
156144
157145 it ( "returns false if expiration is defined, but creds expire in >5 mins" , ( ) => {
158- const memoizeExpiredFn = ( memoize as jest . Mock ) . mock . calls [ 0 ] [ 1 ] ;
159146 const expiration = new Date ( mockDateNow + 301 * 1000 ) ;
160- expect ( memoizeExpiredFn ( { expiration } ) ) . toEqual ( false ) ;
147+ expect ( credentialsTreatedAsExpired ( { ... mockCreds , expiration } ) ) . toEqual ( false ) ;
161148 } ) ;
162149
163150 it ( "returns false if expiration is not defined" , ( ) => {
164- const memoizeExpiredFn = ( memoize as jest . Mock ) . mock . calls [ 0 ] [ 1 ] ;
165- expect ( memoizeExpiredFn ( { } ) ) . toEqual ( false ) ;
151+ expect ( credentialsTreatedAsExpired ( { ...mockCreds } ) ) . toEqual ( false ) ;
166152 } ) ;
167153 } ) ;
168154
169- describe ( "memoize requiresRefresh" , ( ) => {
170- beforeEach ( async ( ) => {
171- await defaultProvider ( mockInit ) ( ) ;
172- } ) ;
173-
155+ describe ( credentialsWillNeedRefresh . name , ( ) => {
174156 it ( "returns true if expiration is not defined" , ( ) => {
175- const memoizeRefreshFn = ( memoize as jest . Mock ) . mock . calls [ 0 ] [ 2 ] ;
176- const expiration = Date . now ( ) ;
177- expect ( memoizeRefreshFn ( { expiration } ) ) . toEqual ( true ) ;
157+ const expiration = new Date ( ) ;
158+ expect ( credentialsWillNeedRefresh ( { ...mockCreds , expiration } ) ) . toEqual ( true ) ;
178159 } ) ;
179160
180161 it ( "returns false if expiration is not defined" , ( ) => {
181- const memoizeRefreshFn = ( memoize as jest . Mock ) . mock . calls [ 0 ] [ 2 ] ;
182- expect ( memoizeRefreshFn ( { } ) ) . toEqual ( false ) ;
162+ expect ( credentialsWillNeedRefresh ( { ...mockCreds } ) ) . toEqual ( false ) ;
183163 } ) ;
184164 } ) ;
185165} ) ;
0 commit comments