You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sqoop.apache.org by ja...@apache.org on 2015/02/04 05:25:23 UTC

[2/2] sqoop git commit: SQOOP-1591: Sqoop2: PostgreSQL integration tests

SQOOP-1591: Sqoop2: PostgreSQL integration tests

(Abraham Elmahrek via Jarek Jarcec Cecho)


Project: http://git-wip-us.apache.org/repos/asf/sqoop/repo
Commit: http://git-wip-us.apache.org/repos/asf/sqoop/commit/332a7bdd
Tree: http://git-wip-us.apache.org/repos/asf/sqoop/tree/332a7bdd
Diff: http://git-wip-us.apache.org/repos/asf/sqoop/diff/332a7bdd

Branch: refs/heads/sqoop2
Commit: 332a7bdd80bad2e9905ab5c9d2abe64a43b0728a
Parents: 27d87b4
Author: Jarek Jarcec Cecho <ja...@apache.org>
Authored: Tue Feb 3 20:25:04 2015 -0800
Committer: Jarek Jarcec Cecho <ja...@apache.org>
Committed: Tue Feb 3 20:25:04 2015 -0800

----------------------------------------------------------------------
 .../sqoop/common/test/db/DatabaseProvider.java  |  92 ++++-
 .../sqoop/common/test/db/DerbyProvider.java     |   5 +
 .../sqoop/common/test/db/NetezzaProvider.java   |   5 +
 .../sqoop/common/test/db/OracleProvider.java    |   5 +
 .../common/test/db/PostgreSQLProvider.java      |   5 +
 .../sqoop/common/test/db/SqlServerProvider.java |   5 +
 .../sqoop/common/test/db/TeradataProvider.java  |   5 +
 repository/repository-postgresql/pom.xml        |  64 +++-
 .../postgresql/PostgresqlRepoConstants.java     |   2 +-
 .../postgresql/PostgresqlRepositoryHandler.java |  43 ++-
 .../postgresql/PostgresqlTestCase.java          | 166 +++++++++
 .../postgresql/PostgresqlTestUtils.java         |  96 +++++
 .../postgresql/TestConnectorHandling.java       | 152 ++++++++
 .../postgresql/TestDriverHandling.java          |  85 +++++
 .../repository/postgresql/TestJobHandling.java  | 289 +++++++++++++++
 .../repository/postgresql/TestLinkHandling.java | 284 +++++++++++++++
 .../repository/postgresql/TestStructure.java    |  78 ++++
 .../postgresql/TestSubmissionHandling.java      | 353 +++++++++++++++++++
 .../postgresql/PostgresqlTestCase.java          |  59 ----
 .../postgresql/PostgresqlTestUtils.java         |  96 -----
 .../repository/postgresql/TestStructure.java    |  77 ----
 .../sqoop/test/testcases/ConnectorTestCase.java |  10 +-
 .../jdbc/generic/FromHDFSToRDBMSTest.java       |   2 +-
 .../jdbc/generic/TableStagedRDBMSTest.java      |   4 +-
 24 files changed, 1714 insertions(+), 268 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/sqoop/blob/332a7bdd/common-test/src/main/java/org/apache/sqoop/common/test/db/DatabaseProvider.java
----------------------------------------------------------------------
diff --git a/common-test/src/main/java/org/apache/sqoop/common/test/db/DatabaseProvider.java b/common-test/src/main/java/org/apache/sqoop/common/test/db/DatabaseProvider.java
index 82289e8..be04caa 100644
--- a/common-test/src/main/java/org/apache/sqoop/common/test/db/DatabaseProvider.java
+++ b/common-test/src/main/java/org/apache/sqoop/common/test/db/DatabaseProvider.java
@@ -22,6 +22,7 @@ import org.apache.log4j.Logger;
 
 import java.sql.Connection;
 import java.sql.DriverManager;
+import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
@@ -89,6 +90,20 @@ abstract public class DatabaseProvider {
   abstract public String escapeTableName(String tableName);
 
   /**
+   * Escape schema name based on specific database requirements.
+   *
+   * @param schemaName Schema name
+   * @return Escaped schemaname
+   */
+  public String escapeSchemaName(String schemaName) {
+    if (!isSupportingScheme()) {
+      throw new UnsupportedOperationException("Schema is not supported in this database");
+    }
+
+    return schemaName;
+  }
+
+  /**
    * Escape string value that can be safely used in the queries.
    *
    * @param value String value
@@ -119,6 +134,26 @@ abstract public class DatabaseProvider {
   }
 
   /**
+   * Get full table name with qualifications
+   * @param schemaName
+   * @param tableName
+   * @param escape
+   * @return String table name
+   */
+  public String getTableName(String schemaName, String tableName, boolean escape) {
+    StringBuilder sb = new StringBuilder();
+
+    if (schemaName != null) {
+      sb.append(escape ? escapeSchemaName(schemaName) : schemaName);
+      sb.append(".");
+    }
+
+    sb.append(escape ? escapeTableName(tableName) : tableName);
+
+    return sb.toString();
+  }
+
+  /**
    * Start the handler.
    */
   public void start() {
@@ -217,6 +252,46 @@ abstract public class DatabaseProvider {
   }
 
   /**
+   * Execute given insert query in a new statement object and return
+   * generated IDs.
+   *
+   * @param query Query to execute
+   * @return Generated ID.
+   */
+  public Long executeInsertQuery(String query, Object... args) {
+    LOG.info("Executing query: " + query);
+    ResultSet rs = null;
+
+    try {
+      PreparedStatement stmt = databaseConnection.prepareStatement(query, PreparedStatement.RETURN_GENERATED_KEYS);
+      for (int i = 0; i < args.length; ++i) {
+        if (args[i] instanceof String) {
+          stmt.setString(i + 1, (String) args[i]);
+        } else if (args[i] instanceof Long) {
+          stmt.setLong(i + 1, (Long) args[i]);
+        } else if (args[i] instanceof Boolean) {
+          stmt.setBoolean(i + 1, (Boolean) args[i]);
+        } else {
+          stmt.setObject(i + 1, args[i]);
+        }
+      }
+
+      stmt.execute();
+      rs = stmt.getGeneratedKeys();
+      if (rs.next()) {
+        return rs.getLong(1);
+      }
+    } catch (SQLException e) {
+      LOG.error("Error in executing query", e);
+      throw new RuntimeException("Error in executing query", e);
+    } finally {
+      closeResultSetWithStatement(rs);
+    }
+
+    return -1L;
+  }
+
+  /**
    * Create new table.
    *
    * @param name Table name
@@ -357,7 +432,7 @@ abstract public class DatabaseProvider {
    */
   public void dropSchema(String schemaName) {
     StringBuilder sb = new StringBuilder("DROP SCHEMA ");
-    sb.append(escapeTableName(schemaName));
+    sb.append(escapeSchemaName(schemaName));
     sb.append(" CASCADE");
 
     try {
@@ -370,12 +445,13 @@ abstract public class DatabaseProvider {
   /**
    * Return number of rows from given table.
    *
+   * @param schemaName Schema name
    * @param tableName Table name
    * @return Number of rows
    */
-  public long rowCount(String tableName) {
+  public long rowCount(String schemaName, String tableName) {
     StringBuilder sb = new StringBuilder("SELECT COUNT(*) FROM ");
-    sb.append(escapeTableName(tableName));
+    sb.append(getTableName(schemaName, tableName, true));
 
     ResultSet rs = null;
     try {
@@ -394,6 +470,16 @@ abstract public class DatabaseProvider {
   }
 
   /**
+   * Return number of rows from a given table.
+   *
+   * @param tableName
+   * @return Number of rows
+   */
+  public long rowCount(String tableName) {
+    return rowCount(null, tableName);
+  }
+
+  /**
    * Close given result set (if not null) and associated statement.
    *
    * @param rs ResultSet to close.

http://git-wip-us.apache.org/repos/asf/sqoop/blob/332a7bdd/common-test/src/main/java/org/apache/sqoop/common/test/db/DerbyProvider.java
----------------------------------------------------------------------
diff --git a/common-test/src/main/java/org/apache/sqoop/common/test/db/DerbyProvider.java b/common-test/src/main/java/org/apache/sqoop/common/test/db/DerbyProvider.java
index 98591a3..cf981f5 100644
--- a/common-test/src/main/java/org/apache/sqoop/common/test/db/DerbyProvider.java
+++ b/common-test/src/main/java/org/apache/sqoop/common/test/db/DerbyProvider.java
@@ -128,6 +128,11 @@ public class DerbyProvider extends DatabaseProvider {
   }
 
   @Override
+  public String escapeSchemaName(String schemaName) {
+    return escape(schemaName);
+  }
+
+  @Override
   public String escapeValueString(String value) {
     return "'" + value + "'";
   }

http://git-wip-us.apache.org/repos/asf/sqoop/blob/332a7bdd/common-test/src/main/java/org/apache/sqoop/common/test/db/NetezzaProvider.java
----------------------------------------------------------------------
diff --git a/common-test/src/main/java/org/apache/sqoop/common/test/db/NetezzaProvider.java b/common-test/src/main/java/org/apache/sqoop/common/test/db/NetezzaProvider.java
index d31bf28..842bd9d 100644
--- a/common-test/src/main/java/org/apache/sqoop/common/test/db/NetezzaProvider.java
+++ b/common-test/src/main/java/org/apache/sqoop/common/test/db/NetezzaProvider.java
@@ -67,6 +67,11 @@ public class NetezzaProvider extends DatabaseProvider {
     return escapeObjectName(tableName);
   }
 
+  @Override
+  public String escapeSchemaName(String schemaName) {
+    return schemaName;
+  }
+
   public String escapeObjectName(String name) {
     return '"' + name + '"';
   }

http://git-wip-us.apache.org/repos/asf/sqoop/blob/332a7bdd/common-test/src/main/java/org/apache/sqoop/common/test/db/OracleProvider.java
----------------------------------------------------------------------
diff --git a/common-test/src/main/java/org/apache/sqoop/common/test/db/OracleProvider.java b/common-test/src/main/java/org/apache/sqoop/common/test/db/OracleProvider.java
index ed29a23..b5f3104 100644
--- a/common-test/src/main/java/org/apache/sqoop/common/test/db/OracleProvider.java
+++ b/common-test/src/main/java/org/apache/sqoop/common/test/db/OracleProvider.java
@@ -68,6 +68,11 @@ public class OracleProvider extends DatabaseProvider {
   }
 
   @Override
+  public String escapeSchemaName(String schemaName) {
+    return escape(schemaName);
+  }
+
+  @Override
   public String escapeValueString(String value) {
     return "'" + value + "'";
   }

http://git-wip-us.apache.org/repos/asf/sqoop/blob/332a7bdd/common-test/src/main/java/org/apache/sqoop/common/test/db/PostgreSQLProvider.java
----------------------------------------------------------------------
diff --git a/common-test/src/main/java/org/apache/sqoop/common/test/db/PostgreSQLProvider.java b/common-test/src/main/java/org/apache/sqoop/common/test/db/PostgreSQLProvider.java
index d46e01d..c48b2f3 100644
--- a/common-test/src/main/java/org/apache/sqoop/common/test/db/PostgreSQLProvider.java
+++ b/common-test/src/main/java/org/apache/sqoop/common/test/db/PostgreSQLProvider.java
@@ -68,6 +68,11 @@ public class PostgreSQLProvider extends DatabaseProvider {
   }
 
   @Override
+  public String escapeSchemaName(String schemaName) {
+    return escape(schemaName);
+  }
+
+  @Override
   public String escapeValueString(String value) {
     return "'" + value + "'";
   }

http://git-wip-us.apache.org/repos/asf/sqoop/blob/332a7bdd/common-test/src/main/java/org/apache/sqoop/common/test/db/SqlServerProvider.java
----------------------------------------------------------------------
diff --git a/common-test/src/main/java/org/apache/sqoop/common/test/db/SqlServerProvider.java b/common-test/src/main/java/org/apache/sqoop/common/test/db/SqlServerProvider.java
index 9c56886..b8d037f 100644
--- a/common-test/src/main/java/org/apache/sqoop/common/test/db/SqlServerProvider.java
+++ b/common-test/src/main/java/org/apache/sqoop/common/test/db/SqlServerProvider.java
@@ -68,6 +68,11 @@ public class SqlServerProvider extends DatabaseProvider {
   }
 
   @Override
+  public String escapeSchemaName(String schemaName) {
+    return escape(schemaName);
+  }
+
+  @Override
   public String escapeValueString(String value) {
     return "'" + value + "'";
   }

http://git-wip-us.apache.org/repos/asf/sqoop/blob/332a7bdd/common-test/src/main/java/org/apache/sqoop/common/test/db/TeradataProvider.java
----------------------------------------------------------------------
diff --git a/common-test/src/main/java/org/apache/sqoop/common/test/db/TeradataProvider.java b/common-test/src/main/java/org/apache/sqoop/common/test/db/TeradataProvider.java
index f99d1ed..eb4e1fe 100644
--- a/common-test/src/main/java/org/apache/sqoop/common/test/db/TeradataProvider.java
+++ b/common-test/src/main/java/org/apache/sqoop/common/test/db/TeradataProvider.java
@@ -68,6 +68,11 @@ public class TeradataProvider extends DatabaseProvider {
   }
 
   @Override
+  public String escapeSchemaName(String schemaName) {
+    return schemaName;
+  }
+
+  @Override
   public String escapeValueString(String value) {
     return "'" + value + "'";
   }

http://git-wip-us.apache.org/repos/asf/sqoop/blob/332a7bdd/repository/repository-postgresql/pom.xml
----------------------------------------------------------------------
diff --git a/repository/repository-postgresql/pom.xml b/repository/repository-postgresql/pom.xml
index 0ee9081..bb3859f 100644
--- a/repository/repository-postgresql/pom.xml
+++ b/repository/repository-postgresql/pom.xml
@@ -70,7 +70,69 @@ limitations under the License.
       <type>test-jar</type>
       <scope>test</scope>
     </dependency>
-
   </dependencies>
 
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <excludedGroups>postgresql</excludedGroups>
+
+          <excludes>
+            <exclude>**/integration/**</exclude>
+          </excludes>
+          <systemPropertyVariables>
+            <sqoop.integration.tmpdir>${project.build.directory}</sqoop.integration.tmpdir>
+          </systemPropertyVariables>
+        </configuration>
+        <executions>
+          <execution>
+            <id>integration-test</id>
+            <goals>
+              <goal>test</goal>
+            </goals>
+            <phase>integration-test</phase>
+            <configuration>
+              <excludes>
+                <exclude>none</exclude>
+              </excludes>
+              <includes>
+                <include>**/integration/**</include>
+              </includes>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+
+
+  <profiles>
+    <profile>
+      <id>postgresql</id>
+
+      <activation>
+        <property>
+          <name>postgresql</name>
+        </property>
+      </activation>
+
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-surefire-plugin</artifactId>
+
+            <configuration>
+              <groups>postgresql</groups>
+              <excludedGroups>none</excludedGroups>
+            </configuration>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+
 </project>

http://git-wip-us.apache.org/repos/asf/sqoop/blob/332a7bdd/repository/repository-postgresql/src/main/java/org/apache/sqoop/repository/postgresql/PostgresqlRepoConstants.java
----------------------------------------------------------------------
diff --git a/repository/repository-postgresql/src/main/java/org/apache/sqoop/repository/postgresql/PostgresqlRepoConstants.java b/repository/repository-postgresql/src/main/java/org/apache/sqoop/repository/postgresql/PostgresqlRepoConstants.java
index bdefd4c..5951a4c 100644
--- a/repository/repository-postgresql/src/main/java/org/apache/sqoop/repository/postgresql/PostgresqlRepoConstants.java
+++ b/repository/repository-postgresql/src/main/java/org/apache/sqoop/repository/postgresql/PostgresqlRepoConstants.java
@@ -23,7 +23,7 @@ public class PostgresqlRepoConstants {
    * Expected version of the repository structures.
    *
    * History:
-   * 1 - Version 1.99.4
+   * 1 - Version 1.99.5
    */
   public static final int LATEST_POSTGRESQL_REPOSITORY_VERSION = 1;
 

http://git-wip-us.apache.org/repos/asf/sqoop/blob/332a7bdd/repository/repository-postgresql/src/main/java/org/apache/sqoop/repository/postgresql/PostgresqlRepositoryHandler.java
----------------------------------------------------------------------
diff --git a/repository/repository-postgresql/src/main/java/org/apache/sqoop/repository/postgresql/PostgresqlRepositoryHandler.java b/repository/repository-postgresql/src/main/java/org/apache/sqoop/repository/postgresql/PostgresqlRepositoryHandler.java
index 85af9a4..e72c8c1 100644
--- a/repository/repository-postgresql/src/main/java/org/apache/sqoop/repository/postgresql/PostgresqlRepositoryHandler.java
+++ b/repository/repository-postgresql/src/main/java/org/apache/sqoop/repository/postgresql/PostgresqlRepositoryHandler.java
@@ -17,9 +17,6 @@
  */
 package org.apache.sqoop.repository.postgresql;
 
-import static org.apache.sqoop.repository.postgresql.PostgresqlSchemaQuery.*;
-import static org.apache.sqoop.repository.postgresql.PostgresqlSchemaCreateQuery.*;
-
 import org.apache.log4j.Logger;
 import org.apache.sqoop.common.Direction;
 import org.apache.sqoop.common.SqoopException;
@@ -85,7 +82,7 @@ public class PostgresqlRepositoryHandler extends CommonRepositoryHandler {
           PostgresqlSchemaConstants.TABLE_SQ_SYSTEM_NAME.toLowerCase(), null);
 
       if (metadataResultSet.next()) {
-        stmt = conn.prepareStatement(STMT_SELECT_SYSTEM);
+        stmt = conn.prepareStatement(PostgresqlSchemaQuery.STMT_SELECT_SYSTEM);
         stmt.setString(1, CommonRepoConstants.SYSKEY_VERSION);
         rs = stmt.executeQuery();
 
@@ -118,22 +115,22 @@ public class PostgresqlRepositoryHandler extends CommonRepositoryHandler {
     }
 
     if (version == 0) {
-      runQuery(QUERY_CREATE_SCHEMA_SQOOP, conn);
-      runQuery(QUERY_CREATE_TABLE_SQ_CONFIGURABLE, conn);
-      runQuery(QUERY_CREATE_TABLE_SQ_CONFIG, conn);
-      runQuery(QUERY_CREATE_TABLE_SQ_INPUT, conn);
-      runQuery(QUERY_CREATE_TABLE_SQ_LINK, conn);
-      runQuery(QUERY_CREATE_TABLE_SQ_JOB, conn);
-      runQuery(QUERY_CREATE_TABLE_SQ_LINK_INPUT, conn);
-      runQuery(QUERY_CREATE_TABLE_SQ_JOB_INPUT, conn);
-      runQuery(QUERY_CREATE_TABLE_SQ_SUBMISSION, conn);
-      runQuery(QUERY_CREATE_TABLE_SQ_COUNTER_GROUP, conn);
-      runQuery(QUERY_CREATE_TABLE_SQ_COUNTER, conn);
-      runQuery(QUERY_CREATE_TABLE_SQ_COUNTER_SUBMISSION, conn);
-      runQuery(QUERY_CREATE_TABLE_SQ_SYSTEM, conn);
-      runQuery(QUERY_CREATE_TABLE_SQ_DIRECTION, conn);
-      runQuery(QUERY_CREATE_TABLE_SQ_CONNECTOR_DIRECTIONS, conn);
-      runQuery(QUERY_CREATE_TABLE_SQ_CONFIG_DIRECTIONS, conn);
+      runQuery(PostgresqlSchemaCreateQuery.QUERY_CREATE_SCHEMA_SQOOP, conn);
+      runQuery(PostgresqlSchemaCreateQuery.QUERY_CREATE_TABLE_SQ_CONFIGURABLE, conn);
+      runQuery(PostgresqlSchemaCreateQuery.QUERY_CREATE_TABLE_SQ_CONFIG, conn);
+      runQuery(PostgresqlSchemaCreateQuery.QUERY_CREATE_TABLE_SQ_INPUT, conn);
+      runQuery(PostgresqlSchemaCreateQuery.QUERY_CREATE_TABLE_SQ_LINK, conn);
+      runQuery(PostgresqlSchemaCreateQuery.QUERY_CREATE_TABLE_SQ_JOB, conn);
+      runQuery(PostgresqlSchemaCreateQuery.QUERY_CREATE_TABLE_SQ_LINK_INPUT, conn);
+      runQuery(PostgresqlSchemaCreateQuery.QUERY_CREATE_TABLE_SQ_JOB_INPUT, conn);
+      runQuery(PostgresqlSchemaCreateQuery.QUERY_CREATE_TABLE_SQ_SUBMISSION, conn);
+      runQuery(PostgresqlSchemaCreateQuery.QUERY_CREATE_TABLE_SQ_COUNTER_GROUP, conn);
+      runQuery(PostgresqlSchemaCreateQuery.QUERY_CREATE_TABLE_SQ_COUNTER, conn);
+      runQuery(PostgresqlSchemaCreateQuery.QUERY_CREATE_TABLE_SQ_COUNTER_SUBMISSION, conn);
+      runQuery(PostgresqlSchemaCreateQuery.QUERY_CREATE_TABLE_SQ_SYSTEM, conn);
+      runQuery(PostgresqlSchemaCreateQuery.QUERY_CREATE_TABLE_SQ_DIRECTION, conn);
+      runQuery(PostgresqlSchemaCreateQuery.QUERY_CREATE_TABLE_SQ_CONNECTOR_DIRECTIONS, conn);
+      runQuery(PostgresqlSchemaCreateQuery.QUERY_CREATE_TABLE_SQ_CONFIG_DIRECTIONS, conn);
 
       // Insert FROM and TO directions.
       insertDirections(conn);
@@ -145,13 +142,13 @@ public class PostgresqlRepositoryHandler extends CommonRepositoryHandler {
     ResultSet rs = null;
     PreparedStatement stmt = null;
     try {
-      stmt = conn.prepareStatement(STMT_DELETE_SYSTEM);
+      stmt = conn.prepareStatement(PostgresqlSchemaQuery.STMT_DELETE_SYSTEM);
       stmt.setString(1, CommonRepoConstants.SYSKEY_VERSION);
       stmt.executeUpdate();
 
       closeStatements(stmt);
 
-      stmt = conn.prepareStatement(STMT_INSERT_SYSTEM);
+      stmt = conn.prepareStatement(PostgresqlSchemaQuery.STMT_INSERT_SYSTEM);
       stmt.setString(1, CommonRepoConstants.SYSKEY_VERSION);
       stmt.setString(2, Integer.toString(PostgresqlRepoConstants.LATEST_POSTGRESQL_REPOSITORY_VERSION));
       stmt.executeUpdate();
@@ -175,7 +172,7 @@ public class PostgresqlRepositoryHandler extends CommonRepositoryHandler {
     try {
       // Insert directions and get IDs.
       for (Direction direction : Direction.values()) {
-        insertDirectionStmt = conn.prepareStatement(STMT_INSERT_DIRECTION, Statement.RETURN_GENERATED_KEYS);
+        insertDirectionStmt = conn.prepareStatement(PostgresqlSchemaQuery.STMT_INSERT_DIRECTION, Statement.RETURN_GENERATED_KEYS);
         insertDirectionStmt.setString(1, direction.toString());
         if (insertDirectionStmt.executeUpdate() != 1) {
           throw new SqoopException(PostgresqlRepoError.POSTGRESQLREPO_0003, "Could not add directions FROM and TO.");

http://git-wip-us.apache.org/repos/asf/sqoop/blob/332a7bdd/repository/repository-postgresql/src/test/java/org/apache/sqoop/integration/repository/postgresql/PostgresqlTestCase.java
----------------------------------------------------------------------
diff --git a/repository/repository-postgresql/src/test/java/org/apache/sqoop/integration/repository/postgresql/PostgresqlTestCase.java b/repository/repository-postgresql/src/test/java/org/apache/sqoop/integration/repository/postgresql/PostgresqlTestCase.java
new file mode 100644
index 0000000..08a3342
--- /dev/null
+++ b/repository/repository-postgresql/src/test/java/org/apache/sqoop/integration/repository/postgresql/PostgresqlTestCase.java
@@ -0,0 +1,166 @@
+/**
+ * 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.integration.repository.postgresql;
+
+import org.apache.sqoop.common.Direction;
+import org.apache.sqoop.common.test.db.DatabaseProvider;
+import org.apache.sqoop.common.test.db.PostgreSQLProvider;
+import org.apache.sqoop.json.DriverBean;
+import org.apache.sqoop.model.*;
+import org.apache.sqoop.repository.postgresql.PostgresqlRepositoryHandler;
+import org.apache.sqoop.submission.SubmissionStatus;
+import org.apache.sqoop.submission.counter.CounterGroup;
+import org.apache.sqoop.submission.counter.Counters;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Abstract class with convenience methods for testing postgresql repository.
+ */
+abstract public class PostgresqlTestCase {
+
+  public static DatabaseProvider provider;
+  public static PostgresqlTestUtils utils;
+  public PostgresqlRepositoryHandler handler;
+
+  @BeforeClass(alwaysRun = true)
+  public void setUpClass() {
+    provider = new PostgreSQLProvider();
+    utils = new PostgresqlTestUtils(provider);
+  }
+
+  @BeforeMethod(alwaysRun = true)
+  public void setUp() throws Exception {
+    provider.start();
+
+    handler = new PostgresqlRepositoryHandler();
+    handler.createOrUpgradeRepository(provider.getConnection());
+  }
+
+  @AfterMethod(alwaysRun = true)
+  public void tearDown() throws Exception {
+    provider.dropSchema("SQOOP");
+    provider.stop();
+  }
+
+  protected MConnector getConnector(String name, String className, String version, boolean from, boolean to) {
+    return new MConnector(name, className, version, getLinkConfig(),
+        from ? getFromConfig() : null, to ? getToConfig() : null);
+  }
+
+  protected MDriver getDriver() {
+    return new MDriver(getDriverConfig(), DriverBean.CURRENT_DRIVER_VERSION);
+  }
+
+  protected MLink getLink(String name, MConnector connector) {
+    MLink link = new MLink(connector.getPersistenceId(), connector.getLinkConfig());
+    link.setName(name);
+    fillLink(link);
+    return link;
+  }
+
+  protected MJob getJob(String name, MConnector connectorA, MConnector connectorB, MLink linkA, MLink linkB) {
+    MDriver driver = handler.findDriver(MDriver.DRIVER_NAME, provider.getConnection());
+    MJob job = new MJob(
+        connectorA.getPersistenceId(),
+        connectorB.getPersistenceId(),
+        linkA.getPersistenceId(),
+        linkB.getPersistenceId(),
+        connectorA.getFromConfig(),
+        connectorB.getToConfig(),
+        driver.getDriverConfig());
+    job.setName(name);
+    fillJob(job);
+
+    return job;
+  }
+
+  protected MSubmission getSubmission(MJob job, SubmissionStatus submissionStatus) {
+    MSubmission submission = new MSubmission(job.getPersistenceId(), new Date(), submissionStatus);
+    fillSubmission(submission);
+    return submission;
+  }
+
+  protected void fillLink(MLink link) {
+    List<MConfig> configs = link.getConnectorLinkConfig().getConfigs();
+    ((MStringInput) configs.get(0).getInputs().get(0)).setValue("Value1");
+    ((MStringInput) configs.get(1).getInputs().get(0)).setValue("Value2");
+  }
+
+  protected void fillJob(MJob job) {
+    List<MConfig> configs = job.getJobConfig(Direction.FROM).getConfigs();
+    ((MStringInput) configs.get(0).getInputs().get(0)).setValue("Value1");
+    ((MStringInput) configs.get(1).getInputs().get(0)).setValue("Value2");
+
+    configs = job.getJobConfig(Direction.TO).getConfigs();
+    ((MStringInput) configs.get(0).getInputs().get(0)).setValue("Value1");
+    ((MStringInput) configs.get(1).getInputs().get(0)).setValue("Value2");
+
+    configs = job.getDriverConfig().getConfigs();
+    ((MStringInput) configs.get(0).getInputs().get(0)).setValue("Value1");
+    ((MStringInput) configs.get(1).getInputs().get(0)).setValue("Value2");
+  }
+
+  protected void fillSubmission(MSubmission submission) {
+    Counters counters = new Counters();
+    counters.addCounterGroup(new CounterGroup("test-1"));
+    counters.addCounterGroup(new CounterGroup("test-2"));
+    submission.setCounters(counters);
+  }
+
+  protected MLinkConfig getLinkConfig() {
+    return new MLinkConfig(getConfigs("l1", "l2"));
+  }
+
+  protected MFromConfig getFromConfig() {
+    return new MFromConfig(getConfigs("from1", "from2"));
+  }
+
+  protected MToConfig getToConfig() {
+    return new MToConfig(getConfigs("to1", "to2"));
+  }
+
+  protected MDriverConfig getDriverConfig() {
+    return new MDriverConfig(getConfigs("d1", "d2"));
+  }
+
+  protected List<MConfig> getConfigs(String configName1, String configName2) {
+    List<MConfig> configs = new LinkedList<MConfig>();
+
+    List<MInput<?>> inputs = new LinkedList<MInput<?>>();
+    MInput input = new MStringInput("I1", false, (short) 30);
+    inputs.add(input);
+    input = new MMapInput("I2", false);
+    inputs.add(input);
+    configs.add(new MConfig(configName1, inputs));
+
+    inputs = new LinkedList<MInput<?>>();
+    input = new MStringInput("I3", false, (short) 30);
+    inputs.add(input);
+    input = new MMapInput("I4", false);
+    inputs.add(input);
+    configs.add(new MConfig(configName2, inputs));
+
+    return configs;
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/sqoop/blob/332a7bdd/repository/repository-postgresql/src/test/java/org/apache/sqoop/integration/repository/postgresql/PostgresqlTestUtils.java
----------------------------------------------------------------------
diff --git a/repository/repository-postgresql/src/test/java/org/apache/sqoop/integration/repository/postgresql/PostgresqlTestUtils.java b/repository/repository-postgresql/src/test/java/org/apache/sqoop/integration/repository/postgresql/PostgresqlTestUtils.java
new file mode 100644
index 0000000..0742e2d
--- /dev/null
+++ b/repository/repository-postgresql/src/test/java/org/apache/sqoop/integration/repository/postgresql/PostgresqlTestUtils.java
@@ -0,0 +1,96 @@
+/**
+ * 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.integration.repository.postgresql;
+
+import org.apache.sqoop.common.test.db.DatabaseProvider;
+import org.apache.sqoop.repository.common.CommonRepoUtils;
+
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+public class PostgresqlTestUtils {
+
+  private DatabaseProvider provider;
+
+  public PostgresqlTestUtils(DatabaseProvider provider) {
+    this.provider = provider;
+  }
+
+  public void assertTableExists(String schema, String table) throws Exception {
+    DatabaseMetaData md = provider.getConnection().getMetaData();
+    ResultSet rs = md.getTables(null, schema, table, null);
+    while (rs.next()) {
+      if (rs.getString(3).equals(table)) {
+        return;
+      }
+    }
+
+    throw new AssertionError("Could not find table '" + table + "' part of schema '" + schema + "'");
+  }
+
+  public void assertForeignKey(String schema, String table, String column,
+                               String foreignKeyTable, String foreignKeyColumn) throws Exception {
+    DatabaseMetaData md = provider.getConnection().getMetaData();
+    ResultSet rs = md.getCrossReference(null, schema, table, null, schema, foreignKeyTable);
+    while (rs.next()) {
+      if (rs.getString(4).equals(column) && rs.getString(8).equals(foreignKeyColumn)) {
+        return;
+      }
+    }
+
+    throw new AssertionError("Could not find '" + table + "." + column
+        + "' part of schema '" + schema + "' with reference to '" + table + "." + column + "'");
+  }
+
+  public void assertUniqueConstraints(String schema, String table, String... columns) throws Exception {
+    Set<String> columnSet = new TreeSet<String>();
+    Map<String, Set<String>> indexColumnMap = new HashMap<String, Set<String>>();
+
+    for (String column : columns) {
+      columnSet.add(CommonRepoUtils.escapeColumnName(column));
+    }
+
+    DatabaseMetaData md = provider.getConnection().getMetaData();
+    ResultSet rs = md.getIndexInfo(null, schema, table, true, false);
+
+    // Get map of index => columns
+    while (rs.next()) {
+      String indexName = rs.getString(6);
+      String columnName = rs.getString(9);
+      if (!indexColumnMap.containsKey(indexName)) {
+        indexColumnMap.put(indexName, new TreeSet<String>());
+      }
+      indexColumnMap.get(indexName).add(columnName);
+    }
+
+    // Validate unique constraints
+    for (String index : indexColumnMap.keySet()) {
+      if (indexColumnMap.get(index).equals(columnSet)) {
+        return;
+      }
+    }
+
+    throw new AssertionError("Could not find unique constraint on table '" + table
+            + "' part of schema '" + schema + "' with reference to columns '" + columnSet + "'");
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/sqoop/blob/332a7bdd/repository/repository-postgresql/src/test/java/org/apache/sqoop/integration/repository/postgresql/TestConnectorHandling.java
----------------------------------------------------------------------
diff --git a/repository/repository-postgresql/src/test/java/org/apache/sqoop/integration/repository/postgresql/TestConnectorHandling.java b/repository/repository-postgresql/src/test/java/org/apache/sqoop/integration/repository/postgresql/TestConnectorHandling.java
new file mode 100644
index 0000000..c1f5a20
--- /dev/null
+++ b/repository/repository-postgresql/src/test/java/org/apache/sqoop/integration/repository/postgresql/TestConnectorHandling.java
@@ -0,0 +1,152 @@
+/**
+ * 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.integration.repository.postgresql;
+
+import org.apache.sqoop.model.MConnector;
+import org.testng.annotations.Test;
+
+import java.util.List;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.AssertJUnit.assertNotNull;
+import static org.testng.AssertJUnit.assertNull;
+
+/**
+ * Test connector methods on Derby repository.
+ */
+@Test(groups = "postgresql")
+public class TestConnectorHandling extends PostgresqlTestCase {
+
+  @Test
+  public void testFindConnector() throws Exception {
+    // On empty repository, no connectors should be there
+    assertNull(handler.findConnector("A", provider.getConnection()));
+
+    // Register a single connector
+    handler.registerConnector(
+        getConnector("A", "org.apache.sqoop.test.A", "1.0-test", true, true),
+        provider.getConnection());
+
+    // Retrieve it and compare with original
+    MConnector connector = handler.findConnector("A", provider.getConnection());
+    assertNotNull(connector);
+    assertEquals(
+        getConnector("A", "org.apache.sqoop.test.A", "1.0-test", true, true),
+        connector);
+  }
+
+  @Test
+  public void testFindAllConnectors() throws Exception {
+    // No connectors in an empty repository, we expect an empty list
+    assertEquals(handler.findConnectors(provider.getConnection()).size(), 0);
+
+    // Register connectors
+    handler.registerConnector(
+        getConnector("A", "org.apache.sqoop.test.A", "1.0-test", true, true),
+        provider.getConnection());
+    handler.registerConnector(
+        getConnector("B", "org.apache.sqoop.test.B", "1.0-test", true, true),
+        provider.getConnection());
+
+//    loadConfigurables();
+    // Retrieve connectors
+    List<MConnector> connectors = handler.findConnectors(provider.getConnection());
+    assertNotNull(connectors);
+    assertEquals(connectors.size(), 2);
+    assertEquals(connectors.get(0).getUniqueName(), "A");
+    assertEquals(connectors.get(1).getUniqueName(), "B");
+  }
+
+  @Test
+  public void testRegisterConnector() throws Exception {
+    MConnector connector = getConnector("A", "org.apache.sqoop.test.A", "1.0-test", true, true);
+    handler.registerConnector(connector, provider.getConnection());
+    // Connector should get persistence ID
+    assertEquals(1, connector.getPersistenceId());
+
+    // Now check content in corresponding tables
+    assertEquals(provider.rowCount("SQOOP", "SQ_CONFIGURABLE"), 1);
+    assertEquals(provider.rowCount("SQOOP", "SQ_CONFIG"), 6);
+    assertEquals(provider.rowCount("SQOOP", "SQ_INPUT"), 12);
+
+    // Registered connector should be easily recovered back
+    MConnector retrieved = handler.findConnector("A", provider.getConnection());
+    assertNotNull(retrieved);
+    assertEquals(connector, retrieved);
+  }
+
+  @Test
+  public void testFromDirection() throws Exception {
+    MConnector connector = getConnector("A", "org.apache.sqoop.test.A", "1.0-test", true, false);
+
+    handler.registerConnector(connector, provider.getConnection());
+
+    // Connector should get persistence ID
+    assertEquals(1, connector.getPersistenceId());
+
+    // Now check content in corresponding tables
+    assertEquals(provider.rowCount("SQOOP", "SQ_CONFIGURABLE"), 1);
+    assertEquals(provider.rowCount("SQOOP", "SQ_CONFIG"), 4);
+    assertEquals(provider.rowCount("SQOOP", "SQ_INPUT"), 8);
+
+    // Registered connector should be easily recovered back
+    MConnector retrieved = handler.findConnector("A", provider.getConnection());
+    assertNotNull(retrieved);
+    assertEquals(connector, retrieved);
+  }
+
+  @Test
+  public void testToDirection() throws Exception {
+    MConnector connector = getConnector("A", "org.apache.sqoop.test.A", "1.0-test", false, true);
+
+    handler.registerConnector(connector, provider.getConnection());
+
+    // Connector should get persistence ID
+    assertEquals(1, connector.getPersistenceId());
+
+    // Now check content in corresponding tables
+    assertEquals(provider.rowCount("SQOOP", "SQ_CONFIGURABLE"), 1);
+    assertEquals(provider.rowCount("SQOOP", "SQ_CONFIG"), 4);
+    assertEquals(provider.rowCount("SQOOP", "SQ_INPUT"), 8);
+
+    // Registered connector should be easily recovered back
+    MConnector retrieved = handler.findConnector("A", provider.getConnection());
+    assertNotNull(retrieved);
+    assertEquals(connector, retrieved);
+  }
+
+  @Test
+  public void testNeitherDirection() throws Exception {
+    MConnector connector = getConnector("A", "org.apache.sqoop.test.A", "1.0-test", false, false);
+
+    handler.registerConnector(connector, provider.getConnection());
+
+    // Connector should get persistence ID
+    assertEquals(1, connector.getPersistenceId());
+
+    // Now check content in corresponding tables
+    assertEquals(provider.rowCount("SQOOP", "SQ_CONFIGURABLE"), 1);
+    assertEquals(provider.rowCount("SQOOP", "SQ_CONFIG"), 2);
+    assertEquals(provider.rowCount("SQOOP", "SQ_INPUT"), 4);
+
+    // Registered connector should be easily recovered back
+    MConnector retrieved = handler.findConnector("A", provider.getConnection());
+    assertNotNull(retrieved);
+    assertEquals(connector, retrieved);
+  }
+}

http://git-wip-us.apache.org/repos/asf/sqoop/blob/332a7bdd/repository/repository-postgresql/src/test/java/org/apache/sqoop/integration/repository/postgresql/TestDriverHandling.java
----------------------------------------------------------------------
diff --git a/repository/repository-postgresql/src/test/java/org/apache/sqoop/integration/repository/postgresql/TestDriverHandling.java b/repository/repository-postgresql/src/test/java/org/apache/sqoop/integration/repository/postgresql/TestDriverHandling.java
new file mode 100644
index 0000000..2139720
--- /dev/null
+++ b/repository/repository-postgresql/src/test/java/org/apache/sqoop/integration/repository/postgresql/TestDriverHandling.java
@@ -0,0 +1,85 @@
+/**
+ * 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.integration.repository.postgresql;
+
+import org.apache.sqoop.model.MDriver;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.AssertJUnit.assertNotNull;
+
+/**
+ * Test driver methods on Derby repository.
+ */
+@Test(groups = "postgresql")
+public class TestDriverHandling extends PostgresqlTestCase {
+
+  private static final Object CURRENT_DRIVER_VERSION = "1";
+
+  @Test
+  public void testFindDriver() throws Exception {
+    // On empty repository, no driverConfig should be there
+    assertNull(handler.findDriver(MDriver.DRIVER_NAME, provider.getConnection()));
+
+    // Register driver
+    handler.registerDriver(getDriver(), provider.getConnection());
+
+    // Retrieve it
+    MDriver driver = handler.findDriver(MDriver.DRIVER_NAME, provider.getConnection());
+    assertNotNull(driver);
+    assertNotNull(driver.getDriverConfig());
+    assertEquals("1", driver.getVersion());
+    assertEquals("1", driver.getVersion());
+
+    // Compare with original
+    assertEquals(getDriver().getDriverConfig(), driver.getDriverConfig());
+  }
+
+  @Test
+  public void testRegisterDriver() throws Exception {
+    MDriver driver = getDriver();
+    handler.registerDriver(driver, provider.getConnection());
+
+    // Connector should get persistence ID
+    assertEquals(1, driver.getPersistenceId());
+
+    // Now check content in corresponding tables
+    assertEquals(provider.rowCount("SQOOP", "SQ_CONFIGURABLE"), 1);
+    assertEquals(provider.rowCount("SQOOP", "SQ_CONFIG"), 2);
+    assertEquals(provider.rowCount("SQOOP", "SQ_INPUT"), 4);
+
+    // Registered driver and config should be easily recovered back
+    MDriver retrieved = handler.findDriver(MDriver.DRIVER_NAME, provider.getConnection());
+    assertNotNull(retrieved);
+    assertEquals(driver, retrieved);
+    assertEquals(driver.getVersion(), retrieved.getVersion());
+  }
+
+
+  @Test
+  public void testDriverVersionUpgrade() throws Exception {
+    MDriver driver = getDriver();
+    handler.registerDriver(driver, provider.getConnection());
+    String registeredDriverVersion = handler.findDriver(MDriver.DRIVER_NAME, provider.getConnection()).getVersion();
+    assertEquals(CURRENT_DRIVER_VERSION, registeredDriverVersion);
+    driver.setVersion("2");
+    handler.upgradeDriverAndConfigs(driver, provider.getConnection());
+    assertEquals("2", driver.getVersion());
+  }
+}

http://git-wip-us.apache.org/repos/asf/sqoop/blob/332a7bdd/repository/repository-postgresql/src/test/java/org/apache/sqoop/integration/repository/postgresql/TestJobHandling.java
----------------------------------------------------------------------
diff --git a/repository/repository-postgresql/src/test/java/org/apache/sqoop/integration/repository/postgresql/TestJobHandling.java b/repository/repository-postgresql/src/test/java/org/apache/sqoop/integration/repository/postgresql/TestJobHandling.java
new file mode 100644
index 0000000..d613267
--- /dev/null
+++ b/repository/repository-postgresql/src/test/java/org/apache/sqoop/integration/repository/postgresql/TestJobHandling.java
@@ -0,0 +1,289 @@
+/**
+ * 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.integration.repository.postgresql;
+
+import org.apache.sqoop.common.Direction;
+import org.apache.sqoop.common.SqoopException;
+import org.apache.sqoop.model.MConfig;
+import org.apache.sqoop.model.MConnector;
+import org.apache.sqoop.model.MJob;
+import org.apache.sqoop.model.MLink;
+import org.apache.sqoop.model.MMapInput;
+import org.apache.sqoop.model.MStringInput;
+import org.apache.sqoop.model.MSubmission;
+import org.apache.sqoop.submission.SubmissionStatus;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static junit.framework.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertNotNull;
+import static org.testng.AssertJUnit.assertTrue;
+
+/**
+ * Test job methods on Derby repository.
+ */
+@Test(groups = "postgresql")
+public class TestJobHandling extends PostgresqlTestCase {
+
+  public static final String CONNECTOR_A_NAME = "A";
+  public static final String CONNECTOR_A_CLASSNAME = "org.apache.sqoop.test.A";
+  public static final String CONNECTOR_A_VERSION = "1.0-test";
+  public static final String CONNECTOR_B_NAME = "B";
+  public static final String CONNECTOR_B_CLASSNAME = "org.apache.sqoop.test.B";
+  public static final String CONNECTOR_B_VERSION = "1.0-test";
+  public static final String LINK_A_NAME = "Link-A";
+  public static final String LINK_B_NAME = "Link-B";
+  public static final String JOB_A_NAME = "Job-A";
+  public static final String JOB_B_NAME = "Job-B";
+
+  @BeforeMethod(alwaysRun = true)
+  public void setUp() throws Exception {
+    super.setUp();
+
+    handler.registerDriver(getDriver(), provider.getConnection());
+    MConnector connectorA = getConnector(CONNECTOR_A_NAME, CONNECTOR_A_CLASSNAME, CONNECTOR_A_VERSION, true, true);
+    MConnector connectorB = getConnector(CONNECTOR_B_NAME, CONNECTOR_B_CLASSNAME, CONNECTOR_B_VERSION, true, true);
+    handler.registerConnector(connectorA, provider.getConnection());
+    handler.registerConnector(connectorB, provider.getConnection());
+    MLink linkA = getLink(LINK_A_NAME, connectorA);
+    MLink linkB = getLink(LINK_B_NAME, connectorB);
+    handler.createLink(linkA, provider.getConnection());
+    handler.createLink(linkB, provider.getConnection());
+    handler.createJob(getJob(JOB_A_NAME, connectorA, connectorB, linkA, linkB), provider.getConnection());
+    handler.createJob(getJob(JOB_B_NAME, connectorB, connectorA, linkB, linkA), provider.getConnection());
+  }
+
+  @Test(expectedExceptions = SqoopException.class)
+  public void testFindJobFail() throws Exception {
+    for (MJob job : handler.findJobs(provider.getConnection())) {
+      handler.deleteJob(job.getPersistenceId(), provider.getConnection());
+    }
+
+    // Let's try to find non existing job
+    handler.findJob(1, provider.getConnection());
+  }
+
+  @Test
+  public void testFindJobSuccess() throws Exception {
+    MJob firstJob = handler.findJob(1, provider.getConnection());
+    assertNotNull(firstJob);
+    assertEquals(1, firstJob.getPersistenceId());
+    assertEquals(JOB_A_NAME, firstJob.getName());
+
+    List<MConfig> configs;
+
+    configs = firstJob.getJobConfig(Direction.FROM).getConfigs();
+    assertEquals(2, configs.size());
+    assertEquals("Value1", configs.get(0).getInputs().get(0).getValue());
+    assertNull(configs.get(0).getInputs().get(1).getValue());
+    assertEquals("Value2", configs.get(1).getInputs().get(0).getValue());
+    assertNull(configs.get(1).getInputs().get(1).getValue());
+
+    configs = firstJob.getJobConfig(Direction.TO).getConfigs();
+    assertEquals(2, configs.size());
+    assertEquals("Value1", configs.get(0).getInputs().get(0).getValue());
+    assertNull(configs.get(0).getInputs().get(1).getValue());
+    assertEquals("Value2", configs.get(1).getInputs().get(0).getValue());
+    assertNull(configs.get(1).getInputs().get(1).getValue());
+
+    configs = firstJob.getDriverConfig().getConfigs();
+    assertEquals(2, configs.size());
+    assertEquals("Value1", configs.get(0).getInputs().get(0).getValue());
+    assertNull(configs.get(0).getInputs().get(1).getValue());
+    assertEquals("Value2", configs.get(1).getInputs().get(0).getValue());
+    assertNull(configs.get(1).getInputs().get(1).getValue());
+  }
+
+  @Test
+  public void testFindJobs() throws Exception {
+    List<MJob> list;
+
+    list = handler.findJobs(provider.getConnection());
+    assertEquals(2, list.size());
+    assertEquals(JOB_A_NAME, list.get(0).getName());
+    assertEquals(JOB_B_NAME, list.get(1).getName());
+
+    // Delete jobs
+    for (MJob job : handler.findJobs(provider.getConnection())) {
+      handler.deleteJob(job.getPersistenceId(), provider.getConnection());
+    }
+
+    // Load all two links on loaded repository
+    list = handler.findJobs(provider.getConnection());
+    assertEquals(0, list.size());
+  }
+
+  @Test
+  public void testFindJobsByConnector() throws Exception {
+    List<MJob> list = handler.findJobsForConnector(
+        handler.findConnector("A", provider.getConnection()).getPersistenceId(),
+        provider.getConnection());
+    assertEquals(2, list.size());
+    assertEquals(JOB_A_NAME, list.get(0).getName());
+    assertEquals(JOB_B_NAME, list.get(1).getName());
+  }
+
+  @Test
+  public void testFindJobsForNonExistingConnector() throws Exception {
+    List<MJob> list = handler.findJobsForConnector(11, provider.getConnection());
+    assertEquals(0, list.size());
+  }
+
+  @Test
+  public void testExistsJob() throws Exception {
+    assertTrue(handler.existsJob(1, provider.getConnection()));
+    assertTrue(handler.existsJob(2, provider.getConnection()));
+    assertFalse(handler.existsJob(3, provider.getConnection()));
+
+    // Delete jobs
+    for (MJob job : handler.findJobs(provider.getConnection())) {
+      handler.deleteJob(job.getPersistenceId(), provider.getConnection());
+    }
+
+    // There shouldn't be anything on empty repository
+    assertFalse(handler.existsJob(1, provider.getConnection()));
+    assertFalse(handler.existsJob(2, provider.getConnection()));
+    assertFalse(handler.existsJob(3, provider.getConnection()));
+  }
+
+  @Test
+  public void testInUseJob() throws Exception {
+    MSubmission submission = getSubmission(handler.findJob(1, provider.getConnection()), SubmissionStatus.RUNNING);
+    handler.createSubmission(submission, provider.getConnection());
+
+    assertTrue(handler.inUseJob(1, provider.getConnection()));
+    assertFalse(handler.inUseJob(2, provider.getConnection()));
+    assertFalse(handler.inUseJob(3, provider.getConnection()));
+  }
+
+  @Test
+  public void testCreateJob() throws Exception {
+    Assert.assertEquals(provider.rowCount("SQOOP", "SQ_JOB"), 2);
+    Assert.assertEquals(provider.rowCount("SQOOP", "SQ_JOB_INPUT"), 12);
+
+    MJob retrieved = handler.findJob(1, provider.getConnection());
+    assertEquals(1, retrieved.getPersistenceId());
+
+    List<MConfig> configs;
+    configs = retrieved.getJobConfig(Direction.FROM).getConfigs();
+    assertEquals("Value1", configs.get(0).getInputs().get(0).getValue());
+    assertNull(configs.get(0).getInputs().get(1).getValue());
+    configs = retrieved.getJobConfig(Direction.TO).getConfigs();
+    assertEquals("Value2", configs.get(1).getInputs().get(0).getValue());
+    assertNull(configs.get(0).getInputs().get(1).getValue());
+
+    configs = retrieved.getDriverConfig().getConfigs();
+    assertEquals("Value1", configs.get(0).getInputs().get(0).getValue());
+    assertNull(configs.get(0).getInputs().get(1).getValue());
+    assertEquals("Value2", configs.get(1).getInputs().get(0).getValue());
+    assertNull(configs.get(1).getInputs().get(1).getValue());
+  }
+
+  @Test(expectedExceptions = SqoopException.class)
+  public void testCreateDuplicateJob() throws Exception {
+    // Duplicate jobs
+    MJob job = handler.findJob(JOB_A_NAME, provider.getConnection());
+    job.setPersistenceId(MJob.PERSISTANCE_ID_DEFAULT);
+    handler.createJob(job, provider.getConnection());
+  }
+
+  @Test
+  public void testUpdateJob() throws Exception {
+    Assert.assertEquals(provider.rowCount("SQOOP", "SQ_JOB"), 2);
+    Assert.assertEquals(provider.rowCount("SQOOP", "SQ_JOB_INPUT"), 12);
+
+    MJob job = handler.findJob(1, provider.getConnection());
+
+    List<MConfig> configs;
+
+    configs = job.getJobConfig(Direction.FROM).getConfigs();
+    ((MStringInput)configs.get(0).getInputs().get(0)).setValue("Updated");
+    ((MMapInput)configs.get(0).getInputs().get(1)).setValue(null);
+
+    configs = job.getJobConfig(Direction.TO).getConfigs();
+    ((MStringInput)configs.get(0).getInputs().get(0)).setValue("Updated");
+    ((MMapInput)configs.get(0).getInputs().get(1)).setValue(null);
+
+    configs = job.getDriverConfig().getConfigs();
+    ((MStringInput)configs.get(0).getInputs().get(0)).setValue("Updated");
+    ((MMapInput)configs.get(0).getInputs().get(1)).setValue(new HashMap<String, String>()); // inject new map value
+    ((MStringInput)configs.get(1).getInputs().get(0)).setValue("Updated");
+    ((MMapInput)configs.get(1).getInputs().get(1)).setValue(new HashMap<String, String>()); // inject new map value
+
+    job.setName("name");
+
+    handler.updateJob(job, provider.getConnection());
+
+    assertEquals(1, job.getPersistenceId());
+    Assert.assertEquals(provider.rowCount("SQOOP", "SQ_JOB"), 2);
+    Assert.assertEquals(provider.rowCount("SQOOP", "SQ_JOB_INPUT"), 14);
+
+    MJob retrieved = handler.findJob(1, provider.getConnection());
+    assertEquals("name", retrieved.getName());
+
+    configs = job.getJobConfig(Direction.FROM).getConfigs();
+    assertEquals(2, configs.size());
+    assertEquals("Updated", configs.get(0).getInputs().get(0).getValue());
+    assertNull(configs.get(0).getInputs().get(1).getValue());
+    configs = job.getJobConfig(Direction.TO).getConfigs();
+    assertEquals(2, configs.size());
+    assertEquals("Updated", configs.get(0).getInputs().get(0).getValue());
+    assertNull(configs.get(0).getInputs().get(1).getValue());
+
+    configs = retrieved.getDriverConfig().getConfigs();
+    assertEquals(2, configs.size());
+    assertEquals("Updated", configs.get(0).getInputs().get(0).getValue());
+    assertNotNull(configs.get(0).getInputs().get(1).getValue());
+    assertEquals(((Map)configs.get(0).getInputs().get(1).getValue()).size(), 0);
+  }
+
+  @Test
+  public void testEnableAndDisableJob() throws Exception {
+    // disable job 1
+    handler.enableJob(1, false, provider.getConnection());
+
+    MJob retrieved = handler.findJob(1, provider.getConnection());
+    assertNotNull(retrieved);
+    assertEquals(false, retrieved.getEnabled());
+
+    // enable job 1
+    handler.enableJob(1, true, provider.getConnection());
+
+    retrieved = handler.findJob(1, provider.getConnection());
+    assertNotNull(retrieved);
+    assertEquals(true, retrieved.getEnabled());
+  }
+
+  @Test
+  public void testDeleteJob() throws Exception {
+    handler.deleteJob(1, provider.getConnection());
+    Assert.assertEquals(provider.rowCount("SQOOP", "SQ_JOB"), 1);
+    Assert.assertEquals(provider.rowCount("SQOOP", "SQ_JOB_INPUT"), 6);
+
+    handler.deleteJob(2, provider.getConnection());
+    Assert.assertEquals(provider.rowCount("SQOOP", "SQ_JOB"), 0);
+    Assert.assertEquals(provider.rowCount("SQOOP", "SQ_JOB_INPUT"), 0);
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/sqoop/blob/332a7bdd/repository/repository-postgresql/src/test/java/org/apache/sqoop/integration/repository/postgresql/TestLinkHandling.java
----------------------------------------------------------------------
diff --git a/repository/repository-postgresql/src/test/java/org/apache/sqoop/integration/repository/postgresql/TestLinkHandling.java b/repository/repository-postgresql/src/test/java/org/apache/sqoop/integration/repository/postgresql/TestLinkHandling.java
new file mode 100644
index 0000000..7ae540b
--- /dev/null
+++ b/repository/repository-postgresql/src/test/java/org/apache/sqoop/integration/repository/postgresql/TestLinkHandling.java
@@ -0,0 +1,284 @@
+/**
+ * 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.integration.repository.postgresql;
+
+import java.util.List;
+
+import org.apache.sqoop.common.SqoopException;
+import org.apache.sqoop.model.MConfig;
+import org.apache.sqoop.model.MConnector;
+import org.apache.sqoop.model.MJob;
+import org.apache.sqoop.model.MLink;
+import org.apache.sqoop.model.MMapInput;
+import org.apache.sqoop.model.MStringInput;
+import org.apache.sqoop.model.MSubmission;
+import org.apache.sqoop.submission.SubmissionStatus;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import static junit.framework.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertNotNull;
+import static org.testng.AssertJUnit.assertTrue;
+
+/**
+ * Test link methods on Derby repository.
+ */
+@Test(groups = "postgresql")
+public class TestLinkHandling extends PostgresqlTestCase {
+
+  public static final String CONNECTOR_A_NAME = "A";
+  public static final String CONNECTOR_A_CLASSNAME = "org.apache.sqoop.test.A";
+  public static final String CONNECTOR_A_VERSION = "1.0-test";
+  public static final String CONNECTOR_B_NAME = "B";
+  public static final String CONNECTOR_B_CLASSNAME = "org.apache.sqoop.test.B";
+  public static final String CONNECTOR_B_VERSION = "1.0-test";
+  public static final String LINK_A_NAME = "Link-A";
+  public static final String LINK_B_NAME = "Link-B";
+
+  @BeforeMethod(alwaysRun = true)
+  public void setUp() throws Exception {
+    super.setUp();
+
+    handler.registerDriver(getDriver(), provider.getConnection());
+    MConnector connectorA = getConnector(CONNECTOR_A_NAME, CONNECTOR_A_CLASSNAME, CONNECTOR_A_VERSION, true, true);
+    MConnector connectorB = getConnector(CONNECTOR_B_NAME, CONNECTOR_B_CLASSNAME, CONNECTOR_B_VERSION, true, true);
+    handler.registerConnector(connectorA, provider.getConnection());
+    handler.registerConnector(connectorB, provider.getConnection());
+    MLink linkA = getLink(LINK_A_NAME, connectorA);
+    MLink linkB = getLink(LINK_B_NAME, connectorB);
+    handler.createLink(linkA, provider.getConnection());
+    handler.createLink(linkB, provider.getConnection());
+  }
+
+  @Test(expectedExceptions = SqoopException.class)
+  public void testFindLinkFail() {
+    // Delete links
+    for (MLink link : handler.findLinks(provider.getConnection())) {
+      handler.deleteLink(link.getPersistenceId(), provider.getConnection());
+    }
+
+    handler.findLink(1, provider.getConnection());
+  }
+
+  @Test
+  public void testFindLinkSuccess() throws Exception {
+    MLink linkA = handler.findLink(1, provider.getConnection());
+    assertNotNull(linkA);
+    assertEquals(1, linkA.getPersistenceId());
+    assertEquals(LINK_A_NAME, linkA.getName());
+
+    // Check connector link config
+    List<MConfig> configs = linkA.getConnectorLinkConfig().getConfigs();
+    assertEquals("Value1", configs.get(0).getInputs().get(0).getValue());
+    assertNull(configs.get(0).getInputs().get(1).getValue());
+    assertEquals("Value2", configs.get(1).getInputs().get(0).getValue());
+    assertNull(configs.get(1).getInputs().get(1).getValue());
+  }
+
+  @Test
+  public void testFindLinkByName() throws Exception {
+    // Load non-existing
+    assertNull(handler.findLink("non-existing", provider.getConnection()));
+
+    MLink linkA = handler.findLink(LINK_A_NAME, provider.getConnection());
+    assertNotNull(linkA);
+    assertEquals(1, linkA.getPersistenceId());
+    assertEquals(LINK_A_NAME, linkA.getName());
+
+    // Check connector link config
+    List<MConfig> configs = linkA.getConnectorLinkConfig().getConfigs();
+    assertEquals("Value1", configs.get(0).getInputs().get(0).getValue());
+    assertNull(configs.get(0).getInputs().get(1).getValue());
+    assertEquals("Value2", configs.get(1).getInputs().get(0).getValue());
+    assertNull(configs.get(1).getInputs().get(1).getValue());
+  }
+
+  @Test
+  public void testFindLinks() throws Exception {
+    List<MLink> list;
+
+    // Load all two links on loaded repository
+    list = handler.findLinks(provider.getConnection());
+    assertEquals(2, list.size());
+    assertEquals(LINK_A_NAME, list.get(0).getName());
+    assertEquals(LINK_B_NAME, list.get(1).getName());
+
+    // Delete links
+    for (MLink link : handler.findLinks(provider.getConnection())) {
+      handler.deleteLink(link.getPersistenceId(), provider.getConnection());
+    }
+
+    // Load empty list on empty repository
+    list = handler.findLinks(provider.getConnection());
+    assertEquals(0, list.size());
+  }
+
+  @Test
+  public void testFindLinksByConnector() throws Exception {
+    List<MLink> list;
+    Long connectorId = handler.findConnector("A", provider.getConnection()).getPersistenceId();
+
+    // Load all two links on loaded repository
+    list = handler.findLinksForConnector(connectorId, provider.getConnection());
+    assertEquals(1, list.size());
+    assertEquals(LINK_A_NAME, list.get(0).getName());
+
+    // Delete links
+    for (MLink link : handler.findLinks(provider.getConnection())) {
+      handler.deleteLink(link.getPersistenceId(), provider.getConnection());
+    }
+
+    // Load empty list on empty repository
+    list = handler.findLinksForConnector(connectorId, provider.getConnection());
+    assertEquals(0, list.size());
+  }
+
+  @Test
+  public void testFindLinksByNonExistingConnector() throws Exception {
+    List<MLink> list = handler.findLinksForConnector(11, provider.getConnection());
+    assertEquals(0, list.size());
+  }
+
+  @Test
+  public void testExistsLink() throws Exception {
+    assertTrue(handler.existsLink(1, provider.getConnection()));
+    assertTrue(handler.existsLink(2, provider.getConnection()));
+    assertFalse(handler.existsLink(3, provider.getConnection()));
+
+    // Delete links
+    for (MLink link : handler.findLinks(provider.getConnection())) {
+      handler.deleteLink(link.getPersistenceId(), provider.getConnection());
+    }
+
+    assertFalse(handler.existsLink(1, provider.getConnection()));
+    assertFalse(handler.existsLink(2, provider.getConnection()));
+    assertFalse(handler.existsLink(3, provider.getConnection()));
+  }
+
+  @Test
+  public void testCreateLink() throws Exception {
+    List<MConfig> configs;
+
+    MLink retrieved = handler.findLink(1, provider.getConnection());
+    assertEquals(1, retrieved.getPersistenceId());
+
+    configs = retrieved.getConnectorLinkConfig().getConfigs();
+    assertEquals("Value1", configs.get(0).getInputs().get(0).getValue());
+    assertNull(configs.get(0).getInputs().get(1).getValue());
+    assertEquals("Value2", configs.get(1).getInputs().get(0).getValue());
+    assertNull(configs.get(1).getInputs().get(1).getValue());
+
+    retrieved = handler.findLink(2, provider.getConnection());
+    assertEquals(2, retrieved.getPersistenceId());
+
+    configs = retrieved.getConnectorLinkConfig().getConfigs();
+    assertEquals("Value1", configs.get(0).getInputs().get(0).getValue());
+    assertNull(configs.get(0).getInputs().get(1).getValue());
+    assertEquals("Value2", configs.get(1).getInputs().get(0).getValue());
+    assertNull(configs.get(1).getInputs().get(1).getValue());
+
+    Assert.assertEquals(provider.rowCount("SQOOP", "SQ_LINK"), 2);
+    Assert.assertEquals(provider.rowCount("SQOOP", "SQ_LINK_INPUT"), 4);
+  }
+
+  @Test(expectedExceptions = SqoopException.class)
+  public void testCreateDuplicateLink() throws Exception {
+    MLink link = handler.findLink(LINK_A_NAME, provider.getConnection());
+    link.setPersistenceId(MLink.PERSISTANCE_ID_DEFAULT);
+    handler.createLink(link, provider.getConnection());
+  }
+
+  @Test
+  public void testInUseLink() throws Exception {
+    assertFalse(handler.inUseLink(1, provider.getConnection()));
+
+    // Create job and submission and make that job in use to make sure link is in use.
+    MLink linkA = handler.findLink(LINK_A_NAME, provider.getConnection());
+    MJob job = getJob("Job-A",
+        handler.findConnector("A", provider.getConnection()),
+        handler.findConnector("B", provider.getConnection()),
+        linkA,
+        handler.findLink(LINK_B_NAME, provider.getConnection()));
+    handler.createJob(job, provider.getConnection());
+    MSubmission submission = getSubmission(job, SubmissionStatus.RUNNING);
+    handler.createSubmission(submission, provider.getConnection());
+
+    assertTrue(handler.inUseLink(linkA.getPersistenceId(), provider.getConnection()));
+  }
+
+  @Test
+  public void testUpdateLink() throws Exception {
+    MLink link = handler.findLink(1, provider.getConnection());
+
+    List<MConfig> configs;
+
+    configs = link.getConnectorLinkConfig().getConfigs();
+    ((MStringInput) configs.get(0).getInputs().get(0)).setValue("Updated");
+    ((MMapInput) configs.get(0).getInputs().get(1)).setValue(null);
+    ((MStringInput) configs.get(1).getInputs().get(0)).setValue("Updated");
+    ((MMapInput) configs.get(1).getInputs().get(1)).setValue(null);
+
+    link.setName("name");
+
+    handler.updateLink(link, provider.getConnection());
+
+    assertEquals(1, link.getPersistenceId());
+    Assert.assertEquals(provider.rowCount("SQOOP", "SQ_LINK"), 2);
+    Assert.assertEquals(provider.rowCount("SQOOP", "SQ_LINK_INPUT"), 4);
+
+    MLink retrieved = handler.findLink(1, provider.getConnection());
+    assertEquals("name", link.getName());
+
+    configs = retrieved.getConnectorLinkConfig().getConfigs();
+    assertEquals("Updated", configs.get(0).getInputs().get(0).getValue());
+    assertNull(configs.get(0).getInputs().get(1).getValue());
+    assertEquals("Updated", configs.get(1).getInputs().get(0).getValue());
+    assertNull(configs.get(1).getInputs().get(1).getValue());
+  }
+
+  @Test
+  public void testEnableAndDisableLink() throws Exception {
+    // disable link 1
+    handler.enableLink(1, false, provider.getConnection());
+
+    MLink retrieved = handler.findLink(1, provider.getConnection());
+    assertNotNull(retrieved);
+    assertEquals(false, retrieved.getEnabled());
+
+    // enable link 1
+    handler.enableLink(1, true, provider.getConnection());
+
+    retrieved = handler.findLink(1, provider.getConnection());
+    assertNotNull(retrieved);
+    assertEquals(true, retrieved.getEnabled());
+  }
+
+  @Test
+  public void testDeleteLink() throws Exception {
+    handler.deleteLink(1, provider.getConnection());
+    Assert.assertEquals(provider.rowCount("SQOOP", "SQ_LINK"), 1);
+    Assert.assertEquals(provider.rowCount("SQOOP", "SQ_LINK_INPUT"), 2);
+
+    handler.deleteLink(2, provider.getConnection());
+    Assert.assertEquals(provider.rowCount("SQOOP", "SQ_LINK"), 0);
+    Assert.assertEquals(provider.rowCount("SQOOP", "SQ_LINK_INPUT"), 0);
+  }
+}

http://git-wip-us.apache.org/repos/asf/sqoop/blob/332a7bdd/repository/repository-postgresql/src/test/java/org/apache/sqoop/integration/repository/postgresql/TestStructure.java
----------------------------------------------------------------------
diff --git a/repository/repository-postgresql/src/test/java/org/apache/sqoop/integration/repository/postgresql/TestStructure.java b/repository/repository-postgresql/src/test/java/org/apache/sqoop/integration/repository/postgresql/TestStructure.java
new file mode 100644
index 0000000..42cf3ed
--- /dev/null
+++ b/repository/repository-postgresql/src/test/java/org/apache/sqoop/integration/repository/postgresql/TestStructure.java
@@ -0,0 +1,78 @@
+/**
+ * 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.integration.repository.postgresql;
+
+import org.testng.annotations.Test;
+
+/**
+ * Test connector methods on PostgreSQL repository.
+ */
+@Test(groups = "postgresql")
+public class TestStructure extends PostgresqlTestCase {
+
+  @Test
+  public void testTables() throws Exception {
+    utils.assertTableExists("SQOOP", "SQ_SYSTEM");
+    utils.assertTableExists("SQOOP", "SQ_DIRECTION");
+    utils.assertTableExists("SQOOP", "SQ_CONFIGURABLE");
+    utils.assertTableExists("SQOOP", "SQ_CONNECTOR_DIRECTIONS");
+    utils.assertTableExists("SQOOP", "SQ_CONFIG");
+    utils.assertTableExists("SQOOP", "SQ_CONNECTOR_DIRECTIONS");
+    utils.assertTableExists("SQOOP", "SQ_INPUT");
+    utils.assertTableExists("SQOOP", "SQ_LINK");
+    utils.assertTableExists("SQOOP", "SQ_JOB");
+    utils.assertTableExists("SQOOP", "SQ_LINK_INPUT");
+    utils.assertTableExists("SQOOP", "SQ_JOB_INPUT");
+    utils.assertTableExists("SQOOP", "SQ_SUBMISSION");
+    utils.assertTableExists("SQOOP", "SQ_COUNTER_GROUP");
+    utils.assertTableExists("SQOOP", "SQ_COUNTER");
+    utils.assertTableExists("SQOOP", "SQ_COUNTER_SUBMISSION");
+  }
+
+  @Test
+  public void testForeignKeys() throws Exception {
+    utils.assertForeignKey("SQOOP", "SQ_CONFIGURABLE", "SQC_ID", "SQ_CONNECTOR_DIRECTIONS", "SQCD_CONNECTOR");
+    utils.assertForeignKey("SQOOP", "SQ_DIRECTION", "SQD_ID", "SQ_CONNECTOR_DIRECTIONS", "SQCD_DIRECTION");
+    utils.assertForeignKey("SQOOP", "SQ_CONFIGURABLE", "SQC_ID", "SQ_CONFIG", "SQ_CFG_CONFIGURABLE");
+    utils.assertForeignKey("SQOOP", "SQ_CONFIG", "SQ_CFG_ID", "SQ_CONFIG_DIRECTIONS", "SQ_CFG_DIR_CONFIG");
+    utils.assertForeignKey("SQOOP", "SQ_DIRECTION", "SQD_ID", "SQ_CONFIG_DIRECTIONS", "SQ_CFG_DIR_DIRECTION");
+    utils.assertForeignKey("SQOOP", "SQ_CONFIG", "SQ_CFG_ID", "SQ_INPUT", "SQI_CONFIG");
+    utils.assertForeignKey("SQOOP", "SQ_CONFIGURABLE", "SQC_ID", "SQ_LINK", "SQ_LNK_CONFIGURABLE");
+    utils.assertForeignKey("SQOOP", "SQ_LINK", "SQ_LNK_ID", "SQ_JOB", "SQB_FROM_LINK");
+    utils.assertForeignKey("SQOOP", "SQ_LINK", "SQ_LNK_ID", "SQ_JOB", "SQB_TO_LINK");
+    utils.assertForeignKey("SQOOP", "SQ_LINK", "SQ_LNK_ID", "SQ_LINK_INPUT", "SQ_LNKI_LINK");
+    utils.assertForeignKey("SQOOP", "SQ_INPUT", "SQI_ID", "SQ_LINK_INPUT", "SQ_LNKI_INPUT");
+    utils.assertForeignKey("SQOOP", "SQ_JOB", "SQB_ID", "SQ_JOB_INPUT", "SQBI_JOB");
+    utils.assertForeignKey("SQOOP", "SQ_INPUT", "SQI_ID", "SQ_JOB_INPUT", "SQBI_INPUT");
+    utils.assertForeignKey("SQOOP", "SQ_JOB", "SQB_ID", "SQ_SUBMISSION", "SQS_JOB");
+    utils.assertForeignKey("SQOOP", "SQ_COUNTER", "SQR_ID", "SQ_COUNTER_SUBMISSION", "SQRS_COUNTER");
+    utils.assertForeignKey("SQOOP", "SQ_COUNTER_GROUP", "SQG_ID", "SQ_COUNTER_SUBMISSION", "SQRS_GROUP");
+    utils.assertForeignKey("SQOOP", "SQ_SUBMISSION", "SQS_ID", "SQ_COUNTER_SUBMISSION", "SQRS_SUBMISSION");
+  }
+
+  @Test
+  public void testUniqueConstraints() throws Exception {
+    utils.assertUniqueConstraints("SQOOP", "SQ_CONFIGURABLE", "SQC_NAME");
+    utils.assertUniqueConstraints("SQOOP", "SQ_LINK", "SQ_LNK_NAME");
+    utils.assertUniqueConstraints("SQOOP", "SQ_JOB", "SQB_NAME");
+    utils.assertUniqueConstraints("SQOOP", "SQ_CONFIG", "SQ_CFG_NAME", "SQ_CFG_CONFIGURABLE", "SQ_CFG_TYPE");
+    utils.assertUniqueConstraints("SQOOP", "SQ_INPUT", "SQI_NAME", "SQI_TYPE", "SQI_CONFIG");
+    utils.assertUniqueConstraints("SQOOP", "SQ_COUNTER", "SQR_NAME");
+    utils.assertUniqueConstraints("SQOOP", "SQ_COUNTER_GROUP", "SQG_NAME");
+  }
+}