diff --git a/internal/provider/body.go b/internal/provider/body.go index 68389a2..ee41289 100644 --- a/internal/provider/body.go +++ b/internal/provider/body.go @@ -14,12 +14,12 @@ import ( // If compensateBaseAttrs is set, then any attribute path element only found in the base body will // be added up to the result body. func ModifyBody(base, body string, compensateBaseAttrs []string) (string, error) { - var baseJSON map[string]interface{} + var baseJSON interface{} if err := json.Unmarshal([]byte(base), &baseJSON); err != nil { return "", fmt.Errorf("unmarshal the base %q: %v", base, err) } - var bodyJSON map[string]interface{} + var bodyJSON interface{} if err := json.Unmarshal([]byte(body), &bodyJSON); err != nil { return "", fmt.Errorf("unmarshal the body %q: %v", body, err) } @@ -82,11 +82,11 @@ func ModifyBodyForImport(base, body string) (string, error) { if base == "" { return body, nil } - var baseJSON map[string]interface{} + var baseJSON interface{} if err := json.Unmarshal([]byte(base), &baseJSON); err != nil { return "", fmt.Errorf("unmarshal the base %q: %v", base, err) } - var bodyJSON map[string]interface{} + var bodyJSON interface{} if err := json.Unmarshal([]byte(body), &bodyJSON); err != nil { return "", fmt.Errorf("unmarshal the body %q: %v", body, err) } diff --git a/internal/provider/resource.go b/internal/provider/resource.go index eb085cc..e191c19 100644 --- a/internal/provider/resource.go +++ b/internal/provider/resource.go @@ -1073,7 +1073,7 @@ type importSpec struct { // Body represents the properties expected to be managed and tracked by Terraform. The value of these properties can be null as a place holder. // When absent, all the response payload read wil be set to `body`. - Body map[string]interface{} + Body interface{} } func (Resource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { @@ -1109,7 +1109,7 @@ func (Resource) ImportState(ctx context.Context, req resource.ImportStateRequest } var body string - if len(imp.Body) != 0 { + if imp.Body != nil { b, err := json.Marshal(imp.Body) if err != nil { resp.Diagnostics.AddError( diff --git a/internal/provider/resource_dead_simple_json_server_test.go b/internal/provider/resource_dead_simple_json_server_test.go new file mode 100644 index 0000000..c7ad36b --- /dev/null +++ b/internal/provider/resource_dead_simple_json_server_test.go @@ -0,0 +1,116 @@ +package provider_test + +import ( + "context" + "fmt" + "net/http" + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/magodo/terraform-provider-restful/internal/acceptance" + "github.com/magodo/terraform-provider-restful/internal/client" +) + +const RESTFUL_DEAD_SIMPLE_SERVER_URL = "RESTFUL_DEAD_SIMPLE_SERVER_URL" + +type deadSimpleServerData struct { + url string +} + +func (d deadSimpleServerData) precheck(t *testing.T) { + if d.url == "" { + t.Skipf("%q is not specified", RESTFUL_DEAD_SIMPLE_SERVER_URL) + } + return +} + +func newDeadSimpleServerData() deadSimpleServerData { + return deadSimpleServerData{ + url: os.Getenv(RESTFUL_DEAD_SIMPLE_SERVER_URL), + } +} + +func TestResource_DeadSimpleServer_Basic(t *testing.T) { + addr := "restful_resource.test" + d := newDeadSimpleServerData() + resource.Test(t, resource.TestCase{ + PreCheck: func() { d.precheck(t) }, + CheckDestroy: d.CheckDestroy(addr), + ProtoV6ProviderFactories: acceptance.ProviderFactory(), + Steps: []resource.TestStep{ + { + Config: d.basic("foo"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(addr, "output"), + ), + }, + { + ResourceName: addr, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"create_method"}, + ImportStateIdFunc: func(s *terraform.State) (string, error) { + return `{"id": "test", "path": "test", "body": [{"foo": null}]}`, nil + }, + }, + { + Config: d.basic("bar"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(addr, "output"), + ), + }, + { + ResourceName: addr, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"create_method"}, + ImportStateIdFunc: func(s *terraform.State) (string, error) { + return `{"id": "test", "path": "test", "body": [{"foo": null}]}`, nil + }, + }, + }, + }) +} + +func (d deadSimpleServerData) CheckDestroy(addr string) func(*terraform.State) error { + return func(s *terraform.State) error { + c, err := client.New(context.TODO(), d.url, nil) + if err != nil { + return err + } + for key, resource := range s.RootModule().Resources { + if key != addr { + continue + } + resp, err := c.Read(context.TODO(), resource.Primary.ID, client.ReadOption{}) + if err != nil { + return fmt.Errorf("reading %s: %v", addr, err) + } + if resp.StatusCode() != http.StatusNotFound { + return fmt.Errorf("%s: still exists", addr) + } + return nil + } + panic("unreachable") + } +} + +func (d deadSimpleServerData) basic(v string) string { + return fmt.Sprintf(` +provider "restful" { + base_url = %q +} + +resource "restful_resource" "test" { + path = "test" + create_method = "PUT" + body = jsonencode([ + { + foo = %q + } +]) +} +`, d.url, v) +}