Skip to content

Commit 7537b92

Browse files
author
Renato Costa
committed
roachtest/mixedversion: move helper functions to its own file
This makes it easier for test authors to see all helper functions available without having to browse through internal framework code. Epic: CRDB-19321 Release note: None
1 parent f75ebe7 commit 7537b92

File tree

3 files changed

+135
-111
lines changed

3 files changed

+135
-111
lines changed

pkg/cmd/roachtest/roachtestutil/mixedversion/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
33
go_library(
44
name = "mixedversion",
55
srcs = [
6+
"helper.go",
67
"mixedversion.go",
78
"planner.go",
89
"runner.go",
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
// Copyright 2023 The Cockroach Authors.
2+
//
3+
// Use of this software is governed by the Business Source License
4+
// included in the file licenses/BSL.txt.
5+
//
6+
// As of the Change Date specified in that file, in accordance with
7+
// the Business Source License, use of this software will be governed
8+
// by the Apache License, Version 2.0, included in the file
9+
// licenses/APL.txt.
10+
11+
package mixedversion
12+
13+
import (
14+
"context"
15+
gosql "database/sql"
16+
"fmt"
17+
"math/rand"
18+
"path"
19+
"strings"
20+
"sync/atomic"
21+
22+
"github.com/cockroachdb/cockroach/pkg/cmd/roachtest/option"
23+
"github.com/cockroachdb/cockroach/pkg/roachprod/logger"
24+
)
25+
26+
func (h *Helper) RandomNode(prng *rand.Rand, nodes option.NodeListOption) int {
27+
return nodes[prng.Intn(len(nodes))]
28+
}
29+
30+
// RandomDB returns a (nodeID, connection) tuple for a randomly picked
31+
// cockroach node according to the parameters passed.
32+
func (h *Helper) RandomDB(prng *rand.Rand, nodes option.NodeListOption) (int, *gosql.DB) {
33+
node := h.RandomNode(prng, nodes)
34+
return node, h.Connect(node)
35+
}
36+
37+
// QueryRow performs `db.QueryRowContext` on a randomly picked
38+
// database node. The query and the node picked are logged in the logs
39+
// of the step that calls this function.
40+
func (h *Helper) QueryRow(rng *rand.Rand, query string, args ...interface{}) *gosql.Row {
41+
node, db := h.RandomDB(rng, h.runner.crdbNodes)
42+
h.stepLogger.Printf("running SQL statement:\n%s\nArgs: %v\nNode: %d", query, args, node)
43+
return db.QueryRowContext(h.ctx, query, args...)
44+
}
45+
46+
// Exec performs `db.ExecContext` on a randomly picked database node.
47+
// The query and the node picked are logged in the logs of the step
48+
// that calls this function.
49+
func (h *Helper) Exec(rng *rand.Rand, query string, args ...interface{}) error {
50+
node, db := h.RandomDB(rng, h.runner.crdbNodes)
51+
h.stepLogger.Printf("running SQL statement:\n%s\nArgs: %v\nNode: %d", query, args, node)
52+
_, err := db.ExecContext(h.ctx, query, args...)
53+
return err
54+
}
55+
56+
func (h *Helper) Connect(node int) *gosql.DB {
57+
return h.runner.conn(node)
58+
}
59+
60+
// SetContext should be called by steps that need access to the test
61+
// context, as that is only visible to them.
62+
func (h *Helper) SetContext(c *Context) {
63+
h.testContext = c
64+
}
65+
66+
// Context returns the test context associated with a certain step. It
67+
// is made available for user-functions (see runHookStep).
68+
func (h *Helper) Context() *Context {
69+
return h.testContext
70+
}
71+
72+
// Background allows test authors to create functions that run in the
73+
// background in mixed-version hooks.
74+
func (h *Helper) Background(
75+
name string, fn func(context.Context, *logger.Logger) error,
76+
) context.CancelFunc {
77+
return h.runner.background.Start(name, func(ctx context.Context) error {
78+
bgLogger, err := h.loggerFor(name)
79+
if err != nil {
80+
return fmt.Errorf("failed to create logger for background function %q: %w", name, err)
81+
}
82+
83+
err = panicAsError(bgLogger, func() error { return fn(ctx, bgLogger) })
84+
if err != nil {
85+
if isContextCanceled(ctx) {
86+
return err
87+
}
88+
89+
desc := fmt.Sprintf("error in background function %s: %s", name, err)
90+
return h.runner.testFailure(desc, bgLogger)
91+
}
92+
93+
return nil
94+
})
95+
}
96+
97+
// BackgroundCommand has the same semantics of `Background()`; the
98+
// command passed will run and the test will fail if the command is
99+
// not successful.
100+
func (h *Helper) BackgroundCommand(cmd string, nodes option.NodeListOption) context.CancelFunc {
101+
desc := fmt.Sprintf("run command: %q", cmd)
102+
return h.Background(desc, func(ctx context.Context, l *logger.Logger) error {
103+
l.Printf("running command `%s` on nodes %v in the background", cmd, nodes)
104+
return h.runner.cluster.RunE(ctx, nodes, cmd)
105+
})
106+
}
107+
108+
// ExpectDeath alerts the testing infrastructure that a node is
109+
// expected to die. Regular restarts as part of the mixedversion
110+
// testing are already taken into account. This function should only
111+
// be used by tests that perform their own node restarts or chaos
112+
// events.
113+
func (h *Helper) ExpectDeath() {
114+
h.ExpectDeaths(1)
115+
}
116+
117+
// ExpectDeaths is the general version of `ExpectDeath()`.
118+
func (h *Helper) ExpectDeaths(n int) {
119+
h.runner.monitor.ExpectDeaths(n)
120+
}
121+
122+
// loggerFor creates a logger instance to be used by background
123+
// functions (created by calling `Background` on the helper
124+
// instance). It is similar to the logger instances created for
125+
// mixed-version steps, but with the `background_` prefix.
126+
func (h *Helper) loggerFor(name string) (*logger.Logger, error) {
127+
atomic.AddInt64(&h.bgCount, 1)
128+
129+
fileName := invalidChars.ReplaceAllString(strings.ToLower(name), "")
130+
fileName = fmt.Sprintf("background_%s_%d", fileName, h.bgCount)
131+
fileName = path.Join(logPrefix, fileName)
132+
133+
return prefixedLogger(h.runner.logger, fileName)
134+
}

pkg/cmd/roachtest/roachtestutil/mixedversion/runner.go

Lines changed: 0 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import (
1414
"context"
1515
gosql "database/sql"
1616
"fmt"
17-
"math/rand"
1817
"os"
1918
"path"
2019
"path/filepath"
@@ -603,116 +602,6 @@ func (br *backgroundRunner) CompletedEvents() <-chan backgroundEvent {
603602
return br.events
604603
}
605604

606-
func (h *Helper) RandomNode(prng *rand.Rand, nodes option.NodeListOption) int {
607-
return nodes[prng.Intn(len(nodes))]
608-
}
609-
610-
// RandomDB returns a (nodeID, connection) tuple for a randomly picked
611-
// cockroach node according to the parameters passed.
612-
func (h *Helper) RandomDB(prng *rand.Rand, nodes option.NodeListOption) (int, *gosql.DB) {
613-
node := h.RandomNode(prng, nodes)
614-
return node, h.Connect(node)
615-
}
616-
617-
// QueryRow performs `db.QueryRowContext` on a randomly picked
618-
// database node. The query and the node picked are logged in the logs
619-
// of the step that calls this function.
620-
func (h *Helper) QueryRow(rng *rand.Rand, query string, args ...interface{}) *gosql.Row {
621-
node, db := h.RandomDB(rng, h.runner.crdbNodes)
622-
h.stepLogger.Printf("running SQL statement:\n%s\nArgs: %v\nNode: %d", query, args, node)
623-
return db.QueryRowContext(h.ctx, query, args...)
624-
}
625-
626-
// Exec performs `db.ExecContext` on a randomly picked database node.
627-
// The query and the node picked are logged in the logs of the step
628-
// that calls this function.
629-
func (h *Helper) Exec(rng *rand.Rand, query string, args ...interface{}) error {
630-
node, db := h.RandomDB(rng, h.runner.crdbNodes)
631-
h.stepLogger.Printf("running SQL statement:\n%s\nArgs: %v\nNode: %d", query, args, node)
632-
_, err := db.ExecContext(h.ctx, query, args...)
633-
return err
634-
}
635-
636-
func (h *Helper) Connect(node int) *gosql.DB {
637-
return h.runner.conn(node)
638-
}
639-
640-
// SetContext should be called by steps that need access to the test
641-
// context, as that is only visible to them.
642-
func (h *Helper) SetContext(c *Context) {
643-
h.testContext = c
644-
}
645-
646-
// Context returns the test context associated with a certain step. It
647-
// is made available for user-functions (see runHookStep).
648-
func (h *Helper) Context() *Context {
649-
return h.testContext
650-
}
651-
652-
// Background allows test authors to create functions that run in the
653-
// background in mixed-version hooks.
654-
func (h *Helper) Background(
655-
name string, fn func(context.Context, *logger.Logger) error,
656-
) context.CancelFunc {
657-
return h.runner.background.Start(name, func(ctx context.Context) error {
658-
bgLogger, err := h.loggerFor(name)
659-
if err != nil {
660-
return fmt.Errorf("failed to create logger for background function %q: %w", name, err)
661-
}
662-
663-
err = panicAsError(bgLogger, func() error { return fn(ctx, bgLogger) })
664-
if err != nil {
665-
if isContextCanceled(ctx) {
666-
return err
667-
}
668-
669-
desc := fmt.Sprintf("error in background function %s: %s", name, err)
670-
return h.runner.testFailure(desc, bgLogger)
671-
}
672-
673-
return nil
674-
})
675-
}
676-
677-
// BackgroundCommand has the same semantics of `Background()`; the
678-
// command passed will run and the test will fail if the command is
679-
// not successful.
680-
func (h *Helper) BackgroundCommand(cmd string, nodes option.NodeListOption) context.CancelFunc {
681-
desc := fmt.Sprintf("run command: %q", cmd)
682-
return h.Background(desc, func(ctx context.Context, l *logger.Logger) error {
683-
l.Printf("running command `%s` on nodes %v in the background", cmd, nodes)
684-
return h.runner.cluster.RunE(ctx, nodes, cmd)
685-
})
686-
}
687-
688-
// ExpectDeath alerts the testing infrastructure that a node is
689-
// expected to die. Regular restarts as part of the mixedversion
690-
// testing are already taken into account. This function should only
691-
// be used by tests that perform their own node restarts or chaos
692-
// events.
693-
func (h *Helper) ExpectDeath() {
694-
h.ExpectDeaths(1)
695-
}
696-
697-
// ExpectDeaths is the general version of `ExpectDeath()`.
698-
func (h *Helper) ExpectDeaths(n int) {
699-
h.runner.monitor.ExpectDeaths(n)
700-
}
701-
702-
// loggerFor creates a logger instance to be used by background
703-
// functions (created by calling `Background` on the helper
704-
// instance). It is similar to the logger instances created for
705-
// mixed-version steps, but with the `background_` prefix.
706-
func (h *Helper) loggerFor(name string) (*logger.Logger, error) {
707-
atomic.AddInt64(&h.bgCount, 1)
708-
709-
fileName := invalidChars.ReplaceAllString(strings.ToLower(name), "")
710-
fileName = fmt.Sprintf("background_%s_%d", fileName, h.bgCount)
711-
fileName = path.Join(logPrefix, fileName)
712-
713-
return prefixedLogger(h.runner.logger, fileName)
714-
}
715-
716605
func (tf *testFailure) Error() string {
717606
if tf.summarized {
718607
return tf.description

0 commit comments

Comments
 (0)