Skip to content

Commit

Permalink
Revert "Revert "small fixes""
Browse files Browse the repository at this point in the history
This reverts commit 30ab3f4.
  • Loading branch information
sszafGCA committed Nov 16, 2023
1 parent 30ab3f4 commit 6feb0a8
Show file tree
Hide file tree
Showing 56 changed files with 1,483 additions and 0 deletions.
31 changes: 31 additions & 0 deletions apps/server/src/apps/deletion-console.app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* istanbul ignore file */
import { BootstrapConsole } from 'nestjs-console';
import { DeletionConsoleModule } from '@modules/deletion';

async function run() {
const bootstrap = new BootstrapConsole({
module: DeletionConsoleModule,
useDecorators: true,
});

const app = await bootstrap.init();

try {
await app.init();

// Execute console application with provided arguments.
await bootstrap.boot();
} catch (err) {
// eslint-disable-next-line no-console, @typescript-eslint/no-unsafe-call
console.error(err);

// Set the exit code to 1 to indicate a console app failure.
process.exitCode = 1;
}

// Always close the app, even if some exception
// has been thrown from the console app.
await app.close();
}

void run();
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { ObjectId } from 'bson';
import { DeletionRequestInput } from '../interface';
import { DeletionRequestInputBuilder } from './deletion-request-input.builder';

describe(DeletionRequestInputBuilder.name, () => {
describe(DeletionRequestInputBuilder.build.name, () => {
describe('when called with proper arguments', () => {
const setup = () => {
const targetRefDomain = 'school';
const targetRefId = new ObjectId().toHexString();
const deleteInMinutes = 43200;

const expectedOutput: DeletionRequestInput = {
targetRef: {
domain: targetRefDomain,
id: targetRefId,
},
deleteInMinutes,
};

return { targetRefDomain, targetRefId, deleteInMinutes, expectedOutput };
};

it('should return valid object with expected values', () => {
const { targetRefDomain, targetRefId, deleteInMinutes, expectedOutput } = setup();

const output = DeletionRequestInputBuilder.build(targetRefDomain, targetRefId, deleteInMinutes);

expect(output).toStrictEqual(expectedOutput);
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { DeletionRequestInput } from '../interface';
import { DeletionRequestTargetRefInputBuilder } from './deletion-request-target-ref-input.builder';

export class DeletionRequestInputBuilder {
static build(targetRefDomain: string, targetRefId: string, deleteInMinutes?: number): DeletionRequestInput {
return {
targetRef: DeletionRequestTargetRefInputBuilder.build(targetRefDomain, targetRefId),
deleteInMinutes,
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { ObjectId } from 'bson';
import { DeletionRequestOutput } from '../interface';
import { DeletionRequestOutputBuilder } from './deletion-request-output.builder';

describe(DeletionRequestOutputBuilder.name, () => {
describe(DeletionRequestOutputBuilder.build.name, () => {
describe('when called with proper arguments', () => {
const setup = () => {
const requestId = new ObjectId().toHexString();
const deletionPlannedAt = new Date();

const expectedOutput: DeletionRequestOutput = {
requestId,
deletionPlannedAt,
};

return { requestId, deletionPlannedAt, expectedOutput };
};

it('should return valid object with expected values', () => {
const { requestId, deletionPlannedAt, expectedOutput } = setup();

const output = DeletionRequestOutputBuilder.build(requestId, deletionPlannedAt);

expect(output).toStrictEqual(expectedOutput);
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { DeletionRequestOutput } from '../interface';

export class DeletionRequestOutputBuilder {
static build(requestId: string, deletionPlannedAt: Date): DeletionRequestOutput {
return {
requestId,
deletionPlannedAt,
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { ObjectId } from 'bson';
import { DeletionRequestTargetRefInput } from '../interface';
import { DeletionRequestTargetRefInputBuilder } from './deletion-request-target-ref-input.builder';

describe(DeletionRequestTargetRefInputBuilder.name, () => {
describe(DeletionRequestTargetRefInputBuilder.build.name, () => {
describe('when called with proper arguments', () => {
const setup = () => {
const domain = 'user';
const id = new ObjectId().toHexString();

const expectedOutput: DeletionRequestTargetRefInput = { domain, id };

return { domain, id, expectedOutput };
};

it('should return valid object with expected values', () => {
const { domain, id, expectedOutput } = setup();

const output = DeletionRequestTargetRefInputBuilder.build(domain, id);

expect(output).toStrictEqual(expectedOutput);
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { DeletionRequestTargetRefInput } from '../interface';

export class DeletionRequestTargetRefInputBuilder {
static build(domain: string, id: string): DeletionRequestTargetRefInput {
return { domain, id };
}
}
3 changes: 3 additions & 0 deletions apps/server/src/modules/deletion/client/builder/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './deletion-request-target-ref-input.builder';
export * from './deletion-request-input.builder';
export * from './deletion-request-output.builder';
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { IConfig } from '@hpi-schul-cloud/commons/lib/interfaces/IConfig';
import { Configuration } from '@hpi-schul-cloud/commons/lib';
import { DeletionClientConfig } from './interface';
import { getDeletionClientConfig } from './deletion-client.config';

describe(getDeletionClientConfig.name, () => {
let configBefore: IConfig;

beforeAll(() => {
configBefore = Configuration.toObject({ plainSecrets: true });
});

afterEach(() => {
Configuration.reset(configBefore);
});

describe('when called', () => {
const setup = () => {
const baseUrl = 'http://api-admin:4030';
const apiKey = '652559c2-93da-42ad-94e1-640e3afbaca0';

Configuration.set('ADMIN_API_CLIENT__BASE_URL', baseUrl);
Configuration.set('ADMIN_API_CLIENT__API_KEY', apiKey);

const expectedConfig: DeletionClientConfig = {
ADMIN_API_CLIENT_BASE_URL: baseUrl,
ADMIN_API_CLIENT_API_KEY: apiKey,
};

return { expectedConfig };
};

it('should return config with proper values', () => {
const { expectedConfig } = setup();

const config = getDeletionClientConfig();

expect(config).toEqual(expectedConfig);
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Configuration } from '@hpi-schul-cloud/commons/lib';
import { DeletionClientConfig } from './interface';

export const getDeletionClientConfig = (): DeletionClientConfig => {
return {
ADMIN_API_CLIENT_BASE_URL: Configuration.get('ADMIN_API_CLIENT__BASE_URL') as string,
ADMIN_API_CLIENT_API_KEY: Configuration.get('ADMIN_API_CLIENT__API_KEY') as string,
};
};
154 changes: 154 additions & 0 deletions apps/server/src/modules/deletion/client/deletion.client.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import { of } from 'rxjs';
import { AxiosResponse } from 'axios';
import { HttpService } from '@nestjs/axios';
import { ConfigService } from '@nestjs/config';
import { Test, TestingModule } from '@nestjs/testing';
import { createMock, DeepMocked } from '@golevelup/ts-jest';
import { axiosResponseFactory } from '@shared/testing';
import { DeletionRequestInputBuilder, DeletionRequestOutputBuilder } from '.';
import { DeletionRequestOutput } from './interface';
import { DeletionClient } from './deletion.client';

describe(DeletionClient.name, () => {
let module: TestingModule;
let client: DeletionClient;
let httpService: DeepMocked<HttpService>;

beforeEach(async () => {
module = await Test.createTestingModule({
providers: [
DeletionClient,
{
provide: ConfigService,
useValue: createMock<ConfigService>({
get: jest.fn((key: string) => {
if (key === 'ADMIN_API_CLIENT_BASE_URL') {
return 'http://localhost:4030';
}

// Default is for the Admin APIs API Key.
return '6b3df003-61e9-467c-9e6b-579634801896';
}),
}),
},
{
provide: HttpService,
useValue: createMock<HttpService>(),
},
],
}).compile();

client = module.get(DeletionClient);
httpService = module.get(HttpService);
});

afterEach(() => {
jest.resetAllMocks();
});

afterAll(async () => {
await module.close();
});

describe('queueDeletionRequest', () => {
describe('when received valid response with expected HTTP status code', () => {
const setup = () => {
const input = DeletionRequestInputBuilder.build('user', '652f1625e9bc1a13bdaae48b');

const output: DeletionRequestOutput = DeletionRequestOutputBuilder.build(
'6536ce29b595d7c8e5faf200',
new Date('2024-10-15T12:42:50.521Z')
);

const response: AxiosResponse<DeletionRequestOutput> = axiosResponseFactory.build({
data: output,
status: 202,
});

httpService.post.mockReturnValueOnce(of(response));

return { input, output };
};

it('should return proper output', async () => {
const { input, output } = setup();

const result = await client.queueDeletionRequest(input);

expect(result).toEqual(output);
});
});

describe('when received invalid HTTP status code in a response', () => {
const setup = () => {
const input = DeletionRequestInputBuilder.build('user', '652f1625e9bc1a13bdaae48b');

const output: DeletionRequestOutput = DeletionRequestOutputBuilder.build('', new Date());

const response: AxiosResponse<DeletionRequestOutput> = axiosResponseFactory.build({
data: output,
status: 200,
});

httpService.post.mockReturnValueOnce(of(response));

return { input };
};

it('should throw an exception', async () => {
const { input } = setup();

await expect(client.queueDeletionRequest(input)).rejects.toThrow(Error);
});
});

describe('when received no requestId in a response', () => {
const setup = () => {
const input = DeletionRequestInputBuilder.build('user', '652f1625e9bc1a13bdaae48b');

const output: DeletionRequestOutput = DeletionRequestOutputBuilder.build(
'',
new Date('2024-10-15T12:42:50.521Z')
);

const response: AxiosResponse<DeletionRequestOutput> = axiosResponseFactory.build({
data: output,
status: 202,
});

httpService.post.mockReturnValueOnce(of(response));

return { input };
};

it('should throw an exception', async () => {
const { input } = setup();

await expect(client.queueDeletionRequest(input)).rejects.toThrow(Error);
});
});

describe('when received no deletionPlannedAt in a response', () => {
const setup = () => {
const input = DeletionRequestInputBuilder.build('user', '652f1625e9bc1a13bdaae48b');

const response: AxiosResponse<DeletionRequestOutput> = axiosResponseFactory.build({
data: {
requestId: '6536ce29b595d7c8e5faf200',
},
status: 202,
});

httpService.post.mockReturnValueOnce(of(response));

return { input };
};

it('should throw an exception', async () => {
const { input } = setup();

await expect(client.queueDeletionRequest(input)).rejects.toThrow(Error);
});
});
});
});
Loading

0 comments on commit 6feb0a8

Please sign in to comment.