com.mtgi.analytics.JdbcEventTestCase.java Source code

Java tutorial

Introduction

Here is the source code for com.mtgi.analytics.JdbcEventTestCase.java

Source

/* 
 * Copyright 2008-2009 the original author or authors.
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 */

package com.mtgi.analytics;

import static org.junit.Assert.fail;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;

import javax.sql.DataSource;

import org.custommonkey.xmlunit.Diff;
import org.dbunit.DatabaseUnitException;
import org.dbunit.database.DatabaseConnection;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.Column;
import org.dbunit.dataset.CompositeTable;
import org.dbunit.dataset.DataSetException;
import org.dbunit.dataset.DefaultTableMetaData;
import org.dbunit.dataset.ITable;
import org.dbunit.dataset.ITableMetaData;
import org.dbunit.dataset.datatype.StringDataType;
import org.dbunit.dataset.datatype.TypeCastException;
import org.dbunit.dataset.xml.FlatXmlDataSet;
import org.junit.After;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.unitils.UnitilsJUnit4TestClassRunner;
import org.unitils.spring.annotation.SpringApplicationContext;
import org.unitils.spring.annotation.SpringBeanByType;
import org.unitils.thirdparty.org.apache.commons.io.IOUtils;

@SpringApplicationContext("applicationContext-test.xml")
@RunWith(UnitilsJUnit4TestClassRunner.class)
public abstract class JdbcEventTestCase {

    @SpringBeanByType
    protected DataSource ds;

    //we keep a connection and statement open for general purpose verification during test runs
    protected Connection conn;
    protected Statement stmt;

    @Before
    public void createDB() throws IOException, SQLException {
        conn = ds.getConnection();
        stmt = conn.createStatement();
        runResourceScript("create/create_behavior_tracking.sql");
    }

    @After
    public void dropDB() throws IOException, SQLException {
        try {
            runResourceScript("create/drop_behavior_tracking.sql");
        } finally {
            stmt.close();
            conn.close();
        }
    }

    /**
     * Verify that the contents of the test event database match the dataset in the given resource XML file.
     * The comparison excludes the START and DURATION_MS columns, since these will change with each test run.
     */
    public void assertEventDataMatches(String dataSetResource)
            throws SQLException, DataSetException, IOException, DatabaseUnitException {
        IDatabaseConnection connection = new DatabaseConnection(conn);
        ITable actualTable = connection.createDataSet().getTable("BEHAVIOR_TRACKING_EVENT");
        actualTable = normalizedEventTable(actualTable);

        InputStream expectedData = getClass().getResourceAsStream(dataSetResource);
        FlatXmlDataSet expectedDataSet = new FlatXmlDataSet(expectedData, true);
        ITable expectedTable = expectedDataSet.getTable("BEHAVIOR_TRACKING_EVENT");
        expectedTable = normalizedEventTable(expectedTable);

        org.dbunit.Assertion.assertEquals(expectedTable, actualTable);
    }

    /** 
     * transform the given dbunit table into one that can be used to meaningfully compare
     * event data, without raising false negatives due to differences in start date or minor
     * changes in XML syntax for the event_data column.
     * @throws DataSetException 
     */
    public static ITable normalizedEventTable(ITable table) throws DataSetException {
        ITableMetaData metaData = table.getTableMetaData();
        ArrayList<Column> columns = new ArrayList<Column>();
        for (Column c : metaData.getColumns()) {
            String name = c.getColumnName();
            //strip out time columns.
            //TODO: leave in duration, with which we can compare with a tolerance value?
            if ("EVENT_START".equals(name) || "DURATION_NS".equals(name))
                continue;
            //replace string data type comparator with an xmlunit-based comparator
            if ("EVENT_DATA".equals(name))
                c = new Column("EVENT_DATA",
                        new XmlStringDataType(c.getSqlTypeName(), c.getDataType().getSqlType()));
            columns.add(c);
        }
        return new CompositeTable(new DefaultTableMetaData(metaData.getTableName(),
                columns.toArray(new Column[columns.size()]), metaData.getPrimaryKeys()), table);
    }

    protected void runResourceScript(String resource) throws IOException, SQLException {
        URL location = Thread.currentThread().getContextClassLoader().getResource(resource);
        if (location == null)
            fail("Unable to find script " + resource);

        InputStream is = location.openStream();
        String sql = IOUtils.toString(is);
        is.close();

        //convert oracle types to hsql types
        sql = sql.replaceAll("VARCHAR2", "VARCHAR");
        sql = sql.replaceAll("NUMBER", "NUMERIC");
        sql = sql.replaceAll("CLOB", "LONGVARCHAR");
        stmt.execute(sql);
    }

    public static class XmlStringDataType extends StringDataType {

        public XmlStringDataType(String name, int sqlType) {
            super(name, sqlType);
        }

        @Override
        public int compare(Object o1, Object o2) throws TypeCastException {
            String s1 = asString(o1);
            String s2 = asString(o2);

            if (s1 != null && s2 != null) {
                Diff diff;
                try {
                    diff = new Diff(s1, s2);
                } catch (Exception e) {
                    throw new TypeCastException("Error parsing XML data", e);
                }
                if (diff.identical())
                    return 0;
            }
            return super.compare(o1, o2);
        }

    }
}