Files
hatchet/cmd/hatchet-loadtest/load_e2e_test.go
T
abelanger5 5c5c1aa5a1 feat: more features in the load testing harness (#1691)
* fix: make stripped payload size configurable

* feat: more load test features

* Update cmd/hatchet-loadtest/do.go

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix: try to fix load tests

* increase timeout, update goleak ignores

* fix: data race in scheduler with snapshot input

* fix: logger improvements

* add one more goleak ignore

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-05-07 21:39:30 -04:00

171 lines
3.8 KiB
Go

//go:build load
package main
import (
"log"
"testing"
"time"
"github.com/hatchet-dev/hatchet/pkg/config/shared"
"github.com/hatchet-dev/hatchet/pkg/logger"
"github.com/hatchet-dev/hatchet/pkg/random"
"github.com/hatchet-dev/hatchet/pkg/testing/harness"
)
func TestMain(m *testing.M) {
harness.RunTestWithEngine(m)
}
func TestLoadCLI(t *testing.T) {
// We're using LoadTestConfig directly instead of an args struct
l = logger.NewStdErr(
&shared.LoggerConfigFile{
Level: "warn",
Format: "console",
},
"loadtest",
)
tests := []struct {
name string
config LoadTestConfig
wantErr bool
}{
{
name: "test simple workflow",
config: LoadTestConfig{
Duration: 240 * time.Second,
Events: 10,
Delay: 0 * time.Second,
Wait: 60 * time.Second,
Concurrency: 0,
Slots: 100,
FailureRate: 0.0,
PayloadSize: "0kb",
EventFanout: 1,
DagSteps: 1,
RlKeys: 0,
RlLimit: 0,
RlDurationUnit: "",
},
},
{
name: "test with DAG",
config: LoadTestConfig{
Duration: 240 * time.Second,
Events: 10,
Delay: 0 * time.Second,
Wait: 60 * time.Second,
Concurrency: 0,
Slots: 100,
FailureRate: 0.0,
PayloadSize: "0kb",
EventFanout: 1,
DagSteps: 2,
RlKeys: 0,
RlLimit: 0,
RlDurationUnit: "",
},
},
{
name: "test with event fanout",
config: LoadTestConfig{
Duration: 240 * time.Second,
Events: 10,
Delay: 0 * time.Second,
Wait: 60 * time.Second,
Concurrency: 0,
Slots: 100,
FailureRate: 0.0,
PayloadSize: "0kb",
EventFanout: 2,
DagSteps: 1,
RlKeys: 0,
RlLimit: 0,
RlDurationUnit: "",
},
},
{
name: "test with global concurrency key",
config: LoadTestConfig{
Duration: 240 * time.Second,
Events: 10,
Delay: 0 * time.Second,
Wait: 60 * time.Second,
Concurrency: 10,
Slots: 100,
FailureRate: 0.0,
PayloadSize: "0kb",
EventFanout: 1,
DagSteps: 1,
RlKeys: 0,
RlLimit: 0,
RlDurationUnit: "",
},
},
{
name: "test for many queued events and little worker throughput",
config: LoadTestConfig{
Duration: 240 * time.Second,
Events: 10,
Delay: 0 * time.Second,
WorkerDelay: 120 * time.Second, // will write 1200 events before the worker is ready
Wait: 120 * time.Second,
Concurrency: 0,
Slots: 100,
FailureRate: 0.0,
PayloadSize: "0kb",
EventFanout: 1,
DagSteps: 1,
RlKeys: 0,
RlLimit: 0,
RlDurationUnit: "",
},
},
{
name: "test with rate limits",
config: LoadTestConfig{
Duration: 240 * time.Second,
Events: 10,
Delay: 0 * time.Second,
Wait: 60 * time.Second,
Concurrency: 0,
Slots: 100,
FailureRate: 0.0,
PayloadSize: "0kb",
EventFanout: 1,
DagSteps: 1,
RlKeys: 10,
RlLimit: 100,
RlDurationUnit: "second",
},
},
}
// TODO instead of waiting, figure out when the engine setup is complete
time.Sleep(15 * time.Second)
for _, tt := range tests {
tt := tt // pin the loop variable
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
namespace, err := random.Generate(8)
if err != nil {
t.Fatalf("could not generate random namespace: %s", err)
}
testConfig := tt.config
testConfig.Namespace = namespace
if err := do(testConfig); (err != nil) != tt.wantErr {
t.Errorf("do() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
log.Printf("test complete")
}