/*
 * 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.facebook.presto.tests;

import com.facebook.presto.spi.ConnectorSession;
import com.facebook.presto.testing.MaterializedResult;
import com.facebook.presto.testing.QueryRunner;
import org.testng.annotations.Test;

import static com.facebook.presto.spi.type.BooleanType.BOOLEAN;
import static com.facebook.presto.spi.type.VarcharType.VARCHAR;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;

public abstract class AbstractTestIntegrationSmokeTest
        extends AbstractTestQueryFramework
{
    private final ConnectorSession sampledSession;

    public AbstractTestIntegrationSmokeTest(QueryRunner queryRunner, ConnectorSession sampledSession)
    {
        super(queryRunner);
        this.sampledSession = checkNotNull(sampledSession, "sampledSession is null");
    }

    @Test
    public void testAggregateSingleColumn()
            throws Exception
    {
        assertQuery("SELECT SUM(orderkey) FROM ORDERS");
        assertQuery("SELECT SUM(totalprice) FROM ORDERS");
        assertQuery("SELECT MAX(comment) FROM ORDERS");
    }

    @Test
    public void testApproximateQuerySum()
            throws Exception
    {
        assertApproximateQuery(sampledSession, "SELECT SUM(totalprice) FROM orders APPROXIMATE AT 99.999 CONFIDENCE", "SELECT 2 * SUM(totalprice) FROM orders");
    }

    @Test
    public void testColumnsInReverseOrder()
            throws Exception
    {
        assertQuery("SELECT shippriority, clerk, totalprice FROM ORDERS");
    }

    @Test
    public void testCountAll()
            throws Exception
    {
        assertQuery("SELECT COUNT(*) FROM ORDERS");
    }

    @Test
    public void testExactPredicate()
            throws Exception
    {
        assertQuery("SELECT * FROM ORDERS WHERE orderkey = 10");
    }

    @Test
    public void testInListPredicate()
            throws Exception
    {
        assertQuery("SELECT * FROM ORDERS WHERE orderkey IN (10, 11, 20, 21)");
    }

    @Test
    public void testIsNullPredicate()
            throws Exception
    {
        assertQuery("SELECT * FROM ORDERS WHERE orderkey = 10 OR orderkey IS NULL");
    }

    @Test
    public void testMultipleRangesPredicate()
            throws Exception
    {
        assertQuery("SELECT * FROM ORDERS WHERE orderkey BETWEEN 10 AND 50 or orderkey BETWEEN 100 AND 150");
    }

    @Test
    public void testRangePredicate()
            throws Exception
    {
        assertQuery("SELECT * FROM ORDERS WHERE orderkey BETWEEN 10 AND 50");
    }

    @Test
    public void testSelectAll()
            throws Exception
    {
        assertQuery("SELECT * FROM ORDERS");
    }

    @Test
    public void testTableSampleSystem()
            throws Exception
    {
        int total = computeActual("SELECT orderkey FROM orders").getMaterializedRows().size();

        boolean sampleSizeFound = false;
        for (int i = 0; i < 100; i++) {
            int sampleSize = computeActual("SELECT orderkey FROM ORDERS TABLESAMPLE SYSTEM (50)").getMaterializedRows().size();
            if (sampleSize > 0 && sampleSize < total) {
                sampleSizeFound = true;
                break;
            }
        }
        assertTrue(sampleSizeFound, "Table sample returned unexpected number of rows");
    }

    @Test
    public void testShowSchemas()
            throws Exception
    {
        MaterializedResult actualSchemas = computeActual("SHOW SCHEMAS").toJdbcTypes();
        MaterializedResult expectedSchemas = MaterializedResult.resultBuilder(queryRunner.getDefaultSession(), VARCHAR)
                .row("tpch")
                .row("tpch_sampled")
                .build();
        assertTrue(actualSchemas.getMaterializedRows().containsAll(expectedSchemas.getMaterializedRows()));
    }

    @Test
    public void testShowTables()
            throws Exception
    {
        MaterializedResult actualTables = computeActual("SHOW TABLES").toJdbcTypes();
        MaterializedResult expectedTables = MaterializedResult.resultBuilder(queryRunner.getDefaultSession(), VARCHAR)
                .row("orders")
                .build();
        assertEquals(actualTables, expectedTables);
    }

    @Test
    public void testDescribeTable()
            throws Exception
    {
        MaterializedResult actualColumns = computeActual("DESC ORDERS").toJdbcTypes();
        MaterializedResult expectedColumns = MaterializedResult.resultBuilder(queryRunner.getDefaultSession(), VARCHAR, VARCHAR, BOOLEAN, BOOLEAN, VARCHAR)
                .row("orderkey", "bigint", true, false, "")
                .row("custkey", "bigint", true, false, "")
                .row("orderstatus", "varchar", true, false, "")
                .row("totalprice", "double", true, false, "")
                .row("orderdate", "varchar", true, false, "")
                .row("orderpriority", "varchar", true, false, "")
                .row("clerk", "varchar", true, false, "")
                .row("shippriority", "bigint", true, false, "")
                .row("comment", "varchar", true, false, "")
                .build();
        assertEquals(actualColumns, expectedColumns);
    }
}

@@ -743,16 +743,103 @@
 Runner;%0A
+import com.google.common.base.Optional;%0Aimport org.intellij.lang.annotations.Language;%0A
 import o
@@ -1269,16 +1269,25 @@
 e final 
+Optional%3C
 Connecto
@@ -1286,32 +1286,33 @@
 ConnectorSession
+%3E
  sampledSession;
@@ -1318,21 +1318,385 @@
 ;%0A%0A    p
-ublic
+rotected AbstractTestIntegrationSmokeTest(QueryRunner queryRunner)%0A    %7B%0A        this(queryRunner, Optional.%3CConnectorSession%3Eabsent());%0A    %7D%0A%0A    protected AbstractTestIntegrationSmokeTest(QueryRunner queryRunner, ConnectorSession sampledSession)%0A    %7B%0A        this(queryRunner, Optional.of(checkNotNull(sampledSession, %22sampledSession is null%22)));%0A    %7D%0A%0A    private
  Abstrac
@@ -1738,32 +1738,41 @@
 er queryRunner, 
+Optional%3C
 ConnectorSession
@@ -1763,32 +1763,33 @@
 ConnectorSession
+%3E
  sampledSession)
@@ -2302,32 +2302,16 @@
 teQuery(
-sampledSession, 
 %22SELECT 
@@ -6217,11 +6217,289 @@
 );%0A    %7D
+%0A%0A    protected void assertApproximateQuery(@Language(%22SQL%22) String actual, @Language(%22SQL%22) String expected)%0A            throws Exception%0A    %7B%0A        if (sampledSession.isPresent()) %7B%0A            assertApproximateQuery(sampledSession.get(), actual, expected);%0A        %7D%0A    %7D
 %0A%7D%0A

Allow using smoke tests for non-sampled connectors