@@ -97,6 +97,7 @@ func TestTracerouteAutodetectFlagsOnly(t *testing.T) {
9797}
9898
9999func TestTracerouteHandlerWithoutQuery (t * testing.T ) {
100+ initTracerouteSemaphore (setting .tr_max_concurrent )
100101 r := httptest .NewRequest (http .MethodGet , "/traceroute" , nil )
101102 w := httptest .NewRecorder ()
102103 tracerouteHandler (w , r )
@@ -107,6 +108,7 @@ func TestTracerouteHandlerWithoutQuery(t *testing.T) {
107108}
108109
109110func TestTracerouteHandlerShlexError (t * testing.T ) {
111+ initTracerouteSemaphore (setting .tr_max_concurrent )
110112 r := httptest .NewRequest (http .MethodGet , "/traceroute?q=" + url .QueryEscape ("\" 1.1.1.1" ), nil )
111113 w := httptest .NewRecorder ()
112114 tracerouteHandler (w , r )
@@ -117,6 +119,7 @@ func TestTracerouteHandlerShlexError(t *testing.T) {
117119}
118120
119121func TestTracerouteHandlerNoTracerouteFound (t * testing.T ) {
122+ initTracerouteSemaphore (setting .tr_max_concurrent )
120123 setting .tr_bin = ""
121124 setting .tr_flags = nil
122125
@@ -130,6 +133,7 @@ func TestTracerouteHandlerNoTracerouteFound(t *testing.T) {
130133}
131134
132135func TestTracerouteHandlerExecuteError (t * testing.T ) {
136+ initTracerouteSemaphore (setting .tr_max_concurrent )
133137 setting .tr_bin = "sh"
134138 setting .tr_flags = []string {"-c" , "false" }
135139 setting .tr_raw = true
@@ -144,6 +148,7 @@ func TestTracerouteHandlerExecuteError(t *testing.T) {
144148}
145149
146150func TestTracerouteHandlerRaw (t * testing.T ) {
151+ initTracerouteSemaphore (setting .tr_max_concurrent )
147152 setting .tr_bin = "sh"
148153 setting .tr_flags = []string {"-c" , "echo Mock" }
149154 setting .tr_raw = true
@@ -156,6 +161,7 @@ func TestTracerouteHandlerRaw(t *testing.T) {
156161}
157162
158163func TestTracerouteHandlerPostprocess (t * testing.T ) {
164+ initTracerouteSemaphore (setting .tr_max_concurrent )
159165 setting .tr_bin = "sh"
160166 setting .tr_flags = []string {"-c" , "echo \" first line\n 2 *\n third line\" " }
161167 setting .tr_raw = false
@@ -166,3 +172,49 @@ func TestTracerouteHandlerPostprocess(t *testing.T) {
166172 assert .Equal (t , w .Code , http .StatusOK )
167173 assert .Equal (t , w .Body .String (), "first line\n third line\n \n 1 hops not responding." )
168174}
175+
176+ func TestTracerouteHandlerConcurrencyLimit (t * testing.T ) {
177+ // Set a low limit for testing
178+ maxConcurrent := 2
179+ initTracerouteSemaphore (maxConcurrent )
180+ setting .tr_max_concurrent = maxConcurrent
181+
182+ // Use a slow command to keep requests running
183+ setting .tr_bin = "sh"
184+ setting .tr_flags = []string {"-c" , "sleep 1; echo Done" }
185+ setting .tr_raw = true
186+
187+ // Launch more concurrent requests than the limit
188+ numRequests := 5
189+ responses := make (chan int , numRequests )
190+
191+ for i := 0 ; i < numRequests ; i ++ {
192+ go func () {
193+ r := httptest .NewRequest (http .MethodGet , "/traceroute?q=" + url .QueryEscape ("1.1.1.1" ), nil )
194+ w := httptest .NewRecorder ()
195+ tracerouteHandler (w , r )
196+ responses <- w .Code
197+ }()
198+ }
199+
200+ // Collect all responses
201+ statusCodes := make (map [int ]int )
202+ for i := 0 ; i < numRequests ; i ++ {
203+ code := <- responses
204+ statusCodes [code ]++
205+ }
206+
207+ // Verify that some requests succeeded (200) and some were rejected (503)
208+ if statusCodes [http .StatusOK ] == 0 {
209+ t .Error ("Expected at least one request to succeed with 200" )
210+ }
211+ if statusCodes [http .StatusServiceUnavailable ] == 0 {
212+ t .Error ("Expected at least one request to be rejected with 503" )
213+ }
214+
215+ // Verify we didn't get any unexpected status codes
216+ totalRequests := statusCodes [http .StatusOK ] + statusCodes [http .StatusServiceUnavailable ]
217+ if totalRequests != numRequests {
218+ t .Errorf ("Expected %d total requests, got %d" , numRequests , totalRequests )
219+ }
220+ }
0 commit comments