diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp index 4fd1f8c4..1bf1dbf5 100644 --- a/src/test/rpc_wallet_tests.cpp +++ b/src/test/rpc_wallet_tests.cpp @@ -38,6 +38,10 @@ extern Value CallRPC(string args); extern CWallet* pwalletMain; +bool find_error(const Object& objError, const std::string& expected) { + return find_value(objError, "message").get_str().find(expected) != string::npos; +} + BOOST_FIXTURE_TEST_SUITE(rpc_wallet_tests, TestingSetup) BOOST_AUTO_TEST_CASE(rpc_addmultisig) @@ -646,9 +650,6 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_async_operations_parallel_cancel) std::vector ids = q->getAllOperationIds(); BOOST_CHECK(ids.size()==numOperations); q->closeAndWait(); - - // the shared counter should equal the number of successful operations. - BOOST_CHECK_NE(numOperations, gCounter.load()); int numSuccess = 0; int numCancelled = 0; @@ -725,6 +726,11 @@ BOOST_AUTO_TEST_CASE(rpc_z_getoperations) Object resultObj = resultArray.front().get_obj(); Value resultId = find_value(resultObj, "id"); BOOST_CHECK_EQUAL(id.get_str(), resultId.get_str()); + + // verify the operation has been removed + BOOST_CHECK_NO_THROW(result = CallRPC("z_getoperationresult [\"" + id.get_str() + "\"]")); + resultArray = result.get_array(); + BOOST_CHECK(resultArray.size() == 0); } // operations removed @@ -746,15 +752,23 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_parameters) BOOST_CHECK_THROW(CallRPC("z_sendmany too many args here"), runtime_error); // bad from address - BOOST_CHECK_THROW(CallRPC("z_sendmany INVALIDmwehwBzEHJTB5hiyxjmVkuFu9CHD2Cojjs []"), runtime_error); + BOOST_CHECK_THROW(CallRPC("z_sendmany " + "INVALIDmwehwBzEHJTB5hiyxjmVkuFu9CHD2Cojjs []"), runtime_error); // empty amounts - BOOST_CHECK_THROW(CallRPC("z_sendmany mwehwBzEHJTB5hiyxjmVkuFu9CHD2Cojjs []"), runtime_error); + BOOST_CHECK_THROW(CallRPC("z_sendmany " + "mwehwBzEHJTB5hiyxjmVkuFu9CHD2Cojjs []"), runtime_error); // don't have the spending key for this address - BOOST_CHECK_THROW(CallRPC("z_sendmany tnpoQJVnYBZZqkFadj2bJJLThNCxbADGB5gSGeYTAGGrT5tejsxY9Zc1BtY8nnHmZkBUkJ1oSfbhTJhm72WiZizvkZz5aH1 []"), runtime_error); + BOOST_CHECK_THROW(CallRPC("z_sendmany " + "tnpoQJVnYBZZqkFadj2bJJLThNCxbADGB5gSGeYTAGGrT5tejsxY9Zc1BtY8nnHmZkB" + "UkJ1oSfbhTJhm72WiZizvkZz5aH1 []"), runtime_error); // duplicate address - BOOST_CHECK_THROW(CallRPC("z_sendmany mwehwBzEHJTB5hiyxjmVkuFu9CHD2Cojjs [{\"address\":\"mvBkHw3UTeV2ivipmSA6uo8yjN4DqZ5KoG\", \"amount\":50.0}, {\"address\":\"mvBkHw3UTeV2ivipmSA6uo8yjN4DqZ5KoG\", \"amount\":12.0} ]"), runtime_error); + BOOST_CHECK_THROW(CallRPC("z_sendmany " + "mwehwBzEHJTB5hiyxjmVkuFu9CHD2Cojjs " + "[{\"address\":\"mvBkHw3UTeV2ivipmSA6uo8yjN4DqZ5KoG\", \"amount\":50.0}," + " {\"address\":\"mvBkHw3UTeV2ivipmSA6uo8yjN4DqZ5KoG\", \"amount\":12.0} ]" + ), runtime_error); // memo bigger than allowed length of ZC_MEMO_SIZE std::vector v (2 * (ZC_MEMO_SIZE+1)); // x2 for hexadecimal string format @@ -762,32 +776,33 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_parameters) std::string badmemo(v.begin(), v.end()); CZCPaymentAddress pa = pwalletMain->GenerateNewZKey(); std::string zaddr1 = pa.ToString(); - BOOST_CHECK_THROW(CallRPC(string("z_sendmany mwehwBzEHJTB5hiyxjmVkuFu9CHD2Cojjs ") + "[{\"address\":\"" + zaddr1 + "\", \"amount\":123.456}]"), runtime_error); + BOOST_CHECK_THROW(CallRPC(string("z_sendmany mwehwBzEHJTB5hiyxjmVkuFu9CHD2Cojjs ") + + "[{\"address\":\"" + zaddr1 + "\", \"amount\":123.456}]"), runtime_error); // Test constructor of AsyncRPCOperation_sendmany try { std::shared_ptr operation(new AsyncRPCOperation_sendmany("",{}, {}, -1)); } catch (const Object& objError) { - BOOST_CHECK( find_value(objError, "message").get_str().find("Minconf cannot be negative") != string::npos); + BOOST_CHECK( find_error(objError, "Minconf cannot be negative")); } try { std::shared_ptr operation(new AsyncRPCOperation_sendmany("",{}, {}, 1)); } catch (const Object& objError) { - BOOST_CHECK( find_value(objError, "message").get_str().find("From address parameter missing")!= string::npos); + BOOST_CHECK( find_error(objError, "From address parameter missing")); } try { std::shared_ptr operation( new AsyncRPCOperation_sendmany("mwehwBzEHJTB5hiyxjmVkuFu9CHD2Cojjs", {}, {}, 1) ); } catch (const Object& objError) { - BOOST_CHECK( find_value(objError, "message").get_str().find("No recipients")!= string::npos); + BOOST_CHECK( find_error(objError, "No recipients")); } try { std::vector recipients = { SendManyRecipient("dummy",1.0, "") }; std::shared_ptr operation( new AsyncRPCOperation_sendmany("INVALID", recipients, {}, 1) ); } catch (const Object& objError) { - BOOST_CHECK( find_value(objError, "message").get_str().find("payment address is invalid")!= string::npos); + BOOST_CHECK( find_error(objError, "payment address is invalid")); } // This test is for testnet addresses which begin with 't' not 'z'. @@ -795,7 +810,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_parameters) std::vector recipients = { SendManyRecipient("dummy",1.0, "") }; std::shared_ptr operation( new AsyncRPCOperation_sendmany("zcMuhvq8sEkHALuSU2i4NbNQxshSAYrpCExec45ZjtivYPbuiFPwk6WHy4SvsbeZ4siy1WheuRGjtaJmoD1J8bFqNXhsG6U", recipients, {}, 1) ); } catch (const Object& objError) { - BOOST_CHECK( find_value(objError, "message").get_str().find("payment address is for wrong network type")!= string::npos); + BOOST_CHECK( find_error(objError, "payment address is for wrong network type")); } // Note: The following will crash as a google test because AsyncRPCOperation_sendmany @@ -804,7 +819,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_parameters) std::vector recipients = { SendManyRecipient("dummy",1.0, "") }; std::shared_ptr operation( new AsyncRPCOperation_sendmany("tnpoQJVnYBZZqkFadj2bJJLThNCxbADGB5gSGeYTAGGrT5tejsxY9Zc1BtY8nnHmZkBUkJ1oSfbhTJhm72WiZizvkZz5aH1", recipients, {}, 1) ); } catch (const Object& objError) { - BOOST_CHECK( find_value(objError, "message").get_str().find("no spending key found for zaddr")!= string::npos); + BOOST_CHECK( find_error(objError, "no spending key found for zaddr")); } } @@ -869,7 +884,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_internals) try { proxy.get_memo_from_hex_string(bigmemo); } catch (const Object& objError) { - BOOST_CHECK( find_value(objError, "message").get_str().find("too big")!= string::npos); + BOOST_CHECK( find_error(objError, "too big")); } // invalid hexadecimal string @@ -879,18 +894,18 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_internals) try { proxy.get_memo_from_hex_string(badmemo); } catch (const Object& objError) { - BOOST_CHECK( find_value(objError, "message").get_str().find("hexadecimal format")!= string::npos); + BOOST_CHECK( find_error(objError, "hexadecimal format")); } // odd length hexadecimal string std::fill(v.begin(),v.end(), 'A'); v.resize(v.size() - 1); - BOOST_CHECK(v.size() %2 == 1); // odd length + assert(v.size() %2 == 1); // odd length std::string oddmemo(v.begin(), v.end()); try { proxy.get_memo_from_hex_string(oddmemo); } catch (const Object& objError) { - BOOST_CHECK( find_value(objError, "message").get_str().find("hexadecimal format")!= string::npos); + BOOST_CHECK( find_error(objError, "hexadecimal format")); } } @@ -956,9 +971,17 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_internals) // Enable test mode so tx is not sent static_cast(operation.get())->testmode = true; + + // Pretend that the operation completed successfully + proxy.set_state(OperationStatus::SUCCESS); - // No taddr inputs, so signed tx is the same as unsigned. + // Verify test mode is returning output (since no input taddrs, signed and unsigned are the same). BOOST_CHECK_NO_THROW( proxy.sign_send_raw_transaction(obj) ); + Value result = operation->getResult(); + BOOST_CHECK(!result.is_null()); + Object resultObj = result.get_obj(); + std::string hex = find_value(resultObj, "hex").get_str(); + BOOST_CHECK_EQUAL(hex, raw); } diff --git a/src/wallet/asyncrpcoperation_sendmany.h b/src/wallet/asyncrpcoperation_sendmany.h index df10a2ce..df9c3d8d 100644 --- a/src/wallet/asyncrpcoperation_sendmany.h +++ b/src/wallet/asyncrpcoperation_sendmany.h @@ -162,6 +162,10 @@ public: void sign_send_raw_transaction(Object obj) { delegate->sign_send_raw_transaction(obj); } + + void set_state(OperationStatus state) { + delegate->state_.store(state); + } };