Major additions: - Community Next.js app (port 18187) for browsing claims with API docs - stemedb-chaos crate: Fault injection, chaos testing, CRDT properties - Latent ingestion system: Reddit/FDA ingesters with ADK-Go agents - Disputed claims handling: Manual review workflows and validation - Aphoria security scanner: New extractors (SQL injection, command injection, weak crypto, TLS version), policy-based ignores, UAT reports - Docker infrastructure: Dockerfile, docker-compose.yml for full stack - VulnBank demo: Intentionally vulnerable multi-language test corpus SDK & API enhancements: - Source registry handlers for tracking data provenance - Metrics endpoint - Skeptic filtering improvements Code quality: - Split 14 large files (>500 lines) into focused modules - All files now under 500-line limit per project guidelines Documentation: - Chaos testing guide, circuit breakers, observability docs - Phase 7 UAT documentation updates - Martin Kleppmann technical writer agent Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
171 lines
4.1 KiB
Go
171 lines
4.1 KiB
Go
//go:build integration
|
|
|
|
package steme
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// Integration tests for Query operations including lenses and filtering.
|
|
|
|
// TestIntegration_Query_WithLens tests querying with different lenses.
|
|
func TestIntegration_Query_WithLens(t *testing.T) {
|
|
client := getTestClient(t)
|
|
ctx := context.Background()
|
|
|
|
// Create a unique subject for this test
|
|
subject := uniqueSubject("IntegrationTest_Lens")
|
|
predicate := "has_revenue"
|
|
|
|
// Create multiple assertions with different values
|
|
assertions := []struct {
|
|
value float64
|
|
confidence float64
|
|
}{
|
|
{100.0, 0.9},
|
|
{105.0, 0.95},
|
|
{100.0, 0.85}, // Duplicate value to test consensus
|
|
}
|
|
|
|
for i, a := range assertions {
|
|
assertion := NewAssertion(subject, predicate).
|
|
WithNumber(a.value).
|
|
WithConfidence(a.confidence).
|
|
WithSourceHash("0000000000000000000000000000000000000000000000000000000000000000").
|
|
Build()
|
|
|
|
hash, err := client.Assert(ctx, assertion)
|
|
if err != nil {
|
|
t.Fatalf("Assert(%d) failed: %v", i, err)
|
|
}
|
|
|
|
t.Logf("Created assertion %d with hash: %s (value: %.1f, confidence: %.2f)",
|
|
i, hash, a.value, a.confidence)
|
|
}
|
|
|
|
// Small delay for indexing
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
// Test different lenses
|
|
lensTests := []struct {
|
|
name string
|
|
lens Lens
|
|
}{
|
|
{"Recency", LensRecency},
|
|
{"Consensus", LensConsensus},
|
|
{"Authority", LensAuthority},
|
|
}
|
|
|
|
for _, tt := range lensTests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
params := NewQuery().
|
|
WithSubject(subject).
|
|
WithPredicate(predicate).
|
|
WithLens(tt.lens).
|
|
Build()
|
|
|
|
result, err := client.Query(ctx, params)
|
|
if err != nil {
|
|
t.Fatalf("Query() with lens %s failed: %v", tt.lens, err)
|
|
}
|
|
|
|
if result.TotalCount == 0 {
|
|
t.Errorf("Query() with lens %s returned no results", tt.lens)
|
|
}
|
|
|
|
t.Logf("Lens %s returned %d results", tt.lens, result.TotalCount)
|
|
|
|
// Verify all results match our subject/predicate
|
|
for _, a := range result.Assertions {
|
|
if a.Subject != subject {
|
|
t.Errorf("Result has wrong subject: %s, want %s", a.Subject, subject)
|
|
}
|
|
|
|
if a.Predicate != predicate {
|
|
t.Errorf("Result has wrong predicate: %s, want %s", a.Predicate, predicate)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestIntegration_Query_NotFound tests querying for non-existent data.
|
|
func TestIntegration_Query_NotFound(t *testing.T) {
|
|
client := getTestClient(t)
|
|
ctx := context.Background()
|
|
|
|
// Query for a subject that definitely doesn't exist
|
|
subject := uniqueSubject("IntegrationTest_NonExistent")
|
|
|
|
params := NewQuery().
|
|
WithSubject(subject).
|
|
WithPredicate("does_not_exist").
|
|
Build()
|
|
|
|
result, err := client.Query(ctx, params)
|
|
if err != nil {
|
|
t.Fatalf("Query() failed: %v", err)
|
|
}
|
|
|
|
if result.TotalCount != 0 {
|
|
t.Errorf("Query() for non-existent data returned %d results, want 0", result.TotalCount)
|
|
}
|
|
|
|
if len(result.Assertions) != 0 {
|
|
t.Errorf("Query() for non-existent data returned %d assertions, want 0", len(result.Assertions))
|
|
}
|
|
|
|
if result.HasMore {
|
|
t.Error("Query() for non-existent data claims HasMore = true")
|
|
}
|
|
}
|
|
|
|
// TestIntegration_Query_Limit tests the limit parameter.
|
|
func TestIntegration_Query_Limit(t *testing.T) {
|
|
client := getTestClient(t)
|
|
ctx := context.Background()
|
|
|
|
subject := uniqueSubject("IntegrationTest_Limit")
|
|
predicate := "has_index"
|
|
|
|
// Create 5 assertions
|
|
const numAssertions = 5
|
|
for i := 0; i < numAssertions; i++ {
|
|
assertion := NewAssertion(subject, predicate).
|
|
WithNumber(float64(i)).
|
|
WithConfidence(0.9).
|
|
WithSourceHash("0000000000000000000000000000000000000000000000000000000000000000").
|
|
Build()
|
|
|
|
_, err := client.Assert(ctx, assertion)
|
|
if err != nil {
|
|
t.Fatalf("Assert(%d) failed: %v", i, err)
|
|
}
|
|
}
|
|
|
|
// Small delay for indexing
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
// Query with limit of 2
|
|
params := NewQuery().
|
|
WithSubject(subject).
|
|
WithPredicate(predicate).
|
|
WithLimit(2).
|
|
Build()
|
|
|
|
result, err := client.Query(ctx, params)
|
|
if err != nil {
|
|
t.Fatalf("Query() failed: %v", err)
|
|
}
|
|
|
|
if len(result.Assertions) > 2 {
|
|
t.Errorf("Query() with limit=2 returned %d results, want at most 2", len(result.Assertions))
|
|
}
|
|
|
|
if result.TotalCount > 2 && !result.HasMore {
|
|
t.Error("Query() should indicate HasMore when total > limit")
|
|
}
|
|
}
|