All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.deephacks.tools4j.config.test.integration.IntegrationConfigTests Maven / Gradle / Ivy

There is a newer version: 0.15.0
Show newest version
package org.deephacks.tools4j.config.test.integration;

import com.google.common.collect.ImmutableList;
import junit.framework.AssertionFailedError;
import org.deephacks.tools4j.config.RuntimeContext;
import org.deephacks.tools4j.config.admin.AdminContext;
import org.deephacks.tools4j.config.model.AbortRuntimeException;
import org.deephacks.tools4j.config.model.Bean;
import org.deephacks.tools4j.config.model.Bean.BeanId;
import org.deephacks.tools4j.config.model.Lookup;
import org.deephacks.tools4j.config.test.ConfigTestData.*;
import org.deephacks.tools4j.config.test.FeatureTestsRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static org.deephacks.tools4j.config.model.Events.*;
import static org.deephacks.tools4j.config.test.ConfigTestData.*;
import static org.deephacks.tools4j.config.test.ConversionUtils.toBean;
import static org.deephacks.tools4j.config.test.ConversionUtils.toBeans;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.unitils.reflectionassert.ReflectionAssert.assertReflectionEquals;
import static org.unitils.reflectionassert.ReflectionComparatorMode.LENIENT_ORDER;

@RunWith(FeatureTestsRunner.class)
public class IntegrationConfigTests {

    private RuntimeContext runtime = Lookup.get().lookup(RuntimeContext.class);
    private AdminContext admin = Lookup.get().lookup(AdminContext.class);
    private Child c1;
    private Child c2;
    private Parent p1;
    private Parent p2;
    private Grandfather g1;
    private Grandfather g2;
    private SingletonParent sp1;
    private Singleton s1;
    private Collection defaultBeans;

    @Before
    public void setupDefaultConfigData() {
        sp1 = getSingletonParent("sp1");
        s1 = getSingleton();

        c1 = getChild("c1");
        c2 = getChild("c2");

        p1 = getParent("p1");
        p1.add(c2, c1);
        p1.set(c1);
        p1.put(c1);
        p1.put(c2);

        p2 = getParent("p2");
        p2.add(c1, c2);
        p2.set(c2);
        p2.put(c1);
        p2.put(c2);

        g1 = getGrandfather("g1");
        g1.add(p1, p2);

        g2 = getGrandfather("g2");
        g2.add(p1, p2);
        g2.put(p1);

        runtime.register(Grandfather.class, Parent.class, Child.class, Singleton.class,
                SingletonParent.class, JSR303Validation.class);
        if (defaultBeans == null) {
            // toBeans steals quite a bit of performance when having larger hierarchies.
            defaultBeans = ImmutableList.copyOf(toBeans(c1, c2, p1, p2, g1, g2));
        }
    }

    @Test
    public void test_create_set_merge_non_existing_property() {
        createDefault();
        Bean bean = Bean.create(c1.getId());
        bean.addProperty("non_existing", "bogus");
        try {
            admin.create(bean);
            fail("Not possible to set property names that does not exist in schema");
        } catch (AbortRuntimeException e) {
            assertThat(e.getEvent().getCode(), is(CFG110));
        }
        try {
            admin.set(bean);
            fail("Not possible to set property names that does not exist in schema");
        } catch (AbortRuntimeException e) {
            assertThat(e.getEvent().getCode(), is(CFG110));
        }
        try {
            admin.merge(bean);
            fail("Not possible to set property names that does not exist in schema");
        } catch (AbortRuntimeException e) {
            assertThat(e.getEvent().getCode(), is(CFG110));
        }
        try {
            bean = Bean.create(BeanId.create("c5", CHILD_SCHEMA_NAME));
            bean.setReference("non_existing", c1.getId());
            admin.create(bean);
            fail("Not possible to set property names that does not exist in schema");
        } catch (AbortRuntimeException e) {
            assertThat(e.getEvent().getCode(), is(CFG111));
        }
        bean = Bean.create(c1.getId());
        bean.addProperty("non_existing", "bogus");

        try {
            admin.set(bean);
            fail("Not possible to set property names that does not exist in schema");
        } catch (AbortRuntimeException e) {
            assertThat(e.getEvent().getCode(), is(CFG110));
        }
        try {
            admin.merge(bean);
            fail("Not possible to set property names that does not exist in schema");
        } catch (AbortRuntimeException e) {
            assertThat(e.getEvent().getCode(), is(CFG110));
        }
    }

    /**
     * Test the possibility for:
     *
     * 1) Creating individual beans that have references to eachother.
     * 2) Created beans can be fetched individually.
     * 3) That the runtime view sees the same result.
     */
    @Test
    public void test_create_single_then_get_list() {
        createThenGet(c1);
        createThenGet(c2);
        listAndAssert(c1.getId().getSchemaName(), c1, c2);
        createThenGet(p1);
        createThenGet(p2);
        listAndAssert(p1.getId().getSchemaName(), p1, p2);
        createThenGet(g1);
        createThenGet(g2);
        listAndAssert(g1.getId().getSchemaName(), g1, g2);
    }

    /**
     * Test the possibility for:
     *
     * 1) Creating a collection of beans that have references to eachother.
     * 2) Created beans can be fetched individually afterwards.
     * 3) Created beans can be listed afterwards.
     * 4) That the runtime view sees the same result as admin view.
     */
    @Test
    public void test_create_multiple_then_get_list() {
        createDefault();
        getAndAssert(c1);
        getAndAssert(c2);
        listAndAssert(c1.getId().getSchemaName(), c1, c2);
        getAndAssert(p1);
        getAndAssert(p2);
        listAndAssert(p1.getId().getSchemaName(), p1, p2);
        getAndAssert(g1);
        getAndAssert(g2);
        listAndAssert(g1.getId().getSchemaName(), g1, g2);

    }

    /**
     * Test that singleton beans have their default instance created after registration.
     */
    @Test
    public void test_register_singleton() {
        Singleton singleton = runtime.singleton(Singleton.class);
        assertNotNull(singleton);
    }

    /**
     * Test that singleton references are automatically assigned without needing to provision them
     * from admin context.
     */
    @Test
    public void test_singleton_references() {
        // provision a bean without the singleton reference.
        Bean singletonParent = toBean(sp1);
        admin.create(singletonParent);

        // asert that the singleton reference is set for runtime
        SingletonParent parent = runtime.get(singletonParent.getId().getInstanceId(),
                SingletonParent.class);
        assertNotNull(parent.getSingleton());

        // assert that the singleton reference is set for admin
        Bean result = admin.get(singletonParent.getId());
        BeanId singletonId = result.getFirstReference("singleton");
        assertThat(singletonId, is(s1.getBeanId()));
        assertThat(singletonId.getBean(), is(toBean(s1)));

    }

    /**
     * Test the possibility for:
     *
     * 1) Setting an empty bean that will erase properties and references.
     * 3) Bean that was set empty can be fetched individually.
     * 4) That the runtime view sees the same result as admin view.
     */
    @Test
    public void test_set_get_single() {
        createDefault();
        Grandfather empty = new Grandfather("g1");
        Bean empty_expect = toBean(empty);

        admin.set(empty_expect);
        Bean empty_result = admin.get(empty.getId());
        assertReflectionEquals(empty_expect, empty_result, LENIENT_ORDER);
    }

    @Test
    public void test_set_get_list() {
        createDefault();
        Grandfather empty_g1 = new Grandfather("g1");
        Grandfather empty_g2 = new Grandfather("g2");
        Collection empty_expect = toBeans(empty_g1, empty_g2);
        admin.set(empty_expect);
        Collection empty_result = admin.list(empty_g1.getId().getSchemaName());
        assertReflectionEquals(empty_expect, empty_result, LENIENT_ORDER);
        runtimeAllAndAssert(empty_g1.getClass(), empty_g1, empty_g2);
    }

    @Test
    public void test_set_empty_properties() {
        createThenGet(c1);
        Bean b = Bean.create(BeanId.create("c1", CHILD_SCHEMA_NAME));
        admin.set(b);
        Bean result = admin.get(b.getId());
        assertThat(result.getPropertyNames().size(), is(0));
    }

    @Test
    public void test_merge_get_single() {
        createDefault();

        Grandfather merged = new Grandfather("g1");
        merged.setProp14(TimeUnit.NANOSECONDS);
        merged.setProp19(Arrays.asList(TimeUnit.DAYS, TimeUnit.HOURS));
        merged.setProp1("newName");

        Bean mergeBean = toBean(merged);
        admin.merge(mergeBean);

        // modify the original to fit the expected merge
        g1.setProp1(merged.getProp1());
        g1.setProp19(merged.getProp19());
        g1.setProp14(merged.getProp14());
        getAndAssert(g1);
    }

    @Test
    public void test_merge_get_list() {
        createDefault();

        Grandfather g1_merged = new Grandfather("g1");
        g1_merged.setProp14(TimeUnit.NANOSECONDS);
        g1_merged.setProp19(Arrays.asList(TimeUnit.DAYS, TimeUnit.HOURS));
        g1_merged.setProp1("newName");

        Grandfather g2_merged = new Grandfather("g2");
        g2_merged.setProp14(TimeUnit.NANOSECONDS);
        g2_merged.setProp19(Arrays.asList(TimeUnit.DAYS, TimeUnit.HOURS));
        g2_merged.setProp1("newName");

        Collection mergeBeans = toBeans(g1_merged, g2_merged);
        admin.merge(mergeBeans);

        // modify the original to fit the expected merge
        g1.setProp1(g1_merged.getProp1());
        g1.setProp19(g1_merged.getProp19());
        g1.setProp14(g1_merged.getProp14());

        g2.setProp1(g2_merged.getProp1());
        g2.setProp19(g2_merged.getProp19());
        g2.setProp14(g2_merged.getProp14());

        listAndAssert(g1.getId().getSchemaName(), g1, g2);

    }

    @Test
    public void test_merge_and_set_broken_references() {
        createDefault();
        // try merge a invalid single reference
        Bean b = Bean.create(BeanId.create("p1", PARENT_SCHEMA_NAME));
        b.addReference("prop6", BeanId.create("non_existing_child_ref", ""));
        try {
            admin.merge(b);
            fail("Should not be possible to merge invalid reference");
        } catch (AbortRuntimeException e) {
            if (e.getEvent().getCode() != CFG301 && e.getEvent().getCode() != CFG304) {
                fail("Should not be possible to merge invalid reference");
            }
        }

        // try merge a invalid reference on collection
        b = Bean.create(BeanId.create("p2", PARENT_SCHEMA_NAME));
        b.addReference("prop7", BeanId.create("non_existing_child_ref", ""));
        try {
            admin.merge(b);
            fail("Should not be possible to merge invalid reference");
        } catch (AbortRuntimeException e) {
            if (e.getEvent().getCode() != CFG301 && e.getEvent().getCode() != CFG304) {
                fail("Should not be possible to merge invalid reference");
            }
        }

        // try set a invalid single reference
        b = Bean.create(BeanId.create("parent4", PARENT_SCHEMA_NAME));
        b.addReference("prop6", BeanId.create("non_existing_child_ref", ""));
        try {
            admin.set(b);
            fail("Should not be possible to merge beans that does not exist");
        } catch (AbortRuntimeException e) {
            if (e.getEvent().getCode() != CFG301 && e.getEvent().getCode() != CFG304) {
                fail("Should not be possible to merge invalid reference");
            }
        }

        // try merge a invalid single reference
        b = Bean.create(BeanId.create("p1", PARENT_SCHEMA_NAME));
        b.addReference("prop6", BeanId.create("non_existing_child_ref", ""));
        try {
            admin.set(b);
            fail("Should not be possible to merge invalid reference");
        } catch (AbortRuntimeException e) {
            if (e.getEvent().getCode() != CFG301 && e.getEvent().getCode() != CFG304) {
                fail("Should not be possible to merge invalid reference");
            }
        }
    }

    @Test
    public void test_merge_delete_check_predecessors() {
        Grandfather g1 = new Grandfather("g1");
        Parent p1 = new Parent("p1");
        Child c1 = new Child("c1");
        g1.add(p1);

        admin.create(toBean(c1));
        admin.create(toBean(p1));
        admin.create(toBean(g1));

        Bean gb1 = toBean(g1);
        Bean pb1 = toBean(p1);
        admin.get(pb1.getId());

        // delete the parent reference by setting the property to empty list
        gb1.setReferences("prop7", new ArrayList());

        admin.merge(gb1);
        try {
            admin.delete(pb1.getId());
        } catch (AbortRuntimeException e) {
            fail("Should be possible to delete parent since grandfather "
                    + "no longer have a reference to it");
        }
    }

    @Test
    public void test_set_delete_check_predecessors() {
        Grandfather g1 = new Grandfather("g1");
        Parent p1 = new Parent("p1");
        Child c1 = new Child("c1");
        g1.add(p1);

        admin.create(toBean(c1));
        admin.create(toBean(p1));
        admin.create(toBean(g1));

        Bean gb1 = toBean(g1);
        Bean pb1 = toBean(p1);
        admin.get(pb1.getId());

        // delete the parent reference by setting the property to empty list
        gb1.setReferences("prop7", new ArrayList());

        admin.set(gb1);
        try {
            admin.delete(pb1.getId());
        } catch (AbortRuntimeException e) {
            fail("Should be possible to delete parent since grandfather "
                    + "no longer have a reference to it");
        }
    }

    @Test
    public void test_delete_bean() {
        createDefault();

        admin.delete(g1.getId());

        try {
            admin.get(g1.getId());
            fail("Bean should have been deleted");
        } catch (AbortRuntimeException e) {
            assertThat(e.getEvent().getCode(), is(CFG304));
        }
    }

    @Test
    public void test_delete_beans() {
        createDefault();

        admin.delete(g1.getId().getSchemaName(), Arrays.asList("g1", "g2"));

        List result = admin.list(g1.getId().getSchemaName());
        assertThat(result.size(), is(0));
    }

    @Test
    public void test_delete_reference_violation() {
        admin.create(toBeans(g1, g2, p1, p2, c1, c2));
        // test single
        try {
            admin.delete(BeanId.create("c1", CHILD_SCHEMA_NAME));
            fail("Should not be possible to delete a bean with references");
        } catch (AbortRuntimeException e) {
            assertThat(e.getEvent().getCode(), is(CFG302));
        }
        // test multiple
        try {
            admin.delete(CHILD_SCHEMA_NAME, Arrays.asList("c1", "c2"));
            fail("Should not be possible to delete a bean with references");
        } catch (AbortRuntimeException e) {
            assertThat(e.getEvent().getCode(), is(CFG302));
        }
    }

    @Test
    public void test_set_merge_without_schema() {
        Bean b = Bean.create(BeanId.create("1", "missing_schema_name"));
        try {
            admin.create(b);
            fail("Cant add beans without a schema.");
        } catch (AbortRuntimeException e) {
            assertThat(e.getEvent().getCode(), is(CFG101));
        }
        try {
            admin.merge(b);
            fail("Cant add beans without a schema.");
        } catch (AbortRuntimeException e) {
            assertThat(e.getEvent().getCode(), is(CFG101));
        }
    }

    @Test
    public void test_set_merge_violating_types() {
        admin.create(toBeans(g1, g2, p1, p2, c1, c2));

        Bean child = Bean.create(BeanId.create("c1", CHILD_SCHEMA_NAME));
        // child merge invalid byte
        try {
            child.setProperty("prop8", "100000");
            admin.set(child);
            fail("10000 does not fit java.lang.Byte");
        } catch (AbortRuntimeException e) {
            assertThat(e.getEvent().getCode(), is(CFG105));
        }
        // child merge invalid integer
        try {
            child.addProperty("prop3", "2.2");
            admin.merge(child);
            fail("2.2 does not fit a collection of java.lang.Integer");
        } catch (AbortRuntimeException e) {
            assertThat(e.getEvent().getCode(), is(CFG105));
        }
        // parent set invalid enum value
        Bean parent = Bean.create(BeanId.create("g1", GRANDFATHER_SCHEMA_NAME));
        try {
            parent.setProperty("prop14", "not_a_enum");
            admin.set(parent);
            fail("not_a_enum is not a value of TimeUnit");
        } catch (AbortRuntimeException e) {
            assertThat(e.getEvent().getCode(), is(CFG105));
        }
        // parent merge invalid value to enum list
        parent = Bean.create(BeanId.create("p1", PARENT_SCHEMA_NAME));
        try {
            parent.addProperty("prop19", "not_a_enum");
            admin.merge(parent);
            fail("not_a_enum is not a value of TimeUnit");
        } catch (AbortRuntimeException e) {
            assertThat(e.getEvent().getCode(), is(CFG105));
        }

        // grandfather merge invalid multiplicity type, i.e. single on multi value.
        Bean grandfather = Bean.create(BeanId.create("g1", GRANDFATHER_SCHEMA_NAME));
        try {
            grandfather.addProperty("prop1", Arrays.asList("1", "2"));
            admin.merge(grandfather);
            fail("Cannot add mutiple values to a single valued property.");
        } catch (AbortRuntimeException e) {
            assertThat(e.getEvent().getCode(), is(CFG106));
        }

        // grandfather set invalid multiplicity type, multi value on single.
        grandfather = Bean.create(BeanId.create("p1", PARENT_SCHEMA_NAME));
        try {
            grandfather.addProperty("prop11", "2.0");
            admin.set(parent);
            fail("Cannot add a value to a single typed value.");
        } catch (AbortRuntimeException e) {
            assertThat(e.getEvent().getCode(), is(CFG105));
        }

    }

    @Test
    public void test_circular_references() {
        String personSchema = "person";
        runtime.register(Person.class);

        BeanId aId = BeanId.create("a", personSchema);
        BeanId bId = BeanId.create("b", personSchema);
        BeanId cId = BeanId.create("c", personSchema);
        BeanId dId = BeanId.create("d", personSchema);

        Bean a = Bean.create(aId);
        Bean b = Bean.create(bId);
        Bean c = Bean.create(cId);
        Bean d = Bean.create(dId);

        admin.create(Arrays.asList(a, b, c, d));

        a.setReference("bestFriend", bId);
        b.setReference("bestFriend", aId);
        c.setReference("bestFriend", dId);
        d.setReference("bestFriend", cId);

        a.addReference("closeFriends", Arrays.asList(bId, cId, dId));
        b.addReference("closeFriends", Arrays.asList(aId, cId, dId));
        c.addReference("closeFriends", Arrays.asList(aId, bId, dId));
        d.addReference("closeFriends", Arrays.asList(aId, bId, cId));

        a.addReference("colleauges", Arrays.asList(bId, cId, dId));
        b.addReference("colleauges", Arrays.asList(aId, cId, dId));
        c.addReference("colleauges", Arrays.asList(aId, bId, dId));
        d.addReference("colleauges", Arrays.asList(aId, bId, cId));
        /**
         * Now test all operations from admin and runtime to make
         * sure that none of them get stuck in infinite recrusion.
         */

        admin.merge(Arrays.asList(a, b, c, d));
        admin.set(Arrays.asList(a, b, c, d));
        admin.list("person");
        admin.get(BeanId.create("b", "person"));
        runtime.all(Person.class);
        runtime.get("c", Person.class);

    }

    private void createThenGet(Object object) throws AssertionFailedError {
        Bean bean = toBean(object);
        admin.create(bean);
        getAndAssert(object);
    }

    private void getAndAssert(Object object) throws AssertionFailedError {
        Bean bean = toBean(object);
        Bean result = admin.get(bean.getId());
        assertReflectionEquals(bean, result, LENIENT_ORDER);
        runtimeGetAndAssert(object, bean);
    }

    /**
     * Create the default testdata structure.
     */
    private void createDefault() {
        admin.create(defaultBeans);

    }

    private void listAndAssert(String schemaName, Object... objects) {
        Collection beans = admin.list(schemaName);
        assertReflectionEquals(toBeans(objects), beans, LENIENT_ORDER);
        runtimeAllAndAssert(objects[0].getClass(), objects);
    }

    private void runtimeGetAndAssert(Object object, Bean bean) throws AssertionFailedError {
        Object o = runtime.get(bean.getId().getInstanceId(), object.getClass());
        assertReflectionEquals(object, o, LENIENT_ORDER);
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    private void runtimeAllAndAssert(Class clazz, Object... objects) throws AssertionFailedError {
        List reslut = runtime.all(clazz);
        assertReflectionEquals(objects, reslut, LENIENT_ORDER);
    }
}