/**
 * 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 com.cloudera.sqoop.metastore;

import java.sql.SQLException;
import java.sql.Statement;

import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.apache.hadoop.conf.Configuration;

import com.cloudera.sqoop.SqoopOptions;
import com.cloudera.sqoop.manager.HsqldbManager;
import com.cloudera.sqoop.metastore.hsqldb.AutoHsqldbStorage;
import com.cloudera.sqoop.tool.VersionTool;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import java.io.IOException;
import java.sql.Connection;

import static org.junit.Assert.assertEquals;

/**
 * Test the metastore and job-handling features.
 *
 * These all make use of the auto-connect hsqldb-based metastore.
 * The metastore URL is configured to be in-memory, and drop all
 * state between individual tests.
 */
public class TestSavedJobs {

  public static final String TEST_AUTOCONNECT_URL =
      "jdbc:hsqldb:mem:sqoopmetastore";
  public static final String TEST_AUTOCONNECT_USER = "SA";
  public static final String TEST_AUTOCONNECT_PASS = "";

  @Rule
  public ExpectedException thrown = ExpectedException.none();

  @Before
  public void setUp() throws Exception {
    // Delete db state between tests.
    resetJobSchema();
  }

  public static void resetJobSchema() throws SQLException {
    SqoopOptions options = new SqoopOptions();
    options.setConnectString(TEST_AUTOCONNECT_URL);
    options.setUsername(TEST_AUTOCONNECT_USER);
    options.setPassword(TEST_AUTOCONNECT_PASS);

    resetSchema(options);
  }

  /**
   * Drop all tables in the configured HSQLDB-based schema/user/pass.
   */
  public static void resetSchema(SqoopOptions options) throws SQLException {
    HsqldbManager manager = new HsqldbManager(options);
    Connection c = manager.getConnection();
    Statement s = c.createStatement();
    try {
      String [] tables = manager.listTables();
      for (String table : tables) {
        s.executeUpdate("DROP TABLE " + manager.escapeTableName(table));
      }

      c.commit();
    } finally {
      s.close();
    }
  }

  public static Configuration newConf() {
    Configuration conf = new Configuration();
    conf.set(AutoHsqldbStorage.AUTO_STORAGE_USER_KEY, TEST_AUTOCONNECT_USER);
    conf.set(AutoHsqldbStorage.AUTO_STORAGE_PASS_KEY, TEST_AUTOCONNECT_PASS);
    conf.set(AutoHsqldbStorage.AUTO_STORAGE_CONNECT_STRING_KEY,
        TEST_AUTOCONNECT_URL);

    return conf;
  }

  @Test
  public void testAutoConnect() throws IOException {
    // By default, we should be able to auto-connect with an
    // empty connection descriptor. We should see an empty
    // job set.

    Configuration conf = newConf();
    JobStorageFactory ssf = new JobStorageFactory(conf);

    Map<String, String> descriptor = new TreeMap<String, String>();
    JobStorage storage = ssf.getJobStorage(descriptor);

    storage.open(descriptor);
    List<String> jobs = storage.list();
    assertEquals(0, jobs.size());
    storage.close();
  }

  @Test
  public void testCreateSameJob() throws IOException {
    Configuration conf = newConf();
    JobStorageFactory ssf = new JobStorageFactory(conf);

    Map<String, String> descriptor = new TreeMap<String, String>();
    JobStorage storage = ssf.getJobStorage(descriptor);

    storage.open(descriptor);

    // Job list should start out empty.
    List<String> jobs = storage.list();
    assertEquals(0, jobs.size());

    // Create a job that displays the version.
    JobData data = new JobData(new SqoopOptions(), new VersionTool());
    storage.create("versionJob", data);

    jobs = storage.list();
    assertEquals(1, jobs.size());
    assertEquals("versionJob", jobs.get(0));

    try {
      // Try to create that same job name again. This should fail.
      thrown.expect(IOException.class);
      thrown.reportMissingExceptionWithMessage("Expected IOException since job already exists");
      storage.create("versionJob", data);
    } finally {
      jobs = storage.list();
      assertEquals(1, jobs.size());

      // Restore our job, check that it exists.
      JobData outData = storage.read("versionJob");
      assertEquals(new VersionTool().getToolName(),
          outData.getSqoopTool().getToolName());

      storage.close();
    }
  }

  @Test
  public void testDeleteJob() throws IOException {
    Configuration conf = newConf();
    JobStorageFactory ssf = new JobStorageFactory(conf);

    Map<String, String> descriptor = new TreeMap<String, String>();
    JobStorage storage = ssf.getJobStorage(descriptor);

    storage.open(descriptor);

    // Job list should start out empty.
    List<String> jobs = storage.list();
    assertEquals(0, jobs.size());

    // Create a job that displays the version.
    JobData data = new JobData(new SqoopOptions(), new VersionTool());
    storage.create("versionJob", data);

    jobs = storage.list();
    assertEquals(1, jobs.size());
    assertEquals("versionJob", jobs.get(0));

    // Now delete the job.
    storage.delete("versionJob");

    // After delete, we should have no jobs.
    jobs = storage.list();
    assertEquals(0, jobs.size());

    storage.close();
  }

  @Test
  public void testRestoreNonExistingJob() throws IOException {
    Configuration conf = newConf();
    JobStorageFactory ssf = new JobStorageFactory(conf);

    Map<String, String> descriptor = new TreeMap<String, String>();
    JobStorage storage = ssf.getJobStorage(descriptor);

    storage.open(descriptor);

    try {
      // Try to restore a job that doesn't exist. Watch it fail.
      thrown.expect(IOException.class);
      thrown.reportMissingExceptionWithMessage("Expected IOException since job doesn't exist");
      storage.read("DoesNotExist");
    } finally {
      storage.close();
    }
  }

  @Test
    public void testCreateJobWithExtraArgs() throws IOException {
        Configuration conf = newConf();
        JobStorageFactory ssf = new JobStorageFactory(conf);

        Map<String, String> descriptor = new TreeMap<String, String>();
        JobStorage storage = ssf.getJobStorage(descriptor);

        storage.open(descriptor);

        // Job list should start out empty.
        List<String> jobs = storage.list();
        assertEquals(0, jobs.size());

        // Create a job with extra args
        com.cloudera.sqoop.SqoopOptions opts = new SqoopOptions();
        String[] args = {"-schema", "test"};
        opts.setExtraArgs(args);
        JobData data = new JobData(opts, new VersionTool());
        storage.create("versionJob", data);

        jobs = storage.list();
        assertEquals(1, jobs.size());
        assertEquals("versionJob", jobs.get(0));

        // Restore our job, check that it exists.
        JobData outData = storage.read("versionJob");
        assertEquals(new VersionTool().getToolName(),
                outData.getSqoopTool().getToolName());

        String[] storedArgs = outData.getSqoopOptions().getExtraArgs();
        for(int index = 0; index < args.length; ++index) {
            assertEquals(args[index], storedArgs[index]);
        }

        // Now delete the job.
        storage.delete("versionJob");

        storage.close();
    }

  @Test
  public void testMultiConnections() throws IOException {
    // Ensure that a job can be retrieved when the storage is
    // closed and reopened.

    Configuration conf = newConf();
    JobStorageFactory ssf = new JobStorageFactory(conf);

    Map<String, String> descriptor = new TreeMap<String, String>();
    JobStorage storage = ssf.getJobStorage(descriptor);

    storage.open(descriptor);

    // Job list should start out empty.
    List<String> jobs = storage.list();
    assertEquals(0, jobs.size());

    // Create a job that displays the version.
    JobData data = new JobData(new SqoopOptions(), new VersionTool());
    storage.create("versionJob", data);

    jobs = storage.list();
    assertEquals(1, jobs.size());
    assertEquals("versionJob", jobs.get(0));

    storage.close(); // Close the existing connection

    // Now re-open the storage.
    ssf = new JobStorageFactory(newConf());
    storage = ssf.getJobStorage(descriptor);
    storage.open(descriptor);

    jobs = storage.list();
    assertEquals(1, jobs.size());
    assertEquals("versionJob", jobs.get(0));

    // Restore our job, check that it exists.
    JobData outData = storage.read("versionJob");
    assertEquals(new VersionTool().getToolName(),
        outData.getSqoopTool().getToolName());

    storage.close();
  }

}

