From 2476a85ac1ddc5c7b0cfa507360a8dd534b7e784 Mon Sep 17 00:00:00 2001 From: batiati Date: Wed, 14 Feb 2024 12:45:50 -0300 Subject: [PATCH 1/2] [Go] Add client batching integration tests --- src/clients/go/tb_client_test.go | 67 +++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 6 deletions(-) diff --git a/src/clients/go/tb_client_test.go b/src/clients/go/tb_client_test.go index 7d5e9bf191..c180645985 100644 --- a/src/clients/go/tb_client_test.go +++ b/src/clients/go/tb_client_test.go @@ -3,6 +3,7 @@ package tigerbeetle_go import ( "bytes" "fmt" + "math/big" "os" "os/exec" "runtime" @@ -14,10 +15,11 @@ import ( ) const ( - TIGERBEETLE_PORT = "3000" - TIGERBEETLE_CLUSTER_ID uint64 = 0 - TIGERBEETLE_REPLICA_ID uint32 = 0 - TIGERBEETLE_REPLICA_COUNT uint32 = 1 + TIGERBEETLE_PORT = "3000" + TIGERBEETLE_CLUSTER_ID uint64 = 0 + TIGERBEETLE_REPLICA_ID uint32 = 0 + TIGERBEETLE_REPLICA_COUNT uint32 = 1 + TIGERBEETLE_CONCURRENCY_MAX uint = 4096 ) func HexStringToUint128(value string) types.Uint128 { @@ -70,8 +72,7 @@ func WithClient(s testing.TB, withClient func(Client)) { }) addresses := []string{"127.0.0.1:" + TIGERBEETLE_PORT} - concurrencyMax := uint(32) - client, err := NewClient(types.ToUint128(TIGERBEETLE_CLUSTER_ID), addresses, concurrencyMax) + client, err := NewClient(types.ToUint128(TIGERBEETLE_CLUSTER_ID), addresses, TIGERBEETLE_CONCURRENCY_MAX) if err != nil { s.Fatal(err) } @@ -230,6 +231,60 @@ func doTestClient(s *testing.T, client Client) { assert.Equal(t, types.ToUint128(0), accountB.DebitsPending) }) + s.Run("can create concurrent transfers", func(t *testing.T) { + const TRANSFERS_MAX = 1_000_000 + concurrencyMax := make(chan struct{}, TIGERBEETLE_CONCURRENCY_MAX) + finished := make(chan struct{}, TRANSFERS_MAX) + + accounts, err := client.LookupAccounts([]types.Uint128{accountA.ID, accountB.ID}) + if err != nil { + t.Fatal(err) + } + assert.Len(t, accounts, 2) + accountACredits := accounts[0].CreditsPosted.BigInt() + accountBDebits := accounts[1].DebitsPosted.BigInt() + + for i := 0; i < TRANSFERS_MAX; i++ { + go func(i int) { + concurrencyMax <- struct{}{} + results, err := client.CreateTransfers([]types.Transfer{ + { + ID: types.ToUint128(uint64(TRANSFERS_MAX + i)), + CreditAccountID: accountA.ID, + DebitAccountID: accountB.ID, + Amount: types.ToUint128(1), + Ledger: 1, + Code: 1, + }, + }) + <-concurrencyMax + if err != nil { + t.Fatal(err) + } + + assert.Empty(t, results) + finished <- struct{}{} + }(i) + } + + for i := 0; i < TRANSFERS_MAX; i++ { + <-finished + } + + accounts, err = client.LookupAccounts([]types.Uint128{accountA.ID, accountB.ID}) + if err != nil { + t.Fatal(err) + } + assert.Len(t, accounts, 2) + accountACreditsAfter := accounts[0].CreditsPosted.BigInt() + accountBDebitsAfter := accounts[1].DebitsPosted.BigInt() + + // Each transfer moves ONE unit, + // so the credit/debit must differ from TRANSFERS_MAX units: + assert.Equal(t, TRANSFERS_MAX, big.NewInt(0).Sub(&accountACreditsAfter, &accountACredits).Int64()) + assert.Equal(t, TRANSFERS_MAX, big.NewInt(0).Sub(&accountBDebitsAfter, &accountBDebits).Int64()) + }) + s.Run("can query transfers for an account", func(t *testing.T) { // Create a new account: accountC := types.Account{ From f237fadc601e58c07d993ea0a25a23fc0495a75d Mon Sep 17 00:00:00 2001 From: batiati Date: Wed, 14 Feb 2024 14:05:20 -0300 Subject: [PATCH 2/2] [Go] Use waitGroup --- src/clients/go/tb_client_test.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/clients/go/tb_client_test.go b/src/clients/go/tb_client_test.go index c180645985..8511ef95fe 100644 --- a/src/clients/go/tb_client_test.go +++ b/src/clients/go/tb_client_test.go @@ -7,6 +7,7 @@ import ( "os" "os/exec" "runtime" + "sync" "testing" "unsafe" @@ -234,7 +235,6 @@ func doTestClient(s *testing.T, client Client) { s.Run("can create concurrent transfers", func(t *testing.T) { const TRANSFERS_MAX = 1_000_000 concurrencyMax := make(chan struct{}, TIGERBEETLE_CONCURRENCY_MAX) - finished := make(chan struct{}, TRANSFERS_MAX) accounts, err := client.LookupAccounts([]types.Uint128{accountA.ID, accountB.ID}) if err != nil { @@ -244,8 +244,13 @@ func doTestClient(s *testing.T, client Client) { accountACredits := accounts[0].CreditsPosted.BigInt() accountBDebits := accounts[1].DebitsPosted.BigInt() + var waitGroup sync.WaitGroup for i := 0; i < TRANSFERS_MAX; i++ { + waitGroup.Add(1) + go func(i int) { + defer waitGroup.Done() + concurrencyMax <- struct{}{} results, err := client.CreateTransfers([]types.Transfer{ { @@ -263,13 +268,9 @@ func doTestClient(s *testing.T, client Client) { } assert.Empty(t, results) - finished <- struct{}{} }(i) } - - for i := 0; i < TRANSFERS_MAX; i++ { - <-finished - } + waitGroup.Wait() accounts, err = client.LookupAccounts([]types.Uint128{accountA.ID, accountB.ID}) if err != nil {