| /** |
| * 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.sqoop.manager.sqlserver; |
| |
| import java.io.FileWriter; |
| import java.io.IOException; |
| import java.sql.Connection; |
| import java.sql.PreparedStatement; |
| import java.sql.ResultSet; |
| import java.sql.SQLException; |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| import org.apache.hadoop.conf.Configuration; |
| import org.apache.hadoop.fs.FileSystem; |
| import org.apache.hadoop.fs.Path; |
| import org.apache.hadoop.util.StringUtils; |
| import org.apache.sqoop.manager.sqlserver.MSSQLTestData.KEY_STRINGS; |
| import org.apache.sqoop.manager.sqlserver.MSSQLTestDataFileParser.DATATYPES; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.apache.sqoop.Sqoop; |
| import org.apache.sqoop.SqoopOptions; |
| import org.apache.sqoop.testutil.ExportJobTestCase; |
| import org.apache.sqoop.tool.ExportTool; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assert.fail; |
| |
| /** |
| * Test utilities for export to SQL Server. |
| */ |
| public abstract class ManagerCompatExport extends ExportJobTestCase { |
| |
| private MSSQLTestDataFileParser tdfs; |
| |
| public void createTable(DATATYPES dt) throws SQLException { |
| String tname = getTableName(dt); |
| String createTableSql = "CREATE TABLE " + tname + " ( " + getColName() |
| + " " + dt.toString() + " )"; |
| |
| dropTableIfExists(tname); |
| |
| Connection conn = getManager().getConnection(); |
| PreparedStatement statement = conn.prepareStatement(createTableSql, |
| ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); |
| statement.executeUpdate(); |
| conn.commit(); |
| statement.close(); |
| |
| } |
| |
| public void createTable(DATATYPES dt, MSSQLTestData td) throws Exception { |
| String tname = getTableName(dt); |
| String scale = td.getData(KEY_STRINGS.SCALE); |
| String precision = td.getData(KEY_STRINGS.PREC); |
| String createTableSql = ""; |
| if (scale != null && precision != null) { |
| // this is decimal/numeric thing |
| createTableSql = "CREATE TABLE " + tname + " (" + getColName() |
| + " " + dt.toString() + "(" + scale + "," + precision |
| + ") )"; |
| } else if (scale != null && precision == null) { |
| // this is decimal/numeric thing |
| createTableSql = "CREATE TABLE " + tname + " ( " + getColName() |
| + " " + dt.toString() + "(" + scale + ") )"; |
| } else { |
| throw new Exception("Invalid data for create table"); |
| } |
| |
| dropTableIfExists(tname); |
| |
| Connection conn = getManager().getConnection(); |
| PreparedStatement statement = conn.prepareStatement(createTableSql, |
| ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); |
| statement.executeUpdate(); |
| conn.commit(); |
| statement.close(); |
| |
| } |
| |
| public String getColName() { |
| return "COL_1"; |
| } |
| |
| public String getTableName(DATATYPES dt) { |
| return "t_" + dt.toString(); |
| } |
| |
| public Path getTablePath(DATATYPES dt) { |
| Path warehousePath = new Path(getWarehouseDir()); |
| Path tablePath = new Path(warehousePath, getTableName(dt)); |
| return tablePath; |
| |
| } |
| |
| public abstract void createFile(DATATYPES dt, String[] data) |
| throws Exception; |
| |
| public abstract void createFile(DATATYPES dt, String data) throws Exception; |
| |
| @Test |
| public void testVarBinary() throws Exception { |
| |
| exportTestMethod(DATATYPES.VARBINARY); |
| |
| } |
| |
| @Test |
| public void testTime() throws Exception { |
| |
| exportTestMethod(DATATYPES.TIME); |
| |
| } |
| |
| @Test |
| public void testSmalldatetime() throws Exception { |
| |
| exportTestMethod(DATATYPES.SMALLDATETIME); |
| |
| } |
| |
| @Test |
| public void testdatetime2() throws Exception { |
| |
| exportTestMethod(DATATYPES.DATETIME2); |
| |
| } |
| |
| @Test |
| public void testdatetime() throws Exception { |
| |
| exportTestMethod(DATATYPES.DATETIME); |
| |
| } |
| |
| @Test |
| public void testdatetimeoffset() throws Exception { |
| |
| exportTestMethod(DATATYPES.DATETIMEOFFSET); |
| |
| } |
| |
| @Test |
| public void testDecimal() throws Exception { |
| exportTestMethod(DATATYPES.DECIMAL); |
| |
| } |
| |
| @Test |
| public void testNumeric() throws Exception { |
| exportTestMethod(DATATYPES.NUMERIC); |
| |
| } |
| |
| @Test |
| public void testBigInt() throws Exception { |
| |
| exportTestMethod(DATATYPES.BIGINT); |
| } |
| |
| @Test |
| public void testInt() throws Exception { |
| exportTestMethod(DATATYPES.INT); |
| |
| } |
| |
| @Test |
| public void testSmallInt() throws Exception { |
| exportTestMethod(DATATYPES.SMALLINT); |
| |
| } |
| |
| @Test |
| public void testTinyint() throws Exception { |
| exportTestMethod(DATATYPES.TINYINT); |
| |
| } |
| |
| @Test |
| public void testFloat() throws Exception { |
| exportTestMethod(DATATYPES.FLOAT); |
| |
| } |
| |
| @Test |
| public void testReal() throws Exception { |
| exportTestMethod(DATATYPES.REAL); |
| |
| } |
| |
| @Test |
| public void testDate() throws Exception { |
| exportTestMethod(DATATYPES.DATE); |
| |
| } |
| |
| @Test |
| public void testMoney() throws Exception { |
| exportTestMethod(DATATYPES.MONEY); |
| |
| } |
| |
| @Test |
| public void testSmallMoney() throws Exception { |
| exportTestMethod(DATATYPES.SMALLMONEY); |
| |
| } |
| |
| @Test |
| public void testText() throws Exception { |
| exportTestMethod(DATATYPES.TEXT); |
| |
| } |
| |
| @Test |
| public void testVarchar() throws Exception { |
| exportTestMethod(DATATYPES.VARCHAR); |
| |
| } |
| |
| @Test |
| public void testChar() throws Exception { |
| exportTestMethod(DATATYPES.CHAR); |
| |
| } |
| |
| @Test |
| public void testNText() throws Exception { |
| exportTestMethod(DATATYPES.NTEXT); |
| |
| } |
| |
| @Test |
| public void testNChar() throws Exception { |
| exportTestMethod(DATATYPES.NCHAR); |
| |
| } |
| |
| @Test |
| public void testNVarchar() throws Exception { |
| exportTestMethod(DATATYPES.NVARCHAR); |
| |
| } |
| |
| @Test |
| public void testImage() throws Exception { |
| exportTestMethod(DATATYPES.IMAGE); |
| |
| } |
| |
| @Test |
| public void testBinary() throws Exception { |
| exportTestMethod(DATATYPES.BINARY); |
| |
| } |
| |
| public void exportTestMethod(DATATYPES dt) throws SQLException { |
| int exceptionCount = 0; |
| |
| List testdata = tdfs.getTestdata(dt); |
| System.out.println("Total Samples found : " + testdata.size()); |
| for (Iterator<MSSQLTestData> itr = testdata.iterator(); itr.hasNext();) { |
| MSSQLTestData current = itr.next(); |
| System.out.println("Testing with : \n" + current); |
| |
| try { |
| |
| if (dt.equals(DATATYPES.INT) || dt.equals(DATATYPES.BIGINT) |
| || dt.equals(DATATYPES.SMALLINT) |
| || dt.equals(DATATYPES.TINYINT) |
| || dt.equals(DATATYPES.MONEY) |
| || dt.equals(DATATYPES.SMALLMONEY) |
| || dt.equals(DATATYPES.TIME) |
| || dt.equals(DATATYPES.DATETIME) |
| || dt.equals(DATATYPES.DATE) |
| || dt.equals(DATATYPES.DATETIME2) |
| || dt.equals(DATATYPES.DATETIMEOFFSET) |
| || dt.equals(DATATYPES.REAL) |
| || dt.equals(DATATYPES.FLOAT) |
| || dt.equals(DATATYPES.SMALLDATETIME) |
| || dt.equals(DATATYPES.NTEXT) |
| || dt.equals(DATATYPES.TEXT) |
| || dt.equals(DATATYPES.IMAGE)) { |
| |
| createTable(dt); |
| createFile(dt, current.getData(KEY_STRINGS.HDFS_READBACK)); |
| runExport(getArgv(dt)); |
| verifyExport(dt, current.getData(KEY_STRINGS.DB_READBACK)); |
| addToReport(current, null); |
| } else if (dt.equals(DATATYPES.DECIMAL) |
| || (dt.equals(DATATYPES.NUMERIC) |
| || dt.equals(DATATYPES.CHAR) |
| || dt.equals(DATATYPES.VARCHAR) |
| || dt.equals(DATATYPES.NCHAR) |
| || dt.equals(DATATYPES.NVARCHAR) |
| || dt.equals(DATATYPES.VARBINARY) || dt |
| .equals(DATATYPES.BINARY))) { |
| |
| createTable(dt, current); |
| createFile(dt, current.getData(KEY_STRINGS.HDFS_READBACK)); |
| runExport(getArgv(dt)); |
| verifyExport(dt, current.getData(KEY_STRINGS.DB_READBACK)); |
| addToReport(current, null); |
| } |
| |
| } catch (AssertionError ae) { |
| if (current.getData(KEY_STRINGS.NEG_POS_FLAG).equals("NEG")) { |
| System.out.println("failure was expected, PASS"); |
| addToReport(current, null); |
| } else { |
| System.out |
| .println("------------------------------------------------------" |
| + "-----"); |
| System.out.println("Failure for following Test Data :\n" |
| + current.toString()); |
| System.out |
| .println("------------------------------------------------------" |
| + "-----"); |
| System.out.println("Exception details : \n"); |
| System.out.println(ae.getMessage()); |
| System.out |
| .println("------------------------------------------------------" |
| + "-----"); |
| addToReport(current, ae); |
| exceptionCount++; |
| |
| } |
| |
| } catch (Exception ae) { |
| if (current.getData(KEY_STRINGS.NEG_POS_FLAG).equals("NEG")) { |
| System.out.println("failure was expected, PASS"); |
| addToReport(current, null); |
| } else { |
| System.out |
| .println("------------------------------------------------------" |
| + "-----"); |
| System.out.println("Failure for following Test Data :\n" |
| + current.toString()); |
| System.out |
| .println("------------------------------------------------------" |
| + "-----"); |
| System.out.println("Exception details : \n"); |
| System.out.println(ae.getMessage()); |
| System.out |
| .println("------------------------------------------------------" |
| + "-----"); |
| addToReport(current, ae); |
| exceptionCount++; |
| |
| } |
| |
| } catch (Error e) { |
| addToReport(current, e); |
| exceptionCount++; |
| } finally { |
| dropTableIfExists(getTableName(dt)); |
| } |
| } |
| if (exceptionCount > 0) { |
| |
| System.out.println("There were failures for :" + dt.toString()); |
| System.out.println("Failed for " + exceptionCount + "/" |
| + testdata.size() + " test data samples\n"); |
| System.out.println("Scroll up for detailed errors"); |
| System.out |
| .println("----------------------------------------------------------" |
| + "-"); |
| throw new AssertionError("Failed for " + exceptionCount |
| + " test data sample"); |
| } |
| |
| } |
| |
| public void verifyExport(DATATYPES dt, String[] data) throws SQLException { |
| LOG.info("Verifying export: " + getTableName()); |
| // Check that we got back the correct number of records. |
| Connection conn = getManager().getConnection(); |
| |
| PreparedStatement statement = conn.prepareStatement("SELECT " |
| + getColName() + " FROM " + getTableName(dt), |
| ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); |
| System.out.println("data samples being compared : " + data.length); |
| |
| ResultSet rs = null; |
| try { |
| rs = statement.executeQuery(); |
| int cnt = 0; |
| try { |
| while (rs.next()) { |
| String tmp = rs.getString(1); |
| String expected = data[cnt++]; |
| System.out.println("Readback, expected" + tmp + " :" |
| + expected); |
| if (tmp == null) { |
| assertNull("Must be null", expected); |
| } else { |
| assertEquals("Data must match", expected, tmp); |
| } |
| } |
| System.out.println("expected samples : " + data.length |
| + " Actual samples : " + cnt); |
| assertEquals("Resultset must contain expected samples", |
| data.length, cnt); |
| } finally { |
| |
| rs.close(); |
| } |
| } finally { |
| statement.close(); |
| } |
| |
| } |
| |
| public void verifyExport(DATATYPES dt, String data) throws SQLException { |
| verifyExport(dt, new String[] { data }); |
| |
| } |
| |
| /** |
| * Run a MapReduce-based export (using the argv provided to control |
| * execution). |
| * |
| * @return the generated jar filename |
| */ |
| protected List<String> runExport(String[] argv) throws IOException { |
| // run the tool through the normal entry-point. |
| int ret; |
| List<String> generatedJars = null; |
| try { |
| ExportTool exporter = new ExportTool(); |
| |
| Sqoop sqoop = new Sqoop(exporter); |
| |
| String username = MSSQLTestUtils.getDBUserName(); |
| String password = MSSQLTestUtils.getDBPassWord(); |
| sqoop.getOptions().setUsername(username); |
| sqoop.getOptions().setPassword(password); |
| |
| ret = Sqoop.runSqoop(sqoop, argv); |
| generatedJars = exporter.getGeneratedJarFiles(); |
| } catch (Exception e) { |
| LOG.error("Got exception running Sqoop: " |
| + StringUtils.stringifyException(e)); |
| ret = 1; |
| } |
| |
| // expect a successful return. |
| if (0 != ret) { |
| throw new IOException("Failure during job; return status " + ret); |
| } |
| |
| return generatedJars; |
| } |
| |
| @Before |
| public void setUp() { |
| // start the server |
| super.setUp(); |
| String warehouseDir = getWarehouseDir(); |
| Path tablePath = new Path(warehouseDir); |
| try { |
| String testfile = System.getProperty("test.data.dir") |
| + "/" + System.getProperty("ms.datatype.test.data.file.export"); |
| String delim = System.getProperty("ms.datatype.test.data.file.delim", ","); |
| tdfs = new MSSQLTestDataFileParser(testfile); |
| tdfs.setDelim(delim); |
| tdfs.parse(); |
| } catch (Exception e) { |
| LOG.error(StringUtils.stringifyException(e)); |
| System.out.println("Error with test data file;"); |
| System.out |
| .println("check stack trace for cause.\nTests cannont continue."); |
| System.exit(0); |
| } |
| try { |
| FileSystem fs = FileSystem.get(new Configuration()); |
| fs.delete(tablePath, true); |
| System.out.println("Warehouse dir deleted"); |
| } catch (IOException e) { |
| LOG.error("Setup fail with IOException: " + |
| StringUtils.stringifyException(e)); |
| } |
| if (useHsqldbTestServer()) { |
| // throw away any existing data that might be in the database. |
| try { |
| this.getTestServer().dropExistingSchema(); |
| } catch (SQLException sqlE) { |
| LOG.error("Setup fail with SQLException: " + |
| StringUtils.stringifyException(sqlE)); |
| fail(sqlE.toString()); |
| } |
| } |
| } |
| |
| protected boolean useHsqldbTestServer() { |
| return false; |
| } |
| |
| @Override |
| protected String getConnectString() { |
| return MSSQLTestUtils.getDBConnectString(); |
| } |
| |
| /** |
| * Drop a table if it already exists in the database. |
| * |
| * @param table |
| * the name of the table to drop. |
| * @throws SQLException |
| * if something goes wrong. |
| */ |
| protected void dropTableIfExists(String table) throws SQLException { |
| Connection conn = getManager().getConnection(); |
| System.out.println("DROPing Table " + table); |
| String sqlStmt = "IF OBJECT_ID('" + table |
| + "') IS NOT NULL DROP TABLE " + table; |
| PreparedStatement statement = conn.prepareStatement(sqlStmt, |
| ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); |
| try { |
| statement.executeUpdate(); |
| conn.commit(); |
| } finally { |
| statement.close(); |
| } |
| } |
| |
| protected SqoopOptions getSqoopOptions(Configuration conf) { |
| |
| String username = MSSQLTestUtils.getDBUserName(); |
| String password = MSSQLTestUtils.getDBPassWord(); |
| SqoopOptions opts = new SqoopOptions(conf); |
| opts.setUsername(username); |
| opts.setPassword(password); |
| return opts; |
| |
| } |
| |
| protected String[] getArgv(DATATYPES dt) { |
| ArrayList<String> args = new ArrayList<String>(); |
| |
| args.add("--table"); |
| args.add(getTableName(dt)); |
| args.add("--export-dir"); |
| args.add(getTablePath(dt).toString()); |
| args.add("--connect"); |
| args.add(getConnectString()); |
| args.add("--fields-terminated-by"); |
| args.add(","); |
| args.add("--lines-terminated-by"); |
| args.add("\\n"); |
| args.add("-m"); |
| args.add("1"); |
| |
| LOG.debug("args:"); |
| for (String a : args) { |
| LOG.debug(" " + a); |
| } |
| |
| return args.toArray(new String[0]); |
| } |
| |
| public String getOutputFileName() { |
| return "ManagerCompatExport.txt"; |
| } |
| |
| public void addToReport(MSSQLTestData td, Object result) { |
| try { |
| FileWriter fr = new FileWriter(getOutputFileName(), true); |
| String offset = td.getData(KEY_STRINGS.OFFSET); |
| String dt = td.getDatatype(); |
| String res = "_"; |
| if (result == null) { |
| res = "Success"; |
| } else { |
| try { |
| res = "FAILED " |
| + removeNewLines(((AssertionError) result) |
| .getMessage()); |
| |
| } catch (Exception ae) { |
| if (result instanceof Exception) { |
| res = "FAILED " |
| + removeNewLines(((Exception) result) |
| .getMessage()); |
| } else { |
| res = "FAILED " + result.toString(); |
| } |
| } |
| } |
| |
| fr.append(offset + "\t" + "\t" + res + "\t" + dt + "\t" |
| + removeNewLines(td.toString()) + "\n"); |
| fr.close(); |
| } catch (Exception e) { |
| LOG.error(StringUtils.stringifyException(e)); |
| } |
| |
| } |
| |
| public static String removeNewLines(String str) { |
| if (str != null) { |
| String[] tmp = str.split("\n"); |
| String result = ""; |
| for (String a : tmp) { |
| result += " " + a; |
| } |
| return result; |
| } else { |
| return ""; |
| } |
| } |
| |
| } |