Files
nezha_domains/integration/agentcompat/internal/scenario/held_readiness_test.go
T
2026-07-20 04:51:20 +00:00

135 lines
4.8 KiB
Go

//go:build linux
package scenario
import (
"context"
"os"
"path/filepath"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/nezhahq/nezha/integration/agentcompat/internal/agent"
)
func TestHeldReadinessValidation_AcceptsCompleteEvidenceForActualAgent(t *testing.T) {
// Given
agentInstance := newHeldReadinessTestAgent(t, "00000000-0000-0000-0000-000000000301")
readiness := completeHeldReadiness(agentInstance.UUID())
// When
err := validateHeldReadiness(agentInstance, readiness)
// Then
require.NoError(t, err)
}
func TestHeldReadinessValidation_RejectsEachInvalidDimensionWithExactError(t *testing.T) {
// Given
agentInstance := newHeldReadinessTestAgent(t, "00000000-0000-0000-0000-000000000302")
valid := completeHeldReadiness(agentInstance.UUID())
allSentinels := []error{
ErrHeldReadinessServerID,
ErrHeldReadinessUUID,
ErrHeldReadinessAgentMismatch,
ErrHeldReadinessVersion,
ErrHeldReadinessOnline,
ErrHeldReadinessVersionObserved,
ErrHeldReadinessRequestTaskEstablished,
ErrHeldReadinessStateReceiptObserved,
}
tests := []struct {
name string
field string
wantError error
mutate func(*agent.Readiness)
}{
{name: "zero server ID", field: "server_id", wantError: ErrHeldReadinessServerID, mutate: func(readiness *agent.Readiness) { readiness.ServerID = 0 }},
{name: "empty UUID", field: "uuid", wantError: ErrHeldReadinessUUID, mutate: func(readiness *agent.Readiness) { readiness.UUID = "" }},
{name: "agent UUID mismatch", field: "uuid", wantError: ErrHeldReadinessAgentMismatch, mutate: func(readiness *agent.Readiness) { readiness.UUID = "00000000-0000-0000-0000-000000000399" }},
{name: "empty version", field: "version", wantError: ErrHeldReadinessVersion, mutate: func(readiness *agent.Readiness) { readiness.Version = "" }},
{name: "offline", field: "online", wantError: ErrHeldReadinessOnline, mutate: func(readiness *agent.Readiness) { readiness.Online = false }},
{name: "version not observed", field: "version_observed", wantError: ErrHeldReadinessVersionObserved, mutate: func(readiness *agent.Readiness) { readiness.VersionObserved = false }},
{name: "request task not established", field: "request_task_established", wantError: ErrHeldReadinessRequestTaskEstablished, mutate: func(readiness *agent.Readiness) { readiness.RequestTaskEstablished = false }},
{name: "state receipt not observed", field: "state_receipt_observed", wantError: ErrHeldReadinessStateReceiptObserved, mutate: func(readiness *agent.Readiness) { readiness.StateReceiptObserved = false }},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
readiness := valid
test.mutate(&readiness)
// When
err := validateHeldReadiness(agentInstance, readiness)
// Then
require.ErrorIs(t, err, ErrInvalidHeldReadiness)
require.ErrorIs(t, err, test.wantError)
var validationError *HeldReadinessValidationError
require.ErrorAs(t, err, &validationError)
require.Equal(t, test.field, validationError.Field)
require.NotContains(t, err.Error(), valid.UUID)
require.NotContains(t, err.Error(), valid.Version)
for _, sentinel := range allSentinels {
if sentinel != test.wantError {
require.NotErrorIs(t, err, sentinel)
}
}
})
}
}
func completeHeldReadiness(uuid string) agent.Readiness {
return agent.Readiness{
ServerID: 301,
UUID: uuid,
Version: "v2.1.0",
Online: true,
VersionObserved: true,
RequestTaskEstablished: true,
StateReceiptObserved: true,
}
}
func newHeldReadinessTestAgent(t *testing.T, uuid string) *agent.Agent {
t.Helper()
sourceDirectory := t.TempDir()
mainDirectory := filepath.Join(sourceDirectory, "cmd", "agent")
monitorDirectory := filepath.Join(sourceDirectory, "pkg", "monitor")
require.NoError(t, os.MkdirAll(mainDirectory, 0o700))
require.NoError(t, os.MkdirAll(monitorDirectory, 0o700))
require.NoError(t, os.WriteFile(filepath.Join(sourceDirectory, "go.mod"), []byte("module github.com/nezhahq/agent\n\ngo 1.26.3\n"), 0o600))
require.NoError(t, os.WriteFile(filepath.Join(monitorDirectory, "version.go"), []byte("package monitor\n\nvar Version = \"test\"\n"), 0o600))
require.NoError(t, os.WriteFile(filepath.Join(mainDirectory, "main.go"), []byte(`package main
import (
"os"
"os/signal"
"syscall"
"github.com/nezhahq/agent/pkg/monitor"
)
func main() {
_ = monitor.Version
signals := make(chan os.Signal, 1)
signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
<-signals
}
`), 0o600))
agentInstance, err := agent.Start(t.Context(), agent.AgentStartConfig{
SourceDir: sourceDirectory,
Endpoint: "127.0.0.1:1",
UUID: uuid,
})
require.NoError(t, err)
t.Cleanup(func() {
cleanupContext, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
require.NoError(t, agentInstance.Stop(cleanupContext))
})
return agentInstance
}