Renames 2-3 letter abbreviated locals to predictable names per AX Principle 1: pm→profileManager, sm→settingsManager, rl→rateLimiter, cb→breaker, hr→rate, wg→waitGroup, pm1/pm2→firstProfileManager/ secondProfileManager, cb1/cb2→firstBreaker/secondBreaker. Co-Authored-By: Charon <charon@lethean.io>
227 lines
6.5 KiB
Go
227 lines
6.5 KiB
Go
package mining
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
func TestSettingsManager_DefaultSettings_Good(t *testing.T) {
|
|
defaults := DefaultSettings()
|
|
|
|
if defaults.Window.Width != 1400 {
|
|
t.Errorf("Expected default width 1400, got %d", defaults.Window.Width)
|
|
}
|
|
if defaults.Window.Height != 900 {
|
|
t.Errorf("Expected default height 900, got %d", defaults.Window.Height)
|
|
}
|
|
if defaults.MinerDefaults.CPUMaxThreadsHint != 50 {
|
|
t.Errorf("Expected default CPU hint 50, got %d", defaults.MinerDefaults.CPUMaxThreadsHint)
|
|
}
|
|
if defaults.MinerDefaults.CPUThrottleThreshold != 80 {
|
|
t.Errorf("Expected default throttle threshold 80, got %d", defaults.MinerDefaults.CPUThrottleThreshold)
|
|
}
|
|
if !defaults.PauseOnBattery {
|
|
t.Error("Expected PauseOnBattery to be true by default")
|
|
}
|
|
}
|
|
|
|
func TestSettingsManager_SaveAndLoad_Good(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
settingsPath := filepath.Join(tmpDir, "settings.json")
|
|
|
|
settingsManager := &SettingsManager{
|
|
settings: DefaultSettings(),
|
|
settingsPath: settingsPath,
|
|
}
|
|
|
|
settingsManager.settings.Window.Width = 1920
|
|
settingsManager.settings.Window.Height = 1080
|
|
settingsManager.settings.StartOnBoot = true
|
|
settingsManager.settings.AutostartMiners = true
|
|
settingsManager.settings.CPUThrottlePercent = 50
|
|
|
|
err := settingsManager.Save()
|
|
if err != nil {
|
|
t.Fatalf("Failed to save settings: %v", err)
|
|
}
|
|
|
|
if _, err := os.Stat(settingsPath); os.IsNotExist(err) {
|
|
t.Fatal("Settings file was not created")
|
|
}
|
|
|
|
loadedSettingsManager := &SettingsManager{
|
|
settings: DefaultSettings(),
|
|
settingsPath: settingsPath,
|
|
}
|
|
err = loadedSettingsManager.Load()
|
|
if err != nil {
|
|
t.Fatalf("Failed to load settings: %v", err)
|
|
}
|
|
|
|
if loadedSettingsManager.settings.Window.Width != 1920 {
|
|
t.Errorf("Expected width 1920, got %d", loadedSettingsManager.settings.Window.Width)
|
|
}
|
|
if loadedSettingsManager.settings.Window.Height != 1080 {
|
|
t.Errorf("Expected height 1080, got %d", loadedSettingsManager.settings.Window.Height)
|
|
}
|
|
if !loadedSettingsManager.settings.StartOnBoot {
|
|
t.Error("Expected StartOnBoot to be true")
|
|
}
|
|
if !loadedSettingsManager.settings.AutostartMiners {
|
|
t.Error("Expected AutostartMiners to be true")
|
|
}
|
|
if loadedSettingsManager.settings.CPUThrottlePercent != 50 {
|
|
t.Errorf("Expected CPUThrottlePercent 50, got %d", loadedSettingsManager.settings.CPUThrottlePercent)
|
|
}
|
|
}
|
|
|
|
func TestSettingsManager_SaveAndLoad_Bad(t *testing.T) {
|
|
// Load from a path that does not exist — must return an error.
|
|
settingsManager := &SettingsManager{
|
|
settings: DefaultSettings(),
|
|
settingsPath: filepath.Join(t.TempDir(), "does_not_exist", "settings.json"),
|
|
}
|
|
|
|
if err := settingsManager.Load(); err == nil {
|
|
t.Error("Expected error loading from missing path, got nil")
|
|
}
|
|
}
|
|
|
|
func TestSettingsManager_UpdateWindowState_Good(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
settingsPath := filepath.Join(tmpDir, "settings.json")
|
|
|
|
settingsManager := &SettingsManager{
|
|
settings: DefaultSettings(),
|
|
settingsPath: settingsPath,
|
|
}
|
|
|
|
err := settingsManager.UpdateWindowState(100, 200, 800, 600, false)
|
|
if err != nil {
|
|
t.Fatalf("Failed to update window state: %v", err)
|
|
}
|
|
|
|
state := settingsManager.GetWindowState()
|
|
if state.X != 100 {
|
|
t.Errorf("Expected X 100, got %d", state.X)
|
|
}
|
|
if state.Y != 200 {
|
|
t.Errorf("Expected Y 200, got %d", state.Y)
|
|
}
|
|
if state.Width != 800 {
|
|
t.Errorf("Expected Width 800, got %d", state.Width)
|
|
}
|
|
if state.Height != 600 {
|
|
t.Errorf("Expected Height 600, got %d", state.Height)
|
|
}
|
|
}
|
|
|
|
func TestSettingsManager_SetCPUThrottle_Good(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
settingsPath := filepath.Join(tmpDir, "settings.json")
|
|
|
|
settingsManager := &SettingsManager{
|
|
settings: DefaultSettings(),
|
|
settingsPath: settingsPath,
|
|
}
|
|
|
|
err := settingsManager.SetCPUThrottle(true, 30)
|
|
if err != nil {
|
|
t.Fatalf("Failed to set CPU throttle: %v", err)
|
|
}
|
|
|
|
settings := settingsManager.Get()
|
|
if !settings.EnableCPUThrottle {
|
|
t.Error("Expected EnableCPUThrottle to be true")
|
|
}
|
|
if settings.CPUThrottlePercent != 30 {
|
|
t.Errorf("Expected CPUThrottlePercent 30, got %d", settings.CPUThrottlePercent)
|
|
}
|
|
}
|
|
|
|
func TestSettingsManager_SetCPUThrottle_Bad(t *testing.T) {
|
|
// An out-of-range percentage (>100) must be ignored, leaving the prior value unchanged.
|
|
tmpDir := t.TempDir()
|
|
settingsPath := filepath.Join(tmpDir, "settings.json")
|
|
|
|
settingsManager := &SettingsManager{
|
|
settings: DefaultSettings(),
|
|
settingsPath: settingsPath,
|
|
}
|
|
|
|
if err := settingsManager.SetCPUThrottle(true, 30); err != nil {
|
|
t.Fatalf("Setup: failed to set initial throttle: %v", err)
|
|
}
|
|
|
|
if err := settingsManager.SetCPUThrottle(true, 150); err != nil {
|
|
t.Fatalf("Expected no error on invalid percent, got: %v", err)
|
|
}
|
|
|
|
settings := settingsManager.Get()
|
|
if settings.CPUThrottlePercent != 30 {
|
|
t.Errorf("Expected CPUThrottlePercent to remain 30 after invalid input, got %d", settings.CPUThrottlePercent)
|
|
}
|
|
}
|
|
|
|
func TestSettingsManager_SetMinerDefaults_Good(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
settingsPath := filepath.Join(tmpDir, "settings.json")
|
|
|
|
settingsManager := &SettingsManager{
|
|
settings: DefaultSettings(),
|
|
settingsPath: settingsPath,
|
|
}
|
|
|
|
minerDefaults := MinerDefaults{
|
|
DefaultPool: "stratum+tcp://pool.example.com:3333",
|
|
DefaultWallet: "wallet123",
|
|
DefaultAlgorithm: "rx/0",
|
|
CPUMaxThreadsHint: 25,
|
|
CPUThrottleThreshold: 90,
|
|
}
|
|
|
|
err := settingsManager.SetMinerDefaults(minerDefaults)
|
|
if err != nil {
|
|
t.Fatalf("Failed to set miner defaults: %v", err)
|
|
}
|
|
|
|
settings := settingsManager.Get()
|
|
if settings.MinerDefaults.DefaultPool != "stratum+tcp://pool.example.com:3333" {
|
|
t.Errorf("Expected pool to be set, got %s", settings.MinerDefaults.DefaultPool)
|
|
}
|
|
if settings.MinerDefaults.CPUMaxThreadsHint != 25 {
|
|
t.Errorf("Expected CPUMaxThreadsHint 25, got %d", settings.MinerDefaults.CPUMaxThreadsHint)
|
|
}
|
|
}
|
|
|
|
func TestSettingsManager_ConcurrentAccess_Ugly(t *testing.T) {
|
|
// Ugly: concurrent reads and writes must not race or corrupt state.
|
|
tmpDir := t.TempDir()
|
|
settingsPath := filepath.Join(tmpDir, "settings.json")
|
|
|
|
settingsManager := &SettingsManager{
|
|
settings: DefaultSettings(),
|
|
settingsPath: settingsPath,
|
|
}
|
|
|
|
done := make(chan bool)
|
|
for i := 0; i < 10; i++ {
|
|
go func(n int) {
|
|
for j := 0; j < 100; j++ {
|
|
_ = settingsManager.Get()
|
|
settingsManager.UpdateWindowState(n*10, n*10, 800+n, 600+n, false)
|
|
}
|
|
done <- true
|
|
}(i)
|
|
}
|
|
|
|
for i := 0; i < 10; i++ {
|
|
<-done
|
|
}
|
|
|
|
state := settingsManager.GetWindowState()
|
|
if state.Width < 800 || state.Width > 900 {
|
|
t.Errorf("Unexpected width after concurrent access: %d", state.Width)
|
|
}
|
|
}
|