phoenix-issues mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From vincentpoon <...@git.apache.org>
Subject [GitHub] phoenix pull request #411: PHOENIX-4832: Add Canary Test Tool for Phoenix Qu...
Date Wed, 05 Dec 2018 22:10:22 GMT
Github user vincentpoon commented on a diff in the pull request:

    https://github.com/apache/phoenix/pull/411#discussion_r239256956
  
    --- Diff: phoenix-core/src/main/java/org/apache/phoenix/queryserver/tool/QueryServerCanaryTool.java
---
    @@ -0,0 +1,476 @@
    +/*
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you 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 org.apache.phoenix.queryserver.tool;
    +
    +import com.google.common.base.Throwables;
    +import com.google.common.io.Files;
    +import com.google.common.util.concurrent.SimpleTimeLimiter;
    +import com.google.gson.Gson;
    +import com.google.gson.GsonBuilder;
    +import net.sourceforge.argparse4j.ArgumentParsers;
    +import net.sourceforge.argparse4j.inf.ArgumentParser;
    +import net.sourceforge.argparse4j.inf.ArgumentParserException;
    +import net.sourceforge.argparse4j.inf.Namespace;
    +import org.apache.hadoop.conf.Configured;
    +import org.apache.hadoop.hbase.util.Bytes;
    +import org.apache.hadoop.util.Tool;
    +import org.apache.hadoop.util.ToolRunner;
    +import org.slf4j.Logger;
    +import org.slf4j.LoggerFactory;
    +import java.io.File;
    +import java.io.InputStream;
    +import java.sql.Connection;
    +import java.sql.DatabaseMetaData;
    +import java.sql.DriverManager;
    +import java.sql.PreparedStatement;
    +import java.sql.ResultSet;
    +import java.sql.Statement;
    +import java.text.SimpleDateFormat;
    +import java.util.ArrayList;
    +import java.util.Date;
    +import java.util.List;
    +import java.util.Properties;
    +import java.util.concurrent.Callable;
    +import java.util.concurrent.TimeUnit;
    +
    +/**
    + * A Canary Tool to perform synthetic tests for Query Server
    + */
    +public class QueryServerCanaryTool extends Configured implements Tool {
    +
    +    private static String TEST_SCHEMA_NAME = "TEST";
    +    private static String TEST_TABLE_NAME = "PQSTEST";
    +    private static String FQ_TABLE_NAME = "TEST.PQSTEST";
    +    private boolean USE_NAMESPACE = true;
    +
    +    private Sink sink = new StdOutSink();
    +
    +    /**
    +     * Base class for a Canary Test
    +     */
    +    private abstract static class CanaryTest {
    +
    +        CanaryTestResult result = new CanaryTestResult();
    +
    +        Connection connection = null;
    +
    +        private void onCreate(Connection connection) {
    +            result.setTimestamp(getCurrentTimestamp());
    +            result.setStartTime(System.currentTimeMillis());
    +            this.connection = connection;
    +        }
    +
    +        abstract void onExecute() throws Exception;
    +
    +        private void onExit() {
    +            result.setExecutionTime(System.currentTimeMillis() - result.getStartTime());
    +        }
    +
    +        CanaryTestResult runTest(Connection connection) {
    +            try {
    +                onCreate(connection);
    +                onExecute();
    +                result.setSuccessful(true);
    +                result.setMessage("Test " + result.getTestName() + " successful");
    +            } catch (Exception e) {
    +                result.setSuccessful(false);
    +                result.setMessage(Throwables.getStackTraceAsString(e));
    +            } finally {
    +                onExit();
    +            }
    +            return result;
    +        }
    +    }
    +
    +    /**
    +     * Test which prepares environment before other tests run
    +     */
    +    static class PrepareTest extends CanaryTest {
    +        void onExecute() throws Exception {
    +            result.setTestName("prepare");
    +            Statement statement = connection.createStatement();
    +            DatabaseMetaData dbm = connection.getMetaData();
    +            ResultSet tables = dbm.getTables(null, TEST_SCHEMA_NAME, TEST_TABLE_NAME,
null);
    +            if (tables.next()) {
    +                // Drop test Table if exists
    +                statement.executeUpdate("DROP TABLE IF EXISTS " + FQ_TABLE_NAME);
    +            }
    +
    +            // Drop test schema if exists
    +            if (TEST_SCHEMA_NAME != null) {
    +                statement = connection.createStatement();
    +                statement.executeUpdate("DROP SCHEMA IF EXISTS " + TEST_SCHEMA_NAME);
    +            }
    +        }
    +    }
    +
    +    /**
    +     * Create Schema Test
    +     */
    +    static class CreateSchemaTest extends CanaryTest {
    +        void onExecute() throws Exception {
    +            result.setTestName("createSchema");
    +            Statement statement = connection.createStatement();
    +            statement.executeUpdate("CREATE SCHEMA IF NOT EXISTS " + TEST_SCHEMA_NAME);
    +        }
    +    }
    +
    +    /**
    +     * Create Table Test
    +     */
    +    static class CreateTableTest extends CanaryTest {
    +        void onExecute() throws Exception {
    +            result.setTestName("createTable");
    +            Statement statement = connection.createStatement();
    +            // Create Table
    +            statement.executeUpdate("CREATE TABLE " + FQ_TABLE_NAME + " (mykey " + "INTEGER
"
    +                    + "NOT " + "NULL PRIMARY KEY, " + "mycolumn VARCHAR)");
    +        }
    +    }
    +
    +    /**
    +     * Upsert Data into Table Test
    +     */
    +    static class UpsertTableTest extends CanaryTest {
    +        void onExecute() throws Exception {
    +            result.setTestName("upsertTable");
    +            // Insert data
    +            Statement statement = connection.createStatement();
    +            statement.executeUpdate("UPSERT INTO " + FQ_TABLE_NAME + " VALUES (1, " +
    +                    "'Hello" + " World')");
    +            connection.commit();
    +        }
    +    }
    +
    +    /**
    +     * Read data from Table Test
    +     */
    +    static class ReadTableTest extends CanaryTest {
    +        void onExecute() throws Exception {
    +            result.setTestName("readTable");
    +            // Query for table
    +            PreparedStatement ps = connection.prepareStatement("SELECT * FROM " + FQ_TABLE_NAME);
    +            ResultSet rs = ps.executeQuery();
    +
    +            // Check correctness
    +            int totalRows = 0;
    +            while (rs.next()) {
    +                totalRows += 1;
    +                Integer myKey = rs.getInt(1);
    +                String myColumn = rs.getString(2);
    +                if (myKey != 1 || !myColumn.equals("Hello World")) {
    +                    throw new Exception("Retrieved values do not match the inserted "
+ "values");
    +                }
    +            }
    +            if (totalRows != 1) {
    +                throw new Exception(totalRows + " rows fetched instead of just one.");
    +            }
    +            ps.close();
    +            rs.close();
    +        }
    +    }
    +
    +    /**
    +     * Delete test table Test
    +     */
    +    static class DeleteTableTest extends CanaryTest {
    +        void onExecute() throws Exception {
    +            result.setTestName("deleteTable");
    +            Statement statement = connection.createStatement();
    +            statement.executeUpdate("DROP TABLE " + FQ_TABLE_NAME);
    +
    +            // Check if table dropped
    +            DatabaseMetaData dbm = connection.getMetaData();
    +            ResultSet tables = dbm.getTables(null, TEST_SCHEMA_NAME, TEST_TABLE_NAME,
null);
    +            if (tables.next()) {
    +                throw new Exception("Test Table could not be dropped");
    +            }
    +        }
    +    }
    +
    +    /**
    +     * Delete test Schema Test
    +     */
    +    static class DeleteSchemaTest extends CanaryTest {
    +        void onExecute() throws Exception {
    +            result.setTestName("deleteSchema");
    +            Statement statement = connection.createStatement();
    +            statement.executeUpdate("DROP SCHEMA IF EXISTS " + TEST_SCHEMA_NAME);
    +        }
    +    }
    +
    +    /**
    +     * Sink interface used by the canary to output information
    +     */
    +    public interface Sink {
    +        List<CanaryTestResult> getResults();
    +
    +        void updateResults(CanaryTestResult result);
    +
    +        void publishResults() throws Exception;
    +
    +        void clearResults();
    +    }
    +
    +    /**
    +     * Implementation of Std Out Sink
    +     */
    +    public static class StdOutSink implements Sink {
    +        private List<CanaryTestResult> results = new ArrayList<>();
    +
    +        @Override
    +        public void updateResults(CanaryTestResult result) {
    +            results.add(result);
    +        }
    +
    +        @Override
    +        public List<CanaryTestResult> getResults() {
    +            return results;
    +        }
    +
    +        @Override
    +        public void publishResults() throws Exception {
    +
    +            Gson gson = new GsonBuilder().setPrettyPrinting().create();
    +            String resultJson = gson.toJson(results);
    +            System.out.println(resultJson);
    +        }
    +
    +        @Override
    +        public void clearResults() {
    +            results.clear();
    +        }
    +    }
    +
    +    /**
    +     * Implementation of File Out Sink
    +     */
    +    public static class FileOutSink implements Sink {
    +        private List<CanaryTestResult> results = new ArrayList<>();
    +        File dir;
    +        String logfileName;
    +        String propFileName = "pqs-canary-file-sink.properties";
    +
    +        public FileOutSink() throws Exception {
    +            Properties prop = new Properties();
    +            InputStream input = ClassLoader.getSystemResourceAsStream(propFileName);
    +            if (input == null) {
    +                throw new Exception("Cannot load " + propFileName + " file for " + "FileOutSink.");
    +            }
    +            prop.load(input);
    +            logfileName = prop.getProperty("file.name");
    +            dir = new File(prop.getProperty("file.location"));
    +            dir.mkdirs();
    +        }
    +
    +        @Override
    +        public void updateResults(CanaryTestResult result) {
    +            results.add(result);
    +        }
    +
    +        @Override
    +        public List<CanaryTestResult> getResults() {
    +            return results;
    +        }
    +
    +        @Override
    +        public void publishResults() throws Exception {
    +            Gson gson = new GsonBuilder().setPrettyPrinting().create();
    +            String resultJson = gson.toJson(results);
    +            String fileName = logfileName + "-" + new SimpleDateFormat("yyyy.MM.dd.HH"
+ ".mm" +
    +                    ".ss").format(new Date()) + ".log";
    +            File file = new File(dir, fileName);
    +            Files.write(Bytes.toBytes(resultJson), file);
    +        }
    +
    +        @Override
    +        public void clearResults() {
    +            results.clear();
    +        }
    +    }
    +
    +    private static final Logger LOG = LoggerFactory.getLogger(QueryServerCanaryTool.class);
    +
    +    private static String getCurrentTimestamp() {
    +        return new SimpleDateFormat("yyyy.MM.dd.HH.mm.ss.ms").format(new Date());
    +    }
    +
    +    private static Namespace parseArgs(String[] args) {
    +
    +        ArgumentParser parser = ArgumentParsers.newFor("PQS Canary Test Tool").build()
    +                .description("PQS Canary Test Tool");
    +
    +        parser.addArgument("--hostname", "-hn").type(String.class).nargs("?").help("Hostname
on "
    +                + "which PQS is running.");
    +
    +        parser.addArgument("--port", "-p").type(String.class).nargs("?").help("Port on
which PQS " +
    +                "" + "is running.");
    +
    +        parser.addArgument("--constring", "-cs").type(String.class).nargs("?").help("Pass
an " +
    +                "explicit connection String to connect to PQS. default: null");
    --- End diff --
    
    Is the default really null?  Looks like below if you don't specify this, it uses jdbc:phoenix:thin:serialization=PROTOBUF;url=
...
    Maybe we should put that as an example here so the usage is clearer


---

Mime
View raw message