mirror of
https://github.com/Buriburizaem0n/nezha_domains.git
synced 2026-09-19 09:40:12 +00:00
155 lines
4.5 KiB
Go
155 lines
4.5 KiB
Go
//go:build linux && agentcompat
|
|
|
|
package scenario
|
|
|
|
import (
|
|
"bufio"
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"net"
|
|
"net/http"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/nezhahq/nezha/integration/agentcompat/internal/fixture"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestNAT_HTTPRequestObservesPeerWriteCloseAfterDeclaredBody(t *testing.T) {
|
|
// Given
|
|
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
|
require.NoError(t, err)
|
|
t.Cleanup(func() { require.NoError(t, listener.Close()) })
|
|
serverDone := make(chan error, 1)
|
|
go func() {
|
|
connection, acceptErr := listener.Accept()
|
|
if acceptErr != nil {
|
|
serverDone <- acceptErr
|
|
return
|
|
}
|
|
defer connection.Close()
|
|
request, readErr := http.ReadRequest(bufio.NewReader(connection))
|
|
if readErr != nil {
|
|
serverDone <- readErr
|
|
return
|
|
}
|
|
_, readErr = io.Copy(io.Discard, request.Body)
|
|
if closeErr := request.Body.Close(); readErr == nil {
|
|
readErr = closeErr
|
|
}
|
|
if readErr != nil {
|
|
serverDone <- readErr
|
|
return
|
|
}
|
|
body := "closed"
|
|
if _, writeErr := fmt.Fprintf(connection, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n\r\n%s%s", len(body), body, io.EOF.Error()); writeErr != nil {
|
|
serverDone <- writeErr
|
|
return
|
|
}
|
|
tcpConnection, ok := connection.(*net.TCPConn)
|
|
if !ok {
|
|
serverDone <- errors.New("test listener did not accept TCP connection")
|
|
return
|
|
}
|
|
serverDone <- tcpConnection.CloseWrite()
|
|
}()
|
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
|
defer cancel()
|
|
|
|
// When
|
|
response, err := natHTTPRequest(ctx, natHTTPRequestSpec{Endpoint: listener.Addr().String(), Host: natTestDomain, Method: http.MethodGet, Path: "/"})
|
|
|
|
// Then
|
|
require.NoError(t, err)
|
|
require.Equal(t, http.StatusOK, response.Status)
|
|
require.Equal(t, "closed", response.Body)
|
|
require.Equal(t, io.EOF.Error(), response.LegacyCloseMarker)
|
|
require.True(t, response.PeerWriteClosed)
|
|
require.NoError(t, <-serverDone)
|
|
}
|
|
|
|
func TestNAT_ParseResponsePreservesExactRequestFields(t *testing.T) {
|
|
// Given
|
|
body := natExpectedBody(natHTTPRequestSpec{Host: natTestDomain, Method: http.MethodPatch, Path: "/nat?case=ordinary", Body: "ordinary"})
|
|
|
|
// When
|
|
record, err := parseNATResponse(body)
|
|
|
|
// Then
|
|
require.NoError(t, err)
|
|
require.Equal(t, http.MethodPatch, record.Method)
|
|
require.Equal(t, "/nat?case=ordinary", record.Path)
|
|
require.Equal(t, natTestDomain, record.Host)
|
|
require.Equal(t, "fixture", record.HeaderValue)
|
|
require.Equal(t, []byte("ordinary"), record.Body)
|
|
}
|
|
|
|
func TestNAT_ParseResponseRejectsMissingEvidence(t *testing.T) {
|
|
// Given
|
|
body := "method=GET\npath=/\n"
|
|
|
|
// When
|
|
_, err := parseNATResponse(body)
|
|
|
|
// Then
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestNAT_ExactRequestObservedRejectsMismatchedHalfCloseEvidence(t *testing.T) {
|
|
// Given
|
|
request := natHTTPRequestSpec{Host: natHalfCloseTestDomain, Method: http.MethodPost, Path: "/nat?case=half-close", Body: "half-closed"}
|
|
exact := fixture.NATEchoRecord{Method: request.Method, Path: request.Path, Host: request.Host, HeaderValue: natEchoHeaderValue, Body: []byte(request.Body)}
|
|
mismatched := exact
|
|
mismatched.Host = natTestDomain
|
|
|
|
// When
|
|
observed := natExactRequestObserved(request, exact, mismatched)
|
|
|
|
// Then
|
|
require.False(t, observed)
|
|
}
|
|
|
|
func TestNAT_DeletedRouteObservedRequiresFallbackStatusAndBody(t *testing.T) {
|
|
// Given
|
|
request := natHTTPRequestSpec{Host: natTestDomain, Method: http.MethodGet, Path: "/"}
|
|
|
|
// When
|
|
observed := natDeletedRouteObserved(natRawResponse{Status: http.StatusOK, Body: "dashboard fallback"}, nil, request)
|
|
echoObserved := natDeletedRouteObserved(natRawResponse{Status: http.StatusOK, Body: natExpectedBody(request)}, nil, request)
|
|
rejectedObserved := natDeletedRouteObserved(natRawResponse{Status: http.StatusNotFound, Body: "not found"}, nil, request)
|
|
|
|
// Then
|
|
require.True(t, observed)
|
|
require.False(t, echoObserved)
|
|
require.False(t, rejectedObserved)
|
|
}
|
|
|
|
func TestNAT_FinishReturnsTypedFailedAssertion(t *testing.T) {
|
|
// Given
|
|
assertions := NewAssertionSet()
|
|
assertions.Record("deleted profile no longer routes", false, "backend connection observed")
|
|
|
|
// When
|
|
result, err := finishNAT(assertions, nil)
|
|
|
|
// Then
|
|
require.EqualError(t, err, "deleted profile no longer routes: backend connection observed")
|
|
require.Equal(t, "nat", result.Name)
|
|
require.False(t, result.Passed)
|
|
require.False(t, result.CleanupOK)
|
|
}
|
|
|
|
func TestNAT_FinishPreservesRuntimeError(t *testing.T) {
|
|
// Given
|
|
runtimeErr := errors.New("NAT runtime failed")
|
|
|
|
// When
|
|
result, err := finishNAT(NewAssertionSet(), runtimeErr)
|
|
|
|
// Then
|
|
require.ErrorIs(t, err, runtimeErr)
|
|
require.Equal(t, "NAT runtime failed", result.Error)
|
|
}
|