cloud: TestCloud_backendWithTags

Implementing this test was quite a rabbithole, as in order to satisfy
backendTestBackendStates() the workspaces returned from
backend.Workspaces() must match exactly, and the shortcut taken to test
pagination in 3cc58813f0 created an
impossible circumstance that got plastered over with the fact that
prefix filtering is done clientside, not by the API as it should be.

Tagging does not rely on clientside filtering, and expects that the
request made to the TFC API returns exactly those workspaces with the
given tags.

These changes include a better way to test pagination, wherein we
actually create over a page worth of valid workspaces in the mock client
and implement a simplified pagination behavior to match how the TFC API
actually works.
This commit is contained in:
Chris Arcand 2021-09-15 00:04:15 -05:00
parent a97a1c8f66
commit 1791b71196
5 changed files with 91 additions and 40 deletions

View File

@ -777,9 +777,7 @@ func TestRemote_applyApprovedExternally(t *testing.T) {
wl, err := b.client.Workspaces.List( wl, err := b.client.Workspaces.List(
ctx, ctx,
b.organization, b.organization,
tfe.WorkspaceListOptions{ tfe.WorkspaceListOptions{},
ListOptions: tfe.ListOptions{PageNumber: 2, PageSize: 10},
},
) )
if err != nil { if err != nil {
t.Fatalf("unexpected error listing workspaces: %v", err) t.Fatalf("unexpected error listing workspaces: %v", err)
@ -853,9 +851,7 @@ func TestRemote_applyDiscardedExternally(t *testing.T) {
wl, err := b.client.Workspaces.List( wl, err := b.client.Workspaces.List(
ctx, ctx,
b.organization, b.organization,
tfe.WorkspaceListOptions{ tfe.WorkspaceListOptions{},
ListOptions: tfe.ListOptions{PageNumber: 2, PageSize: 10},
},
) )
if err != nil { if err != nil {
t.Fatalf("unexpected error listing workspaces: %v", err) t.Fatalf("unexpected error listing workspaces: %v", err)

View File

@ -767,9 +767,7 @@ func TestCloud_applyApprovedExternally(t *testing.T) {
wl, err := b.client.Workspaces.List( wl, err := b.client.Workspaces.List(
ctx, ctx,
b.organization, b.organization,
tfe.WorkspaceListOptions{ tfe.WorkspaceListOptions{},
ListOptions: tfe.ListOptions{PageNumber: 2, PageSize: 10},
},
) )
if err != nil { if err != nil {
t.Fatalf("unexpected error listing workspaces: %v", err) t.Fatalf("unexpected error listing workspaces: %v", err)
@ -843,9 +841,7 @@ func TestCloud_applyDiscardedExternally(t *testing.T) {
wl, err := b.client.Workspaces.List( wl, err := b.client.Workspaces.List(
ctx, ctx,
b.organization, b.organization,
tfe.WorkspaceListOptions{ tfe.WorkspaceListOptions{},
ListOptions: tfe.ListOptions{PageNumber: 2, PageSize: 10},
},
) )
if err != nil { if err != nil {
t.Fatalf("unexpected error listing workspaces: %v", err) t.Fatalf("unexpected error listing workspaces: %v", err)

View File

@ -40,6 +40,30 @@ func TestCloud_backendWithPrefix(t *testing.T) {
backend.TestBackendStates(t, b) 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) { func TestCloud_PrepareConfig(t *testing.T) {
cases := map[string]struct { cases := map[string]struct {
config cty.Value config cty.Value

View File

@ -92,6 +92,24 @@ func testBackendWithPrefix(t *testing.T) (*Cloud, func()) {
return testBackend(t, obj) 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()) { func testBackendNoOperations(t *testing.T) (*Cloud, func()) {
obj := cty.ObjectVal(map[string]cty.Value{ obj := cty.ObjectVal(map[string]cty.Value{
"hostname": cty.NullVal(cty.String), "hostname": cty.NullVal(cty.String),

View File

@ -1091,20 +1091,36 @@ func newMockWorkspaces(client *MockClient) *MockWorkspaces {
} }
func (m *MockWorkspaces) List(ctx context.Context, organization string, options tfe.WorkspaceListOptions) (*tfe.WorkspaceList, error) { func (m *MockWorkspaces) List(ctx context.Context, organization string, options tfe.WorkspaceListOptions) (*tfe.WorkspaceList, error) {
dummyWorkspaces := 10
wl := &tfe.WorkspaceList{} wl := &tfe.WorkspaceList{}
// Get the prefix from the search options. // Get all the workspaces that match the Search value
prefix := "" searchValue := ""
if options.Search != nil { if options.Search != nil {
prefix = *options.Search searchValue = *options.Search
} }
// Get all the workspaces that match the prefix.
var ws []*tfe.Workspace var ws []*tfe.Workspace
var tags []string
if options.Tags != nil {
tags = strings.Split(*options.Tags, ",")
}
for _, w := range m.workspaceIDs { for _, w := range m.workspaceIDs {
if strings.Contains(w.Name, prefix) { wTags := make(map[string]struct{})
ws = append(ws, w) 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 wl, nil
} }
// Return dummy workspaces for the first page to test pagination. numPages := (len(ws) / 20) + 1
if options.PageNumber <= 1 { currentPage := 1
for i := 0; i < dummyWorkspaces; i++ { if options.PageNumber != 0 {
wl.Items = append(wl.Items, &tfe.Workspace{ currentPage = options.PageNumber
ID: GenerateID("ws-"), }
Name: fmt.Sprintf("dummy-workspace-%d", i), previousPage := currentPage - 1
}) nextPage := currentPage + 1
}
wl.Pagination = &tfe.Pagination{ for i := ((currentPage - 1) * 20); i < ((currentPage-1)*20)+20; i++ {
CurrentPage: 1, if i > (len(ws) - 1) {
NextPage: 2, break
TotalPages: 2,
TotalCount: len(wl.Items) + len(ws),
} }
wl.Items = append(wl.Items, ws[i])
return wl, nil
} }
// Return the actual workspaces that matched as the second page.
wl.Items = ws
wl.Pagination = &tfe.Pagination{ wl.Pagination = &tfe.Pagination{
CurrentPage: 2, CurrentPage: currentPage,
PreviousPage: 1, NextPage: nextPage,
TotalPages: 2, PreviousPage: previousPage,
TotalCount: len(wl.Items) + dummyWorkspaces, TotalPages: numPages,
TotalCount: len(wl.Items),
} }
return wl, nil return wl, nil
@ -1173,6 +1184,12 @@ func (m *MockWorkspaces) Create(ctx context.Context, organization string, option
} else { } else {
w.TerraformVersion = tfversion.String() 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.workspaceIDs[w.ID] = w
m.workspaceNames[w.Name] = w m.workspaceNames[w.Name] = w
return w, nil return w, nil