diff --git a/programs/cleos/main.cpp b/programs/cleos/main.cpp index ba86b622f33..3e8e54ab613 100644 --- a/programs/cleos/main.cpp +++ b/programs/cleos/main.cpp @@ -514,7 +514,9 @@ void print_action( const fc::variant& at ) { const auto& act = at["act"].get_object(); auto code = act["account"].as_string(); auto func = act["name"].as_string(); - auto args = fc::json::to_string( act["data"], fc::time_point::maximum() ); + string args; + if(act.contains("data")) + args = fc::json::to_string( act["data"], fc::time_point::maximum() ); auto console = at["console"].as_string(); /* @@ -3135,14 +3137,16 @@ int main( int argc, char** argv ) { auto code = act["account"].as_string(); auto func = act["name"].as_string(); string args; - if( prettyact ) { - args = fc::json::to_pretty_string( act["data"] ); - } - else { - args = fc::json::to_string( act["data"], fc::time_point::maximum() ); - if( !fullact ) { - args = args.substr(0,60) + "..."; - } + if(act.contains("data")) { + if( prettyact ) { + args = fc::json::to_pretty_string( act["data"] ); + } + else { + args = fc::json::to_string( act["data"], fc::time_point::maximum() ); + if( !fullact ) { + args = args.substr(0,60) + "..."; + } + } } out << std::setw(24) << std::right<< (code +"::" + func) << " => " << left << std::setw(13) << receiver; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 172c5291967..0ce4ddaa645 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -70,6 +70,7 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/privacy_tls_test.py ${CMAKE_CURRENT_B configure_file(${CMAKE_CURRENT_SOURCE_DIR}/privacy_scenario_3_test.py ${CMAKE_CURRENT_BINARY_DIR}/privacy_scenario_3_test.py COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/privacy_forked_network.py ${CMAKE_CURRENT_BINARY_DIR}/privacy_forked_network.py COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/read_only_query_tests.py ${CMAKE_CURRENT_BINARY_DIR}/read_only_query_tests.py COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cleos_action_no_params.py ${CMAKE_CURRENT_BINARY_DIR}/cleos_action_no_params.py COPYONLY) #To run plugin_test with all log from blockchain displayed, put --verbose after --, i.e. plugin_test -- --verbose add_test(NAME plugin_test COMMAND plugin_test --report_level=detailed --color_output) @@ -138,6 +139,8 @@ add_test(NAME privacy_forked_network COMMAND tests/privacy_forked_network.py -p set_property(TEST privacy_forked_network PROPERTY LABELS nonparallelizable_tests) add_test(NAME read_only_query COMMAND tests/read_only_query_tests.py -p 1 -v --dump-error-detail WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) set_property(TEST read_only_query PROPERTY LABELS nonparallelizable_tests) +add_test(NAME cleos_action_no_params COMMAND tests/cleos_action_no_params.py WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +set_property(TEST cleos_action_no_params PROPERTY LABELS nonparallelizable_tests) # Long running tests add_test(NAME nodeos_sanity_lr_test COMMAND tests/nodeos_run_test.py -v --sanity-test --clean-run --dump-error-detail WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) diff --git a/tests/cleos_action_no_params.py b/tests/cleos_action_no_params.py new file mode 100755 index 00000000000..9e61a9477f9 --- /dev/null +++ b/tests/cleos_action_no_params.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python3 + +from testUtils import Account +from testUtils import Utils +from testUtils import ReturnType +from Cluster import Cluster +from WalletMgr import WalletMgr +from TestHelper import TestHelper +import subprocess # for subprocess.CalledProcessError + +############################################################### +# cleos_action_no_params +# +# Tests that cleos does not report error when no "data" field +# is present in action results. This happens if contract action +# does not have anhy parameters +# +# To easily test this against an older version, simply copy +# cleos executable from older build into programs/cleos/cleos +# +############################################################### + +Print=Utils.Print +errorExit=Utils.errorExit + +args=TestHelper.parse_args({"-p","-n","-d","-s","--nodes-file","--seed" + ,"--dump-error-details","-v","--leave-running" + ,"--clean-run","--keep-logs"}) + +pnodes=args.p +topo=args.s +delay=args.d +total_nodes = pnodes if args.n < pnodes else args.n +debug=args.v +nodesFile=args.nodes_file +dontLaunch=nodesFile is not None +seed=args.seed +dontKill=args.leave_running +dumpErrorDetails=args.dump_error_details +killAll=args.clean_run +keepLogs=args.keep_logs + +killWallet=not dontKill +killEosInstances=not dontKill +if nodesFile is not None: + killEosInstances=False + +Utils.Debug=debug +testSuccessful=False + +cluster=Cluster(walletd=True) + +walletMgr=WalletMgr(True) +EOSIO_ACCT_PRIVATE_DEFAULT_KEY = "5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3" +EOSIO_ACCT_PUBLIC_DEFAULT_KEY = "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" +contractDir='unittests/contracts/' +wasmFile='test_action_no_param.wasm' +abiFile='test_action_no_param.abi' + +try: + cluster.killall(allInstances=False) + cluster.cleanup() + + Print ("producing nodes: %s, non-producing nodes: %d, topology: %s, delay between nodes launch(seconds): %d" % + (pnodes, total_nodes-pnodes, topo, delay)) + + Print("Stand up cluster") + if cluster.launch(pnodes=1, totalNodes=1) is False: + errorExit("Failed to stand up eos cluster.") + + Print ("Wait for Cluster stabilization") + # wait for cluster to start producing blocks + if not cluster.waitOnClusterBlockNumSync(3): + errorExit("Cluster never stabilized") + + Print("Creating test account") + testacct = Account('testacct') + testacct.ownerPublicKey = EOSIO_ACCT_PUBLIC_DEFAULT_KEY + testacct.activePublicKey = EOSIO_ACCT_PUBLIC_DEFAULT_KEY + cluster.createAccountAndVerify(testacct, cluster.eosioAccount, buyRAM=70000) + + Print("Validating accounts after bootstrap") + cluster.validateAccounts([testacct]) + + node = cluster.getNode() + + Print("Loading contract") + node.publishContract(testacct, contractDir, wasmFile, abiFile, waitForTransBlock=True) + + Print("Test action with no parameters") + cmdArr= [Utils.EosClientPath, '-v', 'push', 'action', 'testacct', 'foo', '[]', '-p', 'testacct@active'] + clargs = node.eosClientArgs().split() + for x in clargs[::-1]: + cmdArr.insert(1, x) + # we need to use checkoutput here because pushMessages uses the -j option which suppresses error message + try: + result = Utils.checkOutput(cmdArr, ignoreError=False) + Print("result= ", result) + + testSuccessful=True + except subprocess.CalledProcessError as e: + Print('error running cleos') + Print('cmd= ', e.cmd) + Print('output= ', e.output.decode("utf-8")) + + assert testSuccessful + +finally: + TestHelper.shutdown(cluster, walletMgr, testSuccessful, killEosInstances, killWallet) + +exit(0) diff --git a/unittests/contracts/CMakeLists.txt b/unittests/contracts/CMakeLists.txt index 63f993cea3c..9c49b6def13 100644 --- a/unittests/contracts/CMakeLists.txt +++ b/unittests/contracts/CMakeLists.txt @@ -14,3 +14,5 @@ file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/kv_bios.abi DESTINATION ${CMAKE_CURRENT_BI file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/kv_bios.wasm DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/read_only_query_tests.abi DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/read_only_query_tests.wasm DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/test_action_no_param.abi DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/test_action_no_param.wasm DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/) diff --git a/unittests/contracts/test_action_no_param.abi b/unittests/contracts/test_action_no_param.abi new file mode 100644 index 00000000000..0915bb50f77 --- /dev/null +++ b/unittests/contracts/test_action_no_param.abi @@ -0,0 +1,37 @@ +{ + "____comment": "This file was generated with eosio-abigen. DO NOT EDIT ", + "version": "eosio::abi/1.1", + "types": [], + "structs": [ + { + "name": "bar", + "base": "", + "fields": [ + { + "name": "param", + "type": "int32" + } + ] + }, + { + "name": "foo", + "base": "", + "fields": [] + } + ], + "actions": [ + { + "name": "bar", + "type": "bar", + "ricardian_contract": "" + }, + { + "name": "foo", + "type": "foo", + "ricardian_contract": "" + } + ], + "tables": [], + "ricardian_clauses": [], + "variants": [] +} \ No newline at end of file diff --git a/unittests/contracts/test_action_no_param.wasm b/unittests/contracts/test_action_no_param.wasm new file mode 100755 index 00000000000..c960c0afa19 Binary files /dev/null and b/unittests/contracts/test_action_no_param.wasm differ