From 89d50e55b4daf350833fe6f2f57e7362ff9def9c Mon Sep 17 00:00:00 2001 From: Bartosz Lenart Date: Mon, 24 Apr 2023 12:36:29 +0200 Subject: [PATCH] Stress test the REST API. --- README.md | 74 +++++++++++++++++++++----------- bookkeeping/bookkeeping.go | 16 +++++++ cmd/central/main.go | 6 ++- docs/docs.md | 68 ++++++++++++++++++----------- docs/git_hub_header.md | 6 +++ gendocs.sh | 1 - logging/logging.go | 31 ++++++++++--- mongodb_queries/create_tokens.js | 8 +--- repo/transaction.go | 16 +++++++ server/rest.go | 15 ++++--- server_settings_example.yaml | 2 +- stress/stress.go | 1 + stress/stress_test.go | 53 +++++++++++++++++++++++ 13 files changed, 225 insertions(+), 72 deletions(-) create mode 100644 stress/stress.go create mode 100644 stress/stress_test.go diff --git a/README.md b/README.md index 8de92bb..b3caa8a 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,12 @@ Computantis is not keeping track of all transactions in a single blockchain but 0. Run database `docker compose up`. 1. Create `server_settings.yaml` according to `server_settings_example.yaml` in the repo root folder. 2. Run `make run` or `go run cmd/central/main.go`. + +## Stress test + +Directory `./stress/` contains REST API performance tests. +For example the test on MacBook with M2 arm64 chip, 24GB RAM, mongodb run in docker container with 1CPU and 1GB RAM, +for full cycle of creating 1000 transactions took 3.75 sec. # block @@ -230,7 +236,7 @@ var ( ) ``` -## type [AddressChecker]() +## type [AddressChecker]() ```go type AddressChecker interface { @@ -238,7 +244,7 @@ type AddressChecker interface { } ``` -## type [BlockFinder]() +## type [BlockFinder]() ```go type BlockFinder interface { @@ -247,7 +253,7 @@ type BlockFinder interface { } ``` -## type [BlockReadWriter]() +## type [BlockReadWriter]() ```go type BlockReadWriter interface { @@ -256,7 +262,7 @@ type BlockReadWriter interface { } ``` -## type [BlockReader]() +## type [BlockReader]() ```go type BlockReader interface { @@ -264,7 +270,7 @@ type BlockReader interface { } ``` -## type [BlockWriter]() +## type [BlockWriter]() ```go type BlockWriter interface { @@ -272,7 +278,7 @@ type BlockWriter interface { } ``` -## type [Config]() +## type [Config]() ```go type Config struct { @@ -282,13 +288,13 @@ type Config struct { } ``` -### func \(Config\) [Validate]() +### func \(Config\) [Validate]() ```go func (c Config) Validate() error ``` -## type [Ledger]() +## type [Ledger]() Ledger is a collection of ledger functionality to perform bookkeeping. @@ -298,7 +304,7 @@ type Ledger struct { } ``` -### func [NewLedger]() +### func [NewLedger]() ```go func NewLedger(config Config, bc BlockReadWriter, tx TrxWriteReadMover, ac AddressChecker, vr SignatureVerifier, tf BlockFinder, log logger.Logger) (*Ledger, error) @@ -306,7 +312,7 @@ func NewLedger(config Config, bc BlockReadWriter, tx TrxWriteReadMover, ac Addre NewLedger creates new Ledger if config is valid or returns error otherwise. -### func \(\*Ledger\) [Run]() +### func \(\*Ledger\) [Run]() ```go func (l *Ledger) Run(ctx context.Context) @@ -314,13 +320,13 @@ func (l *Ledger) Run(ctx context.Context) Run runs the Ladger engine that writes blocks to the blockchain repository. Run starts a goroutine and can be stopped by cancelling the context. -### func \(\*Ledger\) [VerifySignature]() +### func \(\*Ledger\) [VerifySignature]() ```go func (l *Ledger) VerifySignature(message, signature []byte, hash [32]byte, address string) error ``` -### func \(\*Ledger\) [WriteCandidateTransaction]() +### func \(\*Ledger\) [WriteCandidateTransaction]() ```go func (l *Ledger) WriteCandidateTransaction(ctx context.Context, trx *transaction.Transaction) error @@ -328,7 +334,7 @@ func (l *Ledger) WriteCandidateTransaction(ctx context.Context, trx *transaction WriteCandidateTransaction validates and writes a transaction to the repository. Transaction is not yet a part of the blockchain. -### func \(\*Ledger\) [WriteIssuerSignedTransactionForReceiver]() +### func \(\*Ledger\) [WriteIssuerSignedTransactionForReceiver]() ```go func (l *Ledger) WriteIssuerSignedTransactionForReceiver(ctx context.Context, receiverAddr string, trx *transaction.Transaction) error @@ -336,7 +342,7 @@ func (l *Ledger) WriteIssuerSignedTransactionForReceiver(ctx context.Context, re WriteIssuerSignedTransactionForReceiver validates issuer signature and writes a transaction to the repository for receiver. -## type [SignatureVerifier]() +## type [SignatureVerifier]() ```go type SignatureVerifier interface { @@ -344,7 +350,7 @@ type SignatureVerifier interface { } ``` -## type [TrxWriteReadMover]() +## type [TrxWriteReadMover]() ```go type TrxWriteReadMover interface { @@ -354,6 +360,7 @@ type TrxWriteReadMover interface { RemoveAwaitingTransaction(ctx context.Context, trxHash [32]byte) error ReadAwaitingTransactionsByReceiver(ctx context.Context, address string) ([]transaction.Transaction, error) ReadAwaitingTransactionsByIssuer(ctx context.Context, address string) ([]transaction.Transaction, error) + ReadTemporaryTransactions(ctx context.Context) ([]transaction.Transaction, error) } ``` @@ -693,7 +700,7 @@ import "github.com/bartossh/Computantis/logging" ## Index - [type Helper](<#type-helper>) - - [func New(callOnErr func(error), writers ...io.Writer) Helper](<#func-new>) + - [func New(callOnWriteLogErr, callOnFatal func(error), writers ...io.Writer) Helper](<#func-new>) - [func (h Helper) Debug(msg string)](<#func-helper-debug>) - [func (h Helper) Error(msg string)](<#func-helper-error>) - [func (h Helper) Fatal(msg string)](<#func-helper-fatal>) @@ -701,7 +708,7 @@ import "github.com/bartossh/Computantis/logging" - [func (h Helper) Warn(msg string)](<#func-helper-warn>) -## type [Helper]() +## type [Helper]() Helper helps with writing logs to io.Writers. Helper implements logger.Logger interface. Writing is done concurrently with out blocking the current thread. @@ -711,15 +718,15 @@ type Helper struct { } ``` -### func [New]() +### func [New]() ```go -func New(callOnErr func(error), writers ...io.Writer) Helper +func New(callOnWriteLogErr, callOnFatal func(error), writers ...io.Writer) Helper ``` New creates new Helper. -### func \(Helper\) [Debug]() +### func \(Helper\) [Debug]() ```go func (h Helper) Debug(msg string) @@ -727,7 +734,7 @@ func (h Helper) Debug(msg string) Debug writes debug log. -### func \(Helper\) [Error]() +### func \(Helper\) [Error]() ```go func (h Helper) Error(msg string) @@ -735,7 +742,7 @@ func (h Helper) Error(msg string) Error writes error log. -### func \(Helper\) [Fatal]() +### func \(Helper\) [Fatal]() ```go func (h Helper) Fatal(msg string) @@ -743,7 +750,7 @@ func (h Helper) Fatal(msg string) Fatal writes fatal log. -### func \(Helper\) [Info]() +### func \(Helper\) [Info]() ```go func (h Helper) Info(msg string) @@ -751,7 +758,7 @@ func (h Helper) Info(msg string) Info writes info log. -### func \(Helper\) [Warn]() +### func \(Helper\) [Warn]() ```go func (h Helper) Warn(msg string) @@ -782,6 +789,7 @@ import "github.com/bartossh/Computantis/repo" - [func (db DataBase) ReadAwaitingTransactionsByIssuer(ctx context.Context, address string) ([]transaction.Transaction, error)](<#func-database-readawaitingtransactionsbyissuer>) - [func (db DataBase) ReadAwaitingTransactionsByReceiver(ctx context.Context, address string) ([]transaction.Transaction, error)](<#func-database-readawaitingtransactionsbyreceiver>) - [func (db DataBase) ReadBlockByHash(ctx context.Context, hash [32]byte) (block.Block, error)](<#func-database-readblockbyhash>) + - [func (db DataBase) ReadTemporaryTransactions(ctx context.Context) ([]transaction.Transaction, error)](<#func-database-readtemporarytransactions>) - [func (db DataBase) RemoveAwaitingTransaction(ctx context.Context, trxHash [32]byte) error](<#func-database-removeawaitingtransaction>) - [func (c DataBase) RunMigration(ctx context.Context) error](<#func-database-runmigration>) - [func (db DataBase) Write(p []byte) (n int, err error)](<#func-database-write>) @@ -927,6 +935,14 @@ func (db DataBase) ReadBlockByHash(ctx context.Context, hash [32]byte) (block.Bl ReadBlockByHash returns block with given hash. +### func \(DataBase\) [ReadTemporaryTransactions]() + +```go +func (db DataBase) ReadTemporaryTransactions(ctx context.Context) ([]transaction.Transaction, error) +``` + +ReadTemporaryTransactions reads transactions from the temporary storage. + ### func \(DataBase\) [RemoveAwaitingTransaction]() ```go @@ -1381,6 +1397,16 @@ type UpgradeConnectionRequest struct { } ``` +# stress + +```go +import "github.com/bartossh/Computantis/stress" +``` + +## Index + + + # transaction ```go diff --git a/bookkeeping/bookkeeping.go b/bookkeeping/bookkeeping.go index 9285715..d9499be 100644 --- a/bookkeeping/bookkeeping.go +++ b/bookkeeping/bookkeeping.go @@ -40,6 +40,7 @@ type TrxWriteReadMover interface { RemoveAwaitingTransaction(ctx context.Context, trxHash [32]byte) error ReadAwaitingTransactionsByReceiver(ctx context.Context, address string) ([]transaction.Transaction, error) ReadAwaitingTransactionsByIssuer(ctx context.Context, address string) ([]transaction.Transaction, error) + ReadTemporaryTransactions(ctx context.Context) ([]transaction.Transaction, error) } type BlockReader interface { @@ -133,6 +134,9 @@ func NewLedger( // Run runs the Ladger engine that writes blocks to the blockchain repository. // Run starts a goroutine and can be stopped by cancelling the context. func (l *Ledger) Run(ctx context.Context) { + if err := l.forgeTemporary(ctx); err != nil { + l.log.Fatal(fmt.Sprintf("forging temporary failed: %s", err.Error())) + } go func(ctx context.Context) { ticker := time.NewTicker(time.Duration(l.config.BlockWriteTimestamp) * time.Second) outer: @@ -198,6 +202,18 @@ func (l *Ledger) VerifySignature(message, signature []byte, hash [32]byte, addre return l.vr.Verify(message, signature, hash, address) } +func (l *Ledger) forgeTemporary(ctx context.Context) error { + trxs, err := l.tx.ReadTemporaryTransactions(ctx) + if err != nil { + return err + } + for _, trx := range trxs { + l.hashes = append(l.hashes, trx.Hash) + } + l.forge(ctx) + return nil +} + func (l *Ledger) forge(ctx context.Context) { defer l.cleanHashes() blcHash, err := l.saveBlock(ctx) diff --git a/cmd/central/main.go b/cmd/central/main.go index 56a3747..9c7da0d 100644 --- a/cmd/central/main.go +++ b/cmd/central/main.go @@ -44,7 +44,11 @@ func main() { fmt.Println("error with logger: ", err) } - log := logging.New(callbackOnErr, db) + callbackOnFatal := func(err error) { + panic(fmt.Sprintf("error with logger: %s", err)) + } + + log := logging.New(callbackOnErr, callbackOnFatal, db) if err := blockchain.GenesisBlock(ctx, db); err != nil { fmt.Println(err) diff --git a/docs/docs.md b/docs/docs.md index 394e38f..165934f 100644 --- a/docs/docs.md +++ b/docs/docs.md @@ -213,7 +213,7 @@ var ( ) ``` -## type [AddressChecker]() +## type [AddressChecker]() ```go type AddressChecker interface { @@ -221,7 +221,7 @@ type AddressChecker interface { } ``` -## type [BlockFinder]() +## type [BlockFinder]() ```go type BlockFinder interface { @@ -230,7 +230,7 @@ type BlockFinder interface { } ``` -## type [BlockReadWriter]() +## type [BlockReadWriter]() ```go type BlockReadWriter interface { @@ -239,7 +239,7 @@ type BlockReadWriter interface { } ``` -## type [BlockReader]() +## type [BlockReader]() ```go type BlockReader interface { @@ -247,7 +247,7 @@ type BlockReader interface { } ``` -## type [BlockWriter]() +## type [BlockWriter]() ```go type BlockWriter interface { @@ -255,7 +255,7 @@ type BlockWriter interface { } ``` -## type [Config]() +## type [Config]() ```go type Config struct { @@ -265,13 +265,13 @@ type Config struct { } ``` -### func \(Config\) [Validate]() +### func \(Config\) [Validate]() ```go func (c Config) Validate() error ``` -## type [Ledger]() +## type [Ledger]() Ledger is a collection of ledger functionality to perform bookkeeping. @@ -281,7 +281,7 @@ type Ledger struct { } ``` -### func [NewLedger]() +### func [NewLedger]() ```go func NewLedger(config Config, bc BlockReadWriter, tx TrxWriteReadMover, ac AddressChecker, vr SignatureVerifier, tf BlockFinder, log logger.Logger) (*Ledger, error) @@ -289,7 +289,7 @@ func NewLedger(config Config, bc BlockReadWriter, tx TrxWriteReadMover, ac Addre NewLedger creates new Ledger if config is valid or returns error otherwise. -### func \(\*Ledger\) [Run]() +### func \(\*Ledger\) [Run]() ```go func (l *Ledger) Run(ctx context.Context) @@ -297,13 +297,13 @@ func (l *Ledger) Run(ctx context.Context) Run runs the Ladger engine that writes blocks to the blockchain repository. Run starts a goroutine and can be stopped by cancelling the context. -### func \(\*Ledger\) [VerifySignature]() +### func \(\*Ledger\) [VerifySignature]() ```go func (l *Ledger) VerifySignature(message, signature []byte, hash [32]byte, address string) error ``` -### func \(\*Ledger\) [WriteCandidateTransaction]() +### func \(\*Ledger\) [WriteCandidateTransaction]() ```go func (l *Ledger) WriteCandidateTransaction(ctx context.Context, trx *transaction.Transaction) error @@ -311,7 +311,7 @@ func (l *Ledger) WriteCandidateTransaction(ctx context.Context, trx *transaction WriteCandidateTransaction validates and writes a transaction to the repository. Transaction is not yet a part of the blockchain. -### func \(\*Ledger\) [WriteIssuerSignedTransactionForReceiver]() +### func \(\*Ledger\) [WriteIssuerSignedTransactionForReceiver]() ```go func (l *Ledger) WriteIssuerSignedTransactionForReceiver(ctx context.Context, receiverAddr string, trx *transaction.Transaction) error @@ -319,7 +319,7 @@ func (l *Ledger) WriteIssuerSignedTransactionForReceiver(ctx context.Context, re WriteIssuerSignedTransactionForReceiver validates issuer signature and writes a transaction to the repository for receiver. -## type [SignatureVerifier]() +## type [SignatureVerifier]() ```go type SignatureVerifier interface { @@ -327,7 +327,7 @@ type SignatureVerifier interface { } ``` -## type [TrxWriteReadMover]() +## type [TrxWriteReadMover]() ```go type TrxWriteReadMover interface { @@ -337,6 +337,7 @@ type TrxWriteReadMover interface { RemoveAwaitingTransaction(ctx context.Context, trxHash [32]byte) error ReadAwaitingTransactionsByReceiver(ctx context.Context, address string) ([]transaction.Transaction, error) ReadAwaitingTransactionsByIssuer(ctx context.Context, address string) ([]transaction.Transaction, error) + ReadTemporaryTransactions(ctx context.Context) ([]transaction.Transaction, error) } ``` @@ -676,7 +677,7 @@ import "github.com/bartossh/Computantis/logging" ## Index - [type Helper](<#type-helper>) - - [func New(callOnErr func(error), writers ...io.Writer) Helper](<#func-new>) + - [func New(callOnWriteLogErr, callOnFatal func(error), writers ...io.Writer) Helper](<#func-new>) - [func (h Helper) Debug(msg string)](<#func-helper-debug>) - [func (h Helper) Error(msg string)](<#func-helper-error>) - [func (h Helper) Fatal(msg string)](<#func-helper-fatal>) @@ -684,7 +685,7 @@ import "github.com/bartossh/Computantis/logging" - [func (h Helper) Warn(msg string)](<#func-helper-warn>) -## type [Helper]() +## type [Helper]() Helper helps with writing logs to io.Writers. Helper implements logger.Logger interface. Writing is done concurrently with out blocking the current thread. @@ -694,15 +695,15 @@ type Helper struct { } ``` -### func [New]() +### func [New]() ```go -func New(callOnErr func(error), writers ...io.Writer) Helper +func New(callOnWriteLogErr, callOnFatal func(error), writers ...io.Writer) Helper ``` New creates new Helper. -### func \(Helper\) [Debug]() +### func \(Helper\) [Debug]() ```go func (h Helper) Debug(msg string) @@ -710,7 +711,7 @@ func (h Helper) Debug(msg string) Debug writes debug log. -### func \(Helper\) [Error]() +### func \(Helper\) [Error]() ```go func (h Helper) Error(msg string) @@ -718,7 +719,7 @@ func (h Helper) Error(msg string) Error writes error log. -### func \(Helper\) [Fatal]() +### func \(Helper\) [Fatal]() ```go func (h Helper) Fatal(msg string) @@ -726,7 +727,7 @@ func (h Helper) Fatal(msg string) Fatal writes fatal log. -### func \(Helper\) [Info]() +### func \(Helper\) [Info]() ```go func (h Helper) Info(msg string) @@ -734,7 +735,7 @@ func (h Helper) Info(msg string) Info writes info log. -### func \(Helper\) [Warn]() +### func \(Helper\) [Warn]() ```go func (h Helper) Warn(msg string) @@ -765,6 +766,7 @@ import "github.com/bartossh/Computantis/repo" - [func (db DataBase) ReadAwaitingTransactionsByIssuer(ctx context.Context, address string) ([]transaction.Transaction, error)](<#func-database-readawaitingtransactionsbyissuer>) - [func (db DataBase) ReadAwaitingTransactionsByReceiver(ctx context.Context, address string) ([]transaction.Transaction, error)](<#func-database-readawaitingtransactionsbyreceiver>) - [func (db DataBase) ReadBlockByHash(ctx context.Context, hash [32]byte) (block.Block, error)](<#func-database-readblockbyhash>) + - [func (db DataBase) ReadTemporaryTransactions(ctx context.Context) ([]transaction.Transaction, error)](<#func-database-readtemporarytransactions>) - [func (db DataBase) RemoveAwaitingTransaction(ctx context.Context, trxHash [32]byte) error](<#func-database-removeawaitingtransaction>) - [func (c DataBase) RunMigration(ctx context.Context) error](<#func-database-runmigration>) - [func (db DataBase) Write(p []byte) (n int, err error)](<#func-database-write>) @@ -910,6 +912,14 @@ func (db DataBase) ReadBlockByHash(ctx context.Context, hash [32]byte) (block.Bl ReadBlockByHash returns block with given hash. +### func \(DataBase\) [ReadTemporaryTransactions]() + +```go +func (db DataBase) ReadTemporaryTransactions(ctx context.Context) ([]transaction.Transaction, error) +``` + +ReadTemporaryTransactions reads transactions from the temporary storage. + ### func \(DataBase\) [RemoveAwaitingTransaction]() ```go @@ -1364,6 +1374,16 @@ type UpgradeConnectionRequest struct { } ``` +# stress + +```go +import "github.com/bartossh/Computantis/stress" +``` + +## Index + + + # transaction ```go diff --git a/docs/git_hub_header.md b/docs/git_hub_header.md index 38dfbcb..041f2f6 100644 --- a/docs/git_hub_header.md +++ b/docs/git_hub_header.md @@ -20,3 +20,9 @@ Computantis is not keeping track of all transactions in a single blockchain but 0. Run database `docker compose up`. 1. Create `server_settings.yaml` according to `server_settings_example.yaml` in the repo root folder. 2. Run `make run` or `go run cmd/central/main.go`. + +## Stress test + +Directory `./stress/` contains REST API performance tests. +For example the test on MacBook with M2 arm64 chip, 24GB RAM, mongodb run in docker container with 1CPU and 1GB RAM, +for full cycle of creating 1000 transactions took 3.75 sec. diff --git a/gendocs.sh b/gendocs.sh index 4b2325c..cc4c9e8 100755 --- a/gendocs.sh +++ b/gendocs.sh @@ -1,5 +1,4 @@ #!/bin/bash - gomarkdoc ./... > docs.md cat docs/header.txt docs.md > docs/docs.md echo "docs generated web page" diff --git a/logging/logging.go b/logging/logging.go index 10fc1cf..7eeee1d 100644 --- a/logging/logging.go +++ b/logging/logging.go @@ -2,6 +2,7 @@ package logging import ( "encoding/json" + "fmt" "io" "time" @@ -13,13 +14,14 @@ import ( // Helper implements logger.Logger interface. // Writing is done concurrently with out blocking the current thread. type Helper struct { - callOnErr func(error) - writers []io.Writer + callOnWriteLogErr func(error) + callOnFatal func(error) + writers []io.Writer } // New creates new Helper. -func New(callOnErr func(error), writers ...io.Writer) Helper { - return Helper{callOnErr: callOnErr, writers: writers} +func New(callOnWriteLogErr, callOnFatal func(error), writers ...io.Writer) Helper { + return Helper{callOnWriteLogErr: callOnWriteLogErr, callOnFatal: callOnFatal, writers: writers} } // Debug writes debug log. @@ -74,19 +76,34 @@ func (h Helper) Fatal(msg string) { Msg: msg, CreatedAt: time.Now(), } - h.write(&l) + h.writeFatal(&l) } func (h Helper) write(l *logger.Log) { go func() { raw, err := json.Marshal(l) if err != nil { - h.callOnErr(err) + h.callOnWriteLogErr(err) + } + for _, w := range h.writers { + if _, err := w.Write(raw); err != nil { + h.callOnWriteLogErr(err) + } + } + }() +} + +func (h Helper) writeFatal(l *logger.Log) { + go func() { + raw, err := json.Marshal(l) + if err != nil { + h.callOnWriteLogErr(err) } for _, w := range h.writers { if _, err := w.Write(raw); err != nil { - h.callOnErr(err) + h.callOnWriteLogErr(err) } } + h.callOnFatal(fmt.Errorf(l.Msg)) }() } diff --git a/mongodb_queries/create_tokens.js b/mongodb_queries/create_tokens.js index 6440e04..e8819ae 100644 --- a/mongodb_queries/create_tokens.js +++ b/mongodb_queries/create_tokens.js @@ -1,11 +1,5 @@ // run with: mongo < create_tokens.js or VScode extension: MongoDB for VS Code use('accountant'); -db.getCollection('tokens') - .insertOne( - { - "token": "wpg6d0grqJjyRicC8oI0/w6IGivm5ypFNTO/wwPGW9A=", - "valid": true, - "expiration_date": 1957894000000000000 - }); +db.getCollection('tokens').insertOne({"token": "GWFuhvyFnmMg1/vhPCfoa9ct1pAMC1pWwlRg4kt0D/w=","valid": true,"expiration_date": 1957894000000000000}); \ No newline at end of file diff --git a/repo/transaction.go b/repo/transaction.go index 153827b..22e2f88 100644 --- a/repo/transaction.go +++ b/repo/transaction.go @@ -117,3 +117,19 @@ func (db DataBase) MoveTransactionsFromTemporaryToPermanent(ctx context.Context, return err } + +// ReadTemporaryTransactions reads transactions from the temporary storage. +func (db DataBase) ReadTemporaryTransactions(ctx context.Context) ([]transaction.Transaction, error) { + var trxs []transaction.Transaction + curs, err := db.inner.Collection(transactionsTemporaryCollection).Find(ctx, bson.M{}) + if err != nil { + if errors.Is(err, mongo.ErrNoDocuments) { + return nil, nil + } + return nil, err + } + if err := curs.All(ctx, &trxs); err != nil { + return nil, err + } + return trxs, nil +} diff --git a/server/rest.go b/server/rest.go index a745818..2de5a79 100644 --- a/server/rest.go +++ b/server/rest.go @@ -273,15 +273,15 @@ func (s *server) addressCreate(c *fiber.Ctx) error { if ok, err := s.repo.CheckToken(c.Context(), req.Token); !ok || err != nil { if err != nil { - s.log.Error(fmt.Sprintf("address create endpoint, failed to check token: %s", err.Error())) + s.log.Error(fmt.Sprintf("address create endpoint, address: %s, failed to check token: %s", req.Address, err.Error())) return fiber.ErrGone } - s.log.Error(fmt.Sprintf("address create endpoint, token is invalid: %s", req.Token)) + s.log.Error(fmt.Sprintf("address create endpoint, token: %s not found in the repository", req.Token)) return fiber.ErrForbidden } if err := s.repo.InvalidateToken(c.Context(), req.Token); err != nil { - s.log.Error(fmt.Sprintf("address create endpoint, failed to invalidate token: %s", err.Error())) + s.log.Error(fmt.Sprintf("address create endpoint, failed to invalidate token: %s, %s", req.Token, err.Error())) return fiber.ErrGone } @@ -293,16 +293,17 @@ func (s *server) addressCreate(c *fiber.Ctx) error { if ok, err := s.repo.CheckAddressExists(c.Context(), req.Address); ok || err != nil { if err != nil { - s.log.Error(fmt.Sprintf("address create endpoint, failed to check address: %s", err.Error())) + s.log.Error(fmt.Sprintf("address create endpoint, failed to check address: %s,%s", req.Address, err.Error())) return fiber.ErrGone } - s.log.Error(fmt.Sprintf("address create endpoint, address already exists: %s", req.Address)) + s.log.Error(fmt.Sprintf("address create endpoint, address already exists: %s, %s", req.Address, err.Error())) return fiber.ErrConflict } if err := s.repo.WriteAddress(c.Context(), req.Address); err != nil { - s.log.Error(fmt.Sprintf("address create endpoint, failed to write address: %s", err.Error())) + s.log.Error(fmt.Sprintf("address create endpoint, failed to write address: %s, %s", req.Address, err.Error())) return fiber.ErrConflict } - return c.JSON(CreateAddressResponse{Success: true, Address: req.Address}) + + return c.JSON(&CreateAddressResponse{Success: true, Address: req.Address}) } diff --git a/server_settings_example.yaml b/server_settings_example.yaml index 0b044a6..c1879c8 100644 --- a/server_settings_example.yaml +++ b/server_settings_example.yaml @@ -6,7 +6,7 @@ server: port: 8080 database: conn_str: "mongodb://example_user:user_secret@localhost:27017" - database_name: "accountant" + database_name: "computantis" token: "somerandomtokenfoapiclients" token_expiration: 604800 dataprovider: diff --git a/stress/stress.go b/stress/stress.go new file mode 100644 index 0000000..58c3687 --- /dev/null +++ b/stress/stress.go @@ -0,0 +1 @@ +package stress diff --git a/stress/stress_test.go b/stress/stress_test.go new file mode 100644 index 0000000..6560ad3 --- /dev/null +++ b/stress/stress_test.go @@ -0,0 +1,53 @@ +// go:build stress +// Running stress test requirements: +// - create test database to ensure your data is not polluted, +// - ensure your database contains valid tokens allowing to create wallets, +// - run server with: go run cmd/central/main.go. +// Run test with: `go test -v -run ./stress_test.go -tags stress` +// It is the best to test it when server runs on separate machine. + +package stress + +import ( + "fmt" + "testing" + "time" + + "github.com/bartossh/Computantis/client" + "github.com/bartossh/Computantis/fileoperations" + "github.com/bartossh/Computantis/wallet" + "github.com/stretchr/testify/assert" +) + +func TestFullClientApiCycle(t *testing.T) { + issuer := client.NewRest("http://localhost:8080", 5*time.Second, wallet.Helper{}, fileoperations.Helper{}, wallet.New) + err := issuer.ValidateApiVersion() + assert.Nil(t, err) + err = issuer.NewWallet("wpg6d0grqJjyRicC8oI0/w6IGivm5ypFNTO/wwPGW9A=") + assert.Nil(t, err) + + receiver := client.NewRest("http://localhost:8080", 5*time.Second, wallet.Helper{}, fileoperations.Helper{}, wallet.New) + err = receiver.ValidateApiVersion() + assert.Nil(t, err) + err = receiver.NewWallet("GWFuhvyFnmMg1/vhPCfoa9ct1pAMC1pWwlRg4kt0D/w=") + assert.Nil(t, err) + + now := time.Now() + for i := 0; i < 1000; i++ { + receiverAddr, err := receiver.Address() + assert.Nil(t, err) + err = issuer.ProposeTransaction(receiverAddr, "text", []byte("test_transaction_data")) + assert.Nil(t, err) + + awaitedTrx, err := receiver.ReadWaitingTransactions() + assert.Nil(t, err) + assert.Equal(t, 1, len(awaitedTrx)) + + err = receiver.ConfirmTransaction(awaitedTrx[0]) + assert.Nil(t, err) + } + fmt.Printf("1000 transactions in %v\n", time.Since(now)) + + issuer.FlushWalletFromMemory() + receiver.FlushWalletFromMemory() +}