Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions internal/acctest/acctest.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,48 @@ func cleanupProject(t testing.TB, client projectCleaner, id string) {
})
}

// CleanupProfile registers a cleanup that deletes the profile from projectID;
// empty means the env-configured default project.
func CleanupProfile(t testing.TB, projectID, id string) {
t.Helper()

cleanupProfile(t, ClientFromEnv(), projectID, id)
}

type profileCleaner interface {
DefaultProjectID() string
DeleteProfile(context.Context, string, string) error
}

func cleanupProfile(t testing.TB, client profileCleaner, projectID, id string) {
t.Helper()

if id == "" {
return
}
if !AcceptanceEnabled() {
t.Fatalf("%s must be set to clean up Kernel acceptance test resources", EnvAcceptance)
return
}
if os.Getenv(EnvAPIKey) == "" {
t.Fatalf("%s must be set to clean up Kernel acceptance test resources", EnvAPIKey)
return
}

if projectID == "" {
projectID = client.DefaultProjectID()
}

t.Cleanup(func() {
ctx, cancel := context.WithTimeout(context.Background(), cleanupTimeout)
defer cancel()

if err := client.DeleteProfile(ctx, projectID, id); err != nil && !IsNotFound(err) {
t.Errorf("cleanup Kernel profile %s: %v", id, err)
}
})
}

func ClientFromEnv() kernelclient.Clients {
return kernelclient.New(kernelclient.Config{
APIKey: os.Getenv(EnvAPIKey),
Expand Down
118 changes: 118 additions & 0 deletions internal/acctest/profile_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package acctest

import (
"context"
"errors"
"testing"
)

type fakeProfileCleaner struct {
defaultProjectID string
delete func(context.Context, string, string) error
}

func (f fakeProfileCleaner) DefaultProjectID() string {
return f.defaultProjectID
}

func (f fakeProfileCleaner) DeleteProfile(ctx context.Context, projectID, id string) error {
return f.delete(ctx, projectID, id)
}

func TestCleanupProfile(t *testing.T) {
tests := map[string]struct {
acceptance string
apiKey string
projectID string
defaultProject string
id string
deleteErr error
wantProjectID string
wantCleanups int
wantDelete bool
wantFailure bool
}{
"empty ID is ignored": {},
"acceptance disabled": {
apiKey: "test-key",
id: "profile_123",
wantFailure: true,
},
"API key missing": {
acceptance: "1",
id: "profile_123",
wantFailure: true,
},
"default project is resolved": {
acceptance: "1",
apiKey: "test-key",
defaultProject: "project_default",
id: "profile_123",
wantProjectID: "project_default",
wantCleanups: 1,
wantDelete: true,
},
"not found is already clean": {
acceptance: "1",
apiKey: "test-key",
projectID: "project_explicit",
id: "profile_123",
deleteErr: notFoundAPIError(),
wantProjectID: "project_explicit",
wantCleanups: 1,
wantDelete: true,
},
"delete error is reported": {
acceptance: "1",
apiKey: "test-key",
projectID: "project_explicit",
id: "profile_123",
deleteErr: errors.New("connection reset"),
wantProjectID: "project_explicit",
wantCleanups: 1,
wantDelete: true,
wantFailure: true,
},
}

for name, test := range tests {
t.Run(name, func(t *testing.T) {
t.Setenv(EnvAcceptance, test.acceptance)
t.Setenv(EnvAPIKey, test.apiKey)

var gotID, gotProjectID string
deleteCalled := false
deadlineSet := false
recorder := &testRecorder{TB: t}
cleanupProfile(recorder, fakeProfileCleaner{
defaultProjectID: test.defaultProject,
delete: func(ctx context.Context, projectID, id string) error {
deleteCalled = true
_, deadlineSet = ctx.Deadline()
gotProjectID = projectID
gotID = id
return test.deleteErr
},
}, test.projectID, test.id)

if got, want := len(recorder.cleanups), test.wantCleanups; got != want {
t.Fatalf("cleanupProfile registered %d cleanups, want %d", got, want)
}
if test.wantCleanups == 1 {
recorder.cleanups[0]()
}
if recorder.failed != test.wantFailure {
t.Fatalf("cleanupProfile failure = %t, want %t", recorder.failed, test.wantFailure)
}
if deleteCalled != test.wantDelete {
t.Fatalf("cleanupProfile called delete = %t, want %t", deleteCalled, test.wantDelete)
}
if deleteCalled && !deadlineSet {
t.Fatal("cleanupProfile called delete without a context deadline")
}
if test.wantDelete && (gotID != test.id || gotProjectID != test.wantProjectID) {
t.Fatalf("cleanup profile scope/id = %q/%q, want %q/%q", gotProjectID, gotID, test.wantProjectID, test.id)
}
})
}
}
8 changes: 8 additions & 0 deletions internal/kernelclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,14 @@ func (c Clients) GetProfile(ctx context.Context, projectID, idOrName string) (*k
return c.profiles.Get(ctx, idOrName, scope(projectID)...)
}

func (c Clients) CreateProfile(ctx context.Context, projectID string, params kernel.ProfileNewParams) (*kernel.Profile, error) {
return c.profiles.New(ctx, params, scope(projectID, noMutationRetries())...)
}

func (c Clients) DeleteProfile(ctx context.Context, projectID, idOrName string) error {
return c.profiles.Delete(ctx, idOrName, scope(projectID, noMutationRetries())...)
}

func (c Clients) ListProfilePage(ctx context.Context, projectID, query string, offset int64) (ProfilePage, error) {
var raw *http.Response
params := kernel.ProfileListParams{
Expand Down
25 changes: 25 additions & 0 deletions internal/kernelclient/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,23 @@ func TestMutationsDisableSDKRetriesAndUseExpectedScope(t *testing.T) {
return clients.DeleteProject(ctx, "project_123")
},
},
"profile create": {
method: http.MethodPost,
path: "/profiles",
projectID: "project_123",
call: func(ctx context.Context, clients Clients) error {
_, err := clients.CreateProfile(ctx, "project_123", kernel.ProfileNewParams{Name: kernel.String("Profile")})
return err
},
},
"profile delete": {
method: http.MethodDelete,
path: "/profiles/profile_123",
projectID: "project_123",
call: func(ctx context.Context, clients Clients) error {
return clients.DeleteProfile(ctx, "project_123", "profile_123")
},
},
"browser pool create": {
method: http.MethodPost,
path: "/browser_pools",
Expand Down Expand Up @@ -443,6 +460,14 @@ func TestClientsDoNotExposeRuntimeBrowserPoolMethods(t *testing.T) {
}
}

func TestClientsDoNotExposeProfileArchiveMethods(t *testing.T) {
t.Parallel()

if _, ok := reflect.TypeOf(Clients{}).MethodByName("DownloadProfile"); ok {
t.Fatal("Clients exposes profile archive download")
}
}

type capturedRequest struct {
Method string
Path string
Expand Down