com.avanza.ymer.MirroredObjectTest.java Source code

Java tutorial

Introduction

Here is the source code for com.avanza.ymer.MirroredObjectTest.java

Source

/*
 * Copyright 2015 Avanza Bank AB
 *
 * 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
 *
 *      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 com.avanza.ymer;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

import org.junit.Test;
import org.openspaces.core.GigaSpace;
import org.openspaces.core.GigaSpaceConfigurer;
import org.openspaces.core.space.EmbeddedSpaceConfigurer;
import org.springframework.data.mongodb.MongoCollectionUtils;

import com.avanza.gs.test.JVMGlobalLus;
import com.gigaspaces.annotation.pojo.SpaceId;
import com.gigaspaces.annotation.pojo.SpaceRouting;
import com.mongodb.BasicDBObject;

/**
 *
 * @author Elias Lindholm (elilin)
 *
 */
public class MirroredObjectTest {

    @Test(expected = IllegalArgumentException.class)
    public void cannotMirrorTypesWithNoRoutingMethod() throws Exception {
        class InvalidSpaceObject {
            @SuppressWarnings("unused")
            public Integer fooMethod() {
                return null; // Never used
            }
        }
        DocumentPatch[] patches = {};
        MirroredObjectDefinition.create(InvalidSpaceObject.class).documentPatches(patches).buildMirroredDocument();
    }

    @Test
    public void routingMethodIsSpaceIdMethodIfNoSpaceRoutingAnnotationPresent() throws Exception {
        class SpaceObject {
            @SpaceId
            public Integer routingKey() {
                return 21;
            }
        }
        DocumentPatch[] patches = {};
        MirroredObject<SpaceObject> mirroredObject = MirroredObjectDefinition.create(SpaceObject.class)
                .documentPatches(patches).buildMirroredDocument();
        assertEquals(21, mirroredObject.getRoutingKey(new SpaceObject()));
    }

    @Test
    public void returnsGigaSpaceApplicableRoutingKey() throws Exception {
        class SpaceObject {
            @SpaceId(autoGenerate = true)
            public String routingKey() {
                return "A1^1403854928211^257";
            }
        }
        DocumentPatch[] patches = {};
        MirroredObject<SpaceObject> mirroredObject = MirroredObjectDefinition.create(SpaceObject.class)
                .documentPatches(patches).buildMirroredDocument();
        assertEquals("A1", mirroredObject.getRoutingKey(new SpaceObject()));
    }

    public static class MySpaceObject {
        String id;

        public MySpaceObject() {
        }

        @SpaceId(autoGenerate = true)
        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }
    }

    @Test
    public void decidesCorrectRouingKey() throws Exception {
        EmbeddedSpace embeddedSpace = new EmbeddedSpace();
        GigaSpace gigaSpace = embeddedSpace.gigaSpace();
        DocumentPatch[] patches = {};

        MirroredObject<MySpaceObject> mirroredObject = MirroredObjectDefinition.create(MySpaceObject.class)
                .documentPatches(patches).buildMirroredDocument();

        gigaSpace.writeMultiple(new MySpaceObject[] { new MySpaceObject(), new MySpaceObject(), new MySpaceObject(),
                new MySpaceObject(), new MySpaceObject(), new MySpaceObject(), new MySpaceObject(),
                new MySpaceObject(), new MySpaceObject() });
        for (MySpaceObject spaceObject : gigaSpace.readMultiple(new MySpaceObject())) {
            assertEquals((String) mirroredObject.getRoutingKey(spaceObject), 1,
                    Math.abs(mirroredObject.getRoutingKey(spaceObject).hashCode()) % 2);
        }

        embeddedSpace.destroy();
    }

    @Test
    public void usesSpaceRoutingAnnotationToFindRoutingKey() throws Exception {
        class SpaceObject {
            @SpaceRouting
            public Integer routing() {
                return 21;
            }

            @SpaceId
            public Integer id() {
                return 19;
            }
        }
        DocumentPatch[] patches = {};
        MirroredObject<SpaceObject> mirroredObject = MirroredObjectDefinition.create(SpaceObject.class)
                .documentPatches(patches).buildMirroredDocument();
        assertEquals(21, mirroredObject.getRoutingKey(new SpaceObject()));
    }

    @Test
    public void patchesAreAppliedInCorrectOrder() throws Exception {
        List<FakePatch> appliedPatchesInAppliedOrder = new ArrayList<>();
        FakePatch patch2 = new FakePatch(2, appliedPatchesInAppliedOrder);
        FakePatch patch1 = new FakePatch(1, appliedPatchesInAppliedOrder);
        DocumentPatch[] patches = { patch2, patch1 };
        MirroredObject<MirroredType> document = MirroredObjectDefinition.create(MirroredType.class)
                .documentPatches(patches).buildMirroredDocument();

        BasicDBObject dbObject = new BasicDBObject();
        document.patch(dbObject);
        assertEquals(2, appliedPatchesInAppliedOrder.size());
        assertSame(patch1, appliedPatchesInAppliedOrder.get(0));
        assertSame(patch2, appliedPatchesInAppliedOrder.get(1));
    }

    @Test
    public void currentVersionIsOneMoreThanLatestPathchedVersion() throws Exception {
        DocumentPatch[] patches = { new FakePatch(1), new FakePatch(2) };
        MirroredObject<MirroredType> document = MirroredObjectDefinition.create(MirroredType.class)
                .documentPatches(patches).buildMirroredDocument();
        assertEquals(3, document.getCurrentVersion());
    }

    @Test
    public void currentVersionIsOnIfeDocumentHasNoPatches() throws Exception {
        DocumentPatch[] patches = {};
        MirroredObject<MirroredType> document = MirroredObjectDefinition.create(MirroredType.class)
                .documentPatches(patches).buildMirroredDocument();
        assertEquals(1, document.getCurrentVersion());
    }

    @Test
    public void documentRequiresPatchingIfVersionToOld() throws Exception {
        DocumentPatch[] patches = { new FakePatch(1), new FakePatch(2) };
        MirroredObject<MirroredType> document = MirroredObjectDefinition.create(MirroredType.class)
                .documentPatches(patches).buildMirroredDocument();

        BasicDBObject dbObject = new BasicDBObject();
        document.setDocumentVersion(dbObject, document.getCurrentVersion() - 1);

        assertTrue(document.requiresPatching(dbObject));
    }

    @Test
    public void documentDoesNotRequirePatchingIfDocumentIsUpToDate() throws Exception {
        DocumentPatch[] patches = { new FakePatch(1), new FakePatch(2) };
        MirroredObject<MirroredType> document = MirroredObjectDefinition.create(MirroredType.class)
                .documentPatches(patches).buildMirroredDocument();

        BasicDBObject dbObject = new BasicDBObject();
        document.setDocumentVersion(dbObject, document.getCurrentVersion());

        assertFalse(document.requiresPatching(dbObject));
    }

    @Test(expected = UnknownDocumentVersionException.class)
    public void cannotPatchDocumentThatAreNewerThanLatestKnownVersion() throws Exception {
        DocumentPatch[] patches = { new FakePatch(1), new FakePatch(2) };
        MirroredObject<MirroredType> document = MirroredObjectDefinition.create(MirroredType.class)
                .documentPatches(patches).buildMirroredDocument();

        BasicDBObject dbObject = new BasicDBObject();
        document.setDocumentVersion(dbObject, document.getCurrentVersion() + 1);
        document.requiresPatching(dbObject);
    }

    @Test(expected = UnknownDocumentVersionException.class)
    public void cannotPatchDocumentThatAreOlderThanOldestKnownVersion() throws Exception {
        DocumentPatch[] patches = { new FakePatch(2), new FakePatch(3) };
        MirroredObject<MirroredType> document = MirroredObjectDefinition.create(MirroredType.class)
                .documentPatches(patches).buildMirroredDocument();

        BasicDBObject dbObject = new BasicDBObject();
        document.setDocumentVersion(dbObject, 1);

        document.requiresPatching(dbObject);
    }

    @Test(expected = IllegalArgumentException.class)
    public void patchingWhenNoPatchesExistsThrowsIllegalArgumentException() throws Exception {
        DocumentPatch[] patches = {};
        MirroredObject<MirroredType> document = MirroredObjectDefinition.create(MirroredType.class)
                .documentPatches(patches).buildMirroredDocument();
        BasicDBObject dbObject = new BasicDBObject();
        BasicDBObject patched = document.patch(dbObject);
        assertEquals(dbObject, patched);
    }

    @Test
    public void patchedDocumentHasLatestDocFormatVersion() throws Exception {
        DocumentPatch[] patches = { new FakePatch(1), new FakePatch(2) };
        MirroredObject<MirroredType> document = MirroredObjectDefinition.create(MirroredType.class)
                .documentPatches(patches).buildMirroredDocument();

        BasicDBObject dbObject = new BasicDBObject();
        BasicDBObject patched = document.patch(dbObject);

        assertEquals(3, document.getDocumentVersion(patched));
    }

    @Test
    public void appliesAllPathechesIfDocumentIsOnVersionOne() throws Exception {
        FakePatch patch1 = new FakePatch(1);
        FakePatch patch2 = new FakePatch(2);
        DocumentPatch[] patches = { patch1, patch2 };
        MirroredObject<MirroredType> document = MirroredObjectDefinition.create(MirroredType.class)
                .documentPatches(patches).buildMirroredDocument();
        BasicDBObject dbObject = new BasicDBObject();

        document.patch(dbObject);
        assertTrue(patch1.applied);
        assertTrue(patch2.applied);
    }

    @Test
    public void onlyAppliesAppropriatePatches() throws Exception {
        FakePatch patch1 = new FakePatch(1);
        FakePatch patch2 = new FakePatch(2);
        DocumentPatch[] patches = { patch1, patch2 };
        MirroredObject<MirroredType> document = MirroredObjectDefinition.create(MirroredType.class)
                .documentPatches(patches).buildMirroredDocument();
        BasicDBObject dbObject = new BasicDBObject();
        document.setDocumentVersion(dbObject, 2);
        document.patch(dbObject);
        assertFalse(patch1.applied);
        assertTrue(patch2.applied);
    }

    @Test(expected = UnknownDocumentVersionException.class)
    public void throwsUnkownDocumentVersionExceptionIfFormatVersionIsNewerThanCurrentFormatVersion()
            throws Exception {
        DocumentPatch[] patches = { new FakePatch(1) };
        MirroredObject<MirroredType> document = MirroredObjectDefinition.create(MirroredType.class)
                .documentPatches(patches).buildMirroredDocument();
        BasicDBObject dbObject = new BasicDBObject();
        document.setDocumentVersion(dbObject, 3);

        document.requiresPatching(dbObject);
    }

    @Test
    public void knownVersions() throws Exception {
        DocumentPatch[] patches = { new FakePatch(2), new FakePatch(3) };
        MirroredObject<MirroredType> document = MirroredObjectDefinition.create(MirroredType.class)
                .documentPatches(patches).buildMirroredDocument();
        assertFalse("Versions before oldest known version are not known", document.isKnownVersion(1));
        assertTrue(document.isKnownVersion(2));
        assertTrue(document.isKnownVersion(3));
        assertTrue(document.isKnownVersion(4));
        assertFalse("Versions after current version is not known", document.isKnownVersion(5));
    }

    @Test
    public void collectionName() throws Exception {
        DocumentPatch[] patches = { new FakePatch(2), new FakePatch(3) };
        MirroredObject<MirroredType> document = MirroredObjectDefinition.create(MirroredType.class)
                .documentPatches(patches).buildMirroredDocument();
        assertEquals(MongoCollectionUtils.getPreferredCollectionName(document.getMirroredType()),
                document.getCollectionName());
    }

    @Test
    public void setCollectionName() throws Exception {
        String collectionName = "fakeCollection";
        MirroredObject<MirroredType> document = MirroredObjectDefinition.create(MirroredType.class)
                .collectionName(collectionName).documentPatches(new FakePatch(2), new FakePatch(3))
                .buildMirroredDocument();
        assertEquals(collectionName, document.getCollectionName());

    }

    @Test
    public void oldestVersionIsCurrentVersionIfNoPatchesExists() throws Exception {
        DocumentPatch[] patches = {};
        MirroredObject<MirroredType> document = MirroredObjectDefinition.create(MirroredType.class)
                .documentPatches(patches).buildMirroredDocument();
        assertEquals(document.getCurrentVersion(), document.getOldestKnownVersion());
    }

    @Test
    public void oldestVersionIsOldestPatchedVersionIfPatchesExists() throws Exception {
        DocumentPatch[] patches = { new FakePatch(2), new FakePatch(3) };
        MirroredObject<MirroredType> document = MirroredObjectDefinition.create(MirroredType.class)
                .documentPatches(patches).buildMirroredDocument();
        assertEquals(2, document.getOldestKnownVersion());
    }

    @Test
    public void patchOneVersionAppliesOnlyASinglePatch() throws Exception {
        FakePatch patch1 = new FakePatch(1);
        FakePatch patch2 = new FakePatch(2);
        FakePatch patch3 = new FakePatch(3);
        DocumentPatch[] patches = { patch1, patch2, patch3 };
        MirroredObject<MirroredType> document = MirroredObjectDefinition.create(MirroredType.class)
                .documentPatches(patches).buildMirroredDocument();

        BasicDBObject dbObject = new BasicDBObject();
        document.setDocumentVersion(dbObject, 2);

        document.patchToNextVersion(dbObject);

        assertFalse(patch1.applied);
        assertTrue(patch2.applied);
        assertFalse(patch3.applied);
    }

    @Test
    public void setsRoutingFieldForRoutedDocumentLoad() throws Exception {
        DocumentPatch[] patches = {};
        MirroredObject<MirroredType> document = MirroredObjectDefinition.create(MirroredType.class)
                .loadDocumentsRouted(true).documentPatches(patches).buildMirroredDocument();
        BasicDBObject dbObject = new BasicDBObject();

        document.setDocumentAttributes(dbObject, new MirroredType(23));
        assertEquals(23, dbObject.get(MirroredObject.DOCUMENT_ROUTING_KEY));
    }

    @Test
    public void canDetermineRoutingKeyFromStringRoutingValue() throws Exception {
        DocumentPatch[] patches = {};
        MirroredObject<RoutedType> document = MirroredObjectDefinition.create(RoutedType.class)
                .loadDocumentsRouted(true).documentPatches(patches).buildMirroredDocument();
        BasicDBObject dbObject = new BasicDBObject();

        document.setDocumentAttributes(dbObject, new RoutedType(23, "bananskal"));
        assertEquals("bananskal".hashCode(), dbObject.get(MirroredObject.DOCUMENT_ROUTING_KEY));
    }

    static class MirroredType {
        private final int routingKey;

        public MirroredType() {
            this(1);
        }

        public MirroredType(int routingKey) {
            this.routingKey = routingKey;
        }

        @SpaceRouting
        public Integer getRoutingKey() {
            return routingKey;
        }
    }

    static class RoutedType {
        private final Integer id;
        private final String myRoute;

        private RoutedType(Integer id, String myRoute) {
            this.id = id;
            this.myRoute = myRoute;
        }

        @SpaceId(autoGenerate = false)
        public final Integer getId() {
            return id;
        }

        @SpaceRouting
        public final String getMyRoute() {
            return myRoute;
        }
    }

    static class FakePatch implements DocumentPatch {

        private final int patchedVersion;
        public boolean applied = false;
        private final List<FakePatch> appliedPatches;

        public FakePatch(int patchedVersion) {
            this(patchedVersion, new ArrayList<FakePatch>());
        }

        public FakePatch(int patchedVersion, List<FakePatch> appliedPatches) {
            this.patchedVersion = patchedVersion;
            this.appliedPatches = appliedPatches;
        }

        @Override
        public void apply(BasicDBObject dbObject) {
            applied = true;
            appliedPatches.add(this);
        }

        @Override
        public int patchedVersion() {
            return patchedVersion;
        }

    }

    private static class EmbeddedSpace {
        private static final AtomicInteger count = new AtomicInteger();
        EmbeddedSpaceConfigurer configurer = new EmbeddedSpaceConfigurer(
                "MirroredObjectTest-" + count.incrementAndGet()).lookupGroups(JVMGlobalLus.getLookupGroupName());
        GigaSpace space = new GigaSpaceConfigurer(configurer.create()).create();

        public GigaSpace gigaSpace() {
            return space;
        }

        public void destroy() {
            this.configurer.close();
        }
    }

}