Skip to content
Open
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
14 changes: 9 additions & 5 deletions internal/benchrunner/runners/rally/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -924,17 +924,21 @@ func (r *runner) runRally(ctx context.Context) ([]rallyStat, error) {
if err != nil {
return nil, fmt.Errorf("could not open esrally report in path: %s: %w", r.svcInfo.Logs.Folder.Local, err)
}
defer reportCSV.Close()

reader := csv.NewReader(reportCSV)
return parseRallyReport(reportCSV, r.svcInfo.Logs.Folder.Local, errOutput.String())
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The defer should rather be placed in the same method that opens the file. This avoids introducing an unexpected side effect in the function that just parses what is in the reader.

Suggested change
return parseRallyReport(reportCSV, r.svcInfo.Logs.Folder.Local, errOutput.String())
defer reportCSV.Close()
return parseRallyReport(reportCSV, r.svcInfo.Logs.Folder.Local, errOutput.String())

Copy link
Copy Markdown
Author

@buley buley Mar 27, 2026

Choose a reason for hiding this comment

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

Thanks for the suggestion @jsoriano. I moved defer reportCSV.Close() back into runRally immediately after os.Open, so the function that opens the file also owns closing it. parseRallyReport now takes an io.Reader and only parses the CSV, which removes the side effect you called out. I also updated the test to verify parser output rather than close behavior.

}

func parseRallyReport(report io.Reader, logsPath string, stderr string) ([]rallyStat, error) {
reader := csv.NewReader(report)
stats := make([]rallyStat, 0)
for {
record, err := reader.Read()
if err == io.EOF {
record, readErr := reader.Read()
if readErr == io.EOF {
break
}
if err != nil {
return nil, fmt.Errorf("could not read esrally report in path: %s (stderr=%q): %w", r.svcInfo.Logs.Folder.Local, errOutput.String(), err)
if readErr != nil {
return nil, fmt.Errorf("could not read esrally report in path: %s (stderr=%q): %w", logsPath, stderr, readErr)
}

stats = append(stats, rallyStat{Metric: record[0], Task: record[1], Value: record[2], Unit: record[3]})
Expand Down
24 changes: 24 additions & 0 deletions internal/benchrunner/runners/rally/runner_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package rally

import (
"strings"
"testing"
)

func TestParseRallyReportReturnsStats(t *testing.T) {
stats, err := parseRallyReport(strings.NewReader("metric,task,value,unit\n"), "/tmp/rally", "")
if err != nil {
t.Fatalf("parseRallyReport returned error: %v", err)
}
if len(stats) != 1 {
t.Fatalf("expected 1 stat, got %d", len(stats))
}
if stats[0] != (rallyStat{
Metric: "metric",
Task: "task",
Value: "value",
Unit: "unit",
}) {
t.Fatalf("unexpected stat: %#v", stats[0])
}
}