diff --git a/internal/backend/remote/backend_apply_test.go b/internal/backend/remote/backend_apply_test.go index 9b4286010..1f0d319bf 100644 --- a/internal/backend/remote/backend_apply_test.go +++ b/internal/backend/remote/backend_apply_test.go @@ -777,9 +777,7 @@ func TestRemote_applyApprovedExternally(t *testing.T) { wl, err := b.client.Workspaces.List( ctx, b.organization, - tfe.WorkspaceListOptions{ - ListOptions: tfe.ListOptions{PageNumber: 2, PageSize: 10}, - }, + tfe.WorkspaceListOptions{}, ) if err != nil { t.Fatalf("unexpected error listing workspaces: %v", err) @@ -853,9 +851,7 @@ func TestRemote_applyDiscardedExternally(t *testing.T) { wl, err := b.client.Workspaces.List( ctx, b.organization, - tfe.WorkspaceListOptions{ - ListOptions: tfe.ListOptions{PageNumber: 2, PageSize: 10}, - }, + tfe.WorkspaceListOptions{}, ) if err != nil { t.Fatalf("unexpected error listing workspaces: %v", err) diff --git a/internal/cloud/backend_apply_test.go b/internal/cloud/backend_apply_test.go index 090f767cc..99d74c1cc 100644 --- a/internal/cloud/backend_apply_test.go +++ b/internal/cloud/backend_apply_test.go @@ -767,9 +767,7 @@ func TestCloud_applyApprovedExternally(t *testing.T) { wl, err := b.client.Workspaces.List( ctx, b.organization, - tfe.WorkspaceListOptions{ - ListOptions: tfe.ListOptions{PageNumber: 2, PageSize: 10}, - }, + tfe.WorkspaceListOptions{}, ) if err != nil { t.Fatalf("unexpected error listing workspaces: %v", err) @@ -843,9 +841,7 @@ func TestCloud_applyDiscardedExternally(t *testing.T) { wl, err := b.client.Workspaces.List( ctx, b.organization, - tfe.WorkspaceListOptions{ - ListOptions: tfe.ListOptions{PageNumber: 2, PageSize: 10}, - }, + tfe.WorkspaceListOptions{}, ) if err != nil { t.Fatalf("unexpected error listing workspaces: %v", err) diff --git a/internal/cloud/backend_test.go b/internal/cloud/backend_test.go index 5580cc925..928182b53 100644 --- a/internal/cloud/backend_test.go +++ b/internal/cloud/backend_test.go @@ -40,6 +40,30 @@ func TestCloud_backendWithPrefix(t *testing.T) { backend.TestBackendStates(t, b) } +func TestCloud_backendWithTags(t *testing.T) { + b, bCleanup := testBackendWithTags(t) + defer bCleanup() + + backend.TestBackendStates(t, b) + + // Test pagination works + for i := 0; i < 25; i++ { + _, err := b.StateMgr(fmt.Sprintf("foo-%d", i+1)) + if err != nil { + t.Fatalf("error: %s", err) + } + } + + workspaces, err := b.Workspaces() + if err != nil { + t.Fatalf("error: %s", err) + } + actual := len(workspaces) + if actual != 26 { + t.Errorf("expected 26 workspaces (over one standard paginated response), got %d", actual) + } +} + func TestCloud_PrepareConfig(t *testing.T) { cases := map[string]struct { config cty.Value diff --git a/internal/cloud/testing.go b/internal/cloud/testing.go index c5bee1c02..d289a42c2 100644 --- a/internal/cloud/testing.go +++ b/internal/cloud/testing.go @@ -92,6 +92,24 @@ func testBackendWithPrefix(t *testing.T) (*Cloud, func()) { return testBackend(t, obj) } +func testBackendWithTags(t *testing.T) (*Cloud, func()) { + obj := cty.ObjectVal(map[string]cty.Value{ + "hostname": cty.NullVal(cty.String), + "organization": cty.StringVal("hashicorp"), + "token": cty.NullVal(cty.String), + "workspaces": cty.ObjectVal(map[string]cty.Value{ + "name": cty.NullVal(cty.String), + "prefix": cty.NullVal(cty.String), + "tags": cty.SetVal( + []cty.Value{ + cty.StringVal("billing"), + }, + ), + }), + }) + return testBackend(t, obj) +} + func testBackendNoOperations(t *testing.T) (*Cloud, func()) { obj := cty.ObjectVal(map[string]cty.Value{ "hostname": cty.NullVal(cty.String), diff --git a/internal/cloud/tfe_client_mock.go b/internal/cloud/tfe_client_mock.go index 2dea3096d..fd93c48d9 100644 --- a/internal/cloud/tfe_client_mock.go +++ b/internal/cloud/tfe_client_mock.go @@ -1091,20 +1091,36 @@ func newMockWorkspaces(client *MockClient) *MockWorkspaces { } func (m *MockWorkspaces) List(ctx context.Context, organization string, options tfe.WorkspaceListOptions) (*tfe.WorkspaceList, error) { - dummyWorkspaces := 10 wl := &tfe.WorkspaceList{} - // Get the prefix from the search options. - prefix := "" + // Get all the workspaces that match the Search value + searchValue := "" if options.Search != nil { - prefix = *options.Search + searchValue = *options.Search } - // Get all the workspaces that match the prefix. var ws []*tfe.Workspace + var tags []string + + if options.Tags != nil { + tags = strings.Split(*options.Tags, ",") + } for _, w := range m.workspaceIDs { - if strings.Contains(w.Name, prefix) { - ws = append(ws, w) + wTags := make(map[string]struct{}) + for _, wTag := range w.Tags { + wTags[wTag.Name] = struct{}{} + } + + if strings.Contains(w.Name, searchValue) { + tagsSatisfied := true + for _, tag := range tags { + if _, ok := wTags[tag]; !ok { + tagsSatisfied = false + } + } + if tagsSatisfied { + ws = append(ws, w) + } } } @@ -1116,32 +1132,27 @@ func (m *MockWorkspaces) List(ctx context.Context, organization string, options return wl, nil } - // Return dummy workspaces for the first page to test pagination. - if options.PageNumber <= 1 { - for i := 0; i < dummyWorkspaces; i++ { - wl.Items = append(wl.Items, &tfe.Workspace{ - ID: GenerateID("ws-"), - Name: fmt.Sprintf("dummy-workspace-%d", i), - }) - } + numPages := (len(ws) / 20) + 1 + currentPage := 1 + if options.PageNumber != 0 { + currentPage = options.PageNumber + } + previousPage := currentPage - 1 + nextPage := currentPage + 1 - wl.Pagination = &tfe.Pagination{ - CurrentPage: 1, - NextPage: 2, - TotalPages: 2, - TotalCount: len(wl.Items) + len(ws), + for i := ((currentPage - 1) * 20); i < ((currentPage-1)*20)+20; i++ { + if i > (len(ws) - 1) { + break } - - return wl, nil + wl.Items = append(wl.Items, ws[i]) } - // Return the actual workspaces that matched as the second page. - wl.Items = ws wl.Pagination = &tfe.Pagination{ - CurrentPage: 2, - PreviousPage: 1, - TotalPages: 2, - TotalCount: len(wl.Items) + dummyWorkspaces, + CurrentPage: currentPage, + NextPage: nextPage, + PreviousPage: previousPage, + TotalPages: numPages, + TotalCount: len(wl.Items), } return wl, nil @@ -1173,6 +1184,12 @@ func (m *MockWorkspaces) Create(ctx context.Context, organization string, option } else { w.TerraformVersion = tfversion.String() } + var tags []*tfe.Tag + for _, tag := range options.Tags { + tags = append(tags, tag) + w.TagNames = append(w.TagNames, tag.Name) + } + w.Tags = tags m.workspaceIDs[w.ID] = w m.workspaceNames[w.Name] = w return w, nil