Skip to content

Commit

Permalink
fix(oianalytics): fix OIAnalytics message models
Browse files Browse the repository at this point in the history
  • Loading branch information
burgerni10 committed Jun 11, 2024
1 parent 049565f commit ffd9046
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 47 deletions.
19 changes: 6 additions & 13 deletions backend/src/repository/oianalytics-message.repository.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import SqliteDatabaseMock, { all, get, run } from '../tests/__mocks__/database.m
import { Database } from 'better-sqlite3';
import OianalyticsMessageRepository from './oianalytics-message.repository';
import { Page } from '../../../shared/model/types';
import { InfoMessageContent, OIAnalyticsMessageCommand, OIAnalyticsMessageDTO } from '../../../shared/model/oianalytics-message.model';
import { InfoMessageContent, OIAnalyticsMessageDTO } from '../../../shared/model/oianalytics-message.model';

jest.mock('../tests/__mocks__/database.mock');
jest.mock('../service/utils', () => ({
Expand Down Expand Up @@ -35,23 +35,16 @@ describe('OIAnalytics Message repository', () => {
it('should create message', () => {
run.mockReturnValueOnce({ lastInsertRowid: 1 });
get.mockReturnValueOnce({ ...existingMessage, content: '{}' });
const command: OIAnalyticsMessageCommand = {
type: 'INFO',
content: {} as InfoMessageContent
};
repository.createOIAnalyticsMessages(command);

repository.createOIAnalyticsMessages('INFO', {} as InfoMessageContent);
expect(database.prepare).toHaveBeenCalledWith('INSERT INTO oianalytics_messages (id, type, status, content) VALUES (?, ?, ?, ?);');
expect(run).toHaveBeenCalledWith('123456', command.type, 'PENDING', JSON.stringify(command.content));
expect(run).toHaveBeenCalledWith('123456', 'INFO', 'PENDING', JSON.stringify({}));
});

it('should update message', () => {
const command: OIAnalyticsMessageCommand = {
type: 'INFO',
content: {} as InfoMessageContent
};
repository.updateOIAnalyticsMessages('id', command);
repository.updateOIAnalyticsMessages('id', {} as InfoMessageContent);
expect(database.prepare).toHaveBeenCalledWith('UPDATE oianalytics_messages SET content = ? WHERE id = ?;');
expect(run).toHaveBeenCalledWith(JSON.stringify(command.content), 'id');
expect(run).toHaveBeenCalledWith(JSON.stringify({}), 'id');
});

it('should properly get messages page by search criteria', () => {
Expand Down
16 changes: 5 additions & 11 deletions backend/src/repository/oianalytics-message.repository.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import { generateRandomId } from '../service/utils';
import { Database } from 'better-sqlite3';
import { Instant, Page } from '../../../shared/model/types';
import {
OIAnalyticsMessageCommand,
OIAnalyticsMessageDTO,
OIAnalyticsMessageSearchParam
} from '../../../shared/model/oianalytics-message.model';
import { InfoMessage, OIAnalyticsMessageDTO, OIAnalyticsMessageSearchParam } from '../../../shared/model/oianalytics-message.model';

export const OIANALYTICS_MESSAGE_TABLE = 'oianalytics_messages';
const PAGE_SIZE = 50;
Expand Down Expand Up @@ -103,19 +99,17 @@ export default class OianalyticsMessageRepository {
/**
* Update a message
*/
updateOIAnalyticsMessages(id: string, command: OIAnalyticsMessageCommand): void {
updateOIAnalyticsMessages(id: string, content: InfoMessage): void {
const query = `UPDATE ${OIANALYTICS_MESSAGE_TABLE} SET content = ? WHERE id = ?;`;
this.database.prepare(query).run(JSON.stringify(command.content), id);
this.database.prepare(query).run(JSON.stringify(content), id);
}

/**
* Create a message
*/
createOIAnalyticsMessages(command: OIAnalyticsMessageCommand): OIAnalyticsMessageDTO {
createOIAnalyticsMessages(type: string, content: InfoMessage): OIAnalyticsMessageDTO {
const insertQuery = `INSERT INTO ${OIANALYTICS_MESSAGE_TABLE} (id, type, status, content) VALUES (?, ?, ?, ?);`;
const insertResult = this.database
.prepare(insertQuery)
.run(generateRandomId(), command.type, 'PENDING', JSON.stringify(command.content));
const insertResult = this.database.prepare(insertQuery).run(generateRandomId(), type, 'PENDING', JSON.stringify(content));

const query =
`SELECT id, created_at as creationDate, completed_date as compeltedDate, type, status, error, content FROM ${OIANALYTICS_MESSAGE_TABLE} ` +
Expand Down
7 changes: 1 addition & 6 deletions backend/src/service/oia/command.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { DateTime } from 'luxon';
import { RegistrationSettingsDTO } from '../../../../shared/model/engine.model';
import path from 'node:path';
import { version } from '../../../package.json';
import { OIAnalyticsMessageInfoCommandDTO } from '../../../../shared/model/oianalytics-message.model';
import OIAnalyticsMessageService from './message.service';

const DOWNLOAD_TIMEOUT = 600_000;
Expand Down Expand Up @@ -42,11 +41,7 @@ export default class CommandService {
);
engineSettings.version = version;
const info = getOIBusInfo(engineSettings);
const infoMessageCommand: OIAnalyticsMessageInfoCommandDTO = {
type: 'INFO',
content: info
};
const createdMessage = this.repositoryService.oianalyticsMessageRepository.createOIAnalyticsMessages(infoMessageCommand);
const createdMessage = this.repositoryService.oianalyticsMessageRepository.createOIAnalyticsMessages('INFO', info);
this.oianalyticsMessageService.addMessageToQueue(createdMessage);
} else {
this.repositoryService.commandRepository.markAsErrored(
Expand Down
26 changes: 24 additions & 2 deletions backend/src/service/oia/message.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,18 @@ const existingMessage: OIAnalyticsMessageDTO = {
id: '1234',
status: 'ERRORED',
type: 'INFO',
content: {} as InfoMessageContent
content: {
version: 'version',
oibusName: 'oibusName',
oibusId: 'oibusId',
dataDirectory: 'dataDirectory',
binaryDirectory: 'binaryDirectory',
processId: 'processId',
hostname: 'hostname',
operatingSystem: 'operatingSystem',
architecture: 'architecture',
platform: 'platform'
} as InfoMessageContent
};

let service: OIAnalyticsMessageService;
Expand Down Expand Up @@ -196,7 +207,7 @@ describe('OIAnalytics message service without message', () => {
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(existingMessage),
body: JSON.stringify({ type: existingMessage.type, ...existingMessage.content }),
timeout: 15_000,
agent: undefined
});
Expand All @@ -206,6 +217,17 @@ describe('OIAnalytics message service without message', () => {
expect(fetch).toHaveBeenCalledTimes(1);
});

it('should not send message if message type is not recognized', async () => {
service.removeMessageFromQueue = jest.fn();
await service.sendMessage({ id: 'badId', type: 'BAD TYPE' } as any);
expect(logger.debug).toHaveBeenCalledWith(
`Error while sending message badId (created ${existingMessage.creationDate}) of type ` +
`BAD TYPE on http://localhost:4200/api/oianalytics/oibus/message. Error: ` +
`Unrecognized type BAD TYPE. Message badId removed from queue`
);
expect(service.removeMessageFromQueue).toHaveBeenCalledWith('badId');
});

it('should send message and manage 404 error', async () => {
(fetch as unknown as jest.Mock).mockReturnValueOnce(Promise.resolve(new Response('invalid', { status: 404, statusText: 'Not Found' })));

Expand Down
27 changes: 25 additions & 2 deletions backend/src/service/oia/message.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import DeferredPromise from '../deferred-promise';
import { DateTime } from 'luxon';
import { RegistrationSettingsDTO } from '../../../../shared/model/engine.model';
import fetch from 'node-fetch';
import { OIAnalyticsMessageDTO } from '../../../../shared/model/oianalytics-message.model';
import { OIAnalyticsMessageCommand, OIAnalyticsMessageDTO } from '../../../../shared/model/oianalytics-message.model';

const STOP_TIMEOUT = 30_000;
const MESSAGE_TIMEOUT = 15_000;
Expand Down Expand Up @@ -85,6 +85,29 @@ export default class OIAnalyticsMessageService {
this.triggerRun.emit('next');
}

messageToCommandDTO(message: OIAnalyticsMessageDTO): OIAnalyticsMessageCommand {
switch (message.type) {
case 'INFO':
return {
type: 'INFO',
version: message.content.version,
oibusName: message.content.oibusName,
oibusId: message.content.oibusId,
dataDirectory: message.content.dataDirectory,
binaryDirectory: message.content.binaryDirectory,
processId: message.content.processId,
hostname: message.content.hostname,
operatingSystem: message.content.operatingSystem,
architecture: message.content.architecture,
platform: message.content.platform
};

default:
this.removeMessageFromQueue(message.id);
throw new Error(`Unrecognized type ${message.type}. Message ${message.id} removed from queue`);
}
}

async sendMessage(message: OIAnalyticsMessageDTO): Promise<void> {
if (this.retryTimeout) {
clearTimeout(this.retryTimeout);
Expand All @@ -98,7 +121,7 @@ export default class OIAnalyticsMessageService {
try {
const response = await fetch(url, {
method: 'POST',
body: JSON.stringify(message),
body: JSON.stringify(this.messageToCommandDTO(message)),
headers: { ...connectionSettings.headers, 'Content-Type': 'application/json' },
timeout: MESSAGE_TIMEOUT,
agent: connectionSettings.agent
Expand Down
7 changes: 1 addition & 6 deletions backend/src/service/reload.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import HomeMetricsService from './home-metrics.service';
import ProxyServer from '../web-server/proxy-server';
import OIBusService from './oibus.service';
import { getOIBusInfo } from './utils';
import { OIAnalyticsMessageInfoCommandDTO } from '../../../shared/model/oianalytics-message.model';
import OIAnalyticsMessageService from './oia/message.service';

export default class ReloadService {
Expand Down Expand Up @@ -101,11 +100,7 @@ export default class ReloadService {
const registration = this.repositoryService.registrationRepository.getRegistrationSettings()!;
if (oldSettings?.name !== newSettings.name && registration.status !== 'NOT_REGISTERED') {
const info = getOIBusInfo(newSettings);
const infoMessageCommand: OIAnalyticsMessageInfoCommandDTO = {
type: 'INFO',
content: info
};
const createdMessage = this.repositoryService.oianalyticsMessageRepository.createOIAnalyticsMessages(infoMessageCommand);
const createdMessage = this.repositoryService.oianalyticsMessageRepository.createOIAnalyticsMessages('INFO', info);
this._oianalyticsMessageService.addMessageToQueue(createdMessage);
}
}
Expand Down
29 changes: 22 additions & 7 deletions shared/model/oianalytics-message.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@ export type OIAnalyticsMessageStatus = (typeof OIANALYTICS_MESSAGE_STATUS)[numbe
export const OIANALYTICS_MESSAGE_TYPES = ['INFO'] as const;
export type OIAnalyticsMessageType = (typeof OIANALYTICS_MESSAGE_TYPES)[number];

interface BaseOIAnalyticsMessageDTO<T> extends BaseEntity {
interface BaseOIAnalyticsMessageDTO extends BaseEntity {
type: OIAnalyticsMessageType;
status: OIAnalyticsMessageStatus;
error?: string;
completedDate?: Instant;
content: T;
}

interface OIAnalyticsMessageCommandDTO<T> extends Omit<BaseOIAnalyticsMessageDTO<T>, 'id' | 'creationDate' | 'lastEditInstant' | 'status'| 'error' | 'completedDate' > {}
interface BaseOIAnalyticsMessageCommandDTO {
type: string;
}

export interface OIAnalyticsMessageSearchParam {
types: Array<OIAnalyticsMessageType>;
Expand All @@ -36,13 +37,27 @@ export interface InfoMessageContent {
platform: string;
}

export interface OIAnalyticsMessageInfoDTO extends BaseOIAnalyticsMessageDTO<InfoMessageContent> {
type: 'INFO'


export interface OIAnalyticsMessageInfoDTO extends BaseOIAnalyticsMessageDTO {
type: 'INFO',
content: InfoMessageContent
}

export interface OIAnalyticsMessageInfoCommandDTO extends OIAnalyticsMessageCommandDTO<InfoMessageContent> {
type: 'INFO'
export interface OIAnalyticsMessageInfoCommandDTO extends BaseOIAnalyticsMessageCommandDTO {
type: 'INFO';
version: string;
oibusName: string;
oibusId: string;
dataDirectory: string;
binaryDirectory: string;
processId: string;
hostname: string;
operatingSystem: string;
architecture: string;
platform: string;
}

export type OIAnalyticsMessageCommand = OIAnalyticsMessageInfoCommandDTO
export type OIAnalyticsMessageDTO = OIAnalyticsMessageInfoDTO
export type InfoMessage = InfoMessageContent

0 comments on commit ffd9046

Please sign in to comment.