grafana / k6

A modern load testing tool, using Go and JavaScript - https://k6.io
GNU Affero General Public License v3.0
24.93k stars 1.23k forks source link

Option to set default HTTP configuration globally #761

Open na-- opened 5 years ago

na-- commented 5 years ago

Currently users can specify the userAgent that would be used by k6 by default when it makes HTTP requests. I'd be useful if we can generalize that and allow users to specify the default value of any header they want globally. Use cases that I can think of:

na-- commented 5 years ago

It seems worth it to also allow other request options (https://docs.k6.io/docs/params-k6http) to be specified globally. It'd be especially useful to be able add cookies or to change the global default timeout...

marklagendijk commented 5 years ago

I agree that it would be useful to be able to set defaults for all (or most) request options. Now I don't think that all of these would also need a cli option. For most it would be enough to be able to specify them in the script.

simskij commented 3 years ago

Being able to set a global timeout would definitely be a good addition.

na-- commented 3 years ago

https://github.com/loadimpact/k6/issues/1865 is a request to be able to specify the Content-Type header globally, which I'll close in favor of this issue.

In general, it's not certain if we'll implement this issue at all. It's more likely we'll go for a whole new version of the HTTP API where you are able to create multiple HTTP clients, each with different default properties (headers, connection reuse and proxy settings, timeouts, etc.). We've delayed even writing an issue for that new and better HTTP API for probably close to 2 years now, due to the many other things that have had higher priority... :disappointed: So I can't give any ETAs, but it will happen eventually, we're slowly running out of more important things... :sweat_smile:

It will probably be done as an xk6 (https://github.com/k6io/xk6) extension initially, and adopted in the k6 core when it's good enough and stable. If someone wants to take an early stab at it, here is some more info on how extensions are made: https://k6.io/blog/extending-k6-with-xk6

Until then, it's worth pointing out that we already have a pure JavaScript wrapper around k6/http that does some of the things described in this issue, hosted on https://jslib.k6.io/: https://jslib.k6.io/httpx/0.0.3/index.js

We haven't documented it well yet, and it's still a very early prototype, but the code is short enough to be understandable... You can create something like an HTTP client and set headers and tags that are applied to every HTTP request. We also always accept PRs at https://github.com/k6io/jslib.k6.io/ and https://k6.io/docs/ with improvements :sweat_smile:

sniku commented 3 years ago

I encountered the same problem during the implementation of the "functional.js" library for k6.

It's handy to be able to specify default headers, baseURL, tags and other parameters. I implemented a httpx wrapper around the built-in http library to accomplish this. While I have not documented all the functionality, I think the code is self-explanatory, so anyone who finds this issue can consider using it.

import { test } from 'https://jslib.k6.io/functional/0.0.1/index.js';
import { Httpx } from 'https://jslib.k6.io/httpx/0.0.3/index.js';

import { randomIntBetween, randomItem } from "https://jslib.k6.io/k6-utils/1.0.0/index.js";

export let options = {
  thresholds: {
    'http_req_duration{name:PublicCrocs}': ['p(90)<200'],
    checks: [{threshold: 'rate == 1.00', abortOnFail: true}],
  },
};

const USERNAME = `user${randomIntBetween(1, 100000)}@example.com`;  // Set your own email;
const PASSWORD = 'superCroc2019';

let session = new Httpx({
    baseURL: 'https://test-api.k6.io', 
    headers: {
        'User-Agent': "My custom user agent",
        "Content-Type": 'application/x-www-form-urlencoded' // or 'MyDefaultContentType'
    },
    timeout: 20000 // 20s timeout.
});

export default function testSuite() {

  test(`Create a test user ${USERNAME}`, (t) => {

    let resp = session.post(`/user/register/`, {
      first_name: 'Crocodile',
      last_name: 'Owner',
      username: USERNAME,
      password: PASSWORD,
    });

    t.expect(resp.status).as("status").toEqual(201)
      .and(resp).toHaveValidJson();
  })

  &&

  test(`Authenticate the new user ${USERNAME}`, (t) => {

    let resp = session.post(`/auth/token/login/`, {
      username: USERNAME,
      password: PASSWORD
    });

    t.expect(resp.status).as("Auth status").toBeBetween(200, 204)
      .and(resp).toHaveValidJson()
      .and(resp.json('access')).as("auth token").toBeTruthy();

    let authToken = resp.json('access');
    // set the authorization header on the session for the subsequent requests.
    session.addHeader('Authorization', `Bearer ${authToken}`);

  })

  &&

  test('04. Create a new crocodile', (t) => {
    let payload = {
      name: `Croc Name`,
      sex: randomItem(["M", "F"]),
      date_of_birth: '2019-01-01',
    };

    let resp = session.post(`/my/crocodiles/`, payload);

    t.expect(resp.status).as("Croc creation status").toEqual(201)
      .and(resp).toHaveValidJson();
  })

}

Note, I'm defining an http client called session outside of the default function. All requests that use session, get default parameters defined in the constructor. Session parameters can also be updated in the default function. See line

session.addHeader('Authorization', `Bearer ${authToken}`);

which adds a new default header to the existing session. Subsequent requests will get this header by default.

Note: both the functional.js and httpx.js libraries are in active development, so you may want to check https://jslib.k6.io/ to see if there are newer releases.

testn commented 2 years ago

Where are we with this?

ppcano commented 4 months ago

custom headers that should be in every request

Some tests interact with different systems (domains), requiring distinct headers.

Perhaps, it is useful to also allow configuring "global" headers for each specific (sub)domains.