Mining/pkg/mining/profile_manager_test.go
Claude 14cf520778
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 convention across all packages
Renames test functions to follow TestFilename_Function_{Good,Bad,Ugly}
convention per AX test naming rules. Covers profile_manager_test.go
(11 tests), events_test.go (9 tests), container_test.go (8 tests),
logger_test.go (9 tests), database_test.go (10 tests).

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

365 lines
8.9 KiB
Go

package mining
import (
"encoding/json"
"os"
"path/filepath"
"sync"
"testing"
)
// setupTestProfileManager creates a ProfileManager with a temp config path.
func setupTestProfileManager(t *testing.T) (*ProfileManager, func()) {
tmpDir, err := os.MkdirTemp("", "profile-manager-test")
if err != nil {
t.Fatalf("failed to create temp dir: %v", err)
}
configPath := filepath.Join(tmpDir, "mining_profiles.json")
profileManager := &ProfileManager{
profiles: make(map[string]*MiningProfile),
configPath: configPath,
}
cleanup := func() {
os.RemoveAll(tmpDir)
}
return profileManager, cleanup
}
func TestProfileManager_Create_Good(t *testing.T) {
profileManager, cleanup := setupTestProfileManager(t)
defer cleanup()
profile := &MiningProfile{
Name: "Test Profile",
MinerType: "xmrig",
Config: RawConfig(`{"pool": "test.pool.com:3333"}`),
}
created, err := profileManager.CreateProfile(profile)
if err != nil {
t.Fatalf("failed to create profile: %v", err)
}
if created.ID == "" {
t.Error("created profile should have an ID")
}
if created.Name != "Test Profile" {
t.Errorf("expected name 'Test Profile', got '%s'", created.Name)
}
// Verify it's stored
retrieved, exists := profileManager.GetProfile(created.ID)
if !exists {
t.Error("profile should exist after creation")
}
if retrieved.Name != created.Name {
t.Errorf("retrieved name doesn't match: expected '%s', got '%s'", created.Name, retrieved.Name)
}
}
func TestProfileManager_Get_Good(t *testing.T) {
profileManager, cleanup := setupTestProfileManager(t)
defer cleanup()
// Get non-existent profile
_, exists := profileManager.GetProfile("non-existent-id")
if exists {
t.Error("GetProfile should return false for non-existent ID")
}
// Create and get
profile := &MiningProfile{
Name: "Get Test",
MinerType: "xmrig",
}
created, _ := profileManager.CreateProfile(profile)
retrieved, exists := profileManager.GetProfile(created.ID)
if !exists {
t.Error("GetProfile should return true for existing ID")
}
if retrieved.ID != created.ID {
t.Error("GetProfile returned wrong profile")
}
}
func TestProfileManager_GetAll_Good(t *testing.T) {
profileManager, cleanup := setupTestProfileManager(t)
defer cleanup()
// Empty list initially
profiles := profileManager.GetAllProfiles()
if len(profiles) != 0 {
t.Errorf("expected 0 profiles initially, got %d", len(profiles))
}
// Create multiple profiles
for i := 0; i < 3; i++ {
profileManager.CreateProfile(&MiningProfile{
Name: "Profile",
MinerType: "xmrig",
})
}
profiles = profileManager.GetAllProfiles()
if len(profiles) != 3 {
t.Errorf("expected 3 profiles, got %d", len(profiles))
}
}
func TestProfileManager_Update_Good(t *testing.T) {
profileManager, cleanup := setupTestProfileManager(t)
defer cleanup()
// Update non-existent profile
err := profileManager.UpdateProfile(&MiningProfile{ID: "non-existent"})
if err == nil {
t.Error("UpdateProfile should fail for non-existent profile")
}
// Create profile
profile := &MiningProfile{
Name: "Original Name",
MinerType: "xmrig",
}
created, _ := profileManager.CreateProfile(profile)
// Update it
created.Name = "Updated Name"
created.MinerType = "ttminer"
err = profileManager.UpdateProfile(created)
if err != nil {
t.Fatalf("failed to update profile: %v", err)
}
// Verify update
retrieved, _ := profileManager.GetProfile(created.ID)
if retrieved.Name != "Updated Name" {
t.Errorf("expected name 'Updated Name', got '%s'", retrieved.Name)
}
if retrieved.MinerType != "ttminer" {
t.Errorf("expected miner type 'ttminer', got '%s'", retrieved.MinerType)
}
}
func TestProfileManager_Delete_Good(t *testing.T) {
profileManager, cleanup := setupTestProfileManager(t)
defer cleanup()
// Delete non-existent profile
err := profileManager.DeleteProfile("non-existent")
if err == nil {
t.Error("DeleteProfile should fail for non-existent profile")
}
// Create and delete
profile := &MiningProfile{
Name: "Delete Me",
MinerType: "xmrig",
}
created, _ := profileManager.CreateProfile(profile)
err = profileManager.DeleteProfile(created.ID)
if err != nil {
t.Fatalf("failed to delete profile: %v", err)
}
// Verify deletion
_, exists := profileManager.GetProfile(created.ID)
if exists {
t.Error("profile should not exist after deletion")
}
}
func TestProfileManager_Persistence_Good(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "profile-persist-test")
if err != nil {
t.Fatalf("failed to create temp dir: %v", err)
}
defer os.RemoveAll(tmpDir)
configPath := filepath.Join(tmpDir, "mining_profiles.json")
// Create first manager and add profile
firstProfileManager := &ProfileManager{
profiles: make(map[string]*MiningProfile),
configPath: configPath,
}
profile := &MiningProfile{
Name: "Persistent Profile",
MinerType: "xmrig",
Config: RawConfig(`{"pool": "persist.pool.com"}`),
}
created, err := firstProfileManager.CreateProfile(profile)
if err != nil {
t.Fatalf("failed to create profile: %v", err)
}
// Create second manager with same path - should load existing profile
secondProfileManager := &ProfileManager{
profiles: make(map[string]*MiningProfile),
configPath: configPath,
}
err = secondProfileManager.loadProfiles()
if err != nil {
t.Fatalf("failed to load profiles: %v", err)
}
// Verify profile persisted
loaded, exists := secondProfileManager.GetProfile(created.ID)
if !exists {
t.Fatal("profile should be loaded from file")
}
if loaded.Name != "Persistent Profile" {
t.Errorf("expected name 'Persistent Profile', got '%s'", loaded.Name)
}
}
func TestProfileManager_Concurrency_Ugly(t *testing.T) {
profileManager, cleanup := setupTestProfileManager(t)
defer cleanup()
var waitGroup sync.WaitGroup
numGoroutines := 10
// Concurrent creates
for i := 0; i < numGoroutines; i++ {
waitGroup.Add(1)
go func(n int) {
defer waitGroup.Done()
profileManager.CreateProfile(&MiningProfile{
Name: "Concurrent Profile",
MinerType: "xmrig",
})
}(i)
}
waitGroup.Wait()
profiles := profileManager.GetAllProfiles()
if len(profiles) != numGoroutines {
t.Errorf("expected %d profiles, got %d", numGoroutines, len(profiles))
}
// Concurrent reads
for i := 0; i < numGoroutines; i++ {
waitGroup.Add(1)
go func() {
defer waitGroup.Done()
profileManager.GetAllProfiles()
}()
}
waitGroup.Wait()
}
func TestProfileManager_InvalidJSON_Bad(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "profile-invalid-test")
if err != nil {
t.Fatalf("failed to create temp dir: %v", err)
}
defer os.RemoveAll(tmpDir)
configPath := filepath.Join(tmpDir, "mining_profiles.json")
// Write invalid JSON
err = os.WriteFile(configPath, []byte("invalid json{{{"), 0644)
if err != nil {
t.Fatalf("failed to write invalid JSON: %v", err)
}
profileManager := &ProfileManager{
profiles: make(map[string]*MiningProfile),
configPath: configPath,
}
err = profileManager.loadProfiles()
if err == nil {
t.Error("loadProfiles should fail with invalid JSON")
}
}
func TestProfileManager_FileNotFound_Bad(t *testing.T) {
profileManager := &ProfileManager{
profiles: make(map[string]*MiningProfile),
configPath: "/non/existent/path/profiles.json",
}
err := profileManager.loadProfiles()
if err == nil {
t.Error("loadProfiles should fail when file not found")
}
if !os.IsNotExist(err) {
t.Errorf("expected 'file not found' error, got: %v", err)
}
}
func TestProfileManager_CreateRollback_Ugly(t *testing.T) {
profileManager := &ProfileManager{
profiles: make(map[string]*MiningProfile),
configPath: "/invalid/path/that/cannot/be/written/profiles.json",
}
profile := &MiningProfile{
Name: "Rollback Test",
MinerType: "xmrig",
}
_, err := profileManager.CreateProfile(profile)
if err == nil {
t.Error("CreateProfile should fail when save fails")
}
// Verify rollback - profile should not be in memory
profiles := profileManager.GetAllProfiles()
if len(profiles) != 0 {
t.Error("failed create should rollback - no profile should be in memory")
}
}
func TestProfileManager_ConfigWithData_Good(t *testing.T) {
profileManager, cleanup := setupTestProfileManager(t)
defer cleanup()
config := RawConfig(`{
"pool": "pool.example.com:3333",
"wallet": "wallet123",
"threads": 4,
"algorithm": "rx/0"
}`)
profile := &MiningProfile{
Name: "Config Test",
MinerType: "xmrig",
Config: config,
}
created, err := profileManager.CreateProfile(profile)
if err != nil {
t.Fatalf("failed to create profile: %v", err)
}
retrieved, _ := profileManager.GetProfile(created.ID)
// Parse config to verify
var parsedConfig map[string]interface{}
err = json.Unmarshal(retrieved.Config, &parsedConfig)
if err != nil {
t.Fatalf("failed to parse config: %v", err)
}
if parsedConfig["pool"] != "pool.example.com:3333" {
t.Error("config pool value not preserved")
}
if parsedConfig["threads"].(float64) != 4 {
t.Error("config threads value not preserved")
}
}