package main import ( "bytes" "context" "os" "path/filepath" "strings" "testing" "time" "git.asio.asia/nixevol/NixMsg/internal/store" ) func TestCheckConfigRejectsLargeBody(t *testing.T) { dir := t.TempDir() path := filepath.Join(dir, "bad.yaml") body := "listen: \":0\"\ndata_dir: \"" + filepath.ToSlash(dir) + "\"\nlimits:\n max_body_bytes: 262145\n" if err := os.WriteFile(path, []byte(body), 0o644); err != nil { t.Fatal(err) } t.Setenv("NIXMSG_CONFIG", path) err := cmdCheckConfig(nil) if err == nil || !strings.Contains(err.Error(), "max_body_bytes") { t.Fatalf("want max_body_bytes error, got %v", err) } } func TestCheckConfigOK(t *testing.T) { dir := t.TempDir() path := writeTestConfig(t, dir) t.Setenv("NIXMSG_CONFIG", path) if err := cmdCheckConfig(nil); err != nil { t.Fatal(err) } } func TestAdminInitOnceAndSetPassword(t *testing.T) { dir := t.TempDir() path := writeTestConfig(t, dir) t.Setenv("NIXMSG_CONFIG", path) var out bytes.Buffer old := os.Stdout r, w, err := os.Pipe() if err != nil { t.Fatal(err) } os.Stdout = w errInit := cmdAdminInit(nil) _ = w.Close() os.Stdout = old _, _ = out.ReadFrom(r) _ = r.Close() if errInit != nil { t.Fatal(errInit) } text := out.String() if !strings.Contains(text, "admin password:") { t.Fatalf("password not printed: %q", text) } pass := strings.TrimSpace(strings.TrimPrefix(strings.TrimSpace(text), "admin password:")) if len(pass) != 20 { t.Fatalf("password len=%d value=%q", len(pass), pass) } if err2 := cmdAdminInit(nil); err2 == nil || !strings.Contains(err2.Error(), "already initialized") { t.Fatalf("want already initialized, got %v", err2) } if err2 := cmdAdminSetPassword([]string{"--password", "short"}); err2 == nil { t.Fatal("expected short password error") } if err2 := cmdAdminSetPassword([]string{"--password", "long-enough-password"}); err2 != nil { t.Fatal(err2) } db, openErr := store.Open(dir, "FULL") if openErr != nil { t.Fatal(openErr) } defer func() { _ = db.Close() }() ok, hasErr := store.HasAdminPassword(context.Background(), db.Write) if hasErr != nil || !ok { t.Fatalf("has admin: ok=%v err=%v", ok, hasErr) } } func TestBackupVacuumInto(t *testing.T) { dir := t.TempDir() path := writeTestConfig(t, dir) t.Setenv("NIXMSG_CONFIG", path) initAdminForTest(t, dir) out := filepath.Join(dir, "backup", "copy.db") if err := os.MkdirAll(filepath.Dir(out), 0o755); err != nil { t.Fatal(err) } if err := cmdBackup([]string{"--out", out}); err != nil { t.Fatal(err) } st, err := os.Stat(out) if err != nil { t.Fatal(err) } if st.Size() == 0 { t.Fatal("backup empty") } } func TestHealthcheck(t *testing.T) { dir := t.TempDir() cfgPath := writeTestConfig(t, dir) initAdminForTest(t, dir) t.Setenv("NIXMSG_CONFIG", cfgPath) cfg, err := loadAndValidateConfig() if err != nil { t.Fatal(err) } ctx, cancel := context.WithCancel(context.Background()) defer cancel() errCh := make(chan error, 1) go func() { errCh <- runServe(ctx, cfg) }() deadline := time.Now().Add(10 * time.Second) for time.Now().Before(deadline) { if b, readErr := os.ReadFile(filepath.Join(dir, "listen.addr")); readErr == nil && strings.TrimSpace(string(b)) != "" { break } time.Sleep(20 * time.Millisecond) } if err := cmdHealthcheck(nil); err != nil { cancel() <-errCh t.Fatal(err) } cancel() <-errCh } func TestParseSetPasswordArgs(t *testing.T) { t.Parallel() pass, err := parseSetPasswordArgs([]string{"--password", "abcdefghijkl"}, nil) if err != nil || pass != "abcdefghijkl" { t.Fatalf("pass=%q err=%v", pass, err) } pass, err = parseSetPasswordArgs([]string{"twelvechars!!"}, nil) if err != nil || pass != "twelvechars!!" { t.Fatalf("pass=%q err=%v", pass, err) } }