Files
LINUX-AETHERFORGE/cmd/agent/tier_chain_test.go
drjones 3678b199d0
Some checks failed
Test / test (push) Has been cancelled
Initial commit: AetherForge Linux (forge-mesh) v0.1.0-dev
2026-07-04 09:31:23 +00:00

135 lines
3.2 KiB
Go

package main
import (
"context"
"net"
"testing"
"time"
"forge-mesh/internal/api/types"
"forge-mesh/internal/mining"
)
func startMockStratum(t *testing.T) (host, port string) {
t.Helper()
ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { _ = ln.Close() })
go func() {
for {
conn, err := ln.Accept()
if err != nil {
return
}
go func(c net.Conn) {
defer c.Close()
buf := make([]byte, 4096)
_, _ = c.Read(buf)
}(conn)
}
}()
host, port, _ = net.SplitHostPort(ln.Addr().String())
return host, port
}
func TestMinerTierChainStateMachine(t *testing.T) {
host, port := startMockStratum(t)
profile := types.MiningProfile{
WalletAddress: "chain-wallet",
Tiers: []types.MiningTierSpec{
{Type: "stratum", Duration: 0, Config: map[string]string{"algo": "rx/0"}},
{Type: "stratum", Duration: 0, Config: map[string]string{"algo": "rx/0"}},
},
}
cfg := mining.DefaultChainConfig()
cfg.HostID = "chain-host"
cfg.StratumHost = host
cfg.StratumXMRPort = port
cfg.GateWindow = 100 * time.Millisecond
cfg.PollInterval = 40 * time.Millisecond
cfg.DefaultProbe = 800 * time.Millisecond
cfg.MinHashrateHps = 500
chain := mining.NewChain(profile, cfg)
ctx, cancel := context.WithTimeout(context.Background(), 12*time.Second)
defer cancel()
go func() { _ = chain.Run(ctx) }()
seen := map[string]bool{}
deadline := time.Now().Add(10 * time.Second)
for time.Now().Before(deadline) {
st := chain.Status()
if st.TierState != "" {
seen[st.TierState] = true
}
if st.CurrentTier >= 1 && st.HashrateHps >= cfg.MinHashrateHps && st.TierState == mining.TierStateActive {
if st.Wallet != "chain-wallet" {
t.Fatalf("wallet not pinned: %q", st.Wallet)
}
break
}
time.Sleep(80 * time.Millisecond)
}
chain.Stop()
cancel()
if !seen[mining.TierStateProbing] {
t.Fatal("expected probing state in tier chain")
}
if !seen[mining.TierStateActive] {
t.Fatal("expected active state during mock stratum tier")
}
st := chain.Status()
if st.CurrentTier < 1 {
t.Fatalf("expected tier progression, got tier %d", st.CurrentTier)
}
}
func TestMinerTierChainMockHashrateGate(t *testing.T) {
host, port := startMockStratum(t)
profile := types.MiningProfile{
WalletAddress: "mock-wallet",
Tiers: []types.MiningTierSpec{
{Type: "stratum", Duration: 0, Config: map[string]string{"algo": "rx/0"}},
},
}
cfg := mining.DefaultChainConfig()
cfg.HostID = "mock-host"
cfg.StratumHost = host
cfg.StratumXMRPort = port
cfg.GateWindow = 50 * time.Millisecond
cfg.PollInterval = 25 * time.Millisecond
cfg.DefaultProbe = 2 * time.Second
cfg.MinHashrateHps = 100
chain := mining.NewChain(profile, cfg)
ctx, cancel := context.WithTimeout(context.Background(), 6*time.Second)
defer cancel()
go func() { _ = chain.Run(ctx) }()
deadline := time.Now().Add(5 * time.Second)
for time.Now().Before(deadline) {
st := chain.Status()
if st.HashrateHps >= cfg.MinHashrateHps && st.TierState == mining.TierStateActive {
if !st.Simulated {
t.Log("using real stratum path (non-simulated)")
}
chain.Stop()
return
}
time.Sleep(50 * time.Millisecond)
}
t.Fatal("mock stratum tier did not reach hashrate gate")
}