blob: 81192be62786ff6885a6ef0f1e1c80a056c8b325 [file] [log] [blame]
/*
* 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.iceberg.puffin;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import java.io.UncheckedIOException;
import org.apache.iceberg.relocated.com.google.common.collect.ImmutableList;
import org.apache.iceberg.relocated.com.google.common.collect.ImmutableMap;
import org.junit.Test;
public class TestFileMetadataParser {
@Test
public void testInvalidJson() {
assertThatThrownBy(() -> FileMetadataParser.fromJson((String) null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("argument \"content\" is null");
assertThatThrownBy(() -> FileMetadataParser.fromJson(""))
.isInstanceOf(UncheckedIOException.class)
.hasMessageContaining("No content to map due to end-of-input");
assertThatThrownBy(() -> FileMetadataParser.fromJson("{"))
.isInstanceOf(UncheckedIOException.class)
.hasMessageContaining("Unexpected end-of-input: expected close marker for Object");
assertThatThrownBy(() -> FileMetadataParser.fromJson("{\"blobs\": []"))
.isInstanceOf(UncheckedIOException.class)
.hasMessageContaining("Unexpected end-of-input: expected close marker for Object");
}
@Test
public void testMinimalFileMetadata() {
testJsonSerialization(
new FileMetadata(ImmutableList.of(), ImmutableMap.of()),
"{\n" + " \"blobs\" : [ ]\n" + "}");
}
@Test
public void testFileProperties() {
testJsonSerialization(
new FileMetadata(ImmutableList.of(), ImmutableMap.of("a property", "a property value")),
"{\n"
+ " \"blobs\" : [ ],\n"
+ " \"properties\" : {\n"
+ " \"a property\" : \"a property value\"\n"
+ " }\n"
+ "}");
testJsonSerialization(
new FileMetadata(
ImmutableList.of(),
ImmutableMap.of("a property", "a property value", "another one", "also with value")),
"{\n"
+ " \"blobs\" : [ ],\n"
+ " \"properties\" : {\n"
+ " \"a property\" : \"a property value\",\n"
+ " \"another one\" : \"also with value\"\n"
+ " }\n"
+ "}");
}
@Test
public void testMissingBlobs() {
assertThatThrownBy(() -> FileMetadataParser.fromJson("{\"properties\": {}}"))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Cannot parse missing field: blobs");
}
@Test
public void testBadBlobs() {
assertThatThrownBy(() -> FileMetadataParser.fromJson("{\"blobs\": {}}"))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Cannot parse blobs from non-array: {}");
}
@Test
public void testBlobMetadata() {
testJsonSerialization(
new FileMetadata(
ImmutableList.of(
new BlobMetadata(
"type-a", ImmutableList.of(1), 14, 3, 4, 16, null, ImmutableMap.of()),
new BlobMetadata(
"type-bbb",
ImmutableList.of(2, 3, 4),
77,
4,
Integer.MAX_VALUE * 10000L,
79834,
null,
ImmutableMap.of())),
ImmutableMap.of()),
"{\n"
+ " \"blobs\" : [ {\n"
+ " \"type\" : \"type-a\",\n"
+ " \"fields\" : [ 1 ],\n"
+ " \"snapshot-id\" : 14,\n"
+ " \"sequence-number\" : 3,\n"
+ " \"offset\" : 4,\n"
+ " \"length\" : 16\n"
+ " }, {\n"
+ " \"type\" : \"type-bbb\",\n"
+ " \"fields\" : [ 2, 3, 4 ],\n"
+ " \"snapshot-id\" : 77,\n"
+ " \"sequence-number\" : 4,\n"
+ " \"offset\" : 21474836470000,\n"
+ " \"length\" : 79834\n"
+ " } ]\n"
+ "}");
}
@Test
public void testBlobProperties() {
testJsonSerialization(
new FileMetadata(
ImmutableList.of(
new BlobMetadata(
"type-a",
ImmutableList.of(1),
14,
3,
4,
16,
null,
ImmutableMap.of("some key", "some value"))),
ImmutableMap.of()),
"{\n"
+ " \"blobs\" : [ {\n"
+ " \"type\" : \"type-a\",\n"
+ " \"fields\" : [ 1 ],\n"
+ " \"snapshot-id\" : 14,\n"
+ " \"sequence-number\" : 3,\n"
+ " \"offset\" : 4,\n"
+ " \"length\" : 16,\n"
+ " \"properties\" : {\n"
+ " \"some key\" : \"some value\"\n"
+ " }\n"
+ " } ]\n"
+ "}");
}
@Test
public void testFieldNumberOutOfRange() {
assertThatThrownBy(
() ->
FileMetadataParser.fromJson(
"{\n"
+ " \"blobs\" : [ {\n"
+ " \"type\" : \"type-a\",\n"
+ " \"fields\" : [ "
+ (Integer.MAX_VALUE + 1L)
+ " ],\n"
+ " \"offset\" : 4,\n"
+ " \"length\" : 16\n"
+ " } ]\n"
+ "}"))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Cannot parse integer from non-int value: 2147483648");
}
private void testJsonSerialization(FileMetadata fileMetadata, String json) {
assertThat(FileMetadataParser.toJson(fileMetadata, true)).isEqualTo(json);
// Test round-trip. Note that FileMetadata doesn't implement equals()
FileMetadata parsed = FileMetadataParser.fromJson(json);
assertThat(FileMetadataParser.toJson(parsed, true)).isEqualTo(json);
}
}