Files
dex/pkg/metric/metric_test.go
zeekay 1aa4e9b3bb refactor: Q-Chain is verifier, not price source
Q-Chain provides quantum finality verification for prices/orders from
other sources, NOT its own price feed. Changes:

- Rename QChainSource to QChainVerifier (with backwards compat alias)
- Remove Q-Chain from price aggregator (not a Source interface)
- Q-Chain only used with -verify flag to verify finality
- Update architecture diagram to show Q-Chain as verification layer

Price Sources (6 total):
- X-Chain (2.0): Native DEX orderbook
- C-Chain (1.8): AMM pools
- Zoo Chain (1.7): Zoo Labs DEX
- A-Chain (1.5): Validator-attested network oracle
- Pyth (1.2): External oracle
- Chainlink (1.0): External oracle (reference)

Q-Chain Verifier:
- Post-quantum signatures (dilithium, sphincs+)
- Cross-chain order inclusion proofs
- Validator quorum consensus (3/4)
- ~50ms finality latency
2025-12-11 14:44:34 -08:00

241 lines
5.0 KiB
Go

package metric
import (
"sync"
"testing"
"github.com/stretchr/testify/assert"
)
func TestNewRegistry(t *testing.T) {
reg := NewRegistry()
assert.NotNil(t, reg)
assert.NotNil(t, reg.counters)
assert.NotNil(t, reg.histograms)
}
func TestCounterInc(t *testing.T) {
counter := &Counter{}
assert.Equal(t, int64(0), counter.Count())
counter.Inc(1)
assert.Equal(t, int64(1), counter.Count())
counter.Inc(5)
assert.Equal(t, int64(6), counter.Count())
counter.Inc(10)
assert.Equal(t, int64(16), counter.Count())
}
func TestCounterConcurrency(t *testing.T) {
counter := &Counter{}
var wg sync.WaitGroup
// 100 goroutines each incrementing 1000 times
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for j := 0; j < 1000; j++ {
counter.Inc(1)
}
}()
}
wg.Wait()
assert.Equal(t, int64(100000), counter.Count())
}
func TestRegistryCounter(t *testing.T) {
reg := NewRegistry()
// Get counter creates new one
c1 := reg.Counter("requests_total")
assert.NotNil(t, c1)
assert.Equal(t, int64(0), c1.Count())
// Increment it
c1.Inc(5)
assert.Equal(t, int64(5), c1.Count())
// Get same counter returns same instance
c2 := reg.Counter("requests_total")
assert.Equal(t, int64(5), c2.Count())
// Different name creates different counter
c3 := reg.Counter("errors_total")
assert.Equal(t, int64(0), c3.Count())
}
func TestRegistryCounterConcurrency(t *testing.T) {
reg := NewRegistry()
var wg sync.WaitGroup
// Multiple goroutines getting and incrementing same counter
for i := 0; i < 50; i++ {
wg.Add(1)
go func() {
defer wg.Done()
counter := reg.Counter("concurrent_counter")
for j := 0; j < 100; j++ {
counter.Inc(1)
}
}()
}
wg.Wait()
assert.Equal(t, int64(5000), reg.Counter("concurrent_counter").Count())
}
func TestHistogramObserve(t *testing.T) {
h := &Histogram{values: make([]float64, 0)}
h.Observe(1.0)
h.Observe(2.0)
h.Observe(3.0)
assert.Len(t, h.values, 3)
}
func TestHistogramPercentile(t *testing.T) {
h := &Histogram{values: make([]float64, 0)}
// Empty histogram
assert.Equal(t, 0.0, h.Percentile(0.5))
// Add values
h.Observe(10.0)
h.Observe(20.0)
h.Observe(30.0)
// Current implementation returns average
p50 := h.Percentile(0.5)
assert.Equal(t, 20.0, p50) // Average of 10, 20, 30
}
func TestHistogramConcurrency(t *testing.T) {
h := &Histogram{values: make([]float64, 0, 10000)}
var wg sync.WaitGroup
// Multiple goroutines observing values
for i := 0; i < 100; i++ {
wg.Add(1)
go func(val float64) {
defer wg.Done()
for j := 0; j < 100; j++ {
h.Observe(val)
}
}(float64(i))
}
wg.Wait()
assert.Len(t, h.values, 10000)
}
func TestRegistryHistogram(t *testing.T) {
reg := NewRegistry()
// Get histogram creates new one
h1 := reg.Histogram("latency_ms")
assert.NotNil(t, h1)
// Observe values
h1.Observe(10.0)
h1.Observe(20.0)
// Get same histogram returns same instance
h2 := reg.Histogram("latency_ms")
h2.Observe(30.0)
// Should have all 3 values
assert.Equal(t, 20.0, h1.Percentile(0.5)) // Average: (10+20+30)/3
// Different name creates different histogram
h3 := reg.Histogram("other_latency")
assert.Equal(t, 0.0, h3.Percentile(0.5))
}
func TestRegistryMultipleMetrics(t *testing.T) {
reg := NewRegistry()
// Create various metrics
requestCounter := reg.Counter("http_requests_total")
errorCounter := reg.Counter("http_errors_total")
latencyHist := reg.Histogram("http_request_duration_ms")
sizeHist := reg.Histogram("http_response_size_bytes")
// Use them
requestCounter.Inc(100)
errorCounter.Inc(5)
latencyHist.Observe(50.0)
latencyHist.Observe(100.0)
sizeHist.Observe(1024.0)
// Verify
assert.Equal(t, int64(100), requestCounter.Count())
assert.Equal(t, int64(5), errorCounter.Count())
assert.Equal(t, 75.0, latencyHist.Percentile(0.5))
assert.Equal(t, 1024.0, sizeHist.Percentile(0.5))
}
func TestCounterNegativeIncrement(t *testing.T) {
counter := &Counter{}
counter.Inc(10)
counter.Inc(-3) // Decrement
assert.Equal(t, int64(7), counter.Count())
}
func TestRegistryGetOrCreate(t *testing.T) {
reg := NewRegistry()
// First call creates
c1 := reg.Counter("test")
c1.Inc(5)
// Second call returns existing
c2 := reg.Counter("test")
assert.Equal(t, int64(5), c2.Count())
// Same for histogram
h1 := reg.Histogram("test_hist")
h1.Observe(100.0)
h2 := reg.Histogram("test_hist")
assert.Equal(t, 100.0, h2.Percentile(0.5))
}
func TestHistogramWithManyValues(t *testing.T) {
h := &Histogram{values: make([]float64, 0, 1000)}
// Add 1000 values from 1 to 1000
for i := 1; i <= 1000; i++ {
h.Observe(float64(i))
}
// Average should be 500.5
avg := h.Percentile(0.5)
assert.InDelta(t, 500.5, avg, 0.001)
}
func BenchmarkCounterInc(b *testing.B) {
counter := &Counter{}
for i := 0; i < b.N; i++ {
counter.Inc(1)
}
}
func BenchmarkHistogramObserve(b *testing.B) {
h := &Histogram{values: make([]float64, 0, b.N)}
for i := 0; i < b.N; i++ {
h.Observe(float64(i))
}
}
func BenchmarkRegistryCounter(b *testing.B) {
reg := NewRegistry()
for i := 0; i < b.N; i++ {
reg.Counter("test").Inc(1)
}
}