Skip to content
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ Group lines under `Added` / `Changed` / `Fixed` / `Removed`. Append a PR link

### Changed

- Driver insert-method defaults now fill only load requests that leave their method unset, preserving methods selected by workloads. ([#152](https://github.com/stroppy-io/stroppy/pull/152))
- SIGINT and SIGTERM now cancel the running workload and trigger graceful teardown; a second signal forces immediate exit. Exit status is 130 (SIGINT) or 143 (SIGTERM) after a graceful cancellation, 2 after a forced exit, and 1 for other errors. ([#148](https://github.com/stroppy-io/stroppy/pull/148))
- Built-in workloads expose their tuning options as typed parameters while preserving the existing environment-variable names. ([#128](https://github.com/stroppy-io/stroppy/pull/128))
- TPC-DS typed loads format common cell types directly into reusable buffers. ([#126](https://github.com/stroppy-io/stroppy/pull/126))
Expand Down
6 changes: 3 additions & 3 deletions cmd/stroppy/commands/help/topic_drivers.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ DRIVER OPTIONS (-D / --driver-opt)
authUser string Username for static credentials auth
authPassword string Password for static credentials auth
tlsInsecureSkipVerify bool Skip TLS cert verification (testing only)
defaultInsertMethod string Fallback for load requests without a method

TLS is enabled automatically when the URL uses a secure scheme (e.g.
grpcs:// for YDB). The options above are only needed when the server uses
Expand All @@ -103,9 +104,8 @@ DRIVER OPTIONS (-D / --driver-opt)
pool.* options are sugar — they map to the driver-specific pool config
(pgx pool or sql pool) based on driverType. They are ignored for noop/csv.

"defaultInsertMethod" remains accepted in config files for compatibility,
but does not control workload execution. Insert methods are owned by each
workload's load request.
defaultInsertMethod is used only when a workload leaves its load request's
method unset. A workload-selected method always takes precedence.

HOW IT WORKS

Expand Down
23 changes: 20 additions & 3 deletions cmd/stroppy/commands/run/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/stroppy-io/stroppy/pkg/bench"
"github.com/stroppy-io/stroppy/pkg/common/logger"
"github.com/stroppy-io/stroppy/pkg/config"
"github.com/stroppy-io/stroppy/pkg/driver"
)

const (
Expand Down Expand Up @@ -507,8 +508,9 @@ func runGoWorkload(
// No -d given: default to the local postgres preset (mirrors TS
// declareDriverSetup defaults).
drivers[0] = &config.DriverConfig{ //nolint:gosec // G101: URL field name, not an embedded credential
DriverType: config.DriverTypePostgres,
URL: "postgres://postgres:postgres@localhost:5432",
DriverType: config.DriverTypePostgres,
URL: "postgres://postgres:postgres@localhost:5432",
DefaultInsertMethod: "native",
}
}

Expand Down Expand Up @@ -540,6 +542,8 @@ func buildDriverConfig(idx int, cfg *runner.DriverCLIConfig) (*config.DriverConf

driverType := cfg.DriverType
url := cfg.URL
defaultInsertMethod := cfg.DefaultInsertMethod
hasDefaultInsertMethod := cfg.HasDefaultInsertMethod()

if overrides != nil {
if overrides.DriverType != nil {
Expand All @@ -549,6 +553,11 @@ func buildDriverConfig(idx int, cfg *runner.DriverCLIConfig) (*config.DriverConf
if overrides.URL != nil {
url = overrides.GetURL()
}

if overrides.DefaultInsertMethod != nil {
defaultInsertMethod = overrides.GetDefaultInsertMethod()
hasDefaultInsertMethod = true
}
}

dc := &config.DriverConfig{URL: url}
Expand All @@ -562,7 +571,15 @@ func buildDriverConfig(idx int, cfg *runner.DriverCLIConfig) (*config.DriverConf
dc.DriverType = t
}

// defaultInsertMethod is owned by each Go workload's InsertRequest.
if hasDefaultInsertMethod {
method, err := driver.ResolveInsertMethod(dc.DriverType, defaultInsertMethod)
if err != nil {
return nil, invalidConfig(fmt.Errorf("driver %d: %w", idx, err))
}

dc.DefaultInsertMethod = method.String()
}

if err := applyDriverExtras(idx, dc, cfg.Extra); err != nil {
return nil, invalidConfig(err)
}
Expand Down
235 changes: 235 additions & 0 deletions cmd/stroppy/commands/run/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1171,6 +1171,82 @@ func TestApplyDriverPresetAliasesReachRuntimeConfig(t *testing.T) {
}
}

func TestApplyDriverOptInsertMethodAliasesRespectPrecedenceAndIndex(t *testing.T) {
postgres := "postgres"
plainBulk := "plain_bulk"

for _, key := range []string{
"defaultInsertMethod",
"default_insert_method",
"insertMethod",
"insert_method",
} {
t.Run(key, func(t *testing.T) {
configs, err := runner.DriverCLIConfigsFromFile(map[uint32]*config.DriverRunConfig{
0: {DriverType: &postgres, DefaultInsertMethod: &plainBulk},
1: {DriverType: &postgres, DefaultInsertMethod: &plainBulk},
})
if err != nil {
t.Fatalf("DriverCLIConfigsFromFile() error = %v", err)
}

for _, idx := range []int{0, 1} {
if err := applyDriverPreset(configs, idx, "pg"); err != nil {
t.Fatalf("applyDriverPreset(%d) error = %v", idx, err)
}
}

if err := applyDriverOpt(configs, 1, key, "columnar"); err != nil {
t.Fatalf("applyDriverOpt(%q) error = %v", key, err)
}

first, err := buildDriverConfig(0, configs[0])
if err != nil {
t.Fatalf("buildDriverConfig(0) error = %v", err)
}

second, err := buildDriverConfig(1, configs[1])
if err != nil {
t.Fatalf("buildDriverConfig(1) error = %v", err)
}

if first.DefaultInsertMethod != "native" || second.DefaultInsertMethod != "columnar" {
t.Fatalf(
"defaults = (%q, %q), want preset then indexed CLI override",
first.DefaultInsertMethod,
second.DefaultInsertMethod,
)
}
})
}
}

func TestApplyDriverOptInsertMethodAliasConflictIsOrderIndependent(t *testing.T) {
for _, alias := range []string{"default_insert_method", "insertMethod", "insert_method"} {
t.Run(alias, func(t *testing.T) {
first := runner.DriverCLIConfigs{}
if err := applyDriverOpt(first, 0, "defaultInsertMethod", "native"); err != nil {
t.Fatal(err)
}

firstErr := applyDriverOpt(first, 0, alias, "columnar")
if firstErr == nil {
t.Fatal("second insert method override succeeded")
}

second := runner.DriverCLIConfigs{}
if err := applyDriverOpt(second, 0, alias, "columnar"); err != nil {
t.Fatal(err)
}

secondErr := applyDriverOpt(second, 0, "defaultInsertMethod", "native")
if secondErr == nil || secondErr.Error() != firstErr.Error() {
t.Fatalf("reverse collision error = %v, want %v", secondErr, firstErr)
}
})
}
}

func TestDriverExtrasRejectAliasCollisionsAndWrongCase(t *testing.T) {
tests := []struct {
name string
Expand Down Expand Up @@ -1400,6 +1476,165 @@ func TestRemovedIsolationRejectedAtDriverCLISurfaces(t *testing.T) {
}
}

func TestBuildDriverConfigEmptyDefaultInsertMethod(t *testing.T) {
postgres := "postgres"
empty := ""

build := func(t *testing.T, cfg *runner.DriverCLIConfig, want string) {
t.Helper()

got, err := buildDriverConfig(0, cfg)
if err != nil {
t.Fatalf("buildDriverConfig() error = %v", err)
}

if got.DefaultInsertMethod != want {
t.Fatalf("DefaultInsertMethod = %q, want %q", got.DefaultInsertMethod, want)
}
}

for _, key := range []string{
"defaultInsertMethod",
"default_insert_method",
"insertMethod",
"insert_method",
} {
t.Run("driver option/"+key, func(t *testing.T) {
cfg := &runner.DriverCLIConfig{DriverType: postgres}
if err := cfg.ApplyOverride(key, empty); err != nil {
t.Fatalf("ApplyOverride(%q) error = %v", key, err)
}

build(t, cfg, "plain_query")
})
}

t.Run("raw driver JSON", func(t *testing.T) {
cfg, err := runner.NewDriverCLIConfigFromJSON(`{"driverType":"postgres","defaultInsertMethod":""}`)
if err != nil {
t.Fatalf("NewDriverCLIConfigFromJSON() error = %v", err)
}

build(t, &cfg, "plain_query")
})

t.Run("config file", func(t *testing.T) {
configs, err := runner.DriverCLIConfigsFromFile(map[uint32]*config.DriverRunConfig{
0: {DriverType: &postgres, DefaultInsertMethod: &empty},
})
if err != nil {
t.Fatalf("DriverCLIConfigsFromFile() error = %v", err)
}

build(t, configs[0], "plain_query")
})

t.Run("absent", func(t *testing.T) {
build(t, &runner.DriverCLIConfig{DriverType: postgres}, "")

configs, err := runner.DriverCLIConfigsFromFile(map[uint32]*config.DriverRunConfig{
0: {DriverType: &postgres},
})
if err != nil {
t.Fatalf("DriverCLIConfigsFromFile() error = %v", err)
}

build(t, configs[0], "")
})
}

func TestBuildDriverConfigDefaultInsertMethod(t *testing.T) {
for _, test := range []struct {
name string
cfg *runner.DriverCLIConfig
want string
wantErr bool
}{
{
name: "winning supported default",
cfg: &runner.DriverCLIConfig{
DriverType: "postgres", DefaultInsertMethod: "columnar",
},
want: "columnar",
},
{
name: "winning unsupported default",
cfg: &runner.DriverCLIConfig{
DriverType: "mysql", DefaultInsertMethod: "columnar",
},
wantErr: true,
},
} {
t.Run(test.name, func(t *testing.T) {
got, err := buildDriverConfig(0, test.cfg)
if test.wantErr {
if err == nil {
t.Fatal("buildDriverConfig() succeeded")
}

return
}

if err != nil {
t.Fatalf("buildDriverConfig() error = %v", err)
}

if got.DefaultInsertMethod != test.want {
t.Fatalf("DefaultInsertMethod = %q, want %q", got.DefaultInsertMethod, test.want)
}
})
}
}

func TestDriverDefaultInputPrecedenceAndIndices(t *testing.T) {
mysql := "mysql"
unsupported := "columnar"

configs, err := runner.DriverCLIConfigsFromFile(map[uint32]*config.DriverRunConfig{
0: {DriverType: &mysql, DefaultInsertMethod: &unsupported},
})
if err != nil {
t.Fatalf("DriverCLIConfigsFromFile() error = %v", err)
}

if err := applyDriverPreset(configs, 0, "pg"); err != nil {
t.Fatalf("applyDriverPreset() error = %v", err)
}

if err := applyDriverPreset(configs, 1, "mysql"); err != nil {
t.Fatalf("applyDriverPreset() error = %v", err)
}

if err := applyDriverOpt(configs, 1, "defaultInsertMethod", "native"); err != nil {
t.Fatalf("applyDriverOpt() error = %v", err)
}

first, err := buildDriverConfig(0, configs[0])
if err != nil {
t.Fatalf("buildDriverConfig(0) error = %v", err)
}

second, err := buildDriverConfig(1, configs[1])
if err != nil {
t.Fatalf("buildDriverConfig(1) error = %v", err)
}

if first.DefaultInsertMethod != "native" || second.DefaultInsertMethod != "native" {
t.Fatalf("defaults = (%q, %q), want native per driver", first.DefaultInsertMethod, second.DefaultInsertMethod)
}

if first.DriverType != config.DriverTypePostgres || second.DriverType != config.DriverTypeMySQL {
t.Fatalf("driver types = (%s, %s), want postgres, mysql", first.DriverType, second.DriverType)
}
}

func TestGlobalInsertMethodFlagIsRejected(t *testing.T) {
err := Cmd.RunE(Cmd, []string{"simple", "--insert-method", "native"})
if err == nil || !contains(err.Error(), `unknown CLI parameter "insert-method"`) {
t.Fatalf("RunE() error = %v, want unknown CLI parameter", err)
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

func marshalDriverConfig(t *testing.T, cfg *runner.DriverCLIConfig) map[string]any {
t.Helper()

Expand Down
Loading