Mining/pkg/database/database_race_test.go
Claude c67dca2a97
Some checks are pending
Security Scan / security (push) Waiting to run
Test / test (push) Waiting to run
ax(batch): apply Good/Bad/Ugly test naming to remaining test files
Second pass of test naming convention across xmrig_test.go,
xmrig_gpu_test.go, stats_collector_test.go, manager_race_test.go,
throttle_test.go, service_test.go, interface_test.go,
database_race_test.go. 30 additional tests renamed.

Co-Authored-By: Charon <charon@lethean.io>
2026-04-02 18:23:59 +01:00

273 lines
5.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package database
import (
"os"
"path/filepath"
"sync"
"testing"
"time"
)
// cleanup := setupRaceTestDB(t)
// defer cleanup()
func setupRaceTestDB(t *testing.T) func() {
tmpDir := t.TempDir()
dbPath := filepath.Join(tmpDir, "race_test.db")
config := Config{
Enabled: true,
Path: dbPath,
RetentionDays: 7,
}
if err := Initialize(config); err != nil {
t.Fatalf("Failed to initialize database: %v", err)
}
return func() {
Close()
os.Remove(dbPath)
}
}
// 10 goroutines × 100 inserts each → no race detector warnings
func TestDatabaseRace_ConcurrentHashrateInserts_Ugly(t *testing.T) {
cleanup := setupRaceTestDB(t)
defer cleanup()
var wg sync.WaitGroup
// 10 goroutines inserting points concurrently
for i := 0; i < 10; i++ {
wg.Add(1)
go func(minerIndex int) {
defer wg.Done()
minerName := "miner" + string(rune('A'+minerIndex))
minerType := "xmrig"
for j := 0; j < 100; j++ {
point := HashratePoint{
Timestamp: time.Now().Add(time.Duration(-j) * time.Second),
Hashrate: 1000 + minerIndex*100 + j,
}
err := InsertHashratePoint(nil, minerName, minerType, point, ResolutionHigh)
if err != nil {
t.Errorf("Insert error for %s: %v", minerName, err)
}
}
}(i)
}
wg.Wait()
// Verify data was inserted
for i := 0; i < 10; i++ {
minerName := "miner" + string(rune('A'+i))
history, err := GetHashrateHistory(minerName, ResolutionHigh, time.Now().Add(-2*time.Minute), time.Now())
if err != nil {
t.Errorf("Failed to get history for %s: %v", minerName, err)
}
if len(history) == 0 {
t.Errorf("Expected history for %s, got none", minerName)
}
}
}
// 1 writer + 5 readers concurrently → no race detector warnings
func TestDatabaseRace_ConcurrentInsertAndQuery_Ugly(t *testing.T) {
cleanup := setupRaceTestDB(t)
defer cleanup()
var wg sync.WaitGroup
stop := make(chan struct{})
// Writer goroutine
wg.Add(1)
go func() {
defer wg.Done()
for i := 0; ; i++ {
select {
case <-stop:
return
default:
point := HashratePoint{
Timestamp: time.Now(),
Hashrate: 1000 + i,
}
InsertHashratePoint(nil, "concurrent-test", "xmrig", point, ResolutionHigh)
time.Sleep(time.Millisecond)
}
}
}()
// Multiple reader goroutines
for i := 0; i < 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for j := 0; j < 50; j++ {
select {
case <-stop:
return
default:
GetHashrateHistory("concurrent-test", ResolutionHigh, time.Now().Add(-time.Hour), time.Now())
time.Sleep(2 * time.Millisecond)
}
}
}()
}
// Let it run for a bit
time.Sleep(200 * time.Millisecond)
close(stop)
wg.Wait()
// Test passes if no race detector warnings
}
// inserts (old + new data) + periodic Cleanup(7) → no race detector warnings
func TestDatabaseRace_ConcurrentInsertAndCleanup_Ugly(t *testing.T) {
cleanup := setupRaceTestDB(t)
defer cleanup()
var wg sync.WaitGroup
stop := make(chan struct{})
// Continuous inserts
wg.Add(1)
go func() {
defer wg.Done()
for i := 0; ; i++ {
select {
case <-stop:
return
default:
// Insert some old data and some new data
oldPoint := HashratePoint{
Timestamp: time.Now().AddDate(0, 0, -10), // 10 days old
Hashrate: 500 + i,
}
InsertHashratePoint(nil, "cleanup-test", "xmrig", oldPoint, ResolutionHigh)
newPoint := HashratePoint{
Timestamp: time.Now(),
Hashrate: 1000 + i,
}
InsertHashratePoint(nil, "cleanup-test", "xmrig", newPoint, ResolutionHigh)
time.Sleep(time.Millisecond)
}
}
}()
// Periodic cleanup
wg.Add(1)
go func() {
defer wg.Done()
for i := 0; i < 10; i++ {
select {
case <-stop:
return
default:
Cleanup(7) // 7 day retention
time.Sleep(20 * time.Millisecond)
}
}
}()
// Let it run
time.Sleep(200 * time.Millisecond)
close(stop)
wg.Wait()
// Test passes if no race detector warnings
}
// 20 goroutines × 50 GetHashrateStats calls → no race detector warnings
func TestDatabaseRace_ConcurrentStats_Ugly(t *testing.T) {
cleanup := setupRaceTestDB(t)
defer cleanup()
// Insert some test data
minerName := "stats-test"
for i := 0; i < 100; i++ {
point := HashratePoint{
Timestamp: time.Now().Add(time.Duration(-i) * time.Second),
Hashrate: 1000 + i*10,
}
InsertHashratePoint(nil, minerName, "xmrig", point, ResolutionHigh)
}
var wg sync.WaitGroup
// Multiple goroutines querying stats
for i := 0; i < 20; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for j := 0; j < 50; j++ {
stats, err := GetHashrateStats(minerName)
if err != nil {
t.Errorf("Stats error: %v", err)
}
if stats != nil && stats.TotalPoints == 0 {
// This is fine, data might be in flux
}
}
}()
}
wg.Wait()
// Test passes if no race detector warnings
}
// 10 readers + 1 writer concurrently on GetAllMinerStats → no race detector warnings
func TestDatabaseRace_ConcurrentGetAllStats_Ugly(t *testing.T) {
cleanup := setupRaceTestDB(t)
defer cleanup()
// Insert data for multiple miners
for m := 0; m < 5; m++ {
minerName := "all-stats-" + string(rune('A'+m))
for i := 0; i < 50; i++ {
point := HashratePoint{
Timestamp: time.Now().Add(time.Duration(-i) * time.Second),
Hashrate: 1000 + m*100 + i,
}
InsertHashratePoint(nil, minerName, "xmrig", point, ResolutionHigh)
}
}
var wg sync.WaitGroup
// Multiple goroutines querying all stats
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for j := 0; j < 30; j++ {
_, err := GetAllMinerStats()
if err != nil {
t.Errorf("GetAllMinerStats error: %v", err)
}
}
}()
}
// Concurrent inserts
wg.Add(1)
go func() {
defer wg.Done()
for i := 0; i < 50; i++ {
point := HashratePoint{
Timestamp: time.Now(),
Hashrate: 2000 + i,
}
InsertHashratePoint(nil, "all-stats-new", "xmrig", point, ResolutionHigh)
}
}()
wg.Wait()
// Test passes if no race detector warnings
}