mirror of
https://github.com/Buriburizaem0n/nezha_domains.git
synced 2026-09-22 03:00:12 +00:00
test(agentcompat): add integration scenarios
Co-authored-by: naiba/CloudCode <hi+cloudcode@nai.ba>
This commit is contained in:
@@ -0,0 +1,257 @@
|
||||
//go:build linux
|
||||
|
||||
package scenario
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/nezhahq/nezha/integration/agentcompat/internal/agent"
|
||||
"github.com/nezhahq/nezha/integration/agentcompat/internal/client"
|
||||
)
|
||||
|
||||
func TestHeldTerminalCommandSubmitsWithLineFeed(t *testing.T) {
|
||||
command := heldTerminalCommand("marker-session")
|
||||
|
||||
require.Equal(t, byte('\n'), command[len(command)-1])
|
||||
require.NotContains(t, command, "exit\\n")
|
||||
}
|
||||
|
||||
func TestHeldTerminalProofRejectsEchoOnlyExactTokens(t *testing.T) {
|
||||
proof := newHeldTerminalProof("marker-session")
|
||||
|
||||
proof.Consume(client.Frame{Type: client.FrameText, Payload: []byte("printf 'compat-size='; stty size; printf 'marker-session\\n'; read -r held_terminal_release; exit\\n\r\ncompat-size=43 132\r\nmarker-session\r\n")})
|
||||
|
||||
require.False(t, proof.Complete())
|
||||
}
|
||||
|
||||
func TestHeldTerminalProofAcceptsMarkerAndExactSizeAcrossFrames(t *testing.T) {
|
||||
// Given
|
||||
proof := newHeldTerminalProof("marker-session")
|
||||
|
||||
// When
|
||||
proof.Consume(client.Frame{Type: client.FrameText, Payload: []byte("prefix\r\n\x1emarker-session|43 ")})
|
||||
proof.Consume(client.Frame{Type: client.FrameBinary, Payload: []byte("132\x1f\r\n")})
|
||||
|
||||
// Then
|
||||
require.True(t, proof.Complete())
|
||||
require.Equal(t, uint32(43), proof.Rows())
|
||||
require.Equal(t, uint32(132), proof.Columns())
|
||||
}
|
||||
|
||||
func TestHeldTerminalProofIgnoresMarkerInEchoedCommand(t *testing.T) {
|
||||
// Given
|
||||
proof := newHeldTerminalProof("marker-session")
|
||||
|
||||
// When
|
||||
proof.Consume(client.Frame{Type: client.FrameText, Payload: []byte("printf '\\036%s%s|' 'marker-' 'session'; stty size; printf '\\037'\r\n")})
|
||||
proof.Consume(client.Frame{Type: client.FrameText, Payload: []byte("\x1emarker-session|43 132\x1f\r\n")})
|
||||
|
||||
// Then
|
||||
require.True(t, proof.Complete())
|
||||
require.Equal(t, uint32(43), proof.Rows())
|
||||
require.Equal(t, uint32(132), proof.Columns())
|
||||
}
|
||||
|
||||
func TestHeldTerminalProofRejectsWrongMarkerAndWrongSize(t *testing.T) {
|
||||
// Given
|
||||
wrongMarker := newHeldTerminalProof("marker-session")
|
||||
wrongSize := newHeldTerminalProof("marker-session")
|
||||
|
||||
// When
|
||||
wrongMarker.Consume(client.Frame{Type: client.FrameText, Payload: []byte("\x1emarker-other|43 132\x1f\r\n")})
|
||||
wrongSize.Consume(client.Frame{Type: client.FrameText, Payload: []byte("\x1emarker-session|42 132\x1f\r\n")})
|
||||
|
||||
// Then
|
||||
require.False(t, wrongMarker.Complete())
|
||||
require.False(t, wrongSize.Complete())
|
||||
}
|
||||
|
||||
func TestHeldTerminalProofAcceptsValidRecordAfterWrongMarkerInSameFrame(t *testing.T) {
|
||||
// Given
|
||||
proof := newHeldTerminalProof("marker-session")
|
||||
frame := []byte("\x1emarker-other|43 132\x1f\x1emarker-session|43 132\x1f")
|
||||
|
||||
// When
|
||||
proof.Consume(client.Frame{Type: client.FrameText, Payload: frame})
|
||||
|
||||
// Then
|
||||
require.True(t, proof.Complete())
|
||||
}
|
||||
|
||||
func TestHeldTerminalProofAcceptsValidRecordAfterMalformedRecordInSameFrame(t *testing.T) {
|
||||
// Given
|
||||
proof := newHeldTerminalProof("marker-session")
|
||||
frame := []byte("\x1emarker-session|43 nope\x1f\x1emarker-session|43 132\x1f")
|
||||
|
||||
// When
|
||||
proof.Consume(client.Frame{Type: client.FrameBinary, Payload: frame})
|
||||
|
||||
// Then
|
||||
require.True(t, proof.Complete())
|
||||
}
|
||||
|
||||
func TestHeldTerminalProofScansMultipleInvalidRecordsBeforeValidRecord(t *testing.T) {
|
||||
// Given
|
||||
proof := newHeldTerminalProof("marker-session")
|
||||
frame := []byte("noise\x1emarker-other|43 132\x1f\x1emarker-session|43 nope\x1f\x1emarker-session|43 132\x1f")
|
||||
|
||||
// When
|
||||
proof.Consume(client.Frame{Type: client.FrameText, Payload: frame})
|
||||
|
||||
// Then
|
||||
require.True(t, proof.Complete())
|
||||
}
|
||||
|
||||
func TestHeldTerminalProofAcceptsFramedRecordAcrossFrames(t *testing.T) {
|
||||
proof := newHeldTerminalProof("marker-session")
|
||||
|
||||
proof.Consume(client.Frame{Type: client.FrameBinary, Payload: []byte("prefix\x1emarker-session|43 ")})
|
||||
proof.Consume(client.Frame{Type: client.FrameBinary, Payload: []byte("132\x1f\r\n")})
|
||||
|
||||
require.True(t, proof.Complete())
|
||||
}
|
||||
|
||||
func TestHeldTerminalProofRejectsMalformedOrUnclosedRecord(t *testing.T) {
|
||||
malformed := newHeldTerminalProof("marker-session")
|
||||
unclosed := newHeldTerminalProof("marker-session")
|
||||
|
||||
malformed.Consume(client.Frame{Type: client.FrameBinary, Payload: []byte("\x1emarker-session|43 nope\x1f")})
|
||||
unclosed.Consume(client.Frame{Type: client.FrameBinary, Payload: []byte("\x1emarker-session|43 132")})
|
||||
|
||||
require.False(t, malformed.Complete())
|
||||
require.False(t, unclosed.Complete())
|
||||
require.Equal(t, []byte("\x1emarker-session|43 132"), unclosed.buffer)
|
||||
}
|
||||
|
||||
func TestHeldTerminalProofAcceptsEchoThenFramedRecord(t *testing.T) {
|
||||
proof := newHeldTerminalProof("marker-session")
|
||||
|
||||
proof.Consume(client.Frame{Type: client.FrameText, Payload: []byte("printf '\\036%s%s|' 'marker-' 'session'; stty size; printf '\\037' exit\\n\r\n")})
|
||||
require.False(t, proof.Complete())
|
||||
proof.Consume(client.Frame{Type: client.FrameBinary, Payload: []byte("\x1emarker-session|43 132\x1f")})
|
||||
|
||||
require.True(t, proof.Complete())
|
||||
}
|
||||
|
||||
func TestHeldTerminalProofRejectsClosedPumpBeforeProof(t *testing.T) {
|
||||
// Given
|
||||
proof := newHeldTerminalProof("marker-session")
|
||||
|
||||
// When
|
||||
err := proof.Closed(errors.New("pump closed"))
|
||||
|
||||
// Then
|
||||
require.Error(t, err)
|
||||
require.ErrorContains(t, err, "pump closed")
|
||||
}
|
||||
|
||||
func TestHeldTerminalProofBoundsAccumulator(t *testing.T) {
|
||||
// Given
|
||||
proof := newHeldTerminalProof("marker-session")
|
||||
|
||||
// When
|
||||
proof.Consume(client.Frame{Type: client.FrameText, Payload: make([]byte, heldTerminalProofLimit+1)})
|
||||
|
||||
// Then
|
||||
require.LessOrEqual(t, len(proof.buffer), heldTerminalProofLimit)
|
||||
}
|
||||
|
||||
func TestHeldTerminalResponseRequiresExactSessionServerIdentity(t *testing.T) {
|
||||
// Given
|
||||
response := terminalCreateResponse{SessionID: "session", ServerID: 9}
|
||||
|
||||
// When
|
||||
err := validateHeldTerminalResponse(response, 8)
|
||||
|
||||
// Then
|
||||
require.ErrorIs(t, err, ErrHeldTerminalProtocol)
|
||||
require.NoError(t, validateHeldTerminalResponse(response, 9))
|
||||
}
|
||||
|
||||
func TestHeldTerminalInputRejectsMissingResourcesAndMismatchedReadiness(t *testing.T) {
|
||||
// Given
|
||||
plan := heldTestPlan(t)
|
||||
input := heldTerminalInput{Plan: plan, Readiness: agent.Readiness{ServerID: 7, UUID: "agent"}}
|
||||
|
||||
// When
|
||||
err := validateHeldTerminalInput(context.Background(), input)
|
||||
|
||||
// Then
|
||||
require.ErrorIs(t, err, ErrInvalidHeldTerminalInput)
|
||||
}
|
||||
|
||||
func TestHeldTerminalInputRejectsMissingPATClientBeforeRemoteMutation(t *testing.T) {
|
||||
err := validateHeldPATClient(nil)
|
||||
|
||||
require.ErrorIs(t, err, ErrInvalidHeldPATClient)
|
||||
}
|
||||
|
||||
func TestHeldTerminalCommandKeepsShellHeldUntilInput(t *testing.T) {
|
||||
// Given
|
||||
command := heldTerminalCommand("marker-session")
|
||||
|
||||
// Then
|
||||
require.Contains(t, command, "marker-")
|
||||
require.Contains(t, command, "session")
|
||||
require.Contains(t, command, "stty size")
|
||||
require.Contains(t, command, "read -r")
|
||||
require.Contains(t, command, "exit")
|
||||
require.Contains(t, command, "\\036")
|
||||
require.Contains(t, command, "\\037")
|
||||
require.NotEqual(t, "\n", command)
|
||||
}
|
||||
|
||||
func TestHeldTerminalCleanupOwnerDoesNotUseCanceledWaiter(t *testing.T) {
|
||||
// Given
|
||||
cleanupStarted := make(chan struct{})
|
||||
cleanupRelease := make(chan struct{})
|
||||
lifecycle := heldTestLifecycle(t, "held-terminal-session")
|
||||
stack := newHeldCleanupStack()
|
||||
require.NoError(t, stack.Push(heldCleanupAction{name: "blocked", cleanup: func(cleanupContext context.Context) error {
|
||||
require.NoError(t, cleanupContext.Err())
|
||||
close(cleanupStarted)
|
||||
<-cleanupRelease
|
||||
return nil
|
||||
}}))
|
||||
session := newHeldTerminalSessionForTest(lifecycle, stack)
|
||||
|
||||
// When
|
||||
canceled, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
first := make(chan error, 1)
|
||||
go func() { first <- session.Close(canceled) }()
|
||||
<-cleanupStarted
|
||||
|
||||
// Then
|
||||
require.ErrorIs(t, <-first, context.Canceled)
|
||||
close(cleanupRelease)
|
||||
require.NoError(t, session.Close(context.Background()))
|
||||
}
|
||||
|
||||
func TestHeldTerminalCleanupStackReleasesHoldBeforeTransport(t *testing.T) {
|
||||
// Given
|
||||
stack := newHeldCleanupStack()
|
||||
var order []string
|
||||
require.NoError(t, stack.Push(heldCleanupAction{name: "absence", cleanup: func(context.Context) error {
|
||||
order = append(order, "absence")
|
||||
return nil
|
||||
}}))
|
||||
require.NoError(t, stack.Push(heldCleanupAction{name: "transport", cleanup: func(context.Context) error {
|
||||
order = append(order, "transport")
|
||||
return nil
|
||||
}}))
|
||||
require.NoError(t, stack.Push(heldCleanupAction{name: "release", cleanup: func(context.Context) error {
|
||||
order = append(order, "release")
|
||||
return nil
|
||||
}}))
|
||||
|
||||
// When
|
||||
require.NoError(t, stack.Run(context.Background()))
|
||||
|
||||
// Then
|
||||
require.Equal(t, []string{"release", "transport", "absence"}, order)
|
||||
}
|
||||
Reference in New Issue
Block a user