Mining/pkg/database/database_race_test.go
Claude 8c4e8bd8f2
ax(batch): rename abbreviated locals in test files
m→manager, wg→waitGroup, w→recorder, da→digestAuth, nc→nonceCount,
tt→testCase, tc→testCase, et→eventType, bt→bundleType, mu→mutex,
c→testCase, h→hash, p→point, s→statEntry across all test files.

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

273 lines
6.1 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 waitGroup sync.WaitGroup
// 10 goroutines inserting points concurrently
for i := 0; i < 10; i++ {
waitGroup.Add(1)
go func(minerIndex int) {
defer waitGroup.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)
}
waitGroup.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 waitGroup sync.WaitGroup
stop := make(chan struct{})
// Writer goroutine
waitGroup.Add(1)
go func() {
defer waitGroup.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++ {
waitGroup.Add(1)
go func() {
defer waitGroup.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)
waitGroup.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 waitGroup sync.WaitGroup
stop := make(chan struct{})
// Continuous inserts
waitGroup.Add(1)
go func() {
defer waitGroup.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
waitGroup.Add(1)
go func() {
defer waitGroup.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)
waitGroup.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 waitGroup sync.WaitGroup
// Multiple goroutines querying stats
for i := 0; i < 20; i++ {
waitGroup.Add(1)
go func() {
defer waitGroup.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
}
}
}()
}
waitGroup.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 waitGroup sync.WaitGroup
// Multiple goroutines querying all stats
for i := 0; i < 10; i++ {
waitGroup.Add(1)
go func() {
defer waitGroup.Done()
for j := 0; j < 30; j++ {
_, err := GetAllMinerStats()
if err != nil {
t.Errorf("GetAllMinerStats error: %v", err)
}
}
}()
}
// Concurrent inserts
waitGroup.Add(1)
go func() {
defer waitGroup.Done()
for i := 0; i < 50; i++ {
point := HashratePoint{
Timestamp: time.Now(),
Hashrate: 2000 + i,
}
InsertHashratePoint(nil, "all-stats-new", "xmrig", point, ResolutionHigh)
}
}()
waitGroup.Wait()
// Test passes if no race detector warnings
}