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,112 @@
|
||||
//go:build linux
|
||||
|
||||
package scenario
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/nezhahq/nezha/integration/agentcompat/internal/client"
|
||||
)
|
||||
|
||||
var terminalSizePattern = regexp.MustCompile(`compat-size=([0-9]+) ([0-9]+)`)
|
||||
|
||||
type terminalFrameConnection interface {
|
||||
WriteFrame(context.Context, client.Frame) error
|
||||
ReadFrame(context.Context) (client.Frame, error)
|
||||
}
|
||||
|
||||
type terminalExitInput struct {
|
||||
InitialOutput []byte
|
||||
ExitSentAt time.Time
|
||||
Now func() time.Time
|
||||
}
|
||||
|
||||
type terminalOutputReadInput struct {
|
||||
InitialOutput []byte
|
||||
ExitSentAt time.Time
|
||||
Now func() time.Time
|
||||
}
|
||||
|
||||
type terminalOutputResult struct {
|
||||
Output string
|
||||
MarkerObserved bool
|
||||
SizeObserved bool
|
||||
StreamClosed bool
|
||||
Rows uint32
|
||||
Cols uint32
|
||||
CloseCode int
|
||||
CloseElapsed time.Duration
|
||||
}
|
||||
|
||||
func executeTerminalExit(ctx context.Context, input terminalExitInput, connection terminalFrameConnection) (terminalOutputResult, error) {
|
||||
contractContext, cancelContract := context.WithDeadline(ctx, input.ExitSentAt.Add(terminalShutdownContract+terminalShutdownHarnessMargin))
|
||||
defer cancelContract()
|
||||
if err := connection.WriteFrame(contractContext, client.Frame{Type: client.FrameText, Payload: []byte(terminalCommand)}); err != nil {
|
||||
return terminalOutputResult{}, err
|
||||
}
|
||||
return readTerminalOutput(contractContext, terminalOutputReadInput{InitialOutput: input.InitialOutput, ExitSentAt: input.ExitSentAt, Now: input.Now}, connection.ReadFrame)
|
||||
}
|
||||
|
||||
func readTerminalOutput(ctx context.Context, input terminalOutputReadInput, read func(context.Context) (client.Frame, error)) (terminalOutputResult, error) {
|
||||
var output bytes.Buffer
|
||||
output.Write(input.InitialOutput)
|
||||
result := terminalOutputResult{Output: output.String()}
|
||||
observeTerminalOutput(&result, output.Bytes())
|
||||
for {
|
||||
frame, err := read(ctx)
|
||||
if err != nil {
|
||||
result.Output = output.String()
|
||||
result.CloseCode = closeErrorCode(err)
|
||||
var closeError *client.WebSocketCloseError
|
||||
if result.MarkerObserved && result.SizeObserved && errors.As(err, &closeError) && terminalCloseCodeAccepted(closeError.Code) {
|
||||
result.StreamClosed = true
|
||||
result.CloseElapsed = input.Now().Sub(input.ExitSentAt)
|
||||
return result, nil
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
output.Write(frame.Payload)
|
||||
observeTerminalOutput(&result, output.Bytes())
|
||||
}
|
||||
}
|
||||
|
||||
func observeTerminalOutput(result *terminalOutputResult, output []byte) {
|
||||
result.MarkerObserved = bytes.Contains(output, []byte(terminalMarker))
|
||||
matches := terminalSizePattern.FindSubmatch(output)
|
||||
if len(matches) != 3 {
|
||||
return
|
||||
}
|
||||
rows, rowsErr := strconv.ParseUint(string(matches[1]), 10, 32)
|
||||
cols, colsErr := strconv.ParseUint(string(matches[2]), 10, 32)
|
||||
if rowsErr == nil && colsErr == nil {
|
||||
result.SizeObserved = true
|
||||
result.Rows = uint32(rows)
|
||||
result.Cols = uint32(cols)
|
||||
}
|
||||
}
|
||||
|
||||
func terminalCloseWithinContract(elapsed time.Duration) bool {
|
||||
return elapsed <= terminalShutdownContract+terminalShutdownHarnessMargin
|
||||
}
|
||||
|
||||
func terminalCloseCodeAccepted(code int) bool {
|
||||
return code == 1000 || code == 1006
|
||||
}
|
||||
|
||||
func closeErrorCode(err error) int {
|
||||
var closeError *client.WebSocketCloseError
|
||||
if errors.As(err, &closeError) {
|
||||
return closeError.Code
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func terminalOutputDetails(output terminalOutputResult, err error) string {
|
||||
return fmt.Sprintf("marker=%t size_observed=%t rows=%d cols=%d closed=%t close_code=%d close_elapsed_ms=%d close_limit_ms=%d output=%q error=%s", output.MarkerObserved, output.SizeObserved, output.Rows, output.Cols, output.StreamClosed, output.CloseCode, output.CloseElapsed.Milliseconds(), (terminalShutdownContract + terminalShutdownHarnessMargin).Milliseconds(), output.Output, errorText(err))
|
||||
}
|
||||
Reference in New Issue
Block a user