package google import ( "bytes" "fmt" "log" "reflect" "sort" "testing" "github.com/hashicorp/terraform/helper/acctest" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" "google.golang.org/api/servicemanagement/v1" ) // Test that services can be enabled and disabled on a project func TestAccGoogleProjectServices_basic(t *testing.T) { pid := "terraform-" + acctest.RandString(10) services1 := []string{"iam.googleapis.com", "cloudresourcemanager.googleapis.com"} services2 := []string{"cloudresourcemanager.googleapis.com"} oobService := "iam.googleapis.com" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, Steps: []resource.TestStep{ // Create a new project with some services resource.TestStep{ Config: testAccGoogleProjectAssociateServicesBasic(services1, pid, pname, org), Check: resource.ComposeTestCheckFunc( testProjectServicesMatch(services1, pid), ), }, // Update services to remove one resource.TestStep{ Config: testAccGoogleProjectAssociateServicesBasic(services2, pid, pname, org), Check: resource.ComposeTestCheckFunc( testProjectServicesMatch(services2, pid), ), }, // Add a service out-of-band and ensure it is removed resource.TestStep{ PreConfig: func() { config := testAccProvider.Meta().(*Config) enableService(oobService, pid, config) }, Config: testAccGoogleProjectAssociateServicesBasic(services2, pid, pname, org), Check: resource.ComposeTestCheckFunc( testProjectServicesMatch(services2, pid), ), }, }, }) } // Test that services are authoritative when a project has existing // sevices not represented in config func TestAccGoogleProjectServices_authoritative(t *testing.T) { pid := "terraform-" + acctest.RandString(10) services := []string{"cloudresourcemanager.googleapis.com"} oobService := "iam.googleapis.com" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, Steps: []resource.TestStep{ // Create a new project with no services resource.TestStep{ Config: testAccGoogleProject_create(pid, pname, org), Check: resource.ComposeTestCheckFunc( testAccCheckGoogleProjectExists("google_project.acceptance", pid), ), }, // Add a service out-of-band, then apply a config that creates a service. // It should remove the out-of-band service. resource.TestStep{ PreConfig: func() { config := testAccProvider.Meta().(*Config) enableService(oobService, pid, config) }, Config: testAccGoogleProjectAssociateServicesBasic(services, pid, pname, org), Check: resource.ComposeTestCheckFunc( testProjectServicesMatch(services, pid), ), }, }, }) } // Test that services are authoritative when a project has existing // sevices, some which are represented in the config and others // that are not func TestAccGoogleProjectServices_authoritative2(t *testing.T) { pid := "terraform-" + acctest.RandString(10) oobServices := []string{"iam.googleapis.com", "cloudresourcemanager.googleapis.com"} services := []string{"iam.googleapis.com"} resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, Steps: []resource.TestStep{ // Create a new project with no services resource.TestStep{ Config: testAccGoogleProject_create(pid, pname, org), Check: resource.ComposeTestCheckFunc( testAccCheckGoogleProjectExists("google_project.acceptance", pid), ), }, // Add a service out-of-band, then apply a config that creates a service. // It should remove the out-of-band service. resource.TestStep{ PreConfig: func() { config := testAccProvider.Meta().(*Config) for _, s := range oobServices { enableService(s, pid, config) } }, Config: testAccGoogleProjectAssociateServicesBasic(services, pid, pname, org), Check: resource.ComposeTestCheckFunc( testProjectServicesMatch(services, pid), ), }, }, }) } func testAccGoogleProjectAssociateServicesBasic(services []string, pid, name, org string) string { return fmt.Sprintf(` resource "google_project" "acceptance" { project_id = "%s" name = "%s" org_id = "%s" } resource "google_project_services" "acceptance" { project = "${google_project.acceptance.project_id}" services = [%s] } `, pid, name, org, testStringsToString(services)) } func testProjectServicesMatch(services []string, pid string) resource.TestCheckFunc { return func(s *terraform.State) error { config := testAccProvider.Meta().(*Config) apiServices, err := getApiServices(pid, config) if err != nil { return fmt.Errorf("Error listing services for project %q: %v", pid, err) } sort.Strings(services) sort.Strings(apiServices) if !reflect.DeepEqual(services, apiServices) { return fmt.Errorf("Services in config (%v) do not exactly match services returned by API (%v)", services, apiServices) } return nil } } func testStringsToString(s []string) string { var b bytes.Buffer for i, v := range s { b.WriteString(fmt.Sprintf("\"%s\"", v)) if i < len(s)-1 { b.WriteString(",") } } r := b.String() log.Printf("[DEBUG]: Converted list of strings to %s", r) return b.String() } func testManagedServicesToString(svcs []*servicemanagement.ManagedService) string { var b bytes.Buffer for _, s := range svcs { b.WriteString(s.ServiceName) } return b.String() }