/* * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you 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 io.siddhi.extension.io.kafka.multidc; import io.siddhi.core.stream.input.source.SourceEventListener; import io.siddhi.extension.io.kafka.multidc.source.SourceSynchronizer; import io.siddhi.query.api.definition.StreamDefinition; import org.apache.log4j.Logger; import org.junit.Assert; import org.junit.Test; import org.testng.annotations.BeforeMethod; import java.util.ArrayList; import java.util.List; /** * Class implementing the Test cases for KafkaMultiDCSource Synchronize Test Case. */ public class KafkaMultiDCSourceSynchronizerTestCases { private static final Logger LOG = Logger.getLogger(KafkaMultiDCSourceSynchronizerTestCases.class); private static final String SOURCE_1 = "source:9000"; private static final String SOURCE_2 = "source2:9000"; private static String[] servers = {SOURCE_1, SOURCE_2}; private List<Object> eventsArrived = new ArrayList<>(); private SourceEventListener eventListener = new SourceEventListener() { @Override public StreamDefinition getStreamDefinition() { return null; } @Override public void onEvent(Object eventObject, Object[] transportProperties) { eventsArrived.add(eventObject); } @Override public void onEvent(Object o, String[] strings) { eventsArrived.add(o); } @Override public void onEvent(Object eventObject, Object[] transportProperties, String[] transportSyncProperties) { eventsArrived.add(eventObject); } @Override public void onEvent(Object o, String[] strings, String[] strings1) { eventsArrived.add(o); } }; private static String buildDummyEvent(String source, long seqNo) { StringBuilder builder = new StringBuilder(); builder.append(source).append(":").append(seqNo); return builder.toString(); } @BeforeMethod public void reset() { eventsArrived.clear(); } private boolean compareEventSequnce(List<Object> expectedEventSequence) { if (eventsArrived.size() != expectedEventSequence.size()) { LOG.info("Expected number of events and actual number of events are different. " + "Expected=" + expectedEventSequence.size() + ". Arrived=" + eventsArrived.size()); return false; } for (int i = 0; i < expectedEventSequence.size(); i++) { if (!eventsArrived.get(i).toString().equals(expectedEventSequence.get(i))) { LOG.warn("Event " + i + " in the expected and arrived events are different." + " Expected=" + expectedEventSequence.get(i).toString() + ", Arrived=" + eventsArrived.get(i).toString()); return false; } } return true; } private void sendEvent(SourceSynchronizer synchronizer, String source, long seqNo) { String[] dummyDynamicOptions = new String[2]; synchronizer.onEvent(source, seqNo, buildDummyEvent(source, seqNo), dummyDynamicOptions); } /* Source1: 0 - 1 - 2 Source2: 0 - 1 - 2 */ @Test public void testWithoutGaps1() { SourceSynchronizer synchronizer = new SourceSynchronizer(eventListener, servers, 1000, 1000); sendEvent(synchronizer, SOURCE_1, 0); sendEvent(synchronizer, SOURCE_2, 0); sendEvent(synchronizer, SOURCE_1, 1); sendEvent(synchronizer, SOURCE_2, 1); sendEvent(synchronizer, SOURCE_1, 2); sendEvent(synchronizer, SOURCE_2, 2); List<Object> expectedEvents = new ArrayList<>(); expectedEvents.add(buildDummyEvent(SOURCE_1, 0)); expectedEvents.add(buildDummyEvent(SOURCE_1, 1)); expectedEvents.add(buildDummyEvent(SOURCE_1, 2)); Assert.assertTrue(compareEventSequnce(expectedEvents)); } /* Source1: 0 1 2 Source2: 0 1 2 */ @Test public void testWithoutGaps2() { SourceSynchronizer synchronizer = new SourceSynchronizer(eventListener, servers, 1000, 1000); sendEvent(synchronizer, SOURCE_1, 0); sendEvent(synchronizer, SOURCE_1, 1); sendEvent(synchronizer, SOURCE_1, 2); sendEvent(synchronizer, SOURCE_2, 0); sendEvent(synchronizer, SOURCE_2, 1); sendEvent(synchronizer, SOURCE_2, 2); List<Object> expectedEvents = new ArrayList<>(); expectedEvents.add(buildDummyEvent(SOURCE_1, 0)); expectedEvents.add(buildDummyEvent(SOURCE_1, 1)); expectedEvents.add(buildDummyEvent(SOURCE_1, 2)); Assert.assertTrue(compareEventSequnce(expectedEvents)); } /* Source1: 0 - - - 1 2 Source2: 0 1 2 */ @Test public void testWithoutGaps3() { SourceSynchronizer synchronizer = new SourceSynchronizer(eventListener, servers, 1000, 1000); sendEvent(synchronizer, SOURCE_1, 0); sendEvent(synchronizer, SOURCE_2, 0); sendEvent(synchronizer, SOURCE_2, 1); sendEvent(synchronizer, SOURCE_2, 2); sendEvent(synchronizer, SOURCE_1, 1); sendEvent(synchronizer, SOURCE_1, 2); List<Object> expectedEvents = new ArrayList<>(); expectedEvents.add(buildDummyEvent(SOURCE_1, 0)); expectedEvents.add(buildDummyEvent(SOURCE_2, 1)); expectedEvents.add(buildDummyEvent(SOURCE_2, 2)); Assert.assertTrue(compareEventSequnce(expectedEvents)); } /* Source1: 0 <gap> 2 - - - Source2: 0 1 2 */ @Test public void testGapFiledByOtherSource() { SourceSynchronizer synchronizer = new SourceSynchronizer(eventListener, servers, 1000, 1000); sendEvent(synchronizer, SOURCE_1, 0); sendEvent(synchronizer, SOURCE_1, 2); sendEvent(synchronizer, SOURCE_2, 0); sendEvent(synchronizer, SOURCE_2, 1); sendEvent(synchronizer, SOURCE_2, 2); List<Object> expectedEvents = new ArrayList<>(); expectedEvents.add(buildDummyEvent(SOURCE_1, 0)); expectedEvents.add(buildDummyEvent(SOURCE_2, 1)); expectedEvents.add(buildDummyEvent(SOURCE_1, 2)); Assert.assertTrue(compareEventSequnce(expectedEvents)); } /* Source1: 0 <gap> 4 - - - - 5 Source2: 0 1 2 3 */ @Test public void testMultiMessageGapFiledByOtherSource() throws InterruptedException { SourceSynchronizer synchronizer = new SourceSynchronizer(eventListener, servers, 1000, 10 * 1000); sendEvent(synchronizer, SOURCE_1, 0); sendEvent(synchronizer, SOURCE_1, 4); sendEvent(synchronizer, SOURCE_2, 0); sendEvent(synchronizer, SOURCE_2, 1); sendEvent(synchronizer, SOURCE_2, 2); sendEvent(synchronizer, SOURCE_2, 3); sendEvent(synchronizer, SOURCE_1, 5); List<Object> expectedEvents = new ArrayList<>(); expectedEvents.add(buildDummyEvent(SOURCE_1, 0)); expectedEvents.add(buildDummyEvent(SOURCE_2, 1)); expectedEvents.add(buildDummyEvent(SOURCE_2, 2)); expectedEvents.add(buildDummyEvent(SOURCE_2, 3)); expectedEvents.add(buildDummyEvent(SOURCE_1, 4)); expectedEvents.add(buildDummyEvent(SOURCE_1, 5)); Assert.assertTrue(compareEventSequnce(expectedEvents)); } /* Source1: 0 <gap> 4 - - 5 Source2: 0 1 - 2 3 */ @Test public void testMultiMessageGapFiledByOtherSource1() throws InterruptedException { SourceSynchronizer synchronizer = new SourceSynchronizer(eventListener, servers, 1000, 10 * 1000); sendEvent(synchronizer, SOURCE_1, 0); sendEvent(synchronizer, SOURCE_1, 4); sendEvent(synchronizer, SOURCE_2, 0); sendEvent(synchronizer, SOURCE_2, 1); sendEvent(synchronizer, SOURCE_1, 5); sendEvent(synchronizer, SOURCE_2, 2); sendEvent(synchronizer, SOURCE_2, 3); List<Object> expectedEvents = new ArrayList<>(); expectedEvents.add(buildDummyEvent(SOURCE_1, 0)); expectedEvents.add(buildDummyEvent(SOURCE_2, 1)); expectedEvents.add(buildDummyEvent(SOURCE_2, 2)); expectedEvents.add(buildDummyEvent(SOURCE_2, 3)); expectedEvents.add(buildDummyEvent(SOURCE_1, 4)); expectedEvents.add(buildDummyEvent(SOURCE_1, 5)); Assert.assertTrue(compareEventSequnce(expectedEvents)); } /* Source1: <gap> 3 - - 4 Source2: 0 1 - 2 3 */ @Test public void testMultiMessageGapFiledByOtherSource2() throws InterruptedException { SourceSynchronizer synchronizer = new SourceSynchronizer(eventListener, servers, 1000, 10 * 1000); sendEvent(synchronizer, SOURCE_1, 3); sendEvent(synchronizer, SOURCE_2, 0); sendEvent(synchronizer, SOURCE_2, 1); sendEvent(synchronizer, SOURCE_1, 4); sendEvent(synchronizer, SOURCE_2, 2); sendEvent(synchronizer, SOURCE_2, 3); List<Object> expectedEvents = new ArrayList<>(); expectedEvents.add(buildDummyEvent(SOURCE_2, 0)); expectedEvents.add(buildDummyEvent(SOURCE_2, 1)); expectedEvents.add(buildDummyEvent(SOURCE_2, 2)); expectedEvents.add(buildDummyEvent(SOURCE_1, 3)); expectedEvents.add(buildDummyEvent(SOURCE_1, 4)); Assert.assertTrue(compareEventSequnce(expectedEvents)); } /* Source1: <gap> 3 4 Source2: 0 1 2 <gap> 5 */ @Test public void testMultiMessageGapFiledByOtherSource3() throws InterruptedException { SourceSynchronizer synchronizer = new SourceSynchronizer(eventListener, servers, 1000, 10 * 1000); sendEvent(synchronizer, SOURCE_1, 3); sendEvent(synchronizer, SOURCE_1, 4); sendEvent(synchronizer, SOURCE_2, 0); sendEvent(synchronizer, SOURCE_2, 1); sendEvent(synchronizer, SOURCE_2, 2); sendEvent(synchronizer, SOURCE_2, 5); List<Object> expectedEvents = new ArrayList<>(); expectedEvents.add(buildDummyEvent(SOURCE_2, 0)); expectedEvents.add(buildDummyEvent(SOURCE_2, 1)); expectedEvents.add(buildDummyEvent(SOURCE_2, 2)); expectedEvents.add(buildDummyEvent(SOURCE_1, 3)); expectedEvents.add(buildDummyEvent(SOURCE_1, 4)); expectedEvents.add(buildDummyEvent(SOURCE_2, 5)); Assert.assertTrue(compareEventSequnce(expectedEvents)); } /* Source1: 0 1 <gap> 4 - 5 Source2: 0 1 - - - 6 */ @Test public void testUnrecoverableGap() throws InterruptedException { SourceSynchronizer synchronizer = new SourceSynchronizer(eventListener, servers, 1000, 10 * 1000); sendEvent(synchronizer, SOURCE_1, 0); sendEvent(synchronizer, SOURCE_1, 1); sendEvent(synchronizer, SOURCE_1, 4); sendEvent(synchronizer, SOURCE_2, 0); sendEvent(synchronizer, SOURCE_2, 1); sendEvent(synchronizer, SOURCE_2, 6); sendEvent(synchronizer, SOURCE_1, 5); List<Object> expectedEvents = new ArrayList<>(); expectedEvents.add(buildDummyEvent(SOURCE_1, 0)); expectedEvents.add(buildDummyEvent(SOURCE_1, 1)); expectedEvents.add(buildDummyEvent(SOURCE_1, 4)); expectedEvents.add(buildDummyEvent(SOURCE_1, 5)); expectedEvents.add(buildDummyEvent(SOURCE_2, 6)); Assert.assertTrue(compareEventSequnce(expectedEvents)); } /* Source1: 0 1 <gap> 4 - 5 <gap> 8 9 Source2: 0 1 <gap> - 8 <gap> */ @Test public void testTwoUnrecoverableGaps() throws InterruptedException { SourceSynchronizer synchronizer = new SourceSynchronizer(eventListener, servers, 1000, 10 * 1000); sendEvent(synchronizer, SOURCE_1, 0); sendEvent(synchronizer, SOURCE_1, 1); sendEvent(synchronizer, SOURCE_1, 4); sendEvent(synchronizer, SOURCE_2, 0); sendEvent(synchronizer, SOURCE_2, 1); sendEvent(synchronizer, SOURCE_2, 8); sendEvent(synchronizer, SOURCE_1, 5); sendEvent(synchronizer, SOURCE_1, 8); sendEvent(synchronizer, SOURCE_1, 9); List<Object> expectedEvents = new ArrayList<>(); expectedEvents.add(buildDummyEvent(SOURCE_1, 0)); expectedEvents.add(buildDummyEvent(SOURCE_1, 1)); expectedEvents.add(buildDummyEvent(SOURCE_1, 4)); expectedEvents.add(buildDummyEvent(SOURCE_1, 5)); expectedEvents.add(buildDummyEvent(SOURCE_1, 8)); expectedEvents.add(buildDummyEvent(SOURCE_1, 9)); Assert.assertTrue(compareEventSequnce(expectedEvents)); } /* Source1: 0 1 <gap> 4 - 5 <gap> 8 9 - - 12 Source2: 0 1 <gap> - 8 <gap> - - 10 11 */ @Test public void testMultipleoUnrecoverableGaps() throws InterruptedException { SourceSynchronizer synchronizer = new SourceSynchronizer(eventListener, servers, 1000, 10 * 1000); sendEvent(synchronizer, SOURCE_1, 0); sendEvent(synchronizer, SOURCE_1, 1); sendEvent(synchronizer, SOURCE_1, 4); sendEvent(synchronizer, SOURCE_2, 0); sendEvent(synchronizer, SOURCE_2, 1); sendEvent(synchronizer, SOURCE_2, 8); sendEvent(synchronizer, SOURCE_1, 5); sendEvent(synchronizer, SOURCE_1, 8); sendEvent(synchronizer, SOURCE_1, 9); sendEvent(synchronizer, SOURCE_2, 10); sendEvent(synchronizer, SOURCE_2, 11); sendEvent(synchronizer, SOURCE_1, 12); List<Object> expectedEvents = new ArrayList<>(); expectedEvents.add(buildDummyEvent(SOURCE_1, 0)); expectedEvents.add(buildDummyEvent(SOURCE_1, 1)); expectedEvents.add(buildDummyEvent(SOURCE_1, 4)); expectedEvents.add(buildDummyEvent(SOURCE_1, 5)); expectedEvents.add(buildDummyEvent(SOURCE_1, 8)); expectedEvents.add(buildDummyEvent(SOURCE_1, 9)); expectedEvents.add(buildDummyEvent(SOURCE_2, 10)); expectedEvents.add(buildDummyEvent(SOURCE_2, 11)); expectedEvents.add(buildDummyEvent(SOURCE_1, 12)); Assert.assertTrue(compareEventSequnce(expectedEvents)); } /* Source1: 0 1 <gap> 4 - 5 <gap> 8 9 Source2: 0 1 <gap> - 8 <gap> 11 12 */ @Test public void testTwoUnrecoverableGapFlushedWithTimer() throws InterruptedException { SourceSynchronizer synchronizer = new SourceSynchronizer(eventListener, servers, 1000, 10 * 1000); sendEvent(synchronizer, SOURCE_1, 0); sendEvent(synchronizer, SOURCE_1, 1); sendEvent(synchronizer, SOURCE_1, 4); sendEvent(synchronizer, SOURCE_2, 0); sendEvent(synchronizer, SOURCE_2, 1); sendEvent(synchronizer, SOURCE_2, 8); sendEvent(synchronizer, SOURCE_1, 5); sendEvent(synchronizer, SOURCE_1, 8); sendEvent(synchronizer, SOURCE_1, 9); sendEvent(synchronizer, SOURCE_2, 11); sendEvent(synchronizer, SOURCE_2, 12); // Since no events are received from source1, it will wait for a tolerance period expecting the events to come. // When the time expires it will forcefully flush the events. Thread.sleep(15 * 1000); List<Object> expectedEvents = new ArrayList<>(); expectedEvents.add(buildDummyEvent(SOURCE_1, 0)); expectedEvents.add(buildDummyEvent(SOURCE_1, 1)); expectedEvents.add(buildDummyEvent(SOURCE_1, 4)); expectedEvents.add(buildDummyEvent(SOURCE_1, 5)); expectedEvents.add(buildDummyEvent(SOURCE_1, 8)); expectedEvents.add(buildDummyEvent(SOURCE_1, 9)); expectedEvents.add(buildDummyEvent(SOURCE_2, 11)); expectedEvents.add(buildDummyEvent(SOURCE_2, 12)); Assert.assertTrue(compareEventSequnce(expectedEvents)); } }