package com.linkedin.databus2.schemas;
/*
*
* Copyright 2013 LinkedIn Corp. All rights reserved
*
* Licensed 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.
*
*/
import java.util.Map;
import java.util.SortedMap;
import org.apache.avro.Schema;
import org.testng.Assert;
import org.testng.annotations.Test;
public class TestVersionedSchemaSet
{
private static final String TEST_SCHEMA1_TEXT =
"{\"name\":\"schema1\",\"namespace\":\"com.linkedin.databus2.test\",\"type\":\"record\"," +
" \"fields\":[{\"name\":\"field1\",\"type\":\"string\"},{\"name\":\"field2\",\"type\":\"int\"}]}";
private static final String TEST_SCHEMA2_TEXT =
"{\"name\":\"schema2\",\"namespace\":\"com.linkedin.databus2.test\",\"type\":\"record\"," +
" \"fields\":[{\"name\":\"field1\",\"type\":\"double\"},{\"name\":\"field2\",\"type\":\"string\"}]}";
private static final String TEST_SCHEMA3_TEXT =
"{\"name\":\"AnotherSchema1\",\"namespace\":\"com.linkedin.databus2.test\",\"type\":\"record\"," +
" \"fields\":[{\"name\":\"field1\",\"type\":\"double\"},{\"name\":\"field2\",\"type\":\"string\"}]}";
private static final String TEST_SCHEMA4_TEXT_TEMPLATE =
"{\"name\":\"%s\",\"namespace\":\"com.linkedin.databus2.test\",\"type\":\"record\"," +
" \"fields\":[{\"name\":\"field1\",\"type\":\"string\"},{\"name\":\"field2\",\"type\":\"int\"}]}";
@Test
public void testOneAdd() throws Exception
{
VersionedSchemaSet schemaSet = new VersionedSchemaSet();
Schema schema1 = Schema.parse(TEST_SCHEMA1_TEXT);
VersionedSchema vs1 = new VersionedSchema("testSchema", (short)1, schema1, null);
Assert.assertTrue(schemaSet.add(vs1));
VersionedSchema test1 = schemaSet.getLatestVersionByName("testSchema");
Assert.assertNotNull(test1, "schema present");
Assert.assertEquals(test1.getVersion(), (short)1, "version correct");
Assert.assertEquals(test1.getSchemaBaseName(), "testSchema");
SchemaId vs1Id = SchemaId.createWithMd5(schema1);
VersionedSchema test2 = schemaSet.getById(vs1Id);
Assert.assertNotNull(test2, "schema present");
Assert.assertEquals(test2, vs1, "schema id correct");
VersionedSchema test3 = schemaSet.getSchemaByNameVersion("testSchema", (short)1);
Assert.assertNotNull(test3, "schema present");
Assert.assertEquals(test3, vs1, "schema name-version correct");
test3 = schemaSet.getSchemaByNameVersion("testSchema", (short)2);
Assert.assertNull(test3, "schema name-version not present");
test1 = schemaSet.getLatestVersionByName("TestSchema");
Assert.assertNull(test1, "schema base name not present");
//make sure we don't readd the same schema
Assert.assertTrue(!schemaSet.add(vs1));
Assert.assertTrue(!schemaSet.add("testSchema", (short)1, TEST_SCHEMA1_TEXT));
//make sure we don't override existing schema
Assert.assertTrue(!schemaSet.add("testSchema", (short)1, TEST_SCHEMA2_TEXT));
Assert.assertEquals(schemaSet.getSchema(new VersionedSchemaId("testSchema", (short)1)),
vs1);
}
@Test
public void testExternalSchemaIdAdd() throws Exception
{
VersionedSchemaSet schemaSet = new VersionedSchemaSet();
byte[] crc32 = {0x01,0x02,0x03,0x04};
String sourceName = "test_schema";
boolean added = schemaSet.add(sourceName,(short) 1,new SchemaId(crc32),TEST_SCHEMA1_TEXT);
Assert.assertTrue(added);
SchemaId fetchId = new SchemaId(crc32);
VersionedSchema vs = schemaSet.getById(fetchId);
Assert.assertTrue(vs != null);
Assert.assertEquals(vs.getVersion() , 1);
Assert.assertEquals(sourceName,vs.getSchemaBaseName());
}
@Test
public void testMultiAdd() throws Exception
{
VersionedSchemaSet schemaSet = new VersionedSchemaSet();
Schema schema1 = Schema.parse(TEST_SCHEMA1_TEXT);
SchemaId vs1Id = SchemaId.createWithMd5(schema1);
VersionedSchema vs1 = new VersionedSchema("testSchema", (short)1, schema1, null);
schemaSet.add(vs1);
Schema schema2 = Schema.parse(TEST_SCHEMA2_TEXT);
SchemaId vs2Id = SchemaId.createWithMd5(schema2);
VersionedSchema vs2 = new VersionedSchema("testSchema", (short)2, schema2, null);
schemaSet.add(vs2);
Schema schema3 = Schema.parse(TEST_SCHEMA3_TEXT);
SchemaId vs3Id = SchemaId.createWithMd5(schema3);
VersionedSchema vs3 = new VersionedSchema("anotherSchema", (short)3, schema3, null);
schemaSet.add(vs3);
VersionedSchema test1 = schemaSet.getLatestVersionByName("testSchema");
Assert.assertNotNull(test1, "schema present");
Assert.assertEquals(test1.getVersion(), (short)2, "version correct");
Assert.assertEquals(test1.getSchemaBaseName(), "testSchema");
VersionedSchema test2 = schemaSet.getById(vs1Id);
Assert.assertNotNull(test2, "schema present");
Assert.assertEquals(test2, vs1, "schema id 1 correct");
test2 = schemaSet.getById(vs2Id);
Assert.assertNotNull(test2, "schema present");
Assert.assertEquals(test2, vs2, "schema id 2 correct");
test2 = schemaSet.getById(vs3Id);
Assert.assertNotNull(test2, "schema present");
Assert.assertEquals(test2, vs3, "schema id 3 correct");
VersionedSchema test3 = schemaSet.getSchemaByNameVersion("anotherSchema", (short)3);
Assert.assertNotNull(test3, "schema present");
Assert.assertEquals(test3, vs3, "schema name-version correct");
test3 = schemaSet.getSchemaByNameVersion("testSchema", (short)2);
Assert.assertNotNull(test3, "schema present");
Assert.assertEquals(test3, vs2, "schema name-version correct");
SortedMap<VersionedSchemaId, VersionedSchema> testSchemas = schemaSet.getAllVersionsByName("testSchema");
Assert.assertNotNull(testSchemas, "schemas list present");
Assert.assertEquals(testSchemas.size(), 2, "correct number of schemas list");
Assert.assertEquals(testSchemas.get(testSchemas.firstKey()), vs1, "v1 present");
Assert.assertEquals(testSchemas.get(testSchemas.lastKey()), vs2, "v2 present");
schemaSet.add("testSchema", (short)3, TEST_SCHEMA3_TEXT);
Assert.assertEquals(schemaSet.getLatestVersionByName("testSchema").getSchema().getName(),
"AnotherSchema1");
}
@Test
public void testConcurrentAdd() throws InterruptedException
{
final VersionedSchemaSet schemaSet = new VersionedSchemaSet();
final int schemaNum = 10;
final short versionNum = 10;
Thread[][] threads = new Thread[schemaNum][];
for (int sIdx = 0; sIdx < schemaNum; ++sIdx)
{
threads[sIdx] = new Thread[versionNum + 1];
for (short vIdx = 1; vIdx <= versionNum; ++vIdx)
{
final int finalSIdx = sIdx;
final short finalVIdx = vIdx;
threads[sIdx][vIdx] = new Thread(new Runnable()
{
@Override
public void run()
{
String schemaName = "schema" + finalSIdx;
String schemaStr = String.format(TEST_SCHEMA4_TEXT_TEMPLATE, schemaName);
schemaSet.add(schemaName, finalVIdx, schemaStr);
}
}, "schema adder " + sIdx + "-" + vIdx);
threads[sIdx][vIdx].setDaemon(true);
}
}
for (int sIdx = 0; sIdx < schemaNum; ++sIdx)
{
for (short vIdx = 1; vIdx <= versionNum; ++vIdx)
{
threads[sIdx][vIdx].start();
}
}
for (int sIdx = 0; sIdx < schemaNum; ++sIdx)
{
for (short vIdx = 1; vIdx <= versionNum; ++vIdx)
{
threads[sIdx][vIdx].join(1000);
Assert.assertTrue(!threads[sIdx][vIdx].isAlive(), threads[sIdx][vIdx].getName() + " is dead");
VersionedSchema vschema = schemaSet.getSchemaByNameVersion("schema" + sIdx, vIdx);
Assert.assertNotNull(vschema, "schema" + sIdx + "-" + vIdx + " added");
Assert.assertEquals(vschema.getSchemaBaseName(), "schema" + sIdx);
Assert.assertEquals(vschema.getSchema().getName(), "schema" + sIdx);
Assert.assertEquals(vschema.getVersion(), vIdx);
}
}
}
@Test
/** Test that schemas which don't have stable reparsing, we add all MD5's */
public void testUpdateMd5Index()
{
final String schemaStr = "{\"type\":\"record\",\"name\":\"A\",\"fields\":[" +
"{\"name\":\"J\",\"type\":\"string\",\"J1\":\"V1\",\"indexType\":\"V2\",\"d\":" +
"\"V3\",\"J3\":\"10000\"}]}";
VersionedSchemaSet vschemaSet = new VersionedSchemaSet(true);
vschemaSet.add("testSchema", (short)1, schemaStr);
Assert.assertEquals(vschemaSet.getIdToSchema().size(), 2);
vschemaSet.add("TestSchema", (short)3, TEST_SCHEMA3_TEXT);
Assert.assertEquals(vschemaSet.getIdToSchema().size(), 3);
for (Map.Entry<SchemaId, VersionedSchema> e: vschemaSet.getIdToSchema().entrySet())
{
System.out.println(String.format("ids[%s] -> %s.%d", e.getKey(), e.getValue().getSchemaBaseName(),
e.getValue().getVersion()));
}
}
}