chore: sync testing plan with gateway
This commit is contained in:
@@ -234,16 +234,27 @@ func (g runningAuthenticatedGateway) stop(t *testing.T) {
|
||||
func dialGatewayClient(t *testing.T, addr string) *grpc.ClientConn {
|
||||
t.Helper()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||
defer cancel()
|
||||
var conn *grpc.ClientConn
|
||||
require.Eventually(t, func() bool {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
|
||||
defer cancel()
|
||||
|
||||
conn, err := grpc.DialContext(
|
||||
ctx,
|
||||
addr,
|
||||
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||
grpc.WithBlock(),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
candidate, err := grpc.DialContext(
|
||||
ctx,
|
||||
addr,
|
||||
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||
grpc.WithBlock(),
|
||||
)
|
||||
if err != nil {
|
||||
if candidate != nil {
|
||||
_ = candidate.Close()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
conn = candidate
|
||||
return true
|
||||
}, 2*time.Second, 10*time.Millisecond, "gateway did not accept gRPC connections")
|
||||
|
||||
return conn
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"time"
|
||||
|
||||
"galaxy/gateway/internal/authn"
|
||||
"galaxy/gateway/internal/config"
|
||||
"galaxy/gateway/internal/downstream"
|
||||
"galaxy/gateway/internal/testutil"
|
||||
gatewayv1 "galaxy/gateway/proto/galaxy/gateway/v1"
|
||||
@@ -143,6 +144,78 @@ func TestExecuteCommandMapsDownstreamUnavailableToUnavailable(t *testing.T) {
|
||||
assert.Equal(t, 1, failingClient.executeCalls)
|
||||
}
|
||||
|
||||
func TestExecuteCommandMapsDownstreamTimeoutToUnavailable(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
stallingClient := &recordingDownstreamClient{
|
||||
executeFunc: func(ctx context.Context, _ downstream.AuthenticatedCommand) (downstream.UnaryResult, error) {
|
||||
<-ctx.Done()
|
||||
return downstream.UnaryResult{}, ctx.Err()
|
||||
},
|
||||
}
|
||||
|
||||
server, runGateway := newTestGatewayWithGRPCConfig(t, newAuthenticatedGRPCConfigForTest(func(cfg *config.AuthenticatedGRPCConfig) {
|
||||
cfg.DownstreamTimeout = 50 * time.Millisecond
|
||||
}), ServerDependencies{
|
||||
Router: downstream.NewStaticRouter(map[string]downstream.Client{
|
||||
"fleet.move": stallingClient,
|
||||
}),
|
||||
SessionCache: userMappedSessionCache(map[string]string{"device-session-123": "user-123"}),
|
||||
ReplayStore: staticReplayStore{},
|
||||
ResponseSigner: newTestResponseSigner(),
|
||||
})
|
||||
defer runGateway.stop(t)
|
||||
|
||||
addr := waitForListenAddr(t, server)
|
||||
conn := dialGatewayClient(t, addr)
|
||||
defer func() {
|
||||
require.NoError(t, conn.Close())
|
||||
}()
|
||||
|
||||
client := gatewayv1.NewEdgeGatewayClient(conn)
|
||||
_, err := client.ExecuteCommand(context.Background(), newValidExecuteCommandRequest())
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, codes.Unavailable, status.Code(err))
|
||||
assert.Equal(t, "downstream service is unavailable", status.Convert(err).Message())
|
||||
assert.Equal(t, 1, stallingClient.executeCalls)
|
||||
}
|
||||
|
||||
func TestExecuteCommandFailsClosedWhenResponseSignerUnavailable(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
successClient := &recordingDownstreamClient{
|
||||
executeFunc: func(context.Context, downstream.AuthenticatedCommand) (downstream.UnaryResult, error) {
|
||||
return downstream.UnaryResult{
|
||||
ResultCode: "accepted",
|
||||
PayloadBytes: []byte("downstream-response"),
|
||||
}, nil
|
||||
},
|
||||
}
|
||||
|
||||
server, runGateway := newTestGateway(t, ServerDependencies{
|
||||
Router: downstream.NewStaticRouter(map[string]downstream.Client{
|
||||
"fleet.move": successClient,
|
||||
}),
|
||||
ResponseSigner: unavailableResponseSigner{},
|
||||
SessionCache: userMappedSessionCache(map[string]string{"device-session-123": "user-123"}),
|
||||
ReplayStore: staticReplayStore{},
|
||||
})
|
||||
defer runGateway.stop(t)
|
||||
|
||||
addr := waitForListenAddr(t, server)
|
||||
conn := dialGatewayClient(t, addr)
|
||||
defer func() {
|
||||
require.NoError(t, conn.Close())
|
||||
}()
|
||||
|
||||
client := gatewayv1.NewEdgeGatewayClient(conn)
|
||||
_, err := client.ExecuteCommand(context.Background(), newValidExecuteCommandRequest())
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, codes.Unavailable, status.Code(err))
|
||||
assert.Equal(t, "response signer is unavailable", status.Convert(err).Message())
|
||||
assert.Equal(t, 1, successClient.executeCalls)
|
||||
}
|
||||
|
||||
func TestExecuteCommandPropagatesOTelSpanContextToDownstream(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
@@ -216,6 +216,33 @@ func TestSubscribeEventsMissingReplayStoreFailsClosed(t *testing.T) {
|
||||
assert.Equal(t, "replay store is unavailable", status.Convert(err).Message())
|
||||
}
|
||||
|
||||
func TestSubscribeEventsFailsClosedWhenResponseSignerUnavailable(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
server, runGateway := newTestGateway(t, ServerDependencies{
|
||||
ResponseSigner: unavailableResponseSigner{},
|
||||
SessionCache: staticSessionCache{
|
||||
lookupFunc: func(context.Context, string) (session.Record, error) {
|
||||
return newActiveSessionRecord(), nil
|
||||
},
|
||||
},
|
||||
ReplayStore: staticReplayStore{},
|
||||
})
|
||||
defer runGateway.stop(t)
|
||||
|
||||
addr := waitForListenAddr(t, server)
|
||||
conn := dialGatewayClient(t, addr)
|
||||
defer func() {
|
||||
require.NoError(t, conn.Close())
|
||||
}()
|
||||
|
||||
client := gatewayv1.NewEdgeGatewayClient(conn)
|
||||
err := subscribeEventsError(t, context.Background(), client, newValidSubscribeEventsRequest())
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, codes.Unavailable, status.Code(err))
|
||||
assert.Equal(t, "response signer is unavailable", status.Convert(err).Message())
|
||||
}
|
||||
|
||||
func TestServerLifecycle(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
@@ -216,6 +216,83 @@ func TestPublicAntiAbuseBrowserClassBucketsStayIsolatedFromPublicAuth(t *testing
|
||||
}
|
||||
}
|
||||
|
||||
func TestPublicAntiAbuseUsesRemoteAddrInsteadOfForwardedHeaders(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
headerKey string
|
||||
firstHeader string
|
||||
secondHeader string
|
||||
firstRemote string
|
||||
secondRemote string
|
||||
wantSecondCode int
|
||||
}{
|
||||
{
|
||||
name: "same remote addr ignores x-forwarded-for changes",
|
||||
headerKey: "X-Forwarded-For",
|
||||
firstHeader: "198.51.100.10",
|
||||
secondHeader: "198.51.100.11",
|
||||
firstRemote: "192.0.2.10:1234",
|
||||
secondRemote: "192.0.2.10:1234",
|
||||
wantSecondCode: http.StatusTooManyRequests,
|
||||
},
|
||||
{
|
||||
name: "different remote addr wins over shared forwarded header",
|
||||
headerKey: "Forwarded",
|
||||
firstHeader: "for=198.51.100.10",
|
||||
secondHeader: "for=198.51.100.10",
|
||||
firstRemote: "192.0.2.10:1234",
|
||||
secondRemote: "192.0.2.11:1234",
|
||||
wantSecondCode: http.StatusOK,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
cfg := config.DefaultPublicHTTPConfig()
|
||||
cfg.AntiAbuse.PublicAuth.RateLimit = config.PublicRateLimitConfig{
|
||||
Requests: 1,
|
||||
Window: time.Hour,
|
||||
Burst: 1,
|
||||
}
|
||||
cfg.AntiAbuse.SendEmailCodeIdentity.RateLimit = config.PublicRateLimitConfig{
|
||||
Requests: 100,
|
||||
Window: time.Hour,
|
||||
Burst: 100,
|
||||
}
|
||||
|
||||
authService := &recordingAuthServiceClient{
|
||||
sendEmailCodeResult: SendEmailCodeResult{
|
||||
ChallengeID: "challenge-123",
|
||||
},
|
||||
}
|
||||
handler := newPublicHandlerWithConfig(cfg, ServerDependencies{AuthService: authService})
|
||||
|
||||
first := sendEmailCodeRequest(`{"email":"pilot-one@example.com"}`)
|
||||
first.RemoteAddr = tt.firstRemote
|
||||
first.Header.Set(tt.headerKey, tt.firstHeader)
|
||||
|
||||
second := sendEmailCodeRequest(`{"email":"pilot-two@example.com"}`)
|
||||
second.RemoteAddr = tt.secondRemote
|
||||
second.Header.Set(tt.headerKey, tt.secondHeader)
|
||||
|
||||
firstResp := httptest.NewRecorder()
|
||||
handler.ServeHTTP(firstResp, first)
|
||||
|
||||
secondResp := httptest.NewRecorder()
|
||||
handler.ServeHTTP(secondResp, second)
|
||||
|
||||
assert.Equal(t, http.StatusOK, firstResp.Code)
|
||||
assert.Equal(t, tt.wantSecondCode, secondResp.Code)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPublicAntiAbuseSendEmailIdentityThrottle(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user