mirror of
https://github.com/Buriburizaem0n/nezha_domains.git
synced 2026-09-21 02:30:14 +00:00
test(agentcompat): add dashboard runtime harness
Co-authored-by: naiba/CloudCode <hi+cloudcode@nai.ba>
This commit is contained in:
@@ -0,0 +1,177 @@
|
||||
//go:build linux && agentcompat
|
||||
|
||||
package dashboard
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/nezhahq/nezha/model"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestMCPReceiptSet_MatchesUnorderedExactServerTaskIdentities(t *testing.T) {
|
||||
expectations := []MCPReceiptExpectation{
|
||||
{DashboardGeneration: 2, GateGeneration: 9, ServerID: 7, TaskID: 101, TaskType: model.TaskTypeExec},
|
||||
{DashboardGeneration: 2, GateGeneration: 9, ServerID: 8, TaskID: 102, TaskType: model.TaskTypeFsRead},
|
||||
}
|
||||
events := []MCPReceiptEvent{
|
||||
mcpReceiptEvent(1, 2, 9, 8, 102, model.TaskTypeFsRead, MCPReceiptTask),
|
||||
mcpReceiptEvent(2, 2, 9, 8, 102, model.TaskTypeFsRead, MCPReceiptResult),
|
||||
mcpReceiptEvent(3, 2, 9, 7, 101, model.TaskTypeExec, MCPReceiptTask),
|
||||
mcpReceiptEvent(4, 2, 9, 7, 101, model.TaskTypeExec, MCPReceiptResult),
|
||||
}
|
||||
|
||||
pairs, complete, err := matchMCPReceiptSet(events, MCPReceiptCursor{}, expectations)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.True(t, complete)
|
||||
require.Equal(t, uint64(7), pairs[0].Task.ServerID)
|
||||
require.Equal(t, uint64(101), pairs[0].Result.TaskID)
|
||||
require.Equal(t, uint64(8), pairs[1].Task.ServerID)
|
||||
require.Equal(t, uint64(102), pairs[1].Result.TaskID)
|
||||
}
|
||||
|
||||
func TestMCPReceiptSet_RejectsMissingDuplicateAndMismatchedReceipts(t *testing.T) {
|
||||
expectation := []MCPReceiptExpectation{{DashboardGeneration: 2, GateGeneration: 9, ServerID: 7, TaskID: 101, TaskType: model.TaskTypeExec}}
|
||||
task := mcpReceiptEvent(1, 2, 9, 7, 101, model.TaskTypeExec, MCPReceiptTask)
|
||||
|
||||
tests := map[string][]MCPReceiptEvent{
|
||||
"missing result": {task},
|
||||
"duplicate task identity": {task, mcpReceiptEvent(2, 2, 9, 7, 102, model.TaskTypeExec, MCPReceiptTask)},
|
||||
"duplicate task ID": {task, mcpReceiptEvent(2, 2, 9, 7, 101, model.TaskTypeExec, MCPReceiptTask)},
|
||||
"mismatched server": {mcpReceiptEvent(1, 2, 9, 8, 101, model.TaskTypeExec, MCPReceiptTask)},
|
||||
"result gate generation mismatch": {task, mcpReceiptEvent(2, 2, 10, 7, 101, model.TaskTypeExec, MCPReceiptResult)},
|
||||
"result dashboard generation mismatch": {task, mcpReceiptEvent(2, 3, 9, 7, 101, model.TaskTypeExec, MCPReceiptResult)},
|
||||
}
|
||||
for name, events := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
_, complete, err := matchMCPReceiptSet(events, MCPReceiptCursor{}, expectation)
|
||||
if name == "missing result" {
|
||||
require.NoError(t, err)
|
||||
require.False(t, complete)
|
||||
return
|
||||
}
|
||||
require.Error(t, err)
|
||||
require.False(t, complete)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMCPReceiptSet_WaitsForEventAndPreservesCursorGeneration(t *testing.T) {
|
||||
dashboard := newWaiterDashboard()
|
||||
dashboard.eventGeneration = 2
|
||||
dashboard.mcpReceiptEvents = []MCPReceiptEvent{
|
||||
mcpReceiptEvent(1, 1, 8, 7, 100, model.TaskTypeExec, MCPReceiptTask),
|
||||
mcpReceiptEvent(2, 1, 8, 7, 100, model.TaskTypeExec, MCPReceiptResult),
|
||||
}
|
||||
dashboard.mcpReceiptSequence = 2
|
||||
cursor := dashboard.MCPReceiptCursor()
|
||||
result := make(chan struct {
|
||||
pairs []MCPReceiptPair
|
||||
err error
|
||||
}, 1)
|
||||
ctx, cancel := context.WithTimeout(t.Context(), time.Second)
|
||||
defer cancel()
|
||||
go func() {
|
||||
pairs, err := dashboard.WaitForMCPReceiptSet(ctx, cursor, []MCPReceiptExpectation{{DashboardGeneration: 2, GateGeneration: 9, ServerID: 7, TaskID: 101, TaskType: model.TaskTypeExec}})
|
||||
result <- struct {
|
||||
pairs []MCPReceiptPair
|
||||
err error
|
||||
}{pairs: pairs, err: err}
|
||||
}()
|
||||
|
||||
dashboard.eventMu.Lock()
|
||||
dashboard.mcpReceiptEvents = append(dashboard.mcpReceiptEvents,
|
||||
mcpReceiptEvent(3, 2, 9, 7, 101, model.TaskTypeExec, MCPReceiptTask),
|
||||
mcpReceiptEvent(4, 2, 9, 7, 101, model.TaskTypeExec, MCPReceiptResult),
|
||||
)
|
||||
dashboard.mcpReceiptSequence = 4
|
||||
close(dashboard.eventNotify)
|
||||
dashboard.eventNotify = make(chan struct{})
|
||||
dashboard.eventMu.Unlock()
|
||||
|
||||
received := <-result
|
||||
require.NoError(t, received.err)
|
||||
require.Len(t, received.pairs, 1)
|
||||
require.Equal(t, uint64(101), received.pairs[0].Task.TaskID)
|
||||
require.Equal(t, uint64(2), received.pairs[0].Task.DashboardGeneration)
|
||||
require.Equal(t, uint64(9), received.pairs[0].Task.GateGeneration)
|
||||
}
|
||||
|
||||
func TestMCPReceiptSet_RespectsCancellationAndDeadline(t *testing.T) {
|
||||
dashboard := newWaiterDashboard()
|
||||
expectations := []MCPReceiptExpectation{{DashboardGeneration: 2, GateGeneration: 9, ServerID: 7, TaskID: 101, TaskType: model.TaskTypeExec}}
|
||||
|
||||
cancelled, cancel := context.WithCancel(t.Context())
|
||||
cancel()
|
||||
_, err := dashboard.WaitForMCPReceiptSet(cancelled, MCPReceiptCursor{}, expectations)
|
||||
require.ErrorIs(t, err, context.Canceled)
|
||||
|
||||
expired, expire := context.WithDeadline(t.Context(), time.Now())
|
||||
defer expire()
|
||||
_, err = dashboard.WaitForMCPReceiptSet(expired, MCPReceiptCursor{}, expectations)
|
||||
require.ErrorIs(t, err, context.DeadlineExceeded)
|
||||
}
|
||||
|
||||
func TestMCPReceiptSet_RejectsDuplicateExpectations(t *testing.T) {
|
||||
_, err := (&Dashboard{}).WaitForMCPReceiptSet(t.Context(), MCPReceiptCursor{}, []MCPReceiptExpectation{
|
||||
{DashboardGeneration: 2, GateGeneration: 9, ServerID: 7, TaskID: 101, TaskType: model.TaskTypeExec},
|
||||
{DashboardGeneration: 2, GateGeneration: 9, ServerID: 7, TaskID: 101, TaskType: model.TaskTypeExec},
|
||||
})
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestMCPReceiptSet_RejectsWrongExpectedGenerationAndTaskID(t *testing.T) {
|
||||
// Given
|
||||
events := []MCPReceiptEvent{
|
||||
mcpReceiptEvent(1, 2, 9, 7, 101, model.TaskTypeExec, MCPReceiptTask),
|
||||
mcpReceiptEvent(2, 2, 9, 7, 101, model.TaskTypeExec, MCPReceiptResult),
|
||||
}
|
||||
expectation := MCPReceiptExpectation{DashboardGeneration: 3, GateGeneration: 9, ServerID: 7, TaskID: 101, TaskType: model.TaskTypeExec}
|
||||
|
||||
// When
|
||||
_, _, err := matchMCPReceiptSet(events, MCPReceiptCursor{}, []MCPReceiptExpectation{expectation})
|
||||
|
||||
// Then
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestMCPReceiptSet_RejectsZeroGateGenerationExpectation(t *testing.T) {
|
||||
// Given
|
||||
dashboard := newWaiterDashboard()
|
||||
dashboard.eventGeneration = 2
|
||||
dashboard.mcpReceiptEvents = []MCPReceiptEvent{
|
||||
mcpReceiptEvent(1, 2, 9, 7, 101, model.TaskTypeExec, MCPReceiptTask),
|
||||
mcpReceiptEvent(2, 2, 9, 7, 101, model.TaskTypeExec, MCPReceiptResult),
|
||||
}
|
||||
expectation := []MCPReceiptExpectation{{DashboardGeneration: 2, GateGeneration: 0, ServerID: 7, TaskID: 101, TaskType: model.TaskTypeExec}}
|
||||
|
||||
// When
|
||||
_, err := dashboard.WaitForMCPReceiptSet(t.Context(), MCPReceiptCursor{}, expectation)
|
||||
|
||||
// Then
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestMCPReceiptSet_RejectsZeroTaskIDExpectation(t *testing.T) {
|
||||
// Given
|
||||
dashboard := newWaiterDashboard()
|
||||
dashboard.eventGeneration = 2
|
||||
dashboard.mcpReceiptEvents = []MCPReceiptEvent{
|
||||
mcpReceiptEvent(1, 2, 9, 7, 101, model.TaskTypeExec, MCPReceiptTask),
|
||||
mcpReceiptEvent(2, 2, 9, 7, 101, model.TaskTypeExec, MCPReceiptResult),
|
||||
}
|
||||
expectation := []MCPReceiptExpectation{{DashboardGeneration: 2, GateGeneration: 9, ServerID: 7, TaskID: 0, TaskType: model.TaskTypeExec}}
|
||||
|
||||
// When
|
||||
_, err := dashboard.WaitForMCPReceiptSet(t.Context(), MCPReceiptCursor{}, expectation)
|
||||
|
||||
// Then
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func mcpReceiptEvent(sequence, dashboardGeneration, gateGeneration, serverID, taskID, taskType uint64, kind MCPReceiptKind) MCPReceiptEvent {
|
||||
return MCPReceiptEvent{Sequence: sequence, DashboardGeneration: dashboardGeneration, GateGeneration: gateGeneration, ServerID: serverID, TaskID: taskID, TaskType: taskType, Kind: kind}
|
||||
}
|
||||
Reference in New Issue
Block a user