From c3e27b3e0a90ef1816d994efeb28a28084e1dbdd Mon Sep 17 00:00:00 2001 From: Paul Hinze Date: Tue, 15 Mar 2016 10:11:28 -0500 Subject: [PATCH] provider/test: a test provider Here we also introduce a `test` provider meant as an aid to exposing via automated tests issues involving interactions between `helper/schema` and Terraform core. This has been helpful so far in diagnosing `ignore_changes` problems, and I imagine it will be helpful in other contexts as well. We'll have to be careful to prevent the `test` provider from becoming a dumping ground for poorly specified tests that have a clear home elsewhere. But for bug exposure I think it's useful to have. --- builtin/providers/test/provider.go | 19 +++++++++ builtin/providers/test/provider_test.go | 16 ++++++++ builtin/providers/test/resource.go | 53 +++++++++++++++++++++++++ builtin/providers/test/resource_test.go | 32 +++++++++++++++ helper/resource/testing.go | 24 ++++++++++- 5 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 builtin/providers/test/provider.go create mode 100644 builtin/providers/test/provider_test.go create mode 100644 builtin/providers/test/resource.go create mode 100644 builtin/providers/test/resource_test.go diff --git a/builtin/providers/test/provider.go b/builtin/providers/test/provider.go new file mode 100644 index 000000000..a8e8c2470 --- /dev/null +++ b/builtin/providers/test/provider.go @@ -0,0 +1,19 @@ +package test + +import ( + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/terraform" +) + +func Provider() terraform.ResourceProvider { + return &schema.Provider{ + ResourcesMap: map[string]*schema.Resource{ + "test_resource": testResource(), + }, + ConfigureFunc: providerConfigure, + } +} + +func providerConfigure(d *schema.ResourceData) (interface{}, error) { + return nil, nil +} diff --git a/builtin/providers/test/provider_test.go b/builtin/providers/test/provider_test.go new file mode 100644 index 000000000..680bff119 --- /dev/null +++ b/builtin/providers/test/provider_test.go @@ -0,0 +1,16 @@ +package test + +import ( + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/terraform" +) + +var testAccProviders map[string]terraform.ResourceProvider +var testAccProvider *schema.Provider + +func init() { + testAccProvider = Provider().(*schema.Provider) + testAccProviders = map[string]terraform.ResourceProvider{ + "test": testAccProvider, + } +} diff --git a/builtin/providers/test/resource.go b/builtin/providers/test/resource.go new file mode 100644 index 000000000..93403ea92 --- /dev/null +++ b/builtin/providers/test/resource.go @@ -0,0 +1,53 @@ +package test + +import ( + "fmt" + + "github.com/hashicorp/terraform/helper/schema" +) + +func testResource() *schema.Resource { + return &schema.Resource{ + Create: testResourceCreate, + Read: testResourceRead, + Update: testResourceUpdate, + Delete: testResourceDelete, + Schema: map[string]*schema.Schema{ + "required": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "optional": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "optional_force_new": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + }, + } +} + +func testResourceCreate(d *schema.ResourceData, meta interface{}) error { + d.SetId("testId") + + // Required must make it through to Create + if _, ok := d.GetOk("required"); !ok { + return fmt.Errorf("Missing attribute 'required', but it's required!") + } + return nil +} + +func testResourceRead(d *schema.ResourceData, meta interface{}) error { + return nil +} + +func testResourceUpdate(d *schema.ResourceData, meta interface{}) error { + return nil +} + +func testResourceDelete(d *schema.ResourceData, meta interface{}) error { + return nil +} diff --git a/builtin/providers/test/resource_test.go b/builtin/providers/test/resource_test.go new file mode 100644 index 000000000..c281485a6 --- /dev/null +++ b/builtin/providers/test/resource_test.go @@ -0,0 +1,32 @@ +package test + +import ( + "strings" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestResource_basic(t *testing.T) { + resource.UnitTest(t, resource.TestCase{ + Providers: testAccProviders, + CheckDestroy: testAccCheckResourceDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: strings.TrimSpace(` +resource "test_resource" "foo" { + required = "yep" +} + `), + Check: func(s *terraform.State) error { + return nil + }, + }, + }, + }) +} + +func testAccCheckResourceDestroy(s *terraform.State) error { + return nil +} diff --git a/helper/resource/testing.go b/helper/resource/testing.go index c2e50bdeb..5d1e195a5 100644 --- a/helper/resource/testing.go +++ b/helper/resource/testing.go @@ -19,6 +19,10 @@ import ( const TestEnvVar = "TF_ACC" +// UnitTestOverride is a value that when set in TestEnvVar indicates that this +// is a unit test borrowing the acceptance testing framework. +const UnitTestOverride = "UnitTestOverride" + // TestCheckFunc is the callback type used with acceptance tests to check // the state of a resource. The state passed in is the latest state known, // or in the case of being after a destroy, it is the last known state when @@ -108,6 +112,8 @@ func Test(t TestT, c TestCase) { return } + isUnitTest := (os.Getenv(TestEnvVar) == UnitTestOverride) + logWriter, err := logging.LogOutput() if err != nil { t.Error(fmt.Errorf("error setting up logging: %s", err)) @@ -115,7 +121,7 @@ func Test(t TestT, c TestCase) { log.SetOutput(logWriter) // We require verbose mode so that the user knows what is going on. - if !testTesting && !testing.Verbose() { + if !testTesting && !testing.Verbose() && !isUnitTest { t.Fatal("Acceptance tests must be run with the -v flag on tests") return } @@ -173,6 +179,22 @@ func Test(t TestT, c TestCase) { } } +// UnitTest is a helper to force the acceptance testing harness to run in the +// normal unit test suite. This should only be used for resource that don't +// have any external dependencies. +func UnitTest(t TestT, c TestCase) { + oldEnv := os.Getenv(TestEnvVar) + if err := os.Setenv(TestEnvVar, UnitTestOverride); err != nil { + t.Fatal(err) + } + defer func() { + if err := os.Setenv(TestEnvVar, oldEnv); err != nil { + t.Fatal(err) + } + }() + Test(t, c) +} + func testStep( opts terraform.ContextOpts, state *terraform.State,