From f66f8e24a1a6b75ae833f5e1f6f6017df812f4d8 Mon Sep 17 00:00:00 2001 From: Geoffrey Ragot Date: Tue, 12 Nov 2024 10:25:10 +0100 Subject: [PATCH 01/27] test: add antithesis test --- test/antithesis/Earthfile | 46 +++++++ test/antithesis/config/Earthfile | 12 ++ test/antithesis/config/docker-compose.yml | 87 ++++++++++++++ test/antithesis/config/gateway/Caddyfile | 9 ++ test/antithesis/image/Earthfile | 47 ++++++++ test/antithesis/image/entrypoint.sh | 11 ++ test/antithesis/workload/Earthfile | 40 +++++++ test/antithesis/workload/cmd/lifecycle.go | 31 +++++ test/antithesis/workload/cmd/root.go | 30 +++++ test/antithesis/workload/cmd/run.go | 48 ++++++++ test/antithesis/workload/cmd/utils.go | 59 +++++++++ test/antithesis/workload/cmd/utils_test.go | 20 ++++ test/antithesis/workload/cmd/workload.go | 133 +++++++++++++++++++++ test/antithesis/workload/go.mod | 24 ++++ test/antithesis/workload/go.sum | 31 +++++ test/antithesis/workload/main.go | 11 ++ 16 files changed, 639 insertions(+) create mode 100644 test/antithesis/Earthfile create mode 100644 test/antithesis/config/Earthfile create mode 100644 test/antithesis/config/docker-compose.yml create mode 100644 test/antithesis/config/gateway/Caddyfile create mode 100644 test/antithesis/image/Earthfile create mode 100644 test/antithesis/image/entrypoint.sh create mode 100644 test/antithesis/workload/Earthfile create mode 100644 test/antithesis/workload/cmd/lifecycle.go create mode 100644 test/antithesis/workload/cmd/root.go create mode 100644 test/antithesis/workload/cmd/run.go create mode 100644 test/antithesis/workload/cmd/utils.go create mode 100644 test/antithesis/workload/cmd/utils_test.go create mode 100644 test/antithesis/workload/cmd/workload.go create mode 100644 test/antithesis/workload/go.mod create mode 100644 test/antithesis/workload/go.sum create mode 100644 test/antithesis/workload/main.go diff --git a/test/antithesis/Earthfile b/test/antithesis/Earthfile new file mode 100644 index 0000000000..a11d104882 --- /dev/null +++ b/test/antithesis/Earthfile @@ -0,0 +1,46 @@ +VERSION 0.8 + +IMPORT github.com/formancehq/earthly:tags/v0.17.1 AS core + +FROM core+base-image + +run: + COPY ../..+sources/src /src + LET TAG=$(tar cf - /src | sha1sum | awk '{print $1}') + + WAIT + BUILD +requirements-build --TAG=$TAG + END + + FROM curlimages/curl + ARG ANTITHESIS_USERNAME=formance + ARG --required ANTITHESIS_SLACK_REPORT_RECIPIENT + RUN --no-cache --secret ANTITHESIS_PASSWORD curl \ + --fail \ + --user "$ANTITHESIS_USERNAME:$ANTITHESIS_PASSWORD" \ + -X POST https://formance.antithesis.com/api/v1/launch_experiment/formance -d "{ + \"params\": { + \"custom.duration\": \"0.1\", + \"antithesis.report.recipients\": \"${ANTITHESIS_SLACK_REPORT_RECIPIENT}\", + \"antithesis.config_image\": \"antithesis-config-dev:$TAG\", + \"antithesis.images\": \"ledger:$TAG;workload:$TAG\" + } + }" + +run-local: + LOCALLY + + WAIT + BUILD +requirements-build + END + + RUN --no-cache docker compose -f config/docker-compose.yml up workload + RUN --no-cache docker compose -f config/docker-compose.yml down -v + +requirements-build: + ARG TAG=latest + ARG --required ANTITHESIS_REPOSITORY + + BUILD --pass-args ./config+build + BUILD --pass-args ./image+build + BUILD --pass-args ./workload+build \ No newline at end of file diff --git a/test/antithesis/config/Earthfile b/test/antithesis/config/Earthfile new file mode 100644 index 0000000000..936b8c4dfc --- /dev/null +++ b/test/antithesis/config/Earthfile @@ -0,0 +1,12 @@ +VERSION 0.8 + +IMPORT github.com/formancehq/earthly:tags/v0.17.1 AS core + +build: + FROM --platform=linux/amd64 scratch + ARG TAG=latest + ARG --required ANTITHESIS_REPOSITORY + COPY docker-compose.yml /docker-compose.yml + COPY --dir gateway /gateway + + SAVE IMAGE --push --no-manifest-list ${ANTITHESIS_REPOSITORY}/antithesis-config-dev:$TAG \ No newline at end of file diff --git a/test/antithesis/config/docker-compose.yml b/test/antithesis/config/docker-compose.yml new file mode 100644 index 0000000000..3d33654d9b --- /dev/null +++ b/test/antithesis/config/docker-compose.yml @@ -0,0 +1,87 @@ +--- +networks: + formance: + driver: bridge + ipam: + config: + - subnet: 10.0.29.0/24 + +services: + postgres: + image: "postgres:15-alpine" + hostname: postgres + container_name: postgres + command: + - -c + - max_connections=100 + environment: + POSTGRES_USER: "ledger" + POSTGRES_PASSWORD: "ledger" + POSTGRES_DB: "ledger" + PGDATA: /data/postgres + healthcheck: + test: [ "CMD-SHELL", "pg_isready -U ledger" ] + interval: 10s + timeout: 5s + retries: 5 + networks: + formance: + ipv4_address: 10.0.29.16 + + ledger1: + image: "us-central1-docker.pkg.dev/molten-verve-216720/formance-repository/ledger:latest" + hostname: ledger1 + container_name: ledger1 + environment: + POSTGRES_URI: "postgresql://ledger:ledger@10.0.29.16:5432/ledger?sslmode=disable" + BIND: ":8080" + networks: + formance: + ipv4_address: 10.0.29.17 + depends_on: + postgres: + condition: service_healthy + + ledger2: + image: "us-central1-docker.pkg.dev/molten-verve-216720/formance-repository/ledger:latest" + hostname: ledger2 + container_name: ledger2 + environment: + POSTGRES_URI: "postgresql://ledger:ledger@10.0.29.16:5432/ledger?sslmode=disable" + BIND: ":8080" + networks: + formance: + ipv4_address: 10.0.29.18 + depends_on: + postgres: + condition: service_healthy + + workload: + image: "us-central1-docker.pkg.dev/molten-verve-216720/formance-repository/workload:latest" + hostname: workload + container_name: workload + networks: + formance: + ipv4_address: 10.0.29.19 + depends_on: + - gateway + + gateway: + image: "ghcr.io/formancehq/gateway:v2.0.0-rc.20" + hostname: gateway + container_name: gateway + volumes: + - ./gateway/Caddyfile:/etc/caddy/Caddyfile + ports: + - "8080:8080" + networks: + formance: + ipv4_address: 10.0.29.20 + depends_on: + - ledger1 + - ledger2 + healthcheck: + test: curl --fail http://localhost:8080 || exit 1 + interval: 2s + retries: 5 + start_period: 1s \ No newline at end of file diff --git a/test/antithesis/config/gateway/Caddyfile b/test/antithesis/config/gateway/Caddyfile new file mode 100644 index 0000000000..2eb65652c7 --- /dev/null +++ b/test/antithesis/config/gateway/Caddyfile @@ -0,0 +1,9 @@ +{ + # Local env dev config + auto_https off + debug +} + +:8080 { + reverse_proxy ledger1:8080 ledger2:8080 +} diff --git a/test/antithesis/image/Earthfile b/test/antithesis/image/Earthfile new file mode 100644 index 0000000000..eef58211bf --- /dev/null +++ b/test/antithesis/image/Earthfile @@ -0,0 +1,47 @@ +VERSION 0.8 + +IMPORT github.com/formancehq/earthly:tags/v0.17.1 AS core + +FROM core+base-image + +CACHE --sharing=shared --id go-mod-cache /go/pkg/mod +CACHE --sharing=shared --id go-cache /root/.cache/go-build + +compile: + FROM --platform=linux/amd64 golang:1.22.2 + CACHE --sharing=shared --id go-mod-cache /go/pkg/mod + CACHE --sharing=shared --id go-cache /root/.cache/go-build + + COPY ../../..+sources/src /src + RUN go install github.com/antithesishq/antithesis-sdk-go/tools/antithesis-go-instrumentor@latest + WORKDIR /src + + RUN go mod download + RUN mkdir -p /ledger_instrumented + RUN /go/bin/antithesis-go-instrumentor . /ledger_instrumented + + WORKDIR /ledger_instrumented/customer + RUN go mod download + RUN go build -race -o ledger + + SAVE ARTIFACT /ledger_instrumented/customer/ledger + SAVE ARTIFACT /ledger_instrumented/symbols + +build: + FROM --platform=linux/amd64 ubuntu:latest + RUN apt-get update -y && apt-get install -y postgresql-client curl + ARG TAG=latest + + COPY (+compile/ledger) /bin/ledger + COPY (+compile/symbols) /symbols + COPY entrypoint.sh /bin/entrypoint.sh + + RUN chmod 777 /bin/ledger + RUN chmod 777 /bin/entrypoint.sh + + ENTRYPOINT ["/bin/entrypoint.sh"] + EXPOSE 8080 + + ARG --required ANTITHESIS_REPOSITORY + + SAVE IMAGE --push --no-manifest-list "${ANTITHESIS_REPOSITORY}/ledger:${TAG}" \ No newline at end of file diff --git a/test/antithesis/image/entrypoint.sh b/test/antithesis/image/entrypoint.sh new file mode 100644 index 0000000000..37973d9470 --- /dev/null +++ b/test/antithesis/image/entrypoint.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# make sure pg is ready to accept connections +until pg_isready -d ledger -h 10.0.29.16 -U ledger +do + echo "Waiting for postgres at: $POSTGRES_URI" + sleep 2; +done + +echo "Postgres is ready; serving ledger!" + +ledger serve diff --git a/test/antithesis/workload/Earthfile b/test/antithesis/workload/Earthfile new file mode 100644 index 0000000000..bd792457fd --- /dev/null +++ b/test/antithesis/workload/Earthfile @@ -0,0 +1,40 @@ +VERSION 0.7 + +FROM --platform=linux/amd64 golang:1.22.2 + +CACHE --sharing=shared --id go-mod-cache /go/pkg/mod +CACHE --sharing=shared --id go-cache /root/.cache/go-build + +compile: + CACHE --id go-mod-cache /go/pkg/mod + CACHE --id go-cache /root/.cache/go-build + + RUN go install github.com/antithesishq/antithesis-sdk-go/tools/antithesis-go-instrumentor@latest + + COPY ../../..+lint/pkg /src/pkg + COPY ../../..+lint/internal /src/internal + COPY ../../..+lint/cmd /src/cmd + COPY ../../..+lint/*.go /src/ + COPY ../../..+tidy/go.mod /src/ + COPY ../../..+tidy/go.sum /src/ + + WORKDIR /src/test/antithesis/workload + COPY *.go go.* . + COPY --dir cmd . + + RUN mkdir -p /workload_instrumented + RUN /go/bin/antithesis-go-instrumentor -assert_only . + RUN go build -o main + + SAVE ARTIFACT main + +build: + FROM --platform=linux/amd64 ubuntu:latest + ARG TAG=latest + COPY (+compile/main) /bin/workload + RUN chmod 777 /bin/workload + ENTRYPOINT ["/bin/workload"] + + ARG --required ANTITHESIS_REPOSITORY + + SAVE IMAGE --push --no-manifest-list ${ANTITHESIS_REPOSITORY}/workload:${TAG} \ No newline at end of file diff --git a/test/antithesis/workload/cmd/lifecycle.go b/test/antithesis/workload/cmd/lifecycle.go new file mode 100644 index 0000000000..f649e02954 --- /dev/null +++ b/test/antithesis/workload/cmd/lifecycle.go @@ -0,0 +1,31 @@ +package cmd + +import ( + "context" + "fmt" + "github.com/formancehq/ledger/pkg/client" + "os" + "time" +) + +func waitServicesReady(ctx context.Context, client *client.Formance) { + fmt.Println("Waiting for services to be ready") + waitingServicesCtx, cancel := context.WithDeadline(ctx, time.Now().Add(30*time.Second)) + defer cancel() + + for { + select { + case <-time.After(time.Second): + fmt.Println("Trying to get info of the ledger...") + _, err := client.Ledger.GetInfo(ctx) + if err != nil { + fmt.Printf("error pinging ledger: %s\r\n", err) + continue + } + return + case <-waitingServicesCtx.Done(): + fmt.Printf("timeout waiting for services to be ready\r\n") + os.Exit(1) + } + } +} diff --git a/test/antithesis/workload/cmd/root.go b/test/antithesis/workload/cmd/root.go new file mode 100644 index 0000000000..7eac0b0d67 --- /dev/null +++ b/test/antithesis/workload/cmd/root.go @@ -0,0 +1,30 @@ +package cmd + +import ( + "os" + + "github.com/spf13/cobra" +) + + + +// rootCmd represents the base command when called without any subcommands +var rootCmd = &cobra.Command{ + Use: "antithesis", + Run: run, +} + +// Execute adds all child commands to the root command and sets flags appropriately. +// This is called by main.main(). It only needs to happen once to the rootCmd. +func Execute() { + err := rootCmd.Execute() + if err != nil { + os.Exit(1) + } +} + +func init() { + rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} + + diff --git a/test/antithesis/workload/cmd/run.go b/test/antithesis/workload/cmd/run.go new file mode 100644 index 0000000000..42b1cb24b6 --- /dev/null +++ b/test/antithesis/workload/cmd/run.go @@ -0,0 +1,48 @@ +package cmd + +import ( + "context" + "fmt" + "github.com/formancehq/ledger/pkg/client/models/operations" + "github.com/spf13/cobra" + "net/http" + "time" + + "github.com/antithesishq/antithesis-sdk-go/assert" + "github.com/formancehq/ledger/pkg/client" +) + +type Details map[string]any + +func run(cmd *cobra.Command, _ []string) { + client := client.New( + client.WithServerURL("http://gateway:8080"), + client.WithClient(&http.Client{ + Timeout: 10 * time.Second, + }), + ) + + waitServicesReady(cmd.Context(), client) + runWorkload(cmd.Context(), client) +} + +func createLedger(ctx context.Context, client *client.Formance) error { + + deadline := time.Now().Add(10 * time.Second) + ctx, cancel := context.WithDeadline(ctx, deadline) + defer cancel() + + fmt.Printf("Creating ledger with deadline %s...\r\n", deadline) + _, err := client.Ledger.V2.CreateLedger(ctx, operations.V2CreateLedgerRequest{ + Ledger: "default", + }) + fmt.Println("Ledger created!") + + if assert.Always(err == nil, "ledger should have been created", Details{ + "error": fmt.Sprintf("%+v\n", err), + }); err != nil { + return err + } + + return nil +} diff --git a/test/antithesis/workload/cmd/utils.go b/test/antithesis/workload/cmd/utils.go new file mode 100644 index 0000000000..a98b713a79 --- /dev/null +++ b/test/antithesis/workload/cmd/utils.go @@ -0,0 +1,59 @@ +package cmd + +import ( + "fmt" + "math/big" + "sync" + + "github.com/antithesishq/antithesis-sdk-go/random" +) + +func randomBigInt() *big.Int { + v := random.GetRandom() + ret := big.NewInt(0) + ret.SetString(fmt.Sprintf("%d", v), 10) + return ret +} + +type IDSeq struct { + sync.Mutex + Count int64 + Sum *big.Int +} + +func NewIDSeq() *IDSeq { + return &IDSeq{ + Count: 0, + Sum: big.NewInt(0), + } +} + +func (s *IDSeq) Register(id *big.Int) { + s.Lock() + defer s.Unlock() + + s.Count++ + s.Sum.Add(s.Sum, id) +} + +func (s *IDSeq) Check() error { + s.Lock() + defer s.Unlock() + + // As the IDs are generated sequentially, the + // expected sum is the sum of the first n integers + // where n is the number of IDs generated. + expectedSum := big.NewInt(0).Div( + big.NewInt(0).Mul( + big.NewInt(s.Count-1), + big.NewInt(0).Add(big.NewInt(s.Count-1), big.NewInt(1)), + ), + big.NewInt(2), + ) + + if s.Sum.Cmp(expectedSum) != 0 { + return fmt.Errorf("sum of IDs is incorrect") + } + + return nil +} diff --git a/test/antithesis/workload/cmd/utils_test.go b/test/antithesis/workload/cmd/utils_test.go new file mode 100644 index 0000000000..fd6190661b --- /dev/null +++ b/test/antithesis/workload/cmd/utils_test.go @@ -0,0 +1,20 @@ +package cmd + +import ( + "fmt" + "math/big" + "testing" +) + +func TestIDSeq(t *testing.T) { + idSeq := NewIDSeq() + + for i := 0; i < 10; i++ { + idSeq.Register(big.NewInt(int64(i))) + } + + if err := idSeq.Check(); err != nil { + fmt.Println(idSeq.Count, idSeq.Sum) + t.Errorf("IDSeq check failed") + } +} diff --git a/test/antithesis/workload/cmd/workload.go b/test/antithesis/workload/cmd/workload.go new file mode 100644 index 0000000000..c5c1fb5f65 --- /dev/null +++ b/test/antithesis/workload/cmd/workload.go @@ -0,0 +1,133 @@ +package cmd + +import ( + "context" + "fmt" + "github.com/alitto/pond" + "github.com/antithesishq/antithesis-sdk-go/assert" + "github.com/antithesishq/antithesis-sdk-go/lifecycle" + "github.com/antithesishq/antithesis-sdk-go/random" + "github.com/formancehq/ledger/pkg/client" + "github.com/formancehq/ledger/pkg/client/models/components" + "github.com/formancehq/ledger/pkg/client/models/operations" + "github.com/formancehq/stack/libs/go-libs/pointer" + "go.uber.org/atomic" + "math" + "math/big" +) + +func runWorkload(ctx context.Context, client *client.Formance) { + err := createLedger(ctx, client) + if err != nil { + assert.Always(err == nil, "ledger should have been created", Details{ + "error": err, + }) + return + } + + lifecycle.SetupComplete(Details{ + "Ledger": "Available", + }) + + const count = 1000 + + hasError := atomic.NewBool(false) + totalAmount := big.NewInt(0) + idSeq := NewIDSeq() + + pool := pond.New(20, 10000) + + fmt.Printf("Insert %d transactions...\r\n", count) + for i := 0; i < count; i++ { + amount := randomBigInt() + totalAmount = totalAmount.Add(totalAmount, amount) + pool.Submit(func() { + id, err := runTx(ctx, client, amount) + + if err != nil { + hasError.CompareAndSwap(false, true) + return + } + + idSeq.Register(id) + }) + } + + pool.StopAndWait() + + //err = idSeq.Check() + //assert.Always(err == nil, "IDSeq check should pass", Details{ + // "count": idSeq.Count, + // "sum": idSeq.Sum, + //}) + // + //if err != nil { + // fmt.Println("Error checking ID sequence", err) + // hasError.CompareAndSwap(false, true) + // os.Exit(1) + // return + //} + + cond := !hasError.Load() + if assert.Always(cond, "all transactions should have been written", Details{ + "error": fmt.Sprintf("%+v\n", err), + }); !cond { + return + } + + fmt.Println("Checking balance of 'world'...") + account, err := client.Ledger.V2.GetAccount(ctx, operations.V2GetAccountRequest{ + Address: "world", + Expand: pointer.For("volumes"), + Ledger: "default", + }) + + cond = err == nil + if assert.Always(cond, "we should be able to query account 'world'", Details{ + "error": fmt.Sprintf("%+v\n", err), + }); !cond { + return + } + + output := account.V2AccountResponse.Data.Volumes["USD/2"].Output + + cond = output != nil + if assert.Always(cond, "Expect output of world for USD/2 to be not empty", Details{}); !cond { + return + } + fmt.Printf("Expect output of world to be %s and got %d\r\n", totalAmount, output) + assert.Always( + output.Cmp(totalAmount) == 0, + "output of 'world' should match", + Details{ + "output": output, + }, + ) +} + +func runTx(ctx context.Context, client *client.Formance, amount *big.Int) (*big.Int, error) { + orderID := fmt.Sprint(int64(math.Abs(float64(random.GetRandom())))) + dest := fmt.Sprintf("orders:%s", orderID) + + res, err := client.Ledger.V2.CreateTransaction(ctx, operations.V2CreateTransactionRequest{ + V2PostTransaction: components.V2PostTransaction{ + Postings: []components.V2Posting{{ + Amount: amount, + Asset: "USD/2", + Destination: dest, + Source: "world", + }}, + }, + Ledger: "default", + }) + + assert.Always( + err == nil, + "creating transaction from @world to $account always return a nil error", + Details{ + "error": fmt.Sprintf("%+v\n", err), + }, + ) + + return res.V2CreateTransactionResponse.Data.ID, err +} diff --git a/test/antithesis/workload/go.mod b/test/antithesis/workload/go.mod new file mode 100644 index 0000000000..5a614925e5 --- /dev/null +++ b/test/antithesis/workload/go.mod @@ -0,0 +1,24 @@ +module github.com/formancehq/ledger/test/antithesis + +go 1.21 + +toolchain go1.22.0 + +replace github.com/formancehq/ledger/pkg/client => ../../../pkg/client + +require ( + github.com/alitto/pond v1.8.3 + github.com/antithesishq/antithesis-sdk-go v0.3.8 + github.com/formancehq/formance-sdk-go/v2 v2.1.3 + github.com/formancehq/ledger/pkg/client v0.0.0-00010101000000-000000000000 + github.com/formancehq/stack/libs/go-libs v0.0.0-20240412081813-558ce638a33b + go.uber.org/atomic v1.10.0 +) + +require ( + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/ericlagergren/decimal v0.0.0-20240411145413-00de7ca16731 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/spf13/cobra v1.8.1 // indirect + github.com/spf13/pflag v1.0.5 // indirect +) diff --git a/test/antithesis/workload/go.sum b/test/antithesis/workload/go.sum new file mode 100644 index 0000000000..8bc0368e56 --- /dev/null +++ b/test/antithesis/workload/go.sum @@ -0,0 +1,31 @@ +github.com/alitto/pond v1.8.3 h1:ydIqygCLVPqIX/USe5EaV/aSRXTRXDEI9JwuDdu+/xs= +github.com/alitto/pond v1.8.3/go.mod h1:CmvIIGd5jKLasGI3D87qDkQxjzChdKMmnXMg3fG6M6Q= +github.com/antithesishq/antithesis-sdk-go v0.3.8 h1:OvGoHxIcOXFJLyn9IJQ5DzByZ3YVAWNBc394ObzDRb8= +github.com/antithesishq/antithesis-sdk-go v0.3.8/go.mod h1:IUpT2DPAKh6i/YhSbt6Gl3v2yvUZjmKncl7U91fup7E= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/ericlagergren/decimal v0.0.0-20240411145413-00de7ca16731 h1:R/ZjJpjQKsZ6L/+Gf9WHbt31GG8NMVcpRqUE+1mMIyo= +github.com/ericlagergren/decimal v0.0.0-20240411145413-00de7ca16731/go.mod h1:M9R1FoZ3y//hwwnJtO51ypFGwm8ZfpxPT/ZLtO1mcgQ= +github.com/formancehq/formance-sdk-go/v2 v2.1.3 h1:9RpF1DkkJZWsKO2sFgF6DVr0bEaCUYNdI6bC3J0Yrz0= +github.com/formancehq/formance-sdk-go/v2 v2.1.3/go.mod h1:NjU319mP7CaRRpCEAuqP4biPuCBLd+OY5hD8PYOG+JY= +github.com/formancehq/stack/libs/go-libs v0.0.0-20240412081813-558ce638a33b h1:Z1DaupQL+i5dgZjCnhdGDs2Zevzv8DuyCSddnnDWjBw= +github.com/formancehq/stack/libs/go-libs v0.0.0-20240412081813-558ce638a33b/go.mod h1:YdhBeBSjIECXCw7g5V1Ie9LxFCXCme0s15lP2D6grVU= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= +go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/test/antithesis/workload/main.go b/test/antithesis/workload/main.go new file mode 100644 index 0000000000..3ef2e966d4 --- /dev/null +++ b/test/antithesis/workload/main.go @@ -0,0 +1,11 @@ +/* +Copyright © 2024 NAME HERE + +*/ +package main + +import "github.com/formancehq/ledger/test/antithesis/cmd" + +func main() { + cmd.Execute() +} From df41f3d685dec961dc48434e17eda3542f22153c Mon Sep 17 00:00:00 2001 From: Geoffrey Ragot Date: Wed, 13 Nov 2024 11:24:41 +0100 Subject: [PATCH 02/27] chore: some test --- test/antithesis/config/docker-compose.yml | 7 +------ test/antithesis/config/gateway/Caddyfile | 5 ++++- test/antithesis/workload/cmd/run.go | 4 +++- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/test/antithesis/config/docker-compose.yml b/test/antithesis/config/docker-compose.yml index 3d33654d9b..79a1da0fd3 100644 --- a/test/antithesis/config/docker-compose.yml +++ b/test/antithesis/config/docker-compose.yml @@ -79,9 +79,4 @@ services: ipv4_address: 10.0.29.20 depends_on: - ledger1 - - ledger2 - healthcheck: - test: curl --fail http://localhost:8080 || exit 1 - interval: 2s - retries: 5 - start_period: 1s \ No newline at end of file + - ledger2 \ No newline at end of file diff --git a/test/antithesis/config/gateway/Caddyfile b/test/antithesis/config/gateway/Caddyfile index 2eb65652c7..95dd650008 100644 --- a/test/antithesis/config/gateway/Caddyfile +++ b/test/antithesis/config/gateway/Caddyfile @@ -5,5 +5,8 @@ } :8080 { - reverse_proxy ledger1:8080 ledger2:8080 + reverse_proxy { + to ledger1:8080 ledger2:8080 + lb_policy first + } } diff --git a/test/antithesis/workload/cmd/run.go b/test/antithesis/workload/cmd/run.go index 42b1cb24b6..79fd06ae3c 100644 --- a/test/antithesis/workload/cmd/run.go +++ b/test/antithesis/workload/cmd/run.go @@ -23,6 +23,7 @@ func run(cmd *cobra.Command, _ []string) { ) waitServicesReady(cmd.Context(), client) + <-time.After(10 * time.Second) runWorkload(cmd.Context(), client) } @@ -36,7 +37,6 @@ func createLedger(ctx context.Context, client *client.Formance) error { _, err := client.Ledger.V2.CreateLedger(ctx, operations.V2CreateLedgerRequest{ Ledger: "default", }) - fmt.Println("Ledger created!") if assert.Always(err == nil, "ledger should have been created", Details{ "error": fmt.Sprintf("%+v\n", err), @@ -44,5 +44,7 @@ func createLedger(ctx context.Context, client *client.Formance) error { return err } + fmt.Println("Ledger created!") + return nil } From eead415e8d400f41ca3c91daeb4d6b095e9041d0 Mon Sep 17 00:00:00 2001 From: Geoffrey Ragot Date: Wed, 13 Nov 2024 21:32:03 +0100 Subject: [PATCH 03/27] feat: first workable setup --- go.mod | 26 +++--- go.sum | 56 +++++------ test/antithesis/Earthfile | 25 ++--- test/antithesis/config/Earthfile | 3 +- test/antithesis/config/docker-compose.yml | 6 ++ test/antithesis/image/Earthfile | 5 +- test/antithesis/workload/Earthfile | 74 +++++++++++---- .../main.go | 30 ++++++ .../cmds/singleton_driver_main/main.go} | 93 ++++++++----------- test/antithesis/workload/bin/init/main.go | 35 +++++++ test/antithesis/workload/cmd/lifecycle.go | 31 ------- test/antithesis/workload/cmd/root.go | 30 ------ test/antithesis/workload/cmd/run.go | 50 ---------- test/antithesis/workload/cmd/utils.go | 59 ------------ test/antithesis/workload/cmd/utils_test.go | 20 ---- test/antithesis/workload/go.mod | 19 ++-- test/antithesis/workload/go.sum | 44 +++++---- test/antithesis/workload/internal/utils.go | 50 ++++++++++ test/antithesis/workload/main.go | 11 --- test/rolling-upgrades/go.mod | 2 +- test/rolling-upgrades/go.sum | 4 +- tools/generator/go.mod | 2 +- tools/generator/go.sum | 56 +++++------ 23 files changed, 332 insertions(+), 399 deletions(-) create mode 100644 test/antithesis/workload/bin/cmds/eventually_aggregated_volumes_should_be_zeroed/main.go rename test/antithesis/workload/{cmd/workload.go => bin/cmds/singleton_driver_main/main.go} (50%) create mode 100644 test/antithesis/workload/bin/init/main.go delete mode 100644 test/antithesis/workload/cmd/lifecycle.go delete mode 100644 test/antithesis/workload/cmd/root.go delete mode 100644 test/antithesis/workload/cmd/run.go delete mode 100644 test/antithesis/workload/cmd/utils.go delete mode 100644 test/antithesis/workload/cmd/utils_test.go create mode 100644 test/antithesis/workload/internal/utils.go delete mode 100644 test/antithesis/workload/main.go diff --git a/go.mod b/go.mod index 2fca2d73fb..12f9eba8f6 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 github.com/bluele/gcache v0.0.2 github.com/dop251/goja v0.0.0-20241009100908-5f46f2705ca3 - github.com/formancehq/go-libs/v2 v2.0.1-0.20241114125605-4a3e447246a9 + github.com/formancehq/go-libs/v2 v2.0.1-0.20241119202934-d93d89fd8778 github.com/formancehq/ledger/pkg/client v0.0.0-00010101000000-000000000000 github.com/go-chi/chi/v5 v5.1.0 github.com/go-chi/cors v1.2.1 @@ -68,20 +68,20 @@ require ( github.com/ajg/form v1.5.1 // indirect github.com/antlr4-go/antlr/v4 v4.13.1 // indirect github.com/aws/aws-msk-iam-sasl-signer-go v1.0.0 // indirect - github.com/aws/aws-sdk-go-v2 v1.32.4 // indirect - github.com/aws/aws-sdk-go-v2/config v1.28.3 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.17.44 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.19 // indirect + github.com/aws/aws-sdk-go-v2 v1.32.5 // indirect + github.com/aws/aws-sdk-go-v2/config v1.28.5 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.17.46 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.20 // indirect github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.4.23 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.23 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.23 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.4 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.24.5 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.4 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.32.4 // indirect - github.com/aws/smithy-go v1.22.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.5 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.24.6 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.33.1 // indirect + github.com/aws/smithy-go v1.22.1 // indirect github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/buger/jsonparser v1.1.1 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect diff --git a/go.sum b/go.sum index 1cb9b579f5..45e793ceed 100644 --- a/go.sum +++ b/go.sum @@ -30,34 +30,34 @@ github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYW github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw= github.com/aws/aws-msk-iam-sasl-signer-go v1.0.0 h1:UyjtGmO0Uwl/K+zpzPwLoXzMhcN9xmnR2nrqJoBrg3c= github.com/aws/aws-msk-iam-sasl-signer-go v1.0.0/go.mod h1:TJAXuFs2HcMib3sN5L0gUC+Q01Qvy3DemvA55WuC+iA= -github.com/aws/aws-sdk-go-v2 v1.32.4 h1:S13INUiTxgrPueTmrm5DZ+MiAo99zYzHEFh1UNkOxNE= -github.com/aws/aws-sdk-go-v2 v1.32.4/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo= -github.com/aws/aws-sdk-go-v2/config v1.28.3 h1:kL5uAptPcPKaJ4q0sDUjUIdueO18Q7JDzl64GpVwdOM= -github.com/aws/aws-sdk-go-v2/config v1.28.3/go.mod h1:SPEn1KA8YbgQnwiJ/OISU4fz7+F6Fe309Jf0QTsRCl4= -github.com/aws/aws-sdk-go-v2/credentials v1.17.44 h1:qqfs5kulLUHUEXlHEZXLJkgGoF3kkUeFUTVA585cFpU= -github.com/aws/aws-sdk-go-v2/credentials v1.17.44/go.mod h1:0Lm2YJ8etJdEdw23s+q/9wTpOeo2HhNE97XcRa7T8MA= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.19 h1:woXadbf0c7enQ2UGCi8gW/WuKmE0xIzxBF/eD94jMKQ= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.19/go.mod h1:zminj5ucw7w0r65bP6nhyOd3xL6veAUMc3ElGMoLVb4= +github.com/aws/aws-sdk-go-v2 v1.32.5 h1:U8vdWJuY7ruAkzaOdD7guwJjD06YSKmnKCJs7s3IkIo= +github.com/aws/aws-sdk-go-v2 v1.32.5/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U= +github.com/aws/aws-sdk-go-v2/config v1.28.5 h1:Za41twdCXbuyyWv9LndXxZZv3QhTG1DinqlFsSuvtI0= +github.com/aws/aws-sdk-go-v2/config v1.28.5/go.mod h1:4VsPbHP8JdcdUDmbTVgNL/8w9SqOkM5jyY8ljIxLO3o= +github.com/aws/aws-sdk-go-v2/credentials v1.17.46 h1:AU7RcriIo2lXjUfHFnFKYsLCwgbz1E7Mm95ieIRDNUg= +github.com/aws/aws-sdk-go-v2/credentials v1.17.46/go.mod h1:1FmYyLGL08KQXQ6mcTlifyFXfJVCNJTVGuQP4m0d/UA= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.20 h1:sDSXIrlsFSFJtWKLQS4PUWRvrT580rrnuLydJrCQ/yA= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.20/go.mod h1:WZ/c+w0ofps+/OUqMwWgnfrgzZH1DZO1RIkktICsqnY= github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.4.23 h1:B2qK61ZXCQu8tkD6eG/gUiIt9Vw9tmWFD7Xo02JPdMY= github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.4.23/go.mod h1:02rz9vMZsrOX9IwUcpoGZM4jPprFNPmtD6t9Ume9ECY= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.23 h1:A2w6m6Tmr+BNXjDsr7M90zkWjsu4JXHwrzPg235STs4= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.23/go.mod h1:35EVp9wyeANdujZruvHiQUAo9E3vbhnIO1mTCAxMlY0= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.23 h1:pgYW9FCabt2M25MoHYCfMrVY2ghiiBKYWUVXfwZs+sU= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.23/go.mod h1:c48kLgzO19wAu3CPkDWC28JbaJ+hfQlsdl7I2+oqIbk= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24 h1:4usbeaes3yJnCFC7kfeyhkdkPtoRYPa/hTmCqMpKpLI= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24/go.mod h1:5CI1JemjVwde8m2WG3cz23qHKPOxbpkq0HaoreEgLIY= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24 h1:N1zsICrQglfzaBnrfM0Ys00860C+QFwu6u/5+LomP+o= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24/go.mod h1:dCn9HbJ8+K31i8IQ8EWmWj0EiIk0+vKiHNMxTTYveAg= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 h1:TToQNkvGguu209puTojY/ozlqy2d/SFNcoLIqTFi42g= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0/go.mod h1:0jp+ltwkf+SwG2fm/PKo8t4y8pJSgOCO4D8Lz3k0aHQ= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.4 h1:tHxQi/XHPK0ctd/wdOw0t7Xrc2OxcRCnVzv8lwWPu0c= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.4/go.mod h1:4GQbF1vJzG60poZqWatZlhP31y8PGCCVTvIGPdaaYJ0= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.5 h1:HJwZwRt2Z2Tdec+m+fPjvdmkq2s9Ra+VR0hjF7V2o40= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.5/go.mod h1:wrMCEwjFPms+V86TCQQeOxQF/If4vT44FGIOFiMC2ck= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.4 h1:zcx9LiGWZ6i6pjdcoE9oXAB6mUdeyC36Ia/QEiIvYdg= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.4/go.mod h1:Tp/ly1cTjRLGBBmNccFumbZ8oqpZlpdhFf80SrRh4is= -github.com/aws/aws-sdk-go-v2/service/sts v1.32.4 h1:yDxvkz3/uOKfxnv8YhzOi9m+2OGIxF+on3KOISbK5IU= -github.com/aws/aws-sdk-go-v2/service/sts v1.32.4/go.mod h1:9XEUty5v5UAsMiFOBJrNibZgwCeOma73jgGwwhgffa8= -github.com/aws/smithy-go v1.22.0 h1:uunKnWlcoL3zO7q+gG2Pk53joueEOsnNB28QdMsmiMM= -github.com/aws/smithy-go v1.22.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 h1:iXtILhvDxB6kPvEXgsDhGaZCSC6LQET5ZHSdJozeI0Y= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1/go.mod h1:9nu0fVANtYiAePIBh2/pFUSwtJ402hLnp854CNoDOeE= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.5 h1:wtpJ4zcwrSbwhECWQoI/g6WM9zqCcSpHDJIWSbMLOu4= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.5/go.mod h1:qu/W9HXQbbQ4+1+JcZp0ZNPV31ym537ZJN+fiS7Ti8E= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.6 h1:3zu537oLmsPfDMyjnUS2g+F2vITgy5pB74tHI+JBNoM= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.6/go.mod h1:WJSZH2ZvepM6t6jwu4w/Z45Eoi75lPN7DcydSRtJg6Y= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5 h1:K0OQAsDywb0ltlFrZm0JHPY3yZp/S9OaoLU33S7vPS8= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5/go.mod h1:ORITg+fyuMoeiQFiVGoqB3OydVTLkClw/ljbblMq6Cc= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.1 h1:6SZUVRQNvExYlMLbHdlKB48x0fLbc2iVROyaNEwBHbU= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.1/go.mod h1:GqWyYCwLXnlUB1lOAXQyNSPqPLQJvmo8J0DWBzp9mtg= +github.com/aws/smithy-go v1.22.1 h1:/HPHZQ0g7f4eUeK6HKglFz8uwVfZKgoI25rb/J+dnro= +github.com/aws/smithy-go v1.22.1/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw= @@ -104,8 +104,8 @@ github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/formancehq/go-libs/v2 v2.0.1-0.20241114125605-4a3e447246a9 h1:l6jieaR+sn4Ff+puBDMbTYmT2HTYC7Yt7GTxBAwC3eU= -github.com/formancehq/go-libs/v2 v2.0.1-0.20241114125605-4a3e447246a9/go.mod h1:m0uKkey9OC/AeyWMwjMfZqhLzoWrPFBk8vuYdSSYj4Y= +github.com/formancehq/go-libs/v2 v2.0.1-0.20241119202934-d93d89fd8778 h1:k/PmHjR692rBLxCanof/lD0c1K8WLKCNYCl5y1EHJPg= +github.com/formancehq/go-libs/v2 v2.0.1-0.20241119202934-d93d89fd8778/go.mod h1:6vkHEfWEkDSPOv/G2o1Exxra3ouuYxRiCkznwKxTMHU= github.com/formancehq/numscript v0.0.9-0.20241009144012-1150c14a1417 h1:LOd5hxnXDIBcehFrpW1OnXk+VSs0yJXeu1iAOO+Hji4= github.com/formancehq/numscript v0.0.9-0.20241009144012-1150c14a1417/go.mod h1:btuSv05cYwi9BvLRxVs5zrunU+O1vTgigG1T6UsawcY= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= @@ -142,8 +142,8 @@ github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIx github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/mock v1.7.0-rc.1 h1:YojYx61/OLFsiv6Rw1Z96LpldJIy31o+UHmwAUMJ6/U= +github.com/golang/mock v1.7.0-rc.1/go.mod h1:s42URUywIqd+OcERslBJvOjepvNymP31m3q8d/GkuRs= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= diff --git a/test/antithesis/Earthfile b/test/antithesis/Earthfile index a11d104882..ff11c9213b 100644 --- a/test/antithesis/Earthfile +++ b/test/antithesis/Earthfile @@ -5,11 +5,8 @@ IMPORT github.com/formancehq/earthly:tags/v0.17.1 AS core FROM core+base-image run: - COPY ../..+sources/src /src - LET TAG=$(tar cf - /src | sha1sum | awk '{print $1}') - WAIT - BUILD +requirements-build --TAG=$TAG + BUILD +requirements-build END FROM curlimages/curl @@ -22,25 +19,17 @@ run: \"params\": { \"custom.duration\": \"0.1\", \"antithesis.report.recipients\": \"${ANTITHESIS_SLACK_REPORT_RECIPIENT}\", - \"antithesis.config_image\": \"antithesis-config-dev:$TAG\", - \"antithesis.images\": \"ledger:$TAG;workload:$TAG\" + \"antithesis.config_image\": \"antithesis-config:latest\", + \"antithesis.images\": \"ledger:latest;workload:latest\" } }" -run-local: - LOCALLY - - WAIT - BUILD +requirements-build - END - - RUN --no-cache docker compose -f config/docker-compose.yml up workload - RUN --no-cache docker compose -f config/docker-compose.yml down -v - requirements-build: - ARG TAG=latest ARG --required ANTITHESIS_REPOSITORY BUILD --pass-args ./config+build BUILD --pass-args ./image+build - BUILD --pass-args ./workload+build \ No newline at end of file + BUILD --pass-args ./workload+build + +pre-commit: + BUILD ./workload+pre-commit \ No newline at end of file diff --git a/test/antithesis/config/Earthfile b/test/antithesis/config/Earthfile index 936b8c4dfc..201f9c5094 100644 --- a/test/antithesis/config/Earthfile +++ b/test/antithesis/config/Earthfile @@ -4,9 +4,8 @@ IMPORT github.com/formancehq/earthly:tags/v0.17.1 AS core build: FROM --platform=linux/amd64 scratch - ARG TAG=latest ARG --required ANTITHESIS_REPOSITORY COPY docker-compose.yml /docker-compose.yml COPY --dir gateway /gateway - SAVE IMAGE --push --no-manifest-list ${ANTITHESIS_REPOSITORY}/antithesis-config-dev:$TAG \ No newline at end of file + SAVE IMAGE --push --no-manifest-list ${ANTITHESIS_REPOSITORY}/antithesis-config:latest \ No newline at end of file diff --git a/test/antithesis/config/docker-compose.yml b/test/antithesis/config/docker-compose.yml index 79a1da0fd3..8de28914a9 100644 --- a/test/antithesis/config/docker-compose.yml +++ b/test/antithesis/config/docker-compose.yml @@ -35,6 +35,9 @@ services: environment: POSTGRES_URI: "postgresql://ledger:ledger@10.0.29.16:5432/ledger?sslmode=disable" BIND: ":8080" + POSTGRES_CONN_MAX_IDLE_TIME: "1m0s" + POSTGRES_MAX_IDLE_CONNS: "20" + POSTGRES_MAX_OPEN_CONNS: "20" networks: formance: ipv4_address: 10.0.29.17 @@ -48,6 +51,9 @@ services: container_name: ledger2 environment: POSTGRES_URI: "postgresql://ledger:ledger@10.0.29.16:5432/ledger?sslmode=disable" + POSTGRES_CONN_MAX_IDLE_TIME: "1m0s" + POSTGRES_MAX_IDLE_CONNS: "20" + POSTGRES_MAX_OPEN_CONNS: "20" BIND: ":8080" networks: formance: diff --git a/test/antithesis/image/Earthfile b/test/antithesis/image/Earthfile index eef58211bf..b6b9b5e071 100644 --- a/test/antithesis/image/Earthfile +++ b/test/antithesis/image/Earthfile @@ -21,7 +21,6 @@ compile: RUN /go/bin/antithesis-go-instrumentor . /ledger_instrumented WORKDIR /ledger_instrumented/customer - RUN go mod download RUN go build -race -o ledger SAVE ARTIFACT /ledger_instrumented/customer/ledger @@ -30,13 +29,11 @@ compile: build: FROM --platform=linux/amd64 ubuntu:latest RUN apt-get update -y && apt-get install -y postgresql-client curl - ARG TAG=latest COPY (+compile/ledger) /bin/ledger COPY (+compile/symbols) /symbols COPY entrypoint.sh /bin/entrypoint.sh - RUN chmod 777 /bin/ledger RUN chmod 777 /bin/entrypoint.sh ENTRYPOINT ["/bin/entrypoint.sh"] @@ -44,4 +41,4 @@ build: ARG --required ANTITHESIS_REPOSITORY - SAVE IMAGE --push --no-manifest-list "${ANTITHESIS_REPOSITORY}/ledger:${TAG}" \ No newline at end of file + SAVE IMAGE --push --no-manifest-list "${ANTITHESIS_REPOSITORY}/ledger:latest" \ No newline at end of file diff --git a/test/antithesis/workload/Earthfile b/test/antithesis/workload/Earthfile index bd792457fd..fb4aa9f202 100644 --- a/test/antithesis/workload/Earthfile +++ b/test/antithesis/workload/Earthfile @@ -4,6 +4,44 @@ FROM --platform=linux/amd64 golang:1.22.2 CACHE --sharing=shared --id go-mod-cache /go/pkg/mod CACHE --sharing=shared --id go-cache /root/.cache/go-build +CACHE --sharing=shared --id golangci-cache /root/.cache/golangci-lint + +sources: + COPY --dir ../../..+lint/* /src/ + COPY ../../..+tidy/* /src/ + + WORKDIR /src/test/antithesis/workload + COPY go.* . + COPY --dir bin internal . + + SAVE ARTIFACT /src + +tidy: + FROM +sources + + CACHE --id go-mod-cache /go/pkg/mod + CACHE --id go-cache /root/.cache/go-build + + WORKDIR /src/test/antithesis/workload + RUN go mod tidy + + SAVE ARTIFACT go.mod AS LOCAL go.mod + SAVE ARTIFACT go.sum AS LOCAL go.sum + +lint: + #todo: get config from core + FROM +tidy + + RUN curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.61.0 + + CACHE --id go-mod-cache /go/pkg/mod + CACHE --id go-cache /root/.cache/go-build + CACHE --id golangci-cache /root/.cache/golangci-lint + + RUN golangci-lint run --fix --timeout 5m + + SAVE ARTIFACT bin AS LOCAL bin + SAVE ARTIFACT internal AS LOCAL internal compile: CACHE --id go-mod-cache /go/pkg/mod @@ -11,30 +49,32 @@ compile: RUN go install github.com/antithesishq/antithesis-sdk-go/tools/antithesis-go-instrumentor@latest - COPY ../../..+lint/pkg /src/pkg - COPY ../../..+lint/internal /src/internal - COPY ../../..+lint/cmd /src/cmd - COPY ../../..+lint/*.go /src/ - COPY ../../..+tidy/go.mod /src/ - COPY ../../..+tidy/go.sum /src/ + COPY +sources/src /src WORKDIR /src/test/antithesis/workload - COPY *.go go.* . - COPY --dir cmd . - RUN mkdir -p /workload_instrumented - RUN /go/bin/antithesis-go-instrumentor -assert_only . - RUN go build -o main + RUN mkdir -p /out/cmds + + RUN antithesis-go-instrumentor -assert_only . + RUN go build -o /out/init ./bin/init + + FOR file IN $(ls bin/cmds) + RUN go build -o /out/cmds/$file ./bin/cmds/$file + END - SAVE ARTIFACT main + SAVE ARTIFACT /out build: FROM --platform=linux/amd64 ubuntu:latest - ARG TAG=latest - COPY (+compile/main) /bin/workload - RUN chmod 777 /bin/workload - ENTRYPOINT ["/bin/workload"] + COPY (+compile/out/init) /init + ENTRYPOINT ["/init"] + + COPY (+compile/out/cmds/*) /opt/antithesis/test/v1/main/ ARG --required ANTITHESIS_REPOSITORY - SAVE IMAGE --push --no-manifest-list ${ANTITHESIS_REPOSITORY}/workload:${TAG} \ No newline at end of file + SAVE IMAGE --push --no-manifest-list ${ANTITHESIS_REPOSITORY}/workload:latest + +pre-commit: + BUILD +tidy + BUILD +lint \ No newline at end of file diff --git a/test/antithesis/workload/bin/cmds/eventually_aggregated_volumes_should_be_zeroed/main.go b/test/antithesis/workload/bin/cmds/eventually_aggregated_volumes_should_be_zeroed/main.go new file mode 100644 index 0000000000..959a32bd47 --- /dev/null +++ b/test/antithesis/workload/bin/cmds/eventually_aggregated_volumes_should_be_zeroed/main.go @@ -0,0 +1,30 @@ +package main + +import ( + "context" + "github.com/antithesishq/antithesis-sdk-go/assert" + "github.com/formancehq/ledger/pkg/client/models/operations" + "github.com/formancehq/ledger/test/antithesis/internal" + "math/big" +) + +func main() { + ctx := context.Background() + client := internal.NewClient() + + aggregated, err := client.Ledger.V2.GetBalancesAggregated(ctx, operations.V2GetBalancesAggregatedRequest{ + Ledger: "default", + }) + if err != nil { + assert.Always(err == nil, "error getting aggregated balances", internal.Details{ + "error": err, + }) + return + } + + for asset, volumes := range aggregated.V2AggregateBalancesResponse.Data { + assert.Always(volumes.Cmp(new(big.Int)) == 0, "aggregated volumes for asset "+asset+" should be 0", internal.Details{ + "error": err, + }) + } +} diff --git a/test/antithesis/workload/cmd/workload.go b/test/antithesis/workload/bin/cmds/singleton_driver_main/main.go similarity index 50% rename from test/antithesis/workload/cmd/workload.go rename to test/antithesis/workload/bin/cmds/singleton_driver_main/main.go index c5c1fb5f65..ca295a9a20 100644 --- a/test/antithesis/workload/cmd/workload.go +++ b/test/antithesis/workload/bin/cmds/singleton_driver_main/main.go @@ -1,115 +1,105 @@ -package cmd +package main import ( "context" "fmt" "github.com/alitto/pond" "github.com/antithesishq/antithesis-sdk-go/assert" - "github.com/antithesishq/antithesis-sdk-go/lifecycle" "github.com/antithesishq/antithesis-sdk-go/random" + "github.com/formancehq/go-libs/v2/pointer" "github.com/formancehq/ledger/pkg/client" "github.com/formancehq/ledger/pkg/client/models/components" "github.com/formancehq/ledger/pkg/client/models/operations" - "github.com/formancehq/stack/libs/go-libs/pointer" + "github.com/formancehq/ledger/test/antithesis/internal" "go.uber.org/atomic" "math" "math/big" ) -func runWorkload(ctx context.Context, client *client.Formance) { +func main() { + ctx := context.Background() + client := internal.NewClient() + err := createLedger(ctx, client) if err != nil { - assert.Always(err == nil, "ledger should have been created", Details{ + assert.Always(err == nil, "ledger should have been created", internal.Details{ "error": err, }) return } - lifecycle.SetupComplete(Details{ - "Ledger": "Available", - }) - const count = 1000 hasError := atomic.NewBool(false) totalAmount := big.NewInt(0) - idSeq := NewIDSeq() - pool := pond.New(20, 10000) + pool := pond.New(10, 10000) - fmt.Printf("Insert %d transactions...\r\n", count) for i := 0; i < count; i++ { - amount := randomBigInt() + amount := internal.RandomBigInt() totalAmount = totalAmount.Add(totalAmount, amount) pool.Submit(func() { - id, err := runTx(ctx, client, amount) - - if err != nil { + if !internal.AssertAlwaysErrNil( + runTx(ctx, client, amount), + "creating transaction from @world to $account always return a nil error", + ) { hasError.CompareAndSwap(false, true) - return } - - idSeq.Register(id) }) } pool.StopAndWait() - //err = idSeq.Check() - //assert.Always(err == nil, "IDSeq check should pass", Details{ - // "count": idSeq.Count, - // "sum": idSeq.Sum, - //}) - // - //if err != nil { - // fmt.Println("Error checking ID sequence", err) - // hasError.CompareAndSwap(false, true) - // os.Exit(1) - // return - //} - cond := !hasError.Load() - if assert.Always(cond, "all transactions should have been written", Details{ - "error": fmt.Sprintf("%+v\n", err), - }); !cond { + if assert.Always(cond, "all transactions should have been written", internal.Details{}); !cond { return } - fmt.Println("Checking balance of 'world'...") account, err := client.Ledger.V2.GetAccount(ctx, operations.V2GetAccountRequest{ Address: "world", Expand: pointer.For("volumes"), Ledger: "default", }) - cond = err == nil - if assert.Always(cond, "we should be able to query account 'world'", Details{ - "error": fmt.Sprintf("%+v\n", err), - }); !cond { + if !internal.AssertAlwaysErrNil(err, "we should be able to query account 'world'") { return } output := account.V2AccountResponse.Data.Volumes["USD/2"].Output - cond = output != nil - if assert.Always(cond, "Expect output of world for USD/2 to be not empty", Details{}); !cond { + if !internal.AssertAlways(output != nil, "Expect output of world for USD/2 to be not empty", internal.Details{}) { return } - fmt.Printf("Expect output of world to be %s and got %d\r\n", totalAmount, output) + assert.Always( output.Cmp(totalAmount) == 0, "output of 'world' should match", - Details{ + internal.Details{ "output": output, }, ) } -func runTx(ctx context.Context, client *client.Formance, amount *big.Int) (*big.Int, error) { +func createLedger(ctx context.Context, client *client.Formance) error { + + _, err := client.Ledger.V2.CreateLedger(ctx, operations.V2CreateLedgerRequest{ + Ledger: "default", + }) + + if assert.Always(err == nil, "ledger should have been created", internal.Details{ + "error": fmt.Sprintf("%+v\n", err), + }); err != nil { + return err + } + + return nil +} + +func runTx(ctx context.Context, client *client.Formance, amount *big.Int) error { orderID := fmt.Sprint(int64(math.Abs(float64(random.GetRandom())))) dest := fmt.Sprintf("orders:%s", orderID) - res, err := client.Ledger.V2.CreateTransaction(ctx, operations.V2CreateTransactionRequest{ + _, err := client.Ledger.V2.CreateTransaction(ctx, operations.V2CreateTransactionRequest{ V2PostTransaction: components.V2PostTransaction{ Postings: []components.V2Posting{{ Amount: amount, @@ -120,14 +110,5 @@ func runTx(ctx context.Context, client *client.Formance, amount *big.Int) (*big. }, Ledger: "default", }) - - assert.Always( - err == nil, - "creating transaction from @world to $account always return a nil error", - Details{ - "error": fmt.Sprintf("%+v\n", err), - }, - ) - - return res.V2CreateTransactionResponse.Data.ID, err + return err } diff --git a/test/antithesis/workload/bin/init/main.go b/test/antithesis/workload/bin/init/main.go new file mode 100644 index 0000000000..a469dbe5d3 --- /dev/null +++ b/test/antithesis/workload/bin/init/main.go @@ -0,0 +1,35 @@ +package main + +import ( + "context" + "github.com/antithesishq/antithesis-sdk-go/lifecycle" + "github.com/formancehq/ledger/test/antithesis/internal" + "os" + "os/signal" + "syscall" + "time" +) + +func main() { + ctx := context.Background() + client := internal.NewClient() + + for { + time.Sleep(time.Second) + + _, err := client.Ledger.GetInfo(ctx) + if err != nil { + continue + } + break + } + + lifecycle.SetupComplete(map[string]any{ + "Ledger": "Available", + }) + + sigs := make(chan os.Signal, 1) + signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) + + <-sigs +} diff --git a/test/antithesis/workload/cmd/lifecycle.go b/test/antithesis/workload/cmd/lifecycle.go deleted file mode 100644 index f649e02954..0000000000 --- a/test/antithesis/workload/cmd/lifecycle.go +++ /dev/null @@ -1,31 +0,0 @@ -package cmd - -import ( - "context" - "fmt" - "github.com/formancehq/ledger/pkg/client" - "os" - "time" -) - -func waitServicesReady(ctx context.Context, client *client.Formance) { - fmt.Println("Waiting for services to be ready") - waitingServicesCtx, cancel := context.WithDeadline(ctx, time.Now().Add(30*time.Second)) - defer cancel() - - for { - select { - case <-time.After(time.Second): - fmt.Println("Trying to get info of the ledger...") - _, err := client.Ledger.GetInfo(ctx) - if err != nil { - fmt.Printf("error pinging ledger: %s\r\n", err) - continue - } - return - case <-waitingServicesCtx.Done(): - fmt.Printf("timeout waiting for services to be ready\r\n") - os.Exit(1) - } - } -} diff --git a/test/antithesis/workload/cmd/root.go b/test/antithesis/workload/cmd/root.go deleted file mode 100644 index 7eac0b0d67..0000000000 --- a/test/antithesis/workload/cmd/root.go +++ /dev/null @@ -1,30 +0,0 @@ -package cmd - -import ( - "os" - - "github.com/spf13/cobra" -) - - - -// rootCmd represents the base command when called without any subcommands -var rootCmd = &cobra.Command{ - Use: "antithesis", - Run: run, -} - -// Execute adds all child commands to the root command and sets flags appropriately. -// This is called by main.main(). It only needs to happen once to the rootCmd. -func Execute() { - err := rootCmd.Execute() - if err != nil { - os.Exit(1) - } -} - -func init() { - rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") -} - - diff --git a/test/antithesis/workload/cmd/run.go b/test/antithesis/workload/cmd/run.go deleted file mode 100644 index 79fd06ae3c..0000000000 --- a/test/antithesis/workload/cmd/run.go +++ /dev/null @@ -1,50 +0,0 @@ -package cmd - -import ( - "context" - "fmt" - "github.com/formancehq/ledger/pkg/client/models/operations" - "github.com/spf13/cobra" - "net/http" - "time" - - "github.com/antithesishq/antithesis-sdk-go/assert" - "github.com/formancehq/ledger/pkg/client" -) - -type Details map[string]any - -func run(cmd *cobra.Command, _ []string) { - client := client.New( - client.WithServerURL("http://gateway:8080"), - client.WithClient(&http.Client{ - Timeout: 10 * time.Second, - }), - ) - - waitServicesReady(cmd.Context(), client) - <-time.After(10 * time.Second) - runWorkload(cmd.Context(), client) -} - -func createLedger(ctx context.Context, client *client.Formance) error { - - deadline := time.Now().Add(10 * time.Second) - ctx, cancel := context.WithDeadline(ctx, deadline) - defer cancel() - - fmt.Printf("Creating ledger with deadline %s...\r\n", deadline) - _, err := client.Ledger.V2.CreateLedger(ctx, operations.V2CreateLedgerRequest{ - Ledger: "default", - }) - - if assert.Always(err == nil, "ledger should have been created", Details{ - "error": fmt.Sprintf("%+v\n", err), - }); err != nil { - return err - } - - fmt.Println("Ledger created!") - - return nil -} diff --git a/test/antithesis/workload/cmd/utils.go b/test/antithesis/workload/cmd/utils.go deleted file mode 100644 index a98b713a79..0000000000 --- a/test/antithesis/workload/cmd/utils.go +++ /dev/null @@ -1,59 +0,0 @@ -package cmd - -import ( - "fmt" - "math/big" - "sync" - - "github.com/antithesishq/antithesis-sdk-go/random" -) - -func randomBigInt() *big.Int { - v := random.GetRandom() - ret := big.NewInt(0) - ret.SetString(fmt.Sprintf("%d", v), 10) - return ret -} - -type IDSeq struct { - sync.Mutex - Count int64 - Sum *big.Int -} - -func NewIDSeq() *IDSeq { - return &IDSeq{ - Count: 0, - Sum: big.NewInt(0), - } -} - -func (s *IDSeq) Register(id *big.Int) { - s.Lock() - defer s.Unlock() - - s.Count++ - s.Sum.Add(s.Sum, id) -} - -func (s *IDSeq) Check() error { - s.Lock() - defer s.Unlock() - - // As the IDs are generated sequentially, the - // expected sum is the sum of the first n integers - // where n is the number of IDs generated. - expectedSum := big.NewInt(0).Div( - big.NewInt(0).Mul( - big.NewInt(s.Count-1), - big.NewInt(0).Add(big.NewInt(s.Count-1), big.NewInt(1)), - ), - big.NewInt(2), - ) - - if s.Sum.Cmp(expectedSum) != 0 { - return fmt.Errorf("sum of IDs is incorrect") - } - - return nil -} diff --git a/test/antithesis/workload/cmd/utils_test.go b/test/antithesis/workload/cmd/utils_test.go deleted file mode 100644 index fd6190661b..0000000000 --- a/test/antithesis/workload/cmd/utils_test.go +++ /dev/null @@ -1,20 +0,0 @@ -package cmd - -import ( - "fmt" - "math/big" - "testing" -) - -func TestIDSeq(t *testing.T) { - idSeq := NewIDSeq() - - for i := 0; i < 10; i++ { - idSeq.Register(big.NewInt(int64(i))) - } - - if err := idSeq.Check(); err != nil { - fmt.Println(idSeq.Count, idSeq.Sum) - t.Errorf("IDSeq check failed") - } -} diff --git a/test/antithesis/workload/go.mod b/test/antithesis/workload/go.mod index 5a614925e5..6acf815dd4 100644 --- a/test/antithesis/workload/go.mod +++ b/test/antithesis/workload/go.mod @@ -1,24 +1,27 @@ module github.com/formancehq/ledger/test/antithesis -go 1.21 +go 1.22.0 -toolchain go1.22.0 +toolchain go1.23.2 replace github.com/formancehq/ledger/pkg/client => ../../../pkg/client require ( github.com/alitto/pond v1.8.3 - github.com/antithesishq/antithesis-sdk-go v0.3.8 - github.com/formancehq/formance-sdk-go/v2 v2.1.3 + github.com/antithesishq/antithesis-sdk-go v0.4.2 + github.com/formancehq/go-libs/v2 v2.0.1-0.20241114125605-4a3e447246a9 github.com/formancehq/ledger/pkg/client v0.0.0-00010101000000-000000000000 - github.com/formancehq/stack/libs/go-libs v0.0.0-20240412081813-558ce638a33b go.uber.org/atomic v1.10.0 ) require ( + github.com/bahlo/generic-list-go v0.2.0 // indirect + github.com/buger/jsonparser v1.1.1 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/ericlagergren/decimal v0.0.0-20240411145413-00de7ca16731 // indirect - github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/spf13/cobra v1.8.1 // indirect - github.com/spf13/pflag v1.0.5 // indirect + github.com/invopop/jsonschema v0.12.0 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/test/antithesis/workload/go.sum b/test/antithesis/workload/go.sum index 8bc0368e56..0286b6e241 100644 --- a/test/antithesis/workload/go.sum +++ b/test/antithesis/workload/go.sum @@ -1,31 +1,35 @@ github.com/alitto/pond v1.8.3 h1:ydIqygCLVPqIX/USe5EaV/aSRXTRXDEI9JwuDdu+/xs= github.com/alitto/pond v1.8.3/go.mod h1:CmvIIGd5jKLasGI3D87qDkQxjzChdKMmnXMg3fG6M6Q= -github.com/antithesishq/antithesis-sdk-go v0.3.8 h1:OvGoHxIcOXFJLyn9IJQ5DzByZ3YVAWNBc394ObzDRb8= -github.com/antithesishq/antithesis-sdk-go v0.3.8/go.mod h1:IUpT2DPAKh6i/YhSbt6Gl3v2yvUZjmKncl7U91fup7E= +github.com/antithesishq/antithesis-sdk-go v0.4.2 h1:cYLNRnojCYp6rKoLKdK6M9UKi9EahFXBtF6WR1vc6V0= +github.com/antithesishq/antithesis-sdk-go v0.4.2/go.mod h1:IUpT2DPAKh6i/YhSbt6Gl3v2yvUZjmKncl7U91fup7E= +github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= +github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= +github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/ericlagergren/decimal v0.0.0-20240411145413-00de7ca16731 h1:R/ZjJpjQKsZ6L/+Gf9WHbt31GG8NMVcpRqUE+1mMIyo= github.com/ericlagergren/decimal v0.0.0-20240411145413-00de7ca16731/go.mod h1:M9R1FoZ3y//hwwnJtO51ypFGwm8ZfpxPT/ZLtO1mcgQ= -github.com/formancehq/formance-sdk-go/v2 v2.1.3 h1:9RpF1DkkJZWsKO2sFgF6DVr0bEaCUYNdI6bC3J0Yrz0= -github.com/formancehq/formance-sdk-go/v2 v2.1.3/go.mod h1:NjU319mP7CaRRpCEAuqP4biPuCBLd+OY5hD8PYOG+JY= -github.com/formancehq/stack/libs/go-libs v0.0.0-20240412081813-558ce638a33b h1:Z1DaupQL+i5dgZjCnhdGDs2Zevzv8DuyCSddnnDWjBw= -github.com/formancehq/stack/libs/go-libs v0.0.0-20240412081813-558ce638a33b/go.mod h1:YdhBeBSjIECXCw7g5V1Ie9LxFCXCme0s15lP2D6grVU= -github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= -github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= -github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/formancehq/go-libs/v2 v2.0.1-0.20241114125605-4a3e447246a9 h1:l6jieaR+sn4Ff+puBDMbTYmT2HTYC7Yt7GTxBAwC3eU= +github.com/formancehq/go-libs/v2 v2.0.1-0.20241114125605-4a3e447246a9/go.mod h1:m0uKkey9OC/AeyWMwjMfZqhLzoWrPFBk8vuYdSSYj4Y= +github.com/invopop/jsonschema v0.12.0 h1:6ovsNSuvn9wEQVOyc72aycBMVQFKz7cPdMJn10CvzRI= +github.com/invopop/jsonschema v0.12.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= +github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/test/antithesis/workload/internal/utils.go b/test/antithesis/workload/internal/utils.go new file mode 100644 index 0000000000..4f0ceb21e1 --- /dev/null +++ b/test/antithesis/workload/internal/utils.go @@ -0,0 +1,50 @@ +package internal + +import ( + "fmt" + "github.com/antithesishq/antithesis-sdk-go/assert" + "github.com/antithesishq/antithesis-sdk-go/random" + "github.com/formancehq/go-libs/v2/time" + "github.com/formancehq/ledger/pkg/client" + "github.com/formancehq/ledger/pkg/client/retry" + "math/big" + "net/http" +) + +type Details map[string]any + +func RandomBigInt() *big.Int { + v := random.GetRandom() + ret := big.NewInt(0) + ret.SetString(fmt.Sprintf("%d", v), 10) + return ret +} + +func AssertAlways(condition bool, message string, details map[string]any) bool { + assert.Always(condition, message, details) + return condition +} + +func AssertAlwaysErrNil(err error, message string) bool { + return AssertAlways(err == nil, message, Details{ + "error": fmt.Sprint(err), + }) +} + +func NewClient() *client.Formance { + return client.New( + client.WithServerURL("http://gateway:8080"), + client.WithClient(&http.Client{ + Timeout: time.Minute, + }), + client.WithRetryConfig(retry.Config{ + Strategy: "backoff", + Backoff: &retry.BackoffStrategy{ + InitialInterval: 200, + Exponent: 1.5, + MaxElapsedTime: 4000, + }, + RetryConnectionErrors: true, + }), + ) +} diff --git a/test/antithesis/workload/main.go b/test/antithesis/workload/main.go deleted file mode 100644 index 3ef2e966d4..0000000000 --- a/test/antithesis/workload/main.go +++ /dev/null @@ -1,11 +0,0 @@ -/* -Copyright © 2024 NAME HERE - -*/ -package main - -import "github.com/formancehq/ledger/test/antithesis/cmd" - -func main() { - cmd.Execute() -} diff --git a/test/rolling-upgrades/go.mod b/test/rolling-upgrades/go.mod index 5d4f65e885..99d8ef9bdb 100644 --- a/test/rolling-upgrades/go.mod +++ b/test/rolling-upgrades/go.mod @@ -9,7 +9,7 @@ replace github.com/formancehq/ledger/pkg/client => ../../pkg/client replace github.com/formancehq/ledger => ../.. require ( - github.com/formancehq/go-libs/v2 v2.0.1-0.20241114125605-4a3e447246a9 + github.com/formancehq/go-libs/v2 v2.0.1-0.20241119202934-d93d89fd8778 github.com/formancehq/ledger v0.0.0-00010101000000-000000000000 github.com/pulumi/pulumi-kubernetes/sdk/v4 v4.12.0 github.com/pulumi/pulumi/sdk/v3 v3.117.0 diff --git a/test/rolling-upgrades/go.sum b/test/rolling-upgrades/go.sum index e9ab1cc7b6..c04f9517cd 100644 --- a/test/rolling-upgrades/go.sum +++ b/test/rolling-upgrades/go.sum @@ -56,8 +56,8 @@ github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= -github.com/formancehq/go-libs/v2 v2.0.1-0.20241114125605-4a3e447246a9 h1:l6jieaR+sn4Ff+puBDMbTYmT2HTYC7Yt7GTxBAwC3eU= -github.com/formancehq/go-libs/v2 v2.0.1-0.20241114125605-4a3e447246a9/go.mod h1:m0uKkey9OC/AeyWMwjMfZqhLzoWrPFBk8vuYdSSYj4Y= +github.com/formancehq/go-libs/v2 v2.0.1-0.20241119202934-d93d89fd8778 h1:k/PmHjR692rBLxCanof/lD0c1K8WLKCNYCl5y1EHJPg= +github.com/formancehq/go-libs/v2 v2.0.1-0.20241119202934-d93d89fd8778/go.mod h1:6vkHEfWEkDSPOv/G2o1Exxra3ouuYxRiCkznwKxTMHU= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE= diff --git a/tools/generator/go.mod b/tools/generator/go.mod index ae37af068f..756cb7acfa 100644 --- a/tools/generator/go.mod +++ b/tools/generator/go.mod @@ -9,7 +9,7 @@ replace github.com/formancehq/ledger => ../.. replace github.com/formancehq/ledger/pkg/client => ../../pkg/client require ( - github.com/formancehq/go-libs/v2 v2.0.1-0.20241114125605-4a3e447246a9 + github.com/formancehq/go-libs/v2 v2.0.1-0.20241119202934-d93d89fd8778 github.com/formancehq/ledger v0.0.0-00010101000000-000000000000 github.com/formancehq/ledger/pkg/client v0.0.0-00010101000000-000000000000 github.com/spf13/cobra v1.8.1 diff --git a/tools/generator/go.sum b/tools/generator/go.sum index 44dc83bc19..aff71c5d7a 100644 --- a/tools/generator/go.sum +++ b/tools/generator/go.sum @@ -28,34 +28,34 @@ github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYW github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw= github.com/aws/aws-msk-iam-sasl-signer-go v1.0.0 h1:UyjtGmO0Uwl/K+zpzPwLoXzMhcN9xmnR2nrqJoBrg3c= github.com/aws/aws-msk-iam-sasl-signer-go v1.0.0/go.mod h1:TJAXuFs2HcMib3sN5L0gUC+Q01Qvy3DemvA55WuC+iA= -github.com/aws/aws-sdk-go-v2 v1.32.4 h1:S13INUiTxgrPueTmrm5DZ+MiAo99zYzHEFh1UNkOxNE= -github.com/aws/aws-sdk-go-v2 v1.32.4/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo= -github.com/aws/aws-sdk-go-v2/config v1.28.3 h1:kL5uAptPcPKaJ4q0sDUjUIdueO18Q7JDzl64GpVwdOM= -github.com/aws/aws-sdk-go-v2/config v1.28.3/go.mod h1:SPEn1KA8YbgQnwiJ/OISU4fz7+F6Fe309Jf0QTsRCl4= -github.com/aws/aws-sdk-go-v2/credentials v1.17.44 h1:qqfs5kulLUHUEXlHEZXLJkgGoF3kkUeFUTVA585cFpU= -github.com/aws/aws-sdk-go-v2/credentials v1.17.44/go.mod h1:0Lm2YJ8etJdEdw23s+q/9wTpOeo2HhNE97XcRa7T8MA= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.19 h1:woXadbf0c7enQ2UGCi8gW/WuKmE0xIzxBF/eD94jMKQ= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.19/go.mod h1:zminj5ucw7w0r65bP6nhyOd3xL6veAUMc3ElGMoLVb4= +github.com/aws/aws-sdk-go-v2 v1.32.5 h1:U8vdWJuY7ruAkzaOdD7guwJjD06YSKmnKCJs7s3IkIo= +github.com/aws/aws-sdk-go-v2 v1.32.5/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U= +github.com/aws/aws-sdk-go-v2/config v1.28.5 h1:Za41twdCXbuyyWv9LndXxZZv3QhTG1DinqlFsSuvtI0= +github.com/aws/aws-sdk-go-v2/config v1.28.5/go.mod h1:4VsPbHP8JdcdUDmbTVgNL/8w9SqOkM5jyY8ljIxLO3o= +github.com/aws/aws-sdk-go-v2/credentials v1.17.46 h1:AU7RcriIo2lXjUfHFnFKYsLCwgbz1E7Mm95ieIRDNUg= +github.com/aws/aws-sdk-go-v2/credentials v1.17.46/go.mod h1:1FmYyLGL08KQXQ6mcTlifyFXfJVCNJTVGuQP4m0d/UA= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.20 h1:sDSXIrlsFSFJtWKLQS4PUWRvrT580rrnuLydJrCQ/yA= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.20/go.mod h1:WZ/c+w0ofps+/OUqMwWgnfrgzZH1DZO1RIkktICsqnY= github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.4.23 h1:B2qK61ZXCQu8tkD6eG/gUiIt9Vw9tmWFD7Xo02JPdMY= github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.4.23/go.mod h1:02rz9vMZsrOX9IwUcpoGZM4jPprFNPmtD6t9Ume9ECY= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.23 h1:A2w6m6Tmr+BNXjDsr7M90zkWjsu4JXHwrzPg235STs4= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.23/go.mod h1:35EVp9wyeANdujZruvHiQUAo9E3vbhnIO1mTCAxMlY0= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.23 h1:pgYW9FCabt2M25MoHYCfMrVY2ghiiBKYWUVXfwZs+sU= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.23/go.mod h1:c48kLgzO19wAu3CPkDWC28JbaJ+hfQlsdl7I2+oqIbk= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24 h1:4usbeaes3yJnCFC7kfeyhkdkPtoRYPa/hTmCqMpKpLI= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24/go.mod h1:5CI1JemjVwde8m2WG3cz23qHKPOxbpkq0HaoreEgLIY= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24 h1:N1zsICrQglfzaBnrfM0Ys00860C+QFwu6u/5+LomP+o= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24/go.mod h1:dCn9HbJ8+K31i8IQ8EWmWj0EiIk0+vKiHNMxTTYveAg= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 h1:TToQNkvGguu209puTojY/ozlqy2d/SFNcoLIqTFi42g= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0/go.mod h1:0jp+ltwkf+SwG2fm/PKo8t4y8pJSgOCO4D8Lz3k0aHQ= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.4 h1:tHxQi/XHPK0ctd/wdOw0t7Xrc2OxcRCnVzv8lwWPu0c= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.4/go.mod h1:4GQbF1vJzG60poZqWatZlhP31y8PGCCVTvIGPdaaYJ0= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.5 h1:HJwZwRt2Z2Tdec+m+fPjvdmkq2s9Ra+VR0hjF7V2o40= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.5/go.mod h1:wrMCEwjFPms+V86TCQQeOxQF/If4vT44FGIOFiMC2ck= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.4 h1:zcx9LiGWZ6i6pjdcoE9oXAB6mUdeyC36Ia/QEiIvYdg= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.4/go.mod h1:Tp/ly1cTjRLGBBmNccFumbZ8oqpZlpdhFf80SrRh4is= -github.com/aws/aws-sdk-go-v2/service/sts v1.32.4 h1:yDxvkz3/uOKfxnv8YhzOi9m+2OGIxF+on3KOISbK5IU= -github.com/aws/aws-sdk-go-v2/service/sts v1.32.4/go.mod h1:9XEUty5v5UAsMiFOBJrNibZgwCeOma73jgGwwhgffa8= -github.com/aws/smithy-go v1.22.0 h1:uunKnWlcoL3zO7q+gG2Pk53joueEOsnNB28QdMsmiMM= -github.com/aws/smithy-go v1.22.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 h1:iXtILhvDxB6kPvEXgsDhGaZCSC6LQET5ZHSdJozeI0Y= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1/go.mod h1:9nu0fVANtYiAePIBh2/pFUSwtJ402hLnp854CNoDOeE= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.5 h1:wtpJ4zcwrSbwhECWQoI/g6WM9zqCcSpHDJIWSbMLOu4= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.5/go.mod h1:qu/W9HXQbbQ4+1+JcZp0ZNPV31ym537ZJN+fiS7Ti8E= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.6 h1:3zu537oLmsPfDMyjnUS2g+F2vITgy5pB74tHI+JBNoM= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.6/go.mod h1:WJSZH2ZvepM6t6jwu4w/Z45Eoi75lPN7DcydSRtJg6Y= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5 h1:K0OQAsDywb0ltlFrZm0JHPY3yZp/S9OaoLU33S7vPS8= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5/go.mod h1:ORITg+fyuMoeiQFiVGoqB3OydVTLkClw/ljbblMq6Cc= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.1 h1:6SZUVRQNvExYlMLbHdlKB48x0fLbc2iVROyaNEwBHbU= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.1/go.mod h1:GqWyYCwLXnlUB1lOAXQyNSPqPLQJvmo8J0DWBzp9mtg= +github.com/aws/smithy-go v1.22.1 h1:/HPHZQ0g7f4eUeK6HKglFz8uwVfZKgoI25rb/J+dnro= +github.com/aws/smithy-go v1.22.1/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw= @@ -100,8 +100,8 @@ github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/formancehq/go-libs/v2 v2.0.1-0.20241114125605-4a3e447246a9 h1:l6jieaR+sn4Ff+puBDMbTYmT2HTYC7Yt7GTxBAwC3eU= -github.com/formancehq/go-libs/v2 v2.0.1-0.20241114125605-4a3e447246a9/go.mod h1:m0uKkey9OC/AeyWMwjMfZqhLzoWrPFBk8vuYdSSYj4Y= +github.com/formancehq/go-libs/v2 v2.0.1-0.20241119202934-d93d89fd8778 h1:k/PmHjR692rBLxCanof/lD0c1K8WLKCNYCl5y1EHJPg= +github.com/formancehq/go-libs/v2 v2.0.1-0.20241119202934-d93d89fd8778/go.mod h1:6vkHEfWEkDSPOv/G2o1Exxra3ouuYxRiCkznwKxTMHU= github.com/formancehq/numscript v0.0.9-0.20241009144012-1150c14a1417 h1:LOd5hxnXDIBcehFrpW1OnXk+VSs0yJXeu1iAOO+Hji4= github.com/formancehq/numscript v0.0.9-0.20241009144012-1150c14a1417/go.mod h1:btuSv05cYwi9BvLRxVs5zrunU+O1vTgigG1T6UsawcY= github.com/gkampitakis/ciinfo v0.3.0 h1:gWZlOC2+RYYttL0hBqcoQhM7h1qNkVqvRCV1fOvpAv8= @@ -135,8 +135,8 @@ github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIx github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/mock v1.7.0-rc.1 h1:YojYx61/OLFsiv6Rw1Z96LpldJIy31o+UHmwAUMJ6/U= +github.com/golang/mock v1.7.0-rc.1/go.mod h1:s42URUywIqd+OcERslBJvOjepvNymP31m3q8d/GkuRs= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= From 24c347af4fe582359c485c6aab26f865a1028ae4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Sala=C3=BCn?= Date: Fri, 21 Feb 2025 23:34:08 +0100 Subject: [PATCH 04/27] wip: bring up to date and new driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Clément Salaün --- test/antithesis/Earthfile | 11 ++-- test/antithesis/image/Earthfile | 2 +- test/antithesis/workload/Earthfile | 42 ++++------------ .../main.go | 50 ++++--------------- test/antithesis/workload/bin/init/main.go | 9 ++-- test/antithesis/workload/internal/utils.go | 42 +++++++++++++++- 6 files changed, 68 insertions(+), 88 deletions(-) rename test/antithesis/workload/bin/cmds/{singleton_driver_main => parallel_driver_transactions}/main.go (59%) diff --git a/test/antithesis/Earthfile b/test/antithesis/Earthfile index ff11c9213b..36c037e3af 100644 --- a/test/antithesis/Earthfile +++ b/test/antithesis/Earthfile @@ -25,11 +25,8 @@ run: }" requirements-build: - ARG --required ANTITHESIS_REPOSITORY + ARG --required ANTITHESIS_REPOSITORY - BUILD --pass-args ./config+build - BUILD --pass-args ./image+build - BUILD --pass-args ./workload+build - -pre-commit: - BUILD ./workload+pre-commit \ No newline at end of file + BUILD --pass-args ./config+build + BUILD --pass-args ./image+build + BUILD --pass-args ./workload+build \ No newline at end of file diff --git a/test/antithesis/image/Earthfile b/test/antithesis/image/Earthfile index b6b9b5e071..118d292f6b 100644 --- a/test/antithesis/image/Earthfile +++ b/test/antithesis/image/Earthfile @@ -8,7 +8,7 @@ CACHE --sharing=shared --id go-mod-cache /go/pkg/mod CACHE --sharing=shared --id go-cache /root/.cache/go-build compile: - FROM --platform=linux/amd64 golang:1.22.2 + FROM --platform=linux/amd64 golang:1.23 CACHE --sharing=shared --id go-mod-cache /go/pkg/mod CACHE --sharing=shared --id go-cache /root/.cache/go-build diff --git a/test/antithesis/workload/Earthfile b/test/antithesis/workload/Earthfile index fb4aa9f202..bc1f89eb00 100644 --- a/test/antithesis/workload/Earthfile +++ b/test/antithesis/workload/Earthfile @@ -4,44 +4,25 @@ FROM --platform=linux/amd64 golang:1.22.2 CACHE --sharing=shared --id go-mod-cache /go/pkg/mod CACHE --sharing=shared --id go-cache /root/.cache/go-build -CACHE --sharing=shared --id golangci-cache /root/.cache/golangci-lint sources: - COPY --dir ../../..+lint/* /src/ - COPY ../../..+tidy/* /src/ - WORKDIR /src/test/antithesis/workload COPY go.* . COPY --dir bin internal . SAVE ARTIFACT /src -tidy: - FROM +sources - - CACHE --id go-mod-cache /go/pkg/mod - CACHE --id go-cache /root/.cache/go-build - - WORKDIR /src/test/antithesis/workload - RUN go mod tidy - - SAVE ARTIFACT go.mod AS LOCAL go.mod - SAVE ARTIFACT go.sum AS LOCAL go.sum - -lint: - #todo: get config from core - FROM +tidy - - RUN curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.61.0 +# tidy: +# FROM +sources - CACHE --id go-mod-cache /go/pkg/mod - CACHE --id go-cache /root/.cache/go-build - CACHE --id golangci-cache /root/.cache/golangci-lint +# CACHE --id go-mod-cache /go/pkg/mod +# CACHE --id go-cache /root/.cache/go-build - RUN golangci-lint run --fix --timeout 5m +# WORKDIR /src/test/antithesis/workload +# RUN go mod tidy - SAVE ARTIFACT bin AS LOCAL bin - SAVE ARTIFACT internal AS LOCAL internal +# SAVE ARTIFACT go.mod AS LOCAL go.mod +# SAVE ARTIFACT go.sum AS LOCAL go.sum compile: CACHE --id go-mod-cache /go/pkg/mod @@ -52,6 +33,7 @@ compile: COPY +sources/src /src WORKDIR /src/test/antithesis/workload + COPY --dir ../../../pkg/client+client/client ../../../pkg/client RUN mkdir -p /workload_instrumented RUN mkdir -p /out/cmds @@ -73,8 +55,4 @@ build: ARG --required ANTITHESIS_REPOSITORY - SAVE IMAGE --push --no-manifest-list ${ANTITHESIS_REPOSITORY}/workload:latest - -pre-commit: - BUILD +tidy - BUILD +lint \ No newline at end of file + SAVE IMAGE --push --no-manifest-list ${ANTITHESIS_REPOSITORY}/workload:latest \ No newline at end of file diff --git a/test/antithesis/workload/bin/cmds/singleton_driver_main/main.go b/test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go similarity index 59% rename from test/antithesis/workload/bin/cmds/singleton_driver_main/main.go rename to test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go index ca295a9a20..44b8ded27a 100644 --- a/test/antithesis/workload/bin/cmds/singleton_driver_main/main.go +++ b/test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go @@ -3,24 +3,25 @@ package main import ( "context" "fmt" + "math/big" + "github.com/alitto/pond" "github.com/antithesishq/antithesis-sdk-go/assert" - "github.com/antithesishq/antithesis-sdk-go/random" "github.com/formancehq/go-libs/v2/pointer" - "github.com/formancehq/ledger/pkg/client" - "github.com/formancehq/ledger/pkg/client/models/components" "github.com/formancehq/ledger/pkg/client/models/operations" "github.com/formancehq/ledger/test/antithesis/internal" "go.uber.org/atomic" - "math" - "math/big" ) func main() { ctx := context.Background() client := internal.NewClient() - err := createLedger(ctx, client) + err := internal.CreateLedger( + ctx, + client, + fmt.Sprintf("ledger-%d", internal.RandomBigInt().Int64()), + ) if err != nil { assert.Always(err == nil, "ledger should have been created", internal.Details{ "error": err, @@ -33,14 +34,14 @@ func main() { hasError := atomic.NewBool(false) totalAmount := big.NewInt(0) - pool := pond.New(10, 10000) + pool := pond.New(10, 10e3) for i := 0; i < count; i++ { amount := internal.RandomBigInt() totalAmount = totalAmount.Add(totalAmount, amount) pool.Submit(func() { if !internal.AssertAlwaysErrNil( - runTx(ctx, client, amount), + internal.RunTx(ctx, client, amount), "creating transaction from @world to $account always return a nil error", ) { hasError.CompareAndSwap(false, true) @@ -79,36 +80,3 @@ func main() { }, ) } - -func createLedger(ctx context.Context, client *client.Formance) error { - - _, err := client.Ledger.V2.CreateLedger(ctx, operations.V2CreateLedgerRequest{ - Ledger: "default", - }) - - if assert.Always(err == nil, "ledger should have been created", internal.Details{ - "error": fmt.Sprintf("%+v\n", err), - }); err != nil { - return err - } - - return nil -} - -func runTx(ctx context.Context, client *client.Formance, amount *big.Int) error { - orderID := fmt.Sprint(int64(math.Abs(float64(random.GetRandom())))) - dest := fmt.Sprintf("orders:%s", orderID) - - _, err := client.Ledger.V2.CreateTransaction(ctx, operations.V2CreateTransactionRequest{ - V2PostTransaction: components.V2PostTransaction{ - Postings: []components.V2Posting{{ - Amount: amount, - Asset: "USD/2", - Destination: dest, - Source: "world", - }}, - }, - Ledger: "default", - }) - return err -} diff --git a/test/antithesis/workload/bin/init/main.go b/test/antithesis/workload/bin/init/main.go index a469dbe5d3..e58198415d 100644 --- a/test/antithesis/workload/bin/init/main.go +++ b/test/antithesis/workload/bin/init/main.go @@ -2,12 +2,13 @@ package main import ( "context" - "github.com/antithesishq/antithesis-sdk-go/lifecycle" - "github.com/formancehq/ledger/test/antithesis/internal" "os" "os/signal" "syscall" "time" + + "github.com/antithesishq/antithesis-sdk-go/lifecycle" + "github.com/formancehq/ledger/test/antithesis/internal" ) func main() { @@ -24,9 +25,7 @@ func main() { break } - lifecycle.SetupComplete(map[string]any{ - "Ledger": "Available", - }) + lifecycle.SetupComplete(map[string]any{}) sigs := make(chan os.Signal, 1) signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) diff --git a/test/antithesis/workload/internal/utils.go b/test/antithesis/workload/internal/utils.go index 4f0ceb21e1..e550c2b86a 100644 --- a/test/antithesis/workload/internal/utils.go +++ b/test/antithesis/workload/internal/utils.go @@ -1,14 +1,19 @@ package internal import ( + "context" "fmt" + "math" + "math/big" + "net/http" + "github.com/antithesishq/antithesis-sdk-go/assert" "github.com/antithesishq/antithesis-sdk-go/random" "github.com/formancehq/go-libs/v2/time" "github.com/formancehq/ledger/pkg/client" + "github.com/formancehq/ledger/pkg/client/models/components" + "github.com/formancehq/ledger/pkg/client/models/operations" "github.com/formancehq/ledger/pkg/client/retry" - "math/big" - "net/http" ) type Details map[string]any @@ -48,3 +53,36 @@ func NewClient() *client.Formance { }), ) } + +func CreateLedger(ctx context.Context, client *client.Formance, name string) error { + + _, err := client.Ledger.V2.CreateLedger(ctx, operations.V2CreateLedgerRequest{ + Ledger: name, + }) + + if assert.Always(err == nil, "ledger should have been created", Details{ + "error": fmt.Sprintf("%+v\n", err), + }); err != nil { + return err + } + + return nil +} + +func RunTx(ctx context.Context, client *client.Formance, amount *big.Int) error { + orderID := fmt.Sprint(int64(math.Abs(float64(random.GetRandom())))) + dest := fmt.Sprintf("orders:%s", orderID) + + _, err := client.Ledger.V2.CreateTransaction(ctx, operations.V2CreateTransactionRequest{ + V2PostTransaction: components.V2PostTransaction{ + Postings: []components.V2Posting{{ + Amount: amount, + Asset: "USD/2", + Destination: dest, + Source: "world", + }}, + }, + Ledger: "default", + }) + return err +} From 0addc57463fc5e65c74dbbdc54bbfd42951d826f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Sala=C3=BCn?= Date: Thu, 13 Mar 2025 13:50:37 +0100 Subject: [PATCH 05/27] fix: test composer changes --- go.mod | 1 + go.sum | 2 + internal/controller/system/controller.go | 5 +- internal/storage/driver/driver.go | 51 ++++++++++++++++++- pkg/client/Earthfile | 8 +++ .../main.go | 3 +- .../cmds/parallel_driver_transactions/main.go | 16 +++--- test/antithesis/workload/internal/utils.go | 18 +++---- 8 files changed, 82 insertions(+), 22 deletions(-) create mode 100644 pkg/client/Earthfile diff --git a/go.mod b/go.mod index 3d8ed3380a..6dac650778 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ replace google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215 => google. require ( github.com/ThreeDotsLabs/watermill v1.4.4 github.com/alitto/pond v1.9.2 + github.com/antithesishq/antithesis-sdk-go v0.4.3 github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 github.com/bluele/gcache v0.0.2 github.com/dop251/goja v0.0.0-20241009100908-5f46f2705ca3 diff --git a/go.sum b/go.sum index b6ccf30d9e..99455cc011 100644 --- a/go.sum +++ b/go.sum @@ -24,6 +24,8 @@ github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/alitto/pond v1.9.2 h1:9Qb75z/scEZVCoSU+osVmQ0I0JOeLfdTDafrbcJ8CLs= github.com/alitto/pond v1.9.2/go.mod h1:xQn3P/sHTYcU/1BR3i86IGIrilcrGC2LiS+E2+CJWsI= +github.com/antithesishq/antithesis-sdk-go v0.4.3 h1:a2hGdDogClzHzFu20r1z0tzD6zwSWUipiaerAjZVP90= +github.com/antithesishq/antithesis-sdk-go v0.4.3/go.mod h1:IUpT2DPAKh6i/YhSbt6Gl3v2yvUZjmKncl7U91fup7E= github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 h1:yL7+Jz0jTC6yykIK/Wh74gnTJnrGr5AyrNMXuA0gves= github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ= diff --git a/internal/controller/system/controller.go b/internal/controller/system/controller.go index ca2f836c0d..d94e94cc09 100644 --- a/internal/controller/system/controller.go +++ b/internal/controller/system/controller.go @@ -2,11 +2,12 @@ package system import ( "context" - "github.com/formancehq/ledger/pkg/features" - "go.opentelemetry.io/otel/attribute" "reflect" "time" + "github.com/formancehq/ledger/pkg/features" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric" noopmetrics "go.opentelemetry.io/otel/metric/noop" "go.opentelemetry.io/otel/trace" diff --git a/internal/storage/driver/driver.go b/internal/storage/driver/driver.go index 519f34d0d4..87c59f66f7 100644 --- a/internal/storage/driver/driver.go +++ b/internal/storage/driver/driver.go @@ -4,7 +4,10 @@ import ( "context" "errors" "fmt" + "time" + "github.com/alitto/pond" + "github.com/antithesishq/antithesis-sdk-go/assert" "github.com/formancehq/go-libs/v2/metadata" "github.com/formancehq/go-libs/v2/migrations" "github.com/formancehq/go-libs/v2/platform/postgres" @@ -14,7 +17,6 @@ import ( noopmetrics "go.opentelemetry.io/otel/metric/noop" "go.opentelemetry.io/otel/trace" nooptracer "go.opentelemetry.io/otel/trace/noop" - "time" ledgercontroller "github.com/formancehq/ledger/internal/controller/ledger" @@ -37,8 +39,43 @@ type Driver struct { parallelBucketMigrations int } +/* +CreateLedger creates a new ledger in the system and sets up all necessary database objects. + +The function follows these steps: + 1. Create a ledger record in the system store (_system.ledgers table) + 2. Get the bucket (database schema) for this ledger + 3. Check if the bucket is already initialized: + a. If initialized: Verify it's up to date and add ledger-specific objects to it + b. If not initialized: Create the bucket schema with all necessary tables + 4. Return a ledger store that provides an interface to interact with the ledger + +Note: This process is not atomic. If context cancellation occurs between creating +the ledger record and setting up the bucket, the system could be left in an +inconsistent state with a ledger record but no corresponding database objects. +*/ func (d *Driver) CreateLedger(ctx context.Context, l *ledger.Ledger) (*ledgerstore.Store, error) { + // Track whether we've successfully created the ledger in the system store + ledgerCreatedInSystemStore := false + bucketSetupComplete := false + + // Defer an assertion check that will run when the function exits + defer func() { + // The invariant we want to check: + // Either (1) both steps completed successfully OR (2) neither step completed + // If only the ledger was created but bucket setup failed, that's a problem + invariantMaintained := (!ledgerCreatedInSystemStore && !bucketSetupComplete) || + (ledgerCreatedInSystemStore && bucketSetupComplete) + + assert.Always(invariantMaintained, "ledger_creation_atomic", map[string]any{ + "ledger_name": l.Name, + "bucket": l.Bucket, + "ledger_created_in_system_store": ledgerCreatedInSystemStore, + "bucket_setup_complete": bucketSetupComplete, + }) + }() + // Create ledger record in system store if err := d.systemStore.CreateLedger(ctx, l); err != nil { if errors.Is(postgres.ResolveError(err), postgres.ErrConstraintsFailed{}) { return nil, systemcontroller.ErrLedgerAlreadyExists @@ -46,12 +83,18 @@ func (d *Driver) CreateLedger(ctx context.Context, l *ledger.Ledger) (*ledgersto return nil, postgres.ResolveError(err) } + // Mark that we've successfully created the ledger in the system store + ledgerCreatedInSystemStore = true + + // Get the bucket for this ledger b := d.bucketFactory.Create(l.Bucket) isInitialized, err := b.IsInitialized(ctx) if err != nil { return nil, fmt.Errorf("checking if bucket is initialized: %w", err) } + if isInitialized { + // Bucket exists - check if it's up to date upToDate, err := b.IsUpToDate(ctx) if err != nil { return nil, fmt.Errorf("checking if bucket is up to date: %w", err) @@ -61,10 +104,12 @@ func (d *Driver) CreateLedger(ctx context.Context, l *ledger.Ledger) (*ledgersto return nil, systemcontroller.ErrBucketOutdated } + // Add ledger-specific objects to the bucket if err := b.AddLedger(ctx, *l); err != nil { return nil, fmt.Errorf("adding ledger to bucket: %w", err) } } else { + // Bucket doesn't exist - create it if err := b.Migrate( ctx, migrations.WithLockRetryInterval(d.migratorLockRetryInterval), @@ -73,6 +118,10 @@ func (d *Driver) CreateLedger(ctx context.Context, l *ledger.Ledger) (*ledgersto } } + // Mark that bucket setup is complete + bucketSetupComplete = true + + // Create and return a store for interacting with the ledger return d.ledgerStoreFactory.Create(b, *l), nil } diff --git a/pkg/client/Earthfile b/pkg/client/Earthfile new file mode 100644 index 0000000000..a17835da3f --- /dev/null +++ b/pkg/client/Earthfile @@ -0,0 +1,8 @@ +VERSION 0.7 + +FROM --platform=linux/amd64 golang:1.22.2 + +client: + FROM scratch + COPY . /client + SAVE ARTIFACT /client client \ No newline at end of file diff --git a/test/antithesis/workload/bin/cmds/eventually_aggregated_volumes_should_be_zeroed/main.go b/test/antithesis/workload/bin/cmds/eventually_aggregated_volumes_should_be_zeroed/main.go index 959a32bd47..8079ed4015 100644 --- a/test/antithesis/workload/bin/cmds/eventually_aggregated_volumes_should_be_zeroed/main.go +++ b/test/antithesis/workload/bin/cmds/eventually_aggregated_volumes_should_be_zeroed/main.go @@ -2,10 +2,11 @@ package main import ( "context" + "math/big" + "github.com/antithesishq/antithesis-sdk-go/assert" "github.com/formancehq/ledger/pkg/client/models/operations" "github.com/formancehq/ledger/test/antithesis/internal" - "math/big" ) func main() { diff --git a/test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go b/test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go index 44b8ded27a..07d8182ada 100644 --- a/test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go +++ b/test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go @@ -16,20 +16,21 @@ import ( func main() { ctx := context.Background() client := internal.NewClient() + ledger := fmt.Sprintf("ledger-%d", internal.RandomBigInt().Int64()) err := internal.CreateLedger( ctx, client, - fmt.Sprintf("ledger-%d", internal.RandomBigInt().Int64()), + ledger, ) if err != nil { - assert.Always(err == nil, "ledger should have been created", internal.Details{ + assert.Always(err == nil, "ledger should have been created properly", internal.Details{ "error": err, }) return } - const count = 1000 + const count = 100 hasError := atomic.NewBool(false) totalAmount := big.NewInt(0) @@ -41,8 +42,11 @@ func main() { totalAmount = totalAmount.Add(totalAmount, amount) pool.Submit(func() { if !internal.AssertAlwaysErrNil( - internal.RunTx(ctx, client, amount), + internal.RunTx(ctx, client, amount, ledger), "creating transaction from @world to $account always return a nil error", + internal.Details{ + "ledger": ledger, + }, ) { hasError.CompareAndSwap(false, true) } @@ -59,10 +63,10 @@ func main() { account, err := client.Ledger.V2.GetAccount(ctx, operations.V2GetAccountRequest{ Address: "world", Expand: pointer.For("volumes"), - Ledger: "default", + Ledger: ledger, }) - if !internal.AssertAlwaysErrNil(err, "we should be able to query account 'world'") { + if !internal.AssertAlwaysErrNil(err, "we should be able to query account 'world'", nil) { return } diff --git a/test/antithesis/workload/internal/utils.go b/test/antithesis/workload/internal/utils.go index e550c2b86a..680f18cea0 100644 --- a/test/antithesis/workload/internal/utils.go +++ b/test/antithesis/workload/internal/utils.go @@ -30,9 +30,10 @@ func AssertAlways(condition bool, message string, details map[string]any) bool { return condition } -func AssertAlwaysErrNil(err error, message string) bool { +func AssertAlwaysErrNil(err error, message string, details map[string]any) bool { return AssertAlways(err == nil, message, Details{ - "error": fmt.Sprint(err), + "error": fmt.Sprint(err), + "details": details, }) } @@ -55,21 +56,14 @@ func NewClient() *client.Formance { } func CreateLedger(ctx context.Context, client *client.Formance, name string) error { - _, err := client.Ledger.V2.CreateLedger(ctx, operations.V2CreateLedgerRequest{ Ledger: name, }) - if assert.Always(err == nil, "ledger should have been created", Details{ - "error": fmt.Sprintf("%+v\n", err), - }); err != nil { - return err - } - - return nil + return err } -func RunTx(ctx context.Context, client *client.Formance, amount *big.Int) error { +func RunTx(ctx context.Context, client *client.Formance, amount *big.Int, ledger string) error { orderID := fmt.Sprint(int64(math.Abs(float64(random.GetRandom())))) dest := fmt.Sprintf("orders:%s", orderID) @@ -82,7 +76,7 @@ func RunTx(ctx context.Context, client *client.Formance, amount *big.Int) error Source: "world", }}, }, - Ledger: "default", + Ledger: ledger, }) return err } From d64d1ef04a34be5db2274b78581856e8c09426c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Sala=C3=BCn?= Date: Thu, 13 Mar 2025 18:26:10 +0100 Subject: [PATCH 06/27] wip: improve assertions --- internal/storage/driver/driver.go | 64 ++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/internal/storage/driver/driver.go b/internal/storage/driver/driver.go index ba966c64a2..430ad2b400 100644 --- a/internal/storage/driver/driver.go +++ b/internal/storage/driver/driver.go @@ -8,6 +8,7 @@ import ( "time" "github.com/alitto/pond" + "github.com/antithesishq/antithesis-sdk-go/assert" "github.com/formancehq/go-libs/v2/metadata" "github.com/formancehq/go-libs/v2/platform/postgres" systemcontroller "github.com/formancehq/ledger/internal/controller/system" @@ -38,51 +39,112 @@ type Driver struct { parallelBucketMigrations int } -func (d *Driver) CreateLedger(ctx context.Context, l *ledger.Ledger) (*ledgerstore.Store, error) { +/* +CreateLedger creates a new ledger in the system and sets up all necessary database objects. + +The function follows these steps: + 1. Create a ledger record in the system store (_system.ledgers table) + 2. Get the bucket (database schema) for this ledger + 3. Check if the bucket is already initialized: + a. If initialized: Verify it's up to date and add ledger-specific objects to it + b. If not initialized: Create the bucket schema with all necessary tables + 4. Return a ledger store that provides an interface to interact with the ledger +Note: This entire process is wrapped in a database transaction, ensuring atomicity. +If any step fails, the entire transaction is rolled back, preventing partial state. +*/ +func (d *Driver) CreateLedger(ctx context.Context, l *ledger.Ledger) (*ledgerstore.Store, error) { var ret *ledgerstore.Store + + // Run the entire ledger creation process in a transaction for atomicity + // This ensures that either all steps succeed or none do (preventing partial state) err := d.db.RunInTx(ctx, nil, func(ctx context.Context, tx bun.Tx) error { + // Create a system store that uses the current transaction systemStore := systemstore.New(tx) + // Step 1: Create the ledger record in the system store if err := systemStore.CreateLedger(ctx, l); err != nil { + // Handle the case where the ledger already exists if errors.Is(postgres.ResolveError(err), postgres.ErrConstraintsFailed{}) { return systemcontroller.ErrLedgerAlreadyExists } return err } + // Step 2: Get a bucket handler for this ledger + // The bucket is a database schema where the ledger's data will be stored b := d.bucketFactory.Create(l.Bucket, tx) + + // Step 3: Check if the bucket is already initialized in the database isInitialized, err := b.IsInitialized(ctx) if err != nil { return fmt.Errorf("checking if bucket is initialized: %w", err) } + if isInitialized { + // Step 3a: Bucket exists - check if it's up to date upToDate, err := b.IsUpToDate(ctx) if err != nil { return fmt.Errorf("checking if bucket is up to date: %w", err) } if !upToDate { + assert.AlwaysOrUnreachable( + // @todo: replace this with a proper flag detailing wether we're + // operating a new version of the binary or not. + // if we are, we are definitely expecting this to happen. + // if we're not, this should be unreachable. + false, + "Bucket is outdated", + map[string]any{ + "bucket": l.Bucket, + }, + ) + return systemcontroller.ErrBucketOutdated } + // Add ledger-specific objects to the bucket + // This creates sequences and other database objects for this ledger if err := b.AddLedger(ctx, *l); err != nil { + assert.Unreachable( + "Adding ledger to bucket should never fail", + map[string]any{ + "bucket": l.Bucket, + "error": err, + }, + ) + return fmt.Errorf("adding ledger to bucket: %w", err) } } else { + // Step 3b: Bucket doesn't exist - create it + // This creates the bucket schema and all necessary tables if err := b.Migrate(ctx); err != nil { + assert.Unreachable( + "Migrating bucket should never fail", + map[string]any{ + "bucket": l.Bucket, + "error": err, + }, + ) + return fmt.Errorf("migrating bucket: %w", err) } } + // Step 4: Create a store for interacting with the ledger ret = d.ledgerStoreFactory.Create(b, *l) return nil }) + + // If any error occurred during the transaction, resolve and return it if err != nil { return nil, postgres.ResolveError(err) } + // Return the created ledger store return ret, nil } From 32759cc4a27bc387d660b8ed12627bf28465a800 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Sala=C3=BCn?= Date: Thu, 13 Mar 2025 18:53:07 +0100 Subject: [PATCH 07/27] fix: overly ambitious assertions --- internal/storage/driver/driver.go | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/internal/storage/driver/driver.go b/internal/storage/driver/driver.go index 430ad2b400..1ad8ee16b0 100644 --- a/internal/storage/driver/driver.go +++ b/internal/storage/driver/driver.go @@ -107,28 +107,12 @@ func (d *Driver) CreateLedger(ctx context.Context, l *ledger.Ledger) (*ledgersto // Add ledger-specific objects to the bucket // This creates sequences and other database objects for this ledger if err := b.AddLedger(ctx, *l); err != nil { - assert.Unreachable( - "Adding ledger to bucket should never fail", - map[string]any{ - "bucket": l.Bucket, - "error": err, - }, - ) - return fmt.Errorf("adding ledger to bucket: %w", err) } } else { // Step 3b: Bucket doesn't exist - create it // This creates the bucket schema and all necessary tables if err := b.Migrate(ctx); err != nil { - assert.Unreachable( - "Migrating bucket should never fail", - map[string]any{ - "bucket": l.Bucket, - "error": err, - }, - ) - return fmt.Errorf("migrating bucket: %w", err) } } From a380c0b3aa96cb5b9f23f70dbb9fe9b5307df3e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Sala=C3=BCn?= Date: Thu, 13 Mar 2025 23:13:27 +0100 Subject: [PATCH 08/27] wip: add debugger --- test/antithesis/Earthfile | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/antithesis/Earthfile b/test/antithesis/Earthfile index 36c037e3af..4f2e5fac0f 100644 --- a/test/antithesis/Earthfile +++ b/test/antithesis/Earthfile @@ -24,6 +24,32 @@ run: } }" +debugger: + FROM curlimages/curl + + ARG ANTITHESIS_USERNAME=formance + ARG --required ANTITHESIS_SLACK_REPORT_RECIPIENT + ARG --required VTIME + ARG --required SESSION_ID + ARG --required HASH + RUN echo "{ + \"params\": { + \"antithesis.debugging.session_id\": \"${SESSION_ID}\", + \"antithesis.debugging.input_hash\": \"${HASH}\", + \"antithesis.debugging.vtime\": \"${VTIME}\", + \"antithesis.report.recipients\": \"${ANTITHESIS_SLACK_REPORT_RECIPIENT}\" + } + }" > /tmp/debug_params.json + + # Display the debug parameters for verification + RUN cat /tmp/debug_params.json + + RUN --no-cache --secret ANTITHESIS_PASSWORD curl \ + --fail \ + --user "$ANTITHESIS_USERNAME:$ANTITHESIS_PASSWORD" \ + -X POST https://formance.antithesis.com/api/v1/launch/debugging \ + -d @/tmp/debug_params.json + requirements-build: ARG --required ANTITHESIS_REPOSITORY From 0919823644c77db3cfc11efb7b549fc99a95b654 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Sala=C3=BCn?= Date: Wed, 23 Apr 2025 15:51:47 +0200 Subject: [PATCH 09/27] feat: add antithesis ci MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Clément Salaün --- .github/workflows/antithesis.yml | 62 ++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 .github/workflows/antithesis.yml diff --git a/.github/workflows/antithesis.yml b/.github/workflows/antithesis.yml new file mode 100644 index 0000000000..01110774e0 --- /dev/null +++ b/.github/workflows/antithesis.yml @@ -0,0 +1,62 @@ +name: Antithesis Integration +on: + workflow_dispatch: + inputs: + run_tests: + description: 'Run Antithesis tests after pushing images' + type: boolean + default: true + push: + branches: + - main + pull_request: + types: [opened, synchronize, reopened] + paths: + - 'test/antithesis/**' + +jobs: + push-antithesis-images: + name: Push Images to Antithesis + runs-on: shipfox-4vcpu-ubuntu-2404 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Earthly + uses: earthly/actions-setup@v1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + version: "latest" + + - name: Setup Environment + uses: ./.github/actions/default + with: + token: ${{ secrets.NUMARY_GITHUB_TOKEN }} + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Antithesis Docker Registry + uses: docker/login-action@v3 + with: + registry: ${{ secrets.ANTITHESIS_REGISTRY }} + username: ${{ secrets.ANTITHESIS_USERNAME }} + password: ${{ secrets.ANTITHESIS_PASSWORD }} + + - name: Build and Push Config Image + run: | + cd test/antithesis + earthly --push +requirements-build --ANTITHESIS_REPOSITORY=${{ secrets.ANTITHESIS_REGISTRY }} + + - name: Run Antithesis Tests + if: ${{ github.event_name == 'workflow_dispatch' && inputs.run_tests == true }} + run: | + cd test/antithesis + earthly --push +run --ANTITHESIS_SLACK_REPORT_RECIPIENT="${{ secrets.ANTITHESIS_SLACK_REPORT_RECIPIENT }}" --ANTITHESIS_REPOSITORY=${{ secrets.ANTITHESIS_REGISTRY }} + env: + ANTITHESIS_PASSWORD: ${{ secrets.ANTITHESIS_PASSWORD }} \ No newline at end of file From 8aa8fb7c5d213e655b1c6aeb0eda9619d6e2f1ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Sala=C3=BCn?= Date: Wed, 23 Apr 2025 17:18:39 +0200 Subject: [PATCH 10/27] fix: antithesis registry docker login --- .github/workflows/antithesis.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/antithesis.yml b/.github/workflows/antithesis.yml index 01110774e0..fd85b89561 100644 --- a/.github/workflows/antithesis.yml +++ b/.github/workflows/antithesis.yml @@ -42,11 +42,8 @@ jobs: uses: docker/setup-buildx-action@v3 - name: Login to Antithesis Docker Registry - uses: docker/login-action@v3 - with: - registry: ${{ secrets.ANTITHESIS_REGISTRY }} - username: ${{ secrets.ANTITHESIS_USERNAME }} - password: ${{ secrets.ANTITHESIS_PASSWORD }} + run: | + echo '${{ secrets.ANTITHESIS_JSON_KEY }}' | docker login -u _json_key --password-stdin ${{ secrets.ANTITHESIS_REGISTRY }} - name: Build and Push Config Image run: | From 6d3747a115c7f86b9a68e6022ddbdccd69256e8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Sala=C3=BCn?= Date: Wed, 23 Apr 2025 17:27:50 +0200 Subject: [PATCH 11/27] fix: antithesis docker login MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Clément Salaün --- .github/workflows/antithesis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/antithesis.yml b/.github/workflows/antithesis.yml index fd85b89561..a4bfb87a61 100644 --- a/.github/workflows/antithesis.yml +++ b/.github/workflows/antithesis.yml @@ -43,7 +43,7 @@ jobs: - name: Login to Antithesis Docker Registry run: | - echo '${{ secrets.ANTITHESIS_JSON_KEY }}' | docker login -u _json_key --password-stdin ${{ secrets.ANTITHESIS_REGISTRY }} + echo '${{ secrets.ANTITHESIS_JSON_KEY }}' | docker login -u _json_key https://us-central1-docker.pkg.dev --password-stdin - name: Build and Push Config Image run: | From 256bfb97f1bf1835d29013643b1d2d0a73664217 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Sala=C3=BCn?= Date: Wed, 23 Apr 2025 17:53:38 +0200 Subject: [PATCH 12/27] fix: antithesis github workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Clément Salaün --- .github/workflows/antithesis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/antithesis.yml b/.github/workflows/antithesis.yml index a4bfb87a61..f95fe24779 100644 --- a/.github/workflows/antithesis.yml +++ b/.github/workflows/antithesis.yml @@ -48,12 +48,12 @@ jobs: - name: Build and Push Config Image run: | cd test/antithesis - earthly --push +requirements-build --ANTITHESIS_REPOSITORY=${{ secrets.ANTITHESIS_REGISTRY }} + earthly --push +requirements-build --ANTITHESIS_REPOSITORY=${{ secrets.ANTITHESIS_REPOSITORY }} - name: Run Antithesis Tests if: ${{ github.event_name == 'workflow_dispatch' && inputs.run_tests == true }} run: | cd test/antithesis - earthly --push +run --ANTITHESIS_SLACK_REPORT_RECIPIENT="${{ secrets.ANTITHESIS_SLACK_REPORT_RECIPIENT }}" --ANTITHESIS_REPOSITORY=${{ secrets.ANTITHESIS_REGISTRY }} - env: - ANTITHESIS_PASSWORD: ${{ secrets.ANTITHESIS_PASSWORD }} \ No newline at end of file + earthly +run --ANTITHESIS_SLACK_REPORT_RECIPIENT="${{ secrets.ANTITHESIS_SLACK_REPORT_RECIPIENT }}" --ANTITHESIS_REPOSITORY=${{ secrets.ANTITHESIS_REGISTRY }} --ANTITHESIS_PASSWORD=${{ secrets.ANTITHESIS_PASSWORD }} + # env: + # ANTITHESIS_PASSWORD: ${{ secrets.ANTITHESIS_PASSWORD }} \ No newline at end of file From 10acc49862ff2f8f8ab7dcdab5b18a8358596e5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Sala=C3=BCn?= Date: Wed, 23 Apr 2025 18:49:19 +0200 Subject: [PATCH 13/27] fix: workload build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Clément Salaün --- test/antithesis/workload/go.mod | 4 +--- test/antithesis/workload/go.sum | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/test/antithesis/workload/go.mod b/test/antithesis/workload/go.mod index 6acf815dd4..53f78d6112 100644 --- a/test/antithesis/workload/go.mod +++ b/test/antithesis/workload/go.mod @@ -2,8 +2,6 @@ module github.com/formancehq/ledger/test/antithesis go 1.22.0 -toolchain go1.23.2 - replace github.com/formancehq/ledger/pkg/client => ../../../pkg/client require ( @@ -12,12 +10,12 @@ require ( github.com/formancehq/go-libs/v2 v2.0.1-0.20241114125605-4a3e447246a9 github.com/formancehq/ledger/pkg/client v0.0.0-00010101000000-000000000000 go.uber.org/atomic v1.10.0 + golang.org/x/sync v0.9.0 // indirect; indirect, for singleflight package ) require ( github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/buger/jsonparser v1.1.1 // indirect - github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/ericlagergren/decimal v0.0.0-20240411145413-00de7ca16731 // indirect github.com/invopop/jsonschema v0.12.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect diff --git a/test/antithesis/workload/go.sum b/test/antithesis/workload/go.sum index 0286b6e241..1c3c2cf9c7 100644 --- a/test/antithesis/workload/go.sum +++ b/test/antithesis/workload/go.sum @@ -6,8 +6,6 @@ github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPn github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= -github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= -github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/ericlagergren/decimal v0.0.0-20240411145413-00de7ca16731 h1:R/ZjJpjQKsZ6L/+Gf9WHbt31GG8NMVcpRqUE+1mMIyo= @@ -29,6 +27,8 @@ github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/ github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= From a2351d6c4aa3c222f4d7bd023b4d2428a532edc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Sala=C3=BCn?= Date: Fri, 2 May 2025 13:51:06 +0200 Subject: [PATCH 14/27] feat: improve test composing sequence --- .../bin/cmds/first_default_ledger/main.go | 26 +++++++++++++++ .../cmds/parallel_drive_ledger_create/main.go | 29 +++++++++++++++++ .../cmds/parallel_driver_transactions/main.go | 13 +------- .../main.go | 28 +++++++++++++--- test/antithesis/workload/internal/utils.go | 32 +++++++++++++++++++ tools/generator/cmd/root.go | 7 ++-- 6 files changed, 116 insertions(+), 19 deletions(-) create mode 100644 test/antithesis/workload/bin/cmds/first_default_ledger/main.go create mode 100644 test/antithesis/workload/bin/cmds/parallel_drive_ledger_create/main.go rename test/antithesis/workload/bin/cmds/{eventually_aggregated_volumes_should_be_zeroed => parallel_driver_volumes}/main.go (50%) diff --git a/test/antithesis/workload/bin/cmds/first_default_ledger/main.go b/test/antithesis/workload/bin/cmds/first_default_ledger/main.go new file mode 100644 index 0000000000..aa7388db9e --- /dev/null +++ b/test/antithesis/workload/bin/cmds/first_default_ledger/main.go @@ -0,0 +1,26 @@ +package main + +import ( + "context" + + "github.com/antithesishq/antithesis-sdk-go/assert" + "github.com/formancehq/ledger/test/antithesis/internal" +) + +func main() { + ctx := context.Background() + client := internal.NewClient() + ledger := "default" + + err := internal.CreateLedger( + ctx, + client, + ledger, + ) + if err != nil { + assert.Always(err == nil, "ledger should have been created properly", internal.Details{ + "error": err, + }) + return + } +} diff --git a/test/antithesis/workload/bin/cmds/parallel_drive_ledger_create/main.go b/test/antithesis/workload/bin/cmds/parallel_drive_ledger_create/main.go new file mode 100644 index 0000000000..75255b205d --- /dev/null +++ b/test/antithesis/workload/bin/cmds/parallel_drive_ledger_create/main.go @@ -0,0 +1,29 @@ +package main + +import ( + "context" + "fmt" + "math/big" + + "github.com/antithesishq/antithesis-sdk-go/assert" + "github.com/formancehq/ledger/test/antithesis/internal" +) + +func main() { + ctx := context.Background() + client := internal.NewClient() + id := big.NewInt(0).Abs(internal.RandomBigInt()).Int64() + ledger := fmt.Sprintf("ledger-%d", id) + + err := internal.CreateLedger( + ctx, + client, + ledger, + ) + if err != nil { + assert.Always(err == nil, "ledger should have been created properly", internal.Details{ + "error": err, + }) + return + } +} diff --git a/test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go b/test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go index 07d8182ada..876963a092 100644 --- a/test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go +++ b/test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go @@ -16,19 +16,8 @@ import ( func main() { ctx := context.Background() client := internal.NewClient() - ledger := fmt.Sprintf("ledger-%d", internal.RandomBigInt().Int64()) - err := internal.CreateLedger( - ctx, - client, - ledger, - ) - if err != nil { - assert.Always(err == nil, "ledger should have been created properly", internal.Details{ - "error": err, - }) - return - } + ledger := fmt.Sprintf("ledger-%d", internal.RandomBigInt().Int64()) const count = 100 diff --git a/test/antithesis/workload/bin/cmds/eventually_aggregated_volumes_should_be_zeroed/main.go b/test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go similarity index 50% rename from test/antithesis/workload/bin/cmds/eventually_aggregated_volumes_should_be_zeroed/main.go rename to test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go index 8079ed4015..a81f884d85 100644 --- a/test/antithesis/workload/bin/cmds/eventually_aggregated_volumes_should_be_zeroed/main.go +++ b/test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go @@ -2,9 +2,11 @@ package main import ( "context" + "fmt" "math/big" "github.com/antithesishq/antithesis-sdk-go/assert" + "github.com/formancehq/ledger/pkg/client" "github.com/formancehq/ledger/pkg/client/models/operations" "github.com/formancehq/ledger/test/antithesis/internal" ) @@ -13,8 +15,22 @@ func main() { ctx := context.Background() client := internal.NewClient() + ledgers, err := client.Ledger.V2.ListLedgers(ctx, operations.V2ListLedgersRequest{}) + if err != nil { + assert.Always(err == nil, "error listing ledgers", internal.Details{ + "error": err, + }) + return + } + + for _, ledger := range ledgers.V2LedgerListResponse.Cursor.Data { + go checkVolumes(ctx, client, ledger.Name) + } +} + +func checkVolumes(ctx context.Context, client *client.Formance, ledger string) { aggregated, err := client.Ledger.V2.GetBalancesAggregated(ctx, operations.V2GetBalancesAggregatedRequest{ - Ledger: "default", + Ledger: ledger, }) if err != nil { assert.Always(err == nil, "error getting aggregated balances", internal.Details{ @@ -24,8 +40,12 @@ func main() { } for asset, volumes := range aggregated.V2AggregateBalancesResponse.Data { - assert.Always(volumes.Cmp(new(big.Int)) == 0, "aggregated volumes for asset "+asset+" should be 0", internal.Details{ - "error": err, - }) + assert.Always( + volumes.Cmp(new(big.Int)) == 0, + fmt.Sprintf("aggregated volumes for asset %s should be 0", + asset, + ), internal.Details{ + "error": err, + }) } } diff --git a/test/antithesis/workload/internal/utils.go b/test/antithesis/workload/internal/utils.go index 680f18cea0..b502436ac9 100644 --- a/test/antithesis/workload/internal/utils.go +++ b/test/antithesis/workload/internal/utils.go @@ -5,6 +5,7 @@ import ( "fmt" "math" "math/big" + "math/rand" "net/http" "github.com/antithesishq/antithesis-sdk-go/assert" @@ -63,6 +64,37 @@ func CreateLedger(ctx context.Context, client *client.Formance, name string) err return err } +func ListLedgers(ctx context.Context, client *client.Formance) ([]string, error) { + res, err := client.Ledger.V2.ListLedgers(ctx, operations.V2ListLedgersRequest{}) + if err != nil { + return nil, err + } + + ledgers := []string{} + for _, ledger := range res.V2LedgerListResponse.Cursor.Data { + ledgers = append(ledgers, ledger.Name) + } + + return ledgers, nil +} + +func GetRandomLedger(ctx context.Context, client *client.Formance) (string, error) { + ledgers, err := ListLedgers(ctx, client) + if err != nil { + return "", err + } + + if len(ledgers) == 0 { + return "", fmt.Errorf("no ledgers found") + } + + // Get a random index within the ledgers slice + randomIndex := rand.Intn(len(ledgers)) + + // Return the ledger at the random index + return ledgers[randomIndex], nil +} + func RunTx(ctx context.Context, client *client.Formance, amount *big.Int, ledger string) error { orderID := fmt.Sprint(int64(math.Abs(float64(random.GetRandom())))) dest := fmt.Sprintf("orders:%s", orderID) diff --git a/tools/generator/cmd/root.go b/tools/generator/cmd/root.go index 3825417726..7f5e00d172 100644 --- a/tools/generator/cmd/root.go +++ b/tools/generator/cmd/root.go @@ -5,6 +5,10 @@ import ( "crypto/tls" "errors" "fmt" + "net/http" + "os" + "strings" + "github.com/formancehq/go-libs/v3/logging" ledgerclient "github.com/formancehq/ledger/pkg/client" "github.com/formancehq/ledger/pkg/client/models/components" @@ -14,9 +18,6 @@ import ( "github.com/spf13/cobra" "golang.org/x/oauth2" "golang.org/x/oauth2/clientcredentials" - "net/http" - "os" - "strings" ) const ( From 58524d76702e93d097f5a01ebfa04eb3d6ade506 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Sala=C3=BCn?= Date: Mon, 5 May 2025 12:34:43 +0200 Subject: [PATCH 15/27] feat: improve test composer sequence --- test/antithesis/Earthfile | 20 +++++++++++ test/antithesis/workload/Earthfile | 12 ------- .../bin/cmds/first_default_ledger/main.go | 5 +++ .../main.go | 4 +++ .../cmds/parallel_driver_transactions/main.go | 35 +++++-------------- .../bin/cmds/parallel_driver_volumes/main.go | 9 +++-- 6 files changed, 43 insertions(+), 42 deletions(-) rename test/antithesis/workload/bin/cmds/{parallel_drive_ledger_create => parallel_driver_ledger_create}/main.go (81%) diff --git a/test/antithesis/Earthfile b/test/antithesis/Earthfile index 4f2e5fac0f..0052105553 100644 --- a/test/antithesis/Earthfile +++ b/test/antithesis/Earthfile @@ -24,6 +24,26 @@ run: } }" +run-1h: + WAIT + BUILD +requirements-build + END + + FROM curlimages/curl + ARG ANTITHESIS_USERNAME=formance + ARG --required ANTITHESIS_SLACK_REPORT_RECIPIENT + RUN --no-cache --secret ANTITHESIS_PASSWORD curl \ + --fail \ + --user "$ANTITHESIS_USERNAME:$ANTITHESIS_PASSWORD" \ + -X POST https://formance.antithesis.com/api/v1/launch_experiment/formance -d "{ + \"params\": { + \"custom.duration\": \"1\", + \"antithesis.report.recipients\": \"${ANTITHESIS_SLACK_REPORT_RECIPIENT}\", + \"antithesis.config_image\": \"antithesis-config:latest\", + \"antithesis.images\": \"ledger:latest;workload:latest\" + } + }" + debugger: FROM curlimages/curl diff --git a/test/antithesis/workload/Earthfile b/test/antithesis/workload/Earthfile index bc1f89eb00..4dfef2d51b 100644 --- a/test/antithesis/workload/Earthfile +++ b/test/antithesis/workload/Earthfile @@ -12,18 +12,6 @@ sources: SAVE ARTIFACT /src -# tidy: -# FROM +sources - -# CACHE --id go-mod-cache /go/pkg/mod -# CACHE --id go-cache /root/.cache/go-build - -# WORKDIR /src/test/antithesis/workload -# RUN go mod tidy - -# SAVE ARTIFACT go.mod AS LOCAL go.mod -# SAVE ARTIFACT go.sum AS LOCAL go.sum - compile: CACHE --id go-mod-cache /go/pkg/mod CACHE --id go-cache /root/.cache/go-build diff --git a/test/antithesis/workload/bin/cmds/first_default_ledger/main.go b/test/antithesis/workload/bin/cmds/first_default_ledger/main.go index aa7388db9e..96e2046daa 100644 --- a/test/antithesis/workload/bin/cmds/first_default_ledger/main.go +++ b/test/antithesis/workload/bin/cmds/first_default_ledger/main.go @@ -2,12 +2,15 @@ package main import ( "context" + "log" "github.com/antithesishq/antithesis-sdk-go/assert" "github.com/formancehq/ledger/test/antithesis/internal" ) func main() { + log.Println("composer: first_default_ledger") + ctx := context.Background() client := internal.NewClient() ledger := "default" @@ -23,4 +26,6 @@ func main() { }) return } + + log.Println("composer: first_default_ledger: done") } diff --git a/test/antithesis/workload/bin/cmds/parallel_drive_ledger_create/main.go b/test/antithesis/workload/bin/cmds/parallel_driver_ledger_create/main.go similarity index 81% rename from test/antithesis/workload/bin/cmds/parallel_drive_ledger_create/main.go rename to test/antithesis/workload/bin/cmds/parallel_driver_ledger_create/main.go index 75255b205d..c882a8ba42 100644 --- a/test/antithesis/workload/bin/cmds/parallel_drive_ledger_create/main.go +++ b/test/antithesis/workload/bin/cmds/parallel_driver_ledger_create/main.go @@ -3,6 +3,7 @@ package main import ( "context" "fmt" + "log" "math/big" "github.com/antithesishq/antithesis-sdk-go/assert" @@ -10,6 +11,7 @@ import ( ) func main() { + log.Println("composer: parallel_driver_ledger_create") ctx := context.Background() client := internal.NewClient() id := big.NewInt(0).Abs(internal.RandomBigInt()).Int64() @@ -26,4 +28,6 @@ func main() { }) return } + + log.Println("composer: parallel_driver_ledger_create: done") } diff --git a/test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go b/test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go index 876963a092..2e582189fa 100644 --- a/test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go +++ b/test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go @@ -2,22 +2,25 @@ package main import ( "context" - "fmt" + "log" "math/big" "github.com/alitto/pond" "github.com/antithesishq/antithesis-sdk-go/assert" - "github.com/formancehq/go-libs/v2/pointer" - "github.com/formancehq/ledger/pkg/client/models/operations" "github.com/formancehq/ledger/test/antithesis/internal" "go.uber.org/atomic" ) func main() { + log.Println("composer: parallel_driver_transactions") + ctx := context.Background() client := internal.NewClient() - ledger := fmt.Sprintf("ledger-%d", internal.RandomBigInt().Int64()) + ledger, err := internal.GetRandomLedger(ctx, client) + if err != nil { + log.Fatalf("error getting random ledger: %s", err) + } const count = 100 @@ -49,27 +52,5 @@ func main() { return } - account, err := client.Ledger.V2.GetAccount(ctx, operations.V2GetAccountRequest{ - Address: "world", - Expand: pointer.For("volumes"), - Ledger: ledger, - }) - - if !internal.AssertAlwaysErrNil(err, "we should be able to query account 'world'", nil) { - return - } - - output := account.V2AccountResponse.Data.Volumes["USD/2"].Output - - if !internal.AssertAlways(output != nil, "Expect output of world for USD/2 to be not empty", internal.Details{}) { - return - } - - assert.Always( - output.Cmp(totalAmount) == 0, - "output of 'world' should match", - internal.Details{ - "output": output, - }, - ) + log.Println("composer: parallel_driver_transactions: done") } diff --git a/test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go b/test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go index a81f884d85..a5d97794f7 100644 --- a/test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go +++ b/test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go @@ -33,9 +33,12 @@ func checkVolumes(ctx context.Context, client *client.Formance, ledger string) { Ledger: ledger, }) if err != nil { - assert.Always(err == nil, "error getting aggregated balances", internal.Details{ - "error": err, - }) + assert.Always( + err == nil, + fmt.Sprintf("error getting aggregated balances for ledger %s", ledger), + internal.Details{ + "error": err, + }) return } From 4ed1eb52a13377b5000d1f748e1e979a0522a150 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Sala=C3=BCn?= Date: Mon, 5 May 2025 13:35:47 +0200 Subject: [PATCH 16/27] fix: volumes driver --- .../bin/cmds/parallel_driver_volumes/main.go | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go b/test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go index a5d97794f7..521babd128 100644 --- a/test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go +++ b/test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go @@ -3,7 +3,10 @@ package main import ( "context" "fmt" + "log" "math/big" + "os" + "sync" "github.com/antithesishq/antithesis-sdk-go/assert" "github.com/formancehq/ledger/pkg/client" @@ -12,20 +15,25 @@ import ( ) func main() { + log.Println("composer: parallel_driver_volumes") ctx := context.Background() client := internal.NewClient() ledgers, err := client.Ledger.V2.ListLedgers(ctx, operations.V2ListLedgersRequest{}) if err != nil { - assert.Always(err == nil, "error listing ledgers", internal.Details{ - "error": err, - }) - return + log.Printf("error listing ledgers: %s", err) + os.Exit(1) } + wg := sync.WaitGroup{} for _, ledger := range ledgers.V2LedgerListResponse.Cursor.Data { - go checkVolumes(ctx, client, ledger.Name) + wg.Add(1) + go func(ledger string) { + defer wg.Done() + checkVolumes(ctx, client, ledger) + }(ledger.Name) } + wg.Wait() } func checkVolumes(ctx context.Context, client *client.Formance, ledger string) { @@ -51,4 +59,6 @@ func checkVolumes(ctx context.Context, client *client.Formance, ledger string) { "error": err, }) } + + log.Printf("composer: parallel_driver_volumes: done for ledger %s", ledger) } From 8aaa393e9ea4820f467e7dc141d418172abcc469 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Sala=C3=BCn?= Date: Mon, 5 May 2025 13:41:42 +0200 Subject: [PATCH 17/27] fix: don't overuse assertions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Clément Salaün --- .../workload/bin/cmds/first_default_ledger/main.go | 6 +----- .../workload/bin/cmds/parallel_driver_volumes/main.go | 8 +------- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/test/antithesis/workload/bin/cmds/first_default_ledger/main.go b/test/antithesis/workload/bin/cmds/first_default_ledger/main.go index 96e2046daa..088cbaa41a 100644 --- a/test/antithesis/workload/bin/cmds/first_default_ledger/main.go +++ b/test/antithesis/workload/bin/cmds/first_default_ledger/main.go @@ -4,7 +4,6 @@ import ( "context" "log" - "github.com/antithesishq/antithesis-sdk-go/assert" "github.com/formancehq/ledger/test/antithesis/internal" ) @@ -21,10 +20,7 @@ func main() { ledger, ) if err != nil { - assert.Always(err == nil, "ledger should have been created properly", internal.Details{ - "error": err, - }) - return + log.Fatalf("error creating ledger %s: %s", ledger, err) } log.Println("composer: first_default_ledger: done") diff --git a/test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go b/test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go index 521babd128..34e1d39593 100644 --- a/test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go +++ b/test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go @@ -41,13 +41,7 @@ func checkVolumes(ctx context.Context, client *client.Formance, ledger string) { Ledger: ledger, }) if err != nil { - assert.Always( - err == nil, - fmt.Sprintf("error getting aggregated balances for ledger %s", ledger), - internal.Details{ - "error": err, - }) - return + log.Fatalf("error getting aggregated balances for ledger %s: %s", ledger, err) } for asset, volumes := range aggregated.V2AggregateBalancesResponse.Data { From 3ec2e4c7b0e48219be0ec0082a3918b578be60bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Sala=C3=BCn?= Date: Mon, 5 May 2025 15:12:00 +0200 Subject: [PATCH 18/27] fix: ledger id --- .../workload/bin/cmds/parallel_driver_ledger_create/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/antithesis/workload/bin/cmds/parallel_driver_ledger_create/main.go b/test/antithesis/workload/bin/cmds/parallel_driver_ledger_create/main.go index c882a8ba42..43b122d6c1 100644 --- a/test/antithesis/workload/bin/cmds/parallel_driver_ledger_create/main.go +++ b/test/antithesis/workload/bin/cmds/parallel_driver_ledger_create/main.go @@ -4,7 +4,7 @@ import ( "context" "fmt" "log" - "math/big" + "math/rand" "github.com/antithesishq/antithesis-sdk-go/assert" "github.com/formancehq/ledger/test/antithesis/internal" @@ -14,7 +14,7 @@ func main() { log.Println("composer: parallel_driver_ledger_create") ctx := context.Background() client := internal.NewClient() - id := big.NewInt(0).Abs(internal.RandomBigInt()).Int64() + id := rand.Intn(1e6) ledger := fmt.Sprintf("ledger-%d", id) err := internal.CreateLedger( From 9f22e06536e8d246ed615c61e1b8714b700d5e9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Sala=C3=BCn?= Date: Mon, 5 May 2025 15:14:01 +0200 Subject: [PATCH 19/27] fix: bucket/ledger --- .../workload/bin/cmds/first_default_ledger/main.go | 1 + .../bin/cmds/parallel_driver_ledger_create/main.go | 1 + test/antithesis/workload/internal/utils.go | 7 +++++-- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/test/antithesis/workload/bin/cmds/first_default_ledger/main.go b/test/antithesis/workload/bin/cmds/first_default_ledger/main.go index 088cbaa41a..206b5f0580 100644 --- a/test/antithesis/workload/bin/cmds/first_default_ledger/main.go +++ b/test/antithesis/workload/bin/cmds/first_default_ledger/main.go @@ -18,6 +18,7 @@ func main() { ctx, client, ledger, + ledger, ) if err != nil { log.Fatalf("error creating ledger %s: %s", ledger, err) diff --git a/test/antithesis/workload/bin/cmds/parallel_driver_ledger_create/main.go b/test/antithesis/workload/bin/cmds/parallel_driver_ledger_create/main.go index 43b122d6c1..e16b180849 100644 --- a/test/antithesis/workload/bin/cmds/parallel_driver_ledger_create/main.go +++ b/test/antithesis/workload/bin/cmds/parallel_driver_ledger_create/main.go @@ -21,6 +21,7 @@ func main() { ctx, client, ledger, + ledger, ) if err != nil { assert.Always(err == nil, "ledger should have been created properly", internal.Details{ diff --git a/test/antithesis/workload/internal/utils.go b/test/antithesis/workload/internal/utils.go index b502436ac9..67528b8348 100644 --- a/test/antithesis/workload/internal/utils.go +++ b/test/antithesis/workload/internal/utils.go @@ -49,16 +49,19 @@ func NewClient() *client.Formance { Backoff: &retry.BackoffStrategy{ InitialInterval: 200, Exponent: 1.5, - MaxElapsedTime: 4000, + MaxElapsedTime: 10_000, }, RetryConnectionErrors: true, }), ) } -func CreateLedger(ctx context.Context, client *client.Formance, name string) error { +func CreateLedger(ctx context.Context, client *client.Formance, name string, bucket string) error { _, err := client.Ledger.V2.CreateLedger(ctx, operations.V2CreateLedgerRequest{ Ledger: name, + V2CreateLedgerRequest: components.V2CreateLedgerRequest{ + Bucket: &bucket, + }, }) return err From e8b6e8231b5677b677be7ca17a9b9c45fd5f7271 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Sala=C3=BCn?= Date: Mon, 5 May 2025 16:54:18 +0200 Subject: [PATCH 20/27] fix: remove exhaustive assertion on tx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Clément Salaün --- .../bin/cmds/parallel_driver_transactions/main.go | 11 ++++------- .../workload/bin/cmds/parallel_driver_volumes/main.go | 1 + 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go b/test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go index 2e582189fa..e6d20ba799 100644 --- a/test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go +++ b/test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go @@ -24,7 +24,7 @@ func main() { const count = 100 - hasError := atomic.NewBool(false) + hasSuccess := atomic.NewBool(false) totalAmount := big.NewInt(0) pool := pond.New(10, 10e3) @@ -33,24 +33,21 @@ func main() { amount := internal.RandomBigInt() totalAmount = totalAmount.Add(totalAmount, amount) pool.Submit(func() { - if !internal.AssertAlwaysErrNil( + if internal.AssertAlwaysErrNil( internal.RunTx(ctx, client, amount, ledger), "creating transaction from @world to $account always return a nil error", internal.Details{ "ledger": ledger, }, ) { - hasError.CompareAndSwap(false, true) + hasSuccess.CompareAndSwap(false, true) } }) } pool.StopAndWait() - cond := !hasError.Load() - if assert.Always(cond, "all transactions should have been written", internal.Details{}); !cond { - return - } + assert.Always(hasSuccess.Load(), "at least some transactions were written", internal.Details{}) log.Println("composer: parallel_driver_transactions: done") } diff --git a/test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go b/test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go index 34e1d39593..43792b9b39 100644 --- a/test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go +++ b/test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go @@ -20,6 +20,7 @@ func main() { client := internal.NewClient() ledgers, err := client.Ledger.V2.ListLedgers(ctx, operations.V2ListLedgersRequest{}) + if err != nil { log.Printf("error listing ledgers: %s", err) os.Exit(1) From 9fc1cf7efa0915f323b2e679990c1007996bb690 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Sala=C3=BCn?= Date: Mon, 5 May 2025 17:23:11 +0200 Subject: [PATCH 21/27] fix: switch to sometimes assertions for tx commit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Clément Salaün --- .../cmds/parallel_driver_transactions/main.go | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go b/test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go index e6d20ba799..4bffdc2e3e 100644 --- a/test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go +++ b/test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go @@ -8,7 +8,6 @@ import ( "github.com/alitto/pond" "github.com/antithesishq/antithesis-sdk-go/assert" "github.com/formancehq/ledger/test/antithesis/internal" - "go.uber.org/atomic" ) func main() { @@ -24,7 +23,6 @@ func main() { const count = 100 - hasSuccess := atomic.NewBool(false) totalAmount := big.NewInt(0) pool := pond.New(10, 10e3) @@ -33,21 +31,14 @@ func main() { amount := internal.RandomBigInt() totalAmount = totalAmount.Add(totalAmount, amount) pool.Submit(func() { - if internal.AssertAlwaysErrNil( - internal.RunTx(ctx, client, amount, ledger), - "creating transaction from @world to $account always return a nil error", - internal.Details{ - "ledger": ledger, - }, - ) { - hasSuccess.CompareAndSwap(false, true) - } + err := internal.RunTx(ctx, client, amount, ledger) + assert.Sometimes(err == nil, "transaction was committed successfully", internal.Details{ + "ledger": ledger, + }) }) } pool.StopAndWait() - assert.Always(hasSuccess.Load(), "at least some transactions were written", internal.Details{}) - log.Println("composer: parallel_driver_transactions: done") } From e52be33421a0fc66047a9058dae7d03fd954546b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Sala=C3=BCn?= Date: Mon, 5 May 2025 17:27:03 +0200 Subject: [PATCH 22/27] feat: switch ledger creation to sometimes assertions as well MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Clément Salaün --- .../bin/cmds/parallel_driver_ledger_create/main.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/test/antithesis/workload/bin/cmds/parallel_driver_ledger_create/main.go b/test/antithesis/workload/bin/cmds/parallel_driver_ledger_create/main.go index e16b180849..797bd357ba 100644 --- a/test/antithesis/workload/bin/cmds/parallel_driver_ledger_create/main.go +++ b/test/antithesis/workload/bin/cmds/parallel_driver_ledger_create/main.go @@ -23,12 +23,9 @@ func main() { ledger, ledger, ) - if err != nil { - assert.Always(err == nil, "ledger should have been created properly", internal.Details{ - "error": err, - }) - return - } + assert.Sometimes(err == nil, "ledger should have been created properly", internal.Details{ + "error": err, + }) log.Println("composer: parallel_driver_ledger_create: done") } From 40c1a3984696da973266ad33befe4edac9da8cb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Sala=C3=BCn?= Date: Mon, 5 May 2025 19:32:53 +0200 Subject: [PATCH 23/27] fix: move correctness check to eventually MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Clément Salaün --- .../{parallel_driver_volumes => eventually_correct}/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename test/antithesis/workload/bin/cmds/{parallel_driver_volumes => eventually_correct}/main.go (91%) diff --git a/test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go b/test/antithesis/workload/bin/cmds/eventually_correct/main.go similarity index 91% rename from test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go rename to test/antithesis/workload/bin/cmds/eventually_correct/main.go index 43792b9b39..2bcbf6cce0 100644 --- a/test/antithesis/workload/bin/cmds/parallel_driver_volumes/main.go +++ b/test/antithesis/workload/bin/cmds/eventually_correct/main.go @@ -15,7 +15,7 @@ import ( ) func main() { - log.Println("composer: parallel_driver_volumes") + log.Println("composer: eventually_correct") ctx := context.Background() client := internal.NewClient() @@ -55,5 +55,5 @@ func checkVolumes(ctx context.Context, client *client.Formance, ledger string) { }) } - log.Printf("composer: parallel_driver_volumes: done for ledger %s", ledger) + log.Printf("composer: eventually_correct: done for ledger %s", ledger) } From c8ab708ac79b892bc52076c2a6ffd8c46e0e0ba3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Sala=C3=BCn?= Date: Tue, 6 May 2025 10:03:26 +0200 Subject: [PATCH 24/27] feat: improve error handling on eventually MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Clément Salaün --- .../bin/cmds/eventually_correct/main.go | 17 ++++++++++++++++- test/antithesis/workload/internal/utils.go | 4 ++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/test/antithesis/workload/bin/cmds/eventually_correct/main.go b/test/antithesis/workload/bin/cmds/eventually_correct/main.go index 2bcbf6cce0..7a5ce3e022 100644 --- a/test/antithesis/workload/bin/cmds/eventually_correct/main.go +++ b/test/antithesis/workload/bin/cmds/eventually_correct/main.go @@ -10,6 +10,7 @@ import ( "github.com/antithesishq/antithesis-sdk-go/assert" "github.com/formancehq/ledger/pkg/client" + "github.com/formancehq/ledger/pkg/client/models/components" "github.com/formancehq/ledger/pkg/client/models/operations" "github.com/formancehq/ledger/test/antithesis/internal" ) @@ -42,7 +43,17 @@ func checkVolumes(ctx context.Context, client *client.Formance, ledger string) { Ledger: ledger, }) if err != nil { - log.Fatalf("error getting aggregated balances for ledger %s: %s", ledger, err) + if internal.IsServerError(aggregated.GetHTTPMeta()) { + assert.Always( + false, + fmt.Sprintf("error getting aggregated balances for ledger %s: %s", ledger, err), + internal.Details{ + "error": err, + }, + ) + } else { + log.Fatalf("error getting aggregated balances for ledger %s: %s", ledger, err) + } } for asset, volumes := range aggregated.V2AggregateBalancesResponse.Data { @@ -57,3 +68,7 @@ func checkVolumes(ctx context.Context, client *client.Formance, ledger string) { log.Printf("composer: eventually_correct: done for ledger %s", ledger) } + +func IsServerError(httpMeta components.HTTPMetadata) bool { + return httpMeta.Response.StatusCode >= 400 && httpMeta.Response.StatusCode < 600 +} diff --git a/test/antithesis/workload/internal/utils.go b/test/antithesis/workload/internal/utils.go index 67528b8348..ab116b907a 100644 --- a/test/antithesis/workload/internal/utils.go +++ b/test/antithesis/workload/internal/utils.go @@ -56,6 +56,10 @@ func NewClient() *client.Formance { ) } +func IsServerError(httpMeta components.HTTPMetadata) bool { + return httpMeta.Response.StatusCode >= 400 && httpMeta.Response.StatusCode < 600 +} + func CreateLedger(ctx context.Context, client *client.Formance, name string, bucket string) error { _, err := client.Ledger.V2.CreateLedger(ctx, operations.V2CreateLedgerRequest{ Ledger: name, From 979b33a61f8c6839ffecf9bd216a10cfc329735f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Sala=C3=BCn?= Date: Tue, 6 May 2025 17:07:33 +0200 Subject: [PATCH 25/27] fix: improve error handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Clément Salaün --- .../bin/cmds/parallel_driver_transactions/main.go | 9 +++++++-- test/antithesis/workload/internal/utils.go | 7 ++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go b/test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go index 4bffdc2e3e..7bc15c22ed 100644 --- a/test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go +++ b/test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go @@ -18,7 +18,8 @@ func main() { ledger, err := internal.GetRandomLedger(ctx, client) if err != nil { - log.Fatalf("error getting random ledger: %s", err) + ledger = "default" + log.Printf("error getting random ledger: %s", err) } const count = 100 @@ -31,10 +32,14 @@ func main() { amount := internal.RandomBigInt() totalAmount = totalAmount.Add(totalAmount, amount) pool.Submit(func() { - err := internal.RunTx(ctx, client, amount, ledger) + res, err := internal.RunTx(ctx, client, amount, ledger) assert.Sometimes(err == nil, "transaction was committed successfully", internal.Details{ "ledger": ledger, }) + assert.Always(!internal.IsServerError(res.GetHTTPMeta()), "no internal server error when committing transaction", internal.Details{ + "ledger": ledger, + "error": err, + }) }) } diff --git a/test/antithesis/workload/internal/utils.go b/test/antithesis/workload/internal/utils.go index ab116b907a..f51be7bdd8 100644 --- a/test/antithesis/workload/internal/utils.go +++ b/test/antithesis/workload/internal/utils.go @@ -102,11 +102,11 @@ func GetRandomLedger(ctx context.Context, client *client.Formance) (string, erro return ledgers[randomIndex], nil } -func RunTx(ctx context.Context, client *client.Formance, amount *big.Int, ledger string) error { +func RunTx(ctx context.Context, client *client.Formance, amount *big.Int, ledger string) (*operations.V2CreateTransactionResponse, error) { orderID := fmt.Sprint(int64(math.Abs(float64(random.GetRandom())))) dest := fmt.Sprintf("orders:%s", orderID) - _, err := client.Ledger.V2.CreateTransaction(ctx, operations.V2CreateTransactionRequest{ + res, err := client.Ledger.V2.CreateTransaction(ctx, operations.V2CreateTransactionRequest{ V2PostTransaction: components.V2PostTransaction{ Postings: []components.V2Posting{{ Amount: amount, @@ -117,5 +117,6 @@ func RunTx(ctx context.Context, client *client.Formance, amount *big.Int, ledger }, Ledger: ledger, }) - return err + + return res, err } From 49b0414f433833866c7aa60126cc8b14a98b1a3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Sala=C3=BCn?= Date: Wed, 7 May 2025 15:03:23 +0200 Subject: [PATCH 26/27] wip: improve MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Clément Salaün --- .../bin/cmds/anytime_version_upgrade/main.go | 8 ++++ .../bin/cmds/first_default_ledger/main.go | 3 +- .../parallel_driver_ledger_create/main.go | 11 ++++- .../cmds/parallel_driver_transactions/main.go | 46 ++++++++++++++++++- test/antithesis/workload/datagen/example.json | 3 ++ test/antithesis/workload/datagen/main.go | 17 +++++++ test/antithesis/workload/internal/utils.go | 28 ++--------- 7 files changed, 88 insertions(+), 28 deletions(-) create mode 100644 test/antithesis/workload/bin/cmds/anytime_version_upgrade/main.go create mode 100644 test/antithesis/workload/datagen/example.json create mode 100644 test/antithesis/workload/datagen/main.go diff --git a/test/antithesis/workload/bin/cmds/anytime_version_upgrade/main.go b/test/antithesis/workload/bin/cmds/anytime_version_upgrade/main.go new file mode 100644 index 0000000000..93ed37a6f2 --- /dev/null +++ b/test/antithesis/workload/bin/cmds/anytime_version_upgrade/main.go @@ -0,0 +1,8 @@ +package main + +import "log" + +func main() { + // TODO: implement + log.Println("placeholder command for anytime_version_upgrade") +} diff --git a/test/antithesis/workload/bin/cmds/first_default_ledger/main.go b/test/antithesis/workload/bin/cmds/first_default_ledger/main.go index 206b5f0580..b609ed331d 100644 --- a/test/antithesis/workload/bin/cmds/first_default_ledger/main.go +++ b/test/antithesis/workload/bin/cmds/first_default_ledger/main.go @@ -14,12 +14,13 @@ func main() { client := internal.NewClient() ledger := "default" - err := internal.CreateLedger( + _, err := internal.CreateLedger( ctx, client, ledger, ledger, ) + if err != nil { log.Fatalf("error creating ledger %s: %s", ledger, err) } diff --git a/test/antithesis/workload/bin/cmds/parallel_driver_ledger_create/main.go b/test/antithesis/workload/bin/cmds/parallel_driver_ledger_create/main.go index 797bd357ba..4a3c649361 100644 --- a/test/antithesis/workload/bin/cmds/parallel_driver_ledger_create/main.go +++ b/test/antithesis/workload/bin/cmds/parallel_driver_ledger_create/main.go @@ -17,15 +17,24 @@ func main() { id := rand.Intn(1e6) ledger := fmt.Sprintf("ledger-%d", id) - err := internal.CreateLedger( + res, err := internal.CreateLedger( ctx, client, ledger, ledger, ) + assert.Sometimes(err == nil, "ledger should have been created properly", internal.Details{ "error": err, }) + assert.Always( + !internal.IsServerError(res.GetHTTPMeta()), + "no internal server error when creating ledger", + internal.Details{ + "error": err, + }, + ) + log.Println("composer: parallel_driver_ledger_create: done") } diff --git a/test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go b/test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go index 7bc15c22ed..882948a37a 100644 --- a/test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go +++ b/test/antithesis/workload/bin/cmds/parallel_driver_transactions/main.go @@ -7,6 +7,9 @@ import ( "github.com/alitto/pond" "github.com/antithesishq/antithesis-sdk-go/assert" + "github.com/formancehq/ledger/pkg/client" + "github.com/formancehq/ledger/pkg/client/models/components" + "github.com/formancehq/ledger/pkg/client/models/operations" "github.com/formancehq/ledger/test/antithesis/internal" ) @@ -32,7 +35,7 @@ func main() { amount := internal.RandomBigInt() totalAmount = totalAmount.Add(totalAmount, amount) pool.Submit(func() { - res, err := internal.RunTx(ctx, client, amount, ledger) + res, err := RunTx(ctx, client, Transaction(), ledger) assert.Sometimes(err == nil, "transaction was committed successfully", internal.Details{ "ledger": ledger, }) @@ -47,3 +50,44 @@ func main() { log.Println("composer: parallel_driver_transactions: done") } + +type Postings []components.V2Posting + +func RunTx( + ctx context.Context, + client *client.Formance, + postings Postings, + ledger string, +) (*operations.V2CreateTransactionResponse, error) { + res, err := client.Ledger.V2.CreateTransaction(ctx, operations.V2CreateTransactionRequest{ + Ledger: ledger, + V2PostTransaction: components.V2PostTransaction{ + Postings: postings, + }, + }) + + return res, err +} + +func Transaction() []components.V2Posting { + postings := []components.V2Posting{} + + postings = append(postings, components.V2Posting{ + Amount: big.NewInt(100), + Asset: "USD/2", + Destination: "orders:1234", + Source: "world", + }) + + return postings +} + +func Sequence() []Postings { + postings := []Postings{} + + for i := 0; i < 10; i++ { + postings = append(postings, Transaction()) + } + + return postings +} diff --git a/test/antithesis/workload/datagen/example.json b/test/antithesis/workload/datagen/example.json new file mode 100644 index 0000000000..ec2649bb49 --- /dev/null +++ b/test/antithesis/workload/datagen/example.json @@ -0,0 +1,3 @@ +[ + {} +] \ No newline at end of file diff --git a/test/antithesis/workload/datagen/main.go b/test/antithesis/workload/datagen/main.go new file mode 100644 index 0000000000..a25249ac83 --- /dev/null +++ b/test/antithesis/workload/datagen/main.go @@ -0,0 +1,17 @@ +package main + +import ( + "fmt" + "math/rand" +) + +type Sequence struct { +} + +func Account() string { + return fmt.Sprintf("%d", rand.Intn(10e9)) +} + +func main() { + fmt.Println(Account()) +} diff --git a/test/antithesis/workload/internal/utils.go b/test/antithesis/workload/internal/utils.go index f51be7bdd8..4bb87f8890 100644 --- a/test/antithesis/workload/internal/utils.go +++ b/test/antithesis/workload/internal/utils.go @@ -3,7 +3,6 @@ package internal import ( "context" "fmt" - "math" "math/big" "math/rand" "net/http" @@ -60,15 +59,15 @@ func IsServerError(httpMeta components.HTTPMetadata) bool { return httpMeta.Response.StatusCode >= 400 && httpMeta.Response.StatusCode < 600 } -func CreateLedger(ctx context.Context, client *client.Formance, name string, bucket string) error { - _, err := client.Ledger.V2.CreateLedger(ctx, operations.V2CreateLedgerRequest{ +func CreateLedger(ctx context.Context, client *client.Formance, name string, bucket string) (*operations.V2CreateLedgerResponse, error) { + res, err := client.Ledger.V2.CreateLedger(ctx, operations.V2CreateLedgerRequest{ Ledger: name, V2CreateLedgerRequest: components.V2CreateLedgerRequest{ Bucket: &bucket, }, }) - return err + return res, err } func ListLedgers(ctx context.Context, client *client.Formance) ([]string, error) { @@ -95,28 +94,7 @@ func GetRandomLedger(ctx context.Context, client *client.Formance) (string, erro return "", fmt.Errorf("no ledgers found") } - // Get a random index within the ledgers slice randomIndex := rand.Intn(len(ledgers)) - // Return the ledger at the random index return ledgers[randomIndex], nil } - -func RunTx(ctx context.Context, client *client.Formance, amount *big.Int, ledger string) (*operations.V2CreateTransactionResponse, error) { - orderID := fmt.Sprint(int64(math.Abs(float64(random.GetRandom())))) - dest := fmt.Sprintf("orders:%s", orderID) - - res, err := client.Ledger.V2.CreateTransaction(ctx, operations.V2CreateTransactionRequest{ - V2PostTransaction: components.V2PostTransaction{ - Postings: []components.V2Posting{{ - Amount: amount, - Asset: "USD/2", - Destination: dest, - Source: "world", - }}, - }, - Ledger: ledger, - }) - - return res, err -} From 9248bd8c00b27e0649da8964753c7e8c3d3f69fa Mon Sep 17 00:00:00 2001 From: Maxence Maireaux Date: Thu, 19 Jun 2025 14:22:02 +0200 Subject: [PATCH 27/27] feat: add Kubernetes pod configuration for workload --- test/antithesis/config/kube.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 test/antithesis/config/kube.yaml diff --git a/test/antithesis/config/kube.yaml b/test/antithesis/config/kube.yaml new file mode 100644 index 0000000000..e6b6497229 --- /dev/null +++ b/test/antithesis/config/kube.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Pod +metadata: + name: workload + namespace: formance-dev + labels: + app: workload +spec: + containers: + - name: workload + image: us-central1-docker.pkg.dev/molten-verve-216720/formance-repository/workload:latest + imagePullPolicy: Always \ No newline at end of file