~bigbes/lethe

ref: 72508a536dd54662af89cce0002f6f3dee1ed0f8 lethe/internal/collector/config/config_test.go -rw-r--r-- 4.6 KiB
72508a53 — Eugene Blikh docs: refresh search and opencode plan 24 days ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
package config_test

import (
	"os"
	"path/filepath"
	"strings"
	"testing"
	"time"

	"sourcecraft.dev/bigbes/lethe/internal/collector/config"
)

const validYAML = `
host: "laptop"
server_url: "https://phoebe.tailnet.ts.net"
sources:
  - tool: "claude-code"
    path: "~/.claude/projects"
`

func writeYAML(t *testing.T, body string) string {
	t.Helper()
	dir := t.TempDir()
	path := filepath.Join(dir, "config.yaml")
	if err := os.WriteFile(path, []byte(body), 0o600); err != nil {
		t.Fatalf("write yaml: %v", err)
	}
	return path
}

func TestLoad_Valid(t *testing.T) {
	path := writeYAML(t, validYAML)
	cfg, err := config.Load(path)
	if err != nil {
		t.Fatalf("Load: %v", err)
	}
	if cfg.Host != "laptop" {
		t.Errorf("Host = %q, want laptop", cfg.Host)
	}
	if cfg.ServerURL != "https://phoebe.tailnet.ts.net" {
		t.Errorf("ServerURL = %q", cfg.ServerURL)
	}
	if len(cfg.Sources) != 1 || cfg.Sources[0].Tool != "claude-code" {
		t.Errorf("Sources = %+v", cfg.Sources)
	}
}

func TestLoad_MissingHostRejected(t *testing.T) {
	body := strings.Replace(validYAML, `host: "laptop"`, ``, 1)
	if _, err := config.Load(writeYAML(t, body)); err == nil {
		t.Fatal("expected error for missing host, got nil")
	}
}

func TestLoad_MissingServerURLRejected(t *testing.T) {
	body := strings.Replace(validYAML, `server_url: "https://phoebe.tailnet.ts.net"`, ``, 1)
	if _, err := config.Load(writeYAML(t, body)); err == nil {
		t.Fatal("expected error for missing server_url, got nil")
	}
}

func TestLoad_MissingSourcesRejected(t *testing.T) {
	body := strings.Replace(validYAML, "sources:\n  - tool: \"claude-code\"\n    path: \"~/.claude/projects\"\n", ``, 1)
	if _, err := config.Load(writeYAML(t, body)); err == nil {
		t.Fatal("expected error for missing sources, got nil")
	}
}

func TestLoad_EmptySourcesRejected(t *testing.T) {
	body := strings.Replace(validYAML, "sources:\n  - tool: \"claude-code\"\n    path: \"~/.claude/projects\"\n", "sources: []\n", 1)
	if _, err := config.Load(writeYAML(t, body)); err == nil {
		t.Fatal("expected error for empty sources, got nil")
	}
}

func TestLoad_Defaults(t *testing.T) {
	path := writeYAML(t, validYAML)
	cfg, err := config.Load(path)
	if err != nil {
		t.Fatalf("Load: %v", err)
	}
	if cfg.StateDir == "" {
		t.Error("StateDir is empty")
	}
	if cfg.HTTP.Timeout != 30*time.Second {
		t.Errorf("HTTP.Timeout = %s, want 30s", cfg.HTTP.Timeout)
	}
	if cfg.HTTP.RetryMax != 5 {
		t.Errorf("HTTP.RetryMax = %d, want 5", cfg.HTTP.RetryMax)
	}
	if cfg.Outbox.MaxBytes != 104857600 {
		t.Errorf("Outbox.MaxBytes = %d, want 104857600", cfg.Outbox.MaxBytes)
	}
	if cfg.Sources[0].PollInterval != 30*time.Second {
		t.Errorf("Sources[0].PollInterval = %s, want 30s", cfg.Sources[0].PollInterval)
	}
	if cfg.Sources[0].BatchMaxLines != 500 {
		t.Errorf("Sources[0].BatchMaxLines = %d, want 500", cfg.Sources[0].BatchMaxLines)
	}
	if cfg.Sources[0].BatchMaxBytes != 8388608 {
		t.Errorf("Sources[0].BatchMaxBytes = %d, want 8388608", cfg.Sources[0].BatchMaxBytes)
	}
	if cfg.Log.Level != "info" {
		t.Errorf("Log.Level = %q, want info", cfg.Log.Level)
	}
	if cfg.Log.Format != "human" {
		t.Errorf("Log.Format = %q, want human", cfg.Log.Format)
	}
}

func TestLoad_TildeExpansion(t *testing.T) {
	path := writeYAML(t, validYAML)
	cfg, err := config.Load(path)
	if err != nil {
		t.Fatalf("Load: %v", err)
	}
	home, _ := os.UserHomeDir()
	want := filepath.Join(home, ".claude/projects")
	if cfg.Sources[0].Path != want {
		t.Errorf("Sources[0].Path = %q, want %q", cfg.Sources[0].Path, want)
	}
	wantState := filepath.Join(home, ".local/state/lethe")
	if cfg.StateDir != wantState {
		t.Errorf("StateDir = %q, want %q", cfg.StateDir, wantState)
	}
}

func TestLoad_UnknownYAMLKeyRejected(t *testing.T) {
	body := validYAML + "totally_unknown_key: 42\n"
	if _, err := config.Load(writeYAML(t, body)); err == nil {
		t.Fatal("expected error for unknown YAML key, got nil")
	}
}

func TestLoad_InvalidServerURLRejected(t *testing.T) {
	body := strings.Replace(validYAML, `server_url: "https://phoebe.tailnet.ts.net"`, `server_url: "not a url"`, 1)
	if _, err := config.Load(writeYAML(t, body)); err == nil {
		t.Fatal("expected error for invalid server_url, got nil")
	}
}

func TestLoad_EnvOverride(t *testing.T) {
	path := writeYAML(t, validYAML)
	t.Setenv("LETHE_COLLECTOR_HOST", "desktop")
	cfg, err := config.Load(path)
	if err != nil {
		t.Fatalf("Load: %v", err)
	}
	if cfg.Host != "desktop" {
		t.Errorf("Host = %q, want desktop", cfg.Host)
	}
}

func TestMustLoad_PanicsOnError(t *testing.T) {
	defer func() {
		if r := recover(); r == nil {
			t.Fatal("expected MustLoad to panic on missing file")
		}
	}()
	config.MustLoad("/nonexistent/path/that/should/not/exist.yaml")
}