Skip to content

Commit afc2ca1

Browse files
committed
GH-1302: Simplify JSON extension tests
Change-Id: I2f961fbc983bd29bffd2b4280021f7b696e3ad50
1 parent 864c250 commit afc2ca1

2 files changed

Lines changed: 110 additions & 105 deletions

File tree

vector/src/test/java/org/apache/arrow/vector/TestJsonType.java

Lines changed: 110 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
*/
1717
package org.apache.arrow.vector;
1818

19+
import static org.apache.arrow.vector.testing.ValueVectorDataPopulator.setVector;
1920
import static org.junit.jupiter.api.Assertions.assertEquals;
2021
import static org.junit.jupiter.api.Assertions.assertFalse;
2122
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
@@ -25,11 +26,13 @@
2526

2627
import java.io.ByteArrayInputStream;
2728
import java.io.ByteArrayOutputStream;
29+
import java.io.IOException;
30+
import java.io.InputStream;
2831
import java.nio.ByteBuffer;
2932
import java.nio.charset.StandardCharsets;
30-
import java.util.Base64;
3133
import java.util.Collections;
3234
import java.util.stream.Stream;
35+
import org.apache.arrow.memory.BufferAllocator;
3336
import org.apache.arrow.memory.RootAllocator;
3437
import org.apache.arrow.vector.extension.InvalidExtensionMetadataException;
3538
import org.apache.arrow.vector.extension.JsonType;
@@ -43,35 +46,61 @@
4346
import org.apache.arrow.vector.types.pojo.Schema;
4447
import org.apache.arrow.vector.util.Text;
4548
import org.apache.arrow.vector.util.TransferPair;
49+
import org.junit.jupiter.api.AfterEach;
50+
import org.junit.jupiter.api.BeforeEach;
4651
import org.junit.jupiter.api.Test;
4752
import org.junit.jupiter.params.ParameterizedTest;
4853
import org.junit.jupiter.params.provider.MethodSource;
4954
import org.junit.jupiter.params.provider.NullSource;
5055
import org.junit.jupiter.params.provider.ValueSource;
5156

5257
class TestJsonType {
58+
BufferAllocator allocator;
59+
ArrowType.ExtensionType previousType;
60+
61+
@BeforeEach
62+
void beforeEach() {
63+
allocator = new RootAllocator();
64+
previousType = ExtensionTypeRegistry.lookup(JsonType.EXTENSION_NAME);
65+
JsonType.ensureRegistered();
66+
}
67+
68+
@AfterEach
69+
void afterEach() {
70+
ExtensionTypeRegistry.unregister(new JsonType(ArrowType.Utf8.INSTANCE));
71+
if (previousType != null) {
72+
ExtensionTypeRegistry.register(previousType);
73+
}
74+
allocator.close();
75+
}
76+
5377
static Stream<ArrowType> storageTypes() {
5478
return Stream.of(
5579
ArrowType.Utf8.INSTANCE, ArrowType.LargeUtf8.INSTANCE, ArrowType.Utf8View.INSTANCE);
5680
}
5781

5882
@ParameterizedTest
5983
@MethodSource("storageTypes")
60-
void testType(ArrowType storage) {
84+
void testRoundTrip(ArrowType storage) {
6185
JsonType type = new JsonType(storage);
6286
assertEquals("arrow.json", type.extensionName());
6387
assertEquals(storage, type.storageType());
6488
assertFalse(type.isComplex());
6589
assertEquals("", type.serialize());
66-
for (String metadata : new String[] {"", "{}", " { } ", "{\"future\": {\"value\": 1}}"}) {
67-
ArrowType restored = type.deserialize(storage, metadata);
68-
assertEquals(type, restored);
69-
assertEquals(type.hashCode(), restored.hashCode());
70-
}
71-
storageTypes()
72-
.filter(other -> !storage.equals(other))
73-
.forEach(other -> assertNotEquals(type, new JsonType(other)));
74-
assertNotEquals(type, storage);
90+
assertEquals(type, type.deserialize(storage, type.serialize()));
91+
assertNotEquals(
92+
type,
93+
new JsonType(
94+
storage instanceof ArrowType.Utf8
95+
? ArrowType.LargeUtf8.INSTANCE
96+
: ArrowType.Utf8.INSTANCE));
97+
}
98+
99+
@ParameterizedTest
100+
@ValueSource(strings = {"", "{}", " { } ", "{\"future\": 1}"})
101+
void testDeserializeValid(String metadata) {
102+
JsonType type = new JsonType(ArrowType.Utf8.INSTANCE);
103+
assertEquals(type, type.deserialize(type.storageType(), metadata));
75104
}
76105

77106
@ParameterizedTest
@@ -103,7 +132,6 @@ void testInvalidStorage() {
103132
@ParameterizedTest
104133
@MethodSource("storageTypes")
105134
void testSchemaRoundTrip(ArrowType storage) {
106-
JsonType.ensureRegistered();
107135
for (boolean nullable : new boolean[] {false, true}) {
108136
Field field = field(storage, nullable);
109137
Schema schema = new Schema(Collections.singletonList(field));
@@ -115,21 +143,11 @@ void testSchemaRoundTrip(ArrowType storage) {
115143
// nullable=False, metadata={"custom": "preserved"}) for t in
116144
// [pa.string(), pa.large_string(), pa.string_view()]]).serialize().
117145
@Test
118-
void testPyArrowSchema() {
119-
JsonType.ensureRegistered();
120-
String encoded =
121-
"/////9ACAAAQAAAAAAAKAAwABgAFAAgACgAAAAABBAAMAAAACAAIAAAABAAIAAAABAAAAAMAAADEAQAA2AAAAAQAAABa/v//"
122-
+ "AAAAGBQAAADAAAAACAAAABQAAAAAAAAABAAAAGpzb24AAAAAAwAAAHgAAABAAAAABAAAANz9//8YAAAABAAAAAoAAABhcnJv"
123-
+ "dy5qc29uAAAUAAAAQVJST1c6ZXh0ZW5zaW9uOm5hbWUAAAAAFP7//xAAAAAEAAAAAAAAAAAAAAAYAAAAQVJST1c6ZXh0ZW5z"
124-
+ "aW9uOm1ldGFkYXRhAAAAAEj+//8YAAAABAAAAAkAAABwcmVzZXJ2ZWQAAAAGAAAAY3VzdG9tAABA/v//Kv///wAAABQUAAAA"
125-
+ "xAAAAAgAAAAUAAAAAAAAAAQAAABqc29uAAAAAAMAAAB4AAAAQAAAAAQAAACs/v//GAAAAAQAAAAKAAAAYXJyb3cuanNvbgAA"
126-
+ "FAAAAEFSUk9XOmV4dGVuc2lvbjpuYW1lAAAAAOT+//8QAAAABAAAAAAAAAAAAAAAGAAAAEFSUk9XOmV4dGVuc2lvbjptZXRh"
127-
+ "ZGF0YQAAAAAY////GAAAAAQAAAAJAAAAcHJlc2VydmVkAAAABgAAAGN1c3RvbQAABAAGAAQAAAAAABIAGAAIAAAABwAMAAAA"
128-
+ "EAAUABIAAAAAAAAFFAAAAMwAAAAIAAAAFAAAAAAAAAAEAAAAanNvbgAAAAADAAAAgAAAAEAAAAAEAAAAlP///xgAAAAEAAAA"
129-
+ "CgAAAGFycm93Lmpzb24AABQAAABBUlJPVzpleHRlbnNpb246bmFtZQAAAADM////EAAAAAQAAAAAAAAAAAAAABgAAABBUlJP"
130-
+ "VzpleHRlbnNpb246bWV0YWRhdGEAAAAACAAMAAQACAAIAAAAGAAAAAQAAAAJAAAAcHJlc2VydmVkAAAABgAAAGN1c3RvbQAA"
131-
+ "BAAEAAQAAAA=";
132-
Schema schema = Schema.deserializeMessage(ByteBuffer.wrap(Base64.getDecoder().decode(encoded)));
146+
void testPyArrowSchema() throws IOException {
147+
Schema schema;
148+
try (InputStream input = getClass().getResourceAsStream("/pyarrow_json_schema.arrow")) {
149+
schema = Schema.deserializeMessage(ByteBuffer.wrap(input.readAllBytes()));
150+
}
133151
ArrowType[] storage = storageTypes().toArray(ArrowType[]::new);
134152
for (int i = 0; i < storage.length; i++) {
135153
assertEquals(field(storage[i], false), schema.getFields().get(i));
@@ -148,108 +166,95 @@ nullable, new JsonType(storage), null, Collections.singletonMap("custom", "prese
148166
@MethodSource("storageTypes")
149167
void testTransfer(ArrowType storage) {
150168
Field field = field(storage, true);
151-
try (RootAllocator allocator = new RootAllocator();
152-
JsonVector source = (JsonVector) field.createVector(allocator)) {
169+
try (JsonVector source = (JsonVector) field.createVector(allocator)) {
153170
byte[] bytes =
154171
"{\"key\":\"value longer than twelve bytes\"}".getBytes(StandardCharsets.UTF_8);
155-
FieldVector underlying = source.getUnderlyingVector();
156-
if (underlying instanceof VarCharVector) {
157-
((VarCharVector) underlying).setSafe(0, bytes);
158-
} else if (underlying instanceof LargeVarCharVector) {
159-
((LargeVarCharVector) underlying).setSafe(0, bytes);
160-
} else {
161-
((ViewVarCharVector) underlying).setSafe(0, bytes);
162-
}
163-
source.setNull(1);
164-
source.setValueCount(2);
172+
setVector((VariableWidthFieldVector) source.getUnderlyingVector(), null, bytes, null);
165173
TransferPair split = source.getTransferPair("copy", allocator);
166174
try (JsonVector target = assertInstanceOf(JsonVector.class, split.getTo())) {
167-
split.splitAndTransfer(0, 2);
175+
split.splitAndTransfer(1, 2);
168176
assertEquals("copy", target.getName());
169177
assertEquals(field.getFieldType(), target.getField().getFieldType());
170-
assertEquals(source.getObject(0), target.getObject(0));
178+
assertEquals(new Text(bytes), target.getObject(0));
171179
assertTrue(target.isNull(1));
172180
}
173181
try (JsonVector target = (JsonVector) field.createVector(allocator)) {
174182
TransferPair copy = source.makeTransferPair(target);
175-
copy.copyValueSafe(0, 0);
176-
copy.copyValueSafe(1, 1);
183+
copy.copyValueSafe(1, 0);
184+
copy.copyValueSafe(2, 1);
177185
target.setValueCount(2);
178-
assertEquals(source.getObject(0), target.getObject(0));
186+
assertEquals(new Text(bytes), target.getObject(0));
179187
assertTrue(target.isNull(1));
180188
}
181189
TransferPair transfer = source.getTransferPair(allocator);
182190
try (JsonVector target = assertInstanceOf(JsonVector.class, transfer.getTo())) {
183191
transfer.transfer();
184192
assertEquals(field, target.getField());
185-
assertEquals(new Text(bytes), target.getObject(0));
186-
assertTrue(target.isNull(1));
187-
assertEquals(2, target.getValueCount());
193+
assertTrue(target.isNull(0));
194+
assertEquals(new Text(bytes), target.getObject(1));
195+
assertTrue(target.isNull(2));
196+
assertEquals(3, target.getValueCount());
188197
assertEquals(0, source.getValueCount());
189198
}
190199
}
191200
}
192201

193202
@ParameterizedTest
194203
@MethodSource("storageTypes")
195-
void testIpcAndUnregisteredFallback(ArrowType storage) throws Exception {
196-
ArrowType.ExtensionType previous = ExtensionTypeRegistry.lookup(JsonType.EXTENSION_NAME);
197-
JsonType type = new JsonType(storage);
198-
JsonType.ensureRegistered();
199-
try (RootAllocator allocator = new RootAllocator()) {
200-
Field field = field(storage, true);
201-
Schema schema = new Schema(Collections.singletonList(field));
202-
ByteArrayOutputStream out = new ByteArrayOutputStream();
203-
String[] values = {
204-
"{\"message\":\"你好, a JSON value longer than twelve bytes\"}", null, "null", "42", "[]"
205-
};
206-
try (VectorSchemaRoot root = VectorSchemaRoot.create(schema, allocator);
207-
ArrowStreamWriter writer = new ArrowStreamWriter(root, null, out)) {
208-
JsonVector vector = assertInstanceOf(JsonVector.class, root.getVector(0));
209-
FieldVector underlying = vector.getUnderlyingVector();
210-
for (int i = 0; i < values.length; i++) {
211-
if (values[i] == null) {
212-
vector.setNull(i);
213-
} else {
214-
byte[] bytes = values[i].getBytes(StandardCharsets.UTF_8);
215-
if (storage instanceof ArrowType.Utf8) {
216-
assertInstanceOf(VarCharVector.class, underlying).setSafe(i, bytes);
217-
} else if (storage instanceof ArrowType.LargeUtf8) {
218-
assertInstanceOf(LargeVarCharVector.class, underlying).setSafe(i, bytes);
219-
} else {
220-
assertInstanceOf(ViewVarCharVector.class, underlying).setSafe(i, bytes);
221-
}
222-
}
223-
}
224-
root.setRowCount(values.length);
225-
assertEquals(underlying.hashCode(0), vector.hashCode(0));
226-
writer.start();
227-
writer.writeBatch();
228-
writer.end();
229-
}
230-
for (boolean registered : new boolean[] {true, false}) {
231-
if (!registered) {
232-
ExtensionTypeRegistry.unregister(type);
233-
}
234-
try (ArrowStreamReader reader =
235-
new ArrowStreamReader(new ByteArrayInputStream(out.toByteArray()), allocator)) {
236-
assertTrue(reader.loadNextBatch());
237-
FieldVector vector = reader.getVectorSchemaRoot().getVector(0);
238-
assertEquals(registered ? type : storage, vector.getField().getType());
239-
assertEquals(field.getMetadata(), vector.getField().getMetadata());
240-
assertTrue(vector.getField().isNullable());
241-
assertEquals(values.length, vector.getValueCount());
242-
for (int i = 0; i < values.length; i++) {
243-
assertEquals(values[i] == null ? null : new Text(values[i]), vector.getObject(i));
244-
}
245-
assertFalse(reader.loadNextBatch());
246-
}
247-
}
248-
} finally {
249-
ExtensionTypeRegistry.unregister(type);
250-
if (previous != null) {
251-
ExtensionTypeRegistry.register(previous);
252-
}
204+
void testVectorIpcRoundTrip(ArrowType storage) throws IOException {
205+
Field field = field(storage, true);
206+
byte[] serialized = writeStream(field);
207+
try (ArrowStreamReader reader =
208+
new ArrowStreamReader(new ByteArrayInputStream(serialized), allocator)) {
209+
assertTrue(reader.loadNextBatch());
210+
JsonVector vector =
211+
assertInstanceOf(JsonVector.class, reader.getVectorSchemaRoot().getVector(0));
212+
assertEquals(field, vector.getField());
213+
assertValues(vector);
253214
}
254215
}
216+
217+
@ParameterizedTest
218+
@MethodSource("storageTypes")
219+
void testReadUnderlyingType(ArrowType storage) throws IOException {
220+
Field field = field(storage, true);
221+
byte[] serialized = writeStream(field);
222+
ExtensionTypeRegistry.unregister((JsonType) field.getType());
223+
try (ArrowStreamReader reader =
224+
new ArrowStreamReader(new ByteArrayInputStream(serialized), allocator)) {
225+
assertTrue(reader.loadNextBatch());
226+
FieldVector vector = reader.getVectorSchemaRoot().getVector(0);
227+
assertEquals(storage, vector.getField().getType());
228+
assertEquals(field.getMetadata(), vector.getField().getMetadata());
229+
assertValues(vector);
230+
}
231+
}
232+
233+
private static final String JSON = "{\"message\":\"你好, a JSON value longer than twelve bytes\"}";
234+
235+
private byte[] writeStream(Field field) throws IOException {
236+
ByteArrayOutputStream out = new ByteArrayOutputStream();
237+
try (VectorSchemaRoot root =
238+
VectorSchemaRoot.create(new Schema(Collections.singletonList(field)), allocator);
239+
ArrowStreamWriter writer = new ArrowStreamWriter(root, null, out)) {
240+
JsonVector vector = (JsonVector) root.getVector(0);
241+
setVector(
242+
(VariableWidthFieldVector) vector.getUnderlyingVector(),
243+
JSON.getBytes(StandardCharsets.UTF_8),
244+
null,
245+
"null".getBytes(StandardCharsets.UTF_8));
246+
root.setRowCount(3);
247+
writer.start();
248+
writer.writeBatch();
249+
writer.end();
250+
}
251+
return out.toByteArray();
252+
}
253+
254+
private static void assertValues(FieldVector vector) {
255+
assertEquals(3, vector.getValueCount());
256+
assertEquals(new Text(JSON), vector.getObject(0));
257+
assertTrue(vector.isNull(1));
258+
assertEquals(new Text("null"), vector.getObject(2));
259+
}
255260
}
728 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)