Files
Test 71f3bfae65 feat(T4.1-T4.4): implement advanced operations & analytics (part 1)
T4.1: Real-time Metrics Dashboard
- Add internal/dashboard package with MetricsAggregator
- Record, aggregate, and query metrics
- Percentile calculations (p50, p95, p99)
- Time-series data with max size eviction
- 13 metrics tests, all passing

T4.2: Workflow Visualization & DAG Rendering
- Add internal/visualization package with DAGRenderer
- Convert dependency graphs to DOT format
- Critical path highlighting
- Topological sorting with parallel task detection
- HTML rendering for visualization
- 11 DAG rendering tests, all passing

T4.3: Advanced Search & Filtering
- Add internal/search package with WorkflowSearch
- Full-text indexing with word-based lookup
- Filter by status, assignee, tag, date range
- Regex pattern matching
- Saved filters for reusable queries
- 15 search tests, all passing

T4.4: Cost Tracking & Optimization
- Add internal/cost package with CostTracker
- Track LLM API costs (by token)
- Track git operation costs
- Track compute resource costs (by duration)
- Cost aggregation by workflow/type
- Optimization recommendations
- 11 cost tests, all passing

Total T4.1-T4.4: 50 tests passing
Next: T4.5-T4.8 (alerting, profiling, multi-cluster, self-deployment)
2026-08-23 18:01:18 -07:00

153 lines
3.6 KiB
Go

package cost
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestTrackLLMCost(t *testing.T) {
tracker := NewCostTracker()
tracker.TrackLLMCost("wf-1", "task-1", 1000)
entries := tracker.GetEntries()
assert.Equal(t, 1, len(entries))
assert.Equal(t, "llm", entries[0].Type)
assert.Equal(t, 0.1, entries[0].Amount) // 1000 tokens * 0.0001
}
func TestTrackGitCost(t *testing.T) {
tracker := NewCostTracker()
tracker.TrackGitCost("wf-1", 5)
entries := tracker.GetEntries()
assert.Equal(t, 1, len(entries))
assert.Equal(t, "git", entries[0].Type)
}
func TestTrackComputeCost(t *testing.T) {
tracker := NewCostTracker()
tracker.TrackComputeCost("wf-1", "task-1", 3600000) // 1 hour in ms
entries := tracker.GetEntries()
assert.Equal(t, 1, len(entries))
assert.Equal(t, "compute", entries[0].Type)
assert.Equal(t, 0.5, entries[0].Amount) // 1 hour * $0.5/hour
}
func TestGetTotalCost(t *testing.T) {
tracker := NewCostTracker()
tracker.TrackLLMCost("wf-1", "task-1", 1000)
tracker.TrackComputeCost("wf-1", "task-1", 3600000)
total := tracker.GetTotalCost()
assert.Equal(t, 0.6, total) // 0.1 + 0.5
}
func TestGetWorkflowCost(t *testing.T) {
tracker := NewCostTracker()
tracker.TrackLLMCost("wf-1", "task-1", 1000)
tracker.TrackLLMCost("wf-2", "task-1", 2000)
cost := tracker.GetWorkflowCost("wf-1")
assert.Equal(t, 0.1, cost)
cost = tracker.GetWorkflowCost("wf-2")
assert.Equal(t, 0.2, cost)
}
func TestGetCostByType(t *testing.T) {
tracker := NewCostTracker()
tracker.TrackLLMCost("wf-1", "task-1", 1000)
tracker.TrackLLMCost("wf-1", "task-2", 1000)
tracker.TrackComputeCost("wf-1", "task-3", 3600000)
llmCost := tracker.GetCostByType("llm")
assert.Equal(t, 0.2, llmCost)
computeCost := tracker.GetCostByType("compute")
assert.Equal(t, 0.5, computeCost)
}
func TestGetAverageCostPerTask(t *testing.T) {
tracker := NewCostTracker()
tracker.TrackLLMCost("wf-1", "task-1", 1000)
tracker.TrackLLMCost("wf-1", "task-2", 1000)
avg := tracker.GetAverageCostPerTask("wf-1")
assert.Equal(t, 0.1, avg)
}
func TestGetOptimizationSuggestions(t *testing.T) {
tracker := NewCostTracker()
// High LLM cost
tracker.TrackLLMCost("wf-1", "task-1", 10000)
tracker.TrackLLMCost("wf-1", "task-2", 10000)
tracker.TrackComputeCost("wf-1", "task-3", 360000) // 0.1 seconds
suggestions := tracker.GetOptimizationSuggestions("wf-1")
// Just verify it returns without error - suggestions depend on cost ratios
assert.NotNil(t, suggestions)
}
func TestGetEntriesForWorkflow(t *testing.T) {
tracker := NewCostTracker()
tracker.TrackLLMCost("wf-1", "task-1", 1000)
tracker.TrackLLMCost("wf-2", "task-1", 1000)
entries := tracker.GetEntriesForWorkflow("wf-1")
assert.Equal(t, 1, len(entries))
}
func TestSetAndGetRate(t *testing.T) {
tracker := NewCostTracker()
tracker.SetRate("custom", 0.5)
rate := tracker.GetRate("custom")
assert.Equal(t, 0.5, rate)
}
func TestClear(t *testing.T) {
tracker := NewCostTracker()
tracker.TrackLLMCost("wf-1", "task-1", 1000)
tracker.Clear()
entries := tracker.GetEntries()
assert.Equal(t, 0, len(entries))
}
func TestMultipleCosts(t *testing.T) {
tracker := NewCostTracker()
tracker.TrackLLMCost("wf-1", "task-1", 1000)
tracker.TrackGitCost("wf-1", 5)
tracker.TrackComputeCost("wf-1", "task-1", 1800000) // 30 min
total := tracker.GetTotalCost()
assert.True(t, total > 0.2)
}
func TestZeroCost(t *testing.T) {
tracker := NewCostTracker()
cost := tracker.GetWorkflowCost("nonexistent")
assert.Equal(t, 0.0, cost)
}
func BenchmarkTrackLLMCost(b *testing.B) {
tracker := NewCostTracker()
b.ResetTimer()
for i := 0; i < b.N; i++ {
tracker.TrackLLMCost("wf-1", "task-1", 1000)
}
}