Skip to content
This repository has been archived by the owner on Apr 17, 2019. It is now read-only.

ITF checking statuses set #1720

Merged
merged 18 commits into from
Oct 18, 2018
Merged

ITF checking statuses set #1720

merged 18 commits into from
Oct 18, 2018

Conversation

l4l
Copy link
Contributor

@l4l l4l commented Sep 15, 2018

Description of the Change

ITF before only able to check, whether the sent tx is stateless valid or not (only the first status). This RP introduce the ITF feature to check against all the specified statuses, both for single transaction and tx sequence.

Benefits

It is possible to check all statuses with one itf command, their order and responses content (e.g error message)

Possible Drawbacks

Current implementation doesn't check the order of passed transaction. Is it an issue?

Usage Examples or Tests

As a usage example CreateRole::Basic acceptance test was reworked according to new ITF::sendTx.
Also for ITF::sendTxSequence there was reworked a fn call in BatchPipelineTest::InvalidAtomicBatch

Signed-off-by: Kitsu <mail@kitsu.me>
@l4l l4l added needs-review pr awaits review from maintainers tests pr aimed at the code coverage increase or test refactorings labels Sep 15, 2018
@l4l l4l requested review from kamilsa and lebdron September 15, 2018 08:52
.filter([&](auto s) { return s->transactionHash() == tx.hash(); })
.map([](auto s) { return TxStatus(s->get().which()); })
.filter([&statuses](auto s) { return statuses.count(s) != 0; })
.take_while([&statuses](auto) { return statuses.size() != 0; })
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This chain calls probably can be improved, feel free to propose solution

Signed-off-by: Kitsu <mail@kitsu.me>
Signed-off-by: Kitsu <mail@kitsu.me>
/**
* Send transactions to Iroha and validate obtained statuses
* @param tx_sequence - transactions sequence
* @param statuses - vector of statues list to be checked against, which
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo with statues

iroha_instance_->getIrohaInstance()->getCommandService()->ListTorii(
tx_list);

// wait, until all of the statuses are recieved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: received

iroha_instance_->instance_->getStatusBus()
->statuses()
.filter([&](auto s) { return s->transactionHash() == tx.hash(); })
.map([](auto s) { return TxStatus(s->get().which()); })
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dangerous cast from variant to enum. If someone changes the order of types in either variant or enum it will be hard to find the reason of the error. Maybe cast it explicitly via visit_in_place?

return tx_statsues.find(s->transactionHash()) != tx_statsues.end();
})
.subscribe([&](auto s) {
auto status = TxStatus(s->get().which());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same. Maybe we can define a separate function, responsible for such conversion?

Signed-off-by: Kitsu <mail@kitsu.me>
Signed-off-by: Kitsu <mail@kitsu.me>
Signed-off-by: Kitsu <mail@kitsu.me>
Copy link
Contributor

@lebdron lebdron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This approach does not allow to compare the error message in responses, and introduces code duplication for statuses. Consider accepting a visitor for each transaction.


// mapping transaction hash to its statuses that need to be checked
std::map<shared_model::crypto::Hash, std::set<TxStatus>, HashCmp>
tx_statsues;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix that typo

This reverts commit 047cb29.

Signed-off-by: Kitsu <mail@kitsu.me>
Signed-off-by: Kitsu <mail@kitsu.me>
if (response != statuses.end()) {
statuses.erase(response);
}
status_list.emplace_back(iroha::protocol::ToriiResponse(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make status list to be vector of interfaces and use clone function instead of copying protobuf explicitly?

const shared_model::proto::Transaction &tx, std::set<TxStatus> statuses) {
const shared_model::proto::Transaction &tx,
std::function<
void(const std::vector<shared_model::proto::TransactionResponse> &)>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we change to interface::TransactionResponse?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only if it std::vector<std::shared_ptr<iface::TxResponse>>

@@ -153,8 +153,12 @@ namespace integration_framework {
* @param statuses - list of statuses to check against
* @return this
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update comment

makeUserWithPerms(),
[](auto &resps) {
for (auto &&r : resps) {
std::cout << r.get().which() << std::endl;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did yoy forget to remove that?

IntegrationTestFramework &sendTx(const shared_model::proto::Transaction &tx,
std::set<TxStatus> statuses);
IntegrationTestFramework &sendTx(
const shared_model::proto::Transaction &tx,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, can we work with interfaces here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's consistent with ITF interface, so what's the point?

Signed-off-by: Kitsu <mail@kitsu.me>
@sorabot
Copy link

sorabot commented Sep 25, 2018

SonarQube analysis reported 3 issues

  1. MAJOR integration_test_framework.cpp#L319: Reference to auto variable returned. rule
  2. MINOR acceptance_fixture.hpp#L162: The class 'PipelineIntegrationTest' defines member variable with name 'kAdminId' also defined in its parent class 'AcceptanceFixture'. rule
  3. MINOR acceptance_fixture.hpp#L163: The class 'PipelineIntegrationTest' defines member variable with name 'kAdminKeypair' also defined in its parent class 'AcceptanceFixture'. rule

Copy link
Contributor

@lebdron lebdron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

status_count approach will not work because in case a new status is added, it may be required to refactor all the tests with the new value. It is required to discuss another possible approaches.

Signed-off-by: Kitsu <mail@kitsu.me>
Signed-off-by: Kitsu <mail@kitsu.me>
@@ -276,6 +289,18 @@ namespace integration_framework {
tbb::concurrent_queue<ProposalType> proposal_queue_;
tbb::concurrent_queue<ProposalType> verified_proposal_queue_;
tbb::concurrent_queue<BlockType> block_queue_;

struct HashCmp {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this really required? Maybe use std::string from hash hex instead?

};

std::map<shared_model::interface::types::HashType,
tbb::concurrent_queue<TxResponseType>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Observable does not emit values concurrently, so there is no need in a concurrent queue for pushes. Reads are also done in main test thread, so read concurrency is also not required.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gRPC-based thread is writing here and the ITF main thread is reading. So there should be concurrent queue

template <typename T>
void checkStatus(const shared_model::interface::TransactionResponse &resp) {
ASSERT_NO_THROW(
boost::apply_visitor(framework::SpecifiedVisitor<T>(), resp.get()));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use boost::get instead.

@@ -25,11 +34,24 @@ AcceptanceFixture::AcceptanceFixture()
shared_model::crypto::DefaultCryptoAlgorithmType::generateKeypair()),
kUserKeypair(
shared_model::crypto::DefaultCryptoAlgorithmType::generateKeypair()),
checkEnoughSignatures([](auto &status) {
checkStatus<shared_model::interface::EnoughSignaturesCollectedResponse>(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks copy-pasted. Define and instantiate a template variable instead:

template <typename T>
const std::function<void(const shared_model::proto::TransactionResponse &)> check_status = [](const shared_model::proto::TransactionResponse &) {
  ...
}

template const std::function<void(const shared_model::proto::TransactionResponse &)> check_status<shared_model::interface::EnoughSignaturesCollectedResponse>;

Copy link
Contributor Author

@l4l l4l Oct 4, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are just comfy aliases to checkStatus itself.
It's much more descriptive:
itf.checkStatus(checkEnoughSignatures)

rather than:
itf.checkStatus(check_status<shared_model::interface::EnoughSignaturesCollectedResponse)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, but is it possible to initialize the variables with the function directly, so that it is not required to wrap checkStatus<T> in a lambda? This will reduce code in this file at least.

@@ -162,8 +163,18 @@ class AcceptanceFixture : public ::testing::Test {
const shared_model::crypto::Keypair kAdminKeypair;
const shared_model::crypto::Keypair kUserKeypair;

const std::function<void(const shared_model::proto::TransactionResponse &)>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like copy-paste. Declare a template variable:

template <typename T>
const std::function<void(const shared_model::proto::TransactionResponse &)> check_status;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can declare the variables with just once type to avoid duplication:
const std::function<void(const TxResponseType &)> checkEnoughSignatures, checkStatelessInvalid, ...

namespace {
template <typename T>
void checkStatus(const shared_model::interface::TransactionResponse &resp) {
ASSERT_NO_THROW(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assertions are better done in the test body, so that log contains a reference to line of test code.

@@ -11,6 +11,7 @@
#include <string>
#include <vector>
#include "cryptography/keypair.hpp"
#include "framework/integration_framework/integration_test_framework.hpp"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is unused, so it can be removed.

Signed-off-by: Kitsu <mail@kitsu.me>
Signed-off-by: Kitsu <mail@kitsu.me>
@@ -163,6 +165,12 @@ namespace integration_framework {
log_->info("commit");
queue_cond.notify_all();
});
iroha_instance_->getIrohaInstance()->getStatusBus()->statuses().subscribe(
[this](auto responses) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

responses -> response

const shared_model::interface::types::HashType &tx_hash,
std::function<void(const shared_model::proto::TransactionResponse &)>
validation) {
// fetch first proposal from proposal queue
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment looks out of place, please rephrase appropriately.

@@ -375,6 +383,21 @@ namespace integration_framework {
return *this;
}

IntegrationTestFramework &IntegrationTestFramework::checkStatus(
const shared_model::interface::types::HashType &tx_hash,
std::function<void(const shared_model::proto::TransactionResponse &)>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

checkProposal, checkVerifiedProposal, checkBlock use interface type for lambdas. Please use it here as well for consistency:
std::function<void(const TxResponseType &)>

@@ -25,11 +34,24 @@ AcceptanceFixture::AcceptanceFixture()
shared_model::crypto::DefaultCryptoAlgorithmType::generateKeypair()),
kUserKeypair(
shared_model::crypto::DefaultCryptoAlgorithmType::generateKeypair()),
checkEnoughSignatures([](auto &status) {
checkStatus<shared_model::interface::EnoughSignaturesCollectedResponse>(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, but is it possible to initialize the variables with the function directly, so that it is not required to wrap checkStatus<T> in a lambda? This will reduce code in this file at least.

@@ -162,8 +163,18 @@ class AcceptanceFixture : public ::testing::Test {
const shared_model::crypto::Keypair kAdminKeypair;
const shared_model::crypto::Keypair kUserKeypair;

const std::function<void(const shared_model::proto::TransactionResponse &)>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can declare the variables with just once type to avoid duplication:
const std::function<void(const TxResponseType &)> checkEnoughSignatures, checkStatelessInvalid, ...

Signed-off-by: Kitsu <mail@kitsu.me>
Signed-off-by: Kitsu <mail@kitsu.me>

#define CHECK_COMMITTED \
[](const shared_model::interface::TransactionResponse &resp) { \
SCOPED_TRACE("CHECK_COMMITTE"); \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

find&replace ninja failed :( thanks!

Signed-off-by: Kitsu <mail@kitsu.me>
Signed-off-by: Kitsu <mail@kitsu.me>
} // namespace shared_model
namespace {
template <typename Type>
void __checkFunction(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codestyle requires camelcase names without underscores for functions. Leading underscores are used by system and compiler methods, so there is no need for them here.

}

#define CHECK_ENOUGH_SIGNATURES \
[](const shared_model::interface::TransactionResponse &resp) { \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please separate these macros into two:

#define VALIDATE_RESPONSE(type)                                            \
  [](const shared_model::interface::TransactionResponse &resp) {           \
    SCOPED_TRACE("#type");                                                 \
    checkFunction<shared_model::interface::##type>(resp);                  \
}

#define CHECK_ENOUGH_SIGNATURES VALIDATE_RESPONSE(EnoughSignaturesCollectedResponse)

User proper naming for internal checking repsonse function. Also reuse
code in macros.

Signed-off-by: Kitsu <mail@kitsu.me>
@l4l l4l merged commit 001fac8 into dev Oct 18, 2018
@l4l l4l deleted the feature/itf_statuses branch October 18, 2018 11:36
bakhtin pushed a commit that referenced this pull request Nov 2, 2018
Signed-off-by: Kitsu <mail@kitsu.me>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
needs-review pr awaits review from maintainers tests pr aimed at the code coverage increase or test refactorings
Development

Successfully merging this pull request may close these issues.

None yet

4 participants