diff --git a/client/app_test.go b/client/app_test.go index 631bbac..f3aef67 100644 --- a/client/app_test.go +++ b/client/app_test.go @@ -2,13 +2,12 @@ package client import ( "context" + "github.com/cloudfoundry/go-cfclient/v3/resource" + "github.com/stretchr/testify/require" "net/http" "testing" - "github.com/cloudfoundry/go-cfclient/v3/resource" "github.com/cloudfoundry/go-cfclient/v3/testutil" - - "github.com/stretchr/testify/require" ) func TestApps(t *testing.T) { @@ -20,11 +19,11 @@ func TestApps(t *testing.T) { space1 := g.Space().JSON space2 := g.Space().JSON org := g.Organization().JSON - appEnvironment := g.AppEnvironment().JSON + appEnvironment := g.AppEnvironment() + appEnvironmentExpected := g.AppEnvironmentExpected(appEnvironment.Name).JSON appEnvVar := g.AppEnvVar().JSON appSSH := g.AppSSH().JSON appPermission := g.AppPermission().JSON - tests := []RouteTest{ { Description: "Create app", @@ -104,10 +103,10 @@ func TestApps(t *testing.T) { Route: testutil.MockRoute{ Method: "GET", Endpoint: "/v3/apps/1cb006ee-fb05-47e1-b541-c34179ddc446/env", - Output: g.Single(appEnvironment), + Output: g.Single(appEnvironment.JSON), Status: http.StatusOK, }, - Expected: appEnvironment, + Expected: appEnvironmentExpected, Action: func(c *Client, t *testing.T) (any, error) { return c.Applications.GetEnvironment(context.Background(), "1cb006ee-fb05-47e1-b541-c34179ddc446") }, @@ -140,7 +139,7 @@ func TestApps(t *testing.T) { Output: g.Single(appEnvVar), Status: http.StatusOK, }, - Expected: `{ "RAILS_ENV": "production" }`, + Expected: `{ "RAILS_ENV": "production", "SOME_BOOLEAN": "true", "SOME_FLOAT64": "10.4", "SOME_INT": "5" }`, Action: func(c *Client, t *testing.T) (any, error) { return c.Applications.GetEnvironmentVariables(context.Background(), "1cb006ee-fb05-47e1-b541-c34179ddc446") }, diff --git a/client/revision_test.go b/client/revision_test.go index 837c3d7..c5462e0 100644 --- a/client/revision_test.go +++ b/client/revision_test.go @@ -38,7 +38,7 @@ func TestRevisions(t *testing.T) { Output: g.Single(appEnvVar), Status: http.StatusOK, }, - Expected: `{ "RAILS_ENV": "production" }`, + Expected: `{ "RAILS_ENV": "production", "SOME_BOOLEAN":"true", "SOME_FLOAT64":"10.4", "SOME_INT":"5" }`, Action: func(c *Client, t *testing.T) (any, error) { return c.Revisions.GetEnvironmentVariables(context.Background(), "5a49a370-92cd-4091-bb62-e0914460f7b2") }, diff --git a/resource/app.go b/resource/app.go index 0018f7d..b45700b 100644 --- a/resource/app.go +++ b/resource/app.go @@ -1,7 +1,10 @@ package resource import ( + "C" "encoding/json" + "fmt" + "strconv" ) type App struct { @@ -132,3 +135,96 @@ func NewAppCreate(name, spaceGUID string) *AppCreate { }, } } + +type InterfaceEnvVar struct { + Var map[string]interface{} `json:"var"` +} + +func (f *EnvVar) UnmarshalJSON(b []byte) error { + s := string(b) + if s == "" || s == "\"\"" { + return nil + } + + var interfaceEnvVar InterfaceEnvVar + + err := json.Unmarshal(b, &interfaceEnvVar) + + if err != nil { + return err + } + + varMap := make(map[string]*string) + for key, value := range interfaceEnvVar.Var { + switch v := value.(type) { + default: + fmt.Printf("unexpected env var type, skipping env var: %T", v) + continue + case int: + stringVal := strconv.Itoa(v) + varMap[key] = &stringVal + case string: + varMap[key] = &v + case bool: + stringBool := strconv.FormatBool(v) + varMap[key] = &stringBool + case float64: + stringFloat := strconv.FormatFloat(v, 'f', -1, 64) + varMap[key] = &stringFloat + } + } + f.Var = varMap + + return nil +} + +type InterfaceAppEnvironment struct { + EnvVars map[string]interface{} `json:"environment_variables,omitempty"` + StagingEnv map[string]interface{} `json:"staging_env_json,omitempty"` + RunningEnv map[string]interface{} `json:"running_env_json,omitempty"` + SystemEnvVars map[string]json.RawMessage `json:"system_env_json,omitempty"` // VCAP_SERVICES + AppEnvVars map[string]json.RawMessage `json:"application_env_json,omitempty"` // VCAP_APPLICATION +} + +func (f *AppEnvironment) UnmarshalJSON(b []byte) error { + s := string(b) + if s == "" || s == "\"\"" { + return nil + } + + var interfaceAppEnvironment InterfaceAppEnvironment + + err := json.Unmarshal(b, &interfaceAppEnvironment) + + if err != nil { + return err + } + + f.EnvVars = convertEnvVars(interfaceAppEnvironment.EnvVars) + f.StagingEnv = convertEnvVars(interfaceAppEnvironment.StagingEnv) + f.RunningEnv = convertEnvVars(interfaceAppEnvironment.RunningEnv) + f.AppEnvVars = interfaceAppEnvironment.AppEnvVars + f.SystemEnvVars = interfaceAppEnvironment.SystemEnvVars + + return nil +} + +func convertEnvVars(envVars map[string]interface{}) map[string]string { + envVarMap := make(map[string]string) + for key, value := range envVars { + switch v := value.(type) { + default: + fmt.Printf("unexpected env var type, skipping env var: %T", v) + continue + case int: + envVarMap[key] = strconv.Itoa(v) + case string: + envVarMap[key] = v + case bool: + envVarMap[key] = strconv.FormatBool(v) + case float64: + envVarMap[key] = strconv.FormatFloat(v, 'f', -1, 64) + } + } + return envVarMap +} diff --git a/testutil/object_generator.go b/testutil/object_generator.go index 9004abc..281844f 100644 --- a/testutil/object_generator.go +++ b/testutil/object_generator.go @@ -119,6 +119,13 @@ func (o ObjectJSONGenerator) AppEnvironment() *JSONResource { return o.renderTemplate(r, "app_environment.json") } +func (o ObjectJSONGenerator) AppEnvironmentExpected(name string) *JSONResource { + r := &JSONResource{ + Name: name, + } + return o.renderTemplate(r, "app_environment_expected.json") +} + func (o ObjectJSONGenerator) AppEnvVar() *JSONResource { r := &JSONResource{} return o.renderTemplate(r, "app_envvar.json") diff --git a/testutil/template/app_environment.json b/testutil/template/app_environment.json index 4edc680..c73472f 100644 --- a/testutil/template/app_environment.json +++ b/testutil/template/app_environment.json @@ -1,12 +1,21 @@ { "staging_env_json": { - "GEM_CACHE": "http://gem-cache.example.org" + "GEM_CACHE": "http://gem-cache.example.org", + "SOME_BOOLEAN": true, + "SOME_INT": 5, + "SOME_FLOAT64": 10.4 }, "running_env_json": { - "HTTP_PROXY": "http://proxy.example.org" + "HTTP_PROXY": "http://proxy.example.org", + "SOME_BOOLEAN": true, + "SOME_INT": 5, + "SOME_FLOAT64": 10.4 }, "environment_variables": { - "RAILS_ENV": "production" + "RAILS_ENV": "production", + "SOME_BOOLEAN": true, + "SOME_INT": 5, + "SOME_FLOAT64": 10.4 }, "system_env_json": { "VCAP_SERVICES": { diff --git a/testutil/template/app_environment_expected.json b/testutil/template/app_environment_expected.json new file mode 100644 index 0000000..bdfe24c --- /dev/null +++ b/testutil/template/app_environment_expected.json @@ -0,0 +1,57 @@ +{ + "staging_env_json": { + "GEM_CACHE": "http://gem-cache.example.org", + "SOME_BOOLEAN": "true", + "SOME_INT": "5", + "SOME_FLOAT64": "10.4" + }, + "running_env_json": { + "HTTP_PROXY": "http://proxy.example.org", + "SOME_BOOLEAN": "true", + "SOME_INT": "5", + "SOME_FLOAT64": "10.4" + }, + "environment_variables": { + "RAILS_ENV": "production", + "SOME_BOOLEAN": "true", + "SOME_INT": "5", + "SOME_FLOAT64": "10.4" + }, + "system_env_json": { + "VCAP_SERVICES": { + "mysql": [ + { + "name": "db-for-my-app", + "binding_id": "0e85b634-e043-4b43-96da-f83dfe83ab33", + "binding_name": "db-for-my-app", + "instance_id": "07fca01c-f789-4d45-80b4-e19ba3ca862c", + "instance_name": "my-mysql-service", + "label": "mysql", + "tags": ["relational", "sql"], + "plan": "xlarge", + "credentials": { + "username": "user", + "password": "top-secret" + }, + "syslog_drain_url": "https://syslog.example.org/drain", + "volume_mounts": [], + "provider": null + } + ] + } + }, + "application_env_json": { + "VCAP_APPLICATION": { + "limits": { + "fds": 16384 + }, + "application_name": "{{.Name}}", + "application_uris": [ "{{.Name}}.example.org" ], + "name": "{{.Name}}", + "space_name": "my_space", + "space_id": "2f35885d-0c9d-4423-83ad-fd05066f8576", + "uris": [ "my_app.example.org" ], + "users": null + } + } +} \ No newline at end of file diff --git a/testutil/template/app_envvar.json b/testutil/template/app_envvar.json index c0d016d..7358633 100644 --- a/testutil/template/app_envvar.json +++ b/testutil/template/app_envvar.json @@ -1,6 +1,9 @@ { "var": { - "RAILS_ENV": "production" + "RAILS_ENV": "production", + "SOME_BOOLEAN": true, + "SOME_INT": 5, + "SOME_FLOAT64": 10.4 }, "links": { "self": { @@ -10,4 +13,5 @@ "href": "https://api.example.org/v3/apps/[guid]" } } -} \ No newline at end of file +} +