From 372a80bc42d0c9b4ab5a6105543bebcbac64f93c Mon Sep 17 00:00:00 2001 From: Clint Date: Tue, 6 Jun 2017 10:34:17 -0500 Subject: [PATCH] provider/aws: Add Sweeper setup, Sweepers for DB Option Group, Key Pair (#14773) * provider/aws: Add Sweeper setup, Sweepers for DB Option Group, Key Pair * provider/google: Add sweeper for any leaked databases * more recursion and added LC sweeper, to test out the Dependency path * implement a dependency example * implement sweep-run flag to filter runs * stub a test for TestMain * test for multiple -sweep-run list --- builtin/providers/aws/aws_sweeper_test.go | 37 ++++ .../resource_aws_autoscaling_group_test.go | 68 ++++++++ .../aws/resource_aws_db_option_group_test.go | 61 +++++++ .../aws/resource_aws_key_pair_test.go | 42 +++++ .../resource_aws_launch_configuration_test.go | 56 +++++++ builtin/providers/google/gcp_sweeper_test.go | 35 ++++ .../resource_sql_database_instance_test.go | 100 +++++++++++ helper/resource/testing.go | 148 ++++++++++++++++ helper/resource/testing_test.go | 158 ++++++++++++++++++ 9 files changed, 705 insertions(+) create mode 100644 builtin/providers/aws/aws_sweeper_test.go create mode 100644 builtin/providers/google/gcp_sweeper_test.go diff --git a/builtin/providers/aws/aws_sweeper_test.go b/builtin/providers/aws/aws_sweeper_test.go new file mode 100644 index 000000000..57f403c76 --- /dev/null +++ b/builtin/providers/aws/aws_sweeper_test.go @@ -0,0 +1,37 @@ +package aws + +import ( + "fmt" + "os" + "testing" + + "github.com/hashicorp/terraform/helper/resource" +) + +func TestMain(m *testing.M) { + resource.TestMain(m) +} + +// sharedClientForRegion returns a common AWSClient setup needed for the sweeper +// functions for a given region +func sharedClientForRegion(region string) (interface{}, error) { + if os.Getenv("AWS_ACCESS_KEY_ID") == "" { + return nil, fmt.Errorf("empty AWS_ACCESS_KEY_ID") + } + + if os.Getenv("AWS_SECRET_ACCESS_KEY") == "" { + return nil, fmt.Errorf("empty AWS_SECRET_ACCESS_KEY") + } + + conf := &Config{ + Region: region, + } + + // configures a default client for the region, using the above env vars + client, err := conf.Client() + if err != nil { + return nil, fmt.Errorf("error getting AWS client") + } + + return client, nil +} diff --git a/builtin/providers/aws/resource_aws_autoscaling_group_test.go b/builtin/providers/aws/resource_aws_autoscaling_group_test.go index b60694a7b..8a898f700 100644 --- a/builtin/providers/aws/resource_aws_autoscaling_group_test.go +++ b/builtin/providers/aws/resource_aws_autoscaling_group_test.go @@ -3,11 +3,13 @@ package aws import ( "errors" "fmt" + "log" "reflect" "regexp" "sort" "strings" "testing" + "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" @@ -18,6 +20,72 @@ import ( "github.com/hashicorp/terraform/terraform" ) +func init() { + resource.AddTestSweepers("aws_autoscaling_group", &resource.Sweeper{ + Name: "aws_autoscaling_group", + F: testSweepAutoscalingGroups, + }) +} + +func testSweepAutoscalingGroups(region string) error { + client, err := sharedClientForRegion(region) + if err != nil { + return fmt.Errorf("error getting client: %s", err) + } + conn := client.(*AWSClient).autoscalingconn + + resp, err := conn.DescribeAutoScalingGroups(&autoscaling.DescribeAutoScalingGroupsInput{}) + if err != nil { + return fmt.Errorf("Error retrieving launch configuration: %s", err) + } + + if len(resp.AutoScalingGroups) == 0 { + log.Print("[DEBUG] No aws autoscaling groups to sweep") + return nil + } + + for _, asg := range resp.AutoScalingGroups { + var testOptGroup bool + for _, testName := range []string{"foobar", "terraform-"} { + if strings.HasPrefix(*asg.AutoScalingGroupName, testName) { + testOptGroup = true + } + } + + if !testOptGroup { + continue + } + + deleteopts := autoscaling.DeleteAutoScalingGroupInput{ + AutoScalingGroupName: asg.AutoScalingGroupName, + ForceDelete: aws.Bool(true), + } + + err = resource.Retry(5*time.Minute, func() *resource.RetryError { + if _, err := conn.DeleteAutoScalingGroup(&deleteopts); err != nil { + if awserr, ok := err.(awserr.Error); ok { + switch awserr.Code() { + case "InvalidGroup.NotFound": + return nil + case "ResourceInUse", "ScalingActivityInProgress": + return resource.RetryableError(awserr) + } + } + + // Didn't recognize the error, so shouldn't retry. + return resource.NonRetryableError(err) + } + // Successful delete + return nil + }) + if err != nil { + return err + } + } + + return nil +} + func TestAccAWSAutoScalingGroup_basic(t *testing.T) { var group autoscaling.Group var lc autoscaling.LaunchConfiguration diff --git a/builtin/providers/aws/resource_aws_db_option_group_test.go b/builtin/providers/aws/resource_aws_db_option_group_test.go index b82cc781c..65148d84b 100644 --- a/builtin/providers/aws/resource_aws_db_option_group_test.go +++ b/builtin/providers/aws/resource_aws_db_option_group_test.go @@ -2,8 +2,11 @@ package aws import ( "fmt" + "log" "regexp" + "strings" "testing" + "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" @@ -13,6 +16,64 @@ import ( "github.com/hashicorp/terraform/terraform" ) +func init() { + resource.AddTestSweepers("aws_db_option_group", &resource.Sweeper{ + Name: "aws_db_option_group", + F: testSweepDbOptionGroups, + }) +} + +func testSweepDbOptionGroups(region string) error { + client, err := sharedClientForRegion(region) + if err != nil { + return fmt.Errorf("error getting client: %s", err) + } + + conn := client.(*AWSClient).rdsconn + + opts := rds.DescribeOptionGroupsInput{} + resp, err := conn.DescribeOptionGroups(&opts) + if err != nil { + return fmt.Errorf("error describing DB Option Groups in Sweeper: %s", err) + } + + for _, og := range resp.OptionGroupsList { + var testOptGroup bool + for _, testName := range []string{"option-group-test-terraform-", "tf-test"} { + if strings.HasPrefix(*og.OptionGroupName, testName) { + testOptGroup = true + } + } + + if !testOptGroup { + continue + } + + deleteOpts := &rds.DeleteOptionGroupInput{ + OptionGroupName: og.OptionGroupName, + } + + ret := resource.Retry(1*time.Minute, func() *resource.RetryError { + _, err := conn.DeleteOptionGroup(deleteOpts) + if err != nil { + if awsErr, ok := err.(awserr.Error); ok { + if awsErr.Code() == "InvalidOptionGroupStateFault" { + log.Printf("[DEBUG] AWS believes the RDS Option Group is still in use, retrying") + return resource.RetryableError(awsErr) + } + } + return resource.NonRetryableError(err) + } + return nil + }) + if ret != nil { + return fmt.Errorf("Error Deleting DB Option Group (%s) in Sweeper: %s", *og.OptionGroupName, ret) + } + } + + return nil +} + func TestAccAWSDBOptionGroup_basic(t *testing.T) { var v rds.OptionGroup rName := fmt.Sprintf("option-group-test-terraform-%s", acctest.RandString(5)) diff --git a/builtin/providers/aws/resource_aws_key_pair_test.go b/builtin/providers/aws/resource_aws_key_pair_test.go index 3252a8963..e0c510d26 100644 --- a/builtin/providers/aws/resource_aws_key_pair_test.go +++ b/builtin/providers/aws/resource_aws_key_pair_test.go @@ -2,6 +2,7 @@ package aws import ( "fmt" + "log" "strings" "testing" @@ -12,6 +13,47 @@ import ( "github.com/hashicorp/terraform/terraform" ) +func init() { + resource.AddTestSweepers("aws_key_pair", &resource.Sweeper{ + Name: "aws_key_pair", + F: testSweepKeyPairs, + }) +} + +func testSweepKeyPairs(region string) error { + client, err := sharedClientForRegion(region) + if err != nil { + return fmt.Errorf("error getting client: %s", err) + } + ec2conn := client.(*AWSClient).ec2conn + + log.Printf("Destroying the tmp keys in (%s)", client.(*AWSClient).region) + + resp, err := ec2conn.DescribeKeyPairs(&ec2.DescribeKeyPairsInput{ + Filters: []*ec2.Filter{ + &ec2.Filter{ + Name: aws.String("key-name"), + Values: []*string{aws.String("tmp-key*")}, + }, + }, + }) + if err != nil { + return fmt.Errorf("Error describing key pairs in Sweeper: %s", err) + } + + keyPairs := resp.KeyPairs + for _, d := range keyPairs { + _, err := ec2conn.DeleteKeyPair(&ec2.DeleteKeyPairInput{ + KeyName: d.KeyName, + }) + + if err != nil { + return fmt.Errorf("Error deleting key pairs in Sweeper: %s", err) + } + } + return nil +} + func TestAccAWSKeyPair_basic(t *testing.T) { var conf ec2.KeyPairInfo diff --git a/builtin/providers/aws/resource_aws_launch_configuration_test.go b/builtin/providers/aws/resource_aws_launch_configuration_test.go index c0e63de7b..255414914 100644 --- a/builtin/providers/aws/resource_aws_launch_configuration_test.go +++ b/builtin/providers/aws/resource_aws_launch_configuration_test.go @@ -2,6 +2,7 @@ package aws import ( "fmt" + "log" "math/rand" "strings" "testing" @@ -16,6 +17,61 @@ import ( "github.com/hashicorp/terraform/terraform" ) +func init() { + resource.AddTestSweepers("aws_launch_configuration", &resource.Sweeper{ + Name: "aws_launch_configuration", + Dependencies: []string{"aws_autoscaling_group"}, + F: testSweepLaunchConfigurations, + }) +} + +func testSweepLaunchConfigurations(region string) error { + client, err := sharedClientForRegion(region) + if err != nil { + return fmt.Errorf("error getting client: %s", err) + } + autoscalingconn := client.(*AWSClient).autoscalingconn + + resp, err := autoscalingconn.DescribeLaunchConfigurations(&autoscaling.DescribeLaunchConfigurationsInput{}) + if err != nil { + return fmt.Errorf("Error retrieving launch configuration: %s", err) + } + + if len(resp.LaunchConfigurations) == 0 { + log.Print("[DEBUG] No aws launch configurations to sweep") + return nil + } + + for _, lc := range resp.LaunchConfigurations { + var testOptGroup bool + for _, testName := range []string{"terraform-", "foobar"} { + if strings.HasPrefix(*lc.LaunchConfigurationName, testName) { + testOptGroup = true + } + } + + if !testOptGroup { + continue + } + + _, err := autoscalingconn.DeleteLaunchConfiguration( + &autoscaling.DeleteLaunchConfigurationInput{ + LaunchConfigurationName: lc.LaunchConfigurationName, + }) + if err != nil { + autoscalingerr, ok := err.(awserr.Error) + if ok && (autoscalingerr.Code() == "InvalidConfiguration.NotFound" || autoscalingerr.Code() == "ValidationError") { + log.Printf("[DEBUG] Launch configuration (%s) not found", *lc.LaunchConfigurationName) + return nil + } + + return err + } + } + + return nil +} + func TestAccAWSLaunchConfiguration_basic(t *testing.T) { var conf autoscaling.LaunchConfiguration diff --git a/builtin/providers/google/gcp_sweeper_test.go b/builtin/providers/google/gcp_sweeper_test.go new file mode 100644 index 000000000..54661f050 --- /dev/null +++ b/builtin/providers/google/gcp_sweeper_test.go @@ -0,0 +1,35 @@ +package google + +import ( + "fmt" + "os" + "testing" + + "github.com/hashicorp/terraform/helper/resource" +) + +func TestMain(m *testing.M) { + resource.TestMain(m) +} + +// sharedConfigForRegion returns a common config setup needed for the sweeper +// functions for a given region +func sharedConfigForRegion(region string) (*Config, error) { + project := os.Getenv("GOOGLE_PROJECT") + if project == "" { + return nil, fmt.Errorf("empty GOOGLE_PROJECT") + } + + creds := os.Getenv("GOOGLE_CREDENTIALS") + if creds == "" { + return nil, fmt.Errorf("empty GOOGLE_CREDENTIALS") + } + + conf := &Config{ + Credentials: creds, + Region: region, + Project: project, + } + + return conf, nil +} diff --git a/builtin/providers/google/resource_sql_database_instance_test.go b/builtin/providers/google/resource_sql_database_instance_test.go index c553cbc44..4ff5192da 100644 --- a/builtin/providers/google/resource_sql_database_instance_test.go +++ b/builtin/providers/google/resource_sql_database_instance_test.go @@ -9,6 +9,7 @@ package google import ( "fmt" + "log" "strconv" "strings" "testing" @@ -20,6 +21,105 @@ import ( "google.golang.org/api/sqladmin/v1beta4" ) +func init() { + resource.AddTestSweepers("gcp_sql_db_instance", &resource.Sweeper{ + Name: "gcp_sql_db_instance", + F: testSweepDatabases, + }) +} + +func testSweepDatabases(region string) error { + config, err := sharedConfigForRegion(region) + if err != nil { + return fmt.Errorf("error getting shared config for region: %s", err) + } + + err = config.loadAndValidate() + if err != nil { + log.Fatalf("error loading: %s", err) + } + + found, err := config.clientSqlAdmin.Instances.List(config.Project).Do() + if err != nil { + log.Fatalf("error listing databases: %s", err) + } + + if len(found.Items) == 0 { + log.Printf("No databases found") + return nil + } + + for _, d := range found.Items { + var testDbInstance bool + for _, testName := range []string{"tf-lw-", "sqldatabasetest"} { + // only destroy instances we know to fit our test naming pattern + if strings.HasPrefix(d.Name, testName) { + testDbInstance = true + } + } + + if !testDbInstance { + continue + } + + log.Printf("Destroying SQL Instance (%s)", d.Name) + + // replicas need to be stopped and destroyed before destroying a master + // instance. The ordering slice tracks replica databases for a given master + // and we call destroy on them before destroying the master + var ordering []string + for _, replicaName := range d.ReplicaNames { + // need to stop replication before being able to destroy a database + op, err := config.clientSqlAdmin.Instances.StopReplica(config.Project, replicaName).Do() + + if err != nil { + return fmt.Errorf("error, failed to stop replica instance (%s) for instance (%s): %s", replicaName, d.Name, err) + } + + err = sqladminOperationWait(config, op, "Stop Replica") + if err != nil { + if strings.Contains(err.Error(), "does not exist") { + log.Printf("Replication operation not found") + } else { + return err + } + } + + ordering = append(ordering, replicaName) + } + + // ordering has a list of replicas (or none), now add the primary to the end + ordering = append(ordering, d.Name) + + for _, db := range ordering { + // destroy instances, replicas first + op, err := config.clientSqlAdmin.Instances.Delete(config.Project, db).Do() + + if err != nil { + if strings.Contains(err.Error(), "409") { + // the GCP api can return a 409 error after the delete operation + // reaches a successful end + log.Printf("Operation not found, got 409 response") + continue + } + + return fmt.Errorf("Error, failed to delete instance %s: %s", db, err) + } + + err = sqladminOperationWait(config, op, "Delete Instance") + if err != nil { + if strings.Contains(err.Error(), "does not exist") { + log.Printf("SQL instance not found") + continue + } + return err + } + } + } + + return nil +} + func TestAccGoogleSqlDatabaseInstance_basic(t *testing.T) { var instance sqladmin.DatabaseInstance databaseID := acctest.RandInt() diff --git a/helper/resource/testing.go b/helper/resource/testing.go index 04367c53c..ebdbde2b5 100644 --- a/helper/resource/testing.go +++ b/helper/resource/testing.go @@ -1,6 +1,7 @@ package resource import ( + "flag" "fmt" "io" "io/ioutil" @@ -20,6 +21,153 @@ import ( "github.com/hashicorp/terraform/terraform" ) +// flagSweep is a flag available when running tests on the command line. It +// contains a comma seperated list of regions to for the sweeper functions to +// run in. This flag bypasses the normal Test path and instead runs functions designed to +// clean up any leaked resources a testing environment could have created. It is +// a best effort attempt, and relies on Provider authors to implement "Sweeper" +// methods for resources. + +// Adding Sweeper methods with AddTestSweepers will +// construct a list of sweeper funcs to be called here. We iterate through +// regions provided by the sweep flag, and for each region we iterate through the +// tests, and exit on any errors. At time of writing, sweepers are ran +// sequentially, however they can list dependencies to be ran first. We track +// the sweepers that have been ran, so as to not run a sweeper twice for a given +// region. +// +// WARNING: +// Sweepers are designed to be destructive. You should not use the -sweep flag +// in any environment that is not strictly a test environment. Resources will be +// destroyed. + +var flagSweep = flag.String("sweep", "", "List of Regions to run available Sweepers") +var flagSweepRun = flag.String("sweep-run", "", "Comma seperated list of Sweeper Tests to run") +var sweeperFuncs map[string]*Sweeper + +// map of sweepers that have ran, and the success/fail status based on any error +// raised +var sweeperRunList map[string]bool + +// type SweeperFunc is a signature for a function that acts as a sweeper. It +// accepts a string for the region that the sweeper is to be ran in. This +// function must be able to construct a valid client for that region. +type SweeperFunc func(r string) error + +type Sweeper struct { + // Name for sweeper. Must be unique to be ran by the Sweeper Runner + Name string + + // Dependencies list the const names of other Sweeper functions that must be ran + // prior to running this Sweeper. This is an ordered list that will be invoked + // recursively at the helper/resource level + Dependencies []string + + // Sweeper function that when invoked sweeps the Provider of specific + // resources + F SweeperFunc +} + +func init() { + sweeperFuncs = make(map[string]*Sweeper) +} + +// AddTestSweepers function adds a given name and Sweeper configuration +// pair to the internal sweeperFuncs map. Invoke this function to register a +// resource sweeper to be available for running when the -sweep flag is used +// with `go test`. Sweeper names must be unique to help ensure a given sweeper +// is only ran once per run. +func AddTestSweepers(name string, s *Sweeper) { + if _, ok := sweeperFuncs[name]; ok { + log.Fatalf("[ERR] Error adding (%s) to sweeperFuncs: function already exists in map", name) + } + + sweeperFuncs[name] = s +} + +func TestMain(m *testing.M) { + flag.Parse() + if *flagSweep != "" { + // parse flagSweep contents for regions to run + regions := strings.Split(*flagSweep, ",") + + // get filtered list of sweepers to run based on sweep-run flag + sweepers := filterSweepers(*flagSweepRun, sweeperFuncs) + for _, region := range regions { + region = strings.TrimSpace(region) + // reset sweeperRunList for each region + sweeperRunList = map[string]bool{} + + log.Printf("[DEBUG] Running Sweepers for region (%s):\n", region) + for _, sweeper := range sweepers { + if err := runSweeperWithRegion(region, sweeper); err != nil { + log.Fatalf("[ERR] error running (%s): %s", sweeper.Name, err) + } + } + + log.Printf("Sweeper Tests ran:\n") + for s, _ := range sweeperRunList { + fmt.Printf("\t- %s\n", s) + } + } + } else { + os.Exit(m.Run()) + } +} + +// filterSweepers takes a comma seperated string listing the names of sweepers +// to be ran, and returns a filtered set from the list of all of sweepers to +// run based on the names given. +func filterSweepers(f string, source map[string]*Sweeper) map[string]*Sweeper { + filterSlice := strings.Split(strings.ToLower(f), ",") + if len(filterSlice) == 1 && filterSlice[0] == "" { + // if the filter slice is a single element of "" then no sweeper list was + // given, so just return the full list + return source + } + + sweepers := make(map[string]*Sweeper) + for name, sweeper := range source { + for _, s := range filterSlice { + if strings.Contains(strings.ToLower(name), s) { + sweepers[name] = sweeper + } + } + } + return sweepers +} + +// runSweeperWithRegion recieves a sweeper and a region, and recursively calls +// itself with that region for every dependency found for that sweeper. If there +// are no dependencies, invoke the contained sweeper fun with the region, and +// add the success/fail status to the sweeperRunList. +func runSweeperWithRegion(region string, s *Sweeper) error { + for _, dep := range s.Dependencies { + if depSweeper, ok := sweeperFuncs[dep]; ok { + log.Printf("[DEBUG] Sweeper (%s) has dependency (%s), running..", s.Name, dep) + if err := runSweeperWithRegion(region, depSweeper); err != nil { + return err + } + } else { + log.Printf("[DEBUG] Sweeper (%s) has dependency (%s), but that sweeper was not found", s.Name, dep) + } + } + + if _, ok := sweeperRunList[s.Name]; ok { + log.Printf("[DEBUG] Sweeper (%s) already ran in region (%s)", s.Name, region) + return nil + } + + runE := s.F(region) + if runE == nil { + sweeperRunList[s.Name] = true + } else { + sweeperRunList[s.Name] = false + } + + return runE +} + const TestEnvVar = "TF_ACC" // TestProvider can be implemented by any ResourceProvider to provide custom diff --git a/helper/resource/testing_test.go b/helper/resource/testing_test.go index 7c64f9eb8..cfadc2509 100644 --- a/helper/resource/testing_test.go +++ b/helper/resource/testing_test.go @@ -2,9 +2,12 @@ package resource import ( "errors" + "flag" "fmt" "os" + "reflect" "regexp" + "sort" "strings" "sync" "sync/atomic" @@ -619,3 +622,158 @@ func testProvider() *terraform.MockResourceProvider { const testConfigStr = ` resource "test_instance" "foo" {} ` + +func TestTest_Main(t *testing.T) { + flag.Parse() + if *flagSweep == "" { + // Tests for the TestMain method used for Sweepers will panic without the -sweep + // flag specified. Mock the value for now + *flagSweep = "us-east-1" + } + + cases := []struct { + Name string + Sweepers map[string]*Sweeper + ExpectedRunList []string + SweepRun string + }{ + { + Name: "normal", + Sweepers: map[string]*Sweeper{ + "aws_dummy": &Sweeper{ + Name: "aws_dummy", + F: mockSweeperFunc, + }, + }, + ExpectedRunList: []string{"aws_dummy"}, + }, + { + Name: "with dep", + Sweepers: map[string]*Sweeper{ + "aws_dummy": &Sweeper{ + Name: "aws_dummy", + F: mockSweeperFunc, + }, + "aws_top": &Sweeper{ + Name: "aws_top", + Dependencies: []string{"aws_sub"}, + F: mockSweeperFunc, + }, + "aws_sub": &Sweeper{ + Name: "aws_sub", + F: mockSweeperFunc, + }, + }, + ExpectedRunList: []string{"aws_dummy", "aws_sub", "aws_top"}, + }, + { + Name: "with filter", + Sweepers: map[string]*Sweeper{ + "aws_dummy": &Sweeper{ + Name: "aws_dummy", + F: mockSweeperFunc, + }, + "aws_top": &Sweeper{ + Name: "aws_top", + Dependencies: []string{"aws_sub"}, + F: mockSweeperFunc, + }, + "aws_sub": &Sweeper{ + Name: "aws_sub", + F: mockSweeperFunc, + }, + }, + ExpectedRunList: []string{"aws_dummy"}, + SweepRun: "aws_dummy", + }, + { + Name: "with two filters", + Sweepers: map[string]*Sweeper{ + "aws_dummy": &Sweeper{ + Name: "aws_dummy", + F: mockSweeperFunc, + }, + "aws_top": &Sweeper{ + Name: "aws_top", + Dependencies: []string{"aws_sub"}, + F: mockSweeperFunc, + }, + "aws_sub": &Sweeper{ + Name: "aws_sub", + F: mockSweeperFunc, + }, + }, + ExpectedRunList: []string{"aws_dummy", "aws_sub"}, + SweepRun: "aws_dummy,aws_sub", + }, + { + Name: "with dep and filter", + Sweepers: map[string]*Sweeper{ + "aws_dummy": &Sweeper{ + Name: "aws_dummy", + F: mockSweeperFunc, + }, + "aws_top": &Sweeper{ + Name: "aws_top", + Dependencies: []string{"aws_sub"}, + F: mockSweeperFunc, + }, + "aws_sub": &Sweeper{ + Name: "aws_sub", + F: mockSweeperFunc, + }, + }, + ExpectedRunList: []string{"aws_top", "aws_sub"}, + SweepRun: "aws_top", + }, + { + Name: "filter and none", + Sweepers: map[string]*Sweeper{ + "aws_dummy": &Sweeper{ + Name: "aws_dummy", + F: mockSweeperFunc, + }, + "aws_top": &Sweeper{ + Name: "aws_top", + Dependencies: []string{"aws_sub"}, + F: mockSweeperFunc, + }, + "aws_sub": &Sweeper{ + Name: "aws_sub", + F: mockSweeperFunc, + }, + }, + SweepRun: "none", + }, + } + + for _, tc := range cases { + // reset sweepers + sweeperFuncs = map[string]*Sweeper{} + + t.Run(tc.Name, func(t *testing.T) { + for n, s := range tc.Sweepers { + AddTestSweepers(n, s) + } + *flagSweepRun = tc.SweepRun + + TestMain(&testing.M{}) + + // get list of tests ran from sweeperRunList keys + var keys []string + for k, _ := range sweeperRunList { + keys = append(keys, k) + } + + sort.Strings(keys) + sort.Strings(tc.ExpectedRunList) + if !reflect.DeepEqual(keys, tc.ExpectedRunList) { + t.Fatalf("Expected keys mismatch, expected:\n%#v\ngot:\n%#v\n", tc.ExpectedRunList, keys) + } + }) + } +} + +func mockSweeperFunc(s string) error { + return nil +}