Skip to content
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

Support locking in integration tests #776

Merged
merged 13 commits into from
Jan 24, 2024
Merged

Conversation

mgyucht
Copy link
Contributor

@mgyucht mgyucht commented Jan 23, 2024

Changes

Locking Interface

Integration tests run in parallel, both within a single action runner as well as across different runs of an action (e.g. multiple people running integration tests in parallel). Some tests modify certain resources and need exclusive access to those resources during the duration of the test. As a result, when two tests that modify a shared resource run concurrently, they fail.

This PR introduces an integration test locking framework for the Go SDK & tools built on the Go SDK. In general, for Databricks integration tests, usage will look like the example in git_credentials_test.go:

func acquireGitCredentialsLock(ctx context.Context, t *testing.T, w *databricks.WorkspaceClient) {
	me, err := w.CurrentUser.Me(ctx)
	require.NoError(t, err)
	lockable := lock.GitCredentials{
		WorkspaceHost: w.Config.Host,
		Username:      me.UserName,
	}
	_, err = lock.Acquire(ctx, lockable, lock.InTest(t))
	require.NoError(t, err)
}

func TestAccGitCredentials(t *testing.T) {
	ctx, w := workspaceTest(t)

	// skip-next-line-roll
	acquireGitCredentialsLock(ctx, t, w)
	...
}

Calling lock.Acquire() will attempt to lock a resource using a lock backend, returning a lock. When used in tests, unlocking the lock will be registered automatically as a test cleanup, so you only need to check that no error occurred while acquiring the lock. By default, the lock will be held for 60 seconds, and locks will be created in a workspace for which the serialized SDK config can be found in LOCK_CLIENT_CONFIG and the path to the lock directory in LOCK_DIRECTORY.

A lockable resource is any resource implementing the Lockable interface, which provides the lock ID to use. I've added several implementations of Lockable for cases that I know about, but any string or structure containing only string/int fields can be used as a Lockable through lock.NewLockableImpl(). If a string is provided, the lock ID is the string itself. If a struct is provided, the lock ID is the struct name followed by the names of each field & the value of each field, separated by semicolon. For example: testStruct:A=hello;B=1.

OpenAPI Code Generator

Additionally, I've added a directive // skip-next-line-roll in the integration test parser. This makes it possible to skip the next statement from the codegen parsing. This should make it easier to add other code to integration tests without needing to update the OpenAPI test compiler. Just add the comment right before the statement you want to skip from example generation, e.g.

func TestMwsAccAbc(t *testing.T) {
	...
	// skip-next-line-roll
	myCustomFunc()
	....
}

Finally, I've made a small bugfix in the comment parsing, which currently sets hint to the last comment before the current node, even if the current node is not immediately preceded by a comment.

Tests

  • make test passing
  • make fmt applied
  • relevant integration tests applied

return err
}
b.blobClient = blobClient
fmt.Printf("Created a container client object with URL %s\n", blobClient.URL())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this print the token?

// Now acquire a lease on the container.
// You can choose to pass an empty string for proposed ID so that the service automatically assigns one for you.
leaseDuration := int32(math.Min(60, duration.Seconds()))
acquireLeaseResponse, err := blobLeaseClient.AcquireLease(context.TODO(), leaseDuration, nil)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is TODO on purpose? Maybe some note on what kind of context we want here.

}

func (b *azureBackend) RenewLock(ctx context.Context, leaseId string) error {
_, err := b.leaseClient.RenewLease(ctx, nil)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we use the leaseId?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, it's part of the leaseClient in this particular implementation. Maybe add a comment.

fmt.Printf("Created a blob lease client object with lease ID %s\n", leaseId)

// Now acquire a lease on the container.
// You can choose to pass an empty string for proposed ID so that the service automatically assigns one for you.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add the comment to the AcquireLock function, since the leaseID is passed there as a parameter

Copy link
Contributor

@pietern pietern left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(incomplete review)

GithubRunId string `env:"GITHUB_RUN_ID"`
GithubRunNumber string `env:"GITHUB_RUN_NUMBER"`
GithubSha string `env:"GITHUB_SHA"`
GithubWorkflow string `env:"GITHUB_WORKFLOW"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the repository encoded in one of these?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, will add!

}

func (l *LockState) Extend(duration time.Duration) {
l.Expiry = time.Now().Add(duration)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this also persist the extended expiry time?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nevermind, this is done elsewhere.

Could the lock state itself be unexported?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed offline, I'll add doccomments here.

}

opts := []workspace.UploadOption{
workspace.UploadLanguage(workspace.LanguagePython),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we omit the language setting here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, otherwise the API thinks this is a ZIP file (probably DBC archive).

"github.com/databricks/databricks-sdk-go/qa/lock/internal"
)

func TestGenerateBlobName(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test looks like it should live in internal as well (only uses GenerateBlobName).

qa/lock/lock.go Outdated
// By default, the lock will be acquired for 1 minute. This can be changed by
// passing the WithLeaseDuration() LockOption.
//
// By default, the lock will be acquired using the azureBackend. This can be
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Default is different.

qa/lock/lock.go Outdated
testTimer := time.NewTimer(opts.LeaseDuration)
defer close(errs)
for {
timer.Reset(duration)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be a time.Ticker?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most certainly.

@codecov-commenter
Copy link

Codecov Report

Attention: 67 lines in your changes are missing coverage. Please review.

Comparison is base (aad9abf) 18.27% compared to head (f5bc4a6) 18.69%.
Report is 1 commits behind head on main.

Files Patch % Lines
qa/lock/databricks/databricks_backend.go 57.14% 25 Missing and 8 partials ⚠️
qa/lock/lock.go 62.96% 17 Missing and 3 partials ⚠️
openapi/roll/tool.go 68.00% 7 Missing and 1 partial ⚠️
qa/lock/internal/lockable.go 92.59% 1 Missing and 1 partial ⚠️
qa/lock/lock_options.go 66.66% 2 Missing ⚠️
qa/lock/lockables.go 50.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #776      +/-   ##
==========================================
+ Coverage   18.27%   18.69%   +0.41%     
==========================================
  Files         110      115       +5     
  Lines       14834    15135     +301     
==========================================
+ Hits         2711     2829     +118     
- Misses      11901    12071     +170     
- Partials      222      235      +13     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@mgyucht mgyucht added this pull request to the merge queue Jan 24, 2024
Merged via the queue into main with commit a28e2bb Jan 24, 2024
4 checks passed
@mgyucht mgyucht deleted the add-integration-test-locking branch January 24, 2024 07:09
hectorcast-db added a commit that referenced this pull request Jan 24, 2024
Other changes:

* Added RequiredPositionalArguments method for codegen ([#773](#773)).
* Support locking in integration tests ([#776](#776)).
* Update OpenAPI spec and fix incompatible changes ([#778](#778)).

API Changes:

 * Added `Exists` method for [w.Tables](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#TablesAPI) workspace-level service.
 * Added [w.LakehouseMonitors](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#LakehouseMonitorsAPI) workspace-level service.
 * Added [catalog.CreateMonitor](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#CreateMonitor), [catalog.DeleteLakehouseMonitorRequest](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#DeleteLakehouseMonitorRequest), [catalog.ExistsRequest](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#ExistsRequest), [catalog.GetLakehouseMonitorRequest](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#GetLakehouseMonitorRequest), [catalog.MonitorCronSchedule](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#MonitorCronSchedule), [catalog.MonitorCronSchedulePauseStatus](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#MonitorCronSchedulePauseStatus), [catalog.MonitorCustomMetric](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#MonitorCustomMetric), [catalog.MonitorCustomMetricType](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#MonitorCustomMetricType), [catalog.MonitorDataClassificationConfig](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#MonitorDataClassificationConfig), [catalog.MonitorDestinations](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#MonitorDestinations), [catalog.MonitorInferenceLogProfileType](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#MonitorInferenceLogProfileType), [catalog.MonitorInferenceLogProfileTypeProblemType](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#MonitorInferenceLogProfileTypeProblemType), [catalog.MonitorInfo](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#MonitorInfo), [catalog.MonitorInfoStatus](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#MonitorInfoStatus), [catalog.MonitorNotificationsConfig](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#MonitorNotificationsConfig), [catalog.MonitorTimeSeriesProfileType](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#MonitorTimeSeriesProfileType), [catalog.TableExistsResponse](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#TableExistsResponse) and [catalog.UpdateMonitor](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#UpdateMonitor).
 * Added `InitScripts` field for [pipelines.PipelineCluster](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/pipelines#PipelineCluster).
 * Added `ValidateOnly` field for [pipelines.StartUpdate](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/pipelines#StartUpdate).
 * Added `ValidateOnly` field for [pipelines.UpdateInfo](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/pipelines#UpdateInfo).
 * Changed `CreateOboToken` method for [w.TokenManagement](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/settings#TokenManagementAPI) workspace-level service with new required argument order.
 * Changed `Get` method for [w.TokenManagement](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/settings#TokenManagementAPI) workspace-level service to return [settings.GetTokenResponse](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/settings#GetTokenResponse).
 * Changed `LifetimeSeconds` field for [settings.CreateOboTokenRequest](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/settings#CreateOboTokenRequest) to no longer be required.
 * Added [settings.GetTokenResponse](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/settings#GetTokenResponse).
 * Changed `Create` method for [w.Dashboards](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/sql#DashboardsAPI) workspace-level service . New request type is [sql.DashboardPostContent](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/sql#DashboardPostContent).
 * Added `Update` method for [w.Dashboards](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/sql#DashboardsAPI) workspace-level service.
 * Removed [sql.CreateDashboardRequest](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/sql#CreateDashboardRequest).
 * Added `HttpHeaders` field for [sql.ExternalLink](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/sql#ExternalLink).
 * Added `RunAsRole` field for [sql.QueryEditContent](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/sql#QueryEditContent).
 * Added [sql.DashboardEditContent](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/sql#DashboardEditContent).
 * Added [sql.DashboardPostContent](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/sql#DashboardPostContent).

OpenAPI SHA: e05401ed5dd4974c5333d737ec308a7d451f749f, Date: 2024-01-23
@hectorcast-db hectorcast-db mentioned this pull request Jan 24, 2024
github-merge-queue bot pushed a commit that referenced this pull request Jan 24, 2024
Other changes:

* Added RequiredPositionalArguments method for codegen
([#773](#773)).
* Support locking in integration tests
([#776](#776)).
* Update OpenAPI spec and fix incompatible changes
([#778](#778)).

API Changes:

* Added `Exists` method for
[w.Tables](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#TablesAPI)
workspace-level service.
* Added
[w.LakehouseMonitors](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#LakehouseMonitorsAPI)
workspace-level service.
* Added
[catalog.CreateMonitor](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#CreateMonitor),
[catalog.DeleteLakehouseMonitorRequest](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#DeleteLakehouseMonitorRequest),
[catalog.ExistsRequest](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#ExistsRequest),
[catalog.GetLakehouseMonitorRequest](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#GetLakehouseMonitorRequest),
[catalog.MonitorCronSchedule](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#MonitorCronSchedule),
[catalog.MonitorCronSchedulePauseStatus](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#MonitorCronSchedulePauseStatus),
[catalog.MonitorCustomMetric](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#MonitorCustomMetric),
[catalog.MonitorCustomMetricType](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#MonitorCustomMetricType),
[catalog.MonitorDataClassificationConfig](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#MonitorDataClassificationConfig),
[catalog.MonitorDestinations](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#MonitorDestinations),
[catalog.MonitorInferenceLogProfileType](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#MonitorInferenceLogProfileType),
[catalog.MonitorInferenceLogProfileTypeProblemType](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#MonitorInferenceLogProfileTypeProblemType),
[catalog.MonitorInfo](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#MonitorInfo),
[catalog.MonitorInfoStatus](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#MonitorInfoStatus),
[catalog.MonitorNotificationsConfig](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#MonitorNotificationsConfig),
[catalog.MonitorTimeSeriesProfileType](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#MonitorTimeSeriesProfileType),
[catalog.TableExistsResponse](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#TableExistsResponse)
and
[catalog.UpdateMonitor](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/catalog#UpdateMonitor).
* Added `InitScripts` field for
[pipelines.PipelineCluster](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/pipelines#PipelineCluster).
* Added `ValidateOnly` field for
[pipelines.StartUpdate](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/pipelines#StartUpdate).
* Added `ValidateOnly` field for
[pipelines.UpdateInfo](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/pipelines#UpdateInfo).
* Changed `CreateOboToken` method for
[w.TokenManagement](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/settings#TokenManagementAPI)
workspace-level service with new required argument order.
* Changed `Get` method for
[w.TokenManagement](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/settings#TokenManagementAPI)
workspace-level service to return
[settings.GetTokenResponse](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/settings#GetTokenResponse).
* Changed `LifetimeSeconds` field for
[settings.CreateOboTokenRequest](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/settings#CreateOboTokenRequest)
to no longer be required.
* Added
[settings.GetTokenResponse](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/settings#GetTokenResponse).
* Changed `Create` method for
[w.Dashboards](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/sql#DashboardsAPI)
workspace-level service . New request type is
[sql.DashboardPostContent](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/sql#DashboardPostContent).
* Added `Update` method for
[w.Dashboards](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/sql#DashboardsAPI)
workspace-level service.
* Removed
[sql.CreateDashboardRequest](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/sql#CreateDashboardRequest).
* Added `HttpHeaders` field for
[sql.ExternalLink](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/sql#ExternalLink).
* Added `RunAsRole` field for
[sql.QueryEditContent](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/sql#QueryEditContent).
* Added
[sql.DashboardEditContent](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/sql#DashboardEditContent).
* Added
[sql.DashboardPostContent](https://pkg.go.dev/github.com/databricks/databricks-sdk-go/service/sql#DashboardPostContent).

OpenAPI SHA: e05401ed5dd4974c5333d737ec308a7d451f749f, Date: 2024-01-23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants