SQOOP-931: Integrate HCatalog with Sqoop
[sqoop.git] / src / test / com / cloudera / sqoop / hive / TestHiveImport.java
index 1ffd24f..9c47bad 100644 (file)
@@ -1,8 +1,8 @@
 /**
- * Licensed to Cloudera, Inc. under one
+ * 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.  Cloudera, Inc. licenses this file
+ * 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
@@ -32,6 +32,7 @@ import org.apache.hadoop.fs.Path;
 import org.junit.Test;
 
 import com.cloudera.sqoop.SqoopOptions;
+import com.cloudera.sqoop.SqoopOptions.InvalidOptionsException;
 import com.cloudera.sqoop.testutil.CommonArgs;
 import com.cloudera.sqoop.testutil.HsqldbTestServer;
 import com.cloudera.sqoop.testutil.ImportJobTestCase;
@@ -40,6 +41,7 @@ import com.cloudera.sqoop.tool.CodeGenTool;
 import com.cloudera.sqoop.tool.CreateHiveTableTool;
 import com.cloudera.sqoop.tool.ImportTool;
 import com.cloudera.sqoop.tool.SqoopTool;
+import org.apache.commons.cli.ParseException;
 
 /**
  * Test HiveImport capability after an import to HDFS.
@@ -49,6 +51,16 @@ public class TestHiveImport extends ImportJobTestCase {
   public static final Log LOG = LogFactory.getLog(
       TestHiveImport.class.getName());
 
+  public void setUp() {
+    super.setUp();
+    HiveImport.setTestMode(true);
+  }
+
+  public void tearDown() {
+    super.tearDown();
+    HiveImport.setTestMode(false);
+  }
+
   /**
    * Sets the expected number of columns in the table being manipulated
    * by the test. Under the hood, this sets the expected column names
@@ -107,6 +119,28 @@ public class TestHiveImport extends ImportJobTestCase {
   }
 
   /**
+   * @return the argv to supply to a create-table only job for Hive imports.
+   */
+  protected String [] getCreateTableArgv(boolean includeHadoopFlags,
+      String [] moreArgs) {
+
+    ArrayList<String> args = new ArrayList<String>();
+
+    if (null != moreArgs) {
+      for (String arg: moreArgs) {
+        args.add(arg);
+      }
+    }
+
+    args.add("--table");
+    args.add(getTableName());
+    args.add("--connect");
+    args.add(HsqldbTestServer.getUrl());
+
+    return args.toArray(new String[0]);
+  }
+
+  /**
    * @return the argv to supply to a code-gen only job for Hive imports.
    */
   protected String [] getCodeGenArgs() {
@@ -158,15 +192,16 @@ public class TestHiveImport extends ImportJobTestCase {
 
     // create a table and populate it with a row...
     createTableWithColTypes(types, values);
-    
+
     // set up our mock hive shell to compare our generated script
     // against the correct expected one.
     SqoopOptions options = getSqoopOptions(args, tool);
     String hiveHome = options.getHiveHome();
     assertNotNull("hive.home was not set", hiveHome);
-    Path testDataPath = new Path(new Path(hiveHome),
-        "scripts/" + verificationScript);
-    System.setProperty("expected.script", testDataPath.toString());
+    String testDataPath = new Path(new Path(hiveHome),
+        "scripts/" + verificationScript).toString();
+    System.setProperty("expected.script",
+        new File(testDataPath).getAbsolutePath());
 
     // verify that we can import it correctly into hive.
     runImport(tool, args);
@@ -245,7 +280,7 @@ public class TestHiveImport extends ImportJobTestCase {
     setNumCols(3);
     String [] types = { "VARCHAR(32)", "INTEGER", "CHAR(64)" };
     String [] vals = { "'test'", "42", "'somestring'" };
-    String [] extraArgs = {"--hive-overwrite"};
+    String [] extraArgs = {"--hive-overwrite", "--create-hive-table"};
     runImportTest(TABLE_NAME, types, vals,
         "createOverwriteImport.q", getCreateHiveTableArgs(extraArgs),
         new CreateHiveTableTool());
@@ -359,4 +394,153 @@ public class TestHiveImport extends ImportJobTestCase {
     }
   }
 
+  /**
+   * Test hive import with row that has new line in it.
+   */
+  @Test
+  public void testFieldWithHiveDelimsReplacement() throws IOException,
+    InterruptedException {
+    final String TABLE_NAME = "FIELD_WITH_NL_REPLACEMENT_HIVE_IMPORT";
+
+    LOG.info("Doing import of single row into "
+        + "FIELD_WITH_NL_REPLACEMENT_HIVE_IMPORT table");
+    setCurTableName(TABLE_NAME);
+    setNumCols(3);
+    String[] types = { "VARCHAR(32)", "INTEGER", "CHAR(64)" };
+    String[] vals = { "'test with\nnew lines\n'", "42",
+        "'oh no " + '\01' + " field delims " + '\01' + "'", };
+    String[] moreArgs = { "--"+BaseSqoopTool.HIVE_DELIMS_REPLACEMENT_ARG, " "};
+
+    runImportTest(TABLE_NAME, types, vals,
+        "fieldWithNewlineReplacementImport.q", getArgv(false, moreArgs),
+        new ImportTool());
+
+    LOG.info("Validating data in single row is present in: "
+          + "FIELD_WITH_NL_REPLACEMENT_HIVE_IMPORT table");
+
+    // Ideally, we would actually invoke hive code to verify that record with
+    // record and field delimiters have values replaced and that we have the
+    // proper number of hive records. Unfortunately, this is a non-trivial task,
+    // and better dealt with at an integration test level
+    //
+    // Instead, this assumes the path of the generated table and just validate
+    // map job output.
+
+    // Get and read the raw output file
+    String whDir = getWarehouseDir();
+    File p = new File(new File(whDir, TABLE_NAME), "part-m-00000");
+    File f = new File(p.toString());
+    FileReader fr = new FileReader(f);
+    BufferedReader br = new BufferedReader(fr);
+    try {
+      // verify the output
+      assertEquals(br.readLine(), "test with new lines " + '\01' + "42"
+          + '\01' + "oh no   field delims  ");
+      assertEquals(br.readLine(), null); // should only be one line
+    } catch (IOException ioe) {
+      fail("Unable to read files generated from hive");
+    } finally {
+      br.close();
+    }
+  }
+
+  /**
+   * Test hive drop and replace option validation.
+   */
+  @Test
+  public void testHiveDropAndReplaceOptionValidation() throws ParseException {
+    LOG.info("Testing conflicting Hive delimiter drop/replace options");
+
+    setNumCols(3);
+    String[] moreArgs = { "--"+BaseSqoopTool.HIVE_DELIMS_REPLACEMENT_ARG, " ",
+      "--"+BaseSqoopTool.HIVE_DROP_DELIMS_ARG, };
+
+    ImportTool tool = new ImportTool();
+    try {
+      tool.validateOptions(tool.parseArguments(getArgv(false, moreArgs), null,
+          null, true));
+      fail("Expected InvalidOptionsException");
+    } catch (InvalidOptionsException ex) {
+      /* success */
+    }
+  }
+
+  /**
+   * Test hive import with row that has new line in it.
+   */
+  @Test
+  public void testImportHiveWithPartitions() throws IOException,
+      InterruptedException {
+    final String TABLE_NAME = "PARTITION_HIVE_IMPORT";
+
+    LOG.info("Doing import of single row into PARTITION_HIVE_IMPORT table");
+    setCurTableName(TABLE_NAME);
+    setNumCols(3);
+    String[] types = { "VARCHAR(32)", "INTEGER", "CHAR(64)", };
+    String[] vals = { "'whoop'", "42", "'I am a row in a partition'", };
+    String[] moreArgs = { "--" + BaseSqoopTool.HIVE_PARTITION_KEY_ARG, "ds",
+        "--" + BaseSqoopTool.HIVE_PARTITION_VALUE_ARG, "20110413", };
+
+    runImportTest(TABLE_NAME, types, vals, "partitionImport.q",
+        getArgv(false, moreArgs), new ImportTool());
+  }
+
+  /**
+   * If partition key is set to one of importing columns, we should get an
+   * IOException.
+   * */
+  @Test
+  public void testImportWithBadPartitionKey() {
+    final String TABLE_NAME = "FAILING_PARTITION_HIVE_IMPORT";
+
+    LOG.info("Doing import of single row into " + TABLE_NAME + " table");
+    setCurTableName(TABLE_NAME);
+    setNumCols(3);
+    String[] types = { "VARCHAR(32)", "INTEGER", "CHAR(64)", };
+    String[] vals = { "'key'", "42", "'I am a row in a partition'", };
+
+    String partitionKey = getColNames()[0];
+
+    // Specify 1st column as partition key and import every column of the
+    // table by default (i.e. no --columns option).
+    String[] moreArgs1 = {
+        "--" + BaseSqoopTool.HIVE_PARTITION_KEY_ARG,
+        partitionKey,
+    };
+
+    // Specify 1st column as both partition key and importing column.
+    String[] moreArgs2 = {
+        "--" + BaseSqoopTool.HIVE_PARTITION_KEY_ARG,
+        partitionKey,
+        "--" + BaseSqoopTool.COLUMNS_ARG,
+        partitionKey,
+    };
+
+    // Test hive-import with the 1st args.
+    try {
+      runImportTest(TABLE_NAME, types, vals, "partitionImport.q",
+          getArgv(false, moreArgs1), new ImportTool());
+      fail(TABLE_NAME + " test should have thrown IOException");
+    } catch (IOException ioe) {
+      // expected; ok.
+    }
+
+    // Test hive-import with the 2nd args.
+    try {
+      runImportTest(TABLE_NAME, types, vals, "partitionImport.q",
+          getArgv(false, moreArgs2), new ImportTool());
+      fail(TABLE_NAME + " test should have thrown IOException");
+    } catch (IOException ioe) {
+      // expected; ok.
+    }
+
+    // Test create-hive-table with the 1st args.
+    try {
+      runImportTest(TABLE_NAME, types, vals, "partitionImport.q",
+          getCreateTableArgv(false, moreArgs1), new CreateHiveTableTool());
+      fail(TABLE_NAME + " test should have thrown IOException");
+    } catch (IOException ioe) {
+      // expected; ok.
+    }
+  }
 }