Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add basic event loop with some API to be used by modules #2228

Merged
merged 7 commits into from
Mar 2, 2022
2 changes: 1 addition & 1 deletion core/local/eventloop_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func eventLoopTest(t *testing.T, script []byte, testHandle func(context.Context,
logHook := &testutils.SimpleLogrusHook{HookedLevels: []logrus.Level{logrus.InfoLevel, logrus.WarnLevel, logrus.ErrorLevel}}
logger.AddHook(logHook)

script = []byte(`import {setTimeout} from "k6";
script = []byte(`import {setTimeout} from "k6/experimental";
` + string(script))
registry := metrics.NewRegistry()
builtinMetrics := metrics.RegisterBuiltinMetrics(registry)
Expand Down
24 changes: 13 additions & 11 deletions js/initcontext.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import (
"go.k6.io/k6/js/modules/k6/data"
"go.k6.io/k6/js/modules/k6/encoding"
"go.k6.io/k6/js/modules/k6/execution"
"go.k6.io/k6/js/modules/k6/experimental"
"go.k6.io/k6/js/modules/k6/grpc"
"go.k6.io/k6/js/modules/k6/html"
"go.k6.io/k6/js/modules/k6/http"
Expand Down Expand Up @@ -383,17 +384,18 @@ func (i *InitContext) allowOnlyOpenedFiles() {

func getInternalJSModules() map[string]interface{} {
return map[string]interface{}{
"k6": k6.New(),
"k6/crypto": crypto.New(),
"k6/crypto/x509": x509.New(),
"k6/data": data.New(),
"k6/encoding": encoding.New(),
"k6/execution": execution.New(),
"k6/net/grpc": grpc.New(),
"k6/html": html.New(),
"k6/http": http.New(),
"k6/metrics": metrics.New(),
"k6/ws": ws.New(),
"k6": k6.New(),
"k6/crypto": crypto.New(),
"k6/crypto/x509": x509.New(),
"k6/data": data.New(),
"k6/encoding": encoding.New(),
"k6/execution": execution.New(),
"k6/net/grpc": grpc.New(),
"k6/html": html.New(),
"k6/http": http.New(),
"k6/metrics": metrics.New(),
"k6/ws": ws.New(),
"k6/experimental": experimental.New(),
}
}

Expand Down
68 changes: 68 additions & 0 deletions js/modules/k6/experimental/experimental.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Package experimental includes experimental module features
package experimental

import (
"errors"
"time"

"github.com/dop251/goja"
"go.k6.io/k6/js/common"
"go.k6.io/k6/js/modules"
)

type (
// RootModule is the root experimental module
RootModule struct{}
// ModuleInstance represents an instance of the experimental module
ModuleInstance struct {
vu modules.VU
}
)

var (
_ modules.Module = &RootModule{}
_ modules.Instance = &ModuleInstance{}
)

// NewModuleInstance implements modules.Module interface
func (*RootModule) NewModuleInstance(m modules.VU) modules.Instance {
return &ModuleInstance{vu: m}
}

// New returns a new RootModule.
func New() *RootModule {
return &RootModule{}
}

// Exports returns the exports of the experimental module
func (mi *ModuleInstance) Exports() modules.Exports {
return modules.Exports{
Named: map[string]interface{}{
"setTimeout": mi.setTimeout,
},
}
}

func (mi *ModuleInstance) setTimeout(f goja.Callable, t float64) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that we have it as an explicit experiment could we add the expected timeoutID as returned value and set it always to zero?

Copy link
Member

@na-- na-- Feb 23, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I plan to make a PR with my PoC from #2228 (comment) tomorrow

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer if we leave this for the next release. Given that this won't be used by anyone.

We can have this changes in :

  1. extension
  2. in that module temporarily through the development cycle

but I would argue we would probably want them globally available by next release.

Adding unnecessary changes days before cutoff IMO just adds more ways for this to break. We currently only care about this call in order to test the event loop - anyone actually wanting to use it - shouldn't

if f == nil {
common.Throw(mi.vu.Runtime(), errors.New("setTimeout requires a function as first argument"))
}
// TODO maybe really return something to use with `clearTimeout
// TODO support arguments ... maybe
runOnLoop := mi.vu.RegisterCallback()
go func() {
timer := time.NewTimer(time.Duration(t * float64(time.Millisecond)))
select {
case <-timer.C:
runOnLoop(func() error {
_, err := f(goja.Undefined())
return err
})
case <-mi.vu.Context().Done():
// TODO log something?

timer.Stop()
runOnLoop(func() error { return nil })
}
}()
}
25 changes: 0 additions & 25 deletions js/modules/k6/k6.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ func (mi *K6) Exports() modules.Exports {
"group": mi.Group,
"randomSeed": mi.RandomSeed,
"sleep": mi.Sleep,
"setTimeout": mi.setTimeout,
},
}
}
Expand Down Expand Up @@ -232,27 +231,3 @@ func (mi *K6) Check(arg0, checks goja.Value, extras ...goja.Value) (bool, error)

return succ, nil
}

func (mi *K6) setTimeout(f goja.Callable, t float64) {
if f == nil {
common.Throw(mi.vu.Runtime(), errors.New("setTimeout requires a function as first argument"))
}
// TODO maybe really return something to use with `clearTimeout
// TODO support arguments ... maybe
runOnLoop := mi.vu.RegisterCallback()
go func() {
timer := time.NewTimer(time.Duration(t * float64(time.Millisecond)))
select {
case <-timer.C:
runOnLoop(func() error {
_, err := f(goja.Undefined())
return err
})
case <-mi.vu.Context().Done():
// TODO log something?

timer.Stop()
runOnLoop(func() error { return nil })
}
}()
}