/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.kafka.connect.data;
import org.apache.kafka.connect.errors.SchemaBuilderException;
import org.junit.Test;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class SchemaBuilderTest {
private static final String NAME = "name";
private static final Integer VERSION = 2;
private static final String DOC = "doc";
private static final Map<String, String> NO_PARAMS = null;
@Test
public void testInt8Builder() {
Schema schema = SchemaBuilder.int8().build();
assertTypeAndDefault(schema, Schema.Type.INT8, false, null);
assertNoMetadata(schema);
schema = SchemaBuilder.int8().name(NAME).optional().defaultValue((byte) 12)
.version(VERSION).doc(DOC).build();
assertTypeAndDefault(schema, Schema.Type.INT8, true, (byte) 12);
assertMetadata(schema, NAME, VERSION, DOC, NO_PARAMS);
}
@Test(expected = SchemaBuilderException.class)
public void testInt8BuilderInvalidDefault() {
SchemaBuilder.int8().defaultValue("invalid");
}
@Test
public void testInt16Builder() {
Schema schema = SchemaBuilder.int16().build();
assertTypeAndDefault(schema, Schema.Type.INT16, false, null);
assertNoMetadata(schema);
schema = SchemaBuilder.int16().name(NAME).optional().defaultValue((short) 12)
.version(VERSION).doc(DOC).build();
assertTypeAndDefault(schema, Schema.Type.INT16, true, (short) 12);
assertMetadata(schema, NAME, VERSION, DOC, NO_PARAMS);
}
@Test(expected = SchemaBuilderException.class)
public void testInt16BuilderInvalidDefault() {
SchemaBuilder.int16().defaultValue("invalid");
}
@Test
public void testInt32Builder() {
Schema schema = SchemaBuilder.int32().build();
assertTypeAndDefault(schema, Schema.Type.INT32, false, null);
assertNoMetadata(schema);
schema = SchemaBuilder.int32().name(NAME).optional().defaultValue(12)
.version(VERSION).doc(DOC).build();
assertTypeAndDefault(schema, Schema.Type.INT32, true, 12);
assertMetadata(schema, NAME, VERSION, DOC, NO_PARAMS);
}
@Test(expected = SchemaBuilderException.class)
public void testInt32BuilderInvalidDefault() {
SchemaBuilder.int32().defaultValue("invalid");
}
@Test
public void testInt64Builder() {
Schema schema = SchemaBuilder.int64().build();
assertTypeAndDefault(schema, Schema.Type.INT64, false, null);
assertNoMetadata(schema);
schema = SchemaBuilder.int64().name(NAME).optional().defaultValue((long) 12)
.version(VERSION).doc(DOC).build();
assertTypeAndDefault(schema, Schema.Type.INT64, true, (long) 12);
assertMetadata(schema, NAME, VERSION, DOC, NO_PARAMS);
}
@Test(expected = SchemaBuilderException.class)
public void testInt64BuilderInvalidDefault() {
SchemaBuilder.int64().defaultValue("invalid");
}
@Test
public void testFloatBuilder() {
Schema schema = SchemaBuilder.float32().build();
assertTypeAndDefault(schema, Schema.Type.FLOAT32, false, null);
assertNoMetadata(schema);
schema = SchemaBuilder.float32().name(NAME).optional().defaultValue(12.f)
.version(VERSION).doc(DOC).build();
assertTypeAndDefault(schema, Schema.Type.FLOAT32, true, 12.f);
assertMetadata(schema, NAME, VERSION, DOC, NO_PARAMS);
}
@Test(expected = SchemaBuilderException.class)
public void testFloatBuilderInvalidDefault() {
SchemaBuilder.float32().defaultValue("invalid");
}
@Test
public void testDoubleBuilder() {
Schema schema = SchemaBuilder.float64().build();
assertTypeAndDefault(schema, Schema.Type.FLOAT64, false, null);
assertNoMetadata(schema);
schema = SchemaBuilder.float64().name(NAME).optional().defaultValue(12.0)
.version(VERSION).doc(DOC).build();
assertTypeAndDefault(schema, Schema.Type.FLOAT64, true, 12.0);
assertMetadata(schema, NAME, VERSION, DOC, NO_PARAMS);
}
@Test(expected = SchemaBuilderException.class)
public void testDoubleBuilderInvalidDefault() {
SchemaBuilder.float64().defaultValue("invalid");
}
@Test
public void testBooleanBuilder() {
Schema schema = SchemaBuilder.bool().build();
assertTypeAndDefault(schema, Schema.Type.BOOLEAN, false, null);
assertNoMetadata(schema);
schema = SchemaBuilder.bool().name(NAME).optional().defaultValue(true)
.version(VERSION).doc(DOC).build();
assertTypeAndDefault(schema, Schema.Type.BOOLEAN, true, true);
assertMetadata(schema, NAME, VERSION, DOC, NO_PARAMS);
}
@Test(expected = SchemaBuilderException.class)
public void testBooleanBuilderInvalidDefault() {
SchemaBuilder.bool().defaultValue("invalid");
}
@Test
public void testStringBuilder() {
Schema schema = SchemaBuilder.string().build();
assertTypeAndDefault(schema, Schema.Type.STRING, false, null);
assertNoMetadata(schema);
schema = SchemaBuilder.string().name(NAME).optional().defaultValue("a default string")
.version(VERSION).doc(DOC).build();
assertTypeAndDefault(schema, Schema.Type.STRING, true, "a default string");
assertMetadata(schema, NAME, VERSION, DOC, NO_PARAMS);
}
@Test(expected = SchemaBuilderException.class)
public void testStringBuilderInvalidDefault() {
SchemaBuilder.string().defaultValue(true);
}
@Test
public void testBytesBuilder() {
Schema schema = SchemaBuilder.bytes().build();
assertTypeAndDefault(schema, Schema.Type.BYTES, false, null);
assertNoMetadata(schema);
schema = SchemaBuilder.bytes().name(NAME).optional().defaultValue("a default byte array".getBytes())
.version(VERSION).doc(DOC).build();
assertTypeAndDefault(schema, Schema.Type.BYTES, true, "a default byte array".getBytes());
assertMetadata(schema, NAME, VERSION, DOC, NO_PARAMS);
}
@Test(expected = SchemaBuilderException.class)
public void testBytesBuilderInvalidDefault() {
SchemaBuilder.bytes().defaultValue("a string, not bytes");
}
@Test
public void testParameters() {
Map<String, String> expectedParameters = new HashMap<>();
expectedParameters.put("foo", "val");
expectedParameters.put("bar", "baz");
Schema schema = SchemaBuilder.string().parameter("foo", "val").parameter("bar", "baz").build();
assertTypeAndDefault(schema, Schema.Type.STRING, false, null);
assertMetadata(schema, null, null, null, expectedParameters);
schema = SchemaBuilder.string().parameters(expectedParameters).build();
assertTypeAndDefault(schema, Schema.Type.STRING, false, null);
assertMetadata(schema, null, null, null, expectedParameters);
}
@Test
public void testStructBuilder() {
Schema schema = SchemaBuilder.struct()
.field("field1", Schema.INT8_SCHEMA)
.field("field2", Schema.INT8_SCHEMA)
.build();
assertTypeAndDefault(schema, Schema.Type.STRUCT, false, null);
assertEquals(2, schema.fields().size());
assertEquals("field1", schema.fields().get(0).name());
assertEquals(0, schema.fields().get(0).index());
assertEquals(Schema.INT8_SCHEMA, schema.fields().get(0).schema());
assertEquals("field2", schema.fields().get(1).name());
assertEquals(1, schema.fields().get(1).index());
assertEquals(Schema.INT8_SCHEMA, schema.fields().get(1).schema());
assertNoMetadata(schema);
}
@Test(expected = SchemaBuilderException.class)
public void testNonStructCantHaveFields() {
SchemaBuilder.int8().field("field", SchemaBuilder.int8().build());
}
@Test
public void testArrayBuilder() {
Schema schema = SchemaBuilder.array(Schema.INT8_SCHEMA).build();
assertTypeAndDefault(schema, Schema.Type.ARRAY, false, null);
assertEquals(schema.valueSchema(), Schema.INT8_SCHEMA);
assertNoMetadata(schema);
// Default value
List<Byte> defArray = Arrays.asList((byte) 1, (byte) 2);
schema = SchemaBuilder.array(Schema.INT8_SCHEMA).defaultValue(defArray).build();
assertTypeAndDefault(schema, Schema.Type.ARRAY, false, defArray);
assertEquals(schema.valueSchema(), Schema.INT8_SCHEMA);
assertNoMetadata(schema);
}
@Test(expected = SchemaBuilderException.class)
public void testArrayBuilderInvalidDefault() {
// Array, but wrong embedded type
SchemaBuilder.array(Schema.INT8_SCHEMA).defaultValue(Arrays.asList("string")).build();
}
@Test
public void testMapBuilder() {
// SchemaBuilder should also pass the check
Schema schema = SchemaBuilder.map(Schema.INT8_SCHEMA, Schema.INT8_SCHEMA);
assertTypeAndDefault(schema, Schema.Type.MAP, false, null);
assertEquals(schema.keySchema(), Schema.INT8_SCHEMA);
assertEquals(schema.valueSchema(), Schema.INT8_SCHEMA);
assertNoMetadata(schema);
schema = SchemaBuilder.map(Schema.INT8_SCHEMA, Schema.INT8_SCHEMA).build();
assertTypeAndDefault(schema, Schema.Type.MAP, false, null);
assertEquals(schema.keySchema(), Schema.INT8_SCHEMA);
assertEquals(schema.valueSchema(), Schema.INT8_SCHEMA);
assertNoMetadata(schema);
// Default value
Map<Byte, Byte> defMap = Collections.singletonMap((byte) 5, (byte) 10);
schema = SchemaBuilder.map(Schema.INT8_SCHEMA, Schema.INT8_SCHEMA)
.defaultValue(defMap).build();
assertTypeAndDefault(schema, Schema.Type.MAP, false, defMap);
assertEquals(schema.keySchema(), Schema.INT8_SCHEMA);
assertEquals(schema.valueSchema(), Schema.INT8_SCHEMA);
assertNoMetadata(schema);
}
@Test(expected = SchemaBuilderException.class)
public void testMapBuilderInvalidDefault() {
// Map, but wrong embedded type
Map<Byte, String> defMap = Collections.singletonMap((byte) 5, "foo");
SchemaBuilder.map(Schema.INT8_SCHEMA, Schema.INT8_SCHEMA)
.defaultValue(defMap).build();
}
@Test
public void testEmptyStruct() {
final SchemaBuilder emptyStructSchemaBuilder = SchemaBuilder.struct();
assertEquals(0, emptyStructSchemaBuilder.fields().size());
new Struct(emptyStructSchemaBuilder);
final Schema emptyStructSchema = emptyStructSchemaBuilder.build();
assertEquals(0, emptyStructSchema.fields().size());
new Struct(emptyStructSchema);
}
@Test(expected = SchemaBuilderException.class)
public void testDuplicateFields() {
final Schema schema = SchemaBuilder.struct()
.name("testing")
.field("id", SchemaBuilder.string().doc("").build())
.field("id", SchemaBuilder.string().doc("").build())
.build();
final Struct struct = new Struct(schema)
.put("id", "testing");
struct.validate();
}
@Test
public void testDefaultFieldsSameValueOverwriting() {
final SchemaBuilder schemaBuilder = SchemaBuilder.string().name("testing").version(123);
schemaBuilder.name("testing");
schemaBuilder.version(123);
assertEquals("testing", schemaBuilder.name());
}
@Test(expected = SchemaBuilderException.class)
public void testDefaultFieldsDifferentValueOverwriting() {
final SchemaBuilder schemaBuilder = SchemaBuilder.string().name("testing").version(123);
schemaBuilder.name("testing");
schemaBuilder.version(456);
}
private void assertTypeAndDefault(Schema schema, Schema.Type type, boolean optional, Object defaultValue) {
assertEquals(type, schema.type());
assertEquals(optional, schema.isOptional());
if (type == Schema.Type.BYTES) {
// byte[] is not comparable, need to wrap to check correctly
if (defaultValue == null)
assertNull(schema.defaultValue());
else
assertEquals(ByteBuffer.wrap((byte[]) defaultValue), ByteBuffer.wrap((byte[]) schema.defaultValue()));
} else {
assertEquals(defaultValue, schema.defaultValue());
}
}
private void assertMetadata(Schema schema, String name, Integer version, String doc, Map<String, String> parameters) {
assertEquals(name, schema.name());
assertEquals(version, schema.version());
assertEquals(doc, schema.doc());
assertEquals(parameters, schema.parameters());
}
private void assertNoMetadata(Schema schema) {
assertMetadata(schema, null, null, null, null);
}
}