Skip to content

Commit 8585a31

Browse files
julianknutsenclaude
andcommitted
Inject WLCommonsStore via factory and add handler-level tests
Centralize store creation through an openStore factory variable, replacing direct commons.NewWLCommons() calls in all 9 mutation/query handlers. This makes handlers unit-testable without a real dolt database. Add handler-level tests for runConfigGet, runConfigSet, runStatus, runPost, runClaim, runDelete, and runUnclaim using store factory override with fakeWLCommonsStore. Also make the live DoltHub integration test skip gracefully when network is unavailable. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 9d53c5c commit 8585a31

13 files changed

Lines changed: 462 additions & 11 deletions

cmd/wl/cmd_accept.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ func runAccept(cmd *cobra.Command, stdout, _ io.Writer, wantedID string, quality
8686
}
8787
defer cleanup()
8888

89-
store := commons.NewWLCommons(wlCfg.LocalDir)
89+
store := openStore(wlCfg.LocalDir)
9090

9191
stamp, err := acceptCompletion(store, wantedID, rigHandle, quality, reliability, severity, skillTags, message)
9292
if err != nil {

cmd/wl/cmd_claim.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ func runClaim(cmd *cobra.Command, stdout, _ io.Writer, wantedID string, noPush b
5151
}
5252
defer cleanup()
5353

54-
store := commons.NewWLCommons(wlCfg.LocalDir)
54+
store := openStore(wlCfg.LocalDir)
5555
item, err := claimWanted(store, wantedID, rigHandle)
5656
if err != nil {
5757
return err

cmd/wl/cmd_config_test.go

Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
package main
22

33
import (
4+
"bytes"
5+
"strings"
46
"testing"
7+
"time"
58

9+
"github.com/spf13/cobra"
610
"github.com/steveyegge/wasteland/internal/federation"
711
)
812

@@ -58,3 +62,243 @@ func TestValidConfigKeys_ProviderType(t *testing.T) {
5862
t.Error("expected 'provider-type' to be a valid config key")
5963
}
6064
}
65+
66+
// --- Handler-level tests for runConfigGet / runConfigSet ---
67+
68+
func saveTestConfig(t *testing.T, cfg *federation.Config) {
69+
t.Helper()
70+
store := federation.NewConfigStore()
71+
if err := store.Save(cfg); err != nil {
72+
t.Fatalf("saving test config: %v", err)
73+
}
74+
}
75+
76+
func configCmd() *cobra.Command {
77+
cmd := &cobra.Command{}
78+
cmd.Flags().String("wasteland", "", "")
79+
return cmd
80+
}
81+
82+
func TestRunConfigGet_Mode(t *testing.T) {
83+
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
84+
saveTestConfig(t, &federation.Config{
85+
Upstream: "hop/wl-commons", ForkOrg: "alice", ForkDB: "wl-commons",
86+
Mode: "pr", JoinedAt: time.Now(),
87+
})
88+
89+
var stdout, stderr bytes.Buffer
90+
err := runConfigGet(configCmd(), &stdout, &stderr, "mode")
91+
if err != nil {
92+
t.Fatalf("runConfigGet(mode) error: %v", err)
93+
}
94+
if got := strings.TrimSpace(stdout.String()); got != "pr" {
95+
t.Errorf("runConfigGet(mode) = %q, want %q", got, "pr")
96+
}
97+
}
98+
99+
func TestRunConfigGet_ModeDefault(t *testing.T) {
100+
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
101+
saveTestConfig(t, &federation.Config{
102+
Upstream: "hop/wl-commons", ForkOrg: "alice", ForkDB: "wl-commons",
103+
JoinedAt: time.Now(),
104+
})
105+
106+
var stdout, stderr bytes.Buffer
107+
err := runConfigGet(configCmd(), &stdout, &stderr, "mode")
108+
if err != nil {
109+
t.Fatalf("runConfigGet(mode) error: %v", err)
110+
}
111+
if got := strings.TrimSpace(stdout.String()); got != "wild-west" {
112+
t.Errorf("runConfigGet(mode default) = %q, want %q", got, "wild-west")
113+
}
114+
}
115+
116+
func TestRunConfigGet_ProviderType(t *testing.T) {
117+
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
118+
saveTestConfig(t, &federation.Config{
119+
Upstream: "hop/wl-commons", ForkOrg: "alice", ForkDB: "wl-commons",
120+
ProviderType: "github", JoinedAt: time.Now(),
121+
})
122+
123+
var stdout, stderr bytes.Buffer
124+
err := runConfigGet(configCmd(), &stdout, &stderr, "provider-type")
125+
if err != nil {
126+
t.Fatalf("runConfigGet(provider-type) error: %v", err)
127+
}
128+
if got := strings.TrimSpace(stdout.String()); got != "github" {
129+
t.Errorf("runConfigGet(provider-type) = %q, want %q", got, "github")
130+
}
131+
}
132+
133+
func TestRunConfigGet_ProviderTypeDefault(t *testing.T) {
134+
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
135+
saveTestConfig(t, &federation.Config{
136+
Upstream: "hop/wl-commons", ForkOrg: "alice", ForkDB: "wl-commons",
137+
JoinedAt: time.Now(),
138+
})
139+
140+
var stdout, stderr bytes.Buffer
141+
err := runConfigGet(configCmd(), &stdout, &stderr, "provider-type")
142+
if err != nil {
143+
t.Fatalf("runConfigGet(provider-type) error: %v", err)
144+
}
145+
if got := strings.TrimSpace(stdout.String()); got != "dolthub" {
146+
t.Errorf("runConfigGet(provider-type default) = %q, want %q", got, "dolthub")
147+
}
148+
}
149+
150+
func TestRunConfigGet_GitHubRepo(t *testing.T) {
151+
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
152+
saveTestConfig(t, &federation.Config{
153+
Upstream: "hop/wl-commons", ForkOrg: "alice", ForkDB: "wl-commons",
154+
GitHubRepo: "steveyegge/wl-commons", JoinedAt: time.Now(),
155+
})
156+
157+
var stdout, stderr bytes.Buffer
158+
err := runConfigGet(configCmd(), &stdout, &stderr, "github-repo")
159+
if err != nil {
160+
t.Fatalf("runConfigGet(github-repo) error: %v", err)
161+
}
162+
if got := strings.TrimSpace(stdout.String()); got != "steveyegge/wl-commons" {
163+
t.Errorf("runConfigGet(github-repo) = %q, want %q", got, "steveyegge/wl-commons")
164+
}
165+
}
166+
167+
func TestRunConfigGet_UnknownKey(t *testing.T) {
168+
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
169+
saveTestConfig(t, &federation.Config{
170+
Upstream: "hop/wl-commons", ForkOrg: "alice", ForkDB: "wl-commons",
171+
JoinedAt: time.Now(),
172+
})
173+
174+
var stdout, stderr bytes.Buffer
175+
err := runConfigGet(configCmd(), &stdout, &stderr, "nonexistent")
176+
if err == nil {
177+
t.Fatal("runConfigGet(nonexistent) expected error")
178+
}
179+
if !strings.Contains(err.Error(), "unknown config key") {
180+
t.Errorf("error = %q, want to contain 'unknown config key'", err.Error())
181+
}
182+
}
183+
184+
func TestRunConfigGet_NotJoined(t *testing.T) {
185+
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
186+
187+
var stdout, stderr bytes.Buffer
188+
err := runConfigGet(configCmd(), &stdout, &stderr, "mode")
189+
if err == nil {
190+
t.Fatal("runConfigGet when not joined expected error")
191+
}
192+
}
193+
194+
func TestRunConfigSet_Mode(t *testing.T) {
195+
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
196+
saveTestConfig(t, &federation.Config{
197+
Upstream: "hop/wl-commons", ForkOrg: "alice", ForkDB: "wl-commons",
198+
JoinedAt: time.Now(),
199+
})
200+
201+
var stdout, stderr bytes.Buffer
202+
err := runConfigSet(configCmd(), &stdout, &stderr, "mode", "pr")
203+
if err != nil {
204+
t.Fatalf("runConfigSet(mode, pr) error: %v", err)
205+
}
206+
if !strings.Contains(stdout.String(), "mode = pr") {
207+
t.Errorf("output = %q, want to contain 'mode = pr'", stdout.String())
208+
}
209+
210+
// Verify the mode persists.
211+
store := federation.NewConfigStore()
212+
loaded, err := store.Load("hop/wl-commons")
213+
if err != nil {
214+
t.Fatalf("loading config after set: %v", err)
215+
}
216+
if loaded.Mode != "pr" {
217+
t.Errorf("saved Mode = %q, want %q", loaded.Mode, "pr")
218+
}
219+
}
220+
221+
func TestRunConfigSet_ModeInvalid(t *testing.T) {
222+
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
223+
saveTestConfig(t, &federation.Config{
224+
Upstream: "hop/wl-commons", ForkOrg: "alice", ForkDB: "wl-commons",
225+
JoinedAt: time.Now(),
226+
})
227+
228+
var stdout, stderr bytes.Buffer
229+
err := runConfigSet(configCmd(), &stdout, &stderr, "mode", "chaos")
230+
if err == nil {
231+
t.Fatal("runConfigSet(mode, chaos) expected error")
232+
}
233+
if !strings.Contains(err.Error(), "invalid mode") {
234+
t.Errorf("error = %q, want to contain 'invalid mode'", err.Error())
235+
}
236+
}
237+
238+
func TestRunConfigSet_ProviderTypeReadOnly(t *testing.T) {
239+
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
240+
saveTestConfig(t, &federation.Config{
241+
Upstream: "hop/wl-commons", ForkOrg: "alice", ForkDB: "wl-commons",
242+
JoinedAt: time.Now(),
243+
})
244+
245+
var stdout, stderr bytes.Buffer
246+
err := runConfigSet(configCmd(), &stdout, &stderr, "provider-type", "github")
247+
if err == nil {
248+
t.Fatal("runConfigSet(provider-type) expected error (read-only)")
249+
}
250+
if !strings.Contains(err.Error(), "read-only") {
251+
t.Errorf("error = %q, want to contain 'read-only'", err.Error())
252+
}
253+
}
254+
255+
func TestRunConfigSet_GitHubRepo(t *testing.T) {
256+
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
257+
saveTestConfig(t, &federation.Config{
258+
Upstream: "hop/wl-commons", ForkOrg: "alice", ForkDB: "wl-commons",
259+
JoinedAt: time.Now(),
260+
})
261+
262+
var stdout, stderr bytes.Buffer
263+
err := runConfigSet(configCmd(), &stdout, &stderr, "github-repo", "org/repo")
264+
if err != nil {
265+
t.Fatalf("runConfigSet(github-repo) error: %v", err)
266+
}
267+
268+
store := federation.NewConfigStore()
269+
loaded, err := store.Load("hop/wl-commons")
270+
if err != nil {
271+
t.Fatalf("loading config after set: %v", err)
272+
}
273+
if loaded.GitHubRepo != "org/repo" { //nolint:staticcheck // backward compat
274+
t.Errorf("saved GitHubRepo = %q, want %q", loaded.GitHubRepo, "org/repo") //nolint:staticcheck // backward compat
275+
}
276+
}
277+
278+
func TestRunConfigSet_GitHubRepoInvalid(t *testing.T) {
279+
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
280+
saveTestConfig(t, &federation.Config{
281+
Upstream: "hop/wl-commons", ForkOrg: "alice", ForkDB: "wl-commons",
282+
JoinedAt: time.Now(),
283+
})
284+
285+
var stdout, stderr bytes.Buffer
286+
err := runConfigSet(configCmd(), &stdout, &stderr, "github-repo", "noslash")
287+
if err == nil {
288+
t.Fatal("runConfigSet(github-repo, noslash) expected error")
289+
}
290+
if !strings.Contains(err.Error(), "invalid github-repo") {
291+
t.Errorf("error = %q, want to contain 'invalid github-repo'", err.Error())
292+
}
293+
}
294+
295+
func TestRunConfigSet_UnknownKey(t *testing.T) {
296+
var stdout, stderr bytes.Buffer
297+
err := runConfigSet(configCmd(), &stdout, &stderr, "bogus", "value")
298+
if err == nil {
299+
t.Fatal("runConfigSet(bogus) expected error")
300+
}
301+
if !strings.Contains(err.Error(), "unknown config key") {
302+
t.Errorf("error = %q, want to contain 'unknown config key'", err.Error())
303+
}
304+
}

cmd/wl/cmd_delete.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func runDelete(cmd *cobra.Command, stdout, _ io.Writer, wantedID string, noPush
5252
}
5353
defer cleanup()
5454

55-
store := commons.NewWLCommons(wlCfg.LocalDir)
55+
store := openStore(wlCfg.LocalDir)
5656

5757
if err := deleteWanted(store, wantedID); err != nil {
5858
return err

cmd/wl/cmd_done.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ func runDone(cmd *cobra.Command, stdout, _ io.Writer, wantedID, evidence string,
6262
}
6363
defer cleanup()
6464

65-
store := commons.NewWLCommons(wlCfg.LocalDir)
65+
store := openStore(wlCfg.LocalDir)
6666
completionID := commons.GeneratePrefixedID("c", wantedID, rigHandle)
6767

6868
if err := submitDone(store, wantedID, rigHandle, evidence, completionID); err != nil {

cmd/wl/cmd_post.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ func runPost(cmd *cobra.Command, stdout, _ io.Writer, title, description, projec
9696
}
9797
defer cleanup()
9898

99-
store := commons.NewWLCommons(wlCfg.LocalDir)
99+
store := openStore(wlCfg.LocalDir)
100100

101101
if err := postWanted(store, item); err != nil {
102102
return err

cmd/wl/cmd_reject.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ func runReject(cmd *cobra.Command, stdout, _ io.Writer, wantedID, reason string,
5555
}
5656
defer cleanup()
5757

58-
store := commons.NewWLCommons(wlCfg.LocalDir)
58+
store := openStore(wlCfg.LocalDir)
5959

6060
if err := rejectCompletion(store, wantedID, rigHandle, reason); err != nil {
6161
return err

cmd/wl/cmd_status.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func runStatus(cmd *cobra.Command, stdout, _ io.Writer, wantedID string) error {
3434
return fmt.Errorf("loading wasteland config: %w", err)
3535
}
3636

37-
store := commons.NewWLCommons(wlCfg.LocalDir)
37+
store := openStore(wlCfg.LocalDir)
3838

3939
result, err := getStatus(store, wantedID)
4040
if err != nil {

cmd/wl/cmd_unclaim.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ func runUnclaim(cmd *cobra.Command, stdout, _ io.Writer, wantedID string, noPush
5050
}
5151
defer cleanup()
5252

53-
store := commons.NewWLCommons(wlCfg.LocalDir)
53+
store := openStore(wlCfg.LocalDir)
5454
item, err := unclaimWanted(store, wantedID, rigHandle)
5555
if err != nil {
5656
return err

cmd/wl/cmd_update.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ func runUpdate(cmd *cobra.Command, stdout, _ io.Writer, wantedID, title, descrip
9999
}
100100
defer cleanup()
101101

102-
store := commons.NewWLCommons(wlCfg.LocalDir)
102+
store := openStore(wlCfg.LocalDir)
103103

104104
if err := updateWanted(store, wantedID, fields); err != nil {
105105
return err

0 commit comments

Comments
 (0)