Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion internal/controller/httproute_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ func (r *HTTPRouteReconciler) processHTTPRouteBackendRefs(tctx *provider.Transla

if service.Spec.Type == corev1.ServiceTypeExternalName {
tctx.Services[targetNN] = &service
return nil
continue
}

portExists := false
Expand Down
96 changes: 96 additions & 0 deletions test/e2e/gatewayapi/httproute.go
Original file line number Diff line number Diff line change
Expand Up @@ -1730,6 +1730,102 @@ spec:
})
})

Context("Test HTTPRoute Load Balancing", func() {
BeforeEach(beforeEachHTTP)
It("Test load balancing with ExternalName services", func() {
const servicesSpec = `
apiVersion: v1
kind: Service
metadata:
name: httpbin-external-domain
spec:
type: ExternalName
externalName: httpbin.org
---
apiVersion: v1
kind: Service
metadata:
name: mockapi7-external-domain
spec:
type: ExternalName
externalName: mock.api7.ai
---
apiVersion: apisix.apache.org/v1alpha1
kind: BackendTrafficPolicy
metadata:
name: passhost-node
spec:
targetRefs:
- name: httpbin-external-domain
kind: Service
group: ""
- name: mockapi7-external-domain
kind: Service
group: ""
passHost: node
scheme: https
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: lb-route
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: Exact
value: /headers
backendRefs:
- name: httpbin-external-domain
port: 443
weight: 1
- name: mockapi7-external-domain
port: 443
weight: 1
`

By("apply services and HTTPRoute")
err := s.CreateResourceFromString(servicesSpec)
Expect(err).ShouldNot(HaveOccurred(), "apply services and HTTPRoute")
time.Sleep(5 * time.Second)

Comment on lines +1792 to +1793
Copy link

Copilot AI Jul 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of a fixed time.Sleep, use a polling loop or Gomega's Eventually to wait for the HTTPRoute to become ready. This reduces flakiness and can shorten test run time.

Suggested change
time.Sleep(5 * time.Second)
Eventually(func() bool {
resp, err := s.NewAPISIXClient().GET("/headers").Expect().Raw()
if err != nil {
return false
}
return resp.StatusCode == http.StatusOK
}, 30*time.Second, 1*time.Second).Should(BeTrue(), "HTTPRoute should become ready")

Copilot uses AI. Check for mistakes.
By("verify load balancing works")
// Test multiple requests to verify load balancing
upstreamHosts := make(map[string]int)
totalRequests := 20

for i := 0; i < totalRequests; i++ {
resp := s.NewAPISIXClient().GET("/headers").Expect().Status(http.StatusOK)

// Parse JSON response to get the Host header
var responseBody map[string]any
resp.JSON().Decode(&responseBody)

if headers, ok := responseBody["headers"].(map[string]any); ok {
var host string
if host, ok = headers["Host"].(string); !ok {
host, ok = headers["host"].(string)
}
if ok && host != "" {
upstreamHosts[host]++
}
Expect(ok).To(BeTrue(), "Host header should be present")
Expect(host).Should(Or(Equal("httpbin.org"), Equal("mock.api7.ai")))
}
time.Sleep(100 * time.Millisecond) // Small delay between requests
}
Comment on lines +1799 to +1818
Copy link

Copilot AI Jul 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Avoid fixed delays inside the request loop. If pacing is needed, consider using parallel requests with a timeout or parameterizing the delay to speed up the suite.

Suggested change
for i := 0; i < totalRequests; i++ {
resp := s.NewAPISIXClient().GET("/headers").Expect().Status(http.StatusOK)
// Parse JSON response to get the Host header
var responseBody map[string]any
resp.JSON().Decode(&responseBody)
if headers, ok := responseBody["headers"].(map[string]any); ok {
var host string
if host, ok = headers["Host"].(string); !ok {
host, ok = headers["host"].(string)
}
if ok && host != "" {
upstreamHosts[host]++
}
Expect(ok).To(BeTrue(), "Host header should be present")
Expect(host).Should(Or(Equal("httpbin.org"), Equal("mock.api7.ai")))
}
time.Sleep(100 * time.Millisecond) // Small delay between requests
}
var wg sync.WaitGroup
var mu sync.Mutex
for i := 0; i < totalRequests; i++ {
wg.Add(1)
go func() {
defer wg.Done()
resp := s.NewAPISIXClient().GET("/headers").Expect().Status(http.StatusOK)
// Parse JSON response to get the Host header
var responseBody map[string]any
resp.JSON().Decode(&responseBody)
if headers, ok := responseBody["headers"].(map[string]any); ok {
var host string
if host, ok = headers["Host"].(string); !ok {
host, ok = headers["host"].(string)
}
if ok && host != "" {
mu.Lock()
upstreamHosts[host]++
mu.Unlock()
}
Expect(ok).To(BeTrue(), "Host header should be present")
Expect(host).Should(Or(Equal("httpbin.org"), Equal("mock.api7.ai")))
}
}()
}
wg.Wait()

Copilot uses AI. Check for mistakes.

By("verify both upstreams received requests")
Expect(upstreamHosts).Should(HaveLen(2))

for host, count := range upstreamHosts {
Expect(count).Should(BeNumerically(">", 0), fmt.Sprintf("upstream %s should receive requests", host))
}
})
})

/*
Context("HTTPRoute Status Updated", func() {
})
Expand Down
Loading