mirror of
https://github.com/Buriburizaem0n/nezha_domains.git
synced 2026-09-19 17:50:12 +00:00
fix(mcp): harden dashboard dispatch lifecycle
Co-authored-by: naiba/CloudCode <hi+cloudcode@nai.ba>
This commit is contained in:
@@ -3,6 +3,7 @@ package rpc
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -33,6 +34,17 @@ func TestCallAgent_KillSwitchBeatsConcurrentLateResult(t *testing.T) {
|
||||
cleanup := installFakeServer(t, target, stream)
|
||||
defer cleanup()
|
||||
|
||||
resultSelected := make(chan struct{})
|
||||
resumeResult := make(chan struct{})
|
||||
var resultHook atomic.Pointer[func()]
|
||||
hook := func() {
|
||||
close(resultSelected)
|
||||
<-resumeResult
|
||||
}
|
||||
resultHook.Store(&hook)
|
||||
testMCPResultBeforeCancellationCheck.Store(resultHook.Load())
|
||||
t.Cleanup(func() { testMCPResultBeforeCancellationCheck.Store(nil) })
|
||||
|
||||
delivered := make(chan struct{})
|
||||
go func() {
|
||||
sent := <-stream.sent
|
||||
@@ -42,18 +54,67 @@ func TestCallAgent_KillSwitchBeatsConcurrentLateResult(t *testing.T) {
|
||||
Successful: true,
|
||||
Data: `{"exit_code":0,"stdout":"should-not-surface"}`,
|
||||
}, target)
|
||||
CancelAllMCPInflight()
|
||||
close(delivered)
|
||||
}()
|
||||
|
||||
_, err := CallAgent(context.Background(), target, model.TaskTypeExec,
|
||||
model.ExecRequest{Cmd: "x"}, 2*time.Second)
|
||||
errCh := make(chan error, 1)
|
||||
go func() {
|
||||
_, err := CallAgent(context.Background(), target, model.TaskTypeExec,
|
||||
model.ExecRequest{Cmd: "x"}, 2*time.Second)
|
||||
errCh <- err
|
||||
}()
|
||||
<-resultSelected
|
||||
CancelAllMCPInflight()
|
||||
close(resumeResult)
|
||||
<-delivered
|
||||
err := <-errCh
|
||||
if !errors.Is(err, ErrMCPDisabled) {
|
||||
t.Fatalf("kill switch must win the race with a late agent reply; want ErrMCPDisabled, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCallAgent_ResultBeforeKillSwitchReturnsSuccess(t *testing.T) {
|
||||
const target uint64 = 7303
|
||||
|
||||
stream := newFakeStream()
|
||||
cleanup := installFakeServer(t, target, stream)
|
||||
defer cleanup()
|
||||
|
||||
resultClaimed := make(chan struct{})
|
||||
resumeResult := make(chan struct{})
|
||||
var resultHook atomic.Pointer[func()]
|
||||
hook := func() {
|
||||
close(resultClaimed)
|
||||
<-resumeResult
|
||||
}
|
||||
resultHook.Store(&hook)
|
||||
testMCPResultAfterCancellationCheck.Store(resultHook.Load())
|
||||
t.Cleanup(func() { testMCPResultAfterCancellationCheck.Store(nil) })
|
||||
|
||||
go func() {
|
||||
sent := <-stream.sent
|
||||
deliverMCPResultFromReporter(&pb.TaskResult{
|
||||
Id: sent.GetId(),
|
||||
Type: model.TaskTypeExec,
|
||||
Successful: true,
|
||||
Data: `{"exit_code":0}`,
|
||||
}, target)
|
||||
}()
|
||||
|
||||
errCh := make(chan error, 1)
|
||||
go func() {
|
||||
_, err := CallAgent(context.Background(), target, model.TaskTypeExec,
|
||||
model.ExecRequest{Cmd: "x"}, 2*time.Second)
|
||||
errCh <- err
|
||||
}()
|
||||
<-resultClaimed
|
||||
CancelAllMCPInflight()
|
||||
close(resumeResult)
|
||||
if err := <-errCh; err != nil {
|
||||
t.Fatalf("result claimed before kill switch must succeed, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// CancelAllMCPInflight must eagerly evict entries so a stale TaskResult
|
||||
// that arrives after the kill switch cannot still land in resultCh.
|
||||
// Without the cancelled flag this entry would still be reachable through
|
||||
|
||||
Reference in New Issue
Block a user