package com.linkedin.databus.client.registration; /* * * Copyright 2013 LinkedIn Corp. All rights reserved * * 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. * */ import com.linkedin.databus.client.DatabusHttpClientImpl; import com.linkedin.databus.client.DatabusHttpClientImpl.RuntimeConfigBuilder; import com.linkedin.databus.client.SingleSourceSCN; import com.linkedin.databus.client.consumer.AbstractDatabusCombinedConsumer; import com.linkedin.databus.client.pub.ConsumerCallbackResult; import com.linkedin.databus.client.pub.DatabusClientException; import com.linkedin.databus.client.pub.DatabusCombinedConsumer; import com.linkedin.databus.client.pub.DatabusRegistration; import com.linkedin.databus.client.pub.DatabusRegistration.RegistrationState; import com.linkedin.databus.client.pub.DbusEventDecoder; import com.linkedin.databus.client.pub.SCN; import com.linkedin.databus.client.pub.ServerInfo; import com.linkedin.databus.client.pub.ServerInfo.ServerInfoBuilder; import com.linkedin.databus.core.DatabusComponentStatus.Status; import com.linkedin.databus.core.DbusEvent; import com.linkedin.databus.core.DbusEventBuffer; import com.linkedin.databus.core.DbusEventBuffer.AllocationPolicy; import com.linkedin.databus.core.DbusEventV2Factory; import com.linkedin.databus.core.DbusEventKey; import com.linkedin.databus.core.util.InvalidConfigException; import com.linkedin.databus2.schemas.utils.SchemaHelper; import com.linkedin.databus2.test.TestUtil; import com.linkedin.databus2.test.container.SimpleObjectCaptureHandler; import com.linkedin.databus2.test.container.SimpleTestServerConnection; import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import org.apache.avro.Schema; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.group.ChannelGroup; import org.jboss.netty.channel.group.DefaultChannelGroup; import org.jboss.netty.handler.codec.http.HttpServerCodec; import org.jboss.netty.handler.logging.LoggingHandler; import org.jboss.netty.logging.InternalLogLevel; import org.jboss.netty.logging.InternalLoggerFactory; import org.jboss.netty.logging.Log4JLoggerFactory; import org.jboss.netty.util.HashedWheelTimer; import org.jboss.netty.util.Timer; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import static org.testng.AssertJUnit.assertEquals; public class TestDatabusV2RegistrationImpl { public static final Logger LOG = Logger.getLogger("TestDatabusV2RegistrationImpl"); static final Schema SOURCE1_SCHEMA = Schema.parse("{\"name\":\"source1\",\"type\":\"record\",\"fields\":[{\"name\":\"s\",\"type\":\"string\"}]}"); static final String SOURCE1_SCHEMA_STR = SOURCE1_SCHEMA.toString(); static final byte[] SOURCE1_SCHEMAID = SchemaHelper.getSchemaId(SOURCE1_SCHEMA_STR); static final ExecutorService BOSS_POOL = Executors.newCachedThreadPool(); static final ExecutorService IO_POOL = Executors.newCachedThreadPool(); static final int[] RELAY_PORT = {14467, 14468, 14469}; static final int CLIENT_PORT = 15500; static final Timer NETWORK_TIMER = new HashedWheelTimer(10, TimeUnit.MILLISECONDS); static final ChannelGroup TEST_CHANNELS_GROUP = new DefaultChannelGroup(); static final long DEFAULT_READ_TIMEOUT_MS = 10000; static final long DEFAULT_WRITE_TIMEOUT_MS = 10000; static final String SOURCE1_NAME = "test.event.source1"; static SimpleTestServerConnection[] _dummyServer = new SimpleTestServerConnection[RELAY_PORT.length]; static DbusEventBuffer.StaticConfig _bufCfg; static DatabusHttpClientImpl.StaticConfig _stdClientCfg; static DatabusHttpClientImpl.Config _stdClientCfgBuilder; @Test public void testOneConsumerRegistrationOps() throws Exception { DatabusHttpClientImpl client = null; try { DatabusHttpClientImpl.Config clientConfig = new DatabusHttpClientImpl.Config(); clientConfig.getContainer().getJmx().setRmiEnabled(false); clientConfig.getContainer().setHttpPort(12003); client = new DatabusHttpClientImpl(clientConfig); registerRelay(1, "relay1", new InetSocketAddress("localhost", 8888), "S1,S2", client); registerRelay(2, "relay2", new InetSocketAddress("localhost", 7777), "S1,S3", client); registerRelay(3, "relay1.1", new InetSocketAddress("localhost", 8887), "S1,S2", client); registerRelay(4, "relay3", new InetSocketAddress("localhost", 6666), "S3,S4,S5", client); TestConsumer listener1 = new TestConsumer(); DatabusRegistration reg = client.register(listener1, "S1", "S3"); assertEquals("Registered State", RegistrationState.REGISTERED, reg.getState()); assertEquals("Component Name" , "Status_TestConsumer_a62d57a7", reg.getStatus().getComponentName()); assertEquals("Component Status", Status.INITIALIZING, reg.getStatus().getStatus()); // Start boolean started = reg.start(); assertEquals("Started", true, started); assertEquals("Registered State", RegistrationState.STARTED, reg.getState()); assertEquals("Component Status", Status.RUNNING, reg.getStatus().getStatus()); //Start again started = reg.start(); assertEquals("Started", false, started); assertEquals("Registered State", RegistrationState.STARTED, reg.getState()); // Pause reg.pause(); assertEquals("Registered State", RegistrationState.PAUSED, reg.getState()); assertEquals("Component Status", Status.PAUSED, reg.getStatus().getStatus()); // resume reg.resume(); assertEquals("Registered State", RegistrationState.RESUMED, reg.getState()); assertEquals("Component Status", Status.RUNNING, reg.getStatus().getStatus()); // suspend due to error reg.suspendOnError(new Exception("dummy")); assertEquals("Registered State", RegistrationState.SUSPENDED_ON_ERROR, reg.getState()); assertEquals("Component Status", Status.SUSPENDED_ON_ERROR, reg.getStatus().getStatus()); // SHutdown reg.shutdown(); assertEquals("Registered State", RegistrationState.SHUTDOWN, reg.getState()); assertEquals("Component Status", Status.SHUTDOWN, reg.getStatus().getStatus()); // Duplicate regId DatabusRegistration reg2 = client.register(listener1, "S1", "S3"); boolean isException = false; try { reg2.withRegId(reg.getRegistrationId()); } catch (DatabusClientException ex) { isException = true; } assertEquals("Exception expected", true, isException); reg2.deregister(); reg.deregister(); } finally { if ( null != client) client.shutdown(); } } @Test public void testErrorRegistration() throws Exception { DatabusHttpClientImpl client = null; try { DatabusHttpClientImpl.Config clientConfig = new DatabusHttpClientImpl.Config(); clientConfig.getContainer().getJmx().setRmiEnabled(false); clientConfig.getContainer().setHttpPort(12003); client = new DatabusHttpClientImpl(clientConfig); registerRelay(1, "relay1", new InetSocketAddress("localhost", 8888), "S1,S2", client); registerRelay(2, "relay2", new InetSocketAddress("localhost", 7777), "S1,S3", client); registerRelay(3, "relay1.1", new InetSocketAddress("localhost", 8887), "S1,S2", client); registerRelay(4, "relay3", new InetSocketAddress("localhost", 6666), "S3,S4,S5", client); TestConsumer listener1 = new TestConsumer(); DatabusRegistration reg = client.register(listener1, "S6", "S2"); assertEquals("Registered State", RegistrationState.REGISTERED, reg.getState()); assertEquals("Component Name" , "Status_TestConsumer_6fdc9d8d", reg.getStatus().getComponentName()); assertEquals("Component Status", Status.INITIALIZING, reg.getStatus().getStatus()); // Start boolean started = false; boolean gotException = false; try { started = reg.start(); } catch (DatabusClientException ex) { gotException = true; } assertEquals("gotException", true, gotException); assertEquals("Registered State", RegistrationState.REGISTERED, reg.getState()); assertEquals("Component Status", Status.INITIALIZING, reg.getStatus().getStatus()); gotException = false; try { reg = client.register((AbstractDatabusCombinedConsumer)null, "S6", "S2"); } catch (DatabusClientException ex) { gotException = true; } assertEquals("gotException", true, gotException); gotException = false; try { reg = client.register(listener1, null); } catch (DatabusClientException ex) { gotException = true; } assertEquals("gotException", true, gotException); if ( reg != null) reg.deregister(); } finally { if ( null != client) client.shutdown(); } } @Test public void testMultiConsumerRegistrationOps() throws Exception { DatabusHttpClientImpl client = null; try { DatabusHttpClientImpl.Config clientConfig = new DatabusHttpClientImpl.Config(); clientConfig.getContainer().getJmx().setRmiEnabled(false); clientConfig.getContainer().setHttpPort(12003); client = new DatabusHttpClientImpl(clientConfig); registerRelay(1, "relay1", new InetSocketAddress("localhost", 8888), "S1,S2", client); registerRelay(2, "relay2", new InetSocketAddress("localhost", 7777), "S1,S3", client); registerRelay(3, "relay1.1", new InetSocketAddress("localhost", 8887), "S1,S2", client); registerRelay(4, "relay3", new InetSocketAddress("localhost", 6666), "S3,S4,S5", client); TestConsumer listener1 = new TestConsumer(); TestConsumer listener2 = new TestConsumer(); List<DatabusCombinedConsumer> listeners = new ArrayList<DatabusCombinedConsumer>(); listeners.add(listener1); listeners.add(listener2); DatabusRegistration reg = client.register(listeners, "S1", "S2"); assertEquals("Registered State", RegistrationState.REGISTERED, reg.getState()); assertEquals("Component Name" , "Status_TestConsumer_922c5e28", reg.getStatus().getComponentName()); assertEquals("Component Status", Status.INITIALIZING, reg.getStatus().getStatus()); // Start boolean started = reg.start(); assertEquals("Started", true, started); assertEquals("Registered State", RegistrationState.STARTED, reg.getState()); assertEquals("Component Status", Status.RUNNING, reg.getStatus().getStatus()); //Start again started = reg.start(); assertEquals("Started", false, started); assertEquals("Registered State", RegistrationState.STARTED, reg.getState()); // Pause reg.pause(); assertEquals("Registered State", RegistrationState.PAUSED, reg.getState()); assertEquals("Component Status", Status.PAUSED, reg.getStatus().getStatus()); // resume reg.resume(); assertEquals("Registered State", RegistrationState.RESUMED, reg.getState()); assertEquals("Component Status", Status.RUNNING, reg.getStatus().getStatus()); // suspend due to error reg.suspendOnError(new Exception("dummy")); assertEquals("Registered State", RegistrationState.SUSPENDED_ON_ERROR, reg.getState()); assertEquals("Component Status", Status.SUSPENDED_ON_ERROR, reg.getStatus().getStatus()); // SHutdown reg.shutdown(); assertEquals("Registered State", RegistrationState.SHUTDOWN, reg.getState()); assertEquals("Component Status", Status.SHUTDOWN, reg.getStatus().getStatus()); reg.deregister(); } finally { if ( null != client ) client.shutdown(); } } @BeforeClass public void setUpClass() throws InvalidConfigException { //setup logging TestUtil.setupLogging(true, null, Level.INFO); InternalLoggerFactory.setDefaultFactory(new Log4JLoggerFactory()); //initialize relays for (int relayN = 0; relayN < RELAY_PORT.length; ++relayN) { _dummyServer[relayN] = new SimpleTestServerConnection(new DbusEventV2Factory().getByteOrder(), SimpleTestServerConnection.ServerType.NIO); _dummyServer[relayN].setPipelineFactory(new ChannelPipelineFactory() { @Override public ChannelPipeline getPipeline() throws Exception { return Channels.pipeline(new LoggingHandler(InternalLogLevel.DEBUG), new HttpServerCodec(), new LoggingHandler(InternalLogLevel.DEBUG), new SimpleObjectCaptureHandler()); } }); _dummyServer[relayN].start(RELAY_PORT[relayN]); } //create standard client config DatabusHttpClientImpl.Config clientCfgBuilder = new DatabusHttpClientImpl.Config(); clientCfgBuilder.getContainer().setHttpPort(CLIENT_PORT); clientCfgBuilder.getContainer().getJmx().setRmiEnabled(false); clientCfgBuilder.getContainer().setReadTimeoutMs(10000000); clientCfgBuilder.getConnectionDefaults().getPullerRetries().setInitSleep(10); clientCfgBuilder.getRuntime().getBootstrap().setEnabled(false); clientCfgBuilder.getCheckpointPersistence().setClearBeforeUse(true); for (int i = 0; i < RELAY_PORT.length; ++i) { clientCfgBuilder.getRuntime().getRelay(Integer.toString(i)).setHost("localhost"); clientCfgBuilder.getRuntime().getRelay(Integer.toString(i)).setPort(RELAY_PORT[i]); clientCfgBuilder.getRuntime().getRelay(Integer.toString(i)).setSources(SOURCE1_NAME); } _stdClientCfgBuilder = clientCfgBuilder; _stdClientCfg = clientCfgBuilder.build(); //create standard relay buffer config DbusEventBuffer.Config bufCfgBuilder = new DbusEventBuffer.Config(); bufCfgBuilder.setAllocationPolicy(AllocationPolicy.HEAP_MEMORY.toString()); bufCfgBuilder.setMaxSize(100000); bufCfgBuilder.setScnIndexSize(128); bufCfgBuilder.setAverageEventSize(1); _bufCfg = bufCfgBuilder.build(); } private ServerInfo registerRelay(int id, String name, InetSocketAddress addr, String sources, DatabusHttpClientImpl client) throws InvalidConfigException { RuntimeConfigBuilder rtConfigBuilder = (RuntimeConfigBuilder)client.getClientConfigManager().getConfigBuilder(); ServerInfoBuilder relayConfigBuilder = rtConfigBuilder.getRelay(Integer.toString(id)); relayConfigBuilder.setName(name); relayConfigBuilder.setHost(addr.getHostName()); relayConfigBuilder.setPort(addr.getPort()); relayConfigBuilder.setSources(sources); ServerInfo si = relayConfigBuilder.build(); client.getClientConfigManager().setNewConfig(rtConfigBuilder.build()); return si; } static class TestConsumer extends AbstractDatabusCombinedConsumer { public static final String MODULE = TestConsumer.class.getName(); public static final Logger LOG = Logger.getLogger(MODULE); private int _eventNum; private int _winNum; private long _rollbackScn; private final List<DbusEventKey> keys = new ArrayList<DbusEventKey>(); private final List<Long> sequences = new ArrayList<Long>(); public TestConsumer() { resetCounters(); } public void resetCounters() { _eventNum = 0; _winNum = 0; _rollbackScn = -1; } public void resetEvents() { keys.clear(); sequences.clear(); } public List<DbusEventKey> getKeys() { return keys; } public List<Long> getSequences() { return sequences; } protected int getEventNum() { return _eventNum; } protected int getWinNum() { return _winNum; } @Override public ConsumerCallbackResult onDataEvent(DbusEvent e, DbusEventDecoder eventDecoder) { ++ _eventNum; if ( (! e.isCheckpointMessage()) && (!e.isControlMessage())) { sequences.add(e.sequence()); if ( e.isKeyNumber()) keys.add(new DbusEventKey(e.key())); else keys.add(new DbusEventKey(e.keyBytes())); } LOG.info("TestConsumer: OnDataEvent : Sequence : " + e.sequence()); return super.onDataEvent(e, eventDecoder); } @Override public ConsumerCallbackResult onStartDataEventSequence(SCN startScn) { ++ _winNum; return super.onStartDataEventSequence(startScn); } @Override public ConsumerCallbackResult onRollback(SCN startScn) { if (startScn instanceof SingleSourceSCN) { SingleSourceSCN s = (SingleSourceSCN)startScn; _rollbackScn = s.getSequence(); } else { throw new RuntimeException("SCN not instance of SingleSourceSCN"); } return super.onRollback(startScn); } protected long getRollbackScn() { return _rollbackScn; } } }