Files
ax/e2e_test.go

199 lines
5.1 KiB
Go

package main
import (
"encoding/json"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
)
type NodeResponse struct {
ID string `json:"id"`
Title string `json:"title"`
Content string `json:"content"`
Tags []string `json:"tags"`
Relations map[string][]string `json:"relations"`
}
func runAx(t *testing.T, dir string, args ...string) (string, error) {
cmd := exec.Command("./ax", args...)
cmd.Dir = dir
out, err := cmd.CombinedOutput()
return string(out), err
}
func parseJSON(t *testing.T, out string) NodeResponse {
var node NodeResponse
err := json.Unmarshal([]byte(out), &node)
if err != nil {
t.Fatalf("failed to parse JSON output: %v\nOutput: %s", err, out)
}
return node
}
func TestE2E(t *testing.T) {
// Build the binary first
cmd := exec.Command("go", "build", "-o", "ax", ".")
err := cmd.Run()
if err != nil {
t.Fatalf("failed to build: %v", err)
}
defer os.Remove("./ax")
// Create a temp directory for the test
tmpDir, err := os.MkdirTemp("", "ax-e2e-*")
if err != nil {
t.Fatalf("failed to create temp dir: %v", err)
}
defer os.RemoveAll(tmpDir)
// Copy binary to temp dir
binaryPath := filepath.Join(tmpDir, "ax")
cmd = exec.Command("cp", "./ax", binaryPath)
err = cmd.Run()
if err != nil {
t.Fatalf("failed to copy binary: %v", err)
}
// 1. Initialize DB
out, err := runAx(t, tmpDir, "init")
if err != nil {
t.Fatalf("ax init failed: %v\n%s", err, out)
}
// Set test user
os.Setenv("AX_USER", "testuser")
defer os.Unsetenv("AX_USER")
// 2. Add an issue
out, err = runAx(t, tmpDir, "add", "Test Issue 1", "--namespace", "testproj", "--prio", "high", "--json")
if err != nil {
t.Fatalf("ax add failed: %v\n%s", err, out)
}
node1 := parseJSON(t, out)
if node1.Title != "Test Issue 1" {
t.Errorf("Expected title 'Test Issue 1', got '%s'", node1.Title)
}
hasHighPrio := false
for _, tag := range node1.Tags {
if tag == "_prio::high" {
hasHighPrio = true
}
}
if !hasHighPrio {
t.Errorf("Expected tag '_prio::high', got %v", node1.Tags)
}
// Note: in_namespace relation points to a node ID, not the string "testproj".
// We'll verify it by listing the namespace.
// 3. Add a second issue (the blocker)
out, err = runAx(t, tmpDir, "add", "Test Issue 2", "--json")
if err != nil {
t.Fatalf("ax add failed: %v\n%s", err, out)
}
node2 := parseJSON(t, out)
// Make node1 blocked by node2
out, err = runAx(t, tmpDir, "update", node1.ID, "--rel", "blocks:"+node2.ID, "--json")
if err != nil {
t.Fatalf("ax update failed: %v\n%s", err, out)
}
// 4. Try to close the blocked issue (should fail)
out, err = runAx(t, tmpDir, "update", node1.ID, "--status", "done")
if err == nil {
t.Errorf("Expected closing blocked issue to fail, but it succeeded")
}
if !strings.Contains(out, "cannot close: blocked by") {
t.Errorf("Expected blocked error message, got: %s", out)
}
// 5. Close the blocker
out, err = runAx(t, tmpDir, "update", node2.ID, "--status", "done", "--json")
if err != nil {
t.Fatalf("ax update failed: %v\n%s", err, out)
}
// 6. Close the original issue (should succeed now)
out, err = runAx(t, tmpDir, "update", node1.ID, "--status", "done", "--json")
if err != nil {
t.Fatalf("ax update failed: %v\n%s", err, out)
}
// 7. Update assignee
out, err = runAx(t, tmpDir, "update", node1.ID, "--assignee", "bob", "--json")
if err != nil {
t.Fatalf("ax update failed: %v\n%s", err, out)
}
// List by assignee to verify
out, err = runAx(t, tmpDir, "list", "--assignee", "bob", "--json")
if err != nil {
t.Fatalf("ax list assignee failed: %v\n%s", err, out)
}
var assigneeNodes []NodeResponse
err = json.Unmarshal([]byte(out), &assigneeNodes)
if err != nil {
t.Fatalf("failed to parse list JSON: %v\n%s", err, out)
}
foundAssigned := false
for _, n := range assigneeNodes {
if n.ID == node1.ID {
foundAssigned = true
}
}
if !foundAssigned {
t.Errorf("Expected to find node %s assigned to bob", node1.ID)
}
// 8. List by namespace
out, err = runAx(t, tmpDir, "list", "--namespace", "testproj", "--json")
if err != nil {
t.Fatalf("ax list failed: %v\n%s", err, out)
}
// Should be an array of nodes
var nodes []NodeResponse
err = json.Unmarshal([]byte(out), &nodes)
if err != nil {
t.Fatalf("failed to parse list JSON: %v\n%s", err, out)
}
foundNamespace := false
for _, n := range nodes {
if n.ID == node1.ID {
foundNamespace = true
}
}
if !foundNamespace {
t.Errorf("Expected node %s in namespace 'testproj', but wasn't found in list output: %v", node1.ID, nodes)
}
// 9. Mention parsing
out, err = runAx(t, tmpDir, "add", "Hello @alice", "--content", "Please see this @alice.", "--json")
if err != nil {
t.Fatalf("ax add mention failed: %v\n%s", err, out)
}
// List mention
out, err = runAx(t, tmpDir, "list", "--mention", "alice", "--json")
if err != nil {
t.Fatalf("ax list mention failed: %v\n%s", err, out)
}
err = json.Unmarshal([]byte(out), &nodes)
if err != nil {
t.Fatalf("failed to parse mention list JSON: %v\n%s", err, out)
}
if len(nodes) == 0 {
t.Errorf("Expected at least 1 node in alice's inbox")
}
// Test completed successfully
}