Skip to content

Commit

Permalink
Fix schema being always updated
Browse files Browse the repository at this point in the history
* add tests, that verify contents of the schema
* add test for Swagger/OpenAPI based schemas
* add fetching schema definition either from `value` or `definitions` based on
  content type
* add Json supress diff function, that allows ignoring insignificant changes,
  e.g. in white spaces
* use Json supress diff function when the content type is json based
  • Loading branch information
wiktorn committed Jun 12, 2021
1 parent 46cee82 commit 5a6423b
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package apimanagement

import (
"encoding/json"
"fmt"
"log"
"time"
Expand All @@ -12,6 +13,7 @@ import (
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/apimanagement/parse"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/apimanagement/schemaz"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/pluginsdk"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/suppress"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/validation"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
Expand Down Expand Up @@ -52,6 +54,12 @@ func resourceApiManagementApiSchema() *pluginsdk.Resource {
Type: pluginsdk.TypeString,
Required: true,
ValidateFunc: validation.StringIsNotEmpty,
DiffSuppressFunc: func(k, old, new string, d *pluginsdk.ResourceData) bool {
if d.Get("content_type") == "application/vnd.ms-azure-apim.swagger.definitions+json" || d.Get("content_type") == "application/vnd.oai.openapi.components+json" {
return suppress.JsonDiff(k, old, new, d)
}
return old == new
},
},
},
}
Expand Down Expand Up @@ -140,10 +148,32 @@ func resourceApiManagementApiSchemaRead(d *pluginsdk.ResourceData, meta interfac
if properties := resp.SchemaContractProperties; properties != nil {
d.Set("content_type", properties.ContentType)
if documentProperties := properties.SchemaDocumentProperties; documentProperties != nil {
d.Set("value", documentProperties.Value)
/*
As per https://docs.microsoft.com/en-us/rest/api/apimanagement/2019-12-01/api-schema/get#schemacontract
- Swagger Schema use application/vnd.ms-azure-apim.swagger.definitions+json
- WSDL Schema use application/vnd.ms-azure-apim.xsd+xml
- OpenApi Schema use application/vnd.oai.openapi.components+json
- WADL Schema use application/vnd.ms-azure-apim.wadl.grammars+xml.
Definitions used for Swagger/OpenAPI schemas only, otherwise Value is used
*/
if *properties.ContentType == "application/vnd.ms-azure-apim.swagger.definitions+json" || *properties.ContentType == "application/vnd.oai.openapi.components+json" {
if documentProperties.Definitions != nil {
value, err := json.Marshal(documentProperties.Definitions)
if err != nil {
return fmt.Errorf("[FATAL] Unable to serialize schema to json. Error: %+v. Schema struct: %+v", err, documentProperties.Definitions)
}
d.Set("value", string(value))
}
} else if *properties.ContentType == "application/vnd.ms-azure-apim.xsd+xml" || *properties.ContentType == "application/vnd.ms-azure-apim.wadl.grammars+xml" {
d.Set("value", documentProperties.Value)
} else {
return fmt.Errorf("[FATAL] Unkown content type %q for schema %q (API Management Service %q / API %q / Resource Group %q)", *properties.ContentType, schemaID, serviceName, apiName, resourceGroup)
}
}
}

}
return nil
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package apimanagement_test
import (
"context"
"fmt"
"io/ioutil"
"strings"
"testing"

"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure"
Expand All @@ -19,12 +21,31 @@ type ApiManagementApiSchemaResource struct {
func TestAccApiManagementApiSchema_basic(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_api_management_api_schema", "test")
r := ApiManagementApiSchemaResource{}
schema, _ := ioutil.ReadFile("testdata/api_management_api_schema.xml")

data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.basic(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
check.That(data.ResourceName).Key("value").HasValue(string(schema)),
),
},
data.ImportStep(),
})
}

func TestAccApiManagementApiSchema_basicSwagger(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_api_management_api_schema", "test")
r := ApiManagementApiSchemaResource{}
schema, _ := ioutil.ReadFile("testdata/api_management_api_schema_swagger.json")

data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.basicSwagger(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
check.That(data.ResourceName).Key("value").HasValue(strings.TrimRight(string(schema), "\r\n")),
),
},
data.ImportStep(),
Expand Down Expand Up @@ -79,6 +100,21 @@ resource "azurerm_api_management_api_schema" "test" {
`, r.template(data), data.RandomInteger)
}

func (r ApiManagementApiSchemaResource) basicSwagger(data acceptance.TestData) string {
return fmt.Sprintf(`
%s
resource "azurerm_api_management_api_schema" "test" {
api_name = azurerm_api_management_api.test.name
api_management_name = azurerm_api_management_api.test.api_management_name
resource_group_name = azurerm_api_management_api.test.resource_group_name
schema_id = "acctestSchema%d"
content_type = "application/vnd.ms-azure-apim.swagger.definitions+json"
value = file("testdata/api_management_api_schema_swagger.json")
}
`, r.template(data), data.RandomInteger)
}

func (r ApiManagementApiSchemaResource) requiresImport(data acceptance.TestData) string {
return fmt.Sprintf(`
%s
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"schema-bug-example":{"properties":{"Field2":{"description":"Field2","type":"string"},"field1":{"description":"Field1","type":"string"}},"required":["field1","Field2"],"type":"object"}}
21 changes: 21 additions & 0 deletions azurerm/internal/tf/suppress/json.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package suppress

import (
"encoding/json"
"reflect"

"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)

func JsonDiff(_, old, new string, _ *schema.ResourceData) bool {
if old == new {
return true
}
var oldJson interface{}
var newJson interface{}

json.Unmarshal([]byte(old), &oldJson)
json.Unmarshal([]byte(new), &newJson)

return reflect.DeepEqual(oldJson, newJson)
}
39 changes: 39 additions & 0 deletions azurerm/internal/tf/suppress/json_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package suppress

import "testing"

func TestJsonDiff(t *testing.T) {
cases := []struct {
Name string
StringA string
StringB string
Suppress bool
}{
{
Name: "empty",
StringA: "",
StringB: "",
Suppress: true,
},
{
Name: "simple same object",
StringA: "{\"field\": \"value\"}",
StringB: "{\"field\": \"value\"}",
Suppress: true,
},
{
Name: "simple object whitespace diff",
StringA: "{\n\"field\": \"value\"\n}",
StringB: "{\"field\": \"value\"}",
Suppress: false,
},
}

for _, tc := range cases {
t.Run(tc.Name, func(t *testing.T) {
if JsonDiff("test", tc.StringA, tc.StringB, nil) != tc.Suppress {
t.Fatalf("Expected JsonDiff to return %t for '%q' == '%q'", tc.Suppress, tc.StringA, tc.StringB)
}
})
}
}

0 comments on commit 5a6423b

Please sign in to comment.