mirror of
https://github.com/Buriburizaem0n/nezha_domains.git
synced 2026-09-19 17:50: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,117 @@
|
||||
//go:build linux
|
||||
|
||||
package scenario
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/nezhahq/nezha/integration/agentcompat/internal/fixture"
|
||||
)
|
||||
|
||||
type natRawResponse struct {
|
||||
Status int
|
||||
Body string
|
||||
LegacyCloseMarker string
|
||||
PeerWriteClosed bool
|
||||
}
|
||||
|
||||
type natHTTPRequestSpec struct {
|
||||
Endpoint string
|
||||
Host string
|
||||
Method string
|
||||
Path string
|
||||
Body string
|
||||
}
|
||||
|
||||
const natEchoHeaderValue = "fixture"
|
||||
|
||||
func natHTTPStatus(ctx context.Context, endpoint, host string) (natRawResponse, error) {
|
||||
return natHTTPRequest(ctx, natHTTPRequestSpec{Endpoint: endpoint, Host: host, Method: http.MethodGet, Path: "/"})
|
||||
}
|
||||
|
||||
func natHTTPRoundTrip(ctx context.Context, request natHTTPRequestSpec) (natRawResponse, fixture.NATEchoRecord, error) {
|
||||
response, err := natHTTPRequest(ctx, request)
|
||||
if err != nil {
|
||||
return natRawResponse{}, fixture.NATEchoRecord{}, err
|
||||
}
|
||||
record, err := parseNATResponse(response.Body)
|
||||
return response, record, err
|
||||
}
|
||||
|
||||
func natHTTPRequest(ctx context.Context, request natHTTPRequestSpec) (natRawResponse, error) {
|
||||
connection, err := (&net.Dialer{}).DialContext(ctx, "tcp", request.Endpoint)
|
||||
if err != nil {
|
||||
return natRawResponse{}, err
|
||||
}
|
||||
defer connection.Close()
|
||||
if deadline, ok := ctx.Deadline(); ok {
|
||||
if err := connection.SetDeadline(deadline); err != nil {
|
||||
return natRawResponse{}, err
|
||||
}
|
||||
}
|
||||
wireRequest := fmt.Sprintf("%s %s HTTP/1.1\r\nHost: %s\r\nX-AgentCompat-Echo: %s\r\nContent-Length: %d\r\nConnection: close\r\n\r\n%s", request.Method, request.Path, request.Host, natEchoHeaderValue, len(request.Body), request.Body)
|
||||
if _, err := io.WriteString(connection, wireRequest); err != nil {
|
||||
return natRawResponse{}, err
|
||||
}
|
||||
reader := bufio.NewReader(connection)
|
||||
response, err := http.ReadResponse(reader, nil)
|
||||
if err != nil {
|
||||
return natRawResponse{}, err
|
||||
}
|
||||
responseBody, err := io.ReadAll(response.Body)
|
||||
if closeErr := response.Body.Close(); err == nil {
|
||||
err = closeErr
|
||||
}
|
||||
if err != nil {
|
||||
return natRawResponse{}, err
|
||||
}
|
||||
// Agent preserves its legacy wire contract by forwarding the local read
|
||||
// result after the HTTP body. Reading through that marker to EOF proves the
|
||||
// backend write-close reached Agent and the stream then terminated.
|
||||
closeMarker, peerCloseErr := io.ReadAll(reader)
|
||||
if peerCloseErr != nil {
|
||||
return natRawResponse{}, fmt.Errorf("observe NAT peer write close: %w", peerCloseErr)
|
||||
}
|
||||
return natRawResponse{Status: response.StatusCode, Body: string(responseBody), LegacyCloseMarker: string(closeMarker), PeerWriteClosed: true}, nil
|
||||
}
|
||||
|
||||
func natAssertNoBackendConnection(ctx context.Context, backend *fixture.NATEchoBackend) error {
|
||||
deadline, cancel := context.WithTimeout(ctx, 300*time.Millisecond)
|
||||
defer cancel()
|
||||
err := backend.WaitConnection(deadline)
|
||||
if errors.Is(err, context.DeadlineExceeded) {
|
||||
return nil
|
||||
}
|
||||
if err == nil {
|
||||
return errors.New("NAT backend received an unexpected connection")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func parseNATResponse(body string) (fixture.NATEchoRecord, error) {
|
||||
values := make(map[string]string)
|
||||
for _, line := range strings.Split(strings.TrimSuffix(body, "\n"), "\n") {
|
||||
key, value, ok := strings.Cut(line, "=")
|
||||
if ok {
|
||||
values[key] = value
|
||||
}
|
||||
}
|
||||
for _, key := range []string{"method", "path", "host", "x-agentcompat-echo", "body"} {
|
||||
if _, ok := values[key]; !ok {
|
||||
return fixture.NATEchoRecord{}, fmt.Errorf("NAT response missing %s", key)
|
||||
}
|
||||
}
|
||||
return fixture.NATEchoRecord{Method: values["method"], Path: values["path"], Host: values["host"], HeaderValue: values["x-agentcompat-echo"], Body: []byte(values["body"])}, nil
|
||||
}
|
||||
|
||||
func natExpectedBody(request natHTTPRequestSpec) string {
|
||||
return fmt.Sprintf("method=%s\npath=%s\nhost=%s\nx-agentcompat-echo=%s\nbody=%s\n", request.Method, request.Path, request.Host, natEchoHeaderValue, request.Body)
|
||||
}
|
||||
Reference in New Issue
Block a user