@Test
  public void testTransformerExternalTable() throws Exception {
    try {
      final String dbName = "db1";
      String basetblName = "oldstyleexttable";
      Map<String, Object> tProps = new HashMap<>();
      int buckets = 32;

      // create external table with uppercase
      String tblNameUpper = "TAB_EXT1";
      tProps.put("DBNAME", dbName);
      tProps.put("TBLNAME", tblNameUpper);
      tProps.put("TBLTYPE", TableType.EXTERNAL_TABLE);
      tProps.put("BUCKETS", buckets);
      StringBuilder properties = new StringBuilder();
      properties.append("EXTERNAL").append("=").append("TRUE");
      tProps.put("PROPERTIES", properties.toString());
      Table tbl = createTableWithCapabilities(tProps);

      Table hiveTbl = client.getTable(dbName, tblNameUpper.toLowerCase(Locale.ROOT));
      Path actualPath = new Path(hiveTbl.getSd().getLocation());
      Database db = client.getDatabase(dbName);
      LOG.info("Table=" + tblNameUpper + ",Table Details=" + hiveTbl);
      assertEquals("Created and retrieved tables do not match:" + hiveTbl.getTableName() + ":" +
              tblNameUpper.toLowerCase(Locale.ROOT), hiveTbl.getTableName(),
          tblNameUpper.toLowerCase(Locale.ROOT));
      Path expectedTablePath = new Path(db.getLocationUri(), tblNameUpper.toLowerCase(Locale.ROOT));
      assertEquals(String.format("Table location %s is not a subset of the database location %s",
          actualPath.toString(), db.getLocationUri()), expectedTablePath.toString(), actualPath.toString());

      String tblName = basetblName;
      tProps = new HashMap<>();
      tProps.put("DBNAME", dbName);
      tProps.put("TBLNAME", tblName);
      tProps.put("TBLTYPE", TableType.EXTERNAL_TABLE);
      tProps.put("BUCKETS", buckets);
      properties = new StringBuilder();
      properties.append("EXTERNAL").append("=").append("TRUE");
      tProps.put("PROPERTIES", properties.toString());
      tbl = createTableWithCapabilities(tProps);

      // retrieve the table
      Table tbl2 = client.getTable(dbName, tblName);
      LOG.info("Table=" + tblName + ",Access=" + tbl2.getAccessType());
      assertEquals("Created and retrieved tables do not match:" + tbl2.getTableName() + ":" + tblName,
          tbl2.getTableName(), tblName);
      assertEquals("TableType mismatch", TableType.EXTERNAL_TABLE.name(), tbl2.getTableType());
      assertEquals(buckets, tbl2.getSd().getNumBuckets()); // no transformation
      assertEquals("Table access type does not match expected value:" + tblName,
          0, tbl2.getAccessType()); // old client, AccessType not set
      assertNull(tbl2.getRequiredReadCapabilities());

      setHMSClient("testTransformerExternalTable", (new String[] { "HIVEBUCKET2" }));
      tbl2 = client.getTable(dbName, tblName);
      assertEquals("Expected buckets does not match:", buckets, tbl2.getSd().getNumBuckets()); // no transformation
      assertEquals("Table access type does not match expected value:" + tblName,
              ACCESSTYPE_READWRITE, tbl2.getAccessType()); // RW with HIVEBUCKET2 but no EXTWRITE
      resetHMSClient();

      setHMSClient("testTransformerAcceptsUnmodifiedMetadata", (new String[] { "ACCEPTS_UNMODIFIED_METADATA" }));
      tbl2 = client.getTable(dbName, tblName);
      assertEquals("Expected buckets does not match:", buckets, tbl2.getSd().getNumBuckets()); // no transformation
      assertEquals("Table access type does not match expected value:" + tblName,
          ACCESSTYPE_READONLY, tbl2.getAccessType()); // RO without HIVEBUCKET2 but with ACCEPTS_UNMODIFIED_METADATA
      resetHMSClient();

      tblName = "test_ext_bucketed_wc";
      properties = new StringBuilder();
      properties.append("EXTERNAL").append("=").append("TRUE");
      properties.append(";");
      properties.append(CAPABILITIES_KEY).append("=").append("HIVEBUCKET2,EXTREAD,EXTWRITE");
      tProps.put("TBLNAME", tblName);
      tProps.put("PROPERTIES", properties.toString());
      tbl = createTableWithCapabilities(tProps);

      tbl2 = client.getTable(dbName, tblName);
      assertEquals("Table access type does not match expected value:" + tblName,
          0, tbl2.getAccessType());
      assertEquals(buckets, tbl2.getSd().getNumBuckets()); // no tranformation

      setHMSClient("testTranformerExternalTable", (new String[] { "HIVEBUCKET2", "EXTREAD", "EXTWRITE"}));
      tbl2 = client.getTable(dbName, tblName);
      assertEquals("Table access type does not match the expected value:" + tblName,
          ACCESSTYPE_READWRITE, tbl2.getAccessType());
      assertEquals(buckets, tbl2.getSd().getNumBuckets()); // client has the HIVEBUCKET2 capability, retain bucketing info
      assertNull(tbl2.getRequiredWriteCapabilities());
      assertNull(tbl2.getRequiredReadCapabilities());
      resetHMSClient();

      setHMSClient("testTransformerExternalTableRO", (new String[] { "EXTREAD", "EXTWRITE"}));
      tbl2 = client.getTable(dbName, tblName);
      assertEquals("Table access type does not match the expected value:" + tblName,
          ACCESSTYPE_READONLY, tbl2.getAccessType());
      assertEquals(-1, tbl2.getSd().getNumBuckets()); // client has no HIVEBUCKET2 capability, remove bucketing info
      assertNotNull("Required write capabilities is null",
              tbl2.getRequiredWriteCapabilities());
      assertTrue("Returned required capabilities list does not contain HIVEBUCKET2",
              tbl2.getRequiredWriteCapabilities().contains("HIVEBUCKET2"));
      resetHMSClient();

      setHMSClient("testTransformerExternalTableROwAUM", (new String[] { "EXTREAD", "EXTWRITE", "ACCEPTS_UNMODIFIED_METADATA"}));
      tbl2 = client.getTable(dbName, tblName);
      assertEquals("Table access type does not match the expected value:" + tblName,
          ACCESSTYPE_READONLY, tbl2.getAccessType());
      assertEquals(buckets, tbl2.getSd().getNumBuckets()); // client has no HIVEBUCKET2 capability, but has ACCEPTS_UNMODIFIED_METADATA
      assertNotNull("Required write capabilities is null",
          tbl2.getRequiredWriteCapabilities());
      assertTrue("Returned required capabilities list does not contain HIVEBUCKET2",
          tbl2.getRequiredWriteCapabilities().contains("HIVEBUCKET2"));
      resetHMSClient();

      tblName = "test_ext_unbucketed_wc";
      properties = new StringBuilder();
      properties.append(CAPABILITIES_KEY).append("=").append("EXTREAD,EXTWRITE");
      tProps.put("TBLNAME", tblName);
      tProps.put("PROPERTIES", properties.toString());
      tProps.remove("BUCKETS");
      tbl = createTableWithCapabilities(tProps);

      setHMSClient("TestTransformerExternalUnbucketed", (new String[] {"EXTREAD", "EXTWRITE"}));
      tbl2 = client.getTable(dbName, tblName);
      assertEquals("Table access type does not match the expected value:" + tblName,
          ACCESSTYPE_READWRITE, tbl2.getAccessType());
      assertNull("Required read capabilities are not null", tbl2.getRequiredReadCapabilities());
      assertNull("Required write capabilities are not null", tbl2.getRequiredWriteCapabilities());

      resetHMSClient();

      tblName = "test_ext_sparkbucketed_wc";
      properties = new StringBuilder();
      properties.append("EXTERNAL").append("=").append("TRUE");
      properties.append(";");
      properties.append(CAPABILITIES_KEY).append("=").append("SPARKDECIMAL,SPARKBUCKET,EXTREAD,EXTWRITE");
      tProps.put("TBLNAME", tblName);
      tProps.put("PROPERTIES", properties.toString());
      tProps.put("BUCKETS", buckets);
      tbl = createTableWithCapabilities(tProps);

      setHMSClient("testTransformerExternalTableSpark", (new String[] { "HIVEFULLACIDREAD", "CONNECTORREAD"}));
      tbl2 = client.getTable(dbName, tblName);
      assertEquals("Table access type does not match the expected value:" + tblName,
          ACCESSTYPE_NONE, tbl2.getAccessType()); // requires EXTREAD for RO
      assertEquals(buckets, tbl2.getSd().getNumBuckets());
      assertNotNull("Required read capabilities is null", tbl2.getRequiredReadCapabilities());
      assertNotNull("Required write capabilities is null", tbl2.getRequiredWriteCapabilities());
      assertTrue("Required read capabilities does not contain EXTREAD",
              tbl2.getRequiredReadCapabilities().contains("EXTREAD"));
      assertTrue("Required write capabilities does not contain EXTWRITE",
              tbl2.getRequiredWriteCapabilities().contains("EXTWRITE"));

      setHMSClient("testTransformerExternalTableSpark", (new String[] { "EXTREAD", "CONNECTORREAD"}));
      tbl2 = client.getTable(dbName, tblName);
      assertEquals("Table access type does not match the expected value:" + tblName,
          ACCESSTYPE_READONLY, tbl2.getAccessType()); // requires EXTREAD for RO
      assertEquals(buckets, tbl2.getSd().getNumBuckets());
      assertNotNull("Required write capabilities is null", tbl2.getRequiredWriteCapabilities());
      assertTrue("Required write capabilities does not contain EXTWRITE",
              tbl2.getRequiredWriteCapabilities().contains("EXTWRITE"));


      setHMSClient("testTransformerExternalTableSpark", (new String[] { "SPARKBUCKET", "SPARKDECIMAL", "EXTREAD", "EXTWRITE" }));
      tbl2 = client.getTable(dbName, tblName);
      assertEquals("Table access type does not match the expected value:" + tblName,
          ACCESSTYPE_READWRITE, tbl2.getAccessType());
      assertEquals(buckets, tbl2.getSd().getNumBuckets()); // client has SPARKBUCKET capability
      resetHMSClient();

      LOG.info("Test execution complete:testTransformerExternalTable");
    } catch (Exception e) {
      fail("testTransformerExternalTable failed with " + e.getMessage());
    } finally {
      resetHMSClient();
    }
  }
EXTERNAL_TABLE
  1) Old table (name in upper case) with no capabilities
  2) Old table with no capabilities
  3a) New table with capabilities with no client requirements
  3b) New table with capabilities with no matching client requirements
  3c) New table with capabilities with partial match requirements
  3d) New table with capabilities with full match requirements
itests/hive-unit/src/test/java/org/apache/hadoop/hive/metastore/TestHiveMetastoreTransformer.java