@@ -2,11 +2,13 @@ package proxy
22
33import (
44 "context"
5+ "errors"
56 "fmt"
67 "io"
78 "log/slog"
89 "net/http"
910 "net/http/httptest"
11+ "net/url"
1012 "os"
1113 "testing"
1214 "time"
@@ -52,29 +54,6 @@ func TestRPCProxy(t *testing.T) {
5254 stats := proxy .Stats ()
5355 require .Len (t , stats , 3 )
5456
55- var srv1Stats ServerStat
56- var srv2Stats ServerStat
57- var srv3Stats ServerStat
58- for _ , st := range stats {
59- if st .Name == "srv1" {
60- srv1Stats = st
61- }
62- if st .Name == "srv2" {
63- srv2Stats = st
64- }
65- if st .Name == "srv3" {
66- srv3Stats = st
67- }
68- }
69- require .Zero (t , srv1Stats .ErrorRate )
70- require .Zero (t , srv2Stats .ErrorRate )
71- require .Equal (t , float64 (100 ), srv3Stats .ErrorRate )
72- require .Greater (t , srv1Stats .Requests , srv2Stats .Requests )
73- require .Greater (t , srv2Stats .Avg , srv1Stats .Avg )
74- require .False (t , srv1Stats .Degraded )
75- require .False (t , srv2Stats .Degraded )
76- require .True (t , srv1Stats .Initialized )
77- require .True (t , srv2Stats .Initialized )
7857}
7958
8059func TestRestProxy (t * testing.T ) {
@@ -107,33 +86,6 @@ func TestRestProxy(t *testing.T) {
10786
10887 // stop the proxy
10988 cancel ()
110-
111- stats := proxy .Stats ()
112- require .Len (t , stats , 3 )
113-
114- var srv1Stats ServerStat
115- var srv2Stats ServerStat
116- var srv3Stats ServerStat
117- for _ , st := range stats {
118- if st .Name == "srv1" {
119- srv1Stats = st
120- }
121- if st .Name == "srv2" {
122- srv2Stats = st
123- }
124- if st .Name == "srv3" {
125- srv3Stats = st
126- }
127- }
128- require .Zero (t , srv1Stats .ErrorRate )
129- require .Zero (t , srv2Stats .ErrorRate )
130- require .Equal (t , float64 (100 ), srv3Stats .ErrorRate )
131- require .Greater (t , srv1Stats .Requests , srv2Stats .Requests )
132- require .Greater (t , srv2Stats .Avg , srv1Stats .Avg )
133- require .False (t , srv1Stats .Degraded )
134- require .False (t , srv2Stats .Degraded )
135- require .True (t , srv1Stats .Initialized )
136- require .True (t , srv2Stats .Initialized )
13789}
13890
13991func generateServerList (t * testing.T ) []seed.Node {
@@ -205,3 +157,174 @@ func sendSeed(ch chan seed.Seed, serverList []seed.Node) {
205157 },
206158 }
207159}
160+
161+ func TestNewReverseProxy (t * testing.T ) {
162+ tests := []struct {
163+ name string
164+ serverURL string
165+ reqPath string
166+ wantScheme string
167+ wantHost string
168+ wantPath string
169+ }{
170+ {
171+ name : "basic proxy test" ,
172+ serverURL : "http://node.com/base" ,
173+ reqPath : "/test" ,
174+ wantScheme : "http" ,
175+ wantHost : "node.com" ,
176+ wantPath : "/base/test" ,
177+ },
178+ {
179+ name : "https proxy test" ,
180+ serverURL : "https://api.node.com" ,
181+ reqPath : "/v1/data" ,
182+ wantScheme : "https" ,
183+ wantHost : "api.node.com" ,
184+ wantPath : "/v1/data" ,
185+ },
186+ }
187+
188+ for _ , tt := range tests {
189+ t .Run (tt .name , func (t * testing.T ) {
190+ // Setup test server
191+ targetURL , err := url .Parse (tt .serverURL )
192+ require .NoError (t , err )
193+
194+ srv := & Server {
195+ Url : targetURL ,
196+ name : "test-server" ,
197+ }
198+
199+ logger := slog .New (slog .NewTextHandler (io .Discard , nil ))
200+ proxy := newReverseProxy (srv , logger )
201+
202+ // Create test request
203+ req := httptest .NewRequest ("GET" , tt .reqPath , nil )
204+
205+ // Test Director function
206+ proxy .Director (req )
207+
208+ require .Equal (t , tt .wantScheme , req .URL .Scheme )
209+ require .Equal (t , tt .wantHost , req .URL .Host )
210+ require .Equal (t , tt .wantPath , req .URL .Path )
211+ })
212+ }
213+ }
214+
215+ func TestReverseProxy_ModifyResponse (t * testing.T ) {
216+ targetURL , _ := url .Parse ("http://node.com" )
217+ srv := & Server {Url : targetURL }
218+ logger := slog .New (slog .NewTextHandler (io .Discard , nil ))
219+ proxy := newReverseProxy (srv , logger )
220+
221+ resp := & http.Response {Header : make (http.Header )}
222+ resp .Header .Set ("Access-Control-Allow-Origin" , "*" )
223+ resp .Header .Set ("Access-Control-Allow-Methods" , "GET,POST" )
224+ resp .Header .Set ("Access-Control-Allow-Headers" , "Content-Type" )
225+
226+ err := proxy .ModifyResponse (resp )
227+ require .NoError (t , err )
228+
229+ require .Empty (t , resp .Header .Get ("Access-Control-Allow-Origin" ))
230+ require .Empty (t , resp .Header .Get ("Access-Control-Allow-Methods" ))
231+ require .Empty (t , resp .Header .Get ("Access-Control-Allow-Headers" ))
232+ }
233+
234+ func TestReverseProxy_ErrorHandler (t * testing.T ) {
235+ targetURL , _ := url .Parse ("http://node.com" )
236+ srv := & Server {Url : targetURL }
237+ logger := slog .New (slog .NewTextHandler (io .Discard , nil ))
238+ proxy := newReverseProxy (srv , logger )
239+
240+ w := httptest .NewRecorder ()
241+ req := httptest .NewRequest ("GET" , "/test" , nil )
242+ testErr := errors .New ("test error" )
243+
244+ proxy .ErrorHandler (w , req , testErr )
245+
246+ require .Equal (t , http .StatusInternalServerError , w .Code )
247+ require .Contains (t , w .Body .String (), "could not proxy request" )
248+ }
249+
250+ func TestDoUpdate (t * testing.T ) {
251+ tests := []struct {
252+ name string
253+ providers []seed.Node
254+ wantErr bool
255+ expectedServers int
256+ }{
257+ {
258+ name : "Add new server" ,
259+ providers : []seed.Node {
260+ {
261+ Provider : "test1" ,
262+ Address : "example.com" ,
263+ Status : seed.Status {
264+ CatchingUp : false ,
265+ Reachable : true ,
266+ IsLatestBlock : true ,
267+ },
268+ },
269+ },
270+ wantErr : false ,
271+ expectedServers : 1 ,
272+ },
273+ {
274+ name : "Remove unhealthy server" ,
275+ providers : []seed.Node {
276+ {
277+ Provider : "test2" ,
278+ Address : "example.com" ,
279+ Status : seed.Status {
280+ CatchingUp : false ,
281+ Reachable : true ,
282+ IsLatestBlock : true ,
283+ },
284+ },
285+ {
286+ Provider : "test3" ,
287+ Address : "example.com" ,
288+ Status : seed.Status {
289+ CatchingUp : true ,
290+ Reachable : false ,
291+ IsLatestBlock : false ,
292+ },
293+ },
294+ },
295+ wantErr : false ,
296+ expectedServers : 1 , // Unhealthy server should be removed
297+ },
298+ }
299+
300+ for _ , tt := range tests {
301+ t .Run (tt .name , func (t * testing.T ) {
302+ p := & Proxy {
303+ cfg : config.Config {},
304+ log : slog .Default (),
305+ servers : []* Server {},
306+ lb : & MockLoadBalancer {},
307+ }
308+
309+ err := p .doUpdate (tt .providers )
310+ if (err != nil ) != tt .wantErr {
311+ t .Errorf ("doUpdate() error = %v, wantErr %v" , err , tt .wantErr )
312+ }
313+
314+ if ! tt .wantErr {
315+ if ! p .initialized .Load () {
316+ t .Error ("proxy should be initialized after successful update" )
317+ }
318+ require .Len (t , p .servers , tt .expectedServers )
319+ }
320+ })
321+ }
322+ }
323+
324+ type MockLoadBalancer struct {}
325+
326+ func (m * MockLoadBalancer ) Update (servers []* Server ) {}
327+
328+ func (m * MockLoadBalancer ) Next () * Server {
329+ return nil
330+ }
0 commit comments