feat(mining): Increase test coverage for manager
Added tests for StartMiner and StopMiner in the manager, increasing test coverage for the pkg/mining package. Refactored the findMinerBinary function to fall back to the system PATH, making the application more robust and easier to test.
This commit is contained in:
parent
2885a152f3
commit
1e2fa7a85a
2 changed files with 135 additions and 77 deletions
|
|
@ -1,47 +1,104 @@
|
|||
package mining
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestManager_StartStopMultipleMiners tests starting and stopping multiple miners.
|
||||
func TestManager_StartStopMultipleMiners(t *testing.T) {
|
||||
manager := NewManager()
|
||||
defer manager.Stop()
|
||||
// setupTestManager creates a new Manager and a dummy executable for tests.
|
||||
// It also temporarily modifies the PATH to include the dummy executable's directory.
|
||||
func setupTestManager(t *testing.T) *Manager {
|
||||
dummyDir := t.TempDir()
|
||||
executableName := "xmrig"
|
||||
if runtime.GOOS == "windows" {
|
||||
executableName += ".exe"
|
||||
}
|
||||
dummyPath := filepath.Join(dummyDir, executableName)
|
||||
|
||||
configs := []*Config{
|
||||
{Pool: "pool1", Wallet: "wallet1"},
|
||||
// Create a script that does nothing but exit, to simulate the miner executable
|
||||
var script []byte
|
||||
if runtime.GOOS == "windows" {
|
||||
script = []byte("@echo off\r\nexit 0")
|
||||
} else {
|
||||
script = []byte("#!/bin/sh\nexit 0")
|
||||
}
|
||||
|
||||
minerNames := []string{"xmrig"}
|
||||
|
||||
for i, config := range configs {
|
||||
// Since we can't start a real miner in the test, we'll just check that the manager doesn't crash.
|
||||
// A more complete test would involve a mock miner.
|
||||
_, err := manager.StartMiner(minerNames[i], config)
|
||||
if err == nil {
|
||||
t.Errorf("Expected error when starting miner without executable")
|
||||
}
|
||||
if err := os.WriteFile(dummyPath, script, 0755); err != nil {
|
||||
t.Fatalf("Failed to create dummy miner executable: %v", err)
|
||||
}
|
||||
|
||||
// Prepend the dummy directory to the PATH
|
||||
originalPath := os.Getenv("PATH")
|
||||
t.Cleanup(func() {
|
||||
os.Setenv("PATH", originalPath)
|
||||
})
|
||||
os.Setenv("PATH", dummyDir+string(os.PathListSeparator)+originalPath)
|
||||
|
||||
return NewManager()
|
||||
}
|
||||
|
||||
// TestManager_collectMinerStats tests the stat collection logic.
|
||||
func TestManager_collectMinerStats(t *testing.T) {
|
||||
manager := NewManager()
|
||||
defer manager.Stop()
|
||||
// TestStartMiner tests the StartMiner function
|
||||
func TestStartMiner(t *testing.T) {
|
||||
m := setupTestManager(t)
|
||||
defer m.Stop()
|
||||
|
||||
// Since we can't start a real miner, we can't fully test this.
|
||||
// A more complete test would involve a mock miner that can be added to the manager.
|
||||
manager.collectMinerStats()
|
||||
}
|
||||
config := &Config{
|
||||
HTTPPort: 9001, // Use a different port to avoid conflict
|
||||
Pool: "test:1234",
|
||||
Wallet: "testwallet",
|
||||
}
|
||||
|
||||
// TestManager_GetMinerHashrateHistory tests getting hashrate history.
|
||||
func TestManager_GetMinerHashrateHistory(t *testing.T) {
|
||||
manager := NewManager()
|
||||
defer manager.Stop()
|
||||
// Case 1: Successfully start a supported miner
|
||||
miner, err := m.StartMiner("xmrig", config)
|
||||
if err != nil {
|
||||
t.Fatalf("Expected to start miner, but got error: %v", err)
|
||||
}
|
||||
if miner == nil {
|
||||
t.Fatal("Expected miner to be non-nil, but it was")
|
||||
}
|
||||
if _, exists := m.miners[miner.GetName()]; !exists {
|
||||
t.Errorf("Miner %s was not added to the manager's list", miner.GetName())
|
||||
}
|
||||
|
||||
_, err := manager.GetMinerHashrateHistory("non-existent")
|
||||
// Case 2: Attempt to start an unsupported miner
|
||||
_, err = m.StartMiner("unsupported", config)
|
||||
if err == nil {
|
||||
t.Error("Expected error for getting hashrate history for non-existent miner")
|
||||
t.Error("Expected an error when starting an unsupported miner, but got nil")
|
||||
}
|
||||
|
||||
// Case 3: Attempt to start a duplicate miner
|
||||
_, err = m.StartMiner("xmrig", config)
|
||||
if err == nil {
|
||||
t.Error("Expected an error when starting a duplicate miner, but got nil")
|
||||
}
|
||||
}
|
||||
|
||||
// TestStopMiner tests the StopMiner function
|
||||
func TestStopMiner(t *testing.T) {
|
||||
m := setupTestManager(t)
|
||||
defer m.Stop()
|
||||
|
||||
config := &Config{
|
||||
HTTPPort: 9002,
|
||||
Pool: "test:1234",
|
||||
Wallet: "testwallet",
|
||||
}
|
||||
|
||||
// Case 1: Stop a running miner
|
||||
miner, _ := m.StartMiner("xmrig", config)
|
||||
err := m.StopMiner(miner.GetName())
|
||||
if err != nil {
|
||||
t.Fatalf("Expected to stop miner, but got error: %v", err)
|
||||
}
|
||||
if _, exists := m.miners[miner.GetName()]; exists {
|
||||
t.Errorf("Miner %s was not removed from the manager's list", miner.GetName())
|
||||
}
|
||||
|
||||
// Case 2: Attempt to stop a non-existent miner
|
||||
err = m.StopMiner("nonexistent")
|
||||
if err == nil {
|
||||
t.Error("Expected an error when stopping a non-existent miner, but got nil")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
|
@ -161,76 +162,76 @@ func (m *XMRigMiner) Uninstall() error {
|
|||
return os.RemoveAll(m.GetPath())
|
||||
}
|
||||
|
||||
// CheckInstallation checks if the miner is installed and returns its details
|
||||
func (m *XMRigMiner) CheckInstallation() (*InstallationDetails, error) {
|
||||
// findMinerBinary searches for the miner executable, first in the standard installation path,
|
||||
// then falls back to the system's PATH.
|
||||
func (m *XMRigMiner) findMinerBinary() (string, error) {
|
||||
executableName := "xmrig"
|
||||
if runtime.GOOS == "windows" {
|
||||
executableName += ".exe"
|
||||
}
|
||||
|
||||
// 1. Check the standard installation directory first
|
||||
baseInstallPath := m.GetPath()
|
||||
details := &InstallationDetails{
|
||||
Path: baseInstallPath, // Initialize with base path, will be updated to versioned path
|
||||
}
|
||||
|
||||
if _, err := os.Stat(baseInstallPath); os.IsNotExist(err) {
|
||||
details.IsInstalled = false
|
||||
return details, nil
|
||||
}
|
||||
|
||||
// The directory exists, now check for the executable by finding the versioned sub-folder
|
||||
files, err := os.ReadDir(baseInstallPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not read installation directory: %w", err)
|
||||
}
|
||||
|
||||
var versionedDir string
|
||||
for _, f := range files {
|
||||
if f.IsDir() && strings.HasPrefix(f.Name(), "xmrig-") {
|
||||
versionedDir = f.Name()
|
||||
break
|
||||
if _, err := os.Stat(baseInstallPath); err == nil {
|
||||
files, err := os.ReadDir(baseInstallPath)
|
||||
if err == nil {
|
||||
for _, f := range files {
|
||||
if f.IsDir() && strings.HasPrefix(f.Name(), "xmrig-") {
|
||||
versionedPath := filepath.Join(baseInstallPath, f.Name())
|
||||
fullPath := filepath.Join(versionedPath, executableName)
|
||||
if _, err := os.Stat(fullPath); err == nil {
|
||||
log.Printf("Found miner binary at standard path: %s", fullPath)
|
||||
return fullPath, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if versionedDir == "" {
|
||||
details.IsInstalled = false // Directory exists but is empty or malformed
|
||||
return details, nil
|
||||
// 2. Fallback to searching the system PATH
|
||||
path, err := exec.LookPath(executableName)
|
||||
if err == nil {
|
||||
log.Printf("Found miner binary in system PATH: %s", path)
|
||||
return path, nil
|
||||
}
|
||||
|
||||
// Update the Path to be the versioned directory
|
||||
details.Path = filepath.Join(baseInstallPath, versionedDir)
|
||||
return "", errors.New("miner executable not found in standard directory or system PATH")
|
||||
}
|
||||
|
||||
var executableName string
|
||||
if runtime.GOOS == "windows" {
|
||||
executableName = "xmrig.exe"
|
||||
} else {
|
||||
executableName = "xmrig"
|
||||
}
|
||||
// CheckInstallation checks if the miner is installed and returns its details
|
||||
func (m *XMRigMiner) CheckInstallation() (*InstallationDetails, error) {
|
||||
details := &InstallationDetails{}
|
||||
|
||||
executablePath := filepath.Join(details.Path, executableName)
|
||||
if _, err := os.Stat(executablePath); os.IsNotExist(err) {
|
||||
details.IsInstalled = false // Versioned folder exists, but no executable
|
||||
return details, nil
|
||||
binaryPath, err := m.findMinerBinary()
|
||||
if err != nil {
|
||||
details.IsInstalled = false
|
||||
return details, nil // Return not-installed, but no error
|
||||
}
|
||||
|
||||
details.IsInstalled = true
|
||||
details.MinerBinary = executablePath // Set the full path to the miner binary
|
||||
details.MinerBinary = binaryPath
|
||||
details.Path = filepath.Dir(binaryPath) // The directory containing the executable
|
||||
|
||||
// Try to get the version from the executable
|
||||
cmd := exec.Command(executablePath, "--version")
|
||||
cmd := exec.Command(binaryPath, "--version")
|
||||
var out bytes.Buffer
|
||||
cmd.Stdout = &out
|
||||
if err := cmd.Run(); err != nil {
|
||||
details.Version = "Unknown (could not run executable)"
|
||||
return details, nil
|
||||
}
|
||||
|
||||
// XMRig version output is typically "XMRig 6.18.0"
|
||||
fields := strings.Fields(out.String())
|
||||
if len(fields) >= 2 {
|
||||
details.Version = fields[1]
|
||||
} else {
|
||||
details.Version = "Unknown (could not parse version)"
|
||||
// XMRig version output is typically "XMRig 6.18.0"
|
||||
fields := strings.Fields(out.String())
|
||||
if len(fields) >= 2 {
|
||||
details.Version = fields[1]
|
||||
} else {
|
||||
details.Version = "Unknown (could not parse version)"
|
||||
}
|
||||
}
|
||||
|
||||
// Update the XMRigMiner struct's Path and MinerBinary fields
|
||||
// Update the XMRigMiner struct's fields
|
||||
m.Path = details.Path
|
||||
m.MinerBinary = details.MinerBinary
|
||||
m.Version = details.Version // Keep the miner's version in sync
|
||||
|
||||
return details, nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue