licence-server/internal/config/config_test.go
Nenad Djukic 1abe7176ec Preimenovanje: dal-license-server -> licence-server (+ debrendiranje)
Vlasnik izlazi iz DAL price za ovaj projekat - postaje samostalan proizvod.
Preimenovanje je mehanicko (import putanje, imena fajlova/baze/UI naslova),
NIJEDNA linija poslovne logike u internal/handler ili internal/service nije
dirana - go build, go vet i go test ./... prolaze cisto pod novim imenom.

- go.mod: module dal-license-server -> licence-server; 28 import linija u
  13 .go fajlova usaglaseno
- internal/config/config.go (+test): default DB_NAME licence_db
- HTML sabloni (7 stranica) + 7 Playwright e2e spec fajlova: "DAL License
  Server" -> "Licence Server" u title/nav-brand, testovi usaglaseni u istom
  prolazu (nista ne moze da se razdvoji)
- package.json/package-lock.json/.gitignore/.claude/project.json: ime
  projekta/binarnog fajla/work_dir
- Usput: package.json je u repository.url nosio OTVORENU Gitea lozinku u
  cistom tekstu - uklonjena (URL sad bez kredencijala). Lozinka je i dalje
  u staroj git istoriji - preporuka: rotirati je posebno.
- CLAUDE.md/README/API/TESTING/docs/SPEC/ARCHITECTURE/SETUP: naslovi, ASCII
  dijagrami, git clone URL, mysqldump primer, systemd predlozak u SETUP.md
  zamenjen stvarnim (obrazac terminia.service - journal log + graceful
  shutdown, ne stari minimalni predlozak)
- Debrendiranje: "Univerzalni licencni server za sve DAL proizvode" ->
  "za vise proizvoda i klijenata"; potpis "Nenad Djukic / DAL d.o.o." ->
  "Nenad Djukic". NE dirano: nazivi ESIR/ARV/LIGHT_TICKET (tudji proizvodi,
  ne DAL brend), "DAL" kao stvaran naziv org-a u RBAC modelu
  (docs/loggerservice/README.md) - to je podatak, ne branding ovog servera.
- docs/asp-terminia/, docs/loggerservice/: prozni pomeni imena servera

Baza (dal_license_db -> licence_db) i deploy na 151 idu u posebnom koraku,
posle preimenovanja Gitea repoa - vidi CLAUDE.md istorijsku belesku na dnu.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 07:55:26 +02: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 != "licence_db" {
t.Errorf("DBName default: ocekivano 'licence_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
}