Skip to content

Commit

Permalink
Feat: Adding JSON Format to configuration variables (#196)
Browse files Browse the repository at this point in the history
* adding JSON Format

* adding tests for config client json format

* test

* changes to spec

* test for resource

* adding option to run single provider test

* better skip

* removing indentation for test fix

* small refactor
  • Loading branch information
avnerenv0 committed Jan 3, 2022
1 parent 2ad99bb commit 1608c1b
Show file tree
Hide file tree
Showing 9 changed files with 154 additions and 104 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ Run from root directory:
go test ./...
```

#### Running a single provider test
```shell
export TEST_PATTERN="TestUnitConfigurationVariableResource/Create" && go test ./env0
```

#### How to use mocks

1. Make sure `GOPATH` is in your `PATH`
Expand Down
81 changes: 57 additions & 24 deletions client/configuration_variable_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package client_test
import (
. "github.com/env0/terraform-provider-env0/client"
"github.com/golang/mock/gomock"
"github.com/jinzhu/copier"
. "github.com/onsi/ginkgo"
. "github.com/onsi/ginkgo/extensions/table"
. "github.com/onsi/gomega"
Expand Down Expand Up @@ -32,43 +33,59 @@ var _ = Describe("Configuration Variable", func() {
Describe("ConfigurationVariableCreate", func() {
var createdConfigurationVariable ConfigurationVariable

BeforeEach(func() {
mockOrganizationIdCall(organizationId)

expectedCreateRequest := []map[string]interface{}{{
"name": mockConfigurationVariable.Name,
"description": mockConfigurationVariable.Description,
"isSensitive": *mockConfigurationVariable.IsSensitive,
"value": mockConfigurationVariable.Value,
var GetExpectedRequest = func(mockConfig ConfigurationVariable) []map[string]interface{} {
schema := map[string]interface{}{
"type": mockConfig.Schema.Type,
"format": mockConfig.Schema.Format,
}

if mockConfig.Schema.Format == Text {
delete(schema, "format")
}

request := []map[string]interface{}{{
"name": mockConfig.Name,
"description": mockConfig.Description,
"isSensitive": *mockConfig.IsSensitive,
"value": mockConfig.Value,
"organizationId": organizationId,
"scopeId": mockConfigurationVariable.ScopeId,
"scope": mockConfigurationVariable.Scope,
"type": *mockConfigurationVariable.Type,
"schema": map[string]interface{}{
"type": mockConfigurationVariable.Schema.Type,
"format": mockConfigurationVariable.Schema.Format,
},
"scopeId": mockConfig.ScopeId,
"scope": mockConfig.Scope,
"type": *mockConfig.Type,
"schema": schema,
}}
return request
}

var SetCreateRequestExpectation = func(mockConfig ConfigurationVariable) {
expectedCreateRequest := GetExpectedRequest(mockConfig)
httpCall = mockHttpClient.EXPECT().
Post("configuration", expectedCreateRequest, gomock.Any()).
Do(func(path string, request interface{}, response *[]ConfigurationVariable) {
*response = []ConfigurationVariable{mockConfigurationVariable}
*response = []ConfigurationVariable{mockConfig}
})
}

var DoCreateRequest = func(mockConfig ConfigurationVariable) {
createdConfigurationVariable, _ = apiClient.ConfigurationVariableCreate(
ConfigurationVariableCreateParams{
Name: mockConfigurationVariable.Name,
Value: mockConfigurationVariable.Value,
Description: mockConfigurationVariable.Description,
IsSensitive: *mockConfigurationVariable.IsSensitive,
Scope: mockConfigurationVariable.Scope,
ScopeId: mockConfigurationVariable.ScopeId,
Type: *mockConfigurationVariable.Type,
Name: mockConfig.Name,
Value: mockConfig.Value,
Description: mockConfig.Description,
IsSensitive: *mockConfig.IsSensitive,
Scope: mockConfig.Scope,
ScopeId: mockConfig.ScopeId,
Type: *mockConfig.Type,
EnumValues: nil,
Format: mockConfigurationVariable.Schema.Format,
Format: mockConfig.Schema.Format,
},
)
}

BeforeEach(func() {
mockOrganizationIdCall(organizationId)
SetCreateRequestExpectation(mockConfigurationVariable)
DoCreateRequest(mockConfigurationVariable)
})

It("Should get organization id", func() {
Expand All @@ -82,6 +99,22 @@ var _ = Describe("Configuration Variable", func() {
It("Should return created configuration variable", func() {
Expect(createdConfigurationVariable).To(Equal(mockConfigurationVariable))
})

DescribeTable("Create with different schema format", func(schemaFormat Format) {
var mockWithFormat = ConfigurationVariable{}
copier.Copy(&mockWithFormat, &mockConfigurationVariable)
mockWithFormat.Schema.Format = schemaFormat
SetCreateRequestExpectation(mockWithFormat)

DoCreateRequest(mockWithFormat)

httpCall.Times(1)
Expect(createdConfigurationVariable).To(Equal(mockWithFormat))
},
Entry("Text Format", Text),
Entry("JSON Format", JSON),
Entry("HCL Format", HCL),
)
})

Describe("ConfigurationVariableDelete", func() {
Expand Down
1 change: 1 addition & 0 deletions client/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ type Format string
const (
Text Format = ""
HCL Format = "HCL"
JSON Format = "JSON"
)

type Scope string
Expand Down
2 changes: 1 addition & 1 deletion env0/data_configuration_variable.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func dataConfigurationVariable() *schema.Resource {
},
"format": {
Type: schema.TypeString,
Description: "specifies the format of the configuration value (for example: HCL)",
Description: "specifies the format of the configuration value (HCL/JSON)",
Computed: true,
},
},
Expand Down
8 changes: 7 additions & 1 deletion env0/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ var testUnitProviders = map[string]func() (*schema.Provider, error){
}

func runUnitTest(t *testing.T, testCase resource.TestCase, mockFunc func(mockFunc *client.MockApiClientInterface)) {
testPattern := os.Getenv("TEST_PATTERN")
if testPattern != "" && !strings.Contains(t.Name(), testPattern) {
t.SkipNow()
return
}

testReporter := utils.TestReporter{T: t}
ctrl = gomock.NewController(&testReporter)
defer ctrl.Finish()
Expand Down Expand Up @@ -64,7 +70,7 @@ func testExpectedProviderError(t *testing.T, diags diag.Diagnostics, expectedKey
}

if errorDetail == "" {
t.Fatalf("Error wasn't recieved, expected: %s", expectedError)
t.Fatalf("Error wasn't received, expected: %s", expectedError)
}
}

Expand Down
20 changes: 7 additions & 13 deletions env0/resource_configuration_variable.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,17 +79,11 @@ func resourceConfigurationVariable() *schema.Resource {
},
},
"format": {
Type: schema.TypeString,
Description: "specifies the format of the configuration value (for example: HCL)",
Default: "",
Optional: true,
ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) {
value := val.(string)
if value != string(client.HCL) && value != string(client.Text) {
errs = append(errs, fmt.Errorf("%q can be either \"HCL\" or empty, got: %q", key, value))
}
return
},
Type: schema.TypeString,
Description: "specifies the format of the configuration value (HCL/JSON)",
Default: "",
Optional: true,
ValidateFunc: ValidateConfigurationPropertySchema,
},
},
}
Expand Down Expand Up @@ -205,8 +199,8 @@ func resourceConfigurationVariableRead(ctx context.Context, d *schema.ResourceDa
d.Set("enum", variable.Schema.Enum)
}

if variable.Schema.Format == client.HCL {
d.Set("format", string(client.HCL))
if variable.Schema.Format != "" {
d.Set("format", variable.Schema.Format)
}
}

Expand Down
110 changes: 56 additions & 54 deletions env0/resource_configuration_variable_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,77 +114,79 @@ func TestUnitConfigurationVariableResource(t *testing.T) {
})
})

t.Run("Create HCL Variable", func(t *testing.T) {
for _, format := range []client.Format{client.HCL, client.JSON} {
t.Run("Create "+string(format)+" Variable", func(t *testing.T) {

expectedVariable := `{
expectedVariable := `{
A = "A"
B = "B"
C = "C"
}
`

schema := client.ConfigurationVariableSchema{
Type: "string",
Format: client.HCL,
}
configVar := client.ConfigurationVariable{
Id: "id0",
Name: "name0",
Description: "desc0",
Value: expectedVariable,
Schema: &schema,
}
terraformDirective := `<<EOT
schema := client.ConfigurationVariableSchema{
Type: "string",
Format: format,
}
configVar := client.ConfigurationVariable{
Id: "id0",
Name: "name0",
Description: "desc0",
Value: expectedVariable,
Schema: &schema,
}
terraformDirective := `<<EOT
{
%{ for key, value in var.map ~}
${key} = "${value}"
%{ endfor ~}
}
EOT`
stepConfig := fmt.Sprintf(`
variable "map" {
description = "a mapped variable"
type = map(string)
default = %s
}
resource "%s" "test" {
name = "%s"
description = "%s"
value = %s
format = "HCL"
}`, expectedVariable, resourceType, configVar.Name, configVar.Description, terraformDirective)
stepConfig := fmt.Sprintf(`
variable "map" {
description = "a mapped variable"
type = map(string)
default = %s
}
createTestCase := resource.TestCase{
Steps: []resource.TestStep{
{
Config: stepConfig,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(accessor, "value", configVar.Value),
resource.TestCheckResourceAttr(accessor, "format", string(client.HCL)),
),
resource "%s" "test" {
name = "%s"
description = "%s"
value = %s
format = "%s"
}`, expectedVariable, resourceType, configVar.Name, configVar.Description, terraformDirective, string(format))

createTestCase := resource.TestCase{
Steps: []resource.TestStep{
{
Config: stepConfig,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(accessor, "value", configVar.Value),
resource.TestCheckResourceAttr(accessor, "format", string(format)),
),
},
},
},
}
}

runUnitTest(t, createTestCase, func(mock *client.MockApiClientInterface) {
mock.EXPECT().ConfigurationVariableCreate(
client.ConfigurationVariableCreateParams{
Name: configVar.Name,
Value: expectedVariable,
IsSensitive: false,
Scope: client.ScopeGlobal,
ScopeId: "",
Type: client.ConfigurationVariableTypeEnvironment,
EnumValues: configVar.Schema.Enum,
Description: configVar.Description,
Format: client.HCL,
}).Times(1).Return(configVar, nil)
mock.EXPECT().ConfigurationVariables(client.ScopeGlobal, "").Times(1).Return([]client.ConfigurationVariable{configVar}, nil)
mock.EXPECT().ConfigurationVariableDelete(configVar.Id).Times(1).Return(nil)
runUnitTest(t, createTestCase, func(mock *client.MockApiClientInterface) {
mock.EXPECT().ConfigurationVariableCreate(
client.ConfigurationVariableCreateParams{
Name: configVar.Name,
Value: expectedVariable,
IsSensitive: false,
Scope: client.ScopeGlobal,
ScopeId: "",
Type: client.ConfigurationVariableTypeEnvironment,
EnumValues: configVar.Schema.Enum,
Description: configVar.Description,
Format: format,
}).Times(1).Return(configVar, nil)
mock.EXPECT().ConfigurationVariables(client.ScopeGlobal, "").Times(1).Return([]client.ConfigurationVariable{configVar}, nil)
mock.EXPECT().ConfigurationVariableDelete(configVar.Id).Times(1).Return(nil)
})
})
})
}

t.Run("Create Enum with wrong value", func(t *testing.T) {
stepConfig := fmt.Sprintf(`
Expand Down
16 changes: 5 additions & 11 deletions env0/resource_environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,17 +163,11 @@ func resourceEnvironment() *schema.Resource {
},
},
"schema_format": &schema.Schema{
Type: schema.TypeString,
Description: "the variable format:",
Default: "",
Optional: true,
ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) {
value := val.(string)
if value != string(client.HCL) && value != string(client.Text) {
errs = append(errs, fmt.Errorf("%q can be either \"HCL\" or empty, got: %q", key, value))
}
return
},
Type: schema.TypeString,
Description: "the variable format:",
Default: "",
Optional: true,
ValidateFunc: ValidateConfigurationPropertySchema,
},
},
},
Expand Down
15 changes: 15 additions & 0 deletions env0/validators.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package env0

import (
"fmt"

"github.com/env0/terraform-provider-env0/client"
)

func ValidateConfigurationPropertySchema(val interface{}, key string) (warns []string, errs []error) {
value := val.(string)
if value != string(client.HCL) && value != string(client.Text) && value != string(client.JSON) {
errs = append(errs, fmt.Errorf("%q can be either \"HCL\", \"JSON\" or empty, got: %q", key, value))
}
return
}

0 comments on commit 1608c1b

Please sign in to comment.