Skip to content

Commit

Permalink
chore: configuration test additions (#588)
Browse files Browse the repository at this point in the history
  • Loading branch information
basmasking authored Dec 24, 2024
1 parent 95b14c1 commit dcd6ac1
Show file tree
Hide file tree
Showing 29 changed files with 448 additions and 28 deletions.
2 changes: 1 addition & 1 deletion .sonar-project.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
sonar.projectKey=jitar
sonar.projectName=jitar
sonar.langugage=typescript
sonar.language=typescript

# Path to sources
sonar.sources=packages/**/src
Expand Down
4 changes: 3 additions & 1 deletion packages/configuration/src/ConfigurationManager.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

import { Validator } from '@jitar/validation';
import { LocalFileManager } from '@jitar/sourcing';

import { EnvironmentConfigurator } from './environment';
import { RuntimeConfiguration, RuntimeConfigurationBuilder } from './runtime';
Expand All @@ -17,7 +18,8 @@ export default class ConfigurationManager

constructor(rootPath: string = DEFAULT_ROOT_PATH)
{
const reader = new ConfigurationReader(rootPath);
const fileManager = new LocalFileManager(rootPath);
const reader = new ConfigurationReader(fileManager);
const validator = new Validator();

this.#environmentConfigurator = new EnvironmentConfigurator();
Expand Down
1 change: 1 addition & 0 deletions packages/configuration/src/runtime/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

export { default as RuntimeConfigurationInvalid } from './errors/RuntimeConfigurationInvalid';
export { default as RuntimeConfiguration } from './definitions/RuntimeConfiguration';
export { default as RuntimeConfigurationBuilder } from './ConfigurationBuilder';
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { ValidationScheme } from '@jitar/validation';

type GatewayConfiguration =
{
monitor: number;
monitor?: number;
trustKey?: string;
};

Expand Down
2 changes: 2 additions & 0 deletions packages/configuration/src/server/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@

export { default as ServerConfigurationInvalid } from './errors/ServerConfigurationInvalid';

export { default as ServerConfiguration } from './definitions/ServerConfiguration';
export { default as StandaloneConfiguration } from './definitions/StandaloneConfiguration';
export { default as ProxyConfiguration } from './definitions/ProxyConfiguration';
Expand Down
25 changes: 12 additions & 13 deletions packages/configuration/src/utils/ConfigurationReader.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@

import { LocalFileManager } from '@jitar/sourcing';
import type { FileManager } from '@jitar/sourcing';

import InvalidFileType from './errors/InvalidConfigurationFile';

const ENVIRONMENT_VARIABLE_REGEX = /\${([^}]*)}/g;

export default class ConfigurationReader
{
readonly #fileManager: FileManager;

constructor(rootPath: string)
constructor(fileManager: FileManager)
{
this.#fileManager = new LocalFileManager(rootPath);
this.#fileManager = fileManager;
}

async read(filename: string): Promise<Record<string, unknown>>
Expand All @@ -23,12 +24,16 @@ export default class ConfigurationReader
}

const file = await this.#fileManager.read(filename);

if (file.type.includes('json') === false)
{
throw new InvalidFileType(filename);
}

const content = file.content.toString();
const configuration = this.#replaceEnvironmentVariables(content);

return file.type.includes('json')
? this.#parseJson(configuration)
: this.#parseText(configuration);

return this.#parseJson(configuration);
}

#replaceEnvironmentVariables(content: string): string
Expand All @@ -43,10 +48,4 @@ export default class ConfigurationReader
{
return JSON.parse(configuration);
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
#parseText(configuration: string): Record<string, unknown>
{
return {};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

export default class InvalidConfigurationFile extends Error
{
constructor(filename: string)
{
super(`${filename} is not a valid configuration file.`);
}
}
1 change: 1 addition & 0 deletions packages/configuration/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@

export { default as InvalidConfigurationFile } from './errors/InvalidConfigurationFile';
export { default as ConfigurationReader } from './ConfigurationReader';
12 changes: 0 additions & 12 deletions packages/configuration/test/dummy.spec.ts

This file was deleted.

10 changes: 10 additions & 0 deletions packages/configuration/test/environment/Configurator.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

import { describe, expect, it } from 'vitest';

describe('Configurator', () =>
{
it('should not test standard library functions', async () =>
{
expect(true).toBeTruthy();
});
});
86 changes: 86 additions & 0 deletions packages/configuration/test/fixtures/fileManager.fixture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@

import { File, FileManager } from '@jitar/sourcing';

export default class TestFileManager implements FileManager
{
readonly #files: Record<string, File>;

constructor(files: Record<string, File>)
{
this.#files = files;
}

getRootLocation(): string
{
throw new Error('Method not implemented.');
}

getAbsoluteLocation(filename: string): string
{
throw new Error('Method not implemented.');
}

getRelativeLocation(filename: string): string
{
throw new Error('Method not implemented.');
}

getType(filename: string): Promise<string>
{
throw new Error('Method not implemented.');
}

getContent(filename: string): Promise<Buffer | string>
{
throw new Error('Method not implemented.');
}

exists(filename: string): Promise<boolean>
{
for (const key in this.#files)
{
const value = this.#files[key];

if (value.location === filename)
{
return Promise.resolve(true);
}
}

return Promise.resolve(false);
}

read(filename: string): Promise<File>
{
let file: File | undefined;

for (const key in this.#files)
{
const value = this.#files[key];

if (value.location === filename)
{
file = value;

break;
}
}

return Promise.resolve(file as File);
}

write(filename: string, content: string): Promise<void>
{
throw new Error('Method not implemented.');
}

delete(filename: string): Promise<void>
{
throw new Error('Method not implemented.');
}

filter(pattern: string): Promise<string[]>
{
throw new Error('Method not implemented.');
}
}
2 changes: 2 additions & 0 deletions packages/configuration/test/fixtures/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

export { default as FileManager } from './fileManager.fixture';
35 changes: 35 additions & 0 deletions packages/configuration/test/runtime/ConfigurationBuilder.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@

import { describe, expect, it } from 'vitest';

import { configurationBuilder, FILENAMES, CONFIGURATIONS, RuntimeConfigurationInvalid, VALIDATION_RESULT } from './fixtures';

describe('runtime/ConfigurationBuilder', () =>
{
it('should build a default runtime configuration without configuration file', async () =>
{
const promise = configurationBuilder.build();

await expect(promise).resolves.toEqual(CONFIGURATIONS.DEFAULT);
});

it('should build a valid runtime configuration from a valid file', async () =>
{
const promise = configurationBuilder.build(FILENAMES.VALID);

await expect(promise).resolves.toEqual(CONFIGURATIONS.RUNTIME);
});

it('should build a default runtime when the configuration file does not exist', async () =>
{
const promise = configurationBuilder.build(FILENAMES.MISSING);

await expect(promise).resolves.toEqual(CONFIGURATIONS.DEFAULT);
});

it('should reject an invalid runtime configuration', async () =>
{
const promise = configurationBuilder.build(FILENAMES.INVALID);

await expect(promise).rejects.toEqual(new RuntimeConfigurationInvalid(VALIDATION_RESULT));
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@

import { RuntimeConfiguration } from '../../../src/runtime';

const defaultConfiguration: RuntimeConfiguration =
{
source: './src',
target: './dist',
} as const;

const runtimeConfiguration: RuntimeConfiguration =
{
source: './source',
target: './target',
} as const;

const invalidConfiguration: any =
{
invalid: true
} as const;

export const CONFIGURATIONS: Record<string, RuntimeConfiguration> =
{
DEFAULT: defaultConfiguration,
RUNTIME: runtimeConfiguration,
INVALID: invalidConfiguration,
} as const;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

export const FILENAMES = {
DEFAULT: './jitar.json',
VALID: 'valid-runtime-configuration.json',
INVALID: 'invalid-runtime-configuration.json',
MISSING: 'missing-runtime-configuration.json',
} as const;
12 changes: 12 additions & 0 deletions packages/configuration/test/runtime/fixtures/files.fixture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

import { File } from '@jitar/sourcing';

import { CONFIGURATIONS } from './configuration.fixture';
import { FILENAMES } from './filenames.fixture';

export const FILES: Record<string, File> =
{
DEFAULT: new File(FILENAMES.DEFAULT, 'text/json', JSON.stringify(CONFIGURATIONS.DEFAULT)),
VALID: new File(FILENAMES.VALID, 'text/json', JSON.stringify(CONFIGURATIONS.RUNTIME)),
INVALID: new File(FILENAMES.INVALID, 'text/json', JSON.stringify(CONFIGURATIONS.INVALID))
} as const;
21 changes: 21 additions & 0 deletions packages/configuration/test/runtime/fixtures/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@

import { Validator } from '@jitar/validation';

import { RuntimeConfigurationBuilder } from '../../../src/runtime';
import RuntimeConfigurationInvalid from '../../../src/runtime/errors/RuntimeConfigurationInvalid';
import { ConfigurationReader } from '../../../src/utils';

import { FileManager } from '../../fixtures';

import { FILES } from './files.fixture';
import { FILENAMES } from './filenames.fixture';
import { CONFIGURATIONS } from './configuration.fixture';
import { VALIDATION_RESULT } from './validation.fixture';

const fileManager = new FileManager(FILES);
const configurationReader = new ConfigurationReader(fileManager);
const validator = new Validator();

const configurationBuilder = new RuntimeConfigurationBuilder(configurationReader, validator);

export { configurationBuilder, FILENAMES, CONFIGURATIONS, RuntimeConfigurationInvalid, VALIDATION_RESULT };
12 changes: 12 additions & 0 deletions packages/configuration/test/runtime/fixtures/validation.fixture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

import { ValidationResult } from "@jitar/validation";

const VALIDATION_RESULT: ValidationResult =
{
valid: false,
errors: [
"Unknown field 'invalid'",
]
} as const;

export { VALIDATION_RESULT };
21 changes: 21 additions & 0 deletions packages/configuration/test/server/ConfigurationBuilder.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@

import { describe, expect, it } from 'vitest';

import { configurationBuilder, FILENAMES, SERVER_CONFIGURATION, ServerConfigurationInvalid, VALIDATION_RESULT } from './fixtures';

describe('server/ConfigurationBuilder', () =>
{
it('should build a valid server configuration', async () =>
{
const promise = configurationBuilder.build(FILENAMES.VALID_CONFIGURATION);

await expect(promise).resolves.toEqual(SERVER_CONFIGURATION);
});

it('should reject an invalid server configuration', async () =>
{
const promise = configurationBuilder.build(FILENAMES.INVALID_CONFIGURATION);

await expect(promise).rejects.toEqual(new ServerConfigurationInvalid(VALIDATION_RESULT));
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

import type { GatewayConfiguration, ProxyConfiguration, RepositoryConfiguration, ServerConfiguration, StandaloneConfiguration, WorkerConfiguration } from '../../../src/server';

const serveIndexOnNotFound = true;
const assets = ['index.html', 'favicon.ico'];
const segments = ['segment'];
const indexFilename = 'index.html';
const trustKey = 'trust-key';
const gateway = 'https://gateway';
const repository = 'https://repository';

const gatewayConfiguration: GatewayConfiguration = { monitor: 5000, trustKey } as const;
const proxyConfiguration: ProxyConfiguration = { gateway, repository } as const;
const repositoryConfiguration: RepositoryConfiguration = { indexFilename, serveIndexOnNotFound, assets } as const;
const standaloneConfiguration: StandaloneConfiguration = { segments, indexFilename, serveIndexOnNotFound, assets } as const;
const workerConfiguration: WorkerConfiguration = { gateway, segments, trustKey } as const;

export const SERVER_CONFIGURATION: ServerConfiguration =
{
url: 'https://server',
setUp: ['setup'],
tearDown: ['tearDown'],
middleware: ['middleware'],
healthChecks: ['healthChecks'],

gateway: gatewayConfiguration,
proxy: proxyConfiguration,
repository: repositoryConfiguration,
standalone: standaloneConfiguration,
worker: workerConfiguration
} as const;
Loading

0 comments on commit dcd6ac1

Please sign in to comment.