// This software is released into the Public Domain. See copying.txt for details. package org.openstreetmap.osmosis.apidb.v0_6.impl; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Collections; import java.util.Date; import org.junit.Assert; import org.junit.Test; import org.openstreetmap.osmosis.core.OsmosisRuntimeException; /** * Tests for the Replicator class. */ public class ReplicatorTest { private Date buildDate(String rawDate) { try { return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(rawDate); } catch (ParseException e) { throw new OsmosisRuntimeException("The date could not be parsed.", e); } } /** * Tests replication behaviour during initialisation. Initialisation occurs the first time * replication is run. */ @Test public void testInitialization() { Replicator replicator; MockReplicationSource source; MockReplicationDestination destination; MockTransactionSnapshotLoader snapshotLoader; MockSystemTimeLoader timeLoader; ReplicationState state; // Build the mocks. source = new MockReplicationSource(); destination = new MockReplicationDestination(); snapshotLoader = new MockTransactionSnapshotLoader(); timeLoader = new MockSystemTimeLoader(); // Instantiate the new replicator. replicator = new Replicator(source, destination, snapshotLoader, timeLoader, 1, 0, 0); // Provide initialisation data. timeLoader.getTimes().add(buildDate("2009-10-11 12:13:14")); timeLoader.getTimes().add(buildDate("2009-10-11 12:13:14")); snapshotLoader.getSnapshots().add(new TransactionSnapshot("100:200:110,112")); // Launch the replication process. replicator.replicate(); // Verify the final state. state = destination.getCurrentState(); Assert.assertEquals("Incorrect final state.", new ReplicationState( 200, 200, Arrays.asList(new Long[]{110L, 112L}), Arrays.asList(new Long[]{}), buildDate("2009-10-11 12:13:14"), 0), state); } /** * Tests replication behaviour when no replication is required. */ @Test public void testNoAction() { Replicator replicator; MockReplicationSource source; MockReplicationDestination destination; MockTransactionSnapshotLoader snapshotLoader; MockSystemTimeLoader timeLoader; ReplicationState initialState; ReplicationState finalState; // Build initial replication state. initialState = new ReplicationState( 200, 200, Arrays.asList(new Long[]{110L, 112L}), Arrays.asList(new Long[]{}), buildDate("2009-10-11 12:13:14"), 0); // Build the mocks. source = new MockReplicationSource(); destination = new MockReplicationDestination(initialState); snapshotLoader = new MockTransactionSnapshotLoader(); timeLoader = new MockSystemTimeLoader(); // Instantiate the new replicator. replicator = new Replicator(source, destination, snapshotLoader, timeLoader, 1, 0, 0); // We want the snapshot loader to return the same snapshot to simulate no database changes. snapshotLoader.getSnapshots().add(new TransactionSnapshot("100:200:110,112")); // But we want the clock time to have progressed. timeLoader.getTimes().add(buildDate("2009-10-11 12:13:15")); timeLoader.getTimes().add(buildDate("2009-10-11 12:13:15")); timeLoader.getTimes().add(buildDate("2009-10-11 12:13:15")); // Launch the replication process. replicator.replicate(); // Verify that the final state does not match the initial state, but that the only // difference is the time and increment sequence number. finalState = destination.getCurrentState(); Assert.assertFalse("Final state should not match initial state.", finalState.equals(initialState)); finalState.setTimestamp(initialState.getTimestamp()); finalState.setSequenceNumber(finalState.getSequenceNumber() - 1); Assert.assertTrue("Final state should match initial state after updating timestamp.", finalState.equals(initialState)); // Verify that no changes were replicated. Assert.assertTrue("No changes should have been replicated.", source.getPredicatesList().size() == 0); } /** * Tests replication behaviour when a simple replication interval is required. */ @Test public void testSimpleIncrement() { Replicator replicator; MockReplicationSource source; MockReplicationDestination destination; MockTransactionSnapshotLoader snapshotLoader; MockSystemTimeLoader timeLoader; ReplicationState state; ReplicationQueryPredicates predicates; // Build initial replication state. state = new ReplicationState( 200, 200, Arrays.asList(new Long[]{}), Arrays.asList(new Long[]{}), buildDate("2009-10-11 12:13:14"), 0); // Build the mocks. source = new MockReplicationSource(); destination = new MockReplicationDestination(state); snapshotLoader = new MockTransactionSnapshotLoader(); timeLoader = new MockSystemTimeLoader(); // Instantiate the new replicator. replicator = new Replicator(source, destination, snapshotLoader, timeLoader, 1, 0, 0); // Set the snapshot loader to return a snapshot with higher xMax. snapshotLoader.getSnapshots().add(new TransactionSnapshot("100:220")); // We also want the clock time to have progressed. timeLoader.getTimes().add(buildDate("2009-10-11 12:13:15")); timeLoader.getTimes().add(buildDate("2009-10-11 12:13:15")); // Launch the replication process. replicator.replicate(); // Verify that the final state is correct. state = destination.getCurrentState(); Assert.assertEquals("Incorrect final state.", new ReplicationState( 220, 220, Arrays.asList(new Long[]{}), Arrays.asList(new Long[]{}), buildDate("2009-10-11 12:13:15"), 1), state); // Verify that the correct changes were replicated. Assert.assertTrue("A single interval should have been replicated.", source.getPredicatesList().size() == 1); predicates = source.getPredicatesList().get(0); Assert.assertEquals("Incorrect active list.", Collections.emptyList(), predicates.getActiveList()); Assert.assertEquals("Incorrect ready list.", Collections.emptyList(), predicates.getReadyList()); Assert.assertEquals("Incorrect bottom transaction id.", 200, predicates.getBottomTransactionId()); Assert.assertEquals("Incorrect top transaction id.", 220, predicates.getTopTransactionId()); } /** * Tests replication behaviour when active list manipulation is required. */ @Test public void testInFlightTxnIncrement() { Replicator replicator; MockReplicationSource source; MockReplicationDestination destination; MockTransactionSnapshotLoader snapshotLoader; MockSystemTimeLoader timeLoader; ReplicationState state; ReplicationQueryPredicates predicates; // Build initial replication state. state = new ReplicationState( 200, 200, Arrays.asList(new Long[]{180L, 185L}), Arrays.asList(new Long[]{}), buildDate("2009-10-11 12:13:14"), 0); // Build the mocks. source = new MockReplicationSource(); destination = new MockReplicationDestination(state); snapshotLoader = new MockTransactionSnapshotLoader(); timeLoader = new MockSystemTimeLoader(); // Instantiate the new replicator. replicator = new Replicator(source, destination, snapshotLoader, timeLoader, 1, 0, 0); // Set the snapshot loader to return a snapshot with higher xMax. snapshotLoader.getSnapshots().add(new TransactionSnapshot("100:220:185")); // We also want the clock time to have progressed. timeLoader.getTimes().add(buildDate("2009-10-11 12:13:15")); timeLoader.getTimes().add(buildDate("2009-10-11 12:13:15")); // Launch the replication process. replicator.replicate(); // Verify that the final state is correct. state = destination.getCurrentState(); Assert.assertEquals("Incorrect final state.", new ReplicationState( 220, 220, Arrays.asList(new Long[]{185L}), Arrays.asList(new Long[]{}), buildDate("2009-10-11 12:13:15"), 1), state); // Verify that the correct changes were replicated. Assert.assertTrue("A single interval should have been replicated.", source.getPredicatesList().size() == 1); predicates = source.getPredicatesList().get(0); Assert.assertEquals("Incorrect active list.", Arrays.asList(new Long[]{185L}), predicates.getActiveList()); Assert.assertEquals("Incorrect ready list.", Arrays.asList(new Long[]{180L}), predicates.getReadyList()); Assert.assertEquals("Incorrect bottom transaction id.", 200, predicates.getBottomTransactionId()); Assert.assertEquals("Incorrect top transaction id.", 220, predicates.getTopTransactionId()); } /** * Tests replication behaviour when catching up from outage and some active transactions are overtaken. */ @Test public void testOutageCatchupWithActiveTxns() { Replicator replicator; MockReplicationSource source; MockReplicationDestination destination; MockTransactionSnapshotLoader snapshotLoader; MockSystemTimeLoader timeLoader; ReplicationState state; ReplicationQueryPredicates predicates; // Build initial replication state. state = new ReplicationState( 5, 5, Arrays.asList(new Long[]{24000L, 26000L}), Arrays.asList(new Long[]{}), buildDate("2009-10-11 12:13:14"), 0); // Build the mocks. source = new MockReplicationSource(); destination = new MockReplicationDestination(state); snapshotLoader = new MockTransactionSnapshotLoader(); timeLoader = new MockSystemTimeLoader(); // Instantiate the new replicator. replicator = new Replicator(source, destination, snapshotLoader, timeLoader, 1, 0, 0); // Set the snapshot loader to return a snapshot with higher xMax. snapshotLoader.getSnapshots().add(new TransactionSnapshot("20000:30000:26000")); // We also want the clock time to have progressed. timeLoader.getTimes().add(buildDate("2009-10-11 12:13:15")); timeLoader.getTimes().add(buildDate("2009-10-11 12:13:15")); // Launch the replication process. replicator.replicate(); // Verify that the final state is correct. state = destination.getCurrentState(); Assert.assertEquals("Incorrect final state.", new ReplicationState( 30000, 25005, Arrays.asList(new Long[]{26000L}), Arrays.asList(new Long[]{}), buildDate("2009-10-11 12:13:14"), 1), state); // Verify that the correct changes were replicated. Assert.assertTrue("A single interval should have been replicated.", source.getPredicatesList().size() == 1); predicates = source.getPredicatesList().get(0); Assert.assertEquals("Incorrect active list.", Arrays.asList(new Long[]{26000L}), predicates.getActiveList()); Assert.assertEquals("Incorrect ready list.", Arrays.asList(new Long[]{}), predicates.getReadyList()); Assert.assertEquals("Incorrect bottom transaction id.", 5, predicates.getBottomTransactionId()); Assert.assertEquals("Incorrect top transaction id.", 25005, predicates.getTopTransactionId()); } }