Skip to content

Commit 185f729

Browse files
committed
Update leader_forwarder and unit test
1 parent 4fa55ae commit 185f729

File tree

2 files changed

+105
-0
lines changed

2 files changed

+105
-0
lines changed

pkg/clusteragent/api/leader_forwarder.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ func (lf *LeaderForwarder) Forward(rw http.ResponseWriter, req *http.Request) {
8787

8888
if req.Header.Get(forwardHeader) != "" {
8989
http.Error(rw, "Query was already forwarded from: "+req.RemoteAddr, http.StatusLoopDetected)
90+
return
9091
}
9192

9293
var currentProxy *httputil.ReverseProxy
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
// Unless explicitly stated otherwise all files in this repository are licensed
2+
// under the Apache License Version 2.0.
3+
// This product includes software developed at Datadog (https://www.datadoghq.com/).
4+
// Copyright 2016-present Datadog, Inc.
5+
6+
//go:build test
7+
8+
package api
9+
10+
import (
11+
"net"
12+
"net/http"
13+
"net/http/httptest"
14+
"testing"
15+
16+
"github.com/stretchr/testify/assert"
17+
)
18+
19+
func TestLeaderForwarder_SetLeaderIP(t *testing.T) {
20+
lf := NewLeaderForwarder(5005, 10)
21+
22+
// Initially no leader IP
23+
assert.Equal(t, "", lf.GetLeaderIP())
24+
assert.Nil(t, lf.proxy)
25+
26+
// Set leader IP
27+
lf.SetLeaderIP("1.1.1.1")
28+
assert.Equal(t, "1.1.1.1", lf.GetLeaderIP())
29+
assert.NotNil(t, lf.proxy)
30+
31+
// Update leader IP
32+
lf.SetLeaderIP("2.2.2.2")
33+
assert.Equal(t, "2.2.2.2", lf.GetLeaderIP())
34+
assert.NotNil(t, lf.proxy)
35+
36+
// Clear proxy with empty string - note: leaderIP is NOT cleared (returns early)
37+
lf.SetLeaderIP("")
38+
assert.Equal(t, "2.2.2.2", lf.GetLeaderIP()) // leaderIP unchanged
39+
assert.Nil(t, lf.proxy) // but proxy is cleared
40+
}
41+
42+
func TestLeaderForwarder_Forward_NilProxy(t *testing.T) {
43+
lf := NewLeaderForwarder(5005, 10)
44+
45+
// No leader set, proxy is nil
46+
rw := httptest.NewRecorder()
47+
req := httptest.NewRequest("GET", "http://example.com/foo", nil)
48+
49+
lf.Forward(rw, req)
50+
51+
assert.Equal(t, http.StatusServiceUnavailable, rw.Code)
52+
assert.Equal(t, "true", rw.Header().Get("X-DCA-Forwarded"))
53+
}
54+
55+
func TestLeaderForwarder_Forward_LoopDetection(t *testing.T) {
56+
// Track if leader server was called
57+
leaderCalled := false
58+
leaderServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
59+
leaderCalled = true
60+
w.WriteHeader(http.StatusOK)
61+
}))
62+
defer leaderServer.Close()
63+
64+
port := leaderServer.Listener.Addr().(*net.TCPAddr).Port
65+
lf := NewLeaderForwarder(port, 10)
66+
lf.SetLeaderIP("127.0.0.1")
67+
68+
// Request already has forward header (loop detection)
69+
rw := httptest.NewRecorder()
70+
req := httptest.NewRequest("GET", "http://example.com/foo", nil)
71+
req.Header.Set("X-DCA-Follower-Forwarded", "true")
72+
73+
lf.Forward(rw, req)
74+
75+
// Loop detection should return 508 and NOT forward to leader
76+
assert.Equal(t, http.StatusLoopDetected, rw.Code)
77+
assert.Equal(t, "true", rw.Header().Get("X-DCA-Forwarded"))
78+
assert.False(t, leaderCalled, "Request should not be forwarded to leader when loop is detected")
79+
}
80+
81+
func TestLeaderForwarder_Forward_WithLeader(t *testing.T) {
82+
// Create a test server to act as the leader
83+
leaderServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
84+
// Verify the forward header was added
85+
assert.Equal(t, "true", r.Header.Get("X-DCA-Follower-Forwarded"))
86+
w.WriteHeader(http.StatusOK)
87+
w.Write([]byte("leader response"))
88+
}))
89+
defer leaderServer.Close()
90+
91+
// Extract port from test server
92+
port := leaderServer.Listener.Addr().(*net.TCPAddr).Port
93+
lf := NewLeaderForwarder(port, 10)
94+
lf.SetLeaderIP("127.0.0.1")
95+
96+
rw := httptest.NewRecorder()
97+
req := httptest.NewRequest("GET", "http://example.com/foo", nil)
98+
99+
lf.Forward(rw, req)
100+
101+
assert.Equal(t, http.StatusOK, rw.Code)
102+
assert.Equal(t, "true", rw.Header().Get("X-DCA-Forwarded"))
103+
assert.Equal(t, "leader response", rw.Body.String())
104+
}

0 commit comments

Comments
 (0)