All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.tascape.qa.th.db.PostgresqlHandler Maven / Gradle / Ivy

There is a newer version: 1.1.9
Show newest version
/*
 * Copyright 2015.
 *
 * 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.tascape.qa.th.db;

import com.tascape.qa.th.ExecutionResult;
import com.tascape.qa.th.TestSuite;
import com.tascape.qa.th.Utils;
import com.jolbox.bonecp.BoneCP;
import com.jolbox.bonecp.BoneCPConfig;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author linsong wang
 */
public class PostgresqlHandler extends DbHandler {
    private static final Logger LOG = LoggerFactory.getLogger(PostgresqlHandler.class);

    private static final String DB_DRIVER = "org.postgresql.Driver";

    private static final String DB_HOST = SYS_CONFIG.getDatabaseHost();

    private static final String DB_SCHEMA = SYS_CONFIG.getDatabaseSchema();

    private static final String DB_USER = SYS_CONFIG.getDatabaseUser();

    private static final String DB_PASS = SYS_CONFIG.getDatabasePass();

    static {
        try {
            Class.forName(DB_DRIVER).newInstance();
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) {
            throw new RuntimeException("Cannot load database driver: " + DB_DRIVER, ex);
        }
    }

    private BoneCP connPool;

    @Override
    protected void init() throws Exception {
        BoneCPConfig connPoolConfig = new BoneCPConfig();
        connPoolConfig.setJdbcUrl("jdbc:postgresql://" + DB_HOST + "/" + DB_SCHEMA);
        connPoolConfig.setUsername(DB_USER);
        connPoolConfig.setPassword(DB_PASS);
        connPoolConfig.setMaxConnectionAgeInSeconds(600);
        connPoolConfig.setDefaultAutoCommit(true);
        connPoolConfig.setIdleConnectionTestPeriodInSeconds(30);
        connPoolConfig.setConnectionTestStatement("SELECT 1");
        this.connPool = new BoneCP(connPoolConfig);

        // todo: shutdown pool
    }

    @Override
    protected Connection getConnection() throws SQLException {
        return connPool.getConnection();
    }

    @Override
    public void queueSuiteExecution(TestSuite suite, String execId) throws SQLException {
        LOG.info("Queue test suite for execution with execution id {}", execId);
        String lock = "testharness." + execId;
        try (Connection conn = this.getConnection()) {
            try {
                if (!this.acquireExecutionLock(conn, lock)) {
                    throw new SQLException("Cannot acquire lock of name " + lock);
                }

                if (this.queueTestSuite(suite, execId)) {
                    this.queueTestCaseResults(execId, suite.getTests());
                }
            } finally {
                this.releaseExecutionLock(conn, lock);
            }
        }
    }

    @Override
    public boolean queueTestSuite(TestSuite suite, String execId) throws SQLException {
        LOG.info("Queueing test suite result with execution id {} ", execId);
        final String sql = "SELECT * FROM " + SuiteResult.TABLE_NAME + " WHERE "
            + SuiteResult.SUITE_RESULT_ID + " = ?";

        try (Connection conn = this.getConnection()) {
            PreparedStatement stmt = conn.prepareStatement(sql,
                ResultSet.TYPE_SCROLL_SENSITIVE,
                ResultSet.CONCUR_UPDATABLE);
            stmt.setMaxRows(1);
            stmt.setString(1, execId);
            ResultSet rs = stmt.executeQuery();
            if (rs.first()) {
                LOG.debug("Suite execution {} is already queued ", execId);
                return false;

            } else {
                Long time = System.currentTimeMillis();
                LOG.debug("Queueing suite execution {}", execId);
                rs.moveToInsertRow();

                rs.updateString(SuiteResult.SUITE_RESULT_ID, execId);
                rs.updateString(SuiteResult.SUITE_NAME, suite.getName());
                rs.updateString(SuiteResult.JOB_NAME, SYS_CONFIG.getJobName());
                rs.updateInt(SuiteResult.JOB_BUILD_NUMBER, SYS_CONFIG.getJobBuildNumber());
                rs.updateString(SuiteResult.JOB_BUILD_URL, SYS_CONFIG.getJobBuildUrl());
                rs.updateLong(SuiteResult.START_TIME, time);
                rs.updateLong(SuiteResult.STOP_TIME, time);
                rs.updateString(SuiteResult.EXECUTION_RESULT, ExecutionResult.QUEUED.getName());
                rs.updateInt(SuiteResult.NUMBER_OF_TESTS, suite.getTests().size());
                rs.updateInt(SuiteResult.NUMBER_OF_FAILURE, suite.getTests().size());
                rs.updateNString(SuiteResult.PRODUCT_UNDER_TEST, SYS_CONFIG.getProdUnderTest());

                rs.insertRow();
                rs.last();
                rs.updateRow();
                return true;
            }
        }
    }

    @Override
    protected int getTestCaseId(TestCase test) throws SQLException {
        LOG.info("Query for id of test case {} ", test.format());
        final String sql = "SELECT * FROM " + TestCase.TABLE_NAME + " WHERE "
            + TestCase.SUITE_CLASS + " = ? AND "
            + TestCase.TEST_CLASS + " = ? AND "
            + TestCase.TEST_METHOD + " = ? AND "
            + TestCase.TEST_DATA_INFO + " = ? AND "
            + TestCase.TEST_DATA + " = ?";

        try (Connection conn = this.getConnection()) {
            PreparedStatement stmt = conn.prepareStatement(sql,
                ResultSet.TYPE_SCROLL_SENSITIVE,
                ResultSet.CONCUR_UPDATABLE);
            stmt.setString(1, test.getSuiteClass());
            stmt.setString(2, test.getTestClass());
            stmt.setString(3, test.getTestMethod());
            stmt.setString(4, test.getTestDataInfo());
            stmt.setString(5, test.getTestData());
            stmt.setMaxRows(1);

            ResultSet rs = stmt.executeQuery();
            if (!rs.next()) {
                rs.moveToInsertRow();
                rs.updateString(TestCase.SUITE_CLASS, test.getSuiteClass());
                rs.updateString(TestCase.TEST_CLASS, test.getTestClass());
                rs.updateString(TestCase.TEST_METHOD, test.getTestMethod());
                rs.updateString(TestCase.TEST_DATA_INFO, test.getTestDataInfo());
                rs.updateString(TestCase.TEST_DATA, test.getTestData());

                rs.insertRow();
                rs.last();
                rs.updateRow();
            }
            return rs.getInt(TestCase.TEST_CASE_ID);
        }
    }

    @Override
    protected void queueTestCaseResults(String execId, List tests) throws SQLException {
        LOG.info("Queue {} test case result(s) with execution id {} ", tests.size(), execId);
        final String sql = "SELECT * FROM " + TestCase.TABLE_NAME + " WHERE "
            + TestResult.SUITE_RESULT + " = ?";
        Map idMap = this.getTestCaseIds(tests);

        try (Connection conn = this.getConnection()) {
            PreparedStatement stmt = conn.prepareStatement(sql,
                ResultSet.TYPE_SCROLL_SENSITIVE,
                ResultSet.CONCUR_UPDATABLE);
            stmt.setMaxRows(1);
            stmt.setString(1, execId);

            ResultSet rs = stmt.executeQuery();
            boolean autoCommit = conn.getAutoCommit();
            try {
                conn.setAutoCommit(false);
                int index = 0;
                for (TestCase test : tests) {
                    index++;
                    rs.moveToInsertRow();

                    Integer tcid = idMap.get(test.format());
                    if (tcid == null) {
                        tcid = this.getTestCaseId(test);
                    }

                    rs.updateString(TestResult.TEST_RESULT_ID, Utils.getUniqueId());
                    rs.updateString(TestResult.SUITE_RESULT, execId);
                    rs.updateInt(TestResult.TEST_CASE_ID, tcid);
                    rs.updateString(TestResult.EXECUTION_RESULT, ExecutionResult.QUEUED.getName());
                    rs.updateLong(TestResult.START_TIME, System.currentTimeMillis());
                    rs.updateLong(TestResult.STOP_TIME, System.currentTimeMillis());
                    rs.updateString(TestResult.TEST_STATION, "?");
                    rs.updateString(TestResult.LOG_DIR, "?");

                    rs.insertRow();
                    rs.last();
                    rs.updateRow();
                    if (index % 100 == 0) {
                        conn.commit();
                    }
                }
                conn.commit();
            } finally {
                conn.setAutoCommit(autoCommit);
            }
        }
    }

    @Override
    public void updateSuiteExecutionResult(String execId) throws SQLException {
        LOG.info("Update test suite execution result with execution id {}", execId);
        String lock = "testharness." + execId;

        Connection conn = this.getConnection();
        try {
            if (!this.acquireExecutionLock(conn, lock)) {
                throw new SQLException("Cannot acquire lock of name " + lock);
            }

            int total = 0, fail = 0;
            final String sql1 = "SELECT " + TestResult.EXECUTION_RESULT + " FROM "
                + TestCase.TABLE_NAME + " WHERE " + TestResult.SUITE_RESULT
                + " = ?;";
            try (PreparedStatement stmt = this.getConnection().prepareStatement(sql1,
                ResultSet.TYPE_FORWARD_ONLY,
                ResultSet.CONCUR_READ_ONLY)) {
                stmt.setString(1, execId);
                stmt.setFetchSize(Integer.MIN_VALUE);
                ResultSet rs = stmt.executeQuery();
                while (rs.next()) {
                    total++;
                    String result = rs.getString(TestResult.EXECUTION_RESULT);
                    if (!result.equals(ExecutionResult.PASS.getName()) && !result.endsWith("/0")) {
                        fail++;
                    }
                }
            }

            final String sql2 = "SELECT * FROM " + SuiteResult.TABLE_NAME
                + " WHERE " + SuiteResult.SUITE_RESULT_ID + " = ?;";
            try (PreparedStatement stmt = this.getConnection().prepareStatement(sql2,
                ResultSet.TYPE_SCROLL_SENSITIVE,
                ResultSet.CONCUR_UPDATABLE)) {
                stmt.setString(1, execId);
                ResultSet rs = stmt.executeQuery();
                if (rs.first()) {
                    rs.updateInt(SuiteResult.NUMBER_OF_TESTS, total);
                    rs.updateInt(SuiteResult.NUMBER_OF_FAILURE, fail);
                    rs.updateString(SuiteResult.EXECUTION_RESULT, fail == 0 ? "PASS" : "FAIL");
                    rs.updateLong(SuiteResult.STOP_TIME, System.currentTimeMillis());
                    rs.updateRow();
                }
            }
        } finally {
            try {
                this.releaseExecutionLock(conn, lock);
            } finally {
                conn.close();
            }
        }
    }

    @Override
    protected boolean acquireExecutionLock(Connection conn, String lock) throws SQLException {
        final String sqlLock = String.format("SELECT pg_advisory_lock(%d);", this.hash(lock));
        LOG.debug("Acquire lock {}", lock);
        try (Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sqlLock)) {
            if (rs.next() && "1".equals(rs.getString(1))) {
                LOG.trace("{} is locked", lock);
            } else {
                return false;
            }
        }
        return true;
    }

    @Override
    protected boolean releaseExecutionLock(Connection conn, String lock) throws SQLException {
        final String sqlRelease = String.format("SELECT pg_advisory_unlock(%d);", this.hash(lock));
        LOG.debug("Release lock {}", lock);
        try (Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sqlRelease)) {
            if (rs.next() && "1".equals(rs.getString(1))) {
                LOG.trace("{} is released", lock);
            } else {
                return false;
            }
        } finally {
            conn.close();
        }
        return true;
    }

    public static void main(String[] args) throws SQLException {
        PostgresqlHandler db = new PostgresqlHandler();
        TestCase tc = new TestCase();
        tc.setSuiteClass("a");
        LOG.debug("test case id = {}", db.getTestCaseId(tc));
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy