generated from jsynowiec/node-typescript-boilerplate
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Making the poller restart the configuration session if there's an error.
- Loading branch information
Showing
4 changed files
with
234 additions
and
57 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,48 +1,171 @@ | ||
import { Poller } from '../src/poller.js'; | ||
import { Poller, PollerConfig } from '../src/poller.js'; | ||
import { | ||
AppConfigDataClient, | ||
GetLatestConfigurationCommand, | ||
StartConfigurationSessionCommand, | ||
} from '@aws-sdk/client-appconfigdata'; | ||
import { mockClient } from 'aws-sdk-client-mock'; | ||
import { AwsError, mockClient } from 'aws-sdk-client-mock'; | ||
import { Uint8ArrayBlobAdapter } from '@smithy/util-stream'; | ||
|
||
const standardConfig: Omit<PollerConfig<string>, 'dataClient'> = { | ||
sessionConfig: { | ||
ApplicationIdentifier: 'MyApp', | ||
EnvironmentIdentifier: 'Test', | ||
ConfigurationProfileIdentifier: 'Config1', | ||
}, | ||
configParser: (s: string) => s.substring(1), | ||
pollIntervalSeconds: 1, | ||
}; | ||
|
||
function wait(ms: number): Promise<void> { | ||
return new Promise((resolve) => setTimeout(resolve, ms)); | ||
} | ||
|
||
describe('Poller', () => { | ||
const appConfigClientMock = mockClient(AppConfigDataClient); | ||
|
||
const configValue = 'Some Configuration'; | ||
let poller: Poller<string> | undefined; | ||
|
||
appConfigClientMock.on(StartConfigurationSessionCommand).resolves({ | ||
InitialConfigurationToken: 'initialToken', | ||
afterEach(() => { | ||
poller.stop(); | ||
appConfigClientMock.reset(); | ||
}); | ||
|
||
appConfigClientMock.on(GetLatestConfigurationCommand).resolves({ | ||
Configuration: Uint8ArrayBlobAdapter.fromString(configValue), | ||
it('Polls', async () => { | ||
const configValue = 'Some Configuration'; | ||
|
||
appConfigClientMock.on(StartConfigurationSessionCommand).resolves({ | ||
InitialConfigurationToken: 'initialToken', | ||
}); | ||
|
||
appConfigClientMock.on(GetLatestConfigurationCommand).resolves({ | ||
Configuration: Uint8ArrayBlobAdapter.fromString(configValue), | ||
}); | ||
|
||
const dataClient = new AppConfigDataClient(); | ||
|
||
poller = new Poller({ | ||
dataClient: dataClient, | ||
...standardConfig, | ||
}); | ||
|
||
await poller.start(); | ||
const latest = poller.getConfigurationString(); | ||
|
||
expect(latest.latestValue).toEqual(configValue); | ||
expect(latest.errorCausingStaleValue).toBeUndefined(); | ||
}); | ||
|
||
const dataClient = new AppConfigDataClient(); | ||
it('Bubbles up error on startup', async () => { | ||
appConfigClientMock.on(StartConfigurationSessionCommand).rejects({ | ||
message: 'Failed to start session', | ||
} as AwsError); | ||
|
||
let poller: Poller<string> | undefined; | ||
const dataClient = new AppConfigDataClient(); | ||
|
||
afterAll(() => { | ||
poller.stop(); | ||
poller = new Poller({ | ||
dataClient: dataClient, | ||
...standardConfig, | ||
}); | ||
|
||
await expect(poller.start()).rejects.toThrow(Error); | ||
}); | ||
|
||
it('Polls', async () => { | ||
it('Bubbles up error if first getLatest fails', async () => { | ||
appConfigClientMock.on(StartConfigurationSessionCommand).resolves({ | ||
InitialConfigurationToken: 'initialToken', | ||
}); | ||
|
||
appConfigClientMock.on(GetLatestConfigurationCommand).rejects({ | ||
message: 'Failed to get latest', | ||
}); | ||
|
||
const dataClient = new AppConfigDataClient(); | ||
|
||
poller = new Poller({ | ||
dataClient: dataClient, | ||
sessionConfig: { | ||
ApplicationIdentifier: 'MyApp', | ||
EnvironmentIdentifier: 'Test', | ||
ConfigurationProfileIdentifier: 'Config1', | ||
...standardConfig, | ||
}); | ||
|
||
await expect(poller.start()).rejects.toThrow(Error); | ||
}); | ||
|
||
it('Continues polling if first getLatest string cannot be parsed', async () => { | ||
appConfigClientMock.on(StartConfigurationSessionCommand).resolves({ | ||
InitialConfigurationToken: 'initialToken', | ||
}); | ||
|
||
appConfigClientMock.on(GetLatestConfigurationCommand).resolves({ | ||
Configuration: Uint8ArrayBlobAdapter.fromString('abc'), | ||
}); | ||
|
||
const dataClient = new AppConfigDataClient(); | ||
|
||
poller = new Poller({ | ||
dataClient: dataClient, | ||
...standardConfig, | ||
configParser(s): string { | ||
throw new Error('bad string ' + s); | ||
}, | ||
logger: console.log, | ||
}); | ||
|
||
await poller.start(); | ||
|
||
const str = poller.getConfigurationString(); | ||
expect(str.latestValue).toBeDefined(); | ||
|
||
const obj = poller.getConfigurationObject(); | ||
expect(obj.latestValue).toBeUndefined(); | ||
expect(obj.errorCausingStaleValue).toBeDefined(); | ||
}); | ||
|
||
it('Attempts session restart if second fetch fails', async () => { | ||
const configValue = 'worked once'; | ||
const configValue2 = 'worked again'; | ||
|
||
appConfigClientMock.on(StartConfigurationSessionCommand).resolves({ | ||
InitialConfigurationToken: 'initialToken', | ||
}); | ||
|
||
appConfigClientMock | ||
.on(GetLatestConfigurationCommand) | ||
.resolvesOnce({ | ||
Configuration: Uint8ArrayBlobAdapter.fromString(configValue), | ||
}) | ||
.rejectsOnce({ | ||
message: 'Failed to get latest', | ||
}) | ||
.resolves({ | ||
Configuration: Uint8ArrayBlobAdapter.fromString(configValue2), | ||
}); | ||
|
||
const dataClient = new AppConfigDataClient(); | ||
|
||
poller = new Poller({ | ||
dataClient: dataClient, | ||
...standardConfig, | ||
}); | ||
|
||
await poller.start(); | ||
const latest = poller.getConfigurationString(); | ||
|
||
expect(latest.latestValue).toEqual(configValue); | ||
expect(latest.errorCausingStaleValue).toBeUndefined(); | ||
|
||
await wait(standardConfig.pollIntervalSeconds * 1000 + 100); | ||
|
||
const updated = poller.getConfigurationObject(); | ||
expect(updated.errorCausingStaleValue).toBeDefined(); | ||
expect(updated.latestValue).toEqual( | ||
standardConfig.configParser(configValue), | ||
); | ||
|
||
await wait(standardConfig.pollIntervalSeconds * 1000 + 100); | ||
|
||
const updatedAgain = poller.getConfigurationObject(); | ||
expect(updatedAgain.errorCausingStaleValue).toBeUndefined(); | ||
expect(updatedAgain.latestValue).toEqual( | ||
standardConfig.configParser(configValue2), | ||
); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.