dal-license-server/internal/config/config_test.go
djuka 1b8db5e4a7 Obimni testovi: 179 ukupno (46 Go + 133 Playwright)
Novi Go testovi:
- config_test.go: 9 testova (defaults, override, DSN, .env loading)
- helpers_test.go: 13 testova (writeJSON, writeError, clientIP)

Prosireni E2E testovi za svaku stranicu:
- login: 15 testova (forma, auth, redirect, sesije)
- dashboard: 18 testova (statistike, navbar, navigacija, odjava)
- licenses: 20 testova (tabela, filteri, pretraga, kombinacije)
- license-crud: 22 testa (forma, validacija, svi proizvodi/tipovi)
- license-detail: 26 testova (info, aktivacije, audit, revoke, release)
- audit: 14 testova (tabela, API zapisi, formati)
- api-client: 18 testova (activate flow, auth, revoke flow)

Azuriran TESTING.md sa kompletnom checklistom

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 07:58:24 +00:00

216 lines
5.5 KiB
Go

package config
import (
"os"
"path/filepath"
"testing"
)
func TestLoad_Defaults(t *testing.T) {
// Clear env to test defaults
envVars := []string{"APP_PORT", "APP_ENV", "DB_HOST", "DB_PORT", "DB_NAME", "DB_USER", "DB_PASS",
"ADMIN_API_KEY", "ADMIN_PASSWORD", "SESSION_SECRET", "RSA_PRIVATE_KEY_PATH",
"RATE_LIMIT_ACTIVATE", "RATE_LIMIT_VALIDATE", "LOG_LEVEL"}
saved := make(map[string]string)
for _, v := range envVars {
saved[v] = os.Getenv(v)
os.Unsetenv(v)
}
defer func() {
for k, v := range saved {
if v != "" {
os.Setenv(k, v)
}
}
}()
cfg := Load()
if cfg.Port != "8090" {
t.Errorf("Port default: ocekivano '8090', dobijeno %q", cfg.Port)
}
if cfg.Env != "development" {
t.Errorf("Env default: ocekivano 'development', dobijeno %q", cfg.Env)
}
if cfg.DBHost != "localhost" {
t.Errorf("DBHost default: ocekivano 'localhost', dobijeno %q", cfg.DBHost)
}
if cfg.DBPort != "3306" {
t.Errorf("DBPort default: ocekivano '3306', dobijeno %q", cfg.DBPort)
}
if cfg.DBName != "dal_license_db" {
t.Errorf("DBName default: ocekivano 'dal_license_db', dobijeno %q", cfg.DBName)
}
if cfg.DBUser != "license" {
t.Errorf("DBUser default: ocekivano 'license', dobijeno %q", cfg.DBUser)
}
if cfg.RSAPrivateKey != "./crypto/private.pem" {
t.Errorf("RSAPrivateKey default: ocekivano './crypto/private.pem', dobijeno %q", cfg.RSAPrivateKey)
}
if cfg.RateLimitActivate != "10" {
t.Errorf("RateLimitActivate default: ocekivano '10', dobijeno %q", cfg.RateLimitActivate)
}
if cfg.RateLimitValidate != "60" {
t.Errorf("RateLimitValidate default: ocekivano '60', dobijeno %q", cfg.RateLimitValidate)
}
if cfg.LogLevel != "info" {
t.Errorf("LogLevel default: ocekivano 'info', dobijeno %q", cfg.LogLevel)
}
}
func TestLoad_EnvOverrides(t *testing.T) {
os.Setenv("APP_PORT", "9999")
os.Setenv("APP_ENV", "production")
os.Setenv("DB_HOST", "db.example.com")
defer func() {
os.Unsetenv("APP_PORT")
os.Unsetenv("APP_ENV")
os.Unsetenv("DB_HOST")
}()
cfg := Load()
if cfg.Port != "9999" {
t.Errorf("Port override: ocekivano '9999', dobijeno %q", cfg.Port)
}
if cfg.Env != "production" {
t.Errorf("Env override: ocekivano 'production', dobijeno %q", cfg.Env)
}
if cfg.DBHost != "db.example.com" {
t.Errorf("DBHost override: ocekivano 'db.example.com', dobijeno %q", cfg.DBHost)
}
}
func TestDSN(t *testing.T) {
cfg := &Config{
DBUser: "testuser",
DBPass: "testpass",
DBHost: "localhost",
DBPort: "3306",
DBName: "testdb",
}
dsn := cfg.DSN()
expected := "testuser:testpass@tcp(localhost:3306)/testdb?parseTime=true&charset=utf8mb4&multiStatements=true"
if dsn != expected {
t.Errorf("DSN:\nocekivano: %q\ndobijeno: %q", expected, dsn)
}
}
func TestDSN_SpecialChars(t *testing.T) {
cfg := &Config{
DBUser: "user",
DBPass: "p@ss:w0rd",
DBHost: "192.168.1.1",
DBPort: "3307",
DBName: "my_db",
}
dsn := cfg.DSN()
if dsn == "" {
t.Error("DSN ne sme biti prazan")
}
// Mora sadrzati sve parametre
if !contains(dsn, "parseTime=true") {
t.Error("DSN mora sadrzati parseTime=true")
}
if !contains(dsn, "multiStatements=true") {
t.Error("DSN mora sadrzati multiStatements=true")
}
if !contains(dsn, "charset=utf8mb4") {
t.Error("DSN mora sadrzati charset=utf8mb4")
}
}
func TestLoadEnvFile(t *testing.T) {
dir := t.TempDir()
envPath := filepath.Join(dir, ".env")
content := `# Comment
TEST_CONFIG_VAR=hello_world
TEST_CONFIG_NUM=42
`
os.WriteFile(envPath, []byte(content), 0644)
os.Unsetenv("TEST_CONFIG_VAR")
os.Unsetenv("TEST_CONFIG_NUM")
loadEnvFile(envPath)
if v := os.Getenv("TEST_CONFIG_VAR"); v != "hello_world" {
t.Errorf("TEST_CONFIG_VAR: ocekivano 'hello_world', dobijeno %q", v)
}
if v := os.Getenv("TEST_CONFIG_NUM"); v != "42" {
t.Errorf("TEST_CONFIG_NUM: ocekivano '42', dobijeno %q", v)
}
os.Unsetenv("TEST_CONFIG_VAR")
os.Unsetenv("TEST_CONFIG_NUM")
}
func TestLoadEnvFile_ExistingEnvNotOverwritten(t *testing.T) {
dir := t.TempDir()
envPath := filepath.Join(dir, ".env")
os.WriteFile(envPath, []byte("TEST_EXISTING=from_file\n"), 0644)
os.Setenv("TEST_EXISTING", "from_env")
defer os.Unsetenv("TEST_EXISTING")
loadEnvFile(envPath)
if v := os.Getenv("TEST_EXISTING"); v != "from_env" {
t.Errorf("env varijabla ne sme biti prepisana iz fajla: ocekivano 'from_env', dobijeno %q", v)
}
}
func TestLoadEnvFile_SkipsComments(t *testing.T) {
dir := t.TempDir()
envPath := filepath.Join(dir, ".env")
os.WriteFile(envPath, []byte("# COMMENTED_VAR=should_not_set\nACTUAL_VAR=set_this\n"), 0644)
os.Unsetenv("COMMENTED_VAR")
os.Unsetenv("ACTUAL_VAR")
loadEnvFile(envPath)
if v := os.Getenv("COMMENTED_VAR"); v != "" {
t.Errorf("komentarisana varijabla ne sme biti setovana: dobijeno %q", v)
}
if v := os.Getenv("ACTUAL_VAR"); v != "set_this" {
t.Errorf("ACTUAL_VAR: ocekivano 'set_this', dobijeno %q", v)
}
os.Unsetenv("ACTUAL_VAR")
}
func TestLoadEnvFile_EmptyLines(t *testing.T) {
dir := t.TempDir()
envPath := filepath.Join(dir, ".env")
os.WriteFile(envPath, []byte("\n\nVAR_AFTER_EMPTY=works\n\n"), 0644)
os.Unsetenv("VAR_AFTER_EMPTY")
loadEnvFile(envPath)
if v := os.Getenv("VAR_AFTER_EMPTY"); v != "works" {
t.Errorf("ocekivano 'works', dobijeno %q", v)
}
os.Unsetenv("VAR_AFTER_EMPTY")
}
func TestLoadEnvFile_NonexistentFile(t *testing.T) {
// Ne sme pasti
loadEnvFile("/nonexistent/path/.env")
}
func contains(s, substr string) bool {
return len(s) >= len(substr) && (s == substr || len(s) > 0 && containsStr(s, substr))
}
func containsStr(s, sub string) bool {
for i := 0; i <= len(s)-len(sub); i++ {
if s[i:i+len(sub)] == sub {
return true
}
}
return false
}