From 3565546ae56c191708b111a66d163f6524f150e5 Mon Sep 17 00:00:00 2001 From: UlyanaAndrukhiv Date: Mon, 9 Dec 2024 19:11:21 +0200 Subject: [PATCH 01/21] Moved common used models to common rest models package, refactored rest http --- .../rest/{http => common}/models/block.go | 0 .../{http => common}/models/collection.go | 0 .../rest/{http => common}/models/enums.go | 0 .../rest/{http => common}/models/event.go | 0 .../models/execution_result.go | 0 .../rest/{http => common}/models/link.go | 0 .../models/model_aggregated_signature.go | 0 .../{http => common}/models/model_block.go | 0 .../models/model_block__expandable.go | 0 .../models/model_block_events.go | 0 .../models/model_block_header.go | 0 .../models/model_block_height.go | 0 .../models/model_block_payload.go | 0 .../models/model_block_seal.go | 0 .../{http => common}/models/model_chunk.go | 0 .../models/model_collection.go | 0 .../models/model_collection__expandable.go | 0 .../models/model_collection_guarantee.go | 0 .../{http => common}/models/model_event.go | 0 .../models/model_execution_result.go | 0 .../{http => common}/models/model_links.go | 0 .../models/model_proposal_key.go | 0 .../models/model_transaction.go | 0 .../models/model_transaction__expandable.go | 0 .../models/model_transaction_execution.go | 0 .../models/model_transaction_result.go | 0 .../models/model_transaction_signature.go | 0 .../models/model_transaction_status.go | 0 .../{http => common}/models/transaction.go | 0 engine/access/rest/http/handler.go | 2 +- engine/access/rest/http/models/account.go | 5 ++-- .../access/rest/http/models/model_account.go | 6 ++++- .../http/models/model_transactions_body.go | 16 +++++++----- .../access/rest/http/request/proposal_key.go | 2 +- .../rest/http/request/signature_test.go | 2 +- engine/access/rest/http/request/signatures.go | 2 +- .../rest/http/routes/account_balance.go | 3 ++- .../access/rest/http/routes/account_keys.go | 5 ++-- engine/access/rest/http/routes/accounts.go | 3 ++- engine/access/rest/http/routes/blocks.go | 22 ++++++++-------- engine/access/rest/http/routes/collections.go | 6 ++--- engine/access/rest/http/routes/events.go | 6 ++--- .../rest/http/routes/execution_result.go | 13 +++++----- engine/access/rest/http/routes/network.go | 3 ++- .../rest/http/routes/node_version_info.go | 3 ++- engine/access/rest/http/routes/scripts.go | 2 +- .../access/rest/http/routes/transactions.go | 15 +++++------ .../rest/http/routes/transactions_test.go | 2 +- engine/access/rest/router/router.go | 2 +- engine/access/rest/util/select_filter_test.go | 26 +++++++++---------- 50 files changed, 79 insertions(+), 67 deletions(-) rename engine/access/rest/{http => common}/models/block.go (100%) rename engine/access/rest/{http => common}/models/collection.go (100%) rename engine/access/rest/{http => common}/models/enums.go (100%) rename engine/access/rest/{http => common}/models/event.go (100%) rename engine/access/rest/{http => common}/models/execution_result.go (100%) rename engine/access/rest/{http => common}/models/link.go (100%) rename engine/access/rest/{http => common}/models/model_aggregated_signature.go (100%) rename engine/access/rest/{http => common}/models/model_block.go (100%) rename engine/access/rest/{http => common}/models/model_block__expandable.go (100%) rename engine/access/rest/{http => common}/models/model_block_events.go (100%) rename engine/access/rest/{http => common}/models/model_block_header.go (100%) rename engine/access/rest/{http => common}/models/model_block_height.go (100%) rename engine/access/rest/{http => common}/models/model_block_payload.go (100%) rename engine/access/rest/{http => common}/models/model_block_seal.go (100%) rename engine/access/rest/{http => common}/models/model_chunk.go (100%) rename engine/access/rest/{http => common}/models/model_collection.go (100%) rename engine/access/rest/{http => common}/models/model_collection__expandable.go (100%) rename engine/access/rest/{http => common}/models/model_collection_guarantee.go (100%) rename engine/access/rest/{http => common}/models/model_event.go (100%) rename engine/access/rest/{http => common}/models/model_execution_result.go (100%) rename engine/access/rest/{http => common}/models/model_links.go (100%) rename engine/access/rest/{http => common}/models/model_proposal_key.go (100%) rename engine/access/rest/{http => common}/models/model_transaction.go (100%) rename engine/access/rest/{http => common}/models/model_transaction__expandable.go (100%) rename engine/access/rest/{http => common}/models/model_transaction_execution.go (100%) rename engine/access/rest/{http => common}/models/model_transaction_result.go (100%) rename engine/access/rest/{http => common}/models/model_transaction_signature.go (100%) rename engine/access/rest/{http => common}/models/model_transaction_status.go (100%) rename engine/access/rest/{http => common}/models/transaction.go (100%) diff --git a/engine/access/rest/http/models/block.go b/engine/access/rest/common/models/block.go similarity index 100% rename from engine/access/rest/http/models/block.go rename to engine/access/rest/common/models/block.go diff --git a/engine/access/rest/http/models/collection.go b/engine/access/rest/common/models/collection.go similarity index 100% rename from engine/access/rest/http/models/collection.go rename to engine/access/rest/common/models/collection.go diff --git a/engine/access/rest/http/models/enums.go b/engine/access/rest/common/models/enums.go similarity index 100% rename from engine/access/rest/http/models/enums.go rename to engine/access/rest/common/models/enums.go diff --git a/engine/access/rest/http/models/event.go b/engine/access/rest/common/models/event.go similarity index 100% rename from engine/access/rest/http/models/event.go rename to engine/access/rest/common/models/event.go diff --git a/engine/access/rest/http/models/execution_result.go b/engine/access/rest/common/models/execution_result.go similarity index 100% rename from engine/access/rest/http/models/execution_result.go rename to engine/access/rest/common/models/execution_result.go diff --git a/engine/access/rest/http/models/link.go b/engine/access/rest/common/models/link.go similarity index 100% rename from engine/access/rest/http/models/link.go rename to engine/access/rest/common/models/link.go diff --git a/engine/access/rest/http/models/model_aggregated_signature.go b/engine/access/rest/common/models/model_aggregated_signature.go similarity index 100% rename from engine/access/rest/http/models/model_aggregated_signature.go rename to engine/access/rest/common/models/model_aggregated_signature.go diff --git a/engine/access/rest/http/models/model_block.go b/engine/access/rest/common/models/model_block.go similarity index 100% rename from engine/access/rest/http/models/model_block.go rename to engine/access/rest/common/models/model_block.go diff --git a/engine/access/rest/http/models/model_block__expandable.go b/engine/access/rest/common/models/model_block__expandable.go similarity index 100% rename from engine/access/rest/http/models/model_block__expandable.go rename to engine/access/rest/common/models/model_block__expandable.go diff --git a/engine/access/rest/http/models/model_block_events.go b/engine/access/rest/common/models/model_block_events.go similarity index 100% rename from engine/access/rest/http/models/model_block_events.go rename to engine/access/rest/common/models/model_block_events.go diff --git a/engine/access/rest/http/models/model_block_header.go b/engine/access/rest/common/models/model_block_header.go similarity index 100% rename from engine/access/rest/http/models/model_block_header.go rename to engine/access/rest/common/models/model_block_header.go diff --git a/engine/access/rest/http/models/model_block_height.go b/engine/access/rest/common/models/model_block_height.go similarity index 100% rename from engine/access/rest/http/models/model_block_height.go rename to engine/access/rest/common/models/model_block_height.go diff --git a/engine/access/rest/http/models/model_block_payload.go b/engine/access/rest/common/models/model_block_payload.go similarity index 100% rename from engine/access/rest/http/models/model_block_payload.go rename to engine/access/rest/common/models/model_block_payload.go diff --git a/engine/access/rest/http/models/model_block_seal.go b/engine/access/rest/common/models/model_block_seal.go similarity index 100% rename from engine/access/rest/http/models/model_block_seal.go rename to engine/access/rest/common/models/model_block_seal.go diff --git a/engine/access/rest/http/models/model_chunk.go b/engine/access/rest/common/models/model_chunk.go similarity index 100% rename from engine/access/rest/http/models/model_chunk.go rename to engine/access/rest/common/models/model_chunk.go diff --git a/engine/access/rest/http/models/model_collection.go b/engine/access/rest/common/models/model_collection.go similarity index 100% rename from engine/access/rest/http/models/model_collection.go rename to engine/access/rest/common/models/model_collection.go diff --git a/engine/access/rest/http/models/model_collection__expandable.go b/engine/access/rest/common/models/model_collection__expandable.go similarity index 100% rename from engine/access/rest/http/models/model_collection__expandable.go rename to engine/access/rest/common/models/model_collection__expandable.go diff --git a/engine/access/rest/http/models/model_collection_guarantee.go b/engine/access/rest/common/models/model_collection_guarantee.go similarity index 100% rename from engine/access/rest/http/models/model_collection_guarantee.go rename to engine/access/rest/common/models/model_collection_guarantee.go diff --git a/engine/access/rest/http/models/model_event.go b/engine/access/rest/common/models/model_event.go similarity index 100% rename from engine/access/rest/http/models/model_event.go rename to engine/access/rest/common/models/model_event.go diff --git a/engine/access/rest/http/models/model_execution_result.go b/engine/access/rest/common/models/model_execution_result.go similarity index 100% rename from engine/access/rest/http/models/model_execution_result.go rename to engine/access/rest/common/models/model_execution_result.go diff --git a/engine/access/rest/http/models/model_links.go b/engine/access/rest/common/models/model_links.go similarity index 100% rename from engine/access/rest/http/models/model_links.go rename to engine/access/rest/common/models/model_links.go diff --git a/engine/access/rest/http/models/model_proposal_key.go b/engine/access/rest/common/models/model_proposal_key.go similarity index 100% rename from engine/access/rest/http/models/model_proposal_key.go rename to engine/access/rest/common/models/model_proposal_key.go diff --git a/engine/access/rest/http/models/model_transaction.go b/engine/access/rest/common/models/model_transaction.go similarity index 100% rename from engine/access/rest/http/models/model_transaction.go rename to engine/access/rest/common/models/model_transaction.go diff --git a/engine/access/rest/http/models/model_transaction__expandable.go b/engine/access/rest/common/models/model_transaction__expandable.go similarity index 100% rename from engine/access/rest/http/models/model_transaction__expandable.go rename to engine/access/rest/common/models/model_transaction__expandable.go diff --git a/engine/access/rest/http/models/model_transaction_execution.go b/engine/access/rest/common/models/model_transaction_execution.go similarity index 100% rename from engine/access/rest/http/models/model_transaction_execution.go rename to engine/access/rest/common/models/model_transaction_execution.go diff --git a/engine/access/rest/http/models/model_transaction_result.go b/engine/access/rest/common/models/model_transaction_result.go similarity index 100% rename from engine/access/rest/http/models/model_transaction_result.go rename to engine/access/rest/common/models/model_transaction_result.go diff --git a/engine/access/rest/http/models/model_transaction_signature.go b/engine/access/rest/common/models/model_transaction_signature.go similarity index 100% rename from engine/access/rest/http/models/model_transaction_signature.go rename to engine/access/rest/common/models/model_transaction_signature.go diff --git a/engine/access/rest/http/models/model_transaction_status.go b/engine/access/rest/common/models/model_transaction_status.go similarity index 100% rename from engine/access/rest/http/models/model_transaction_status.go rename to engine/access/rest/common/models/model_transaction_status.go diff --git a/engine/access/rest/http/models/transaction.go b/engine/access/rest/common/models/transaction.go similarity index 100% rename from engine/access/rest/http/models/transaction.go rename to engine/access/rest/common/models/transaction.go diff --git a/engine/access/rest/http/handler.go b/engine/access/rest/http/handler.go index cac602a6888..4f1986c1528 100644 --- a/engine/access/rest/http/handler.go +++ b/engine/access/rest/http/handler.go @@ -7,7 +7,7 @@ import ( "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/engine/access/rest/common" - "github.com/onflow/flow-go/engine/access/rest/http/models" + "github.com/onflow/flow-go/engine/access/rest/common/models" "github.com/onflow/flow-go/engine/access/rest/util" "github.com/onflow/flow-go/model/flow" ) diff --git a/engine/access/rest/http/models/account.go b/engine/access/rest/http/models/account.go index 9855fe22667..7f43b257d81 100644 --- a/engine/access/rest/http/models/account.go +++ b/engine/access/rest/http/models/account.go @@ -1,6 +1,7 @@ package models import ( + "github.com/onflow/flow-go/engine/access/rest/common/models" "github.com/onflow/flow-go/engine/access/rest/util" "github.com/onflow/flow-go/model/flow" ) @@ -8,7 +9,7 @@ import ( const expandableKeys = "keys" const expandableContracts = "contracts" -func (a *Account) Build(flowAccount *flow.Account, link LinkGenerator, expand map[string]bool) error { +func (a *Account) Build(flowAccount *flow.Account, link models.LinkGenerator, expand map[string]bool) error { a.Address = flowAccount.Address.String() a.Balance = util.FromUint(flowAccount.Balance) a.Expandable = &AccountExpandable{} @@ -31,7 +32,7 @@ func (a *Account) Build(flowAccount *flow.Account, link LinkGenerator, expand ma a.Expandable.Contracts = expandableContracts } - var self Links + var self models.Links err := self.Build(link.AccountLink(a.Address)) if err != nil { return err diff --git a/engine/access/rest/http/models/model_account.go b/engine/access/rest/http/models/model_account.go index bca079b86b2..da1c6152bfb 100644 --- a/engine/access/rest/http/models/model_account.go +++ b/engine/access/rest/http/models/model_account.go @@ -8,6 +8,10 @@ */ package models +import ( + "github.com/onflow/flow-go/engine/access/rest/common/models" +) + type Account struct { Address string `json:"address"` // Flow balance of the account. @@ -15,5 +19,5 @@ type Account struct { Keys []AccountPublicKey `json:"keys,omitempty"` Contracts map[string]string `json:"contracts,omitempty"` Expandable *AccountExpandable `json:"_expandable"` - Links *Links `json:"_links,omitempty"` + Links *models.Links `json:"_links,omitempty"` } diff --git a/engine/access/rest/http/models/model_transactions_body.go b/engine/access/rest/http/models/model_transactions_body.go index dafb271c86e..5ec8326af85 100644 --- a/engine/access/rest/http/models/model_transactions_body.go +++ b/engine/access/rest/http/models/model_transactions_body.go @@ -8,6 +8,10 @@ */ package models +import ( + "github.com/onflow/flow-go/engine/access/rest/common/models" +) + type TransactionsBody struct { // Base64 encoded content of the Cadence script. Script string `json:"script"` @@ -15,10 +19,10 @@ type TransactionsBody struct { Arguments []string `json:"arguments"` ReferenceBlockId string `json:"reference_block_id"` // The limit on the amount of computation a transaction is allowed to preform. - GasLimit string `json:"gas_limit"` - Payer string `json:"payer"` - ProposalKey *ProposalKey `json:"proposal_key"` - Authorizers []string `json:"authorizers"` - PayloadSignatures []TransactionSignature `json:"payload_signatures"` - EnvelopeSignatures []TransactionSignature `json:"envelope_signatures"` + GasLimit string `json:"gas_limit"` + Payer string `json:"payer"` + ProposalKey *models.ProposalKey `json:"proposal_key"` + Authorizers []string `json:"authorizers"` + PayloadSignatures []models.TransactionSignature `json:"payload_signatures"` + EnvelopeSignatures []models.TransactionSignature `json:"envelope_signatures"` } diff --git a/engine/access/rest/http/request/proposal_key.go b/engine/access/rest/http/request/proposal_key.go index 1bc792022ac..487e8daf4a8 100644 --- a/engine/access/rest/http/request/proposal_key.go +++ b/engine/access/rest/http/request/proposal_key.go @@ -3,7 +3,7 @@ package request import ( "fmt" - "github.com/onflow/flow-go/engine/access/rest/http/models" + "github.com/onflow/flow-go/engine/access/rest/common/models" "github.com/onflow/flow-go/engine/access/rest/util" "github.com/onflow/flow-go/model/flow" ) diff --git a/engine/access/rest/http/request/signature_test.go b/engine/access/rest/http/request/signature_test.go index a8219f34bbc..ced16cd0295 100644 --- a/engine/access/rest/http/request/signature_test.go +++ b/engine/access/rest/http/request/signature_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/assert" - "github.com/onflow/flow-go/engine/access/rest/http/models" + "github.com/onflow/flow-go/engine/access/rest/common/models" "github.com/onflow/flow-go/engine/access/rest/util" "github.com/onflow/flow-go/model/flow" ) diff --git a/engine/access/rest/http/request/signatures.go b/engine/access/rest/http/request/signatures.go index e333be3781b..19808277803 100644 --- a/engine/access/rest/http/request/signatures.go +++ b/engine/access/rest/http/request/signatures.go @@ -3,7 +3,7 @@ package request import ( "fmt" - "github.com/onflow/flow-go/engine/access/rest/http/models" + "github.com/onflow/flow-go/engine/access/rest/common/models" "github.com/onflow/flow-go/engine/access/rest/util" "github.com/onflow/flow-go/model/flow" ) diff --git a/engine/access/rest/http/routes/account_balance.go b/engine/access/rest/http/routes/account_balance.go index 3d0ebf50667..44afc38f164 100644 --- a/engine/access/rest/http/routes/account_balance.go +++ b/engine/access/rest/http/routes/account_balance.go @@ -5,12 +5,13 @@ import ( "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/engine/access/rest/common" + commonmodels "github.com/onflow/flow-go/engine/access/rest/common/models" "github.com/onflow/flow-go/engine/access/rest/http/models" "github.com/onflow/flow-go/engine/access/rest/http/request" ) // GetAccountBalance handler retrieves an account balance by address and block height and returns the response -func GetAccountBalance(r *common.Request, backend access.API, _ models.LinkGenerator) (interface{}, error) { +func GetAccountBalance(r *common.Request, backend access.API, _ commonmodels.LinkGenerator) (interface{}, error) { req, err := request.GetAccountBalanceRequest(r) if err != nil { return nil, common.NewBadRequestError(err) diff --git a/engine/access/rest/http/routes/account_keys.go b/engine/access/rest/http/routes/account_keys.go index fa4e429c20d..4b3a5647f79 100644 --- a/engine/access/rest/http/routes/account_keys.go +++ b/engine/access/rest/http/routes/account_keys.go @@ -5,13 +5,14 @@ import ( "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/engine/access/rest/common" + commonmodels "github.com/onflow/flow-go/engine/access/rest/common/models" "github.com/onflow/flow-go/engine/access/rest/http/request" "github.com/onflow/flow-go/engine/access/rest/http/models" ) // GetAccountKeyByIndex handler retrieves an account key by address and index and returns the response -func GetAccountKeyByIndex(r *common.Request, backend access.API, _ models.LinkGenerator) (interface{}, error) { +func GetAccountKeyByIndex(r *common.Request, backend access.API, _ commonmodels.LinkGenerator) (interface{}, error) { req, err := request.GetAccountKeyRequest(r) if err != nil { return nil, common.NewBadRequestError(err) @@ -41,7 +42,7 @@ func GetAccountKeyByIndex(r *common.Request, backend access.API, _ models.LinkGe } // GetAccountKeys handler retrieves an account keys by address and returns the response -func GetAccountKeys(r *common.Request, backend access.API, _ models.LinkGenerator) (interface{}, error) { +func GetAccountKeys(r *common.Request, backend access.API, _ commonmodels.LinkGenerator) (interface{}, error) { req, err := request.GetAccountKeysRequest(r) if err != nil { return nil, common.NewBadRequestError(err) diff --git a/engine/access/rest/http/routes/accounts.go b/engine/access/rest/http/routes/accounts.go index a27eaa248c5..ade6736d4ac 100644 --- a/engine/access/rest/http/routes/accounts.go +++ b/engine/access/rest/http/routes/accounts.go @@ -3,12 +3,13 @@ package routes import ( "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/engine/access/rest/common" + commonmodels "github.com/onflow/flow-go/engine/access/rest/common/models" "github.com/onflow/flow-go/engine/access/rest/http/models" "github.com/onflow/flow-go/engine/access/rest/http/request" ) // GetAccount handler retrieves account by address and returns the response -func GetAccount(r *common.Request, backend access.API, link models.LinkGenerator) (interface{}, error) { +func GetAccount(r *common.Request, backend access.API, link commonmodels.LinkGenerator) (interface{}, error) { req, err := request.GetAccountRequest(r) if err != nil { return nil, common.NewBadRequestError(err) diff --git a/engine/access/rest/http/routes/blocks.go b/engine/access/rest/http/routes/blocks.go index f3995d2a5a5..875d5367181 100644 --- a/engine/access/rest/http/routes/blocks.go +++ b/engine/access/rest/http/routes/blocks.go @@ -10,19 +10,19 @@ import ( "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/engine/access/rest/common" - "github.com/onflow/flow-go/engine/access/rest/http/models" + commonmodels "github.com/onflow/flow-go/engine/access/rest/common/models" "github.com/onflow/flow-go/engine/access/rest/http/request" "github.com/onflow/flow-go/model/flow" ) // GetBlocksByIDs gets blocks by provided ID or list of IDs. -func GetBlocksByIDs(r *common.Request, backend access.API, link models.LinkGenerator) (interface{}, error) { +func GetBlocksByIDs(r *common.Request, backend access.API, link commonmodels.LinkGenerator) (interface{}, error) { req, err := request.GetBlockByIDsRequest(r) if err != nil { return nil, common.NewBadRequestError(err) } - blocks := make([]*models.Block, len(req.IDs)) + blocks := make([]*commonmodels.Block, len(req.IDs)) for i, id := range req.IDs { block, err := getBlock(forID(&id), r, backend, link) @@ -36,7 +36,7 @@ func GetBlocksByIDs(r *common.Request, backend access.API, link models.LinkGener } // GetBlocksByHeight gets blocks by height. -func GetBlocksByHeight(r *common.Request, backend access.API, link models.LinkGenerator) (interface{}, error) { +func GetBlocksByHeight(r *common.Request, backend access.API, link commonmodels.LinkGenerator) (interface{}, error) { req, err := request.GetBlockRequest(r) if err != nil { return nil, common.NewBadRequestError(err) @@ -48,12 +48,12 @@ func GetBlocksByHeight(r *common.Request, backend access.API, link models.LinkGe return nil, err } - return []*models.Block{block}, nil + return []*commonmodels.Block{block}, nil } // if the query is /blocks/height=1000,1008,1049... if req.HasHeights() { - blocks := make([]*models.Block, len(req.Heights)) + blocks := make([]*commonmodels.Block, len(req.Heights)) for i, h := range req.Heights { block, err := getBlock(forHeight(h), r, backend, link) if err != nil { @@ -79,7 +79,7 @@ func GetBlocksByHeight(r *common.Request, backend access.API, link models.LinkGe } } - blocks := make([]*models.Block, 0) + blocks := make([]*commonmodels.Block, 0) // start and end height inclusive for i := req.StartHeight; i <= req.EndHeight; i++ { block, err := getBlock(forHeight(i), r, backend, link) @@ -93,7 +93,7 @@ func GetBlocksByHeight(r *common.Request, backend access.API, link models.LinkGe } // GetBlockPayloadByID gets block payload by ID -func GetBlockPayloadByID(r *common.Request, backend access.API, _ models.LinkGenerator) (interface{}, error) { +func GetBlockPayloadByID(r *common.Request, backend access.API, _ commonmodels.LinkGenerator) (interface{}, error) { req, err := request.GetBlockPayloadRequest(r) if err != nil { return nil, common.NewBadRequestError(err) @@ -105,7 +105,7 @@ func GetBlockPayloadByID(r *common.Request, backend access.API, _ models.LinkGen return nil, statusErr } - var payload models.BlockPayload + var payload commonmodels.BlockPayload err = payload.Build(blk.Payload) if err != nil { return nil, err @@ -114,7 +114,7 @@ func GetBlockPayloadByID(r *common.Request, backend access.API, _ models.LinkGen return payload, nil } -func getBlock(option blockProviderOption, req *common.Request, backend access.API, link models.LinkGenerator) (*models.Block, error) { +func getBlock(option blockProviderOption, req *common.Request, backend access.API, link commonmodels.LinkGenerator) (*commonmodels.Block, error) { // lookup block blkProvider := NewBlockProvider(backend, option) blk, blockStatus, err := blkProvider.getBlock(req.Context()) @@ -124,7 +124,7 @@ func getBlock(option blockProviderOption, req *common.Request, backend access.AP // lookup execution result // (even if not specified as expandable, since we need the execution result ID to generate its expandable link) - var block models.Block + var block commonmodels.Block executionResult, err := backend.GetExecutionResultForBlockID(req.Context(), blk.ID()) if err != nil { // handle case where execution result is not yet available diff --git a/engine/access/rest/http/routes/collections.go b/engine/access/rest/http/routes/collections.go index 84157cd68ae..574ab96318d 100644 --- a/engine/access/rest/http/routes/collections.go +++ b/engine/access/rest/http/routes/collections.go @@ -3,13 +3,13 @@ package routes import ( "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/engine/access/rest/common" - "github.com/onflow/flow-go/engine/access/rest/http/models" + commonmodels "github.com/onflow/flow-go/engine/access/rest/common/models" "github.com/onflow/flow-go/engine/access/rest/http/request" "github.com/onflow/flow-go/model/flow" ) // GetCollectionByID retrieves a collection by ID and builds a response -func GetCollectionByID(r *common.Request, backend access.API, link models.LinkGenerator) (interface{}, error) { +func GetCollectionByID(r *common.Request, backend access.API, link commonmodels.LinkGenerator) (interface{}, error) { req, err := request.GetCollectionRequest(r) if err != nil { return nil, common.NewBadRequestError(err) @@ -33,7 +33,7 @@ func GetCollectionByID(r *common.Request, backend access.API, link models.LinkGe } } - var response models.Collection + var response commonmodels.Collection err = response.Build(collection, transactions, link, r.ExpandFields) if err != nil { return nil, err diff --git a/engine/access/rest/http/routes/events.go b/engine/access/rest/http/routes/events.go index fed682555d0..93ea1367b3b 100644 --- a/engine/access/rest/http/routes/events.go +++ b/engine/access/rest/http/routes/events.go @@ -7,7 +7,7 @@ import ( "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/engine/access/rest/common" - "github.com/onflow/flow-go/engine/access/rest/http/models" + commonmodels "github.com/onflow/flow-go/engine/access/rest/common/models" "github.com/onflow/flow-go/engine/access/rest/http/request" ) @@ -15,14 +15,14 @@ const BlockQueryParam = "block_ids" const EventTypeQuery = "type" // GetEvents for the provided block range or list of block IDs filtered by type. -func GetEvents(r *common.Request, backend access.API, _ models.LinkGenerator) (interface{}, error) { +func GetEvents(r *common.Request, backend access.API, _ commonmodels.LinkGenerator) (interface{}, error) { req, err := request.GetEventsRequest(r) if err != nil { return nil, common.NewBadRequestError(err) } // if the request has block IDs provided then return events for block IDs - var blocksEvents models.BlocksEvents + var blocksEvents commonmodels.BlocksEvents if len(req.BlockIDs) > 0 { events, err := backend.GetEventsForBlockIDs( r.Context(), diff --git a/engine/access/rest/http/routes/execution_result.go b/engine/access/rest/http/routes/execution_result.go index b1c32ac4912..74508753d77 100644 --- a/engine/access/rest/http/routes/execution_result.go +++ b/engine/access/rest/http/routes/execution_result.go @@ -5,27 +5,26 @@ import ( "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/engine/access/rest/common" + commonmodels "github.com/onflow/flow-go/engine/access/rest/common/models" "github.com/onflow/flow-go/engine/access/rest/http/request" - - "github.com/onflow/flow-go/engine/access/rest/http/models" ) // GetExecutionResultsByBlockIDs gets Execution Result payload by block IDs. -func GetExecutionResultsByBlockIDs(r *common.Request, backend access.API, link models.LinkGenerator) (interface{}, error) { +func GetExecutionResultsByBlockIDs(r *common.Request, backend access.API, link commonmodels.LinkGenerator) (interface{}, error) { req, err := request.GetExecutionResultByBlockIDsRequest(r) if err != nil { return nil, common.NewBadRequestError(err) } // for each block ID we retrieve execution result - results := make([]models.ExecutionResult, len(req.BlockIDs)) + results := make([]commonmodels.ExecutionResult, len(req.BlockIDs)) for i, id := range req.BlockIDs { res, err := backend.GetExecutionResultForBlockID(r.Context(), id) if err != nil { return nil, err } - var response models.ExecutionResult + var response commonmodels.ExecutionResult err = response.Build(res, link) if err != nil { return nil, err @@ -37,7 +36,7 @@ func GetExecutionResultsByBlockIDs(r *common.Request, backend access.API, link m } // GetExecutionResultByID gets execution result by the ID. -func GetExecutionResultByID(r *common.Request, backend access.API, link models.LinkGenerator) (interface{}, error) { +func GetExecutionResultByID(r *common.Request, backend access.API, link commonmodels.LinkGenerator) (interface{}, error) { req, err := request.GetExecutionResultRequest(r) if err != nil { return nil, common.NewBadRequestError(err) @@ -53,7 +52,7 @@ func GetExecutionResultByID(r *common.Request, backend access.API, link models.L return nil, common.NewNotFoundError(err.Error(), err) } - var response models.ExecutionResult + var response commonmodels.ExecutionResult err = response.Build(res, link) if err != nil { return nil, err diff --git a/engine/access/rest/http/routes/network.go b/engine/access/rest/http/routes/network.go index c363a38a7a6..5f2954e4b8e 100644 --- a/engine/access/rest/http/routes/network.go +++ b/engine/access/rest/http/routes/network.go @@ -3,11 +3,12 @@ package routes import ( "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/engine/access/rest/common" + commonmodels "github.com/onflow/flow-go/engine/access/rest/common/models" "github.com/onflow/flow-go/engine/access/rest/http/models" ) // GetNetworkParameters returns network-wide parameters of the blockchain -func GetNetworkParameters(r *common.Request, backend access.API, _ models.LinkGenerator) (interface{}, error) { +func GetNetworkParameters(r *common.Request, backend access.API, _ commonmodels.LinkGenerator) (interface{}, error) { params := backend.GetNetworkParameters(r.Context()) var response models.NetworkParameters diff --git a/engine/access/rest/http/routes/node_version_info.go b/engine/access/rest/http/routes/node_version_info.go index 71b4aa08b43..da2da3e59af 100644 --- a/engine/access/rest/http/routes/node_version_info.go +++ b/engine/access/rest/http/routes/node_version_info.go @@ -3,11 +3,12 @@ package routes import ( "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/engine/access/rest/common" + commonmodels "github.com/onflow/flow-go/engine/access/rest/common/models" "github.com/onflow/flow-go/engine/access/rest/http/models" ) // GetNodeVersionInfo returns node version information -func GetNodeVersionInfo(r *common.Request, backend access.API, _ models.LinkGenerator) (interface{}, error) { +func GetNodeVersionInfo(r *common.Request, backend access.API, _ commonmodels.LinkGenerator) (interface{}, error) { params, err := backend.GetNodeVersionInfo(r.Context()) if err != nil { return nil, err diff --git a/engine/access/rest/http/routes/scripts.go b/engine/access/rest/http/routes/scripts.go index 2c747ff8850..92ec825de7e 100644 --- a/engine/access/rest/http/routes/scripts.go +++ b/engine/access/rest/http/routes/scripts.go @@ -3,7 +3,7 @@ package routes import ( "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/engine/access/rest/common" - "github.com/onflow/flow-go/engine/access/rest/http/models" + "github.com/onflow/flow-go/engine/access/rest/common/models" "github.com/onflow/flow-go/engine/access/rest/http/request" "github.com/onflow/flow-go/model/flow" ) diff --git a/engine/access/rest/http/routes/transactions.go b/engine/access/rest/http/routes/transactions.go index 02afef949e8..80129464498 100644 --- a/engine/access/rest/http/routes/transactions.go +++ b/engine/access/rest/http/routes/transactions.go @@ -5,13 +5,12 @@ import ( "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/engine/access/rest/common" + commonmodels "github.com/onflow/flow-go/engine/access/rest/common/models" "github.com/onflow/flow-go/engine/access/rest/http/request" - - "github.com/onflow/flow-go/engine/access/rest/http/models" ) // GetTransactionByID gets a transaction by requested ID. -func GetTransactionByID(r *common.Request, backend access.API, link models.LinkGenerator) (interface{}, error) { +func GetTransactionByID(r *common.Request, backend access.API, link commonmodels.LinkGenerator) (interface{}, error) { req, err := request.GetTransactionRequest(r) if err != nil { return nil, common.NewBadRequestError(err) @@ -37,13 +36,13 @@ func GetTransactionByID(r *common.Request, backend access.API, link models.LinkG } } - var response models.Transaction + var response commonmodels.Transaction response.Build(tx, txr, link) return response, nil } // GetTransactionResultByID retrieves transaction result by the transaction ID. -func GetTransactionResultByID(r *common.Request, backend access.API, link models.LinkGenerator) (interface{}, error) { +func GetTransactionResultByID(r *common.Request, backend access.API, link commonmodels.LinkGenerator) (interface{}, error) { req, err := request.GetTransactionResultRequest(r) if err != nil { return nil, common.NewBadRequestError(err) @@ -60,13 +59,13 @@ func GetTransactionResultByID(r *common.Request, backend access.API, link models return nil, err } - var response models.TransactionResult + var response commonmodels.TransactionResult response.Build(txr, req.ID, link) return response, nil } // CreateTransaction creates a new transaction from provided payload. -func CreateTransaction(r *common.Request, backend access.API, link models.LinkGenerator) (interface{}, error) { +func CreateTransaction(r *common.Request, backend access.API, link commonmodels.LinkGenerator) (interface{}, error) { req, err := request.CreateTransactionRequest(r) if err != nil { return nil, common.NewBadRequestError(err) @@ -77,7 +76,7 @@ func CreateTransaction(r *common.Request, backend access.API, link models.LinkGe return nil, err } - var response models.Transaction + var response commonmodels.Transaction response.Build(&req.Transaction, nil, link) return response, nil } diff --git a/engine/access/rest/http/routes/transactions_test.go b/engine/access/rest/http/routes/transactions_test.go index e2deadd16e1..dc8c29a9c42 100644 --- a/engine/access/rest/http/routes/transactions_test.go +++ b/engine/access/rest/http/routes/transactions_test.go @@ -19,7 +19,7 @@ import ( "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/access/mock" - "github.com/onflow/flow-go/engine/access/rest/http/models" + "github.com/onflow/flow-go/engine/access/rest/common/models" "github.com/onflow/flow-go/engine/access/rest/router" "github.com/onflow/flow-go/engine/access/rest/util" "github.com/onflow/flow-go/model/flow" diff --git a/engine/access/rest/router/router.go b/engine/access/rest/router/router.go index 93879da6aaa..ac190000b50 100644 --- a/engine/access/rest/router/router.go +++ b/engine/access/rest/router/router.go @@ -11,8 +11,8 @@ import ( "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/engine/access/rest/common/middleware" + "github.com/onflow/flow-go/engine/access/rest/common/models" flowhttp "github.com/onflow/flow-go/engine/access/rest/http" - "github.com/onflow/flow-go/engine/access/rest/http/models" "github.com/onflow/flow-go/engine/access/rest/websockets" dp "github.com/onflow/flow-go/engine/access/rest/websockets/data_providers" legacyws "github.com/onflow/flow-go/engine/access/rest/websockets/legacy" diff --git a/engine/access/rest/util/select_filter_test.go b/engine/access/rest/util/select_filter_test.go index 54d186e0e5e..c023414e303 100644 --- a/engine/access/rest/util/select_filter_test.go +++ b/engine/access/rest/util/select_filter_test.go @@ -8,7 +8,7 @@ import ( "testing" "time" - "github.com/onflow/flow-go/engine/access/rest/http/models" + commonmodels "github.com/onflow/flow-go/engine/access/rest/common/models" "github.com/onflow/flow-go/engine/access/rest/util" "github.com/stretchr/testify/require" @@ -91,7 +91,7 @@ func testFilter(t *testing.T, inputJson, exepectedJson string, description strin func TestExampleSelectFilter(t *testing.T) { - blocks := make([]models.Block, 2) + blocks := make([]commonmodels.Block, 2) for i := range blocks { block, err := generateBlock() require.NoError(t, err) @@ -122,7 +122,7 @@ func TestExampleSelectFilter(t *testing.T) { require.Equal(t, string(byteValue), string(marshalled)) } -func generateBlock() (models.Block, error) { +func generateBlock() (commonmodels.Block, error) { dummySignature := "abcdef0123456789" multipleDummySignatures := []string{dummySignature, dummySignature} @@ -130,31 +130,31 @@ func generateBlock() (models.Block, error) { dateString := "2021-11-20T11:45:26.371Z" t, err := time.Parse(time.RFC3339, dateString) if err != nil { - return models.Block{}, err + return commonmodels.Block{}, err } - return models.Block{ - Header: &models.BlockHeader{ + return commonmodels.Block{ + Header: &commonmodels.BlockHeader{ Id: dummyID, ParentId: dummyID, Height: "100", Timestamp: t, ParentVoterSignature: dummySignature, }, - Payload: &models.BlockPayload{ - CollectionGuarantees: []models.CollectionGuarantee{ + Payload: &commonmodels.BlockPayload{ + CollectionGuarantees: []commonmodels.CollectionGuarantee{ { CollectionId: "abcdef0123456789", SignerIndices: fmt.Sprintf("%x", []byte{1}), Signature: dummySignature, }, }, - BlockSeals: []models.BlockSeal{ + BlockSeals: []commonmodels.BlockSeal{ { BlockId: dummyID, ResultId: dummyID, FinalState: "final", - AggregatedApprovalSignatures: []models.AggregatedSignature{ + AggregatedApprovalSignatures: []commonmodels.AggregatedSignature{ { VerifierSignatures: multipleDummySignatures, SignerIds: multipleDummySignatures, @@ -163,10 +163,10 @@ func generateBlock() (models.Block, error) { }, }, }, - ExecutionResult: &models.ExecutionResult{ + ExecutionResult: &commonmodels.ExecutionResult{ Id: dummyID, BlockId: dummyID, - Events: []models.Event{ + Events: []commonmodels.Event{ { Type_: "type", TransactionId: dummyID, @@ -182,7 +182,7 @@ func generateBlock() (models.Block, error) { Payload: "payload", }, }, - Links: &models.Links{ + Links: &commonmodels.Links{ Self: "link", }, }, From 8716c928fc4424a95a15440ddf54d6407f2406b2 Mon Sep 17 00:00:00 2001 From: UlyanaAndrukhiv Date: Tue, 10 Dec 2024 13:04:42 +0200 Subject: [PATCH 02/21] Updated websocket response types for block headers and block digests, updated tests --- .../data_providers/block_digests_provider.go | 7 +- .../block_digests_provider_test.go | 34 +++++--- .../data_providers/block_headers_provider.go | 8 +- .../block_headers_provider_test.go | 31 ++++++-- .../data_providers/blocks_provider_test.go | 77 ++++++++++++------- .../rest/websockets/models/block_digest.go | 12 +++ .../rest/websockets/models/block_models.go | 5 +- .../websockets/models/model_block_digest.go | 11 +++ 8 files changed, 134 insertions(+), 51 deletions(-) create mode 100644 engine/access/rest/websockets/models/block_digest.go create mode 100644 engine/access/rest/websockets/models/model_block_digest.go diff --git a/engine/access/rest/websockets/data_providers/block_digests_provider.go b/engine/access/rest/websockets/data_providers/block_digests_provider.go index 1fa3f7a6dc7..e8f3ffcac73 100644 --- a/engine/access/rest/websockets/data_providers/block_digests_provider.go +++ b/engine/access/rest/websockets/data_providers/block_digests_provider.go @@ -60,9 +60,12 @@ func NewBlockDigestsDataProvider( func (p *BlockDigestsDataProvider) Run() error { return subscription.HandleSubscription( p.subscription, - subscription.HandleResponse(p.send, func(block *flow.BlockDigest) (interface{}, error) { + subscription.HandleResponse(p.send, func(b *flow.BlockDigest) (interface{}, error) { + var block models.BlockDigest + block.Build(b) + return &models.BlockDigestMessageResponse{ - Block: block, + Block: &block, }, nil }), ) diff --git a/engine/access/rest/websockets/data_providers/block_digests_provider_test.go b/engine/access/rest/websockets/data_providers/block_digests_provider_test.go index 476edf77111..d8863f81e1d 100644 --- a/engine/access/rest/websockets/data_providers/block_digests_provider_test.go +++ b/engine/access/rest/websockets/data_providers/block_digests_provider_test.go @@ -54,6 +54,16 @@ func (s *BlockDigestsProviderSuite) TestBlockDigestsDataProvider_InvalidArgument // validBlockDigestsArgumentsTestCases defines test happy cases for block digests data providers. // Each test case specifies input arguments, and setup functions for the mock API used in the test. func (s *BlockDigestsProviderSuite) validBlockDigestsArgumentsTestCases() []testType { + expectedResponses := make([]interface{}, len(s.blocks)) + for i, b := range s.blocks { + blockDigest := flow.NewBlockDigest(b.Header.ID(), b.Header.Height, b.Header.Timestamp) + + var block models.BlockDigest + block.Build(blockDigest) + + expectedResponses[i] = &models.BlockDigestMessageResponse{Block: &block} + } + return []testType{ { name: "happy path with start_block_id argument", @@ -69,6 +79,7 @@ func (s *BlockDigestsProviderSuite) validBlockDigestsArgumentsTestCases() []test flow.BlockStatusFinalized, ).Return(sub).Once() }, + expectedResponses: expectedResponses, }, { name: "happy path with start_block_height argument", @@ -84,6 +95,7 @@ func (s *BlockDigestsProviderSuite) validBlockDigestsArgumentsTestCases() []test flow.BlockStatusFinalized, ).Return(sub).Once() }, + expectedResponses: expectedResponses, }, { name: "happy path without any start argument", @@ -97,6 +109,7 @@ func (s *BlockDigestsProviderSuite) validBlockDigestsArgumentsTestCases() []test flow.BlockStatusFinalized, ).Return(sub).Once() }, + expectedResponses: expectedResponses, }, } } @@ -106,11 +119,13 @@ func (s *BlockDigestsProviderSuite) validBlockDigestsArgumentsTestCases() []test // validates that block digests are correctly streamed to the channel and ensures // no unexpected errors occur. func (s *BlockDigestsProviderSuite) TestBlockDigestsDataProvider_HappyPath() { - s.testHappyPath( + testHappyPath( + s.T(), BlockDigestsTopic, + s.factory, s.validBlockDigestsArgumentsTestCases(), - func(dataChan chan interface{}, blocks []*flow.Block) { - for _, block := range blocks { + func(dataChan chan interface{}) { + for _, block := range s.blocks { dataChan <- flow.NewBlockDigest(block.Header.ID(), block.Header.Height, block.Header.Timestamp) } }, @@ -119,11 +134,12 @@ func (s *BlockDigestsProviderSuite) TestBlockDigestsDataProvider_HappyPath() { } // requireBlockHeaders ensures that the received block header information matches the expected data. -func (s *BlocksProviderSuite) requireBlockDigests(v interface{}, expectedBlock *flow.Block) { - actualResponse, ok := v.(*models.BlockDigestMessageResponse) - require.True(s.T(), ok, "unexpected response type: %T", v) +func (s *BlocksProviderSuite) requireBlockDigests(actual interface{}, expected interface{}) { + actualResponse, ok := actual.(*models.BlockDigestMessageResponse) + require.True(s.T(), ok, "unexpected response type: %T", actual) + + expectedResponse, ok := expected.(*models.BlockDigestMessageResponse) + require.True(s.T(), ok, "unexpected response type: %T", expected) - s.Require().Equal(expectedBlock.Header.ID(), actualResponse.Block.ID()) - s.Require().Equal(expectedBlock.Header.Height, actualResponse.Block.Height) - s.Require().Equal(expectedBlock.Header.Timestamp, actualResponse.Block.Timestamp) + s.Require().Equal(expectedResponse.Block, actualResponse.Block) } diff --git a/engine/access/rest/websockets/data_providers/block_headers_provider.go b/engine/access/rest/websockets/data_providers/block_headers_provider.go index 4f9e29e2428..6ad94a58ecf 100644 --- a/engine/access/rest/websockets/data_providers/block_headers_provider.go +++ b/engine/access/rest/websockets/data_providers/block_headers_provider.go @@ -7,6 +7,7 @@ import ( "github.com/rs/zerolog" "github.com/onflow/flow-go/access" + commonmodels "github.com/onflow/flow-go/engine/access/rest/common/models" "github.com/onflow/flow-go/engine/access/rest/http/request" "github.com/onflow/flow-go/engine/access/rest/websockets/models" "github.com/onflow/flow-go/engine/access/subscription" @@ -60,9 +61,12 @@ func NewBlockHeadersDataProvider( func (p *BlockHeadersDataProvider) Run() error { return subscription.HandleSubscription( p.subscription, - subscription.HandleResponse(p.send, func(header *flow.Header) (interface{}, error) { + subscription.HandleResponse(p.send, func(h *flow.Header) (interface{}, error) { + var header commonmodels.BlockHeader + header.Build(h) + return &models.BlockHeaderMessageResponse{ - Header: header, + Header: &header, }, nil }), ) diff --git a/engine/access/rest/websockets/data_providers/block_headers_provider_test.go b/engine/access/rest/websockets/data_providers/block_headers_provider_test.go index 57c262d8795..4ca10b45802 100644 --- a/engine/access/rest/websockets/data_providers/block_headers_provider_test.go +++ b/engine/access/rest/websockets/data_providers/block_headers_provider_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" + commonmodels "github.com/onflow/flow-go/engine/access/rest/common/models" "github.com/onflow/flow-go/engine/access/rest/common/parser" "github.com/onflow/flow-go/engine/access/rest/websockets/models" statestreamsmock "github.com/onflow/flow-go/engine/access/state_stream/mock" @@ -54,6 +55,14 @@ func (s *BlockHeadersProviderSuite) TestBlockHeadersDataProvider_InvalidArgument // validBlockHeadersArgumentsTestCases defines test happy cases for block headers data providers. // Each test case specifies input arguments, and setup functions for the mock API used in the test. func (s *BlockHeadersProviderSuite) validBlockHeadersArgumentsTestCases() []testType { + expectedResponses := make([]interface{}, len(s.blocks)) + for i, b := range s.blocks { + var header commonmodels.BlockHeader + header.Build(b.Header) + + expectedResponses[i] = &models.BlockHeaderMessageResponse{Header: &header} + } + return []testType{ { name: "happy path with start_block_id argument", @@ -69,6 +78,7 @@ func (s *BlockHeadersProviderSuite) validBlockHeadersArgumentsTestCases() []test flow.BlockStatusFinalized, ).Return(sub).Once() }, + expectedResponses: expectedResponses, }, { name: "happy path with start_block_height argument", @@ -84,6 +94,7 @@ func (s *BlockHeadersProviderSuite) validBlockHeadersArgumentsTestCases() []test flow.BlockStatusFinalized, ).Return(sub).Once() }, + expectedResponses: expectedResponses, }, { name: "happy path without any start argument", @@ -97,6 +108,7 @@ func (s *BlockHeadersProviderSuite) validBlockHeadersArgumentsTestCases() []test flow.BlockStatusFinalized, ).Return(sub).Once() }, + expectedResponses: expectedResponses, }, } } @@ -106,11 +118,13 @@ func (s *BlockHeadersProviderSuite) validBlockHeadersArgumentsTestCases() []test // validates that block headers are correctly streamed to the channel and ensures // no unexpected errors occur. func (s *BlockHeadersProviderSuite) TestBlockHeadersDataProvider_HappyPath() { - s.testHappyPath( + testHappyPath( + s.T(), BlockHeadersTopic, + s.factory, s.validBlockHeadersArgumentsTestCases(), - func(dataChan chan interface{}, blocks []*flow.Block) { - for _, block := range blocks { + func(dataChan chan interface{}) { + for _, block := range s.blocks { dataChan <- block.Header } }, @@ -119,9 +133,12 @@ func (s *BlockHeadersProviderSuite) TestBlockHeadersDataProvider_HappyPath() { } // requireBlockHeaders ensures that the received block header information matches the expected data. -func (s *BlockHeadersProviderSuite) requireBlockHeaders(v interface{}, expectedBlock *flow.Block) { - actualResponse, ok := v.(*models.BlockHeaderMessageResponse) - require.True(s.T(), ok, "unexpected response type: %T", v) +func (s *BlockHeadersProviderSuite) requireBlockHeaders(actual interface{}, expected interface{}) { + actualResponse, ok := actual.(*models.BlockHeaderMessageResponse) + require.True(s.T(), ok, "unexpected response type: %T", actual) + + expectedResponse, ok := expected.(*models.BlockHeaderMessageResponse) + require.True(s.T(), ok, "unexpected response type: %T", expected) - s.Require().Equal(expectedBlock.Header, actualResponse.Header) + s.Require().Equal(expectedResponse.Header, actualResponse.Header) } diff --git a/engine/access/rest/websockets/data_providers/blocks_provider_test.go b/engine/access/rest/websockets/data_providers/blocks_provider_test.go index 9e07f9459e9..888b3146548 100644 --- a/engine/access/rest/websockets/data_providers/blocks_provider_test.go +++ b/engine/access/rest/websockets/data_providers/blocks_provider_test.go @@ -30,9 +30,10 @@ type testErrType struct { // testType represents a valid test scenario for subscribing type testType struct { - name string - arguments models.Arguments - setupBackend func(sub *statestreamsmock.Subscription) + name string + arguments models.Arguments + setupBackend func(sub *statestreamsmock.Subscription) + expectedResponses []interface{} } // BlocksProviderSuite is a test suite for testing the block providers functionality. @@ -137,6 +138,11 @@ func (s *BlocksProviderSuite) TestBlocksDataProvider_InvalidArguments() { // validBlockArgumentsTestCases defines test happy cases for block data providers. // Each test case specifies input arguments, and setup functions for the mock API used in the test. func (s *BlocksProviderSuite) validBlockArgumentsTestCases() []testType { + expectedResponses := make([]interface{}, len(s.blocks)) + for i, b := range s.blocks { + expectedResponses[i] = b + } + return []testType{ { name: "happy path with start_block_id argument", @@ -152,6 +158,7 @@ func (s *BlocksProviderSuite) validBlockArgumentsTestCases() []testType { flow.BlockStatusFinalized, ).Return(sub).Once() }, + expectedResponses: expectedResponses, }, { name: "happy path with start_block_height argument", @@ -167,6 +174,7 @@ func (s *BlocksProviderSuite) validBlockArgumentsTestCases() []testType { flow.BlockStatusFinalized, ).Return(sub).Once() }, + expectedResponses: expectedResponses, }, { name: "happy path without any start argument", @@ -180,6 +188,7 @@ func (s *BlocksProviderSuite) validBlockArgumentsTestCases() []testType { flow.BlockStatusFinalized, ).Return(sub).Once() }, + expectedResponses: expectedResponses, }, } } @@ -189,11 +198,13 @@ func (s *BlocksProviderSuite) validBlockArgumentsTestCases() []testType { // validates that blocks are correctly streamed to the channel and ensures // no unexpected errors occur. func (s *BlocksProviderSuite) TestBlocksDataProvider_HappyPath() { - s.testHappyPath( + testHappyPath( + s.T(), BlocksTopic, + s.factory, s.validBlockArgumentsTestCases(), - func(dataChan chan interface{}, blocks []*flow.Block) { - for _, block := range blocks { + func(dataChan chan interface{}) { + for _, block := range s.blocks { dataChan <- block } }, @@ -202,11 +213,14 @@ func (s *BlocksProviderSuite) TestBlocksDataProvider_HappyPath() { } // requireBlocks ensures that the received block information matches the expected data. -func (s *BlocksProviderSuite) requireBlock(v interface{}, expectedBlock *flow.Block) { - actualResponse, ok := v.(*models.BlockMessageResponse) - require.True(s.T(), ok, "unexpected response type: %T", v) +func (s *BlocksProviderSuite) requireBlock(actual interface{}, expected interface{}) { + actualResponse, ok := actual.(*models.BlockMessageResponse) + require.True(s.T(), ok, "unexpected response type: %T", actual) - s.Require().Equal(expectedBlock, actualResponse.Block) + expectedResponse, ok := expected.(*flow.Block) + require.True(s.T(), ok, "unexpected response type: %T", expected) + + s.Require().Equal(expectedResponse, actualResponse.Block) } // testHappyPath tests a variety of scenarios for data providers in @@ -215,18 +229,23 @@ func (s *BlocksProviderSuite) requireBlock(v interface{}, expectedBlock *flow.Bl // as expected without encountering errors. // // Arguments: -// - topic: The topic associated with the data provider. -// - tests: A slice of test cases to run, each specifying setup and validation logic. -// - sendData: A function to simulate emitting data into the subscription's data channel. -// - requireFn: A function to validate the output received in the send channel. -func (s *BlocksProviderSuite) testHappyPath( +// - t: The testing context. +// - topic: The topic associated with the data provider under test. +// - factory: An instance of DataProviderFactoryImpl used to create data providers. +// - tests: A slice of testType structs, each specifying the setup logic, arguments, +// and expected responses for the test case. +// - sendData: A function that simulates sending data into the subscription's data channel. +// - requireFn: A validation function to compare the received responses against the expected ones. +func testHappyPath( + t *testing.T, topic string, + factory *DataProviderFactoryImpl, tests []testType, - sendData func(chan interface{}, []*flow.Block), - requireFn func(interface{}, *flow.Block), + sendData func(chan interface{}), + requireFn func(interface{}, interface{}), ) { for _, test := range tests { - s.Run(test.name, func() { + t.Run(test.name, func(t *testing.T) { ctx := context.Background() send := make(chan interface{}, 10) @@ -234,36 +253,36 @@ func (s *BlocksProviderSuite) testHappyPath( dataChan := make(chan interface{}) // Create a mock subscription and mock the channel - sub := statestreamsmock.NewSubscription(s.T()) + sub := statestreamsmock.NewSubscription(t) sub.On("Channel").Return((<-chan interface{})(dataChan)) sub.On("Err").Return(nil) test.setupBackend(sub) // Create the data provider instance - provider, err := s.factory.NewDataProvider(ctx, topic, test.arguments, send) - s.Require().NotNil(provider) - s.Require().NoError(err) + provider, err := factory.NewDataProvider(ctx, topic, test.arguments, send) + require.NotNil(t, provider) + require.NoError(t, err) // Run the provider in a separate goroutine go func() { err = provider.Run() - s.Require().NoError(err) + require.NoError(t, err) }() // Simulate emitting data to the data channel go func() { defer close(dataChan) - sendData(dataChan, s.blocks) + sendData(dataChan) }() // Collect responses - for _, b := range s.blocks { - unittest.RequireReturnsBefore(s.T(), func() { + for _, expected := range test.expectedResponses { + unittest.RequireReturnsBefore(t, func() { v, ok := <-send - s.Require().True(ok, "channel closed while waiting for block %x %v: err: %v", b.Header.Height, b.ID(), sub.Err()) + require.True(t, ok, "channel closed while waiting for response %v: err: %v", expected, sub.Err()) - requireFn(v, b) - }, time.Second, fmt.Sprintf("timed out waiting for block %d %v", b.Header.Height, b.ID())) + requireFn(v, expected) + }, time.Second, fmt.Sprintf("timed out waiting for response %v", expected)) } // Ensure the provider is properly closed after the test diff --git a/engine/access/rest/websockets/models/block_digest.go b/engine/access/rest/websockets/models/block_digest.go new file mode 100644 index 00000000000..64d075fedce --- /dev/null +++ b/engine/access/rest/websockets/models/block_digest.go @@ -0,0 +1,12 @@ +package models + +import ( + "github.com/onflow/flow-go/engine/access/rest/util" + "github.com/onflow/flow-go/model/flow" +) + +func (b *BlockDigest) Build(block *flow.BlockDigest) { + b.BlockId = block.ID().String() + b.Height = util.FromUint(block.Height) + b.Timestamp = block.Timestamp +} diff --git a/engine/access/rest/websockets/models/block_models.go b/engine/access/rest/websockets/models/block_models.go index fa7af987236..b5b503149b7 100644 --- a/engine/access/rest/websockets/models/block_models.go +++ b/engine/access/rest/websockets/models/block_models.go @@ -1,6 +1,7 @@ package models import ( + "github.com/onflow/flow-go/engine/access/rest/common/models" "github.com/onflow/flow-go/model/flow" ) @@ -15,12 +16,12 @@ type BlockMessageResponse struct { type BlockHeaderMessageResponse struct { // The sealed or finalized block headers according to the block status // in the request. - Header *flow.Header `json:"header"` + Header *models.BlockHeader `json:"header"` } // BlockDigestMessageResponse is the response message for 'block_digests' topic. type BlockDigestMessageResponse struct { // The sealed or finalized block digest according to the block status // in the request. - Block *flow.BlockDigest `json:"block_digest"` + Block *BlockDigest `json:"block_digest"` } diff --git a/engine/access/rest/websockets/models/model_block_digest.go b/engine/access/rest/websockets/models/model_block_digest.go new file mode 100644 index 00000000000..d1e066b44e6 --- /dev/null +++ b/engine/access/rest/websockets/models/model_block_digest.go @@ -0,0 +1,11 @@ +package models + +import ( + "time" +) + +type BlockDigest struct { + BlockId string `json:"block_id"` + Height string `json:"height"` + Timestamp time.Time `json:"timestamp"` +} From e027b13cf2fb8d429b73f0625bc1aeb6ecc1fe43 Mon Sep 17 00:00:00 2001 From: UlyanaAndrukhiv Date: Tue, 10 Dec 2024 16:21:12 +0200 Subject: [PATCH 03/21] Updated blocks responses, added tests, merged with AndriiDiachuk/6588-events-data-provider --- Makefile | 1 + engine/access/rest/common/models/block.go | 5 +- .../rest/common/models/mock/link_generator.go | 223 ++++++++++++++++++ engine/access/rest/common/request.go | 10 +- engine/access/rest/common/utils.go | 9 + engine/access/rest/router/router.go | 12 +- engine/access/rest/server.go | 4 +- .../data_providers/blocks_provider.go | 39 ++- .../data_providers/blocks_provider_test.go | 99 +++++++- .../data_providers/events_provider_test.go | 4 +- .../rest/websockets/data_providers/factory.go | 7 +- .../websockets/data_providers/factory_test.go | 5 +- .../rest/websockets/models/block_models.go | 3 +- 13 files changed, 379 insertions(+), 42 deletions(-) create mode 100644 engine/access/rest/common/models/mock/link_generator.go create mode 100644 engine/access/rest/common/utils.go diff --git a/Makefile b/Makefile index 36075edd094..202619bebd3 100644 --- a/Makefile +++ b/Makefile @@ -205,6 +205,7 @@ generate-mocks: install-mock-generators mockery --name 'BlockTracker' --dir="./engine/access/subscription" --case=underscore --output="./engine/access/subscription/mock" --outpkg="mock" mockery --name 'DataProvider' --dir="./engine/access/rest/websockets/data_providers" --case=underscore --output="./engine/access/rest/websockets/data_providers/mock" --outpkg="mock" mockery --name 'DataProviderFactory' --dir="./engine/access/rest/websockets/data_providers" --case=underscore --output="./engine/access/rest/websockets/data_providers/mock" --outpkg="mock" + mockery --name 'LinkGenerator' --dir="./engine/access/rest/common/models" --case=underscore --output="./engine/access/rest/common/models/mock" --outpkg="mock" mockery --name 'ExecutionDataTracker' --dir="./engine/access/subscription" --case=underscore --output="./engine/access/subscription/mock" --outpkg="mock" mockery --name 'ConnectionFactory' --dir="./engine/access/rpc/connection" --case=underscore --output="./engine/access/rpc/connection/mock" --outpkg="mock" mockery --name 'Communicator' --dir="./engine/access/rpc/backend" --case=underscore --output="./engine/access/rpc/backend/mock" --outpkg="mock" diff --git a/engine/access/rest/common/models/block.go b/engine/access/rest/common/models/block.go index f868cc6d3a3..b94412929fa 100644 --- a/engine/access/rest/common/models/block.go +++ b/engine/access/rest/common/models/block.go @@ -5,6 +5,9 @@ import ( "github.com/onflow/flow-go/model/flow" ) +const ExpandableFieldPayload = "payload" +const ExpandableExecutionResult = "execution_result" + func (b *Block) Build( block *flow.Block, execResult *flow.ExecutionResult, @@ -23,7 +26,6 @@ func (b *Block) Build( // add the payload to the response if it is specified as an expandable field b.Expandable = &BlockExpandable{} - const ExpandableFieldPayload = "payload" if expand[ExpandableFieldPayload] { var payload BlockPayload err := payload.Build(block.Payload) @@ -43,7 +45,6 @@ func (b *Block) Build( // execution result might not yet exist if execResult != nil { // add the execution result to the response if it is specified as an expandable field - const ExpandableExecutionResult = "execution_result" if expand[ExpandableExecutionResult] { var exeResult ExecutionResult err := exeResult.Build(execResult, link) diff --git a/engine/access/rest/common/models/mock/link_generator.go b/engine/access/rest/common/models/mock/link_generator.go new file mode 100644 index 00000000000..6cf58664106 --- /dev/null +++ b/engine/access/rest/common/models/mock/link_generator.go @@ -0,0 +1,223 @@ +// Code generated by mockery v2.43.2. DO NOT EDIT. + +package mock + +import ( + flow "github.com/onflow/flow-go/model/flow" + mock "github.com/stretchr/testify/mock" +) + +// LinkGenerator is an autogenerated mock type for the LinkGenerator type +type LinkGenerator struct { + mock.Mock +} + +// AccountLink provides a mock function with given fields: address +func (_m *LinkGenerator) AccountLink(address string) (string, error) { + ret := _m.Called(address) + + if len(ret) == 0 { + panic("no return value specified for AccountLink") + } + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func(string) (string, error)); ok { + return rf(address) + } + if rf, ok := ret.Get(0).(func(string) string); ok { + r0 = rf(address) + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(address) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// BlockLink provides a mock function with given fields: id +func (_m *LinkGenerator) BlockLink(id flow.Identifier) (string, error) { + ret := _m.Called(id) + + if len(ret) == 0 { + panic("no return value specified for BlockLink") + } + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func(flow.Identifier) (string, error)); ok { + return rf(id) + } + if rf, ok := ret.Get(0).(func(flow.Identifier) string); ok { + r0 = rf(id) + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func(flow.Identifier) error); ok { + r1 = rf(id) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CollectionLink provides a mock function with given fields: id +func (_m *LinkGenerator) CollectionLink(id flow.Identifier) (string, error) { + ret := _m.Called(id) + + if len(ret) == 0 { + panic("no return value specified for CollectionLink") + } + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func(flow.Identifier) (string, error)); ok { + return rf(id) + } + if rf, ok := ret.Get(0).(func(flow.Identifier) string); ok { + r0 = rf(id) + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func(flow.Identifier) error); ok { + r1 = rf(id) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ExecutionResultLink provides a mock function with given fields: id +func (_m *LinkGenerator) ExecutionResultLink(id flow.Identifier) (string, error) { + ret := _m.Called(id) + + if len(ret) == 0 { + panic("no return value specified for ExecutionResultLink") + } + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func(flow.Identifier) (string, error)); ok { + return rf(id) + } + if rf, ok := ret.Get(0).(func(flow.Identifier) string); ok { + r0 = rf(id) + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func(flow.Identifier) error); ok { + r1 = rf(id) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// PayloadLink provides a mock function with given fields: id +func (_m *LinkGenerator) PayloadLink(id flow.Identifier) (string, error) { + ret := _m.Called(id) + + if len(ret) == 0 { + panic("no return value specified for PayloadLink") + } + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func(flow.Identifier) (string, error)); ok { + return rf(id) + } + if rf, ok := ret.Get(0).(func(flow.Identifier) string); ok { + r0 = rf(id) + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func(flow.Identifier) error); ok { + r1 = rf(id) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// TransactionLink provides a mock function with given fields: id +func (_m *LinkGenerator) TransactionLink(id flow.Identifier) (string, error) { + ret := _m.Called(id) + + if len(ret) == 0 { + panic("no return value specified for TransactionLink") + } + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func(flow.Identifier) (string, error)); ok { + return rf(id) + } + if rf, ok := ret.Get(0).(func(flow.Identifier) string); ok { + r0 = rf(id) + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func(flow.Identifier) error); ok { + r1 = rf(id) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// TransactionResultLink provides a mock function with given fields: id +func (_m *LinkGenerator) TransactionResultLink(id flow.Identifier) (string, error) { + ret := _m.Called(id) + + if len(ret) == 0 { + panic("no return value specified for TransactionResultLink") + } + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func(flow.Identifier) (string, error)); ok { + return rf(id) + } + if rf, ok := ret.Get(0).(func(flow.Identifier) string); ok { + r0 = rf(id) + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func(flow.Identifier) error); ok { + r1 = rf(id) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewLinkGenerator creates a new instance of LinkGenerator. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewLinkGenerator(t interface { + mock.TestingT + Cleanup(func()) +}) *LinkGenerator { + mock := &LinkGenerator{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/engine/access/rest/common/request.go b/engine/access/rest/common/request.go index b0b4a67f501..efabf0661ec 100644 --- a/engine/access/rest/common/request.go +++ b/engine/access/rest/common/request.go @@ -54,7 +54,7 @@ func Decorate(r *http.Request, chain flow.Chain) *Request { } if expandFields, found := middleware.GetFieldsToExpand(r); found { - decoratedReq.ExpandFields = sliceToMap(expandFields) + decoratedReq.ExpandFields = SliceToMap(expandFields) } if selectFields, found := middleware.GetFieldsToSelect(r); found { @@ -64,14 +64,6 @@ func Decorate(r *http.Request, chain flow.Chain) *Request { return decoratedReq } -func sliceToMap(values []string) map[string]bool { - valueMap := make(map[string]bool, len(values)) - for _, v := range values { - valueMap[v] = true - } - return valueMap -} - func toStringArray(in string) []string { // currently, the swagger generated Go REST client is incorrectly doing a `fmt.Sprintf("%v", id)` for the id slice // resulting in the client sending the ids in the format [id1 id2 id3...]. This is a temporary workaround to diff --git a/engine/access/rest/common/utils.go b/engine/access/rest/common/utils.go new file mode 100644 index 00000000000..7a31e2d0665 --- /dev/null +++ b/engine/access/rest/common/utils.go @@ -0,0 +1,9 @@ +package common + +func SliceToMap(values []string) map[string]bool { + valueMap := make(map[string]bool, len(values)) + for _, v := range values { + valueMap[v] = true + } + return valueMap +} diff --git a/engine/access/rest/router/router.go b/engine/access/rest/router/router.go index ac190000b50..453b2874b93 100644 --- a/engine/access/rest/router/router.go +++ b/engine/access/rest/router/router.go @@ -27,6 +27,8 @@ type RouterBuilder struct { logger zerolog.Logger router *mux.Router v1SubRouter *mux.Router + + LinkGenerator models.LinkGenerator } // NewRouterBuilder creates a new RouterBuilder instance with common middleware and a v1 sub-router. @@ -43,9 +45,10 @@ func NewRouterBuilder( v1SubRouter.Use(middleware.MetricsMiddleware(restCollector)) return &RouterBuilder{ - logger: logger, - router: router, - v1SubRouter: v1SubRouter, + logger: logger, + router: router, + v1SubRouter: v1SubRouter, + LinkGenerator: models.NewLinkGeneratorImpl(v1SubRouter), } } @@ -55,9 +58,8 @@ func (b *RouterBuilder) AddRestRoutes( chain flow.Chain, maxRequestSize int64, ) *RouterBuilder { - linkGenerator := models.NewLinkGeneratorImpl(b.v1SubRouter) for _, r := range Routes { - h := flowhttp.NewHandler(b.logger, backend, r.Handler, linkGenerator, chain, maxRequestSize) + h := flowhttp.NewHandler(b.logger, backend, r.Handler, b.LinkGenerator, chain, maxRequestSize) b.v1SubRouter. Methods(r.Method). Path(r.Pattern). diff --git a/engine/access/rest/server.go b/engine/access/rest/server.go index c45919725b2..6efcc65fb62 100644 --- a/engine/access/rest/server.go +++ b/engine/access/rest/server.go @@ -57,7 +57,9 @@ func NewServer(serverAPI access.API, serverAPI, chain, stateStreamConfig.EventFilterConfig, - stateStreamConfig.HeartbeatInterval) + stateStreamConfig.HeartbeatInterval, + builder.LinkGenerator, // TODO: guess how to avoid public LinkGenerator + ) builder.AddWebsocketsRoute(chain, wsConfig, config.MaxRequestSize, dataProviderFactory) c := cors.New(cors.Options{ diff --git a/engine/access/rest/websockets/data_providers/blocks_provider.go b/engine/access/rest/websockets/data_providers/blocks_provider.go index 28e0a9a03d2..bc465e9616b 100644 --- a/engine/access/rest/websockets/data_providers/blocks_provider.go +++ b/engine/access/rest/websockets/data_providers/blocks_provider.go @@ -7,6 +7,8 @@ import ( "github.com/rs/zerolog" "github.com/onflow/flow-go/access" + "github.com/onflow/flow-go/engine/access/rest/common" + commonmodels "github.com/onflow/flow-go/engine/access/rest/common/models" "github.com/onflow/flow-go/engine/access/rest/common/parser" "github.com/onflow/flow-go/engine/access/rest/http/request" "github.com/onflow/flow-go/engine/access/rest/util" @@ -20,14 +22,17 @@ type BlocksArguments struct { StartBlockID flow.Identifier // ID of the block to start subscription from StartBlockHeight uint64 // Height of the block to start subscription from BlockStatus flow.BlockStatus // Status of blocks to subscribe to + Expand map[string]bool } // BlocksDataProvider is responsible for providing blocks type BlocksDataProvider struct { *baseDataProvider - logger zerolog.Logger - api access.API + logger zerolog.Logger + api access.API + arguments BlocksArguments + linkGenerator commonmodels.LinkGenerator } var _ DataProvider = (*BlocksDataProvider)(nil) @@ -37,17 +42,20 @@ func NewBlocksDataProvider( ctx context.Context, logger zerolog.Logger, api access.API, + linkGenerator commonmodels.LinkGenerator, topic string, arguments models.Arguments, send chan<- interface{}, ) (*BlocksDataProvider, error) { p := &BlocksDataProvider{ - logger: logger.With().Str("component", "blocks-data-provider").Logger(), - api: api, + logger: logger.With().Str("component", "blocks-data-provider").Logger(), + api: api, + linkGenerator: linkGenerator, } // Parse arguments passed to the provider. - blockArgs, err := ParseBlocksArguments(arguments) + var err error + p.arguments, err = ParseBlocksArguments(arguments) if err != nil { return nil, fmt.Errorf("invalid arguments: %w", err) } @@ -57,7 +65,7 @@ func NewBlocksDataProvider( topic, cancel, send, - p.createSubscription(subCtx, blockArgs), // Set up a subscription to blocks based on arguments. + p.createSubscription(subCtx, p.arguments), // Set up a subscription to blocks based on arguments. ) return p, nil @@ -69,9 +77,13 @@ func NewBlocksDataProvider( func (p *BlocksDataProvider) Run() error { return subscription.HandleSubscription( p.subscription, - subscription.HandleResponse(p.send, func(block *flow.Block) (interface{}, error) { + subscription.HandleResponse(p.send, func(b *flow.Block) (interface{}, error) { + var block commonmodels.Block + //TODO: decide if execution result should be a part of response + block.Build(b, nil, p.linkGenerator, p.arguments.BlockStatus, p.arguments.Expand) + return &models.BlockMessageResponse{ - Block: block, + Block: &block, }, nil }), ) @@ -145,5 +157,16 @@ func ParseBlocksArguments(arguments models.Arguments) (BlocksArguments, error) { args.StartBlockHeight = request.EmptyHeight } + // Parse 'expand' as a JSON array of string + // expected values: "payload" + if expandIn, ok := arguments["expand"]; ok && expandIn != "" { + result, ok := expandIn.([]string) + if !ok { + return args, fmt.Errorf("'expand' must be an array of string") + } + + args.Expand = common.SliceToMap(result) + } + return args, nil } diff --git a/engine/access/rest/websockets/data_providers/blocks_provider_test.go b/engine/access/rest/websockets/data_providers/blocks_provider_test.go index 7331f73b0c7..6205e57b9ad 100644 --- a/engine/access/rest/websockets/data_providers/blocks_provider_test.go +++ b/engine/access/rest/websockets/data_providers/blocks_provider_test.go @@ -8,11 +8,14 @@ import ( "time" "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" accessmock "github.com/onflow/flow-go/access/mock" + commonmodels "github.com/onflow/flow-go/engine/access/rest/common/models" + mockcommonmodels "github.com/onflow/flow-go/engine/access/rest/common/models/mock" "github.com/onflow/flow-go/engine/access/rest/common/parser" "github.com/onflow/flow-go/engine/access/rest/websockets/models" "github.com/onflow/flow-go/engine/access/state_stream" @@ -49,7 +52,8 @@ type BlocksProviderSuite struct { rootBlock flow.Block finalizedBlock *flow.Header - factory *DataProviderFactoryImpl + factory *DataProviderFactoryImpl + linkGenerator *mockcommonmodels.LinkGenerator } func TestBlocksProviderSuite(t *testing.T) { @@ -59,6 +63,7 @@ func TestBlocksProviderSuite(t *testing.T) { func (s *BlocksProviderSuite) SetupTest() { s.log = unittest.Logger() s.api = accessmock.NewAPI(s.T()) + s.linkGenerator = mockcommonmodels.NewLinkGenerator(s.T()) blockCount := 5 s.blocks = make([]*flow.Block, 0, blockCount) @@ -69,10 +74,13 @@ func (s *BlocksProviderSuite) SetupTest() { for i := 0; i < blockCount; i++ { block := unittest.BlockWithParentFixture(parent) + transaction := unittest.TransactionFixture() + col := flow.CollectionFromTransactions([]*flow.Transaction{&transaction}) + guarantee := col.Guarantee() + block.SetPayload(unittest.PayloadFixture(unittest.WithGuarantees(&guarantee))) // update for next iteration parent = block.Header s.blocks = append(s.blocks, block) - } s.finalizedBlock = parent @@ -82,7 +90,9 @@ func (s *BlocksProviderSuite) SetupTest() { s.api, flow.Testnet.Chain(), state_stream.DefaultEventFilterConfig, - subscription.DefaultHeartbeatInterval) + subscription.DefaultHeartbeatInterval, + s.linkGenerator, + ) s.Require().NotNil(s.factory) } @@ -135,7 +145,7 @@ func (s *BlocksProviderSuite) TestBlocksDataProvider_InvalidArguments() { for _, test := range s.invalidArgumentsTestCases() { s.Run(test.name, func() { - provider, err := NewBlocksDataProvider(ctx, s.log, s.api, BlocksTopic, test.arguments, send) + provider, err := NewBlocksDataProvider(ctx, s.log, s.api, nil, BlocksTopic, test.arguments, send) s.Require().Nil(provider) s.Require().Error(err) s.Require().Contains(err.Error(), test.expectedErrorMsg) @@ -146,10 +156,8 @@ func (s *BlocksProviderSuite) TestBlocksDataProvider_InvalidArguments() { // validBlockArgumentsTestCases defines test happy cases for block data providers. // Each test case specifies input arguments, and setup functions for the mock API used in the test. func (s *BlocksProviderSuite) validBlockArgumentsTestCases() []testType { - expectedResponses := make([]interface{}, len(s.blocks)) - for i, b := range s.blocks { - expectedResponses[i] = b - } + expectedResponses := expectedBlockResponses(s.blocks, s.linkGenerator, map[string]bool{}, flow.BlockStatusFinalized) + expectedPayloadExpandedResponse := expectedBlockResponses(s.blocks, s.linkGenerator, map[string]bool{commonmodels.ExpandableFieldPayload: true}, flow.BlockStatusFinalized) return []testType{ { @@ -198,6 +206,35 @@ func (s *BlocksProviderSuite) validBlockArgumentsTestCases() []testType { }, expectedResponses: expectedResponses, }, + { + name: "happy path without any start argument", + arguments: models.Arguments{ + "block_status": parser.Finalized, + }, + setupBackend: func(sub *statestreamsmock.Subscription) { + s.api.On( + "SubscribeBlocksFromLatest", + mock.Anything, + flow.BlockStatusFinalized, + ).Return(sub).Once() + }, + expectedResponses: expectedResponses, + }, + { + name: "happy path payload expanded", + arguments: models.Arguments{ + "block_status": parser.Finalized, + "expand": []string{"payload"}, + }, + setupBackend: func(sub *statestreamsmock.Subscription) { + s.api.On( + "SubscribeBlocksFromLatest", + mock.Anything, + flow.BlockStatusFinalized, + ).Return(sub).Once() + }, + expectedResponses: expectedPayloadExpandedResponse, + }, } } @@ -206,6 +243,28 @@ func (s *BlocksProviderSuite) validBlockArgumentsTestCases() []testType { // validates that blocks are correctly streamed to the channel and ensures // no unexpected errors occur. func (s *BlocksProviderSuite) TestBlocksDataProvider_HappyPath() { + s.linkGenerator.On("BlockLink", mock.AnythingOfType("flow.Identifier")).Return( + func(id flow.Identifier) (string, error) { + for _, block := range s.blocks { + if block.ID() == id { + return fmt.Sprintf("/v1/blocks/%s", id), nil + } + } + return "", assert.AnError + }, + ) + + s.linkGenerator.On("PayloadLink", mock.AnythingOfType("flow.Identifier")).Return( + func(id flow.Identifier) (string, error) { + for _, block := range s.blocks { + if block.ID() == id { + return fmt.Sprintf("/v1/blocks/%s/payload", id), nil + } + } + return "", assert.AnError + }, + ) + testHappyPath( s.T(), BlocksTopic, @@ -225,10 +284,10 @@ func (s *BlocksProviderSuite) requireBlock(actual interface{}, expected interfac actualResponse, ok := actual.(*models.BlockMessageResponse) require.True(s.T(), ok, "unexpected response type: %T", actual) - expectedResponse, ok := expected.(*flow.Block) + expectedResponse, ok := expected.(*models.BlockMessageResponse) require.True(s.T(), ok, "unexpected response type: %T", expected) - s.Require().Equal(expectedResponse, actualResponse.Block) + s.Require().Equal(expectedResponse.Block, actualResponse.Block) } // testHappyPath tests a variety of scenarios for data providers in @@ -298,3 +357,23 @@ func testHappyPath( }) } } + +// expectedBlockResponses generates a list of expected block responses for the given blocks. +func expectedBlockResponses( + blocks []*flow.Block, + linkGenerator *mockcommonmodels.LinkGenerator, + expand map[string]bool, + status flow.BlockStatus, +) []interface{} { + responses := make([]interface{}, len(blocks)) + for i, b := range blocks { + var block commonmodels.Block + block.Build(b, nil, linkGenerator, status, expand) + + responses[i] = &models.BlockMessageResponse{ + Block: &block, + } + } + + return responses +} diff --git a/engine/access/rest/websockets/data_providers/events_provider_test.go b/engine/access/rest/websockets/data_providers/events_provider_test.go index c1728eef4a9..48c0cddecbd 100644 --- a/engine/access/rest/websockets/data_providers/events_provider_test.go +++ b/engine/access/rest/websockets/data_providers/events_provider_test.go @@ -53,7 +53,9 @@ func (s *EventsProviderSuite) SetupTest() { nil, flow.Testnet.Chain(), state_stream.DefaultEventFilterConfig, - subscription.DefaultHeartbeatInterval) + subscription.DefaultHeartbeatInterval, + nil, + ) s.Require().NotNil(s.factory) } diff --git a/engine/access/rest/websockets/data_providers/factory.go b/engine/access/rest/websockets/data_providers/factory.go index e39a6643d4e..3a5562aec86 100644 --- a/engine/access/rest/websockets/data_providers/factory.go +++ b/engine/access/rest/websockets/data_providers/factory.go @@ -7,6 +7,7 @@ import ( "github.com/rs/zerolog" "github.com/onflow/flow-go/access" + commonmodels "github.com/onflow/flow-go/engine/access/rest/common/models" "github.com/onflow/flow-go/engine/access/rest/websockets/models" "github.com/onflow/flow-go/engine/access/state_stream" "github.com/onflow/flow-go/model/flow" @@ -48,6 +49,8 @@ type DataProviderFactoryImpl struct { chain flow.Chain eventFilterConfig state_stream.EventFilterConfig heartbeatInterval uint64 + + linkGenerator commonmodels.LinkGenerator } // NewDataProviderFactory creates a new DataProviderFactory @@ -64,6 +67,7 @@ func NewDataProviderFactory( chain flow.Chain, eventFilterConfig state_stream.EventFilterConfig, heartbeatInterval uint64, + linkGenerator commonmodels.LinkGenerator, ) *DataProviderFactoryImpl { return &DataProviderFactoryImpl{ logger: logger, @@ -72,6 +76,7 @@ func NewDataProviderFactory( chain: chain, eventFilterConfig: eventFilterConfig, heartbeatInterval: heartbeatInterval, + linkGenerator: linkGenerator, } } @@ -93,7 +98,7 @@ func (s *DataProviderFactoryImpl) NewDataProvider( ) (DataProvider, error) { switch topic { case BlocksTopic: - return NewBlocksDataProvider(ctx, s.logger, s.accessApi, topic, arguments, ch) + return NewBlocksDataProvider(ctx, s.logger, s.accessApi, s.linkGenerator, topic, arguments, ch) case BlockHeadersTopic: return NewBlockHeadersDataProvider(ctx, s.logger, s.accessApi, topic, arguments, ch) case BlockDigestsTopic: diff --git a/engine/access/rest/websockets/data_providers/factory_test.go b/engine/access/rest/websockets/data_providers/factory_test.go index 3323e3cc258..76acb27e51d 100644 --- a/engine/access/rest/websockets/data_providers/factory_test.go +++ b/engine/access/rest/websockets/data_providers/factory_test.go @@ -45,15 +45,14 @@ func (s *DataProviderFactorySuite) SetupTest() { s.ctx = context.Background() s.ch = make(chan interface{}) - chain := flow.Testnet.Chain() - s.factory = NewDataProviderFactory( log, s.stateStreamApi, s.accessApi, - chain, + flow.Testnet.Chain(), state_stream.DefaultEventFilterConfig, subscription.DefaultHeartbeatInterval, + nil, ) s.Require().NotNil(s.factory) } diff --git a/engine/access/rest/websockets/models/block_models.go b/engine/access/rest/websockets/models/block_models.go index b5b503149b7..76ea0697962 100644 --- a/engine/access/rest/websockets/models/block_models.go +++ b/engine/access/rest/websockets/models/block_models.go @@ -2,14 +2,13 @@ package models import ( "github.com/onflow/flow-go/engine/access/rest/common/models" - "github.com/onflow/flow-go/model/flow" ) // BlockMessageResponse is the response message for 'blocks' topic. type BlockMessageResponse struct { // The sealed or finalized blocks according to the block status // in the request. - Block *flow.Block `json:"block"` + Block *models.Block `json:"block"` } // BlockHeaderMessageResponse is the response message for 'block_headers' topic. From 9d94c22dda8f0be882d1faed04c0d4db57d87f56 Mon Sep 17 00:00:00 2001 From: UlyanaAndrukhiv Date: Wed, 11 Dec 2024 11:18:18 +0200 Subject: [PATCH 04/21] Updated websocket response for events --- .../data_providers/events_provider.go | 6 +++- .../data_providers/events_provider_test.go | 34 ++++++++++++++----- .../rest/websockets/models/event_models.go | 12 +++---- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/engine/access/rest/websockets/data_providers/events_provider.go b/engine/access/rest/websockets/data_providers/events_provider.go index b3cbb41d635..fcbf2d0f795 100644 --- a/engine/access/rest/websockets/data_providers/events_provider.go +++ b/engine/access/rest/websockets/data_providers/events_provider.go @@ -7,6 +7,7 @@ import ( "github.com/rs/zerolog" + commonmodels "github.com/onflow/flow-go/engine/access/rest/common/models" "github.com/onflow/flow-go/engine/access/rest/common/parser" "github.com/onflow/flow-go/engine/access/rest/http/request" "github.com/onflow/flow-go/engine/access/rest/util" @@ -100,11 +101,14 @@ func (p *EventsDataProvider) handleResponse() func(eventsResponse *backend.Event return fmt.Errorf("message index already incremented to: %d", messageIndex.Value()) } + var events commonmodels.Events + events.Build(eventsResponse.Events) + p.send <- &models.EventResponse{ BlockId: eventsResponse.BlockID.String(), BlockHeight: strconv.FormatUint(eventsResponse.Height, 10), BlockTimestamp: eventsResponse.BlockTimestamp, - Events: eventsResponse.Events, + Events: events, MessageIndex: strconv.FormatUint(index, 10), } diff --git a/engine/access/rest/websockets/data_providers/events_provider_test.go b/engine/access/rest/websockets/data_providers/events_provider_test.go index 48c0cddecbd..416fe6eba2d 100644 --- a/engine/access/rest/websockets/data_providers/events_provider_test.go +++ b/engine/access/rest/websockets/data_providers/events_provider_test.go @@ -11,6 +11,8 @@ import ( "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" + commonmodels "github.com/onflow/flow-go/engine/access/rest/common/models" + "github.com/onflow/flow-go/engine/access/rest/util" "github.com/onflow/flow-go/engine/access/rest/websockets/models" "github.com/onflow/flow-go/engine/access/state_stream" "github.com/onflow/flow-go/engine/access/state_stream/backend" @@ -129,7 +131,7 @@ func (s *EventsProviderSuite) TestEventsDataProvider_HappyPath() { func (s *EventsProviderSuite) testHappyPath( topic string, tests []testType, - requireFn func(interface{}, *backend.EventsResponse), + requireFn func(interface{}, *models.EventResponse), ) { expectedEvents := []flow.Event{ unittest.EventFixture(flow.EventAccountCreated, 0, 0, unittest.IdentifierFixture(), 0), @@ -138,16 +140,32 @@ func (s *EventsProviderSuite) testHappyPath( unittest.EventFixture(flow.EventAccountUpdated, 0, 0, unittest.IdentifierFixture(), 0), } - var expectedEventsResponses []backend.EventsResponse + var backendResponses []*backend.EventsResponse + var expectedEventsResponses []*models.EventResponse for i := 0; i < len(expectedEvents); i++ { - expectedEventsResponses = append(expectedEventsResponses, backend.EventsResponse{ + var events commonmodels.Events + events.Build(expectedEvents) + + backendResponses = append(backendResponses, &backend.EventsResponse{ Height: s.rootBlock.Header.Height, BlockID: s.rootBlock.ID(), Events: expectedEvents, BlockTimestamp: s.rootBlock.Header.Timestamp, }) + expectedEventsResponses = append(expectedEventsResponses, &models.EventResponse{ + BlockHeight: util.FromUint(s.rootBlock.Header.Height), + BlockId: s.rootBlock.ID().String(), + Events: events, + BlockTimestamp: s.rootBlock.Header.Timestamp, + }) + } + + for i := 0; i < len(expectedEvents); i++ { + var events commonmodels.Events + events.Build(expectedEvents) + } for _, test := range tests { @@ -179,17 +197,17 @@ func (s *EventsProviderSuite) testHappyPath( go func() { defer close(eventChan) - for i := 0; i < len(expectedEventsResponses); i++ { - eventChan <- &expectedEventsResponses[i] + for i := 0; i < len(backendResponses); i++ { + eventChan <- backendResponses[i] } }() // Collect responses for _, e := range expectedEventsResponses { v, ok := <-send - s.Require().True(ok, "channel closed while waiting for event %v: err: %v", e.BlockID, sub.Err()) + s.Require().True(ok, "channel closed while waiting for event %v: err: %v", e.BlockId, sub.Err()) - requireFn(v, &e) + requireFn(v, e) } // Ensure the provider is properly closed after the test @@ -199,7 +217,7 @@ func (s *EventsProviderSuite) testHappyPath( } // requireEvents ensures that the received event information matches the expected data. -func (s *EventsProviderSuite) requireEvents(v interface{}, expectedEventsResponse *backend.EventsResponse) { +func (s *EventsProviderSuite) requireEvents(v interface{}, expectedEventsResponse *models.EventResponse) { actualResponse, ok := v.(*models.EventResponse) require.True(s.T(), ok, "Expected *models.EventResponse, got %T", v) diff --git a/engine/access/rest/websockets/models/event_models.go b/engine/access/rest/websockets/models/event_models.go index 48d085d9b85..002b131ed82 100644 --- a/engine/access/rest/websockets/models/event_models.go +++ b/engine/access/rest/websockets/models/event_models.go @@ -3,14 +3,14 @@ package models import ( "time" - "github.com/onflow/flow-go/model/flow" + "github.com/onflow/flow-go/engine/access/rest/common/models" ) // EventResponse is the response message for 'events' topic. type EventResponse struct { - BlockId string `json:"block_id"` - BlockHeight string `json:"block_height"` - BlockTimestamp time.Time `json:"block_timestamp"` - Events []flow.Event `json:"events"` - MessageIndex string `json:"message_index"` + BlockId string `json:"block_id"` + BlockHeight string `json:"block_height"` + BlockTimestamp time.Time `json:"block_timestamp"` + Events models.Events `json:"events"` + MessageIndex string `json:"message_index"` } From ada49d9aeddbde56bfa68e75f637bc2894fb9bb2 Mon Sep 17 00:00:00 2001 From: UlyanaAndrukhiv Date: Wed, 11 Dec 2024 12:52:05 +0200 Subject: [PATCH 05/21] Updated websocket account statuses responses, updated tests --- .../account_statuses_provider.go | 5 ++- .../account_statuses_provider_test.go | 31 +++++++++++++------ .../data_providers/events_provider_test.go | 11 +++---- .../rest/websockets/models/account_events.go | 20 ++++++++++++ .../rest/websockets/models/account_models.go | 10 +++--- 5 files changed, 55 insertions(+), 22 deletions(-) create mode 100644 engine/access/rest/websockets/models/account_events.go diff --git a/engine/access/rest/websockets/data_providers/account_statuses_provider.go b/engine/access/rest/websockets/data_providers/account_statuses_provider.go index 1a3aee203c9..2dc4dd0d39e 100644 --- a/engine/access/rest/websockets/data_providers/account_statuses_provider.go +++ b/engine/access/rest/websockets/data_providers/account_statuses_provider.go @@ -116,10 +116,13 @@ func (p *AccountStatusesDataProvider) handleResponse() func(accountStatusesRespo return status.Errorf(codes.Internal, "message index already incremented to %d", messageIndex.Value()) } + var accountEvents models.AccountEvents + accountEvents.Build(accountStatusesResponse.AccountEvents) + p.send <- &models.AccountStatusesResponse{ BlockID: accountStatusesResponse.BlockID.String(), Height: strconv.FormatUint(accountStatusesResponse.Height, 10), - AccountEvents: accountStatusesResponse.AccountEvents, + AccountEvents: accountEvents, MessageIndex: strconv.FormatUint(index, 10), } diff --git a/engine/access/rest/websockets/data_providers/account_statuses_provider_test.go b/engine/access/rest/websockets/data_providers/account_statuses_provider_test.go index aeadd68f649..89a241acb52 100644 --- a/engine/access/rest/websockets/data_providers/account_statuses_provider_test.go +++ b/engine/access/rest/websockets/data_providers/account_statuses_provider_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" + "github.com/onflow/flow-go/engine/access/rest/util" "github.com/onflow/flow-go/engine/access/rest/websockets/models" "github.com/onflow/flow-go/engine/access/state_stream" "github.com/onflow/flow-go/engine/access/state_stream/backend" @@ -52,7 +53,9 @@ func (s *AccountStatusesProviderSuite) SetupTest() { nil, flow.Testnet.Chain(), state_stream.DefaultEventFilterConfig, - subscription.DefaultHeartbeatInterval) + subscription.DefaultHeartbeatInterval, + nil, + ) s.Require().NotNil(s.factory) } @@ -71,22 +74,32 @@ func (s *AccountStatusesProviderSuite) TestAccountStatusesDataProvider_HappyPath func (s *AccountStatusesProviderSuite) testHappyPath( topic string, tests []testType, - requireFn func(interface{}, *backend.AccountStatusesResponse), + requireFn func(interface{}, *models.AccountStatusesResponse), ) { expectedEvents := []flow.Event{ unittest.EventFixture(state_stream.CoreEventAccountCreated, 0, 0, unittest.IdentifierFixture(), 0), unittest.EventFixture(state_stream.CoreEventAccountKeyAdded, 0, 0, unittest.IdentifierFixture(), 0), } - var expectedAccountStatusesResponses []backend.AccountStatusesResponse + var backendResponses []*backend.AccountStatusesResponse + var expectedResponses []*models.AccountStatusesResponse for i := 0; i < len(expectedEvents); i++ { - expectedAccountStatusesResponses = append(expectedAccountStatusesResponses, backend.AccountStatusesResponse{ + backendResponse := &backend.AccountStatusesResponse{ Height: s.rootBlock.Header.Height, BlockID: s.rootBlock.ID(), AccountEvents: map[string]flow.EventsList{ unittest.RandomAddressFixture().String(): expectedEvents, }, + } + backendResponses = append(backendResponses, backendResponse) + + var accountEvents models.AccountEvents + accountEvents.Build(backendResponse.AccountEvents) + expectedResponses = append(expectedResponses, &models.AccountStatusesResponse{ + Height: util.FromUint(s.rootBlock.Header.Height), + BlockID: s.rootBlock.ID().String(), + AccountEvents: accountEvents, }) } @@ -119,17 +132,17 @@ func (s *AccountStatusesProviderSuite) testHappyPath( go func() { defer close(accStatusesChan) - for i := 0; i < len(expectedAccountStatusesResponses); i++ { - accStatusesChan <- &expectedAccountStatusesResponses[i] + for i := 0; i < len(backendResponses); i++ { + accStatusesChan <- backendResponses[i] } }() // Collect responses - for _, e := range expectedAccountStatusesResponses { + for _, e := range expectedResponses { v, ok := <-send s.Require().True(ok, "channel closed while waiting for event %v: err: %v", e.BlockID, sub.Err()) - requireFn(v, &e) + requireFn(v, e) } // Ensure the provider is properly closed after the test @@ -186,7 +199,7 @@ func (s *AccountStatusesProviderSuite) subscribeAccountStatusesDataProviderTestC // requireAccountStatuses ensures that the received account statuses information matches the expected data. func (s *AccountStatusesProviderSuite) requireAccountStatuses( v interface{}, - expectedAccountStatusesResponse *backend.AccountStatusesResponse, + expectedAccountStatusesResponse *models.AccountStatusesResponse, ) { _, ok := v.(*models.AccountStatusesResponse) require.True(s.T(), ok, "Expected *models.AccountStatusesResponse, got %T", v) diff --git a/engine/access/rest/websockets/data_providers/events_provider_test.go b/engine/access/rest/websockets/data_providers/events_provider_test.go index bf1e1778eca..f4bfadda898 100644 --- a/engine/access/rest/websockets/data_providers/events_provider_test.go +++ b/engine/access/rest/websockets/data_providers/events_provider_test.go @@ -141,12 +141,9 @@ func (s *EventsProviderSuite) testHappyPath( } var backendResponses []*backend.EventsResponse - var expectedEventsResponses []*models.EventResponse + var expectedResponses []*models.EventResponse for i := 0; i < len(expectedEvents); i++ { - var events commonmodels.Events - events.Build(expectedEvents) - backendResponses = append(backendResponses, &backend.EventsResponse{ Height: s.rootBlock.Header.Height, BlockID: s.rootBlock.ID(), @@ -154,7 +151,9 @@ func (s *EventsProviderSuite) testHappyPath( BlockTimestamp: s.rootBlock.Header.Timestamp, }) - expectedEventsResponses = append(expectedEventsResponses, &models.EventResponse{ + var events commonmodels.Events + events.Build(expectedEvents) + expectedResponses = append(expectedResponses, &models.EventResponse{ BlockHeight: util.FromUint(s.rootBlock.Header.Height), BlockId: s.rootBlock.ID().String(), Events: events, @@ -203,7 +202,7 @@ func (s *EventsProviderSuite) testHappyPath( }() // Collect responses - for _, e := range expectedEventsResponses { + for _, e := range expectedResponses { v, ok := <-send s.Require().True(ok, "channel closed while waiting for event %v: err: %v", e.BlockId, sub.Err()) diff --git a/engine/access/rest/websockets/models/account_events.go b/engine/access/rest/websockets/models/account_events.go new file mode 100644 index 00000000000..2eb74c7101d --- /dev/null +++ b/engine/access/rest/websockets/models/account_events.go @@ -0,0 +1,20 @@ +package models + +import ( + "github.com/onflow/flow-go/engine/access/rest/common/models" + "github.com/onflow/flow-go/model/flow" +) + +type AccountEvents map[string]models.Events + +func (a *AccountEvents) Build(accountEvents map[string]flow.EventsList) { + result := make(map[string]models.Events, len(accountEvents)) + + for i, e := range accountEvents { + var events models.Events + events.Build(e) + result[i] = events + } + + *a = result +} diff --git a/engine/access/rest/websockets/models/account_models.go b/engine/access/rest/websockets/models/account_models.go index 712f7a1be6a..abfa25800dc 100644 --- a/engine/access/rest/websockets/models/account_models.go +++ b/engine/access/rest/websockets/models/account_models.go @@ -1,11 +1,9 @@ package models -import "github.com/onflow/flow-go/model/flow" - // AccountStatusesResponse is the response message for 'events' topic. type AccountStatusesResponse struct { - BlockID string `json:"blockID"` - Height string `json:"height"` - AccountEvents map[string]flow.EventsList `json:"account_events"` - MessageIndex string `json:"message_index"` + BlockID string `json:"blockID"` + Height string `json:"height"` + AccountEvents AccountEvents `json:"account_events"` + MessageIndex string `json:"message_index"` } From ad054f2ea15c88194357a79bc0cc043014351d98 Mon Sep 17 00:00:00 2001 From: UlyanaAndrukhiv Date: Wed, 11 Dec 2024 12:54:18 +0200 Subject: [PATCH 06/21] Merged with AndriiDiachuk/6588-events-data-provider --- .../websockets/data_providers/account_statuses_provider_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/access/rest/websockets/data_providers/account_statuses_provider_test.go b/engine/access/rest/websockets/data_providers/account_statuses_provider_test.go index 2c48101cf3f..3c968f4e3e4 100644 --- a/engine/access/rest/websockets/data_providers/account_statuses_provider_test.go +++ b/engine/access/rest/websockets/data_providers/account_statuses_provider_test.go @@ -204,7 +204,7 @@ func (s *AccountStatusesProviderSuite) requireAccountStatuses( actualResponse, ok := v.(*models.AccountStatusesResponse) require.True(s.T(), ok, "Expected *models.AccountStatusesResponse, got %T", v) - require.Equal(s.T(), expectedAccountStatusesResponse.BlockID.String(), actualResponse.BlockID) + require.Equal(s.T(), expectedAccountStatusesResponse.BlockID, actualResponse.BlockID) require.Equal(s.T(), len(expectedAccountStatusesResponse.AccountEvents), len(actualResponse.AccountEvents)) for key, expectedEvents := range expectedAccountStatusesResponse.AccountEvents { From d3035cb023f5c4cd706434ab60f51d97b593a402 Mon Sep 17 00:00:00 2001 From: UlyanaAndrukhiv Date: Wed, 11 Dec 2024 13:09:26 +0200 Subject: [PATCH 07/21] Added missed godoc --- engine/access/rest/websockets/models/account_events.go | 2 ++ engine/access/rest/websockets/models/block_digest.go | 1 + 2 files changed, 3 insertions(+) diff --git a/engine/access/rest/websockets/models/account_events.go b/engine/access/rest/websockets/models/account_events.go index 2eb74c7101d..ae2d67cb9a1 100644 --- a/engine/access/rest/websockets/models/account_events.go +++ b/engine/access/rest/websockets/models/account_events.go @@ -5,8 +5,10 @@ import ( "github.com/onflow/flow-go/model/flow" ) +// AccountEvents represents a mapping of account addresses to their associated events. type AccountEvents map[string]models.Events +// Build creates AccountEvents instance by converting each flow.EventsList to the corresponding models.Events. func (a *AccountEvents) Build(accountEvents map[string]flow.EventsList) { result := make(map[string]models.Events, len(accountEvents)) diff --git a/engine/access/rest/websockets/models/block_digest.go b/engine/access/rest/websockets/models/block_digest.go index 64d075fedce..a7f7dac500a 100644 --- a/engine/access/rest/websockets/models/block_digest.go +++ b/engine/access/rest/websockets/models/block_digest.go @@ -5,6 +5,7 @@ import ( "github.com/onflow/flow-go/model/flow" ) +// Build creates a BlockDigest instance with data from the provided flow.BlockDigest. func (b *BlockDigest) Build(block *flow.BlockDigest) { b.BlockId = block.ID().String() b.Height = util.FromUint(block.Height) From 396d87ba77c0c4a9010868f3e97b90a272ed554e Mon Sep 17 00:00:00 2001 From: UlyanaAndrukhiv Date: Thu, 12 Dec 2024 11:15:34 +0200 Subject: [PATCH 08/21] Linted, added more godoc --- engine/access/rest/common/utils.go | 2 ++ .../rest/websockets/data_providers/blocks_provider.go | 5 ++++- .../websockets/data_providers/blocks_provider_test.go | 9 +++++---- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/engine/access/rest/common/utils.go b/engine/access/rest/common/utils.go index 7a31e2d0665..0a707e686ac 100644 --- a/engine/access/rest/common/utils.go +++ b/engine/access/rest/common/utils.go @@ -1,5 +1,7 @@ package common +// SliceToMap converts a slice of strings into a map where each string +// in the slice becomes a key in the map with the value set to true. func SliceToMap(values []string) map[string]bool { valueMap := make(map[string]bool, len(values)) for _, v := range values { diff --git a/engine/access/rest/websockets/data_providers/blocks_provider.go b/engine/access/rest/websockets/data_providers/blocks_provider.go index bc465e9616b..d4cce9479a9 100644 --- a/engine/access/rest/websockets/data_providers/blocks_provider.go +++ b/engine/access/rest/websockets/data_providers/blocks_provider.go @@ -80,7 +80,10 @@ func (p *BlocksDataProvider) Run() error { subscription.HandleResponse(p.send, func(b *flow.Block) (interface{}, error) { var block commonmodels.Block //TODO: decide if execution result should be a part of response - block.Build(b, nil, p.linkGenerator, p.arguments.BlockStatus, p.arguments.Expand) + err := block.Build(b, nil, p.linkGenerator, p.arguments.BlockStatus, p.arguments.Expand) + if err != nil { + return nil, fmt.Errorf("failed to build block response :%w", err) + } return &models.BlockMessageResponse{ Block: &block, diff --git a/engine/access/rest/websockets/data_providers/blocks_provider_test.go b/engine/access/rest/websockets/data_providers/blocks_provider_test.go index f4b524de731..9fe34303d2e 100644 --- a/engine/access/rest/websockets/data_providers/blocks_provider_test.go +++ b/engine/access/rest/websockets/data_providers/blocks_provider_test.go @@ -156,8 +156,8 @@ func (s *BlocksProviderSuite) TestBlocksDataProvider_InvalidArguments() { // validBlockArgumentsTestCases defines test happy cases for block data providers. // Each test case specifies input arguments, and setup functions for the mock API used in the test. func (s *BlocksProviderSuite) validBlockArgumentsTestCases() []testType { - expectedResponses := expectedBlockResponses(s.blocks, s.linkGenerator, map[string]bool{}, flow.BlockStatusFinalized) - expectedPayloadExpandedResponse := expectedBlockResponses(s.blocks, s.linkGenerator, map[string]bool{commonmodels.ExpandableFieldPayload: true}, flow.BlockStatusFinalized) + expectedResponses := s.expectedBlockResponses(s.blocks, s.linkGenerator, map[string]bool{}, flow.BlockStatusFinalized) + expectedPayloadExpandedResponse := s.expectedBlockResponses(s.blocks, s.linkGenerator, map[string]bool{commonmodels.ExpandableFieldPayload: true}, flow.BlockStatusFinalized) return []testType{ { @@ -359,7 +359,7 @@ func testHappyPath( } // expectedBlockResponses generates a list of expected block responses for the given blocks. -func expectedBlockResponses( +func (s *BlocksProviderSuite) expectedBlockResponses( blocks []*flow.Block, linkGenerator *mockcommonmodels.LinkGenerator, expand map[string]bool, @@ -368,7 +368,8 @@ func expectedBlockResponses( responses := make([]interface{}, len(blocks)) for i, b := range blocks { var block commonmodels.Block - block.Build(b, nil, linkGenerator, status, expand) + err := block.Build(b, nil, linkGenerator, status, expand) + s.Require().NoError(err) responses[i] = &models.BlockMessageResponse{ Block: &block, From e1905d79c98c2d2d2852c4ba5ecf984aee2635c2 Mon Sep 17 00:00:00 2001 From: UlyanaAndrukhiv Date: Thu, 12 Dec 2024 11:23:40 +0200 Subject: [PATCH 09/21] Added godoc for block digest rest model --- engine/access/rest/websockets/models/model_block_digest.go | 1 + 1 file changed, 1 insertion(+) diff --git a/engine/access/rest/websockets/models/model_block_digest.go b/engine/access/rest/websockets/models/model_block_digest.go index d1e066b44e6..539604a28c3 100644 --- a/engine/access/rest/websockets/models/model_block_digest.go +++ b/engine/access/rest/websockets/models/model_block_digest.go @@ -4,6 +4,7 @@ import ( "time" ) +// BlockDigest is a lightweight block information model. type BlockDigest struct { BlockId string `json:"block_id"` Height string `json:"height"` From 8f184ca89552326fd2117a3f6a5e466f0759c956 Mon Sep 17 00:00:00 2001 From: UlyanaAndrukhiv Date: Thu, 12 Dec 2024 12:16:13 +0200 Subject: [PATCH 10/21] Added helper Build for event response --- .../data_providers/events_provider.go | 14 +++-------- .../data_providers/events_provider_test.go | 15 ++++-------- .../rest/websockets/models/eventResponse.go | 23 +++++++++++++++++++ .../rest/websockets/models/event_models.go | 9 ++------ 4 files changed, 32 insertions(+), 29 deletions(-) create mode 100644 engine/access/rest/websockets/models/eventResponse.go diff --git a/engine/access/rest/websockets/data_providers/events_provider.go b/engine/access/rest/websockets/data_providers/events_provider.go index c3f11c42aa4..0ed3de04d76 100644 --- a/engine/access/rest/websockets/data_providers/events_provider.go +++ b/engine/access/rest/websockets/data_providers/events_provider.go @@ -3,11 +3,9 @@ package data_providers import ( "context" "fmt" - "strconv" "github.com/rs/zerolog" - commonmodels "github.com/onflow/flow-go/engine/access/rest/common/models" "github.com/onflow/flow-go/engine/access/rest/common/parser" "github.com/onflow/flow-go/engine/access/rest/http/request" "github.com/onflow/flow-go/engine/access/rest/util" @@ -104,16 +102,10 @@ func (p *EventsDataProvider) handleResponse() func(eventsResponse *backend.Event return fmt.Errorf("message index already incremented to: %d", messageIndex.Value()) } - var events commonmodels.Events - events.Build(eventsResponse.Events) + var response models.EventResponse + response.Build(eventsResponse, index) - p.send <- &models.EventResponse{ - BlockId: eventsResponse.BlockID.String(), - BlockHeight: strconv.FormatUint(eventsResponse.Height, 10), - BlockTimestamp: eventsResponse.BlockTimestamp, - Events: events, - MessageIndex: strconv.FormatUint(index, 10), - } + p.send <- &response return nil } diff --git a/engine/access/rest/websockets/data_providers/events_provider_test.go b/engine/access/rest/websockets/data_providers/events_provider_test.go index a47cac086a1..575e7695d0e 100644 --- a/engine/access/rest/websockets/data_providers/events_provider_test.go +++ b/engine/access/rest/websockets/data_providers/events_provider_test.go @@ -11,8 +11,6 @@ import ( "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" - commonmodels "github.com/onflow/flow-go/engine/access/rest/common/models" - "github.com/onflow/flow-go/engine/access/rest/util" "github.com/onflow/flow-go/engine/access/rest/websockets/models" "github.com/onflow/flow-go/engine/access/state_stream" "github.com/onflow/flow-go/engine/access/state_stream/backend" @@ -317,15 +315,10 @@ func (s *EventsProviderSuite) expectedEventsResponses( expectedResponses := make([]interface{}, len(events)) for i, resp := range backendResponses { - var restEvents commonmodels.Events - restEvents.Build(events) - - expectedResponses[i] = &models.EventResponse{ - BlockHeight: util.FromUint(resp.Height), - BlockId: resp.BlockID.String(), - Events: restEvents, - BlockTimestamp: resp.BlockTimestamp, - } + var expectedResponse models.EventResponse + expectedResponse.Build(resp, uint64(i)) + + expectedResponses[i] = &expectedResponse } return expectedResponses } diff --git a/engine/access/rest/websockets/models/eventResponse.go b/engine/access/rest/websockets/models/eventResponse.go new file mode 100644 index 00000000000..827e176c228 --- /dev/null +++ b/engine/access/rest/websockets/models/eventResponse.go @@ -0,0 +1,23 @@ +package models + +import ( + "strconv" + + commonmodels "github.com/onflow/flow-go/engine/access/rest/common/models" + "github.com/onflow/flow-go/engine/access/state_stream/backend" +) + +// Build creates EventResponse instance. +func (e *EventResponse) Build(eventsResponse *backend.EventsResponse, index uint64) { + var events commonmodels.Events + events.Build(eventsResponse.Events) + + e.BlockEvents = commonmodels.BlockEvents{ + BlockId: eventsResponse.BlockID.String(), + BlockHeight: strconv.FormatUint(eventsResponse.Height, 10), + BlockTimestamp: eventsResponse.BlockTimestamp, + Events: events, + } + + e.MessageIndex = strconv.FormatUint(index, 10) +} diff --git a/engine/access/rest/websockets/models/event_models.go b/engine/access/rest/websockets/models/event_models.go index 002b131ed82..6d6ab3fa595 100644 --- a/engine/access/rest/websockets/models/event_models.go +++ b/engine/access/rest/websockets/models/event_models.go @@ -1,16 +1,11 @@ package models import ( - "time" - "github.com/onflow/flow-go/engine/access/rest/common/models" ) // EventResponse is the response message for 'events' topic. type EventResponse struct { - BlockId string `json:"block_id"` - BlockHeight string `json:"block_height"` - BlockTimestamp time.Time `json:"block_timestamp"` - Events models.Events `json:"events"` - MessageIndex string `json:"message_index"` + models.BlockEvents // Embed BlockEvents struct to reuse its fields + MessageIndex string `json:"message_index"` } From 5c4f6721fe1b0dbebfb87365f39589934c652f13 Mon Sep 17 00:00:00 2001 From: UlyanaAndrukhiv Date: Thu, 12 Dec 2024 12:29:09 +0200 Subject: [PATCH 11/21] Added account statuses response build helper --- .../account_statuses_provider.go | 12 +++-------- .../account_statuses_provider_test.go | 11 +++------- .../models/account_statuses_response.go | 20 +++++++++++++++++++ .../{eventResponse.go => event_response.go} | 0 4 files changed, 26 insertions(+), 17 deletions(-) create mode 100644 engine/access/rest/websockets/models/account_statuses_response.go rename engine/access/rest/websockets/models/{eventResponse.go => event_response.go} (100%) diff --git a/engine/access/rest/websockets/data_providers/account_statuses_provider.go b/engine/access/rest/websockets/data_providers/account_statuses_provider.go index 2dc4dd0d39e..a9970ba8cb6 100644 --- a/engine/access/rest/websockets/data_providers/account_statuses_provider.go +++ b/engine/access/rest/websockets/data_providers/account_statuses_provider.go @@ -3,7 +3,6 @@ package data_providers import ( "context" "fmt" - "strconv" "github.com/rs/zerolog" "google.golang.org/grpc/codes" @@ -116,15 +115,10 @@ func (p *AccountStatusesDataProvider) handleResponse() func(accountStatusesRespo return status.Errorf(codes.Internal, "message index already incremented to %d", messageIndex.Value()) } - var accountEvents models.AccountEvents - accountEvents.Build(accountStatusesResponse.AccountEvents) + var response models.AccountStatusesResponse + response.Build(accountStatusesResponse, index) - p.send <- &models.AccountStatusesResponse{ - BlockID: accountStatusesResponse.BlockID.String(), - Height: strconv.FormatUint(accountStatusesResponse.Height, 10), - AccountEvents: accountEvents, - MessageIndex: strconv.FormatUint(index, 10), - } + p.send <- &response return nil } diff --git a/engine/access/rest/websockets/data_providers/account_statuses_provider_test.go b/engine/access/rest/websockets/data_providers/account_statuses_provider_test.go index 84380aa8b4b..b6b19872d12 100644 --- a/engine/access/rest/websockets/data_providers/account_statuses_provider_test.go +++ b/engine/access/rest/websockets/data_providers/account_statuses_provider_test.go @@ -10,7 +10,6 @@ import ( "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" - "github.com/onflow/flow-go/engine/access/rest/util" "github.com/onflow/flow-go/engine/access/rest/websockets/models" "github.com/onflow/flow-go/engine/access/state_stream" "github.com/onflow/flow-go/engine/access/state_stream/backend" @@ -287,14 +286,10 @@ func (s *AccountStatusesProviderSuite) expectedAccountStatusesResponses(events [ expectedResponses := make([]interface{}, len(events)) for i, resp := range backendResponses { - var accountEvents models.AccountEvents - accountEvents.Build(resp.AccountEvents) + var expectedResponse models.AccountStatusesResponse + expectedResponse.Build(resp, uint64(i)) - expectedResponses[i] = &models.AccountStatusesResponse{ - Height: util.FromUint(resp.Height), - BlockID: resp.BlockID.String(), - AccountEvents: accountEvents, - } + expectedResponses[i] = &expectedResponse } return expectedResponses diff --git a/engine/access/rest/websockets/models/account_statuses_response.go b/engine/access/rest/websockets/models/account_statuses_response.go new file mode 100644 index 00000000000..5598f7618fa --- /dev/null +++ b/engine/access/rest/websockets/models/account_statuses_response.go @@ -0,0 +1,20 @@ +package models + +import ( + "strconv" + + "github.com/onflow/flow-go/engine/access/state_stream/backend" +) + +// Build creates AccountStatusesResponse instance. +func (e *AccountStatusesResponse) Build(accountStatusesResponse *backend.AccountStatusesResponse, index uint64) { + var accountEvents AccountEvents + accountEvents.Build(accountStatusesResponse.AccountEvents) + + *e = AccountStatusesResponse{ + BlockID: accountStatusesResponse.BlockID.String(), + Height: strconv.FormatUint(accountStatusesResponse.Height, 10), + AccountEvents: accountEvents, + MessageIndex: strconv.FormatUint(index, 10), + } +} diff --git a/engine/access/rest/websockets/models/eventResponse.go b/engine/access/rest/websockets/models/event_response.go similarity index 100% rename from engine/access/rest/websockets/models/eventResponse.go rename to engine/access/rest/websockets/models/event_response.go From 3f2906f76688cb7d4bc8b88cc808e8d4be6a9021 Mon Sep 17 00:00:00 2001 From: UlyanaAndrukhiv Date: Thu, 12 Dec 2024 12:52:11 +0200 Subject: [PATCH 12/21] Updated unit tests to more readable --- .../data_providers/account_statuses_provider_test.go | 9 ++++----- .../websockets/data_providers/events_provider_test.go | 9 ++++----- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/engine/access/rest/websockets/data_providers/account_statuses_provider_test.go b/engine/access/rest/websockets/data_providers/account_statuses_provider_test.go index b6b19872d12..99aa6778744 100644 --- a/engine/access/rest/websockets/data_providers/account_statuses_provider_test.go +++ b/engine/access/rest/websockets/data_providers/account_statuses_provider_test.go @@ -74,7 +74,7 @@ func (s *AccountStatusesProviderSuite) TestAccountStatusesDataProvider_HappyPath s.T(), AccountStatusesTopic, s.factory, - s.subscribeAccountStatusesDataProviderTestCases(events, backendResponses), + s.subscribeAccountStatusesDataProviderTestCases(backendResponses), func(dataChan chan interface{}) { for i := 0; i < len(backendResponses); i++ { dataChan <- backendResponses[i] @@ -85,10 +85,9 @@ func (s *AccountStatusesProviderSuite) TestAccountStatusesDataProvider_HappyPath } func (s *AccountStatusesProviderSuite) subscribeAccountStatusesDataProviderTestCases( - events []flow.Event, backendResponses []*backend.AccountStatusesResponse, ) []testType { - expectedResponses := s.expectedAccountStatusesResponses(events, backendResponses) + expectedResponses := s.expectedAccountStatusesResponses(backendResponses) return []testType{ { @@ -282,8 +281,8 @@ func (s *AccountStatusesProviderSuite) backendAccountStatusesResponses(events [] } // expectedAccountStatusesResponses creates the expected responses for the provided events and backend responses. -func (s *AccountStatusesProviderSuite) expectedAccountStatusesResponses(events []flow.Event, backendResponses []*backend.AccountStatusesResponse) []interface{} { - expectedResponses := make([]interface{}, len(events)) +func (s *AccountStatusesProviderSuite) expectedAccountStatusesResponses(backendResponses []*backend.AccountStatusesResponse) []interface{} { + expectedResponses := make([]interface{}, len(backendResponses)) for i, resp := range backendResponses { var expectedResponse models.AccountStatusesResponse diff --git a/engine/access/rest/websockets/data_providers/events_provider_test.go b/engine/access/rest/websockets/data_providers/events_provider_test.go index 575e7695d0e..c0d914f7cdb 100644 --- a/engine/access/rest/websockets/data_providers/events_provider_test.go +++ b/engine/access/rest/websockets/data_providers/events_provider_test.go @@ -75,7 +75,7 @@ func (s *EventsProviderSuite) TestEventsDataProvider_HappyPath() { s.T(), EventsTopic, s.factory, - s.subscribeEventsDataProviderTestCases(events, backendResponses), + s.subscribeEventsDataProviderTestCases(backendResponses), func(dataChan chan interface{}) { for i := 0; i < len(backendResponses); i++ { dataChan <- backendResponses[i] @@ -86,8 +86,8 @@ func (s *EventsProviderSuite) TestEventsDataProvider_HappyPath() { } // subscribeEventsDataProviderTestCases generates test cases for events data providers. -func (s *EventsProviderSuite) subscribeEventsDataProviderTestCases(events []flow.Event, backendResponses []*backend.EventsResponse) []testType { - expectedResponses := s.expectedEventsResponses(events, backendResponses) +func (s *EventsProviderSuite) subscribeEventsDataProviderTestCases(backendResponses []*backend.EventsResponse) []testType { + expectedResponses := s.expectedEventsResponses(backendResponses) return []testType{ { @@ -309,10 +309,9 @@ func (s *EventsProviderSuite) backendEventsResponses(events []flow.Event) []*bac // expectedEventsResponses creates the expected responses for the provided events and backend responses. func (s *EventsProviderSuite) expectedEventsResponses( - events []flow.Event, backendResponses []*backend.EventsResponse, ) []interface{} { - expectedResponses := make([]interface{}, len(events)) + expectedResponses := make([]interface{}, len(backendResponses)) for i, resp := range backendResponses { var expectedResponse models.EventResponse From 1b21753ed26d33b8003e7ccd3763f804a0212cef Mon Sep 17 00:00:00 2001 From: UlyanaAndrukhiv Date: Wed, 18 Dec 2024 16:52:11 +0200 Subject: [PATCH 13/21] Expanded block response by execution result for websockets, added test --- engine/access/rest/server.go | 2 +- .../data_providers/blocks_provider.go | 28 +++++++++-- .../data_providers/blocks_provider_test.go | 50 +++++++++++++++++-- 3 files changed, 72 insertions(+), 8 deletions(-) diff --git a/engine/access/rest/server.go b/engine/access/rest/server.go index 6efcc65fb62..bfd92955144 100644 --- a/engine/access/rest/server.go +++ b/engine/access/rest/server.go @@ -58,7 +58,7 @@ func NewServer(serverAPI access.API, chain, stateStreamConfig.EventFilterConfig, stateStreamConfig.HeartbeatInterval, - builder.LinkGenerator, // TODO: guess how to avoid public LinkGenerator + builder.LinkGenerator, ) builder.AddWebsocketsRoute(chain, wsConfig, config.MaxRequestSize, dataProviderFactory) diff --git a/engine/access/rest/websockets/data_providers/blocks_provider.go b/engine/access/rest/websockets/data_providers/blocks_provider.go index 9aa56873a3d..f4f60aa8fd5 100644 --- a/engine/access/rest/websockets/data_providers/blocks_provider.go +++ b/engine/access/rest/websockets/data_providers/blocks_provider.go @@ -5,6 +5,8 @@ import ( "fmt" "github.com/rs/zerolog" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/engine/access/rest/common" @@ -79,8 +81,13 @@ func (p *BlocksDataProvider) Run() error { p.subscription, subscription.HandleResponse(p.send, func(b *flow.Block) (interface{}, error) { var block commonmodels.Block - //TODO: decide if execution result should be a part of response - err := block.Build(b, nil, p.linkGenerator, p.arguments.BlockStatus, p.arguments.Expand) + + executionResult, err := p.getExecutionResult(b) + if err != nil { + return nil, err + } + + err = block.Build(b, executionResult, p.linkGenerator, p.arguments.BlockStatus, p.arguments.Expand) if err != nil { return nil, fmt.Errorf("failed to build block response :%w", err) } @@ -92,6 +99,21 @@ func (p *BlocksDataProvider) Run() error { ) } +// getExecutionResult retrieves the execution result for the given block. +// If the execution result is not yet available, it returns a nil execution result and no error. +// +// No errors are expected during normal operations. +func (p *BlocksDataProvider) getExecutionResult(b *flow.Block) (*flow.ExecutionResult, error) { + executionResult, err := p.api.GetExecutionResultForBlockID(context.TODO(), b.ID()) + if err != nil { + if se, ok := status.FromError(err); ok && se.Code() == codes.NotFound { + return nil, nil // Execution result not yet available + } + return nil, fmt.Errorf("failed to get execution result for block: %s, %d: %w", b.ID(), b.Header.Height, err) + } + return executionResult, nil +} + // createSubscription creates a new subscription using the specified input arguments. func (p *BlocksDataProvider) createSubscription(ctx context.Context, args blocksArguments) subscription.Subscription { if args.StartBlockID != flow.ZeroID { @@ -161,7 +183,7 @@ func ParseBlocksArguments(arguments models.Arguments) (blocksArguments, error) { } // Parse 'expand' as a JSON array of string - // expected values: "payload" + // expected values: "payload", "execution_result" if expandIn, ok := arguments["expand"]; ok && expandIn != "" { result, ok := expandIn.([]string) if !ok { diff --git a/engine/access/rest/websockets/data_providers/blocks_provider_test.go b/engine/access/rest/websockets/data_providers/blocks_provider_test.go index d58f2a8b25d..8139b54707e 100644 --- a/engine/access/rest/websockets/data_providers/blocks_provider_test.go +++ b/engine/access/rest/websockets/data_providers/blocks_provider_test.go @@ -33,7 +33,9 @@ type BlocksProviderSuite struct { log zerolog.Logger api *accessmock.API - blocks []*flow.Block + blocks []*flow.Block + resultMap map[flow.Identifier]*flow.ExecutionResult + rootBlock flow.Block finalizedBlock *flow.Header @@ -52,6 +54,7 @@ func (s *BlocksProviderSuite) SetupTest() { blockCount := 5 s.blocks = make([]*flow.Block, 0, blockCount) + s.resultMap = make(map[flow.Identifier]*flow.ExecutionResult, blockCount) s.rootBlock = unittest.BlockFixture() s.rootBlock.Header.Height = 0 @@ -66,6 +69,7 @@ func (s *BlocksProviderSuite) SetupTest() { // update for next iteration parent = block.Header s.blocks = append(s.blocks, block) + s.resultMap[block.ID()] = unittest.ExecutionResultFixture(unittest.WithExecutionResultBlockID(block.ID())) } s.finalizedBlock = parent @@ -141,8 +145,9 @@ func (s *BlocksProviderSuite) TestBlocksDataProvider_InvalidArguments() { // validBlockArgumentsTestCases defines test happy cases for block data providers. // Each test case specifies input arguments, and setup functions for the mock API used in the test. func (s *BlocksProviderSuite) validBlockArgumentsTestCases() []testType { - expectedResponses := s.expectedBlockResponses(s.blocks, map[string]bool{}, flow.BlockStatusFinalized) - expectedPayloadExpandedResponse := s.expectedBlockResponses(s.blocks, map[string]bool{commonmodels.ExpandableFieldPayload: true}, flow.BlockStatusFinalized) + expectedResponses := s.expectedBlockResponses(s.blocks, s.resultMap, map[string]bool{}, flow.BlockStatusFinalized) + expectedPayloadExpandedResponse := s.expectedBlockResponses(s.blocks, s.resultMap, map[string]bool{commonmodels.ExpandableFieldPayload: true}, flow.BlockStatusFinalized) + expectedExecutionResultExpandedResponse := s.expectedBlockResponses(s.blocks, s.resultMap, map[string]bool{commonmodels.ExpandableExecutionResult: true}, flow.BlockStatusFinalized) return []testType{ { @@ -220,6 +225,21 @@ func (s *BlocksProviderSuite) validBlockArgumentsTestCases() []testType { }, expectedResponses: expectedPayloadExpandedResponse, }, + { + name: "happy path execution result expanded", + arguments: models.Arguments{ + "block_status": parser.Finalized, + "expand": []string{"execution_result"}, + }, + setupBackend: func(sub *statestreamsmock.Subscription) { + s.api.On( + "SubscribeBlocksFromLatest", + mock.Anything, + flow.BlockStatusFinalized, + ).Return(sub).Once() + }, + expectedResponses: expectedExecutionResultExpandedResponse, + }, } } @@ -250,6 +270,27 @@ func (s *BlocksProviderSuite) TestBlocksDataProvider_HappyPath() { }, ) + s.linkGenerator.On("ExecutionResultLink", mock.AnythingOfType("flow.Identifier")).Return( + func(id flow.Identifier) (string, error) { + for _, result := range s.resultMap { + if result.ID() == id { + return fmt.Sprintf("/v1/execution_results/%s", id), nil + } + } + return "", assert.AnError + }, + ) + + s.api.On("GetExecutionResultForBlockID", mock.Anything, mock.AnythingOfType("flow.Identifier")). + Return(func(ctx context.Context, blockId flow.Identifier) (*flow.ExecutionResult, error) { + for id, result := range s.resultMap { + if id == blockId { + return result, nil + } + } + return nil, assert.AnError + }) + testHappyPath( s.T(), BlocksTopic, @@ -278,13 +319,14 @@ func (s *BlocksProviderSuite) requireBlock(actual interface{}, expected interfac // expectedBlockResponses generates a list of expected block responses for the given blocks. func (s *BlocksProviderSuite) expectedBlockResponses( blocks []*flow.Block, + executionResults map[flow.Identifier]*flow.ExecutionResult, expand map[string]bool, status flow.BlockStatus, ) []interface{} { responses := make([]interface{}, len(blocks)) for i, b := range blocks { var block commonmodels.Block - err := block.Build(b, nil, s.linkGenerator, status, expand) + err := block.Build(b, executionResults[b.ID()], s.linkGenerator, status, expand) s.Require().NoError(err) responses[i] = &models.BlockMessageResponse{ From 275b16ee859cc3a05e0a0f33067dce1b44cf004a Mon Sep 17 00:00:00 2001 From: Andrii Date: Thu, 26 Dec 2024 16:45:50 +0200 Subject: [PATCH 14/21] Changed response to consostent for block provider --- .../rest/websockets/data_providers/blocks_provider.go | 9 +++++++-- .../websockets/data_providers/blocks_provider_test.go | 7 +++++-- engine/access/rest/websockets/models/base_message.go | 7 +++++++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/engine/access/rest/websockets/data_providers/blocks_provider.go b/engine/access/rest/websockets/data_providers/blocks_provider.go index 6c09c4a623a..43c9fcadfab 100644 --- a/engine/access/rest/websockets/data_providers/blocks_provider.go +++ b/engine/access/rest/websockets/data_providers/blocks_provider.go @@ -70,8 +70,13 @@ func (p *BlocksDataProvider) Run() error { return subscription.HandleSubscription( p.subscription, subscription.HandleResponse(p.send, func(block *flow.Block) (interface{}, error) { - return &models.BlockMessageResponse{ - Block: block, + + return &models.BaseDataProvidersResponse{ + ID: p.ID().String(), + Topic: p.Topic(), + Data: &models.BlockMessageResponse{ + Block: block, + }, }, nil }), ) diff --git a/engine/access/rest/websockets/data_providers/blocks_provider_test.go b/engine/access/rest/websockets/data_providers/blocks_provider_test.go index 85136ae5819..cefd2c51aa9 100644 --- a/engine/access/rest/websockets/data_providers/blocks_provider_test.go +++ b/engine/access/rest/websockets/data_providers/blocks_provider_test.go @@ -203,8 +203,11 @@ func (s *BlocksProviderSuite) requireBlock(v interface{}, expected interface{}) expectedBlock, ok := expected.(*flow.Block) require.True(s.T(), ok, "unexpected type: %T", v) - actualResponse, ok := v.(*models.BlockMessageResponse) + actualResponse, ok := v.(*models.BaseDataProvidersResponse) require.True(s.T(), ok, "unexpected response type: %T", v) - s.Require().Equal(expectedBlock, actualResponse.Block) + actualResponseBlock, ok := actualResponse.Data.(*models.BlockMessageResponse) + require.True(s.T(), ok, "unexpected response data type: %T", v) + + s.Require().Equal(expectedBlock, actualResponseBlock.Block) } diff --git a/engine/access/rest/websockets/models/base_message.go b/engine/access/rest/websockets/models/base_message.go index f56d62fda8f..5d9fe89a48d 100644 --- a/engine/access/rest/websockets/models/base_message.go +++ b/engine/access/rest/websockets/models/base_message.go @@ -11,3 +11,10 @@ type BaseMessageResponse struct { Success bool `json:"success"` // Indicates success or failure ErrorMessage string `json:"error_message,omitempty"` // Error message, if any } + +// BaseDataProvidersResponse represents a base structure for responses from subscriptions. +type BaseDataProvidersResponse struct { + ID string `json:"id"` // Unique subscription ID + Topic string `json:"topic"` // Topic of the subscription + Data interface{} `json:"data"` // Data that's being returned within a subscription. +} From 9d2a761dbea8475946872997ec0f684de4725331 Mon Sep 17 00:00:00 2001 From: Andrii Date: Fri, 27 Dec 2024 15:44:42 +0200 Subject: [PATCH 15/21] Changed responses to be consistant for all block data providers --- .../data_providers/block_digests_provider.go | 9 +++++++-- .../data_providers/block_digests_provider_test.go | 11 +++++++---- .../data_providers/block_headers_provider.go | 8 ++++++-- .../data_providers/block_headers_provider_test.go | 7 +++++-- .../rest/websockets/data_providers/blocks_provider.go | 1 - .../websockets/data_providers/blocks_provider_test.go | 4 ++-- 6 files changed, 27 insertions(+), 13 deletions(-) diff --git a/engine/access/rest/websockets/data_providers/block_digests_provider.go b/engine/access/rest/websockets/data_providers/block_digests_provider.go index 80307be6b64..5716aab940b 100644 --- a/engine/access/rest/websockets/data_providers/block_digests_provider.go +++ b/engine/access/rest/websockets/data_providers/block_digests_provider.go @@ -61,9 +61,14 @@ func (p *BlockDigestsDataProvider) Run() error { return subscription.HandleSubscription( p.subscription, subscription.HandleResponse(p.send, func(block *flow.BlockDigest) (interface{}, error) { - return &models.BlockDigestMessageResponse{ - Block: block, + return &models.BaseDataProvidersResponse{ + ID: p.ID().String(), + Topic: p.Topic(), + Data: &models.BlockDigestMessageResponse{ + Block: block, + }, }, nil + }), ) } diff --git a/engine/access/rest/websockets/data_providers/block_digests_provider_test.go b/engine/access/rest/websockets/data_providers/block_digests_provider_test.go index 975716c74af..975c1ce7fa8 100644 --- a/engine/access/rest/websockets/data_providers/block_digests_provider_test.go +++ b/engine/access/rest/websockets/data_providers/block_digests_provider_test.go @@ -126,10 +126,13 @@ func (s *BlocksProviderSuite) requireBlockDigest(v interface{}, expected interfa expectedBlock, ok := expected.(*flow.Block) require.True(s.T(), ok, "unexpected type: %T", v) - actualResponse, ok := v.(*models.BlockDigestMessageResponse) + actualResponse, ok := v.(*models.BaseDataProvidersResponse) require.True(s.T(), ok, "unexpected response type: %T", v) - s.Require().Equal(expectedBlock.Header.ID(), actualResponse.Block.ID()) - s.Require().Equal(expectedBlock.Header.Height, actualResponse.Block.Height) - s.Require().Equal(expectedBlock.Header.Timestamp, actualResponse.Block.Timestamp) + actualResponseData, ok := actualResponse.Data.(*models.BlockDigestMessageResponse) + require.True(s.T(), ok, "unexpected response data type: %T", v) + + s.Require().Equal(expectedBlock.Header.ID(), actualResponseData.Block.ID()) + s.Require().Equal(expectedBlock.Header.Height, actualResponseData.Block.Height) + s.Require().Equal(expectedBlock.Header.Timestamp, actualResponseData.Block.Timestamp) } diff --git a/engine/access/rest/websockets/data_providers/block_headers_provider.go b/engine/access/rest/websockets/data_providers/block_headers_provider.go index 4fddeb499f2..92d68a9402f 100644 --- a/engine/access/rest/websockets/data_providers/block_headers_provider.go +++ b/engine/access/rest/websockets/data_providers/block_headers_provider.go @@ -61,8 +61,12 @@ func (p *BlockHeadersDataProvider) Run() error { return subscription.HandleSubscription( p.subscription, subscription.HandleResponse(p.send, func(header *flow.Header) (interface{}, error) { - return &models.BlockHeaderMessageResponse{ - Header: header, + return &models.BaseDataProvidersResponse{ + ID: p.ID().String(), + Topic: p.Topic(), + Data: &models.BlockHeaderMessageResponse{ + Header: header, + }, }, nil }), ) diff --git a/engine/access/rest/websockets/data_providers/block_headers_provider_test.go b/engine/access/rest/websockets/data_providers/block_headers_provider_test.go index b929a46d076..0439c27cfa6 100644 --- a/engine/access/rest/websockets/data_providers/block_headers_provider_test.go +++ b/engine/access/rest/websockets/data_providers/block_headers_provider_test.go @@ -126,8 +126,11 @@ func (s *BlockHeadersProviderSuite) requireBlockHeader(v interface{}, expected i expectedBlock, ok := expected.(*flow.Block) require.True(s.T(), ok, "unexpected type: %T", v) - actualResponse, ok := v.(*models.BlockHeaderMessageResponse) + actualResponse, ok := v.(*models.BaseDataProvidersResponse) require.True(s.T(), ok, "unexpected response type: %T", v) - s.Require().Equal(expectedBlock.Header, actualResponse.Header) + actualResponseData, ok := actualResponse.Data.(*models.BlockHeaderMessageResponse) + require.True(s.T(), ok, "unexpected response data type: %T", v) + + s.Require().Equal(expectedBlock.Header, actualResponseData.Header) } diff --git a/engine/access/rest/websockets/data_providers/blocks_provider.go b/engine/access/rest/websockets/data_providers/blocks_provider.go index 43c9fcadfab..fb7f46a78c0 100644 --- a/engine/access/rest/websockets/data_providers/blocks_provider.go +++ b/engine/access/rest/websockets/data_providers/blocks_provider.go @@ -70,7 +70,6 @@ func (p *BlocksDataProvider) Run() error { return subscription.HandleSubscription( p.subscription, subscription.HandleResponse(p.send, func(block *flow.Block) (interface{}, error) { - return &models.BaseDataProvidersResponse{ ID: p.ID().String(), Topic: p.Topic(), diff --git a/engine/access/rest/websockets/data_providers/blocks_provider_test.go b/engine/access/rest/websockets/data_providers/blocks_provider_test.go index cefd2c51aa9..89d15b44a89 100644 --- a/engine/access/rest/websockets/data_providers/blocks_provider_test.go +++ b/engine/access/rest/websockets/data_providers/blocks_provider_test.go @@ -206,8 +206,8 @@ func (s *BlocksProviderSuite) requireBlock(v interface{}, expected interface{}) actualResponse, ok := v.(*models.BaseDataProvidersResponse) require.True(s.T(), ok, "unexpected response type: %T", v) - actualResponseBlock, ok := actualResponse.Data.(*models.BlockMessageResponse) + actualResponseData, ok := actualResponse.Data.(*models.BlockMessageResponse) require.True(s.T(), ok, "unexpected response data type: %T", v) - s.Require().Equal(expectedBlock, actualResponseBlock.Block) + s.Require().Equal(expectedBlock, actualResponseData.Block) } From aafcc4de2f3adb902caf9f1c75875c0079011f4d Mon Sep 17 00:00:00 2001 From: Andrii Date: Fri, 27 Dec 2024 15:53:27 +0200 Subject: [PATCH 16/21] Refactored response type of account statuses data provider --- .../account_statuses_provider.go | 21 ++++++++++++++----- .../account_statuses_provider_test.go | 19 ++++++++++------- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/engine/access/rest/websockets/data_providers/account_statuses_provider.go b/engine/access/rest/websockets/data_providers/account_statuses_provider.go index 396dcbc7b9a..99e0b85820e 100644 --- a/engine/access/rest/websockets/data_providers/account_statuses_provider.go +++ b/engine/access/rest/websockets/data_providers/account_statuses_provider.go @@ -116,11 +116,22 @@ func (p *AccountStatusesDataProvider) handleResponse() func(accountStatusesRespo return status.Errorf(codes.Internal, "message index already incremented to %d", messageIndex.Value()) } - p.send <- &models.AccountStatusesResponse{ - BlockID: accountStatusesResponse.BlockID.String(), - Height: strconv.FormatUint(accountStatusesResponse.Height, 10), - AccountEvents: accountStatusesResponse.AccountEvents, - MessageIndex: index, + //p.send <- &models.AccountStatusesResponse{ + // BlockID: accountStatusesResponse.BlockID.String(), + // Height: strconv.FormatUint(accountStatusesResponse.Height, 10), + // AccountEvents: accountStatusesResponse.AccountEvents, + // MessageIndex: index, + //} + + p.send <- &models.BaseDataProvidersResponse{ + ID: p.ID().String(), + Topic: p.Topic(), + Data: &models.AccountStatusesResponse{ + BlockID: accountStatusesResponse.BlockID.String(), + Height: strconv.FormatUint(accountStatusesResponse.Height, 10), + AccountEvents: accountStatusesResponse.AccountEvents, + MessageIndex: index, + }, } return nil diff --git a/engine/access/rest/websockets/data_providers/account_statuses_provider_test.go b/engine/access/rest/websockets/data_providers/account_statuses_provider_test.go index 8f689ca034a..a7be006be6e 100644 --- a/engine/access/rest/websockets/data_providers/account_statuses_provider_test.go +++ b/engine/access/rest/websockets/data_providers/account_statuses_provider_test.go @@ -146,14 +146,17 @@ func (s *AccountStatusesProviderSuite) requireAccountStatuses( expectedAccountStatusesResponse, ok := expectedResponse.(backend.AccountStatusesResponse) require.True(s.T(), ok, "unexpected type: %T", expectedResponse) - actualResponse, ok := v.(*models.AccountStatusesResponse) - require.True(s.T(), ok, "Expected *models.AccountStatusesResponse, got %T", v) + actualResponse, ok := v.(*models.BaseDataProvidersResponse) + require.True(s.T(), ok, "Expected *models.BaseDataProvidersResponse, got %T", v) - require.Equal(s.T(), expectedAccountStatusesResponse.BlockID.String(), actualResponse.BlockID) - require.Equal(s.T(), len(expectedAccountStatusesResponse.AccountEvents), len(actualResponse.AccountEvents)) + actualResponseData, ok := actualResponse.Data.(*models.AccountStatusesResponse) + require.True(s.T(), ok, "unexpected response data type: %T", v) + + require.Equal(s.T(), expectedAccountStatusesResponse.BlockID.String(), actualResponseData.BlockID) + require.Equal(s.T(), len(expectedAccountStatusesResponse.AccountEvents), len(actualResponseData.AccountEvents)) for key, expectedEvents := range expectedAccountStatusesResponse.AccountEvents { - actualEvents, ok := actualResponse.AccountEvents[key] + actualEvents, ok := actualResponseData.AccountEvents[key] require.True(s.T(), ok, "Missing key in actual AccountEvents: %s", key) s.Require().Equal(expectedEvents, actualEvents, "Mismatch for key: %s", key) @@ -249,9 +252,11 @@ func (s *AccountStatusesProviderSuite) TestMessageIndexAccountStatusesProviderRe var responses []*models.AccountStatusesResponse for i := 0; i < accountStatusesCount; i++ { res := <-send - accountStatusesRes, ok := res.(*models.AccountStatusesResponse) + accountStatusesRes, ok := res.(*models.BaseDataProvidersResponse) + s.Require().True(ok, "Expected *models.BaseDataProvidersResponse, got %T", res) + accountStatusesResData, ok := accountStatusesRes.Data.(*models.AccountStatusesResponse) s.Require().True(ok, "Expected *models.AccountStatusesResponse, got %T", res) - responses = append(responses, accountStatusesRes) + responses = append(responses, accountStatusesResData) } // Verifying that indices are starting from 0 From 453f8d72bb09ddaf14e27c3d2d6c246c4d580281 Mon Sep 17 00:00:00 2001 From: Andrii Date: Fri, 27 Dec 2024 16:03:01 +0200 Subject: [PATCH 17/21] Refactored respone type of events daya provider --- .../data_providers/account_statuses_provider.go | 7 ------- .../account_statuses_provider_test.go | 2 ++ .../websockets/data_providers/events_provider.go | 16 ++++++++++------ .../data_providers/events_provider_test.go | 15 +++++++++++---- 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/engine/access/rest/websockets/data_providers/account_statuses_provider.go b/engine/access/rest/websockets/data_providers/account_statuses_provider.go index 99e0b85820e..52b4a860122 100644 --- a/engine/access/rest/websockets/data_providers/account_statuses_provider.go +++ b/engine/access/rest/websockets/data_providers/account_statuses_provider.go @@ -116,13 +116,6 @@ func (p *AccountStatusesDataProvider) handleResponse() func(accountStatusesRespo return status.Errorf(codes.Internal, "message index already incremented to %d", messageIndex.Value()) } - //p.send <- &models.AccountStatusesResponse{ - // BlockID: accountStatusesResponse.BlockID.String(), - // Height: strconv.FormatUint(accountStatusesResponse.Height, 10), - // AccountEvents: accountStatusesResponse.AccountEvents, - // MessageIndex: index, - //} - p.send <- &models.BaseDataProvidersResponse{ ID: p.ID().String(), Topic: p.Topic(), diff --git a/engine/access/rest/websockets/data_providers/account_statuses_provider_test.go b/engine/access/rest/websockets/data_providers/account_statuses_provider_test.go index a7be006be6e..20a5e1d1a53 100644 --- a/engine/access/rest/websockets/data_providers/account_statuses_provider_test.go +++ b/engine/access/rest/websockets/data_providers/account_statuses_provider_test.go @@ -254,8 +254,10 @@ func (s *AccountStatusesProviderSuite) TestMessageIndexAccountStatusesProviderRe res := <-send accountStatusesRes, ok := res.(*models.BaseDataProvidersResponse) s.Require().True(ok, "Expected *models.BaseDataProvidersResponse, got %T", res) + accountStatusesResData, ok := accountStatusesRes.Data.(*models.AccountStatusesResponse) s.Require().True(ok, "Expected *models.AccountStatusesResponse, got %T", res) + responses = append(responses, accountStatusesResData) } diff --git a/engine/access/rest/websockets/data_providers/events_provider.go b/engine/access/rest/websockets/data_providers/events_provider.go index 318e8081d2c..ff925d9ba9c 100644 --- a/engine/access/rest/websockets/data_providers/events_provider.go +++ b/engine/access/rest/websockets/data_providers/events_provider.go @@ -102,12 +102,16 @@ func (p *EventsDataProvider) handleResponse() func(eventsResponse *backend.Event return fmt.Errorf("message index already incremented to: %d", messageIndex.Value()) } - p.send <- &models.EventResponse{ - BlockId: eventsResponse.BlockID.String(), - BlockHeight: strconv.FormatUint(eventsResponse.Height, 10), - BlockTimestamp: eventsResponse.BlockTimestamp, - Events: eventsResponse.Events, - MessageIndex: index, + p.send <- &models.BaseDataProvidersResponse{ + ID: p.ID().String(), + Topic: p.Topic(), + Data: &models.EventResponse{ + BlockId: eventsResponse.BlockID.String(), + BlockHeight: strconv.FormatUint(eventsResponse.Height, 10), + BlockTimestamp: eventsResponse.BlockTimestamp, + Events: eventsResponse.Events, + MessageIndex: index, + }, } return nil diff --git a/engine/access/rest/websockets/data_providers/events_provider_test.go b/engine/access/rest/websockets/data_providers/events_provider_test.go index 4902f3b35a6..6b75b9fa249 100644 --- a/engine/access/rest/websockets/data_providers/events_provider_test.go +++ b/engine/access/rest/websockets/data_providers/events_provider_test.go @@ -144,10 +144,13 @@ func (s *EventsProviderSuite) requireEvents(v interface{}, expectedResponse inte expectedEventsResponse, ok := expectedResponse.(backend.EventsResponse) require.True(s.T(), ok, "unexpected type: %T", expectedResponse) - actualResponse, ok := v.(*models.EventResponse) + actualResponse, ok := v.(*models.BaseDataProvidersResponse) require.True(s.T(), ok, "Expected *models.EventResponse, got %T", v) - s.Require().ElementsMatch(expectedEventsResponse.Events, actualResponse.Events) + actualResponseData, ok := actualResponse.Data.(*models.EventResponse) + require.True(s.T(), ok, "unexpected response data type: %T", v) + + s.Require().ElementsMatch(expectedEventsResponse.Events, actualResponseData.Events) } // invalidArgumentsTestCases returns a list of test cases with invalid argument combinations @@ -275,9 +278,13 @@ func (s *EventsProviderSuite) TestMessageIndexEventProviderResponse_HappyPath() var responses []*models.EventResponse for i := 0; i < eventsCount; i++ { res := <-send - eventRes, ok := res.(*models.EventResponse) + eventRes, ok := res.(*models.BaseDataProvidersResponse) + s.Require().True(ok, "Expected *models.BaseDataProvidersResponse, got %T", res) + + eventResData, ok := eventRes.Data.(*models.EventResponse) s.Require().True(ok, "Expected *models.EventResponse, got %T", res) - responses = append(responses, eventRes) + + responses = append(responses, eventResData) } // Verifying that indices are starting from 1 From 92016bebc0050cee8f727ae447234d1212ff5c79 Mon Sep 17 00:00:00 2001 From: Andrii Date: Fri, 27 Dec 2024 16:11:02 +0200 Subject: [PATCH 18/21] Refactored transaction statuses data providers --- ...d_and_get_transaction_statuses_provider.go | 10 +++++++--- ..._get_transaction_statuses_provider_test.go | 10 ++++++---- .../transaction_statuses_provider.go | 10 +++++++--- .../transaction_statuses_provider_test.go | 20 +++++++++++++------ 4 files changed, 34 insertions(+), 16 deletions(-) diff --git a/engine/access/rest/websockets/data_providers/send_and_get_transaction_statuses_provider.go b/engine/access/rest/websockets/data_providers/send_and_get_transaction_statuses_provider.go index f6db73ac4e0..8a85e5afb9c 100644 --- a/engine/access/rest/websockets/data_providers/send_and_get_transaction_statuses_provider.go +++ b/engine/access/rest/websockets/data_providers/send_and_get_transaction_statuses_provider.go @@ -93,9 +93,13 @@ func (p *SendAndGetTransactionStatusesDataProvider) handleResponse() func(txResu return status.Errorf(codes.Internal, "message index already incremented to %d", messageIndex.Value()) } - p.send <- &models.TransactionStatusesResponse{ - TransactionResult: txResults[i], - MessageIndex: index, + p.send <- &models.BaseDataProvidersResponse{ + ID: p.ID().String(), + Topic: p.Topic(), + Data: &models.TransactionStatusesResponse{ + TransactionResult: txResults[i], + MessageIndex: index, + }, } } diff --git a/engine/access/rest/websockets/data_providers/send_and_get_transaction_statuses_provider_test.go b/engine/access/rest/websockets/data_providers/send_and_get_transaction_statuses_provider_test.go index 1776d7a873a..da58d49ff2c 100644 --- a/engine/access/rest/websockets/data_providers/send_and_get_transaction_statuses_provider_test.go +++ b/engine/access/rest/websockets/data_providers/send_and_get_transaction_statuses_provider_test.go @@ -104,12 +104,14 @@ func (s *SendTransactionStatusesProviderSuite) requireTransactionStatuses( expectedTxStatusesResponse, ok := expectedResponse.(*access.TransactionResult) require.True(s.T(), ok, "unexpected type: %T", expectedResponse) - actualResponse, ok := v.(*models.TransactionStatusesResponse) - require.True(s.T(), ok, "Expected *models.TransactionStatusesResponse, got %T", v) + actualResponse, ok := v.(*models.BaseDataProvidersResponse) + require.True(s.T(), ok, "Expected *models.BaseDataProvidersResponse, got %T", v) - require.Equal(s.T(), expectedTxStatusesResponse.BlockID, actualResponse.TransactionResult.BlockID) - require.Equal(s.T(), expectedTxStatusesResponse.BlockHeight, actualResponse.TransactionResult.BlockHeight) + actualResponseData, ok := actualResponse.Data.(*models.TransactionStatusesResponse) + require.True(s.T(), ok, "unexpected response data type: %T", v) + require.Equal(s.T(), expectedTxStatusesResponse.BlockID, actualResponseData.TransactionResult.BlockID) + require.Equal(s.T(), expectedTxStatusesResponse.BlockHeight, actualResponseData.TransactionResult.BlockHeight) } // TestSendTransactionStatusesDataProvider_InvalidArguments tests the behavior of the send transaction statuses data provider diff --git a/engine/access/rest/websockets/data_providers/transaction_statuses_provider.go b/engine/access/rest/websockets/data_providers/transaction_statuses_provider.go index 3b75bde006a..2cfc3a37929 100644 --- a/engine/access/rest/websockets/data_providers/transaction_statuses_provider.go +++ b/engine/access/rest/websockets/data_providers/transaction_statuses_provider.go @@ -104,9 +104,13 @@ func (p *TransactionStatusesDataProvider) handleResponse() func(txResults []*acc return status.Errorf(codes.Internal, "message index already incremented to %d", messageIndex.Value()) } - p.send <- &models.TransactionStatusesResponse{ - TransactionResult: txResults[i], - MessageIndex: index, + p.send <- &models.BaseDataProvidersResponse{ + ID: p.ID().String(), + Topic: p.Topic(), + Data: &models.TransactionStatusesResponse{ + TransactionResult: txResults[i], + MessageIndex: index, + }, } } diff --git a/engine/access/rest/websockets/data_providers/transaction_statuses_provider_test.go b/engine/access/rest/websockets/data_providers/transaction_statuses_provider_test.go index c045553f4bc..3321f979554 100644 --- a/engine/access/rest/websockets/data_providers/transaction_statuses_provider_test.go +++ b/engine/access/rest/websockets/data_providers/transaction_statuses_provider_test.go @@ -134,11 +134,14 @@ func (s *TransactionStatusesProviderSuite) requireTransactionStatuses( expectedTxStatusesResponse, ok := expectedResponse.(*access.TransactionResult) require.True(s.T(), ok, "unexpected type: %T", expectedResponse) - actualResponse, ok := v.(*models.TransactionStatusesResponse) - require.True(s.T(), ok, "Expected *models.TransactionStatusesResponse, got %T", v) + actualResponse, ok := v.(*models.BaseDataProvidersResponse) + require.True(s.T(), ok, "Expected *models.BaseDataProvidersResponse, got %T", v) - require.Equal(s.T(), expectedTxStatusesResponse.BlockID, actualResponse.TransactionResult.BlockID) - require.Equal(s.T(), expectedTxStatusesResponse.BlockHeight, actualResponse.TransactionResult.BlockHeight) + actualResponseData, ok := actualResponse.Data.(*models.TransactionStatusesResponse) + require.True(s.T(), ok, "unexpected response data type: %T", v) + + require.Equal(s.T(), expectedTxStatusesResponse.BlockID, actualResponseData.TransactionResult.BlockID) + require.Equal(s.T(), expectedTxStatusesResponse.BlockHeight, actualResponseData.TransactionResult.BlockHeight) } // TestTransactionStatusesDataProvider_InvalidArguments tests the behavior of the transaction statuses data provider @@ -273,9 +276,14 @@ func (s *TransactionStatusesProviderSuite) TestMessageIndexTransactionStatusesPr var responses []*models.TransactionStatusesResponse for i := 0; i < txStatusesCount; i++ { res := <-send - txStatusesRes, ok := res.(*models.TransactionStatusesResponse) + + txStatusesRes, ok := res.(*models.BaseDataProvidersResponse) + s.Require().True(ok, "Expected *models.BaseDataProvidersResponse, got %T", res) + + txStatusesResData, ok := txStatusesRes.Data.(*models.TransactionStatusesResponse) s.Require().True(ok, "Expected *models.TransactionStatusesResponse, got %T", res) - responses = append(responses, txStatusesRes) + + responses = append(responses, txStatusesResData) } // Verifying that indices are starting from 0 From 526b2486227fc81578541ec90b04add6c60fa2bb Mon Sep 17 00:00:00 2001 From: UlyanaAndrukhiv Date: Thu, 2 Jan 2025 20:01:19 +0200 Subject: [PATCH 19/21] Removed expand argument from websocket blocks subscription, removed execution result from response, added payload to result --- .../data_providers/blocks_provider.go | 38 +--------- .../data_providers/blocks_provider_test.go | 74 +------------------ 2 files changed, 5 insertions(+), 107 deletions(-) diff --git a/engine/access/rest/websockets/data_providers/blocks_provider.go b/engine/access/rest/websockets/data_providers/blocks_provider.go index e3b7ec2fd76..3de10f2cd95 100644 --- a/engine/access/rest/websockets/data_providers/blocks_provider.go +++ b/engine/access/rest/websockets/data_providers/blocks_provider.go @@ -5,11 +5,8 @@ import ( "fmt" "github.com/rs/zerolog" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" "github.com/onflow/flow-go/access" - "github.com/onflow/flow-go/engine/access/rest/common" commonmodels "github.com/onflow/flow-go/engine/access/rest/common/models" "github.com/onflow/flow-go/engine/access/rest/common/parser" "github.com/onflow/flow-go/engine/access/rest/http/request" @@ -24,7 +21,6 @@ type blocksArguments struct { StartBlockID flow.Identifier // ID of the block to start subscription from StartBlockHeight uint64 // Height of the block to start subscription from BlockStatus flow.BlockStatus // Status of blocks to subscribe to - Expand map[string]bool } // BlocksDataProvider is responsible for providing blocks @@ -82,12 +78,8 @@ func (p *BlocksDataProvider) Run() error { subscription.HandleResponse(p.send, func(b *flow.Block) (interface{}, error) { var block commonmodels.Block - executionResult, err := p.getExecutionResult(b) - if err != nil { - return nil, err - } - - err = block.Build(b, executionResult, p.linkGenerator, p.arguments.BlockStatus, p.arguments.Expand) + expandPayload := map[string]bool{commonmodels.ExpandableFieldPayload: true} + err := block.Build(b, nil, p.linkGenerator, p.arguments.BlockStatus, expandPayload) if err != nil { return nil, fmt.Errorf("failed to build block response :%w", err) } @@ -99,21 +91,6 @@ func (p *BlocksDataProvider) Run() error { ) } -// getExecutionResult retrieves the execution result for the given block. -// If the execution result is not yet available, it returns a nil execution result and no error. -// -// No errors are expected during normal operations. -func (p *BlocksDataProvider) getExecutionResult(b *flow.Block) (*flow.ExecutionResult, error) { - executionResult, err := p.api.GetExecutionResultForBlockID(context.TODO(), b.ID()) - if err != nil { - if se, ok := status.FromError(err); ok && se.Code() == codes.NotFound { - return nil, nil // Execution result not yet available - } - return nil, fmt.Errorf("failed to get execution result for block: %s, %d: %w", b.ID(), b.Header.Height, err) - } - return executionResult, nil -} - // createSubscription creates a new subscription using the specified input arguments. func (p *BlocksDataProvider) createSubscription(ctx context.Context, args blocksArguments) subscription.Subscription { if args.StartBlockID != flow.ZeroID { @@ -154,17 +131,6 @@ func ParseBlocksArguments(arguments models.Arguments) (blocksArguments, error) { args.StartBlockID = startBlockID args.StartBlockHeight = startBlockHeight - // Parse 'expand' as a JSON array of string - // expected values: "payload", "execution_result" - if expandIn, ok := arguments["expand"]; ok && expandIn != "" { - result, ok := expandIn.([]string) - if !ok { - return args, fmt.Errorf("'expand' must be an array of string") - } - - args.Expand = common.SliceToMap(result) - } - return args, nil } diff --git a/engine/access/rest/websockets/data_providers/blocks_provider_test.go b/engine/access/rest/websockets/data_providers/blocks_provider_test.go index 8139b54707e..e73dc99df1d 100644 --- a/engine/access/rest/websockets/data_providers/blocks_provider_test.go +++ b/engine/access/rest/websockets/data_providers/blocks_provider_test.go @@ -33,8 +33,7 @@ type BlocksProviderSuite struct { log zerolog.Logger api *accessmock.API - blocks []*flow.Block - resultMap map[flow.Identifier]*flow.ExecutionResult + blocks []*flow.Block rootBlock flow.Block finalizedBlock *flow.Header @@ -54,7 +53,6 @@ func (s *BlocksProviderSuite) SetupTest() { blockCount := 5 s.blocks = make([]*flow.Block, 0, blockCount) - s.resultMap = make(map[flow.Identifier]*flow.ExecutionResult, blockCount) s.rootBlock = unittest.BlockFixture() s.rootBlock.Header.Height = 0 @@ -69,7 +67,6 @@ func (s *BlocksProviderSuite) SetupTest() { // update for next iteration parent = block.Header s.blocks = append(s.blocks, block) - s.resultMap[block.ID()] = unittest.ExecutionResultFixture(unittest.WithExecutionResultBlockID(block.ID())) } s.finalizedBlock = parent @@ -145,9 +142,7 @@ func (s *BlocksProviderSuite) TestBlocksDataProvider_InvalidArguments() { // validBlockArgumentsTestCases defines test happy cases for block data providers. // Each test case specifies input arguments, and setup functions for the mock API used in the test. func (s *BlocksProviderSuite) validBlockArgumentsTestCases() []testType { - expectedResponses := s.expectedBlockResponses(s.blocks, s.resultMap, map[string]bool{}, flow.BlockStatusFinalized) - expectedPayloadExpandedResponse := s.expectedBlockResponses(s.blocks, s.resultMap, map[string]bool{commonmodels.ExpandableFieldPayload: true}, flow.BlockStatusFinalized) - expectedExecutionResultExpandedResponse := s.expectedBlockResponses(s.blocks, s.resultMap, map[string]bool{commonmodels.ExpandableExecutionResult: true}, flow.BlockStatusFinalized) + expectedResponses := s.expectedBlockResponses(s.blocks, map[string]bool{commonmodels.ExpandableFieldPayload: true}, flow.BlockStatusFinalized) return []testType{ { @@ -210,36 +205,6 @@ func (s *BlocksProviderSuite) validBlockArgumentsTestCases() []testType { }, expectedResponses: expectedResponses, }, - { - name: "happy path payload expanded", - arguments: models.Arguments{ - "block_status": parser.Finalized, - "expand": []string{"payload"}, - }, - setupBackend: func(sub *statestreamsmock.Subscription) { - s.api.On( - "SubscribeBlocksFromLatest", - mock.Anything, - flow.BlockStatusFinalized, - ).Return(sub).Once() - }, - expectedResponses: expectedPayloadExpandedResponse, - }, - { - name: "happy path execution result expanded", - arguments: models.Arguments{ - "block_status": parser.Finalized, - "expand": []string{"execution_result"}, - }, - setupBackend: func(sub *statestreamsmock.Subscription) { - s.api.On( - "SubscribeBlocksFromLatest", - mock.Anything, - flow.BlockStatusFinalized, - ).Return(sub).Once() - }, - expectedResponses: expectedExecutionResultExpandedResponse, - }, } } @@ -259,38 +224,6 @@ func (s *BlocksProviderSuite) TestBlocksDataProvider_HappyPath() { }, ) - s.linkGenerator.On("PayloadLink", mock.AnythingOfType("flow.Identifier")).Return( - func(id flow.Identifier) (string, error) { - for _, block := range s.blocks { - if block.ID() == id { - return fmt.Sprintf("/v1/blocks/%s/payload", id), nil - } - } - return "", assert.AnError - }, - ) - - s.linkGenerator.On("ExecutionResultLink", mock.AnythingOfType("flow.Identifier")).Return( - func(id flow.Identifier) (string, error) { - for _, result := range s.resultMap { - if result.ID() == id { - return fmt.Sprintf("/v1/execution_results/%s", id), nil - } - } - return "", assert.AnError - }, - ) - - s.api.On("GetExecutionResultForBlockID", mock.Anything, mock.AnythingOfType("flow.Identifier")). - Return(func(ctx context.Context, blockId flow.Identifier) (*flow.ExecutionResult, error) { - for id, result := range s.resultMap { - if id == blockId { - return result, nil - } - } - return nil, assert.AnError - }) - testHappyPath( s.T(), BlocksTopic, @@ -319,14 +252,13 @@ func (s *BlocksProviderSuite) requireBlock(actual interface{}, expected interfac // expectedBlockResponses generates a list of expected block responses for the given blocks. func (s *BlocksProviderSuite) expectedBlockResponses( blocks []*flow.Block, - executionResults map[flow.Identifier]*flow.ExecutionResult, expand map[string]bool, status flow.BlockStatus, ) []interface{} { responses := make([]interface{}, len(blocks)) for i, b := range blocks { var block commonmodels.Block - err := block.Build(b, executionResults[b.ID()], s.linkGenerator, status, expand) + err := block.Build(b, nil, s.linkGenerator, status, expand) s.Require().NoError(err) responses[i] = &models.BlockMessageResponse{ From 4c3e5ae9963c7715caabf0660b8b3dc03510906e Mon Sep 17 00:00:00 2001 From: Andrii Date: Fri, 3 Jan 2025 11:57:03 +0200 Subject: [PATCH 20/21] Renamed fields naming --- .../websockets/data_providers/account_statuses_provider.go | 6 +++--- .../data_providers/account_statuses_provider_test.go | 4 ++-- .../websockets/data_providers/block_digests_provider.go | 6 +++--- .../data_providers/block_digests_provider_test.go | 2 +- .../websockets/data_providers/block_headers_provider.go | 6 +++--- .../data_providers/block_headers_provider_test.go | 2 +- .../rest/websockets/data_providers/blocks_provider.go | 6 +++--- .../rest/websockets/data_providers/blocks_provider_test.go | 2 +- .../rest/websockets/data_providers/events_provider.go | 6 +++--- .../rest/websockets/data_providers/events_provider_test.go | 4 ++-- .../send_and_get_transaction_statuses_provider.go | 6 +++--- .../send_and_get_transaction_statuses_provider_test.go | 2 +- .../data_providers/transaction_statuses_provider.go | 6 +++--- .../data_providers/transaction_statuses_provider_test.go | 4 ++-- engine/access/rest/websockets/models/base_message.go | 6 +++--- 15 files changed, 34 insertions(+), 34 deletions(-) diff --git a/engine/access/rest/websockets/data_providers/account_statuses_provider.go b/engine/access/rest/websockets/data_providers/account_statuses_provider.go index 52b4a860122..d33c3374d74 100644 --- a/engine/access/rest/websockets/data_providers/account_statuses_provider.go +++ b/engine/access/rest/websockets/data_providers/account_statuses_provider.go @@ -117,9 +117,9 @@ func (p *AccountStatusesDataProvider) handleResponse() func(accountStatusesRespo } p.send <- &models.BaseDataProvidersResponse{ - ID: p.ID().String(), - Topic: p.Topic(), - Data: &models.AccountStatusesResponse{ + SubscriptionID: p.ID().String(), + Topic: p.Topic(), + Payload: &models.AccountStatusesResponse{ BlockID: accountStatusesResponse.BlockID.String(), Height: strconv.FormatUint(accountStatusesResponse.Height, 10), AccountEvents: accountStatusesResponse.AccountEvents, diff --git a/engine/access/rest/websockets/data_providers/account_statuses_provider_test.go b/engine/access/rest/websockets/data_providers/account_statuses_provider_test.go index eeb5348b171..30e71becd49 100644 --- a/engine/access/rest/websockets/data_providers/account_statuses_provider_test.go +++ b/engine/access/rest/websockets/data_providers/account_statuses_provider_test.go @@ -149,7 +149,7 @@ func (s *AccountStatusesProviderSuite) requireAccountStatuses( actualResponse, ok := v.(*models.BaseDataProvidersResponse) require.True(s.T(), ok, "Expected *models.BaseDataProvidersResponse, got %T", v) - actualResponseData, ok := actualResponse.Data.(*models.AccountStatusesResponse) + actualResponseData, ok := actualResponse.Payload.(*models.AccountStatusesResponse) require.True(s.T(), ok, "unexpected response data type: %T", v) require.Equal(s.T(), expectedAccountStatusesResponse.BlockID.String(), actualResponseData.BlockID) @@ -258,7 +258,7 @@ func (s *AccountStatusesProviderSuite) TestMessageIndexAccountStatusesProviderRe accountStatusesRes, ok := res.(*models.BaseDataProvidersResponse) s.Require().True(ok, "Expected *models.BaseDataProvidersResponse, got %T", res) - accountStatusesResData, ok := accountStatusesRes.Data.(*models.AccountStatusesResponse) + accountStatusesResData, ok := accountStatusesRes.Payload.(*models.AccountStatusesResponse) s.Require().True(ok, "Expected *models.AccountStatusesResponse, got %T", res) responses = append(responses, accountStatusesResData) diff --git a/engine/access/rest/websockets/data_providers/block_digests_provider.go b/engine/access/rest/websockets/data_providers/block_digests_provider.go index 5716aab940b..78d8233d79a 100644 --- a/engine/access/rest/websockets/data_providers/block_digests_provider.go +++ b/engine/access/rest/websockets/data_providers/block_digests_provider.go @@ -62,9 +62,9 @@ func (p *BlockDigestsDataProvider) Run() error { p.subscription, subscription.HandleResponse(p.send, func(block *flow.BlockDigest) (interface{}, error) { return &models.BaseDataProvidersResponse{ - ID: p.ID().String(), - Topic: p.Topic(), - Data: &models.BlockDigestMessageResponse{ + SubscriptionID: p.ID().String(), + Topic: p.Topic(), + Payload: &models.BlockDigestMessageResponse{ Block: block, }, }, nil diff --git a/engine/access/rest/websockets/data_providers/block_digests_provider_test.go b/engine/access/rest/websockets/data_providers/block_digests_provider_test.go index 975c1ce7fa8..8b774374502 100644 --- a/engine/access/rest/websockets/data_providers/block_digests_provider_test.go +++ b/engine/access/rest/websockets/data_providers/block_digests_provider_test.go @@ -129,7 +129,7 @@ func (s *BlocksProviderSuite) requireBlockDigest(v interface{}, expected interfa actualResponse, ok := v.(*models.BaseDataProvidersResponse) require.True(s.T(), ok, "unexpected response type: %T", v) - actualResponseData, ok := actualResponse.Data.(*models.BlockDigestMessageResponse) + actualResponseData, ok := actualResponse.Payload.(*models.BlockDigestMessageResponse) require.True(s.T(), ok, "unexpected response data type: %T", v) s.Require().Equal(expectedBlock.Header.ID(), actualResponseData.Block.ID()) diff --git a/engine/access/rest/websockets/data_providers/block_headers_provider.go b/engine/access/rest/websockets/data_providers/block_headers_provider.go index 92d68a9402f..a13c2e360d4 100644 --- a/engine/access/rest/websockets/data_providers/block_headers_provider.go +++ b/engine/access/rest/websockets/data_providers/block_headers_provider.go @@ -62,9 +62,9 @@ func (p *BlockHeadersDataProvider) Run() error { p.subscription, subscription.HandleResponse(p.send, func(header *flow.Header) (interface{}, error) { return &models.BaseDataProvidersResponse{ - ID: p.ID().String(), - Topic: p.Topic(), - Data: &models.BlockHeaderMessageResponse{ + SubscriptionID: p.ID().String(), + Topic: p.Topic(), + Payload: &models.BlockHeaderMessageResponse{ Header: header, }, }, nil diff --git a/engine/access/rest/websockets/data_providers/block_headers_provider_test.go b/engine/access/rest/websockets/data_providers/block_headers_provider_test.go index 0439c27cfa6..62c9ece05b8 100644 --- a/engine/access/rest/websockets/data_providers/block_headers_provider_test.go +++ b/engine/access/rest/websockets/data_providers/block_headers_provider_test.go @@ -129,7 +129,7 @@ func (s *BlockHeadersProviderSuite) requireBlockHeader(v interface{}, expected i actualResponse, ok := v.(*models.BaseDataProvidersResponse) require.True(s.T(), ok, "unexpected response type: %T", v) - actualResponseData, ok := actualResponse.Data.(*models.BlockHeaderMessageResponse) + actualResponseData, ok := actualResponse.Payload.(*models.BlockHeaderMessageResponse) require.True(s.T(), ok, "unexpected response data type: %T", v) s.Require().Equal(expectedBlock.Header, actualResponseData.Header) diff --git a/engine/access/rest/websockets/data_providers/blocks_provider.go b/engine/access/rest/websockets/data_providers/blocks_provider.go index fb7f46a78c0..e1203d1fb61 100644 --- a/engine/access/rest/websockets/data_providers/blocks_provider.go +++ b/engine/access/rest/websockets/data_providers/blocks_provider.go @@ -71,9 +71,9 @@ func (p *BlocksDataProvider) Run() error { p.subscription, subscription.HandleResponse(p.send, func(block *flow.Block) (interface{}, error) { return &models.BaseDataProvidersResponse{ - ID: p.ID().String(), - Topic: p.Topic(), - Data: &models.BlockMessageResponse{ + SubscriptionID: p.ID().String(), + Topic: p.Topic(), + Payload: &models.BlockMessageResponse{ Block: block, }, }, nil diff --git a/engine/access/rest/websockets/data_providers/blocks_provider_test.go b/engine/access/rest/websockets/data_providers/blocks_provider_test.go index 89d15b44a89..774448182ae 100644 --- a/engine/access/rest/websockets/data_providers/blocks_provider_test.go +++ b/engine/access/rest/websockets/data_providers/blocks_provider_test.go @@ -206,7 +206,7 @@ func (s *BlocksProviderSuite) requireBlock(v interface{}, expected interface{}) actualResponse, ok := v.(*models.BaseDataProvidersResponse) require.True(s.T(), ok, "unexpected response type: %T", v) - actualResponseData, ok := actualResponse.Data.(*models.BlockMessageResponse) + actualResponseData, ok := actualResponse.Payload.(*models.BlockMessageResponse) require.True(s.T(), ok, "unexpected response data type: %T", v) s.Require().Equal(expectedBlock, actualResponseData.Block) diff --git a/engine/access/rest/websockets/data_providers/events_provider.go b/engine/access/rest/websockets/data_providers/events_provider.go index ff925d9ba9c..afe7f0de329 100644 --- a/engine/access/rest/websockets/data_providers/events_provider.go +++ b/engine/access/rest/websockets/data_providers/events_provider.go @@ -103,9 +103,9 @@ func (p *EventsDataProvider) handleResponse() func(eventsResponse *backend.Event } p.send <- &models.BaseDataProvidersResponse{ - ID: p.ID().String(), - Topic: p.Topic(), - Data: &models.EventResponse{ + SubscriptionID: p.ID().String(), + Topic: p.Topic(), + Payload: &models.EventResponse{ BlockId: eventsResponse.BlockID.String(), BlockHeight: strconv.FormatUint(eventsResponse.Height, 10), BlockTimestamp: eventsResponse.BlockTimestamp, diff --git a/engine/access/rest/websockets/data_providers/events_provider_test.go b/engine/access/rest/websockets/data_providers/events_provider_test.go index b3ea709ab9e..ea84df5349a 100644 --- a/engine/access/rest/websockets/data_providers/events_provider_test.go +++ b/engine/access/rest/websockets/data_providers/events_provider_test.go @@ -147,7 +147,7 @@ func (s *EventsProviderSuite) requireEvents(v interface{}, expectedResponse inte actualResponse, ok := v.(*models.BaseDataProvidersResponse) require.True(s.T(), ok, "Expected *models.EventResponse, got %T", v) - actualResponseData, ok := actualResponse.Data.(*models.EventResponse) + actualResponseData, ok := actualResponse.Payload.(*models.EventResponse) require.True(s.T(), ok, "unexpected response data type: %T", v) s.Require().ElementsMatch(expectedEventsResponse.Events, actualResponseData.Events) @@ -285,7 +285,7 @@ func (s *EventsProviderSuite) TestMessageIndexEventProviderResponse_HappyPath() eventRes, ok := res.(*models.BaseDataProvidersResponse) s.Require().True(ok, "Expected *models.BaseDataProvidersResponse, got %T", res) - eventResData, ok := eventRes.Data.(*models.EventResponse) + eventResData, ok := eventRes.Payload.(*models.EventResponse) s.Require().True(ok, "Expected *models.EventResponse, got %T", res) responses = append(responses, eventResData) diff --git a/engine/access/rest/websockets/data_providers/send_and_get_transaction_statuses_provider.go b/engine/access/rest/websockets/data_providers/send_and_get_transaction_statuses_provider.go index 8a85e5afb9c..0384ecd80e0 100644 --- a/engine/access/rest/websockets/data_providers/send_and_get_transaction_statuses_provider.go +++ b/engine/access/rest/websockets/data_providers/send_and_get_transaction_statuses_provider.go @@ -94,9 +94,9 @@ func (p *SendAndGetTransactionStatusesDataProvider) handleResponse() func(txResu } p.send <- &models.BaseDataProvidersResponse{ - ID: p.ID().String(), - Topic: p.Topic(), - Data: &models.TransactionStatusesResponse{ + SubscriptionID: p.ID().String(), + Topic: p.Topic(), + Payload: &models.TransactionStatusesResponse{ TransactionResult: txResults[i], MessageIndex: index, }, diff --git a/engine/access/rest/websockets/data_providers/send_and_get_transaction_statuses_provider_test.go b/engine/access/rest/websockets/data_providers/send_and_get_transaction_statuses_provider_test.go index da58d49ff2c..b4e58ce6122 100644 --- a/engine/access/rest/websockets/data_providers/send_and_get_transaction_statuses_provider_test.go +++ b/engine/access/rest/websockets/data_providers/send_and_get_transaction_statuses_provider_test.go @@ -107,7 +107,7 @@ func (s *SendTransactionStatusesProviderSuite) requireTransactionStatuses( actualResponse, ok := v.(*models.BaseDataProvidersResponse) require.True(s.T(), ok, "Expected *models.BaseDataProvidersResponse, got %T", v) - actualResponseData, ok := actualResponse.Data.(*models.TransactionStatusesResponse) + actualResponseData, ok := actualResponse.Payload.(*models.TransactionStatusesResponse) require.True(s.T(), ok, "unexpected response data type: %T", v) require.Equal(s.T(), expectedTxStatusesResponse.BlockID, actualResponseData.TransactionResult.BlockID) diff --git a/engine/access/rest/websockets/data_providers/transaction_statuses_provider.go b/engine/access/rest/websockets/data_providers/transaction_statuses_provider.go index 2cfc3a37929..3a65f27be12 100644 --- a/engine/access/rest/websockets/data_providers/transaction_statuses_provider.go +++ b/engine/access/rest/websockets/data_providers/transaction_statuses_provider.go @@ -105,9 +105,9 @@ func (p *TransactionStatusesDataProvider) handleResponse() func(txResults []*acc } p.send <- &models.BaseDataProvidersResponse{ - ID: p.ID().String(), - Topic: p.Topic(), - Data: &models.TransactionStatusesResponse{ + SubscriptionID: p.ID().String(), + Topic: p.Topic(), + Payload: &models.TransactionStatusesResponse{ TransactionResult: txResults[i], MessageIndex: index, }, diff --git a/engine/access/rest/websockets/data_providers/transaction_statuses_provider_test.go b/engine/access/rest/websockets/data_providers/transaction_statuses_provider_test.go index 94d6371cdbd..7a9bcdbedd8 100644 --- a/engine/access/rest/websockets/data_providers/transaction_statuses_provider_test.go +++ b/engine/access/rest/websockets/data_providers/transaction_statuses_provider_test.go @@ -137,7 +137,7 @@ func (s *TransactionStatusesProviderSuite) requireTransactionStatuses( actualResponse, ok := v.(*models.BaseDataProvidersResponse) require.True(s.T(), ok, "Expected *models.BaseDataProvidersResponse, got %T", v) - actualResponseData, ok := actualResponse.Data.(*models.TransactionStatusesResponse) + actualResponseData, ok := actualResponse.Payload.(*models.TransactionStatusesResponse) require.True(s.T(), ok, "unexpected response data type: %T", v) require.Equal(s.T(), expectedTxStatusesResponse.BlockID, actualResponseData.TransactionResult.BlockID) @@ -284,7 +284,7 @@ func (s *TransactionStatusesProviderSuite) TestMessageIndexTransactionStatusesPr txStatusesRes, ok := res.(*models.BaseDataProvidersResponse) s.Require().True(ok, "Expected *models.BaseDataProvidersResponse, got %T", res) - txStatusesResData, ok := txStatusesRes.Data.(*models.TransactionStatusesResponse) + txStatusesResData, ok := txStatusesRes.Payload.(*models.TransactionStatusesResponse) s.Require().True(ok, "Expected *models.TransactionStatusesResponse, got %T", res) responses = append(responses, txStatusesResData) diff --git a/engine/access/rest/websockets/models/base_message.go b/engine/access/rest/websockets/models/base_message.go index ae694c68652..1e62f4fc828 100644 --- a/engine/access/rest/websockets/models/base_message.go +++ b/engine/access/rest/websockets/models/base_message.go @@ -22,7 +22,7 @@ type BaseMessageResponse struct { // BaseDataProvidersResponse represents a base structure for responses from subscriptions. type BaseDataProvidersResponse struct { - ID string `json:"id"` // Unique subscription ID - Topic string `json:"topic"` // Topic of the subscription - Data interface{} `json:"data"` // Data that's being returned within a subscription. + SubscriptionID string `json:"subscription_id"` // Unique subscriptionID + Topic string `json:"topic"` // Topic of the subscription + Payload interface{} `json:"payload"` // Payload that's being returned within a subscription. } From 5d8189c5c3353de6f6106abd3551ab38f1d72a0b Mon Sep 17 00:00:00 2001 From: Andrii Date: Tue, 7 Jan 2025 16:33:50 +0200 Subject: [PATCH 21/21] Chanaged expected types in data provider tests to be consistent, added topic check in tests --- .../account_statuses_provider.go | 4 +-- .../account_statuses_provider_test.go | 29 ++++++++++++------- .../data_providers/base_provider.go | 16 +++++----- .../data_providers/block_digests_provider.go | 4 +-- .../block_digests_provider_test.go | 8 ++--- .../data_providers/block_headers_provider.go | 4 +-- .../block_headers_provider_test.go | 10 +++---- .../data_providers/blocks_provider.go | 4 +-- .../data_providers/blocks_provider_test.go | 6 ++-- .../data_providers/events_provider.go | 4 +-- .../data_providers/events_provider_test.go | 22 +++++++++----- ...d_and_get_transaction_statuses_provider.go | 4 +-- ..._get_transaction_statuses_provider_test.go | 14 +++++---- .../transaction_statuses_provider.go | 4 +-- .../transaction_statuses_provider_test.go | 24 ++++++++++----- .../rest/websockets/models/base_message.go | 2 +- 16 files changed, 91 insertions(+), 68 deletions(-) diff --git a/engine/access/rest/websockets/data_providers/account_statuses_provider.go b/engine/access/rest/websockets/data_providers/account_statuses_provider.go index 3607a7f3de1..182db1cc0d7 100644 --- a/engine/access/rest/websockets/data_providers/account_statuses_provider.go +++ b/engine/access/rest/websockets/data_providers/account_statuses_provider.go @@ -26,7 +26,7 @@ type accountStatusesArguments struct { } type AccountStatusesDataProvider struct { - *BaseDataProvider + *baseDataProvider logger zerolog.Logger stateStreamApi state_stream.API @@ -62,7 +62,7 @@ func NewAccountStatusesDataProvider( subCtx, cancel := context.WithCancel(ctx) - p.BaseDataProvider = newBaseDataProvider( + p.baseDataProvider = newBaseDataProvider( topic, cancel, send, diff --git a/engine/access/rest/websockets/data_providers/account_statuses_provider_test.go b/engine/access/rest/websockets/data_providers/account_statuses_provider_test.go index 5db1b86b61f..eb12fc615ca 100644 --- a/engine/access/rest/websockets/data_providers/account_statuses_provider_test.go +++ b/engine/access/rest/websockets/data_providers/account_statuses_provider_test.go @@ -138,21 +138,25 @@ func (s *AccountStatusesProviderSuite) subscribeAccountStatusesDataProviderTestC // requireAccountStatuses ensures that the received account statuses information matches the expected data. func (s *AccountStatusesProviderSuite) requireAccountStatuses(actual interface{}, expected interface{}) { - expectedResponse, ok := expected.(*models.AccountStatusesResponse) - require.True(s.T(), ok, "Expected *models.AccountStatusesResponse, got %T", expected) + expectedResponse, ok := expected.(*models.BaseDataProvidersResponse) + require.True(s.T(), ok, "Expected *models.BaseDataProvidersResponse, got %T", expected) + + expectedResponsePayload, ok := expectedResponse.Payload.(*models.AccountStatusesResponse) + require.True(s.T(), ok, "Unexpected response payload type: %T", expectedResponse.Payload) actualResponse, ok := actual.(*models.BaseDataProvidersResponse) require.True(s.T(), ok, "Expected *models.BaseDataProvidersResponse, got %T", actual) actualResponsePayload, ok := actualResponse.Payload.(*models.AccountStatusesResponse) - require.True(s.T(), ok, "unexpected response payload type: %T", actualResponse.Payload) + require.True(s.T(), ok, "Unexpected response payload type: %T", actualResponse.Payload) - require.Equal(s.T(), expectedResponse.BlockID, actualResponsePayload.BlockID) - require.Equal(s.T(), len(expectedResponse.AccountEvents), len(actualResponsePayload.AccountEvents)) - require.Equal(s.T(), expectedResponse.MessageIndex, actualResponsePayload.MessageIndex) - require.Equal(s.T(), expectedResponse.Height, actualResponsePayload.Height) + require.Equal(s.T(), expectedResponsePayload.BlockID, actualResponsePayload.BlockID) + require.Equal(s.T(), len(expectedResponsePayload.AccountEvents), len(actualResponsePayload.AccountEvents)) + require.Equal(s.T(), expectedResponsePayload.MessageIndex, actualResponsePayload.MessageIndex) + require.Equal(s.T(), expectedResponsePayload.Height, actualResponsePayload.Height) + require.Equal(s.T(), expectedResponse.Topic, actualResponse.Topic) - for key, expectedEvents := range expectedResponse.AccountEvents { + for key, expectedEvents := range expectedResponsePayload.AccountEvents { actualEvents, ok := actualResponsePayload.AccountEvents[key] require.True(s.T(), ok, "Missing key in actual AccountEvents: %s", key) @@ -294,10 +298,13 @@ func (s *AccountStatusesProviderSuite) expectedAccountStatusesResponses(backendR expectedResponses := make([]interface{}, len(backendResponses)) for i, resp := range backendResponses { - var expectedResponse models.AccountStatusesResponse - expectedResponse.Build(resp, uint64(i)) + var expectedResponsePayload models.AccountStatusesResponse + expectedResponsePayload.Build(resp, uint64(i)) - expectedResponses[i] = &expectedResponse + expectedResponses[i] = &models.BaseDataProvidersResponse{ + Topic: AccountStatusesTopic, + Payload: &expectedResponsePayload, + } } return expectedResponses diff --git a/engine/access/rest/websockets/data_providers/base_provider.go b/engine/access/rest/websockets/data_providers/base_provider.go index ee228fd4adf..0ee040cd4ac 100644 --- a/engine/access/rest/websockets/data_providers/base_provider.go +++ b/engine/access/rest/websockets/data_providers/base_provider.go @@ -8,8 +8,8 @@ import ( "github.com/onflow/flow-go/engine/access/subscription" ) -// BaseDataProvider holds common objects for the provider -type BaseDataProvider struct { +// baseDataProvider holds common objects for the provider +type baseDataProvider struct { id uuid.UUID topic string cancel context.CancelFunc @@ -17,14 +17,14 @@ type BaseDataProvider struct { subscription subscription.Subscription } -// newBaseDataProvider creates a new instance of BaseDataProvider. +// newBaseDataProvider creates a new instance of baseDataProvider. func newBaseDataProvider( topic string, cancel context.CancelFunc, send chan<- interface{}, subscription subscription.Subscription, -) *BaseDataProvider { - return &BaseDataProvider{ +) *baseDataProvider { + return &baseDataProvider{ id: uuid.New(), topic: topic, cancel: cancel, @@ -34,18 +34,18 @@ func newBaseDataProvider( } // ID returns the unique identifier of the data provider. -func (b *BaseDataProvider) ID() uuid.UUID { +func (b *baseDataProvider) ID() uuid.UUID { return b.id } // Topic returns the topic associated with the data provider. -func (b *BaseDataProvider) Topic() string { +func (b *baseDataProvider) Topic() string { return b.topic } // Close terminates the data provider. // // No errors are expected during normal operations. -func (b *BaseDataProvider) Close() { +func (b *baseDataProvider) Close() { b.cancel() } diff --git a/engine/access/rest/websockets/data_providers/block_digests_provider.go b/engine/access/rest/websockets/data_providers/block_digests_provider.go index b9651cc69da..8d9603306e2 100644 --- a/engine/access/rest/websockets/data_providers/block_digests_provider.go +++ b/engine/access/rest/websockets/data_providers/block_digests_provider.go @@ -15,7 +15,7 @@ import ( // BlockDigestsDataProvider is responsible for providing block digests type BlockDigestsDataProvider struct { - *BaseDataProvider + *baseDataProvider logger zerolog.Logger api access.API @@ -44,7 +44,7 @@ func NewBlockDigestsDataProvider( } subCtx, cancel := context.WithCancel(ctx) - p.BaseDataProvider = newBaseDataProvider( + p.baseDataProvider = newBaseDataProvider( topic, cancel, send, diff --git a/engine/access/rest/websockets/data_providers/block_digests_provider_test.go b/engine/access/rest/websockets/data_providers/block_digests_provider_test.go index 7bad20ff750..72c95f39e27 100644 --- a/engine/access/rest/websockets/data_providers/block_digests_provider_test.go +++ b/engine/access/rest/websockets/data_providers/block_digests_provider_test.go @@ -139,16 +139,16 @@ func (s *BlockDigestsProviderSuite) TestBlockDigestsDataProvider_HappyPath() { // requireBlockDigest ensures that the received block header information matches the expected data. func (s *BlocksProviderSuite) requireBlockDigest(actual interface{}, expected interface{}) { expectedResponse, ok := expected.(*models.BaseDataProvidersResponse) - require.True(s.T(), ok, "unexpected response type: %T", expected) + require.True(s.T(), ok, "Expected *models.BaseDataProvidersResponse, got %T", expected) expectedResponsePayload, ok := expectedResponse.Payload.(*models.BlockDigest) - require.True(s.T(), ok, "unexpected response type: %T", expectedResponse.Payload) + require.True(s.T(), ok, "Unexpected response payload type: %T", expectedResponse.Payload) actualResponse, ok := actual.(*models.BaseDataProvidersResponse) - require.True(s.T(), ok, "unexpected response type: %T", actual) + require.True(s.T(), ok, "Expected *models.BaseDataProvidersResponse, got %T", actual) actualResponsePayload, ok := actualResponse.Payload.(*models.BlockDigest) - require.True(s.T(), ok, "unexpected response payload type: %T", actualResponse.Payload) + require.True(s.T(), ok, "Unexpected response payload type: %T", actualResponse.Payload) s.Require().Equal(expectedResponse.Topic, actualResponse.Topic) s.Require().Equal(expectedResponsePayload, actualResponsePayload) diff --git a/engine/access/rest/websockets/data_providers/block_headers_provider.go b/engine/access/rest/websockets/data_providers/block_headers_provider.go index 5f1e5c4a448..291e3fd76d9 100644 --- a/engine/access/rest/websockets/data_providers/block_headers_provider.go +++ b/engine/access/rest/websockets/data_providers/block_headers_provider.go @@ -16,7 +16,7 @@ import ( // BlockHeadersDataProvider is responsible for providing block headers type BlockHeadersDataProvider struct { - *BaseDataProvider + *baseDataProvider logger zerolog.Logger api access.API @@ -45,7 +45,7 @@ func NewBlockHeadersDataProvider( } subCtx, cancel := context.WithCancel(ctx) - p.BaseDataProvider = newBaseDataProvider( + p.baseDataProvider = newBaseDataProvider( topic, cancel, send, diff --git a/engine/access/rest/websockets/data_providers/block_headers_provider_test.go b/engine/access/rest/websockets/data_providers/block_headers_provider_test.go index b860e16615e..ab194c395cc 100644 --- a/engine/access/rest/websockets/data_providers/block_headers_provider_test.go +++ b/engine/access/rest/websockets/data_providers/block_headers_provider_test.go @@ -60,8 +60,6 @@ func (s *BlockHeadersProviderSuite) validBlockHeadersArgumentsTestCases() []test var header commonmodels.BlockHeader header.Build(b.Header) - //expectedResponses[i] = &models.BlockHeaderMessageResponse{Header: &header} - expectedResponses[i] = &models.BaseDataProvidersResponse{ Topic: BlockHeadersTopic, Payload: &header, @@ -140,16 +138,16 @@ func (s *BlockHeadersProviderSuite) TestBlockHeadersDataProvider_HappyPath() { // requireBlockHeaders ensures that the received block header information matches the expected data. func (s *BlockHeadersProviderSuite) requireBlockHeader(actual interface{}, expected interface{}) { expectedResponse, ok := expected.(*models.BaseDataProvidersResponse) - require.True(s.T(), ok, "unexpected response type: %T", expected) + require.True(s.T(), ok, "Expected *models.BaseDataProvidersResponse, got %T", expected) expectedResponsePayload, ok := expectedResponse.Payload.(*commonmodels.BlockHeader) - require.True(s.T(), ok, "unexpected response type: %T", expectedResponse.Payload) + require.True(s.T(), ok, "Unexpected response payload type: %T", expectedResponse.Payload) actualResponse, ok := actual.(*models.BaseDataProvidersResponse) - require.True(s.T(), ok, "unexpected response type: %T", actual) + require.True(s.T(), ok, "Expected *models.BaseDataProvidersResponse, got %T", actual) actualResponsePayload, ok := actualResponse.Payload.(*commonmodels.BlockHeader) - require.True(s.T(), ok, "unexpected response payload type: %T", actualResponse.Payload) + require.True(s.T(), ok, "Unexpected response payload type: %T", actualResponse.Payload) s.Require().Equal(expectedResponse.Topic, actualResponse.Topic) s.Require().Equal(expectedResponsePayload, actualResponsePayload) diff --git a/engine/access/rest/websockets/data_providers/blocks_provider.go b/engine/access/rest/websockets/data_providers/blocks_provider.go index 49e837ce226..c0de76d0727 100644 --- a/engine/access/rest/websockets/data_providers/blocks_provider.go +++ b/engine/access/rest/websockets/data_providers/blocks_provider.go @@ -25,7 +25,7 @@ type blocksArguments struct { // BlocksDataProvider is responsible for providing blocks type BlocksDataProvider struct { - *BaseDataProvider + *baseDataProvider logger zerolog.Logger api access.API @@ -59,7 +59,7 @@ func NewBlocksDataProvider( } subCtx, cancel := context.WithCancel(ctx) - p.BaseDataProvider = newBaseDataProvider( + p.baseDataProvider = newBaseDataProvider( topic, cancel, send, diff --git a/engine/access/rest/websockets/data_providers/blocks_provider_test.go b/engine/access/rest/websockets/data_providers/blocks_provider_test.go index 18b664de14b..f28e9a82e04 100644 --- a/engine/access/rest/websockets/data_providers/blocks_provider_test.go +++ b/engine/access/rest/websockets/data_providers/blocks_provider_test.go @@ -241,13 +241,13 @@ func (s *BlocksProviderSuite) TestBlocksDataProvider_HappyPath() { // requireBlocks ensures that the received block information matches the expected data. func (s *BlocksProviderSuite) requireBlock(actual interface{}, expected interface{}) { expectedResponse, ok := expected.(*models.BaseDataProvidersResponse) - require.True(s.T(), ok, "unexpected response type: %T", expected) + require.True(s.T(), ok, "Expected *models.BaseDataProvidersResponse, got %T", expected) expectedResponsePayload, ok := expectedResponse.Payload.(*commonmodels.Block) - require.True(s.T(), ok, "unexpected response type: %T", expectedResponse.Payload) + require.True(s.T(), ok, "unexpected response payload type: %T", expectedResponse.Payload) actualResponse, ok := actual.(*models.BaseDataProvidersResponse) - require.True(s.T(), ok, "unexpected response type: %T", actual) + require.True(s.T(), ok, "Expected *models.BaseDataProvidersResponse, got %T", actual) actualResponsePayload, ok := actualResponse.Payload.(*commonmodels.Block) require.True(s.T(), ok, "unexpected response payload type: %T", actualResponse.Payload) diff --git a/engine/access/rest/websockets/data_providers/events_provider.go b/engine/access/rest/websockets/data_providers/events_provider.go index 90c14859165..b28bf4e2e95 100644 --- a/engine/access/rest/websockets/data_providers/events_provider.go +++ b/engine/access/rest/websockets/data_providers/events_provider.go @@ -25,7 +25,7 @@ type eventsArguments struct { // EventsDataProvider is responsible for providing events type EventsDataProvider struct { - *BaseDataProvider + *baseDataProvider logger zerolog.Logger stateStreamApi state_stream.API @@ -61,7 +61,7 @@ func NewEventsDataProvider( subCtx, cancel := context.WithCancel(ctx) - p.BaseDataProvider = newBaseDataProvider( + p.baseDataProvider = newBaseDataProvider( topic, cancel, send, diff --git a/engine/access/rest/websockets/data_providers/events_provider_test.go b/engine/access/rest/websockets/data_providers/events_provider_test.go index f75c020dad7..91b09239f1a 100644 --- a/engine/access/rest/websockets/data_providers/events_provider_test.go +++ b/engine/access/rest/websockets/data_providers/events_provider_test.go @@ -138,17 +138,20 @@ func (s *EventsProviderSuite) subscribeEventsDataProviderTestCases(backendRespon // requireEvents ensures that the received event information matches the expected data. func (s *EventsProviderSuite) requireEvents(actual interface{}, expected interface{}) { - expectedResponse, ok := expected.(*models.EventResponse) - require.True(s.T(), ok, "Expected *models.EventResponse, got %T", expected) + expectedResponse, ok := expected.(*models.BaseDataProvidersResponse) + require.True(s.T(), ok, "Expected *models.BaseDataProvidersResponse, got %T", expected) + + expectedResponsePayload, ok := expectedResponse.Payload.(*models.EventResponse) + require.True(s.T(), ok, "Unexpected response payload type: %T", expectedResponse.Payload) actualResponse, ok := actual.(*models.BaseDataProvidersResponse) require.True(s.T(), ok, "Expected *models.BaseDataProvidersResponse, got %T", actual) actualResponsePayload, ok := actualResponse.Payload.(*models.EventResponse) - require.True(s.T(), ok, "unexpected response payload type: %T", actualResponse.Payload) + require.True(s.T(), ok, "Unexpected response payload type: %T", actualResponse.Payload) - s.Require().ElementsMatch(expectedResponse.Events, actualResponsePayload.Events) - s.Require().Equal(expectedResponse.MessageIndex, actualResponsePayload.MessageIndex) + s.Require().ElementsMatch(expectedResponsePayload.Events, actualResponsePayload.Events) + s.Require().Equal(expectedResponsePayload.MessageIndex, actualResponsePayload.MessageIndex) } // invalidArgumentsTestCases returns a list of test cases with invalid argument combinations @@ -324,10 +327,13 @@ func (s *EventsProviderSuite) expectedEventsResponses( expectedResponses := make([]interface{}, len(backendResponses)) for i, resp := range backendResponses { - var expectedResponse models.EventResponse - expectedResponse.Build(resp, uint64(i)) + var expectedResponsePayload models.EventResponse + expectedResponsePayload.Build(resp, uint64(i)) - expectedResponses[i] = &expectedResponse + expectedResponses[i] = &models.BaseDataProvidersResponse{ + Topic: EventsTopic, + Payload: &expectedResponsePayload, + } } return expectedResponses } diff --git a/engine/access/rest/websockets/data_providers/send_and_get_transaction_statuses_provider.go b/engine/access/rest/websockets/data_providers/send_and_get_transaction_statuses_provider.go index 40e49c657c1..d1b9f973d1d 100644 --- a/engine/access/rest/websockets/data_providers/send_and_get_transaction_statuses_provider.go +++ b/engine/access/rest/websockets/data_providers/send_and_get_transaction_statuses_provider.go @@ -26,7 +26,7 @@ type sendAndGetTransactionStatusesArguments struct { } type SendAndGetTransactionStatusesDataProvider struct { - *BaseDataProvider + *baseDataProvider logger zerolog.Logger api access.API @@ -58,7 +58,7 @@ func NewSendAndGetTransactionStatusesDataProvider( subCtx, cancel := context.WithCancel(ctx) - p.BaseDataProvider = newBaseDataProvider( + p.baseDataProvider = newBaseDataProvider( topic, cancel, send, diff --git a/engine/access/rest/websockets/data_providers/send_and_get_transaction_statuses_provider_test.go b/engine/access/rest/websockets/data_providers/send_and_get_transaction_statuses_provider_test.go index df8811b4a2f..a8a1a89d86a 100644 --- a/engine/access/rest/websockets/data_providers/send_and_get_transaction_statuses_provider_test.go +++ b/engine/access/rest/websockets/data_providers/send_and_get_transaction_statuses_provider_test.go @@ -73,7 +73,7 @@ func (s *TransactionStatusesProviderSuite) TestSendTransactionStatusesDataProvid ) backendResponse := backendTransactionStatusesResponse(s.rootBlock) - expectedResponse := s.expectedTransactionStatusesResponses(backendResponse) + expectedResponse := s.expectedTransactionStatusesResponses(backendResponse, SendAndGetTransactionStatusesTopic) sendTxStatutesTestCases := []testType{ { @@ -111,16 +111,20 @@ func (s *SendTransactionStatusesProviderSuite) requireTransactionStatuses( actual interface{}, expected interface{}, ) { - expectedTxStatusesResponse, ok := expected.(*models.TransactionStatusesResponse) - require.True(s.T(), ok, "expected *models.TransactionStatusesResponse, got %T", expected) + expectedResponse, ok := expected.(*models.BaseDataProvidersResponse) + require.True(s.T(), ok, "Expected *models.BaseDataProvidersResponse, got %T", expected) + + expectedResponsePayload, ok := expectedResponse.Payload.(*models.TransactionStatusesResponse) + require.True(s.T(), ok, "Unexpected response payload type: %T", expectedResponse.Payload) actualResponse, ok := actual.(*models.BaseDataProvidersResponse) require.True(s.T(), ok, "Expected *models.BaseDataProvidersResponse, got %T", actual) actualResponsePayload, ok := actualResponse.Payload.(*models.TransactionStatusesResponse) - require.True(s.T(), ok, "unexpected response payload type: %T", actualResponse.Payload) + require.True(s.T(), ok, "Unexpected response payload type: %T", actualResponse.Payload) - require.Equal(s.T(), expectedTxStatusesResponse.TransactionResult.BlockId, actualResponsePayload.TransactionResult.BlockId) + require.Equal(s.T(), expectedResponse.Topic, actualResponse.Topic) + require.Equal(s.T(), expectedResponsePayload.TransactionResult.BlockId, actualResponsePayload.TransactionResult.BlockId) } // TestSendTransactionStatusesDataProvider_InvalidArguments tests the behavior of the send transaction statuses data provider diff --git a/engine/access/rest/websockets/data_providers/transaction_statuses_provider.go b/engine/access/rest/websockets/data_providers/transaction_statuses_provider.go index 1540fa55146..3b86dd39042 100644 --- a/engine/access/rest/websockets/data_providers/transaction_statuses_provider.go +++ b/engine/access/rest/websockets/data_providers/transaction_statuses_provider.go @@ -29,7 +29,7 @@ type transactionStatusesArguments struct { // TransactionStatusesDataProvider is responsible for providing tx statuses type TransactionStatusesDataProvider struct { - *BaseDataProvider + *baseDataProvider logger zerolog.Logger api access.API @@ -61,7 +61,7 @@ func NewTransactionStatusesDataProvider( subCtx, cancel := context.WithCancel(ctx) - p.BaseDataProvider = newBaseDataProvider( + p.baseDataProvider = newBaseDataProvider( topic, cancel, send, diff --git a/engine/access/rest/websockets/data_providers/transaction_statuses_provider_test.go b/engine/access/rest/websockets/data_providers/transaction_statuses_provider_test.go index 4775050931c..05c1c7a63ce 100644 --- a/engine/access/rest/websockets/data_providers/transaction_statuses_provider_test.go +++ b/engine/access/rest/websockets/data_providers/transaction_statuses_provider_test.go @@ -90,7 +90,7 @@ func (s *TransactionStatusesProviderSuite) TestTransactionStatusesDataProvider_H } func (s *TransactionStatusesProviderSuite) subscribeTransactionStatusesDataProviderTestCases(backendResponses []*access.TransactionResult) []testType { - expectedResponses := s.expectedTransactionStatusesResponses(backendResponses) + expectedResponses := s.expectedTransactionStatusesResponses(backendResponses, TransactionStatusesTopic) return []testType{ { @@ -146,29 +146,37 @@ func (s *TransactionStatusesProviderSuite) requireTransactionStatuses( actual interface{}, expected interface{}, ) { - expectedTxStatusesResponse, ok := expected.(*models.TransactionStatusesResponse) - require.True(s.T(), ok, "expected *models.TransactionStatusesResponse, got %T", expected) + expectedResponse, ok := expected.(*models.BaseDataProvidersResponse) + require.True(s.T(), ok, "Expected *models.BaseDataProvidersResponse, got %T", expected) + + expectedResponsePayload, ok := expectedResponse.Payload.(*models.TransactionStatusesResponse) + require.True(s.T(), ok, "Unexpected response payload type: %T", expectedResponse.Payload) actualResponse, ok := actual.(*models.BaseDataProvidersResponse) require.True(s.T(), ok, "Expected *models.BaseDataProvidersResponse, got %T", actual) actualResponsePayload, ok := actualResponse.Payload.(*models.TransactionStatusesResponse) - require.True(s.T(), ok, "unexpected response payload type: %T", actualResponse.Payload) + require.True(s.T(), ok, "Unexpected response payload type: %T", actualResponse.Payload) - require.Equal(s.T(), expectedTxStatusesResponse.TransactionResult.BlockId, actualResponsePayload.TransactionResult.BlockId) + require.Equal(s.T(), expectedResponse.Topic, actualResponse.Topic) + require.Equal(s.T(), expectedResponsePayload.TransactionResult.BlockId, actualResponsePayload.TransactionResult.BlockId) } // expectedTransactionStatusesResponses creates the expected responses for the provided backend responses. func (s *TransactionStatusesProviderSuite) expectedTransactionStatusesResponses( backendResponses []*access.TransactionResult, + topic string, ) []interface{} { expectedResponses := make([]interface{}, len(backendResponses)) for i, resp := range backendResponses { - var expectedResponse models.TransactionStatusesResponse - expectedResponse.Build(s.linkGenerator, resp, uint64(i)) + var expectedResponsePayload models.TransactionStatusesResponse + expectedResponsePayload.Build(s.linkGenerator, resp, uint64(i)) - expectedResponses[i] = &expectedResponse + expectedResponses[i] = &models.BaseDataProvidersResponse{ + Topic: topic, + Payload: &expectedResponsePayload, + } } return expectedResponses diff --git a/engine/access/rest/websockets/models/base_message.go b/engine/access/rest/websockets/models/base_message.go index e0b7fb78cc2..edac10cfb9b 100644 --- a/engine/access/rest/websockets/models/base_message.go +++ b/engine/access/rest/websockets/models/base_message.go @@ -28,7 +28,7 @@ type BaseDataProvidersResponse struct { } // Build creates BaseDataProvidersResponse instance for consistent responses of the data providers. -//func (b *BaseDataProvidersResponse) Build(baseDataProvider *data_providers.BaseDataProvider, payload interface{}) { +//func (b *BaseDataProvidersResponse) Build(baseDataProvider *data_providers.baseDataProvider, payload interface{}) { // *b = BaseDataProvidersResponse{ // SubscriptionID: baseDataProvider.ID().String(), // Topic: baseDataProvider.Topic(),