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

Refactor group and check to not be tightly coupled #3750

Merged
merged 4 commits into from
May 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions api/v1/group_routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
)

func handleGetGroups(cs *ControlSurface, rw http.ResponseWriter, _ *http.Request) {
root := NewGroup(cs.RunState.Runner.GetDefaultGroup(), nil)
root := NewGroup(cs.RunState.GroupSummary.Group(), nil)
groups := FlattenGroup(root)

data, err := json.Marshal(newGroupsJSONAPI(groups))
Expand All @@ -18,7 +18,7 @@ func handleGetGroups(cs *ControlSurface, rw http.ResponseWriter, _ *http.Request
}

func handleGetGroup(cs *ControlSurface, rw http.ResponseWriter, _ *http.Request, id string) {
root := NewGroup(cs.RunState.Runner.GetDefaultGroup(), nil)
root := NewGroup(cs.RunState.GroupSummary.Group(), nil)
groups := FlattenGroup(root)

var group *Group
Expand Down
27 changes: 25 additions & 2 deletions api/v1/group_routes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ func getTestRunState(tb testing.TB, options lib.Options, runner lib.Runner) *lib
TestPreInitState: piState,
Options: options,
Runner: runner,
GroupSummary: lib.NewGroupSummary(piState.Logger),
RunTags: piState.Registry.RootTagSet().WithTagsFromMap(options.RunTags),
}
}
Expand Down Expand Up @@ -64,15 +65,37 @@ func getControlSurface(tb testing.TB, testState *lib.TestRunState) *ControlSurfa
func TestGetGroups(t *testing.T) {
t.Parallel()

cs := getControlSurface(t, getTestRunState(t, lib.Options{}, &minirunner.MiniRunner{}))
require.NoError(t, cs.RunState.GroupSummary.Start())
cs.RunState.GroupSummary.AddMetricSamples([]metrics.SampleContainer{
metrics.Sample{
TimeSeries: metrics.TimeSeries{
Metric: cs.RunState.BuiltinMetrics.GroupDuration,
Tags: cs.RunState.Registry.RootTagSet().With("group", "::group 1"),
},
},
metrics.Sample{
TimeSeries: metrics.TimeSeries{
Metric: cs.RunState.BuiltinMetrics.GroupDuration,
Tags: cs.RunState.Registry.RootTagSet().With("group", ""),
},
},
metrics.Sample{
TimeSeries: metrics.TimeSeries{
Metric: cs.RunState.BuiltinMetrics.GroupDuration,
Tags: cs.RunState.Registry.RootTagSet().With("group", "::group 1::group 2"),
},
},
})
require.NoError(t, cs.RunState.GroupSummary.Stop())

g0, err := lib.NewGroup("", nil)
assert.NoError(t, err)
g1, err := g0.Group("group 1")
assert.NoError(t, err)
g2, err := g1.Group("group 2")
assert.NoError(t, err)

cs := getControlSurface(t, getTestRunState(t, lib.Options{}, &minirunner.MiniRunner{Group: g0}))

t.Run("list", func(t *testing.T) {
t.Parallel()

Expand Down
4 changes: 3 additions & 1 deletion cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ func (c *cmdRun) run(cmd *cobra.Command, args []string) (err error) {
return err
}

outputs = append(outputs, testRunState.GroupSummary)

metricsEngine, err := engine.NewMetricsEngine(testRunState.Registry, logger)
if err != nil {
return err
Expand Down Expand Up @@ -192,7 +194,7 @@ func (c *cmdRun) run(cmd *cobra.Command, args []string) (err error) {
logger.Debug("Generating the end-of-test summary...")
summaryResult, hsErr := test.initRunner.HandleSummary(globalCtx, &lib.Summary{
Metrics: metricsEngine.ObservedMetrics,
RootGroup: testRunState.Runner.GetDefaultGroup(),
RootGroup: testRunState.GroupSummary.Group(),
TestRunDuration: executionState.GetCurrentTestRunDuration(),
NoColor: c.gs.Flags.NoColor,
UIState: lib.UIState{
Expand Down
1 change: 1 addition & 0 deletions cmd/test_load.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ func (lct *loadedAndConfiguredTest) buildTestRunState(
Runner: lct.initRunner,
Options: lct.derivedConfig.Options, // we will always run with the derived options
RunTags: lct.preInitState.Registry.RootTagSet().WithTagsFromMap(configToReinject.RunTags),
GroupSummary: lib.NewGroupSummary(lct.preInitState.Logger),
}, nil
}

Expand Down
3 changes: 2 additions & 1 deletion cmd/ui.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ func printExecutionDescription(
default:
for _, out := range outputs {
desc := out.Description()
if desc == engine.IngesterDescription {
switch desc {
case engine.IngesterDescription, lib.GroupSummaryDescription:
continue
}
if strings.HasPrefix(desc, dashboard.OutputName) {
Expand Down
8 changes: 0 additions & 8 deletions js/initcontext_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,9 +342,6 @@ func TestRequestWithBinaryFile(t *testing.T) {
bi, err := b.Instantiate(context.Background(), 0)
require.NoError(t, err)

root, err := lib.NewGroup("", nil)
require.NoError(t, err)

logger := logrus.New()
logger.Level = logrus.DebugLevel
logger.Out = io.Discard
Expand All @@ -354,7 +351,6 @@ func TestRequestWithBinaryFile(t *testing.T) {
bi.moduleVUImpl.state = &lib.State{
Options: lib.Options{},
Logger: logger,
Group: root,
Transport: &http.Transport{
DialContext: (netext.NewDialer(
net.Dialer{
Expand Down Expand Up @@ -488,9 +484,6 @@ func TestRequestWithMultipleBinaryFiles(t *testing.T) {
bi, err := b.Instantiate(context.Background(), 0)
require.NoError(t, err)

root, err := lib.NewGroup("", nil)
require.NoError(t, err)

logger := logrus.New()
logger.Level = logrus.DebugLevel
logger.Out = io.Discard
Expand All @@ -500,7 +493,6 @@ func TestRequestWithMultipleBinaryFiles(t *testing.T) {
bi.moduleVUImpl.state = &lib.State{
Options: lib.Options{},
Logger: logger,
Group: root,
Transport: &http.Transport{
DialContext: (netext.NewDialer(
net.Dialer{
Expand Down
5 changes: 1 addition & 4 deletions js/modules/k6/grpc/params_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,15 +148,12 @@ func newParamsTestRuntime(t *testing.T, paramsJSON string) (*modulestest.Runtime

testRuntime := modulestest.NewRuntime(t)
registry := metrics.NewRegistry()
root, err := lib.NewGroup("", nil)
require.NoError(t, err)

logger := logrus.New()
logger.SetLevel(logrus.InfoLevel)
logger.Out = io.Discard

state := &lib.State{
Group: root,
Options: lib.Options{
SystemTags: metrics.NewSystemTagSet(
metrics.TagName,
Expand All @@ -171,7 +168,7 @@ func newParamsTestRuntime(t *testing.T, paramsJSON string) (*modulestest.Runtime

testRuntime.MoveToVUContext(state)

_, err = testRuntime.VU.Runtime().RunString(`let params = ` + paramsJSON + `;`)
_, err := testRuntime.VU.Runtime().RunString(`let params = ` + paramsJSON + `;`)
require.NoError(t, err)

params := testRuntime.VU.Runtime().Get("params")
Expand Down
5 changes: 0 additions & 5 deletions js/modules/k6/grpc/teststate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,13 +142,8 @@ func newTestState(t *testing.T) testState {
// ToVUContext moves the test state to the VU context.
func (ts *testState) ToVUContext() {
registry := metrics.NewRegistry()
root, err := lib.NewGroup("", nil)
if err != nil {
panic(err)
}

state := &lib.State{
Group: root,
Dialer: ts.httpBin.Dialer,
TLSConfig: ts.httpBin.TLSClientConfig,
Samples: ts.samples,
Expand Down
5 changes: 1 addition & 4 deletions js/modules/k6/http/request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,6 @@ type httpTestCase struct {
func newTestCase(t testing.TB) *httpTestCase {
tb := httpmultibin.NewHTTPMultiBin(t)

root, err := lib.NewGroup("", nil)
require.NoError(t, err)
registry := metrics.NewRegistry()

logger := logrus.New()
Expand All @@ -152,13 +150,12 @@ func newTestCase(t testing.TB) *httpTestCase {
state := &lib.State{
Options: options,
Logger: logger,
Group: root,
TLSConfig: tb.TLSClientConfig,
Transport: tb.HTTPTransport,
BufferPool: lib.NewBufferPool(),
Samples: samples,
Tags: lib.NewVUStateTags(registry.RootTagSet().WithTagsFromMap(map[string]string{
"group": root.Path,
"group": lib.RootGroupPath,
})),
BuiltinMetrics: metrics.RegisterBuiltinMetrics(registry),
}
Expand Down
11 changes: 4 additions & 7 deletions js/modules/k6/http/response_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.k6.io/k6/lib"
"go.k6.io/k6/metrics"
)

Expand Down Expand Up @@ -109,7 +110,6 @@ func TestResponse(t *testing.T) {
samples := ts.samples
rt := ts.runtime.VU.Runtime()
state := ts.runtime.VU.State()
root := state.Group
sr := tb.Replacer.Replace

tb.Mux.HandleFunc("/myforms/get", myFormHandler)
Expand Down Expand Up @@ -147,17 +147,14 @@ func TestResponse(t *testing.T) {
})

t.Run("group", func(t *testing.T) {
g, err := root.Group("my group")
groupName, err := lib.NewGroupPath(lib.RootGroupPath, "my group")
require.NoError(t, err)
old := state.Group
state.Group = g
state.Tags.Modify(func(tagsAndMeta *metrics.TagsAndMeta) {
tagsAndMeta.SetTag("group", g.Path)
tagsAndMeta.SetTag("group", groupName)
})
defer func() {
state.Group = old
state.Tags.Modify(func(tagsAndMeta *metrics.TagsAndMeta) {
tagsAndMeta.SetTag("group", old.Path)
tagsAndMeta.SetTag("group", "")
})
}()

Expand Down
61 changes: 23 additions & 38 deletions js/modules/k6/k6.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ import (
"errors"
"fmt"
"math/rand"
"sync/atomic"
"strings"
"time"

"github.com/dop251/goja"

"go.k6.io/k6/js/common"
"go.k6.io/k6/js/modules"
"go.k6.io/k6/lib"
"go.k6.io/k6/metrics"
)

Expand Down Expand Up @@ -105,25 +106,23 @@ func (mi *K6) Group(name string, val goja.Value) (goja.Value, error) {
if common.IsAsyncFunction(mi.vu.Runtime(), val) {
return goja.Undefined(), fmt.Errorf(asyncFunctionNotSupportedMsg, "group")
}
g, err := state.Group.Group(name)
oldGroupName, _ := state.Tags.GetCurrentValues().Tags.Get(metrics.TagGroup.String())
// TODO: what are we doing if group is not tagged
newGroupName, err := lib.NewGroupPath(oldGroupName, name)
if err != nil {
return goja.Undefined(), err
}

old := state.Group
state.Group = g

shouldUpdateTag := state.Options.SystemTags.Has(metrics.TagGroup)
if shouldUpdateTag {
state.Tags.Modify(func(tagsAndMeta *metrics.TagsAndMeta) {
tagsAndMeta.SetSystemTagOrMeta(metrics.TagGroup, g.Path)
tagsAndMeta.SetSystemTagOrMeta(metrics.TagGroup, newGroupName)
})
}
defer func() {
state.Group = old
if shouldUpdateTag {
state.Tags.Modify(func(tagsAndMeta *metrics.TagsAndMeta) {
tagsAndMeta.SetSystemTagOrMeta(metrics.TagGroup, old.Path)
tagsAndMeta.SetSystemTagOrMeta(metrics.TagGroup, oldGroupName)
})
}
}()
Expand All @@ -148,8 +147,6 @@ func (mi *K6) Group(name string, val goja.Value) (goja.Value, error) {
}

// Check will emit check metrics for the provided checks.
//
//nolint:funlen
func (mi *K6) Check(arg0, checks goja.Value, extras ...goja.Value) (bool, error) {
state := mi.vu.State()
if state == nil {
Expand All @@ -174,17 +171,14 @@ func (mi *K6) Check(arg0, checks goja.Value, extras ...goja.Value) (bool, error)
var exc error
obj := checks.ToObject(rt)
for _, name := range obj.Keys() {
val := obj.Get(name)

// Resolve the check record.
check, err := state.Group.Check(name)
if err != nil {
return false, err
if strings.Contains(name, lib.GroupSeparator) {
return false, lib.ErrNameContainsGroupSeparator
}
val := obj.Get(name)

tags := commonTagsAndMeta.Tags
if state.Options.SystemTags.Has(metrics.TagCheck) {
tags = tags.With("check", check.Name)
tags = tags.With("check", name)
}

if common.IsAsyncFunction(rt, val) {
Expand All @@ -207,28 +201,19 @@ func (mi *K6) Check(arg0, checks goja.Value, extras ...goja.Value) (bool, error)
succ = false
}

// Emit! (But only if we have a valid context.)
select {
case <-ctx.Done():
default:
sample := metrics.Sample{
TimeSeries: metrics.TimeSeries{
Metric: state.BuiltinMetrics.Checks,
Tags: tags,
},
Time: t,
Metadata: commonTagsAndMeta.Metadata,
Value: 0,
}
if booleanVal {
atomic.AddInt64(&check.Passes, 1)
sample.Value = 1
} else {
atomic.AddInt64(&check.Fails, 1)
}

metrics.PushIfNotDone(ctx, state.Samples, sample)
sample := metrics.Sample{
TimeSeries: metrics.TimeSeries{
Metric: state.BuiltinMetrics.Checks,
Tags: tags,
},
Time: t,
Metadata: commonTagsAndMeta.Metadata,
}
if booleanVal {
sample.Value = 1
}

metrics.PushIfNotDone(ctx, state.Samples, sample)

if exc != nil {
return false, exc
Expand Down
Loading