Best K6 code snippet using http.assertRequestMetricsEmitted
request_test.go
Source:request_test.go
...50 "github.com/stretchr/testify/assert"51 "github.com/stretchr/testify/require"52 null "gopkg.in/guregu/null.v3"53)54func assertRequestMetricsEmitted(t *testing.T, sampleContainers []stats.SampleContainer, method, url, name string, status int, group string) {55 if name == "" {56 name = url57 }58 seenDuration := false59 seenBlocked := false60 seenConnecting := false61 seenTLSHandshaking := false62 seenSending := false63 seenWaiting := false64 seenReceiving := false65 for _, sampleContainer := range sampleContainers {66 for _, sample := range sampleContainer.GetSamples() {67 tags := sample.Tags.CloneTags()68 if tags["url"] == url {69 switch sample.Metric {70 case metrics.HTTPReqDuration:71 seenDuration = true72 case metrics.HTTPReqBlocked:73 seenBlocked = true74 case metrics.HTTPReqConnecting:75 seenConnecting = true76 case metrics.HTTPReqTLSHandshaking:77 seenTLSHandshaking = true78 case metrics.HTTPReqSending:79 seenSending = true80 case metrics.HTTPReqWaiting:81 seenWaiting = true82 case metrics.HTTPReqReceiving:83 seenReceiving = true84 }85 assert.Equal(t, strconv.Itoa(status), tags["status"])86 assert.Equal(t, method, tags["method"])87 assert.Equal(t, group, tags["group"])88 assert.Equal(t, name, tags["name"])89 }90 }91 }92 assert.True(t, seenDuration, "url %s didn't emit Duration", url)93 assert.True(t, seenBlocked, "url %s didn't emit Blocked", url)94 assert.True(t, seenConnecting, "url %s didn't emit Connecting", url)95 assert.True(t, seenTLSHandshaking, "url %s didn't emit TLSHandshaking", url)96 assert.True(t, seenSending, "url %s didn't emit Sending", url)97 assert.True(t, seenWaiting, "url %s didn't emit Waiting", url)98 assert.True(t, seenReceiving, "url %s didn't emit Receiving", url)99}100func newRuntime(101 t testing.TB,102) (*httpmultibin.HTTPMultiBin, *lib.State, chan stats.SampleContainer, *goja.Runtime, *context.Context) {103 tb := httpmultibin.NewHTTPMultiBin(t)104 root, err := lib.NewGroup("", nil)105 require.NoError(t, err)106 logger := logrus.New()107 logger.Level = logrus.DebugLevel108 rt := goja.New()109 rt.SetFieldNameMapper(common.FieldNameMapper{})110 options := lib.Options{111 MaxRedirects: null.IntFrom(10),112 UserAgent: null.StringFrom("TestUserAgent"),113 Throw: null.BoolFrom(true),114 SystemTags: &stats.DefaultSystemTagSet,115 //HTTPDebug: null.StringFrom("full"),116 }117 samples := make(chan stats.SampleContainer, 1000)118 state := &lib.State{119 Options: options,120 Logger: logger,121 Group: root,122 TLSConfig: tb.TLSClientConfig,123 Transport: tb.HTTPTransport,124 BPool: bpool.NewBufferPool(1),125 Samples: samples,126 }127 ctx := new(context.Context)128 *ctx = lib.WithState(tb.Context, state)129 *ctx = common.WithRuntime(*ctx, rt)130 rt.Set("http", common.Bind(rt, New(), ctx))131 return tb, state, samples, rt, ctx132}133func TestRequestAndBatch(t *testing.T) {134 if runtime.GOOS == "windows" {135 t.Skip()136 }137 t.Parallel()138 tb, state, samples, rt, ctx := newRuntime(t)139 defer tb.Cleanup()140 sr := tb.Replacer.Replace141 // Handle paths with custom logic142 tb.Mux.HandleFunc("/digest-auth/failure", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {143 time.Sleep(2 * time.Second)144 }))145 t.Run("Redirects", func(t *testing.T) {146 t.Run("tracing", func(t *testing.T) {147 _, err := common.RunString(rt, sr(`148 let res = http.get("HTTPBIN_URL/redirect/9");149 `))150 assert.NoError(t, err)151 bufSamples := stats.GetBufferedSamples(samples)152 reqsCount := 0153 for _, container := range bufSamples {154 for _, sample := range container.GetSamples() {155 if sample.Metric.Name == "http_reqs" {156 reqsCount++157 }158 }159 }160 assert.Equal(t, 10, reqsCount)161 assertRequestMetricsEmitted(t, bufSamples, "GET", sr("HTTPBIN_URL/get"), sr("HTTPBIN_URL/redirect/9"), 200, "")162 })163 t.Run("10", func(t *testing.T) {164 _, err := common.RunString(rt, sr(`http.get("HTTPBIN_URL/redirect/10")`))165 assert.NoError(t, err)166 })167 t.Run("11", func(t *testing.T) {168 _, err := common.RunString(rt, sr(`169 let res = http.get("HTTPBIN_URL/redirect/11");170 if (res.status != 302) { throw new Error("wrong status: " + res.status) }171 if (res.url != "HTTPBIN_URL/relative-redirect/1") { throw new Error("incorrect URL: " + res.url) }172 if (res.headers["Location"] != "/get") { throw new Error("incorrect Location header: " + res.headers["Location"]) }173 `))174 assert.NoError(t, err)175 t.Run("Unset Max", func(t *testing.T) {176 hook := logtest.NewLocal(state.Logger)177 defer hook.Reset()178 oldOpts := state.Options179 defer func() { state.Options = oldOpts }()180 state.Options.MaxRedirects = null.NewInt(10, false)181 _, err := common.RunString(rt, sr(`182 let res = http.get("HTTPBIN_URL/redirect/11");183 if (res.status != 302) { throw new Error("wrong status: " + res.status) }184 if (res.url != "HTTPBIN_URL/relative-redirect/1") { throw new Error("incorrect URL: " + res.url) }185 if (res.headers["Location"] != "/get") { throw new Error("incorrect Location header: " + res.headers["Location"]) }186 `))187 assert.NoError(t, err)188 logEntry := hook.LastEntry()189 if assert.NotNil(t, logEntry) {190 assert.Equal(t, logrus.WarnLevel, logEntry.Level)191 assert.Equal(t, sr("HTTPBIN_URL/redirect/11"), logEntry.Data["url"])192 assert.Equal(t, "Stopped after 11 redirects and returned the redirection; pass { redirects: n } in request params or set global maxRedirects to silence this", logEntry.Message)193 }194 })195 })196 t.Run("requestScopeRedirects", func(t *testing.T) {197 _, err := common.RunString(rt, sr(`198 let res = http.get("HTTPBIN_URL/redirect/1", {redirects: 3});199 if (res.status != 200) { throw new Error("wrong status: " + res.status) }200 if (res.url != "HTTPBIN_URL/get") { throw new Error("incorrect URL: " + res.url) }201 `))202 assert.NoError(t, err)203 })204 t.Run("requestScopeNoRedirects", func(t *testing.T) {205 _, err := common.RunString(rt, sr(`206 let res = http.get("HTTPBIN_URL/redirect/1", {redirects: 0});207 if (res.status != 302) { throw new Error("wrong status: " + res.status) }208 if (res.url != "HTTPBIN_URL/redirect/1") { throw new Error("incorrect URL: " + res.url) }209 if (res.headers["Location"] != "/get") { throw new Error("incorrect Location header: " + res.headers["Location"]) }210 `))211 assert.NoError(t, err)212 })213 t.Run("post body", func(t *testing.T) {214 tb.Mux.HandleFunc("/post-redirect", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {215 require.Equal(t, r.Method, "POST")216 _, _ = io.Copy(ioutil.Discard, r.Body)217 http.Redirect(w, r, sr("HTTPBIN_URL/post"), http.StatusPermanentRedirect)218 }))219 _, err := common.RunString(rt, sr(`220 let res = http.post("HTTPBIN_URL/post-redirect", "pesho", {redirects: 1});221 if (res.status != 200) { throw new Error("wrong status: " + res.status) }222 if (res.url != "HTTPBIN_URL/post") { throw new Error("incorrect URL: " + res.url) }223 if (res.json().data != "pesho") { throw new Error("incorrect data : " + res.json().data) }224 `))225 assert.NoError(t, err)226 })227 })228 t.Run("Timeout", func(t *testing.T) {229 t.Run("10s", func(t *testing.T) {230 _, err := common.RunString(rt, sr(`231 http.get("HTTPBIN_URL/delay/1", {232 timeout: 5*1000,233 })234 `))235 assert.NoError(t, err)236 })237 t.Run("10s", func(t *testing.T) {238 hook := logtest.NewLocal(state.Logger)239 defer hook.Reset()240 startTime := time.Now()241 _, err := common.RunString(rt, sr(`242 http.get("HTTPBIN_URL/delay/10", {243 timeout: 1*1000,244 })245 `))246 endTime := time.Now()247 assert.EqualError(t, err, sr("GoError: Get HTTPBIN_URL/delay/10: net/http: request canceled (Client.Timeout exceeded while awaiting headers)"))248 assert.WithinDuration(t, startTime.Add(1*time.Second), endTime, 2*time.Second)249 logEntry := hook.LastEntry()250 if assert.NotNil(t, logEntry) {251 assert.Equal(t, logrus.WarnLevel, logEntry.Level)252 assert.EqualError(t, logEntry.Data["error"].(error), sr("Get HTTPBIN_URL/delay/10: net/http: request canceled (Client.Timeout exceeded while awaiting headers)"))253 assert.Equal(t, "Request Failed", logEntry.Message)254 }255 })256 })257 t.Run("UserAgent", func(t *testing.T) {258 _, err := common.RunString(rt, sr(`259 let res = http.get("HTTPBIN_URL/user-agent");260 if (res.json()['user-agent'] != "TestUserAgent") {261 throw new Error("incorrect user agent: " + res.json()['user-agent'])262 }263 `))264 assert.NoError(t, err)265 t.Run("Override", func(t *testing.T) {266 _, err := common.RunString(rt, sr(`267 let res = http.get("HTTPBIN_URL/user-agent", {268 headers: { "User-Agent": "OtherUserAgent" },269 });270 if (res.json()['user-agent'] != "OtherUserAgent") {271 throw new Error("incorrect user agent: " + res.json()['user-agent'])272 }273 `))274 assert.NoError(t, err)275 })276 })277 t.Run("Compression", func(t *testing.T) {278 t.Run("gzip", func(t *testing.T) {279 _, err := common.RunString(rt, sr(`280 let res = http.get("HTTPSBIN_IP_URL/gzip");281 if (res.json()['gzipped'] != true) {282 throw new Error("unexpected body data: " + res.json()['gzipped'])283 }284 `))285 assert.NoError(t, err)286 })287 t.Run("deflate", func(t *testing.T) {288 _, err := common.RunString(rt, sr(`289 let res = http.get("HTTPBIN_URL/deflate");290 if (res.json()['deflated'] != true) {291 throw new Error("unexpected body data: " + res.json()['deflated'])292 }293 `))294 assert.NoError(t, err)295 })296 t.Run("zstd", func(t *testing.T) {297 _, err := common.RunString(rt, sr(`298 let res = http.get("HTTPSBIN_IP_URL/zstd");299 if (res.json()['compression'] != 'zstd') {300 throw new Error("unexpected body data: " + res.json()['compression'])301 }302 `))303 assert.NoError(t, err)304 })305 t.Run("brotli", func(t *testing.T) {306 _, err := common.RunString(rt, sr(`307 let res = http.get("HTTPSBIN_IP_URL/brotli");308 if (res.json()['compression'] != 'br') {309 throw new Error("unexpected body data: " + res.json()['compression'])310 }311 `))312 assert.NoError(t, err)313 })314 t.Run("zstd-br", func(t *testing.T) {315 _, err := common.RunString(rt, sr(`316 let res = http.get("HTTPSBIN_IP_URL/zstd-br");317 if (res.json()['compression'] != 'zstd, br') {318 throw new Error("unexpected compression: " + res.json()['compression'])319 }320 `))321 assert.NoError(t, err)322 })323 })324 t.Run("CompressionWithAcceptEncodingHeader", func(t *testing.T) {325 t.Run("gzip", func(t *testing.T) {326 _, err := common.RunString(rt, sr(`327 let params = { headers: { "Accept-Encoding": "gzip" } };328 let res = http.get("HTTPBIN_URL/gzip", params);329 if (res.json()['gzipped'] != true) {330 throw new Error("unexpected body data: " + res.json()['gzipped'])331 }332 `))333 assert.NoError(t, err)334 })335 t.Run("deflate", func(t *testing.T) {336 _, err := common.RunString(rt, sr(`337 let params = { headers: { "Accept-Encoding": "deflate" } };338 let res = http.get("HTTPBIN_URL/deflate", params);339 if (res.json()['deflated'] != true) {340 throw new Error("unexpected body data: " + res.json()['deflated'])341 }342 `))343 assert.NoError(t, err)344 })345 })346 t.Run("Cancelled", func(t *testing.T) {347 hook := logtest.NewLocal(state.Logger)348 defer hook.Reset()349 oldctx := *ctx350 newctx, cancel := context.WithCancel(oldctx)351 cancel()352 *ctx = newctx353 defer func() { *ctx = oldctx }()354 _, err := common.RunString(rt, sr(`http.get("HTTPBIN_URL/get/");`))355 assert.Error(t, err)356 assert.Nil(t, hook.LastEntry())357 })358 t.Run("HTTP/2", func(t *testing.T) {359 stats.GetBufferedSamples(samples) // Clean up buffered samples from previous tests360 _, err := common.RunString(rt, `361 let res = http.request("GET", "https://http2.akamai.com/demo");362 if (res.status != 200) { throw new Error("wrong status: " + res.status) }363 if (res.proto != "HTTP/2.0") { throw new Error("wrong proto: " + res.proto) }364 `)365 assert.NoError(t, err)366 bufSamples := stats.GetBufferedSamples(samples)367 assertRequestMetricsEmitted(t, bufSamples, "GET", "https://http2.akamai.com/demo", "", 200, "")368 for _, sampleC := range bufSamples {369 for _, sample := range sampleC.GetSamples() {370 proto, ok := sample.Tags.Get("proto")371 assert.True(t, ok)372 assert.Equal(t, "HTTP/2.0", proto)373 }374 }375 })376 t.Run("TLS", func(t *testing.T) {377 t.Run("cert_expired", func(t *testing.T) {378 _, err := common.RunString(rt, `http.get("https://expired.badssl.com/");`)379 assert.EqualError(t, err, "GoError: Get https://expired.badssl.com/: x509: certificate has expired or is not yet valid")380 })381 tlsVersionTests := []struct {382 Name, URL, Version string383 }{384 {Name: "tls10", URL: "https://tls-v1-0.badssl.com:1010/", Version: "http.TLS_1_0"},385 {Name: "tls11", URL: "https://tls-v1-1.badssl.com:1011/", Version: "http.TLS_1_1"},386 {Name: "tls12", URL: "https://badssl.com/", Version: "http.TLS_1_2"},387 }388 for _, versionTest := range tlsVersionTests {389 t.Run(versionTest.Name, func(t *testing.T) {390 _, err := common.RunString(rt, fmt.Sprintf(`391 let res = http.get("%s");392 if (res.tls_version != %s) { throw new Error("wrong TLS version: " + res.tls_version); }393 `, versionTest.URL, versionTest.Version))394 assert.NoError(t, err)395 assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", versionTest.URL, "", 200, "")396 })397 }398 tlsCipherSuiteTests := []struct {399 Name, URL, CipherSuite string400 }{401 {Name: "cipher_suite_cbc", URL: "https://cbc.badssl.com/", CipherSuite: "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"},402 {Name: "cipher_suite_ecc384", URL: "https://ecc384.badssl.com/", CipherSuite: "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"},403 }404 for _, cipherSuiteTest := range tlsCipherSuiteTests {405 t.Run(cipherSuiteTest.Name, func(t *testing.T) {406 _, err := common.RunString(rt, fmt.Sprintf(`407 let res = http.get("%s");408 if (res.tls_cipher_suite != "%s") { throw new Error("wrong TLS cipher suite: " + res.tls_cipher_suite); }409 `, cipherSuiteTest.URL, cipherSuiteTest.CipherSuite))410 assert.NoError(t, err)411 assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", cipherSuiteTest.URL, "", 200, "")412 })413 }414 t.Run("ocsp_stapled_good", func(t *testing.T) {415 _, err := common.RunString(rt, `416 let res = http.request("GET", "https://stackoverflow.com/");417 if (res.ocsp.status != http.OCSP_STATUS_GOOD) { throw new Error("wrong ocsp stapled response status: " + res.ocsp.status); }418 `)419 assert.NoError(t, err)420 assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", "https://stackoverflow.com/", "", 200, "")421 })422 })423 t.Run("Invalid", func(t *testing.T) {424 hook := logtest.NewLocal(state.Logger)425 defer hook.Reset()426 _, err := common.RunString(rt, `http.request("", "");`)427 assert.EqualError(t, err, "GoError: Get : unsupported protocol scheme \"\"")428 logEntry := hook.LastEntry()429 if assert.NotNil(t, logEntry) {430 assert.Equal(t, logrus.WarnLevel, logEntry.Level)431 assert.Equal(t, "Get : unsupported protocol scheme \"\"", logEntry.Data["error"].(error).Error())432 assert.Equal(t, "Request Failed", logEntry.Message)433 }434 t.Run("throw=false", func(t *testing.T) {435 hook := logtest.NewLocal(state.Logger)436 defer hook.Reset()437 _, err := common.RunString(rt, `438 let res = http.request("", "", { throw: false });439 throw new Error(res.error);440 `)441 assert.EqualError(t, err, "GoError: Get : unsupported protocol scheme \"\"")442 logEntry := hook.LastEntry()443 if assert.NotNil(t, logEntry) {444 assert.Equal(t, logrus.WarnLevel, logEntry.Level)445 assert.EqualError(t, logEntry.Data["error"].(error), "Get : unsupported protocol scheme \"\"")446 assert.Equal(t, "Request Failed", logEntry.Message)447 }448 })449 })450 t.Run("Unroutable", func(t *testing.T) {451 _, err := common.RunString(rt, `http.request("GET", "http://sdafsgdhfjg/");`)452 assert.Error(t, err)453 })454 t.Run("Params", func(t *testing.T) {455 for _, literal := range []string{`undefined`, `null`} {456 t.Run(literal, func(t *testing.T) {457 _, err := common.RunString(rt, fmt.Sprintf(sr(`458 let res = http.request("GET", "HTTPBIN_URL/headers", null, %s);459 if (res.status != 200) { throw new Error("wrong status: " + res.status); }460 `), literal))461 assert.NoError(t, err)462 assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/headers"), "", 200, "")463 })464 }465 t.Run("cookies", func(t *testing.T) {466 t.Run("access", func(t *testing.T) {467 cookieJar, err := cookiejar.New(nil)468 assert.NoError(t, err)469 state.CookieJar = cookieJar470 _, err = common.RunString(rt, sr(`471 let res = http.request("GET", "HTTPBIN_URL/cookies/set?key=value", null, { redirects: 0 });472 if (res.cookies.key[0].value != "value") { throw new Error("wrong cookie value: " + res.cookies.key[0].value); }473 const props = ["name", "value", "domain", "path", "expires", "max_age", "secure", "http_only"];474 let cookie = res.cookies.key[0];475 for (let i = 0; i < props.length; i++) {476 if (cookie[props[i]] === undefined) {477 throw new Error("cookie property not found: " + props[i]);478 }479 }480 if (Object.keys(cookie).length != props.length) {481 throw new Error("cookie has more properties than expected: " + JSON.stringify(Object.keys(cookie)));482 }483 `))484 assert.NoError(t, err)485 assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/cookies/set?key=value"), "", 302, "")486 })487 t.Run("vuJar", func(t *testing.T) {488 cookieJar, err := cookiejar.New(nil)489 assert.NoError(t, err)490 state.CookieJar = cookieJar491 _, err = common.RunString(rt, sr(`492 let jar = http.cookieJar();493 jar.set("HTTPBIN_URL/cookies", "key", "value");494 let res = http.request("GET", "HTTPBIN_URL/cookies", null, { cookies: { key2: "value2" } });495 if (res.json().key != "value") { throw new Error("wrong cookie value: " + res.json().key); }496 if (res.json().key2 != "value2") { throw new Error("wrong cookie value: " + res.json().key2); }497 let jarCookies = jar.cookiesForURL("HTTPBIN_URL/cookies");498 if (jarCookies.key[0] != "value") { throw new Error("wrong cookie value in jar"); }499 if (jarCookies.key2 != undefined) { throw new Error("unexpected cookie in jar"); }500 `))501 assert.NoError(t, err)502 assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/cookies"), "", 200, "")503 })504 t.Run("requestScope", func(t *testing.T) {505 cookieJar, err := cookiejar.New(nil)506 assert.NoError(t, err)507 state.CookieJar = cookieJar508 _, err = common.RunString(rt, sr(`509 let res = http.request("GET", "HTTPBIN_URL/cookies", null, { cookies: { key: "value" } });510 if (res.json().key != "value") { throw new Error("wrong cookie value: " + res.json().key); }511 let jar = http.cookieJar();512 let jarCookies = jar.cookiesForURL("HTTPBIN_URL/cookies");513 if (jarCookies.key != undefined) { throw new Error("unexpected cookie in jar"); }514 `))515 assert.NoError(t, err)516 assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/cookies"), "", 200, "")517 })518 t.Run("requestScopeReplace", func(t *testing.T) {519 cookieJar, err := cookiejar.New(nil)520 assert.NoError(t, err)521 state.CookieJar = cookieJar522 _, err = common.RunString(rt, sr(`523 let jar = http.cookieJar();524 jar.set("HTTPBIN_URL/cookies", "key", "value");525 let res = http.request("GET", "HTTPBIN_URL/cookies", null, { cookies: { key: { value: "replaced", replace: true } } });526 if (res.json().key != "replaced") { throw new Error("wrong cookie value: " + res.json().key); }527 let jarCookies = jar.cookiesForURL("HTTPBIN_URL/cookies");528 if (jarCookies.key[0] != "value") { throw new Error("wrong cookie value in jar"); }529 `))530 assert.NoError(t, err)531 assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/cookies"), "", 200, "")532 })533 t.Run("redirect", func(t *testing.T) {534 t.Run("set cookie after redirect", func(t *testing.T) {535 // TODO figure out a way to remove this ?536 tb.Mux.HandleFunc("/set-cookie-without-redirect", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {537 cookie := http.Cookie{538 Name: "key-foo",539 Value: "value-bar",540 Path: "/",541 Domain: sr("HTTPSBIN_DOMAIN"),542 }543 http.SetCookie(w, &cookie)544 w.WriteHeader(200)545 }))546 cookieJar, err := cookiejar.New(nil)547 require.NoError(t, err)548 state.CookieJar = cookieJar549 _, err = common.RunString(rt, sr(`550 let res = http.request("GET", "HTTPBIN_URL/redirect-to?url=HTTPSBIN_URL/set-cookie-without-redirect");551 if (res.status != 200) { throw new Error("wrong status: " + res.status); }552 `))553 require.NoError(t, err)554 redirectURL, err := url.Parse(sr("HTTPSBIN_URL"))555 require.NoError(t, err)556 require.Len(t, cookieJar.Cookies(redirectURL), 1)557 require.Equal(t, "key-foo", cookieJar.Cookies(redirectURL)[0].Name)558 require.Equal(t, "value-bar", cookieJar.Cookies(redirectURL)[0].Value)559 assertRequestMetricsEmitted(560 t,561 stats.GetBufferedSamples(samples),562 "GET",563 sr("HTTPSBIN_URL/set-cookie-without-redirect"),564 sr("HTTPBIN_URL/redirect-to?url=HTTPSBIN_URL/set-cookie-without-redirect"),565 200,566 "",567 )568 })569 t.Run("set cookie before redirect", func(t *testing.T) {570 cookieJar, err := cookiejar.New(nil)571 require.NoError(t, err)572 state.CookieJar = cookieJar573 _, err = common.RunString(rt, sr(`574 let res = http.request("GET", "HTTPSBIN_URL/cookies/set?key=value");575 if (res.status != 200) { throw new Error("wrong status: " + res.status); }576 `))577 require.NoError(t, err)578 redirectURL, err := url.Parse(sr("HTTPSBIN_URL/cookies"))579 require.NoError(t, err)580 require.Len(t, cookieJar.Cookies(redirectURL), 1)581 require.Equal(t, "key", cookieJar.Cookies(redirectURL)[0].Name)582 require.Equal(t, "value", cookieJar.Cookies(redirectURL)[0].Value)583 assertRequestMetricsEmitted(584 t,585 stats.GetBufferedSamples(samples),586 "GET",587 sr("HTTPSBIN_URL/cookies"),588 sr("HTTPSBIN_URL/cookies/set?key=value"),589 200,590 "",591 )592 })593 t.Run("set cookie after redirect and before second redirect", func(t *testing.T) {594 cookieJar, err := cookiejar.New(nil)595 require.NoError(t, err)596 state.CookieJar = cookieJar597 // TODO figure out a way to remove this ?598 tb.Mux.HandleFunc("/set-cookie-and-redirect", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {599 cookie := http.Cookie{600 Name: "key-foo",601 Value: "value-bar",602 Path: "/set-cookie-and-redirect",603 Domain: sr("HTTPSBIN_DOMAIN"),604 }605 http.SetCookie(w, &cookie)606 http.Redirect(w, r, sr("HTTPBIN_IP_URL/get"), http.StatusMovedPermanently)607 }))608 _, err = common.RunString(rt, sr(`609 let res = http.request("GET", "HTTPBIN_IP_URL/redirect-to?url=HTTPSBIN_URL/set-cookie-and-redirect");610 if (res.status != 200) { throw new Error("wrong status: " + res.status); }611 `))612 require.NoError(t, err)613 redirectURL, err := url.Parse(sr("HTTPSBIN_URL/set-cookie-and-redirect"))614 require.NoError(t, err)615 require.Len(t, cookieJar.Cookies(redirectURL), 1)616 require.Equal(t, "key-foo", cookieJar.Cookies(redirectURL)[0].Name)617 require.Equal(t, "value-bar", cookieJar.Cookies(redirectURL)[0].Value)618 for _, cookieLessURL := range []string{"HTTPSBIN_URL", "HTTPBIN_IP_URL/redirect-to", "HTTPBIN_IP_URL/get"} {619 redirectURL, err = url.Parse(sr(cookieLessURL))620 require.NoError(t, err)621 require.Empty(t, cookieJar.Cookies(redirectURL))622 }623 assertRequestMetricsEmitted(624 t,625 stats.GetBufferedSamples(samples),626 "GET",627 sr("HTTPBIN_IP_URL/get"),628 sr("HTTPBIN_IP_URL/redirect-to?url=HTTPSBIN_URL/set-cookie-and-redirect"),629 200,630 "",631 )632 })633 })634 t.Run("domain", func(t *testing.T) {635 cookieJar, err := cookiejar.New(nil)636 assert.NoError(t, err)637 state.CookieJar = cookieJar638 _, err = common.RunString(rt, sr(`639 let jar = http.cookieJar();640 jar.set("HTTPBIN_URL/cookies", "key", "value", { domain: "HTTPBIN_DOMAIN" });641 let res = http.request("GET", "HTTPBIN_URL/cookies");642 if (res.json().key != "value") {643 throw new Error("wrong cookie value 1: " + res.json().key);644 }645 jar.set("HTTPBIN_URL/cookies", "key2", "value2", { domain: "example.com" });646 res = http.request("GET", "HTTPBIN_URL/cookies");647 if (res.json().key != "value") {648 throw new Error("wrong cookie value 2: " + res.json().key);649 }650 if (res.json().key2 != undefined) {651 throw new Error("cookie 'key2' unexpectedly found");652 }653 `))654 assert.NoError(t, err)655 assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/cookies"), "", 200, "")656 })657 t.Run("path", func(t *testing.T) {658 cookieJar, err := cookiejar.New(nil)659 assert.NoError(t, err)660 state.CookieJar = cookieJar661 _, err = common.RunString(rt, sr(`662 let jar = http.cookieJar();663 jar.set("HTTPBIN_URL/cookies", "key", "value", { path: "/cookies" });664 let res = http.request("GET", "HTTPBIN_URL/cookies");665 if (res.json().key != "value") {666 throw new Error("wrong cookie value: " + res.json().key);667 }668 jar.set("HTTPBIN_URL/cookies", "key2", "value2", { path: "/some-other-path" });669 res = http.request("GET", "HTTPBIN_URL/cookies");670 if (res.json().key != "value") {671 throw new Error("wrong cookie value: " + res.json().key);672 }673 if (res.json().key2 != undefined) {674 throw new Error("cookie 'key2' unexpectedly found");675 }676 `))677 assert.NoError(t, err)678 assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/cookies"), "", 200, "")679 })680 t.Run("expires", func(t *testing.T) {681 cookieJar, err := cookiejar.New(nil)682 assert.NoError(t, err)683 state.CookieJar = cookieJar684 _, err = common.RunString(rt, sr(`685 let jar = http.cookieJar();686 jar.set("HTTPBIN_URL/cookies", "key", "value", { expires: "Sun, 24 Jul 1983 17:01:02 GMT" });687 let res = http.request("GET", "HTTPBIN_URL/cookies");688 if (res.json().key != undefined) {689 throw new Error("cookie 'key' unexpectedly found");690 }691 jar.set("HTTPBIN_URL/cookies", "key", "value", { expires: "Sat, 24 Jul 2083 17:01:02 GMT" });692 res = http.request("GET", "HTTPBIN_URL/cookies");693 if (res.json().key != "value") {694 throw new Error("cookie 'key' not found");695 }696 `))697 assert.NoError(t, err)698 assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/cookies"), "", 200, "")699 })700 t.Run("secure", func(t *testing.T) {701 cookieJar, err := cookiejar.New(nil)702 assert.NoError(t, err)703 state.CookieJar = cookieJar704 _, err = common.RunString(rt, sr(`705 let jar = http.cookieJar();706 jar.set("HTTPSBIN_IP_URL/cookies", "key", "value", { secure: true });707 let res = http.request("GET", "HTTPSBIN_IP_URL/cookies");708 if (res.json().key != "value") {709 throw new Error("wrong cookie value: " + res.json().key);710 }711 `))712 assert.NoError(t, err)713 assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPSBIN_IP_URL/cookies"), "", 200, "")714 })715 t.Run("localJar", func(t *testing.T) {716 cookieJar, err := cookiejar.New(nil)717 assert.NoError(t, err)718 state.CookieJar = cookieJar719 _, err = common.RunString(rt, sr(`720 let jar = new http.CookieJar();721 jar.set("HTTPBIN_URL/cookies", "key", "value");722 let res = http.request("GET", "HTTPBIN_URL/cookies", null, { cookies: { key2: "value2" }, jar: jar });723 if (res.json().key != "value") { throw new Error("wrong cookie value: " + res.json().key); }724 if (res.json().key2 != "value2") { throw new Error("wrong cookie value: " + res.json().key2); }725 let jarCookies = jar.cookiesForURL("HTTPBIN_URL/cookies");726 if (jarCookies.key[0] != "value") { throw new Error("wrong cookie value in jar: " + jarCookies.key[0]); }727 if (jarCookies.key2 != undefined) { throw new Error("unexpected cookie in jar"); }728 `))729 assert.NoError(t, err)730 assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/cookies"), "", 200, "")731 })732 })733 t.Run("auth", func(t *testing.T) {734 t.Run("basic", func(t *testing.T) {735 url := sr("http://bob:pass@HTTPBIN_IP:HTTPBIN_PORT/basic-auth/bob/pass")736 urlExpected := sr("http://****:****@HTTPBIN_IP:HTTPBIN_PORT/basic-auth/bob/pass")737 _, err := common.RunString(rt, fmt.Sprintf(`738 let res = http.request("GET", "%s", null, {});739 if (res.status != 200) { throw new Error("wrong status: " + res.status); }740 `, url))741 assert.NoError(t, err)742 assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", urlExpected, "", 200, "")743 })744 t.Run("digest", func(t *testing.T) {745 t.Run("success", func(t *testing.T) {746 url := sr("http://bob:pass@HTTPBIN_IP:HTTPBIN_PORT/digest-auth/auth/bob/pass")747 urlExpected := sr("http://****:****@HTTPBIN_IP:HTTPBIN_PORT/digest-auth/auth/bob/pass")748 _, err := common.RunString(rt, fmt.Sprintf(`749 let res = http.request("GET", "%s", null, { auth: "digest" });750 if (res.status != 200) { throw new Error("wrong status: " + res.status); }751 if (res.error_code != 0) { throw new Error("wrong error code: " + res.error_code); }752 `, url))753 assert.NoError(t, err)754 sampleContainers := stats.GetBufferedSamples(samples)755 assertRequestMetricsEmitted(t, sampleContainers[0:1], "GET",756 sr("HTTPBIN_IP_URL/digest-auth/auth/bob/pass"), urlExpected, 401, "")757 assertRequestMetricsEmitted(t, sampleContainers[1:2], "GET",758 sr("HTTPBIN_IP_URL/digest-auth/auth/bob/pass"), urlExpected, 200, "")759 })760 t.Run("failure", func(t *testing.T) {761 url := sr("http://bob:pass@HTTPBIN_IP:HTTPBIN_PORT/digest-auth/failure")762 _, err := common.RunString(rt, fmt.Sprintf(`763 let res = http.request("GET", "%s", null, { auth: "digest", timeout: 1, throw: false });764 `, url))765 assert.NoError(t, err)766 })767 })768 })769 t.Run("headers", func(t *testing.T) {770 for _, literal := range []string{`null`, `undefined`} {771 t.Run(literal, func(t *testing.T) {772 _, err := common.RunString(rt, fmt.Sprintf(sr(`773 let res = http.request("GET", "HTTPBIN_URL/headers", null, { headers: %s });774 if (res.status != 200) { throw new Error("wrong status: " + res.status); }775 `), literal))776 assert.NoError(t, err)777 assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/headers"), "", 200, "")778 })779 }780 t.Run("object", func(t *testing.T) {781 _, err := common.RunString(rt, sr(`782 let res = http.request("GET", "HTTPBIN_URL/headers", null, {783 headers: { "X-My-Header": "value" },784 });785 if (res.status != 200) { throw new Error("wrong status: " + res.status); }786 if (res.json().headers["X-My-Header"] != "value") { throw new Error("wrong X-My-Header: " + res.json().headers["X-My-Header"]); }787 `))788 assert.NoError(t, err)789 assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/headers"), "", 200, "")790 })791 t.Run("Host", func(t *testing.T) {792 _, err := common.RunString(rt, sr(`793 let res = http.request("GET", "HTTPBIN_URL/headers", null, {794 headers: { "Host": "HTTPBIN_DOMAIN" },795 });796 if (res.status != 200) { throw new Error("wrong status: " + res.status); }797 if (res.json().headers["Host"] != "HTTPBIN_DOMAIN") { throw new Error("wrong Host: " + res.json().headers["Host"]); }798 `))799 assert.NoError(t, err)800 assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/headers"), "", 200, "")801 })802 })803 t.Run("tags", func(t *testing.T) {804 for _, literal := range []string{`null`, `undefined`} {805 t.Run(literal, func(t *testing.T) {806 _, err := common.RunString(rt, fmt.Sprintf(sr(`807 let res = http.request("GET", "HTTPBIN_URL/headers", null, { tags: %s });808 if (res.status != 200) { throw new Error("wrong status: " + res.status); }809 `), literal))810 assert.NoError(t, err)811 assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/headers"), "", 200, "")812 })813 }814 t.Run("object", func(t *testing.T) {815 _, err := common.RunString(rt, sr(`816 let res = http.request("GET", "HTTPBIN_URL/headers", null, { tags: { tag: "value" } });817 if (res.status != 200) { throw new Error("wrong status: " + res.status); }818 `))819 assert.NoError(t, err)820 bufSamples := stats.GetBufferedSamples(samples)821 assertRequestMetricsEmitted(t, bufSamples, "GET", sr("HTTPBIN_URL/headers"), "", 200, "")822 for _, sampleC := range bufSamples {823 for _, sample := range sampleC.GetSamples() {824 tagValue, ok := sample.Tags.Get("tag")825 assert.True(t, ok)826 assert.Equal(t, "value", tagValue)827 }828 }829 })830 t.Run("tags-precedence", func(t *testing.T) {831 oldOpts := state.Options832 defer func() { state.Options = oldOpts }()833 state.Options.RunTags = stats.IntoSampleTags(&map[string]string{"runtag1": "val1", "runtag2": "val2"})834 _, err := common.RunString(rt, sr(`835 let res = http.request("GET", "HTTPBIN_URL/headers", null, { tags: { method: "test", name: "myName", runtag1: "fromreq" } });836 if (res.status != 200) { throw new Error("wrong status: " + res.status); }837 `))838 assert.NoError(t, err)839 bufSamples := stats.GetBufferedSamples(samples)840 assertRequestMetricsEmitted(t, bufSamples, "GET", sr("HTTPBIN_URL/headers"), "myName", 200, "")841 for _, sampleC := range bufSamples {842 for _, sample := range sampleC.GetSamples() {843 tagValue, ok := sample.Tags.Get("method")844 assert.True(t, ok)845 assert.Equal(t, "GET", tagValue)846 tagValue, ok = sample.Tags.Get("name")847 assert.True(t, ok)848 assert.Equal(t, "myName", tagValue)849 tagValue, ok = sample.Tags.Get("runtag1")850 assert.True(t, ok)851 assert.Equal(t, "fromreq", tagValue)852 tagValue, ok = sample.Tags.Get("runtag2")853 assert.True(t, ok)854 assert.Equal(t, "val2", tagValue)855 }856 }857 })858 })859 })860 t.Run("GET", func(t *testing.T) {861 _, err := common.RunString(rt, sr(`862 let res = http.get("HTTPBIN_URL/get?a=1&b=2");863 if (res.status != 200) { throw new Error("wrong status: " + res.status); }864 if (res.json().args.a != "1") { throw new Error("wrong ?a: " + res.json().args.a); }865 if (res.json().args.b != "2") { throw new Error("wrong ?b: " + res.json().args.b); }866 `))867 assert.NoError(t, err)868 assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/get?a=1&b=2"), "", 200, "")869 t.Run("Tagged", func(t *testing.T) {870 _, err := common.RunString(rt, `871 let a = "1";872 let b = "2";873 let res = http.get(http.url`+"`"+sr(`HTTPBIN_URL/get?a=${a}&b=${b}`)+"`"+`);874 if (res.status != 200) { throw new Error("wrong status: " + res.status); }875 if (res.json().args.a != a) { throw new Error("wrong ?a: " + res.json().args.a); }876 if (res.json().args.b != b) { throw new Error("wrong ?b: " + res.json().args.b); }877 `)878 assert.NoError(t, err)879 assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/get?a=1&b=2"), sr("HTTPBIN_URL/get?a=${}&b=${}"), 200, "")880 })881 })882 t.Run("HEAD", func(t *testing.T) {883 _, err := common.RunString(rt, sr(`884 let res = http.head("HTTPBIN_URL/get?a=1&b=2");885 if (res.status != 200) { throw new Error("wrong status: " + res.status); }886 if (res.body.length != 0) { throw new Error("HEAD responses shouldn't have a body"); }887 if (!res.headers["Content-Length"]) { throw new Error("Missing or invalid Content-Length header!"); }888 `))889 assert.NoError(t, err)890 assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "HEAD", sr("HTTPBIN_URL/get?a=1&b=2"), "", 200, "")891 })892 t.Run("OPTIONS", func(t *testing.T) {893 _, err := common.RunString(rt, sr(`894 let res = http.options("HTTPBIN_URL/?a=1&b=2");895 if (res.status != 200) { throw new Error("wrong status: " + res.status); }896 if (!res.headers["Access-Control-Allow-Methods"]) { throw new Error("Missing Access-Control-Allow-Methods header!"); }897 `))898 assert.NoError(t, err)899 assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "OPTIONS", sr("HTTPBIN_URL/?a=1&b=2"), "", 200, "")900 })901 // DELETE HTTP requests shouldn't usually send a request body, they should use url parameters instead; references:902 // https://golang.org/pkg/net/http/#Request.ParseForm903 // https://stackoverflow.com/questions/299628/is-an-entity-body-allowed-for-an-http-delete-request904 // https://tools.ietf.org/html/rfc7231#section-4.3.5905 t.Run("DELETE", func(t *testing.T) {906 _, err := common.RunString(rt, sr(`907 let res = http.del("HTTPBIN_URL/delete?test=mest");908 if (res.status != 200) { throw new Error("wrong status: " + res.status); }909 if (res.json().args.test != "mest") { throw new Error("wrong args: " + JSON.stringify(res.json().args)); }910 `))911 assert.NoError(t, err)912 assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "DELETE", sr("HTTPBIN_URL/delete?test=mest"), "", 200, "")913 })914 postMethods := map[string]string{915 "POST": "post",916 "PUT": "put",917 "PATCH": "patch",918 }919 for method, fn := range postMethods {920 t.Run(method, func(t *testing.T) {921 _, err := common.RunString(rt, fmt.Sprintf(sr(`922 let res = http.%s("HTTPBIN_URL/%s", "data");923 if (res.status != 200) { throw new Error("wrong status: " + res.status); }924 if (res.json().data != "data") { throw new Error("wrong data: " + res.json().data); }925 if (res.json().headers["Content-Type"]) { throw new Error("content type set: " + res.json().headers["Content-Type"]); }926 `), fn, strings.ToLower(method)))927 assert.NoError(t, err)928 assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), method, sr("HTTPBIN_URL/")+strings.ToLower(method), "", 200, "")929 t.Run("object", func(t *testing.T) {930 _, err := common.RunString(rt, fmt.Sprintf(sr(`931 let res = http.%s("HTTPBIN_URL/%s", {a: "a", b: 2});932 if (res.status != 200) { throw new Error("wrong status: " + res.status); }933 if (res.json().form.a != "a") { throw new Error("wrong a=: " + res.json().form.a); }934 if (res.json().form.b != "2") { throw new Error("wrong b=: " + res.json().form.b); }935 if (res.json().headers["Content-Type"] != "application/x-www-form-urlencoded") { throw new Error("wrong content type: " + res.json().headers["Content-Type"]); }936 `), fn, strings.ToLower(method)))937 assert.NoError(t, err)938 assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), method, sr("HTTPBIN_URL/")+strings.ToLower(method), "", 200, "")939 t.Run("Content-Type", func(t *testing.T) {940 _, err := common.RunString(rt, fmt.Sprintf(sr(`941 let res = http.%s("HTTPBIN_URL/%s", {a: "a", b: 2}, {headers: {"Content-Type": "application/x-www-form-urlencoded; charset=utf-8"}});942 if (res.status != 200) { throw new Error("wrong status: " + res.status); }943 if (res.json().form.a != "a") { throw new Error("wrong a=: " + res.json().form.a); }944 if (res.json().form.b != "2") { throw new Error("wrong b=: " + res.json().form.b); }945 if (res.json().headers["Content-Type"] != "application/x-www-form-urlencoded; charset=utf-8") { throw new Error("wrong content type: " + res.json().headers["Content-Type"]); }946 `), fn, strings.ToLower(method)))947 assert.NoError(t, err)948 assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), method, sr("HTTPBIN_URL/")+strings.ToLower(method), "", 200, "")949 })950 })951 })952 }953 t.Run("Batch", func(t *testing.T) {954 t.Run("GET", func(t *testing.T) {955 _, err := common.RunString(rt, sr(`956 let reqs = [957 ["GET", "HTTPBIN_URL/"],958 ["GET", "HTTPBIN_IP_URL/"],959 ];960 let res = http.batch(reqs);961 for (var key in res) {962 if (res[key].status != 200) { throw new Error("wrong status: " + res[key].status); }963 if (res[key].url != reqs[key][1]) { throw new Error("wrong url: " + res[key].url); }964 }`))965 assert.NoError(t, err)966 bufSamples := stats.GetBufferedSamples(samples)967 assertRequestMetricsEmitted(t, bufSamples, "GET", sr("HTTPBIN_URL/"), "", 200, "")968 assertRequestMetricsEmitted(t, bufSamples, "GET", sr("HTTPBIN_IP_URL/"), "", 200, "")969 t.Run("Tagged", func(t *testing.T) {970 _, err := common.RunString(rt, sr(`971 let fragment = "get";972 let reqs = [973 ["GET", http.url`+"`"+`HTTPBIN_URL/${fragment}`+"`"+`],974 ["GET", http.url`+"`"+`HTTPBIN_IP_URL/`+"`"+`],975 ];976 let res = http.batch(reqs);977 for (var key in res) {978 if (res[key].status != 200) { throw new Error("wrong status: " + key + ": " + res[key].status); }979 if (res[key].url != reqs[key][1].url) { throw new Error("wrong url: " + key + ": " + res[key].url + " != " + reqs[key][1].url); }980 }`))981 assert.NoError(t, err)982 bufSamples := stats.GetBufferedSamples(samples)983 assertRequestMetricsEmitted(t, bufSamples, "GET", sr("HTTPBIN_URL/get"), sr("HTTPBIN_URL/${}"), 200, "")984 assertRequestMetricsEmitted(t, bufSamples, "GET", sr("HTTPBIN_IP_URL/"), "", 200, "")985 })986 t.Run("Shorthand", func(t *testing.T) {987 _, err := common.RunString(rt, sr(`988 let reqs = [989 "HTTPBIN_URL/",990 "HTTPBIN_IP_URL/",991 ];992 let res = http.batch(reqs);993 for (var key in res) {994 if (res[key].status != 200) { throw new Error("wrong status: " + key + ": " + res[key].status); }995 if (res[key].url != reqs[key]) { throw new Error("wrong url: " + key + ": " + res[key].url); }996 }`))997 assert.NoError(t, err)998 bufSamples := stats.GetBufferedSamples(samples)999 assertRequestMetricsEmitted(t, bufSamples, "GET", sr("HTTPBIN_URL/"), "", 200, "")1000 assertRequestMetricsEmitted(t, bufSamples, "GET", sr("HTTPBIN_IP_URL/"), "", 200, "")1001 t.Run("Tagged", func(t *testing.T) {1002 _, err := common.RunString(rt, sr(`1003 let fragment = "get";1004 let reqs = [1005 http.url`+"`"+`HTTPBIN_URL/${fragment}`+"`"+`,1006 http.url`+"`"+`HTTPBIN_IP_URL/`+"`"+`,1007 ];1008 let res = http.batch(reqs);1009 for (var key in res) {1010 if (res[key].status != 200) { throw new Error("wrong status: " + key + ": " + res[key].status); }1011 if (res[key].url != reqs[key].url) { throw new Error("wrong url: " + key + ": " + res[key].url + " != " + reqs[key].url); }1012 }`))1013 assert.NoError(t, err)1014 bufSamples := stats.GetBufferedSamples(samples)1015 assertRequestMetricsEmitted(t, bufSamples, "GET", sr("HTTPBIN_URL/get"), sr("HTTPBIN_URL/${}"), 200, "")1016 assertRequestMetricsEmitted(t, bufSamples, "GET", sr("HTTPBIN_IP_URL/"), "", 200, "")1017 })1018 })1019 t.Run("ObjectForm", func(t *testing.T) {1020 _, err := common.RunString(rt, sr(`1021 let reqs = [1022 { method: "GET", url: "HTTPBIN_URL/" },1023 { url: "HTTPBIN_IP_URL/", method: "GET"},1024 ];1025 let res = http.batch(reqs);1026 for (var key in res) {1027 if (res[key].status != 200) { throw new Error("wrong status: " + key + ": " + res[key].status); }1028 if (res[key].url != reqs[key].url) { throw new Error("wrong url: " + key + ": " + res[key].url + " != " + reqs[key].url); }1029 }`))1030 assert.NoError(t, err)1031 bufSamples := stats.GetBufferedSamples(samples)1032 assertRequestMetricsEmitted(t, bufSamples, "GET", sr("HTTPBIN_URL/"), "", 200, "")1033 assertRequestMetricsEmitted(t, bufSamples, "GET", sr("HTTPBIN_IP_URL/"), "", 200, "")1034 })1035 t.Run("ObjectKeys", func(t *testing.T) {1036 _, err := common.RunString(rt, sr(`1037 let reqs = {1038 shorthand: "HTTPBIN_URL/get?r=shorthand",1039 arr: ["GET", "HTTPBIN_URL/get?r=arr", null, {tags: {name: 'arr'}}],1040 obj1: { method: "GET", url: "HTTPBIN_URL/get?r=obj1" },1041 obj2: { url: "HTTPBIN_URL/get?r=obj2", params: {tags: {name: 'obj2'}}, method: "GET"},1042 };1043 let res = http.batch(reqs);1044 for (var key in res) {1045 if (res[key].status != 200) { throw new Error("wrong status: " + key + ": " + res[key].status); }1046 if (res[key].json().args.r != key) { throw new Error("wrong request id: " + key); }1047 }`))1048 assert.NoError(t, err)1049 bufSamples := stats.GetBufferedSamples(samples)1050 assertRequestMetricsEmitted(t, bufSamples, "GET", sr("HTTPBIN_URL/get?r=shorthand"), "", 200, "")1051 assertRequestMetricsEmitted(t, bufSamples, "GET", sr("HTTPBIN_URL/get?r=arr"), "arr", 200, "")1052 assertRequestMetricsEmitted(t, bufSamples, "GET", sr("HTTPBIN_URL/get?r=obj1"), "", 200, "")1053 assertRequestMetricsEmitted(t, bufSamples, "GET", sr("HTTPBIN_URL/get?r=obj2"), "obj2", 200, "")1054 })1055 t.Run("BodyAndParams", func(t *testing.T) {1056 testStr := "testbody"1057 rt.Set("someStrFile", testStr)1058 rt.Set("someBinFile", []byte(testStr))1059 _, err := common.RunString(rt, sr(`1060 let reqs = [1061 ["POST", "HTTPBIN_URL/post", "testbody"],1062 ["POST", "HTTPBIN_URL/post", someStrFile],1063 ["POST", "HTTPBIN_URL/post", someBinFile],1064 {1065 method: "POST",1066 url: "HTTPBIN_URL/post",1067 test: "test1",1068 body: "testbody",1069 }, {1070 body: someBinFile,1071 url: "HTTPBIN_IP_URL/post",1072 params: { tags: { name: "myname" } },1073 method: "POST",1074 }, {1075 method: "POST",1076 url: "HTTPBIN_IP_URL/post",1077 body: {1078 hello: "world!",1079 },1080 params: {1081 tags: { name: "myname" },1082 headers: { "Content-Type": "application/x-www-form-urlencoded" },1083 },1084 },1085 ];1086 let res = http.batch(reqs);1087 for (var key in res) {1088 if (res[key].status != 200) { throw new Error("wrong status: " + key + ": " + res[key].status); }1089 if (res[key].json().data != "testbody" && res[key].json().form.hello != "world!") { throw new Error("wrong response for " + key + ": " + res[key].body); }1090 }`))1091 assert.NoError(t, err)1092 bufSamples := stats.GetBufferedSamples(samples)1093 assertRequestMetricsEmitted(t, bufSamples, "POST", sr("HTTPBIN_URL/post"), "", 200, "")1094 assertRequestMetricsEmitted(t, bufSamples, "POST", sr("HTTPBIN_IP_URL/post"), "myname", 200, "")1095 })1096 })1097 t.Run("POST", func(t *testing.T) {1098 _, err := common.RunString(rt, sr(`1099 let res = http.batch([ ["POST", "HTTPBIN_URL/post", { key: "value" }] ]);1100 for (var key in res) {1101 if (res[key].status != 200) { throw new Error("wrong status: " + key + ": " + res[key].status); }1102 if (res[key].json().form.key != "value") { throw new Error("wrong form: " + key + ": " + JSON.stringify(res[key].json().form)); }1103 }`))1104 assert.NoError(t, err)1105 assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "POST", sr("HTTPBIN_URL/post"), "", 200, "")1106 })1107 t.Run("PUT", func(t *testing.T) {1108 _, err := common.RunString(rt, sr(`1109 let res = http.batch([ ["PUT", "HTTPBIN_URL/put", { key: "value" }] ]);1110 for (var key in res) {1111 if (res[key].status != 200) { throw new Error("wrong status: " + key + ": " + res[key].status); }1112 if (res[key].json().form.key != "value") { throw new Error("wrong form: " + key + ": " + JSON.stringify(res[key].json().form)); }1113 }`))1114 assert.NoError(t, err)1115 assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "PUT", sr("HTTPBIN_URL/put"), "", 200, "")1116 })1117 })1118 t.Run("HTTPRequest", func(t *testing.T) {1119 t.Run("EmptyBody", func(t *testing.T) {1120 _, err := common.RunString(rt, sr(`1121 let reqUrl = "HTTPBIN_URL/cookies"1122 let res = http.get(reqUrl);1123 let jar = new http.CookieJar();1124 jar.set("HTTPBIN_URL/cookies", "key", "value");1125 res = http.request("GET", "HTTPBIN_URL/cookies", null, { cookies: { key2: "value2" }, jar: jar });1126 if (res.json().key != "value") { throw new Error("wrong cookie value: " + res.json().key); }1127 if (res.status != 200) { throw new Error("wrong status: " + res.status); }1128 if (res.request["method"] !== "GET") { throw new Error("http request method was not \"GET\": " + JSON.stringify(res.request)) }1129 if (res.request["body"].length != 0) { throw new Error("http request body was not null: " + JSON.stringify(res.request["body"])) }1130 if (res.request["url"] != reqUrl) {1131 throw new Error("wrong http request url: " + JSON.stringify(res.request))1132 }1133 if (res.request["cookies"]["key2"][0].name != "key2") { throw new Error("wrong http request cookies: " + JSON.stringify(JSON.stringify(res.request["cookies"]["key2"]))) }1134 if (res.request["headers"]["User-Agent"][0] != "TestUserAgent") { throw new Error("wrong http request headers: " + JSON.stringify(res.request)) }1135 `))1136 assert.NoError(t, err)1137 })1138 t.Run("NonEmptyBody", func(t *testing.T) {1139 _, err := common.RunString(rt, sr(`1140 let res = http.post("HTTPBIN_URL/post", {a: "a", b: 2}, {headers: {"Content-Type": "application/x-www-form-urlencoded; charset=utf-8"}});1141 if (res.status != 200) { throw new Error("wrong status: " + res.status); }1142 if (res.request["body"] != "a=a&b=2") { throw new Error("http request body was not set properly: " + JSON.stringify(res.request))}1143 `))1144 assert.NoError(t, err)1145 })1146 })1147}1148func TestSystemTags(t *testing.T) {1149 t.Parallel()1150 tb, state, samples, rt, _ := newRuntime(t)1151 defer tb.Cleanup()1152 // Handple paths with custom logic1153 tb.Mux.HandleFunc("/wrong-redirect", func(w http.ResponseWriter, r *http.Request) {1154 w.Header().Add("Location", "%")1155 w.WriteHeader(http.StatusTemporaryRedirect)1156 })1157 httpGet := fmt.Sprintf(`http.get("%s");`, tb.ServerHTTP.URL)1158 httpsGet := fmt.Sprintf(`http.get("%s");`, tb.ServerHTTPS.URL)1159 httpURL, err := url.Parse(tb.ServerHTTP.URL)1160 require.NoError(t, err)1161 testedSystemTags := []struct{ tag, code, expVal string }{1162 {"proto", httpGet, "HTTP/1.1"},1163 {"status", httpGet, "200"},1164 {"method", httpGet, "GET"},1165 {"url", httpGet, tb.ServerHTTP.URL},1166 {"url", httpsGet, tb.ServerHTTPS.URL},1167 {"ip", httpGet, httpURL.Hostname()},1168 {"name", httpGet, tb.ServerHTTP.URL},1169 {"group", httpGet, ""},1170 {"vu", httpGet, "0"},1171 {"iter", httpGet, "0"},1172 {"tls_version", httpsGet, expectedTLSVersion},1173 {"ocsp_status", httpsGet, "unknown"},1174 {1175 "error",1176 tb.Replacer.Replace(`http.get("http://127.0.0.1:1");`),1177 `dial: connection refused`,1178 },1179 {1180 "error_code",1181 tb.Replacer.Replace(`http.get("http://127.0.0.1:1");`),1182 "1212",1183 },1184 }1185 state.Options.Throw = null.BoolFrom(false)1186 state.Options.Apply(lib.Options{TLSVersion: &lib.TLSVersions{Max: lib.TLSVersion13}})1187 for num, tc := range testedSystemTags {1188 tc := tc1189 t.Run(fmt.Sprintf("TC %d with only %s", num, tc.tag), func(t *testing.T) {1190 state.Options.SystemTags = stats.ToSystemTagSet([]string{tc.tag})1191 _, err := common.RunString(rt, tc.code)1192 assert.NoError(t, err)1193 bufSamples := stats.GetBufferedSamples(samples)1194 assert.NotEmpty(t, bufSamples)1195 for _, sampleC := range bufSamples {1196 for _, sample := range sampleC.GetSamples() {1197 assert.NotEmpty(t, sample.Tags)1198 for emittedTag, emittedVal := range sample.Tags.CloneTags() {1199 assert.Equal(t, tc.tag, emittedTag)1200 assert.Equal(t, tc.expVal, emittedVal)1201 }1202 }1203 }1204 })1205 }1206}1207func TestRequestCompression(t *testing.T) {1208 t.Parallel()1209 tb, state, _, rt, _ := newRuntime(t)1210 defer tb.Cleanup()1211 logHook := testutils.SimpleLogrusHook{HookedLevels: []logrus.Level{logrus.WarnLevel}}1212 state.Logger.AddHook(&logHook)1213 // We don't expect any failed requests1214 state.Options.Throw = null.BoolFrom(true)1215 var text = `1216 Lorem ipsum dolor sit amet, consectetur adipiscing elit.1217 Maecenas sed pharetra sapien. Nunc laoreet molestie ante ac gravida.1218 Etiam interdum dui viverra posuere egestas. Pellentesque at dolor tristique,1219 mattis turpis eget, commodo purus. Nunc orci aliquam.`1220 var decompress = func(algo string, input io.Reader) io.Reader {1221 switch algo {1222 case "br":1223 w := brotli.NewReader(input)1224 return w1225 case "gzip":1226 w, err := gzip.NewReader(input)1227 if err != nil {1228 t.Fatal(err)1229 }1230 return w1231 case "deflate":1232 w, err := zlib.NewReader(input)1233 if err != nil {1234 t.Fatal(err)1235 }1236 return w1237 case "zstd":1238 w, err := zstd.NewReader(input)1239 if err != nil {1240 t.Fatal(err)1241 }1242 return w1243 default:1244 t.Fatal("unknown algorithm " + algo)1245 }1246 return nil // unreachable1247 }1248 var (1249 expectedEncoding string1250 actualEncoding string1251 )1252 tb.Mux.HandleFunc("/compressed-text", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {1253 require.Equal(t, expectedEncoding, r.Header.Get("Content-Encoding"))1254 expectedLength, err := strconv.Atoi(r.Header.Get("Content-Length"))1255 require.NoError(t, err)1256 var algos = strings.Split(actualEncoding, ", ")1257 var compressedBuf = new(bytes.Buffer)1258 n, err := io.Copy(compressedBuf, r.Body)1259 require.Equal(t, int(n), expectedLength)1260 require.NoError(t, err)1261 var prev io.Reader = compressedBuf1262 if expectedEncoding != "" {1263 for i := len(algos) - 1; i >= 0; i-- {1264 prev = decompress(algos[i], prev)1265 }1266 }1267 var buf bytes.Buffer1268 _, err = io.Copy(&buf, prev)1269 require.NoError(t, err)1270 require.Equal(t, text, buf.String())1271 }))1272 var testCases = []struct {1273 name string1274 compression string1275 expectedError string1276 }{1277 {compression: ""},1278 {compression: " "},1279 {compression: "gzip"},1280 {compression: "gzip, gzip"},1281 {compression: "gzip, gzip "},1282 {compression: "gzip,gzip"},1283 {compression: "gzip, gzip, gzip, gzip, gzip, gzip, gzip"},1284 {compression: "deflate"},1285 {compression: "deflate, gzip"},1286 {compression: "gzip,deflate, gzip"},1287 {compression: "zstd"},1288 {compression: "zstd, gzip, deflate"},1289 {compression: "br"},1290 {compression: "br, gzip, deflate"},1291 {1292 compression: "George",1293 expectedError: `unknown compression algorithm George`,1294 },1295 {1296 compression: "gzip, George",1297 expectedError: `unknown compression algorithm George`,1298 },1299 }1300 for _, testCase := range testCases {1301 testCase := testCase1302 t.Run(testCase.compression, func(t *testing.T) {1303 var algos = strings.Split(testCase.compression, ",")1304 for i, algo := range algos {1305 algos[i] = strings.TrimSpace(algo)1306 }1307 expectedEncoding = strings.Join(algos, ", ")1308 actualEncoding = expectedEncoding1309 _, err := common.RunString(rt, tb.Replacer.Replace(`1310 http.post("HTTPBIN_URL/compressed-text", `+"`"+text+"`"+`, {"compression": "`+testCase.compression+`"});1311 `))1312 if testCase.expectedError == "" {1313 require.NoError(t, err)1314 } else {1315 require.Error(t, err)1316 require.Contains(t, err.Error(), testCase.expectedError)1317 }1318 })1319 }1320 t.Run("custom set header", func(t *testing.T) {1321 expectedEncoding = "not, valid"1322 actualEncoding = "gzip, deflate"1323 logHook.Drain()1324 t.Run("encoding", func(t *testing.T) {1325 _, err := common.RunString(rt, tb.Replacer.Replace(`1326 http.post("HTTPBIN_URL/compressed-text", `+"`"+text+"`"+`,1327 {"compression": "`+actualEncoding+`",1328 "headers": {"Content-Encoding": "`+expectedEncoding+`"}1329 }1330 );1331 `))1332 require.NoError(t, err)1333 require.NotEmpty(t, logHook.Drain())1334 })1335 t.Run("encoding and length", func(t *testing.T) {1336 _, err := common.RunString(rt, tb.Replacer.Replace(`1337 http.post("HTTPBIN_URL/compressed-text", `+"`"+text+"`"+`,1338 {"compression": "`+actualEncoding+`",1339 "headers": {"Content-Encoding": "`+expectedEncoding+`",1340 "Content-Length": "12"}1341 }1342 );1343 `))1344 require.NoError(t, err)1345 require.NotEmpty(t, logHook.Drain())1346 })1347 expectedEncoding = actualEncoding1348 t.Run("correct encoding", func(t *testing.T) {1349 _, err := common.RunString(rt, tb.Replacer.Replace(`1350 http.post("HTTPBIN_URL/compressed-text", `+"`"+text+"`"+`,1351 {"compression": "`+actualEncoding+`",1352 "headers": {"Content-Encoding": "`+actualEncoding+`"}1353 }1354 );1355 `))1356 require.NoError(t, err)1357 require.Empty(t, logHook.Drain())1358 })1359 //TODO: move to some other test?1360 t.Run("correct length", func(t *testing.T) {1361 _, err := common.RunString(rt, tb.Replacer.Replace(1362 `http.post("HTTPBIN_URL/post", "0123456789", { "headers": {"Content-Length": "10"}});`,1363 ))1364 require.NoError(t, err)1365 require.Empty(t, logHook.Drain())1366 })1367 t.Run("content-length is set", func(t *testing.T) {1368 _, err := common.RunString(rt, tb.Replacer.Replace(`1369 let resp = http.post("HTTPBIN_URL/post", "0123456789");1370 if (resp.json().headers["Content-Length"][0] != "10") {1371 throw new Error("content-length not set: " + JSON.stringify(resp.json().headers));1372 }1373 `))1374 require.NoError(t, err)1375 require.Empty(t, logHook.Drain())1376 })1377 })1378}1379func TestResponseTypes(t *testing.T) {1380 t.Parallel()1381 tb, state, _, rt, _ := newRuntime(t)1382 defer tb.Cleanup()1383 // We don't expect any failed requests1384 state.Options.Throw = null.BoolFrom(true)1385 text := `â¢?((¯°·._.⢠ţâ¬$ţɨɲǥ µɲɨȼà¹Ä⬠ɨɲ Ð6 â¢._.·°¯))Øâ¢`1386 textLen := len(text)1387 tb.Mux.HandleFunc("/get-text", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {1388 n, err := w.Write([]byte(text))1389 assert.NoError(t, err)1390 assert.Equal(t, textLen, n)1391 }))1392 tb.Mux.HandleFunc("/compare-text", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {1393 body, err := ioutil.ReadAll(r.Body)1394 require.NoError(t, err)1395 assert.Equal(t, text, string(body))1396 }))1397 binaryLen := 3001398 binary := make([]byte, binaryLen)1399 for i := 0; i < binaryLen; i++ {1400 binary[i] = byte(i)1401 }1402 tb.Mux.HandleFunc("/get-bin", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {1403 n, err := w.Write(binary)1404 assert.NoError(t, err)1405 assert.Equal(t, binaryLen, n)1406 }))1407 tb.Mux.HandleFunc("/compare-bin", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {1408 body, err := ioutil.ReadAll(r.Body)1409 require.NoError(t, err)1410 assert.True(t, bytes.Equal(binary, body))1411 }))1412 replace := func(s string) string {1413 return strings.NewReplacer(1414 "EXP_TEXT", text,1415 "EXP_BIN_LEN", strconv.Itoa(binaryLen),1416 ).Replace(tb.Replacer.Replace(s))1417 }1418 _, err := common.RunString(rt, replace(`1419 let expText = "EXP_TEXT";1420 let expBinLength = EXP_BIN_LEN;1421 // Check default behaviour with a unicode text1422 let respTextImplicit = http.get("HTTPBIN_URL/get-text").body;1423 if (respTextImplicit !== expText) {1424 throw new Error("default response body should be '" + expText + "' but was '" + respTextImplicit + "'");1425 }1426 http.post("HTTPBIN_URL/compare-text", respTextImplicit);1427 // Check discarding of responses1428 let respNone = http.get("HTTPBIN_URL/get-text", { responseType: "none" }).body;1429 if (respNone != null) {1430 throw new Error("none response body should be null but was " + respNone);1431 }1432 // Check binary transmission of the text response as well1433 let respTextInBin = http.get("HTTPBIN_URL/get-text", { responseType: "binary" }).body;1434 // Hack to convert a utf-8 array to a JS string1435 let strConv = "";1436 function pad(n) { return n.length < 2 ? "0" + n : n; }1437 for( let i = 0; i < respTextInBin.length; i++ ) {1438 strConv += ( "%" + pad(respTextInBin[i].toString(16)));1439 }1440 strConv = decodeURIComponent(strConv);1441 if (strConv !== expText) {1442 throw new Error("converted response body should be '" + expText + "' but was '" + strConv + "'");1443 }1444 http.post("HTTPBIN_URL/compare-text", respTextInBin);1445 // Check binary response1446 let respBin = http.get("HTTPBIN_URL/get-bin", { responseType: "binary" }).body;1447 if (respBin.length !== expBinLength) {1448 throw new Error("response body length should be '" + expBinLength + "' but was '" + respBin.length + "'");1449 }1450 for( let i = 0; i < respBin.length; i++ ) {1451 if ( respBin[i] !== i%256 ) {1452 throw new Error("expected value " + (i%256) + " to be at position " + i + " but it was " + respBin[i]);1453 }1454 }1455 http.post("HTTPBIN_URL/compare-bin", respBin);1456 `))1457 assert.NoError(t, err)1458 // Verify that if we enable discardResponseBodies globally, the default value is none1459 state.Options.DiscardResponseBodies = null.BoolFrom(true)1460 _, err = common.RunString(rt, replace(`1461 let expText = "EXP_TEXT";1462 // Check default behaviour1463 let respDefault = http.get("HTTPBIN_URL/get-text").body;1464 if (respDefault !== null) {1465 throw new Error("default response body should be discarded and null but was " + respDefault);1466 }1467 // Check explicit text response1468 let respTextExplicit = http.get("HTTPBIN_URL/get-text", { responseType: "text" }).body;1469 if (respTextExplicit !== expText) {1470 throw new Error("text response body should be '" + expText + "' but was '" + respTextExplicit + "'");1471 }1472 http.post("HTTPBIN_URL/compare-text", respTextExplicit);1473 `))1474 assert.NoError(t, err)1475}1476func checkErrorCode(t testing.TB, tags *stats.SampleTags, code int, msg string) {1477 var errorMsg, ok = tags.Get("error")1478 if msg == "" {1479 assert.False(t, ok)1480 } else {1481 assert.Equal(t, msg, errorMsg)1482 }1483 errorCodeStr, ok := tags.Get("error_code")1484 if code == 0 {1485 assert.False(t, ok)1486 } else {1487 var errorCode, err = strconv.Atoi(errorCodeStr)1488 assert.NoError(t, err)1489 assert.Equal(t, code, errorCode)1490 }1491}1492func TestErrorCodes(t *testing.T) {1493 t.Parallel()1494 tb, state, samples, rt, _ := newRuntime(t)1495 state.Options.Throw = null.BoolFrom(false)1496 defer tb.Cleanup()1497 sr := tb.Replacer.Replace1498 // Handple paths with custom logic1499 tb.Mux.HandleFunc("/no-location-redirect", http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {1500 w.WriteHeader(302)1501 }))1502 tb.Mux.HandleFunc("/bad-location-redirect", http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {1503 w.Header().Set("Location", "h\t:/") // \n is forbidden1504 w.WriteHeader(302)1505 }))1506 var testCases = []struct {1507 name string1508 status int1509 moreSamples int1510 expectedErrorCode int1511 expectedErrorMsg string1512 expectedScriptError string1513 script string1514 }{1515 {1516 name: "Unroutable",1517 expectedErrorCode: 1101,1518 expectedErrorMsg: "lookup: no such host",1519 script: `let res = http.request("GET", "http://sdafsgdhfjg/");`,1520 },1521 {1522 name: "404",1523 status: 404,1524 expectedErrorCode: 1404,1525 script: `let res = http.request("GET", "HTTPBIN_URL/status/404");`,1526 },1527 {1528 name: "Unroutable redirect",1529 expectedErrorCode: 1101,1530 expectedErrorMsg: "lookup: no such host",1531 moreSamples: 1,1532 script: `let res = http.request("GET", "HTTPBIN_URL/redirect-to?url=http://dafsgdhfjg/");`,1533 },1534 {1535 name: "Non location redirect",1536 expectedErrorCode: 1000,1537 expectedErrorMsg: "302 response missing Location header",1538 script: `let res = http.request("GET", "HTTPBIN_URL/no-location-redirect");`,1539 },1540 {1541 name: "Bad location redirect",1542 expectedErrorCode: 1000,1543 expectedErrorMsg: "failed to parse Location header \"h\\t:/\": parse h\t:/: net/url: invalid control character in URL", //nolint: lll1544 script: `let res = http.request("GET", "HTTPBIN_URL/bad-location-redirect");`,1545 },1546 {1547 name: "Missing protocol",1548 expectedErrorCode: 1000,1549 expectedErrorMsg: `unsupported protocol scheme ""`,1550 script: `let res = http.request("GET", "dafsgdhfjg/");`,1551 },1552 {1553 name: "Too many redirects",1554 status: 302,1555 moreSamples: 2,1556 script: `1557 let res = http.get("HTTPBIN_URL/relative-redirect/3", {redirects: 2});1558 if (res.url != "HTTPBIN_URL/relative-redirect/1") { throw new Error("incorrect URL: " + res.url) }`,1559 },1560 {1561 name: "Connection refused redirect",1562 status: 0,1563 moreSamples: 1,1564 expectedErrorMsg: `dial: connection refused`,1565 expectedErrorCode: 1212,1566 script: `1567 let res = http.get("HTTPBIN_URL/redirect-to?url=http%3A%2F%2F127.0.0.1%3A1%2Fpesho");1568 if (res.url != "http://127.0.0.1:1/pesho") { throw new Error("incorrect URL: " + res.url) }`,1569 },1570 }1571 for _, testCase := range testCases {1572 testCase := testCase1573 // clear the Samples1574 stats.GetBufferedSamples(samples)1575 t.Run(testCase.name, func(t *testing.T) {1576 _, err := common.RunString(rt,1577 sr(testCase.script+"\n"+fmt.Sprintf(`1578 if (res.status != %d) { throw new Error("wrong status: "+ res.status);}1579 if (res.error != %q) { throw new Error("wrong error: '" + res.error + "'");}1580 if (res.error_code != %d) { throw new Error("wrong error_code: "+ res.error_code);}1581 `, testCase.status, testCase.expectedErrorMsg, testCase.expectedErrorCode)))1582 if testCase.expectedScriptError == "" {1583 require.NoError(t, err)1584 } else {1585 require.Error(t, err)1586 require.Equal(t, err.Error(), testCase.expectedScriptError)1587 }1588 var cs = stats.GetBufferedSamples(samples)1589 assert.Len(t, cs, 1+testCase.moreSamples)1590 for _, c := range cs[len(cs)-1:] {1591 assert.NotZero(t, len(c.GetSamples()))1592 for _, sample := range c.GetSamples() {1593 checkErrorCode(t, sample.GetTags(), testCase.expectedErrorCode, testCase.expectedErrorMsg)1594 }1595 }1596 })1597 }1598}1599func TestResponseWaitingAndReceivingTimings(t *testing.T) {1600 t.Parallel()1601 tb, state, _, rt, _ := newRuntime(t)1602 defer tb.Cleanup()1603 // We don't expect any failed requests1604 state.Options.Throw = null.BoolFrom(true)1605 tb.Mux.HandleFunc("/slow-response", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {1606 flusher, ok := w.(http.Flusher)1607 require.True(t, ok)1608 time.Sleep(1200 * time.Millisecond)1609 n, err := w.Write([]byte("1st bytes!"))1610 assert.NoError(t, err)1611 assert.Equal(t, 10, n)1612 flusher.Flush()1613 time.Sleep(1200 * time.Millisecond)1614 n, err = w.Write([]byte("2nd bytes!"))1615 assert.NoError(t, err)1616 assert.Equal(t, 10, n)1617 }))1618 _, err := common.RunString(rt, tb.Replacer.Replace(`1619 let resp = http.get("HTTPBIN_URL/slow-response");1620 if (resp.timings.waiting < 1000) {1621 throw new Error("expected waiting time to be over 1000ms but was " + resp.timings.waiting);1622 }1623 if (resp.timings.receiving < 1000) {1624 throw new Error("expected receiving time to be over 1000ms but was " + resp.timings.receiving);1625 }1626 if (resp.body !== "1st bytes!2nd bytes!") {1627 throw new Error("wrong response body: " + resp.body);1628 }1629 `))1630 assert.NoError(t, err)1631}1632func TestResponseTimingsWhenTimeout(t *testing.T) {1633 t.Parallel()1634 tb, state, _, rt, _ := newRuntime(t)1635 defer tb.Cleanup()1636 // We expect a failed request1637 state.Options.Throw = null.BoolFrom(false)1638 _, err := common.RunString(rt, tb.Replacer.Replace(`1639 let resp = http.get("HTTPBIN_URL/delay/10", { timeout: 2500 });1640 if (resp.timings.waiting < 2000) {1641 throw new Error("expected waiting time to be over 2000ms but was " + resp.timings.waiting);1642 }1643 if (resp.timings.duration < 2000) {1644 throw new Error("expected duration time to be over 2000ms but was " + resp.timings.duration);1645 }1646 `))1647 assert.NoError(t, err)1648}1649func TestNoResponseBodyMangling(t *testing.T) {1650 t.Parallel()1651 tb, state, _, rt, _ := newRuntime(t)1652 defer tb.Cleanup()1653 // We don't expect any failed requests1654 state.Options.Throw = null.BoolFrom(true)1655 _, err := common.RunString(rt, tb.Replacer.Replace(`1656 const batchSize = 100;1657 let requests = [];1658 for (let i = 0; i < batchSize; i++) {1659 requests.push(["GET", "HTTPBIN_URL/get?req=" + i, null, { responseType: (i % 2 ? "binary" : "text") }]);1660 }1661 let responses = http.batch(requests);1662 for (let i = 0; i < batchSize; i++) {1663 let reqNumber = parseInt(responses[i].json().args.req[0], 10);1664 if (i !== reqNumber) {1665 throw new Error("Response " + i + " has " + reqNumber + ", expected " + i)1666 }1667 }1668 `))1669 assert.NoError(t, err)1670}1671func BenchmarkHandlingOfResponseBodies(b *testing.B) {1672 tb, state, samples, rt, _ := newRuntime(b)1673 defer tb.Cleanup()1674 state.BPool = bpool.NewBufferPool(100)1675 go func() {1676 ctxDone := tb.Context.Done()1677 for {1678 select {1679 case <-samples:1680 case <-ctxDone:1681 return1682 }1683 }1684 }()1685 mbData := bytes.Repeat([]byte("0123456789"), 100000)1686 tb.Mux.HandleFunc("/1mbdata", http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {1687 _, err := resp.Write(mbData)1688 if err != nil {1689 b.Error(err)1690 }1691 }))1692 testCodeTemplate := tb.Replacer.Replace(`1693 http.get("HTTPBIN_URL/", { responseType: "TEST_RESPONSE_TYPE" });1694 http.post("HTTPBIN_URL/post", { responseType: "TEST_RESPONSE_TYPE" });1695 http.batch([1696 ["GET", "HTTPBIN_URL/gzip", null, { responseType: "TEST_RESPONSE_TYPE" }],1697 ["GET", "HTTPBIN_URL/gzip", null, { responseType: "TEST_RESPONSE_TYPE" }],1698 ["GET", "HTTPBIN_URL/deflate", null, { responseType: "TEST_RESPONSE_TYPE" }],1699 ["GET", "HTTPBIN_URL/deflate", null, { responseType: "TEST_RESPONSE_TYPE" }],1700 ["GET", "HTTPBIN_URL/redirect/5", null, { responseType: "TEST_RESPONSE_TYPE" }], // 6 requests1701 ["GET", "HTTPBIN_URL/get", null, { responseType: "TEST_RESPONSE_TYPE" }],1702 ["GET", "HTTPBIN_URL/html", null, { responseType: "TEST_RESPONSE_TYPE" }],1703 ["GET", "HTTPBIN_URL/bytes/100000", null, { responseType: "TEST_RESPONSE_TYPE" }],1704 ["GET", "HTTPBIN_URL/image/png", null, { responseType: "TEST_RESPONSE_TYPE" }],1705 ["GET", "HTTPBIN_URL/image/jpeg", null, { responseType: "TEST_RESPONSE_TYPE" }],1706 ["GET", "HTTPBIN_URL/image/jpeg", null, { responseType: "TEST_RESPONSE_TYPE" }],1707 ["GET", "HTTPBIN_URL/image/webp", null, { responseType: "TEST_RESPONSE_TYPE" }],1708 ["GET", "HTTPBIN_URL/image/svg", null, { responseType: "TEST_RESPONSE_TYPE" }],1709 ["GET", "HTTPBIN_URL/forms/post", null, { responseType: "TEST_RESPONSE_TYPE" }],1710 ["GET", "HTTPBIN_URL/bytes/100000", null, { responseType: "TEST_RESPONSE_TYPE" }],1711 ["GET", "HTTPBIN_URL/stream-bytes/100000", null, { responseType: "TEST_RESPONSE_TYPE" }],1712 ]);1713 http.get("HTTPBIN_URL/get", { responseType: "TEST_RESPONSE_TYPE" });1714 http.get("HTTPBIN_URL/get", { responseType: "TEST_RESPONSE_TYPE" });1715 http.get("HTTPBIN_URL/1mbdata", { responseType: "TEST_RESPONSE_TYPE" });1716 `)1717 testResponseType := func(responseType string) func(b *testing.B) {1718 testCode := strings.Replace(testCodeTemplate, "TEST_RESPONSE_TYPE", responseType, -1)1719 return func(b *testing.B) {1720 for i := 0; i < b.N; i++ {1721 _, err := common.RunString(rt, testCode)1722 if err != nil {1723 b.Error(err)1724 }1725 }1726 }1727 }1728 b.ResetTimer()1729 b.Run("text", testResponseType("text"))1730 b.Run("binary", testResponseType("binary"))1731 b.Run("none", testResponseType("none"))1732}1733func TestErrorsWithDecompression(t *testing.T) {1734 t.Parallel()1735 tb, state, _, rt, _ := newRuntime(t)1736 defer tb.Cleanup()1737 state.Options.Throw = null.BoolFrom(false)1738 tb.Mux.HandleFunc("/broken-archive", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {1739 enc := r.URL.Query()["encoding"][0]1740 w.Header().Set("Content-Encoding", enc)1741 _, _ = fmt.Fprintf(w, "Definitely not %s, but it's all cool...", enc)1742 }))1743 _, err := common.RunString(rt, tb.Replacer.Replace(`1744 function handleResponseEncodingError (encoding) {1745 let resp = http.get("HTTPBIN_URL/broken-archive?encoding=" + encoding);1746 if (resp.error_code != 1701) {1747 throw new Error("Expected error_code 1701 for '" + encoding +"', but got " + resp.error_code);1748 }1749 }1750 ["gzip", "deflate", "br", "zstd"].forEach(handleResponseEncodingError);1751 `))1752 assert.NoError(t, err)1753}1754func TestDigestAuthWithBody(t *testing.T) {1755 t.Parallel()1756 tb, state, samples, rt, _ := newRuntime(t)1757 defer tb.Cleanup()1758 state.Options.Throw = null.BoolFrom(true)1759 state.Options.HTTPDebug = null.StringFrom("full")1760 tb.Mux.HandleFunc("/digest-auth-with-post/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {1761 require.Equal(t, "POST", r.Method)1762 body, err := ioutil.ReadAll(r.Body)1763 require.NoError(t, err)1764 require.Equal(t, "super secret body", string(body))1765 httpbin.New().DigestAuth(w, r) // this doesn't read the body1766 }))1767 urlWithCreds := tb.Replacer.Replace(1768 "http://testuser:testpwd@HTTPBIN_IP:HTTPBIN_PORT/digest-auth-with-post/auth/testuser/testpwd",1769 )1770 _, err := common.RunString(rt, fmt.Sprintf(`1771 let res = http.post(%q, "super secret body", { auth: "digest" });1772 if (res.status !== 200) { throw new Error("wrong status: " + res.status); }1773 if (res.error_code !== 0) { throw new Error("wrong error code: " + res.error_code); }1774 `, urlWithCreds))1775 require.NoError(t, err)1776 expectedURL := tb.Replacer.Replace(1777 "http://HTTPBIN_IP:HTTPBIN_PORT/digest-auth-with-post/auth/testuser/testpwd")1778 expectedName := tb.Replacer.Replace(1779 "http://****:****@HTTPBIN_IP:HTTPBIN_PORT/digest-auth-with-post/auth/testuser/testpwd")1780 sampleContainers := stats.GetBufferedSamples(samples)1781 assertRequestMetricsEmitted(t, sampleContainers[0:1], "POST", expectedURL, expectedName, 401, "")1782 assertRequestMetricsEmitted(t, sampleContainers[1:2], "POST", expectedURL, expectedName, 200, "")1783}...
assertRequestMetricsEmitted
Using AI Code Generation
1import (2func TestHandler(t *testing.T) {3 req, err := http.NewRequest("GET", "/test", nil)4 if err != nil {5 t.Fatal(err)6 }7 rr := httptest.NewRecorder()8 handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {9 fmt.Fprint(w, "Hello, client")10 })11 handler.ServeHTTP(rr, req)12 if rr.Code != http.StatusOK {13 t.Errorf("handler returned wrong status code: got %v want %v",14 }15 if rr.Body.String() != "Hello, client" {16 t.Errorf("handler returned unexpected body: got %v want %v",17 rr.Body.String(), "Hello, client")18 }19 assertRequestMetricsEmitted(t, rr)20}21func assertRequestMetricsEmitted(t *testing.T, rr *httptest.ResponseRecorder) {22 t.Helper()23 if rr.Header().Get("X-Go-Prometheus-Path") == "" {24 t.Errorf("X-Go-Prometheus-Path header not set")25 }26 if rr.Header().Get("X-Go-Prometheus-Method") == "" {27 t.Errorf("X-Go-Prometheus-Method header not set")28 }29 if rr.Header().Get("X-Go-Prometheus-Code") == "" {30 t.Errorf("X-Go-Prometheus-Code header not set")31 }32}33import (34func prometheusMiddleware(next http.Handler) http.Handler {35 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {36 next.ServeHTTP(w, r)37 w.Header().Set("X-Go-Prometheus-Path", r.URL.Path)38 w.Header().Set("X-Go-Prometheus-Method", r.Method)39 w.Header().Set("X-Go-Prometheus-Code", fmt.Sprintf("%d", w.Header().Get("X-Go-Prometheus-Code")))40 })41}42func main() {43 http.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {44 fmt.Fprint(w, "Hello, client
assertRequestMetricsEmitted
Using AI Code Generation
1import (2func TestHandler(t *testing.T) {3 req, err := http.NewRequest("GET", "/foo", nil)4 if err != nil {5 t.Fatal(err)6 }7 rr := httptest.NewRecorder()8 handler := http.HandlerFunc(Handler)9 handler.ServeHTTP(rr, req)10 if status := rr.Code; status != http.StatusOK {11 t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK)12 }13 expected := `{"alive": true}`14 if rr.Body.String() != expected {15 t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected)16 }17}18func TestHandler2(t *testing.T) {19 req, err := http.NewRequest("GET", "/foo", nil)20 if err != nil {21 t.Fatal(err)22 }23 rr := httptest.NewRecorder()24 handler := http.HandlerFunc(Handler)25 handler.ServeHTTP(rr, req)26 if status := rr.Code; status != http.StatusOK {27 t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK)28 }29 expected := `{"alive": true}`30 if rr.Body.String() != expected {31 t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected)32 }33}34import (
assertRequestMetricsEmitted
Using AI Code Generation
1import (2func TestHelloWorld(t *testing.T) {3 if err != nil {4 t.Fatal(err)5 }6 rr := httptest.NewRecorder()7 handler := http.HandlerFunc(HelloWorld)8 handler.ServeHTTP(rr, req)9 assert.Equal(t, http.StatusOK, rr.Code)10 assert.Equal(t, expected, rr.Body.String())11 assertRequestMetricsEmitted(t, req)12}13func HelloWorld(w http.ResponseWriter, r *http.Request) {14 fmt.Fprintf(w, "Hello World!")15}16import (17func TestHelloWorld(t *testing.T) {18 if err != nil {19 t.Fatal(err)20 }21 rr := httptest.NewRecorder()22 handler := http.HandlerFunc(HelloWorld)23 handler.ServeHTTP(rr, req)24 assert.Equal(t, http.StatusOK, rr.Code)25 assert.Equal(t, expected, rr.Body.String())26 assertRequestMetricsEmitted(t, req)27}28func HelloWorld(w http.ResponseWriter, r *http.Request
assertRequestMetricsEmitted
Using AI Code Generation
1import (2func TestHelloWorldHandler(t *testing.T) {3 req, err := http.NewRequest("GET", "/hello", nil)4 if err != nil {5 t.Fatal(err)6 }7 rr := httptest.NewRecorder()8 handler := http.HandlerFunc(HelloWorldHandler)9 handler.ServeHTTP(rr, req)10 if status := rr.Code; status != http.StatusOK {11 t.Errorf("handler returned wrong status code: got %v want %v",12 }13 if rr.Body.String() != expected {14 t.Errorf("handler returned unexpected body: got %v want %v",15 rr.Body.String(), expected)16 }17}18func HelloWorldHandler(w http.ResponseWriter, r *http.Request) {19 fmt.Fprintf(w, "Hello World!")20}21func TestHelloWorldHandler2(t *testing.T) {22 req, err := http.NewRequest("GET", "/hello", nil)23 if err != nil {24 t.Fatal(err)25 }26 rr := httptest.NewRecorder()27 handler := http.HandlerFunc(HelloWorldHandler)28 handler.ServeHTTP(rr, req)29 if status := rr.Code; status != http.StatusOK {30 t.Errorf("handler returned wrong status code: got %v want %v",31 }32 if rr.Body.String() != expected {33 t.Errorf("handler returned unexpected body: got %v want %v",34 rr.Body.String(), expected)35 }36}37func TestHelloWorldHandler3(t *testing.T) {38 req, err := http.NewRequest("GET", "/hello", nil)39 if err != nil {40 t.Fatal(err)41 }42 rr := httptest.NewRecorder()43 handler := http.HandlerFunc(HelloWorldHandler)44 handler.ServeHTTP(rr, req)45 if status := rr.Code; status != http.StatusOK {46 t.Errorf("handler returned wrong status code: got %v want %v",47 }48 if rr.Body.String() != expected {49 t.Errorf("handler returned unexpected body:
assertRequestMetricsEmitted
Using AI Code Generation
1import (2func TestMetricsEmitted(t *testing.T) {3 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {4 fmt.Fprintln(w, "Hello, client")5 }))6 defer ts.Close()7 res, err := http.Get(ts.URL)8 if err != nil {9 t.Fatal(err)10 }11 res.Body.Close()12 if err := http.AssertRequestMetricsEmitted(); err != nil {13 t.Fatal(err)14 }15}16--- FAIL: TestMetricsEmitted (0.00s)
assertRequestMetricsEmitted
Using AI Code Generation
1import (2func TestRequestMetricsEmitted(t *testing.T) {3 req, err := http.NewRequest("GET", "/path", nil)4 if err != nil {5 t.Fatal(err)6 }7 rr := httptest.NewRecorder()8 handler := http.HandlerFunc(handler)9 handler.ServeHTTP(rr, req)10 if status := rr.Code; status != http.StatusOK {11 t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK)12 }13 expected := `{"alive": true}`14 if rr.Body.String() != expected {15 t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected)16 }17}18func handler(w http.ResponseWriter, r *http.Request) {19}20import (21func TestRequestMetricsEmitted(t *testing.T) {22 req, err := http.NewRequest("GET", "/path", nil)23 if err != nil {24 t.Fatal(err)25 }26 rr := httptest.NewRecorder()27 handler := http.HandlerFunc(handler)28 handler.ServeHTTP(rr, req)29 if status := rr.Code; status != http.StatusOK {30 t.Errorf("handler returned wrong status code: got %v want %v", status, http
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!