@@ -26,6 +26,7 @@ import (
2626 "net/http"
2727 "net/http/httptest"
2828 "testing"
29+ "time"
2930
3031 "cuelang.org/go/cue"
3132 "cuelang.org/go/cue/cuecontext"
@@ -99,6 +100,110 @@ func TestHTTPCmdRun(t *testing.T) {
99100
100101}
101102
103+ func TestHTTPCmdRunWithCustomTimeout (t * testing.T ) {
104+ // Start a slow server that takes 200ms to respond
105+ ts := httptest .NewUnstartedServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
106+ time .Sleep (200 * time .Millisecond )
107+ w .WriteHeader (http .StatusOK )
108+ w .Write ([]byte (`{"status":"ok"}` ))
109+ }))
110+ l , err := net .Listen ("tcp" , "127.0.0.1:0" )
111+ if err != nil {
112+ t .Fatalf ("failed to listen on ephemeral port: %v" , err )
113+ }
114+ ts .Listener .Close ()
115+ ts .Listener = l
116+ ts .Start ()
117+ defer ts .Close ()
118+
119+ // Derive the server URL from the listener address
120+ serverURL := fmt .Sprintf ("http://%s/api/v1/slow" , l .Addr ().String ())
121+
122+ // Without custom timeout (default 3s) — should succeed since server responds in 200ms
123+ reqDefault := cuecontext .New ().CompileString (fmt .Sprintf (`{
124+ method: "GET"
125+ url: "%s"
126+ }` , serverURL ))
127+ runner , _ := newHTTPCmd (cue.Value {})
128+ got , err := runner .Run (& registry.Meta {Obj : reqDefault .Value ()})
129+ assert .NoError (t , err )
130+ body := (got .(map [string ]interface {}))["body" ].(string )
131+ assert .Equal (t , `{"status":"ok"}` , body )
132+
133+ // With explicit timeout of 1s — should also succeed
134+ reqCustom := cuecontext .New ().CompileString (fmt .Sprintf (`{
135+ method: "GET"
136+ url: "%s"
137+ request: {
138+ timeout: "1s"
139+ }
140+ }` , serverURL ))
141+ got , err = runner .Run (& registry.Meta {Obj : reqCustom .Value ()})
142+ assert .NoError (t , err )
143+ body = (got .(map [string ]interface {}))["body" ].(string )
144+ assert .Equal (t , `{"status":"ok"}` , body )
145+
146+ // With a very short timeout of 50ms — should fail
147+ reqShort := cuecontext .New ().CompileString (fmt .Sprintf (`{
148+ method: "GET"
149+ url: "%s"
150+ request: {
151+ timeout: "50ms"
152+ }
153+ }` , serverURL ))
154+ _ , err = runner .Run (& registry.Meta {Obj : reqShort .Value ()})
155+ assert .Error (t , err , "expected timeout error with 50ms deadline on a 200ms server" )
156+ }
157+
158+ func TestHTTPCmdRunWithInvalidTimeout (t * testing.T ) {
159+ s := NewMock ()
160+ defer s .Close ()
161+
162+ runner , _ := newHTTPCmd (cue.Value {})
163+
164+ // Invalid timeout value should be silently ignored and use the default 3s
165+ reqInvalid := cuecontext .New ().CompileString (`{
166+ method: "GET"
167+ url: "http://127.0.0.1:8090/api/v1/token?val=test-token"
168+ request: {
169+ timeout: "not-a-duration"
170+ header: {
171+ "Accept-Language": "en,nl"
172+ }
173+ }
174+ }` )
175+ got , err := runner .Run (& registry.Meta {Obj : reqInvalid .Value ()})
176+ assert .NoError (t , err )
177+ body := (got .(map [string ]interface {}))["body" ].(string )
178+ assert .Equal (t , `{"token":"test-token"}` , body )
179+
180+ // Zero timeout should be rejected and fall back to default 3s
181+ reqZero := cuecontext .New ().CompileString (`{
182+ method: "GET"
183+ url: "http://127.0.0.1:8090/api/v1/token?val=test-zero"
184+ request: {
185+ timeout: "0s"
186+ }
187+ }` )
188+ got , err = runner .Run (& registry.Meta {Obj : reqZero .Value ()})
189+ assert .NoError (t , err )
190+ body = (got .(map [string ]interface {}))["body" ].(string )
191+ assert .Equal (t , `{"token":"test-zero"}` , body )
192+
193+ // Negative timeout should be rejected and fall back to default 3s
194+ reqNegative := cuecontext .New ().CompileString (`{
195+ method: "GET"
196+ url: "http://127.0.0.1:8090/api/v1/token?val=test-negative"
197+ request: {
198+ timeout: "-5s"
199+ }
200+ }` )
201+ got , err = runner .Run (& registry.Meta {Obj : reqNegative .Value ()})
202+ assert .NoError (t , err )
203+ body = (got .(map [string ]interface {}))["body" ].(string )
204+ assert .Equal (t , `{"token":"test-negative"}` , body )
205+ }
206+
102207func TestHTTPSRun (t * testing.T ) {
103208 s := newMockHttpsServer ()
104209 defer s .Close ()
0 commit comments