From 66ef4a3e142fc8cd74df76473bfeb3d0cd4c5225 Mon Sep 17 00:00:00 2001 From: ginuerzh Date: Wed, 21 Oct 2026 08:54:22 +0000 Subject: [PATCH] tests(e2e): cover the parallel selector node limit Add an e2e case for the parallel selector configured with maxParallel: 1. With only one node racing per connection the dead node is no longer masked by the live one, so the requests alternate between success and failure - that alternation is what proves the limit is applied. Requires go-gost/x with the parallel selector node limit (gost#916). gost's go.mod still pins v0.19.5, so this test only goes green once that release lands and the dependency is bumped. --- tests/e2e/selector_test.go | 22 ++++++++++++ .../e2e/testdata/selector/parallel_limit.yaml | 34 +++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 tests/e2e/testdata/selector/parallel_limit.yaml diff --git a/tests/e2e/selector_test.go b/tests/e2e/selector_test.go index 6595c24..4c7ca8b 100644 --- a/tests/e2e/selector_test.go +++ b/tests/e2e/selector_test.go @@ -109,6 +109,28 @@ func (s *SelectorSuite) TestParallelSelector() { s.Require().Contains(body, "hello-gost") } +// TestParallelSelectorLimit exercises the parallel strategy with a node +// limit: only one node takes part in each race, so the dead node is no +// longer masked by the live one. With the round-robin mode the requests +// alternate between the live node (succeeds) and the dead node (fails). +func (s *SelectorSuite) TestParallelSelectorLimit() { + gostC, err := RunGostContainerWithPorts(s.ctx, SharedNetworkName, "testdata/selector/parallel_limit.yaml", "8080/tcp") + s.Require().NoError(err) + defer gostC.Terminate(s.ctx) + + code, body := s.proxyRequest(gostC, "8080") + s.Require().Equal(0, code) + s.Require().Contains(body, "hello-gost", "first race should pick the live node") + + code, body = s.proxyRequest(gostC, "8080") + s.Require().Equal(0, code) + s.Require().NotContains(body, "hello-gost", "second race should pick the dead node") + + code, body = s.proxyRequest(gostC, "8080") + s.Require().Equal(0, code) + s.Require().Contains(body, "hello-gost", "third race should pick the live node again") +} + func TestSelectorSuite(t *testing.T) { suite.Run(t, new(SelectorSuite)) } diff --git a/tests/e2e/testdata/selector/parallel_limit.yaml b/tests/e2e/testdata/selector/parallel_limit.yaml new file mode 100644 index 0000000..f50a6a3 --- /dev/null +++ b/tests/e2e/testdata/selector/parallel_limit.yaml @@ -0,0 +1,34 @@ +services: +- name: proxy + addr: :8080 + handler: + type: http + chain: my-chain + listener: + type: tcp + +- name: dummy-1 + addr: :18081 + handler: + type: http + +chains: +- name: my-chain + hops: + - name: hop-1 + selector: + strategy: parallel + # Only one node takes part in each race. + maxParallel: 1 + parallelMode: round + nodes: + - name: node-1 + addr: 127.0.0.1:18081 + connector: + type: http + # dead node: never listens; it is no longer masked by the live node + # because the two of them no longer race concurrently. + - name: node-2 + addr: 127.0.0.1:18082 + connector: + type: http