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

Binary Testing Framework #1485

Merged
merged 11 commits into from
Jul 6, 2018
Merged

Binary Testing Framework #1485

merged 11 commits into from
Jul 6, 2018

Conversation

igor-egorov
Copy link
Contributor

Description of the Change

The PR introduces Binary Testing Framework.
BTF allows performing stateful validation for transactions and queries built using client libraries.
For now, only Python is supported. Java support will be added later on.

This PR comes with python scripts that cover all the set of Iroha permissions.

Benefits

Now here is the tool for stateful validation of transactions and queries created via client libraries.

Also, here is a set of python examples that shows how to use Iroha permissions model. (Scripts' listings will be included into "permissions" page at ReadTheDocs).

Possible Drawbacks

No drawbacks were observed.

Usage Examples or Tests

cmake -H. -Bbuild -DSWIG_PYTHON=ON
cmake --build build --target binary_test
cd build
ctest -R binary

Possible Improvements

The existing set of python example scripts can be extended with tests which validate the correctness of resulting state after applying transactions to Iroha (that approach was not the point of current tests set).

Such improvement will require changes in the implementation of Python and Java launchers.

Igor Egorov added 3 commits June 20, 2018 13:15
Signed-off-by: Igor Egorov <igor@soramitsu.co.jp>
Signed-off-by: Igor Egorov <igor@soramitsu.co.jp>
Signed-off-by: Igor Egorov <igor@soramitsu.co.jp>
@igor-egorov igor-egorov added tests pr aimed at the code coverage increase or test refactorings SDK Anything related to the client bindings labels Jun 20, 2018
@igor-egorov
Copy link
Contributor Author

Note about SonarQube report - that is just a false positive error.

launchers.cpp#L57: The function 'initialized' is never used.

https://github.com/hyperledger/iroha/blob/53f1894ed2b8ba703f6fccb9b939b9c9a76762f7/test/integration/binary/binaries_test_fixture.hpp#L117

Copy link
Contributor

@muratovv muratovv left a comment

Choose a reason for hiding this comment

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

I reviewed only BTF and one example. The rest of review I will provide later.


add_executable(binary_test
launchers.cpp
binaries_test.cpp)
Copy link
Contributor

Choose a reason for hiding this comment

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

Better to move ) to the new line.

boost
schema
shared_model_proto_backend
shared_model_interfaces
Copy link
Contributor

Choose a reason for hiding this comment

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

Looks redundant, but it is not a required issue.

target_include_directories(binary_test PUBLIC ${PROJECT_SOURCE_DIR}/test)

add_dependencies(binary_test irohapy)
add_test(
Copy link
Contributor

Choose a reason for hiding this comment

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

Use addtest instead. https://github.com/hyperledger/iroha/blob/e8cdcc1f0b87058814e8d44c1b5f7b1839af3e92/cmake/functions.cmake#L23

Pls, note that function assumes "type" of test which is required for CI.

Copy link
Contributor

@lebdron lebdron Jun 21, 2018

Choose a reason for hiding this comment

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

It is not possible, because a custom test is defined here, while addtest creates a generic test which calls the test binary without any parameters. The test call is replaced here with python interpreter call.

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 create a generic function for those purposes? We have to manage types of tests in CI.

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe an easier solution would be to override add_test, do custom logic and pass the arguments to real add_test. This will add types to all tests added with add_test.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Discussed offline. Summary: there is no problem because python_binary_test target becomes visible only when SWIG for Python is enabled (-DSWIG_PYTHON=ON). Thus, CI would not be confused.

* SPDX-License-Identifier: Apache-2.0
*/

#include "binaries_test_fixture.hpp"
Copy link
Contributor

Choose a reason for hiding this comment

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

Use full path instead.


namespace internal {

class Void {};
Copy link
Contributor

Choose a reason for hiding this comment

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

Add purpose of usage.

Copy link
Contributor

Choose a reason for hiding this comment

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

*class doc


namespace binary_test {

class Launcher {
Copy link
Contributor

Choose a reason for hiding this comment

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

Add some documentation with purpose

public:
virtual std::string launchCommand(const std::string &test_case) = 0;

void operator()(const std::string &example);
Copy link
Contributor

Choose a reason for hiding this comment

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

Add doc, pls

std::vector<shared_model::proto::Query> queries;

protected:
void readBinaries(boost::process::ipstream &stream);
Copy link
Contributor

Choose a reason for hiding this comment

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

Add contract for the stream in a documentation


std::string JavaLauncher::launchCommand(const std::string &example) {
return "";
// tbd, igor-egorov, 2018-06-20, IR-1389
Copy link
Contributor

Choose a reason for hiding this comment

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

s/tbd/TODO

Copy link
Contributor

Choose a reason for hiding this comment

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

who cares, tbd is also ok

Copy link
Contributor

Choose a reason for hiding this comment

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

Tbd not ok because you can't grep it fast. Better to remember only one name instead of two.

Copy link
Contributor

Choose a reason for hiding this comment

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

@igor-egorov you may create a snippet with TODO in your favorite IDE.

.signAndAddSignature(alice['key']).finish()


print(admin['key'].privateKey().hex())
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe move this framework-related code to separate class (and file) for reducing boilerplate?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Discussed with Fedor in offline.
Let's keep this code for now. We expect the protocol of communication between BTF and external scripts to be changed, so then we can reduce the amount of such boilerplate code.

alice = commons.user('alice@test')


def genesis_tx():
Copy link
Contributor

Choose a reason for hiding this comment

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

That function is pretty similar among the files, that better be moved somewhere

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Finally, it was decided not to modify this place. Moving of the common part will lead to hiding command of domain creation that includes the test role. Otherwise, there will be nothing to move.

Thus, in order to increase examples' demonstrativeness, genesis functions would not be modified.

@@ -0,0 +1,41 @@

if (SWIG_PYTHON OR SWIG_JAVA)
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider adding a variable IS_BINDINGS or SWIG_ENABLED, etc
otherwise it be duplicated in bindings folder as well

Copy link
Contributor

Choose a reason for hiding this comment

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

at least mark with a todo, same for the following one

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Discussed offline. Not a problem.

find_package(PythonInterp 3.5 REQUIRED)
endif ()

foreach (item "block" "commands" "primitive" "queries")
Copy link
Contributor

Choose a reason for hiding this comment

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

The dependency should be moved somewhere at separate target


namespace internal {

class Void {};
Copy link
Contributor

Choose a reason for hiding this comment

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

*class doc


} // namespace query_validation

template <typename T>
Copy link
Contributor

Choose a reason for hiding this comment

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

or even better rename to SdkLauncher


class PythonLauncher : public Launcher {
public:
virtual std::string launchCommand(const std::string &example);
Copy link
Contributor

Choose a reason for hiding this comment

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

virtual std::string launchCommand(const std::string &example) override;
same below

bool initialized(const unsigned &transactions_expected = 0,
const unsigned &queries_expected = 0);

std::shared_ptr<shared_model::crypto::Keypair> admin_key;
Copy link
Contributor

Choose a reason for hiding this comment

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

boost::optional seems more suitable (or even without any wrapper & early fail)

gtest
gmock
boost
schema
Copy link
Contributor

Choose a reason for hiding this comment

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

also redundant, it must be used in backend



def all_permissions():
return iroha.RolePermissionSet([
Copy link
Contributor

Choose a reason for hiding this comment

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

r = iroha.RolePermissionSet()
for i in range(r.size()):
  r.set(i)
return i

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Discussed offline. Since the listing of commons.py will also be included in the documentation page about permissions, it is better to preserve fully-qualified constants' names for better presentation for documentation users.

])


def user(user_id):
Copy link
Contributor

Choose a reason for hiding this comment

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

That will generate a new keypair for the same user, so consider renaming the method
or static vars hack can be used

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Discussed offline. Decided to clarify method naming and not to touch the internals for now.

@l4l l4l added the needs-correction pr/rfc is not completed and might be updated label Jun 26, 2018
Signed-off-by: Igor Egorov <igor@soramitsu.co.jp>
@igor-egorov igor-egorov requested review from l4l and muratovv June 30, 2018 17:08
Signed-off-by: Igor Egorov <igor@soramitsu.co.jp>
* @param response - QueryResponse object to check
*/
template <typename ExpectedResponseType>
inline void checkQueryResponseType(
Copy link
Contributor

Choose a reason for hiding this comment

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

Would be better to return bool, instead of assertion
Otherwise fails will look like Assertion failed at binaries_test_fixture.hpp:67, that is pretty useless

itf.setInitialState(launcher.admin_key.value(), genesis());

std::for_each(
std::next( // first transaction was used as genesis transaction
Copy link
Contributor

Choose a reason for hiding this comment

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

could you move the comment at the separate line above? looks ugly :(

@igor-egorov igor-egorov dismissed muratovv’s stale review July 2, 2018 06:45

requested changes were applied

Copy link
Contributor

@muratovv muratovv left a comment

Choose a reason for hiding this comment

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

Pls, fix minor issues.

#include "framework/specified_visitor.hpp"
#include "integration/binary/launchers.hpp"

using namespace boost::process;
Copy link
Contributor

Choose a reason for hiding this comment

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

using namespace is prohibited to use in headers.

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 use alias instead: namespace proc = boost::process

* execution.
*/
template <typename Head, typename... Tail>
inline void _validateQueries(::query_validation::QueryIterator it,
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the point of _ before the name?

Copy link
Contributor

Choose a reason for hiding this comment

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

Means internal, I guess

@l4l l4l removed the needs-correction pr/rfc is not completed and might be updated label Jul 5, 2018
Igor Egorov added 5 commits July 5, 2018 20:14
Signed-off-by: Igor Egorov <igor@soramitsu.co.jp>
Signed-off-by: Igor Egorov <igor@soramitsu.co.jp>
The signature of AddAssetQuantity and SubtractAssetQuantity was changed.
Now they take two arguments instead of three.

Signed-off-by: Igor Egorov <igor@soramitsu.co.jp>
It was discovered that protobuf does not preserve type
information in binary representation.
That was the reason to introduce custom (BTF) type identifiers
for binaries.

Amount of boilerplate code in python examples was reduced.

Signed-off-by: Igor Egorov <igor@soramitsu.co.jp>
@sorabot
Copy link

sorabot commented Jul 6, 2018

SonarQube analysis reported 1 issue

  1. MINOR launchers.cpp#L73: The function 'initialized' is never used. rule

@igor-egorov igor-egorov merged commit 4c71d49 into develop Jul 6, 2018
@igor-egorov igor-egorov deleted the feature/btf branch July 6, 2018 17:35
l4l pushed a commit that referenced this pull request Jul 25, 2018
Signed-off-by: Igor Egorov <igor@soramitsu.co.jp>
l4l pushed a commit that referenced this pull request Jul 25, 2018
Signed-off-by: Igor Egorov <igor@soramitsu.co.jp>
l4l pushed a commit that referenced this pull request Jul 25, 2018
Signed-off-by: Igor Egorov <igor@soramitsu.co.jp>
l4l pushed a commit that referenced this pull request Jul 25, 2018
Signed-off-by: Igor Egorov <igor@soramitsu.co.jp>
l4l pushed a commit that referenced this pull request Jul 25, 2018
Signed-off-by: Igor Egorov <igor@soramitsu.co.jp>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
SDK Anything related to the client bindings tests pr aimed at the code coverage increase or test refactorings
Development

Successfully merging this pull request may close these issues.

None yet

5 participants