Skip to content

Commit fbb894a

Browse files
refactor() resolve conflicts
2 parents 77297ca + 7db42a1 commit fbb894a

61 files changed

Lines changed: 4362 additions & 135 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ node_modules/
55
/.idea
66
/.awcache
77
/.vscode
8+
*.code-workspace
89

910
# bundle
1011
packages/**/*.d.ts

integration/docker-compose.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,42 @@ services:
3131
- "3306:3306"
3232
restart: always
3333
mongodb:
34+
container_name: test-mongodb
3435
image: mongo:latest
3536
environment:
3637
- MONGODB_DATABASE="test"
3738
ports:
3839
- 27017:27017
3940
rabbit:
41+
container_name: test-rabbit
4042
hostname: rabbit
4143
image: "rabbitmq:management"
4244
ports:
4345
- "15672:15672"
4446
- "5672:5672"
4547
tty: true
48+
zookeeper:
49+
container_name: test-zookeeper
50+
hostname: zookeeper
51+
image: confluentinc/cp-zookeeper:5.3.0
52+
ports:
53+
- "2181:2181"
54+
environment:
55+
ZOOKEEPER_CLIENT_PORT: 2181
56+
ZOOKEEPER_TICK_TIME: 2000
57+
kafka:
58+
container_name: test-kafka
59+
hostname: kafka
60+
image: confluentinc/cp-kafka:5.3.0
61+
depends_on:
62+
- zookeeper
63+
ports:
64+
- "29092:29092"
65+
- "9092:9092"
66+
environment:
67+
KAFKA_BROKER_ID: 1
68+
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
69+
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
70+
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092
71+
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
72+
KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import { INestApplication } from '@nestjs/common';
2+
import { Transport } from '@nestjs/microservices';
3+
import { Test } from '@nestjs/testing';
4+
import { expect } from 'chai';
5+
import * as request from 'supertest';
6+
import { BusinessDto } from '../src/kafka/dtos/business.dto';
7+
import { UserDto } from '../src/kafka/dtos/user.dto';
8+
import { UserEntity } from '../src/kafka/entities/user.entity';
9+
import { KafkaController } from '../src/kafka/kafka.controller';
10+
import { KafkaMessagesController } from '../src/kafka/kafka.messages.controller';
11+
12+
describe('Kafka transport', () => {
13+
let server;
14+
let app: INestApplication;
15+
16+
it(`Start Kafka app`, async () => {
17+
const module = await Test.createTestingModule({
18+
controllers: [KafkaController, KafkaMessagesController],
19+
}).compile();
20+
21+
app = module.createNestApplication();
22+
server = app.getHttpAdapter().getInstance();
23+
24+
app.connectMicroservice({
25+
transport: Transport.KAFKA,
26+
options: {
27+
client: {
28+
brokers: ['localhost:9092'],
29+
},
30+
},
31+
});
32+
await app.startAllMicroservicesAsync();
33+
await app.init();
34+
}).timeout(30000);
35+
36+
it(`/POST (sync sum kafka message)`, () => {
37+
return request(server)
38+
.post('/mathSumSyncKafkaMessage')
39+
.send([1, 2, 3, 4, 5])
40+
.expect(200)
41+
.expect(200, '15');
42+
});
43+
44+
it(`/POST (sync sum kafka(ish) message without key and only the value)`, () => {
45+
return request(server)
46+
.post('/mathSumSyncWithoutKey')
47+
.send([1, 2, 3, 4, 5])
48+
.expect(200)
49+
.expect(200, '15');
50+
});
51+
52+
it(`/POST (sync sum plain object)`, () => {
53+
return request(server)
54+
.post('/mathSumSyncPlainObject')
55+
.send([1, 2, 3, 4, 5])
56+
.expect(200)
57+
.expect(200, '15');
58+
});
59+
60+
it(`/POST (sync sum array)`, () => {
61+
return request(server)
62+
.post('/mathSumSyncArray')
63+
.send([1, 2, 3, 4, 5])
64+
.expect(200)
65+
.expect(200, '15');
66+
});
67+
68+
it(`/POST (sync sum string)`, () => {
69+
return request(server)
70+
.post('/mathSumSyncString')
71+
.send([1, 2, 3, 4, 5])
72+
.expect(200)
73+
.expect(200, '15');
74+
});
75+
76+
it(`/POST (sync sum number)`, () => {
77+
return request(server)
78+
.post('/mathSumSyncNumber')
79+
.send([12345])
80+
.expect(200)
81+
.expect(200, '15');
82+
});
83+
84+
it(`/POST (async event notification)`, done => {
85+
request(server)
86+
.post('/notify')
87+
.send()
88+
.end(() => {
89+
setTimeout(() => {
90+
expect(KafkaController.IS_NOTIFIED).to.be.true;
91+
done();
92+
}, 1000);
93+
});
94+
});
95+
96+
const userDto: UserDto = {
97+
email: 'enriquebenavidesm@gmail.com',
98+
name: 'Ben',
99+
phone: '1112223331',
100+
years: 33,
101+
};
102+
const newUser: UserEntity = new UserEntity(userDto);
103+
const businessDto: BusinessDto = {
104+
name: 'Example',
105+
phone: '2233441122',
106+
user: newUser,
107+
};
108+
it(`/POST (sync command create user)`, () => {
109+
return request(server)
110+
.post('/user')
111+
.send(userDto)
112+
.expect(200);
113+
});
114+
115+
it(`/POST (sync command create business`, () => {
116+
return request(server)
117+
.post('/business')
118+
.send(businessDto)
119+
.expect(200);
120+
});
121+
122+
it(`/POST (sync command create user) Concurrency Test`, async () => {
123+
const promises = [];
124+
for (let concurrencyKey = 0; concurrencyKey < 100; concurrencyKey++) {
125+
const innerUserDto = JSON.parse(JSON.stringify(userDto));
126+
innerUserDto.name += `+${concurrencyKey}`;
127+
promises.push(
128+
request(server)
129+
.post('/user')
130+
.send(userDto)
131+
.expect(200),
132+
);
133+
}
134+
await Promise.all(promises);
135+
});
136+
137+
after(`Stopping Kafka app`, async () => {
138+
await app.close();
139+
});
140+
}).timeout(30000);
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { UserEntity } from '../entities/user.entity';
2+
3+
export class BusinessDto {
4+
name: string;
5+
phone: string;
6+
user: UserEntity;
7+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export class UserDto {
2+
name: string;
3+
email: string;
4+
phone: string;
5+
years: number;
6+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { UserEntity } from './user.entity';
2+
import { BusinessDto } from '../dtos/business.dto';
3+
4+
export class BusinessEntity {
5+
constructor(business: BusinessDto) {
6+
this.id = Math.random() * 99999999;
7+
this.name = business.name;
8+
this.phone = business.phone;
9+
this.createdBy = {
10+
id: business.user.id,
11+
};
12+
this.created = new Date();
13+
}
14+
id: number;
15+
name: string;
16+
phone: string;
17+
createdBy: Partial<UserEntity>;
18+
created: Date;
19+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { UserDto } from '../dtos/user.dto';
2+
3+
export class UserEntity {
4+
constructor(user: UserDto) {
5+
this.id = Math.random() * 99999999;
6+
this.name = user.name;
7+
this.email = user.email;
8+
this.phone = user.phone;
9+
this.years = user.years;
10+
this.created = new Date();
11+
}
12+
id: number;
13+
name: string;
14+
email: string;
15+
phone: string;
16+
years: number;
17+
created: Date;
18+
}
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
import { Body, Controller, HttpCode, OnModuleInit, Post } from '@nestjs/common';
2+
import { Logger } from '@nestjs/common/services/logger.service';
3+
import { Client, ClientKafka, Transport } from '@nestjs/microservices';
4+
import { Observable } from 'rxjs';
5+
import { BusinessDto } from './dtos/business.dto';
6+
import { UserDto } from './dtos/user.dto';
7+
8+
@Controller()
9+
export class KafkaController implements OnModuleInit {
10+
protected readonly logger = new Logger(KafkaController.name);
11+
static IS_NOTIFIED = false;
12+
static MATH_SUM = 0;
13+
14+
@Client({
15+
transport: Transport.KAFKA,
16+
options: {
17+
client: {
18+
brokers: ['localhost:9092'],
19+
},
20+
},
21+
})
22+
private readonly client: ClientKafka;
23+
24+
onModuleInit() {
25+
const requestPatterns = [
26+
'math.sum.sync.kafka.message',
27+
'math.sum.sync.without.key',
28+
'math.sum.sync.plain.object',
29+
'math.sum.sync.array',
30+
'math.sum.sync.string',
31+
'math.sum.sync.number',
32+
'user.create',
33+
'business.create',
34+
];
35+
36+
requestPatterns.forEach(pattern => {
37+
this.client.subscribeToResponseOf(pattern);
38+
});
39+
}
40+
41+
// sync send kafka message
42+
@Post('mathSumSyncKafkaMessage')
43+
@HttpCode(200)
44+
async mathSumSyncKafkaMessage(
45+
@Body() data: number[],
46+
): Promise<Observable<any>> {
47+
const result = await this.client
48+
.send('math.sum.sync.kafka.message', {
49+
key: '1',
50+
value: {
51+
numbers: data,
52+
},
53+
})
54+
.toPromise();
55+
return result;
56+
}
57+
58+
// sync send kafka(ish) message without key and only the value
59+
@Post('mathSumSyncWithoutKey')
60+
@HttpCode(200)
61+
async mathSumSyncWithoutKey(
62+
@Body() data: number[],
63+
): Promise<Observable<any>> {
64+
const result = await this.client
65+
.send('math.sum.sync.without.key', {
66+
value: {
67+
numbers: data,
68+
},
69+
})
70+
.toPromise();
71+
return result;
72+
}
73+
74+
// sync send message without key or value
75+
@Post('mathSumSyncPlainObject')
76+
@HttpCode(200)
77+
async mathSumSyncPlainObject(
78+
@Body() data: number[],
79+
): Promise<Observable<any>> {
80+
const result = await this.client
81+
.send('math.sum.sync.plain.object', {
82+
numbers: data,
83+
})
84+
.toPromise();
85+
return result;
86+
}
87+
88+
// sync send message without key or value
89+
@Post('mathSumSyncArray')
90+
@HttpCode(200)
91+
async mathSumSyncArray(@Body() data: number[]): Promise<Observable<any>> {
92+
const result = await this.client
93+
.send('math.sum.sync.array', data)
94+
.toPromise();
95+
return result;
96+
}
97+
98+
@Post('mathSumSyncString')
99+
@HttpCode(200)
100+
async mathSumSyncString(@Body() data: number[]): Promise<Observable<any>> {
101+
// this.logger.error(util.format('mathSumSyncString() data: %o', data));
102+
const result = await this.client
103+
.send('math.sum.sync.string', data.toString())
104+
.toPromise();
105+
return result;
106+
}
107+
108+
@Post('mathSumSyncNumber')
109+
@HttpCode(200)
110+
async mathSumSyncNumber(@Body() data: number[]): Promise<Observable<any>> {
111+
const result = await this.client
112+
.send('math.sum.sync.number', data[0])
113+
.toPromise();
114+
return result;
115+
}
116+
117+
// async notify
118+
@Post('notify')
119+
async sendNotification(): Promise<any> {
120+
return this.client.emit('notify', { notify: true });
121+
}
122+
123+
// Complex data to send.
124+
@Post('/user')
125+
@HttpCode(200)
126+
async createUser(@Body() user: UserDto): Promise<Observable<any>> {
127+
const result = await this.client
128+
.send('user.create', {
129+
key: '1',
130+
value: {
131+
user,
132+
},
133+
})
134+
.toPromise();
135+
return result;
136+
}
137+
138+
// Complex data to send.
139+
@Post('/business')
140+
@HttpCode(200)
141+
async createBusiness(@Body() business: BusinessDto) {
142+
const result = await this.client
143+
.send('business.create', {
144+
key: '1',
145+
value: {
146+
business,
147+
},
148+
})
149+
.toPromise();
150+
return result;
151+
}
152+
}

0 commit comments

Comments
 (0)