grafana / xk6-browser

k6 module 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
341 stars 42 forks source link

k6/browser proxy field causes invalid memory address or nil pointer dereference #908

Closed PedroCaldeira closed 1 year ago

PedroCaldeira commented 1 year ago

Brief summary

When trying out the BrowserType.launch([options]) api with the proxy field, an error is popping up:

Not having the proxy field runs okay.

k6 version

k6 v0.44.1 ((devel), go1.20.4, darwin/amd64)

OS

MacOS 13.4 Intel

Docker version and image (if applicable)

No response

Steps to reproduce the problem

Run the given code sample via cli:

import { chromium } from 'k6/experimental/browser';
import { sleep } from 'k6';

export default async function () {
    const browser = chromium.launch({args:['ignore-certificate-errors'],
        headless: false,
        proxy: 'someproxy'}); // Replace with a real proxy
    const context = browser.newContext();

    const page = context.newPage();
    try {
        await page.goto('https://google.com');
        await page.waitForLoadState();
        sleep(60)
    } finally {
        page.close();
        browser.close();
    }
}

Expected behaviour

Expected the test to run normally, using the proxy given on the browser.

Actual behaviour

Get the given stack trace:

k6 run k6_test.js

          /\      |‾‾| /‾‾/   /‾‾/
     /\  /  \     |  |/  /   /  /
    /  \/    \    |     (   /   ‾‾\
   /          \   |  |\  \ |  (‾)  |
  / __________ \  |__| \__\ \_____/ .io

  execution: local
     script: k6_test.js
     output: -

  scenarios: (100.00%) 1 scenario, 1 max VUs, 10m30s max duration (incl. graceful stop):
           * default: 1 iterations for each of 1 VUs (maxDuration: 10m0s, gracefulStop: 30s)

ERRO[0000] panic: runtime error: invalid memory address or nil pointer dereference
goroutine 27 [running]:
runtime/debug.Stack()
    runtime/debug/stack.go:24 +0x65
go.k6.io/k6/js/common.RunWithPanicCatching.func1()
    go.k6.io/k6/js/common/util.go:82 +0x1f3
panic({0x20af3e0, 0x3251eb0})
    runtime/panic.go:884 +0x213
github.com/dop251/goja.(*Runtime).runWrapped.func1()
    github.com/dop251/goja@v0.0.0-20230402114112-623f9dda9079/runtime.go:2516 +0x185
panic({0x20af3e0, 0x3251eb0})
    runtime/panic.go:884 +0x213
github.com/dop251/goja.(*vm).handleThrow(0xc002e08000, {0x20af3e0, 0x3251eb0})
    github.com/dop251/goja@v0.0.0-20230402114112-623f9dda9079/vm.go:788 +0x497
github.com/dop251/goja.(*vm).try.func1()
    github.com/dop251/goja@v0.0.0-20230402114112-623f9dda9079/vm.go:807 +0x45
panic({0x20af3e0, 0x3251eb0})
    runtime/panic.go:884 +0x213
github.com/dop251/goja.(*vm).handleThrow(0xc002e08000, {0x20af3e0, 0x3251eb0})
    github.com/dop251/goja@v0.0.0-20230402114112-623f9dda9079/vm.go:788 +0x497
github.com/dop251/goja.(*vm).runTryInner.func1()
    github.com/dop251/goja@v0.0.0-20230402114112-623f9dda9079/vm.go:830 +0x45
panic({0x20af3e0, 0x3251eb0})
    runtime/panic.go:884 +0x213
github.com/grafana/xk6-browser/k6ext.GetVU({0x0?, 0x0?})
    github.com/grafana/xk6-browser@v0.9.0/k6ext/context.go:29 +0x1e
github.com/grafana/xk6-browser/k6ext.Runtime({0x0?, 0x0?})
    github.com/grafana/xk6-browser@v0.9.0/k6ext/context.go:52 +0x25
github.com/grafana/xk6-browser/k6ext.sharedPanic({0x0, 0x0}, 0xc002e46838, {0xc002e3f6e0?, 0x1, 0x1})
    github.com/grafana/xk6-browser@v0.9.0/k6ext/panic.go:41 +0x74
github.com/grafana/xk6-browser/k6ext.Panic({0x0?, 0x0?}, {0x22d05d1?, 0xc000b35900?}, {0xc002e3f6e0?, 0xc000b359c8?, 0x25913e0?})
    github.com/grafana/xk6-browser@v0.9.0/k6ext/panic.go:37 +0x65
github.com/grafana/xk6-browser/chromium.(*BrowserType).Launch(0xc002e548d0?, {0x2590b90?, 0xc002e547e0?})
    github.com/grafana/xk6-browser@v0.9.0/chromium/browser_type.go:161 +0xda
github.com/grafana/xk6-browser/browser.mapBrowserType.func2({0x2590b90?, 0xc002e547e0?})
    github.com/grafana/xk6-browser@v0.9.0/browser/mapping.go:733 +0xcc
reflect.Value.call({0x2055900?, 0xc002e00370?, 0x2c0c2128?}, {0x22a6324, 0x4}, {0xc0006368b8, 0x1, 0x0?})
    reflect/value.go:586 +0xb0b
reflect.Value.Call({0x2055900?, 0xc002e00370?, 0xc002e547e0?}, {0xc0006368b8?, 0xc002e3ef10?, 0x1015b70?})
    reflect/value.go:370 +0xbc
github.com/dop251/goja.(*Runtime).wrapReflectFunc.func1({{0x2590b90, 0xc002e2ed20}, {0xc002e3a6a0, 0x1, 0x6}})
    github.com/dop251/goja@v0.0.0-20230402114112-623f9dda9079/runtime.go:2056 +0x3dc
github.com/dop251/goja.(*nativeFuncObject).vmCall(0xc002e3c480, 0xc002e08000, 0x1)
    github.com/dop251/goja@v0.0.0-20230402114112-623f9dda9079/func.go:559 +0x1af
github.com/dop251/goja.call.exec(0x5?, 0xc002e08000)
    github.com/dop251/goja@v0.0.0-20230402114112-623f9dda9079/vm.go:3366 +0x6a
github.com/dop251/goja.(*vm).run(0xc002e08000)
    github.com/dop251/goja@v0.0.0-20230402114112-623f9dda9079/vm.go:582 +0x62
github.com/dop251/goja.(*vm).runTryInner(0xc002e15348?)
    github.com/dop251/goja@v0.0.0-20230402114112-623f9dda9079/vm.go:834 +0x70
github.com/dop251/goja.(*generator).step(0xc002e3a540)
    github.com/dop251/goja@v0.0.0-20230402114112-623f9dda9079/func.go:758 +0x31
github.com/dop251/goja.(*asyncRunner).start(0xc002e3a540, 0x1)
    github.com/dop251/goja@v0.0.0-20230402114112-623f9dda9079/func.go:729 +0xfd
github.com/dop251/goja.(*baseJsFuncObject).asyncCall(0xc002e3c600, {{0x2591510, 0x32a5720}, {0xc002e3ee90, 0x1, 0x1}}, 0xc002e3eeb0)
    github.com/dop251/goja@v0.0.0-20230402114112-623f9dda9079/func.go:607 +0xa9
github.com/dop251/goja.(*asyncFuncObject).Call(...)
    github.com/dop251/goja@v0.0.0-20230402114112-623f9dda9079/func.go:612
github.com/dop251/goja.AssertFunction.func1.1()
    github.com/dop251/goja@v0.0.0-20230402114112-623f9dda9079/runtime.go:2476 +0x77
github.com/dop251/goja.(*vm).try(0xc002e08000, 0xc000155680)
    github.com/dop251/goja@v0.0.0-20230402114112-623f9dda9079/vm.go:811 +0x244
github.com/dop251/goja.(*Runtime).runWrapped(0xc0015b8c00, 0x3748a68?)
    github.com/dop251/goja@v0.0.0-20230402114112-623f9dda9079/runtime.go:2520 +0x7c
github.com/dop251/goja.AssertFunction.func1({0x2591510?, 0x32a5720?}, {0xc002e3ee90?, 0x1?, 0x1?})
    github.com/dop251/goja@v0.0.0-20230402114112-623f9dda9079/runtime.go:2475 +0x92
go.k6.io/k6/js.(*VU).runFn.func2.1()
    go.k6.io/k6/js/runner.go:826 +0x44
go.k6.io/k6/js/eventloop.(*EventLoop).Start(0xc002e00050, 0xc002e54600)
    go.k6.io/k6/js/eventloop/eventloop.go:177 +0x1bd
go.k6.io/k6/js.(*VU).runFn.func2()
    go.k6.io/k6/js/runner.go:825 +0xea
go.k6.io/k6/js/common.RunWithPanicCatching({0x2595340?, 0xc0006e9180?}, 0x100db07?, 0x30?)
    go.k6.io/k6/js/common/util.go:86 +0x87
go.k6.io/k6/js.(*VU).runFn(0xc002e29540, {0x25836e0, 0xc002e012c0}, 0xa0?, 0xc000636858, 0xc002e3ee80, {0xc002e3ee90, 0x1, 0x1})
    go.k6.io/k6/js/runner.go:824 +0x28a
go.k6.io/k6/js.(*ActiveVU).RunOnce(0xc0008b6dc0)
    go.k6.io/k6/js/runner.go:769 +0x3fe
go.k6.io/k6/lib/executor.getIterationRunner.func1({0x2583788, 0xc002e543f0}, {0x2576d20?, 0xc0008b6dc0?})
    go.k6.io/k6/lib/executor/helpers.go:81 +0x64
go.k6.io/k6/lib/executor.PerVUIterations.Run.func5({0x257dfa8, 0xc002e29540})
    go.k6.io/k6/lib/executor/per_vu_iterations.go:228 +0x40a
created by go.k6.io/k6/lib/executor.PerVUIterations.Run
    go.k6.io/k6/lib/executor/per_vu_iterations.go:241 +0xc29

Goja stack:

     data_received........: 0 B 0 B/s
     data_sent............: 0 B 0 B/s
     iteration_duration...: avg=692.78µs min=692.78µs med=692.78µs max=692.78µs p(90)=692.78µs p(95)=692.78µs
     iterations...........: 1   1138.952164/s

running (00m00.0s), 0/1 VUs, 0 complete and 1 interrupted iterations
default ✗ [======================================] 1 VUs  00m00.0s/10m0s  1/1 iters, 1 per VU
ERRO[0000] a panic occurred during JS execution: runtime error: invalid memory address or nil pointer dereference
inancgumus commented 1 year ago

Hi @PedroCaldeira,

I'd like to point out that we don't support proxy at the moment, and this option will be removed in the next release.

Regarding the issue, the proxy option should be an object rather than a string. For example:

    const browser = chromium.launch({
        args:['ignore-certificate-errors'],
        headless: false,
        proxy: {
            server: "someproxy",
            bypass: "",
            username: "",
            password: "",
        },
    }); // Replace with a real proxy

Other than this, we need to tackle an inherent issue here. Instead of an error message, we get a panic stack trace. I'll be looking into this. Update: I've looked into this and the problem introduced in commit 2b1a852: Here, it panics with a nil context that it gets from init(). After recent updates, this problem has been fixed by returning errors to the mapping layer.