blob: 888949aece3e08492f41619ef7011cce892352de [file] [log] [blame]
/*
* Copyright 2017 The Apache Software Foundation.
*
* 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
*
* https://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.avro.compiler.schema;
import org.apache.avro.Schema;
import org.apache.avro.SchemaCompatibility;
import org.junit.Assert;
import org.junit.Test;
public class TestSchemas {
private static final String SCHEMA = "{\"type\":\"record\",\"name\":\"SampleNode\",\"doc\":\"caca\","
+ "\"namespace\":\"org.spf4j.ssdump2.avro\",\n" + " \"fields\":[\n"
+ " {\"name\":\"count\",\"type\":\"int\",\"default\":0,\"doc\":\"caca\"},\n"
+ " {\"name\":\"kind1\",\"type\":{\"type\":\"enum\", \"name\": \"Kind1\", \"symbols\": [\"A1\", \"B1\"]}},\n"
+ " {\"name\":\"kind2\",\"type\":{\"type\":\"enum\", \"name\": \"Kind2\", \"symbols\": [\"A2\", \"B2\"], \"doc\": \"doc\"}},\n"
+ " {\"name\":\"pat\",\"type\":{\"type\":\"fixed\", \"name\": \"FixedPattern\", \"size\": 10}},\n"
+ " {\"name\":\"uni\",\"type\":[\"int\", \"double\"]},\n"
+ " {\"name\":\"mp\",\"type\":{\"type\":\"map\", \"values\": \"int\"}},\n"
+ " {\"name\":\"subNodes\",\"type\":\n" + " {\"type\":\"array\",\"items\":{\n"
+ " \"type\":\"record\",\"name\":\"SamplePair\",\n" + " \"fields\":[\n"
+ " {\"name\":\"method\",\"type\":\n"
+ " {\"type\":\"record\",\"name\":\"Method\",\n" + " \"fields\":[\n"
+ " {\"name\":\"declaringClass\",\"type\":{\"type\":\"string\",\"avro.java.string\":\"String\"}},\n"
+ " {\"name\":\"methodName\",\"type\":{\"type\":\"string\",\"avro.java.string\":\"String\"}}\n"
+ " ]}},\n" + " {\"name\":\"node\",\"type\":\"SampleNode\"}]}}}" + "]}";
@Test
public void textCloning() {
Schema recSchema = new Schema.Parser().parse(SCHEMA);
CloningVisitor cv = new CloningVisitor(recSchema);
Schema trimmed = Schemas.visit(recSchema, cv);
Assert.assertNull(trimmed.getDoc());
Assert.assertNotNull(recSchema.getDoc());
SchemaCompatibility.SchemaCompatibilityType compat = SchemaCompatibility
.checkReaderWriterCompatibility(trimmed, recSchema).getType();
Assert.assertEquals(SchemaCompatibility.SchemaCompatibilityType.COMPATIBLE, compat);
compat = SchemaCompatibility.checkReaderWriterCompatibility(recSchema, trimmed).getType();
Assert.assertEquals(SchemaCompatibility.SchemaCompatibilityType.COMPATIBLE, compat);
Assert.assertNotNull(cv.toString());
}
@Test
public void textCloningCopyDocs() {
Schema recSchema = new Schema.Parser().parse(SCHEMA);
Schema trimmed = Schemas.visit(recSchema, new CloningVisitor(new CloningVisitor.PropertyCopier() {
@Override
public void copy(final Schema first, final Schema second) {
Schemas.copyLogicalTypes(first, second);
Schemas.copyAliases(first, second);
}
@Override
public void copy(final Schema.Field first, final Schema.Field second) {
Schemas.copyAliases(first, second);
}
}, true, recSchema));
Assert.assertEquals("caca", trimmed.getDoc());
Assert.assertNotNull(recSchema.getDoc());
SchemaCompatibility.SchemaCompatibilityType compat = SchemaCompatibility
.checkReaderWriterCompatibility(trimmed, recSchema).getType();
Assert.assertEquals(SchemaCompatibility.SchemaCompatibilityType.COMPATIBLE, compat);
compat = SchemaCompatibility.checkReaderWriterCompatibility(recSchema, trimmed).getType();
Assert.assertEquals(SchemaCompatibility.SchemaCompatibilityType.COMPATIBLE, compat);
}
@Test(expected = IllegalStateException.class)
public void testCloningError1() {
// Visit Terminal with union
Schema recordSchema = new Schema.Parser().parse(
"{\"type\": \"record\", \"name\": \"R\", \"fields\":[{\"name\": \"f1\", \"type\": [\"int\", \"long\"]}]}");
new CloningVisitor(recordSchema).visitTerminal(recordSchema.getField("f1").schema());
}
@Test(expected = IllegalStateException.class)
public void testCloningError2() {
// After visit Non-terminal with int
Schema recordSchema = new Schema.Parser()
.parse("{\"type\": \"record\", \"name\": \"R\", \"fields\":[{\"name\": \"f1\", \"type\": \"int\"}]}");
new CloningVisitor(recordSchema).afterVisitNonTerminal(recordSchema.getField("f1").schema());
}
@Test
public void testHasGeneratedJavaClass() {
Assert.assertTrue(Schemas
.hasGeneratedJavaClass(new Schema.Parser().parse("{\"type\": \"fixed\", \"name\": \"N\", \"size\": 10}")));
Assert.assertFalse(Schemas.hasGeneratedJavaClass(new Schema.Parser().parse("{\"type\": \"int\"}")));
}
@Test
public void testGetJavaClassName() {
Assert.assertEquals("N",
Schemas.getJavaClassName(new Schema.Parser().parse("{\"type\": \"fixed\", \"name\": \"N\", \"size\": 10}")));
Assert.assertEquals("N", Schemas.getJavaClassName(
new Schema.Parser().parse("{\"type\": \"fixed\", \"name\": \"N\", \"size\": 10, \"namespace\": \"\"}")));
Assert.assertEquals("com.example.N", Schemas.getJavaClassName(new Schema.Parser()
.parse("{\"type\": \"fixed\", \"name\": \"N\", \"size\": 10, \"namespace\": \"com.example\"}")));
}
private static class TestVisitor implements SchemaVisitor<String> {
StringBuilder sb = new StringBuilder();
public SchemaVisitorAction visitTerminal(Schema terminal) {
sb.append(terminal);
return SchemaVisitorAction.CONTINUE;
}
public SchemaVisitorAction visitNonTerminal(Schema nonTerminal) {
String n = nonTerminal.getName();
sb.append(n).append('.');
if (n.startsWith("t")) {
return SchemaVisitorAction.TERMINATE;
} else if (n.startsWith("ss")) {
return SchemaVisitorAction.SKIP_SIBLINGS;
} else if (n.startsWith("st")) {
return SchemaVisitorAction.SKIP_SUBTREE;
} else {
return SchemaVisitorAction.CONTINUE;
}
}
public SchemaVisitorAction afterVisitNonTerminal(Schema nonTerminal) {
sb.append("!");
String n = nonTerminal.getName();
if (n.startsWith("ct")) {
return SchemaVisitorAction.TERMINATE;
} else if (n.startsWith("css")) {
return SchemaVisitorAction.SKIP_SIBLINGS;
} else if (n.startsWith("cst")) {
return SchemaVisitorAction.SKIP_SUBTREE;
} else {
return SchemaVisitorAction.CONTINUE;
}
}
public String get() {
return sb.toString();
}
}
@Test
public void testVisit1() {
String s1 = "{\"type\": \"record\", \"name\": \"t1\", \"fields\": [" + "{\"name\": \"f1\", \"type\": \"int\"}"
+ "]}";
Assert.assertEquals("t1.", Schemas.visit(new Schema.Parser().parse(s1), new TestVisitor()));
}
@Test
public void testVisit2() {
String s2 = "{\"type\": \"record\", \"name\": \"c1\", \"fields\": [" + "{\"name\": \"f1\", \"type\": \"int\"}"
+ "]}";
Assert.assertEquals("c1.\"int\"!", Schemas.visit(new Schema.Parser().parse(s2), new TestVisitor()));
}
@Test
public void testVisit3() {
String s3 = "{\"type\": \"record\", \"name\": \"ss1\", \"fields\": [" + "{\"name\": \"f1\", \"type\": \"int\"}"
+ "]}";
Assert.assertEquals("ss1.", Schemas.visit(new Schema.Parser().parse(s3), new TestVisitor()));
}
@Test
public void testVisit4() {
String s4 = "{\"type\": \"record\", \"name\": \"st1\", \"fields\": [" + "{\"name\": \"f1\", \"type\": \"int\"}"
+ "]}";
Assert.assertEquals("st1.!", Schemas.visit(new Schema.Parser().parse(s4), new TestVisitor()));
}
@Test
public void testVisit5() {
String s5 = "{\"type\": \"record\", \"name\": \"c1\", \"fields\": ["
+ "{\"name\": \"f1\", \"type\": {\"type\": \"record\", \"name\": \"c2\", \"fields\": "
+ "[{\"name\": \"f11\", \"type\": \"int\"}]}}," + "{\"name\": \"f2\", \"type\": \"long\"}" + "]}";
Assert.assertEquals("c1.c2.\"int\"!\"long\"!", Schemas.visit(new Schema.Parser().parse(s5), new TestVisitor()));
}
@Test
public void testVisit6() {
String s6 = "{\"type\": \"record\", \"name\": \"c1\", \"fields\": ["
+ "{\"name\": \"f1\", \"type\": {\"type\": \"record\", \"name\": \"ss2\", \"fields\": "
+ "[{\"name\": \"f11\", \"type\": \"int\"}]}}," + "{\"name\": \"f2\", \"type\": \"long\"}" + "]}";
Assert.assertEquals("c1.ss2.!", Schemas.visit(new Schema.Parser().parse(s6), new TestVisitor()));
}
@Test
public void testVisit7() {
String s7 = "{\"type\": \"record\", \"name\": \"c1\", \"fields\": ["
+ "{\"name\": \"f1\", \"type\": {\"type\": \"record\", \"name\": \"css2\", \"fields\": "
+ "[{\"name\": \"f11\", \"type\": \"int\"}]}}," + "{\"name\": \"f2\", \"type\": \"long\"}" + "]}";
Assert.assertEquals("c1.css2.\"int\"!!", Schemas.visit(new Schema.Parser().parse(s7), new TestVisitor()));
}
@Test(expected = UnsupportedOperationException.class)
public void testVisit8() {
String s8 = "{\"type\": \"record\", \"name\": \"c1\", \"fields\": ["
+ "{\"name\": \"f1\", \"type\": {\"type\": \"record\", \"name\": \"cst2\", \"fields\": "
+ "[{\"name\": \"f11\", \"type\": \"int\"}]}}," + "{\"name\": \"f2\", \"type\": \"int\"}" + "]}";
Schemas.visit(new Schema.Parser().parse(s8), new TestVisitor());
}
@Test
public void testVisit9() {
String s9 = "{\"type\": \"record\", \"name\": \"c1\", \"fields\": ["
+ "{\"name\": \"f1\", \"type\": {\"type\": \"record\", \"name\": \"ct2\", \"fields\": "
+ "[{\"name\": \"f11\", \"type\": \"int\"}]}}," + "{\"name\": \"f2\", \"type\": \"long\"}" + "]}";
Assert.assertEquals("c1.ct2.\"int\"!", Schemas.visit(new Schema.Parser().parse(s9), new TestVisitor()));
}
@Test(expected = UnsupportedOperationException.class)
public void testVisit10() {
String s10 = "{\"type\": \"record\", \"name\": \"c1\", \"fields\": ["
+ "{\"name\": \"f1\", \"type\": {\"type\": \"record\", \"name\": \"ct2\", \"fields\": "
+ "[{\"name\": \"f11\", \"type\": \"int\"}]}}," + "{\"name\": \"f2\", \"type\": \"int\"}" + "]}";
Schemas.visit(new Schema.Parser().parse(s10), new TestVisitor() {
public SchemaVisitorAction visitTerminal(Schema terminal) {
return SchemaVisitorAction.SKIP_SUBTREE;
}
});
}
@Test
public void testVisit11() {
String s11 = "{\"type\": \"record\", \"name\": \"c1\", \"fields\": ["
+ "{\"name\": \"f1\", \"type\": {\"type\": \"record\", \"name\": \"c2\", \"fields\": "
+ "[{\"name\": \"f11\", \"type\": \"int\"},{\"name\": \"f12\", \"type\": \"double\"}" + "]}},"
+ "{\"name\": \"f2\", \"type\": \"long\"}" + "]}";
Assert.assertEquals("c1.c2.\"int\".!\"long\".!", Schemas.visit(new Schema.Parser().parse(s11), new TestVisitor() {
public SchemaVisitorAction visitTerminal(Schema terminal) {
sb.append(terminal).append('.');
return SchemaVisitorAction.SKIP_SIBLINGS;
}
}));
}
@Test
public void testVisit12() {
String s12 = "{\"type\": \"record\", \"name\": \"c1\", \"fields\": ["
+ "{\"name\": \"f1\", \"type\": {\"type\": \"record\", \"name\": \"ct2\", \"fields\": "
+ "[{\"name\": \"f11\", \"type\": \"int\"}]}}," + "{\"name\": \"f2\", \"type\": \"long\"}" + "]}";
Assert.assertEquals("c1.ct2.\"int\".", Schemas.visit(new Schema.Parser().parse(s12), new TestVisitor() {
public SchemaVisitorAction visitTerminal(Schema terminal) {
sb.append(terminal).append('.');
return SchemaVisitorAction.TERMINATE;
}
}));
}
@Test
public void testVisit13() {
String s12 = "{\"type\": \"int\"}";
Assert.assertEquals("\"int\".", Schemas.visit(new Schema.Parser().parse(s12), new TestVisitor() {
public SchemaVisitorAction visitTerminal(Schema terminal) {
sb.append(terminal).append('.');
return SchemaVisitorAction.SKIP_SIBLINGS;
}
}));
}
}