Skip to content
This repository was archived by the owner on Jan 30, 2025. It is now read-only.

Commit 0bc440e

Browse files
committed
Add more locks to execution contexts handling
Also refactor getting a context with a world name.
1 parent 230721f commit 0bc440e

File tree

4 files changed

+43
-18
lines changed

4 files changed

+43
-18
lines changed

common/frame.go

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -345,13 +345,7 @@ func (f *Frame) hasContext(world string) bool {
345345
f.executionContextMu.RLock()
346346
defer f.executionContextMu.RUnlock()
347347

348-
switch world {
349-
case mainWorld:
350-
return f.mainExecutionContext != nil
351-
case utilityWorld:
352-
return f.utilityExecutionContext != nil
353-
}
354-
return false // Should never reach here!
348+
return f.getExecCtx(world) != nil
355349
}
356350

357351
func (f *Frame) hasLifecycleEventFired(event LifecycleEvent) bool {
@@ -517,20 +511,18 @@ func (f *Frame) waitForFunction(apiCtx context.Context, world string, predicateF
517511
"fid:%s furl:%q world:%s pt:%s timeout:%s",
518512
f.ID(), f.URL(), world, polling, timeout)
519513

520-
rt := k6common.GetRuntime(f.ctx)
521514
f.waitForExecutionContext(world)
522515

523516
f.executionContextMu.RLock()
524517
defer f.executionContextMu.RUnlock()
525518

526-
execCtx := f.mainExecutionContext
527-
if world == utilityWorld {
528-
execCtx = f.utilityExecutionContext
529-
}
519+
execCtx := f.getExecCtx(world)
530520
injected, err := execCtx.getInjectedScript(apiCtx)
531521
if err != nil {
532522
return nil, err
533523
}
524+
525+
rt := k6common.GetRuntime(f.ctx)
534526
pageFn := rt.ToValue(`
535527
(injected, predicate, polling, timeout, ...args) => {
536528
return injected.waitForPredicateFunction(predicate, polling, timeout, ...args);
@@ -1241,7 +1233,12 @@ func (f *Frame) SetContent(html string, opts goja.Value) {
12411233
document.write(html);
12421234
document.close();
12431235
}`
1244-
f.waitForExecutionContext(utilityExecutionContext)
1236+
1237+
f.waitForExecutionContext(utilityWorld)
1238+
1239+
f.executionContextMu.RLock()
1240+
defer f.executionContextMu.RUnlock()
1241+
12451242
_, err := f.utilityExecutionContext.evaluate(f.ctx, true, true, rt.ToValue(js), rt.ToValue(html))
12461243
if err != nil {
12471244
k6common.Throw(rt, err)
@@ -1377,6 +1374,9 @@ func (f *Frame) WaitForFunction(pageFunc goja.Value, opts goja.Value, args ...go
13771374
k6common.Throw(rt, fmt.Errorf("failed parsing options: %w", err))
13781375
}
13791376

1377+
f.executionContextMu.RLock()
1378+
defer f.executionContextMu.RUnlock()
1379+
13801380
handle, err := f.waitForFunction(f.ctx, utilityWorld, pageFunc, parsedOpts.Polling, parsedOpts.Interval, parsedOpts.Timeout, args...)
13811381
if err != nil {
13821382
k6common.Throw(rt, err)
@@ -1445,6 +1445,32 @@ func (f *Frame) WaitForTimeout(timeout int64) {
14451445
}
14461446
}
14471447

1448+
func (f *Frame) adoptBackendNodeID(world string, id cdp.BackendNodeID) (*ElementHandle, error) {
1449+
f.executionContextMu.RLock()
1450+
defer f.executionContextMu.RUnlock()
1451+
1452+
ec := f.getExecCtx(world)
1453+
return ec.adoptBackendNodeID(id)
1454+
}
1455+
1456+
func (f *Frame) evaluate(world string, apiCtx context.Context, forceCallable bool, returnByValue bool, pageFunc goja.Value, args ...goja.Value) (res interface{}, err error) {
1457+
f.executionContextMu.RLock()
1458+
defer f.executionContextMu.RUnlock()
1459+
1460+
ec := f.getExecCtx(world)
1461+
return ec.evaluate(apiCtx, forceCallable, returnByValue, pageFunc, args...)
1462+
}
1463+
1464+
// getExecCtx returns an execution context using a given world name.
1465+
// Unsafe to use concurrently.
1466+
func (f *Frame) getExecCtx(world string) frameExecutionContext {
1467+
ec := f.mainExecutionContext
1468+
if world == utilityWorld {
1469+
ec = f.utilityExecutionContext
1470+
}
1471+
return ec
1472+
}
1473+
14481474
// frameExecutionContext represents a JS execution context that belongs to Frame.
14491475
type frameExecutionContext interface {
14501476
// adoptBackendNodeID adopts specified backend node into this execution

common/frame_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func TestFrameNilDocument(t *testing.T) {
5252
// document() waits for the main execution context
5353
ok := make(chan struct{}, 1)
5454
go func() {
55-
frame.setContext(mainExecutionContext, stub)
55+
frame.setContext(mainWorld, stub)
5656
ok <- struct{}{}
5757
}()
5858
select {

common/page.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ func (p *Page) evaluateOnNewDocument(source string) {
193193
// TODO: implement
194194
}
195195

196-
func (p *Page) getFrameElement(f *Frame) (*ElementHandle, error) {
196+
func (p *Page) getFrameElement(f *Frame) (handle *ElementHandle, _ error) {
197197
if f == nil {
198198
p.logger.Debugf("Page:getFrameElement", "sid:%v frame:nil", p.sessionID())
199199
} else {
@@ -220,8 +220,7 @@ func (p *Page) getFrameElement(f *Frame) (*ElementHandle, error) {
220220
if parent == nil {
221221
return nil, errors.New("frame has been detached 2")
222222
}
223-
handle, err := parent.mainExecutionContext.adoptBackendNodeID(backendNodeId)
224-
return handle, err
223+
return parent.adoptBackendNodeID(mainWorld, backendNodeId)
225224
}
226225

227226
func (p *Page) getOwnerFrame(apiCtx context.Context, h *ElementHandle) cdp.FrameID {

common/screenshotter.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func newScreenshotter(ctx context.Context) *screenshotter {
4747

4848
func (s *screenshotter) fullPageSize(p *Page) (*Size, error) {
4949
rt := k6common.GetRuntime(s.ctx)
50-
result, err := p.frameManager.mainFrame.mainExecutionContext.evaluate(s.ctx, true, true, rt.ToValue(`
50+
result, err := p.frameManager.mainFrame.evaluate(mainWorld, s.ctx, true, true, rt.ToValue(`
5151
() => {
5252
if (!document.body || !document.documentElement) {
5353
return null;

0 commit comments

Comments
 (0)