|
- import {IncomingHttpHeaders, IncomingMessage, OutgoingHttpHeaders, request, RequestOptions} from 'http';
- import {Method, DataSource} from '../src/backend';
- import {FALLBACK_LANGUAGE, Language} from '../src/common';
-
- interface ClientParams {
- method: Method;
- path: string;
- headers?: IncomingHttpHeaders;
- body?: unknown;
- }
-
- type ResponseBody = Buffer | string | object;
-
- export interface TestClient {
- (params: ClientParams): Promise<[IncomingMessage, ResponseBody?]>;
- acceptMediaType(mediaType: string): this;
- acceptLanguage(language: string): this;
- acceptCharset(charset: string): this;
- contentType(mediaType: string): this;
- contentCharset(charset: string): this;
- }
-
- export const createTestClient = (options: Omit<RequestOptions, 'method' | 'path'>): TestClient => {
- const additionalHeaders: OutgoingHttpHeaders = {};
- const client = (params: ClientParams) => new Promise<[IncomingMessage, ResponseBody?]>((resolve, reject) => {
- const {
- ...etcAdditionalHeaders
- } = additionalHeaders;
-
- // odd that request() uses OutgoingHttpHeaders instead of IncomingHttpHeaders...
- const headers: OutgoingHttpHeaders = {
- ...(options.headers ?? {}),
- ...etcAdditionalHeaders,
- };
-
- let contentTypeHeader: string | undefined;
- if (typeof params.body !== 'undefined') {
- contentTypeHeader = headers['content-type'] = params.headers?.['content-type'] ?? 'application/json';
- }
-
- const req = request({
- ...options,
- method: params.method,
- path: params.path,
- headers,
- });
-
- req.on('response', (res) => {
- res.on('error', (err) => {
- reject(err);
- });
-
- let resBuffer: Buffer | undefined;
- res.on('data', (c) => {
- resBuffer = (
- typeof resBuffer === 'undefined'
- ? Buffer.from(c)
- : Buffer.concat([resBuffer, c])
- );
- });
-
- res.on('close', () => {
- const acceptHeader = Array.isArray(headers['accept']) ? headers['accept'].join('; ') : headers['accept'];
- const contentTypeBase = acceptHeader ?? 'application/octet-stream';
- const [type, subtype] = contentTypeBase.split('/');
- const allSubtypes = subtype.split('+');
- if (typeof resBuffer !== 'undefined') {
- if (allSubtypes.includes('json')) {
- const acceptCharset = (
- Array.isArray(headers['accept-charset'])
- ? headers['accept-charset'].join('; ')
- : headers['accept-charset']
- ) as BufferEncoding | undefined;
- resolve([res, JSON.parse(resBuffer.toString(acceptCharset ?? 'utf-8'))]);
- return;
- }
-
- if (type === 'text') {
- const acceptCharset = (
- Array.isArray(headers['accept-charset'])
- ? headers['accept-charset'].join('; ')
- : headers['accept-charset']
- ) as BufferEncoding | undefined;
- resolve([res, resBuffer.toString(acceptCharset ?? 'utf-8')]);
- return;
- }
-
- resolve([res, resBuffer]);
- return;
- }
-
- resolve([res]);
- });
- });
-
- req.on('error', (err) => {
- reject(err);
- })
-
- if (typeof params.body !== 'undefined') {
- const theContentTypeHeader = Array.isArray(contentTypeHeader) ? contentTypeHeader.join('; ') : contentTypeHeader?.toString();
- const contentTypeAll = theContentTypeHeader ?? 'application/octet-stream';
- const [contentTypeBase, ...contentTypeParams] = contentTypeAll.split(';').map((s) => s.replace(/\s+/g, '').trim());
- const charsetParam = contentTypeParams.find((s) => s.startsWith('charset='));
- const charset = charsetParam?.split('=')?.[1] as BufferEncoding | undefined;
- const [, subtype] = contentTypeBase.split('/');
- const allSubtypes = subtype.split('+');
- req.write(
- allSubtypes.includes('json')
- ? JSON.stringify(params.body)
- : Buffer.from(params.body?.toString() ?? '', contentTypeBase === 'text' ? charset : undefined)
- );
- }
-
- req.end();
- });
-
- client.acceptMediaType = function acceptMediaType(mediaType: string) {
- additionalHeaders['accept'] = mediaType;
- return this;
- };
-
- client.acceptLanguage = function acceptLanguage(language: string) {
- additionalHeaders['accept-language'] = language;
- return this;
- };
-
- client.acceptCharset = function acceptCharset(charset: string) {
- additionalHeaders['accept-charset'] = charset;
- return this;
- };
-
- client.contentType = function contentType(mediaType: string) {
- additionalHeaders['content-type'] = mediaType;
- return this;
- };
-
- client.contentCharset = function contentCharset(charset: string) {
- additionalHeaders['content-type'] = `${additionalHeaders['content-type']}; charset="${charset}"`;
- return this;
- };
-
- return client;
- };
-
- export const dummyGenerationStrategy = () => Promise.resolve();
-
- export class DummyError extends Error {}
-
- export class DummyDataSource implements DataSource {
- private resource?: { dataSource?: unknown };
-
- async create(): Promise<object> {
- return {};
- }
-
- async delete(): Promise<void> {}
-
- async emplace(): Promise<[object, boolean]> {
- return [{}, false];
- }
-
- async getById(): Promise<object> {
- return {};
- }
-
- async newId(): Promise<string> {
- return '';
- }
-
- async getMultiple(): Promise<object[]> {
- return [];
- }
-
- async getSingle(): Promise<object> {
- return {};
- }
-
- async getTotalCount(): Promise<number> {
- return 0;
- }
-
- async initialize(): Promise<void> {}
-
- async patch(): Promise<object> {
- return {};
- }
-
- prepareResource(rr: unknown) {
- this.resource = rr as unknown as { dataSource: DummyDataSource };
- this.resource.dataSource = this;
- }
- }
-
- export const TEST_LANGUAGE: Language = {
- name: FALLBACK_LANGUAGE.name,
- statusMessages: {
- unableToSerializeResponse: 'Unable To Serialize Response',
- unableToEncodeResponse: 'Unable To Encode Response',
- unableToBindResourceDataSource: 'Unable To Bind $RESOURCE Data Source',
- unableToInitializeResourceDataSource: 'Unable To Initialize $RESOURCE Data Source',
- unableToFetchResourceCollection: 'Unable To Fetch $RESOURCE Collection',
- unableToFetchResource: 'Unable To Fetch $RESOURCE',
- unableToDeleteResource: 'Unable To Delete $RESOURCE',
- languageNotAcceptable: 'Language Not Acceptable',
- characterSetNotAcceptable: 'Character Set Not Acceptable',
- unableToDeserializeResource: 'Unable To Deserialize $RESOURCE',
- unableToDecodeResource: 'Unable To Decode $RESOURCE',
- mediaTypeNotAcceptable: 'Media Type Not Acceptable',
- methodNotAllowed: 'Method Not Allowed',
- urlNotFound: 'URL Not Found',
- badRequest: 'Bad Request',
- ok: 'OK',
- provideOptions: 'Provide Options',
- resourceCollectionFetched: '$RESOURCE Collection Fetched',
- resourceFetched: '$RESOURCE Fetched',
- resourceNotFound: '$RESOURCE Not Found',
- deleteNonExistingResource: 'Delete Non-Existing $RESOURCE',
- resourceDeleted: '$RESOURCE Deleted',
- unableToDeserializeRequest: 'Unable To Deserialize Request',
- patchNonExistingResource: 'Patch Non-Existing $RESOURCE',
- unableToPatchResource: 'Unable To Patch $RESOURCE',
- invalidResourcePatch: 'Invalid $RESOURCE Patch',
- invalidResourcePatchType: 'Invalid $RESOURCE Patch Type',
- invalidResource: 'Invalid $RESOURCE',
- resourcePatched: '$RESOURCE Patched',
- resourceCreated: '$RESOURCE Created',
- resourceReplaced: '$RESOURCE Replaced',
- unableToGenerateIdFromResourceDataSource: 'Unable To Generate ID From $RESOURCE Data Source',
- unableToAssignIdFromResourceDataSource: 'Unable To Assign ID From $RESOURCE Data Source',
- unableToEmplaceResource: 'Unable To Emplace $RESOURCE',
- resourceIdNotGiven: '$RESOURCE ID Not Given',
- unableToCreateResource: 'Unable To Create $RESOURCE',
- notImplemented: 'Not Implemented',
- internalServerError: 'Internal Server Error',
- },
- bodies: {
- badRequest: [
- 'An invalid request has been made.',
- [
- 'Check if the request body has all the required attributes for this endpoint.',
- 'Check if the request body has only the valid attributes for this endpoint.',
- 'Check if the request body matches the schema for the resource associated with this endpoint.',
- 'Check if the request is appropriate for this endpoint.',
- ],
- ],
- languageNotAcceptable: [
- 'The server could not process a response suitable for the client\'s provided language requirement.',
- [
- 'Choose from the available languages on this service.',
- 'Contact the administrator to provide localization for the client\'s given requirements.',
- ],
- ],
- characterSetNotAcceptable: [
- 'The server could not process a response suitable for the client\'s provided character set requirement.',
- [
- 'Choose from the available character sets on this service.',
- 'Contact the administrator to provide localization for the client\'s given requirements.',
- ],
- ],
- mediaTypeNotAcceptable: [
- 'The server could not process a response suitable for the client\'s provided media type requirement.',
- [
- 'Choose from the available media types on this service.',
- 'Contact the administrator to provide localization for the client\'s given requirements.',
- ],
- ],
- deleteNonExistingResource: [
- 'The client has attempted to delete a resource that does not exist.',
- [
- 'Ensure that the resource still exists.',
- 'Ensure that the correct method is provided.',
- ],
- ],
- internalServerError: [
- 'An unknown error has occurred within the service.',
- [
- 'Try the request again at a later time.',
- 'Contact the administrator if the service remains in a degraded or non-functional state.',
- ],
- ],
- invalidResource: [
- 'The request has an invalid structure or is missing some attributes.',
- [
- 'Check if the request body has all the required attributes for this endpoint.',
- 'Check if the request body has only the valid attributes for this endpoint.',
- 'Check if the request body matches the schema for the resource associated with this endpoint.',
- ],
- ],
- invalidResourcePatch: [
- 'The request has an invalid patch data.',
- [
- 'Check if the appropriate patch type is specified on the request data.',
- 'Check if the request body has all the required attributes for this endpoint.',
- 'Check if the request body has only the valid attributes for this endpoint.',
- 'Check if the request body matches the schema for the resource associated with this endpoint.',
- ],
- ],
- invalidResourcePatchType: [
- 'The request has an invalid or unsupported kind of patch data.',
- [
- 'Check if the appropriate patch type is specified on the request data.',
- 'Check if the request body has all the required attributes for this endpoint.',
- 'Check if the request body has only the valid attributes for this endpoint.',
- 'Check if the request body matches the schema for the resource associated with this endpoint.',
- ],
- ],
- methodNotAllowed: [
- 'A request with an invalid or unsupported method has been made.',
- [
- 'Check if the request method is appropriate for this endpoint.',
- 'Check if the client is authorized to perform the method on this endpoint.',
- ]
- ],
- notImplemented: [
- 'The service does not have any implementation for the accessed endpoint.',
- [
- 'Try the request again at a later time.',
- 'Contact the administrator if the service remains in a degraded or non-functional state.',
- ],
- ],
- patchNonExistingResource: [
- 'The client has attempted to patch a resource that does not exist.',
- [
- 'Ensure that the resource still exists.',
- 'Ensure that the correct method is provided.',
- ],
- ],
- resourceIdNotGiven: [
- 'The resource ID is not provided for the accessed endpoint.',
- [
- 'Check if the resource ID is provided and valid in the URL.',
- 'Check if the request method is appropriate for this endpoint.',
- ],
- ],
- unableToAssignIdFromResourceDataSource: [
- 'The resource could not be assigned an ID from the associated data source.',
- [
- 'Try the request again at a later time.',
- 'Contact the administrator regarding missing configuration or unavailability of dependencies.',
- ],
- ],
- unableToBindResourceDataSource: [
- 'The resource could not be associated from the data source.',
- [
- 'Try the request again at a later time.',
- 'Contact the administrator regarding missing configuration or unavailability of dependencies.',
- ],
- ],
- unableToCreateResource: [
- 'An error has occurred on creating the resource.',
- [
- 'Check if the request method is appropriate for this endpoint.',
- 'Check if the request body has all the required attributes for this endpoint.',
- 'Check if the request body has only the valid attributes for this endpoint.',
- 'Check if the request body matches the schema for the resource associated with this endpoint.',
- 'Try the request again at a later time.',
- 'Contact the administrator regarding missing configuration or unavailability of dependencies.',
- ],
- ],
- unableToDecodeResource: [
- 'The resource byte array could not be decoded for the provided character set.',
- [
- 'Choose from the available character sets on this service.',
- 'Contact the administrator to provide localization for the client\'s given requirements.',
- ],
- ],
- unableToDeleteResource: [
- 'An error has occurred on deleting the resource.',
- [
- 'Check if the request method is appropriate for this endpoint.',
- 'Try the request again at a later time.',
- 'Contact the administrator regarding missing configuration or unavailability of dependencies.',
- ],
- ],
- unableToDeserializeRequest: [
- 'The decoded request byte array could not be deserialized for the provided media type.',
- [
- 'Choose from the available media types on this service.',
- 'Contact the administrator to provide localization for the client\'s given requirements.',
- ],
- ],
- unableToDeserializeResource: [
- 'The decoded resource could not be deserialized for the provided media type.',
- [
- 'Choose from the available media types on this service.',
- 'Contact the administrator to provide localization for the client\'s given requirements.',
- ],
- ],
- unableToEmplaceResource: [
- 'An error has occurred on emplacing the resource.',
- [
- 'Check if the request method is appropriate for this endpoint.',
- 'Check if the request body has all the required attributes for this endpoint.',
- 'Check if the request body has only the valid attributes for this endpoint.',
- 'Check if the request body matches the schema for the resource associated with this endpoint.',
- 'Try the request again at a later time.',
- 'Contact the administrator regarding missing configuration or unavailability of dependencies.',
- ],
- ],
- unableToEncodeResponse: [
- 'The response data could not be encoded for the provided character set.',
- [
- 'Choose from the available character sets on this service.',
- 'Contact the administrator to provide localization for the client\'s given requirements.',
- ],
- ],
- unableToFetchResource: [
- 'An error has occurred on fetching the resource.',
- [
- 'Check if the request method is appropriate for this endpoint.',
- 'Try the request again at a later time.',
- 'Contact the administrator regarding missing configuration or unavailability of dependencies.',
- ],
- ],
- unableToFetchResourceCollection: [
- 'An error has occurred on fetching the resource collection.',
- [
- 'Check if the request method is appropriate for this endpoint.',
- 'Try the request again at a later time.',
- 'Contact the administrator regarding missing configuration or unavailability of dependencies.',
- ],
- ],
- unableToGenerateIdFromResourceDataSource: [
- 'The associated data source for the resource could not produce an ID.',
- [
- 'Try the request again at a later time.',
- 'Contact the administrator regarding missing configuration or unavailability of dependencies.',
- ],
- ],
- unableToInitializeResourceDataSource: [
- 'The associated data source for the resource could not be connected for usage.',
- [
- 'Try the request again at a later time.',
- 'Contact the administrator regarding missing configuration or unavailability of dependencies.',
- ],
- ],
- unableToPatchResource: [
- 'An error has occurred on patching the resource.',
- [
- 'Check if the request method is appropriate for this endpoint.',
- 'Check if the request body has all the required attributes for this endpoint.',
- 'Check if the request body has only the valid attributes for this endpoint.',
- 'Check if the request body matches the schema for the resource associated with this endpoint.',
- 'Try the request again at a later time.',
- 'Contact the administrator regarding missing configuration or unavailability of dependencies.',
- ],
- ],
- unableToSerializeResponse: [
- 'The response data could not be serialized for the provided media type.',
- [
- 'Choose from the available media types on this service.',
- 'Contact the administrator to provide localization for the client\'s given requirements.',
- ],
- ],
- urlNotFound: [
- 'An endpoint in the provided URL could not be found.',
- [
- 'Check if the request URL is correct.',
- 'Try the request again at a later time.',
- 'Contact the administrator regarding missing configuration or unavailability of dependencies.',
- ],
- ],
- resourceNotFound: [
- 'The resource in the provided URL could not be found.',
- [
- 'Check if the request URL is correct.',
- 'Try the request again at a later time.',
- 'Contact the administrator regarding missing configuration or unavailability of dependencies.',
- ],
- ],
- },
- };
|