Skip to content

Commit

Permalink
restful_resource - body supports being an array (#90)
Browse files Browse the repository at this point in the history
  • Loading branch information
magodo authored May 11, 2024
1 parent d4c2d40 commit 9c1c14e
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 6 deletions.
8 changes: 4 additions & 4 deletions internal/provider/body.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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)
}
Expand Down
4 changes: 2 additions & 2 deletions internal/provider/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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(
Expand Down
116 changes: 116 additions & 0 deletions internal/provider/resource_dead_simple_json_server_test.go
Original file line number Diff line number Diff line change
@@ -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)
}

0 comments on commit 9c1c14e

Please sign in to comment.