grafana / xk6-browser

k6 extension that adds support for browser automation and end-to-end web testing via the Chrome Devtools Protocol
https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/browser/
GNU Affero General Public License v3.0
337 stars 42 forks source link

VU context should control the iteration #1410

Open ankur22 opened 2 weeks ago

ankur22 commented 2 weeks ago

Brief summary

Currently the browser module relies on the the events that it is subscribed to control its lifecycle. The reasons we have this is to allow the browser module to control the number of chromium instances that are used per test run.

An unexpected consequence of working with the event system is that we were unable to easily work with the vu context to allow k6 to abort tests early. If a vu context was used to control the chromium subprocess/connection then there would be a race condition between chromium unexpectedly shutting down when the iteration ends and the current API calls being made via CDP.

The work around for this is to use a background context that is created when the module is created. This means the module relies on the events system to correctly shut down iterations.

When this doesn't work is when a gracefulStop occurs (SIGTERM for example) and the iteration's vu context is closed. At this point k6 expects the current API call to cancel itself since the context is closed and allow it to clean itself up and gracefully shutdown.

Since the browser module isn't working with the vu context, it fails to shut it self down promptly, which can result in various other timeouts elsewhere. We should look at using the vu context to control the API calls, but rely on the events to control the chromium browser lifecycle -- IterEnd and exit events are called once the iteration's vu context is closed and the browser module hands over the main thread back to k6.

xk6-browser version

v0.53.0

OS

NA

Chrome version

NA

Docker version and image (if applicable)

No response

Steps to reproduce the problem

Run the following script, which will block the iteration and then send a SIGTERM signal (kill -15 {pid}) to the k6 process—it won't quit the process (until a default of 30 seconds or a user-specified timeout elapses):

import { browser } from 'k6/browser';

export const options = {
  scenarios: {
    ui: {
      executor: 'shared-iterations',
      options: {
        browser: {
            type: 'chromium',
        },
      },
    },
  },
}

export default async function() {
  const context = await browser.newContext();
  const page = await context.newPage();

  try {
    await page.goto('https://test.k6.io/', { waitUntil: 'networkidle' });
    await Promise.all([
      page.waitForNavigation(),
      page.locator('a[href="/my_messages.php"]').click(),
    ]);
    // indefinitely block here
    await page.locator("NOT-EXISTS").textContent();
  } finally {
    await page.close();
  }
}

Expected behaviour

The test exits promptly and doesn't wait for the timeout to occur.

Actual behaviour

The browser module waits for the timeout to occur.

### Tasks
- [ ] https://github.com/grafana/xk6-browser/pull/1420
- [ ] Update the k6 release notes
inancgumus commented 2 weeks ago

This issue might be related to #1253 as well.