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

Fixed Summary Generated Events #3730

Closed
Closed
Show file tree
Hide file tree
Changes from 4 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
7 changes: 6 additions & 1 deletion cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ func (c *cmdRun) run(cmd *cobra.Command, args []string) (err error) {
if !testRunState.RuntimeOptions.NoSummary.Bool {
defer func() {
logger.Debug("Generating the end-of-test summary...")
summaryResult, hsErr := test.initRunner.HandleSummary(globalCtx, &lib.Summary{
summaryResult, summaryJs, hsErr := test.initRunner.HandleSummary(globalCtx, &lib.Summary{
Metrics: metricsEngine.ObservedMetrics,
RootGroup: testRunState.Runner.GetDefaultGroup(),
TestRunDuration: executionState.GetCurrentTestRunDuration(),
Expand All @@ -202,6 +202,11 @@ func (c *cmdRun) run(cmd *cobra.Command, args []string) (err error) {
})
if hsErr == nil {
hsErr = handleSummaryResult(c.gs.FS, c.gs.Stdout, c.gs.Stderr, summaryResult)
waitForSummaryGeneratedEvent := emitEvent(&event.Event{
Type: event.TestSummaryGenerated,
Data: &event.SummaryData{Summary: summaryJs},
})
waitForSummaryGeneratedEvent()
}
if hsErr != nil {
logger.WithError(hsErr).Error("failed to handle the end-of-test summary")
Expand Down
3 changes: 3 additions & 0 deletions cmd/tests/cmd_run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2073,6 +2073,7 @@ func TestEventSystemOK(t *testing.T) {
`got event IterStart with data '{Iteration:4 VUID:1 ScenarioName:default Error:<nil>}'`,
`got event IterEnd with data '{Iteration:4 VUID:1 ScenarioName:default Error:<nil>}'`,
`got event TestEnd with data '<nil>'`,
`got event TestSummaryGenerated with data '&{Summary:map[...]...}'`,
`got event Exit with data '&{Error:<nil>}'`,
}
log := ts.LoggerHook.Lines()
Expand Down Expand Up @@ -2107,6 +2108,7 @@ func TestEventSystemError(t *testing.T) {
"got event IterStart with data '{Iteration:0 VUID:1 ScenarioName:default Error:<nil>}'",
"got event IterEnd with data '{Iteration:0 VUID:1 ScenarioName:default Error:test aborted: oops! at file:///-:11:16(6)}'",
"got event TestEnd with data '<nil>'",
"got event TestSummaryGenerated with data '&{Summary:map[...]...}'",
"got event Exit with data '&{Error:test aborted: oops! at file:///-:11:16(6)}'",
"test aborted: oops! at file:///-:11:16(6)",
},
Expand Down Expand Up @@ -2143,6 +2145,7 @@ func TestEventSystemError(t *testing.T) {
"got event IterEnd with data '{Iteration:1 VUID:1 ScenarioName:default Error:Error: oops!\n\tat file:///-:9:11(3)\n}'",
"Error: oops!\n\tat file:///-:9:11(3)\n",
"got event TestEnd with data '<nil>'",
"got event TestSummaryGenerated with data '&{Summary:map[...]...}'",
"got event Exit with data '&{Error:<nil>}'",
},
expExitCode: 0,
Expand Down
14 changes: 13 additions & 1 deletion event/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ const (
IterEnd
// Exit is emitted when the k6 process is about to exit.
Exit
// TestSummaryGenerated is emitted when the summary is generated.
TestSummaryGenerated
)

//nolint:gochecknoglobals
var (
// GlobalEvents are emitted once per test run.
GlobalEvents = []Type{Init, TestStart, TestEnd, Exit}
GlobalEvents = []Type{Init, TestStart, TestEnd, TestSummaryGenerated, Exit}
// VUEvents are emitted multiple times per each VU.
VUEvents = []Type{IterStart, IterEnd}
)
Expand All @@ -41,3 +43,13 @@ type IterData struct {
ScenarioName string
Error error
}

// SummaryData is the data sent in the TestSummaryGenerated event.
type SummaryData struct {
Summary map[string]interface{}
}

// String Overiding for tests
func (s *SummaryData) String() string {
return "&{Summary:map[...]...}"
}
7 changes: 4 additions & 3 deletions event/type_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 11 additions & 8 deletions js/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,9 @@ func (r *Runner) IsExecutable(name string) bool {
}

// HandleSummary calls the specified summary callback, if supplied.
func (r *Runner) HandleSummary(ctx context.Context, summary *lib.Summary) (map[string]io.Reader, error) {
func (r *Runner) HandleSummary(ctx context.Context, summary *lib.Summary) (
map[string]io.Reader, map[string]interface{}, error,
) {
summaryDataForJS := summarizeMetricsToObject(summary, r.Bundle.Options, r.setupData)

out := make(chan metrics.SampleContainer, 100)
Expand All @@ -378,7 +380,7 @@ func (r *Runner) HandleSummary(ctx context.Context, summary *lib.Summary) (map[s

vu, err := r.newVU(summaryCtx, 0, 0, out)
if err != nil {
return nil, err
return nil, nil, err
}

go func() {
Expand All @@ -392,7 +394,7 @@ func (r *Runner) HandleSummary(ctx context.Context, summary *lib.Summary) (map[s
if fn != nil {
handleSummaryFn, ok := goja.AssertFunction(fn)
if !ok {
return nil, fmt.Errorf("exported identifier %s must be a function", consts.HandleSummaryFn)
return nil, nil, fmt.Errorf("exported identifier %s must be a function", consts.HandleSummaryFn)
}

callbackResult, _, _, err = vu.runFn(summaryCtx, false, handleSummaryFn, nil, vu.Runtime.ToValue(summaryDataForJS))
Expand All @@ -405,11 +407,11 @@ func (r *Runner) HandleSummary(ctx context.Context, summary *lib.Summary) (map[s
wrapper := strings.Replace(summaryWrapperLambdaCode, "/*JSLIB_SUMMARY_CODE*/", jslibSummaryCode, 1)
handleSummaryWrapperRaw, err := vu.Runtime.RunString(wrapper)
if err != nil {
return nil, fmt.Errorf("unexpected error while getting the summary wrapper: %w", err)
return nil, nil, fmt.Errorf("unexpected error while getting the summary wrapper: %w", err)
}
handleSummaryWrapper, ok := goja.AssertFunction(handleSummaryWrapperRaw)
if !ok {
return nil, fmt.Errorf("unexpected error did not get a callable summary wrapper")
return nil, nil, fmt.Errorf("unexpected error did not get a callable summary wrapper")
}

wrapperArgs := []goja.Value{
Expand All @@ -420,13 +422,14 @@ func (r *Runner) HandleSummary(ctx context.Context, summary *lib.Summary) (map[s
rawResult, _, _, err := vu.runFn(summaryCtx, false, handleSummaryWrapper, nil, wrapperArgs...)

if deadlineError := r.checkDeadline(summaryCtx, consts.HandleSummaryFn, rawResult, err); deadlineError != nil {
return nil, deadlineError
return nil, nil, deadlineError
}

if err != nil {
return nil, fmt.Errorf("unexpected error while generating the summary: %w", err)
return nil, nil, fmt.Errorf("unexpected error while generating the summary: %w", err)
}
return getSummaryResult(rawResult)
res, err := getSummaryResult(rawResult)
return res, summaryDataForJS, err
}

func (r *Runner) checkDeadline(ctx context.Context, name string, result goja.Value, err error) error {
Expand Down
16 changes: 8 additions & 8 deletions js/summary_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func TestTextSummary(t *testing.T) {
)
require.NoError(t, err)

result, err := runner.HandleSummary(context.Background(), summary)
result, _, err := runner.HandleSummary(context.Background(), summary)
require.NoError(t, err)

require.Len(t, result, 1)
Expand Down Expand Up @@ -116,7 +116,7 @@ func TestTextSummaryWithSubMetrics(t *testing.T) {
)
require.NoError(t, err)

result, err := runner.HandleSummary(context.Background(), summary)
result, _, err := runner.HandleSummary(context.Background(), summary)
require.NoError(t, err)

require.Len(t, result, 1)
Expand Down Expand Up @@ -307,7 +307,7 @@ func TestOldJSONExport(t *testing.T) {
require.NoError(t, err)

summary := createTestSummary(t)
result, err := runner.HandleSummary(context.Background(), summary)
result, _, err := runner.HandleSummary(context.Background(), summary)
require.NoError(t, err)

require.Len(t, result, 2)
Expand Down Expand Up @@ -577,7 +577,7 @@ func TestRawHandleSummaryData(t *testing.T) {
require.NoError(t, err)

summary := createTestSummary(t)
result, err := runner.HandleSummary(context.Background(), summary)
result, _, err := runner.HandleSummary(context.Background(), summary)
require.NoError(t, err)

require.Len(t, result, 2)
Expand Down Expand Up @@ -612,7 +612,7 @@ func TestRawHandleSummaryDataWithSetupData(t *testing.T) {
runner.SetSetupData([]byte("5"))

summary := createTestSummary(t)
result, err := runner.HandleSummary(context.Background(), summary)
result, _, err := runner.HandleSummary(context.Background(), summary)
require.NoError(t, err)
dataWithSetup, err := io.ReadAll(result["dataWithSetup.json"])
require.NoError(t, err)
Expand All @@ -635,7 +635,7 @@ func TestRawHandleSummaryPromise(t *testing.T) {
runner.SetSetupData([]byte("5"))

summary := createTestSummary(t)
result, err := runner.HandleSummary(context.Background(), summary)
result, _, err := runner.HandleSummary(context.Background(), summary)
require.NoError(t, err)
dataWithSetup, err := io.ReadAll(result["dataWithSetup.json"])
require.NoError(t, err)
Expand All @@ -660,7 +660,7 @@ func TestWrongSummaryHandlerExportTypes(t *testing.T) {
require.NoError(t, err)

summary := createTestSummary(t)
_, err = runner.HandleSummary(context.Background(), summary)
_, _, err = runner.HandleSummary(context.Background(), summary)
require.Error(t, err)
})
}
Expand All @@ -685,7 +685,7 @@ func TestExceptionInHandleSummaryFallsBackToTextSummary(t *testing.T) {
require.NoError(t, err)

summary := createTestSummary(t)
result, err := runner.HandleSummary(context.Background(), summary)
result, _, err := runner.HandleSummary(context.Background(), summary)
require.NoError(t, err)

require.Len(t, result, 1)
Expand Down
2 changes: 1 addition & 1 deletion lib/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ type Runner interface {
// function in the script.
IsExecutable(string) bool

HandleSummary(context.Context, *Summary) (map[string]io.Reader, error)
HandleSummary(context.Context, *Summary) (map[string]io.Reader, map[string]interface{}, error)
}

// UIState describes the state of the UI, which might influence what
Expand Down
8 changes: 5 additions & 3 deletions lib/testutils/minirunner/minirunner.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ type MiniRunner struct {
Fn func(ctx context.Context, state *lib.State, out chan<- metrics.SampleContainer) error
SetupFn func(ctx context.Context, out chan<- metrics.SampleContainer) ([]byte, error)
TeardownFn func(ctx context.Context, out chan<- metrics.SampleContainer) error
HandleSummaryFn func(context.Context, *lib.Summary) (map[string]io.Reader, error)
HandleSummaryFn func(context.Context, *lib.Summary) (map[string]io.Reader, map[string]interface{}, error)

SetupData []byte

Expand Down Expand Up @@ -117,11 +117,13 @@ func (r *MiniRunner) SetOptions(opts lib.Options) error {
}

// HandleSummary calls the specified summary callback, if supplied.
func (r *MiniRunner) HandleSummary(ctx context.Context, s *lib.Summary) (map[string]io.Reader, error) {
func (r *MiniRunner) HandleSummary(ctx context.Context, s *lib.Summary) (
map[string]io.Reader, map[string]interface{}, error,
) {
if r.HandleSummaryFn != nil {
return r.HandleSummaryFn(ctx, s)
}
return nil, nil //nolint:nilnil
return nil, nil, nil //nolint:nilnilnil
}

// VU is a mock VU, spawned by a MiniRunner.
Expand Down
Loading