Java tutorial
/** * Copyright (C) 2015 Greg Brandt (brandt.greg@gmail.com) * * 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.brandtg.switchboard; import com.fasterxml.jackson.databind.ObjectMapper; import com.github.brandtg.switchboard.util.DropWizardApplicationRunner; import com.google.code.or.common.glossary.Pair; import com.google.code.or.common.glossary.Row; import org.apache.http.HttpHost; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import org.testng.Assert; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import java.net.InetSocketAddress; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.Statement; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; public class TestMysqlLogServer { private HttpClient httpClient; private long pollMillis; private long timeoutMillis; private String jdbc; private DropWizardApplicationRunner.DropWizardServer server; private HttpHost serverAddress; private HttpHost adminAddress; @BeforeClass public void beforeClass() throws Exception { httpClient = HttpClients.createDefault(); pollMillis = 1000; timeoutMillis = 30000; jdbc = "jdbc:mysql://localhost:3306/test"; serverAddress = new HttpHost("localhost", 8080); adminAddress = new HttpHost("localhost", 8081); } @BeforeMethod public void beforeMethod() throws Exception { // Reset and setup local MySQL try (Connection conn = DriverManager.getConnection(jdbc, "root", "")) { Statement stmt = conn.createStatement(); stmt.execute("RESET MASTER"); stmt.execute("GRANT ALL ON *.* TO 'switchboard'@'localhost' IDENTIFIED BY 'switchboard'"); stmt.execute("DROP TABLE IF EXISTS simple"); stmt.execute("CREATE TABLE simple (k INT, v INT)"); } // Start server MysqlLogServerConfig config = new MysqlLogServerConfig(); server = DropWizardApplicationRunner.createServer(config, MysqlLogServer.class); server.start(); } @AfterMethod public void afterMethod() throws Exception { server.stop(); } private void resetServer() throws Exception { if (server != null) { server.stop(); } MysqlLogServerConfig config = new MysqlLogServerConfig(); server = DropWizardApplicationRunner.createServer(config, MysqlLogServer.class); server.start(); } private void pollAndCheck(HttpHost host, String uri, long count, long highWaterMark) throws Exception { long startTime = System.currentTimeMillis(); long currentTime; do { // Query server HttpGet req = new HttpGet(uri); HttpResponse res = httpClient.execute(host, req); try { if (res.getStatusLine().getStatusCode() == 200) { ObjectMapper mapper = new ObjectMapper(); LogRegionResponse data = mapper.readValue(res.getEntity().getContent(), LogRegionResponse.class); // Get all sorted indexes present in response List<Long> indexes = new ArrayList<>(); for (LogRegion logRegion : data.getLogRegions()) { indexes.add(logRegion.getIndex()); } Collections.sort(indexes); // Check that we've have expected count and reached high watermark if (indexes.size() >= count && indexes.get(indexes.size() - 1) >= highWaterMark) { return; } } } finally { if (res != null) { EntityUtils.consume(res.getEntity()); } } // Wait until next time Thread.sleep(pollMillis); currentTime = System.currentTimeMillis(); } while (currentTime - startTime < timeoutMillis); // Exited, so timed out throw new IllegalStateException("Timed out while waiting for " + uri); } @Test public void testSimpleWrites() throws Exception { try (Connection conn = DriverManager.getConnection(jdbc, "root", "")) { // Write some rows, so we have binlog entries PreparedStatement pstmt = conn.prepareStatement("INSERT INTO simple VALUES(?, ?)"); for (int i = 0; i < 10; i++) { pstmt.setInt(1, i); pstmt.setInt(2, i); pstmt.execute(); } } pollAndCheck(serverAddress, "/log/test/0", 10, 10); } @Test public void testRotateBinlog() throws Exception { try (Connection conn = DriverManager.getConnection(jdbc, "root", "")) { // Write some rows, so we have binlog entries PreparedStatement pstmt = conn.prepareStatement("INSERT INTO simple VALUES(?, ?)"); for (int i = 0; i < 10; i++) { pstmt.setInt(1, i); pstmt.setInt(2, i); pstmt.execute(); } // Rotate logs Statement stmt = conn.createStatement(); stmt.execute("FLUSH LOGS"); // Write more for (int i = 10; i < 20; i++) { pstmt.setInt(1, i); pstmt.setInt(2, i); pstmt.execute(); } } pollAndCheck(serverAddress, "/log/test/0?count=100", 20, 20); } @Test public void testMysqlEventListener() throws Exception { try (Connection conn = DriverManager.getConnection(jdbc, "root", "")) { // Write some rows, so we have binlog entries PreparedStatement pstmt = conn.prepareStatement("INSERT INTO simple VALUES(?, ?)"); for (int i = 0; i < 10; i++) { pstmt.setInt(1, i); pstmt.setInt(2, i); pstmt.execute(); } } final AtomicInteger insertCount = new AtomicInteger(); final AtomicInteger beginCount = new AtomicInteger(); final AtomicInteger commitCount = new AtomicInteger(); final AtomicInteger rollbackCount = new AtomicInteger(); InetSocketAddress sourceAddress = new InetSocketAddress(8080); InetSocketAddress sinkAddress = new InetSocketAddress(9090); MysqlEventListener eventListener = new MysqlEventListener("test", sourceAddress, sinkAddress) { @Override public void onBegin(UUID sourceId, long transactionId) { beginCount.incrementAndGet(); } @Override public void onInsert(List<Row> rows) { insertCount.incrementAndGet(); } @Override public void onUpdate(List<Pair<Row>> rows) { } @Override public void onDelete(List<Row> rows) { } @Override public void onCommit() { commitCount.incrementAndGet(); } @Override public void onRollback() { rollbackCount.incrementAndGet(); } }; try { eventListener.start(); long startTime = System.currentTimeMillis(); long currentTime = startTime; do { // Once we've seen all writes, check expected state if (insertCount.get() == 10) { Assert.assertEquals(beginCount.get(), 10); Assert.assertEquals(commitCount.get(), 10); Assert.assertEquals(rollbackCount.get(), 0); return; } Thread.sleep(pollMillis); currentTime = System.currentTimeMillis(); } while (currentTime - startTime < timeoutMillis); } finally { eventListener.shutdown(); } Assert.fail("Timed out while polling"); } }