com.github.brandtg.switchboard.TestMysqlLogServer.java Source code

Java tutorial

Introduction

Here is the source code for com.github.brandtg.switchboard.TestMysqlLogServer.java

Source

/**
 * 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");
    }
}