/*
* Copyright 2013 Stanley Shyiko
*
* 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.
*/
package com.github.shyiko.mysql.binlog;
import com.github.shyiko.mysql.binlog.jmx.BinaryLogClientStatistics;
import com.github.shyiko.mysql.binlog.network.SocketFactory;
import org.testng.annotations.Test;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
/**
* @author <a href="mailto:stanley.shyiko@gmail.com">Stanley Shyiko</a>
*/
public class BinaryLogClientTest {
@Test
public void testEventListenersManagement() {
BinaryLogClient binaryLogClient = new BinaryLogClient("localhost", 3306, "root", "mysql");
assertTrue(binaryLogClient.getEventListeners().isEmpty());
TraceEventListener traceEventListener = new TraceEventListener();
binaryLogClient.registerEventListener(traceEventListener);
binaryLogClient.registerEventListener(new CountDownEventListener());
binaryLogClient.registerEventListener(new CapturingEventListener());
assertEquals(binaryLogClient.getEventListeners().size(), 3);
binaryLogClient.unregisterEventListener(traceEventListener);
assertEquals(binaryLogClient.getEventListeners().size(), 2);
binaryLogClient.unregisterEventListener(CountDownEventListener.class);
assertEquals(binaryLogClient.getEventListeners().size(), 1);
}
@Test
public void testLifecycleListenersManagement() {
BinaryLogClient binaryLogClient = new BinaryLogClient("localhost", 3306, "root", "mysql");
assertTrue(binaryLogClient.getLifecycleListeners().isEmpty());
TraceLifecycleListener traceLifecycleListener = new TraceLifecycleListener();
binaryLogClient.registerLifecycleListener(traceLifecycleListener);
binaryLogClient.registerLifecycleListener(new BinaryLogClientStatistics());
binaryLogClient.registerLifecycleListener(new BinaryLogClient.AbstractLifecycleListener() {
});
assertEquals(binaryLogClient.getLifecycleListeners().size(), 3);
binaryLogClient.unregisterLifecycleListener(traceLifecycleListener);
assertEquals(binaryLogClient.getLifecycleListeners().size(), 2);
binaryLogClient.unregisterLifecycleListener(BinaryLogClientStatistics.class);
assertEquals(binaryLogClient.getLifecycleListeners().size(), 1);
}
@Test(expectedExceptions = TimeoutException.class)
public void testNoConnectionTimeout() throws Exception {
new BinaryLogClient("_localhost_", 3306, "root", "mysql").connect(0);
}
@Test(timeOut = 15000)
public void testConnectionTimeout() throws Exception {
final BinaryLogClient binaryLogClient = new BinaryLogClient("localhost", 33059, "root", "mysql");
final CountDownLatch socketBound = new CountDownLatch(1);
final CountDownLatch binaryLogClientDisconnected = new CountDownLatch(1);
new Thread(new Runnable() {
@Override
public void run() {
try {
final ServerSocket serverSocket = new ServerSocket();
try {
serverSocket.bind(new InetSocketAddress("localhost", 33059));
socketBound.countDown();
Socket accept = serverSocket.accept();
accept.getOutputStream().write(1);
accept.getOutputStream().flush();
assertTrue(binaryLogClientDisconnected.await(3000, TimeUnit.MILLISECONDS));
} finally {
serverSocket.close();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}).start();
assertTrue(socketBound.await(3000, TimeUnit.MILLISECONDS));
binaryLogClient.setConnectTimeout(1000);
try {
binaryLogClient.connect();
} catch (IOException e) {
binaryLogClientDisconnected.countDown();
}
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testNullEventDeserializerIsNotAllowed() throws Exception {
new BinaryLogClient("localhost", 3306, "root", "mysql").setEventDeserializer(null);
}
@Test(timeOut = 15000)
public void testDisconnectWhileBlockedByFBRead() throws Exception {
final BinaryLogClient binaryLogClient = new BinaryLogClient("localhost", 33060, "root", "mysql");
final CountDownLatch readAttempted = new CountDownLatch(1);
binaryLogClient.setSocketFactory(new SocketFactory() {
@Override
public Socket createSocket() throws SocketException {
return new Socket() {
@Override
public InputStream getInputStream() throws IOException {
return new FilterInputStream(super.getInputStream()) {
@Override
public int read(byte[] b, int off, int len) throws IOException {
readAttempted.countDown();
return super.read(b, off, len);
}
};
}
};
}
});
binaryLogClient.setKeepAlive(false);
final CountDownLatch socketBound = new CountDownLatch(1);
new Thread(new Runnable() {
@Override
public void run() {
try {
final ServerSocket serverSocket = new ServerSocket();
try {
serverSocket.bind(new InetSocketAddress("localhost", 33060));
socketBound.countDown();
serverSocket.accept(); // accept socket but do NOT send anything
assertTrue(readAttempted.await(3000, TimeUnit.MILLISECONDS));
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.yield();
binaryLogClient.disconnect();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
});
thread.start();
thread.join();
} finally {
serverSocket.close();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}).start();
assertTrue(socketBound.await(3000, TimeUnit.MILLISECONDS));
try {
binaryLogClient.connect();
} catch (IOException e) {
assertEquals(readAttempted.getCount(), 0);
assertTrue(e.getMessage().contains("Failed to connect to MySQL"));
}
}
}