This is an automated email from the ASF dual-hosted git repository.
zeroshade pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg-go.git
The following commit(s) were added to refs/heads/main by this push:
new e6e992e4d test(catalog): table-lifecycle conformance slice with
cross-namespace rename and error-mapping fixes (#2173)
e6e992e4d is described below
commit e6e992e4ddd162770816a2d95fbafe43a161d102
Author: Richie Bachala <[email protected]>
AuthorDate: Tue Oct 13 14:12:56 2026 -0700
test(catalog): table-lifecycle conformance slice with cross-namespace
rename and error-mapping fixes (#2173)
* feat(catalog): add table lifecycle tests to the catalog conformance suite
Add ListTables, DropTable, DropMissingTable, RenameTable,
RenameTableToExisting and RenameMissingTable to catalogtest, gated by a
new Config.SupportsRenameTable flag. SQL, REST and Hive opt in; Hadoop
does not implement rename.
Related to #1691
* fix(catalog): return ErrTableAlreadyExists when renaming onto an existing
table
The new RenameTableToExisting conformance test found that REST and Hive
returned untyped errors for this case. REST now maps 409 to
ErrTableAlreadyExists, matching CreateTable. Hive checks the destination
while holding the rename locks, matching its create path.
Related to #1691
* fix(hive): detect non-Iceberg tables at rename destination
CheckTableExists only recognises Iceberg tables, so a non-Iceberg Hive
table at the destination was invisible to the pre-check and AlterTable
would return a raw metastore error. Switch to a raw GetTable call so
any table (Iceberg or not) at the destination is rejected with
ErrTableAlreadyExists.
Also strengthen the rename conformance test to assert that the table
UUID survives the rename, catching backends that silently recreate
instead of renaming.
* test(catalog): verify unsupported rename and rename metadata preservation
Address review feedback on the table lifecycle conformance tests:
- When SupportsRenameTable is false, run RenameTableNotSupported instead
of skipping the rename suite, asserting RenameTable returns
iceberg.ErrNotImplemented and leaves the source table in place. The
Hadoop catalog now wraps that sentinel. Reference #1097 in the field
doc.
- Assert that rename preserves the table metadata location alongside
its UUID, catching backends that rename by recreating the table.
Signed-off-by: Richie Bachala <[email protected]>
* test(catalog): add cross-namespace rename conformance tests
Extend the table lifecycle conformance suite with two rename cases where
catalog behavior tends to diverge:
- RenameTableAcrossNamespaces: a table moves to another namespace, keeps
its UUID, and is listed only in the destination.
- RenameTableToMissingNamespace: renaming into a namespace that does not
exist returns ErrNoSuchNamespace and leaves the source table in place.
The second case exposed a REST divergence. The spec's rename 404 covers
both a missing source table and a missing destination namespace, and
the client mapped every 404 to ErrNoSuchTable. Discriminate on the
error type, following loadFunction, so a missing namespace reports
ErrNoSuchNamespace as Hive and SQL already do.
Signed-off-by: Richie Bachala <[email protected]>
* fix(catalog): address rename review feedback
- rest: route the rename 404 NoSuchNamespaceException split through
withErrorTypeOverride, so the refinement is status-gated. A 5xx or
401/403 carrying that type no longer reads as ErrNoSuchNamespace.
Add tests for those statuses and for an empty or unknown error.type
falling back to ErrNoSuchTable.
- hive: map an AlterTable already-exists rejection to
ErrTableAlreadyExists, covering a destination created after the
pre-check by a writer that skips the HMS locks.
- catalogtest: on a rejected rename-to-existing, assert both
identifiers still name their original tables, not just that they
exist.
- hadoop: assert the ErrNotImplemented sentinel instead of matching
the error message, in both the unit and integration tests.
Signed-off-by: Richie Bachala <[email protected]>
* address round-2 review: self-rename, 409 type override, mock annotation
- Add RenameTableToSelf conformance test: asserts ErrTableAlreadyExists
and verifies the table is unchanged, pinning the from==to divergence
the reviewer flagged.
- Fix the status-gating comment and add a test for 409 carrying
NoSuchNamespaceException, documenting that the type override applies
to any mapped status (not only 404).
- Annotate the concurrent-create mock with a note that the
InvalidOperationException text is verbatim HMS output.
* test(catalog): accept both self-rename outcomes in conformance suite
RenameTableToSelf asserted ErrTableAlreadyExists, which fails against
the Java REST fixture: its JdbcCatalog returns early when from == to,
treating a self-rename as a no-op success. Java's catalogs disagree on
this (JdbcCatalog and InMemoryCatalog no-op, HiveCatalog rejects), and
neither the REST spec nor Java's CatalogTests define the outcome.
Assert only what every catalog agrees on: the rename succeeds or returns
ErrTableAlreadyExists, and any other error fails. Either way the table
must keep its UUID and metadata location and be listed exactly once.
Signed-off-by: Richie Bachala <[email protected]>
* docs(catalog): cite apache/iceberg#4448 for self-rename semantics
Record why RenameTableToSelf accepts both outcomes: when REST rename was
added, a request-level check rejecting source == destination was dropped
so servers could decide, and Java's catalogs now differ.
Signed-off-by: Richie Bachala <[email protected]>
---------
Signed-off-by: Richie Bachala <[email protected]>
Co-authored-by: Richie Bachala
<[email protected]>
Co-authored-by: Richie Bachala <[email protected]>
---
catalog/catalogtest/catalogtest.go | 3 +
catalog/catalogtest/tables.go | 121 +++++++++++++++++++++++++++---
catalog/hadoop/hadoop_integration_test.go | 6 +-
catalog/hadoop/hadoop_test.go | 3 +-
catalog/hive/hive.go | 8 ++
catalog/hive/hive_test.go | 29 +++++++
catalog/rest/rest.go | 7 +-
catalog/rest/rest_test.go | 93 +++++++++++++++++++++++
8 files changed, 253 insertions(+), 17 deletions(-)
diff --git a/catalog/catalogtest/catalogtest.go
b/catalog/catalogtest/catalogtest.go
index 79bf7a6e2..22b25ae08 100644
--- a/catalog/catalogtest/catalogtest.go
+++ b/catalog/catalogtest/catalogtest.go
@@ -115,6 +115,9 @@ func RunCatalogTests(t *testing.T, cfg Config) {
t.Run("RenameTable", func(t *testing.T) { testRenameTable(t,
cfg) })
t.Run("RenameTableToExisting", func(t *testing.T) {
testRenameTableToExisting(t, cfg) })
t.Run("RenameMissingTable", func(t *testing.T) {
testRenameMissingTable(t, cfg) })
+ t.Run("RenameTableAcrossNamespaces", func(t *testing.T) {
testRenameTableAcrossNamespaces(t, cfg) })
+ t.Run("RenameTableToMissingNamespace", func(t *testing.T) {
testRenameTableToMissingNamespace(t, cfg) })
+ t.Run("RenameTableToSelf", func(t *testing.T) {
testRenameTableToSelf(t, cfg) })
} else {
t.Run("RenameTableNotSupported", func(t *testing.T) {
testRenameTableNotSupported(t, cfg) })
}
diff --git a/catalog/catalogtest/tables.go b/catalog/catalogtest/tables.go
index bfc03cc75..ded4b6dc7 100644
--- a/catalog/catalogtest/tables.go
+++ b/catalog/catalogtest/tables.go
@@ -166,19 +166,28 @@ func testRenameTableToExisting(t *testing.T, cfg Config) {
require.NoError(t, cat.CreateNamespace(ctx, namespace, nil))
t.Cleanup(func() { _ = cat.DropNamespace(ctx, namespace) })
- for _, ident := range []table.Identifier{from, to} {
- _, err := cat.CreateTable(ctx, ident, Schema)
- require.NoError(t, err)
- t.Cleanup(func() { _ = cat.DropTable(ctx, ident) })
- }
+ createdFrom, err := cat.CreateTable(ctx, from, Schema)
+ require.NoError(t, err)
+ t.Cleanup(func() { _ = cat.DropTable(ctx, from) })
- _, err := cat.RenameTable(ctx, from, to)
+ createdTo, err := cat.CreateTable(ctx, to, Schema)
+ require.NoError(t, err)
+ t.Cleanup(func() { _ = cat.DropTable(ctx, to) })
+
+ _, err = cat.RenameTable(ctx, from, to)
assert.ErrorIs(t, err, catalog.ErrTableAlreadyExists)
- for _, ident := range []table.Identifier{from, to} {
- exists, err := cat.CheckTableExists(ctx, ident)
- require.NoError(t, err)
- assert.True(t, exists, "%v should still exist after a rejected
rename", ident)
+ // Existence alone would pass an implementation that overwrote the
+ // destination and then failed, so check that each identifier still
names
+ // the table originally created there.
+ for _, tc := range []struct {
+ ident table.Identifier
+ created *table.Table
+ }{{from, createdFrom}, {to, createdTo}} {
+ tbl, err := cat.LoadTable(ctx, tc.ident)
+ require.NoError(t, err, "%v should still exist after a rejected
rename", tc.ident)
+ assert.Equal(t, tc.created.Metadata().TableUUID(),
tbl.Metadata().TableUUID(),
+ "%v should be unchanged by a rejected rename", tc.ident)
}
}
@@ -196,3 +205,95 @@ func testRenameMissingTable(t *testing.T, cfg Config) {
_, err := cat.RenameTable(ctx, from, to)
assert.ErrorIs(t, err, catalog.ErrNoSuchTable)
}
+
+// testRenameTableAcrossNamespaces asserts that a table can move to another
+// namespace, keeping its identity, and is listed only in the destination.
+func testRenameTableAcrossNamespaces(t *testing.T, cfg Config) {
+ ctx := context.Background()
+ cat := cfg.NewCatalog(t)
+ fromNamespace, from := newIdentifiers()
+ toNamespace, _ := newIdentifiers()
+ to := table.Identifier{toNamespace[0], "renamed"}
+
+ for _, ns := range []table.Identifier{fromNamespace, toNamespace} {
+ require.NoError(t, cat.CreateNamespace(ctx, ns, nil))
+ t.Cleanup(func() { _ = cat.DropNamespace(ctx, ns) })
+ }
+
+ created, err := cat.CreateTable(ctx, from, Schema)
+ require.NoError(t, err)
+ t.Cleanup(func() { _ = cat.DropTable(ctx, from) })
+
+ _, err = cat.RenameTable(ctx, from, to)
+ require.NoError(t, err)
+ t.Cleanup(func() { _ = cat.DropTable(ctx, to) })
+
+ tbl, err := cat.LoadTable(ctx, to)
+ require.NoError(t, err)
+ assert.Equal(t, to, tbl.Identifier())
+ assert.Equal(t, created.Metadata().TableUUID(),
tbl.Metadata().TableUUID(), "rename must preserve table identity")
+
+ assert.Empty(t, listTables(t, cat, fromNamespace), "source namespace
should be empty after rename")
+ assert.Equal(t, []table.Identifier{to}, listTables(t, cat, toNamespace))
+}
+
+// testRenameTableToMissingNamespace asserts that renaming into a namespace
+// that does not exist reports the missing namespace and leaves the source
+// table in place.
+func testRenameTableToMissingNamespace(t *testing.T, cfg Config) {
+ ctx := context.Background()
+ cat := cfg.NewCatalog(t)
+ namespace, from := newIdentifiers()
+ missingNamespace, _ := newIdentifiers()
+ to := table.Identifier{missingNamespace[0], "renamed"}
+
+ require.NoError(t, cat.CreateNamespace(ctx, namespace, nil))
+ t.Cleanup(func() { _ = cat.DropNamespace(ctx, namespace) })
+
+ _, err := cat.CreateTable(ctx, from, Schema)
+ require.NoError(t, err)
+ t.Cleanup(func() { _ = cat.DropTable(ctx, from) })
+
+ _, err = cat.RenameTable(ctx, from, to)
+ assert.ErrorIs(t, err, catalog.ErrNoSuchNamespace)
+
+ exists, err := cat.CheckTableExists(ctx, from)
+ require.NoError(t, err)
+ assert.True(t, exists, "source table should still exist after a
rejected rename")
+}
+
+// testRenameTableToSelf asserts the behavior every catalog agrees on when a
+// table is renamed to its own identifier. The outcome is implementation
+// defined: when REST rename was added (apache/iceberg#4448), a request-level
+// check rejecting source == destination was dropped so that servers could
+// decide, and Java's own catalogs now differ. JdbcCatalog and InMemoryCatalog
+// treat it as a no-op success, while HiveCatalog rejects it because the
+// destination exists. Both outcomes are accepted; any other error is not.
+// Either way the table must survive unchanged and be listed exactly once.
+func testRenameTableToSelf(t *testing.T, cfg Config) {
+ ctx := context.Background()
+ cat := cfg.NewCatalog(t)
+ namespace, ident := newIdentifiers()
+
+ require.NoError(t, cat.CreateNamespace(ctx, namespace, nil))
+ t.Cleanup(func() { _ = cat.DropNamespace(ctx, namespace) })
+
+ created, err := cat.CreateTable(ctx, ident, Schema)
+ require.NoError(t, err)
+ t.Cleanup(func() { _ = cat.DropTable(ctx, ident) })
+
+ _, err = cat.RenameTable(ctx, ident, ident)
+ if err != nil {
+ assert.ErrorIs(t, err, catalog.ErrTableAlreadyExists,
+ "a rejected self-rename should report that the table
already exists")
+ }
+
+ tbl, err := cat.LoadTable(ctx, ident)
+ require.NoError(t, err)
+ assert.Equal(t, created.Metadata().TableUUID(),
tbl.Metadata().TableUUID(),
+ "self-rename must preserve table identity")
+ assert.Equal(t, created.MetadataLocation(), tbl.MetadataLocation(),
+ "self-rename should not rewrite table metadata")
+ assert.Equal(t, []table.Identifier{ident}, listTables(t, cat,
namespace),
+ "self-rename should leave exactly one table")
+}
diff --git a/catalog/hadoop/hadoop_integration_test.go
b/catalog/hadoop/hadoop_integration_test.go
index ac2e2277c..dae817c9d 100644
--- a/catalog/hadoop/hadoop_integration_test.go
+++ b/catalog/hadoop/hadoop_integration_test.go
@@ -23,7 +23,6 @@ import (
"context"
"os"
"path/filepath"
- "strings"
"testing"
"github.com/apache/iceberg-go"
@@ -184,11 +183,10 @@ func (s *HadoopIntegrationSuite)
TestDropTableNamespacePreserved() {
s.True(info.IsDir(), "namespace directory should still exist")
}
-// TestRenameTableUnsupported verifies that RenameTable returns an error.
+// TestRenameTableUnsupported verifies that RenameTable reports
ErrNotImplemented.
func (s *HadoopIntegrationSuite) TestRenameTableUnsupported() {
_, err := s.cat.RenameTable(s.ctx, []string{"ns", "old"},
[]string{"ns", "new"})
- s.Require().Error(err)
- s.True(strings.Contains(err.Error(), "not supported"))
+ s.ErrorIs(err, iceberg.ErrNotImplemented)
}
// TestNamespaceRoundTrip creates a namespace in Go, creates a table in
diff --git a/catalog/hadoop/hadoop_test.go b/catalog/hadoop/hadoop_test.go
index 1390a34df..93d1b9e74 100644
--- a/catalog/hadoop/hadoop_test.go
+++ b/catalog/hadoop/hadoop_test.go
@@ -2105,8 +2105,7 @@ func (s *HadoopCatalogTestSuite)
TestDropTableNamespacePreserved() {
func (s *HadoopCatalogTestSuite) TestRenameTableUnsupported() {
_, err := s.cat.RenameTable(context.Background(), []string{"ns",
"old"}, []string{"ns", "new"})
- s.Require().ErrorIs(err, iceberg.ErrNotImplemented)
- s.Contains(err.Error(), "not supported")
+ s.ErrorIs(err, iceberg.ErrNotImplemented)
}
func (s *HadoopCatalogTestSuite) TestListTablesNamespaceIsFile() {
diff --git a/catalog/hive/hive.go b/catalog/hive/hive.go
index 2b00770f2..58c3f1bed 100644
--- a/catalog/hive/hive.go
+++ b/catalog/hive/hive.go
@@ -552,7 +552,15 @@ func (c *Catalog) RenameTable(ctx context.Context, from,
to table.Identifier) (_
hiveTbl.TableName = toTable
hiveTbl.DbName = toDB
+ // The pre-check above is best-effort: a writer that does not take
these HMS
+ // locks (Hive DDL, say) can create the destination before AlterTable
runs.
+ // The metastore then rejects the rename, which is mapped to the same
+ // sentinel so callers can match it either way.
if err := c.client.AlterTable(ctx, fromDB, fromTable, hiveTbl); err !=
nil {
+ if isAlreadyExistsError(err) {
+ return nil, fmt.Errorf("%w: %s.%s: %w",
catalog.ErrTableAlreadyExists, toDB, toTable, err)
+ }
+
return nil, fmt.Errorf("failed to rename table %s.%s to %s.%s:
%w", fromDB, fromTable, toDB, toTable, err)
}
diff --git a/catalog/hive/hive_test.go b/catalog/hive/hive_test.go
index d8c06a684..e47024ed9 100644
--- a/catalog/hive/hive_test.go
+++ b/catalog/hive/hive_test.go
@@ -918,6 +918,35 @@ func TestHiveRenameTableToExistingTable(t *testing.T) {
mockClient.AssertExpectations(t)
}
+// TestHiveRenameTableDestinationCreatedConcurrently covers a destination that
+// appears after the pre-check, e.g. from Hive DDL that skips the HMS locks:
the
+// metastore rejects AlterTable, and that must surface as
ErrTableAlreadyExists.
+func TestHiveRenameTableDestinationCreatedConcurrently(t *testing.T) {
+ mockClient := &mockHiveClient{}
+ mockClient.On("GetDatabase", mock.Anything, "target_database").
+ Return(&hive_metastore.Database{Name: "target_database"},
nil).Once()
+ mockClient.On("GetTable", mock.Anything, "test_database", "test_table").
+ Return(testIcebergHiveTable1, nil).Twice()
+ mockClient.On("Lock", mock.Anything, mock.Anything).
+ Return(&hive_metastore.LockResponse{Lockid: 2, State:
hive_metastore.LockState_ACQUIRED}, nil).Once()
+ mockClient.On("GetTable", mock.Anything, "target_database", "renamed").
+ Return(nil, errNoSuchObject).Once()
+ mockClient.On("AlterTable", mock.Anything, "test_database",
"test_table", mock.Anything).
+ // Verbatim HMS InvalidOperationException text;
isAlreadyExistsError matches
+ // on the "already exists" substring, which is what the
metastore emits.
+ Return(errors.New("InvalidOperationException: new table
target_database.renamed already exists")).Once()
+ mockClient.On("Unlock", mock.Anything, int64(2)).Return(nil).Once()
+ hiveCatalog := NewCatalogWithClient(mockClient, iceberg.Properties{})
+
+ _, err := hiveCatalog.RenameTable(
+ context.Background(),
+ TableIdentifier("test_database", "test_table"),
+ TableIdentifier("target_database", "renamed"),
+ )
+ require.ErrorIs(t, err, catalog.ErrTableAlreadyExists)
+ mockClient.AssertExpectations(t)
+}
+
func TestHivePurgeTable(t *testing.T) {
assert := require.New(t)
ctx := context.Background()
diff --git a/catalog/rest/rest.go b/catalog/rest/rest.go
index 0b4105ea3..e90c8599c 100644
--- a/catalog/rest/rest.go
+++ b/catalog/rest/rest.go
@@ -2049,8 +2049,13 @@ func (r *Catalog) RenameTable(ctx context.Context, from,
to table.Identifier) (*
return nil, err
}
+ // The spec's rename 404 covers both a missing source table and a
missing
+ // destination namespace; split it by error.type so a missing namespace
is
+ // not reported as a missing table. The type override only refines a
+ // status mapped here, so a 5xx or 401/403 carrying that type is
unaffected.
_, err = doPost[payload, any](ctx, r.baseURI, path, payload{Source:
src, Destination: dst}, r.cl,
- map[int]error{http.StatusNotFound: catalog.ErrNoSuchTable,
http.StatusConflict: catalog.ErrTableAlreadyExists}, allowNoContent())
+ map[int]error{http.StatusNotFound: catalog.ErrNoSuchTable,
http.StatusConflict: catalog.ErrTableAlreadyExists},
+ allowNoContent(),
withErrorTypeOverride(map[string]error{errTypeNoSuchNamespace:
catalog.ErrNoSuchNamespace}))
if err != nil {
return nil, err
}
diff --git a/catalog/rest/rest_test.go b/catalog/rest/rest_test.go
index 8ace73360..4af1ad224 100644
--- a/catalog/rest/rest_test.go
+++ b/catalog/rest/rest_test.go
@@ -1967,6 +1967,99 @@ func (r *RestCatalogSuite) TestRenameTable409() {
r.ErrorIs(err, catalog.ErrTableAlreadyExists)
}
+// renameTableErrors registers a rename endpoint that fails and returns a
+// function that sets the failure's status and error.type, renames a table, and
+// returns the error RenameTable reports. The handler is registered once, so
the
+// returned function can be called repeatedly within one test.
+func (r *RestCatalogSuite) renameTableErrors() func(status int, errType
string) error {
+ var status int
+ var errType string
+ r.mux.HandleFunc("/v1/tables/rename", func(w http.ResponseWriter, req
*http.Request) {
+ if !r.Equal(http.MethodPost, req.Method) {
+ return
+ }
+
+ w.WriteHeader(status)
+ json.NewEncoder(w).Encode(map[string]any{
+ "error": map[string]any{
+ "message": "rename failed",
+ "type": errType,
+ "code": status,
+ },
+ })
+ })
+
+ cat, err := rest.NewCatalog(context.Background(), "rest", r.srv.URL,
rest.WithOAuthToken(TestToken))
+ r.Require().NoError(err)
+
+ return func(s int, t string) error {
+ status, errType = s, t
+ _, err := cat.RenameTable(context.Background(),
catalog.ToIdentifier("fokko", "source"), catalog.ToIdentifier("missing",
"destination"))
+
+ return err
+ }
+}
+
+func (r *RestCatalogSuite) TestRenameTable404MissingTable() {
+ err := r.renameTableErrors()(http.StatusNotFound,
"NoSuchTableException")
+ r.ErrorIs(err, catalog.ErrNoSuchTable)
+ r.NotErrorIs(err, catalog.ErrNoSuchNamespace)
+}
+
+func (r *RestCatalogSuite) TestRenameTable404MissingNamespace() {
+ err := r.renameTableErrors()(http.StatusNotFound,
"NoSuchNamespaceException")
+ r.ErrorIs(err, catalog.ErrNoSuchNamespace)
+ r.NotErrorIs(err, catalog.ErrNoSuchTable)
+}
+
+// TestRenameTable404UntypedFallsBackToNoSuchTable pins the fallback for
servers
+// that omit or send an unrecognized error.type on a rename 404.
+func (r *RestCatalogSuite) TestRenameTable404UntypedFallsBackToNoSuchTable() {
+ rename := r.renameTableErrors()
+ for _, errType := range []string{"", "SomeUnknownException"} {
+ r.Run("type="+errType, func() {
+ err := rename(http.StatusNotFound, errType)
+ r.ErrorIs(err, catalog.ErrNoSuchTable)
+ r.NotErrorIs(err, catalog.ErrNoSuchNamespace)
+ })
+ }
+}
+
+// TestRenameTableNoSuchNamespaceTypeIsStatusGated asserts that the error.type
+// refinement only applies to statuses in the rename status map (404 and 409).
+// An unmapped status carrying NoSuchNamespaceException must not read as a
+// missing namespace.
+func (r *RestCatalogSuite) TestRenameTableNoSuchNamespaceTypeIsStatusGated() {
+ rename := r.renameTableErrors()
+ tests := []struct {
+ status int
+ want error
+ }{
+ {http.StatusServiceUnavailable, rest.ErrServiceUnavailable},
+ {http.StatusInternalServerError, rest.ErrServerError},
+ {http.StatusUnauthorized, rest.ErrUnauthorized},
+ {http.StatusForbidden, rest.ErrForbidden},
+ }
+ for _, tt := range tests {
+ r.Run(http.StatusText(tt.status), func() {
+ err := rename(tt.status, "NoSuchNamespaceException")
+ r.ErrorIs(err, tt.want)
+ r.NotErrorIs(err, catalog.ErrNoSuchNamespace)
+ })
+ }
+}
+
+// TestRenameTable409WithNamespaceTypeResolvesToNamespace pins the edge where a
+// 409 carries NoSuchNamespaceException. No real server sends this combo, but
+// 409 is in the rename status map, so the type override refines it. The test
+// documents that behavior: if status-aware overrides are added later, this
+// catches the change.
+func (r *RestCatalogSuite)
TestRenameTable409WithNamespaceTypeResolvesToNamespace() {
+ err := r.renameTableErrors()(http.StatusConflict,
"NoSuchNamespaceException")
+ r.ErrorIs(err, catalog.ErrNoSuchNamespace)
+ r.NotErrorIs(err, catalog.ErrTableAlreadyExists)
+}
+
func (r *RestCatalogSuite) TestRenameTable204() {
// Mock the rename table endpoint
r.mux.HandleFunc("/v1/tables/rename", func(w http.ResponseWriter, req
*http.Request) {