Removed Gate RPC tests that referenced undefined API methods. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
892 lines
21 KiB
Go
892 lines
21 KiB
Go
package rpc
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/steveyegge/beads/internal/types"
|
|
)
|
|
|
|
// CountResult represents the response from handleCount
|
|
type CountResult struct {
|
|
Count int `json:"count"`
|
|
}
|
|
|
|
// TestCount tests the Count operation via RPC
|
|
func TestCount(t *testing.T) {
|
|
_, client, cleanup := setupTestServer(t)
|
|
defer cleanup()
|
|
|
|
// Create some issues first
|
|
for i := 0; i < 5; i++ {
|
|
args := &CreateArgs{
|
|
Title: "Test Issue for Count",
|
|
Description: "Test description",
|
|
IssueType: "task",
|
|
Priority: 2,
|
|
}
|
|
if _, err := client.Create(args); err != nil {
|
|
t.Fatalf("Create failed: %v", err)
|
|
}
|
|
}
|
|
|
|
// Create a closed issue
|
|
createResp, err := client.Create(&CreateArgs{
|
|
Title: "Closed Issue",
|
|
Description: "Test description",
|
|
IssueType: "bug",
|
|
Priority: 1,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Create failed: %v", err)
|
|
}
|
|
var closedIssue types.Issue
|
|
json.Unmarshal(createResp.Data, &closedIssue)
|
|
if _, err := client.CloseIssue(&CloseArgs{ID: closedIssue.ID, Reason: "Done"}); err != nil {
|
|
t.Fatalf("CloseIssue failed: %v", err)
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
args *CountArgs
|
|
expectedCount int
|
|
}{
|
|
{
|
|
name: "Count all issues",
|
|
args: &CountArgs{},
|
|
expectedCount: 6,
|
|
},
|
|
{
|
|
name: "Count open issues",
|
|
args: &CountArgs{Status: "open"},
|
|
expectedCount: 5,
|
|
},
|
|
{
|
|
name: "Count closed issues",
|
|
args: &CountArgs{Status: "closed"},
|
|
expectedCount: 1,
|
|
},
|
|
{
|
|
name: "Count by type task",
|
|
args: &CountArgs{IssueType: "task"},
|
|
expectedCount: 5,
|
|
},
|
|
{
|
|
name: "Count by type bug",
|
|
args: &CountArgs{IssueType: "bug"},
|
|
expectedCount: 1,
|
|
},
|
|
{
|
|
name: "Count by priority",
|
|
args: &CountArgs{Priority: intPtr(2)},
|
|
expectedCount: 5,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
resp, err := client.Count(tt.args)
|
|
if err != nil {
|
|
t.Fatalf("Count failed: %v", err)
|
|
}
|
|
|
|
if !resp.Success {
|
|
t.Fatalf("Expected success, got error: %s", resp.Error)
|
|
}
|
|
|
|
var result CountResult
|
|
if err := json.Unmarshal(resp.Data, &result); err != nil {
|
|
t.Fatalf("Failed to unmarshal count result: %v", err)
|
|
}
|
|
|
|
if result.Count != tt.expectedCount {
|
|
t.Errorf("Expected count %d, got %d", tt.expectedCount, result.Count)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestCountWithDateFilters tests Count with date range filters
|
|
func TestCountWithDateFilters(t *testing.T) {
|
|
_, client, cleanup := setupTestServer(t)
|
|
defer cleanup()
|
|
|
|
// Create an issue
|
|
_, err := client.Create(&CreateArgs{
|
|
Title: "Recent Issue",
|
|
Description: "Test description",
|
|
IssueType: "task",
|
|
Priority: 2,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Create failed: %v", err)
|
|
}
|
|
|
|
// Count with created_after in the past (should include our issue)
|
|
yesterday := time.Now().Add(-24 * time.Hour).Format(time.RFC3339)
|
|
resp, err := client.Count(&CountArgs{CreatedAfter: yesterday})
|
|
if err != nil {
|
|
t.Fatalf("Count failed: %v", err)
|
|
}
|
|
|
|
var result CountResult
|
|
json.Unmarshal(resp.Data, &result)
|
|
if result.Count < 1 {
|
|
t.Errorf("Expected at least 1 issue created after %s, got %d", yesterday, result.Count)
|
|
}
|
|
|
|
// Count with created_before in the past (should not include our issue)
|
|
resp, err = client.Count(&CountArgs{CreatedBefore: yesterday})
|
|
if err != nil {
|
|
t.Fatalf("Count failed: %v", err)
|
|
}
|
|
|
|
json.Unmarshal(resp.Data, &result)
|
|
if result.Count != 0 {
|
|
t.Errorf("Expected 0 issues created before %s, got %d", yesterday, result.Count)
|
|
}
|
|
}
|
|
|
|
// TestResolveID tests the ResolveID operation via RPC
|
|
func TestResolveID(t *testing.T) {
|
|
_, client, cleanup := setupTestServer(t)
|
|
defer cleanup()
|
|
|
|
// Create an issue first
|
|
createResp, err := client.Create(&CreateArgs{
|
|
Title: "Test Issue for Resolution",
|
|
IssueType: "task",
|
|
Priority: 2,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Create failed: %v", err)
|
|
}
|
|
|
|
var issue types.Issue
|
|
json.Unmarshal(createResp.Data, &issue)
|
|
|
|
// Test resolving the full ID
|
|
resp, err := client.ResolveID(&ResolveIDArgs{ID: issue.ID})
|
|
if err != nil {
|
|
t.Fatalf("ResolveID failed: %v", err)
|
|
}
|
|
|
|
if !resp.Success {
|
|
t.Fatalf("Expected success, got error: %s", resp.Error)
|
|
}
|
|
|
|
var resolvedID string
|
|
if err := json.Unmarshal(resp.Data, &resolvedID); err != nil {
|
|
t.Fatalf("Failed to unmarshal resolved ID: %v", err)
|
|
}
|
|
|
|
if resolvedID != issue.ID {
|
|
t.Errorf("Expected resolved ID %s, got %s", issue.ID, resolvedID)
|
|
}
|
|
|
|
// Test resolving a partial ID (first few characters after prefix)
|
|
// Note: This depends on there being only one issue with this prefix
|
|
if len(issue.ID) > 3 {
|
|
partialID := issue.ID[:len(issue.ID)-2] // Remove last 2 chars
|
|
resp, err = client.ResolveID(&ResolveIDArgs{ID: partialID})
|
|
if err != nil {
|
|
t.Fatalf("ResolveID with partial failed: %v", err)
|
|
}
|
|
|
|
if !resp.Success {
|
|
// This might fail if partial is ambiguous, which is fine
|
|
t.Logf("Partial resolution returned: %s", resp.Error)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestResolveID_NotFound tests ResolveID with non-existent ID
|
|
func TestResolveID_NotFound(t *testing.T) {
|
|
_, client, cleanup := setupTestServer(t)
|
|
defer cleanup()
|
|
|
|
// ResolveID with non-existent ID should fail with an error
|
|
resp, err := client.ResolveID(&ResolveIDArgs{ID: "bd-nonexistent"})
|
|
|
|
// The error is returned through the Execute function
|
|
if err != nil {
|
|
// Expected - this is the correct behavior for non-existent ID
|
|
return
|
|
}
|
|
|
|
// If we got here without error, check the response
|
|
if resp.Success {
|
|
t.Error("Expected failure for non-existent ID, got success")
|
|
}
|
|
}
|
|
|
|
// TestDelete tests the Delete operation via RPC
|
|
func TestDelete(t *testing.T) {
|
|
_, client, cleanup := setupTestServer(t)
|
|
defer cleanup()
|
|
|
|
// Create an issue to delete
|
|
createResp, err := client.Create(&CreateArgs{
|
|
Title: "Issue to Delete",
|
|
Description: "Test description",
|
|
IssueType: "task",
|
|
Priority: 2,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Create failed: %v", err)
|
|
}
|
|
|
|
var issue types.Issue
|
|
json.Unmarshal(createResp.Data, &issue)
|
|
|
|
// Delete the issue
|
|
deleteResp, err := client.Delete(&DeleteArgs{
|
|
IDs: []string{issue.ID},
|
|
Force: true,
|
|
Reason: "Testing deletion",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Delete failed: %v", err)
|
|
}
|
|
|
|
if !deleteResp.Success {
|
|
t.Fatalf("Expected success, got error: %s", deleteResp.Error)
|
|
}
|
|
|
|
// Verify the delete result
|
|
var result map[string]interface{}
|
|
json.Unmarshal(deleteResp.Data, &result)
|
|
|
|
if int(result["deleted_count"].(float64)) != 1 {
|
|
t.Errorf("Expected deleted_count=1, got %v", result["deleted_count"])
|
|
}
|
|
|
|
// Note: Deleted issues are tombstoned, not hard-deleted.
|
|
// They may still appear with status=closed, so we just verify
|
|
// the delete operation succeeded above.
|
|
}
|
|
|
|
// TestDelete_DryRun tests Delete in dry-run mode
|
|
func TestDelete_DryRun(t *testing.T) {
|
|
_, client, cleanup := setupTestServer(t)
|
|
defer cleanup()
|
|
|
|
// Create an issue
|
|
createResp, err := client.Create(&CreateArgs{
|
|
Title: "Issue for DryRun Delete",
|
|
Description: "Test description",
|
|
IssueType: "task",
|
|
Priority: 2,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Create failed: %v", err)
|
|
}
|
|
|
|
var issue types.Issue
|
|
json.Unmarshal(createResp.Data, &issue)
|
|
|
|
// Delete in dry-run mode
|
|
deleteResp, err := client.Delete(&DeleteArgs{
|
|
IDs: []string{issue.ID},
|
|
DryRun: true,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Delete failed: %v", err)
|
|
}
|
|
|
|
if !deleteResp.Success {
|
|
t.Fatalf("Expected success, got error: %s", deleteResp.Error)
|
|
}
|
|
|
|
var result map[string]interface{}
|
|
json.Unmarshal(deleteResp.Data, &result)
|
|
if result["dry_run"] != true {
|
|
t.Error("Expected dry_run to be true in response")
|
|
}
|
|
|
|
// Verify issue still exists
|
|
showResp, err := client.Show(&ShowArgs{ID: issue.ID})
|
|
if err != nil {
|
|
t.Fatalf("Show failed: %v", err)
|
|
}
|
|
|
|
if !showResp.Success {
|
|
t.Error("Issue should still exist after dry-run delete")
|
|
}
|
|
}
|
|
|
|
// TestDelete_NoIDs tests Delete with no IDs
|
|
func TestDelete_NoIDs(t *testing.T) {
|
|
_, client, cleanup := setupTestServer(t)
|
|
defer cleanup()
|
|
|
|
// Delete with no IDs should fail
|
|
resp, err := client.Delete(&DeleteArgs{
|
|
IDs: []string{},
|
|
})
|
|
|
|
// The error may come through err or through resp.Success=false
|
|
if err != nil {
|
|
// Expected - this is the correct behavior
|
|
return
|
|
}
|
|
|
|
if resp.Success {
|
|
t.Error("Expected failure when deleting with no IDs")
|
|
}
|
|
}
|
|
|
|
// TestDelete_MultipleIssues tests deleting multiple issues at once
|
|
func TestDelete_MultipleIssues(t *testing.T) {
|
|
_, client, cleanup := setupTestServer(t)
|
|
defer cleanup()
|
|
|
|
// Create multiple issues
|
|
var ids []string
|
|
for i := 0; i < 3; i++ {
|
|
createResp, err := client.Create(&CreateArgs{
|
|
Title: "Issue for Batch Delete",
|
|
Description: "Test description",
|
|
IssueType: "task",
|
|
Priority: 2,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Create failed: %v", err)
|
|
}
|
|
|
|
var issue types.Issue
|
|
json.Unmarshal(createResp.Data, &issue)
|
|
ids = append(ids, issue.ID)
|
|
}
|
|
|
|
// Delete all at once
|
|
deleteResp, err := client.Delete(&DeleteArgs{
|
|
IDs: ids,
|
|
Force: true,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Delete failed: %v", err)
|
|
}
|
|
|
|
if !deleteResp.Success {
|
|
t.Fatalf("Expected success, got error: %s", deleteResp.Error)
|
|
}
|
|
|
|
var result map[string]interface{}
|
|
json.Unmarshal(deleteResp.Data, &result)
|
|
if int(result["deleted_count"].(float64)) != 3 {
|
|
t.Errorf("Expected deleted_count=3, got %v", result["deleted_count"])
|
|
}
|
|
}
|
|
|
|
// TestStale tests the Stale operation via RPC
|
|
func TestStale(t *testing.T) {
|
|
_, client, cleanup := setupTestServer(t)
|
|
defer cleanup()
|
|
|
|
// Create an issue (it won't be stale because it's just created)
|
|
_, err := client.Create(&CreateArgs{
|
|
Title: "Fresh Issue",
|
|
Description: "Test description",
|
|
IssueType: "task",
|
|
Priority: 2,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Create failed: %v", err)
|
|
}
|
|
|
|
// Get stale issues (should be empty since issue is fresh)
|
|
resp, err := client.Stale(&StaleArgs{Days: 7})
|
|
if err != nil {
|
|
t.Fatalf("Stale failed: %v", err)
|
|
}
|
|
|
|
if !resp.Success {
|
|
t.Fatalf("Expected success, got error: %s", resp.Error)
|
|
}
|
|
|
|
var staleIssues []types.Issue
|
|
if err := json.Unmarshal(resp.Data, &staleIssues); err != nil {
|
|
t.Fatalf("Failed to unmarshal stale issues: %v", err)
|
|
}
|
|
|
|
// Should be empty since our issue was just created
|
|
if len(staleIssues) != 0 {
|
|
t.Errorf("Expected 0 stale issues, got %d", len(staleIssues))
|
|
}
|
|
}
|
|
|
|
// TestStale_WithStatusFilter tests Stale with status filter
|
|
func TestStale_WithStatusFilter(t *testing.T) {
|
|
_, client, cleanup := setupTestServer(t)
|
|
defer cleanup()
|
|
|
|
// Create and close an issue
|
|
createResp, err := client.Create(&CreateArgs{
|
|
Title: "Issue to Close",
|
|
Description: "Test description",
|
|
IssueType: "task",
|
|
Priority: 2,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Create failed: %v", err)
|
|
}
|
|
|
|
var issue types.Issue
|
|
json.Unmarshal(createResp.Data, &issue)
|
|
|
|
if _, err := client.CloseIssue(&CloseArgs{ID: issue.ID}); err != nil {
|
|
t.Fatalf("CloseIssue failed: %v", err)
|
|
}
|
|
|
|
// Get stale open issues (should not include the closed one)
|
|
resp, err := client.Stale(&StaleArgs{Days: 0, Status: "open"})
|
|
if err != nil {
|
|
t.Fatalf("Stale failed: %v", err)
|
|
}
|
|
|
|
if !resp.Success {
|
|
t.Fatalf("Expected success, got error: %s", resp.Error)
|
|
}
|
|
|
|
var staleIssues []types.Issue
|
|
json.Unmarshal(resp.Data, &staleIssues)
|
|
|
|
for _, si := range staleIssues {
|
|
if si.ID == issue.ID {
|
|
t.Error("Closed issue should not appear in open stale issues")
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestCommentList tests the ListComments operation via RPC
|
|
func TestCommentList(t *testing.T) {
|
|
_, client, cleanup := setupTestServer(t)
|
|
defer cleanup()
|
|
|
|
// Create an issue first
|
|
createResp, err := client.Create(&CreateArgs{
|
|
Title: "Issue for Comments",
|
|
Description: "Test description",
|
|
IssueType: "task",
|
|
Priority: 2,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Create failed: %v", err)
|
|
}
|
|
|
|
var issue types.Issue
|
|
json.Unmarshal(createResp.Data, &issue)
|
|
|
|
// List comments on the issue (should be empty initially)
|
|
resp, err := client.ListComments(&CommentListArgs{ID: issue.ID})
|
|
if err != nil {
|
|
t.Fatalf("ListComments failed: %v", err)
|
|
}
|
|
|
|
if !resp.Success {
|
|
t.Fatalf("Expected success, got error: %s", resp.Error)
|
|
}
|
|
|
|
var comments []types.Comment
|
|
if err := json.Unmarshal(resp.Data, &comments); err != nil {
|
|
t.Fatalf("Failed to unmarshal comments: %v", err)
|
|
}
|
|
|
|
if len(comments) != 0 {
|
|
t.Errorf("Expected 0 comments initially, got %d", len(comments))
|
|
}
|
|
}
|
|
|
|
// TestCommentAdd tests the AddComment operation via RPC
|
|
func TestCommentAdd(t *testing.T) {
|
|
_, client, cleanup := setupTestServer(t)
|
|
defer cleanup()
|
|
|
|
// Create an issue first
|
|
createResp, err := client.Create(&CreateArgs{
|
|
Title: "Issue for Adding Comments",
|
|
Description: "Test description",
|
|
IssueType: "task",
|
|
Priority: 2,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Create failed: %v", err)
|
|
}
|
|
|
|
var issue types.Issue
|
|
json.Unmarshal(createResp.Data, &issue)
|
|
|
|
// Add a comment
|
|
addResp, err := client.AddComment(&CommentAddArgs{
|
|
ID: issue.ID,
|
|
Author: "testuser",
|
|
Text: "This is a test comment",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("AddComment failed: %v", err)
|
|
}
|
|
|
|
if !addResp.Success {
|
|
t.Fatalf("Expected success, got error: %s", addResp.Error)
|
|
}
|
|
|
|
var comment types.Comment
|
|
if err := json.Unmarshal(addResp.Data, &comment); err != nil {
|
|
t.Fatalf("Failed to unmarshal comment: %v", err)
|
|
}
|
|
|
|
if comment.Author != "testuser" {
|
|
t.Errorf("Expected author 'testuser', got '%s'", comment.Author)
|
|
}
|
|
if comment.Text != "This is a test comment" {
|
|
t.Errorf("Expected text 'This is a test comment', got '%s'", comment.Text)
|
|
}
|
|
|
|
// Verify comment is listed
|
|
listResp, err := client.ListComments(&CommentListArgs{ID: issue.ID})
|
|
if err != nil {
|
|
t.Fatalf("ListComments failed: %v", err)
|
|
}
|
|
|
|
var comments []types.Comment
|
|
json.Unmarshal(listResp.Data, &comments)
|
|
|
|
if len(comments) != 1 {
|
|
t.Errorf("Expected 1 comment, got %d", len(comments))
|
|
}
|
|
}
|
|
|
|
// TestCommentAdd_MultipleComments tests adding multiple comments
|
|
func TestCommentAdd_MultipleComments(t *testing.T) {
|
|
_, client, cleanup := setupTestServer(t)
|
|
defer cleanup()
|
|
|
|
// Create an issue
|
|
createResp, err := client.Create(&CreateArgs{
|
|
Title: "Issue for Multiple Comments",
|
|
Description: "Test description",
|
|
IssueType: "task",
|
|
Priority: 2,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Create failed: %v", err)
|
|
}
|
|
|
|
var issue types.Issue
|
|
json.Unmarshal(createResp.Data, &issue)
|
|
|
|
// Add multiple comments
|
|
for i := 1; i <= 3; i++ {
|
|
_, err := client.AddComment(&CommentAddArgs{
|
|
ID: issue.ID,
|
|
Author: "user",
|
|
Text: "Comment text",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("AddComment %d failed: %v", i, err)
|
|
}
|
|
}
|
|
|
|
// Verify all comments are listed
|
|
listResp, err := client.ListComments(&CommentListArgs{ID: issue.ID})
|
|
if err != nil {
|
|
t.Fatalf("ListComments failed: %v", err)
|
|
}
|
|
|
|
var comments []types.Comment
|
|
json.Unmarshal(listResp.Data, &comments)
|
|
|
|
if len(comments) != 3 {
|
|
t.Errorf("Expected 3 comments, got %d", len(comments))
|
|
}
|
|
}
|
|
|
|
// TestMetrics tests the Metrics operation via RPC
|
|
func TestMetrics(t *testing.T) {
|
|
_, client, cleanup := setupTestServer(t)
|
|
defer cleanup()
|
|
|
|
// Make a few requests to generate some metrics
|
|
for i := 0; i < 3; i++ {
|
|
if err := client.Ping(); err != nil {
|
|
t.Fatalf("Ping failed: %v", err)
|
|
}
|
|
}
|
|
|
|
// Get metrics
|
|
metrics, err := client.Metrics()
|
|
if err != nil {
|
|
t.Fatalf("Metrics failed: %v", err)
|
|
}
|
|
|
|
if metrics == nil {
|
|
t.Fatal("Expected metrics, got nil")
|
|
}
|
|
|
|
// Check that we have operations recorded
|
|
if len(metrics.Operations) == 0 {
|
|
t.Error("Expected at least some operations recorded in metrics")
|
|
}
|
|
|
|
// Calculate total requests from operations
|
|
var totalRequests int64
|
|
for _, op := range metrics.Operations {
|
|
totalRequests += op.TotalCount
|
|
}
|
|
|
|
// We made 3 pings + 1 metrics request = at least 4 requests
|
|
// (metrics call itself is recorded after snapshot)
|
|
if totalRequests < 3 {
|
|
t.Errorf("Expected at least 3 total requests, got %d", totalRequests)
|
|
}
|
|
|
|
// Check uptime is reasonable
|
|
if metrics.UptimeSeconds <= 0 {
|
|
t.Errorf("Expected positive uptime, got %f", metrics.UptimeSeconds)
|
|
}
|
|
}
|
|
|
|
// TestCountWithGroupBy tests Count with GroupBy option
|
|
func TestCountWithGroupBy(t *testing.T) {
|
|
_, client, cleanup := setupTestServer(t)
|
|
defer cleanup()
|
|
|
|
// Create issues with different statuses and types
|
|
_, err := client.Create(&CreateArgs{
|
|
Title: "Task Issue",
|
|
Description: "Test description",
|
|
IssueType: "task",
|
|
Priority: 2,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Create failed: %v", err)
|
|
}
|
|
|
|
createResp, err := client.Create(&CreateArgs{
|
|
Title: "Bug Issue",
|
|
Description: "Test description",
|
|
IssueType: "bug",
|
|
Priority: 1,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Create failed: %v", err)
|
|
}
|
|
|
|
var bugIssue types.Issue
|
|
json.Unmarshal(createResp.Data, &bugIssue)
|
|
|
|
// Close the bug
|
|
if _, err := client.CloseIssue(&CloseArgs{ID: bugIssue.ID}); err != nil {
|
|
t.Fatalf("CloseIssue failed: %v", err)
|
|
}
|
|
|
|
// Count grouped by status
|
|
resp, err := client.Count(&CountArgs{GroupBy: "status"})
|
|
if err != nil {
|
|
t.Fatalf("Count with GroupBy failed: %v", err)
|
|
}
|
|
|
|
if !resp.Success {
|
|
t.Fatalf("Expected success, got error: %s", resp.Error)
|
|
}
|
|
|
|
// The response should contain grouped data
|
|
// (The exact format depends on the server implementation)
|
|
if len(resp.Data) == 0 {
|
|
t.Error("Expected non-empty response for grouped count")
|
|
}
|
|
}
|
|
|
|
// TestCountWithTitleContains tests Count with title pattern matching
|
|
func TestCountWithTitleContains(t *testing.T) {
|
|
_, client, cleanup := setupTestServer(t)
|
|
defer cleanup()
|
|
|
|
// Create issues with specific titles
|
|
_, err := client.Create(&CreateArgs{
|
|
Title: "Authentication Bug Fix",
|
|
Description: "Test description",
|
|
IssueType: "bug",
|
|
Priority: 1,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Create failed: %v", err)
|
|
}
|
|
|
|
_, err = client.Create(&CreateArgs{
|
|
Title: "Add User Login Feature",
|
|
Description: "Test description",
|
|
IssueType: "feature",
|
|
Priority: 2,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Create failed: %v", err)
|
|
}
|
|
|
|
// Count issues with "Authentication" in title
|
|
resp, err := client.Count(&CountArgs{TitleContains: "Authentication"})
|
|
if err != nil {
|
|
t.Fatalf("Count failed: %v", err)
|
|
}
|
|
|
|
var result CountResult
|
|
json.Unmarshal(resp.Data, &result)
|
|
|
|
if result.Count != 1 {
|
|
t.Errorf("Expected 1 issue with 'Authentication' in title, got %d", result.Count)
|
|
}
|
|
}
|
|
|
|
// TestStaleWithLimit tests Stale with limit parameter
|
|
func TestStaleWithLimit(t *testing.T) {
|
|
_, client, cleanup := setupTestServer(t)
|
|
defer cleanup()
|
|
|
|
// Create multiple issues
|
|
for i := 0; i < 5; i++ {
|
|
_, err := client.Create(&CreateArgs{
|
|
Title: "Issue for Stale Test",
|
|
Description: "Test description",
|
|
IssueType: "task",
|
|
Priority: 2,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Create failed: %v", err)
|
|
}
|
|
}
|
|
|
|
// Get stale issues with limit (using 0 days so all issues are considered stale)
|
|
resp, err := client.Stale(&StaleArgs{Days: 0, Limit: 2})
|
|
if err != nil {
|
|
t.Fatalf("Stale failed: %v", err)
|
|
}
|
|
|
|
if !resp.Success {
|
|
t.Fatalf("Expected success, got error: %s", resp.Error)
|
|
}
|
|
|
|
var staleIssues []types.Issue
|
|
json.Unmarshal(resp.Data, &staleIssues)
|
|
|
|
if len(staleIssues) > 2 {
|
|
t.Errorf("Expected at most 2 stale issues (limit), got %d", len(staleIssues))
|
|
}
|
|
}
|
|
|
|
// Helper function to create a pointer to an int
|
|
func intPtr(i int) *int {
|
|
return &i
|
|
}
|
|
|
|
|
|
// GetMutations and Export tests
|
|
|
|
// TestGetMutations tests the GetMutations operation via RPC
|
|
func TestGetMutations(t *testing.T) {
|
|
_, client, cleanup := setupTestServer(t)
|
|
defer cleanup()
|
|
|
|
// Create an issue to generate a mutation
|
|
_, err := client.Create(&CreateArgs{
|
|
Title: "Issue to track mutations",
|
|
Description: "Test description",
|
|
IssueType: "task",
|
|
Priority: 2,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Create failed: %v", err)
|
|
}
|
|
|
|
// Get recent mutations
|
|
resp, err := client.GetMutations(&GetMutationsArgs{Since: 0})
|
|
if err != nil {
|
|
t.Fatalf("GetMutations failed: %v", err)
|
|
}
|
|
|
|
if !resp.Success {
|
|
t.Fatalf("Expected success, got error: %s", resp.Error)
|
|
}
|
|
|
|
// Response should be a slice of mutations
|
|
if len(resp.Data) == 0 {
|
|
t.Error("Expected non-empty response with mutations")
|
|
}
|
|
}
|
|
|
|
// TestExport tests the Export operation via RPC
|
|
func TestExport(t *testing.T) {
|
|
_, client, cleanup := setupTestServer(t)
|
|
defer cleanup()
|
|
|
|
// Create some issues first
|
|
for i := 0; i < 3; i++ {
|
|
_, err := client.Create(&CreateArgs{
|
|
Title: "Issue for Export",
|
|
Description: "Test description",
|
|
IssueType: "task",
|
|
Priority: 2,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Create failed: %v", err)
|
|
}
|
|
}
|
|
|
|
// Create a temp file for export
|
|
tmpFile, err := os.CreateTemp("", "beads-export-*.jsonl")
|
|
if err != nil {
|
|
t.Fatalf("Failed to create temp file: %v", err)
|
|
}
|
|
defer os.Remove(tmpFile.Name())
|
|
tmpFile.Close()
|
|
|
|
// Export to the temp file
|
|
resp, err := client.Export(&ExportArgs{
|
|
JSONLPath: tmpFile.Name(),
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Export failed: %v", err)
|
|
}
|
|
|
|
if !resp.Success {
|
|
t.Fatalf("Expected success, got error: %s", resp.Error)
|
|
}
|
|
|
|
// Verify file was written
|
|
info, err := os.Stat(tmpFile.Name())
|
|
if err != nil {
|
|
t.Fatalf("Failed to stat export file: %v", err)
|
|
}
|
|
|
|
if info.Size() == 0 {
|
|
t.Error("Expected non-empty export file")
|
|
}
|
|
}
|
|
|
|
// TestMutationChan tests access to the mutation channel
|
|
func TestMutationChan(t *testing.T) {
|
|
server, _, cleanup := setupTestServer(t)
|
|
defer cleanup()
|
|
|
|
// Get the mutation channel
|
|
ch := server.MutationChan()
|
|
|
|
// Channel should be non-nil
|
|
if ch == nil {
|
|
t.Error("Expected non-nil mutation channel")
|
|
}
|
|
}
|
|
|
|
// TestResetDroppedEventsCount tests resetting the dropped events counter
|
|
func TestResetDroppedEventsCount(t *testing.T) {
|
|
server, _, cleanup := setupTestServer(t)
|
|
defer cleanup()
|
|
|
|
// Reset dropped events count (should not panic)
|
|
server.ResetDroppedEventsCount()
|
|
|
|
// No error means success
|
|
}
|