Skip to content
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
4 changes: 3 additions & 1 deletion internal/models/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,12 @@ type EnvironmentVariable struct {
UUID string `json:"uuid"`
Key string `json:"key"`
Value string `json:"value" sensitive:"true"`
IsBuildTime bool `json:"is_build_time"`
IsBuildTime bool `json:"is_buildtime"`
IsPreview bool `json:"is_preview"`
IsLiteralValue bool `json:"is_literal"`
IsShownOnce bool `json:"is_shown_once"`
IsRuntime bool `json:"is_runtime"`
IsShared bool `json:"is_shared"`
RealValue *string `json:"real_value,omitempty" sensitive:"true"`
ApplicationID *int `json:"-" table:"-"`
CreatedAt string `json:"-" table:"-"`
Expand Down
130 changes: 130 additions & 0 deletions internal/models/models_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,3 +227,133 @@ func TestServerCreateRequest_Marshal(t *testing.T) {
assert.Equal(t, request.Port, unmarshaled.Port)
assert.True(t, unmarshaled.InstantValidate)
}

func TestEnvironmentVariable_IsBuildtimeField(t *testing.T) {
// Test that is_buildtime (without underscore) unmarshals correctly
jsonData := `{
"uuid": "env-123",
"key": "TEST_VAR",
"value": "test_value",
"is_buildtime": true,
"is_preview": false,
"is_literal": false,
"is_shown_once": false,
"is_runtime": true,
"is_shared": false
}`

var env EnvironmentVariable
err := json.Unmarshal([]byte(jsonData), &env)
require.NoError(t, err)

assert.Equal(t, "env-123", env.UUID)
assert.Equal(t, "TEST_VAR", env.Key)
assert.True(t, env.IsBuildTime, "is_buildtime should unmarshal to true")
assert.True(t, env.IsRuntime, "is_runtime should unmarshal to true")
assert.False(t, env.IsShared, "is_shared should unmarshal to false")
}

func TestEnvironmentVariable_MarshalUnmarshal(t *testing.T) {
realValue := "secret_value"
env := EnvironmentVariable{
UUID: "env-uuid-123",
Key: "DATABASE_URL",
Value: "postgres://localhost/db",
IsBuildTime: true,
IsPreview: false,
IsLiteralValue: true,
IsShownOnce: false,
IsRuntime: true,
IsShared: false,
RealValue: &realValue,
}

// Marshal
data, err := json.Marshal(env)
require.NoError(t, err)

// Verify JSON contains is_buildtime (not is_build_time)
assert.Contains(t, string(data), `"is_buildtime":true`)
assert.NotContains(t, string(data), `"is_build_time"`)

// Unmarshal
var unmarshaled EnvironmentVariable
err = json.Unmarshal(data, &unmarshaled)
require.NoError(t, err)

assert.Equal(t, env.UUID, unmarshaled.UUID)
assert.Equal(t, env.Key, unmarshaled.Key)
assert.Equal(t, env.Value, unmarshaled.Value)
assert.True(t, unmarshaled.IsBuildTime)
assert.True(t, unmarshaled.IsLiteralValue)
assert.True(t, unmarshaled.IsRuntime)
assert.False(t, unmarshaled.IsShared)
assert.NotNil(t, unmarshaled.RealValue)
assert.Equal(t, *env.RealValue, *unmarshaled.RealValue)
}

func TestEnvironmentVariable_UnmarshalFromFixture(t *testing.T) {
fixtureData, err := os.ReadFile(filepath.Join("..", "..", "test", "fixtures", "environment_variable_complete.json"))
require.NoError(t, err)

var env EnvironmentVariable
err = json.Unmarshal(fixtureData, &env)
require.NoError(t, err)

assert.Equal(t, "env-test-uuid-123", env.UUID)
assert.Equal(t, "DATABASE_URL", env.Key)
assert.Equal(t, "postgres://localhost/mydb", env.Value)
assert.True(t, env.IsBuildTime, "IsBuildTime should be true from fixture")
assert.True(t, env.IsRuntime, "IsRuntime should be true from fixture")
assert.False(t, env.IsShared, "IsShared should be false from fixture")
assert.False(t, env.IsPreview)
assert.False(t, env.IsLiteralValue)
assert.False(t, env.IsShownOnce)
assert.NotNil(t, env.RealValue)
assert.Equal(t, "postgres://user:pass@localhost/mydb", *env.RealValue)
}

func TestEnvironmentVariable_PartialResponse(t *testing.T) {
// Test backward compatibility with older API responses that might not have all fields
jsonData := `{
"uuid": "env-123",
"key": "OLD_VAR",
"value": "old_value"
}`

var env EnvironmentVariable
err := json.Unmarshal([]byte(jsonData), &env)
require.NoError(t, err)

assert.Equal(t, "env-123", env.UUID)
assert.Equal(t, "OLD_VAR", env.Key)
assert.False(t, env.IsBuildTime, "Missing boolean fields should default to false")
assert.False(t, env.IsRuntime, "Missing boolean fields should default to false")
assert.False(t, env.IsShared, "Missing boolean fields should default to false")
}

func TestEnvironmentVariableCreateRequest_Marshal(t *testing.T) {
isBuildTime := true
isPreview := false
request := EnvironmentVariableCreateRequest{
Key: "NEW_VAR",
Value: "new_value",
IsBuildTime: &isBuildTime,
IsPreview: &isPreview,
}

data, err := json.Marshal(request)
require.NoError(t, err)

// Request models should still use is_build_time (with underscore) per API spec
assert.Contains(t, string(data), `"is_build_time":true`)

var unmarshaled EnvironmentVariableCreateRequest
err = json.Unmarshal(data, &unmarshaled)
require.NoError(t, err)

assert.Equal(t, request.Key, unmarshaled.Key)
assert.Equal(t, request.Value, unmarshaled.Value)
assert.NotNil(t, unmarshaled.IsBuildTime)
assert.True(t, *unmarshaled.IsBuildTime)
}
146 changes: 146 additions & 0 deletions internal/service/application_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -801,3 +801,149 @@ func TestApplicationService_DeleteEnv_Error(t *testing.T) {
require.Error(t, err)
assert.Contains(t, err.Error(), "failed to delete environment variable")
}

func TestApplicationService_ListEnvs_AllFields(t *testing.T) {
// Test that all fields including is_buildtime (without underscore), is_runtime, and is_shared
// are correctly parsed from API response
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, "/api/v1/applications/app-uuid-123/envs", r.URL.Path)
assert.Equal(t, "GET", r.Method)

// Mock API response with all fields
envs := []models.EnvironmentVariable{
{
UUID: "env-1",
Key: "DATABASE_URL",
Value: "postgres://localhost",
IsBuildTime: true,
IsPreview: false,
IsLiteralValue: true,
IsShownOnce: false,
IsRuntime: true,
IsShared: false,
},
{
UUID: "env-2",
Key: "API_KEY",
Value: "secret",
IsBuildTime: false,
IsPreview: true,
IsLiteralValue: false,
IsShownOnce: false,
IsRuntime: false,
IsShared: true,
},
}
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(envs)
}))
defer server.Close()

client := api.NewClient(server.URL, "test-token")
svc := NewApplicationService(client)

result, err := svc.ListEnvs(context.Background(), "app-uuid-123")
require.NoError(t, err)
assert.Len(t, result, 2)

// Verify first env var
assert.Equal(t, "DATABASE_URL", result[0].Key)
assert.True(t, result[0].IsBuildTime, "IsBuildTime should be true for DATABASE_URL")
assert.True(t, result[0].IsRuntime, "IsRuntime should be true for DATABASE_URL")
assert.False(t, result[0].IsShared, "IsShared should be false for DATABASE_URL")
assert.True(t, result[0].IsLiteralValue)
assert.False(t, result[0].IsPreview)

// Verify second env var
assert.Equal(t, "API_KEY", result[1].Key)
assert.False(t, result[1].IsBuildTime, "IsBuildTime should be false for API_KEY")
assert.False(t, result[1].IsRuntime, "IsRuntime should be false for API_KEY")
assert.True(t, result[1].IsShared, "IsShared should be true for API_KEY")
assert.False(t, result[1].IsLiteralValue)
assert.True(t, result[1].IsPreview)
}

func TestApplicationService_EnvBuildtimeFlag(t *testing.T) {
// Test specifically that is_buildtime (without underscore) unmarshals correctly
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, "/api/v1/applications/app-uuid-123/envs", r.URL.Path)

// Directly write JSON with is_buildtime (no underscore) to mimic actual API
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`[
{
"uuid": "env-test-1",
"key": "BUILD_VAR",
"value": "build_value",
"is_buildtime": true,
"is_preview": false,
"is_literal": false,
"is_shown_once": false,
"is_runtime": true,
"is_shared": false
}
]`))
}))
defer server.Close()

client := api.NewClient(server.URL, "test-token")
svc := NewApplicationService(client)

result, err := svc.ListEnvs(context.Background(), "app-uuid-123")
require.NoError(t, err)
assert.Len(t, result, 1)
assert.Equal(t, "BUILD_VAR", result[0].Key)
assert.True(t, result[0].IsBuildTime, "is_buildtime field should unmarshal correctly to true")
assert.True(t, result[0].IsRuntime, "is_runtime field should unmarshal correctly to true")
}

func TestApplicationService_EnvRuntimeAndShared(t *testing.T) {
// Test is_runtime and is_shared fields specifically
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, "/api/v1/applications/app-uuid-123/envs", r.URL.Path)

w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`[
{
"uuid": "env-runtime",
"key": "RUNTIME_VAR",
"value": "runtime_value",
"is_buildtime": false,
"is_preview": false,
"is_literal": false,
"is_shown_once": false,
"is_runtime": true,
"is_shared": false
},
{
"uuid": "env-shared",
"key": "SHARED_VAR",
"value": "shared_value",
"is_buildtime": false,
"is_preview": false,
"is_literal": false,
"is_shown_once": false,
"is_runtime": false,
"is_shared": true
}
]`))
}))
defer server.Close()

client := api.NewClient(server.URL, "test-token")
svc := NewApplicationService(client)

result, err := svc.ListEnvs(context.Background(), "app-uuid-123")
require.NoError(t, err)
assert.Len(t, result, 2)

// Verify runtime var
assert.Equal(t, "RUNTIME_VAR", result[0].Key)
assert.True(t, result[0].IsRuntime, "IsRuntime should be true")
assert.False(t, result[0].IsShared, "IsShared should be false")

// Verify shared var
assert.Equal(t, "SHARED_VAR", result[1].Key)
assert.False(t, result[1].IsRuntime, "IsRuntime should be false")
assert.True(t, result[1].IsShared, "IsShared should be true")
}
12 changes: 12 additions & 0 deletions test/fixtures/environment_variable_complete.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"uuid": "env-test-uuid-123",
"key": "DATABASE_URL",
"value": "postgres://localhost/mydb",
"real_value": "postgres://user:pass@localhost/mydb",
"is_buildtime": true,
"is_preview": false,
"is_literal": false,
"is_shown_once": false,
"is_runtime": true,
"is_shared": false
}