com.tacitknowledge.util.migration.DistributedJdbcMigrationLauncherFactoryTest.java Source code

Java tutorial

Introduction

Here is the source code for com.tacitknowledge.util.migration.DistributedJdbcMigrationLauncherFactoryTest.java

Source

/* Copyright 2004 Tacit Knowledge
 *  
 * 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.tacitknowledge.util.migration;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.easymock.MockControl;

import com.tacitknowledge.util.migration.jdbc.DistributedJdbcMigrationLauncher;
import com.tacitknowledge.util.migration.jdbc.DistributedJdbcMigrationLauncherFactory;
import com.tacitknowledge.util.migration.jdbc.JdbcMigrationLauncher;
import com.tacitknowledge.util.migration.jdbc.TestDataSourceMigrationContext;
import com.tacitknowledge.util.migration.jdbc.TestDistributedJdbcMigrationLauncherFactory;
import com.tacitknowledge.util.migration.tasks.normal.TestMigrationTask2;

/**
 * Test the distributed launcher factory
 * 
 * @author Mike Hardy (mike@tacitknowledge.com)
 */
public class DistributedJdbcMigrationLauncherFactoryTest extends MigrationListenerTestBase {
    /** Class logger */
    private static Log log = LogFactory.getLog(DistributedJdbcMigrationLauncherFactoryTest.class);

    /** The launcher we're testing */
    private DistributedJdbcMigrationLauncher launcher = null;

    /** A MigrationContext for us */
    private TestMigrationContext context = null;

    /**
     * constructor that takes a name
     *
     * @param name of the test to run
     */
    public DistributedJdbcMigrationLauncherFactoryTest(String name) {
        super(name);
    }

    /**
     * @see junit.framework.TestCase#setUp()
     */
    protected void setUp() throws Exception {
        super.setUp();

        log.debug("setting up " + this.getClass().getName());

        // Make sure we load our test launcher factory, which fakes out the data source context
        System.getProperties().setProperty("migration.factory",
                "com.tacitknowledge.util.migration.jdbc.TestJdbcMigrationLauncherFactory");
        DistributedJdbcMigrationLauncherFactory factory = new TestDistributedJdbcMigrationLauncherFactory();

        // Create the launcher (this does configure it as a side-effect)
        launcher = (DistributedJdbcMigrationLauncher) factory.createMigrationLauncher("orchestration");

        // Make sure we get notification of any migrations
        launcher.getMigrationProcess().addListener(this);

        context = new TestMigrationContext();
    }

    /**
     * @see junit.framework.TestCase#tearDown()
     */
    protected void tearDown() throws Exception {
        super.tearDown();
    }

    /**
     * For the given launchers, set all it's context's patch info stores as mocks
     * that report the given patch level.  This method is a helper to get this
     * test to pass the DisitributedMigrationProcess::validateControlledSystems() test.
     * @param launchers Collection of JDBCMigrationLaunchers
     * @param levelToReport the patch level the mock should report
     * @throws MigrationException 
     */
    protected void setReportedPatchLevel(Collection launchers, int levelToReport) throws MigrationException {
        for (Iterator launchersIterator = launchers.iterator(); launchersIterator.hasNext();) {
            JdbcMigrationLauncher launcher = (JdbcMigrationLauncher) launchersIterator.next();
            for (Iterator it = launcher.getContexts().keySet().iterator(); it.hasNext();) {
                MigrationContext ctx = (MigrationContext) it.next();
                MockControl patchInfoStoreControl = MockControl.createControl(PatchInfoStore.class);
                PatchInfoStore patchInfoStore = (PatchInfoStore) patchInfoStoreControl.getMock();
                patchInfoStore.getPatchLevel();
                patchInfoStoreControl.setReturnValue(levelToReport);
                patchInfoStoreControl.replay();
                launcher.getContexts().put(ctx, patchInfoStore);
            }
        }
    }

    /**
     * Test the configuration of the launchers versus a known property file
     */
    public void testDistributedLauncherConfiguration() {
        HashMap controlledSystems = ((DistributedMigrationProcess) launcher.getMigrationProcess())
                .getControlledSystems();
        assertEquals(3, controlledSystems.size());
    }

    /**
     * Make sure that the task loading works correctly
     * 
     * @exception MigrationException if anything goes wrong
     */
    public void testDistributedMigrationTaskLoading() throws MigrationException {
        DistributedMigrationProcess process = (DistributedMigrationProcess) launcher.getMigrationProcess();
        assertEquals(7, process.getMigrationTasks().size());
        assertEquals(7, process.getMigrationTasksWithLaunchers().size());
    }

    /**
     * Ensure that overlapping tasks even among sub-launchers are detected
     * 
     * @exception Exception if anything goes wrong
     */
    public void testDistributedMigrationTaskValidation() throws Exception {
        MigrationProcess process = launcher.getMigrationProcess();
        process.validateTasks(process.getMigrationTasks());

        // Make one of the sub-tasks conflict with a sub-task from another launcher
        TestMigrationTask2.setPatchLevelOverride(new Integer(3));
        try {
            process.validateTasks(process.getMigrationTasks());
            fail("We should have thrown an exception - " + "there were overlapping tasks among sub-launchers");
        } catch (MigrationException me) {
            // we expect this
        } finally {
            // make sure future tests work
            TestMigrationTask2.reset();
        }
    }

    /**
     * Ensure that read-only mode actually works
     * 
     * @exception Exception if anything goes wrong
     */
    public void testDistributedReadOnlyMode() throws Exception {
        int currentPatchLevel = 3;

        DistributedMigrationProcess process = (DistributedMigrationProcess) launcher.getMigrationProcess();
        process.validateTasks(process.getMigrationTasks());

        // need to mock the patch info stores to return the expected patch levels
        HashMap controlledSystems = process.getControlledSystems();
        setReportedPatchLevel(controlledSystems.values(), currentPatchLevel);

        // Make it readonly
        process.setReadOnly(true);

        // Now do the migrations, and make sure we get the right number of events
        try {
            process.doMigrations(currentPatchLevel, context);
            fail("There should have been an exception - unapplied patches + read-only don't work");
        } catch (MigrationException me) {
            // we expect this
            log.debug("got exception: " + me.getMessage());
        }

        currentPatchLevel = 8;
        // need to mock the patch info stores to return the expected patch levels        
        setReportedPatchLevel(controlledSystems.values(), currentPatchLevel);

        int patches = process.doMigrations(currentPatchLevel, context);
        assertEquals(0, patches);
        assertEquals(0, getMigrationStartedCount());
        assertEquals(0, getMigrationSuccessCount());
    }

    /**
     * Make sure we get notified of patch application
     * 
     * @exception Exception if anything goes wrong
     */
    public void testDistributedMigrationEvents() throws Exception {
        // There should be five listener on the main process
        //  1) the distributed launcher
        //  2) this test object
        //  3-5) the three sub-launchers
        assertEquals(5, launcher.getMigrationProcess().getListeners().size());

        // The sub-MigrationProcesses should have one listener each - the sub-launcher
        HashMap controlledSystems = ((DistributedMigrationProcess) launcher.getMigrationProcess())
                .getControlledSystems();

        for (Iterator controlledSystemIter = controlledSystems.keySet().iterator(); controlledSystemIter
                .hasNext();) {
            String controlledSystemName = (String) controlledSystemIter.next();
            JdbcMigrationLauncher subLauncher = (JdbcMigrationLauncher) controlledSystems.get(controlledSystemName);
            MigrationProcess subProcess = subLauncher.getMigrationProcess();
            assertEquals(1, subProcess.getListeners().size());
        }

        // Now do the migrations, and make sure we get the right number of events
        DistributedMigrationProcess process = (DistributedMigrationProcess) launcher.getMigrationProcess();
        int currentPatchlevel = 3;
        setReportedPatchLevel(process.getControlledSystems().values(), currentPatchlevel);
        int patches = process.doMigrations(currentPatchlevel, context);
        assertEquals(4, patches);
        assertEquals(4, getMigrationStartedCount());
        assertEquals(4, getMigrationSuccessCount());
    }

    /**
     * Make sure we the right patches go in the right spot
     * 
     * @exception Exception if anything goes wrong
     */
    public void testDistributedMigrationContextTargetting() throws Exception {
        int currentPatchLevel = 3;
        HashMap controlledSystems = ((DistributedMigrationProcess) launcher.getMigrationProcess())
                .getControlledSystems();

        // set the patch info store to report the current patch level
        setReportedPatchLevel(controlledSystems.values(), currentPatchLevel);
        // Now do the migrations, and make sure we get the right number of events
        MigrationProcess process = launcher.getMigrationProcess();
        process.doMigrations(currentPatchLevel, context);

        // The orders schema has four tasks that should go, make sure they did
        JdbcMigrationLauncher ordersLauncher = (JdbcMigrationLauncher) controlledSystems.get("orders");
        // FIXME need to test multiple contexts
        TestDataSourceMigrationContext ordersContext = (TestDataSourceMigrationContext) ordersLauncher.getContexts()
                .keySet().iterator().next();
        assertEquals("orders", ordersContext.getSystemName());
        assertTrue(ordersContext.hasExecuted("TestTask1"));
        assertTrue(ordersContext.hasExecuted("TestTask2"));
        assertTrue(ordersContext.hasExecuted("TestTask3"));
        assertTrue(ordersContext.hasExecuted("TestTask4"));

        // The core schema has three tasks that should not go, make sure they exist but did not go
        JdbcMigrationLauncher coreLauncher = (JdbcMigrationLauncher) controlledSystems.get("core");
        // FIXME need to test multiple contexts
        TestDataSourceMigrationContext coreContext = (TestDataSourceMigrationContext) coreLauncher.getContexts()
                .keySet().iterator().next();
        assertEquals(3, coreLauncher.getMigrationProcess().getMigrationTasks().size());
        assertEquals("core", coreContext.getSystemName());
        assertFalse(coreContext.hasExecuted("patch0001_first_patch"));
        assertFalse(coreContext.hasExecuted("patch0002_second_patch"));
        assertFalse(coreContext.hasExecuted("patch0003_third_patch"));
    }

    /**
     * Get the MigrationContext to use during testing
     * 
     * @return TestMigrationContext object
     */
    public TestMigrationContext getContext() {
        return context;
    }

    /**
     * Set the MigrationContext to use for testing
     * 
     * @param context a TestMigrationContext object to use for testing
     */
    public void setContext(TestMigrationContext context) {
        this.context = context;
    }

    /**
     * Get the launcher to use for testing
     * 
     * @return DistributedJdbcMigrationLauncher to use for testing
     */
    public DistributedJdbcMigrationLauncher getLauncher() {
        return launcher;
    }

    /**
     * Set the launcher to test
     * 
     * @param launcher the DistributedJdbcMigrationLauncher to test
     */
    public void setLauncher(DistributedJdbcMigrationLauncher launcher) {
        this.launcher = launcher;
    }
}