-
Notifications
You must be signed in to change notification settings - Fork 218
Wait for app deletion in DoCreate instead of DoDelete #4176
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
andrewnester
merged 5 commits into
databricks:main
from
varundeepsaini:fix-app-deletion-wait-in-create
Jan 2, 2026
Merged
Changes from 3 commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
5f5e4d5
Wait for app deletion in DoCreate instead of DoDelete
bed765e
removed status check, and added retries
2459f80
Check app state before retrying on RESOURCE_ALREADY_EXISTS
900e11a
Add acceptance test for app already exists error
3c7d77a
Merge branch 'main' into fix-app-deletion-wait-in-create
denik File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,170 @@ | ||
| package dresources | ||
|
|
||
| import ( | ||
| "context" | ||
| "testing" | ||
|
|
||
| "github.com/databricks/cli/libs/testserver" | ||
| "github.com/databricks/databricks-sdk-go" | ||
| "github.com/databricks/databricks-sdk-go/service/apps" | ||
| "github.com/stretchr/testify/assert" | ||
| "github.com/stretchr/testify/require" | ||
| ) | ||
|
|
||
| // TestAppDoCreate_RetriesWhenAppIsDeleting verifies that DoCreate retries when | ||
| // an app already exists but is in DELETING state. | ||
| func TestAppDoCreate_RetriesWhenAppIsDeleting(t *testing.T) { | ||
| server := testserver.New(t) | ||
|
|
||
| createCallCount := 0 | ||
| getCallCount := 0 | ||
|
|
||
| server.Handle("POST", "/api/2.0/apps", func(req testserver.Request) any { | ||
| createCallCount++ | ||
| if createCallCount == 1 { | ||
| return testserver.Response{ | ||
| StatusCode: 409, | ||
| Body: map[string]string{ | ||
| "error_code": "RESOURCE_ALREADY_EXISTS", | ||
| "message": "An app with the same name already exists.", | ||
| }, | ||
| } | ||
| } | ||
| return apps.App{ | ||
| Name: "test-app", | ||
| ComputeStatus: &apps.ComputeStatus{ | ||
| State: apps.ComputeStateActive, | ||
| }, | ||
| } | ||
| }) | ||
|
|
||
| server.Handle("GET", "/api/2.0/apps/{name}", func(req testserver.Request) any { | ||
| getCallCount++ | ||
| return apps.App{ | ||
| Name: req.Vars["name"], | ||
| ComputeStatus: &apps.ComputeStatus{ | ||
| State: apps.ComputeStateDeleting, | ||
| }, | ||
| } | ||
| }) | ||
|
|
||
| testserver.AddDefaultHandlers(server) | ||
|
|
||
| client, err := databricks.NewWorkspaceClient(&databricks.Config{ | ||
| Host: server.URL, | ||
| Token: "testtoken", | ||
| }) | ||
| require.NoError(t, err) | ||
|
|
||
| r := (&ResourceApp{}).New(client) | ||
| ctx := context.Background() | ||
| name, _, err := r.DoCreate(ctx, &apps.App{Name: "test-app"}) | ||
|
|
||
| require.NoError(t, err) | ||
| assert.Equal(t, "test-app", name) | ||
| assert.Equal(t, 2, createCallCount, "expected Create to be called twice (1 retry)") | ||
| assert.Equal(t, 1, getCallCount, "expected Get to be called once to check app state") | ||
| } | ||
|
|
||
| // TestAppDoCreate_RetriesWhenGetReturnsNotFound verifies that DoCreate retries | ||
| // when the app was just deleted between the create call and the get call. | ||
| func TestAppDoCreate_RetriesWhenGetReturnsNotFound(t *testing.T) { | ||
| server := testserver.New(t) | ||
|
|
||
| createCallCount := 0 | ||
| getCallCount := 0 | ||
|
|
||
| server.Handle("POST", "/api/2.0/apps", func(req testserver.Request) any { | ||
| createCallCount++ | ||
| if createCallCount == 1 { | ||
| return testserver.Response{ | ||
| StatusCode: 409, | ||
| Body: map[string]string{ | ||
| "error_code": "RESOURCE_ALREADY_EXISTS", | ||
| "message": "An app with the same name already exists.", | ||
| }, | ||
| } | ||
| } | ||
| return apps.App{ | ||
| Name: "test-app", | ||
| ComputeStatus: &apps.ComputeStatus{ | ||
| State: apps.ComputeStateActive, | ||
| }, | ||
| } | ||
| }) | ||
|
|
||
| server.Handle("GET", "/api/2.0/apps/{name}", func(req testserver.Request) any { | ||
| getCallCount++ | ||
| return testserver.Response{ | ||
| StatusCode: 404, | ||
| Body: map[string]string{ | ||
| "error_code": "RESOURCE_DOES_NOT_EXIST", | ||
| "message": "App not found.", | ||
| }, | ||
| } | ||
| }) | ||
|
|
||
| testserver.AddDefaultHandlers(server) | ||
|
|
||
| client, err := databricks.NewWorkspaceClient(&databricks.Config{ | ||
| Host: server.URL, | ||
| Token: "testtoken", | ||
| }) | ||
| require.NoError(t, err) | ||
|
|
||
| r := (&ResourceApp{}).New(client) | ||
| ctx := context.Background() | ||
| name, _, err := r.DoCreate(ctx, &apps.App{Name: "test-app"}) | ||
|
|
||
| require.NoError(t, err) | ||
| assert.Equal(t, "test-app", name) | ||
| assert.Equal(t, 2, createCallCount, "expected Create to be called twice") | ||
| assert.Equal(t, 1, getCallCount, "expected Get to be called once to check app state") | ||
| } | ||
|
|
||
| // TestAppDoCreate_FailsWhenAppExistsAndNotDeleting verifies that DoCreate returns | ||
| // a hard error when an app already exists but is NOT in DELETING state. | ||
| func TestAppDoCreate_FailsWhenAppExistsAndNotDeleting(t *testing.T) { | ||
| server := testserver.New(t) | ||
|
|
||
| createCallCount := 0 | ||
| getCallCount := 0 | ||
|
|
||
| server.Handle("POST", "/api/2.0/apps", func(req testserver.Request) any { | ||
| createCallCount++ | ||
| return testserver.Response{ | ||
| StatusCode: 409, | ||
| Body: map[string]string{ | ||
| "error_code": "RESOURCE_ALREADY_EXISTS", | ||
| "message": "An app with the same name already exists.", | ||
| }, | ||
| } | ||
| }) | ||
|
|
||
| server.Handle("GET", "/api/2.0/apps/{name}", func(req testserver.Request) any { | ||
| getCallCount++ | ||
| return apps.App{ | ||
| Name: req.Vars["name"], | ||
| ComputeStatus: &apps.ComputeStatus{ | ||
| State: apps.ComputeStateActive, | ||
| }, | ||
| } | ||
| }) | ||
|
|
||
| testserver.AddDefaultHandlers(server) | ||
|
|
||
| client, err := databricks.NewWorkspaceClient(&databricks.Config{ | ||
| Host: server.URL, | ||
| Token: "testtoken", | ||
| }) | ||
| require.NoError(t, err) | ||
|
|
||
| r := (&ResourceApp{}).New(client) | ||
| ctx := context.Background() | ||
| _, _, err = r.DoCreate(ctx, &apps.App{Name: "test-app"}) | ||
|
|
||
| require.Error(t, err) | ||
| assert.Contains(t, err.Error(), "already exists") | ||
| assert.Equal(t, 1, createCallCount, "expected Create to be called only once") | ||
| assert.Equal(t, 1, getCallCount, "expected Get to be called once to check app state") | ||
| } | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The two tests above have special logic in the handler, so it makes sense to write them as unit tests. This test can be using standard handlers though, could you rewrite it as acceptance test?
first create app with the same name using databricks cli
$CLI apps create --json '{...}'then do bundle deploy and observe the error:
musterr $CLI bundle deployThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The testserver used to overwrite when an app already exists, i modified it so it returns a 409