package mining import ( "context" "testing" "time" "forge-mesh/internal/api/types" "forge-mesh/internal/policy" ) func TestChainAdvancesOnTimeout(t *testing.T) { profile := policy.DefaultMiningProfile("test-wallet") profile.Tiers = []types.MiningTierSpec{ {Type: "oci", Duration: 0}, {Type: "xmrig", Duration: 0}, } cfg := DefaultChainConfig() cfg.HostID = "test-host" cfg.GateWindow = 200 * time.Millisecond cfg.PollInterval = 50 * time.Millisecond cfg.DefaultProbe = 2 * time.Second cfg.MinHashrateHps = 1500 chain := NewChain(profile, cfg) ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) defer cancel() go func() { _ = chain.Run(ctx) }() deadline := time.Now().Add(12 * time.Second) for time.Now().Before(deadline) { st := chain.Status() if st.CurrentTier >= 2 && st.HashrateHps >= cfg.MinHashrateHps { if st.Wallet != "test-wallet" { t.Fatalf("wallet pin broken: %q", st.Wallet) } chain.Stop() return } time.Sleep(100 * time.Millisecond) } t.Fatal("chain did not advance to tier 2 with hashrate") } func TestWalletPinnedAcrossTiers(t *testing.T) { profile := policy.DefaultMiningProfile("pinned-wallet-abc") cfg := DefaultChainConfig() cfg.HostID = "host-abc" cfg.MinHashrateHps = 1 chain := NewChain(profile, cfg) for _, spec := range profile.Tiers { runner, err := chain.buildRunner(spec) if err != nil { t.Fatal(err) } _ = runner } if chain.Status().Wallet != "pinned-wallet-abc" { t.Fatalf("expected pinned wallet, got %q", chain.Status().Wallet) } }