Skip to content

Commit bdbe8c4

Browse files
committed
fix(ci): resolve 3 remaining scheduler/dolt test failures
Fix #1 — TestBuildDoltSQLCmd_LocalIgnoresInheritedCredentials buildDoltSQLCmd was appending "DOLT_CLI_PASSWORD=" onto os.Environ(), leaving an inherited shell value already in the slice. Strip the key from os.Environ() first via a new filterEnvKey helper so the single canonical entry we append is the only one in cmd.Env. Fix #2 — TestSchedulerAutoConvoyCreation Two bugs: - Test setup didn't register the literal "hq-cv-" route, so bd show from hq couldn't resolve convoy IDs. Add the route in setupSchedulerIntegrationTown and setupMultiRigSchedulerTown, matching what gt install does. - Test passed --allow-stale as a subcommand flag; it's a global flag. Use beads.MaybePrependAllowStale so it lands before the subcommand. Fix #3 — TestSchedulerSlingContextIdempotency listAllSlingContexts iterated every dir from beadsSearchDirs without deduping. In the test fixture, testrig/.beads is a redirect file pointing to testrig/mayor/rig/.beads, so both paths yielded the same underlying beads DB and the same context was counted twice. Dedupe by context ID so redirects (and any future aliasing) can't inflate counts.
1 parent 098b505 commit bdbe8c4

3 files changed

Lines changed: 44 additions & 9 deletions

File tree

internal/cmd/capacity_dispatch.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -489,15 +489,26 @@ func recordDispatchFailure(townBeads *beads.Beads, b capacity.PendingBead, dispa
489489
// (GH#3468), so we scan HQ plus all rig dirs.
490490
// Used by scheduler list/status/clear, cleanupStaleContexts, and areScheduled.
491491
// Does NOT filter by readiness or circuit breaker.
492+
//
493+
// Deduplicates by context ID: different search dirs can resolve to the same
494+
// underlying beads DB (e.g., when a rig's top-level .beads is a redirect to
495+
// mayor/rig/.beads), and both paths would otherwise return the same contexts.
492496
func listAllSlingContexts(townRoot string) []*beads.Issue {
493497
var all []*beads.Issue
498+
seen := make(map[string]bool)
494499
for _, dir := range beadsSearchDirs(townRoot) {
495500
b := beads.NewWithBeadsDir(dir, beads.ResolveBeadsDir(dir))
496501
contexts, err := b.ListOpenSlingContexts()
497502
if err != nil {
498503
continue // Partial failure is acceptable — skip unavailable dirs
499504
}
500-
all = append(all, contexts...)
505+
for _, ctx := range contexts {
506+
if seen[ctx.ID] {
507+
continue
508+
}
509+
seen[ctx.ID] = true
510+
all = append(all, ctx)
511+
}
501512
}
502513
return all
503514
}

internal/cmd/scheduler_integration_test.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,10 @@ func setupSchedulerIntegrationTown(t *testing.T) (hqPath, rigPath, gtBinary stri
140140
routes := []beads.Route{
141141
{Prefix: hqPrefix + "-", Path: "."},
142142
{Prefix: rigPrefix + "-", Path: "testrig/mayor/rig"},
143+
// Convoy beads use a literal "hq-cv-" prefix (see install.go — registered
144+
// on real towns during `gt install`). Route them to HQ so tests that
145+
// look up auto-convoys via `bd show` resolve correctly.
146+
{Prefix: "hq-cv-", Path: "."},
143147
}
144148
if err := beads.WriteRoutes(townBeadsDir, routes); err != nil {
145149
t.Fatalf("write routes: %v", err)
@@ -298,12 +302,14 @@ func TestSchedulerAutoConvoyCreation(t *testing.T) {
298302
t.Fatalf("convoy ID not stored in sling context")
299303
}
300304

301-
// Verify: convoy is resolvable via bd show from hq
302-
cmd := exec.Command("bd", "show", fields.Convoy, "--json", "--allow-stale")
305+
// Verify: convoy is resolvable via bd show from hq.
306+
// --allow-stale is a global flag: must come before the subcommand.
307+
showArgs := beads.MaybePrependAllowStale([]string{"show", fields.Convoy, "--json"})
308+
cmd := exec.Command("bd", showArgs...)
303309
cmd.Dir = hqPath
304-
out, err := cmd.Output()
310+
out, err := cmd.CombinedOutput()
305311
if err != nil {
306-
t.Fatalf("bd show convoy %s failed: %v", fields.Convoy, err)
312+
t.Fatalf("bd show convoy %s failed: %v\noutput: %s", fields.Convoy, err, out)
307313
}
308314
var convoys []struct {
309315
ID string `json:"id"`
@@ -579,6 +585,8 @@ func setupMultiRigSchedulerTown(t *testing.T) (hqPath, rig1Path, rig2Path, gtBin
579585
{Prefix: hqPrefix + "-", Path: "."},
580586
{Prefix: rig1Prefix + "-", Path: "rig1/mayor/rig"},
581587
{Prefix: rig2Prefix + "-", Path: "rig2/mayor/rig"},
588+
// Convoy beads use a literal "hq-cv-" prefix (see install.go).
589+
{Prefix: "hq-cv-", Path: "."},
582590
}
583591
if err := beads.WriteRoutes(townBeadsDir, routes); err != nil {
584592
t.Fatalf("write routes: %v", err)

internal/daemon/dolt.go

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -274,21 +274,37 @@ func (m *DoltServerManager) buildDoltSQLCmd(ctx context.Context, args ...string)
274274
// For remote checks, preserve inherited credentials if config omits a
275275
// password. For local checks, keep forcing the empty-password path so
276276
// inherited shell credentials cannot make a healthy local server look broken.
277+
// Strip any inherited DOLT_CLI_PASSWORD from os.Environ() first so the
278+
// single canonical value we append wins unambiguously — duplicate keys in
279+
// cmd.Env leak credentials into local checks (tests grep cmd.Env directly).
280+
env := filterEnvKey(os.Environ(), "DOLT_CLI_PASSWORD")
277281
if m.config.Password != "" {
278-
cmd.Env = append(os.Environ(), "DOLT_CLI_PASSWORD="+m.config.Password)
282+
cmd.Env = append(env, "DOLT_CLI_PASSWORD="+m.config.Password)
279283
} else if m.isRemote() {
280284
if inherited, ok := os.LookupEnv("DOLT_CLI_PASSWORD"); ok {
281-
cmd.Env = append(os.Environ(), "DOLT_CLI_PASSWORD="+inherited)
285+
cmd.Env = append(env, "DOLT_CLI_PASSWORD="+inherited)
282286
} else {
283-
cmd.Env = append(os.Environ(), "DOLT_CLI_PASSWORD=")
287+
cmd.Env = append(env, "DOLT_CLI_PASSWORD=")
284288
}
285289
} else {
286-
cmd.Env = append(os.Environ(), "DOLT_CLI_PASSWORD=")
290+
cmd.Env = append(env, "DOLT_CLI_PASSWORD=")
287291
}
288292

289293
return cmd
290294
}
291295

296+
// filterEnvKey returns env with all entries matching "<key>=..." removed.
297+
func filterEnvKey(env []string, key string) []string {
298+
prefix := key + "="
299+
out := make([]string, 0, len(env))
300+
for _, e := range env {
301+
if !strings.HasPrefix(e, prefix) {
302+
out = append(out, e)
303+
}
304+
}
305+
return out
306+
}
307+
292308
// HealthCheckInterval returns the configured health check interval,
293309
// falling back to DefaultDoltHealthCheckInterval if not explicitly set.
294310
func (m *DoltServerManager) HealthCheckInterval() time.Duration {

0 commit comments

Comments
 (0)