Skip to content

Commit 5c8f612

Browse files
ScottSuarezanoopkverma-google
authored andcommitted
add sweeper unit tests and enable tests to show in teamcity ui by enabling the golang feature (GoogleCloudPlatform#12833)
1 parent 9fa7cad commit 5c8f612

File tree

4 files changed

+363
-4
lines changed

4 files changed

+363
-4
lines changed

mmv1/third_party/terraform/.teamcity/components/builds/build_configuration_sweepers.kt

+4-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ package builds
1010
import ArtifactRules
1111
import DefaultBuildTimeoutDuration
1212
import DefaultParallelism
13+
import jetbrains.buildServer.configs.kotlin.buildFeatures.GolangFeature
1314
import jetbrains.buildServer.configs.kotlin.BuildType
1415
import jetbrains.buildServer.configs.kotlin.failureConditions.BuildFailureOnText
1516
import jetbrains.buildServer.configs.kotlin.failureConditions.failOnText
@@ -81,7 +82,9 @@ class SweeperDetails(private val sweeperName: String, private val parentProjectN
8182
}
8283

8384
features {
84-
golang()
85+
feature(GolangFeature {
86+
testFormat = "json"
87+
})
8588
if (sharedResources.isNotEmpty()) {
8689
sharedResources {
8790
// When the build runs, it locks the value(s) below

mmv1/third_party/terraform/.teamcity/components/builds/build_steps.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ fun BuildSteps.downloadTerraformBinary() {
7979
fun BuildSteps.runSweepers(sweeperStepName: String) {
8080
step(ScriptBuildStep{
8181
name = sweeperStepName
82-
scriptContent = "go test -v \"%PACKAGE_PATH%\" -sweep=\"%SWEEPER_REGIONS%\" -sweep-allow-failures -sweep-run=\"%SWEEP_RUN%\" -timeout 30m -json"
82+
scriptContent = "go test -v \"%PACKAGE_PATH%\" -run=\"%TEST_PREFIX%\" -sweep=\"%SWEEPER_REGIONS%\" -sweep-allow-failures -sweep-run=\"%SWEEP_RUN%\" -timeout 30m -json"
8383
})
8484
}
8585

mmv1/third_party/terraform/sweeper/gcp_sweeper_test.go.tmpl

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ import (
2525
// TODO: remove dependency on hashicorp flags
2626
// need to blank import hashicorp sweeper code to maintain the flags declared in their package
2727
_ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
28-
28+
2929
"github.com/hashicorp/terraform-provider-google/google/sweeper"
3030
)
3131

32-
func TestSweepers(t *testing.T) {
32+
func TestAccExecuteSweepers(t *testing.T) {
3333
sweeper.ExecuteSweepers(t)
3434
}
3535

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,356 @@
1+
package sweeper
2+
3+
import (
4+
"reflect"
5+
"strings"
6+
"testing"
7+
)
8+
9+
func TestValidateAndOrderSweepers_Simple(t *testing.T) {
10+
sweepers := map[string]*Sweeper{
11+
"B": {
12+
Name: "B",
13+
Dependencies: []string{"A"},
14+
},
15+
"C": {
16+
Name: "C",
17+
Dependencies: []string{"B"},
18+
},
19+
"A": {
20+
Name: "A",
21+
Dependencies: []string{},
22+
},
23+
}
24+
25+
sorted, err := validateAndOrderSweepers(sweepers)
26+
if err != nil {
27+
t.Fatalf("Expected no error, got: %v", err)
28+
}
29+
30+
// Verify order: A should come before B, B before C
31+
names := make([]string, len(sorted))
32+
for i, s := range sorted {
33+
names[i] = s.Name
34+
}
35+
36+
expected := []string{"A", "B", "C"}
37+
if !reflect.DeepEqual(names, expected) {
38+
t.Errorf("Expected order %v, got %v", expected, names)
39+
}
40+
}
41+
42+
func TestValidateAndOrderSweepers_Cycle(t *testing.T) {
43+
testCases := []struct {
44+
name string
45+
sweepers map[string]*Sweeper
46+
wantErr bool
47+
errMsg string
48+
}{
49+
{
50+
name: "direct_cycle",
51+
sweepers: map[string]*Sweeper{
52+
"A": {
53+
Name: "A",
54+
Dependencies: []string{"B"},
55+
},
56+
"B": {
57+
Name: "B",
58+
Dependencies: []string{"A"},
59+
},
60+
},
61+
wantErr: true,
62+
errMsg: "dependency cycle detected",
63+
},
64+
{
65+
name: "indirect_cycle",
66+
sweepers: map[string]*Sweeper{
67+
"A": {
68+
Name: "A",
69+
Dependencies: []string{"B"},
70+
},
71+
"B": {
72+
Name: "B",
73+
Dependencies: []string{"C"},
74+
},
75+
"C": {
76+
Name: "C",
77+
Dependencies: []string{"A"},
78+
},
79+
},
80+
wantErr: true,
81+
errMsg: "dependency cycle detected",
82+
},
83+
}
84+
85+
for _, tc := range testCases {
86+
t.Run(tc.name, func(t *testing.T) {
87+
_, err := validateAndOrderSweepers(tc.sweepers)
88+
if tc.wantErr {
89+
if err == nil {
90+
t.Error("Expected error, got nil")
91+
} else if !strings.Contains(err.Error(), tc.errMsg) {
92+
t.Errorf("Expected error containing %q, got %v", tc.errMsg, err)
93+
}
94+
} else if err != nil {
95+
t.Errorf("Expected no error, got %v", err)
96+
}
97+
})
98+
}
99+
}
100+
101+
func TestValidateAndOrderSweepers_MissingDependency(t *testing.T) {
102+
sweepers := map[string]*Sweeper{
103+
"A": {
104+
Name: "A",
105+
Dependencies: []string{"NonExistent"},
106+
},
107+
}
108+
109+
_, err := validateAndOrderSweepers(sweepers)
110+
if err == nil {
111+
t.Fatal("Expected error for missing dependency, got nil")
112+
}
113+
expected := "sweeper A depends on NonExistent, but NonExistent not found"
114+
if err.Error() != expected {
115+
t.Errorf("Expected error message %q, got %q", expected, err.Error())
116+
}
117+
}
118+
119+
func TestValidateAndOrderSweepers_Complex(t *testing.T) {
120+
sweepers := map[string]*Sweeper{
121+
"A": {
122+
Name: "A",
123+
Dependencies: []string{},
124+
},
125+
"B": {
126+
Name: "B",
127+
Dependencies: []string{"A"},
128+
},
129+
"C": {
130+
Name: "C",
131+
Dependencies: []string{"A"},
132+
},
133+
"D": {
134+
Name: "D",
135+
Dependencies: []string{"B", "C"},
136+
},
137+
"E": {
138+
Name: "E",
139+
Dependencies: []string{"C"},
140+
},
141+
}
142+
143+
sorted, err := validateAndOrderSweepers(sweepers)
144+
if err != nil {
145+
t.Fatalf("Expected no error, got: %v", err)
146+
}
147+
148+
// Create a map to check relative positions
149+
positions := make(map[string]int)
150+
for i, s := range sorted {
151+
positions[s.Name] = i
152+
}
153+
154+
// Verify dependencies come before dependents
155+
checks := []struct {
156+
dependency string
157+
dependent string
158+
}{
159+
{"A", "B"},
160+
{"A", "C"},
161+
{"B", "D"},
162+
{"C", "D"},
163+
{"C", "E"},
164+
}
165+
166+
for _, check := range checks {
167+
if positions[check.dependency] >= positions[check.dependent] {
168+
t.Errorf("Expected %s to come before %s, but got positions %d and %d",
169+
check.dependency, check.dependent,
170+
positions[check.dependency], positions[check.dependent])
171+
}
172+
}
173+
}
174+
175+
func TestValidateAndOrderSweepers_Empty(t *testing.T) {
176+
sweepers := map[string]*Sweeper{}
177+
178+
sorted, err := validateAndOrderSweepers(sweepers)
179+
if err != nil {
180+
t.Fatalf("Expected no error for empty sweepers, got: %v", err)
181+
}
182+
if len(sorted) != 0 {
183+
t.Errorf("Expected empty result for empty input, got %d items", len(sorted))
184+
}
185+
}
186+
187+
func TestValidateAndOrderSweepers_SelfDependency(t *testing.T) {
188+
sweepers := map[string]*Sweeper{
189+
"A": {
190+
Name: "A",
191+
Dependencies: []string{"A"},
192+
},
193+
}
194+
195+
_, err := validateAndOrderSweepers(sweepers)
196+
if err == nil {
197+
t.Fatal("Expected error for self-dependency, got nil")
198+
}
199+
if !strings.Contains(err.Error(), "dependency cycle detected") {
200+
t.Errorf("Expected cycle detection error, got: %v", err)
201+
}
202+
}
203+
204+
func TestFilterSweepers(t *testing.T) {
205+
testCases := []struct {
206+
name string
207+
filter string
208+
sourceSweepers map[string]*Sweeper
209+
expected map[string]*Sweeper
210+
}{
211+
{
212+
name: "empty_filter",
213+
filter: "",
214+
sourceSweepers: map[string]*Sweeper{
215+
"test": {Name: "test"},
216+
"prod": {Name: "prod"},
217+
},
218+
expected: map[string]*Sweeper{
219+
"test": {Name: "test"},
220+
"prod": {Name: "prod"},
221+
},
222+
},
223+
{
224+
name: "single_match",
225+
filter: "test",
226+
sourceSweepers: map[string]*Sweeper{
227+
"test": {Name: "test"},
228+
"testing": {Name: "testing"},
229+
"prod": {Name: "prod"},
230+
},
231+
expected: map[string]*Sweeper{
232+
"test": {Name: "test"},
233+
"testing": {Name: "testing"},
234+
},
235+
},
236+
{
237+
name: "multiple_filters",
238+
filter: "test,prod",
239+
sourceSweepers: map[string]*Sweeper{
240+
"test": {Name: "test"},
241+
"testing": {Name: "testing"},
242+
"prod": {Name: "prod"},
243+
"stage": {Name: "stage"},
244+
},
245+
expected: map[string]*Sweeper{
246+
"test": {Name: "test"},
247+
"testing": {Name: "testing"},
248+
"prod": {Name: "prod"},
249+
},
250+
},
251+
{
252+
name: "case_insensitive",
253+
filter: "TEST",
254+
sourceSweepers: map[string]*Sweeper{
255+
"test": {Name: "test"},
256+
"testing": {Name: "testing"},
257+
},
258+
expected: map[string]*Sweeper{
259+
"test": {Name: "test"},
260+
"testing": {Name: "testing"},
261+
},
262+
},
263+
}
264+
265+
for _, tc := range testCases {
266+
t.Run(tc.name, func(t *testing.T) {
267+
result := filterSweepers(tc.filter, tc.sourceSweepers)
268+
if !reflect.DeepEqual(result, tc.expected) {
269+
t.Errorf("Expected %v, got %v", tc.expected, result)
270+
}
271+
})
272+
}
273+
}
274+
275+
func TestFilterSweeperWithDependencies(t *testing.T) {
276+
testCases := []struct {
277+
name string
278+
sweeper string
279+
sourceSweepers map[string]*Sweeper
280+
expected map[string]*Sweeper
281+
}{
282+
{
283+
name: "no_dependencies",
284+
sweeper: "test",
285+
sourceSweepers: map[string]*Sweeper{
286+
"test": {
287+
Name: "test",
288+
Dependencies: []string{},
289+
},
290+
},
291+
expected: map[string]*Sweeper{
292+
"test": {
293+
Name: "test",
294+
Dependencies: []string{},
295+
},
296+
},
297+
},
298+
{
299+
name: "with_dependencies",
300+
sweeper: "test",
301+
sourceSweepers: map[string]*Sweeper{
302+
"test": {
303+
Name: "test",
304+
Dependencies: []string{"dep1", "dep2"},
305+
},
306+
"dep1": {
307+
Name: "dep1",
308+
Dependencies: []string{},
309+
},
310+
"dep2": {
311+
Name: "dep2",
312+
Dependencies: []string{},
313+
},
314+
},
315+
expected: map[string]*Sweeper{
316+
"test": {
317+
Name: "test",
318+
Dependencies: []string{"dep1", "dep2"},
319+
},
320+
"dep1": {
321+
Name: "dep1",
322+
Dependencies: []string{},
323+
},
324+
"dep2": {
325+
Name: "dep2",
326+
Dependencies: []string{},
327+
},
328+
},
329+
},
330+
{
331+
name: "missing_dependency",
332+
sweeper: "test",
333+
sourceSweepers: map[string]*Sweeper{
334+
"test": {
335+
Name: "test",
336+
Dependencies: []string{"missing"},
337+
},
338+
},
339+
expected: map[string]*Sweeper{
340+
"test": {
341+
Name: "test",
342+
Dependencies: []string{"missing"},
343+
},
344+
},
345+
},
346+
}
347+
348+
for _, tc := range testCases {
349+
t.Run(tc.name, func(t *testing.T) {
350+
result := filterSweeperWithDependencies(tc.sweeper, tc.sourceSweepers)
351+
if !reflect.DeepEqual(result, tc.expected) {
352+
t.Errorf("Expected %v, got %v", tc.expected, result)
353+
}
354+
})
355+
}
356+
}

0 commit comments

Comments
 (0)