8000 Support testing of configurations in JSON syntax. (#722) · hashicorp/terraform-plugin-sdk@aa11e4c · GitHub
[go: up one dir, main page]

Skip to content

Commit aa11e4c

Browse files
authored
Support testing of configurations in JSON syntax. (#722)
Reference: #721
1 parent 907e4a8 commit aa11e4c

File tree

3 files changed

+98
-10
lines changed

3 files changed

+98
-10
lines changed

helper/resource/testing.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,9 @@ type TestStep struct {
445445
// Config a string of the configuration to give to Terraform. If this
446446
// is set, then the TestCase will execute this step with the same logic
447447
// as a `terraform apply`.
448+
//
449+
// JSON Configuration Syntax can be used and is assumed whenever Config
450+
// contains valid JSON.
448451
Config string
449452

450453
// Check is called after the Config is applied. Use this step to

internal/plugintest/working_dir.go

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package plugintest
33
import (
44
"bytes"
55
"context"
6+
"encoding/json"
67
"errors"
78
"fmt"
89
"io/ioutil"
@@ -15,8 +16,9 @@ import (
1516
)
1617

1718
const (
18-
ConfigFileName = "terraform_plugin_test.tf"
19-
PlanFileName = "tfplan"
19+
ConfigFileName = "terraform_plugin_test.tf"
20+
ConfigFileNameJSON = ConfigFileName + ".json"
21+
PlanFileName = "tfplan"
2022
)
2123

2224
// WorkingDir represents a distinct working directory that can be used for
@@ -29,6 +31,10 @@ type WorkingDir struct {
2931
// baseDir is the root of the working directory tree
3032
baseDir string
3133

34+
// configFilename is the full filename where the latest configuration
35+
// was stored; empty until SetConfig is called.
36+
configFilename string
37+
3238
// baseArgs is arguments that should be appended to all commands
3339
baseArgs []string
3440

@@ -85,11 +91,20 @@ func (wd *WorkingDir) GetHelper() *Helper {
8591
// Destroy to establish the configuration. Any previously-set configuration is
8692
// discarded and any saved plan is cleared.
8793
func (wd *WorkingDir) SetConfig(ctx context.Context, cfg string) error {
88-
configFilename := filepath.Join(wd.baseDir, ConfigFileName)
89-
err := ioutil.WriteFile(configFilename, []byte(cfg), 0700)
94+
outFilename := filepath.Join(wd.baseDir, ConfigFileName)
95+
rmFilename := filepath.Join(wd.baseDir, ConfigFileNameJSON)
96+
bCfg := []byte(cfg)
97+
if json.Valid(bCfg) {
98+
outFilename, rmFilename = rmFilename, outFilename
99+
}
100+
if err := os.Remove(rmFilename); err != nil && !os.IsNotExist(err) {
101+
return fmt.Errorf("unable to remove %q: %w", rmFilename, err)
102+
}
103+
err := ioutil.WriteFile(outFilename, bCfg, 0700)
90104
if err != nil {
91105
return err
92106
}
107+
wd.configFilename = outFilename
93108

94109
var mismatch *tfexec.ErrVersionMismatch
95110
err = wd.tf.SetDisablePluginTLS(true)
@@ -158,11 +173,16 @@ func (wd *WorkingDir) ClearPlan(ctx context.Context) error {
158173
return nil
159174
}
160175

176+
var errWorkingDirSetConfigNotCalled = fmt.Errorf("must call SetConfig before Init")
177+
161178
// Init runs "terraform init" for the given working directory, forcing Terraform
162179
// to use the current version of the plugin under test.
163180
func (wd *WorkingDir) Init(ctx context.Context) error {
164-
if _, err := os.Stat(wd.configFilename()); err != nil {
165-
return fmt.Errorf("must call SetConfig before Init")
181+
if wd.configFilename == "" {
182+
return errWorkingDirSetConfigNotCalled
183+
}
184+
if _, err := os.Stat(wd.configFilename); err != nil {
185+
return errWorkingDirSetConfigNotCalled
166186
}
167187

168188
logging.HelperResourceTrace(ctx, "Calling Terraform CLI init command")
@@ -174,10 +194,6 @@ func (wd *WorkingDir) Init(ctx context.Context) error {
174194
return err
175195
}
176196

177-
func (wd *WorkingDir) configFilename() string {
178-
return filepath.Join(wd.baseDir, ConfigFileName)
179-
}
180-
181197
func (wd *WorkingDir) planFilename() string {
182198
return filepath.Join(wd.baseDir, PlanFileName)
183199
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package plugintest_test
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
9+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
10+
)
11+
12+
// TestJSONConfig verifies that TestStep.Config can contain JSON.
13+
// This test also proves that when changing the HCL and JSON formats back and
14+
// forth, the framework deletes the previous configuration file.
15+
func TestJSONConfig(t *testing.T) {
16+
providerFactories := map[string]func() (*schema.Provider, error){
17+
"tst": func() (*schema.Provider, error) { return tstProvider(), nil }, //nolint:unparam // required signature
18+
}
19+
resource.Test 9E7A (t, resource.TestCase{
20+
IsUnitTest: true,
21+
ProviderFactories: providerFactories,
22+
Steps: []resource.TestStep{{
23+
Config: `{"resource":{"tst_t":{"r1":{"s":"x1"}}}}`,
24+
Check: resource.TestCheckResourceAttr("tst_t.r1", "s", "x1"),
25+
}, {
26+
Config: `resource "tst_t" "r1" { s = "x2" }`,
27+
Check: resource.TestCheckResourceAttr("tst_t.r1", "s", "x2"),
28+
}, {
29+
Config: `{"resource":{"tst_t":{"r1":{"s":"x3"}}}}`,
30+
Check: resource.TestCheckResourceAttr("tst_t.r1", "s", "x3"),
31+
}},
32+
})
33+
}
34+
35+
func tstProvider() *schema.Provider {
36+
return &schema.Provider{
37+
ResourcesMap: map[string]*schema.Resource{
38+
"tst_t": {
39+
CreateContext: resourceTstTCreate,
40+
ReadContext: resourceTstTRead,
41+
UpdateContext: resourceTstTCreate, // Update is the same as Create
42+
DeleteContext: resourceTstTDelete,
43+
Schema: map[string]*schema.Schema{
44+
"s": {
45+
Type: schema.TypeString,
46+
Required: true,
47+
},
48+
},
49+
},
50+
},
51+
}
52+
}
53+
54+
func resourceTstTCreate(ctx context.Context, d *schema.ResourceData, _ interface{}) diag.Diagnostics {
55+
d.SetId(d.Get("s").(string))
56+
return nil
57+
}
58+
59+
func resourceTstTRead(ctx context.Context, d *schema.ResourceData, _ interface{}) diag.Diagnostics {
60+
if err := d.Set("s", d.Id()); err != nil {
61+
return diag.FromErr(err)
62+
}
63+
return nil
64+
}
65+
66+
func resourceTstTDelete(ctx context.Context, d *schema.ResourceData, _ interface{}) diag.Diagnostics {
67+
d.SetId("")
68+
return nil
69+
}

0 commit comments

Comments
 (0)
0