Artifact e18656cbfbb59b3fa4d462ce68fe313cebe4bdde1a4effa747154b21da4498c6:
- File
cmd/edgesync/notify_test.go
— part of check-in
[eda7960b81]
at
2026-04-23 19:23:42
on branch trunk
— rename module to github.com/danmestas/EdgeSync
Fix the case-sensitive module path to match the actual GitHub repo URL (danmestas/EdgeSync). Remove tracked leaf/leaf binary and ignore .claude/skills/ scratchpad dirs. (user: [email protected], size: 5647) [annotate] [blame] [check-ins using] [more...]
package main_test import ( "os" "os/exec" "path/filepath" "strings" "testing" ) // buildBinary builds the edgesync binary into a temp dir and returns its path. func buildBinary(t *testing.T) string { t.Helper() bin := filepath.Join(t.TempDir(), "edgesync") cmd := exec.Command("go", "build", "-buildvcs=false", "-o", bin, "./cmd/edgesync/") // Build from the repo root (where go.mod lives). cmd.Dir = repoRoot(t) out, err := cmd.CombinedOutput() if err != nil { t.Fatalf("build failed: %s\n%s", err, out) } return bin } // repoRoot returns the root of the EdgeSync repo (parent of cmd/). func repoRoot(t *testing.T) string { t.Helper() // This test file is in cmd/edgesync/, so go two levels up. wd, err := os.Getwd() if err != nil { t.Fatal(err) } // When running tests, cwd is the package dir (cmd/edgesync/). // Go up to repo root. root := filepath.Dir(filepath.Dir(wd)) if _, err := os.Stat(filepath.Join(root, "go.mod")); err != nil { t.Fatalf("could not find repo root from %s", wd) } return root } func TestNotifyCLIInit(t *testing.T) { bin := buildBinary(t) tmp := t.TempDir() // -R points to a fake repo path — init creates notify.fossil next to it. fakeRepo := filepath.Join(tmp, "project.fossil") cmd := exec.Command(bin, "-R", fakeRepo, "notify", "init") out, err := cmd.CombinedOutput() if err != nil { t.Fatalf("notify init failed: %s\n%s", err, out) } expected := filepath.Join(tmp, "notify.fossil") got := strings.TrimSpace(string(out)) if got != expected { t.Errorf("init output = %q, want %q", got, expected) } // Verify the file was created. if _, err := os.Stat(expected); os.IsNotExist(err) { t.Errorf("notify.fossil not created at %s", expected) } } func TestNotifyCLIPairAndDevices(t *testing.T) { bin := buildBinary(t) tmp := t.TempDir() fakeRepo := filepath.Join(tmp, "project.fossil") // Init. cmd := exec.Command(bin, "-R", fakeRepo, "notify", "init") out, err := cmd.CombinedOutput() if err != nil { t.Fatalf("init: %s\n%s", err, out) } // Pair (no endpoint/NATS = text token only, no QR). cmd = exec.Command(bin, "-R", fakeRepo, "notify", "pair", "--name", "dan-iphone") out, err = cmd.CombinedOutput() if err != nil { t.Fatalf("pair: %s\n%s", err, out) } pairOutput := string(out) // Should contain a token in XXXX-XXXX-XXXX format. if !strings.Contains(pairOutput, "-") { t.Errorf("pair output should contain token with dashes, got: %q", pairOutput) } if !strings.Contains(pairOutput, "expires") { t.Errorf("pair output should mention expiry, got: %q", pairOutput) } // Devices — should be empty (token pending, not yet validated). cmd = exec.Command(bin, "-R", fakeRepo, "notify", "devices") out, err = cmd.CombinedOutput() if err != nil { t.Fatalf("devices: %s\n%s", err, out) } if !strings.Contains(string(out), "no paired devices") { t.Errorf("devices should be empty before validation, got: %q", string(out)) } } func TestNotifyCLIUnpair(t *testing.T) { bin := buildBinary(t) tmp := t.TempDir() fakeRepo := filepath.Join(tmp, "project.fossil") // Init. cmd := exec.Command(bin, "-R", fakeRepo, "notify", "init") if out, err := cmd.CombinedOutput(); err != nil { t.Fatalf("init: %s\n%s", err, out) } // Unpair a device that doesn't exist = error. cmd = exec.Command(bin, "-R", fakeRepo, "notify", "unpair", "nonexistent") if out, err := cmd.CombinedOutput(); err == nil { t.Fatalf("unpair nonexistent should fail, got: %s", out) } } func TestNotifyCLISendAndThreads(t *testing.T) { bin := buildBinary(t) tmp := t.TempDir() fakeRepo := filepath.Join(tmp, "project.fossil") // Init first. cmd := exec.Command(bin, "-R", fakeRepo, "notify", "init") out, err := cmd.CombinedOutput() if err != nil { t.Fatalf("notify init failed: %s\n%s", err, out) } // Send a message. cmd = exec.Command(bin, "-R", fakeRepo, "notify", "send", "--project", "testproj", "--priority", "urgent", "Hello from CLI test") out, err = cmd.CombinedOutput() if err != nil { t.Fatalf("notify send failed: %s\n%s", err, out) } sendOutput := string(out) // stdout should contain the message ID (msg-...). if !strings.Contains(sendOutput, "msg-") { t.Errorf("send output should contain message ID, got: %q", sendOutput) } // stderr has thread info — combined output should contain "thread:". if !strings.Contains(sendOutput, "thread:") { t.Errorf("send output should contain thread info, got: %q", sendOutput) } // List threads. cmd = exec.Command(bin, "-R", fakeRepo, "notify", "threads", "--project", "testproj") out, err = cmd.CombinedOutput() if err != nil { t.Fatalf("notify threads failed: %s\n%s", err, out) } threadsOutput := string(out) if !strings.Contains(threadsOutput, "msgs:1") { t.Errorf("threads should show msgs:1, got: %q", threadsOutput) } if !strings.Contains(threadsOutput, "priority:urgent") { t.Errorf("threads should show priority:urgent, got: %q", threadsOutput) } if !strings.Contains(threadsOutput, "Hello from CLI test") { t.Errorf("threads should show message body, got: %q", threadsOutput) } // Status. cmd = exec.Command(bin, "-R", fakeRepo, "notify", "status") out, err = cmd.CombinedOutput() if err != nil { t.Fatalf("notify status failed: %s\n%s", err, out) } statusOutput := string(out) notifyPath := filepath.Join(tmp, "notify.fossil") if !strings.Contains(statusOutput, notifyPath) { t.Errorf("status should contain notify repo path %s, got: %q", notifyPath, statusOutput) } if !strings.Contains(statusOutput, "repo-only") { t.Errorf("status should show repo-only connection, got: %q", statusOutput) } }