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

Create distinct test state objects for the pre-init and run phases and thread them everywhere #2627

Merged
merged 12 commits into from
Aug 2, 2022
Merged
38 changes: 17 additions & 21 deletions js/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,22 +73,19 @@ type BundleInstance struct {
}

// NewBundle creates a new bundle from a source file and a filesystem.
func NewBundle(
logger logrus.FieldLogger, src *loader.SourceData, filesystems map[string]afero.Fs, rtOpts lib.RuntimeOptions,
registry *metrics.Registry,
) (*Bundle, error) {
compatMode, err := lib.ValidateCompatibilityMode(rtOpts.CompatibilityMode.String)
func NewBundle(rs *lib.RuntimeState, src *loader.SourceData, filesystems map[string]afero.Fs) (*Bundle, error) {
compatMode, err := lib.ValidateCompatibilityMode(rs.RuntimeOptions.CompatibilityMode.String)
if err != nil {
return nil, err
}

// Compile sources, both ES5 and ES6 are supported.
code := string(src.Data)
c := compiler.New(logger)
c := compiler.New(rs.Logger)
c.Options = compiler.Options{
CompatibilityMode: compatMode,
Strict: true,
SourceMapLoader: generateSourceMapLoader(logger, filesystems),
SourceMapLoader: generateSourceMapLoader(rs.Logger, filesystems),
}
pgm, _, err := c.Compile(code, src.URL.String(), false)
if err != nil {
Expand All @@ -100,17 +97,17 @@ func NewBundle(
Filename: src.URL,
Source: code,
Program: pgm,
BaseInitContext: NewInitContext(logger, rt, c, compatMode, filesystems, loader.Dir(src.URL)),
RuntimeOptions: rtOpts,
BaseInitContext: NewInitContext(rs.Logger, rt, c, compatMode, filesystems, loader.Dir(src.URL)),
RuntimeOptions: rs.RuntimeOptions,
CompatibilityMode: compatMode,
exports: make(map[string]goja.Callable),
registry: registry,
registry: rs.Registry,
}
if err = bundle.instantiate(logger, rt, bundle.BaseInitContext, 0); err != nil {
if err = bundle.instantiate(rs.Logger, rt, bundle.BaseInitContext, 0); err != nil {
return nil, err
}

err = bundle.getExports(logger, rt, true)
err = bundle.getExports(rs.Logger, rt, true)
if err != nil {
return nil, err
}
Expand All @@ -119,13 +116,12 @@ func NewBundle(
}

// NewBundleFromArchive creates a new bundle from an lib.Archive.
func NewBundleFromArchive(
logger logrus.FieldLogger, arc *lib.Archive, rtOpts lib.RuntimeOptions, registry *metrics.Registry,
) (*Bundle, error) {
func NewBundleFromArchive(rs *lib.RuntimeState, arc *lib.Archive) (*Bundle, error) {
if arc.Type != "js" {
return nil, fmt.Errorf("expected bundle type 'js', got '%s'", arc.Type)
}

rtOpts := rs.RuntimeOptions // copy the struct from the RuntimeState
if !rtOpts.CompatibilityMode.Valid {
// `k6 run --compatibility-mode=whatever archive.tar` should override
// whatever value is in the archive
Expand All @@ -136,18 +132,18 @@ func NewBundleFromArchive(
return nil, err
}

c := compiler.New(logger)
c := compiler.New(rs.Logger)
c.Options = compiler.Options{
Strict: true,
CompatibilityMode: compatMode,
SourceMapLoader: generateSourceMapLoader(logger, arc.Filesystems),
SourceMapLoader: generateSourceMapLoader(rs.Logger, arc.Filesystems),
}
pgm, _, err := c.Compile(string(arc.Data), arc.FilenameURL.String(), false)
if err != nil {
return nil, err
}
rt := goja.New()
initctx := NewInitContext(logger, rt, c, compatMode, arc.Filesystems, arc.PwdURL)
initctx := NewInitContext(rs.Logger, rt, c, compatMode, arc.Filesystems, arc.PwdURL)

env := arc.Env
if env == nil {
Expand All @@ -168,16 +164,16 @@ func NewBundleFromArchive(
RuntimeOptions: rtOpts,
CompatibilityMode: compatMode,
exports: make(map[string]goja.Callable),
registry: registry,
registry: rs.Registry,
}

if err = bundle.instantiate(logger, rt, bundle.BaseInitContext, 0); err != nil {
if err = bundle.instantiate(rs.Logger, rt, bundle.BaseInitContext, 0); err != nil {
return nil, err
}

// Grab exported objects, but avoid overwriting options, which would
// be initialized from the metadata.json at this point.
err = bundle.getExports(logger, rt, false)
err = bundle.getExports(rs.Logger, rt, false)
if err != nil {
return nil, err
}
Expand Down
43 changes: 28 additions & 15 deletions js/bundle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,31 +50,44 @@ import (

const isWindows = runtime.GOOS == "windows"

func getRuntimeState(tb testing.TB, logger *logrus.Logger, rtOpts *lib.RuntimeOptions) *lib.RuntimeState {
if logger == nil {
logger = testutils.NewLogger(tb)
}
if rtOpts == nil {
rtOpts = &lib.RuntimeOptions{}
}
reg := metrics.NewRegistry()
return &lib.RuntimeState{
Logger: logger,
RuntimeOptions: *rtOpts,
Registry: reg,
BuiltinMetrics: metrics.RegisterBuiltinMetrics(reg),
}
}

func getSimpleBundle(tb testing.TB, filename, data string, opts ...interface{}) (*Bundle, error) {
var (
fs = afero.NewMemMapFs()
rtOpts = lib.RuntimeOptions{}
logger logrus.FieldLogger = testutils.NewLogger(tb)
)
fs := afero.NewMemMapFs()
var rtOpts *lib.RuntimeOptions
var logger *logrus.Logger
for _, o := range opts {
switch opt := o.(type) {
case afero.Fs:
fs = opt
case lib.RuntimeOptions:
rtOpts = opt
case logrus.FieldLogger:
rtOpts = &opt
case *logrus.Logger:
na-- marked this conversation as resolved.
Show resolved Hide resolved
logger = opt
}
}

return NewBundle(
logger,
getRuntimeState(tb, logger, rtOpts),
&loader.SourceData{
URL: &url.URL{Path: filename, Scheme: "file"},
Data: []byte(data),
},
map[string]afero.Fs{"file": fs, "https": afero.NewMemMapFs()},
rtOpts,
metrics.NewRegistry(),
)
}

Expand Down Expand Up @@ -489,7 +502,7 @@ func TestNewBundleFromArchive(t *testing.T) {
}

checkArchive := func(t *testing.T, arc *lib.Archive, rtOpts lib.RuntimeOptions, expError string) {
b, err := NewBundleFromArchive(logger, arc, rtOpts, metrics.NewRegistry())
b, err := NewBundleFromArchive(getRuntimeState(t, logger, &rtOpts), arc)
if expError != "" {
require.Error(t, err)
require.Contains(t, err.Error(), expError)
Expand Down Expand Up @@ -572,7 +585,7 @@ func TestNewBundleFromArchive(t *testing.T) {
PwdURL: &url.URL{Scheme: "file", Path: "/"},
Filesystems: nil,
}
b, err := NewBundleFromArchive(logger, arc, lib.RuntimeOptions{}, metrics.NewRegistry())
b, err := NewBundleFromArchive(getRuntimeState(t, logger, nil), arc)
require.NoError(t, err)
bi, err := b.Instantiate(logger, 0)
require.NoError(t, err)
Expand Down Expand Up @@ -711,7 +724,7 @@ func TestOpen(t *testing.T) {
}
require.NoError(t, err)

arcBundle, err := NewBundleFromArchive(logger, sourceBundle.makeArchive(), lib.RuntimeOptions{}, metrics.NewRegistry())
arcBundle, err := NewBundleFromArchive(getRuntimeState(t, logger, nil), sourceBundle.makeArchive())

require.NoError(t, err)

Expand Down Expand Up @@ -811,7 +824,7 @@ func TestBundleEnv(t *testing.T) {
require.NoError(t, err)

logger := testutils.NewLogger(t)
b2, err := NewBundleFromArchive(logger, b1.makeArchive(), lib.RuntimeOptions{}, metrics.NewRegistry())
b2, err := NewBundleFromArchive(getRuntimeState(t, logger, nil), b1.makeArchive())
require.NoError(t, err)

bundles := map[string]*Bundle{"Source": b1, "Archive": b2}
Expand Down Expand Up @@ -848,7 +861,7 @@ func TestBundleNotSharable(t *testing.T) {
require.NoError(t, err)
logger := testutils.NewLogger(t)

b2, err := NewBundleFromArchive(logger, b1.makeArchive(), lib.RuntimeOptions{}, metrics.NewRegistry())
b2, err := NewBundleFromArchive(getRuntimeState(t, logger, nil), b1.makeArchive())
require.NoError(t, err)

bundles := map[string]*Bundle{"Source": b1, "Archive": b2}
Expand Down
46 changes: 19 additions & 27 deletions js/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ import (

"github.com/dop251/goja"
"github.com/oxtoacart/bpool"
"github.com/sirupsen/logrus"
"github.com/spf13/afero"
"golang.org/x/net/http2"
"golang.org/x/time/rate"
Expand All @@ -65,11 +64,9 @@ var _ lib.Runner = &Runner{}
var nameToCertWarning sync.Once

type Runner struct {
Bundle *Bundle
Logger *logrus.Logger
defaultGroup *lib.Group
builtinMetrics *metrics.BuiltinMetrics
registry *metrics.Registry
Bundle *Bundle
runtimeState *lib.RuntimeState
defaultGroup *lib.Group

BaseDialer net.Dialer
Resolver netext.Resolver
Expand All @@ -79,15 +76,11 @@ type Runner struct {

console *console
setupData []byte

keylogger io.Writer
}

// New returns a new Runner for the provide source
func New(
rs *lib.RuntimeState, src *loader.SourceData, filesystems map[string]afero.Fs,
) (*Runner, error) {
bundle, err := NewBundle(rs.Logger, src, filesystems, rs.RuntimeOptions, rs.Registry)
// New returns a new Runner for the provided source
func New(rs *lib.RuntimeState, src *loader.SourceData, filesystems map[string]afero.Fs) (*Runner, error) {
bundle, err := NewBundle(rs, src, filesystems)
if err != nil {
return nil, err
}
Expand All @@ -97,7 +90,7 @@ func New(

// NewFromArchive returns a new Runner from the source in the provided archive
func NewFromArchive(rs *lib.RuntimeState, arc *lib.Archive) (*Runner, error) {
bundle, err := NewBundleFromArchive(rs.Logger, arc, rs.RuntimeOptions, rs.Registry)
bundle, err := NewBundleFromArchive(rs, arc)
if err != nil {
return nil, err
}
Expand All @@ -115,7 +108,7 @@ func NewFromBundle(rs *lib.RuntimeState, b *Bundle) (*Runner, error) {
defDNS := types.DefaultDNSConfig()
r := &Runner{
Bundle: b,
Logger: rs.Logger,
runtimeState: rs,
defaultGroup: defaultGroup,
BaseDialer: net.Dialer{
Timeout: 30 * time.Second,
Expand All @@ -126,9 +119,6 @@ func NewFromBundle(rs *lib.RuntimeState, b *Bundle) (*Runner, error) {
Resolver: netext.NewResolver(
net.LookupIP, 0, defDNS.Select.DNSSelect, defDNS.Policy.DNSPolicy),
ActualResolver: net.LookupIP,
builtinMetrics: rs.BuiltinMetrics,
registry: rs.Registry,
keylogger: rs.KeyLogger,
}

err = r.SetOptions(r.Bundle.Options)
Expand All @@ -152,7 +142,7 @@ func (r *Runner) NewVU(idLocal, idGlobal uint64, samplesOut chan<- metrics.Sampl
//nolint:funlen
func (r *Runner) newVU(idLocal, idGlobal uint64, samplesOut chan<- metrics.SampleContainer) (*VU, error) {
// Instantiate a new bundle, make a VU out of it.
bi, err := r.Bundle.Instantiate(r.Logger, idLocal)
bi, err := r.Bundle.Instantiate(r.runtimeState.Logger, idLocal)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -203,15 +193,17 @@ func (r *Runner) newVU(idLocal, idGlobal uint64, samplesOut chan<- metrics.Sampl
MaxVersion: uint16(tlsVersions.Max),
Certificates: certs,
Renegotiation: tls.RenegotiateFreelyAsClient,
KeyLogWriter: r.keylogger,
KeyLogWriter: r.runtimeState.KeyLogger,
}
// Follow NameToCertificate in https://pkg.go.dev/crypto/[email protected]#Config, leave this field nil
// when it is empty
if len(nameToCert) > 0 {
nameToCertWarning.Do(func() {
r.Logger.Warn("tlsAuth.domains option could be removed in the next releases, it's recommended to leave it empty " +
"and let k6 automatically detect from the provided certificate. It follows the Go's NameToCertificate " +
"deprecation - https://pkg.go.dev/crypto/[email protected]#Config.")
r.runtimeState.Logger.Warn(
"tlsAuth.domains option could be removed in the next releases, it's recommended to leave it empty " +
"and let k6 automatically detect from the provided certificate. It follows the Go's NameToCertificate " +
"deprecation - https://pkg.go.dev/crypto/[email protected]#Config.",
)
})
//nolint:staticcheck // ignore SA1019 we can deprecate it but we have to continue to support the previous code.
tlsConfig.NameToCertificate = nameToCert
Expand Down Expand Up @@ -254,7 +246,7 @@ func (r *Runner) newVU(idLocal, idGlobal uint64, samplesOut chan<- metrics.Sampl
}

vu.state = &lib.State{
Logger: vu.Runner.Logger,
Logger: vu.Runner.runtimeState.Logger,
Options: vu.Runner.Bundle.Options,
Transport: vu.Transport,
Dialer: vu.Dialer,
Expand All @@ -267,7 +259,7 @@ func (r *Runner) newVU(idLocal, idGlobal uint64, samplesOut chan<- metrics.Sampl
Samples: vu.Samples,
Tags: lib.NewTagMap(vu.Runner.Bundle.Options.RunTags.CloneTags()),
Group: r.defaultGroup,
BuiltinMetrics: r.builtinMetrics,
BuiltinMetrics: r.runtimeState.BuiltinMetrics,
}
vu.moduleVUImpl.state = vu.state
_ = vu.Runtime.Set("console", vu.Console)
Expand Down Expand Up @@ -442,7 +434,7 @@ func (r *Runner) SetOptions(opts lib.Options) error {
// TODO: validate that all exec values are either nil or valid exported methods (or HTTP requests in the future)

if opts.ConsoleOutput.Valid {
c, err := newFileConsole(opts.ConsoleOutput.String, r.Logger.Formatter)
c, err := newFileConsole(opts.ConsoleOutput.String, r.runtimeState.Logger.Formatter)
if err != nil {
return err
}
Expand Down Expand Up @@ -819,7 +811,7 @@ func (u *VU) runFn(

sampleTags := metrics.NewSampleTags(u.state.CloneTags())
u.state.Samples <- u.Dialer.GetTrail(
startTime, endTime, isFullIteration, isDefault, sampleTags, u.Runner.builtinMetrics)
startTime, endTime, isFullIteration, isDefault, sampleTags, u.Runner.runtimeState.BuiltinMetrics)

return v, isFullIteration, endTime.Sub(startTime), err
}
Expand Down
6 changes: 3 additions & 3 deletions js/runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -860,7 +860,7 @@ func TestVUIntegrationInsecureRequests(t *testing.T) {
r := r
t.Run(name, func(t *testing.T) {
t.Parallel()
r.Logger, _ = logtest.NewNullLogger()
r.runtimeState.Logger, _ = logtest.NewNullLogger()

initVU, err := r.NewVU(1, 1, make(chan metrics.SampleContainer, 100))
require.NoError(t, err)
Expand Down Expand Up @@ -1169,7 +1169,7 @@ func TestVUIntegrationTLSConfig(t *testing.T) {
r := r
t.Run(name, func(t *testing.T) {
t.Parallel()
r.Logger, _ = logtest.NewNullLogger()
r.runtimeState.Logger, _ = logtest.NewNullLogger()

initVU, err := r.NewVU(1, 1, make(chan metrics.SampleContainer, 100))
require.NoError(t, err)
Expand Down Expand Up @@ -1596,7 +1596,7 @@ func TestVUIntegrationClientCerts(t *testing.T) {
r := r
t.Run(name, func(t *testing.T) {
t.Parallel()
r.Logger, _ = logtest.NewNullLogger()
r.runtimeState.Logger, _ = logtest.NewNullLogger()
initVU, err := r.NewVU(1, 1, make(chan metrics.SampleContainer, 100))
require.NoError(t, err)
ctx, cancel := context.WithCancel(context.Background())
Expand Down
4 changes: 3 additions & 1 deletion lib/runtime_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,7 @@ type RuntimeState struct {
Registry *metrics.Registry
BuiltinMetrics *metrics.BuiltinMetrics
KeyLogger io.Writer
Logger *logrus.Logger

// TODO: replace with logrus.FieldLogger when all of the tests can be fixed
Logger *logrus.Logger
}