com.ebuddy.cassandra.cql.dao.CqlStructuredDataSupportSystemTest.java Source code

Java tutorial

Introduction

Here is the source code for com.ebuddy.cassandra.cql.dao.CqlStructuredDataSupportSystemTest.java

Source

/*
 * Copyright 2013 eBuddy B.V.
 *
 *    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.ebuddy.cassandra.cql.dao;

import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotSame;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;

import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.UUID;

import org.apache.commons.lang3.StringUtils;
import org.cassandraunit.utils.EmbeddedCassandraServerHelper;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.MockitoAnnotations;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.ConsistencyLevel;
import com.datastax.driver.core.Query;
import com.datastax.driver.core.Session;
import com.datastax.driver.core.exceptions.InvalidQueryException;
import com.ebuddy.cassandra.BatchContext;
import com.ebuddy.cassandra.Path;
import com.ebuddy.cassandra.StructuredDataSupport;
import com.ebuddy.cassandra.TypeReference;
import com.ebuddy.cassandra.databind.CustomTypeResolverBuilder;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * System tests for CqlStructuredDataSupport.
 *
 * @author Eric Zoerner <a href="mailto:ezoerner@ebuddy.com">ezoerner@ebuddy.com</a>
 */
public class CqlStructuredDataSupportSystemTest {
    private static final String LOCALHOST_IP = "localhost";
    private static final String CASSANDRA_HOSTS_SYSTEM_PROPERTY = "cassandra.hosts";
    private static final String TEST_KEYSPACE = "cqlstructureddatasupportsystemtest";

    private Cluster cluster;
    private final String tableName = "testpojo";

    private StructuredDataSupport<UUID> daoSupport;
    private Session session;
    @Captor
    private ArgumentCaptor<Query> queryCaptor;

    @BeforeMethod(groups = { "system" })
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        EmbeddedCassandraServerHelper.startEmbeddedCassandra();

        // default to using cassandra on localhost, but can be overridden with a system property
        String cassandraHostsString = System.getProperty(CASSANDRA_HOSTS_SYSTEM_PROPERTY, LOCALHOST_IP);
        String[] cassandraHosts = StringUtils.split(cassandraHostsString, ',');
        Cluster.Builder clusterBuilder = Cluster.builder();
        for (String host : cassandraHosts) {
            clusterBuilder.addContactPoint(host);
        }
        cluster = clusterBuilder.withPort(9142).build();
        dropAndCreateSchema();

        // get new session using a default keyspace that we now know exists
        session = cluster.connect(TEST_KEYSPACE);
        session = spy(session);
        daoSupport = new CqlStructuredDataSupport<UUID>(tableName, ConsistencyLevel.QUORUM, session);
    }

    @AfterMethod(alwaysRun = true)
    public void tearDown() throws Exception {
        cluster.shutdown();
    }

    @Test(groups = { "system" })
    public void shouldWriteReadDeleteTestPojo() throws Exception {
        TestPojo testObject = new TestPojo("v1", 42L, true, Arrays.asList("e1", "e2"));
        UUID rowKey = UUID.randomUUID();
        Path path = daoSupport.createPath("a", "b", "c");
        TypeReference<TestPojo> typeReference = new TypeReference<TestPojo>() {
        };

        daoSupport.writeToPath(rowKey, path, testObject);

        TestPojo result = daoSupport.readFromPath(rowKey, path, typeReference);
        assertNotSame(result, testObject);
        assertEquals(result, testObject);

        daoSupport.deletePath(rowKey, path);
        TestPojo result2 = daoSupport.readFromPath(rowKey, path, typeReference);
        assertNull(result2);

        verifyConsistency(5);
    }

    @Test(groups = { "system" })
    public void shouldWriteInBatch() throws Exception {
        TestPojo testObject1 = new TestPojo("v1", 42L, true, Arrays.asList("e1", "e2"));
        TestPojo testObject2 = new TestPojo("v2", 43L, false, Arrays.asList("e3", "e4"));

        UUID rowKey1 = UUID.randomUUID();
        UUID rowKey2 = UUID.randomUUID();
        Path path = daoSupport.createPath("test");
        TypeReference<TestPojo> typeReference = new TypeReference<TestPojo>() {
        };

        BatchContext batchContext = daoSupport.beginBatch();
        daoSupport.writeToPath(rowKey1, path, testObject1, batchContext);
        daoSupport.writeToPath(rowKey2, path, testObject2, batchContext);
        daoSupport.applyBatch(batchContext);

        TestPojo result1 = daoSupport.readFromPath(rowKey1, path, typeReference);
        assertNotSame(result1, testObject1);
        assertEquals(result1, testObject1);

        TestPojo result2 = daoSupport.readFromPath(rowKey2, path, typeReference);
        assertNotSame(result2, testObject2);
        assertEquals(result2, testObject2);

        verifyConsistency(3);
    }

    @Test(groups = { "system" })
    public void shouldShrinkList() throws Exception {
        List<String> longList = Arrays.asList("1", "2", "3", "4", "5", "6");
        UUID rowKey = UUID.randomUUID();
        TypeReference<List<String>> typeReference = new TypeReference<List<String>>() {
        };

        Path path = daoSupport.createPath("x");

        daoSupport.writeToPath(rowKey, path, longList);
        List<String> resultLongList = daoSupport.readFromPath(rowKey, path, typeReference);
        assertNotSame(resultLongList, longList);
        assertEquals(resultLongList, longList);

        List<String> shortList = Arrays.asList("1", "2", "3");

        daoSupport.writeToPath(rowKey, path, shortList);
        List<String> resultShortList = daoSupport.readFromPath(rowKey, path, typeReference);
        assertNotSame(resultShortList, shortList);
        assertEquals(resultShortList, shortList);

        verifyConsistency(4);
    }

    @Test(groups = { "system" })
    public void shouldRemoveListCruftWhenDeleting() throws Exception {
        List<String> longList = Arrays.asList("1", "2", "3", "4", "5", "6");
        UUID rowKey = UUID.randomUUID();
        TypeReference<List<String>> typeReference = new TypeReference<List<String>>() {
        };

        Path path = daoSupport.createPath("x");

        daoSupport.writeToPath(rowKey, path, longList);
        List<String> resultLongList = daoSupport.readFromPath(rowKey, path, typeReference);
        assertNotSame(resultLongList, longList);
        assertEquals(resultLongList, longList);

        List<String> shortList = Arrays.asList("1", "2", "3");

        daoSupport.writeToPath(rowKey, path, shortList);
        List<String> resultShortList = daoSupport.readFromPath(rowKey, path, typeReference);
        assertNotSame(resultShortList, shortList);
        assertEquals(resultShortList, shortList);

        Path indexPath = daoSupport.createPath("x").withIndices(4);
        String s = daoSupport.readFromPath(rowKey, indexPath, new TypeReference<String>() {
        });
        assertEquals(s, "5"); // cruft

        daoSupport.deletePath(rowKey, path);

        s = daoSupport.readFromPath(rowKey, indexPath, new TypeReference<String>() {
        });
        assertNull(s); // cruft gone

        verifyConsistency(8);
    }

    @SuppressWarnings("unchecked")
    @Test(groups = { "system" })
    public void convertValueShouldRetainOrderingInMaps() throws Exception {
        SortedMap<String, String> map = new TreeMap<String, String>();
        map.put("b", "1");
        map.put("a", "2");

        ObjectMapper mapper = new ObjectMapper();
        mapper.setDefaultTyping(new CustomTypeResolverBuilder());
        Object converted = mapper.convertValue(map, Object.class);
        assertTrue(converted instanceof LinkedHashMap);
        // keys are sorted by Cassandra as UTF8
        assertEquals(((Map<String, String>) converted).keySet().iterator().next(), "a");
    }

    private void dropAndCreateSchema() {
        Session localSession = cluster.connect();
        try {
            dropKeyspaceIfExists(localSession);
            localSession.execute("CREATE KEYSPACE " + TEST_KEYSPACE + " WITH replication "
                    + "= {'class':'SimpleStrategy', " + "'replication_factor':1};");

            localSession.execute("CREATE TABLE " + TEST_KEYSPACE + "." + tableName + " (key uuid, column1 text, "
                    + "value text, PRIMARY KEY (key, column1));");
        } finally {
            localSession.shutdown();
        }
    }

    private void dropKeyspaceIfExists(Session localSession) {
        try {
            localSession.execute("drop keyspace " + TEST_KEYSPACE);
        } catch (InvalidQueryException ignored) {
            // doesn't exist
        }
    }

    private void verifyConsistency(int numberOfInvocations) {
        verify(session, times(numberOfInvocations)).execute(queryCaptor.capture());
        for (Query q : queryCaptor.getAllValues()) {
            assertEquals(q.getConsistencyLevel(), ConsistencyLevel.QUORUM);
        }
    }
}