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
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func main() {
sqlDB, _ := db.DB()
defer sqlDB.Close()

secretKey := []byte(pkg.GetEnv("JWT_SECRET", "secret-key"))
secretKey := []byte(pkg.GetEnv("JWT_SECRET", ""))
// Dependency wiring
taskRepo := gorm_task.NewTaskRepository(db)
taskSvc := task_service.NewTaskService(taskRepo)
Expand Down
18 changes: 17 additions & 1 deletion pkg/env.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,26 @@
package pkg

import "os"
import (
"fmt"
"log"
"os"
"taskflow/internal/common"
)

func GetEnv(key, fallback string) string {
if value := os.Getenv(key); value != "" {
return value
}

// If fallback is empty, treat it as a required variable.
if fallback == "" {
// Fatal → exit with a clear error message
log.Fatal(
common.ErrorResponse{
Message: fmt.Sprintf("missing required environment variable: %s", key),
}.Error(),
)
}

return fallback
}
107 changes: 107 additions & 0 deletions pkg/env_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package pkg

import (
"os"
"os/exec"
"strings"
"testing"
)

func TestGetEnv(t *testing.T) {
tests := []struct {
name string
key string
fallback string
envValue string
setEnv bool
expected string
}{
{
name: "returns env value when set",
key: "TEST_VAR",
fallback: "default",
envValue: "from_env",
setEnv: true,
expected: "from_env",
},
{
name: "returns env value with special characters",
key: "SPECIAL_VAR",
fallback: "default",
envValue: "value:with:colons",
setEnv: true,
expected: "value:with:colons",
},
{
name: "returns fallback when env not set",
key: "UNSET_VAR",
fallback: "default_value",
setEnv: false,
expected: "default_value",
},
{
name: "returns empty string from env when set to empty",
key: "EMPTY_VAR",
fallback: "default",
envValue: "",
setEnv: true,
expected: "default",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
os.Unsetenv(tt.key)

if tt.setEnv {
os.Setenv(tt.key, tt.envValue)
defer os.Unsetenv(tt.key)
}

result := GetEnv(tt.key, tt.fallback)
if result != tt.expected {
t.Errorf("GetEnv() = %q, want %q", result, tt.expected)
}
})
}
}

func TestGetEnv_MissingRequiredVariable(t *testing.T) {
if os.Getenv("TEST_SUBPROCESS") == "1" {
GetEnv("MISSING_REQUIRED_VAR", "")
return
}

cmd := exec.Command(os.Args[0], "-test.run=TestGetEnv_MissingRequiredVariable")
cmd.Env = append(os.Environ(), "TEST_SUBPROCESS=1")
output, err := cmd.CombinedOutput()

if err == nil {
t.Fatal("expected process to exit with error, but it succeeded")
}

if exitErr, ok := err.(*exec.ExitError); !ok || exitErr.Success() {
t.Errorf("expected non-zero exit status, got: %v", err)
}

outputStr := string(output)
if !strings.Contains(outputStr, "missing required environment variable") {
t.Errorf("expected error message to contain 'missing required environment variable', got: %s", outputStr)
}
if !strings.Contains(outputStr, "MISSING_REQUIRED_VAR") {
t.Errorf("expected error message to contain 'MISSING_REQUIRED_VAR', got: %s", outputStr)
}
}

func TestGetEnv_EmptyFallbackWithSetEnv(t *testing.T) {
key := "SET_VAR_EMPTY_FALLBACK"
value := "actual_value"

os.Setenv(key, value)
defer os.Unsetenv(key)

result := GetEnv(key, "")
if result != value {
t.Errorf("GetEnv() = %q, want %q", result, value)
}
}