Skip to content

Commit

Permalink
add sweeper unit tests and enable tests to show in teamcity ui by ena…
Browse files Browse the repository at this point in the history
…bling the golang feature (#12833)
  • Loading branch information
ScottSuarez authored Jan 23, 2025
1 parent b387b36 commit cb5af1b
Show file tree
Hide file tree
Showing 4 changed files with 363 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ package builds
import ArtifactRules
import DefaultBuildTimeoutDuration
import DefaultParallelism
import jetbrains.buildServer.configs.kotlin.buildFeatures.GolangFeature
import jetbrains.buildServer.configs.kotlin.BuildType
import jetbrains.buildServer.configs.kotlin.failureConditions.BuildFailureOnText
import jetbrains.buildServer.configs.kotlin.failureConditions.failOnText
Expand Down Expand Up @@ -81,7 +82,9 @@ class SweeperDetails(private val sweeperName: String, private val parentProjectN
}

features {
golang()
feature(GolangFeature {
testFormat = "json"
})
if (sharedResources.isNotEmpty()) {
sharedResources {
// When the build runs, it locks the value(s) below
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ fun BuildSteps.downloadTerraformBinary() {
fun BuildSteps.runSweepers(sweeperStepName: String) {
step(ScriptBuildStep{
name = sweeperStepName
scriptContent = "go test -v \"%PACKAGE_PATH%\" -sweep=\"%SWEEPER_REGIONS%\" -sweep-allow-failures -sweep-run=\"%SWEEP_RUN%\" -timeout 30m -json"
scriptContent = "go test -v \"%PACKAGE_PATH%\" -run=\"%TEST_PREFIX%\" -sweep=\"%SWEEPER_REGIONS%\" -sweep-allow-failures -sweep-run=\"%SWEEP_RUN%\" -timeout 30m -json"
})
}

Expand Down
4 changes: 2 additions & 2 deletions mmv1/third_party/terraform/sweeper/gcp_sweeper_test.go.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ import (
// TODO: remove dependency on hashicorp flags
// need to blank import hashicorp sweeper code to maintain the flags declared in their package
_ "github.com/hashicorp/terraform-plugin-testing/helper/resource"

"github.com/hashicorp/terraform-provider-google/google/sweeper"
)

func TestSweepers(t *testing.T) {
func TestAccExecuteSweepers(t *testing.T) {
sweeper.ExecuteSweepers(t)
}

356 changes: 356 additions & 0 deletions mmv1/third_party/terraform/sweeper/hashi_sweeper_fork_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,356 @@
package sweeper

import (
"reflect"
"strings"
"testing"
)

func TestValidateAndOrderSweepers_Simple(t *testing.T) {
sweepers := map[string]*Sweeper{
"B": {
Name: "B",
Dependencies: []string{"A"},
},
"C": {
Name: "C",
Dependencies: []string{"B"},
},
"A": {
Name: "A",
Dependencies: []string{},
},
}

sorted, err := validateAndOrderSweepers(sweepers)
if err != nil {
t.Fatalf("Expected no error, got: %v", err)
}

// Verify order: A should come before B, B before C
names := make([]string, len(sorted))
for i, s := range sorted {
names[i] = s.Name
}

expected := []string{"A", "B", "C"}
if !reflect.DeepEqual(names, expected) {
t.Errorf("Expected order %v, got %v", expected, names)
}
}

func TestValidateAndOrderSweepers_Cycle(t *testing.T) {
testCases := []struct {
name string
sweepers map[string]*Sweeper
wantErr bool
errMsg string
}{
{
name: "direct_cycle",
sweepers: map[string]*Sweeper{
"A": {
Name: "A",
Dependencies: []string{"B"},
},
"B": {
Name: "B",
Dependencies: []string{"A"},
},
},
wantErr: true,
errMsg: "dependency cycle detected",
},
{
name: "indirect_cycle",
sweepers: map[string]*Sweeper{
"A": {
Name: "A",
Dependencies: []string{"B"},
},
"B": {
Name: "B",
Dependencies: []string{"C"},
},
"C": {
Name: "C",
Dependencies: []string{"A"},
},
},
wantErr: true,
errMsg: "dependency cycle detected",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
_, err := validateAndOrderSweepers(tc.sweepers)
if tc.wantErr {
if err == nil {
t.Error("Expected error, got nil")
} else if !strings.Contains(err.Error(), tc.errMsg) {
t.Errorf("Expected error containing %q, got %v", tc.errMsg, err)
}
} else if err != nil {
t.Errorf("Expected no error, got %v", err)
}
})
}
}

func TestValidateAndOrderSweepers_MissingDependency(t *testing.T) {
sweepers := map[string]*Sweeper{
"A": {
Name: "A",
Dependencies: []string{"NonExistent"},
},
}

_, err := validateAndOrderSweepers(sweepers)
if err == nil {
t.Fatal("Expected error for missing dependency, got nil")
}
expected := "sweeper A depends on NonExistent, but NonExistent not found"
if err.Error() != expected {
t.Errorf("Expected error message %q, got %q", expected, err.Error())
}
}

func TestValidateAndOrderSweepers_Complex(t *testing.T) {
sweepers := map[string]*Sweeper{
"A": {
Name: "A",
Dependencies: []string{},
},
"B": {
Name: "B",
Dependencies: []string{"A"},
},
"C": {
Name: "C",
Dependencies: []string{"A"},
},
"D": {
Name: "D",
Dependencies: []string{"B", "C"},
},
"E": {
Name: "E",
Dependencies: []string{"C"},
},
}

sorted, err := validateAndOrderSweepers(sweepers)
if err != nil {
t.Fatalf("Expected no error, got: %v", err)
}

// Create a map to check relative positions
positions := make(map[string]int)
for i, s := range sorted {
positions[s.Name] = i
}

// Verify dependencies come before dependents
checks := []struct {
dependency string
dependent string
}{
{"A", "B"},
{"A", "C"},
{"B", "D"},
{"C", "D"},
{"C", "E"},
}

for _, check := range checks {
if positions[check.dependency] >= positions[check.dependent] {
t.Errorf("Expected %s to come before %s, but got positions %d and %d",
check.dependency, check.dependent,
positions[check.dependency], positions[check.dependent])
}
}
}

func TestValidateAndOrderSweepers_Empty(t *testing.T) {
sweepers := map[string]*Sweeper{}

sorted, err := validateAndOrderSweepers(sweepers)
if err != nil {
t.Fatalf("Expected no error for empty sweepers, got: %v", err)
}
if len(sorted) != 0 {
t.Errorf("Expected empty result for empty input, got %d items", len(sorted))
}
}

func TestValidateAndOrderSweepers_SelfDependency(t *testing.T) {
sweepers := map[string]*Sweeper{
"A": {
Name: "A",
Dependencies: []string{"A"},
},
}

_, err := validateAndOrderSweepers(sweepers)
if err == nil {
t.Fatal("Expected error for self-dependency, got nil")
}
if !strings.Contains(err.Error(), "dependency cycle detected") {
t.Errorf("Expected cycle detection error, got: %v", err)
}
}

func TestFilterSweepers(t *testing.T) {
testCases := []struct {
name string
filter string
sourceSweepers map[string]*Sweeper
expected map[string]*Sweeper
}{
{
name: "empty_filter",
filter: "",
sourceSweepers: map[string]*Sweeper{
"test": {Name: "test"},
"prod": {Name: "prod"},
},
expected: map[string]*Sweeper{
"test": {Name: "test"},
"prod": {Name: "prod"},
},
},
{
name: "single_match",
filter: "test",
sourceSweepers: map[string]*Sweeper{
"test": {Name: "test"},
"testing": {Name: "testing"},
"prod": {Name: "prod"},
},
expected: map[string]*Sweeper{
"test": {Name: "test"},
"testing": {Name: "testing"},
},
},
{
name: "multiple_filters",
filter: "test,prod",
sourceSweepers: map[string]*Sweeper{
"test": {Name: "test"},
"testing": {Name: "testing"},
"prod": {Name: "prod"},
"stage": {Name: "stage"},
},
expected: map[string]*Sweeper{
"test": {Name: "test"},
"testing": {Name: "testing"},
"prod": {Name: "prod"},
},
},
{
name: "case_insensitive",
filter: "TEST",
sourceSweepers: map[string]*Sweeper{
"test": {Name: "test"},
"testing": {Name: "testing"},
},
expected: map[string]*Sweeper{
"test": {Name: "test"},
"testing": {Name: "testing"},
},
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
result := filterSweepers(tc.filter, tc.sourceSweepers)
if !reflect.DeepEqual(result, tc.expected) {
t.Errorf("Expected %v, got %v", tc.expected, result)
}
})
}
}

func TestFilterSweeperWithDependencies(t *testing.T) {
testCases := []struct {
name string
sweeper string
sourceSweepers map[string]*Sweeper
expected map[string]*Sweeper
}{
{
name: "no_dependencies",
sweeper: "test",
sourceSweepers: map[string]*Sweeper{
"test": {
Name: "test",
Dependencies: []string{},
},
},
expected: map[string]*Sweeper{
"test": {
Name: "test",
Dependencies: []string{},
},
},
},
{
name: "with_dependencies",
sweeper: "test",
sourceSweepers: map[string]*Sweeper{
"test": {
Name: "test",
Dependencies: []string{"dep1", "dep2"},
},
"dep1": {
Name: "dep1",
Dependencies: []string{},
},
"dep2": {
Name: "dep2",
Dependencies: []string{},
},
},
expected: map[string]*Sweeper{
"test": {
Name: "test",
Dependencies: []string{"dep1", "dep2"},
},
"dep1": {
Name: "dep1",
Dependencies: []string{},
},
"dep2": {
Name: "dep2",
Dependencies: []string{},
},
},
},
{
name: "missing_dependency",
sweeper: "test",
sourceSweepers: map[string]*Sweeper{
"test": {
Name: "test",
Dependencies: []string{"missing"},
},
},
expected: map[string]*Sweeper{
"test": {
Name: "test",
Dependencies: []string{"missing"},
},
},
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
result := filterSweeperWithDependencies(tc.sweeper, tc.sourceSweepers)
if !reflect.DeepEqual(result, tc.expected) {
t.Errorf("Expected %v, got %v", tc.expected, result)
}
})
}
}

0 comments on commit cb5af1b

Please sign in to comment.