205 lines
5.4 KiB
Go
205 lines
5.4 KiB
Go
|
|
package database
|
||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"testing"
|
||
|
|
"time"
|
||
|
|
)
|
||
|
|
|
||
|
|
func TestDefaultStore(t *testing.T) {
|
||
|
|
cleanup := setupTestDB(t)
|
||
|
|
defer cleanup()
|
||
|
|
|
||
|
|
store := DefaultStore()
|
||
|
|
|
||
|
|
// Test InsertHashratePoint
|
||
|
|
point := HashratePoint{
|
||
|
|
Timestamp: time.Now(),
|
||
|
|
Hashrate: 1500,
|
||
|
|
}
|
||
|
|
if err := store.InsertHashratePoint(nil, "interface-test", "xmrig", point, ResolutionHigh); err != nil {
|
||
|
|
t.Fatalf("InsertHashratePoint failed: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Test GetHashrateHistory
|
||
|
|
history, err := store.GetHashrateHistory("interface-test", ResolutionHigh, time.Now().Add(-time.Hour), time.Now().Add(time.Hour))
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("GetHashrateHistory failed: %v", err)
|
||
|
|
}
|
||
|
|
if len(history) != 1 {
|
||
|
|
t.Errorf("Expected 1 point, got %d", len(history))
|
||
|
|
}
|
||
|
|
|
||
|
|
// Test GetHashrateStats
|
||
|
|
stats, err := store.GetHashrateStats("interface-test")
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("GetHashrateStats failed: %v", err)
|
||
|
|
}
|
||
|
|
if stats == nil {
|
||
|
|
t.Fatal("Expected non-nil stats")
|
||
|
|
}
|
||
|
|
if stats.TotalPoints != 1 {
|
||
|
|
t.Errorf("Expected 1 total point, got %d", stats.TotalPoints)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Test GetAllMinerStats
|
||
|
|
allStats, err := store.GetAllMinerStats()
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("GetAllMinerStats failed: %v", err)
|
||
|
|
}
|
||
|
|
if len(allStats) != 1 {
|
||
|
|
t.Errorf("Expected 1 miner in stats, got %d", len(allStats))
|
||
|
|
}
|
||
|
|
|
||
|
|
// Test Cleanup
|
||
|
|
if err := store.Cleanup(30); err != nil {
|
||
|
|
t.Fatalf("Cleanup failed: %v", err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestDefaultStore_WithContext(t *testing.T) {
|
||
|
|
cleanup := setupTestDB(t)
|
||
|
|
defer cleanup()
|
||
|
|
|
||
|
|
store := DefaultStore()
|
||
|
|
ctx := context.Background()
|
||
|
|
|
||
|
|
point := HashratePoint{
|
||
|
|
Timestamp: time.Now(),
|
||
|
|
Hashrate: 2000,
|
||
|
|
}
|
||
|
|
if err := store.InsertHashratePoint(ctx, "ctx-test", "xmrig", point, ResolutionHigh); err != nil {
|
||
|
|
t.Fatalf("InsertHashratePoint with context failed: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
history, err := store.GetHashrateHistory("ctx-test", ResolutionHigh, time.Now().Add(-time.Hour), time.Now().Add(time.Hour))
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("GetHashrateHistory failed: %v", err)
|
||
|
|
}
|
||
|
|
if len(history) != 1 {
|
||
|
|
t.Errorf("Expected 1 point, got %d", len(history))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestNopStore(t *testing.T) {
|
||
|
|
store := NopStore()
|
||
|
|
|
||
|
|
// All operations should succeed without error
|
||
|
|
point := HashratePoint{
|
||
|
|
Timestamp: time.Now(),
|
||
|
|
Hashrate: 1000,
|
||
|
|
}
|
||
|
|
if err := store.InsertHashratePoint(nil, "test", "xmrig", point, ResolutionHigh); err != nil {
|
||
|
|
t.Errorf("NopStore InsertHashratePoint should not error: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
history, err := store.GetHashrateHistory("test", ResolutionHigh, time.Now().Add(-time.Hour), time.Now())
|
||
|
|
if err != nil {
|
||
|
|
t.Errorf("NopStore GetHashrateHistory should not error: %v", err)
|
||
|
|
}
|
||
|
|
if history != nil {
|
||
|
|
t.Errorf("NopStore GetHashrateHistory should return nil, got %v", history)
|
||
|
|
}
|
||
|
|
|
||
|
|
stats, err := store.GetHashrateStats("test")
|
||
|
|
if err != nil {
|
||
|
|
t.Errorf("NopStore GetHashrateStats should not error: %v", err)
|
||
|
|
}
|
||
|
|
if stats != nil {
|
||
|
|
t.Errorf("NopStore GetHashrateStats should return nil, got %v", stats)
|
||
|
|
}
|
||
|
|
|
||
|
|
allStats, err := store.GetAllMinerStats()
|
||
|
|
if err != nil {
|
||
|
|
t.Errorf("NopStore GetAllMinerStats should not error: %v", err)
|
||
|
|
}
|
||
|
|
if allStats != nil {
|
||
|
|
t.Errorf("NopStore GetAllMinerStats should return nil, got %v", allStats)
|
||
|
|
}
|
||
|
|
|
||
|
|
if err := store.Cleanup(30); err != nil {
|
||
|
|
t.Errorf("NopStore Cleanup should not error: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
if err := store.Close(); err != nil {
|
||
|
|
t.Errorf("NopStore Close should not error: %v", err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// TestInterfaceCompatibility ensures all implementations satisfy HashrateStore
|
||
|
|
func TestInterfaceCompatibility(t *testing.T) {
|
||
|
|
var _ HashrateStore = DefaultStore()
|
||
|
|
var _ HashrateStore = NopStore()
|
||
|
|
var _ HashrateStore = &defaultStore{}
|
||
|
|
var _ HashrateStore = &nopStore{}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestDefaultStore_ContextCancellation(t *testing.T) {
|
||
|
|
cleanup := setupTestDB(t)
|
||
|
|
defer cleanup()
|
||
|
|
|
||
|
|
store := DefaultStore()
|
||
|
|
|
||
|
|
// Create a cancelled context
|
||
|
|
ctx, cancel := context.WithCancel(context.Background())
|
||
|
|
cancel()
|
||
|
|
|
||
|
|
point := HashratePoint{
|
||
|
|
Timestamp: time.Now(),
|
||
|
|
Hashrate: 1000,
|
||
|
|
}
|
||
|
|
|
||
|
|
// Insert with cancelled context should fail
|
||
|
|
err := store.InsertHashratePoint(ctx, "cancel-test", "xmrig", point, ResolutionHigh)
|
||
|
|
if err == nil {
|
||
|
|
t.Log("InsertHashratePoint with cancelled context succeeded (SQLite may not check context)")
|
||
|
|
} else {
|
||
|
|
t.Logf("InsertHashratePoint with cancelled context: %v (expected)", err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestDefaultStore_ContextTimeout(t *testing.T) {
|
||
|
|
cleanup := setupTestDB(t)
|
||
|
|
defer cleanup()
|
||
|
|
|
||
|
|
store := DefaultStore()
|
||
|
|
|
||
|
|
// Create a context that expires very quickly
|
||
|
|
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond)
|
||
|
|
defer cancel()
|
||
|
|
|
||
|
|
// Wait for timeout to expire
|
||
|
|
time.Sleep(1 * time.Millisecond)
|
||
|
|
|
||
|
|
point := HashratePoint{
|
||
|
|
Timestamp: time.Now(),
|
||
|
|
Hashrate: 1000,
|
||
|
|
}
|
||
|
|
|
||
|
|
// Insert with expired context
|
||
|
|
err := store.InsertHashratePoint(ctx, "timeout-test", "xmrig", point, ResolutionHigh)
|
||
|
|
if err == nil {
|
||
|
|
t.Log("InsertHashratePoint with expired context succeeded (SQLite may not check context)")
|
||
|
|
} else {
|
||
|
|
t.Logf("InsertHashratePoint with expired context: %v (expected)", err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestNopStore_WithContext(t *testing.T) {
|
||
|
|
store := NopStore()
|
||
|
|
|
||
|
|
// NopStore should work with any context, including cancelled ones
|
||
|
|
ctx, cancel := context.WithCancel(context.Background())
|
||
|
|
cancel()
|
||
|
|
|
||
|
|
point := HashratePoint{
|
||
|
|
Timestamp: time.Now(),
|
||
|
|
Hashrate: 1000,
|
||
|
|
}
|
||
|
|
|
||
|
|
// Should still succeed (nop store ignores context)
|
||
|
|
if err := store.InsertHashratePoint(ctx, "nop-cancel-test", "xmrig", point, ResolutionHigh); err != nil {
|
||
|
|
t.Errorf("NopStore should succeed even with cancelled context: %v", err)
|
||
|
|
}
|
||
|
|
}
|