package config import ( "strings" "testing" ) const sampleLogPath = `C:\ProgramData\gpu-turnstile\gpu-turnstile.log` var allSettingNames = []string{ "LISTEN_OLLAMA", "LISTEN_COMFY", "OLLAMA_URL", "COMFY_URL", "WARM_MODEL", "UNLOAD_TIMEOUT", "JOB_TIMEOUT", "LLM_WAIT_TIMEOUT", "LLM_BUSY_MODE", "LLM_BUSY_STATUS", "BUSY_RETRY_AFTER", "LOGLEVEL", "LOG_FORMAT", "LOG_FILE", "UNLOAD_POLL_INTERVAL", "HISTORY_POLL_INTERVAL", "PROBE_TIMEOUT", "FREE_TIMEOUT", "WARM_TIMEOUT", "SHUTDOWN_TIMEOUT", "BACKOFF_INITIAL", "BACKOFF_MAX", "PROMPT_CAPTURE_LIMIT", "AUTO_UPDATE", "UPDATE_INTERVAL", "UPDATE_REPO", "UPDATE_ASSET", } func TestSampleEnv(t *testing.T) { sample := SampleEnv("v0.1.7", sampleLogPath) if !strings.HasPrefix(sample, "CFG_VER=v0.1.7\n") { t.Errorf("first line does not carry CFG_VER: %q", strings.SplitN(sample, "\n", 2)[0]) } // Every setting known to Load must appear. for _, name := range allSettingNames { if !strings.Contains(sample, name+"=") { t.Errorf("sample is missing %s", name) } } // The sample must parse cleanly; active values are CFG_VER, APP_VER // and LOG_FILE. values, err := ParseEnvFile(strings.NewReader(sample)) if err != nil { t.Fatalf("sample does not parse: %v", err) } want := map[string]string{"CFG_VER": "v0.1.7", "APP_VER": "stable", "LOG_FILE": sampleLogPath} if len(values) != len(want) { t.Fatalf("active values = %v, want %v", values, want) } for k, v := range want { if values[k] != v { t.Errorf("%s = %q, want %q", k, values[k], v) } } // Without a log path LOG_FILE stays commented out. values, err = ParseEnvFile(strings.NewReader(SampleEnv("v0.1.7", ""))) if err != nil { t.Fatalf("sample without log path does not parse: %v", err) } if len(values) != 2 || values["LOG_FILE"] != "" { t.Fatalf("active values = %v, want only CFG_VER and APP_VER", values) } } func TestSyncSample(t *testing.T) { old := SampleEnv("v0.1.6", sampleLogPath) // Simulate a setting that did not exist yet when the file was written. old = strings.Replace(old, "#UPDATE_ASSET=gpu-turnstile.exe\n", "", 1) out, changed := SyncSample(old, "v0.1.7", sampleLogPath) if !changed { t.Fatal("older installer file was not upgraded") } if !strings.Contains(out, "\nCFG_VER=v0.1.7\n") && !strings.HasPrefix(out, "CFG_VER=v0.1.7\n") { t.Error("CFG_VER was not updated to the new version") } if !strings.Contains(out, "#UPDATE_ASSET=gpu-turnstile.exe") { t.Error("missing setting was not appended") } if !strings.Contains(out, "LOG_FILE="+sampleLogPath) { t.Error("existing active LOG_FILE was lost") } if !strings.Contains(out, "Added by gpu-turnstile v0.1.7") { t.Error("appended section is not attributed") } if _, err := ParseEnvFile(strings.NewReader(out)); err != nil { t.Fatalf("upgraded file does not parse: %v", err) } // A file written by the same or a newer version is left alone. if _, changed := SyncSample(SampleEnv("v0.1.7", sampleLogPath), "v0.1.7", sampleLogPath); changed { t.Error("same-version file was modified") } if _, changed := SyncSample(SampleEnv("v0.2.0", sampleLogPath), "v0.1.7", sampleLogPath); changed { t.Error("newer-version file was modified") } // Files without CFG_VER are not installer-written; the installer // replaces them, SyncSample leaves them alone. user := "OLLAMA_URL=http://host:11434\n" if out, changed := SyncSample(user, "v0.1.7", sampleLogPath); changed || out != user { t.Error("file without CFG_VER was modified") } // A dev build never upgrades. if _, changed := SyncSample(old, "dev", sampleLogPath); changed { t.Error("dev build modified the file") } } func TestSyncSampleAppendsMissingAppVer(t *testing.T) { old := SampleEnv("v0.1.6", sampleLogPath) old = strings.Replace(old, "# "+appVerComment+"\n", "", 1) old = strings.Replace(old, "APP_VER=stable\n", "", 1) out, changed := SyncSample(old, "v0.1.7", sampleLogPath) if !changed { t.Fatal("file without APP_VER was not upgraded") } values, err := ParseEnvFile(strings.NewReader(out)) if err != nil { t.Fatalf("upgraded file does not parse: %v", err) } if values["APP_VER"] != "stable" { t.Fatalf("APP_VER = %q, want appended default \"stable\"", values["APP_VER"]) } } func TestCompareVersions(t *testing.T) { cases := []struct { a, b string want int }{ {"v0.1.6", "v0.1.7", -1}, {"v0.1.7", "v0.1.7", 0}, {"v1.0.0", "v0.9.9", 1}, {"0.1.7", "v0.1.6", 1}, {"dev", "v0.1.7", -1}, {"v0.1.7", "dev", 1}, {"dev", "dev", 0}, } for _, c := range cases { if got := compareVersions(c.a, c.b); got != c.want { t.Errorf("compareVersions(%q, %q) = %d, want %d", c.a, c.b, got, c.want) } } }