mirror of
https://github.com/Buriburizaem0n/nezha_domains.git
synced 2026-09-19 17:50:12 +00:00
155 lines
6.6 KiB
Go
155 lines
6.6 KiB
Go
//go:build linux
|
|
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"os"
|
|
"path/filepath"
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/nezhahq/nezha/integration/agentcompat/internal/contract"
|
|
"github.com/nezhahq/nezha/integration/agentcompat/internal/scenario"
|
|
)
|
|
|
|
func TestCLI_SelectsTransferAndReconnectWithTypedEvidence(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
fault string
|
|
}{
|
|
{contract.ScenarioTransfer100MiB, ""},
|
|
{contract.ScenarioTransfer100MiB, contract.FaultTransferHash},
|
|
{contract.ScenarioReconnect, ""},
|
|
{contract.ScenarioReconnect, contract.FaultDashboardExit},
|
|
}
|
|
for _, test := range tests {
|
|
t.Run(test.name+"/"+test.fault, func(t *testing.T) {
|
|
config := testCLIConfig(t, test.name, test.fault)
|
|
runnerErr := errors.New("dedicated runner sentinel")
|
|
wantResult := scenario.Result{Name: test.name, Passed: false, CleanupOK: true, Error: runnerErr.Error(), Assertions: []scenario.Assertion{{Name: "typed dispatch", Passed: false, Details: test.fault}}}
|
|
wantTransfer := scenario.TransferEvidence{WarmupUploadBytes: 65536, WarmupDownloadBytes: 65536, WarmupSHA256: "warmup", WarmupDuration: time.Second, WarmupDeadlineRemaining: 2 * time.Second, WarmupQuiescent: true, UploadBytes: contract.TransferBytes, DownloadBytes: contract.TransferBytes, UploadSHA256: "transfer-hash", DownloadSHA256: "transfer-hash", UploadChunks: 3, DownloadChunks: 4, UploadDuration: 5 * time.Second, DownloadDuration: 6 * time.Second, RetainedHeapBytes: 7, Mode: "0640", CreateDirs: true, UploadReplayRejected: true, DownloadReplayRejected: true, OversizeRejected: true, OutsideRootSentinelsUnchanged: true}
|
|
wantReconnect := completeReconnectDispatchEvidence(t)
|
|
previousTransfer := runTransferScenario
|
|
previousReconnect := runReconnectScenario
|
|
var receivedTransfer *scenario.TransferInput
|
|
var receivedReconnect *scenario.ReconnectInput
|
|
runTransferScenario = func(_ context.Context, input scenario.TransferInput) (scenario.Result, scenario.TransferEvidence, error) {
|
|
receivedTransfer = &input
|
|
return wantResult, wantTransfer, runnerErr
|
|
}
|
|
runReconnectScenario = func(_ context.Context, input scenario.ReconnectInput) (scenario.Result, scenario.ReconnectEvidence, error) {
|
|
receivedReconnect = &input
|
|
return wantResult, wantReconnect, runnerErr
|
|
}
|
|
t.Cleanup(func() {
|
|
runTransferScenario = previousTransfer
|
|
runReconnectScenario = previousReconnect
|
|
})
|
|
|
|
execution, err := selectScenarioExecution(config)
|
|
if err != nil {
|
|
t.Fatalf("select execution: %v", err)
|
|
}
|
|
output, runErr := execution.run(context.Background())
|
|
if !errors.Is(runErr, runnerErr) {
|
|
t.Fatalf("runner error=%v, want sentinel", runErr)
|
|
}
|
|
if err := output.Validate(); err != nil {
|
|
t.Fatalf("validate typed output: %v", err)
|
|
}
|
|
if !reflect.DeepEqual(output.Result, wantResult) {
|
|
t.Fatalf("result=%#v, want %#v", output.Result, wantResult)
|
|
}
|
|
if test.name == contract.ScenarioTransfer100MiB {
|
|
wantInput := scenario.TransferInput{Paths: config.Paths, Fault: config.Fault}
|
|
if receivedTransfer == nil || *receivedTransfer != wantInput || receivedReconnect != nil {
|
|
t.Fatalf("transfer inputs: received=%#v reconnect=%#v want=%#v", receivedTransfer, receivedReconnect, wantInput)
|
|
}
|
|
if output.Transfer == nil || !reflect.DeepEqual(*output.Transfer, wantTransfer) || output.Reconnect != nil {
|
|
t.Fatalf("transfer evidence=%#v reconnect=%#v", output.Transfer, output.Reconnect)
|
|
}
|
|
} else {
|
|
wantInput := scenario.ReconnectInput{Paths: config.Paths, DashboardFault: config.Fault.String()}
|
|
if receivedReconnect == nil || *receivedReconnect != wantInput || receivedTransfer != nil {
|
|
t.Fatalf("reconnect inputs: received=%#v transfer=%#v want=%#v", receivedReconnect, receivedTransfer, wantInput)
|
|
}
|
|
if output.Reconnect == nil || !reflect.DeepEqual(*output.Reconnect, wantReconnect) || output.Transfer != nil {
|
|
t.Fatalf("reconnect evidence=%#v transfer=%#v", output.Reconnect, output.Transfer)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCLI_RejectsUnsupportedScenarioFaultPairsBeforeRunner(t *testing.T) {
|
|
tests := []struct{ scenario, fault string }{
|
|
{contract.ScenarioTransfer100MiB, contract.FaultDashboardExit},
|
|
{contract.ScenarioReconnect, contract.FaultTransferHash},
|
|
{contract.ScenarioMCPFilesystem, contract.FaultAgentBadSecret},
|
|
}
|
|
for _, test := range tests {
|
|
called := false
|
|
previousTransfer := runTransferScenario
|
|
runTransferScenario = func(context.Context, scenario.TransferInput) (scenario.Result, scenario.TransferEvidence, error) {
|
|
called = true
|
|
return scenario.Result{}, scenario.TransferEvidence{}, errors.New("unexpected")
|
|
}
|
|
_, err := selectScenarioExecution(testCLIConfig(t, test.scenario, test.fault))
|
|
runTransferScenario = previousTransfer
|
|
if err == nil || called {
|
|
t.Fatalf("unsupported pair started runner: scenario=%q fault=%q err=%v", test.scenario, test.fault, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestCLI_WritesDedicatedArtifactWithPrivateMode(t *testing.T) {
|
|
resultsDir := t.TempDir()
|
|
output := scenarioExecutionOutput{
|
|
Result: scenario.Result{Name: contract.ScenarioTransfer100MiB, Passed: false, CleanupOK: true, Error: "transfer scenario: injected hash mismatch"},
|
|
Transfer: &scenario.TransferEvidence{WarmupUploadBytes: 65536, WarmupDownloadBytes: 65536, WarmupSHA256: "abc", WarmupDuration: time.Nanosecond, WarmupDeadlineRemaining: time.Second, WarmupQuiescent: true, OutsideRootSentinelsUnchanged: true},
|
|
}
|
|
config := testCLIConfig(t, contract.ScenarioTransfer100MiB, contract.FaultTransferHash)
|
|
paths, err := contract.NewPaths(config.Paths.NezhaSource().String(), config.Paths.AgentSource().String(), resultsDir)
|
|
if err != nil {
|
|
t.Fatalf("paths: %v", err)
|
|
}
|
|
config.Paths = paths
|
|
if err := writeScenarioEvidence(config, output, time.Now()); err != nil {
|
|
t.Fatalf("write evidence: %v", err)
|
|
}
|
|
info, err := os.Stat(filepath.Join(resultsDir, "transfer.json"))
|
|
if err != nil {
|
|
t.Fatalf("stat transfer evidence: %v", err)
|
|
}
|
|
if info.Mode().Perm() != 0o600 {
|
|
t.Fatalf("transfer evidence mode=%o", info.Mode().Perm())
|
|
}
|
|
}
|
|
|
|
func testCLIConfig(t *testing.T, scenarioName, faultName string) cliConfig {
|
|
t.Helper()
|
|
paths, err := contract.NewPaths("/src/nezha", "/src/agent", t.TempDir())
|
|
if err != nil {
|
|
t.Fatalf("paths: %v", err)
|
|
}
|
|
profile, err := contract.ProfileByName("pr-full")
|
|
if err != nil {
|
|
t.Fatalf("profile: %v", err)
|
|
}
|
|
scenarioValue, err := contract.NewScenario(scenarioName)
|
|
if err != nil {
|
|
t.Fatalf("scenario: %v", err)
|
|
}
|
|
fault := contract.Fault{}
|
|
if faultName != "" {
|
|
fault, err = contract.NewFault(faultName)
|
|
if err != nil {
|
|
t.Fatalf("fault: %v", err)
|
|
}
|
|
}
|
|
return cliConfig{Paths: paths, Profile: profile, Seed: contract.DefaultSeed, Scenarios: scenarioFlags{scenarioValue}, Fault: fault}
|
|
}
|