Skip to content

Commit

Permalink
feat(auth): add EntraId integration tests
Browse files Browse the repository at this point in the history
- 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 `@`
  • Loading branch information
bobymicroby committed Jan 27, 2025
1 parent ac972bd commit 5fa5406
Show file tree
Hide file tree
Showing 30 changed files with 718 additions and 211 deletions.
50 changes: 50 additions & 0 deletions .github/release-drafter/entraid-config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name-template: 'entraid@$NEXT_PATCH_VERSION'
tag-template: 'entraid@$NEXT_PATCH_VERSION'
autolabeler:
- label: 'chore'
files:
- '*.md'
- '.github/*'
- label: 'bug'
branch:
- '/bug-.+'
- label: 'chore'
branch:
- '/chore-.+'
- label: 'feature'
branch:
- '/feature-.+'
categories:
- title: 'Breaking Changes'
labels:
- 'breakingchange'
- title: '🚀 New Features'
labels:
- 'feature'
- 'enhancement'
- title: '🐛 Bug Fixes'
labels:
- 'fix'
- 'bugfix'
- 'bug'
- title: '🧰 Maintenance'
label:
- 'chore'
- 'maintenance'
- 'documentation'
- 'docs'

change-template: '- $TITLE (#$NUMBER)'
include-paths:
- 'packages/entraid'
exclude-labels:
- 'skip-changelog'
template: |
## Changes
$CHANGES
## Contributors
We'd like to thank all the contributors who worked on this release!
$CONTRIBUTORS
24 changes: 24 additions & 0 deletions .github/workflows/release-drafter-entraid.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Release Drafter

on:
push:
# branches to consider in the event; optional, defaults to all
branches:
- master

jobs:

update_release_draft:

permissions:
contents: write
pull-requests: write
runs-on: ubuntu-latest
steps:
# Drafts your next Release notes as Pull Requests are merged into "master"
- uses: release-drafter/release-drafter@v5
with:
# (Optional) specify config name to use, relative to .github/. Default: release-drafter.yml
config-name: release-drafter/entraid-config.yml
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
39 changes: 0 additions & 39 deletions packages/authx/package.json

This file was deleted.

21 changes: 0 additions & 21 deletions packages/authx/tsconfig.json

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@

import { Disposable } from './disposable';
/**
* Provides credentials asynchronously.
*/
Expand Down
6 changes: 6 additions & 0 deletions packages/client/lib/authx/disposable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* Represents a resource that can be disposed.
*/
export interface Disposable {
dispose(): void;
}
File renamed without changes.
10 changes: 6 additions & 4 deletions packages/authx/index.ts → packages/client/lib/authx/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export { TokenManager, TokenManagerConfig, TokenStreamListener, RetryPolicy, IDPError } from './lib/token-manager';
export { TokenManager, TokenManagerConfig, TokenStreamListener, RetryPolicy, IDPError } from './token-manager';
export {
CredentialsProvider,
StreamingCredentialsProvider,
Expand All @@ -8,6 +8,8 @@ export {
AsyncCredentialsProvider,
ReAuthenticationError,
BasicAuth
} from './lib/credentials-provider';
export { Token } from './lib/token';
export { IdentityProvider, TokenResponse } from './lib/identity-provider';
} from './credentials-provider';
export { Token } from './token';
export { IdentityProvider, TokenResponse } from './identity-provider';

export { Disposable } from './disposable'
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ describe('TokenManager', () => {
assert.equal(listener.errors.length, 0, 'Should not have any errors');
assert.equal(manager.getCurrentToken().value, 'token3', 'Should have current token');

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

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

disposable?.[Symbol.dispose]();
disposable?.dispose();
});

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

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

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

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

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

disposable?.[Symbol.dispose]();
disposable?.dispose();
});

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

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

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

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

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

disposable?.[Symbol.dispose]();
disposable?.dispose();

});
});
Expand Down
Loading

0 comments on commit 5fa5406

Please sign in to comment.