forked from ovotech/bit-node-tools
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathintegration.spec.ts
More file actions
162 lines (137 loc) · 5.37 KB
/
Copy pathintegration.spec.ts
File metadata and controls
162 lines (137 loc) · 5.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
import { DateType, TimestampType } from '@ovotech/avro-logical-types';
import { idToSchema } from '@ovotech/schema-registry-api';
import { Type } from 'avsc';
import { readdirSync, readFileSync } from 'fs';
import { ConsumerGroupStream, KafkaClient, Producer, ProducerStream } from 'kafka-node';
import { join } from 'path';
import { Readable } from 'stream';
import { ReadableMock, WritableMock } from 'stream-mock';
import * as uuid from 'uuid';
import { AvroDeserializer, AvroTopicSender, deconstructMessage } from '../src';
import { AvroSerializer } from '../src';
const createTopics = async (topics: string[]) => {
const producer = new Producer(new KafkaClient({ kafkaHost: 'localhost:29092' }));
await new Promise(resolve => producer.on('ready', resolve));
return await new Promise((resolve, reject) =>
producer.createTopics(topics, false, error => {
if (error) {
reject(error);
} else {
setTimeout(() => producer.close(resolve), 1000);
}
}),
);
};
const stopStreamOnCount = (max: number, stream: Readable) => {
let current = 0;
stream.on('data', () => {
current += 1;
if (current >= max) {
stream.push(null);
}
});
return stream;
};
const files = readdirSync(join(__dirname, './assets'));
const sourceData = files.map(file => JSON.parse(String(readFileSync(join(__dirname, './assets', file)))));
const unqiueSourceData = sourceData.map(item => ({ ...item, topic: uuid.v4() }));
const messagesCount = sourceData.reduce((sum, item) => sum + item.messages.length, 0);
const logicalTypes = { date: DateType, 'timestamp-millis': TimestampType };
describe('Integration test', () => {
it('Test Serialier', async () => {
const sourceStream = new ReadableMock(sourceData, { objectMode: true });
const sinkStream = new WritableMock({ objectMode: true });
const serializer = new AvroSerializer('http://localhost:8081', { logicalTypes });
sourceStream.pipe(serializer).pipe(sinkStream);
await new Promise(resolve => {
sinkStream.on('finish', async () => {
for (const [itemIndex, item] of sinkStream.data.entries()) {
const type = Type.forSchema(item.schema);
for (const [messageIndex, message] of item.messages.entries()) {
const messageParts = deconstructMessage(message);
const schemaMessage = await idToSchema('http://localhost:8081', messageParts.schemaId);
const content = type.fromBuffer(messageParts.buffer);
expect(schemaMessage).toEqual(item.schema);
expect(content).toEqual(sourceData[itemIndex].messages[messageIndex]);
}
}
resolve();
});
});
});
it('Test Deserializer with kafka', async () => {
const sourceStream = new ReadableMock(unqiueSourceData, { objectMode: true });
const sinkStream = new WritableMock({ objectMode: true });
const topics = unqiueSourceData.map(item => item.topic);
const deserializer = new AvroDeserializer('http://localhost:8081', { logicalTypes });
const serializer = new AvroSerializer('http://localhost:8081', { logicalTypes });
await createTopics(topics);
const consumerStream = new ConsumerGroupStream(
{
kafkaHost: 'localhost:29092',
groupId: `integration`,
encoding: 'buffer',
fromOffset: 'earliest',
},
topics,
);
const producerStream = new ProducerStream({ kafkaClient: { kafkaHost: 'localhost:29092' } });
stopStreamOnCount(messagesCount, consumerStream);
consumerStream.pipe(deserializer).pipe(sinkStream);
sourceStream.pipe(serializer).pipe(producerStream);
await new Promise(resolve => {
sinkStream.on('finish', () => {
for (let index = 0; index < messagesCount; index++) {
expect(sinkStream.data[index]).toMatchSnapshot({
topic: expect.any(String),
timestamp: expect.any(Date),
});
}
producerStream.close();
consumerStream.close(resolve);
});
});
}, 15000);
it('Test AvroTopicSender with kafka', async () => {
const topic = uuid.v4();
const sender = new AvroTopicSender<{ accountId: string }>({
topic,
partition: 0,
schema: {
type: 'record',
name: 'TestSchema1',
fields: [{ name: 'accountId', type: 'string' }],
},
});
const deserializer = new AvroDeserializer('http://localhost:8081', { logicalTypes });
const serializer = new AvroSerializer('http://localhost:8081', { logicalTypes });
const sinkStream = new WritableMock({ objectMode: true });
await createTopics([topic]);
const consumerStream = new ConsumerGroupStream(
{
kafkaHost: 'localhost:29092',
groupId: `integration`,
encoding: 'buffer',
fromOffset: 'earliest',
},
topic,
);
const producerStream = new ProducerStream({ kafkaClient: { kafkaHost: 'localhost:29092' } });
consumerStream.pipe(deserializer).pipe(sinkStream);
sender.pipe(serializer).pipe(producerStream);
stopStreamOnCount(1, consumerStream);
sender.send({ accountId: '234' });
await new Promise(resolve => {
sinkStream.on('finish', () => {
expect(sinkStream.data).toEqual([
expect.objectContaining({
topic,
value: { accountId: '234' },
}),
]);
producerStream.close();
consumerStream.close(resolve);
});
});
}, 15000);
});