Skip to content

Commit

Permalink
Merge pull request #246 from amosproj/backend-alert-overview-page
Browse files Browse the repository at this point in the history
Backend alert overview page
  • Loading branch information
engelharddirk authored Jan 14, 2025
2 parents 6384d5a + 15b478f commit 3dc2bdb
Show file tree
Hide file tree
Showing 7 changed files with 595 additions and 373 deletions.
243 changes: 36 additions & 207 deletions apps/backend/src/app/alerting/alerting.controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { TaskEntity } from '../tasks/entity/task.entity';
import { MailReceiverEntity } from '../utils/mail/entity/MailReceiver.entity';
import { StorageFillAlertEntity } from './entity/alerts/storageFillAlert.entity';
import { CreateStorageFillAlertDto } from './dto/alerts/createStorageFillAlert.dto';
import { find } from 'rxjs';

const mockedBackupDataEntity: BackupDataEntity = {
id: 'backup-id',
Expand Down Expand Up @@ -69,7 +70,16 @@ const mockSizeAlertRepository = {
save: jest.fn().mockImplementation((alert) => Promise.resolve(alert)),
find: jest.fn().mockImplementation(() => Promise.resolve([sizeAlert])),
findOneBy: jest.fn().mockResolvedValue(null),
createQueryBuilder: jest.fn(() => ({
select: jest.fn().mockReturnThis(),
leftJoinAndSelect: jest.fn().mockReturnThis(),
where: jest.fn().mockReturnThis(),
getQuery: jest.fn().mockReturnThis(),
getManyAndCount: jest.fn().mockResolvedValue([[sizeAlert], 1]),
})),
query: jest.fn().mockResolvedValue([sizeAlert, [{ count: '1' }]]),
};

const mockAlertTypeRepository = {
findOneBy: jest.fn().mockImplementation(({ name, id }) => {
if (name === 'SIZE_ALERT' || id === 'active-id') {
Expand All @@ -94,13 +104,29 @@ const mockAlertTypeRepository = {

const mockCreationDateAlertRepository = {
save: jest.fn().mockImplementation((alert) => Promise.resolve(alert)),
find: jest.fn().mockImplementation(() => Promise.resolve([])),
find: jest.fn().mockImplementation(() => Promise.resolve([sizeAlert])),
createQueryBuilder: jest.fn(() => ({
select: jest.fn().mockReturnThis(),
leftJoinAndSelect: jest.fn().mockReturnThis(),
where: jest.fn().mockReturnThis(),
getQuery: jest.fn().mockReturnThis(),
getManyAndCount: jest.fn().mockResolvedValue([[], 0]),
})),
query: jest.fn().mockResolvedValue([[], [{ count: '1' }]]),
findOneBy: jest.fn().mockResolvedValue(null),
};

const mockStorageFillAlertRepository = {
save: jest.fn().mockImplementation((alert) => Promise.resolve(alert)),
find: jest.fn().mockResolvedValue([]),
find: jest.fn().mockImplementation(() => Promise.resolve([sizeAlert])),
createQueryBuilder: jest.fn(() => ({
select: jest.fn().mockReturnThis(),
leftJoinAndSelect: jest.fn().mockReturnThis(),
where: jest.fn().mockReturnThis(),
getQuery: jest.fn().mockReturnThis(),
getManyAndCount: jest.fn().mockResolvedValue([[], 0]),
})),
query: jest.fn().mockResolvedValue([[], [{ count: '1' }]]),
findOneBy: jest.fn().mockResolvedValue(null),
};

Expand Down Expand Up @@ -147,217 +173,20 @@ describe('AlertingController (e2e)', () => {
await app.close();
});

it('GET /alerting - should return all alerts', async () => {
const response = await request(app.getHttpServer())
.get('/alerting')
.expect(200);

expect(mockSizeAlertRepository.find).toHaveBeenCalledWith({
where: {
alertType: {
user_active: true,
master_active: true,
},
},
});
const receivedAlerts = response.body.map((alert: SizeAlertEntity) => ({
...alert,
backup: {
...alert.backup,
creationDate: new Date(alert.backup?.creationDate ?? ''),
},
creationDate: new Date(alert.creationDate),
}));

expect(receivedAlerts).toEqual([sizeAlert]);
});
it('POST /alerting/type - should create a new alert type', async () => {
const createAlertTypeDto = {
severity: SeverityType.WARNING,
name: 'TEST_ALERT',
master_active: true,
};

await request(app.getHttpServer())
.post('/alerting/type')
.send(createAlertTypeDto)
.expect(201);

expect(mockAlertTypeRepository.save).toHaveBeenCalledWith(
expect.objectContaining(createAlertTypeDto)
);
});

it('GET /alerting - should filter alerts by backupId', async () => {
const response = await request(app.getHttpServer())
.get('/alerting')
.query({ backupId: 'backup-id' })
.expect(200);

expect(mockSizeAlertRepository.find).toHaveBeenCalledWith({
where: {
backup: { id: 'backup-id' },
alertType: { user_active: true, master_active: true },
},
});

const receivedAlerts = response.body.map((alert: SizeAlertEntity) => ({
...alert,
backup: {
...alert.backup,
creationDate: new Date(alert.backup?.creationDate ?? ''),
},
creationDate: new Date(alert.creationDate),
}));

expect(receivedAlerts).toEqual([sizeAlert]);
});

it('GET /alerting - should filter alerts by the last x days', async () => {
const days = 7;
const date = new Date();
date.setDate(date.getDate() - days);
it('GET /alerting - should return paginated alerts', async () => {
const offset = 0;
const limit = 10;

const response = await request(app.getHttpServer())
.get('/alerting')
.query({ days })
.expect(200);

expect(mockSizeAlertRepository.find).toHaveBeenCalledWith({
where: {
backup: { creationDate: MoreThanOrEqual(expect.any(Date)) },
alertType: { user_active: true, master_active: true },
},
});

const receivedAlerts = response.body.map((alert: SizeAlertEntity) => ({
...alert,
backup: {
...alert.backup,
creationDate: new Date(alert.backup?.creationDate ?? ''),
},
creationDate: new Date(alert.creationDate),
}));

expect(receivedAlerts).toEqual([sizeAlert]);
});

it('POST /alerting/size - should create a new size alert', async () => {
const createAlertDto: CreateSizeAlertDto = {
size: 100,
referenceSize: 200,
backupId: 'backup-id',
};

await request(app.getHttpServer())
.post('/alerting/size')
.send(createAlertDto)
.expect(201);

expect(mockSizeAlertRepository.save).toHaveBeenCalledWith(
expect.objectContaining({
size: createAlertDto.size,
referenceSize: createAlertDto.referenceSize,
backup: expect.objectContaining({ id: createAlertDto.backupId }),
alertType: expect.objectContaining({ name: SIZE_ALERT }),
})
);
});

it('POST /alerting/creationDate - should create a new size alert', async () => {
const createCreationDateAlertDto: CreateCreationDateAlertDto = {
date: new Date('2024-12-01T17:53:33.239Z'),
backupId: 'backup-id',
referenceDate: new Date('2024-12-01T17:53:33.239Z'),
};

await request(app.getHttpServer())
.post('/alerting/creationDate')
.send(createCreationDateAlertDto)
.expect(201);

expect(mockCreationDateAlertRepository.save).toHaveBeenCalledWith({
date: new Date('2024-12-01T17:53:33.239Z').toISOString(),
referenceDate: new Date('2024-12-01T17:53:33.239Z').toISOString(),
backup: mockedBackupDataEntity,
alertType: mockedCreationDateAlertTypeEntity,
});
});

it('POST /alerting/storageFill - should create a new storage fill alert', async () => {
const createStorageFillAlertDto: CreateStorageFillAlertDto = {
dataStoreName: 'ExampleDataStore',
filled: 75.123456,
highWaterMark: 80.0,
capacity: 100.0,
};

await request(app.getHttpServer())
.post('/alerting/storageFill')
.send(createStorageFillAlertDto)
.expect(201);

expect(mockStorageFillAlertRepository.save).toHaveBeenCalledWith(
expect.objectContaining({
dataStoreName: createStorageFillAlertDto.dataStoreName,
filled: createStorageFillAlertDto.filled,
highWaterMark: createStorageFillAlertDto.highWaterMark,
capacity: createStorageFillAlertDto.capacity,
.query({
offset: offset,
limit: limit,
})
);
});

it('GET /alerting/storageFill - should return all storage fill alerts', async () => {
const mockAlert = {
dataStoreName: 'ExampleDataStore',
filled: 75.123,
highWaterMark: 80.0,
capacity: 100.0,
};

mockStorageFillAlertRepository.find.mockResolvedValue([mockAlert]);

const response = await request(app.getHttpServer())
.get('/alerting')
.expect(200);

const filteredResponse = response.body.filter(
(alert: any) => alert.highWaterMark !== undefined
);

expect(mockStorageFillAlertRepository.find).toHaveBeenCalled();
expect(filteredResponse).toEqual([mockAlert]);
expect(response.body).toEqual({"data": [], "paginationData": {"limit": "10", "offset": "0", "total": null}});
});

it('PATCH /alerting/type/:alertTypeId/admin - should activate alert type by admin', async () => {
const alertTypeId = 'not-active-id';
const alertStatusDto = { status: true };

await request(app.getHttpServer())
.patch(`/alerting/type/${alertTypeId}/admin`)
.send(alertStatusDto)
.expect(200);

expect(mockAlertTypeRepository.save).toHaveBeenCalledWith({
...mockedSizeAlertTypeEntity,
master_active: true,
user_active: false,
});
});

it('PATCH /alerting/type/:alertTypeId/user - should activate alert type by user', async () => {
const alertTypeId = 'not-active-id';
const alertStatusDto = { status: true };

await request(app.getHttpServer())
.patch(`/alerting/type/${alertTypeId}/user`)
.send(alertStatusDto)
.expect(200);

expect(mockAlertTypeRepository.save).toHaveBeenCalledWith({
...mockedSizeAlertTypeEntity,
master_active: false,
user_active: true,
});
});
// Add more tests as needed
});
33 changes: 16 additions & 17 deletions apps/backend/src/app/alerting/alerting.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
ApiBody,
ApiConflictResponse,
ApiNotFoundResponse,
ApiOkResponse,
ApiOperation,
ApiQuery,
ApiTags,
Expand All @@ -25,6 +26,10 @@ import { BackupType } from '../backupData/dto/backupType';
import { CreateCreationDateAlertDto } from './dto/alerts/createCreationDateAlert.dto';
import { AlertStatusDto } from './dto/alertStatus.dto';
import { CreateStorageFillAlertDto } from './dto/alerts/createStorageFillAlert.dto';
import { PaginationOptionsDto } from '../utils/pagination/PaginationOptionsDto';
import { AlertFilterDto } from './dto/alertFilter.dto';
import { AlertOrderOptionsDto } from './dto/alertOrderOptions.dto';
import { PaginationDto } from '../utils/pagination/PaginationDto';

@ApiTags('Alerting')
@Controller('alerting')
Expand Down Expand Up @@ -91,23 +96,17 @@ export class AlertingController {
}

@Get()
@ApiOperation({ summary: 'Get all alerts.' })
@ApiQuery({
name: 'backupId',
description: 'Filter alerts by backup id',
required: false,
})
@ApiQuery({
name: 'days',
description: 'Filter alerts by backups (or creation Date if not linked with Backup) of the last x days',
required: false,
type: Number,
})
async getAllAlerts(
@Query('backupId') backupId?: string,
@Query('days') days?: number
): Promise<Alert[]> {
return this.alertingService.getAllAlerts(backupId, days);
@ApiOperation({ summary: 'Returns all alert Objects paginated.' })
async findAll(
@Query() paginationOptionsDto: PaginationOptionsDto,
@Query() alertFilterDto: AlertFilterDto,
@Query() backupDataOrderOptionsDto: AlertOrderOptionsDto,
): Promise<PaginationDto<Alert>> {
return this.alertingService.getAllAlertsPaginated(
paginationOptionsDto,
backupDataOrderOptionsDto,
alertFilterDto,
);
}

@Post('size')
Expand Down
Loading

0 comments on commit 3dc2bdb

Please sign in to comment.