diff --git a/.gitattributes b/.gitattributes index 75d7e2eef..8e7f68af6 100644 --- a/.gitattributes +++ b/.gitattributes @@ -92,6 +92,7 @@ experimental/mocks/service/marketplace/mock_provider_personalization_requests_in experimental/mocks/service/marketplace/mock_provider_provider_analytics_dashboards_interface.go linguist-generated=true experimental/mocks/service/marketplace/mock_provider_providers_interface.go linguist-generated=true experimental/mocks/service/ml/mock_experiments_interface.go linguist-generated=true +experimental/mocks/service/ml/mock_feature_engineering_interface.go linguist-generated=true experimental/mocks/service/ml/mock_feature_store_interface.go linguist-generated=true experimental/mocks/service/ml/mock_forecasting_interface.go linguist-generated=true experimental/mocks/service/ml/mock_materialized_features_interface.go linguist-generated=true @@ -180,12 +181,19 @@ experimental/mocks/service/workspace/mock_secrets_interface.go linguist-generate experimental/mocks/service/workspace/mock_workspace_interface.go linguist-generated=true internal/generatedtests/http_call_test.go linguist-generated=true internal/generatedtests/json_marshall_test.go linguist-generated=true +internal/generatedtests/lro_call_test.go linguist-generated=true +internal/testspecs/service/common/api.go linguist-generated=true +internal/testspecs/service/common/impl.go linguist-generated=true +internal/testspecs/service/common/model.go linguist-generated=true internal/testspecs/service/httpcallv2/api.go linguist-generated=true internal/testspecs/service/httpcallv2/impl.go linguist-generated=true internal/testspecs/service/httpcallv2/model.go linguist-generated=true internal/testspecs/service/jsonmarshallv2/api.go linguist-generated=true internal/testspecs/service/jsonmarshallv2/impl.go linguist-generated=true internal/testspecs/service/jsonmarshallv2/model.go linguist-generated=true +internal/testspecs/service/lrotesting/api.go linguist-generated=true +internal/testspecs/service/lrotesting/impl.go linguist-generated=true +internal/testspecs/service/lrotesting/model.go linguist-generated=true service/agentbricks/api.go linguist-generated=true service/agentbricks/impl.go linguist-generated=true service/agentbricks/interface.go linguist-generated=true diff --git a/NEXT_CHANGELOG.md b/NEXT_CHANGELOG.md index 10a8c5ba2..e3c14ac67 100644 --- a/NEXT_CHANGELOG.md +++ b/NEXT_CHANGELOG.md @@ -98,4 +98,4 @@ * [Breaking] Changed `UpdateMask` field for [sql.UpdateVisualizationRequest](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/sql#UpdateVisualizationRequest) to type `string`. * [Breaking] Changed `CreateTime` and `UpdateTime` fields for [sql.Visualization](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/sql#Visualization) to type `string`. * [Breaking] Changed `UpdateMask` field for [tags.UpdateTagPolicyRequest](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/tags#UpdateTagPolicyRequest) to type `string`. -* [Breaking] Removed `DefaultDataSecurityMode` and `EffectiveDefaultDataSecurityMode` fields for [settingsv2.Setting](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/settingsv2#Setting). \ No newline at end of file +* [Breaking] Removed `DefaultDataSecurityMode` and `EffectiveDefaultDataSecurityMode` fields for [settingsv2.Setting](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/settingsv2#Setting). diff --git a/account_client.go b/account_client.go index 4ba36f3fd..07569407f 100755 --- a/account_client.go +++ b/account_client.go @@ -425,6 +425,44 @@ type AccountClient struct { // platform or on a select custom plan that allows multiple workspaces per // account. Workspaces provisioning.WorkspacesInterface + + // Groups simplify identity management, making it easier to assign access to + // Databricks account, data, and other securable objects. + // + // It is best practice to assign access to workspaces and access-control + // policies in Unity Catalog to groups, instead of to users individually. + // All Databricks account identities can be assigned as members of groups, + // and members inherit permissions that are assigned to their group. + // + // Deprecated: Use the GroupsV2 API instead. + Groups iam.AccountGroupsInterface + + // Identities for use with jobs, automated tools, and systems such as + // scripts, apps, and CI/CD platforms. Databricks recommends creating + // service principals to run production jobs or modify production data. If + // all processes that act on production data run with service principals, + // interactive users do not need any write, delete, or modify privileges in + // production. This eliminates the risk of a user overwriting production + // data by accident. + // + // Deprecated: Use the ServicePrincipalsV2 API instead. + ServicePrincipals iam.AccountServicePrincipalsInterface + + // User identities recognized by Databricks and represented by email + // addresses. + // + // Databricks recommends using SCIM provisioning to sync users and groups + // automatically from your identity provider to your Databricks account. + // SCIM streamlines onboarding a new employee or team by using your identity + // provider to create users and groups in Databricks account and give them + // the proper level of access. When a user leaves your organization or no + // longer needs access to Databricks account, admins can terminate the user + // in your identity provider and that user’s account will also be removed + // from Databricks account. This ensures a consistent offboarding process + // and prevents unauthorized users from accessing sensitive data. + // + // Deprecated: Use the UsersV2 API instead. + Users iam.AccountUsersInterface } var ErrNotAccountClient = errors.New("invalid Databricks Account configuration") @@ -488,5 +526,8 @@ func NewAccountClient(c ...*Config) (*AccountClient, error) { WorkspaceAssignment: iam.NewWorkspaceAssignment(apiClient), WorkspaceNetworkConfiguration: settings.NewWorkspaceNetworkConfiguration(apiClient), Workspaces: provisioning.NewWorkspaces(apiClient), + Groups: iam.NewAccountGroups(apiClient), + ServicePrincipals: iam.NewAccountServicePrincipals(apiClient), + Users: iam.NewAccountUsers(apiClient), }, nil } diff --git a/internal/generatedtests/http_call_test.go b/internal/generatedtests/http_call_test.go index 09938783f..647705933 100755 --- a/internal/generatedtests/http_call_test.go +++ b/internal/generatedtests/http_call_test.go @@ -3,9 +3,11 @@ package generated_tests import ( "context" + "encoding/json" "testing" "github.com/databricks/databricks-sdk-go/client" + "github.com/databricks/databricks-sdk-go/common/types/fieldmask" "github.com/databricks/databricks-sdk-go/internal/testspecs/service/httpcallv2" "github.com/databricks/databricks-sdk-go/qa" ) @@ -54,6 +56,7 @@ func TestHttpCall_LegacyHttpPostWithBody(t *testing.T) { func TestHttpCall_UpdateResourceNoQueryParamsNoBody(t *testing.T) { input := httpcallv2.UpdateResourceRequest{ Resource: httpcallv2.Resource{ + AnyField: json.RawMessage("{\"key\": \"value\"}"), NestedPathParamBool: true, NestedPathParamInt: 789, NestedPathParamString: "update_string", @@ -67,6 +70,7 @@ func TestHttpCall_UpdateResourceNoQueryParamsNoBody(t *testing.T) { Method: "PATCH", Resource: "/api/2.0/http-call/update_string/789/true", ExpectedRequest: httpcallv2.Resource{ + AnyField: json.RawMessage("{\"key\": \"value\"}"), NestedPathParamBool: true, NestedPathParamInt: 789, NestedPathParamString: "update_string", @@ -120,7 +124,7 @@ func TestHttpCall_UpdateResourceWithSimpleQueryParams(t *testing.T) { QueryParamString: "query_string_val", QueryParamInt: 999, QueryParamBool: true, - FieldMask: "field.mask.value", + FieldMask: &fieldmask.FieldMask{Paths: []string{"field.mask.value"}}, } qa.HTTPFixtures{ { @@ -178,7 +182,11 @@ func TestHttpCall_UpdateResourceWithRepeatedQueryParam(t *testing.T) { NestedPathParamString: "update_string", NestedPathParamInt: 789, NestedPathParamBool: true, - RepeatedQueryParam: []string{"item1", "item2", "item3"}, + RepeatedQueryParam: []string{ + "item1", + "item2", + "item3", + }, } qa.HTTPFixtures{ { @@ -207,7 +215,11 @@ func TestHttpCall_UpdateResourceWithRepeatedNestedQueryParam(t *testing.T) { NestedPathParamInt: 789, NestedPathParamBool: true, OptionalComplexQueryParam: &httpcallv2.ComplexQueryParam{ - NestedRepeatedQueryParam: []string{"item1", "item2", "item3"}, + NestedRepeatedQueryParam: []string{ + "item1", + "item2", + "item3", + }, }, } qa.HTTPFixtures{ @@ -236,11 +248,22 @@ func TestHttpCall_UpdateResourceWithDoubleRepeatedNestedQueryParam(t *testing.T) NestedPathParamString: "update_string", NestedPathParamInt: 789, NestedPathParamBool: true, - RepeatedComplexQueryParam: []httpcallv2.ComplexQueryParam{httpcallv2.ComplexQueryParam{ - NestedRepeatedQueryParam: []string{"item1", "item2", "item3"}, - }, httpcallv2.ComplexQueryParam{ - NestedRepeatedQueryParam: []string{"item4", "item5", "item6"}, - }}, + RepeatedComplexQueryParam: []httpcallv2.ComplexQueryParam{ + httpcallv2.ComplexQueryParam{ + NestedRepeatedQueryParam: []string{ + "item1", + "item2", + "item3", + }, + }, + httpcallv2.ComplexQueryParam{ + NestedRepeatedQueryParam: []string{ + "item4", + "item5", + "item6", + }, + }, + }, } qa.HTTPFixtures{ { @@ -283,7 +306,7 @@ func TestHttpCall_GetResourceWithSimpleQueryParams(t *testing.T) { QueryParamString: "query_string_val", QueryParamInt: 999, QueryParamBool: true, - FieldMask: "field.mask.value", + FieldMask: &fieldmask.FieldMask{Paths: []string{"field.mask.value"}}, } qa.HTTPFixtures{ { @@ -318,10 +341,14 @@ func TestHttpCall_GetResourceWithOneNestedQueryParam(t *testing.T) { func TestHttpCall_GetResourceWithRepeatedQueryParam(t *testing.T) { input := httpcallv2.GetResourceRequest{ - PathParamString: "get_string", - PathParamInt: 101, - PathParamBool: false, - RepeatedQueryParam: []string{"item1", "item2", "item3"}, + PathParamString: "get_string", + PathParamInt: 101, + PathParamBool: false, + RepeatedQueryParam: []string{ + "item1", + "item2", + "item3", + }, } qa.HTTPFixtures{ { @@ -340,7 +367,11 @@ func TestHttpCall_GetResourceWithRepeatedNestedQueryParam(t *testing.T) { PathParamInt: 202, PathParamBool: true, OptionalComplexQueryParam: &httpcallv2.ComplexQueryParam{ - NestedRepeatedQueryParam: []string{"item1", "item2", "item3"}, + NestedRepeatedQueryParam: []string{ + "item1", + "item2", + "item3", + }, }, } qa.HTTPFixtures{ @@ -359,11 +390,22 @@ func TestHttpCall_GetResourceWithDoubleRepeatedNestedQueryParam(t *testing.T) { PathParamString: "get_string", PathParamInt: 303, PathParamBool: false, - RepeatedComplexQueryParam: []httpcallv2.ComplexQueryParam{httpcallv2.ComplexQueryParam{ - NestedRepeatedQueryParam: []string{"item1", "item2", "item3"}, - }, httpcallv2.ComplexQueryParam{ - NestedRepeatedQueryParam: []string{"item4", "item5", "item6"}, - }}, + RepeatedComplexQueryParam: []httpcallv2.ComplexQueryParam{ + httpcallv2.ComplexQueryParam{ + NestedRepeatedQueryParam: []string{ + "item1", + "item2", + "item3", + }, + }, + httpcallv2.ComplexQueryParam{ + NestedRepeatedQueryParam: []string{ + "item4", + "item5", + "item6", + }, + }, + }, } qa.HTTPFixtures{ { diff --git a/internal/generatedtests/json_marshall_test.go b/internal/generatedtests/json_marshall_test.go index bc3f855f3..3bb536891 100755 --- a/internal/generatedtests/json_marshall_test.go +++ b/internal/generatedtests/json_marshall_test.go @@ -4,11 +4,25 @@ package generated_tests import ( "encoding/json" "testing" + goTime "time" + "github.com/databricks/databricks-sdk-go/common/types/duration" + "github.com/databricks/databricks-sdk-go/common/types/fieldmask" + "github.com/databricks/databricks-sdk-go/common/types/time" "github.com/databricks/databricks-sdk-go/internal/testspecs/service/jsonmarshallv2" "github.com/google/go-cmp/cmp" ) +// Helper functions to simplify test generation. +// This allows us to define the test cases inline. +func timeFromString(s string) goTime.Time { + t, err := goTime.Parse(goTime.RFC3339, s) + if err != nil { + panic(err) + } + return t +} + func TestJsonMarshall(t *testing.T) { testCases := []struct { name string @@ -76,7 +90,10 @@ func TestJsonMarshall(t *testing.T) { { name: "OptionalMap", value: jsonmarshallv2.OptionalFields{ - Map: map[string]string{"key": "test_key", "value": "test_value"}, + Map: map[string]string{ + "key": "test_key", + "value": "test_value", + }, }, want: `{ "map": { @@ -88,7 +105,7 @@ func TestJsonMarshall(t *testing.T) { { name: "OptionalDuration", value: jsonmarshallv2.OptionalFields{ - Duration: "3600s", + Duration: duration.New(3600 * goTime.Second), }, want: `{ "duration": "3600s" @@ -97,7 +114,7 @@ func TestJsonMarshall(t *testing.T) { { name: "OptionalFieldMask", value: jsonmarshallv2.OptionalFields{ - FieldMask: "optional_string,optional_int32", + FieldMask: &fieldmask.FieldMask{Paths: []string{"optional_string", "optional_int32"}}, }, want: `{ "field_mask": "optional_string,optional_int32" @@ -106,7 +123,7 @@ func TestJsonMarshall(t *testing.T) { { name: "OptionalTimestamp", value: jsonmarshallv2.OptionalFields{ - Timestamp: "2023-01-01T00:00:00Z", + Timestamp: time.New(timeFromString("2023-01-01T00:00:00Z")), }, want: `{ "timestamp": "2023-01-01T00:00:00Z" @@ -133,11 +150,14 @@ func TestJsonMarshall(t *testing.T) { "required_int32": 0, "required_int64": 0, "required_bool": false, + "required_value": null, + "required_list_value": null, + "required_struct": null, "required_message": {}, "test_required_enum": "", - "required_duration": "", + "required_duration": "0s", "required_field_mask": "", - "required_timestamp": "" + "required_timestamp": "1970-01-01T00:00:00Z" }`, }, { @@ -154,23 +174,26 @@ func TestJsonMarshall(t *testing.T) { "required_int32": 0, "required_int64": 0, "required_bool": false, + "required_value": null, + "required_list_value": null, + "required_struct": null, "required_message": {}, "test_required_enum": "TEST_ENUM_ONE", - "required_duration": "", + "required_duration": "0s", "required_field_mask": "", - "required_timestamp": "" + "required_timestamp": "1970-01-01T00:00:00Z" }`, }, { name: "RequiredFieldsNonDefaults", value: jsonmarshallv2.RequiredFields{ RequiredBool: true, - RequiredDuration: "7200s", - RequiredFieldMask: "required_string,required_int32", + RequiredDuration: *duration.New(7200 * goTime.Second), + RequiredFieldMask: fieldmask.FieldMask{Paths: []string{"required_string", "required_int32"}}, RequiredInt32: 42, RequiredInt64: 1234567890123456789, RequiredString: "non_default_string", - RequiredTimestamp: "2023-12-31T23:59:59Z", + RequiredTimestamp: *time.New(timeFromString("2023-12-31T23:59:59Z")), TestRequiredEnum: jsonmarshallv2.TestEnumTestEnumTwo, }, want: `{ @@ -178,6 +201,9 @@ func TestJsonMarshall(t *testing.T) { "required_int32": 42, "required_int64": 1234567890123456789, "required_bool": true, + "required_value": null, + "required_list_value": null, + "required_struct": null, "required_message": {}, "test_required_enum": "TEST_ENUM_TWO", "required_duration": "7200s", @@ -197,19 +223,26 @@ func TestJsonMarshall(t *testing.T) { "required_int32": 0, "required_int64": 0, "required_bool": false, + "required_value": null, + "required_list_value": null, + "required_struct": null, "required_message": { "optional_string": "nested_value" }, "test_required_enum": "", - "required_duration": "", + "required_duration": "0s", "required_field_mask": "", - "required_timestamp": "" + "required_timestamp": "1970-01-01T00:00:00Z" }`, }, { name: "RepeatedString", value: jsonmarshallv2.RepeatedFields{ - RepeatedString: []string{"item1", "item2", "item3"}, + RepeatedString: []string{ + "item1", + "item2", + "item3", + }, }, want: `{ "repeated_string": ["item1", "item2", "item3"] @@ -218,7 +251,13 @@ func TestJsonMarshall(t *testing.T) { { name: "RepeatedInt32", value: jsonmarshallv2.RepeatedFields{ - RepeatedInt32: []int{1, 2, 3, 4, 5}, + RepeatedInt32: []int{ + 1, + 2, + 3, + 4, + 5, + }, }, want: `{ "repeated_int32": [1, 2, 3, 4, 5] @@ -227,7 +266,10 @@ func TestJsonMarshall(t *testing.T) { { name: "RepeatedInt64", value: jsonmarshallv2.RepeatedFields{ - RepeatedInt64: []int64{1000000000000000000, 2000000000000000000}, + RepeatedInt64: []int64{ + 1000000000000000000, + 2000000000000000000, + }, }, want: `{ "repeated_int64": [1000000000000000000, 2000000000000000000] @@ -236,7 +278,11 @@ func TestJsonMarshall(t *testing.T) { { name: "RepeatedBool", value: jsonmarshallv2.RepeatedFields{ - RepeatedBool: []bool{true, false, true}, + RepeatedBool: []bool{ + true, + false, + true, + }, }, want: `{ "repeated_bool": [true, false, true] @@ -245,7 +291,10 @@ func TestJsonMarshall(t *testing.T) { { name: "RepeatedEnum", value: jsonmarshallv2.RepeatedFields{ - TestRepeatedEnum: []jsonmarshallv2.TestEnum{jsonmarshallv2.TestEnumTestEnumOne, jsonmarshallv2.TestEnumTestEnumTwo}, + TestRepeatedEnum: []jsonmarshallv2.TestEnum{ + jsonmarshallv2.TestEnumTestEnumOne, + jsonmarshallv2.TestEnumTestEnumTwo, + }, }, want: `{ "test_repeated_enum": ["TEST_ENUM_ONE", "TEST_ENUM_TWO"] @@ -254,11 +303,14 @@ func TestJsonMarshall(t *testing.T) { { name: "RepeatedNestedMessage", value: jsonmarshallv2.RepeatedFields{ - RepeatedMessage: []jsonmarshallv2.NestedMessage{jsonmarshallv2.NestedMessage{ - OptionalString: "nested1", - }, jsonmarshallv2.NestedMessage{ - OptionalString: "nested2", - }}, + RepeatedMessage: []jsonmarshallv2.NestedMessage{ + jsonmarshallv2.NestedMessage{ + OptionalString: "nested1", + }, + jsonmarshallv2.NestedMessage{ + OptionalString: "nested2", + }, + }, }, want: `{ "repeated_message": [ @@ -274,7 +326,11 @@ func TestJsonMarshall(t *testing.T) { { name: "RepeatedDuration", value: jsonmarshallv2.RepeatedFields{ - RepeatedDuration: []string{"60s", "120s", "180s"}, + RepeatedDuration: []duration.Duration{ + *duration.New(60 * goTime.Second), + *duration.New(120 * goTime.Second), + *duration.New(180 * goTime.Second), + }, }, want: `{ "repeated_duration": ["60s", "120s", "180s"] @@ -283,7 +339,10 @@ func TestJsonMarshall(t *testing.T) { { name: "RepeatedFieldMask", value: jsonmarshallv2.RepeatedFields{ - RepeatedFieldMask: []string{"field1", "field2,field3"}, + RepeatedFieldMask: []fieldmask.FieldMask{ + fieldmask.FieldMask{Paths: []string{"field1"}}, + fieldmask.FieldMask{Paths: []string{"field2", "field3"}}, + }, }, want: `{ "repeated_field_mask": ["field1", "field2,field3"] @@ -292,7 +351,10 @@ func TestJsonMarshall(t *testing.T) { { name: "RepeatedTimestamp", value: jsonmarshallv2.RepeatedFields{ - RepeatedTimestamp: []string{"2023-01-01T00:00:00Z", "2023-01-02T00:00:00Z"}, + RepeatedTimestamp: []time.Time{ + *time.New(timeFromString("2023-01-01T00:00:00Z")), + *time.New(timeFromString("2023-01-02T00:00:00Z")), + }, }, want: `{ "repeated_timestamp": ["2023-01-01T00:00:00Z", "2023-01-02T00:00:00Z"] @@ -301,9 +363,20 @@ func TestJsonMarshall(t *testing.T) { { name: "MultipleRepeatedFields", value: jsonmarshallv2.RepeatedFields{ - RepeatedBool: []bool{true, false}, - RepeatedInt32: []int{10, 20, 30}, - RepeatedString: []string{"a", "b", "c"}, + RepeatedBool: []bool{ + true, + false, + }, + RepeatedInt32: []int{ + 10, + 20, + 30, + }, + RepeatedString: []string{ + "a", + "b", + "c", + }, }, want: `{ "repeated_string": ["a", "b", "c"], @@ -333,6 +406,19 @@ func TestJsonMarshall(t *testing.T) { }, want: `{}`, }, + { + name: "LegacyWellKnownTypes", + value: jsonmarshallv2.OptionalFields{ + LegacyDuration: "1s", + LegacyFieldMask: "legacy_duration,legacy_timestamp", + LegacyTimestamp: "2023-01-01T00:00:00Z", + }, + want: `{ + "legacy_duration": "1s", + "legacy_timestamp": "2023-01-01T00:00:00Z", + "legacy_field_mask": "legacy_duration,legacy_timestamp" + }`, + }, } for _, tc := range testCases { diff --git a/internal/generatedtests/lro_call_test.go b/internal/generatedtests/lro_call_test.go new file mode 100755 index 000000000..dfa757db9 --- /dev/null +++ b/internal/generatedtests/lro_call_test.go @@ -0,0 +1,329 @@ +// Code generated from OpenAPI specs by Databricks SDK Generator. DO NOT EDIT. +package generated_tests + +import ( + "context" + "encoding/json" + "testing" + "time" + + "github.com/databricks/databricks-sdk-go/client" + "github.com/databricks/databricks-sdk-go/internal/testspecs/service/common" + "github.com/databricks/databricks-sdk-go/internal/testspecs/service/lrotesting" + "github.com/databricks/databricks-sdk-go/qa" + "github.com/databricks/databricks-sdk-go/service/common/lro" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" +) + +func TestLRO_CreateTestResource_Wait(t *testing.T) { + tests := []struct { + name string + fixtures qa.HTTPFixtures + wantResult *lrotesting.TestResource + wantErr bool + }{ + + { + name: "Success", + fixtures: qa.HTTPFixtures{{ + Method: "POST", + Resource: "/api/2.0/lro-testing/resources", + Response: common.Operation{ + Done: false, + Metadata: json.RawMessage("{\n\t\t\t\t\t\"resource_id\": \"test-resource-123\",\n\t\t\t\t\t\"progress_percent\": 5\n\t\t\t\t}"), + Name: "operations/test-resource-create-12345", + }, + }, { + Method: "GET", + Resource: "/api/2.0/lro-testing/operations/operations/test-resource-create-12345?", + Response: common.Operation{ + Done: false, + Metadata: json.RawMessage("{\n\t\t\t\t\t\"resource_id\": \"test-resource-123\",\n\t\t\t\t\t\"progress_percent\": 75\n\t\t\t\t}"), + Name: "operations/test-resource-create-12345", + }, + }, { + Method: "GET", + Resource: "/api/2.0/lro-testing/operations/operations/test-resource-create-12345?", + Response: common.Operation{ + Done: true, + Metadata: json.RawMessage("{\n\t\t\t\t\t\"resource_id\": \"test-resource-123\",\n\t\t\t\t\t\"progress_percent\": 100\n\t\t\t\t}"), + Name: "operations/test-resource-create-12345", + Response: json.RawMessage("{\n\t\t\t\t\t\"id\": \"test-resource-123\",\n\t\t\t\t\t\"name\": \"test-resource\"\n\t\t\t\t}"), + }, + }}, + wantResult: &lrotesting.TestResource{ + Id: "test-resource-123", + Name: "test-resource", + }, + wantErr: false, + }, + + { + name: "Error", + fixtures: qa.HTTPFixtures{{ + Method: "POST", + Resource: "/api/2.0/lro-testing/resources", + Response: common.Operation{ + Done: false, + Metadata: json.RawMessage("{\n\t\t\t\t\t\"resource_id\": \"test-resource-123\",\n\t\t\t\t\t\"progress_percent\": 5\n\t\t\t\t}"), + Name: "operations/test-resource-create-12345", + }, + }, { + Method: "GET", + Resource: "/api/2.0/lro-testing/operations/operations/test-resource-create-12345?", + Response: common.Operation{ + Done: true, + Error: &common.DatabricksServiceExceptionWithDetailsProto{ + ErrorCode: common.ErrorCodeInternalError, + Message: "Test error message", + }, + Name: "operations/test-resource-create-12345", + }, + }}, + wantResult: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.fixtures.ApplyClient(t, func(ctx context.Context, client *client.DatabricksClient) { + service := lrotesting.NewLroTesting(client) + lroOp, err := service.CreateTestResource(ctx, lrotesting.CreateTestResourceRequest{ + Resource: lrotesting.TestResource{}, + }) + if err != nil { + t.Fatalf("CreateTestResource failed: %v", err) + } + result, err := lroOp.Wait(ctx, &lro.LroOptions{Timeout: 1 * time.Minute}) + if diff := cmp.Diff(tt.wantResult, result, cmpopts.IgnoreFields(lrotesting.TestResource{}, "ForceSendFields")); diff != "" { + t.Errorf("result mismatch (-expected +actual):\n%s", diff) + } + if tt.wantErr && err == nil { + t.Fatalf("expected error, got nil") + } + if !tt.wantErr && err != nil { + t.Fatalf("expected no error, got: %v", err) + } + }) + }) + } +} + +func TestLRO_CancelTestResource_Cancel(t *testing.T) { + tests := []struct { + name string + fixtures qa.HTTPFixtures + wantErr bool + }{ + + { + name: "Success", + fixtures: qa.HTTPFixtures{{ + Method: "POST", + Resource: "/api/2.0/lro-testing/resources", + Response: common.Operation{ + Done: false, + Metadata: json.RawMessage("{\n\t\t\t\t\t\"resource_id\": \"test-resource-123\",\n\t\t\t\t\t\"progress_percent\": 5\n\t\t\t\t}"), + Name: "operations/test-resource-create-12345", + }, + }, { + Method: "POST", + Resource: "/api/2.0/lro-testing/operations/operations/test-resource-create-12345/cancel", + Response: common.Operation{ + Done: true, + Name: "operations/test-resource-create-12345", + }, + }}, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.fixtures.ApplyClient(t, func(ctx context.Context, client *client.DatabricksClient) { + service := lrotesting.NewLroTesting(client) + lroOp, err := service.CreateTestResource(ctx, lrotesting.CreateTestResourceRequest{ + Resource: lrotesting.TestResource{}, + }) + if err != nil { + t.Fatalf("CreateTestResource failed: %v", err) + } + err = lroOp.Cancel(ctx) + if tt.wantErr && err == nil { + t.Fatal("Cancel should have failed") + } + if !tt.wantErr && err != nil { + t.Fatalf("Cancel failed: %v", err) + } + }) + }) + } +} +func TestLRO_CreateTestResource_Name(t *testing.T) { + tests := []struct { + name string + fixtures qa.HTTPFixtures + wantName string + }{ + + { + name: "Success", + fixtures: qa.HTTPFixtures{{ + Method: "POST", + Resource: "/api/2.0/lro-testing/resources", + Response: common.Operation{ + Done: false, + Metadata: json.RawMessage("{\n\t\t\t\t\t\"resource_id\": \"test-resource-123\",\n\t\t\t\t\t\"progress_percent\": 5\n\t\t\t\t}"), + Name: "operations/test-resource-create-12345", + }, + }}, + wantName: "operations/test-resource-create-12345", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.fixtures.ApplyClient(t, func(ctx context.Context, client *client.DatabricksClient) { + service := lrotesting.NewLroTesting(client) + lroOp, err := service.CreateTestResource(ctx, lrotesting.CreateTestResourceRequest{ + Resource: lrotesting.TestResource{}, + }) + if err != nil { + t.Fatalf("CreateTestResource failed: %v", err) + } + name := lroOp.Name() + if name != tt.wantName { + t.Errorf("name mismatch: expected %q, got %q", tt.wantName, name) + } + }) + }) + } +} +func TestLRO_CreateTestResource_Metadata(t *testing.T) { + tests := []struct { + name string + fixtures qa.HTTPFixtures + wantMetadata *lrotesting.TestResourceOperationMetadata + wantErr bool + }{ + + { + name: "Success", + fixtures: qa.HTTPFixtures{{ + Method: "POST", + Resource: "/api/2.0/lro-testing/resources", + Response: common.Operation{ + Done: false, + Metadata: json.RawMessage("{\n\t\t\t\t\t\"resource_id\": \"test-resource-123\",\n\t\t\t\t\t\"progress_percent\": 5\n\t\t\t\t}"), + Name: "operations/test-resource-create-12345", + }, + }}, + wantMetadata: &lrotesting.TestResourceOperationMetadata{ + ProgressPercent: 5, + ResourceId: "test-resource-123", + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.fixtures.ApplyClient(t, func(ctx context.Context, client *client.DatabricksClient) { + service := lrotesting.NewLroTesting(client) + lroOp, err := service.CreateTestResource(ctx, lrotesting.CreateTestResourceRequest{ + Resource: lrotesting.TestResource{}, + }) + if err != nil { + t.Fatalf("CreateTestResource failed: %v", err) + } + metadata, err := lroOp.Metadata() + if tt.wantErr && err == nil { + t.Fatal("Metadata should have failed") + } + if !tt.wantErr && err != nil { + t.Fatalf("Metadata failed: %v", err) + } + if diff := cmp.Diff(tt.wantMetadata, metadata, cmpopts.IgnoreFields(lrotesting.TestResourceOperationMetadata{}, "ForceSendFields")); diff != "" { + t.Errorf("metadata mismatch (-expected +actual):\n%s", diff) + } + }) + }) + } +} +func TestLRO_CreateTestResource_Done(t *testing.T) { + tests := []struct { + name string + fixtures qa.HTTPFixtures + wantDone bool + wantErr bool + }{ + + { + name: "True", + fixtures: qa.HTTPFixtures{{ + Method: "POST", + Resource: "/api/2.0/lro-testing/resources", + Response: common.Operation{ + Done: false, + Metadata: json.RawMessage("{\n\t\t\t\t\t\"resource_id\": \"test-resource-123\",\n\t\t\t\t\t\"progress_percent\": 5\n\t\t\t\t}"), + Name: "operations/test-resource-create-12345", + }, + }, { + Method: "GET", + Resource: "/api/2.0/lro-testing/operations/operations/test-resource-create-12345?", + Response: common.Operation{ + Done: true, + Metadata: json.RawMessage("{\n\t\t\t\t\t\"resource_id\": \"test-resource-123\",\n\t\t\t\t\t\"progress_percent\": 100\n\t\t\t\t}"), + Name: "operations/test-resource-create-12345", + Response: json.RawMessage("{\n\t\t\t\t\t\"id\": \"test-resource-123\",\n\t\t\t\t\t\"name\": \"test-resource\"\n\t\t\t\t}"), + }, + }}, + wantDone: true, + wantErr: false, + }, + + { + name: "False", + fixtures: qa.HTTPFixtures{{ + Method: "POST", + Resource: "/api/2.0/lro-testing/resources", + Response: common.Operation{ + Done: false, + Metadata: json.RawMessage("{\n\t\t\t\t\t\"resource_id\": \"test-resource-123\",\n\t\t\t\t\t\"progress_percent\": 5\n\t\t\t\t}"), + Name: "operations/test-resource-create-12345", + }, + }, { + Method: "GET", + Resource: "/api/2.0/lro-testing/operations/operations/test-resource-create-12345?", + Response: common.Operation{ + Done: false, + Metadata: json.RawMessage("{\n\t\t\t\t\t\"resource_id\": \"test-resource-123\",\n\t\t\t\t\t\"progress_percent\": 75\n\t\t\t\t}"), + Name: "operations/test-resource-create-12345", + }, + }}, + wantDone: false, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.fixtures.ApplyClient(t, func(ctx context.Context, client *client.DatabricksClient) { + service := lrotesting.NewLroTesting(client) + lroOp, err := service.CreateTestResource(ctx, lrotesting.CreateTestResourceRequest{ + Resource: lrotesting.TestResource{}, + }) + if err != nil { + t.Fatalf("CreateTestResource failed: %v", err) + } + done, err := lroOp.Done() + if tt.wantErr && err == nil { + t.Fatal("Done should have failed") + } + if !tt.wantErr && err != nil { + t.Fatalf("Done failed: %v", err) + } + if done != tt.wantDone { + t.Errorf("done mismatch: expected %v, got %v", tt.wantDone, done) + } + }) + }) + } +} diff --git a/internal/testspecs/service/common/api.go b/internal/testspecs/service/common/api.go new file mode 100755 index 000000000..9e75d4f1f --- /dev/null +++ b/internal/testspecs/service/common/api.go @@ -0,0 +1,4 @@ +// Code generated from OpenAPI specs by Databricks SDK Generator. DO NOT EDIT. + +// These APIs allow you to manage etc. +package common diff --git a/internal/testspecs/service/common/impl.go b/internal/testspecs/service/common/impl.go new file mode 100755 index 000000000..e4ce41db1 --- /dev/null +++ b/internal/testspecs/service/common/impl.go @@ -0,0 +1,3 @@ +// Code generated from OpenAPI specs by Databricks SDK Generator. DO NOT EDIT. + +package common diff --git a/internal/testspecs/service/common/model.go b/internal/testspecs/service/common/model.go new file mode 100755 index 000000000..cd47bcfb9 --- /dev/null +++ b/internal/testspecs/service/common/model.go @@ -0,0 +1,357 @@ +// Code generated from OpenAPI specs by Databricks SDK Generator. DO NOT EDIT. + +package common + +import ( + "encoding/json" + "fmt" + + "github.com/databricks/databricks-sdk-go/marshal" +) + +// Serialization format for DatabricksServiceException with error details. This +// message doesn't work for ScalaPB-04 as google.protobuf.Any is only available +// to ScalaPB-09. Note the definition of this message should be in sync with +// DatabricksServiceExceptionProto defined in +// /api-base/proto/legacy/databricks.proto except the later one doesn't have the +// error details field defined. +type DatabricksServiceExceptionWithDetailsProto struct { + // @pbjson-skip + Details []json.RawMessage `json:"details,omitempty"` + + ErrorCode ErrorCode `json:"error_code,omitempty"` + + Message string `json:"message,omitempty"` + + StackTrace string `json:"stack_trace,omitempty"` + + ForceSendFields []string `json:"-" url:"-"` +} + +func (s *DatabricksServiceExceptionWithDetailsProto) UnmarshalJSON(b []byte) error { + return marshal.Unmarshal(b, s) +} + +func (s DatabricksServiceExceptionWithDetailsProto) MarshalJSON() ([]byte, error) { + return marshal.Marshal(s) +} + +// Legacy definition of the ErrorCode enum. Please keep in sync with +// api-base/proto/error_code.proto (except status code mapping annotations as +// this file doesn't have them). Will be removed eventually, pending the ScalaPB +// 0.4 cleanup. +type ErrorCode string + +const ErrorCodeAborted ErrorCode = `ABORTED` + +const ErrorCodeAlreadyExists ErrorCode = `ALREADY_EXISTS` + +const ErrorCodeBadRequest ErrorCode = `BAD_REQUEST` + +const ErrorCodeCancelled ErrorCode = `CANCELLED` + +const ErrorCodeCatalogAlreadyExists ErrorCode = `CATALOG_ALREADY_EXISTS` + +const ErrorCodeCatalogDoesNotExist ErrorCode = `CATALOG_DOES_NOT_EXIST` + +const ErrorCodeCatalogNotEmpty ErrorCode = `CATALOG_NOT_EMPTY` + +const ErrorCodeCouldNotAcquireLock ErrorCode = `COULD_NOT_ACQUIRE_LOCK` + +const ErrorCodeCustomerUnauthorized ErrorCode = `CUSTOMER_UNAUTHORIZED` + +const ErrorCodeDacAlreadyExists ErrorCode = `DAC_ALREADY_EXISTS` + +const ErrorCodeDacDoesNotExist ErrorCode = `DAC_DOES_NOT_EXIST` + +const ErrorCodeDataLoss ErrorCode = `DATA_LOSS` + +const ErrorCodeDeadlineExceeded ErrorCode = `DEADLINE_EXCEEDED` + +const ErrorCodeDeploymentTimeout ErrorCode = `DEPLOYMENT_TIMEOUT` + +const ErrorCodeDirectoryNotEmpty ErrorCode = `DIRECTORY_NOT_EMPTY` + +const ErrorCodeDirectoryProtected ErrorCode = `DIRECTORY_PROTECTED` + +const ErrorCodeDryRunFailed ErrorCode = `DRY_RUN_FAILED` + +const ErrorCodeEndpointNotFound ErrorCode = `ENDPOINT_NOT_FOUND` + +const ErrorCodeExternalLocationAlreadyExists ErrorCode = `EXTERNAL_LOCATION_ALREADY_EXISTS` + +const ErrorCodeExternalLocationDoesNotExist ErrorCode = `EXTERNAL_LOCATION_DOES_NOT_EXIST` + +const ErrorCodeFeatureDisabled ErrorCode = `FEATURE_DISABLED` + +const ErrorCodeGitConflict ErrorCode = `GIT_CONFLICT` + +const ErrorCodeGitRemoteError ErrorCode = `GIT_REMOTE_ERROR` + +const ErrorCodeGitSensitiveTokenDetected ErrorCode = `GIT_SENSITIVE_TOKEN_DETECTED` + +const ErrorCodeGitUnknownRef ErrorCode = `GIT_UNKNOWN_REF` + +const ErrorCodeGitUrlNotOnAllowList ErrorCode = `GIT_URL_NOT_ON_ALLOW_LIST` + +const ErrorCodeInsecurePartnerResponse ErrorCode = `INSECURE_PARTNER_RESPONSE` + +const ErrorCodeInternalError ErrorCode = `INTERNAL_ERROR` + +const ErrorCodeInvalidParameterValue ErrorCode = `INVALID_PARAMETER_VALUE` + +const ErrorCodeInvalidState ErrorCode = `INVALID_STATE` + +const ErrorCodeInvalidStateTransition ErrorCode = `INVALID_STATE_TRANSITION` + +const ErrorCodeIoError ErrorCode = `IO_ERROR` + +const ErrorCodeIpynbFileInRepo ErrorCode = `IPYNB_FILE_IN_REPO` + +const ErrorCodeMalformedPartnerResponse ErrorCode = `MALFORMED_PARTNER_RESPONSE` + +const ErrorCodeMalformedRequest ErrorCode = `MALFORMED_REQUEST` + +const ErrorCodeManagedResourceGroupDoesNotExist ErrorCode = `MANAGED_RESOURCE_GROUP_DOES_NOT_EXIST` + +const ErrorCodeMaxBlockSizeExceeded ErrorCode = `MAX_BLOCK_SIZE_EXCEEDED` + +const ErrorCodeMaxChildNodeSizeExceeded ErrorCode = `MAX_CHILD_NODE_SIZE_EXCEEDED` + +const ErrorCodeMaxListSizeExceeded ErrorCode = `MAX_LIST_SIZE_EXCEEDED` + +const ErrorCodeMaxNotebookSizeExceeded ErrorCode = `MAX_NOTEBOOK_SIZE_EXCEEDED` + +const ErrorCodeMaxReadSizeExceeded ErrorCode = `MAX_READ_SIZE_EXCEEDED` + +const ErrorCodeMetastoreAlreadyExists ErrorCode = `METASTORE_ALREADY_EXISTS` + +const ErrorCodeMetastoreDoesNotExist ErrorCode = `METASTORE_DOES_NOT_EXIST` + +const ErrorCodeMetastoreNotEmpty ErrorCode = `METASTORE_NOT_EMPTY` + +const ErrorCodeNotFound ErrorCode = `NOT_FOUND` + +const ErrorCodeNotImplemented ErrorCode = `NOT_IMPLEMENTED` + +const ErrorCodePartialDelete ErrorCode = `PARTIAL_DELETE` + +const ErrorCodePermissionDenied ErrorCode = `PERMISSION_DENIED` + +const ErrorCodePermissionNotPropagated ErrorCode = `PERMISSION_NOT_PROPAGATED` + +const ErrorCodePrincipalDoesNotExist ErrorCode = `PRINCIPAL_DOES_NOT_EXIST` + +const ErrorCodeProjectsOperationTimeout ErrorCode = `PROJECTS_OPERATION_TIMEOUT` + +const ErrorCodeProviderAlreadyExists ErrorCode = `PROVIDER_ALREADY_EXISTS` + +const ErrorCodeProviderDoesNotExist ErrorCode = `PROVIDER_DOES_NOT_EXIST` + +const ErrorCodeProviderShareNotAccessible ErrorCode = `PROVIDER_SHARE_NOT_ACCESSIBLE` + +const ErrorCodeQuotaExceeded ErrorCode = `QUOTA_EXCEEDED` + +const ErrorCodeRecipientAlreadyExists ErrorCode = `RECIPIENT_ALREADY_EXISTS` + +const ErrorCodeRecipientDoesNotExist ErrorCode = `RECIPIENT_DOES_NOT_EXIST` + +const ErrorCodeRequestLimitExceeded ErrorCode = `REQUEST_LIMIT_EXCEEDED` + +const ErrorCodeResourceAlreadyExists ErrorCode = `RESOURCE_ALREADY_EXISTS` + +const ErrorCodeResourceConflict ErrorCode = `RESOURCE_CONFLICT` + +const ErrorCodeResourceDoesNotExist ErrorCode = `RESOURCE_DOES_NOT_EXIST` + +const ErrorCodeResourceExhausted ErrorCode = `RESOURCE_EXHAUSTED` + +const ErrorCodeResourceLimitExceeded ErrorCode = `RESOURCE_LIMIT_EXCEEDED` + +const ErrorCodeSchemaAlreadyExists ErrorCode = `SCHEMA_ALREADY_EXISTS` + +const ErrorCodeSchemaDoesNotExist ErrorCode = `SCHEMA_DOES_NOT_EXIST` + +const ErrorCodeSchemaNotEmpty ErrorCode = `SCHEMA_NOT_EMPTY` + +const ErrorCodeSearchQueryTooLong ErrorCode = `SEARCH_QUERY_TOO_LONG` + +const ErrorCodeSearchQueryTooShort ErrorCode = `SEARCH_QUERY_TOO_SHORT` + +const ErrorCodeServiceUnderMaintenance ErrorCode = `SERVICE_UNDER_MAINTENANCE` + +const ErrorCodeShareAlreadyExists ErrorCode = `SHARE_ALREADY_EXISTS` + +const ErrorCodeShareDoesNotExist ErrorCode = `SHARE_DOES_NOT_EXIST` + +const ErrorCodeStorageCredentialAlreadyExists ErrorCode = `STORAGE_CREDENTIAL_ALREADY_EXISTS` + +const ErrorCodeStorageCredentialDoesNotExist ErrorCode = `STORAGE_CREDENTIAL_DOES_NOT_EXIST` + +const ErrorCodeTableAlreadyExists ErrorCode = `TABLE_ALREADY_EXISTS` + +const ErrorCodeTableDoesNotExist ErrorCode = `TABLE_DOES_NOT_EXIST` + +const ErrorCodeTemporarilyUnavailable ErrorCode = `TEMPORARILY_UNAVAILABLE` + +const ErrorCodeUnauthenticated ErrorCode = `UNAUTHENTICATED` + +const ErrorCodeUnavailable ErrorCode = `UNAVAILABLE` + +const ErrorCodeUnknown ErrorCode = `UNKNOWN` + +const ErrorCodeUnparseableHttpError ErrorCode = `UNPARSEABLE_HTTP_ERROR` + +const ErrorCodeWorkspaceTemporarilyUnavailable ErrorCode = `WORKSPACE_TEMPORARILY_UNAVAILABLE` + +// String representation for [fmt.Print] +func (f *ErrorCode) String() string { + return string(*f) +} + +// Set raw string value and validate it against allowed values +func (f *ErrorCode) Set(v string) error { + switch v { + case `ABORTED`, `ALREADY_EXISTS`, `BAD_REQUEST`, `CANCELLED`, `CATALOG_ALREADY_EXISTS`, `CATALOG_DOES_NOT_EXIST`, `CATALOG_NOT_EMPTY`, `COULD_NOT_ACQUIRE_LOCK`, `CUSTOMER_UNAUTHORIZED`, `DAC_ALREADY_EXISTS`, `DAC_DOES_NOT_EXIST`, `DATA_LOSS`, `DEADLINE_EXCEEDED`, `DEPLOYMENT_TIMEOUT`, `DIRECTORY_NOT_EMPTY`, `DIRECTORY_PROTECTED`, `DRY_RUN_FAILED`, `ENDPOINT_NOT_FOUND`, `EXTERNAL_LOCATION_ALREADY_EXISTS`, `EXTERNAL_LOCATION_DOES_NOT_EXIST`, `FEATURE_DISABLED`, `GIT_CONFLICT`, `GIT_REMOTE_ERROR`, `GIT_SENSITIVE_TOKEN_DETECTED`, `GIT_UNKNOWN_REF`, `GIT_URL_NOT_ON_ALLOW_LIST`, `INSECURE_PARTNER_RESPONSE`, `INTERNAL_ERROR`, `INVALID_PARAMETER_VALUE`, `INVALID_STATE`, `INVALID_STATE_TRANSITION`, `IO_ERROR`, `IPYNB_FILE_IN_REPO`, `MALFORMED_PARTNER_RESPONSE`, `MALFORMED_REQUEST`, `MANAGED_RESOURCE_GROUP_DOES_NOT_EXIST`, `MAX_BLOCK_SIZE_EXCEEDED`, `MAX_CHILD_NODE_SIZE_EXCEEDED`, `MAX_LIST_SIZE_EXCEEDED`, `MAX_NOTEBOOK_SIZE_EXCEEDED`, `MAX_READ_SIZE_EXCEEDED`, `METASTORE_ALREADY_EXISTS`, `METASTORE_DOES_NOT_EXIST`, `METASTORE_NOT_EMPTY`, `NOT_FOUND`, `NOT_IMPLEMENTED`, `PARTIAL_DELETE`, `PERMISSION_DENIED`, `PERMISSION_NOT_PROPAGATED`, `PRINCIPAL_DOES_NOT_EXIST`, `PROJECTS_OPERATION_TIMEOUT`, `PROVIDER_ALREADY_EXISTS`, `PROVIDER_DOES_NOT_EXIST`, `PROVIDER_SHARE_NOT_ACCESSIBLE`, `QUOTA_EXCEEDED`, `RECIPIENT_ALREADY_EXISTS`, `RECIPIENT_DOES_NOT_EXIST`, `REQUEST_LIMIT_EXCEEDED`, `RESOURCE_ALREADY_EXISTS`, `RESOURCE_CONFLICT`, `RESOURCE_DOES_NOT_EXIST`, `RESOURCE_EXHAUSTED`, `RESOURCE_LIMIT_EXCEEDED`, `SCHEMA_ALREADY_EXISTS`, `SCHEMA_DOES_NOT_EXIST`, `SCHEMA_NOT_EMPTY`, `SEARCH_QUERY_TOO_LONG`, `SEARCH_QUERY_TOO_SHORT`, `SERVICE_UNDER_MAINTENANCE`, `SHARE_ALREADY_EXISTS`, `SHARE_DOES_NOT_EXIST`, `STORAGE_CREDENTIAL_ALREADY_EXISTS`, `STORAGE_CREDENTIAL_DOES_NOT_EXIST`, `TABLE_ALREADY_EXISTS`, `TABLE_DOES_NOT_EXIST`, `TEMPORARILY_UNAVAILABLE`, `UNAUTHENTICATED`, `UNAVAILABLE`, `UNKNOWN`, `UNPARSEABLE_HTTP_ERROR`, `WORKSPACE_TEMPORARILY_UNAVAILABLE`: + *f = ErrorCode(v) + return nil + default: + return fmt.Errorf(`value "%s" is not one of "ABORTED", "ALREADY_EXISTS", "BAD_REQUEST", "CANCELLED", "CATALOG_ALREADY_EXISTS", "CATALOG_DOES_NOT_EXIST", "CATALOG_NOT_EMPTY", "COULD_NOT_ACQUIRE_LOCK", "CUSTOMER_UNAUTHORIZED", "DAC_ALREADY_EXISTS", "DAC_DOES_NOT_EXIST", "DATA_LOSS", "DEADLINE_EXCEEDED", "DEPLOYMENT_TIMEOUT", "DIRECTORY_NOT_EMPTY", "DIRECTORY_PROTECTED", "DRY_RUN_FAILED", "ENDPOINT_NOT_FOUND", "EXTERNAL_LOCATION_ALREADY_EXISTS", "EXTERNAL_LOCATION_DOES_NOT_EXIST", "FEATURE_DISABLED", "GIT_CONFLICT", "GIT_REMOTE_ERROR", "GIT_SENSITIVE_TOKEN_DETECTED", "GIT_UNKNOWN_REF", "GIT_URL_NOT_ON_ALLOW_LIST", "INSECURE_PARTNER_RESPONSE", "INTERNAL_ERROR", "INVALID_PARAMETER_VALUE", "INVALID_STATE", "INVALID_STATE_TRANSITION", "IO_ERROR", "IPYNB_FILE_IN_REPO", "MALFORMED_PARTNER_RESPONSE", "MALFORMED_REQUEST", "MANAGED_RESOURCE_GROUP_DOES_NOT_EXIST", "MAX_BLOCK_SIZE_EXCEEDED", "MAX_CHILD_NODE_SIZE_EXCEEDED", "MAX_LIST_SIZE_EXCEEDED", "MAX_NOTEBOOK_SIZE_EXCEEDED", "MAX_READ_SIZE_EXCEEDED", "METASTORE_ALREADY_EXISTS", "METASTORE_DOES_NOT_EXIST", "METASTORE_NOT_EMPTY", "NOT_FOUND", "NOT_IMPLEMENTED", "PARTIAL_DELETE", "PERMISSION_DENIED", "PERMISSION_NOT_PROPAGATED", "PRINCIPAL_DOES_NOT_EXIST", "PROJECTS_OPERATION_TIMEOUT", "PROVIDER_ALREADY_EXISTS", "PROVIDER_DOES_NOT_EXIST", "PROVIDER_SHARE_NOT_ACCESSIBLE", "QUOTA_EXCEEDED", "RECIPIENT_ALREADY_EXISTS", "RECIPIENT_DOES_NOT_EXIST", "REQUEST_LIMIT_EXCEEDED", "RESOURCE_ALREADY_EXISTS", "RESOURCE_CONFLICT", "RESOURCE_DOES_NOT_EXIST", "RESOURCE_EXHAUSTED", "RESOURCE_LIMIT_EXCEEDED", "SCHEMA_ALREADY_EXISTS", "SCHEMA_DOES_NOT_EXIST", "SCHEMA_NOT_EMPTY", "SEARCH_QUERY_TOO_LONG", "SEARCH_QUERY_TOO_SHORT", "SERVICE_UNDER_MAINTENANCE", "SHARE_ALREADY_EXISTS", "SHARE_DOES_NOT_EXIST", "STORAGE_CREDENTIAL_ALREADY_EXISTS", "STORAGE_CREDENTIAL_DOES_NOT_EXIST", "TABLE_ALREADY_EXISTS", "TABLE_DOES_NOT_EXIST", "TEMPORARILY_UNAVAILABLE", "UNAUTHENTICATED", "UNAVAILABLE", "UNKNOWN", "UNPARSEABLE_HTTP_ERROR", "WORKSPACE_TEMPORARILY_UNAVAILABLE"`, v) + } +} + +// Values returns all possible values for ErrorCode. +// +// There is no guarantee on the order of the values in the slice. +func (f *ErrorCode) Values() []ErrorCode { + return []ErrorCode{ + ErrorCodeAborted, + ErrorCodeAlreadyExists, + ErrorCodeBadRequest, + ErrorCodeCancelled, + ErrorCodeCatalogAlreadyExists, + ErrorCodeCatalogDoesNotExist, + ErrorCodeCatalogNotEmpty, + ErrorCodeCouldNotAcquireLock, + ErrorCodeCustomerUnauthorized, + ErrorCodeDacAlreadyExists, + ErrorCodeDacDoesNotExist, + ErrorCodeDataLoss, + ErrorCodeDeadlineExceeded, + ErrorCodeDeploymentTimeout, + ErrorCodeDirectoryNotEmpty, + ErrorCodeDirectoryProtected, + ErrorCodeDryRunFailed, + ErrorCodeEndpointNotFound, + ErrorCodeExternalLocationAlreadyExists, + ErrorCodeExternalLocationDoesNotExist, + ErrorCodeFeatureDisabled, + ErrorCodeGitConflict, + ErrorCodeGitRemoteError, + ErrorCodeGitSensitiveTokenDetected, + ErrorCodeGitUnknownRef, + ErrorCodeGitUrlNotOnAllowList, + ErrorCodeInsecurePartnerResponse, + ErrorCodeInternalError, + ErrorCodeInvalidParameterValue, + ErrorCodeInvalidState, + ErrorCodeInvalidStateTransition, + ErrorCodeIoError, + ErrorCodeIpynbFileInRepo, + ErrorCodeMalformedPartnerResponse, + ErrorCodeMalformedRequest, + ErrorCodeManagedResourceGroupDoesNotExist, + ErrorCodeMaxBlockSizeExceeded, + ErrorCodeMaxChildNodeSizeExceeded, + ErrorCodeMaxListSizeExceeded, + ErrorCodeMaxNotebookSizeExceeded, + ErrorCodeMaxReadSizeExceeded, + ErrorCodeMetastoreAlreadyExists, + ErrorCodeMetastoreDoesNotExist, + ErrorCodeMetastoreNotEmpty, + ErrorCodeNotFound, + ErrorCodeNotImplemented, + ErrorCodePartialDelete, + ErrorCodePermissionDenied, + ErrorCodePermissionNotPropagated, + ErrorCodePrincipalDoesNotExist, + ErrorCodeProjectsOperationTimeout, + ErrorCodeProviderAlreadyExists, + ErrorCodeProviderDoesNotExist, + ErrorCodeProviderShareNotAccessible, + ErrorCodeQuotaExceeded, + ErrorCodeRecipientAlreadyExists, + ErrorCodeRecipientDoesNotExist, + ErrorCodeRequestLimitExceeded, + ErrorCodeResourceAlreadyExists, + ErrorCodeResourceConflict, + ErrorCodeResourceDoesNotExist, + ErrorCodeResourceExhausted, + ErrorCodeResourceLimitExceeded, + ErrorCodeSchemaAlreadyExists, + ErrorCodeSchemaDoesNotExist, + ErrorCodeSchemaNotEmpty, + ErrorCodeSearchQueryTooLong, + ErrorCodeSearchQueryTooShort, + ErrorCodeServiceUnderMaintenance, + ErrorCodeShareAlreadyExists, + ErrorCodeShareDoesNotExist, + ErrorCodeStorageCredentialAlreadyExists, + ErrorCodeStorageCredentialDoesNotExist, + ErrorCodeTableAlreadyExists, + ErrorCodeTableDoesNotExist, + ErrorCodeTemporarilyUnavailable, + ErrorCodeUnauthenticated, + ErrorCodeUnavailable, + ErrorCodeUnknown, + ErrorCodeUnparseableHttpError, + ErrorCodeWorkspaceTemporarilyUnavailable, + } +} + +// Type always returns ErrorCode to satisfy [pflag.Value] interface +func (f *ErrorCode) Type() string { + return "ErrorCode" +} + +// This resource represents a long-running operation that is the result of a +// network API call. +type Operation struct { + // If the value is `false`, it means the operation is still in progress. If + // `true`, the operation is completed, and either `error` or `response` is + // available. + Done bool `json:"done,omitempty"` + // The error result of the operation in case of failure or cancellation. + Error *DatabricksServiceExceptionWithDetailsProto `json:"error,omitempty"` + // Service-specific metadata associated with the operation. It typically + // contains progress information and common metadata such as create time. + // Some services might not provide such metadata. Any method that returns a + // long-running operation should document the metadata type, if any. + Metadata json.RawMessage `json:"metadata,omitempty"` + // The server-assigned name, which is only unique within the same service + // that originally returns it. If you use the default HTTP mapping, the + // `name` should be a resource name ending with `operations/{unique_id}`. + // + // Note: multi-segment resource names are not yet supported in the RPC + // framework and SDK/TF. Until that support is added, `name` must be string + // without internal `/` separators. + Name string `json:"name,omitempty"` + // The normal, successful response of the operation. If the original method + // returns no data on success, such as `Delete`, the response is + // `google.protobuf.Empty`. If the original method is standard + // `Get`/`Create`/`Update`, the response should be the resource. For other + // methods, the response should have the type `XxxResponse`, where `Xxx` is + // the original method name. For example, if the original method name is + // `TakeSnapshot()`, the inferred response type is `TakeSnapshotResponse`. + Response json.RawMessage `json:"response,omitempty"` + + ForceSendFields []string `json:"-" url:"-"` +} + +func (s *Operation) UnmarshalJSON(b []byte) error { + return marshal.Unmarshal(b, s) +} + +func (s Operation) MarshalJSON() ([]byte, error) { + return marshal.Marshal(s) +} diff --git a/internal/testspecs/service/httpcallv2/impl.go b/internal/testspecs/service/httpcallv2/impl.go index 253f37fcf..9c10a48f3 100755 --- a/internal/testspecs/service/httpcallv2/impl.go +++ b/internal/testspecs/service/httpcallv2/impl.go @@ -4,8 +4,10 @@ package httpcallv2 import ( "context" + "encoding/json" "fmt" "net/http" + "strings" "github.com/databricks/databricks-sdk-go/client" "golang.org/x/exp/slices" @@ -41,25 +43,37 @@ func (a *httpCallV2Impl) UpdateResource(ctx context.Context, request UpdateResou var resource Resource path := fmt.Sprintf("/api/2.0/http-call/%v/%v/%v", request.NestedPathParamString, request.NestedPathParamInt, request.NestedPathParamBool) queryParams := make(map[string]any) - if request.FieldMask != "" || slices.Contains(request.ForceSendFields, "FieldMask") { - queryParams["field_mask"] = request.FieldMask + + if request.FieldMask != nil || slices.Contains(request.ForceSendFields, "FieldMask") { + fieldMaskJson, fieldMaskMarshallError := json.Marshal(request.FieldMask) + if fieldMaskMarshallError != nil { + return nil, fieldMaskMarshallError + } + + queryParams["field_mask"] = strings.Trim(string(fieldMaskJson), `"`) } + if request.OptionalComplexQueryParam != nil || slices.Contains(request.ForceSendFields, "OptionalComplexQueryParam") { queryParams["optional_complex_query_param"] = request.OptionalComplexQueryParam } + if request.QueryParamBool != false || slices.Contains(request.ForceSendFields, "QueryParamBool") { queryParams["query_param_bool"] = request.QueryParamBool } + if request.QueryParamInt != 0 || slices.Contains(request.ForceSendFields, "QueryParamInt") { queryParams["query_param_int"] = request.QueryParamInt } + if request.QueryParamString != "" || slices.Contains(request.ForceSendFields, "QueryParamString") { queryParams["query_param_string"] = request.QueryParamString } - if request.RepeatedComplexQueryParam != nil || slices.Contains(request.ForceSendFields, "RepeatedComplexQueryParam") { + + if slices.Contains(request.ForceSendFields, "RepeatedComplexQueryParam") { queryParams["repeated_complex_query_param"] = request.RepeatedComplexQueryParam } - if request.RepeatedQueryParam != nil || slices.Contains(request.ForceSendFields, "RepeatedQueryParam") { + + if slices.Contains(request.ForceSendFields, "RepeatedQueryParam") { queryParams["repeated_query_param"] = request.RepeatedQueryParam } headers := make(map[string]string) diff --git a/internal/testspecs/service/httpcallv2/model.go b/internal/testspecs/service/httpcallv2/model.go index 156db6cdb..a089f94e4 100755 --- a/internal/testspecs/service/httpcallv2/model.go +++ b/internal/testspecs/service/httpcallv2/model.go @@ -3,6 +3,9 @@ package httpcallv2 import ( + "encoding/json" + + "github.com/databricks/databricks-sdk-go/common/types/fieldmask" "github.com/databricks/databricks-sdk-go/marshal" ) @@ -51,7 +54,7 @@ type GetResourceRequest struct { // Specification of elements in sequence or map fields is not allowed, as // only the entire collection field can be specified. Field names must // exactly match the resource field names. - FieldMask string `json:"-" url:"field_mask,omitempty"` + FieldMask *fieldmask.FieldMask `json:"-" url:"field_mask,omitempty"` OptionalComplexQueryParam *ComplexQueryParam `json:"-" url:"optional_complex_query_param,omitempty"` @@ -83,6 +86,8 @@ func (s GetResourceRequest) MarshalJSON() ([]byte, error) { } type Resource struct { + AnyField json.RawMessage `json:"any_field,omitempty"` + BodyField string `json:"body_field,omitempty"` NestedPathParamBool bool `json:"nested_path_param_bool,omitempty"` @@ -109,7 +114,7 @@ type UpdateResourceRequest struct { // Specification of elements in sequence or map fields is not allowed, as // only the entire collection field can be specified. Field names must // exactly match the resource field names. - FieldMask string `json:"-" url:"field_mask,omitempty"` + FieldMask *fieldmask.FieldMask `json:"-" url:"field_mask,omitempty"` NestedPathParamBool bool `json:"-" url:"-"` diff --git a/internal/testspecs/service/jsonmarshallv2/model.go b/internal/testspecs/service/jsonmarshallv2/model.go index b1e9899e1..be284152b 100755 --- a/internal/testspecs/service/jsonmarshallv2/model.go +++ b/internal/testspecs/service/jsonmarshallv2/model.go @@ -3,8 +3,12 @@ package jsonmarshallv2 import ( + "encoding/json" "fmt" + "github.com/databricks/databricks-sdk-go/common/types/duration" + "github.com/databricks/databricks-sdk-go/common/types/fieldmask" + "github.com/databricks/databricks-sdk-go/common/types/time" "github.com/databricks/databricks-sdk-go/marshal" ) @@ -15,11 +19,11 @@ type GetResourceRequest struct { } type NestedMessage struct { - OptionalDuration string `json:"optional_duration,omitempty" url:"optional_duration,omitempty"` + OptionalDuration *duration.Duration `json:"optional_duration,omitempty" url:"optional_duration,omitempty"` OptionalString string `json:"optional_string,omitempty" url:"optional_string,omitempty"` - OptionalTimestamp string `json:"optional_timestamp,omitempty" url:"optional_timestamp,omitempty"` + OptionalTimestamp *time.Time `json:"optional_timestamp,omitempty" url:"optional_timestamp,omitempty"` ForceSendFields []string `json:"-" url:"-"` } @@ -33,14 +37,27 @@ func (s NestedMessage) MarshalJSON() ([]byte, error) { } type OptionalFields struct { - Duration string `json:"duration,omitempty" url:"duration,omitempty"` + Duration *duration.Duration `json:"duration,omitempty" url:"duration,omitempty"` // The field mask must be a single string, with multiple fields separated by // commas (no spaces). The field path is relative to the resource object, // using a dot (`.`) to navigate sub-fields (e.g., `author.given_name`). // Specification of elements in sequence or map fields is not allowed, as // only the entire collection field can be specified. Field names must // exactly match the resource field names. - FieldMask string `json:"field_mask,omitempty" url:"field_mask,omitempty"` + FieldMask *fieldmask.FieldMask `json:"field_mask,omitempty" url:"field_mask,omitempty"` + // Legacy Well Known types + LegacyDuration string `json:"legacy_duration,omitempty" url:"legacy_duration,omitempty"` + // The field mask must be a single string, with multiple fields separated by + // commas (no spaces). The field path is relative to the resource object, + // using a dot (`.`) to navigate sub-fields (e.g., `author.given_name`). + // Specification of elements in sequence or map fields is not allowed, as + // only the entire collection field can be specified. Field names must + // exactly match the resource field names. + LegacyFieldMask string `json:"legacy_field_mask,omitempty" url:"legacy_field_mask,omitempty"` + + LegacyTimestamp string `json:"legacy_timestamp,omitempty" url:"legacy_timestamp,omitempty"` + + ListValue []json.RawMessage `json:"list_value,omitempty" url:"list_value,omitempty"` // Lint disable reason: This is a dummy field used to test SDK Generation // logic. Map map[string]string `json:"map,omitempty" url:"map,omitempty"` @@ -55,9 +72,13 @@ type OptionalFields struct { OptionalString string `json:"optional_string,omitempty" url:"optional_string,omitempty"` + Struct map[string]json.RawMessage `json:"struct,omitempty" url:"struct,omitempty"` + TestEnum TestEnum `json:"test_enum,omitempty" url:"test_enum,omitempty"` - Timestamp string `json:"timestamp,omitempty" url:"timestamp,omitempty"` + Timestamp *time.Time `json:"timestamp,omitempty" url:"timestamp,omitempty"` + + Value *json.RawMessage `json:"value,omitempty" url:"value,omitempty"` ForceSendFields []string `json:"-" url:"-"` } @@ -73,19 +94,25 @@ func (s OptionalFields) MarshalJSON() ([]byte, error) { type RepeatedFields struct { RepeatedBool []bool `json:"repeated_bool,omitempty" url:"repeated_bool,omitempty"` - RepeatedDuration []string `json:"repeated_duration,omitempty" url:"repeated_duration,omitempty"` + RepeatedDuration []duration.Duration `json:"repeated_duration,omitempty" url:"repeated_duration,omitempty"` - RepeatedFieldMask []string `json:"repeated_field_mask,omitempty" url:"repeated_field_mask,omitempty"` + RepeatedFieldMask []fieldmask.FieldMask `json:"repeated_field_mask,omitempty" url:"repeated_field_mask,omitempty"` RepeatedInt32 []int `json:"repeated_int32,omitempty" url:"repeated_int32,omitempty"` RepeatedInt64 []int64 `json:"repeated_int64,omitempty" url:"repeated_int64,omitempty"` + RepeatedListValue [][]json.RawMessage `json:"repeated_list_value,omitempty" url:"repeated_list_value,omitempty"` + RepeatedMessage []NestedMessage `json:"repeated_message,omitempty" url:"repeated_message,omitempty"` RepeatedString []string `json:"repeated_string,omitempty" url:"repeated_string,omitempty"` - RepeatedTimestamp []string `json:"repeated_timestamp,omitempty" url:"repeated_timestamp,omitempty"` + RepeatedStruct []map[string]json.RawMessage `json:"repeated_struct,omitempty" url:"repeated_struct,omitempty"` + + RepeatedTimestamp []time.Time `json:"repeated_timestamp,omitempty" url:"repeated_timestamp,omitempty"` + + RepeatedValue []json.RawMessage `json:"repeated_value,omitempty" url:"repeated_value,omitempty"` TestRepeatedEnum []TestEnum `json:"test_repeated_enum,omitempty" url:"test_repeated_enum,omitempty"` } @@ -93,24 +120,30 @@ type RepeatedFields struct { type RequiredFields struct { RequiredBool bool `json:"required_bool" url:"required_bool"` - RequiredDuration string `json:"required_duration" url:"required_duration"` + RequiredDuration duration.Duration `json:"required_duration" url:"required_duration"` // The field mask must be a single string, with multiple fields separated by // commas (no spaces). The field path is relative to the resource object, // using a dot (`.`) to navigate sub-fields (e.g., `author.given_name`). // Specification of elements in sequence or map fields is not allowed, as // only the entire collection field can be specified. Field names must // exactly match the resource field names. - RequiredFieldMask string `json:"required_field_mask" url:"required_field_mask"` + RequiredFieldMask fieldmask.FieldMask `json:"required_field_mask" url:"required_field_mask"` RequiredInt32 int `json:"required_int32" url:"required_int32"` RequiredInt64 int64 `json:"required_int64" url:"required_int64"` + RequiredListValue []json.RawMessage `json:"required_list_value" url:"required_list_value"` + RequiredMessage NestedMessage `json:"required_message" url:"required_message"` RequiredString string `json:"required_string" url:"required_string"` - RequiredTimestamp string `json:"required_timestamp" url:"required_timestamp"` + RequiredStruct map[string]json.RawMessage `json:"required_struct" url:"required_struct"` + + RequiredTimestamp time.Time `json:"required_timestamp" url:"required_timestamp"` + + RequiredValue json.RawMessage `json:"required_value" url:"required_value"` TestRequiredEnum TestEnum `json:"test_required_enum" url:"test_required_enum"` } diff --git a/internal/testspecs/service/lrotesting/api.go b/internal/testspecs/service/lrotesting/api.go new file mode 100755 index 000000000..c2bf712a0 --- /dev/null +++ b/internal/testspecs/service/lrotesting/api.go @@ -0,0 +1,159 @@ +// Code generated from OpenAPI specs by Databricks SDK Generator. DO NOT EDIT. + +// Test service for Long Running Operations +package lrotesting + +import ( + "context" + "encoding/json" + "fmt" + "time" + + "github.com/databricks/databricks-sdk-go/client" + "github.com/databricks/databricks-sdk-go/internal/testspecs/service/common" + "github.com/databricks/databricks-sdk-go/retries" + "github.com/databricks/databricks-sdk-go/service/common/lro" + "github.com/databricks/databricks-sdk-go/useragent" +) + +type LroTestingInterface interface { + CancelOperation(ctx context.Context, request CancelOperationRequest) error + + CreateTestResource(ctx context.Context, request CreateTestResourceRequest) (*CreateTestResourceOperation, error) + + GetOperation(ctx context.Context, request GetOperationRequest) (*common.Operation, error) + + // Simple method to get test resource + GetTestResource(ctx context.Context, request GetTestResourceRequest) (*TestResource, error) +} + +func NewLroTesting(client *client.DatabricksClient) *LroTestingAPI { + return &LroTestingAPI{ + lroTestingImpl: lroTestingImpl{ + client: client, + }, + } +} + +// Test service for Long Running Operations +type LroTestingAPI struct { + lroTestingImpl +} + +func (a *LroTestingAPI) CreateTestResource(ctx context.Context, request CreateTestResourceRequest) (*CreateTestResourceOperation, error) { + operation, err := a.lroTestingImpl.CreateTestResource(ctx, request) + if err != nil { + return nil, err + } + return &CreateTestResourceOperation{ + impl: &a.lroTestingImpl, + operation: operation, + }, nil +} + +type CreateTestResourceOperation struct { + impl *lroTestingImpl + operation *common.Operation +} + +// Wait blocks until the long-running operation is completed with default 20 min +// timeout, the timeout can be overridden in the opts. If the operation didn't +// finished within the timeout, this function will through an error of type +// ErrTimedOut, otherwise successful response and any errors encountered. +func (a *CreateTestResourceOperation) Wait(ctx context.Context, opts *lro.LroOptions) (*TestResource, error) { + timeout := 20 * time.Minute // default timeout per LRO spec + if opts != nil && opts.Timeout > 0 { + timeout = opts.Timeout + } + + ctx = useragent.InContext(ctx, "sdk-feature", "long-running") + return retries.Poll[TestResource](ctx, timeout, func() (*TestResource, *retries.Err) { + operation, err := a.impl.GetOperation(ctx, GetOperationRequest{ + Name: a.operation.Name, + }) + if err != nil { + return nil, retries.Halt(err) + } + + // Update local operation state + a.operation = operation + + if !operation.Done { + return nil, retries.Continues("operation still in progress") + } + + if operation.Error != nil { + var errorMsg string + if operation.Error.Message != "" { + errorMsg = operation.Error.Message + } else { + errorMsg = "unknown error" + } + + if operation.Error.ErrorCode != "" { + errorMsg = fmt.Sprintf("[%s] %s", operation.Error.ErrorCode, errorMsg) + } + + return nil, retries.Halt(fmt.Errorf("operation failed: %s", errorMsg)) + } + + // Operation completed successfully, unmarshal response + if operation.Response == nil { + return nil, retries.Halt(fmt.Errorf("operation completed but no response available")) + } + + var testResource TestResource + err = json.Unmarshal(operation.Response, &testResource) + if err != nil { + return nil, retries.Halt(fmt.Errorf("failed to unmarshal testResource response: %w", err)) + } + + return &testResource, nil + }) +} + +// Starts asynchronous cancellation on a long-running operation. The server +// makes a best effort to cancel the operation, but success is not guaranteed. +func (a *CreateTestResourceOperation) Cancel(ctx context.Context) error { + return a.impl.CancelOperation(ctx, CancelOperationRequest{ + Name: a.operation.Name, + }) +} + +// Name returns the name of the long-running operation. The name is assigned +// by the server and is unique within the service from which the operation is created. +func (a *CreateTestResourceOperation) Name() string { + return a.operation.Name +} + +// Metadata returns metadata associated with the long-running operation. +// If the metadata is not available, the returned metadata and error are both nil. +func (a *CreateTestResourceOperation) Metadata() (*TestResourceOperationMetadata, error) { + if a.operation.Metadata == nil { + return nil, nil + } + + var metadata TestResourceOperationMetadata + err := json.Unmarshal(a.operation.Metadata, &metadata) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal operation metadata: %w", err) + } + + return &metadata, nil +} + +// Done reports whether the long-running operation has completed. +func (a *CreateTestResourceOperation) Done() (bool, error) { + // Refresh the operation state first + operation, err := a.impl.GetOperation(context.Background(), GetOperationRequest{ + Name: a.operation.Name, + }) + if err != nil { + return false, err + } + + // Update local operation state + a.operation = operation + + return operation.Done, nil +} diff --git a/internal/testspecs/service/lrotesting/impl.go b/internal/testspecs/service/lrotesting/impl.go new file mode 100755 index 000000000..c975fa3b6 --- /dev/null +++ b/internal/testspecs/service/lrotesting/impl.go @@ -0,0 +1,57 @@ +// Code generated from OpenAPI specs by Databricks SDK Generator. DO NOT EDIT. + +package lrotesting + +import ( + "context" + "fmt" + "net/http" + + "github.com/databricks/databricks-sdk-go/client" + "github.com/databricks/databricks-sdk-go/internal/testspecs/service/common" +) + +// unexported type that holds implementations of just LroTesting API methods +type lroTestingImpl struct { + client *client.DatabricksClient +} + +func (a *lroTestingImpl) CancelOperation(ctx context.Context, request CancelOperationRequest) error { + path := fmt.Sprintf("/api/2.0/lro-testing/operations/%v/cancel", request.Name) + queryParams := make(map[string]any) + headers := make(map[string]string) + headers["Accept"] = "application/json" + err := a.client.Do(ctx, http.MethodPost, path, headers, queryParams, nil, nil) + return err +} + +func (a *lroTestingImpl) CreateTestResource(ctx context.Context, request CreateTestResourceRequest) (*common.Operation, error) { + var operation common.Operation + path := "/api/2.0/lro-testing/resources" + queryParams := make(map[string]any) + headers := make(map[string]string) + headers["Accept"] = "application/json" + headers["Content-Type"] = "application/json" + err := a.client.Do(ctx, http.MethodPost, path, headers, queryParams, request.Resource, &operation) + return &operation, err +} + +func (a *lroTestingImpl) GetOperation(ctx context.Context, request GetOperationRequest) (*common.Operation, error) { + var operation common.Operation + path := fmt.Sprintf("/api/2.0/lro-testing/operations/%v", request.Name) + queryParams := make(map[string]any) + headers := make(map[string]string) + headers["Accept"] = "application/json" + err := a.client.Do(ctx, http.MethodGet, path, headers, queryParams, request, &operation) + return &operation, err +} + +func (a *lroTestingImpl) GetTestResource(ctx context.Context, request GetTestResourceRequest) (*TestResource, error) { + var testResource TestResource + path := fmt.Sprintf("/api/2.0/lro-testing/resources/%v", request.ResourceId) + queryParams := make(map[string]any) + headers := make(map[string]string) + headers["Accept"] = "application/json" + err := a.client.Do(ctx, http.MethodGet, path, headers, queryParams, request, &testResource) + return &testResource, err +} diff --git a/internal/testspecs/service/lrotesting/model.go b/internal/testspecs/service/lrotesting/model.go new file mode 100755 index 000000000..f111e7c3c --- /dev/null +++ b/internal/testspecs/service/lrotesting/model.go @@ -0,0 +1,63 @@ +// Code generated from OpenAPI specs by Databricks SDK Generator. DO NOT EDIT. + +package lrotesting + +import ( + "github.com/databricks/databricks-sdk-go/marshal" +) + +type CancelOperationRequest struct { + // The name of the operation resource to be cancelled. + Name string `json:"-" url:"-"` +} + +type CreateTestResourceRequest struct { + // The resource to create + Resource TestResource `json:"resource"` +} + +type GetOperationRequest struct { + // The name of the operation resource. + Name string `json:"-" url:"-"` +} + +type GetTestResourceRequest struct { + // Resource ID to get + ResourceId string `json:"-" url:"-"` +} + +// Test resource for LRO operations +type TestResource struct { + // Unique identifier for the resource + Id string `json:"id,omitempty"` + // Name of the resource + Name string `json:"name,omitempty"` + + ForceSendFields []string `json:"-" url:"-"` +} + +func (s *TestResource) UnmarshalJSON(b []byte) error { + return marshal.Unmarshal(b, s) +} + +func (s TestResource) MarshalJSON() ([]byte, error) { + return marshal.Marshal(s) +} + +// Metadata for test resource operations +type TestResourceOperationMetadata struct { + // Progress percentage (0-100) + ProgressPercent int `json:"progress_percent,omitempty"` + // ID of the resource being operated on + ResourceId string `json:"resource_id,omitempty"` + + ForceSendFields []string `json:"-" url:"-"` +} + +func (s *TestResourceOperationMetadata) UnmarshalJSON(b []byte) error { + return marshal.Unmarshal(b, s) +} + +func (s TestResourceOperationMetadata) MarshalJSON() ([]byte, error) { + return marshal.Marshal(s) +} diff --git a/service/apps/impl.go b/service/apps/impl.go index 86e0183cc..69f44051f 100755 --- a/service/apps/impl.go +++ b/service/apps/impl.go @@ -22,6 +22,7 @@ func (a *appsImpl) Create(ctx context.Context, request CreateAppRequest) (*App, var app App path := "/api/2.0/apps" queryParams := make(map[string]any) + if request.NoCompute != false || slices.Contains(request.ForceSendFields, "NoCompute") { queryParams["no_compute"] = request.NoCompute } diff --git a/service/billing/impl.go b/service/billing/impl.go index b4f232bee..87443851a 100755 --- a/service/billing/impl.go +++ b/service/billing/impl.go @@ -109,6 +109,7 @@ func (a *budgetPolicyImpl) Update(ctx context.Context, request UpdateBudgetPolic var budgetPolicy BudgetPolicy path := fmt.Sprintf("/api/2.1/accounts/%v/budget-policies/%v", a.client.ConfiguredAccountID(), request.PolicyId) queryParams := make(map[string]any) + if request.LimitConfig != nil { queryParams["limit_config"] = request.LimitConfig } diff --git a/service/catalog/impl.go b/service/catalog/impl.go index 70853eef1..c62c2c01b 100755 --- a/service/catalog/impl.go +++ b/service/catalog/impl.go @@ -666,6 +666,7 @@ func (a *entityTagAssignmentsImpl) Update(ctx context.Context, request UpdateEnt var entityTagAssignment EntityTagAssignment path := fmt.Sprintf("/api/2.1/unity-catalog/entity-tag-assignments/%v/%v/tags/%v", request.EntityType, request.EntityName, request.TagKey) queryParams := make(map[string]any) + if request.UpdateMask != "" { queryParams["update_mask"] = request.UpdateMask } @@ -748,6 +749,7 @@ func (a *externalLineageImpl) UpdateExternalLineageRelationship(ctx context.Cont var externalLineageRelationship ExternalLineageRelationship path := "/api/2.0/lineage-tracking/external-lineage" queryParams := make(map[string]any) + if request.UpdateMask != "" { queryParams["update_mask"] = request.UpdateMask } @@ -941,6 +943,7 @@ func (a *externalMetadataImpl) UpdateExternalMetadata(ctx context.Context, reque var externalMetadata ExternalMetadata path := fmt.Sprintf("/api/2.0/lineage-tracking/external-metadata/%v", request.Name) queryParams := make(map[string]any) + if request.UpdateMask != "" { queryParams["update_mask"] = request.UpdateMask } @@ -1453,6 +1456,7 @@ func (a *policiesImpl) UpdatePolicy(ctx context.Context, request UpdatePolicyReq var policyInfo PolicyInfo path := fmt.Sprintf("/api/2.1/unity-catalog/policies/%v/%v/%v", request.OnSecurableType, request.OnSecurableFullname, request.Name) queryParams := make(map[string]any) + if request.UpdateMask != "" || slices.Contains(request.ForceSendFields, "UpdateMask") { queryParams["update_mask"] = request.UpdateMask } @@ -1777,6 +1781,7 @@ func (a *rfaImpl) UpdateAccessRequestDestinations(ctx context.Context, request U var accessRequestDestinations AccessRequestDestinations path := "/api/3.0/rfa/destinations" queryParams := make(map[string]any) + if request.UpdateMask != "" { queryParams["update_mask"] = request.UpdateMask } diff --git a/service/database/impl.go b/service/database/impl.go index 9ea0e56f6..612a2b34e 100755 --- a/service/database/impl.go +++ b/service/database/impl.go @@ -364,6 +364,7 @@ func (a *databaseImpl) UpdateDatabaseCatalog(ctx context.Context, request Update var databaseCatalog DatabaseCatalog path := fmt.Sprintf("/api/2.0/database/catalogs/%v", request.Name) queryParams := make(map[string]any) + if request.UpdateMask != "" { queryParams["update_mask"] = request.UpdateMask } @@ -378,6 +379,7 @@ func (a *databaseImpl) UpdateDatabaseInstance(ctx context.Context, request Updat var databaseInstance DatabaseInstance path := fmt.Sprintf("/api/2.0/database/instances/%v", request.Name) queryParams := make(map[string]any) + if request.UpdateMask != "" { queryParams["update_mask"] = request.UpdateMask } @@ -392,6 +394,7 @@ func (a *databaseImpl) UpdateSyncedDatabaseTable(ctx context.Context, request Up var syncedDatabaseTable SyncedDatabaseTable path := fmt.Sprintf("/api/2.0/database/synced_tables/%v", request.Name) queryParams := make(map[string]any) + if request.UpdateMask != "" { queryParams["update_mask"] = request.UpdateMask } diff --git a/service/files/impl.go b/service/files/impl.go index 5bf3c6a5b..bea30838e 100755 --- a/service/files/impl.go +++ b/service/files/impl.go @@ -267,6 +267,7 @@ func (a *filesImpl) internalListDirectoryContents(ctx context.Context, request L func (a *filesImpl) Upload(ctx context.Context, request UploadRequest) error { path := fmt.Sprintf("/api/2.0/fs/files%v", httpclient.EncodeMultiSegmentPathParameter(request.FilePath)) queryParams := make(map[string]any) + if request.Overwrite != false || slices.Contains(request.ForceSendFields, "Overwrite") { queryParams["overwrite"] = request.Overwrite } diff --git a/service/iam/model.go b/service/iam/model.go index 7c51c2a33..d05851ce9 100755 --- a/service/iam/model.go +++ b/service/iam/model.go @@ -233,11 +233,17 @@ type GetGroupRequest struct { Id string `json:"-" url:"-"` } +type GetPasswordPermissionLevelsRequest struct { +} + type GetPasswordPermissionLevelsResponse struct { // Specific permission levels PermissionLevels []PasswordPermissionsDescription `json:"permission_levels,omitempty"` } +type GetPasswordPermissionsRequest struct { +} + type GetPermissionLevelsRequest struct { RequestObjectId string `json:"-" url:"-"` // The type of the request object. Can be one of the following: alerts, diff --git a/service/ml/impl.go b/service/ml/impl.go index eb1061b84..78690920b 100755 --- a/service/ml/impl.go +++ b/service/ml/impl.go @@ -667,6 +667,7 @@ func (a *featureEngineeringImpl) UpdateFeature(ctx context.Context, request Upda var feature Feature path := fmt.Sprintf("/api/2.0/feature-engineering/features/%v", request.FullName) queryParams := make(map[string]any) + if request.UpdateMask != "" { queryParams["update_mask"] = request.UpdateMask } @@ -768,6 +769,7 @@ func (a *featureStoreImpl) UpdateOnlineStore(ctx context.Context, request Update var onlineStore OnlineStore path := fmt.Sprintf("/api/2.0/feature-store/online-stores/%v", request.Name) queryParams := make(map[string]any) + if request.UpdateMask != "" { queryParams["update_mask"] = request.UpdateMask } @@ -894,6 +896,7 @@ func (a *materializedFeaturesImpl) UpdateFeatureTag(ctx context.Context, request var featureTag FeatureTag path := fmt.Sprintf("/api/2.0/feature-store/feature-tables/%v/features/%v/tags/%v", request.TableName, request.FeatureName, request.Key) queryParams := make(map[string]any) + if request.UpdateMask != "" || slices.Contains(request.ForceSendFields, "UpdateMask") { queryParams["update_mask"] = request.UpdateMask } diff --git a/service/oauth2/impl.go b/service/oauth2/impl.go index 0adf12013..7d3ebe096 100755 --- a/service/oauth2/impl.go +++ b/service/oauth2/impl.go @@ -22,6 +22,7 @@ func (a *accountFederationPolicyImpl) Create(ctx context.Context, request Create var federationPolicy FederationPolicy path := fmt.Sprintf("/api/2.0/accounts/%v/federationPolicies", a.client.ConfiguredAccountID()) queryParams := make(map[string]any) + if request.PolicyId != "" || slices.Contains(request.ForceSendFields, "PolicyId") { queryParams["policy_id"] = request.PolicyId } @@ -96,6 +97,7 @@ func (a *accountFederationPolicyImpl) Update(ctx context.Context, request Update var federationPolicy FederationPolicy path := fmt.Sprintf("/api/2.0/accounts/%v/federationPolicies/%v", a.client.ConfiguredAccountID(), request.PolicyId) queryParams := make(map[string]any) + if request.UpdateMask != "" || slices.Contains(request.ForceSendFields, "UpdateMask") { queryParams["update_mask"] = request.UpdateMask } @@ -337,6 +339,7 @@ func (a *servicePrincipalFederationPolicyImpl) Create(ctx context.Context, reque var federationPolicy FederationPolicy path := fmt.Sprintf("/api/2.0/accounts/%v/servicePrincipals/%v/federationPolicies", a.client.ConfiguredAccountID(), request.ServicePrincipalId) queryParams := make(map[string]any) + if request.PolicyId != "" || slices.Contains(request.ForceSendFields, "PolicyId") { queryParams["policy_id"] = request.PolicyId } @@ -411,6 +414,7 @@ func (a *servicePrincipalFederationPolicyImpl) Update(ctx context.Context, reque var federationPolicy FederationPolicy path := fmt.Sprintf("/api/2.0/accounts/%v/servicePrincipals/%v/federationPolicies/%v", a.client.ConfiguredAccountID(), request.ServicePrincipalId, request.PolicyId) queryParams := make(map[string]any) + if request.UpdateMask != "" || slices.Contains(request.ForceSendFields, "UpdateMask") { queryParams["update_mask"] = request.UpdateMask } diff --git a/service/pkg.go b/service/pkg.go index 6376bcff0..260b910fe 100644 --- a/service/pkg.go +++ b/service/pkg.go @@ -417,8 +417,8 @@ var ( _ *marketplace.ConsumerListingsAPI = nil _ *marketplace.ConsumerPersonalizationRequestsAPI = nil _ *marketplace.ConsumerProvidersAPI = nil - _ *provisioning.CredentialsAPI = nil _ *catalog.CredentialsAPI = nil + _ *provisioning.CredentialsAPI = nil _ *settings.CredentialsManagerAPI = nil _ *settings.CspEnablementAccountAPI = nil _ *iam.CurrentUserAPI = nil diff --git a/service/settings/impl.go b/service/settings/impl.go index 47cc8fc7e..54b635a74 100755 --- a/service/settings/impl.go +++ b/service/settings/impl.go @@ -981,6 +981,7 @@ func (a *networkConnectivityImpl) UpdatePrivateEndpointRule(ctx context.Context, var nccPrivateEndpointRule NccPrivateEndpointRule path := fmt.Sprintf("/api/2.0/accounts/%v/network-connectivity-configs/%v/private-endpoint-rules/%v", a.client.ConfiguredAccountID(), request.NetworkConnectivityConfigId, request.PrivateEndpointRuleId) queryParams := make(map[string]any) + if request.UpdateMask != "" { queryParams["update_mask"] = request.UpdateMask } diff --git a/service/sharing/impl.go b/service/sharing/impl.go index 203666228..9e50d2596 100755 --- a/service/sharing/impl.go +++ b/service/sharing/impl.go @@ -272,6 +272,7 @@ func (a *recipientFederationPoliciesImpl) Update(ctx context.Context, request Up var federationPolicy FederationPolicy path := fmt.Sprintf("/api/2.0/data-sharing/recipients/%v/federation-policies/%v", request.RecipientName, request.Name) queryParams := make(map[string]any) + if request.UpdateMask != "" || slices.Contains(request.ForceSendFields, "UpdateMask") { queryParams["update_mask"] = request.UpdateMask } diff --git a/service/sql/impl.go b/service/sql/impl.go index 4bba7f326..739ff5590 100755 --- a/service/sql/impl.go +++ b/service/sql/impl.go @@ -238,6 +238,7 @@ func (a *alertsV2Impl) UpdateAlert(ctx context.Context, request UpdateAlertV2Req var alertV2 AlertV2 path := fmt.Sprintf("/api/2.0/alerts/%v", request.Id) queryParams := make(map[string]any) + if request.UpdateMask != "" { queryParams["update_mask"] = request.UpdateMask } diff --git a/service/tags/impl.go b/service/tags/impl.go index 5601e4973..bd69be12a 100755 --- a/service/tags/impl.go +++ b/service/tags/impl.go @@ -92,6 +92,7 @@ func (a *tagPoliciesImpl) UpdateTagPolicy(ctx context.Context, request UpdateTag var tagPolicy TagPolicy path := fmt.Sprintf("/api/2.1/tag-policies/%v", request.TagKey) queryParams := make(map[string]any) + if request.UpdateMask != "" { queryParams["update_mask"] = request.UpdateMask } diff --git a/workspace_client.go b/workspace_client.go index f36e01a8f..207a86dc0 100755 --- a/workspace_client.go +++ b/workspace_client.go @@ -1297,6 +1297,44 @@ type WorkspaceClient struct { // APIs to manage workspace level settings WorkspaceSettingsV2 settingsv2.WorkspaceSettingsV2Interface + + // Groups simplify identity management, making it easier to assign access to + // Databricks workspace, data, and other securable objects. + // + // It is best practice to assign access to workspaces and access-control + // policies in Unity Catalog to groups, instead of to users individually. + // All Databricks workspace identities can be assigned as members of groups, + // and members inherit permissions that are assigned to their group. + // + // Deprecated: Use the GroupsV2 API instead. + Groups iam.GroupsInterface + + // Identities for use with jobs, automated tools, and systems such as + // scripts, apps, and CI/CD platforms. Databricks recommends creating + // service principals to run production jobs or modify production data. If + // all processes that act on production data run with service principals, + // interactive users do not need any write, delete, or modify privileges in + // production. This eliminates the risk of a user overwriting production + // data by accident. + // + // Deprecated: Use the ServicePrincipalsV2 API instead. + ServicePrincipals iam.ServicePrincipalsInterface + + // User identities recognized by Databricks and represented by email + // addresses. + // + // Databricks recommends using SCIM provisioning to sync users and groups + // automatically from your identity provider to your Databricks workspace. + // SCIM streamlines onboarding a new employee or team by using your identity + // provider to create users and groups in Databricks workspace and give them + // the proper level of access. When a user leaves your organization or no + // longer needs access to Databricks workspace, admins can terminate the + // user in your identity provider and that user’s account will also be + // removed from Databricks workspace. This ensures a consistent offboarding + // process and prevents unauthorized users from accessing sensitive data. + // + // Deprecated: Use the UsersV2 API instead. + Users iam.UsersInterface } var ErrNotWorkspaceClient = errors.New("invalid Databricks Workspace configuration") @@ -1452,5 +1490,8 @@ func NewWorkspaceClient(c ...*Config) (*WorkspaceClient, error) { WorkspaceConf: settings.NewWorkspaceConf(databricksClient), WorkspaceIamV2: iamv2.NewWorkspaceIamV2(databricksClient), WorkspaceSettingsV2: settingsv2.NewWorkspaceSettingsV2(databricksClient), + Groups: iam.NewGroups(databricksClient), + ServicePrincipals: iam.NewServicePrincipals(databricksClient), + Users: iam.NewUsers(databricksClient), }, nil }