laskoviymishka commented on code in PR #2173:
URL: https://github.com/apache/iceberg-go/pull/2173#discussion_r4249100968


##########
catalog/catalogtest/catalogtest.go:
##########
@@ -115,6 +115,8 @@ 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) })

Review Comment:
   the from==to self-rename case I flagged last round is still missing from the 
matrix. Hive now reports already-exists through the new pre-check while 
REST/SQL are unspecified, so it's exactly the divergence this suite exists to 
catch. a `testRenameTableToSelf` asserting `ErrTableAlreadyExists` with an 
unchanged UUID, or an explicit follow-up note if the catalogs genuinely 
disagree, would close it.



##########
catalog/rest/rest_test.go:
##########
@@ -1967,6 +1967,87 @@ 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 only a 404 is

Review Comment:
   "only a 404 is refined" is a bit broader than what's implemented: 409 is 
also in the rename status map, so a 409 carrying `NoSuchNamespaceException` 
would refine to `ErrNoSuchNamespace` too. no real server sends that combo so 
it's harmless, but the comment and the table only cover unmapped statuses 
(503/500/401/403). I'd either add a 409 case and decide what it should resolve 
to, or reword to "a status this call doesn't map."



##########
catalog/hive/hive_test.go:
##########
@@ -918,6 +918,33 @@ 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).
+               Return(errors.New("InvalidOperationException: new table 
target_database.renamed already exists")).Once()

Review Comment:
   this passes only because `isAlreadyExistsError` substring-matches the 
message text: the mock returns a plain `errors.New`, not the typed 
`hive_metastore.InvalidOperationException` HMS actually sends. worth a one-line 
comment that the string is verbatim HMS text (or returning the typed exception 
if it's available), so a later tightening of the helper to `errors.As` doesn't 
silently break this while production stays fine.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to