zdravko/pkg/k6/test.go
2024-02-21 14:16:22 +01:00

148 lines
4.3 KiB
Go

package k6
import (
"crypto/x509"
"fmt"
"log/slog"
"time"
"github.com/sirupsen/logrus"
"go.k6.io/k6/errext"
"go.k6.io/k6/errext/exitcodes"
"go.k6.io/k6/js"
"go.k6.io/k6/js/modules"
"go.k6.io/k6/lib"
"go.k6.io/k6/lib/executor"
"go.k6.io/k6/lib/fsext"
"go.k6.io/k6/lib/types"
"go.k6.io/k6/loader"
"go.k6.io/k6/metrics"
)
// loadedTest contains all of data, details and dependencies of a loaded
// k6 test, but without any config consolidation.
type loadedTest struct {
source *loader.SourceData
fs fsext.Fs
fileSystems map[string]fsext.Fs
preInitState *lib.TestPreInitState
initRunner lib.Runner // TODO: rename to something more appropriate
moduleResolver *modules.ModuleResolver
logger *slog.Logger
loggerCompat *logrus.Logger
}
func (lt *loadedTest) initializeFirstRunner() error {
testPath := lt.source.URL.String()
logger := lt.logger.With("test_path", testPath)
logger.Debug("Trying to load as a JS test...")
runner, err := js.New(lt.preInitState, lt.source, lt.fileSystems)
// TODO: should we use common.UnwrapGojaInterruptedError() here?
if err != nil {
return fmt.Errorf("could not load JS test '%s': %w", testPath, err)
}
lt.initRunner = runner
lt.moduleResolver = runner.Bundle.ModuleResolver
return nil
}
func (lt *loadedTest) consolidateDeriveAndValidateConfig() (*loadedAndConfiguredTest, error) {
lt.logger.Debug("Consolidating config layers...")
config := lib.Options{}
config = config.Apply(lt.initRunner.GetOptions())
if config.SystemTags == nil {
config.SystemTags = &metrics.DefaultSystemTagSet
}
if config.SummaryTrendStats == nil {
config.SummaryTrendStats = lib.DefaultSummaryTrendStats
}
defDNS := types.DefaultDNSConfig()
if !config.DNS.TTL.Valid {
config.DNS.TTL = defDNS.TTL
}
if !config.DNS.Select.Valid {
config.DNS.Select = defDNS.Select
}
if !config.DNS.Policy.Valid {
config.DNS.Policy = defDNS.Policy
}
if !config.SetupTimeout.Valid {
config.SetupTimeout.Duration = types.Duration(60 * time.Second)
}
if !config.TeardownTimeout.Valid {
config.TeardownTimeout.Duration = types.Duration(60 * time.Second)
}
lt.logger.Debug("Parsing thresholds and validating config...")
// Parse the thresholds, only if the --no-threshold flag is not set.
// If parsing the threshold expressions failed, consider it as an
// invalid configuration error.
if !lt.preInitState.RuntimeOptions.NoThresholds.Bool {
for metricName, thresholdsDefinition := range config.Thresholds {
err := thresholdsDefinition.Parse()
if err != nil {
return nil, errext.WithExitCodeIfNone(err, exitcodes.InvalidConfig)
}
err = thresholdsDefinition.Validate(metricName, lt.preInitState.Registry)
if err != nil {
return nil, errext.WithExitCodeIfNone(err, exitcodes.InvalidConfig)
}
}
}
config, err := executor.DeriveScenariosFromShortcuts(config, lt.loggerCompat)
if err == nil {
errors := config.Validate()
// FIXME: should show them all.
if len(errors) > 0 {
err = errors[0]
}
}
if err != nil {
return nil, err
}
return &loadedAndConfiguredTest{
loadedTest: lt,
config: config,
}, nil
}
// loadedAndConfiguredTest contains the whole loadedTest, as well as the
// consolidated test config and the full test run state.
type loadedAndConfiguredTest struct {
*loadedTest
config lib.Options
}
// loadSystemCertPool attempts to load system certificates.
func loadSystemCertPool(logger logrus.FieldLogger) {
if _, err := x509.SystemCertPool(); err != nil {
logger.WithError(err).Warning("Unable to load system cert pool")
}
}
func (lct *loadedAndConfiguredTest) buildTestRunState(
configToReinject lib.Options,
) (*lib.TestRunState, error) {
// This might be the full derived or just the consodlidated options
if err := lct.initRunner.SetOptions(configToReinject); err != nil {
return nil, err
}
// it pre-loads system certificates to avoid doing it on the first TLS request.
// This is done async to avoid blocking the rest of the loading process as it will not stop if it fails.
go loadSystemCertPool(lct.preInitState.Logger)
return &lib.TestRunState{
TestPreInitState: lct.preInitState,
Runner: lct.initRunner,
Options: lct.config,
RunTags: lct.preInitState.Registry.RootTagSet().WithTagsFromMap(configToReinject.RunTags),
}, nil
}