@@ -104,4 +104,108 @@ describe("rds-signer", () => {
104104 const token = await signer . getAuthToken ( ) ;
105105 expect ( token ) . toBe ( "testhost:5432?other=url¶meters=here" ) ;
106106 } ) ;
107+
108+ describe ( "credential refresh wrapper" , ( ) => {
109+ it ( "should not force refresh when credentials have no expiration" , async ( ) => {
110+ const provider = vi . fn ( ) . mockResolvedValue ( {
111+ accessKeyId : "key" ,
112+ secretAccessKey : "secret" ,
113+ } ) ;
114+ const signer = new Signer ( { ...minimalParams , credentials : provider } ) ;
115+ await signer . getAuthToken ( ) ;
116+ //@ts -ignore
117+ const wrappedProvider = SignatureV4 . mock . calls [ 0 ] [ 0 ] . credentials ;
118+ await wrappedProvider ( ) ;
119+ expect ( provider ) . toHaveBeenCalledTimes ( 1 ) ;
120+ } ) ;
121+
122+ it ( "should not force refresh when credentials expire in more than 15 minutes" , async ( ) => {
123+ const provider = vi . fn ( ) . mockResolvedValue ( {
124+ accessKeyId : "key" ,
125+ secretAccessKey : "secret" ,
126+ expiration : new Date ( Date . now ( ) + 20 * 60_000 ) ,
127+ } ) ;
128+ const signer = new Signer ( { ...minimalParams , credentials : provider } ) ;
129+ await signer . getAuthToken ( ) ;
130+ //@ts -ignore
131+ const wrappedProvider = SignatureV4 . mock . calls [ 0 ] [ 0 ] . credentials ;
132+ await wrappedProvider ( ) ;
133+ expect ( provider ) . toHaveBeenCalledTimes ( 1 ) ;
134+ } ) ;
135+
136+ it ( "should force refresh when credentials expire within 15 minutes" , async ( ) => {
137+ const refreshedCreds = {
138+ accessKeyId : "refreshed" ,
139+ secretAccessKey : "secret" ,
140+ expiration : new Date ( Date . now ( ) + 60 * 60_000 ) ,
141+ } ;
142+ const provider = vi
143+ . fn ( )
144+ . mockResolvedValueOnce ( {
145+ accessKeyId : "expiring" ,
146+ secretAccessKey : "secret" ,
147+ expiration : new Date ( Date . now ( ) + 2 * 60_000 ) ,
148+ } )
149+ . mockResolvedValueOnce ( refreshedCreds ) ;
150+ const signer = new Signer ( { ...minimalParams , credentials : provider } ) ;
151+ await signer . getAuthToken ( ) ;
152+ //@ts -ignore
153+ const wrappedProvider = SignatureV4 . mock . calls [ 0 ] [ 0 ] . credentials ;
154+ const result = await wrappedProvider ( ) ;
155+ expect ( provider ) . toHaveBeenCalledTimes ( 2 ) ;
156+ expect ( provider ) . toHaveBeenLastCalledWith ( expect . objectContaining ( { forceRefresh : true } ) ) ;
157+ expect ( result ) . toEqual ( refreshedCreds ) ;
158+ } ) ;
159+
160+ it ( "should return original credentials if refresh still expires within 15 minutes" , async ( ) => {
161+ const originalCreds = {
162+ accessKeyId : "expiring" ,
163+ secretAccessKey : "secret" ,
164+ expiration : new Date ( Date . now ( ) + 2 * 60_000 ) ,
165+ } ;
166+ const provider = vi
167+ . fn ( )
168+ . mockResolvedValueOnce ( originalCreds )
169+ . mockResolvedValueOnce ( {
170+ accessKeyId : "still-expiring" ,
171+ secretAccessKey : "secret" ,
172+ expiration : new Date ( Date . now ( ) + 3 * 60_000 ) ,
173+ } ) ;
174+ const signer = new Signer ( { ...minimalParams , credentials : provider } ) ;
175+ await signer . getAuthToken ( ) ;
176+ //@ts -ignore
177+ const wrappedProvider = SignatureV4 . mock . calls [ 0 ] [ 0 ] . credentials ;
178+ const result = await wrappedProvider ( ) ;
179+ expect ( provider ) . toHaveBeenCalledTimes ( 2 ) ;
180+ expect ( result ) . toEqual ( originalCreds ) ;
181+ } ) ;
182+
183+ it ( "should return original credentials if force refresh throws" , async ( ) => {
184+ const originalCreds = {
185+ accessKeyId : "expiring" ,
186+ secretAccessKey : "secret" ,
187+ expiration : new Date ( Date . now ( ) + 2 * 60_000 ) ,
188+ } ;
189+ const provider = vi . fn ( ) . mockResolvedValueOnce ( originalCreds ) . mockRejectedValueOnce ( new Error ( "refresh failed" ) ) ;
190+ const signer = new Signer ( { ...minimalParams , credentials : provider } ) ;
191+ await signer . getAuthToken ( ) ;
192+ //@ts -ignore
193+ const wrappedProvider = SignatureV4 . mock . calls [ 0 ] [ 0 ] . credentials ;
194+ const result = await wrappedProvider ( ) ;
195+ expect ( provider ) . toHaveBeenCalledTimes ( 2 ) ;
196+ expect ( result ) . toEqual ( originalCreds ) ;
197+ } ) ;
198+
199+ it ( "should not wrap static credential objects" , async ( ) => {
200+ const staticCreds = {
201+ accessKeyId : "static" ,
202+ secretAccessKey : "secret" ,
203+ expiration : new Date ( Date . now ( ) + 2 * 60_000 ) ,
204+ } ;
205+ const signer = new Signer ( { ...minimalParams , credentials : staticCreds } ) ;
206+ await signer . getAuthToken ( ) ;
207+ //@ts -ignore
208+ expect ( SignatureV4 . mock . calls [ 0 ] [ 0 ] . credentials ) . toEqual ( staticCreds ) ;
209+ } ) ;
210+ } ) ;
107211} ) ;
0 commit comments