/* # Licensed Materials - Property of IBM # Copyright IBM Corp. 2015 */ package com.ibm.streamsx.topology.test.state; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; import java.util.Date; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.logging.Logger; import org.junit.Before; import org.junit.Test; import com.ibm.streams.operator.logging.LogLevel; import com.ibm.streamsx.topology.TStream; import com.ibm.streamsx.topology.Topology; import com.ibm.streamsx.topology.context.StreamsContext; import com.ibm.streamsx.topology.function.Predicate; import com.ibm.streamsx.topology.streams.BeaconStreams; import com.ibm.streamsx.topology.streams.StringStreams; import com.ibm.streamsx.topology.test.TestTopology; import com.ibm.streamsx.topology.tester.Condition; public class CheckpointTest extends TestTopology { @Before public void checkIsDistributed() { assumeTrue(SC_OK); assumeTrue(getTesterType() == StreamsContext.Type.DISTRIBUTED_TESTER); } @Test public void testPeriodicCheckpoint() throws Exception { testPeriodicCheckpoint(2, 45); } private void testPeriodicCheckpoint(int period, final int crashAfterCount) throws Exception { assumeTrue(SC_OK); assumeTrue(getTesterType() == StreamsContext.Type.DISTRIBUTED_TESTER); final Topology topology = new Topology(); topology.checkpointPeriod(period, TimeUnit.SECONDS); TStream<Long> lb = BeaconStreams.longBeacon(topology, 500); TStream<Long> b = lb.throttle(100, TimeUnit.MILLISECONDS); lb.colocate(b); b = b.filter(new CrashAfter<Long>(crashAfterCount)); lb.colocate(b); TStream<String> sb = StringStreams.toString(b.isolate()); Condition<Long> atLeast = topology.getTester().atLeastTupleCount(sb, 230); Condition<List<String>> output = topology.getTester().stringContents(sb); complete(topology.getTester(), atLeast, 90, TimeUnit.SECONDS); System.err.println("RESULT: " + output.getResult()); Long starting = null; long last = -1; int count = 0; for (String ls : output.getResult()) { long l = Long.valueOf(ls); count++; if (starting == null) { assertEquals(0L, l); starting = last = l; continue; } if (l > last) { if (l == last+1) { assertTrue("no crash @" + l, count < crashAfterCount+1); last = l; continue; } } // Has crashed and restarted, assertEquals("crash count @" + l, crashAfterCount+1, count); // Assert that there was a successful // checkpoint that increased the value assertTrue("after ckpt @" + l, l > starting); starting = last = l; count = 1; } } /** * Crash (exit the process) after N tuples. */ public static class CrashAfter<T> implements Predicate<T> { private static final long serialVersionUID = 1L; private final int crashAt; private transient int counter; public CrashAfter(int crashAt) { this.crashAt = crashAt; } @Override public boolean test(T tuple) { System.err.println("CrashAt:" + counter + " -- " + new Date()); if (counter++ == crashAt) { Logger.getAnonymousLogger().log(LogLevel.INFO, "Intentional crash!"); System.err.println("Intentional crash!"); System.exit(1); } return true; } } }