@confluentinc/schemaregistry
Version:
Node.js client for Confluent Schema Registry
396 lines (395 loc) • 13.4 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const kafka_javascript_1 = require("@confluentinc/kafka-javascript");
const schemaregistry_client_1 = require("../schemaregistry-client");
const globals_1 = require("@jest/globals");
const test_constants_1 = require("../test/test-constants");
const json_1 = require("../serde/json");
const serde_1 = require("../serde/serde");
const json_stringify_deterministic_1 = __importDefault(require("json-stringify-deterministic"));
const uuid_1 = require("uuid");
let schemaRegistryClient;
let serializerConfig;
let serializer;
let deserializer;
let producer;
let consumer;
const kafkaBrokerList = 'localhost:9092';
const kafka = new kafka_javascript_1.KafkaJS.Kafka({
kafkaJS: {
brokers: [kafkaBrokerList],
},
});
//Inspired by dotnet client
const schemaString = (0, json_stringify_deterministic_1.default)({
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Person",
"type": "object",
"additionalProperties": false,
"required": [
"FirstName",
"LastName"
],
"properties": {
"FirstName": {
"type": "string"
},
"MiddleName": {
"type": [
"null",
"string"
]
},
"LastName": {
"type": "string"
},
"Gender": {
"oneOf": [
{
"$ref": "#/definitions/Gender"
}
]
},
"NumberWithRange": {
"type": "integer",
"format": "int32",
"maximum": 5.0,
"minimum": 2.0
},
"Birthday": {
"type": "string",
"format": "date-time"
},
"Company": {
"oneOf": [
{
"$ref": "#/definitions/Company"
},
{
"type": "null"
}
]
},
"Cars": {
"type": [
"array",
"null"
],
"items": {
"$ref": "#/definitions/Car"
}
}
},
"definitions": {
"Gender": {
"type": "integer",
"description": "",
"x-enumNames": [
"Male",
"Female"
],
"enum": [
0,
1
]
},
"Company": {
"type": "object",
"additionalProperties": false,
"properties": {
"Name": {
"type": [
"null",
"string"
]
}
}
},
"Car": {
"type": "object",
"additionalProperties": false,
"properties": {
"Name": {
"type": [
"null",
"string"
]
},
"Manufacturer": {
"oneOf": [
{
"$ref": "#/definitions/Company"
},
{
"type": "null"
}
]
}
}
}
}
});
const orderDetailsSchema = {
schema: (0, json_stringify_deterministic_1.default)({
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://example.com/order_details.schema.json",
"title": "OrderDetails",
"description": "Order Details",
"type": "object",
"properties": {
"id": {
"description": "Order Id",
"type": "integer"
},
"customer": {
"description": "Customer",
"$ref": "http://example.com/customer.schema.json"
},
"payment_id": {
"description": "Payment Id",
"type": "string"
}
},
"required": ["id", "customer"]
}),
schemaType: 'JSON',
};
const orderSchema = {
schema: (0, json_stringify_deterministic_1.default)({
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://example.com/referencedproduct.schema.json",
"title": "Order",
"description": "Order",
"type": "object",
"properties": {
"order_details": {
"description": "Order Details",
"$ref": "http://example.com/order_details.schema.json"
},
"order_date": {
"description": "Order Date",
"type": "string",
"format": "date-time"
}
},
"required": ["order_details"]
}),
schemaType: 'JSON',
};
const customerSchema = {
schema: (0, json_stringify_deterministic_1.default)({
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://example.com/customer.schema.json",
"title": "Customer",
"description": "Customer Data",
"type": "object",
"properties": {
"name": {
"Description": "Customer name",
"type": "string"
},
"id": {
"description": "Customer id",
"type": "integer"
},
"email": {
"description": "Customer email",
"type": "string"
}
},
"required": ["name", "id"]
}),
schemaType: 'JSON',
};
const messageValue = {
"firstName": "Real",
"middleName": "Name",
"lastName": "LastName D. Roger",
"gender": "Male",
"numberWithRange": 3,
"birthday": 7671,
"company": {
"name": "WarpStream"
},
"cars": [
{
"name": "Flink",
"manufacturer": {
"name": "Immerok"
}
},
{
"name": "Car",
"manufacturer": {
"name": "Car Maker"
}
}
]
};
const metadata = {
properties: {
owner: 'Bob Jones',
email: 'bob@acme.com',
},
};
const schemaInfo = {
schema: schemaString,
metadata: metadata,
schemaType: 'JSON'
};
(0, globals_1.describe)('SchemaRegistryClient json Integration Test', () => {
(0, globals_1.beforeEach)(async () => {
schemaRegistryClient = new schemaregistry_client_1.SchemaRegistryClient(test_constants_1.clientConfig);
producer = kafka.producer({
kafkaJS: {
allowAutoTopicCreation: true,
acks: 1,
compression: kafka_javascript_1.KafkaJS.CompressionTypes.GZIP,
}
});
await producer.connect();
consumer = kafka.consumer({
kafkaJS: {
groupId: 'test-group',
fromBeginning: true,
partitionAssigners: [kafka_javascript_1.KafkaJS.PartitionAssigners.roundRobin],
},
});
});
(0, globals_1.afterEach)(async () => {
await producer.disconnect();
});
(0, globals_1.it)("Should serialize and deserialize json", async () => {
const testTopic = (0, uuid_1.v4)();
await schemaRegistryClient.register(testTopic + "-value", schemaInfo);
serializerConfig = { useLatestVersion: true };
serializer = new json_1.JsonSerializer(schemaRegistryClient, serde_1.SerdeType.VALUE, serializerConfig);
deserializer = new json_1.JsonDeserializer(schemaRegistryClient, serde_1.SerdeType.VALUE, {});
const outgoingMessage = {
key: 'key',
value: await serializer.serialize(testTopic, messageValue)
};
await producer.send({
topic: testTopic,
messages: [outgoingMessage]
});
consumer = kafka.consumer({
kafkaJS: {
groupId: 'test-group',
fromBeginning: true,
partitionAssigners: [kafka_javascript_1.KafkaJS.PartitionAssigners.roundRobin],
},
});
await consumer.connect();
await consumer.subscribe({ topic: testTopic });
let messageRcvd = false;
await consumer.run({
eachMessage: async ({ message }) => {
const decodedMessage = {
...message,
value: await deserializer.deserialize(testTopic, message.value)
};
messageRcvd = true;
(0, globals_1.expect)(decodedMessage.value).toMatchObject(messageValue);
},
});
// Wait around until we get a message, and then disconnect.
while (!messageRcvd) {
await new Promise((resolve) => setTimeout(resolve, 100));
}
await consumer.disconnect();
}, 30000);
(0, globals_1.it)("Should serialize with autoRegisterSchemas enabled and useLatestVersion disabled", async () => {
const testTopic = (0, uuid_1.v4)();
serializerConfig = { autoRegisterSchemas: true, useLatestVersion: false };
serializer = new json_1.JsonSerializer(schemaRegistryClient, serde_1.SerdeType.VALUE, serializerConfig);
const outgoingMessage = {
key: 'key',
value: await serializer.serialize(testTopic, messageValue)
};
await producer.send({
topic: testTopic,
messages: [outgoingMessage]
});
});
(0, globals_1.it)('Should fail to serialize with UseLatestVersion enabled and autoRegisterSchemas disabled', async () => {
const testTopic = (0, uuid_1.v4)();
serializerConfig = { autoRegisterSchemas: false, useLatestVersion: true };
serializer = new json_1.JsonSerializer(schemaRegistryClient, serde_1.SerdeType.VALUE, serializerConfig);
const messageValue = { "name": "Bob Jones", "age": 25 };
await (0, globals_1.expect)(serializer.serialize(testTopic, messageValue)).rejects.toThrowError();
});
(0, globals_1.it)("Should serialize referenced schemas", async () => {
const testTopic = (0, uuid_1.v4)();
serializerConfig = { useLatestVersion: true };
serializer = new json_1.JsonSerializer(schemaRegistryClient, serde_1.SerdeType.VALUE, serializerConfig);
deserializer = new json_1.JsonDeserializer(schemaRegistryClient, serde_1.SerdeType.VALUE, {});
const customerSubject = (0, uuid_1.v4)();
const orderDetailsSubject = (0, uuid_1.v4)();
await schemaRegistryClient.register(customerSubject, customerSchema);
const customerIdVersion = (await schemaRegistryClient.getLatestSchemaMetadata(customerSubject)).version;
const customerReference = {
name: "http://example.com/customer.schema.json",
subject: customerSubject,
version: customerIdVersion,
};
orderDetailsSchema.references = [customerReference];
await schemaRegistryClient.register(orderDetailsSubject, orderDetailsSchema);
const orderDetailsIdVersion = (await schemaRegistryClient.getLatestSchemaMetadata(orderDetailsSubject)).version;
const orderDetailsReference = {
name: "http://example.com/order_details.schema.json",
subject: orderDetailsSubject,
version: orderDetailsIdVersion,
};
orderSchema.references = [orderDetailsReference];
await schemaRegistryClient.register(testTopic + "-value", orderSchema);
const order = {
order_details: {
id: 1,
customer: {
name: "Bob Jones",
id: 1,
email: "bob@jones.com"
},
payment_id: "1234"
},
order_date: "2021-07-15T12:00:00Z"
};
const outgoingMessage = {
key: 'key',
value: await serializer.serialize(testTopic, order)
};
await producer.send({
topic: testTopic,
messages: [outgoingMessage]
});
consumer = kafka.consumer({
kafkaJS: {
groupId: 'test-group',
fromBeginning: true,
partitionAssigners: [kafka_javascript_1.KafkaJS.PartitionAssigners.roundRobin],
},
});
await consumer.connect();
await consumer.subscribe({ topic: testTopic });
let messageRcvd = false;
await consumer.run({
eachMessage: async ({ message }) => {
const decodedMessage = {
...message,
value: await deserializer.deserialize(testTopic, message.value)
};
messageRcvd = true;
(0, globals_1.expect)(decodedMessage.value).toMatchObject(order);
},
});
// Wait around until we get a message, and then disconnect.
while (!messageRcvd) {
await new Promise((resolve) => setTimeout(resolve, 100));
}
await consumer.disconnect();
}, 30000);
});