Skip to content

Commit

Permalink
test event-store
Browse files Browse the repository at this point in the history
  • Loading branch information
cyri113 committed Feb 28, 2024
1 parent 8bbebf5 commit 3c52e7d
Show file tree
Hide file tree
Showing 11 changed files with 288 additions and 67 deletions.
103 changes: 103 additions & 0 deletions apps/event-store/src/event-store.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// events.controller.spec.ts

import { Test, TestingModule } from '@nestjs/testing';
import { EventStoreController } from './event-store.controller';
import { EventStoreService } from './event-store.service';
import { Events } from '@app/common';
import { Message, Update } from 'grammy/types';

describe('EventStoreController', () => {
let controller: EventStoreController;
let eventsService: EventStoreService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [EventStoreController],
providers: [
{
provide: EventStoreService,
useValue: {
createEvent: jest.fn(),
},
},
],
}).compile();

controller = module.get<EventStoreController>(EventStoreController);
eventsService = module.get<EventStoreService>(EventStoreService);
});

it('should be defined', () => {
expect(controller).toBeDefined();
});

describe('message', () => {
it('should call createEvent with correct parameters', async () => {
const mockMessage = {
date: 1234,
chat: { id: 1234 },
} as Message;
await controller.message(mockMessage);
expect(eventsService.createEvent).toHaveBeenCalledWith(
mockMessage.date,
mockMessage.chat.id,
Events.Message,
mockMessage,
);
});
});

describe('edited_message', () => {
it('should call createEvent with correct parameters', async () => {
const mockUpdate = {
edited_message: {
date: 1234,
chat: { id: 1234 },
},
} as Update;
await controller.edited_message(mockUpdate);
expect(eventsService.createEvent).toHaveBeenCalledWith(
mockUpdate.edited_message.date,
mockUpdate.edited_message.chat.id,
Events.EditedMessage,
mockUpdate,
);
});
});

describe('message_reaction', () => {
it('should call createEvent with correct parameters', async () => {
const mockUpdate = {
message_reaction: {
date: 1234,
chat: { id: 1234 },
},
} as Update;
await controller.message_reaction(mockUpdate);
expect(eventsService.createEvent).toHaveBeenCalledWith(
mockUpdate.message_reaction.date,
mockUpdate.message_reaction.chat.id,
Events.MessageReaction,
mockUpdate,
);
});
});

describe('chat_member', () => {
it('should call createEvent with correct parameters', async () => {
const mockUpdate = {
chat_member: {
date: 1234,
chat: { id: 1234 },
},
} as Update;
await controller.chat_member(mockUpdate);
expect(eventsService.createEvent).toHaveBeenCalledWith(
mockUpdate.chat_member.date,
mockUpdate.chat_member.chat.id,
Events.ChatMemberUpdated,
mockUpdate,
);
});
});
});
53 changes: 11 additions & 42 deletions apps/event-store/src/event-store.controller.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,27 @@
import { Controller } from '@nestjs/common';
import { EventsService } from './event-store.service';
import {
Ctx,
MessagePattern,
Payload,
RmqContext,
} from '@nestjs/microservices';
import { Controller, UseInterceptors } from '@nestjs/common';
import { EventStoreService } from './event-store.service';
import { MessagePattern, Payload } from '@nestjs/microservices';
import { Events } from '@app/common';
import { Message, Update } from 'grammy/types';
import { EventsInterceptor } from './interceptors/events.interceptor';

@Controller()
export class EventsController {
constructor(private readonly eventsService: EventsService) {}
@UseInterceptors(EventsInterceptor)
export class EventStoreController {
constructor(private readonly eventsService: EventStoreService) {}

@MessagePattern(Events.Message)
async message(
@Payload() data: Message,
@Ctx() context: RmqContext,
): Promise<void> {
async message(@Payload() data: Message): Promise<void> {
await this.eventsService.createEvent(
data.date,
data.chat.id,
Events.Message,
data,
);

const channel = context.getChannelRef();
const originalMsg = context.getMessage();
channel.ack(originalMsg);
}

@MessagePattern(Events.EditedMessage)
async edited_message(
@Payload() data: Update,
@Ctx() context: RmqContext,
): Promise<void> {
async edited_message(@Payload() data: Update): Promise<void> {
const { edited_message } = data;

await this.eventsService.createEvent(
Expand All @@ -43,17 +30,10 @@ export class EventsController {
Events.EditedMessage,
data,
);

const channel = context.getChannelRef();
const originalMsg = context.getMessage();
channel.ack(originalMsg);
}

@MessagePattern(Events.MessageReaction)
async message_reaction(
@Payload() data: Update,
@Ctx() context: RmqContext,
): Promise<void> {
async message_reaction(@Payload() data: Update): Promise<void> {
const { message_reaction } = data;

await this.eventsService.createEvent(
Expand All @@ -62,17 +42,10 @@ export class EventsController {
Events.MessageReaction,
data,
);

const channel = context.getChannelRef();
const originalMsg = context.getMessage();
channel.ack(originalMsg);
}

@MessagePattern(Events.ChatMemberUpdated)
async chat_member(
@Payload() data: Update,
@Ctx() context: RmqContext,
): Promise<void> {
async chat_member(@Payload() data: Update): Promise<void> {
const { chat_member } = data;

await this.eventsService.createEvent(
Expand All @@ -81,9 +54,5 @@ export class EventsController {
Events.ChatMemberUpdated,
data,
);

const channel = context.getChannelRef();
const originalMsg = context.getMessage();
channel.ack(originalMsg);
}
}
32 changes: 32 additions & 0 deletions apps/event-store/src/event-store.module.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// event-store.module.spec.ts

import { Test, TestingModule } from '@nestjs/testing';
import { EventStoreModule } from './event-store.module';
import { ConfigModule } from '@nestjs/config';
import { RmqModule } from '@app/common';
import { MongooseModule } from '@nestjs/mongoose';

describe('EventStoreModule', () => {
let module: TestingModule;

beforeEach(async () => {
module = await Test.createTestingModule({
imports: [
EventStoreModule,
ConfigModule.forRoot({
isGlobal: true,
}),
RmqModule,
MongooseModule.forRootAsync({
useFactory: () => ({
uri: 'mongodb://localhost:27017/test',
}),
}),
],
}).compile();
});

it('should be defined', () => {
expect(module).toBeDefined();
});
});
26 changes: 16 additions & 10 deletions apps/event-store/src/event-store.module.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@
import { Module } from '@nestjs/common';
import { EventsController } from './event-store.controller';
import { EventsService } from './event-store.service';
import { ConfigModule } from '@nestjs/config';
import { schemaConfig, rmqConfig, RmqModule } from '@app/common';
import { EventStoreController } from './event-store.controller';
import { EventStoreService } from './event-store.service';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { schemaConfig, rmqConfig, RmqModule, mongoConfig } from '@app/common';
import { MongooseModule } from '@nestjs/mongoose';
import { EventSchema } from './events.model';
import { EventSchema, Event } from './schemas/event.schema';

@Module({
imports: [
ConfigModule.forRoot({
validationSchema: schemaConfig,
load: [rmqConfig],
load: [rmqConfig, mongoConfig],
isGlobal: true,
}),
RmqModule,
MongooseModule.forRoot('mongodb://root:pass@localhost:27017'),
MongooseModule.forRootAsync({
imports: [ConfigModule.forFeature(mongoConfig)],
useFactory: (configService: ConfigService) => ({
uri: configService.get<string>('mongo.uri'),
}),
inject: [ConfigService],
}),
MongooseModule.forFeature([{ name: Event.name, schema: EventSchema }]),
],
controllers: [EventsController],
providers: [EventsService],
controllers: [EventStoreController],
providers: [EventStoreService],
})
export class EventsModule {}
export class EventStoreModule {}
61 changes: 61 additions & 0 deletions apps/event-store/src/event-store.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { Test, TestingModule } from '@nestjs/testing';
import { EventStoreService } from './event-store.service';
import { getModelToken, getConnectionToken } from '@nestjs/mongoose';
import { Model, Connection } from 'mongoose';
import { Event } from './schemas/event.schema';

describe('EventStoreService', () => {
let service: EventStoreService;
let modelMock: Model<Event>;
let connectionMock: Connection;

beforeEach(async () => {
modelMock = {
create: jest.fn(),
} as unknown as Model<Event>; // Adjust the type according to your actual model

connectionMock = {
useDb: jest.fn(),
} as unknown as Connection; // Adjust the type according to your actual connection

const module: TestingModule = await Test.createTestingModule({
providers: [
EventStoreService,
{
provide: getModelToken(Event.name),
useValue: modelMock,
},
{
provide: getConnectionToken(),
useValue: connectionMock,
},
],
}).compile();

service = module.get<EventStoreService>(EventStoreService);
});

it('should be defined', () => {
expect(service).toBeDefined();
});

describe('createEvent', () => {
it('should create and save event to the appropriate collection', async () => {
const timestamp = Date.now();
const chatId = 123;
const eventType = 'message';
const eventData = {
/* mock event data */
};

await service.createEvent(timestamp, chatId, eventType, eventData);

expect(connectionMock.useDb).toHaveBeenCalledWith(`tg:${chatId}`);
expect(modelMock.create).toHaveBeenCalledWith({
timestamp,
event_type: eventType,
event_data: eventData,
});
});
});
});
18 changes: 9 additions & 9 deletions apps/event-store/src/event-store.service.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
import { Injectable } from '@nestjs/common';
import { InjectConnection, InjectModel } from '@nestjs/mongoose';
import { Connection, Model } from 'mongoose';
import { Event } from './schemas/event.schema';

@Injectable()
export class EventsService {
export class EventStoreService {
constructor(
@InjectModel(Event.name) private readonly eventModel: Model<Event>,
@InjectConnection() private readonly connection: Connection,
) {}

async createEvent(
ts: number,
timestamp: number,
chat_id: number,
event_type: string,
event_data: any,
): Promise<Event> {
const dynamicModel = this.connection.model(
`${chat_id}`,
this.eventModel.schema,
);
const createdEvent = new dynamicModel({
ts,
const dbName = `tg:${chat_id}`;
this.connection.useDb(dbName);

const createdEvent = await this.eventModel.create({
timestamp,
event_type,
event_data,
});
return createdEvent.save();
return createdEvent;
}
}
20 changes: 20 additions & 0 deletions apps/event-store/src/interceptors/events.interceptor.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// events.interceptor.spec.ts

import { Test, TestingModule } from '@nestjs/testing';
import { EventsInterceptor } from './events.interceptor';

describe('EventsInterceptor', () => {
let interceptor: EventsInterceptor;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [EventsInterceptor],
}).compile();

interceptor = module.get<EventsInterceptor>(EventsInterceptor);
});

it('should be defined', () => {
expect(interceptor).toBeDefined();
});
});
Loading

0 comments on commit 3c52e7d

Please sign in to comment.