/* Copyright (c) 2013-2014 Boundless and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Distribution License v1.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/org/documents/edl-v10.html * * Contributors: * Victor Olaya (Boundless) - initial implementation */ package org.locationtech.geogig.storage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Iterator; import java.util.Map; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.locationtech.geogig.api.Bounded; import org.locationtech.geogig.api.Bucket; import org.locationtech.geogig.api.Node; import org.locationtech.geogig.api.ObjectId; import org.locationtech.geogig.api.RevObject; import org.locationtech.geogig.api.RevTree; import org.locationtech.geogig.api.RevTreeImpl; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; import com.vividsolutions.jts.geom.Envelope; public abstract class RevTreeSerializationTest extends Assert { protected ObjectSerializingFactory factory = getObjectSerializingFactory(); protected abstract ObjectSerializingFactory getObjectSerializingFactory(); private RevTree tree1_leaves; private RevTree tree2_internal; private RevTree tree3_buckets; private RevTree tree4_spatial_leaves; private RevTree tree5_spatial_internal; private RevTree tree6_spatial_buckets; @Before public void initialize() { ImmutableList<Node> features = ImmutableList.of(Node.create("foo", ObjectId.forString("nodeid"), ObjectId.forString("metadataid"), RevObject.TYPE.FEATURE, null)); ImmutableList<Node> spatialFeatures = ImmutableList.of(Node.create("foo", ObjectId.forString("nodeid"), ObjectId.forString("metadataid"), RevObject.TYPE.FEATURE, new Envelope(0.0000001, 0.0000002, 0.0000001, 0.0000002))); ImmutableList<Node> trees = ImmutableList.of(Node.create("bar", ObjectId.forString("barnodeid"), ObjectId.forString("barmetadataid"), RevObject.TYPE.TREE, null)); ImmutableList<Node> spatialTrees = ImmutableList.of(Node.create("bar", ObjectId.forString("barnodeid"), ObjectId.forString("barmetadataid"), RevObject.TYPE.TREE, new Envelope(1, 2, 1, 2))); ImmutableMap<Integer, Bucket> spatialBuckets = ImmutableMap.of(1, Bucket.create(ObjectId.forString("buckettree"), new Envelope())); ImmutableMap<Integer, Bucket> buckets = ImmutableMap.of(1, Bucket.create(ObjectId.forString("buckettree"), new Envelope(1, 2, 1, 2))); tree1_leaves = RevTreeImpl.createLeafTree(ObjectId.forString("leaves"), 1, features, ImmutableList.<Node> of()); tree2_internal = RevTreeImpl.createLeafTree(ObjectId.forString("internal"), 1, ImmutableList.<Node> of(), trees); tree3_buckets = RevTreeImpl.createNodeTree(ObjectId.forString("buckets"), 1, 1, buckets); tree4_spatial_leaves = RevTreeImpl.createLeafTree(ObjectId.forString("leaves"), 1, spatialFeatures, ImmutableList.<Node> of()); tree5_spatial_internal = RevTreeImpl.createLeafTree(ObjectId.forString("internal"), 1, ImmutableList.<Node> of(), spatialTrees); tree6_spatial_buckets = RevTreeImpl.createNodeTree(ObjectId.forString("buckets"), 1, 1, spatialBuckets); } @Test public void testRoundTripLeafTree() { RevTree roundTripped = read(tree1_leaves.getId(), write(tree1_leaves)); assertTreesAreEqual(tree1_leaves, roundTripped); } @Test public void testRoundTripInternalTree() { RevTree roundTripped = read(tree2_internal.getId(), write(tree2_internal)); assertTreesAreEqual(tree2_internal, roundTripped); } @Test public void testRoundTripBuckets() { RevTree roundTripped = read(tree3_buckets.getId(), write(tree3_buckets)); assertTreesAreEqual(tree3_buckets, roundTripped); } @Test public void testRoundTripBucketsFull() { ObjectId id = ObjectId.forString("fake"); long size = 100000000; int childTreeCount = 0; Map<Integer, Bucket> bucketTrees = createBuckets(32); final RevTreeImpl tree = RevTreeImpl.createNodeTree(id, size, childTreeCount, bucketTrees); RevTree roundTripped = read(tree.getId(), write(tree)); assertTreesAreEqual(tree, roundTripped); } private Map<Integer, Bucket> createBuckets(int count) { Map<Integer, Bucket> buckets = Maps.newHashMap(); for (int i = 0; i < count; i++) { Bucket bucket = Bucket.create(ObjectId.forString("b" + i), new Envelope(i, i * 2, i, i * 2)); buckets.put(i, bucket); } return buckets; } @Test public void testRoundTripSpatialLeafTree() { RevTree roundTripped = read(tree4_spatial_leaves.getId(), write(tree4_spatial_leaves)); assertTreesAreEqual(tree4_spatial_leaves, roundTripped); } @Test public void testRoundTripSpatialInternalTree() { RevTree roundTripped = read(tree5_spatial_internal.getId(), write(tree5_spatial_internal)); assertTreesAreEqual(tree5_spatial_internal, roundTripped); } @Test public void testRoundTripSpatialBuckets() { RevTree roundTripped = read(tree6_spatial_buckets.getId(), write(tree6_spatial_buckets)); assertTreesAreEqual(tree6_spatial_buckets, roundTripped); } private byte[] write(RevTree tree) { try { ByteArrayOutputStream bout = new ByteArrayOutputStream(); ObjectWriter<RevTree> treeWriter = factory .<RevTree> createObjectWriter(RevObject.TYPE.TREE); treeWriter.write(tree, bout); return bout.toByteArray(); } catch (IOException e) { throw new RuntimeException(e); } } private RevTree read(ObjectId id, byte[] bytes) { ByteArrayInputStream bin = new ByteArrayInputStream(bytes); ObjectReader<RevTree> treeReader = factory .<RevTree> createObjectReader(RevObject.TYPE.TREE); return treeReader.read(id, bin); } private void assertTreesAreEqual(RevTree a, RevTree b) { assertTrue(a.getId().equals(b.getId())); assertTrue(a.buckets().equals(b.buckets())); assertTrue(a.features().equals(b.features())); assertTrue(a.trees().equals(b.trees())); assertTrue(a.numTrees() == b.numTrees()); assertTrue(a.size() == b.size()); Iterator<? extends Bounded> ia; Iterator<? extends Bounded> ib; if (a.buckets().isPresent()) { ia = a.buckets().get().values().iterator(); ib = b.buckets().get().values().iterator(); } else { ia = a.children(); ib = b.children(); } // bounds are not part of the Bounded.equals(Object) contract as its auxiliary information while (ia.hasNext()) { Bounded ba = ia.next(); Bounded bb = ib.next(); Envelope ea = new Envelope(); Envelope eb = new Envelope(); ba.expand(ea); bb.expand(eb); assertEquals(ea.getMinX(), eb.getMinX(), 1e-7D); assertEquals(ea.getMinY(), eb.getMinY(), 1e-7D); assertEquals(ea.getMaxX(), eb.getMaxX(), 1e-7D); assertEquals(ea.getMaxY(), eb.getMaxY(), 1e-7D); } } }