Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Adding JSON Format to configuration variables #196

Merged
merged 9 commits into from
Jan 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this whole logic be duplicated to environment resource's configuration variables as well?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RLRabinowitz looks like it's already there...

configurationSchema := client.ConfigurationVariableSchema{
Type: "string",
Format: client.Format(variable["schema_format"].(string)),
Enum: nil,
}

}

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
}
Comment on lines +9 to +15
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice