Skip to content

Commit

Permalink
bug: rewrite metadata-token-service.ts
Browse files Browse the repository at this point in the history
  • Loading branch information
Alexey Zorkaltsev authored and Alexey Zorkaltsev committed Sep 28, 2023
1 parent b47248b commit 1492b04
Show file tree
Hide file tree
Showing 21 changed files with 2,215 additions and 438 deletions.
30 changes: 20 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
"scripts": {
"test": "jest -c config/jest.ts --passWithNoTests",
"coverage": "jest -c config/jest.coverage.ts --passWithNoTests",
"lint": "eslint src config",
"lint": "eslint src config --fix",
"build": "cross-env NODE_OPTIONS=\"--max-old-space-size=4096\" tsc -p .",
"generate-code": "ts-node scripts/generate-code.ts",
"prepare": "husky install",
Expand Down
2 changes: 1 addition & 1 deletion scripts/generate-code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as path from 'path';
import * as fg from 'fast-glob';
import * as _ from 'lodash';

import { logger } from '../src/utils/logger';
import { logger } from '../src/utils/simple-logger';
import { servicesConfig } from './services';

const GENERATED_CODE_DIR = path.resolve('./src/generated');
Expand Down
67 changes: 67 additions & 0 deletions src/__tests__/metadata-token-service/010.constructors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { MetadataTokenService } from '../../token-service/metadata-token-service';
import { buildTestLogger } from '../../utils/test-logger';
import Mock = jest.Mock;

const {
testLogger,
testLoggerFn,
} = buildTestLogger();

beforeEach(() => {
jest.spyOn(MetadataTokenService.prototype, 'getToken');
// so init sequenc whouldn't start in the constructor
(MetadataTokenService.prototype.getToken as Mock).mockReturnValue(Promise.resolve());
});

afterEach(() => {
testLoggerFn.mockReset();
});

describe('metadata-token-service.constructors', () => {
it('constructor: default', async () => {
const metadataTokenService = new MetadataTokenService({ logger: testLogger });

expect(testLoggerFn.mock.calls)
.toEqual([
['debug',
MetadataTokenService.Messages.debug_ctor,
MetadataTokenService.DEFAULT_URL,
false,
MetadataTokenService.DEFAULT_OPTIONS,
]]);
});

for (const url of [undefined, 'AnURL']) {
for (const doUpdateTokenInBackground of [undefined, true, false]) {
// eslint-disable-next-line @typescript-eslint/no-loop-func
it(`constructor: ${url} ${doUpdateTokenInBackground}`, async () => {
const metadataTokenService = url
? new MetadataTokenService(url, {
headers: {},
doUpdateTokenInBackground,
logger: testLogger,
})
: new MetadataTokenService({
headers: {},
doUpdateTokenInBackground,
logger: testLogger,
});

await metadataTokenService.dispose();

expect(testLoggerFn.mock.calls)
.toEqual([
['debug',
MetadataTokenService.Messages.debug_ctor,
url === undefined
? MetadataTokenService.DEFAULT_URL
: url,
doUpdateTokenInBackground === undefined ? false : doUpdateTokenInBackground,
{ headers: {} },
], ['trace',
MetadataTokenService.Messages.trace_dispose,
]]);
});
}
}
});
157 changes: 157 additions & 0 deletions src/__tests__/metadata-token-service/020.set-iam-response.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import { buildTestLogger } from '../../utils/test-logger';
import { MetadataTokenService } from '../../token-service/metadata-token-service';
import { FakeTimersFixture } from '../../utils/tests/fake-timers-fixture';
import {
TOKEN_LIFETIME_LEFT_TO_REFRESH_PCT,
TOKEN_LIFETIME_LEFT_TO_REPORT_ERROR_PCT,
TOKEN_MINIMUM_LIFETIME_MARGIN_MS,
} from '../../token-service/metadata-token-service.consts';
import { HRInterval } from '../../utils/hr-interval';
import IamGetTokenResponse = MetadataTokenService.IamGetTokenResponse;

describe('MetadataTokenService.setIamResponse', () => {
const fakeTimersFixture = new FakeTimersFixture();

const {
testLogger,
testLoggerFn,
} = buildTestLogger();

let metadataTokenService: MetadataTokenService;

beforeEach(() => {
fakeTimersFixture.setup();
metadataTokenService = new MetadataTokenService({ logger: testLogger });
testLoggerFn.mockReset();
});

afterEach(() => {
testLoggerFn.mockReset();
fakeTimersFixture.dispose();
});

it('general', async () => {
const TTL = 10 * 60 * 60; // sec

metadataTokenService.setIamResponse({
token_type: 'Bearer',
access_token: '123',
expires_in: TTL,
});

// @ts-ignore
expect((metadataTokenService as unknown).token)
.toBe('123');
// @ts-ignore
expect((metadataTokenService as unknown).tokenExpiresAt)
.toBe(Date.now() + (TTL * 1000) - TOKEN_MINIMUM_LIFETIME_MARGIN_MS);
// @ts-ignore
expect((metadataTokenService as unknown).tokenRefreshAt)
.toBe(Date.now() + (TTL * 1000) * (1 - TOKEN_LIFETIME_LEFT_TO_REFRESH_PCT / 100));
// @ts-ignore
expect((metadataTokenService as unknown).tokenStartReportTTLAt)
.toBe(Date.now() + (TTL * 1000) * (1 - TOKEN_LIFETIME_LEFT_TO_REPORT_ERROR_PCT / 100));

expect(testLoggerFn.mock.calls)
.toEqual([
[
'trace',
MetadataTokenService.Messages.trace_setIamResponse,
],
[
'debug',
MetadataTokenService.Messages.debug_new_token_was_received,
new HRInterval(36_000_000),
'',
],
]);
});

it('new token received after an error', async () => {
const TTL = 10 * 60 * 60; // sec

// @ts-ignore
(metadataTokenService as unknown).tokenLastError = {};

metadataTokenService.setIamResponse({
token_type: 'Bearer',
access_token: '123',
expires_in: TTL,
});

expect(testLoggerFn.mock.calls)
.toEqual([
[
'trace',
MetadataTokenService.Messages.trace_setIamResponse,
],
[
'info', // it's info, there was an error
MetadataTokenService.Messages.debug_new_token_was_received,
new HRInterval(36_000_000),
'',
],
]);
});

it('token with TTL less than allowed', async () => {
expect(() => metadataTokenService.setIamResponse({
token_type: 'Bearer',
access_token: '123',
expires_in: TOKEN_MINIMUM_LIFETIME_MARGIN_MS / 1000 / 2,
}))
.toThrow(new Error('insufficient lifetime: 00:07:30'));

expect(testLoggerFn.mock.calls)
.toEqual([
[
'trace',
MetadataTokenService.Messages.trace_setIamResponse,
],
[
'debug',
MetadataTokenService.Messages.debug_new_token_was_received,
new HRInterval(450_000),
' (too small TTL)',
],
]);
});

it('invalid token structure', async () => {
expect(() => metadataTokenService.setIamResponse(undefined as unknown as IamGetTokenResponse))
.toThrow(new Error('invalid iam token: undefined'));

expect(() => metadataTokenService.setIamResponse(null as unknown as IamGetTokenResponse))
.toThrow(new Error('invalid iam token: null'));

expect(() => metadataTokenService.setIamResponse({} as IamGetTokenResponse))
.toThrow(new Error('invalid iam token: {}'));

expect(() => metadataTokenService.setIamResponse({
token_type: 'Bearer',
expires_in: 'str',
} as unknown as IamGetTokenResponse))
.toThrow(new Error('invalid iam token: { token_type: \'Bearer\', expires_in: \'str\' }'));

expect(() => metadataTokenService.setIamResponse({
token_type: 'Bearer',
expires_in: -1,
} as unknown as IamGetTokenResponse))
.toThrow(new Error('invalid iam token: { token_type: \'Bearer\', expires_in: -1 }'));

expect(() => metadataTokenService.setIamResponse({
token_type: 'Bearer',
expires_in: 10 * 60 * 60,
access_token: 111,
} as unknown as IamGetTokenResponse))
.toThrow(new Error('invalid iam token: { token_type: \'Bearer\', expires_in: 36000, access_token: 111 }'));

expect(() => metadataTokenService.setIamResponse({
token_type: 'Bearer',
expires_in: 10 * 60 * 60,
access_token: '123',
} as unknown as IamGetTokenResponse))
.not
.toThrow();
});
});
Loading

0 comments on commit 1492b04

Please sign in to comment.