Skip to content

Commit e52c416

Browse files
committed
tests: added unit tests
1 parent a2de862 commit e52c416

File tree

4 files changed

+471
-50
lines changed

4 files changed

+471
-50
lines changed

Diff for: packages/parameters/src/BaseProvider.ts

+45-38
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import { fromBase64 } from '@aws-sdk/util-base64-node';
2-
import { GetParameterError, TransformParameterError } from 'Exceptions';
3-
import type { BaseProviderInterface, ExpirableValueInterface, GetMultipleOptionsInterface, GetOptionsInterface, Key, TransformOptions } from './types';
2+
import { GetParameterError, TransformParameterError } from './Exceptions';
3+
import type { BaseProviderInterface, ExpirableValueInterface, GetMultipleOptionsInterface, GetOptionsInterface, TransformOptions } from './types';
44

55
const DEFAULT_MAX_AGE_SECS = 5;
6-
// These providers will be dynamically initialized on first use of the helper functions
7-
const DEFAULT_PROVIDERS = new Map();
86
const TRANSFORM_METHOD_JSON = 'json';
97
const TRANSFORM_METHOD_BINARY = 'binary';
108

@@ -23,7 +21,7 @@ class GetMultipleOptions implements GetMultipleOptionsInterface {
2321
public forceFetch: boolean = false;
2422
public maxAge: number = DEFAULT_MAX_AGE_SECS;
2523
public sdkOptions?: unknown;
26-
public throwOnTransformError?: boolean = false;
24+
public throwOnTransformError: boolean = false;
2725
public transform?: TransformOptions;
2826

2927
public constructor(options: GetMultipleOptionsInterface) {
@@ -47,13 +45,13 @@ class ExpirableValue implements ExpirableValueInterface {
4745
}
4846

4947
abstract class BaseProvider implements BaseProviderInterface {
50-
public store: Map<Key, ExpirableValue> = new Map;
48+
public store: Map<string, ExpirableValue> = new Map;
5149

52-
private constructor () {
50+
public constructor () {
5351
this.store = new Map();
5452
}
5553

56-
public addToCache(key: Key, value: string | Record<string, unknown>, maxAge: number): void {
54+
public addToCache(key: string, value: string | Record<string, unknown>, maxAge: number): void {
5755
if (maxAge <= 0) return;
5856

5957
this.store.set(key, new ExpirableValue(value, maxAge));
@@ -79,10 +77,11 @@ abstract class BaseProvider implements BaseProviderInterface {
7977
*/
8078
public async get(name: string, options?: GetOptionsInterface): Promise<undefined | string | Record<string, unknown>> {
8179
const configs = new GetOptions(options);
82-
const key = { [name]: configs.transform };
80+
const key = [ name, configs.transform ].toString();
8381

84-
if (!configs.forceFetch && this.hasNotExpiredInCache(key)) {
85-
return this.store.get(key)?.value;
82+
if (!configs.forceFetch && !this.hasKeyExpiredInCache(key)) {
83+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
84+
return this.store.get(key)!.value;
8685
}
8786

8887
let value;
@@ -93,7 +92,7 @@ abstract class BaseProvider implements BaseProviderInterface {
9392
}
9493

9594
if (value && configs.transform) {
96-
value = transformValue(value, configs.transform);
95+
value = transformValue(value, configs.transform, true);
9796
}
9897

9998
if (value) {
@@ -106,10 +105,11 @@ abstract class BaseProvider implements BaseProviderInterface {
106105

107106
public async getMultiple(path: string, options?: GetMultipleOptionsInterface): Promise<undefined | Record<string, unknown>> {
108107
const configs = new GetMultipleOptions(options || {});
109-
const key = { [path]: configs.transform };
108+
const key = [ path, configs.transform ].toString();
110109

111-
if (!configs.forceFetch && this.hasNotExpiredInCache(key)) {
112-
return this.store.get(key)?.value as Record<string, unknown>; // In this case we know that if it exists, this key corresponds to a Record
110+
if (!configs.forceFetch && !this.hasKeyExpiredInCache(key)) {
111+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
112+
return this.store.get(key)!.value as Record<string, unknown>; // In this case we know that if it exists, this key corresponds to a Record
113113
}
114114

115115
let values: Record<string, unknown> = {};
@@ -119,8 +119,8 @@ abstract class BaseProvider implements BaseProviderInterface {
119119
throw new GetParameterError((error as Error).message);
120120
}
121121

122-
if (configs.transform) {
123-
values = transformValues(values, configs.transform);
122+
if (Object.keys(values) && configs.transform) {
123+
values = transformValues(values, configs.transform, configs.throwOnTransformError);
124124
}
125125

126126
if (Array.from(Object.keys(values)).length !== 0) {
@@ -142,36 +142,48 @@ abstract class BaseProvider implements BaseProviderInterface {
142142
protected abstract _getMultiple(path: string, sdkOptions?: unknown): Promise<Record<string, string|undefined>>;
143143

144144
/**
145-
* Check whether a key has not expired in the cache
145+
* Check whether a key has expired in the cache or not
146146
*
147-
* It returns false if the key is expired or not present in the cache.
147+
* It returns true if the key is expired or not present in the cache.
148148
*
149-
* @param {Key} key - Key to retrieve
149+
* @param {string} key - Stringified representation of the key to retrieve
150150
*/
151-
private hasNotExpiredInCache(key: Key): boolean {
151+
private hasKeyExpiredInCache(key: string): boolean {
152152
const value = this.store.get(key);
153-
if (value) value.isExpired();
153+
if (value) {
154+
if (value.isExpired()) {
155+
this.store.delete(key);
156+
157+
return true;
158+
}
154159

155-
return false;
160+
return value.isExpired();
161+
}
162+
163+
return true;
156164
}
157165

158166
}
159167

160-
const transformValue = (value: string, transform: TransformOptions, throwOnTransformError: boolean = true, key: string = ''): string | Record<string, unknown> | undefined => {
168+
// TODO: revisit `value` type once we are clearer on the types returned by the various SDKs
169+
const transformValue = (value: unknown, transform: TransformOptions, throwOnTransformError: boolean, key: string = ''): string | Record<string, unknown> | undefined => {
161170
try {
162171
const normalizedTransform = transform.toLowerCase();
163172
if (
164-
normalizedTransform === TRANSFORM_METHOD_JSON ||
165-
(normalizedTransform === 'auto' && key.toLowerCase().endsWith(`.${TRANSFORM_METHOD_JSON}`))
173+
(normalizedTransform === TRANSFORM_METHOD_JSON ||
174+
(normalizedTransform === 'auto' && key.toLowerCase().endsWith(`.${TRANSFORM_METHOD_JSON}`))) &&
175+
typeof value === 'string'
166176
) {
167177
return JSON.parse(value) as Record<string, unknown>;
168178
} else if (
169-
normalizedTransform === TRANSFORM_METHOD_BINARY ||
170-
(normalizedTransform === 'auto' && key.toLowerCase().endsWith(`.${TRANSFORM_METHOD_BINARY}`))
179+
(normalizedTransform === TRANSFORM_METHOD_BINARY ||
180+
(normalizedTransform === 'auto' && key.toLowerCase().endsWith(`.${TRANSFORM_METHOD_BINARY}`))) &&
181+
typeof value === 'string'
171182
) {
172183
return new TextDecoder('utf-8').decode(fromBase64(value));
173184
} else {
174-
throw Error(`Invalid transform type ${normalizedTransform}.`);
185+
// TODO: revisit this type once we are clearer on types returned by SDKs
186+
return value as string;
175187
}
176188
} catch (error) {
177189
if (throwOnTransformError)
@@ -181,27 +193,22 @@ const transformValue = (value: string, transform: TransformOptions, throwOnTrans
181193
}
182194
};
183195

184-
const transformValues = (value: string | Uint8Array | Record<string, unknown>, transform: TransformOptions, throwOnTransformError: boolean = true): Record<string, unknown> => {
196+
const transformValues = (value: Record<string, unknown>, transform: TransformOptions, throwOnTransformError: boolean): Record<string, unknown> => {
185197
const transformedValues: Record<string, unknown> = {};
186-
for (const entry in Object.entries(value)) {
187-
const [ entryKey, entryValue ] = entry;
198+
for (const [ entryKey, entryValue ] of Object.entries(value)) {
188199
try {
189-
transformedValues[entryKey] = transformValue(entryValue, transform, true, entryKey);
200+
transformedValues[entryKey] = transformValue(entryValue, transform, throwOnTransformError, entryKey);
190201
} catch (error) {
191202
if (throwOnTransformError)
192203
throw new TransformParameterError(transform, (error as Error).message);
193-
transformedValues[entryKey] = undefined;
194204
}
195205
}
196206

197207
return transformedValues;
198208
};
199209

200-
const clearCaches = (): void => DEFAULT_PROVIDERS.clear();
201-
202210
export {
203-
clearCaches,
204211
BaseProvider,
212+
ExpirableValue,
205213
transformValue,
206-
DEFAULT_PROVIDERS
207214
};

Diff for: packages/parameters/src/index.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
export * from './BaseProvider';
1+
export * from './BaseProvider';
2+
export * from './Exceptions';

Diff for: packages/parameters/src/types/BaseProvider.ts

-11
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,6 @@ interface GetMultipleOptionsInterface {
1515
throwOnTransformError?: boolean
1616
}
1717

18-
interface Key {
19-
[key: string]: TransformOptions | undefined
20-
}
21-
2218
interface ExpirableValueInterface {
2319
value: string | Record<string, unknown>
2420
ttl: number
@@ -29,17 +25,10 @@ interface BaseProviderInterface {
2925
getMultiple(path: string, options?: GetMultipleOptionsInterface): Promise<void | Record<string, unknown>>
3026
}
3127

32-
type TransformValueFn = {
33-
(value: string | Uint8Array, transform: TransformOptions, throwOnTransformError?: boolean, key?: string): string | Record<string, unknown> | undefined
34-
(value: Record<string, unknown>, transform: TransformOptions, throwOnTransformError?: boolean, key?: string): Record<string, unknown>
35-
};
36-
3728
export {
38-
Key,
3929
GetOptionsInterface,
4030
GetMultipleOptionsInterface,
4131
BaseProviderInterface,
4232
ExpirableValueInterface,
4333
TransformOptions,
44-
TransformValueFn
4534
};

0 commit comments

Comments
 (0)