}
}, "relay connection present", 100, log);
final NettyHttpDatabusRelayConnection relayConn =
(NettyHttpDatabusRelayConnection)clientConn.getRelayPullThread().getLastOpenConnection();
final NettyHttpDatabusRelayConnectionInspector relayConnInsp =
new NettyHttpDatabusRelayConnectionInspector(relayConn);
TestUtil.assertWithBackoff(new ConditionCheck()
{
@Override
public boolean check()
{
return null != relayConnInsp.getChannel() && relayConnInsp.getChannel().isConnected();
}
}, "client connected", 200, log);
//figure out the connection to the relay
Channel clientChannel = relayConnInsp.getChannel();
InetSocketAddress relayAddr = (InetSocketAddress)clientChannel.getRemoteAddress();
SocketAddress clientAddr = clientChannel.getLocalAddress();
int relayPort = relayAddr.getPort();
log.info("relay selected: " + relayPort);
SimpleTestServerConnection relay = null;
for (int i = 0; i < RELAY_PORT.length; ++i)
{
if (relayPort == RELAY_PORT[i]) relay = _dummyServer[i];
}
assertTrue(null != relay);
final SocketAddress testClientAddr = clientAddr;
final SimpleTestServerConnection testRelay = relay;
TestUtil.assertWithBackoff(new ConditionCheck()
{
@Override
public boolean check()
{
return null != testRelay.getChildChannel(testClientAddr);
}
}, "relay detects new connection", 1000, log);
Channel serverChannel = relay.getChildChannel(clientAddr);
assertTrue(null != serverChannel);
ChannelPipeline serverPipeline = serverChannel.getPipeline();
SimpleObjectCaptureHandler objCapture = (SimpleObjectCaptureHandler)serverPipeline.get("3");
//process the /sources request
NettyTestUtils.waitForHttpRequest(objCapture, SOURCES_REQUEST_REGEX, 1000);
objCapture.clear();
//send back the /sources response
HttpResponse sourcesResp = new DefaultHttpResponse(HttpVersion.HTTP_1_1,
HttpResponseStatus.OK);
sourcesResp.setHeader(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
sourcesResp.setHeader(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED);
HttpChunk body =
new DefaultHttpChunk(ChannelBuffers.wrappedBuffer(("[{\"id\":1,\"name\":\"" +
SOURCE1_NAME + "\"}]").getBytes(Charset.defaultCharset())));
NettyTestUtils.sendServerResponses(relay, clientAddr, sourcesResp, body);
//make sure the client processes the response correctly
TestUtil.assertWithBackoff(new ConditionCheck()
{
@Override
public boolean check()
{
String idListString = clientConn.getRelayPullThread()._currentState.getSourcesIdListString();
return "1".equals(idListString);
}
}, "client processes /sources response", 100, log);
//process the /register request
NettyTestUtils.waitForHttpRequest(objCapture, "/register.*", 1000);
objCapture.clear();
//send back the /register response
RegisterResponseEntry entry = new RegisterResponseEntry(1L, (short)1, SOURCE1_SCHEMA_STR);
String responseStr = NettyTestUtils.generateRegisterResponse(entry);
body = new DefaultHttpChunk(
ChannelBuffers.wrappedBuffer(responseStr.getBytes(Charset.defaultCharset())));
NettyTestUtils.sendServerResponses(relay, clientAddr, sourcesResp, body);
//make sure the client processes the response correctly
TestUtil.assertWithBackoff(new ConditionCheck()
{
@Override
public boolean check()
{
DispatcherState dispState = clientConn.getRelayDispatcher().getDispatcherState();
return null != dispState.getSchemaMap() && 1 == dispState.getSchemaMap().size();
}
}, "client processes /register response", 100, log);
//process /stream call and return a partial window
NettyTestUtils.waitForHttpRequest(objCapture, "/stream.*", 1000);
objCapture.clear();
//send back the /stream response
final DbusEventsStatisticsCollector stats =
new DbusEventsStatisticsCollector(1, "test1", true, false, null);
Checkpoint cp = Checkpoint.createFlexibleCheckpoint();
ChannelBuffer streamRes = NettyTestUtils.streamToChannelBuffer(relayBuffer[0], cp,
resp1EnfOfs, stats);
HttpResponse streamResp = new DefaultHttpResponse(HttpVersion.HTTP_1_1,
HttpResponseStatus.OK);
streamResp.setHeader(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
streamResp.setHeader(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED);
NettyTestUtils.sendServerResponses(relay, clientAddr, streamResp,
new DefaultHttpChunk(streamRes));
//make sure the client processes the response correctly
TestUtil.assertWithBackoff(new ConditionCheck()
{
@Override
public boolean check()
{
log.debug("LastWritten SCN:" + clientConn.getDataEventsBuffer().lastWrittenScn() );
return clientConn.getDataEventsBuffer().lastWrittenScn() == 30;
}
}, "client receives /stream response", 1100, log);
TestUtil.assertWithBackoff(new ConditionCheck()
{
@Override
public boolean check()
{
log.error("events num=" + consumer.getEventNum());
return stats.getTotalStats().getNumDataEvents() == consumer.getEventNum();
}
}, "client processes /stream response", 110000, log);
assertEquals(-1, consumer.getRollbackScn());
int rollbackNum = 0;
assertEquals(stats.getTotalStats().getNumSysEvents() + 1 + rollbackNum,
consumer.getWinNum());
List<DbusEventKey> expKeys = eventKeys.get(0).subList(0, (int)stats.getTotalStats().getNumDataEvents());
List<Long> expSeqs = new ArrayList<Long>();
for (int i = 0; i < stats.getTotalStats().getNumDataEvents(); i++)
expSeqs.add(30L);
long numEvents = stats.getTotalStats().getNumDataEvents();
assertEquals("Keys", expKeys, consumer.getKeys());
assertEquals("Sequences", expSeqs, consumer.getSequences());
assertEquals("Keys", expKeys, consumer.getKeys());
assertEquals("Sequences", expSeqs, consumer.getSequences());
numEvents = stats.getTotalStats().getNumDataEvents();
//now kill the relay and wait for a failover
serverChannel.close();
TestUtil.assertWithBackoff(new ConditionCheck()
{
@Override
public boolean check()
{
return null != relayConnInsp.getChannel() && !relayConnInsp.getChannel().isConnected();
}
}, "client disconnected", 200, log);
TestUtil.assertWithBackoff(new ConditionCheck()
{
@Override
public boolean check()
{
return clientConn.getRelayPullThread().getLastOpenConnection() != relayConn;
}
}, "new netty connection", 200, log);
/////////// FAKING CONNECTION TO NEW RELAY
final NettyHttpDatabusRelayConnection newRelayConn =
(NettyHttpDatabusRelayConnection)clientConn.getRelayPullThread().getLastOpenConnection();
final NettyHttpDatabusRelayConnectionInspector newRelayConnInsp =
new NettyHttpDatabusRelayConnectionInspector(newRelayConn);
TestUtil.assertWithBackoff(new ConditionCheck()
{
@Override
public boolean check()
{
return null != newRelayConnInsp.getChannel() && newRelayConnInsp.getChannel().isConnected();
}
}, "client connected to new relay", 200, log);
//figure out the connection to the relay
clientChannel = newRelayConnInsp.getChannel();
relayAddr = (InetSocketAddress)clientChannel.getRemoteAddress();
clientAddr = clientChannel.getLocalAddress();
relayPort = relayAddr.getPort();
log.info("new relay selected: " + relayPort);
relay = null;
int relayIdx = 0;
for (; relayIdx < RELAY_PORT.length; ++relayIdx)
{
if (relayPort == RELAY_PORT[relayIdx]) relay = _dummyServer[relayIdx];
}
assertTrue(null != relay);
serverChannel = relay.getChildChannel(clientAddr);
assertTrue(null != serverChannel);
serverPipeline = serverChannel.getPipeline();
objCapture = (SimpleObjectCaptureHandler)serverPipeline.get("3");
//process the /sources request
NettyTestUtils.waitForHttpRequest(objCapture, SOURCES_REQUEST_REGEX, 1000);
objCapture.clear();
//send back the /sources response
body = new DefaultHttpChunk(ChannelBuffers.wrappedBuffer(("[{\"id\":1,\"name\":\"" +
SOURCE1_NAME + "\"}]").getBytes(Charset.defaultCharset())));
NettyTestUtils.sendServerResponses(relay, clientAddr, sourcesResp, body);
//make sure the client processes the response correctly
TestUtil.assertWithBackoff(new ConditionCheck()
{
@Override
public boolean check()
{
String idListString = clientConn.getRelayPullThread()._currentState.getSourcesIdListString();
return "1".equals(idListString);
}
}, "client processes /sources response", 100, log);
//process the /register request
NettyTestUtils.waitForHttpRequest(objCapture, "/register.*", 1000);
objCapture.clear();
//send back the /register response
body = new DefaultHttpChunk(
ChannelBuffers.wrappedBuffer(responseStr.getBytes(Charset.defaultCharset())));
NettyTestUtils.sendServerResponses(relay, clientAddr, sourcesResp, body);
//make sure the client processes the response correctly
TestUtil.assertWithBackoff(new ConditionCheck()
{
@Override
public boolean check()
{
DispatcherState dispState = clientConn.getRelayDispatcher().getDispatcherState();
return null != dispState.getSchemaMap() && 1 == dispState.getSchemaMap().size();
}
}, "client processes /register response", 100, log);
//process /stream call and return a partial window
Matcher streamMatcher =
NettyTestUtils.waitForHttpRequest(objCapture, "/stream.*checkPoint=([^&]*)&.*",
1000);
String cpString = streamMatcher.group(1);
objCapture.clear();
int respStartOfs = eventOfs.get(1).get(1);
int respEndOfs = eventOfs.get(1).get(26);
cp = new Checkpoint(cpString);
assertTrue(cp.getWindowOffset() > 0); //last window read was partial
streamRes = NettyTestUtils.streamToChannelBuffer(relayBuffer[1], cp,
respEndOfs - respStartOfs,
stats);
NettyTestUtils.sendServerResponses(relay, clientAddr, streamResp,
new DefaultHttpChunk(streamRes));
//make sure the client processes the response correctly
TestUtil.assertWithBackoff(new ConditionCheck()
{
@Override
public boolean check()
{
log.debug("lastWrittenScn=" + clientConn.getDataEventsBuffer().lastWrittenScn());
return clientConn.getDataEventsBuffer().lastWrittenScn() == 40;
}
}, "client receives /stream response", 1100, log);
TestUtil.assertWithBackoff(new ConditionCheck()
{
@Override
public boolean check()
{
log.debug("events num=" + consumer.getEventNum());
return stats.getTotalStats().getNumDataEvents() == consumer.getEventNum();
}
}, "client processes /stream response", 11000, log);
assertEquals(20, consumer.getRollbackScn());
//add one more onStartDataEventsSequence after the rollback()
++rollbackNum;
assertEquals(stats.getTotalStats().getNumSysEvents() + 1 + rollbackNum, consumer.getWinNum());
expKeys.addAll(eventKeys.get(1).subList(0, (int)(stats.getTotalStats().getNumDataEvents() - numEvents)));
for (int i = 0; i < (stats.getTotalStats().getNumDataEvents() - numEvents); i++)
expSeqs.add((i/20)*20 + 20L);
log.info("Expected NumKeys :" + expKeys.size() + ", Got NumKeys :" + consumer.getKeys().size());
for(int i = 0; i < expKeys.size(); i++)
{
if (! consumer.getKeys().contains(expKeys.get(i)))
log.error(i + " Key :" + expKeys.get(i) + " missing !!");
else
log.info(i + " Key :" + expKeys.get(i) + " present !!");
}
assertEquals("Keys", expKeys, consumer.getKeys());
assertEquals("Sequences", expSeqs, consumer.getSequences());
assertEquals("Keys", expKeys, consumer.getKeys());
assertEquals("Sequences", expSeqs, consumer.getSequences());
numEvents = stats.getTotalStats().getNumDataEvents();
assertEquals(clientConn.getRelayPullThread().getConnectionState().getDataEventsBuffer().isSCNRegress(), false);
///////////////////////////////////
//simulate a timeout on the server; the client would have sent a /stream call and there
//will be no response from the server, so eventually it should time out and switch servers
TestUtil.assertWithBackoff(new ConditionCheck()
{
@Override
public boolean check()
{
log.debug("Channel :" + newRelayConnInsp.getChannel());
return (null != newRelayConnInsp.getChannel()) && (!newRelayConnInsp.getChannel().isConnected());
}
}, "waiting for a reconnect", (long)(DEFAULT_READ_TIMEOUT_MS * 1.5), log);
TestUtil.assertWithBackoff(new ConditionCheck()
{
@Override
public boolean check()
{
return clientConn.getRelayPullThread().getLastOpenConnection() != relayConn;
}
}, "new netty connection", 200, log);
final NettyHttpDatabusRelayConnection new2RelayConn =
(NettyHttpDatabusRelayConnection)clientConn.getRelayPullThread().getLastOpenConnection();
final NettyHttpDatabusRelayConnectionInspector new2RelayConnInsp =
new NettyHttpDatabusRelayConnectionInspector(new2RelayConn);
TestUtil.assertWithBackoff(new ConditionCheck()
{
@Override
public boolean check()
{
return null != new2RelayConnInsp.getChannel() && new2RelayConnInsp.getChannel().isConnected();
}
}, "client connected to third relay", 200, log);
//figure out the connection to the relay
clientChannel = new2RelayConnInsp.getChannel();
relayAddr = (InetSocketAddress)clientChannel.getRemoteAddress();
clientAddr = clientChannel.getLocalAddress();
relayPort = relayAddr.getPort();
log.info("third relay selected: " + relayPort);