Skip to content

Commit 1173864

Browse files
committed
feat(auth): add EntraId integration tests
- Add integration tests for token renewal and re-authentication flows - Update credentials provider to use uniqueId as username instead of account username - Add test utilities for loading Redis endpoint configurations - Split TypeScript configs into separate files for samples and integration tests - Remove `@redis/authx` package and nest it under `@`
1 parent ac972bd commit 1173864

31 files changed

+723
-214
lines changed
+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
name-template: 'entraid@$NEXT_PATCH_VERSION'
2+
tag-template: 'entraid@$NEXT_PATCH_VERSION'
3+
autolabeler:
4+
- label: 'chore'
5+
files:
6+
- '*.md'
7+
- '.github/*'
8+
- label: 'bug'
9+
branch:
10+
- '/bug-.+'
11+
- label: 'chore'
12+
branch:
13+
- '/chore-.+'
14+
- label: 'feature'
15+
branch:
16+
- '/feature-.+'
17+
categories:
18+
- title: 'Breaking Changes'
19+
labels:
20+
- 'breakingchange'
21+
- title: '🚀 New Features'
22+
labels:
23+
- 'feature'
24+
- 'enhancement'
25+
- title: '🐛 Bug Fixes'
26+
labels:
27+
- 'fix'
28+
- 'bugfix'
29+
- 'bug'
30+
- title: '🧰 Maintenance'
31+
label:
32+
- 'chore'
33+
- 'maintenance'
34+
- 'documentation'
35+
- 'docs'
36+
37+
change-template: '- $TITLE (#$NUMBER)'
38+
include-paths:
39+
- 'packages/entraid'
40+
exclude-labels:
41+
- 'skip-changelog'
42+
template: |
43+
## Changes
44+
45+
$CHANGES
46+
47+
## Contributors
48+
We'd like to thank all the contributors who worked on this release!
49+
50+
$CONTRIBUTORS
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
name: Release Drafter
2+
3+
on:
4+
push:
5+
# branches to consider in the event; optional, defaults to all
6+
branches:
7+
- master
8+
9+
jobs:
10+
11+
update_release_draft:
12+
13+
permissions:
14+
contents: write
15+
pull-requests: write
16+
runs-on: ubuntu-latest
17+
steps:
18+
# Drafts your next Release notes as Pull Requests are merged into "master"
19+
- uses: release-drafter/release-drafter@v5
20+
with:
21+
# (Optional) specify config name to use, relative to .github/. Default: release-drafter.yml
22+
config-name: release-drafter/entraid-config.yml
23+
env:
24+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

packages/authx/package.json

-39
This file was deleted.

packages/authx/tsconfig.json

-21
This file was deleted.

packages/authx/lib/credentials-provider.ts packages/client/lib/authx/credentials-provider.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
1+
import { Disposable } from './disposable';
22
/**
33
* Provides credentials asynchronously.
44
*/
+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/**
2+
* Represents a resource that can be disposed.
3+
*/
4+
export interface Disposable {
5+
dispose(): void;
6+
}
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export { TokenManager, TokenManagerConfig, TokenStreamListener, RetryPolicy, IDPError } from './lib/token-manager';
1+
export { TokenManager, TokenManagerConfig, TokenStreamListener, RetryPolicy, IDPError } from './token-manager';
22
export {
33
CredentialsProvider,
44
StreamingCredentialsProvider,
@@ -8,6 +8,8 @@ export {
88
AsyncCredentialsProvider,
99
ReAuthenticationError,
1010
BasicAuth
11-
} from './lib/credentials-provider';
12-
export { Token } from './lib/token';
13-
export { IdentityProvider, TokenResponse } from './lib/identity-provider';
11+
} from './credentials-provider';
12+
export { Token } from './token';
13+
export { IdentityProvider, TokenResponse } from './identity-provider';
14+
15+
export { Disposable } from './disposable'

packages/authx/lib/token-manager.spec.ts packages/client/lib/authx/token-manager.spec.ts

+12-12
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ describe('TokenManager', () => {
278278
assert.equal(listener.errors.length, 0, 'Should not have any errors');
279279
assert.equal(manager.getCurrentToken().value, 'token3', 'Should have current token');
280280

281-
disposable?.[Symbol.dispose]();
281+
disposable?.dispose();
282282
});
283283
});
284284
});
@@ -328,7 +328,7 @@ describe('TokenManager', () => {
328328
assert.equal(listener.receivedTokens.length, 1, 'Should not receive new token after failure');
329329
assert.equal(listener.errors.length, 1, 'Should receive error');
330330
assert.equal(listener.errors[0].message, 'Fatal error', 'Should have correct error message');
331-
assert.equal(listener.errors[0].isFatal, true, 'Should be a fatal error');
331+
assert.equal(listener.errors[0].isRetryable, false, 'Should be a fatal error');
332332

333333
// verify that the token manager is stopped and no more requests are made after the error and expected refresh time
334334
await delay(80);
@@ -338,7 +338,7 @@ describe('TokenManager', () => {
338338
assert.equal(listener.errors.length, 1, 'Should not receive more errors after error');
339339
assert.equal(manager.isRunning(), false, 'Should stop token manager after error');
340340

341-
disposable?.[Symbol.dispose]();
341+
disposable?.dispose();
342342
});
343343

344344
it('should handle retries with exponential backoff', async () => {
@@ -352,7 +352,7 @@ describe('TokenManager', () => {
352352
initialDelayMs: 100,
353353
maxDelayMs: 1000,
354354
backoffMultiplier: 2,
355-
shouldRetry: (error: unknown) => error instanceof Error && error.message === 'Temporary failure'
355+
isRetryable: (error: unknown) => error instanceof Error && error.message === 'Temporary failure'
356356
}
357357
};
358358

@@ -389,7 +389,7 @@ describe('TokenManager', () => {
389389
// Should have first error but not stop due to retry config
390390
assert.equal(listener.errors.length, 1, 'Should have first error');
391391
assert.ok(listener.errors[0].message.includes('attempt 1'), 'Error should indicate first attempt');
392-
assert.equal(listener.errors[0].isFatal, false, 'Should not be a fatal error');
392+
assert.equal(listener.errors[0].isRetryable, true, 'Should not be a fatal error');
393393
assert.equal(manager.isRunning(), true, 'Should continue running during retries');
394394

395395
// Advance past first retry (delay: 100ms due to backoff)
@@ -401,7 +401,7 @@ describe('TokenManager', () => {
401401

402402
assert.equal(listener.errors.length, 2, 'Should have second error');
403403
assert.ok(listener.errors[1].message.includes('attempt 2'), 'Error should indicate second attempt');
404-
assert.equal(listener.errors[0].isFatal, false, 'Should not be a fatal error');
404+
assert.equal(listener.errors[0].isRetryable, true, 'Should not be a fatal error');
405405
assert.equal(manager.isRunning(), true, 'Should continue running during retries');
406406

407407
// Advance past second retry (delay: 200ms due to backoff)
@@ -420,7 +420,7 @@ describe('TokenManager', () => {
420420
assert.equal(manager.isRunning(), true, 'Should continue running after recovery');
421421
assert.equal(identityProvider.getRequestCount(), 4, 'Should have made exactly 4 requests');
422422

423-
disposable?.[Symbol.dispose]();
423+
disposable?.dispose();
424424
});
425425

426426
it('should stop after max retries exceeded', async () => {
@@ -435,7 +435,7 @@ describe('TokenManager', () => {
435435
maxDelayMs: 1000,
436436
backoffMultiplier: 2,
437437
jitterPercentage: 0,
438-
shouldRetry: (error: unknown) => error instanceof Error && error.message === 'Temporary failure'
438+
isRetryable: (error: unknown) => error instanceof Error && error.message === 'Temporary failure'
439439
}
440440
};
441441

@@ -470,7 +470,7 @@ describe('TokenManager', () => {
470470
// First error
471471
assert.equal(listener.errors.length, 1, 'Should have first error');
472472
assert.equal(manager.isRunning(), true, 'Should continue running after first error');
473-
assert.equal(listener.errors[0].isFatal, false, 'Should not be a fatal error');
473+
assert.equal(listener.errors[0].isRetryable, true, 'Should not be a fatal error');
474474

475475
// Advance past first retry
476476
await delay(100);
@@ -483,7 +483,7 @@ describe('TokenManager', () => {
483483
// Second error
484484
assert.equal(listener.errors.length, 2, 'Should have second error');
485485
assert.equal(manager.isRunning(), true, 'Should continue running after second error');
486-
assert.equal(listener.errors[1].isFatal, false, 'Should not be a fatal error');
486+
assert.equal(listener.errors[1].isRetryable, true, 'Should not be a fatal error');
487487

488488
// Advance past second retry
489489
await delay(200);
@@ -495,11 +495,11 @@ describe('TokenManager', () => {
495495

496496
// Should stop after max retries
497497
assert.equal(listener.errors.length, 3, 'Should have final error');
498-
assert.equal(listener.errors[2].isFatal, true, 'Should not be a fatal error');
498+
assert.equal(listener.errors[2].isRetryable, false, 'Should be a fatal error');
499499
assert.equal(manager.isRunning(), false, 'Should stop after max retries exceeded');
500500
assert.equal(identityProvider.getRequestCount(), 4, 'Should have made exactly 4 requests');
501501

502-
disposable?.[Symbol.dispose]();
502+
disposable?.dispose();
503503

504504
});
505505
});

0 commit comments

Comments
 (0)