blob: c545c5a00456ef095a05c22aaa8745c7f5d06f85 [file] [log] [blame]
package org.apache.avro.specific;
import org.apache.avro.Schema;
import org.apache.avro.data.TimeConversions.DateConversion;
import org.apache.avro.data.TimeConversions.TimeConversion;
import org.apache.avro.data.TimeConversions.TimestampConversion;
import org.apache.avro.file.DataFileReader;
import org.apache.avro.file.DataFileWriter;
import org.apache.avro.file.FileReader;
import org.apache.avro.io.DatumReader;
import org.apache.avro.io.DatumWriter;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalDate;
import org.joda.time.LocalTime;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* This tests compatibility between classes generated before and after
* AVRO-1684. TestRecordWithoutLogicalTypes and TestRecordWithLogicalTypes were
* generated from the same schema, found in
* src/test/resources/record_with_logical_types.avsc, and
* TestRecordWithoutLogicalTypes was renamed to avoid the conflict.
*
* The classes should not be re-generated because they test compatibility of
* Avro with existing Avro-generated sources. When using classes generated
* before AVRO-1684, logical types should not be applied by the read or write
* paths. Those files should behave as they did before.
*/
public class TestSpecificLogicalTypes {
@Rule
public final TemporaryFolder temp = new TemporaryFolder();
@Test
public void testRecordWithLogicalTypes() throws IOException {
TestRecordWithLogicalTypes record = new TestRecordWithLogicalTypes(
true,
34,
35L,
3.14F,
3019.34,
null,
LocalDate.now(),
LocalTime.now(),
DateTime.now().withZone(DateTimeZone.UTC)
);
File data = write(TestRecordWithLogicalTypes.getClassSchema(), record);
List<TestRecordWithLogicalTypes> actual = read(
TestRecordWithLogicalTypes.getClassSchema(), data);
Assert.assertEquals("Should match written record", record, actual.get(0));
}
@Test
public void testRecordWithoutLogicalTypes() throws IOException {
// the significance of the record without logical types is that it has the
// same schema (besides record name) as the one with logical types,
// including the type annotations. this verifies that the type annotations
// are only applied if the record was compiled to use those types. this
// ensures compatibility with already-compiled code.
TestRecordWithoutLogicalTypes record = new TestRecordWithoutLogicalTypes(
true,
34,
35L,
3.14F,
3019.34,
null,
new DateConversion().toInt(LocalDate.now(), null, null),
new TimeConversion().toInt(LocalTime.now(), null, null),
new TimestampConversion().toLong(
DateTime.now().withZone(DateTimeZone.UTC), null, null)
);
File data = write(TestRecordWithoutLogicalTypes.getClassSchema(), record);
List<TestRecordWithoutLogicalTypes> actual = read(
TestRecordWithoutLogicalTypes.getClassSchema(), data);
Assert.assertEquals("Should match written record", record, actual.get(0));
}
@Test
public void testRecordWritePrimitivesReadLogicalTypes() throws IOException {
LocalDate date = LocalDate.now();
LocalTime time = LocalTime.now();
DateTime timestamp = DateTime.now().withZone(DateTimeZone.UTC);
TestRecordWithoutLogicalTypes record = new TestRecordWithoutLogicalTypes(
true,
34,
35L,
3.14F,
3019.34,
null,
new DateConversion().toInt(date, null, null),
new TimeConversion().toInt(time, null, null),
new TimestampConversion().toLong(timestamp, null, null)
);
File data = write(TestRecordWithoutLogicalTypes.getClassSchema(), record);
// read using the schema with logical types
List<TestRecordWithLogicalTypes> actual = read(
TestRecordWithLogicalTypes.getClassSchema(), data);
TestRecordWithLogicalTypes expected = new TestRecordWithLogicalTypes(
true,
34,
35L,
3.14F,
3019.34,
null,
date,
time,
timestamp
);
Assert.assertEquals("Should match written record", expected, actual.get(0));
}
@Test
public void testRecordWriteLogicalTypesReadPrimitives() throws IOException {
LocalDate date = LocalDate.now();
LocalTime time = LocalTime.now();
DateTime timestamp = DateTime.now().withZone(DateTimeZone.UTC);
TestRecordWithLogicalTypes record = new TestRecordWithLogicalTypes(
true,
34,
35L,
3.14F,
3019.34,
null,
date,
time,
timestamp
);
File data = write(TestRecordWithLogicalTypes.getClassSchema(), record);
// read using the schema with logical types
List<TestRecordWithoutLogicalTypes> actual = read(
TestRecordWithoutLogicalTypes.getClassSchema(), data);
TestRecordWithoutLogicalTypes expected = new TestRecordWithoutLogicalTypes(
true,
34,
35L,
3.14F,
3019.34,
null,
new DateConversion().toInt(date, null, null),
new TimeConversion().toInt(time, null, null),
new TimestampConversion().toLong(timestamp, null, null)
);
Assert.assertEquals("Should match written record", expected, actual.get(0));
}
private <D> List<D> read(Schema schema, File file)
throws IOException {
DatumReader<D> reader = newReader(schema);
List<D> data = new ArrayList<D>();
FileReader<D> fileReader = null;
try {
fileReader = new DataFileReader<D>(file, reader);
for (D datum : fileReader) {
data.add(datum);
}
} finally {
if (fileReader != null) {
fileReader.close();
}
}
return data;
}
@SuppressWarnings("unchecked")
private <D> DatumReader<D> newReader(Schema schema) {
return SpecificData.get().createDatumReader(schema);
}
@SuppressWarnings("unchecked")
private <D extends SpecificRecord> File write(Schema schema, D... data)
throws IOException {
File file = temp.newFile();
DatumWriter<D> writer = SpecificData.get().createDatumWriter(schema);
DataFileWriter<D> fileWriter = new DataFileWriter<D>(writer);
try {
fileWriter.create(schema, file);
for (D datum : data) {
fileWriter.append(datum);
}
} finally {
fileWriter.close();
}
return file;
}
}