-
Notifications
You must be signed in to change notification settings - Fork 1.4k
fix(embeddeddolt): /cmd/bd: tests for additional commands #2842
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 2 commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
bc143e7
/cmd/bd: tests for additional commands
coffeegoddd 3311660
/.github: more shards
coffeegoddd 74e6ac7
/{cmd,.github}: fix tests and share go mod cache
coffeegoddd 7e41ced
/.github/{scripts,workflows}: precompile test binary
coffeegoddd cbdc513
/.github/workflows/ci.yml: fix race test
coffeegoddd c5d2ae1
/.github/workflows/ci.yml: fix storage CI tests
coffeegoddd File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,124 @@ | ||
| //go:build embeddeddolt | ||
|
|
||
| package main | ||
|
|
||
| import ( | ||
| "encoding/json" | ||
| "fmt" | ||
| "os" | ||
| "os/exec" | ||
| "strings" | ||
| "sync" | ||
| "testing" | ||
| ) | ||
|
|
||
| func TestEmbeddedBlocked(t *testing.T) { | ||
| if os.Getenv("BEADS_TEST_EMBEDDED_DOLT") != "1" { | ||
| t.Skip("set BEADS_TEST_EMBEDDED_DOLT=1 to run embedded dolt integration tests") | ||
| } | ||
| t.Parallel() | ||
|
|
||
| bd := buildEmbeddedBD(t) | ||
| dir, _, _ := bdInit(t, bd, "--prefix", "bl") | ||
|
|
||
| // ===== Default Empty ===== | ||
|
|
||
| t.Run("blocked_default_empty", func(t *testing.T) { | ||
| cmd := exec.Command(bd, "blocked") | ||
| cmd.Dir = dir | ||
| cmd.Env = bdEnv(dir) | ||
| out, err := cmd.CombinedOutput() | ||
| if err != nil { | ||
| t.Fatalf("bd blocked failed: %v\n%s", err, out) | ||
| } | ||
| // No blocked issues on fresh db | ||
| _ = out | ||
| }) | ||
|
|
||
| // ===== With Blocked Issue ===== | ||
|
|
||
| t.Run("blocked_with_issue", func(t *testing.T) { | ||
| blocker := bdCreate(t, bd, dir, "Blocker for blocked test", "--type", "task") | ||
| blocked := bdCreate(t, bd, dir, "I am blocked", "--type", "task") | ||
|
|
||
| // blocked depends on blocker (blocker blocks blocked) | ||
| cmd := exec.Command(bd, "dep", "add", blocked.ID, blocker.ID) | ||
| cmd.Dir = dir | ||
| cmd.Env = bdEnv(dir) | ||
| if out, err := cmd.CombinedOutput(); err != nil { | ||
| t.Fatalf("dep add failed: %v\n%s", err, out) | ||
| } | ||
|
|
||
| cmd = exec.Command(bd, "blocked") | ||
| cmd.Dir = dir | ||
| cmd.Env = bdEnv(dir) | ||
| out, err := cmd.CombinedOutput() | ||
| if err != nil { | ||
| t.Fatalf("bd blocked failed: %v\n%s", err, out) | ||
| } | ||
| if !strings.Contains(string(out), blocked.ID) { | ||
| t.Errorf("expected %s in blocked output: %s", blocked.ID, out) | ||
| } | ||
| }) | ||
|
|
||
| // ===== --json ===== | ||
|
|
||
| t.Run("blocked_json", func(t *testing.T) { | ||
| cmd := exec.Command(bd, "blocked", "--json") | ||
| cmd.Dir = dir | ||
| cmd.Env = bdEnv(dir) | ||
| out, err := cmd.CombinedOutput() | ||
| if err != nil { | ||
| t.Fatalf("bd blocked --json failed: %v\n%s", err, out) | ||
| } | ||
| s := strings.TrimSpace(string(out)) | ||
| start := strings.IndexAny(s, "[{") | ||
| if start >= 0 { | ||
| if !json.Valid([]byte(s[start:])) { | ||
| t.Errorf("invalid JSON in blocked output: %s", s[:min(200, len(s))]) | ||
| } | ||
| } | ||
| }) | ||
| } | ||
|
|
||
| func TestEmbeddedBlockedConcurrent(t *testing.T) { | ||
| if os.Getenv("BEADS_TEST_EMBEDDED_DOLT") != "1" { | ||
| t.Skip("set BEADS_TEST_EMBEDDED_DOLT=1 to run embedded dolt integration tests") | ||
| } | ||
| t.Parallel() | ||
|
|
||
| bd := buildEmbeddedBD(t) | ||
| dir, _, _ := bdInit(t, bd, "--prefix", "bx") | ||
|
|
||
| bdCreate(t, bd, dir, "Blocked concurrent issue", "--type", "task") | ||
|
|
||
| const numWorkers = 8 | ||
| type workerResult struct { | ||
| worker int | ||
| err error | ||
| } | ||
| results := make([]workerResult, numWorkers) | ||
| var wg sync.WaitGroup | ||
| wg.Add(numWorkers) | ||
|
|
||
| for w := 0; w < numWorkers; w++ { | ||
| go func(worker int) { | ||
| defer wg.Done() | ||
| r := workerResult{worker: worker} | ||
| cmd := exec.Command(bd, "blocked") | ||
| cmd.Dir = dir | ||
| cmd.Env = bdEnv(dir) | ||
| out, err := cmd.CombinedOutput() | ||
| if err != nil { | ||
| r.err = fmt.Errorf("blocked (worker %d): %v\n%s", worker, err, out) | ||
| } | ||
| results[worker] = r | ||
| }(w) | ||
| } | ||
| wg.Wait() | ||
| for _, r := range results { | ||
| if r.err != nil { | ||
| t.Errorf("worker %d failed: %v", r.worker, r.err) | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,202 @@ | ||
| //go:build embeddeddolt | ||
|
|
||
| package main | ||
|
|
||
| import ( | ||
| "encoding/json" | ||
| "fmt" | ||
| "os" | ||
| "os/exec" | ||
| "strings" | ||
| "sync" | ||
| "testing" | ||
| ) | ||
|
|
||
| // bdDefer runs "bd defer" with the given args and returns stdout. | ||
| func bdDefer(t *testing.T, bd, dir string, args ...string) string { | ||
| t.Helper() | ||
| fullArgs := append([]string{"defer"}, args...) | ||
| cmd := exec.Command(bd, fullArgs...) | ||
| cmd.Dir = dir | ||
| cmd.Env = bdEnv(dir) | ||
| out, err := cmd.CombinedOutput() | ||
| if err != nil { | ||
| t.Fatalf("bd defer %s failed: %v\n%s", strings.Join(args, " "), err, out) | ||
| } | ||
| return string(out) | ||
| } | ||
|
|
||
| // bdUndefer runs "bd undefer" with the given args and returns stdout. | ||
| func bdUndefer(t *testing.T, bd, dir string, args ...string) string { | ||
| t.Helper() | ||
| fullArgs := append([]string{"undefer"}, args...) | ||
| cmd := exec.Command(bd, fullArgs...) | ||
| cmd.Dir = dir | ||
| cmd.Env = bdEnv(dir) | ||
| out, err := cmd.CombinedOutput() | ||
| if err != nil { | ||
| t.Fatalf("bd undefer %s failed: %v\n%s", strings.Join(args, " "), err, out) | ||
| } | ||
| return string(out) | ||
| } | ||
|
|
||
| // getIssueStatus returns the status of an issue via bd show --json. | ||
| func getIssueStatus(t *testing.T, bd, dir, id string) string { | ||
| t.Helper() | ||
| cmd := exec.Command(bd, "show", id, "--json") | ||
| cmd.Dir = dir | ||
| cmd.Env = bdEnv(dir) | ||
| out, err := cmd.CombinedOutput() | ||
| if err != nil { | ||
| t.Fatalf("bd show %s --json failed: %v\n%s", id, err, out) | ||
| } | ||
| s := strings.TrimSpace(string(out)) | ||
| // show --json may return an array or object | ||
| start := strings.IndexAny(s, "[{") | ||
| if start < 0 { | ||
| t.Fatalf("no JSON in show output: %s", s) | ||
| } | ||
| if s[start] == '[' { | ||
| var arr []map[string]interface{} | ||
| if err := json.Unmarshal([]byte(s[start:]), &arr); err != nil { | ||
| t.Fatalf("parse show JSON array: %v\n%s", err, s) | ||
| } | ||
| if len(arr) == 0 { | ||
| t.Fatalf("empty JSON array in show output") | ||
| } | ||
| status, _ := arr[0]["status"].(string) | ||
| return status | ||
| } | ||
| var m map[string]interface{} | ||
| if err := json.Unmarshal([]byte(s[start:]), &m); err != nil { | ||
| t.Fatalf("parse show JSON: %v\n%s", err, s) | ||
| } | ||
| status, _ := m["status"].(string) | ||
| return status | ||
| } | ||
|
|
||
| func TestEmbeddedDefer(t *testing.T) { | ||
| if os.Getenv("BEADS_TEST_EMBEDDED_DOLT") != "1" { | ||
| t.Skip("set BEADS_TEST_EMBEDDED_DOLT=1 to run embedded dolt integration tests") | ||
| } | ||
| t.Parallel() | ||
|
|
||
| bd := buildEmbeddedBD(t) | ||
| dir, _, _ := bdInit(t, bd, "--prefix", "df") | ||
|
|
||
| // ===== Single Issue ===== | ||
|
|
||
| t.Run("defer_single", func(t *testing.T) { | ||
| issue := bdCreate(t, bd, dir, "Defer single test", "--type", "task") | ||
| out := bdDefer(t, bd, dir, issue.ID) | ||
| if !strings.Contains(out, "Deferred") { | ||
| t.Errorf("expected 'Deferred' in output: %s", out) | ||
| } | ||
| status := getIssueStatus(t, bd, dir, issue.ID) | ||
| if status != "deferred" { | ||
| t.Errorf("expected status=deferred, got %q", status) | ||
| } | ||
| }) | ||
|
|
||
| // ===== Multiple Issues ===== | ||
|
|
||
| t.Run("defer_multiple", func(t *testing.T) { | ||
| issue1 := bdCreate(t, bd, dir, "Defer multi 1", "--type", "task") | ||
| issue2 := bdCreate(t, bd, dir, "Defer multi 2", "--type", "task") | ||
| out := bdDefer(t, bd, dir, issue1.ID, issue2.ID) | ||
| if !strings.Contains(out, issue1.ID) || !strings.Contains(out, issue2.ID) { | ||
| t.Errorf("expected both IDs in output: %s", out) | ||
| } | ||
| for _, id := range []string{issue1.ID, issue2.ID} { | ||
| status := getIssueStatus(t, bd, dir, id) | ||
| if status != "deferred" { | ||
| t.Errorf("expected %s status=deferred, got %q", id, status) | ||
| } | ||
| } | ||
| }) | ||
|
|
||
| // ===== With --until ===== | ||
|
|
||
| t.Run("defer_until", func(t *testing.T) { | ||
| issue := bdCreate(t, bd, dir, "Defer until test", "--type", "task") | ||
| out := bdDefer(t, bd, dir, issue.ID, "--until", "+1h") | ||
| if !strings.Contains(out, "Deferred") { | ||
| t.Errorf("expected 'Deferred' in output: %s", out) | ||
| } | ||
| status := getIssueStatus(t, bd, dir, issue.ID) | ||
| if status != "deferred" { | ||
| t.Errorf("expected status=deferred, got %q", status) | ||
| } | ||
| }) | ||
|
|
||
| // ===== Already Deferred ===== | ||
|
|
||
| t.Run("defer_already_deferred", func(t *testing.T) { | ||
| issue := bdCreate(t, bd, dir, "Defer idempotent", "--type", "task") | ||
| bdDefer(t, bd, dir, issue.ID) | ||
| // Defer again — should succeed | ||
| out := bdDefer(t, bd, dir, issue.ID) | ||
| if !strings.Contains(out, "Deferred") { | ||
| t.Errorf("expected 'Deferred' on second defer: %s", out) | ||
| } | ||
| }) | ||
| } | ||
|
|
||
| // TestEmbeddedDeferConcurrent exercises defer operations concurrently. | ||
| func TestEmbeddedDeferConcurrent(t *testing.T) { | ||
| if os.Getenv("BEADS_TEST_EMBEDDED_DOLT") != "1" { | ||
| t.Skip("set BEADS_TEST_EMBEDDED_DOLT=1 to run embedded dolt integration tests") | ||
| } | ||
| t.Parallel() | ||
|
|
||
| bd := buildEmbeddedBD(t) | ||
| dir, _, _ := bdInit(t, bd, "--prefix", "dx") | ||
|
|
||
| // Pre-create issues | ||
| var issueIDs []string | ||
| for i := 0; i < 8; i++ { | ||
| issue := bdCreate(t, bd, dir, fmt.Sprintf("defer-concurrent-%d", i), "--type", "task") | ||
| issueIDs = append(issueIDs, issue.ID) | ||
| } | ||
|
|
||
| const numWorkers = 8 | ||
| type workerResult struct { | ||
| worker int | ||
| err error | ||
| } | ||
| results := make([]workerResult, numWorkers) | ||
| var wg sync.WaitGroup | ||
| wg.Add(numWorkers) | ||
|
|
||
| for w := 0; w < numWorkers; w++ { | ||
| go func(worker int) { | ||
| defer wg.Done() | ||
| r := workerResult{worker: worker} | ||
| id := issueIDs[worker] | ||
|
|
||
| cmd := exec.Command(bd, "defer", id) | ||
| cmd.Dir = dir | ||
| cmd.Env = bdEnv(dir) | ||
| out, err := cmd.CombinedOutput() | ||
| if err != nil { | ||
| r.err = fmt.Errorf("defer %s (worker %d): %v\n%s", id, worker, err, out) | ||
| } | ||
| results[worker] = r | ||
| }(w) | ||
| } | ||
| wg.Wait() | ||
|
|
||
| for _, r := range results { | ||
| if r.err != nil { | ||
| t.Errorf("worker %d failed: %v", r.worker, r.err) | ||
| } | ||
| } | ||
|
|
||
| // Verify all are deferred | ||
| for i, id := range issueIDs { | ||
| status := getIssueStatus(t, bd, dir, id) | ||
| if status != "deferred" { | ||
| t.Errorf("issue %d (%s): expected status=deferred, got %q", i, id, status) | ||
| } | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the --json subtest, the test only validates JSON if it finds a '{' or '['. With --json, lack of any JSON should fail the test (as done in other embedded tests). Consider asserting start >= 0 (or specifically requiring an array/object) before calling json.Valid.