@@ -3,6 +3,7 @@ import { beforeEach, describe, expect, test as it, vi } from "vitest";
33
44import { credentialsWillNeedRefresh } from "../defaultProvider" ;
55import { memoizeChain } from "./memoize-chain" ;
6+ import { CredentialsProviderError } from "@smithy/property-provider" ;
67
78describe ( "memoize runtime config aware AWS credential chain" , ( ) => {
89 let staticCredentials ! : RuntimeConfigAwsCredentialIdentityProvider ;
@@ -156,4 +157,37 @@ describe("memoize runtime config aware AWS credential chain", () => {
156157
157158 expect ( expiringCredentials ) . toHaveBeenCalledTimes ( 5 ) ;
158159 } ) ;
160+
161+ it ( "should release locks on credential resolution failure at the end of the chain" , async ( ) => {
162+ const neverAvailableCredentialProvider : ( ) => RuntimeConfigAwsCredentialIdentityProvider = ( ) => async ( ) => {
163+ throw new CredentialsProviderError ( "never available" , { tryNextLink : true } ) ;
164+ } ;
165+
166+ let n = 0 ;
167+ const eventuallyAvailableCredentialProvider : RuntimeConfigAwsCredentialIdentityProvider = async ( ) => {
168+ if ( n ++ === 0 ) {
169+ throw new CredentialsProviderError ( "initially unavailable" , { tryNextLink : false } ) ;
170+ }
171+ return {
172+ accessKeyId : "xyz" ,
173+ secretAccessKey : "xyz" ,
174+ } ;
175+ } ;
176+
177+ const provider = memoizeChain (
178+ [ neverAvailableCredentialProvider ( ) , neverAvailableCredentialProvider ( ) , eventuallyAvailableCredentialProvider ] ,
179+ credentialsWillNeedRefresh
180+ ) ;
181+
182+ try {
183+ await provider ( ) ;
184+ } catch ( e ) {
185+ const credentials = await provider ( ) ;
186+ expect ( credentials ) . toEqual ( {
187+ accessKeyId : "xyz" ,
188+ secretAccessKey : "xyz" ,
189+ } ) ;
190+ }
191+ expect . assertions ( 1 ) ;
192+ } ) ;
159193} ) ;
0 commit comments