Skip to content

Commit 81a81fb

Browse files
committed
roachtest: add native libraries to test specification and verify
This commit adds native libraries to the test specifications. Each native library that is required should be specified by name. The spec is verified in the test runner and uses the existing logic that populates libraryFilePaths to confirm that libraries are present. Note was taken on this change that findLibrary might need to be revised at a later stage to ensure it only provides libraries compatible with the target cluster. Verification happens before the cluster is provisioned. The test will fail quickly if libraries are not present to support the planned execution. Resolves: #81081 Release justification: test-only change. Release note: None.
1 parent 01eb6ab commit 81a81fb

15 files changed

Lines changed: 170 additions & 74 deletions

pkg/cmd/roachtest/cluster.go

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,36 @@ func findBinaryOrLibrary(binOrLib string, name string) (string, error) {
186186
return filepathAbs(path)
187187
}
188188

189+
// VerifyLibraries verifies that the required libraries, specified by name, are
190+
// available for the target environment.
191+
func VerifyLibraries(requiredLibs []string) error {
192+
for _, requiredLib := range requiredLibs {
193+
if !contains(libraryFilePaths, libraryNameFromPath, requiredLib) {
194+
return errors.Wrap(errors.Errorf("missing required library %s", requiredLib), "cluster.VerifyLibraries")
195+
}
196+
}
197+
return nil
198+
}
199+
200+
// libraryNameFromPath returns the name of a library without the extension, for a
201+
// given path.
202+
func libraryNameFromPath(path string) string {
203+
filename := filepath.Base(path)
204+
return strings.TrimSuffix(filename, filepath.Ext(filename))
205+
}
206+
207+
func contains(list []string, transformString func(s string) string, str string) bool {
208+
if transformString == nil {
209+
transformString = func(s string) string { return s }
210+
}
211+
for _, element := range list {
212+
if transformString(element) == str {
213+
return true
214+
}
215+
}
216+
return false
217+
}
218+
189219
func initBinariesAndLibraries() {
190220
// If we're running against an existing "local" cluster, force the local flag
191221
// to true in order to get the "local" test configurations.
@@ -1648,20 +1678,24 @@ func (c *clusterImpl) PutE(
16481678
return errors.Wrap(roachprod.Put(ctx, l, c.MakeNodes(nodes...), src, dest, true /* useTreeDist */), "cluster.PutE")
16491679
}
16501680

1651-
// PutLibraries inserts all available library files into all nodes on the cluster
1681+
// PutLibraries inserts the specified libraries, by name, into all nodes on the cluster
16521682
// at the specified location.
1653-
func (c *clusterImpl) PutLibraries(ctx context.Context, libraryDir string) error {
1683+
func (c *clusterImpl) PutLibraries(
1684+
ctx context.Context, libraryDir string, libraries []string,
1685+
) error {
16541686
if ctx.Err() != nil {
16551687
return errors.Wrap(ctx.Err(), "cluster.Put")
16561688
}
1657-
16581689
c.status("uploading library files")
16591690
defer c.status("")
16601691

16611692
if err := c.RunE(ctx, c.All(), "mkdir", "-p", libraryDir); err != nil {
16621693
return err
16631694
}
16641695
for _, libraryFilePath := range libraryFilePaths {
1696+
if !contains(libraries, nil, libraryNameFromPath(libraryFilePath)) {
1697+
continue
1698+
}
16651699
putPath := filepath.Join(libraryDir, filepath.Base(libraryFilePath))
16661700
if err := c.PutE(
16671701
ctx,

pkg/cmd/roachtest/cluster/cluster_interface.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ type Cluster interface {
4141
Get(ctx context.Context, l *logger.Logger, src, dest string, opts ...option.Option) error
4242
Put(ctx context.Context, src, dest string, opts ...option.Option)
4343
PutE(ctx context.Context, l *logger.Logger, src, dest string, opts ...option.Option) error
44-
PutLibraries(ctx context.Context, libraryDir string) error
44+
PutLibraries(ctx context.Context, libraryDir string, libraries []string) error
4545
Stage(
4646
ctx context.Context, l *logger.Logger, application, versionOrSHA, dir string, opts ...option.Option,
4747
) error
@@ -71,6 +71,7 @@ type Cluster interface {
7171
ExternalPGUrl(ctx context.Context, l *logger.Logger, node option.NodeListOption) ([]string, error)
7272

7373
// SQL clients to nodes.
74+
7475
Conn(ctx context.Context, l *logger.Logger, node int) *gosql.DB
7576
ConnE(ctx context.Context, l *logger.Logger, node int) (*gosql.DB, error)
7677
ConnEAsUser(ctx context.Context, l *logger.Logger, node int, user string) (*gosql.DB, error)

pkg/cmd/roachtest/cluster_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ import (
1919
test2 "github.com/cockroachdb/cockroach/pkg/cmd/roachtest/test"
2020
"github.com/cockroachdb/cockroach/pkg/roachprod/logger"
2121
"github.com/cockroachdb/cockroach/pkg/util/version"
22+
"github.com/cockroachdb/errors"
2223
"github.com/stretchr/testify/assert"
24+
"github.com/stretchr/testify/require"
2325
)
2426

2527
func TestClusterNodes(t *testing.T) {
@@ -177,3 +179,57 @@ func TestCmdLogFileName(t *testing.T) {
177179
cmdLogFileName(ts, nodes, "./cockroach bla --foo bar"),
178180
)
179181
}
182+
183+
func TestVerifyLibraries(t *testing.T) {
184+
testCases := []struct {
185+
name string
186+
verifyLibs []string
187+
libraryFilePaths []string
188+
expectedError error
189+
}{
190+
{
191+
name: "valid nil input",
192+
verifyLibs: nil,
193+
libraryFilePaths: []string{"/some/path/lib.so"},
194+
expectedError: nil,
195+
},
196+
{
197+
name: "no match",
198+
verifyLibs: []string{"required_c"},
199+
libraryFilePaths: []string{"/some/path/lib.so"},
200+
expectedError: errors.Wrap(errors.Errorf("missing required library %s",
201+
"required_c"), "cluster.VerifyLibraries"),
202+
},
203+
{
204+
name: "no match on nil libs",
205+
verifyLibs: []string{"required_b"},
206+
libraryFilePaths: nil,
207+
expectedError: errors.Wrap(errors.Errorf("missing required library %s",
208+
"required_b"), "cluster.VerifyLibraries"),
209+
},
210+
{
211+
name: "single match",
212+
verifyLibs: []string{"geos"},
213+
libraryFilePaths: []string{"/lib/geos.so"},
214+
expectedError: nil,
215+
},
216+
{
217+
name: "multiple matches",
218+
verifyLibs: []string{"lib", "ltwo", "geos"},
219+
libraryFilePaths: []string{"ltwo.so", "a/geos.so", "/some/path/to/lib.so"},
220+
expectedError: nil,
221+
},
222+
}
223+
for _, tc := range testCases {
224+
t.Run(tc.name, func(t *testing.T) {
225+
libraryFilePaths = tc.libraryFilePaths
226+
actualError := VerifyLibraries(tc.verifyLibs)
227+
if tc.expectedError == nil {
228+
require.NoError(t, actualError)
229+
} else {
230+
require.NotNil(t, actualError)
231+
require.EqualError(t, actualError, tc.expectedError.Error())
232+
}
233+
})
234+
}
235+
}

pkg/cmd/roachtest/registry/test_spec.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ import (
2020
"github.com/cockroachdb/cockroach/pkg/cmd/roachtest/test"
2121
)
2222

23+
// LibGEOS is a list of native libraries for libgeos.
24+
var LibGEOS = []string{"libgeos", "libgeos_c"}
25+
2326
// TestSpec is a spec for a roachtest.
2427
type TestSpec struct {
2528
Skip string // if non-empty, test will be skipped
@@ -43,6 +46,9 @@ type TestSpec struct {
4346
Tags []string
4447
// Cluster provides the specification for the cluster to use for the test.
4548
Cluster spec.ClusterSpec
49+
// NativeLibs specifies the native libraries required to be present on
50+
// the cluster during execution.
51+
NativeLibs []string
4652

4753
// UseIOBarrier controls the local-ssd-no-ext4-barrier flag passed to
4854
// roachprod when creating a cluster. If set, the flag is not passed, and so

pkg/cmd/roachtest/test_runner.go

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,13 @@ func (r *testRunner) runWorker(
553553
testToRun.canReuseCluster = false
554554
}
555555
}
556+
557+
// Verify that required native libraries are available.
558+
if err = VerifyLibraries(testToRun.spec.NativeLibs); err != nil {
559+
shout(ctx, l, stdout, "Library verification failed: %s", err)
560+
return err
561+
}
562+
556563
var clusterCreateErr error
557564

558565
if !testToRun.canReuseCluster {
@@ -621,28 +628,37 @@ func (r *testRunner) runWorker(
621628
t.spec.Name = oldName
622629
t.spec.Owner = oldOwner
623630
} else {
624-
// Tell the cluster that, from now on, it will be run "on behalf of this
625-
// test".
626-
c.status("running test")
627631
c.setTest(t)
628-
629-
switch t.Spec().(*registry.TestSpec).EncryptionSupport {
630-
case registry.EncryptionAlwaysEnabled:
631-
c.encAtRest = true
632-
case registry.EncryptionAlwaysDisabled:
633-
c.encAtRest = false
634-
case registry.EncryptionMetamorphic:
635-
// when tests opted-in to metamorphic testing, encryption will
636-
// be enabled according to the probability passed to
637-
// --metamorphic-encryption-probability
638-
c.encAtRest = prng.Float64() < encryptionProbability
632+
c.status("copying libraries")
633+
if len(t.spec.NativeLibs) != 0 {
634+
if err = c.PutLibraries(ctx, "./lib", t.spec.NativeLibs); err != nil {
635+
shout(ctx, l, stdout, "Unable to put native libraries due to: %s", err)
636+
}
639637
}
640638

641-
wStatus.SetCluster(c)
642-
wStatus.SetTest(t, testToRun)
643-
wStatus.SetStatus("running test")
639+
if err == nil {
640+
// Tell the cluster that, from now on, it will be run "on behalf of this
641+
// test".
642+
c.status("running test")
643+
644+
switch t.Spec().(*registry.TestSpec).EncryptionSupport {
645+
case registry.EncryptionAlwaysEnabled:
646+
c.encAtRest = true
647+
case registry.EncryptionAlwaysDisabled:
648+
c.encAtRest = false
649+
case registry.EncryptionMetamorphic:
650+
// when tests opted-in to metamorphic testing, encryption will
651+
// be enabled according to the probability passed to
652+
// --metamorphic-encryption-probability
653+
c.encAtRest = prng.Float64() < encryptionProbability
654+
}
644655

645-
err = r.runTest(ctx, t, testToRun.runNum, testToRun.runCount, c, stdout, testL)
656+
wStatus.SetCluster(c)
657+
wStatus.SetTest(t, testToRun)
658+
wStatus.SetStatus("running test")
659+
660+
err = r.runTest(ctx, t, testToRun.runNum, testToRun.runCount, c, stdout, testL)
661+
}
646662
}
647663

648664
if err != nil {

pkg/cmd/roachtest/tests/activerecord.go

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,6 @@ func registerActiveRecord(r registry.Registry) {
4444
node := c.Node(1)
4545
t.Status("setting up cockroach")
4646
c.Put(ctx, t.Cockroach(), "./cockroach", c.All())
47-
if err := c.PutLibraries(ctx, "./lib"); err != nil {
48-
t.Fatal(err)
49-
}
5047
c.Start(ctx, t.L(), option.DefaultStartOpts(), install.MakeClusterSettings(), c.All())
5148

5249
version, err := fetchCockroachVersion(ctx, t.L(), c, node[0])
@@ -254,10 +251,11 @@ func registerActiveRecord(r registry.Registry) {
254251
}
255252

256253
r.Add(registry.TestSpec{
257-
Name: "activerecord",
258-
Owner: registry.OwnerSQLExperience,
259-
Cluster: r.MakeClusterSpec(1),
260-
Tags: []string{`default`, `orm`},
261-
Run: runActiveRecord,
254+
Name: "activerecord",
255+
Owner: registry.OwnerSQLExperience,
256+
Cluster: r.MakeClusterSpec(1),
257+
NativeLibs: registry.LibGEOS,
258+
Tags: []string{`default`, `orm`},
259+
Run: runActiveRecord,
262260
})
263261
}

pkg/cmd/roachtest/tests/costfuzz.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ func registerCostFuzz(r registry.Registry) {
3232
RequiresLicense: true,
3333
Tags: nil,
3434
Cluster: r.MakeClusterSpec(1),
35+
NativeLibs: registry.LibGEOS,
3536
Run: runCostFuzz,
3637
})
3738
}

pkg/cmd/roachtest/tests/hibernate.go

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,6 @@ func registerHibernate(r registry.Registry, opt hibernateOptions) {
8080
node := c.Node(1)
8181
t.Status("setting up cockroach")
8282
c.Put(ctx, t.Cockroach(), "./cockroach", c.All())
83-
if err := c.PutLibraries(ctx, "./lib"); err != nil {
84-
t.Fatal(err)
85-
}
8683
c.Start(ctx, t.L(), option.DefaultStartOpts(), install.MakeClusterSettings(), c.All())
8784

8885
if opt.dbSetupFunc != nil {
@@ -237,10 +234,11 @@ func registerHibernate(r registry.Registry, opt hibernateOptions) {
237234
}
238235

239236
r.Add(registry.TestSpec{
240-
Name: opt.testName,
241-
Owner: registry.OwnerSQLExperience,
242-
Cluster: r.MakeClusterSpec(1),
243-
Tags: []string{`default`, `orm`},
237+
Name: opt.testName,
238+
Owner: registry.OwnerSQLExperience,
239+
Cluster: r.MakeClusterSpec(1),
240+
NativeLibs: registry.LibGEOS,
241+
Tags: []string{`default`, `orm`},
244242
Run: func(ctx context.Context, t test.Test, c cluster.Cluster) {
245243
runHibernate(ctx, t, c)
246244
},

pkg/cmd/roachtest/tests/knex.go

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,6 @@ func registerKnex(r registry.Registry) {
3838
node := c.Node(1)
3939
t.Status("setting up cockroach")
4040
c.Put(ctx, t.Cockroach(), "./cockroach", c.All())
41-
if err := c.PutLibraries(ctx, "./lib"); err != nil {
42-
t.Fatal(err)
43-
}
4441
c.Start(ctx, t.L(), option.DefaultStartOpts(), install.MakeClusterSettings(), c.All())
4542

4643
version, err := fetchCockroachVersion(ctx, t.L(), c, node[0])
@@ -120,10 +117,11 @@ func registerKnex(r registry.Registry) {
120117
}
121118

122119
r.Add(registry.TestSpec{
123-
Name: "knex",
124-
Owner: registry.OwnerSQLExperience,
125-
Cluster: r.MakeClusterSpec(1),
126-
Tags: []string{`default`, `orm`},
120+
Name: "knex",
121+
Owner: registry.OwnerSQLExperience,
122+
Cluster: r.MakeClusterSpec(1),
123+
NativeLibs: registry.LibGEOS,
124+
Tags: []string{`default`, `orm`},
127125
Run: func(ctx context.Context, t test.Test, c cluster.Cluster) {
128126
runKnex(ctx, t, c)
129127
},

pkg/cmd/roachtest/tests/query_comparison_util.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,6 @@ func runQueryComparison(
5656
}
5757

5858
c.Put(ctx, t.Cockroach(), "./cockroach")
59-
if err := c.PutLibraries(ctx, "./lib"); err != nil {
60-
t.Fatalf("could not initialize libraries: %v", err)
61-
}
6259

6360
for i := 0; ; i++ {
6461
c.Start(ctx, t.L(), option.DefaultStartOpts(), install.MakeClusterSettings())

0 commit comments

Comments
 (0)