From 078dff3f9cd4a159bd82bfbd4c028e13634a9d16 Mon Sep 17 00:00:00 2001 From: Dariusz Kedzierski Date: Mon, 8 Apr 2019 09:33:30 +0200 Subject: [PATCH 1/5] WIP: more proposal payment tests. Minor logging rework --- ...n_test.py => proposal_payment_test_001.py} | 159 ++---------- .../proposal_payment_test_002.py | 234 +++++++++++++++++ .../proposal_payment_test_003.py | 238 ++++++++++++++++++ .../proposal_payment_test_004.py | 238 ++++++++++++++++++ .../steem_utils/steem_runner.py | 13 +- .../steem_utils/steem_tools.py | 14 +- .../steempy_sps_tests/steempy_sps_tests.py | 46 ++-- .../tests/steempy_sps_tests/test_utils.py | 165 ++++++++++++ 8 files changed, 921 insertions(+), 186 deletions(-) rename python_scripts/tests/steempy_sps_tests/{proposal_payment_distribution_test.py => proposal_payment_test_001.py} (56%) create mode 100755 python_scripts/tests/steempy_sps_tests/proposal_payment_test_002.py create mode 100755 python_scripts/tests/steempy_sps_tests/proposal_payment_test_003.py create mode 100755 python_scripts/tests/steempy_sps_tests/proposal_payment_test_004.py create mode 100644 python_scripts/tests/steempy_sps_tests/test_utils.py diff --git a/python_scripts/tests/steempy_sps_tests/proposal_payment_distribution_test.py b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_001.py similarity index 56% rename from python_scripts/tests/steempy_sps_tests/proposal_payment_distribution_test.py rename to python_scripts/tests/steempy_sps_tests/proposal_payment_test_001.py index bfe4011c33..17c78514e6 100755 --- a/python_scripts/tests/steempy_sps_tests/proposal_payment_distribution_test.py +++ b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_001.py @@ -6,13 +6,14 @@ import sys import steem_utils.steem_runner import steem_utils.steem_tools +import test_utils LOG_LEVEL = logging.INFO LOG_FORMAT = "%(asctime)-15s - %(name)s - %(levelname)s - %(message)s" -MAIN_LOG_PATH = "./sps_proposal_payment.log" +MAIN_LOG_PATH = "./sps_proposal_payment_001.log" -MODULE_NAME = "SPS Tester via steempy - proposal payment test" +MODULE_NAME = "SPS-Tester-via-steempy" logger = logging.getLogger(MODULE_NAME) logger.setLevel(LOG_LEVEL) @@ -35,85 +36,11 @@ sys.exit(1) -# 1. create few proposals. +# 1. create few proposals - in this scenatio all proposals have the same start and end date # 2. vote on them to show differences in asset distribution (depending on collected votes) # 3. wait for proposal payment phase # 4. verify (using account history and by checking regular account balance) that given accounts have been correctly paid. - -# create_account "initminer" "pychol" "" true -def create_accounts(node, creator, accounts): - for account in accounts: - logger.info("Creating account: {}".format(account['name'])) - node.commit.create_account(account['name'], - owner_key=account['public_key'], - active_key=account['public_key'], - posting_key=account['public_key'], - memo_key=account['public_key'], - store_keys = False, - creator=creator, - asset='TESTS' - ) - steem_utils.steem_tools.wait_for_blocks_produced(5, node.url) - - -# transfer_to_vesting initminer pychol "310.000 TESTS" true -def transfer_to_vesting(node, from_account, accounts, amount, asset): - for acnt in accounts: - logger.info("Transfer to vesting from {} to {} amount {} {}".format( - from_account, acnt['name'], amount, asset) - ) - - node.commit.transfer_to_vesting(amount, to = acnt['name'], - account = from_account, asset = asset - ) - steem_utils.steem_tools.wait_for_blocks_produced(5, node.url) - - -# transfer initminer pychol "399.000 TESTS" "initial transfer" true -# transfer initminer pychol "398.000 TBD" "initial transfer" true -def transfer_assets_to_accounts(node, from_account, accounts, amount, asset): - for acnt in accounts: - logger.info("Transfer from {} to {} amount {} {}".format(from_account, - acnt['name'], amount, asset) - ) - node.commit.transfer(acnt['name'], amount, asset, - memo = "initial transfer", account = from_account - ) - steem_utils.steem_tools.wait_for_blocks_produced(5, node.url) - - -def transfer_assets_to_treasury(node, from_account, treasury_account, amount, asset): - logger.info("Transfer from {} to {} amount {} {}".format(from_account, - treasury_account, amount, asset) - ) - node.commit.transfer(treasury_account, amount, asset, - memo = "initial transfer", account = from_account - ) - steem_utils.steem_tools.wait_for_blocks_produced(2, node.url) - - -def get_permlink(account): - return "steempy-proposal-title-{}".format(account) - -def create_posts(node, accounts): - logger.info("Creating posts...") - for acnt in accounts: - logger.info("New post ==> ({},{},{},{},{})".format( - "Steempy proposal title [{}]".format(acnt['name']), - "Steempy proposal body [{}]".format(acnt['name']), - acnt['name'], - get_permlink(acnt['name']), - "proposals" - )) - node.commit.post("Steempy proposal title [{}]".format(acnt['name']), - "Steempy proposal body [{}]".format(acnt['name']), - acnt['name'], - permlink = get_permlink(acnt['name']), - tags = "proposals") - steem_utils.steem_tools.wait_for_blocks_produced(5, node.url) - - def create_proposals(node, accounts, start_date, end_date): logger.info("Creating proposals...") for acnt in accounts: @@ -124,7 +51,7 @@ def create_proposals(node, accounts, start_date, end_date): end_date, "24.000 TBD", "Proposal from account {}".format(acnt['name']), - get_permlink(acnt['name']) + test_utils.get_permlink(acnt['name']) )) node.commit.create_proposal( acnt['name'], @@ -133,39 +60,11 @@ def create_proposals(node, accounts, start_date, end_date): end_date, "24.000 TBD", "Proposal from account {}".format(acnt['name']), - get_permlink(acnt['name']) + test_utils.get_permlink(acnt['name']) ) steem_utils.steem_tools.wait_for_blocks_produced(5, node.url) -def vote_proposals(node, accounts): - logger.info("Voting proposals...") - for acnt in accounts: - proposal_set = [x for x in range(0, len(accounts))] - logger.info("Account {} voted for proposals: {}".format(acnt["name"], ",".join(str(x) for x in proposal_set))) - node.commit.update_proposal_votes(acnt["name"], proposal_set, True) - steem_utils.steem_tools.wait_for_blocks_produced(5, node.url) - - -def list_proposals(node, start_date, status): - proposals = node.list_proposals(start_date, "by_start_date", "direction_ascending", 1000, status) - ret = [] - votes = [] - for proposal in proposals: - ret.append("{}:{}".format(proposal.get('id', 'Error'), proposal.get('total_votes', 'Error'))) - votes.append(int(proposal.get('total_votes', -1))) - logger.info("Listing proposals with status {} (id:total_votes): {}".format(status, ",".join(ret))) - return votes - -def print_balance(node, accounts): - balances = [] - for acnt in accounts: - ret = node.get_account(acnt['name']) - logger.info("{} :: balance ==> {}, sbd_balance ==> {}".format(acnt['name'], ret.get('balance', 'Error'), ret.get('sbd_balance', 'Error'))) - balances.append(ret.get('sbd_balance', 'Error')) - return balances - - if __name__ == '__main__': logger.info("Performing SPS tests") import argparse @@ -226,36 +125,34 @@ def print_balance(node, accounts): ) # create accounts - create_accounts(node_client, args.creator, accounts) + test_utils.create_accounts(node_client, args.creator, accounts) # tranfer to vesting - transfer_to_vesting(node_client, args.creator, accounts, "300.000", + test_utils.transfer_to_vesting(node_client, args.creator, accounts, "300.000", "TESTS" ) # transfer assets to accounts - transfer_assets_to_accounts(node_client, args.creator, accounts, + test_utils.transfer_assets_to_accounts(node_client, args.creator, accounts, "400.000", "TESTS" ) - transfer_assets_to_accounts(node_client, args.creator, accounts, + test_utils.transfer_assets_to_accounts(node_client, args.creator, accounts, "400.000", "TBD" ) logger.info("Balances for accounts after initial transfer") - print_balance(node_client, accounts) + test_utils.print_balance(node_client, accounts) # transfer assets to treasury - transfer_assets_to_treasury(node_client, args.creator, args.treasury, + test_utils.transfer_assets_to_treasury(node_client, args.creator, args.treasury, "1000000.000", "TESTS" ) - transfer_assets_to_treasury(node_client, args.creator, args.treasury, + test_utils.transfer_assets_to_treasury(node_client, args.creator, args.treasury, "1000000.000", "TBD" ) - - logger.info("Balances for treasury account after initial transfer") - print_balance(node_client, [{'name' : args.treasury}]) + test_utils.print_balance(node_client, [{'name' : args.treasury}]) # create post for valid permlinks - create_posts(node_client, accounts) + test_utils.create_posts(node_client, accounts) import datetime import dateutil.parser @@ -278,25 +175,23 @@ def print_balance(node, accounts): create_proposals(node_client, accounts, start_date_str, end_date_str) # list proposals with inactive status, it shoud be list of pairs id:total_votes - list_proposals(node_client, start_date_str, "inactive") + test_utils.list_proposals(node_client, start_date_str, "inactive") # each account is voting on proposal - vote_proposals(node_client, accounts) + test_utils.vote_proposals(node_client, accounts) # list proposals with inactive status, it shoud be list of pairs id:total_votes - votes = list_proposals(node_client, start_date_str, "inactive") + votes = test_utils.list_proposals(node_client, start_date_str, "inactive") for vote in votes: #should be 0 for all assert vote == 0, "All votes should be equal to 0" logger.info("Balances for accounts after creating proposals") - balances = print_balance(node_client, accounts) + balances = test_utils.print_balance(node_client, accounts) for balance in balances: #should be 390.000 TBD for all assert balance == '390.000 TBD', "All balances should be equal to 390.000 TBD" - - logger.info("Balances for treasury after creating proposals") - print_balance(node_client, [{'name' : args.treasury}]) + test_utils.print_balance(node_client, [{'name' : args.treasury}]) # move forward in time to see if proposals are paid # moving is made in 1h increments at a time, after each @@ -311,10 +206,9 @@ def print_balance(node, accounts): node_client.debug_generate_blocks_until(wif, current_date_str, False) logger.info("Balances for accounts at time: {}".format(current_date_str)) - print_balance(node_client, accounts) - logger.info("Balances for treasury at time: {}".format(current_date_str)) - print_balance(node_client, [{'name' : args.treasury}]) - votes = list_proposals(node_client, start_date_str, "active") + test_utils.print_balance(node_client, accounts) + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + votes = test_utils.list_proposals(node_client, start_date_str, "active") for vote in votes: # should be > 0 for all assert vote > 0, "All votes counts shoud be greater than 0" @@ -323,13 +217,12 @@ def print_balance(node, accounts): logger.info("Moving to date: {}".format(end_date_blocks_str)) node_client.debug_generate_blocks_until(wif, end_date_blocks_str, False) logger.info("Balances for accounts at time: {}".format(end_date_blocks_str)) - balances = print_balance(node_client, accounts) + balances = test_utils.print_balance(node_client, accounts) for balance in balances: # shoud be 438.000 TBD for all assert balance == '438.000 TBD', "All balances should be equal 438.000 TBD" - logger.info("Balances for treasury at time: {}".format(end_date_blocks_str)) - print_balance(node_client, [{'name' : args.treasury}]) - votes = list_proposals(node_client, start_date_str, "expired") + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + votes = test_utils.list_proposals(node_client, start_date_str, "expired") for vote in votes: # should be > 0 for all assert vote > 0, "All votes counts shoud be greater than 0" diff --git a/python_scripts/tests/steempy_sps_tests/proposal_payment_test_002.py b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_002.py new file mode 100755 index 0000000000..6c046cb7b2 --- /dev/null +++ b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_002.py @@ -0,0 +1,234 @@ +#!/usr/bin/python3 + +from uuid import uuid4 +from time import sleep +import logging +import sys +import steem_utils.steem_runner +import steem_utils.steem_tools +import test_utils + + +LOG_LEVEL = logging.INFO +LOG_FORMAT = "%(asctime)-15s - %(name)s - %(levelname)s - %(message)s" +MAIN_LOG_PATH = "./sps_proposal_payment_002.log" + +MODULE_NAME = "SPS-Tester-via-steempy" +logger = logging.getLogger(MODULE_NAME) +logger.setLevel(LOG_LEVEL) + +ch = logging.StreamHandler(sys.stdout) +ch.setLevel(LOG_LEVEL) +ch.setFormatter(logging.Formatter(LOG_FORMAT)) + +fh = logging.FileHandler(MAIN_LOG_PATH) +fh.setLevel(LOG_LEVEL) +fh.setFormatter(logging.Formatter(LOG_FORMAT)) + +if not logger.hasHandlers(): + logger.addHandler(ch) + logger.addHandler(fh) + +try: + from steem import Steem +except Exception as ex: + logger.error("SteemPy library is not installed.") + sys.exit(1) + + +# 1. create few proposals - in this scenario proposals have different starting and ending dates +# 2. vote on them to show differences in asset distribution (depending on collected votes) +# 3. wait for proposal payment phase +# 4. verify (using account history and by checking regular account balance) that given accounts have been correctly paid. + + +if __name__ == '__main__': + logger.info("Performing SPS tests") + import argparse + parser = argparse.ArgumentParser() + parser.add_argument("creator", help = "Account to create test accounts with") + parser.add_argument("treasury", help = "Treasury account") + parser.add_argument("wif", help="Private key for creator account") + parser.add_argument("--node-url", dest="node_url", default="http://127.0.0.1:8090", help="Url of working steem node") + parser.add_argument("--run-steemd", dest="steemd_path", help = "Path to steemd executable. Warning: using this option will erase contents of selected steemd working directory.") + parser.add_argument("--working_dir", dest="steemd_working_dir", default="/tmp/steemd-data/", help = "Path to steemd working directory") + parser.add_argument("--config_path", dest="steemd_config_path", default="./steem_utils/resources/config.ini.in",help = "Path to source config.ini file") + parser.add_argument("--no-erase-proposal", action='store_false', dest = "no_erase_proposal", help = "Do not erase proposal created with this test") + + + args = parser.parse_args() + + node = None + + if args.steemd_path: + logger.info("Running steemd via {} in {} with config {}".format(args.steemd_path, + args.steemd_working_dir, + args.steemd_config_path) + ) + + node = steem_utils.steem_runner.SteemNode( + args.steemd_path, + args.steemd_working_dir, + args.steemd_config_path + ) + + node_url = args.node_url + wif = args.wif + + if len(wif) == 0: + logger.error("Private-key is not set in config.ini") + sys.exit(1) + + logger.info("Using node at: {}".format(node_url)) + logger.info("Using private-key: {}".format(wif)) + + accounts = [ + # place accounts here in the format: {'name' : name, 'private_key' : private-key, 'public_key' : public-key} + {"name" : "tester001", "private_key" : "5JBuekd1sVXXK3wBu6nvPB1LWypZ83BYdu7tGcUNYVd42xQGGh1", "public_key" : "TST5kSj1yTzBz3PDoJ5QUyVVagdgYfs8Y4vVsZG3dqKJU8hg7WmQN"}, + {"name" : "tester002", "private_key" : "5KgfcV9bgEen3v9mxkoGw6Rhuf2giDRZTHZjzwisjkrpF4FUh3N", "public_key" : "TST5gQPYm5bs9dRPHpqBy6dU32M8FcoKYFdF4YWEChUarc9FdYHzn"}, + {"name" : "tester003", "private_key" : "5Jz3fcrrgKMbL8ncpzTdQmdRVHdxMhi8qScoxSR3TnAFUcdyD5N", "public_key" : "TST57wy5bXyJ4Z337Bo6RbinR6NyTRJxzond5dmGsP4gZ51yN6Zom"}, + {"name" : "tester004", "private_key" : "5KcmobLVMSAVzETrZxfEGG73Zvi5SKTgJuZXtNgU3az2VK3Krye", "public_key" : "TST8dPte853xAuLMDV7PTVmiNMRwP6itMyvSmaht7J5tVczkDLa5K"}, + ] + + if not accounts: + logger.error("Accounts array is empty, please add accounts in a form {\"name\" : name, \"private_key\" : private_key, \"public_key\" : public_key}") + sys.exit(1) + + keys = [wif] + for account in accounts: + keys.append(account["private_key"]) + + if node is not None: + node.run_steem_node(["--enable-stale-production"]) + try: + if node is None or node.is_running(): + node_client = Steem(nodes = [node_url], no_broadcast = False, + keys = keys + ) + + # create accounts + test_utils.create_accounts(node_client, args.creator, accounts) + # tranfer to vesting + test_utils.transfer_to_vesting(node_client, args.creator, accounts, "300.000", + "TESTS" + ) + # transfer assets to accounts + test_utils.transfer_assets_to_accounts(node_client, args.creator, accounts, + "400.000", "TESTS" + ) + + test_utils.transfer_assets_to_accounts(node_client, args.creator, accounts, + "400.000", "TBD" + ) + + logger.info("Balances for accounts after initial transfer") + test_utils.print_balance(node_client, accounts) + # transfer assets to treasury + test_utils.transfer_assets_to_treasury(node_client, args.creator, args.treasury, + "1000000.000", "TESTS" + ) + + test_utils.transfer_assets_to_treasury(node_client, args.creator, args.treasury, + "1000000.000", "TBD" + ) + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + # create post for valid permlinks + test_utils.create_posts(node_client, accounts) + + now = node_client.get_dynamic_global_properties().get('time', None) + if now is None: + raise ValueError("Head time is None") + now = test_utils.date_from_iso(now) + + proposal_data = [ + ['tester001', 1 + 0, 5, '24.000 TBD'], # starts one day from now and lasts five days + ['tester002', 1 + 0, 2, '24.000 TBD'], # starts one day from now and lasts two days + ['tester003', 1 + 2, 1, '24.000 TBD'], # starts three days from now and lasts one day + ['tester004', 1 + 4, 1, '24.000 TBD'] # starts four days from now and lasts one day + ] + + proposals = [ + # pace proposals here in the format: {'creator' : creator, 'receiver' : receiver, 'start_date' : start-date, 'end_date' : end_date} + + ] + + for pd in proposal_data: + start_date, end_date = test_utils.get_start_and_end_date(now, pd[1], pd[2]) + proposal = {'creator' : pd[0], 'receiver' : pd[0], 'start_date' : start_date, 'end_date' : end_date, 'daily_pay' : pd[3]} + proposals.append(proposal) + + import datetime + test_start_date = now + datetime.timedelta(days = 1) + test_start_date_iso = test_utils.date_to_iso(test_start_date) + + test_end_date = test_start_date + datetime.timedelta(days = 6, hours = 1) + test_end_date_iso = test_utils.date_to_iso(test_end_date) + + test_utils.create_proposals(node_client, proposals) + + # list proposals with inactive status, it shoud be list of pairs id:total_votes + test_utils.list_proposals(node_client, test_start_date_iso, "inactive") + + # each account is voting on proposal + test_utils.vote_proposals(node_client, accounts) + + # list proposals with inactive status, it shoud be list of pairs id:total_votes + votes = test_utils.list_proposals(node_client, test_start_date_iso, "inactive") + for vote in votes: + #should be 0 for all + assert vote == 0, "All votes should be equal to 0" + + logger.info("Balances for accounts after creating proposals") + balances = test_utils.print_balance(node_client, accounts) + for balance in balances: + #should be 390.000 TBD for all + assert balance == '390.000 TBD', "All balances should be equal to 390.000 TBD" + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + # move forward in time to see if proposals are paid + # moving is made in 1h increments at a time, after each + # increment balance is printed + logger.info("Moving to date: {}".format(test_start_date_iso)) + node_client.debug_generate_blocks_until(wif, test_start_date_iso, False) + current_date = test_start_date + while current_date < test_end_date: + current_date = current_date + datetime.timedelta(hours = 1) + current_date_iso = test_utils.date_to_iso(current_date) + + logger.info("Moving to date: {}".format(current_date_iso)) + node_client.debug_generate_blocks_until(wif, current_date_iso, False) + + logger.info("Balances for accounts at time: {}".format(current_date_iso)) + test_utils.print_balance(node_client, accounts) + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + votes = test_utils.list_proposals(node_client, test_start_date_iso, "active") + votes = test_utils.list_proposals(node_client, test_start_date_iso, "expired") + votes = test_utils.list_proposals(node_client, test_start_date_iso, "all") + + # move additional hour to ensure that all proposals ended + logger.info("Moving to date: {}".format(test_end_date_iso)) + node_client.debug_generate_blocks_until(wif, test_end_date_iso, False) + logger.info("Balances for accounts at time: {}".format(test_end_date_iso)) + balances = test_utils.print_balance(node_client, accounts) + test_balances = [ + '510.000 TBD', + '438.000 TBD', + '414.000 TBD', + '414.000 TBD', + ] + for idx in range(0, len(test_balances)): + assert balances[idx] == test_balances[idx], "Balances dont match {} != {}".format(balances[idx], test_balances[idx]) + + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + if node is not None: + node.stop_steem_node() + sys.exit(0) + sys.exit(1) + except Exception as ex: + logger.error("Exception: {}".format(ex)) + if node is not None: + node.stop_steem_node() + sys.exit(1) diff --git a/python_scripts/tests/steempy_sps_tests/proposal_payment_test_003.py b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_003.py new file mode 100755 index 0000000000..c4ae391636 --- /dev/null +++ b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_003.py @@ -0,0 +1,238 @@ +#!/usr/bin/python3 + +from uuid import uuid4 +from time import sleep +import logging +import sys +import steem_utils.steem_runner +import steem_utils.steem_tools +import test_utils + + +LOG_LEVEL = logging.INFO +LOG_FORMAT = "%(asctime)-15s - %(name)s - %(levelname)s - %(message)s" +MAIN_LOG_PATH = "./sps_proposal_payment_003.log" + +MODULE_NAME = "SPS-Tester-via-steempy" +logger = logging.getLogger(MODULE_NAME) +logger.setLevel(LOG_LEVEL) + +ch = logging.StreamHandler(sys.stdout) +ch.setLevel(LOG_LEVEL) +ch.setFormatter(logging.Formatter(LOG_FORMAT)) + +fh = logging.FileHandler(MAIN_LOG_PATH) +fh.setLevel(LOG_LEVEL) +fh.setFormatter(logging.Formatter(LOG_FORMAT)) + +if not logger.hasHandlers(): + logger.addHandler(ch) + logger.addHandler(fh) + +try: + from steem import Steem +except Exception as ex: + logger.error("SteemPy library is not installed.") + sys.exit(1) + +# Greedy baby scenario +# 0. In this scenario we have one proposal with huge daily pay and couple with low daily pay +# all proposals have the same number of votes, greedy proposal is first +# 1. create few proposals - in this scenario proposals have the same starting and ending dates +# 2. vote on them to show differences in asset distribution (depending on collected votes) +# 3. wait for proposal payment phase +# 4. verify (using account history and by checking regular account balance) that given accounts have been correctly paid. + +# Expected result: Only greedy baby got paid + + +if __name__ == '__main__': + logger.info("Performing SPS tests") + import argparse + parser = argparse.ArgumentParser() + parser.add_argument("creator", help = "Account to create test accounts with") + parser.add_argument("treasury", help = "Treasury account") + parser.add_argument("wif", help="Private key for creator account") + parser.add_argument("--node-url", dest="node_url", default="http://127.0.0.1:8090", help="Url of working steem node") + parser.add_argument("--run-steemd", dest="steemd_path", help = "Path to steemd executable. Warning: using this option will erase contents of selected steemd working directory.") + parser.add_argument("--working_dir", dest="steemd_working_dir", default="/tmp/steemd-data/", help = "Path to steemd working directory") + parser.add_argument("--config_path", dest="steemd_config_path", default="./steem_utils/resources/config.ini.in",help = "Path to source config.ini file") + parser.add_argument("--no-erase-proposal", action='store_false', dest = "no_erase_proposal", help = "Do not erase proposal created with this test") + + + args = parser.parse_args() + + node = None + + if args.steemd_path: + logger.info("Running steemd via {} in {} with config {}".format(args.steemd_path, + args.steemd_working_dir, + args.steemd_config_path) + ) + + node = steem_utils.steem_runner.SteemNode( + args.steemd_path, + args.steemd_working_dir, + args.steemd_config_path + ) + + node_url = args.node_url + wif = args.wif + + if len(wif) == 0: + logger.error("Private-key is not set in config.ini") + sys.exit(1) + + logger.info("Using node at: {}".format(node_url)) + logger.info("Using private-key: {}".format(wif)) + + accounts = [ + # place accounts here in the format: {'name' : name, 'private_key' : private-key, 'public_key' : public-key} + {"name" : "tester001", "private_key" : "5JBuekd1sVXXK3wBu6nvPB1LWypZ83BYdu7tGcUNYVd42xQGGh1", "public_key" : "TST5kSj1yTzBz3PDoJ5QUyVVagdgYfs8Y4vVsZG3dqKJU8hg7WmQN"}, + {"name" : "tester002", "private_key" : "5KgfcV9bgEen3v9mxkoGw6Rhuf2giDRZTHZjzwisjkrpF4FUh3N", "public_key" : "TST5gQPYm5bs9dRPHpqBy6dU32M8FcoKYFdF4YWEChUarc9FdYHzn"}, + {"name" : "tester003", "private_key" : "5Jz3fcrrgKMbL8ncpzTdQmdRVHdxMhi8qScoxSR3TnAFUcdyD5N", "public_key" : "TST57wy5bXyJ4Z337Bo6RbinR6NyTRJxzond5dmGsP4gZ51yN6Zom"}, + {"name" : "tester004", "private_key" : "5KcmobLVMSAVzETrZxfEGG73Zvi5SKTgJuZXtNgU3az2VK3Krye", "public_key" : "TST8dPte853xAuLMDV7PTVmiNMRwP6itMyvSmaht7J5tVczkDLa5K"}, + ] + + if not accounts: + logger.error("Accounts array is empty, please add accounts in a form {\"name\" : name, \"private_key\" : private_key, \"public_key\" : public_key}") + sys.exit(1) + + keys = [wif] + for account in accounts: + keys.append(account["private_key"]) + + if node is not None: + node.run_steem_node(["--enable-stale-production"]) + try: + if node is None or node.is_running(): + node_client = Steem(nodes = [node_url], no_broadcast = False, + keys = keys + ) + + # create accounts + test_utils.create_accounts(node_client, args.creator, accounts) + # tranfer to vesting + test_utils.transfer_to_vesting(node_client, args.creator, accounts, "300.000", + "TESTS" + ) + # transfer assets to accounts + test_utils.transfer_assets_to_accounts(node_client, args.creator, accounts, + "400.000", "TESTS" + ) + + test_utils.transfer_assets_to_accounts(node_client, args.creator, accounts, + "400.000", "TBD" + ) + + logger.info("Balances for accounts after initial transfer") + test_utils.print_balance(node_client, accounts) + # transfer assets to treasury + test_utils.transfer_assets_to_treasury(node_client, args.creator, args.treasury, + "1000000.000", "TESTS" + ) + + test_utils.transfer_assets_to_treasury(node_client, args.creator, args.treasury, + "1000000.000", "TBD" + ) + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + # create post for valid permlinks + test_utils.create_posts(node_client, accounts) + + now = node_client.get_dynamic_global_properties().get('time', None) + if now is None: + raise ValueError("Head time is None") + now = test_utils.date_from_iso(now) + + proposal_data = [ + ['tester001', 1 + 0, 5, '240000.000 TBD'], # starts one day from now and lasts five days + ['tester002', 1 + 0, 5, '24.000 TBD'], # starts one day from now and lasts two days + ['tester003', 1 + 0, 5, '24.000 TBD'], # starts three days from now and lasts one day + ['tester004', 1 + 0, 5, '24.000 TBD'] # starts four days from now and lasts one day + ] + + proposals = [ + # pace proposals here in the format: {'creator' : creator, 'receiver' : receiver, 'start_date' : start-date, 'end_date' : end_date} + + ] + + for pd in proposal_data: + start_date, end_date = test_utils.get_start_and_end_date(now, pd[1], pd[2]) + proposal = {'creator' : pd[0], 'receiver' : pd[0], 'start_date' : start_date, 'end_date' : end_date, 'daily_pay' : pd[3]} + proposals.append(proposal) + + import datetime + test_start_date = now + datetime.timedelta(days = 1) + test_start_date_iso = test_utils.date_to_iso(test_start_date) + + test_end_date = test_start_date + datetime.timedelta(days = 6, hours = 1) + test_end_date_iso = test_utils.date_to_iso(test_end_date) + + test_utils.create_proposals(node_client, proposals) + + # list proposals with inactive status, it shoud be list of pairs id:total_votes + test_utils.list_proposals(node_client, test_start_date_iso, "inactive") + + # each account is voting on proposal + test_utils.vote_proposals(node_client, accounts) + + # list proposals with inactive status, it shoud be list of pairs id:total_votes + votes = test_utils.list_proposals(node_client, test_start_date_iso, "inactive") + for vote in votes: + #should be 0 for all + assert vote == 0, "All votes should be equal to 0" + + logger.info("Balances for accounts after creating proposals") + balances = test_utils.print_balance(node_client, accounts) + for balance in balances: + #should be 390.000 TBD for all + assert balance == '390.000 TBD', "All balances should be equal to 390.000 TBD" + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + # move forward in time to see if proposals are paid + # moving is made in 1h increments at a time, after each + # increment balance is printed + logger.info("Moving to date: {}".format(test_start_date_iso)) + node_client.debug_generate_blocks_until(wif, test_start_date_iso, False) + current_date = test_start_date + while current_date < test_end_date: + current_date = current_date + datetime.timedelta(hours = 1) + current_date_iso = test_utils.date_to_iso(current_date) + + logger.info("Moving to date: {}".format(current_date_iso)) + node_client.debug_generate_blocks_until(wif, current_date_iso, False) + + logger.info("Balances for accounts at time: {}".format(current_date_iso)) + test_utils.print_balance(node_client, accounts) + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + votes = test_utils.list_proposals(node_client, test_start_date_iso, "active") + votes = test_utils.list_proposals(node_client, test_start_date_iso, "expired") + votes = test_utils.list_proposals(node_client, test_start_date_iso, "all") + + # move additional hour to ensure that all proposals ended + logger.info("Moving to date: {}".format(test_end_date_iso)) + node_client.debug_generate_blocks_until(wif, test_end_date_iso, False) + logger.info("Balances for accounts at time: {}".format(test_end_date_iso)) + balances = test_utils.print_balance(node_client, accounts) + test_balances = [ + '510.000 TBD', + '438.000 TBD', + '414.000 TBD', + '414.000 TBD', + ] + for idx in range(0, len(test_balances)): + assert balances[idx] == test_balances[idx], "Balances dont match {} != {}".format(balances[idx], test_balances[idx]) + + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + if node is not None: + node.stop_steem_node() + sys.exit(0) + sys.exit(1) + except Exception as ex: + logger.error("Exception: {}".format(ex)) + if node is not None: + node.stop_steem_node() + sys.exit(1) diff --git a/python_scripts/tests/steempy_sps_tests/proposal_payment_test_004.py b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_004.py new file mode 100755 index 0000000000..1f2fad0132 --- /dev/null +++ b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_004.py @@ -0,0 +1,238 @@ +#!/usr/bin/python3 + +from uuid import uuid4 +from time import sleep +import logging +import sys +import steem_utils.steem_runner +import steem_utils.steem_tools +import test_utils + + +LOG_LEVEL = logging.INFO +LOG_FORMAT = "%(asctime)-15s - %(name)s - %(levelname)s - %(message)s" +MAIN_LOG_PATH = "./sps_proposal_payment_004.log" + +MODULE_NAME = "SPS-Tester-via-steempy" +logger = logging.getLogger(MODULE_NAME) +logger.setLevel(LOG_LEVEL) + +ch = logging.StreamHandler(sys.stdout) +ch.setLevel(LOG_LEVEL) +ch.setFormatter(logging.Formatter(LOG_FORMAT)) + +fh = logging.FileHandler(MAIN_LOG_PATH) +fh.setLevel(LOG_LEVEL) +fh.setFormatter(logging.Formatter(LOG_FORMAT)) + +if not logger.hasHandlers(): + logger.addHandler(ch) + logger.addHandler(fh) + +try: + from steem import Steem +except Exception as ex: + logger.error("SteemPy library is not installed.") + sys.exit(1) + +# Greedy baby scenario +# 0. In this scenario we have one proposal with huge daily pay and couple with low daily pay +# all proposals have the same number of votes, greedy proposal is last +# 1. create few proposals - in this scenario proposals have the same starting and ending dates +# 2. vote on them to show differences in asset distribution (depending on collected votes) +# 3. wait for proposal payment phase +# 4. verify (using account history and by checking regular account balance) that given accounts have been correctly paid. + +# Expected result: all got paid. + + +if __name__ == '__main__': + logger.info("Performing SPS tests") + import argparse + parser = argparse.ArgumentParser() + parser.add_argument("creator", help = "Account to create test accounts with") + parser.add_argument("treasury", help = "Treasury account") + parser.add_argument("wif", help="Private key for creator account") + parser.add_argument("--node-url", dest="node_url", default="http://127.0.0.1:8090", help="Url of working steem node") + parser.add_argument("--run-steemd", dest="steemd_path", help = "Path to steemd executable. Warning: using this option will erase contents of selected steemd working directory.") + parser.add_argument("--working_dir", dest="steemd_working_dir", default="/tmp/steemd-data/", help = "Path to steemd working directory") + parser.add_argument("--config_path", dest="steemd_config_path", default="./steem_utils/resources/config.ini.in",help = "Path to source config.ini file") + parser.add_argument("--no-erase-proposal", action='store_false', dest = "no_erase_proposal", help = "Do not erase proposal created with this test") + + + args = parser.parse_args() + + node = None + + if args.steemd_path: + logger.info("Running steemd via {} in {} with config {}".format(args.steemd_path, + args.steemd_working_dir, + args.steemd_config_path) + ) + + node = steem_utils.steem_runner.SteemNode( + args.steemd_path, + args.steemd_working_dir, + args.steemd_config_path + ) + + node_url = args.node_url + wif = args.wif + + if len(wif) == 0: + logger.error("Private-key is not set in config.ini") + sys.exit(1) + + logger.info("Using node at: {}".format(node_url)) + logger.info("Using private-key: {}".format(wif)) + + accounts = [ + # place accounts here in the format: {'name' : name, 'private_key' : private-key, 'public_key' : public-key} + {"name" : "tester001", "private_key" : "5JBuekd1sVXXK3wBu6nvPB1LWypZ83BYdu7tGcUNYVd42xQGGh1", "public_key" : "TST5kSj1yTzBz3PDoJ5QUyVVagdgYfs8Y4vVsZG3dqKJU8hg7WmQN"}, + {"name" : "tester002", "private_key" : "5KgfcV9bgEen3v9mxkoGw6Rhuf2giDRZTHZjzwisjkrpF4FUh3N", "public_key" : "TST5gQPYm5bs9dRPHpqBy6dU32M8FcoKYFdF4YWEChUarc9FdYHzn"}, + {"name" : "tester003", "private_key" : "5Jz3fcrrgKMbL8ncpzTdQmdRVHdxMhi8qScoxSR3TnAFUcdyD5N", "public_key" : "TST57wy5bXyJ4Z337Bo6RbinR6NyTRJxzond5dmGsP4gZ51yN6Zom"}, + {"name" : "tester004", "private_key" : "5KcmobLVMSAVzETrZxfEGG73Zvi5SKTgJuZXtNgU3az2VK3Krye", "public_key" : "TST8dPte853xAuLMDV7PTVmiNMRwP6itMyvSmaht7J5tVczkDLa5K"}, + ] + + if not accounts: + logger.error("Accounts array is empty, please add accounts in a form {\"name\" : name, \"private_key\" : private_key, \"public_key\" : public_key}") + sys.exit(1) + + keys = [wif] + for account in accounts: + keys.append(account["private_key"]) + + if node is not None: + node.run_steem_node(["--enable-stale-production"]) + try: + if node is None or node.is_running(): + node_client = Steem(nodes = [node_url], no_broadcast = False, + keys = keys + ) + + # create accounts + test_utils.create_accounts(node_client, args.creator, accounts) + # tranfer to vesting + test_utils.transfer_to_vesting(node_client, args.creator, accounts, "300.000", + "TESTS" + ) + # transfer assets to accounts + test_utils.transfer_assets_to_accounts(node_client, args.creator, accounts, + "400.000", "TESTS" + ) + + test_utils.transfer_assets_to_accounts(node_client, args.creator, accounts, + "400.000", "TBD" + ) + + logger.info("Balances for accounts after initial transfer") + test_utils.print_balance(node_client, accounts) + # transfer assets to treasury + test_utils.transfer_assets_to_treasury(node_client, args.creator, args.treasury, + "1000000.000", "TESTS" + ) + + test_utils.transfer_assets_to_treasury(node_client, args.creator, args.treasury, + "1000000.000", "TBD" + ) + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + # create post for valid permlinks + test_utils.create_posts(node_client, accounts) + + now = node_client.get_dynamic_global_properties().get('time', None) + if now is None: + raise ValueError("Head time is None") + now = test_utils.date_from_iso(now) + + proposal_data = [ + ['tester001', 1 + 0, 5, '24.000 TBD'], # starts one day from now and lasts two days + ['tester002', 1 + 0, 5, '24.000 TBD'], # starts three days from now and lasts one day + ['tester003', 1 + 0, 5, '24.000 TBD'], # starts four days from now and lasts one day + ['tester004', 1 + 0, 5, '240000.000 TBD'], # starts one day from now and lasts five days + ] + + proposals = [ + # pace proposals here in the format: {'creator' : creator, 'receiver' : receiver, 'start_date' : start-date, 'end_date' : end_date} + + ] + + for pd in proposal_data: + start_date, end_date = test_utils.get_start_and_end_date(now, pd[1], pd[2]) + proposal = {'creator' : pd[0], 'receiver' : pd[0], 'start_date' : start_date, 'end_date' : end_date, 'daily_pay' : pd[3]} + proposals.append(proposal) + + import datetime + test_start_date = now + datetime.timedelta(days = 1) + test_start_date_iso = test_utils.date_to_iso(test_start_date) + + test_end_date = test_start_date + datetime.timedelta(days = 6, hours = 1) + test_end_date_iso = test_utils.date_to_iso(test_end_date) + + test_utils.create_proposals(node_client, proposals) + + # list proposals with inactive status, it shoud be list of pairs id:total_votes + test_utils.list_proposals(node_client, test_start_date_iso, "inactive") + + # each account is voting on proposal + test_utils.vote_proposals(node_client, accounts) + + # list proposals with inactive status, it shoud be list of pairs id:total_votes + votes = test_utils.list_proposals(node_client, test_start_date_iso, "inactive") + for vote in votes: + #should be 0 for all + assert vote == 0, "All votes should be equal to 0" + + logger.info("Balances for accounts after creating proposals") + balances = test_utils.print_balance(node_client, accounts) + for balance in balances: + #should be 390.000 TBD for all + assert balance == '390.000 TBD', "All balances should be equal to 390.000 TBD" + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + # move forward in time to see if proposals are paid + # moving is made in 1h increments at a time, after each + # increment balance is printed + logger.info("Moving to date: {}".format(test_start_date_iso)) + node_client.debug_generate_blocks_until(wif, test_start_date_iso, False) + current_date = test_start_date + while current_date < test_end_date: + current_date = current_date + datetime.timedelta(hours = 1) + current_date_iso = test_utils.date_to_iso(current_date) + + logger.info("Moving to date: {}".format(current_date_iso)) + node_client.debug_generate_blocks_until(wif, current_date_iso, False) + + logger.info("Balances for accounts at time: {}".format(current_date_iso)) + test_utils.print_balance(node_client, accounts) + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + votes = test_utils.list_proposals(node_client, test_start_date_iso, "active") + votes = test_utils.list_proposals(node_client, test_start_date_iso, "expired") + votes = test_utils.list_proposals(node_client, test_start_date_iso, "all") + + # move additional hour to ensure that all proposals ended + logger.info("Moving to date: {}".format(test_end_date_iso)) + node_client.debug_generate_blocks_until(wif, test_end_date_iso, False) + logger.info("Balances for accounts at time: {}".format(test_end_date_iso)) + balances = test_utils.print_balance(node_client, accounts) + test_balances = [ + '510.000 TBD', + '438.000 TBD', + '414.000 TBD', + '414.000 TBD', + ] + for idx in range(0, len(test_balances)): + assert balances[idx] == test_balances[idx], "Balances dont match {} != {}".format(balances[idx], test_balances[idx]) + + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + if node is not None: + node.stop_steem_node() + sys.exit(0) + sys.exit(1) + except Exception as ex: + logger.error("Exception: {}".format(ex)) + if node is not None: + node.stop_steem_node() + sys.exit(1) diff --git a/python_scripts/tests/steempy_sps_tests/steem_utils/steem_runner.py b/python_scripts/tests/steempy_sps_tests/steem_utils/steem_runner.py index 00d383daa4..d4306c31bc 100644 --- a/python_scripts/tests/steempy_sps_tests/steem_utils/steem_runner.py +++ b/python_scripts/tests/steempy_sps_tests/steem_utils/steem_runner.py @@ -14,21 +14,10 @@ LOG_FORMAT = "%(asctime)-15s - %(name)s - %(levelname)s - %(message)s" MAIN_LOG_PATH = "./steem_runner.log" -MODULE_NAME = "STEEM Runner Py" +MODULE_NAME = "SPS-Tester-via-steempy.Runner-Py" logger = logging.getLogger(MODULE_NAME) logger.setLevel(LOG_LEVEL) -ch = logging.StreamHandler(sys.stdout) -ch.setLevel(LOG_LEVEL) -ch.setFormatter(logging.Formatter(LOG_FORMAT)) - -fh = logging.FileHandler(MAIN_LOG_PATH) -fh.setLevel(LOG_LEVEL) -fh.setFormatter(logging.Formatter(LOG_FORMAT)) - -if not logger.hasHandlers(): - logger.addHandler(ch) - logger.addHandler(fh) class SteemNode(object): def __init__(self, steem_executable, working_dir, config_src_path): diff --git a/python_scripts/tests/steempy_sps_tests/steem_utils/steem_tools.py b/python_scripts/tests/steempy_sps_tests/steem_utils/steem_tools.py index 4686094631..8a72b69ad9 100644 --- a/python_scripts/tests/steempy_sps_tests/steem_utils/steem_tools.py +++ b/python_scripts/tests/steempy_sps_tests/steem_utils/steem_tools.py @@ -12,23 +12,11 @@ LOG_LEVEL = logging.INFO LOG_FORMAT = "%(asctime)-15s - %(name)s - %(levelname)s - %(message)s" -MAIN_LOG_PATH = "./steem_tools.log" -MODULE_NAME = "Steem Tools Py" +MODULE_NAME = "SPS-Tester-via-steempy.Tools-Py" logger = logging.getLogger(MODULE_NAME) logger.setLevel(LOG_LEVEL) -ch = logging.StreamHandler(sys.stdout) -ch.setLevel(LOG_LEVEL) -ch.setFormatter(logging.Formatter(LOG_FORMAT)) - -fh = logging.FileHandler(MAIN_LOG_PATH) -fh.setLevel(LOG_LEVEL) -fh.setFormatter(logging.Formatter(LOG_FORMAT)) - -if not logger.hasHandlers(): - logger.addHandler(ch) - logger.addHandler(fh) def save_screen_cfg(cfg_file_name, log_file_path): """Creates a config file for screen command. In config file we configure logging path and interval. diff --git a/python_scripts/tests/steempy_sps_tests/steempy_sps_tests.py b/python_scripts/tests/steempy_sps_tests/steempy_sps_tests.py index f5aa7c06a4..e21fca2ef2 100755 --- a/python_scripts/tests/steempy_sps_tests/steempy_sps_tests.py +++ b/python_scripts/tests/steempy_sps_tests/steempy_sps_tests.py @@ -6,12 +6,18 @@ import sys import os import steem_utils.steem_runner +import steem_utils.steem_tools +import test_utils LOG_LEVEL = logging.INFO LOG_FORMAT = "%(asctime)-15s - %(name)s - %(levelname)s - %(message)s" MAIN_LOG_PATH = "./sps_test.log" -MODULE_NAME = "SPS Tester via steempy" +steem_utils.steem_runner.initialize_logging(MAIN_LOG_PATH) +steem_utils.steem_tools.initialize_logging(MAIN_LOG_PATH) +test_utils.initialize_logging(MAIN_LOG_PATH) + +MODULE_NAME = "SPS-Tester-via-steempy" logger = logging.getLogger(MODULE_NAME) logger.setLevel(LOG_LEVEL) @@ -33,21 +39,6 @@ logger.error("SteemPy library is not installed.") sys.exit(1) -def get_date_as_isostr(date): - return date.replace(microsecond=0).isoformat() - - -def get_isostr_start_end_date(now, start_date_delta, end_date_delta): - from datetime import timedelta - - start_date = now + timedelta(days = start_date_delta) - end_date = start_date + timedelta(days = end_date_delta) - - start_date = start_date.replace(microsecond=0).isoformat() - end_date = end_date.replace(microsecond=0).isoformat() - - return start_date, end_date - def test_create_proposal(node, creator_account, receiver_account, wif, subject): logger.info("Testing: create_proposal") @@ -56,7 +47,7 @@ def test_create_proposal(node, creator_account, receiver_account, wif, subject): import datetime now = datetime.datetime.now() - start_date, end_date = get_isostr_start_end_date(now, 10, 2) + start_date, end_date = test_utils.get_start_and_end_date(now, 10, 2) from steem.account import Account try: @@ -158,7 +149,7 @@ def test_vote_proposal(node, account, wif, subject): assert ret["operations"][0][1]["voter"] == account assert ret["operations"][0][1]["proposal_ids"][0] == proposal_id assert ret["operations"][0][1]["approve"] == True - sleep(6) + steem_utils.steem_tools.wait_for_blocks_produced(2, node) def test_list_voter_proposals(node, account, wif, subject): logger.info("Testing: list_voter_proposals") @@ -243,7 +234,7 @@ def test_iterate_results_test(node, creator_account, receiver_account, wif, subj ] for start_end_pair in start_end_pairs: - start_date, end_date = get_isostr_start_end_date(now, start_end_pair[0], start_end_pair[1]) + start_date, end_date = test_utils.get_start_and_end_date(now, start_end_pair[0], start_end_pair[1]) s.commit.create_proposal( creator["name"], @@ -254,10 +245,9 @@ def test_iterate_results_test(node, creator_account, receiver_account, wif, subj subject, "steempy-proposal-title" ) - sleep(3) - sleep(6) + steem_utils.steem_tools.wait_for_blocks_produced(5, node) - start_date = get_date_as_isostr(now + datetime.timedelta(days = 5)) + start_date = test_utils.date_to_iso(now + datetime.timedelta(days = 5)) # 2 then we will list proposals starting from kth proposal with limit set to m < k proposals = s.list_proposals(start_date, "by_start_date", "direction_descending", 3, "all") @@ -284,21 +274,21 @@ def test_iterate_results_test(node, creator_account, receiver_account, wif, subj # 4 then we will use newly introduced last_id field, we should see diferent set of proposals proposals = s.list_proposals(start_date, "by_start_date", "direction_descending", 3, "all", oids[-1]) - start_date, end_date = get_isostr_start_end_date(now, 5, 4) + start_date, end_date = test_utils.get_start_and_end_date(now, 5, 4) assert proposals[-1]["start_date"] == start_date, "Expected start_date do not match {} != {}".format(start_date, proposals[-1]["start_date"]) assert proposals[-1]["end_date"] == end_date, "Expected end_date do not match {} != {}".format(end_date, proposals[-1]["end_date"]) # remove all created proposals if remove: - start_date = get_date_as_isostr(now + datetime.timedelta(days = 6)) + start_date = test_utils.date_to_iso(now + datetime.timedelta(days = 6)) for a in range(0, 2): proposals = s.list_proposals(start_date, "by_start_date", "direction_descending", 5, "all") ids = [] for proposal in proposals: ids.append(int(proposal['id'])) s.commit.remove_proposal(creator["name"], ids) - sleep(12) + steem_utils.steem_tools.wait_for_blocks_produced(3, node) if __name__ == '__main__': @@ -343,16 +333,16 @@ def test_iterate_results_test(node, creator_account, receiver_account, wif, subj try: if node is None or node.is_running(): test_create_proposal(node_url, args.creator, args.receiver, wif, subject) - sleep(6) + steem_utils.steem_tools.wait_for_blocks_produced(2, node) test_list_proposals(node_url, args.creator, wif, subject) test_find_proposals(node_url, args.creator, wif, subject) test_vote_proposal(node_url, args.creator, wif, subject) test_list_voter_proposals(node_url, args.creator, wif, subject) - sleep(6) + steem_utils.steem_tools.wait_for_blocks_produced(2, node) if args.no_erase_proposal: test_remove_proposal(node_url, args.creator, wif, subject) test_iterate_results_test(args.node_url, args.creator, args.receiver, args.wif, str(uuid4()), args.no_erase_proposal) - sleep(6) + steem_utils.steem_tools.wait_for_blocks_produced(2, node) if node is not None: node.stop_steem_node() sys.exit(0) diff --git a/python_scripts/tests/steempy_sps_tests/test_utils.py b/python_scripts/tests/steempy_sps_tests/test_utils.py new file mode 100644 index 0000000000..6ddd446958 --- /dev/null +++ b/python_scripts/tests/steempy_sps_tests/test_utils.py @@ -0,0 +1,165 @@ +from uuid import uuid4 +from time import sleep +import logging +import sys +import steem_utils.steem_runner +import steem_utils.steem_tools + + +LOG_LEVEL = logging.INFO +LOG_FORMAT = "%(asctime)-15s - %(name)s - %(levelname)s - %(message)s" +MAIN_LOG_PATH = "./sps_tester_utils.log" + +MODULE_NAME = "SPS-Tester-via-steempy.SPS-Tester-Utils" +logger = logging.getLogger(MODULE_NAME) +logger.setLevel(LOG_LEVEL) + + +# create_account "initminer" "pychol" "" true +def create_accounts(node, creator, accounts): + for account in accounts: + logger.info("Creating account: {}".format(account['name'])) + node.commit.create_account(account['name'], + owner_key=account['public_key'], + active_key=account['public_key'], + posting_key=account['public_key'], + memo_key=account['public_key'], + store_keys = False, + creator=creator, + asset='TESTS' + ) + steem_utils.steem_tools.wait_for_blocks_produced(5, node.url) + + +# transfer_to_vesting initminer pychol "310.000 TESTS" true +def transfer_to_vesting(node, from_account, accounts, amount, asset): + for acnt in accounts: + logger.info("Transfer to vesting from {} to {} amount {} {}".format( + from_account, acnt['name'], amount, asset) + ) + + node.commit.transfer_to_vesting(amount, to = acnt['name'], + account = from_account, asset = asset + ) + steem_utils.steem_tools.wait_for_blocks_produced(5, node.url) + + +# transfer initminer pychol "399.000 TESTS" "initial transfer" true +# transfer initminer pychol "398.000 TBD" "initial transfer" true +def transfer_assets_to_accounts(node, from_account, accounts, amount, asset): + for acnt in accounts: + logger.info("Transfer from {} to {} amount {} {}".format(from_account, + acnt['name'], amount, asset) + ) + node.commit.transfer(acnt['name'], amount, asset, + memo = "initial transfer", account = from_account + ) + steem_utils.steem_tools.wait_for_blocks_produced(5, node.url) + + +def transfer_assets_to_treasury(node, from_account, treasury_account, amount, asset): + logger.info("Transfer from {} to {} amount {} {}".format(from_account, + treasury_account, amount, asset) + ) + node.commit.transfer(treasury_account, amount, asset, + memo = "initial transfer", account = from_account + ) + steem_utils.steem_tools.wait_for_blocks_produced(2, node.url) + + +def get_permlink(account): + return "steempy-proposal-title-{}".format(account) + + +def create_posts(node, accounts): + logger.info("Creating posts...") + for acnt in accounts: + logger.info("New post ==> ({},{},{},{},{})".format( + "Steempy proposal title [{}]".format(acnt['name']), + "Steempy proposal body [{}]".format(acnt['name']), + acnt['name'], + get_permlink(acnt['name']), + "proposals" + )) + node.commit.post("Steempy proposal title [{}]".format(acnt['name']), + "Steempy proposal body [{}]".format(acnt['name']), + acnt['name'], + permlink = get_permlink(acnt['name']), + tags = "proposals") + steem_utils.steem_tools.wait_for_blocks_produced(5, node.url) + + +def create_proposals(node, proposals): + logger.info("Creating proposals...") + for proposal in proposals: + logger.info("New proposal ==> ({},{},{},{},{},{},{})".format( + proposal['creator'], + proposal['receiver'], + proposal['start_date'], + proposal['end_date'], + proposal['daily_pay'], + "Proposal from account {}".format(proposal['creator']), + get_permlink(proposal['creator']) + )) + node.commit.create_proposal( + proposal['creator'], + proposal['receiver'], + proposal['start_date'], + proposal['end_date'], + proposal['daily_pay'], + "Proposal from account {}".format(proposal['creator']), + get_permlink(proposal['creator']) + ) + steem_utils.steem_tools.wait_for_blocks_produced(5, node.url) + + +def vote_proposals(node, accounts): + logger.info("Voting proposals...") + for acnt in accounts: + proposal_set = [x for x in range(0, len(accounts))] + logger.info("Account {} voted for proposals: {}".format(acnt["name"], ",".join(str(x) for x in proposal_set))) + node.commit.update_proposal_votes(acnt["name"], proposal_set, True) + steem_utils.steem_tools.wait_for_blocks_produced(5, node.url) + + +def list_proposals(node, start_date, status): + proposals = node.list_proposals(start_date, "by_start_date", "direction_ascending", 1000, status) + ret = [] + votes = [] + for proposal in proposals: + ret.append("{}:{}".format(proposal.get('id', 'Error'), proposal.get('total_votes', 'Error'))) + votes.append(int(proposal.get('total_votes', -1))) + logger.info("Listing proposals with status {} (id:total_votes): {}".format(status, ",".join(ret))) + return votes + + +def print_balance(node, accounts): + balances = [] + balances_str = [] + for acnt in accounts: + ret = node.get_account(acnt['name']) + sbd = ret.get('sbd_balance', 'Error') + balances_str.append("{}:{}".format(acnt['name'], sbd)) + balances.append(sbd) + logger.info("Balances ==> {}".format(",".join(balances_str))) + return balances + + +def date_to_iso(date): + return date.replace(microsecond=0).isoformat() + + +def date_from_iso(date_iso_str): + import dateutil.parser + return dateutil.parser.parse(date_iso_str) + + +def get_start_and_end_date(now, start_days_from_now, end_days_from_start): + from datetime import timedelta + start_date = now + timedelta(days = start_days_from_now) + end_date = start_date + timedelta(days = end_days_from_start) + + assert start_date > now, "Start date must be greater than now" + assert end_date > start_date, "End date must be greater than start date" + + return date_to_iso(start_date), date_to_iso(end_date) \ No newline at end of file From 6991380fa4affe2456089a6592d00bf52abf5d05 Mon Sep 17 00:00:00 2001 From: Dariusz Kedzierski Date: Mon, 8 Apr 2019 09:33:30 +0200 Subject: [PATCH 2/5] WIP: more proposal payment tests. Minor logging rework --- ...n_test.py => proposal_payment_test_001.py} | 159 ++---------- .../proposal_payment_test_002.py | 234 +++++++++++++++++ .../proposal_payment_test_003.py | 238 ++++++++++++++++++ .../proposal_payment_test_004.py | 238 ++++++++++++++++++ .../steem_utils/steem_runner.py | 13 +- .../steem_utils/steem_tools.py | 14 +- .../steempy_sps_tests/steempy_sps_tests.py | 46 ++-- .../tests/steempy_sps_tests/test_utils.py | 165 ++++++++++++ 8 files changed, 921 insertions(+), 186 deletions(-) rename python_scripts/tests/steempy_sps_tests/{proposal_payment_distribution_test.py => proposal_payment_test_001.py} (56%) create mode 100755 python_scripts/tests/steempy_sps_tests/proposal_payment_test_002.py create mode 100755 python_scripts/tests/steempy_sps_tests/proposal_payment_test_003.py create mode 100755 python_scripts/tests/steempy_sps_tests/proposal_payment_test_004.py create mode 100644 python_scripts/tests/steempy_sps_tests/test_utils.py diff --git a/python_scripts/tests/steempy_sps_tests/proposal_payment_distribution_test.py b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_001.py similarity index 56% rename from python_scripts/tests/steempy_sps_tests/proposal_payment_distribution_test.py rename to python_scripts/tests/steempy_sps_tests/proposal_payment_test_001.py index bfe4011c33..17c78514e6 100755 --- a/python_scripts/tests/steempy_sps_tests/proposal_payment_distribution_test.py +++ b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_001.py @@ -6,13 +6,14 @@ import sys import steem_utils.steem_runner import steem_utils.steem_tools +import test_utils LOG_LEVEL = logging.INFO LOG_FORMAT = "%(asctime)-15s - %(name)s - %(levelname)s - %(message)s" -MAIN_LOG_PATH = "./sps_proposal_payment.log" +MAIN_LOG_PATH = "./sps_proposal_payment_001.log" -MODULE_NAME = "SPS Tester via steempy - proposal payment test" +MODULE_NAME = "SPS-Tester-via-steempy" logger = logging.getLogger(MODULE_NAME) logger.setLevel(LOG_LEVEL) @@ -35,85 +36,11 @@ sys.exit(1) -# 1. create few proposals. +# 1. create few proposals - in this scenatio all proposals have the same start and end date # 2. vote on them to show differences in asset distribution (depending on collected votes) # 3. wait for proposal payment phase # 4. verify (using account history and by checking regular account balance) that given accounts have been correctly paid. - -# create_account "initminer" "pychol" "" true -def create_accounts(node, creator, accounts): - for account in accounts: - logger.info("Creating account: {}".format(account['name'])) - node.commit.create_account(account['name'], - owner_key=account['public_key'], - active_key=account['public_key'], - posting_key=account['public_key'], - memo_key=account['public_key'], - store_keys = False, - creator=creator, - asset='TESTS' - ) - steem_utils.steem_tools.wait_for_blocks_produced(5, node.url) - - -# transfer_to_vesting initminer pychol "310.000 TESTS" true -def transfer_to_vesting(node, from_account, accounts, amount, asset): - for acnt in accounts: - logger.info("Transfer to vesting from {} to {} amount {} {}".format( - from_account, acnt['name'], amount, asset) - ) - - node.commit.transfer_to_vesting(amount, to = acnt['name'], - account = from_account, asset = asset - ) - steem_utils.steem_tools.wait_for_blocks_produced(5, node.url) - - -# transfer initminer pychol "399.000 TESTS" "initial transfer" true -# transfer initminer pychol "398.000 TBD" "initial transfer" true -def transfer_assets_to_accounts(node, from_account, accounts, amount, asset): - for acnt in accounts: - logger.info("Transfer from {} to {} amount {} {}".format(from_account, - acnt['name'], amount, asset) - ) - node.commit.transfer(acnt['name'], amount, asset, - memo = "initial transfer", account = from_account - ) - steem_utils.steem_tools.wait_for_blocks_produced(5, node.url) - - -def transfer_assets_to_treasury(node, from_account, treasury_account, amount, asset): - logger.info("Transfer from {} to {} amount {} {}".format(from_account, - treasury_account, amount, asset) - ) - node.commit.transfer(treasury_account, amount, asset, - memo = "initial transfer", account = from_account - ) - steem_utils.steem_tools.wait_for_blocks_produced(2, node.url) - - -def get_permlink(account): - return "steempy-proposal-title-{}".format(account) - -def create_posts(node, accounts): - logger.info("Creating posts...") - for acnt in accounts: - logger.info("New post ==> ({},{},{},{},{})".format( - "Steempy proposal title [{}]".format(acnt['name']), - "Steempy proposal body [{}]".format(acnt['name']), - acnt['name'], - get_permlink(acnt['name']), - "proposals" - )) - node.commit.post("Steempy proposal title [{}]".format(acnt['name']), - "Steempy proposal body [{}]".format(acnt['name']), - acnt['name'], - permlink = get_permlink(acnt['name']), - tags = "proposals") - steem_utils.steem_tools.wait_for_blocks_produced(5, node.url) - - def create_proposals(node, accounts, start_date, end_date): logger.info("Creating proposals...") for acnt in accounts: @@ -124,7 +51,7 @@ def create_proposals(node, accounts, start_date, end_date): end_date, "24.000 TBD", "Proposal from account {}".format(acnt['name']), - get_permlink(acnt['name']) + test_utils.get_permlink(acnt['name']) )) node.commit.create_proposal( acnt['name'], @@ -133,39 +60,11 @@ def create_proposals(node, accounts, start_date, end_date): end_date, "24.000 TBD", "Proposal from account {}".format(acnt['name']), - get_permlink(acnt['name']) + test_utils.get_permlink(acnt['name']) ) steem_utils.steem_tools.wait_for_blocks_produced(5, node.url) -def vote_proposals(node, accounts): - logger.info("Voting proposals...") - for acnt in accounts: - proposal_set = [x for x in range(0, len(accounts))] - logger.info("Account {} voted for proposals: {}".format(acnt["name"], ",".join(str(x) for x in proposal_set))) - node.commit.update_proposal_votes(acnt["name"], proposal_set, True) - steem_utils.steem_tools.wait_for_blocks_produced(5, node.url) - - -def list_proposals(node, start_date, status): - proposals = node.list_proposals(start_date, "by_start_date", "direction_ascending", 1000, status) - ret = [] - votes = [] - for proposal in proposals: - ret.append("{}:{}".format(proposal.get('id', 'Error'), proposal.get('total_votes', 'Error'))) - votes.append(int(proposal.get('total_votes', -1))) - logger.info("Listing proposals with status {} (id:total_votes): {}".format(status, ",".join(ret))) - return votes - -def print_balance(node, accounts): - balances = [] - for acnt in accounts: - ret = node.get_account(acnt['name']) - logger.info("{} :: balance ==> {}, sbd_balance ==> {}".format(acnt['name'], ret.get('balance', 'Error'), ret.get('sbd_balance', 'Error'))) - balances.append(ret.get('sbd_balance', 'Error')) - return balances - - if __name__ == '__main__': logger.info("Performing SPS tests") import argparse @@ -226,36 +125,34 @@ def print_balance(node, accounts): ) # create accounts - create_accounts(node_client, args.creator, accounts) + test_utils.create_accounts(node_client, args.creator, accounts) # tranfer to vesting - transfer_to_vesting(node_client, args.creator, accounts, "300.000", + test_utils.transfer_to_vesting(node_client, args.creator, accounts, "300.000", "TESTS" ) # transfer assets to accounts - transfer_assets_to_accounts(node_client, args.creator, accounts, + test_utils.transfer_assets_to_accounts(node_client, args.creator, accounts, "400.000", "TESTS" ) - transfer_assets_to_accounts(node_client, args.creator, accounts, + test_utils.transfer_assets_to_accounts(node_client, args.creator, accounts, "400.000", "TBD" ) logger.info("Balances for accounts after initial transfer") - print_balance(node_client, accounts) + test_utils.print_balance(node_client, accounts) # transfer assets to treasury - transfer_assets_to_treasury(node_client, args.creator, args.treasury, + test_utils.transfer_assets_to_treasury(node_client, args.creator, args.treasury, "1000000.000", "TESTS" ) - transfer_assets_to_treasury(node_client, args.creator, args.treasury, + test_utils.transfer_assets_to_treasury(node_client, args.creator, args.treasury, "1000000.000", "TBD" ) - - logger.info("Balances for treasury account after initial transfer") - print_balance(node_client, [{'name' : args.treasury}]) + test_utils.print_balance(node_client, [{'name' : args.treasury}]) # create post for valid permlinks - create_posts(node_client, accounts) + test_utils.create_posts(node_client, accounts) import datetime import dateutil.parser @@ -278,25 +175,23 @@ def print_balance(node, accounts): create_proposals(node_client, accounts, start_date_str, end_date_str) # list proposals with inactive status, it shoud be list of pairs id:total_votes - list_proposals(node_client, start_date_str, "inactive") + test_utils.list_proposals(node_client, start_date_str, "inactive") # each account is voting on proposal - vote_proposals(node_client, accounts) + test_utils.vote_proposals(node_client, accounts) # list proposals with inactive status, it shoud be list of pairs id:total_votes - votes = list_proposals(node_client, start_date_str, "inactive") + votes = test_utils.list_proposals(node_client, start_date_str, "inactive") for vote in votes: #should be 0 for all assert vote == 0, "All votes should be equal to 0" logger.info("Balances for accounts after creating proposals") - balances = print_balance(node_client, accounts) + balances = test_utils.print_balance(node_client, accounts) for balance in balances: #should be 390.000 TBD for all assert balance == '390.000 TBD', "All balances should be equal to 390.000 TBD" - - logger.info("Balances for treasury after creating proposals") - print_balance(node_client, [{'name' : args.treasury}]) + test_utils.print_balance(node_client, [{'name' : args.treasury}]) # move forward in time to see if proposals are paid # moving is made in 1h increments at a time, after each @@ -311,10 +206,9 @@ def print_balance(node, accounts): node_client.debug_generate_blocks_until(wif, current_date_str, False) logger.info("Balances for accounts at time: {}".format(current_date_str)) - print_balance(node_client, accounts) - logger.info("Balances for treasury at time: {}".format(current_date_str)) - print_balance(node_client, [{'name' : args.treasury}]) - votes = list_proposals(node_client, start_date_str, "active") + test_utils.print_balance(node_client, accounts) + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + votes = test_utils.list_proposals(node_client, start_date_str, "active") for vote in votes: # should be > 0 for all assert vote > 0, "All votes counts shoud be greater than 0" @@ -323,13 +217,12 @@ def print_balance(node, accounts): logger.info("Moving to date: {}".format(end_date_blocks_str)) node_client.debug_generate_blocks_until(wif, end_date_blocks_str, False) logger.info("Balances for accounts at time: {}".format(end_date_blocks_str)) - balances = print_balance(node_client, accounts) + balances = test_utils.print_balance(node_client, accounts) for balance in balances: # shoud be 438.000 TBD for all assert balance == '438.000 TBD', "All balances should be equal 438.000 TBD" - logger.info("Balances for treasury at time: {}".format(end_date_blocks_str)) - print_balance(node_client, [{'name' : args.treasury}]) - votes = list_proposals(node_client, start_date_str, "expired") + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + votes = test_utils.list_proposals(node_client, start_date_str, "expired") for vote in votes: # should be > 0 for all assert vote > 0, "All votes counts shoud be greater than 0" diff --git a/python_scripts/tests/steempy_sps_tests/proposal_payment_test_002.py b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_002.py new file mode 100755 index 0000000000..6c046cb7b2 --- /dev/null +++ b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_002.py @@ -0,0 +1,234 @@ +#!/usr/bin/python3 + +from uuid import uuid4 +from time import sleep +import logging +import sys +import steem_utils.steem_runner +import steem_utils.steem_tools +import test_utils + + +LOG_LEVEL = logging.INFO +LOG_FORMAT = "%(asctime)-15s - %(name)s - %(levelname)s - %(message)s" +MAIN_LOG_PATH = "./sps_proposal_payment_002.log" + +MODULE_NAME = "SPS-Tester-via-steempy" +logger = logging.getLogger(MODULE_NAME) +logger.setLevel(LOG_LEVEL) + +ch = logging.StreamHandler(sys.stdout) +ch.setLevel(LOG_LEVEL) +ch.setFormatter(logging.Formatter(LOG_FORMAT)) + +fh = logging.FileHandler(MAIN_LOG_PATH) +fh.setLevel(LOG_LEVEL) +fh.setFormatter(logging.Formatter(LOG_FORMAT)) + +if not logger.hasHandlers(): + logger.addHandler(ch) + logger.addHandler(fh) + +try: + from steem import Steem +except Exception as ex: + logger.error("SteemPy library is not installed.") + sys.exit(1) + + +# 1. create few proposals - in this scenario proposals have different starting and ending dates +# 2. vote on them to show differences in asset distribution (depending on collected votes) +# 3. wait for proposal payment phase +# 4. verify (using account history and by checking regular account balance) that given accounts have been correctly paid. + + +if __name__ == '__main__': + logger.info("Performing SPS tests") + import argparse + parser = argparse.ArgumentParser() + parser.add_argument("creator", help = "Account to create test accounts with") + parser.add_argument("treasury", help = "Treasury account") + parser.add_argument("wif", help="Private key for creator account") + parser.add_argument("--node-url", dest="node_url", default="http://127.0.0.1:8090", help="Url of working steem node") + parser.add_argument("--run-steemd", dest="steemd_path", help = "Path to steemd executable. Warning: using this option will erase contents of selected steemd working directory.") + parser.add_argument("--working_dir", dest="steemd_working_dir", default="/tmp/steemd-data/", help = "Path to steemd working directory") + parser.add_argument("--config_path", dest="steemd_config_path", default="./steem_utils/resources/config.ini.in",help = "Path to source config.ini file") + parser.add_argument("--no-erase-proposal", action='store_false', dest = "no_erase_proposal", help = "Do not erase proposal created with this test") + + + args = parser.parse_args() + + node = None + + if args.steemd_path: + logger.info("Running steemd via {} in {} with config {}".format(args.steemd_path, + args.steemd_working_dir, + args.steemd_config_path) + ) + + node = steem_utils.steem_runner.SteemNode( + args.steemd_path, + args.steemd_working_dir, + args.steemd_config_path + ) + + node_url = args.node_url + wif = args.wif + + if len(wif) == 0: + logger.error("Private-key is not set in config.ini") + sys.exit(1) + + logger.info("Using node at: {}".format(node_url)) + logger.info("Using private-key: {}".format(wif)) + + accounts = [ + # place accounts here in the format: {'name' : name, 'private_key' : private-key, 'public_key' : public-key} + {"name" : "tester001", "private_key" : "5JBuekd1sVXXK3wBu6nvPB1LWypZ83BYdu7tGcUNYVd42xQGGh1", "public_key" : "TST5kSj1yTzBz3PDoJ5QUyVVagdgYfs8Y4vVsZG3dqKJU8hg7WmQN"}, + {"name" : "tester002", "private_key" : "5KgfcV9bgEen3v9mxkoGw6Rhuf2giDRZTHZjzwisjkrpF4FUh3N", "public_key" : "TST5gQPYm5bs9dRPHpqBy6dU32M8FcoKYFdF4YWEChUarc9FdYHzn"}, + {"name" : "tester003", "private_key" : "5Jz3fcrrgKMbL8ncpzTdQmdRVHdxMhi8qScoxSR3TnAFUcdyD5N", "public_key" : "TST57wy5bXyJ4Z337Bo6RbinR6NyTRJxzond5dmGsP4gZ51yN6Zom"}, + {"name" : "tester004", "private_key" : "5KcmobLVMSAVzETrZxfEGG73Zvi5SKTgJuZXtNgU3az2VK3Krye", "public_key" : "TST8dPte853xAuLMDV7PTVmiNMRwP6itMyvSmaht7J5tVczkDLa5K"}, + ] + + if not accounts: + logger.error("Accounts array is empty, please add accounts in a form {\"name\" : name, \"private_key\" : private_key, \"public_key\" : public_key}") + sys.exit(1) + + keys = [wif] + for account in accounts: + keys.append(account["private_key"]) + + if node is not None: + node.run_steem_node(["--enable-stale-production"]) + try: + if node is None or node.is_running(): + node_client = Steem(nodes = [node_url], no_broadcast = False, + keys = keys + ) + + # create accounts + test_utils.create_accounts(node_client, args.creator, accounts) + # tranfer to vesting + test_utils.transfer_to_vesting(node_client, args.creator, accounts, "300.000", + "TESTS" + ) + # transfer assets to accounts + test_utils.transfer_assets_to_accounts(node_client, args.creator, accounts, + "400.000", "TESTS" + ) + + test_utils.transfer_assets_to_accounts(node_client, args.creator, accounts, + "400.000", "TBD" + ) + + logger.info("Balances for accounts after initial transfer") + test_utils.print_balance(node_client, accounts) + # transfer assets to treasury + test_utils.transfer_assets_to_treasury(node_client, args.creator, args.treasury, + "1000000.000", "TESTS" + ) + + test_utils.transfer_assets_to_treasury(node_client, args.creator, args.treasury, + "1000000.000", "TBD" + ) + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + # create post for valid permlinks + test_utils.create_posts(node_client, accounts) + + now = node_client.get_dynamic_global_properties().get('time', None) + if now is None: + raise ValueError("Head time is None") + now = test_utils.date_from_iso(now) + + proposal_data = [ + ['tester001', 1 + 0, 5, '24.000 TBD'], # starts one day from now and lasts five days + ['tester002', 1 + 0, 2, '24.000 TBD'], # starts one day from now and lasts two days + ['tester003', 1 + 2, 1, '24.000 TBD'], # starts three days from now and lasts one day + ['tester004', 1 + 4, 1, '24.000 TBD'] # starts four days from now and lasts one day + ] + + proposals = [ + # pace proposals here in the format: {'creator' : creator, 'receiver' : receiver, 'start_date' : start-date, 'end_date' : end_date} + + ] + + for pd in proposal_data: + start_date, end_date = test_utils.get_start_and_end_date(now, pd[1], pd[2]) + proposal = {'creator' : pd[0], 'receiver' : pd[0], 'start_date' : start_date, 'end_date' : end_date, 'daily_pay' : pd[3]} + proposals.append(proposal) + + import datetime + test_start_date = now + datetime.timedelta(days = 1) + test_start_date_iso = test_utils.date_to_iso(test_start_date) + + test_end_date = test_start_date + datetime.timedelta(days = 6, hours = 1) + test_end_date_iso = test_utils.date_to_iso(test_end_date) + + test_utils.create_proposals(node_client, proposals) + + # list proposals with inactive status, it shoud be list of pairs id:total_votes + test_utils.list_proposals(node_client, test_start_date_iso, "inactive") + + # each account is voting on proposal + test_utils.vote_proposals(node_client, accounts) + + # list proposals with inactive status, it shoud be list of pairs id:total_votes + votes = test_utils.list_proposals(node_client, test_start_date_iso, "inactive") + for vote in votes: + #should be 0 for all + assert vote == 0, "All votes should be equal to 0" + + logger.info("Balances for accounts after creating proposals") + balances = test_utils.print_balance(node_client, accounts) + for balance in balances: + #should be 390.000 TBD for all + assert balance == '390.000 TBD', "All balances should be equal to 390.000 TBD" + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + # move forward in time to see if proposals are paid + # moving is made in 1h increments at a time, after each + # increment balance is printed + logger.info("Moving to date: {}".format(test_start_date_iso)) + node_client.debug_generate_blocks_until(wif, test_start_date_iso, False) + current_date = test_start_date + while current_date < test_end_date: + current_date = current_date + datetime.timedelta(hours = 1) + current_date_iso = test_utils.date_to_iso(current_date) + + logger.info("Moving to date: {}".format(current_date_iso)) + node_client.debug_generate_blocks_until(wif, current_date_iso, False) + + logger.info("Balances for accounts at time: {}".format(current_date_iso)) + test_utils.print_balance(node_client, accounts) + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + votes = test_utils.list_proposals(node_client, test_start_date_iso, "active") + votes = test_utils.list_proposals(node_client, test_start_date_iso, "expired") + votes = test_utils.list_proposals(node_client, test_start_date_iso, "all") + + # move additional hour to ensure that all proposals ended + logger.info("Moving to date: {}".format(test_end_date_iso)) + node_client.debug_generate_blocks_until(wif, test_end_date_iso, False) + logger.info("Balances for accounts at time: {}".format(test_end_date_iso)) + balances = test_utils.print_balance(node_client, accounts) + test_balances = [ + '510.000 TBD', + '438.000 TBD', + '414.000 TBD', + '414.000 TBD', + ] + for idx in range(0, len(test_balances)): + assert balances[idx] == test_balances[idx], "Balances dont match {} != {}".format(balances[idx], test_balances[idx]) + + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + if node is not None: + node.stop_steem_node() + sys.exit(0) + sys.exit(1) + except Exception as ex: + logger.error("Exception: {}".format(ex)) + if node is not None: + node.stop_steem_node() + sys.exit(1) diff --git a/python_scripts/tests/steempy_sps_tests/proposal_payment_test_003.py b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_003.py new file mode 100755 index 0000000000..c4ae391636 --- /dev/null +++ b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_003.py @@ -0,0 +1,238 @@ +#!/usr/bin/python3 + +from uuid import uuid4 +from time import sleep +import logging +import sys +import steem_utils.steem_runner +import steem_utils.steem_tools +import test_utils + + +LOG_LEVEL = logging.INFO +LOG_FORMAT = "%(asctime)-15s - %(name)s - %(levelname)s - %(message)s" +MAIN_LOG_PATH = "./sps_proposal_payment_003.log" + +MODULE_NAME = "SPS-Tester-via-steempy" +logger = logging.getLogger(MODULE_NAME) +logger.setLevel(LOG_LEVEL) + +ch = logging.StreamHandler(sys.stdout) +ch.setLevel(LOG_LEVEL) +ch.setFormatter(logging.Formatter(LOG_FORMAT)) + +fh = logging.FileHandler(MAIN_LOG_PATH) +fh.setLevel(LOG_LEVEL) +fh.setFormatter(logging.Formatter(LOG_FORMAT)) + +if not logger.hasHandlers(): + logger.addHandler(ch) + logger.addHandler(fh) + +try: + from steem import Steem +except Exception as ex: + logger.error("SteemPy library is not installed.") + sys.exit(1) + +# Greedy baby scenario +# 0. In this scenario we have one proposal with huge daily pay and couple with low daily pay +# all proposals have the same number of votes, greedy proposal is first +# 1. create few proposals - in this scenario proposals have the same starting and ending dates +# 2. vote on them to show differences in asset distribution (depending on collected votes) +# 3. wait for proposal payment phase +# 4. verify (using account history and by checking regular account balance) that given accounts have been correctly paid. + +# Expected result: Only greedy baby got paid + + +if __name__ == '__main__': + logger.info("Performing SPS tests") + import argparse + parser = argparse.ArgumentParser() + parser.add_argument("creator", help = "Account to create test accounts with") + parser.add_argument("treasury", help = "Treasury account") + parser.add_argument("wif", help="Private key for creator account") + parser.add_argument("--node-url", dest="node_url", default="http://127.0.0.1:8090", help="Url of working steem node") + parser.add_argument("--run-steemd", dest="steemd_path", help = "Path to steemd executable. Warning: using this option will erase contents of selected steemd working directory.") + parser.add_argument("--working_dir", dest="steemd_working_dir", default="/tmp/steemd-data/", help = "Path to steemd working directory") + parser.add_argument("--config_path", dest="steemd_config_path", default="./steem_utils/resources/config.ini.in",help = "Path to source config.ini file") + parser.add_argument("--no-erase-proposal", action='store_false', dest = "no_erase_proposal", help = "Do not erase proposal created with this test") + + + args = parser.parse_args() + + node = None + + if args.steemd_path: + logger.info("Running steemd via {} in {} with config {}".format(args.steemd_path, + args.steemd_working_dir, + args.steemd_config_path) + ) + + node = steem_utils.steem_runner.SteemNode( + args.steemd_path, + args.steemd_working_dir, + args.steemd_config_path + ) + + node_url = args.node_url + wif = args.wif + + if len(wif) == 0: + logger.error("Private-key is not set in config.ini") + sys.exit(1) + + logger.info("Using node at: {}".format(node_url)) + logger.info("Using private-key: {}".format(wif)) + + accounts = [ + # place accounts here in the format: {'name' : name, 'private_key' : private-key, 'public_key' : public-key} + {"name" : "tester001", "private_key" : "5JBuekd1sVXXK3wBu6nvPB1LWypZ83BYdu7tGcUNYVd42xQGGh1", "public_key" : "TST5kSj1yTzBz3PDoJ5QUyVVagdgYfs8Y4vVsZG3dqKJU8hg7WmQN"}, + {"name" : "tester002", "private_key" : "5KgfcV9bgEen3v9mxkoGw6Rhuf2giDRZTHZjzwisjkrpF4FUh3N", "public_key" : "TST5gQPYm5bs9dRPHpqBy6dU32M8FcoKYFdF4YWEChUarc9FdYHzn"}, + {"name" : "tester003", "private_key" : "5Jz3fcrrgKMbL8ncpzTdQmdRVHdxMhi8qScoxSR3TnAFUcdyD5N", "public_key" : "TST57wy5bXyJ4Z337Bo6RbinR6NyTRJxzond5dmGsP4gZ51yN6Zom"}, + {"name" : "tester004", "private_key" : "5KcmobLVMSAVzETrZxfEGG73Zvi5SKTgJuZXtNgU3az2VK3Krye", "public_key" : "TST8dPte853xAuLMDV7PTVmiNMRwP6itMyvSmaht7J5tVczkDLa5K"}, + ] + + if not accounts: + logger.error("Accounts array is empty, please add accounts in a form {\"name\" : name, \"private_key\" : private_key, \"public_key\" : public_key}") + sys.exit(1) + + keys = [wif] + for account in accounts: + keys.append(account["private_key"]) + + if node is not None: + node.run_steem_node(["--enable-stale-production"]) + try: + if node is None or node.is_running(): + node_client = Steem(nodes = [node_url], no_broadcast = False, + keys = keys + ) + + # create accounts + test_utils.create_accounts(node_client, args.creator, accounts) + # tranfer to vesting + test_utils.transfer_to_vesting(node_client, args.creator, accounts, "300.000", + "TESTS" + ) + # transfer assets to accounts + test_utils.transfer_assets_to_accounts(node_client, args.creator, accounts, + "400.000", "TESTS" + ) + + test_utils.transfer_assets_to_accounts(node_client, args.creator, accounts, + "400.000", "TBD" + ) + + logger.info("Balances for accounts after initial transfer") + test_utils.print_balance(node_client, accounts) + # transfer assets to treasury + test_utils.transfer_assets_to_treasury(node_client, args.creator, args.treasury, + "1000000.000", "TESTS" + ) + + test_utils.transfer_assets_to_treasury(node_client, args.creator, args.treasury, + "1000000.000", "TBD" + ) + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + # create post for valid permlinks + test_utils.create_posts(node_client, accounts) + + now = node_client.get_dynamic_global_properties().get('time', None) + if now is None: + raise ValueError("Head time is None") + now = test_utils.date_from_iso(now) + + proposal_data = [ + ['tester001', 1 + 0, 5, '240000.000 TBD'], # starts one day from now and lasts five days + ['tester002', 1 + 0, 5, '24.000 TBD'], # starts one day from now and lasts two days + ['tester003', 1 + 0, 5, '24.000 TBD'], # starts three days from now and lasts one day + ['tester004', 1 + 0, 5, '24.000 TBD'] # starts four days from now and lasts one day + ] + + proposals = [ + # pace proposals here in the format: {'creator' : creator, 'receiver' : receiver, 'start_date' : start-date, 'end_date' : end_date} + + ] + + for pd in proposal_data: + start_date, end_date = test_utils.get_start_and_end_date(now, pd[1], pd[2]) + proposal = {'creator' : pd[0], 'receiver' : pd[0], 'start_date' : start_date, 'end_date' : end_date, 'daily_pay' : pd[3]} + proposals.append(proposal) + + import datetime + test_start_date = now + datetime.timedelta(days = 1) + test_start_date_iso = test_utils.date_to_iso(test_start_date) + + test_end_date = test_start_date + datetime.timedelta(days = 6, hours = 1) + test_end_date_iso = test_utils.date_to_iso(test_end_date) + + test_utils.create_proposals(node_client, proposals) + + # list proposals with inactive status, it shoud be list of pairs id:total_votes + test_utils.list_proposals(node_client, test_start_date_iso, "inactive") + + # each account is voting on proposal + test_utils.vote_proposals(node_client, accounts) + + # list proposals with inactive status, it shoud be list of pairs id:total_votes + votes = test_utils.list_proposals(node_client, test_start_date_iso, "inactive") + for vote in votes: + #should be 0 for all + assert vote == 0, "All votes should be equal to 0" + + logger.info("Balances for accounts after creating proposals") + balances = test_utils.print_balance(node_client, accounts) + for balance in balances: + #should be 390.000 TBD for all + assert balance == '390.000 TBD', "All balances should be equal to 390.000 TBD" + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + # move forward in time to see if proposals are paid + # moving is made in 1h increments at a time, after each + # increment balance is printed + logger.info("Moving to date: {}".format(test_start_date_iso)) + node_client.debug_generate_blocks_until(wif, test_start_date_iso, False) + current_date = test_start_date + while current_date < test_end_date: + current_date = current_date + datetime.timedelta(hours = 1) + current_date_iso = test_utils.date_to_iso(current_date) + + logger.info("Moving to date: {}".format(current_date_iso)) + node_client.debug_generate_blocks_until(wif, current_date_iso, False) + + logger.info("Balances for accounts at time: {}".format(current_date_iso)) + test_utils.print_balance(node_client, accounts) + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + votes = test_utils.list_proposals(node_client, test_start_date_iso, "active") + votes = test_utils.list_proposals(node_client, test_start_date_iso, "expired") + votes = test_utils.list_proposals(node_client, test_start_date_iso, "all") + + # move additional hour to ensure that all proposals ended + logger.info("Moving to date: {}".format(test_end_date_iso)) + node_client.debug_generate_blocks_until(wif, test_end_date_iso, False) + logger.info("Balances for accounts at time: {}".format(test_end_date_iso)) + balances = test_utils.print_balance(node_client, accounts) + test_balances = [ + '510.000 TBD', + '438.000 TBD', + '414.000 TBD', + '414.000 TBD', + ] + for idx in range(0, len(test_balances)): + assert balances[idx] == test_balances[idx], "Balances dont match {} != {}".format(balances[idx], test_balances[idx]) + + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + if node is not None: + node.stop_steem_node() + sys.exit(0) + sys.exit(1) + except Exception as ex: + logger.error("Exception: {}".format(ex)) + if node is not None: + node.stop_steem_node() + sys.exit(1) diff --git a/python_scripts/tests/steempy_sps_tests/proposal_payment_test_004.py b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_004.py new file mode 100755 index 0000000000..1f2fad0132 --- /dev/null +++ b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_004.py @@ -0,0 +1,238 @@ +#!/usr/bin/python3 + +from uuid import uuid4 +from time import sleep +import logging +import sys +import steem_utils.steem_runner +import steem_utils.steem_tools +import test_utils + + +LOG_LEVEL = logging.INFO +LOG_FORMAT = "%(asctime)-15s - %(name)s - %(levelname)s - %(message)s" +MAIN_LOG_PATH = "./sps_proposal_payment_004.log" + +MODULE_NAME = "SPS-Tester-via-steempy" +logger = logging.getLogger(MODULE_NAME) +logger.setLevel(LOG_LEVEL) + +ch = logging.StreamHandler(sys.stdout) +ch.setLevel(LOG_LEVEL) +ch.setFormatter(logging.Formatter(LOG_FORMAT)) + +fh = logging.FileHandler(MAIN_LOG_PATH) +fh.setLevel(LOG_LEVEL) +fh.setFormatter(logging.Formatter(LOG_FORMAT)) + +if not logger.hasHandlers(): + logger.addHandler(ch) + logger.addHandler(fh) + +try: + from steem import Steem +except Exception as ex: + logger.error("SteemPy library is not installed.") + sys.exit(1) + +# Greedy baby scenario +# 0. In this scenario we have one proposal with huge daily pay and couple with low daily pay +# all proposals have the same number of votes, greedy proposal is last +# 1. create few proposals - in this scenario proposals have the same starting and ending dates +# 2. vote on them to show differences in asset distribution (depending on collected votes) +# 3. wait for proposal payment phase +# 4. verify (using account history and by checking regular account balance) that given accounts have been correctly paid. + +# Expected result: all got paid. + + +if __name__ == '__main__': + logger.info("Performing SPS tests") + import argparse + parser = argparse.ArgumentParser() + parser.add_argument("creator", help = "Account to create test accounts with") + parser.add_argument("treasury", help = "Treasury account") + parser.add_argument("wif", help="Private key for creator account") + parser.add_argument("--node-url", dest="node_url", default="http://127.0.0.1:8090", help="Url of working steem node") + parser.add_argument("--run-steemd", dest="steemd_path", help = "Path to steemd executable. Warning: using this option will erase contents of selected steemd working directory.") + parser.add_argument("--working_dir", dest="steemd_working_dir", default="/tmp/steemd-data/", help = "Path to steemd working directory") + parser.add_argument("--config_path", dest="steemd_config_path", default="./steem_utils/resources/config.ini.in",help = "Path to source config.ini file") + parser.add_argument("--no-erase-proposal", action='store_false', dest = "no_erase_proposal", help = "Do not erase proposal created with this test") + + + args = parser.parse_args() + + node = None + + if args.steemd_path: + logger.info("Running steemd via {} in {} with config {}".format(args.steemd_path, + args.steemd_working_dir, + args.steemd_config_path) + ) + + node = steem_utils.steem_runner.SteemNode( + args.steemd_path, + args.steemd_working_dir, + args.steemd_config_path + ) + + node_url = args.node_url + wif = args.wif + + if len(wif) == 0: + logger.error("Private-key is not set in config.ini") + sys.exit(1) + + logger.info("Using node at: {}".format(node_url)) + logger.info("Using private-key: {}".format(wif)) + + accounts = [ + # place accounts here in the format: {'name' : name, 'private_key' : private-key, 'public_key' : public-key} + {"name" : "tester001", "private_key" : "5JBuekd1sVXXK3wBu6nvPB1LWypZ83BYdu7tGcUNYVd42xQGGh1", "public_key" : "TST5kSj1yTzBz3PDoJ5QUyVVagdgYfs8Y4vVsZG3dqKJU8hg7WmQN"}, + {"name" : "tester002", "private_key" : "5KgfcV9bgEen3v9mxkoGw6Rhuf2giDRZTHZjzwisjkrpF4FUh3N", "public_key" : "TST5gQPYm5bs9dRPHpqBy6dU32M8FcoKYFdF4YWEChUarc9FdYHzn"}, + {"name" : "tester003", "private_key" : "5Jz3fcrrgKMbL8ncpzTdQmdRVHdxMhi8qScoxSR3TnAFUcdyD5N", "public_key" : "TST57wy5bXyJ4Z337Bo6RbinR6NyTRJxzond5dmGsP4gZ51yN6Zom"}, + {"name" : "tester004", "private_key" : "5KcmobLVMSAVzETrZxfEGG73Zvi5SKTgJuZXtNgU3az2VK3Krye", "public_key" : "TST8dPte853xAuLMDV7PTVmiNMRwP6itMyvSmaht7J5tVczkDLa5K"}, + ] + + if not accounts: + logger.error("Accounts array is empty, please add accounts in a form {\"name\" : name, \"private_key\" : private_key, \"public_key\" : public_key}") + sys.exit(1) + + keys = [wif] + for account in accounts: + keys.append(account["private_key"]) + + if node is not None: + node.run_steem_node(["--enable-stale-production"]) + try: + if node is None or node.is_running(): + node_client = Steem(nodes = [node_url], no_broadcast = False, + keys = keys + ) + + # create accounts + test_utils.create_accounts(node_client, args.creator, accounts) + # tranfer to vesting + test_utils.transfer_to_vesting(node_client, args.creator, accounts, "300.000", + "TESTS" + ) + # transfer assets to accounts + test_utils.transfer_assets_to_accounts(node_client, args.creator, accounts, + "400.000", "TESTS" + ) + + test_utils.transfer_assets_to_accounts(node_client, args.creator, accounts, + "400.000", "TBD" + ) + + logger.info("Balances for accounts after initial transfer") + test_utils.print_balance(node_client, accounts) + # transfer assets to treasury + test_utils.transfer_assets_to_treasury(node_client, args.creator, args.treasury, + "1000000.000", "TESTS" + ) + + test_utils.transfer_assets_to_treasury(node_client, args.creator, args.treasury, + "1000000.000", "TBD" + ) + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + # create post for valid permlinks + test_utils.create_posts(node_client, accounts) + + now = node_client.get_dynamic_global_properties().get('time', None) + if now is None: + raise ValueError("Head time is None") + now = test_utils.date_from_iso(now) + + proposal_data = [ + ['tester001', 1 + 0, 5, '24.000 TBD'], # starts one day from now and lasts two days + ['tester002', 1 + 0, 5, '24.000 TBD'], # starts three days from now and lasts one day + ['tester003', 1 + 0, 5, '24.000 TBD'], # starts four days from now and lasts one day + ['tester004', 1 + 0, 5, '240000.000 TBD'], # starts one day from now and lasts five days + ] + + proposals = [ + # pace proposals here in the format: {'creator' : creator, 'receiver' : receiver, 'start_date' : start-date, 'end_date' : end_date} + + ] + + for pd in proposal_data: + start_date, end_date = test_utils.get_start_and_end_date(now, pd[1], pd[2]) + proposal = {'creator' : pd[0], 'receiver' : pd[0], 'start_date' : start_date, 'end_date' : end_date, 'daily_pay' : pd[3]} + proposals.append(proposal) + + import datetime + test_start_date = now + datetime.timedelta(days = 1) + test_start_date_iso = test_utils.date_to_iso(test_start_date) + + test_end_date = test_start_date + datetime.timedelta(days = 6, hours = 1) + test_end_date_iso = test_utils.date_to_iso(test_end_date) + + test_utils.create_proposals(node_client, proposals) + + # list proposals with inactive status, it shoud be list of pairs id:total_votes + test_utils.list_proposals(node_client, test_start_date_iso, "inactive") + + # each account is voting on proposal + test_utils.vote_proposals(node_client, accounts) + + # list proposals with inactive status, it shoud be list of pairs id:total_votes + votes = test_utils.list_proposals(node_client, test_start_date_iso, "inactive") + for vote in votes: + #should be 0 for all + assert vote == 0, "All votes should be equal to 0" + + logger.info("Balances for accounts after creating proposals") + balances = test_utils.print_balance(node_client, accounts) + for balance in balances: + #should be 390.000 TBD for all + assert balance == '390.000 TBD', "All balances should be equal to 390.000 TBD" + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + # move forward in time to see if proposals are paid + # moving is made in 1h increments at a time, after each + # increment balance is printed + logger.info("Moving to date: {}".format(test_start_date_iso)) + node_client.debug_generate_blocks_until(wif, test_start_date_iso, False) + current_date = test_start_date + while current_date < test_end_date: + current_date = current_date + datetime.timedelta(hours = 1) + current_date_iso = test_utils.date_to_iso(current_date) + + logger.info("Moving to date: {}".format(current_date_iso)) + node_client.debug_generate_blocks_until(wif, current_date_iso, False) + + logger.info("Balances for accounts at time: {}".format(current_date_iso)) + test_utils.print_balance(node_client, accounts) + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + votes = test_utils.list_proposals(node_client, test_start_date_iso, "active") + votes = test_utils.list_proposals(node_client, test_start_date_iso, "expired") + votes = test_utils.list_proposals(node_client, test_start_date_iso, "all") + + # move additional hour to ensure that all proposals ended + logger.info("Moving to date: {}".format(test_end_date_iso)) + node_client.debug_generate_blocks_until(wif, test_end_date_iso, False) + logger.info("Balances for accounts at time: {}".format(test_end_date_iso)) + balances = test_utils.print_balance(node_client, accounts) + test_balances = [ + '510.000 TBD', + '438.000 TBD', + '414.000 TBD', + '414.000 TBD', + ] + for idx in range(0, len(test_balances)): + assert balances[idx] == test_balances[idx], "Balances dont match {} != {}".format(balances[idx], test_balances[idx]) + + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + if node is not None: + node.stop_steem_node() + sys.exit(0) + sys.exit(1) + except Exception as ex: + logger.error("Exception: {}".format(ex)) + if node is not None: + node.stop_steem_node() + sys.exit(1) diff --git a/python_scripts/tests/steempy_sps_tests/steem_utils/steem_runner.py b/python_scripts/tests/steempy_sps_tests/steem_utils/steem_runner.py index a66b5976b6..bec33beac3 100644 --- a/python_scripts/tests/steempy_sps_tests/steem_utils/steem_runner.py +++ b/python_scripts/tests/steempy_sps_tests/steem_utils/steem_runner.py @@ -14,21 +14,10 @@ LOG_FORMAT = "%(asctime)-15s - %(name)s - %(levelname)s - %(message)s" MAIN_LOG_PATH = "./steem_runner.log" -MODULE_NAME = "STEEM Runner Py" +MODULE_NAME = "SPS-Tester-via-steempy.Runner-Py" logger = logging.getLogger(MODULE_NAME) logger.setLevel(LOG_LEVEL) -ch = logging.StreamHandler(sys.stdout) -ch.setLevel(LOG_LEVEL) -ch.setFormatter(logging.Formatter(LOG_FORMAT)) - -fh = logging.FileHandler(MAIN_LOG_PATH) -fh.setLevel(LOG_LEVEL) -fh.setFormatter(logging.Formatter(LOG_FORMAT)) - -if not logger.hasHandlers(): - logger.addHandler(ch) - logger.addHandler(fh) class SteemNode(object): def __init__(self, steem_executable, working_dir, config_src_path): diff --git a/python_scripts/tests/steempy_sps_tests/steem_utils/steem_tools.py b/python_scripts/tests/steempy_sps_tests/steem_utils/steem_tools.py index 4686094631..8a72b69ad9 100644 --- a/python_scripts/tests/steempy_sps_tests/steem_utils/steem_tools.py +++ b/python_scripts/tests/steempy_sps_tests/steem_utils/steem_tools.py @@ -12,23 +12,11 @@ LOG_LEVEL = logging.INFO LOG_FORMAT = "%(asctime)-15s - %(name)s - %(levelname)s - %(message)s" -MAIN_LOG_PATH = "./steem_tools.log" -MODULE_NAME = "Steem Tools Py" +MODULE_NAME = "SPS-Tester-via-steempy.Tools-Py" logger = logging.getLogger(MODULE_NAME) logger.setLevel(LOG_LEVEL) -ch = logging.StreamHandler(sys.stdout) -ch.setLevel(LOG_LEVEL) -ch.setFormatter(logging.Formatter(LOG_FORMAT)) - -fh = logging.FileHandler(MAIN_LOG_PATH) -fh.setLevel(LOG_LEVEL) -fh.setFormatter(logging.Formatter(LOG_FORMAT)) - -if not logger.hasHandlers(): - logger.addHandler(ch) - logger.addHandler(fh) def save_screen_cfg(cfg_file_name, log_file_path): """Creates a config file for screen command. In config file we configure logging path and interval. diff --git a/python_scripts/tests/steempy_sps_tests/steempy_sps_tests.py b/python_scripts/tests/steempy_sps_tests/steempy_sps_tests.py index f5aa7c06a4..e21fca2ef2 100755 --- a/python_scripts/tests/steempy_sps_tests/steempy_sps_tests.py +++ b/python_scripts/tests/steempy_sps_tests/steempy_sps_tests.py @@ -6,12 +6,18 @@ import sys import os import steem_utils.steem_runner +import steem_utils.steem_tools +import test_utils LOG_LEVEL = logging.INFO LOG_FORMAT = "%(asctime)-15s - %(name)s - %(levelname)s - %(message)s" MAIN_LOG_PATH = "./sps_test.log" -MODULE_NAME = "SPS Tester via steempy" +steem_utils.steem_runner.initialize_logging(MAIN_LOG_PATH) +steem_utils.steem_tools.initialize_logging(MAIN_LOG_PATH) +test_utils.initialize_logging(MAIN_LOG_PATH) + +MODULE_NAME = "SPS-Tester-via-steempy" logger = logging.getLogger(MODULE_NAME) logger.setLevel(LOG_LEVEL) @@ -33,21 +39,6 @@ logger.error("SteemPy library is not installed.") sys.exit(1) -def get_date_as_isostr(date): - return date.replace(microsecond=0).isoformat() - - -def get_isostr_start_end_date(now, start_date_delta, end_date_delta): - from datetime import timedelta - - start_date = now + timedelta(days = start_date_delta) - end_date = start_date + timedelta(days = end_date_delta) - - start_date = start_date.replace(microsecond=0).isoformat() - end_date = end_date.replace(microsecond=0).isoformat() - - return start_date, end_date - def test_create_proposal(node, creator_account, receiver_account, wif, subject): logger.info("Testing: create_proposal") @@ -56,7 +47,7 @@ def test_create_proposal(node, creator_account, receiver_account, wif, subject): import datetime now = datetime.datetime.now() - start_date, end_date = get_isostr_start_end_date(now, 10, 2) + start_date, end_date = test_utils.get_start_and_end_date(now, 10, 2) from steem.account import Account try: @@ -158,7 +149,7 @@ def test_vote_proposal(node, account, wif, subject): assert ret["operations"][0][1]["voter"] == account assert ret["operations"][0][1]["proposal_ids"][0] == proposal_id assert ret["operations"][0][1]["approve"] == True - sleep(6) + steem_utils.steem_tools.wait_for_blocks_produced(2, node) def test_list_voter_proposals(node, account, wif, subject): logger.info("Testing: list_voter_proposals") @@ -243,7 +234,7 @@ def test_iterate_results_test(node, creator_account, receiver_account, wif, subj ] for start_end_pair in start_end_pairs: - start_date, end_date = get_isostr_start_end_date(now, start_end_pair[0], start_end_pair[1]) + start_date, end_date = test_utils.get_start_and_end_date(now, start_end_pair[0], start_end_pair[1]) s.commit.create_proposal( creator["name"], @@ -254,10 +245,9 @@ def test_iterate_results_test(node, creator_account, receiver_account, wif, subj subject, "steempy-proposal-title" ) - sleep(3) - sleep(6) + steem_utils.steem_tools.wait_for_blocks_produced(5, node) - start_date = get_date_as_isostr(now + datetime.timedelta(days = 5)) + start_date = test_utils.date_to_iso(now + datetime.timedelta(days = 5)) # 2 then we will list proposals starting from kth proposal with limit set to m < k proposals = s.list_proposals(start_date, "by_start_date", "direction_descending", 3, "all") @@ -284,21 +274,21 @@ def test_iterate_results_test(node, creator_account, receiver_account, wif, subj # 4 then we will use newly introduced last_id field, we should see diferent set of proposals proposals = s.list_proposals(start_date, "by_start_date", "direction_descending", 3, "all", oids[-1]) - start_date, end_date = get_isostr_start_end_date(now, 5, 4) + start_date, end_date = test_utils.get_start_and_end_date(now, 5, 4) assert proposals[-1]["start_date"] == start_date, "Expected start_date do not match {} != {}".format(start_date, proposals[-1]["start_date"]) assert proposals[-1]["end_date"] == end_date, "Expected end_date do not match {} != {}".format(end_date, proposals[-1]["end_date"]) # remove all created proposals if remove: - start_date = get_date_as_isostr(now + datetime.timedelta(days = 6)) + start_date = test_utils.date_to_iso(now + datetime.timedelta(days = 6)) for a in range(0, 2): proposals = s.list_proposals(start_date, "by_start_date", "direction_descending", 5, "all") ids = [] for proposal in proposals: ids.append(int(proposal['id'])) s.commit.remove_proposal(creator["name"], ids) - sleep(12) + steem_utils.steem_tools.wait_for_blocks_produced(3, node) if __name__ == '__main__': @@ -343,16 +333,16 @@ def test_iterate_results_test(node, creator_account, receiver_account, wif, subj try: if node is None or node.is_running(): test_create_proposal(node_url, args.creator, args.receiver, wif, subject) - sleep(6) + steem_utils.steem_tools.wait_for_blocks_produced(2, node) test_list_proposals(node_url, args.creator, wif, subject) test_find_proposals(node_url, args.creator, wif, subject) test_vote_proposal(node_url, args.creator, wif, subject) test_list_voter_proposals(node_url, args.creator, wif, subject) - sleep(6) + steem_utils.steem_tools.wait_for_blocks_produced(2, node) if args.no_erase_proposal: test_remove_proposal(node_url, args.creator, wif, subject) test_iterate_results_test(args.node_url, args.creator, args.receiver, args.wif, str(uuid4()), args.no_erase_proposal) - sleep(6) + steem_utils.steem_tools.wait_for_blocks_produced(2, node) if node is not None: node.stop_steem_node() sys.exit(0) diff --git a/python_scripts/tests/steempy_sps_tests/test_utils.py b/python_scripts/tests/steempy_sps_tests/test_utils.py new file mode 100644 index 0000000000..6ddd446958 --- /dev/null +++ b/python_scripts/tests/steempy_sps_tests/test_utils.py @@ -0,0 +1,165 @@ +from uuid import uuid4 +from time import sleep +import logging +import sys +import steem_utils.steem_runner +import steem_utils.steem_tools + + +LOG_LEVEL = logging.INFO +LOG_FORMAT = "%(asctime)-15s - %(name)s - %(levelname)s - %(message)s" +MAIN_LOG_PATH = "./sps_tester_utils.log" + +MODULE_NAME = "SPS-Tester-via-steempy.SPS-Tester-Utils" +logger = logging.getLogger(MODULE_NAME) +logger.setLevel(LOG_LEVEL) + + +# create_account "initminer" "pychol" "" true +def create_accounts(node, creator, accounts): + for account in accounts: + logger.info("Creating account: {}".format(account['name'])) + node.commit.create_account(account['name'], + owner_key=account['public_key'], + active_key=account['public_key'], + posting_key=account['public_key'], + memo_key=account['public_key'], + store_keys = False, + creator=creator, + asset='TESTS' + ) + steem_utils.steem_tools.wait_for_blocks_produced(5, node.url) + + +# transfer_to_vesting initminer pychol "310.000 TESTS" true +def transfer_to_vesting(node, from_account, accounts, amount, asset): + for acnt in accounts: + logger.info("Transfer to vesting from {} to {} amount {} {}".format( + from_account, acnt['name'], amount, asset) + ) + + node.commit.transfer_to_vesting(amount, to = acnt['name'], + account = from_account, asset = asset + ) + steem_utils.steem_tools.wait_for_blocks_produced(5, node.url) + + +# transfer initminer pychol "399.000 TESTS" "initial transfer" true +# transfer initminer pychol "398.000 TBD" "initial transfer" true +def transfer_assets_to_accounts(node, from_account, accounts, amount, asset): + for acnt in accounts: + logger.info("Transfer from {} to {} amount {} {}".format(from_account, + acnt['name'], amount, asset) + ) + node.commit.transfer(acnt['name'], amount, asset, + memo = "initial transfer", account = from_account + ) + steem_utils.steem_tools.wait_for_blocks_produced(5, node.url) + + +def transfer_assets_to_treasury(node, from_account, treasury_account, amount, asset): + logger.info("Transfer from {} to {} amount {} {}".format(from_account, + treasury_account, amount, asset) + ) + node.commit.transfer(treasury_account, amount, asset, + memo = "initial transfer", account = from_account + ) + steem_utils.steem_tools.wait_for_blocks_produced(2, node.url) + + +def get_permlink(account): + return "steempy-proposal-title-{}".format(account) + + +def create_posts(node, accounts): + logger.info("Creating posts...") + for acnt in accounts: + logger.info("New post ==> ({},{},{},{},{})".format( + "Steempy proposal title [{}]".format(acnt['name']), + "Steempy proposal body [{}]".format(acnt['name']), + acnt['name'], + get_permlink(acnt['name']), + "proposals" + )) + node.commit.post("Steempy proposal title [{}]".format(acnt['name']), + "Steempy proposal body [{}]".format(acnt['name']), + acnt['name'], + permlink = get_permlink(acnt['name']), + tags = "proposals") + steem_utils.steem_tools.wait_for_blocks_produced(5, node.url) + + +def create_proposals(node, proposals): + logger.info("Creating proposals...") + for proposal in proposals: + logger.info("New proposal ==> ({},{},{},{},{},{},{})".format( + proposal['creator'], + proposal['receiver'], + proposal['start_date'], + proposal['end_date'], + proposal['daily_pay'], + "Proposal from account {}".format(proposal['creator']), + get_permlink(proposal['creator']) + )) + node.commit.create_proposal( + proposal['creator'], + proposal['receiver'], + proposal['start_date'], + proposal['end_date'], + proposal['daily_pay'], + "Proposal from account {}".format(proposal['creator']), + get_permlink(proposal['creator']) + ) + steem_utils.steem_tools.wait_for_blocks_produced(5, node.url) + + +def vote_proposals(node, accounts): + logger.info("Voting proposals...") + for acnt in accounts: + proposal_set = [x for x in range(0, len(accounts))] + logger.info("Account {} voted for proposals: {}".format(acnt["name"], ",".join(str(x) for x in proposal_set))) + node.commit.update_proposal_votes(acnt["name"], proposal_set, True) + steem_utils.steem_tools.wait_for_blocks_produced(5, node.url) + + +def list_proposals(node, start_date, status): + proposals = node.list_proposals(start_date, "by_start_date", "direction_ascending", 1000, status) + ret = [] + votes = [] + for proposal in proposals: + ret.append("{}:{}".format(proposal.get('id', 'Error'), proposal.get('total_votes', 'Error'))) + votes.append(int(proposal.get('total_votes', -1))) + logger.info("Listing proposals with status {} (id:total_votes): {}".format(status, ",".join(ret))) + return votes + + +def print_balance(node, accounts): + balances = [] + balances_str = [] + for acnt in accounts: + ret = node.get_account(acnt['name']) + sbd = ret.get('sbd_balance', 'Error') + balances_str.append("{}:{}".format(acnt['name'], sbd)) + balances.append(sbd) + logger.info("Balances ==> {}".format(",".join(balances_str))) + return balances + + +def date_to_iso(date): + return date.replace(microsecond=0).isoformat() + + +def date_from_iso(date_iso_str): + import dateutil.parser + return dateutil.parser.parse(date_iso_str) + + +def get_start_and_end_date(now, start_days_from_now, end_days_from_start): + from datetime import timedelta + start_date = now + timedelta(days = start_days_from_now) + end_date = start_date + timedelta(days = end_days_from_start) + + assert start_date > now, "Start date must be greater than now" + assert end_date > start_date, "End date must be greater than start date" + + return date_to_iso(start_date), date_to_iso(end_date) \ No newline at end of file From e915c9e5444bf9d4b16cf88f472ac11f2c48357d Mon Sep 17 00:00:00 2001 From: Dariusz Kedzierski Date: Wed, 10 Apr 2019 11:15:30 +0200 Subject: [PATCH 3/5] More tests, some fixes and improvements --- .../steempy_sps_tests/id_collision_test.py | 2 +- .../steempy_sps_tests/list_proposals_tests.py | 4 +- .../list_voter_proposal_test.py | 2 +- .../proposal_benchmark_test.py | 4 +- .../proposal_payment_test_001.py | 7 +- .../proposal_payment_test_003.py | 18 +- .../proposal_payment_test_004.py | 18 +- .../proposal_payment_test_005.py | 238 ++++++++++++++++++ .../proposal_payment_test_006.py | 238 ++++++++++++++++++ .../steempy_sps_tests/steempy_sps_tests.py | 12 +- 10 files changed, 510 insertions(+), 33 deletions(-) create mode 100755 python_scripts/tests/steempy_sps_tests/proposal_payment_test_005.py create mode 100755 python_scripts/tests/steempy_sps_tests/proposal_payment_test_006.py diff --git a/python_scripts/tests/steempy_sps_tests/id_collision_test.py b/python_scripts/tests/steempy_sps_tests/id_collision_test.py index 7f6d2127db..03ca32b459 100755 --- a/python_scripts/tests/steempy_sps_tests/id_collision_test.py +++ b/python_scripts/tests/steempy_sps_tests/id_collision_test.py @@ -12,7 +12,7 @@ LOG_FORMAT = "%(asctime)-15s - %(name)s - %(levelname)s - %(message)s" MAIN_LOG_PATH = "./sps_id_collision_test.log" -MODULE_NAME = "SPS Tester via steempy - id collision test" +MODULE_NAME = "SPS-Tester-via-steempy" logger = logging.getLogger(MODULE_NAME) logger.setLevel(LOG_LEVEL) diff --git a/python_scripts/tests/steempy_sps_tests/list_proposals_tests.py b/python_scripts/tests/steempy_sps_tests/list_proposals_tests.py index 8d734a6e56..2c1b860eb4 100755 --- a/python_scripts/tests/steempy_sps_tests/list_proposals_tests.py +++ b/python_scripts/tests/steempy_sps_tests/list_proposals_tests.py @@ -11,9 +11,9 @@ LOG_LEVEL = logging.INFO LOG_FORMAT = "%(asctime)-15s - %(name)s - %(levelname)s - %(message)s" -MAIN_LOG_PATH = "./sps_proposal_payment.log" +MAIN_LOG_PATH = "./sps_list_proposal.log" -MODULE_NAME = "SPS Tester via steempy - list proposals test" +MODULE_NAME = "SPS-Tester-via-steempy" logger = logging.getLogger(MODULE_NAME) logger.setLevel(LOG_LEVEL) diff --git a/python_scripts/tests/steempy_sps_tests/list_voter_proposal_test.py b/python_scripts/tests/steempy_sps_tests/list_voter_proposal_test.py index 2e7c559374..23e90db7aa 100644 --- a/python_scripts/tests/steempy_sps_tests/list_voter_proposal_test.py +++ b/python_scripts/tests/steempy_sps_tests/list_voter_proposal_test.py @@ -13,7 +13,7 @@ LOG_FORMAT = "%(asctime)-15s - %(name)s - %(levelname)s - %(message)s" MAIN_LOG_PATH = "./sps_proposal_payment.log" -MODULE_NAME = "SPS Tester via steempy - proposal payment test" +MODULE_NAME = "SPS-Tester-via-steempy" logger = logging.getLogger(MODULE_NAME) logger.setLevel(LOG_LEVEL) diff --git a/python_scripts/tests/steempy_sps_tests/proposal_benchmark_test.py b/python_scripts/tests/steempy_sps_tests/proposal_benchmark_test.py index 4be7131370..eeeaa5a098 100644 --- a/python_scripts/tests/steempy_sps_tests/proposal_benchmark_test.py +++ b/python_scripts/tests/steempy_sps_tests/proposal_benchmark_test.py @@ -42,9 +42,9 @@ LOG_LEVEL = logging.INFO LOG_FORMAT = "%(asctime)-15s - %(name)s - %(levelname)s - %(message)s" -MAIN_LOG_PATH = "./sps_proposal_payment.log" +MAIN_LOG_PATH = "./sps_benchmark_test.log" -MODULE_NAME = "SPS Tester via steempy - proposal payment test" +MODULE_NAME = "SPS-Tester-via-steempy" logger = logging.getLogger(MODULE_NAME) logger.setLevel(LOG_LEVEL) diff --git a/python_scripts/tests/steempy_sps_tests/proposal_payment_test_001.py b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_001.py index 17c78514e6..0595a98e34 100755 --- a/python_scripts/tests/steempy_sps_tests/proposal_payment_test_001.py +++ b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_001.py @@ -106,7 +106,12 @@ def create_proposals(node, accounts, start_date, end_date): logger.info("Using private-key: {}".format(wif)) accounts = [ - ] + # place accounts here in the format: {'name' : name, 'private_key' : private-key, 'public_key' : public-key} + {"name" : "tester001", "private_key" : "5JBuekd1sVXXK3wBu6nvPB1LWypZ83BYdu7tGcUNYVd42xQGGh1", "public_key" : "TST5kSj1yTzBz3PDoJ5QUyVVagdgYfs8Y4vVsZG3dqKJU8hg7WmQN"}, + {"name" : "tester002", "private_key" : "5KgfcV9bgEen3v9mxkoGw6Rhuf2giDRZTHZjzwisjkrpF4FUh3N", "public_key" : "TST5gQPYm5bs9dRPHpqBy6dU32M8FcoKYFdF4YWEChUarc9FdYHzn"}, + {"name" : "tester003", "private_key" : "5Jz3fcrrgKMbL8ncpzTdQmdRVHdxMhi8qScoxSR3TnAFUcdyD5N", "public_key" : "TST57wy5bXyJ4Z337Bo6RbinR6NyTRJxzond5dmGsP4gZ51yN6Zom"}, + {"name" : "tester004", "private_key" : "5KcmobLVMSAVzETrZxfEGG73Zvi5SKTgJuZXtNgU3az2VK3Krye", "public_key" : "TST8dPte853xAuLMDV7PTVmiNMRwP6itMyvSmaht7J5tVczkDLa5K"}, + ] if not accounts: logger.error("Accounts array is empty, please add accounts in a form {\"name\" : name, \"private_key\" : private_key, \"public_key\" : public_key}") diff --git a/python_scripts/tests/steempy_sps_tests/proposal_payment_test_003.py b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_003.py index c4ae391636..94c7d8dd64 100755 --- a/python_scripts/tests/steempy_sps_tests/proposal_payment_test_003.py +++ b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_003.py @@ -146,10 +146,10 @@ now = test_utils.date_from_iso(now) proposal_data = [ - ['tester001', 1 + 0, 5, '240000.000 TBD'], # starts one day from now and lasts five days - ['tester002', 1 + 0, 5, '24.000 TBD'], # starts one day from now and lasts two days - ['tester003', 1 + 0, 5, '24.000 TBD'], # starts three days from now and lasts one day - ['tester004', 1 + 0, 5, '24.000 TBD'] # starts four days from now and lasts one day + ['tester001', 1 + 0, 3, '240000.000 TBD'], # starts 1 day from now and lasts 3 days + ['tester002', 1 + 0, 3, '24.000 TBD'], # starts 1 day from now and lasts 3 days + ['tester003', 1 + 0, 3, '24.000 TBD'], # starts 1 days from now and lasts 3 day + ['tester004', 1 + 0, 3, '24.000 TBD'] # starts 1 days from now and lasts 3 day ] proposals = [ @@ -166,7 +166,7 @@ test_start_date = now + datetime.timedelta(days = 1) test_start_date_iso = test_utils.date_to_iso(test_start_date) - test_end_date = test_start_date + datetime.timedelta(days = 6, hours = 1) + test_end_date = test_start_date + datetime.timedelta(days = 4, hours = 1) test_end_date_iso = test_utils.date_to_iso(test_end_date) test_utils.create_proposals(node_client, proposals) @@ -217,10 +217,10 @@ logger.info("Balances for accounts at time: {}".format(test_end_date_iso)) balances = test_utils.print_balance(node_client, accounts) test_balances = [ - '510.000 TBD', - '438.000 TBD', - '414.000 TBD', - '414.000 TBD', + '29951.682 TBD', + '390.000 TBD', + '390.000 TBD', + '390.000 TBD', ] for idx in range(0, len(test_balances)): assert balances[idx] == test_balances[idx], "Balances dont match {} != {}".format(balances[idx], test_balances[idx]) diff --git a/python_scripts/tests/steempy_sps_tests/proposal_payment_test_004.py b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_004.py index 1f2fad0132..94eedba269 100755 --- a/python_scripts/tests/steempy_sps_tests/proposal_payment_test_004.py +++ b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_004.py @@ -146,10 +146,10 @@ now = test_utils.date_from_iso(now) proposal_data = [ - ['tester001', 1 + 0, 5, '24.000 TBD'], # starts one day from now and lasts two days - ['tester002', 1 + 0, 5, '24.000 TBD'], # starts three days from now and lasts one day - ['tester003', 1 + 0, 5, '24.000 TBD'], # starts four days from now and lasts one day - ['tester004', 1 + 0, 5, '240000.000 TBD'], # starts one day from now and lasts five days + ['tester001', 1 + 0, 3, '24.000 TBD'], # starts 1 day from now and lasts 3 days + ['tester002', 1 + 0, 3, '24.000 TBD'], # starts 1 days from now and lasts 3 day + ['tester003', 1 + 0, 3, '24.000 TBD'], # starts 1 days from now and lasts 3 day + ['tester004', 1 + 0, 3, '240000.000 TBD'], # starts 1 day from now and lasts 3 days ] proposals = [ @@ -166,7 +166,7 @@ test_start_date = now + datetime.timedelta(days = 1) test_start_date_iso = test_utils.date_to_iso(test_start_date) - test_end_date = test_start_date + datetime.timedelta(days = 6, hours = 1) + test_end_date = test_start_date + datetime.timedelta(days = 4, hours = 1) test_end_date_iso = test_utils.date_to_iso(test_end_date) test_utils.create_proposals(node_client, proposals) @@ -217,10 +217,10 @@ logger.info("Balances for accounts at time: {}".format(test_end_date_iso)) balances = test_utils.print_balance(node_client, accounts) test_balances = [ - '510.000 TBD', - '438.000 TBD', - '414.000 TBD', - '414.000 TBD', + '462.000 TBD', + '462.000 TBD', + '462.000 TBD', + '29735.682 TBD', ] for idx in range(0, len(test_balances)): assert balances[idx] == test_balances[idx], "Balances dont match {} != {}".format(balances[idx], test_balances[idx]) diff --git a/python_scripts/tests/steempy_sps_tests/proposal_payment_test_005.py b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_005.py new file mode 100755 index 0000000000..95bca631db --- /dev/null +++ b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_005.py @@ -0,0 +1,238 @@ +#!/usr/bin/python3 + +from uuid import uuid4 +from time import sleep +import logging +import sys +import steem_utils.steem_runner +import steem_utils.steem_tools +import test_utils + + +LOG_LEVEL = logging.INFO +LOG_FORMAT = "%(asctime)-15s - %(name)s - %(levelname)s - %(message)s" +MAIN_LOG_PATH = "./sps_proposal_payment_003.log" + +MODULE_NAME = "SPS-Tester-via-steempy" +logger = logging.getLogger(MODULE_NAME) +logger.setLevel(LOG_LEVEL) + +ch = logging.StreamHandler(sys.stdout) +ch.setLevel(LOG_LEVEL) +ch.setFormatter(logging.Formatter(LOG_FORMAT)) + +fh = logging.FileHandler(MAIN_LOG_PATH) +fh.setLevel(LOG_LEVEL) +fh.setFormatter(logging.Formatter(LOG_FORMAT)) + +if not logger.hasHandlers(): + logger.addHandler(ch) + logger.addHandler(fh) + +try: + from steem import Steem +except Exception as ex: + logger.error("SteemPy library is not installed.") + sys.exit(1) + +# Greedy baby scenario +# 0. In this scenario we have one proposal with huge daily pay and couple with low daily pay +# all proposals have the same number of votes, greedy proposal is first +# 1. create few proposals - in this scenario proposals have different starting and ending dates +# 2. vote on them to show differences in asset distribution (depending on collected votes) +# 3. wait for proposal payment phase +# 4. verify (using account history and by checking regular account balance) that given accounts have been correctly paid. + +# Expected result: Only greedy baby got paid + + +if __name__ == '__main__': + logger.info("Performing SPS tests") + import argparse + parser = argparse.ArgumentParser() + parser.add_argument("creator", help = "Account to create test accounts with") + parser.add_argument("treasury", help = "Treasury account") + parser.add_argument("wif", help="Private key for creator account") + parser.add_argument("--node-url", dest="node_url", default="http://127.0.0.1:8090", help="Url of working steem node") + parser.add_argument("--run-steemd", dest="steemd_path", help = "Path to steemd executable. Warning: using this option will erase contents of selected steemd working directory.") + parser.add_argument("--working_dir", dest="steemd_working_dir", default="/tmp/steemd-data/", help = "Path to steemd working directory") + parser.add_argument("--config_path", dest="steemd_config_path", default="./steem_utils/resources/config.ini.in",help = "Path to source config.ini file") + parser.add_argument("--no-erase-proposal", action='store_false', dest = "no_erase_proposal", help = "Do not erase proposal created with this test") + + + args = parser.parse_args() + + node = None + + if args.steemd_path: + logger.info("Running steemd via {} in {} with config {}".format(args.steemd_path, + args.steemd_working_dir, + args.steemd_config_path) + ) + + node = steem_utils.steem_runner.SteemNode( + args.steemd_path, + args.steemd_working_dir, + args.steemd_config_path + ) + + node_url = args.node_url + wif = args.wif + + if len(wif) == 0: + logger.error("Private-key is not set in config.ini") + sys.exit(1) + + logger.info("Using node at: {}".format(node_url)) + logger.info("Using private-key: {}".format(wif)) + + accounts = [ + # place accounts here in the format: {'name' : name, 'private_key' : private-key, 'public_key' : public-key} + {"name" : "tester001", "private_key" : "5JBuekd1sVXXK3wBu6nvPB1LWypZ83BYdu7tGcUNYVd42xQGGh1", "public_key" : "TST5kSj1yTzBz3PDoJ5QUyVVagdgYfs8Y4vVsZG3dqKJU8hg7WmQN"}, + {"name" : "tester002", "private_key" : "5KgfcV9bgEen3v9mxkoGw6Rhuf2giDRZTHZjzwisjkrpF4FUh3N", "public_key" : "TST5gQPYm5bs9dRPHpqBy6dU32M8FcoKYFdF4YWEChUarc9FdYHzn"}, + {"name" : "tester003", "private_key" : "5Jz3fcrrgKMbL8ncpzTdQmdRVHdxMhi8qScoxSR3TnAFUcdyD5N", "public_key" : "TST57wy5bXyJ4Z337Bo6RbinR6NyTRJxzond5dmGsP4gZ51yN6Zom"}, + {"name" : "tester004", "private_key" : "5KcmobLVMSAVzETrZxfEGG73Zvi5SKTgJuZXtNgU3az2VK3Krye", "public_key" : "TST8dPte853xAuLMDV7PTVmiNMRwP6itMyvSmaht7J5tVczkDLa5K"}, + ] + + if not accounts: + logger.error("Accounts array is empty, please add accounts in a form {\"name\" : name, \"private_key\" : private_key, \"public_key\" : public_key}") + sys.exit(1) + + keys = [wif] + for account in accounts: + keys.append(account["private_key"]) + + if node is not None: + node.run_steem_node(["--enable-stale-production"]) + try: + if node is None or node.is_running(): + node_client = Steem(nodes = [node_url], no_broadcast = False, + keys = keys + ) + + # create accounts + test_utils.create_accounts(node_client, args.creator, accounts) + # tranfer to vesting + test_utils.transfer_to_vesting(node_client, args.creator, accounts, "300.000", + "TESTS" + ) + # transfer assets to accounts + test_utils.transfer_assets_to_accounts(node_client, args.creator, accounts, + "400.000", "TESTS" + ) + + test_utils.transfer_assets_to_accounts(node_client, args.creator, accounts, + "400.000", "TBD" + ) + + logger.info("Balances for accounts after initial transfer") + test_utils.print_balance(node_client, accounts) + # transfer assets to treasury + test_utils.transfer_assets_to_treasury(node_client, args.creator, args.treasury, + "1000000.000", "TESTS" + ) + + test_utils.transfer_assets_to_treasury(node_client, args.creator, args.treasury, + "1000000.000", "TBD" + ) + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + # create post for valid permlinks + test_utils.create_posts(node_client, accounts) + + now = node_client.get_dynamic_global_properties().get('time', None) + if now is None: + raise ValueError("Head time is None") + now = test_utils.date_from_iso(now) + + proposal_data = [ + ['tester001', 1 + 0, 3, '240000.000 TBD'], # starts 1 day from now and lasts 3 days + ['tester002', 1 + 0, 1, '24.000 TBD'], # starts 1 day from now and lasts 1 days + ['tester003', 1 + 1, 1, '24.000 TBD'], # starts 2 days from now and lasts 1 day + ['tester004', 1 + 2, 1, '24.000 TBD'] # starts 3 days from now and lasts 1 day + ] + + proposals = [ + # pace proposals here in the format: {'creator' : creator, 'receiver' : receiver, 'start_date' : start-date, 'end_date' : end_date} + + ] + + for pd in proposal_data: + start_date, end_date = test_utils.get_start_and_end_date(now, pd[1], pd[2]) + proposal = {'creator' : pd[0], 'receiver' : pd[0], 'start_date' : start_date, 'end_date' : end_date, 'daily_pay' : pd[3]} + proposals.append(proposal) + + import datetime + test_start_date = now + datetime.timedelta(days = 1) + test_start_date_iso = test_utils.date_to_iso(test_start_date) + + test_end_date = test_start_date + datetime.timedelta(days = 4, hours = 1) + test_end_date_iso = test_utils.date_to_iso(test_end_date) + + test_utils.create_proposals(node_client, proposals) + + # list proposals with inactive status, it shoud be list of pairs id:total_votes + test_utils.list_proposals(node_client, test_start_date_iso, "inactive") + + # each account is voting on proposal + test_utils.vote_proposals(node_client, accounts) + + # list proposals with inactive status, it shoud be list of pairs id:total_votes + votes = test_utils.list_proposals(node_client, test_start_date_iso, "inactive") + for vote in votes: + #should be 0 for all + assert vote == 0, "All votes should be equal to 0" + + logger.info("Balances for accounts after creating proposals") + balances = test_utils.print_balance(node_client, accounts) + for balance in balances: + #should be 390.000 TBD for all + assert balance == '390.000 TBD', "All balances should be equal to 390.000 TBD" + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + # move forward in time to see if proposals are paid + # moving is made in 1h increments at a time, after each + # increment balance is printed + logger.info("Moving to date: {}".format(test_start_date_iso)) + node_client.debug_generate_blocks_until(wif, test_start_date_iso, False) + current_date = test_start_date + while current_date < test_end_date: + current_date = current_date + datetime.timedelta(hours = 1) + current_date_iso = test_utils.date_to_iso(current_date) + + logger.info("Moving to date: {}".format(current_date_iso)) + node_client.debug_generate_blocks_until(wif, current_date_iso, False) + + logger.info("Balances for accounts at time: {}".format(current_date_iso)) + test_utils.print_balance(node_client, accounts) + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + votes = test_utils.list_proposals(node_client, test_start_date_iso, "active") + votes = test_utils.list_proposals(node_client, test_start_date_iso, "expired") + votes = test_utils.list_proposals(node_client, test_start_date_iso, "all") + + # move additional hour to ensure that all proposals ended + logger.info("Moving to date: {}".format(test_end_date_iso)) + node_client.debug_generate_blocks_until(wif, test_end_date_iso, False) + logger.info("Balances for accounts at time: {}".format(test_end_date_iso)) + balances = test_utils.print_balance(node_client, accounts) + test_balances = [ + '29951.682 TBD', + '390.000 TBD', + '390.000 TBD', + '390.000 TBD', + ] + for idx in range(0, len(test_balances)): + assert balances[idx] == test_balances[idx], "Balances dont match {} != {}".format(balances[idx], test_balances[idx]) + + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + if node is not None: + node.stop_steem_node() + sys.exit(0) + sys.exit(1) + except Exception as ex: + logger.error("Exception: {}".format(ex)) + if node is not None: + node.stop_steem_node() + sys.exit(1) diff --git a/python_scripts/tests/steempy_sps_tests/proposal_payment_test_006.py b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_006.py new file mode 100755 index 0000000000..234a9b92cb --- /dev/null +++ b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_006.py @@ -0,0 +1,238 @@ +#!/usr/bin/python3 + +from uuid import uuid4 +from time import sleep +import logging +import sys +import steem_utils.steem_runner +import steem_utils.steem_tools +import test_utils + + +LOG_LEVEL = logging.INFO +LOG_FORMAT = "%(asctime)-15s - %(name)s - %(levelname)s - %(message)s" +MAIN_LOG_PATH = "./sps_proposal_payment_004.log" + +MODULE_NAME = "SPS-Tester-via-steempy" +logger = logging.getLogger(MODULE_NAME) +logger.setLevel(LOG_LEVEL) + +ch = logging.StreamHandler(sys.stdout) +ch.setLevel(LOG_LEVEL) +ch.setFormatter(logging.Formatter(LOG_FORMAT)) + +fh = logging.FileHandler(MAIN_LOG_PATH) +fh.setLevel(LOG_LEVEL) +fh.setFormatter(logging.Formatter(LOG_FORMAT)) + +if not logger.hasHandlers(): + logger.addHandler(ch) + logger.addHandler(fh) + +try: + from steem import Steem +except Exception as ex: + logger.error("SteemPy library is not installed.") + sys.exit(1) + +# Greedy baby scenario +# 0. In this scenario we have one proposal with huge daily pay and couple with low daily pay +# all proposals have the same number of votes, greedy proposal is last +# 1. create few proposals - in this scenario proposals have different starting and ending dates +# 2. vote on them to show differences in asset distribution (depending on collected votes) +# 3. wait for proposal payment phase +# 4. verify (using account history and by checking regular account balance) that given accounts have been correctly paid. + +# Expected result: all got paid. + + +if __name__ == '__main__': + logger.info("Performing SPS tests") + import argparse + parser = argparse.ArgumentParser() + parser.add_argument("creator", help = "Account to create test accounts with") + parser.add_argument("treasury", help = "Treasury account") + parser.add_argument("wif", help="Private key for creator account") + parser.add_argument("--node-url", dest="node_url", default="http://127.0.0.1:8090", help="Url of working steem node") + parser.add_argument("--run-steemd", dest="steemd_path", help = "Path to steemd executable. Warning: using this option will erase contents of selected steemd working directory.") + parser.add_argument("--working_dir", dest="steemd_working_dir", default="/tmp/steemd-data/", help = "Path to steemd working directory") + parser.add_argument("--config_path", dest="steemd_config_path", default="./steem_utils/resources/config.ini.in",help = "Path to source config.ini file") + parser.add_argument("--no-erase-proposal", action='store_false', dest = "no_erase_proposal", help = "Do not erase proposal created with this test") + + + args = parser.parse_args() + + node = None + + if args.steemd_path: + logger.info("Running steemd via {} in {} with config {}".format(args.steemd_path, + args.steemd_working_dir, + args.steemd_config_path) + ) + + node = steem_utils.steem_runner.SteemNode( + args.steemd_path, + args.steemd_working_dir, + args.steemd_config_path + ) + + node_url = args.node_url + wif = args.wif + + if len(wif) == 0: + logger.error("Private-key is not set in config.ini") + sys.exit(1) + + logger.info("Using node at: {}".format(node_url)) + logger.info("Using private-key: {}".format(wif)) + + accounts = [ + # place accounts here in the format: {'name' : name, 'private_key' : private-key, 'public_key' : public-key} + {"name" : "tester001", "private_key" : "5JBuekd1sVXXK3wBu6nvPB1LWypZ83BYdu7tGcUNYVd42xQGGh1", "public_key" : "TST5kSj1yTzBz3PDoJ5QUyVVagdgYfs8Y4vVsZG3dqKJU8hg7WmQN"}, + {"name" : "tester002", "private_key" : "5KgfcV9bgEen3v9mxkoGw6Rhuf2giDRZTHZjzwisjkrpF4FUh3N", "public_key" : "TST5gQPYm5bs9dRPHpqBy6dU32M8FcoKYFdF4YWEChUarc9FdYHzn"}, + {"name" : "tester003", "private_key" : "5Jz3fcrrgKMbL8ncpzTdQmdRVHdxMhi8qScoxSR3TnAFUcdyD5N", "public_key" : "TST57wy5bXyJ4Z337Bo6RbinR6NyTRJxzond5dmGsP4gZ51yN6Zom"}, + {"name" : "tester004", "private_key" : "5KcmobLVMSAVzETrZxfEGG73Zvi5SKTgJuZXtNgU3az2VK3Krye", "public_key" : "TST8dPte853xAuLMDV7PTVmiNMRwP6itMyvSmaht7J5tVczkDLa5K"}, + ] + + if not accounts: + logger.error("Accounts array is empty, please add accounts in a form {\"name\" : name, \"private_key\" : private_key, \"public_key\" : public_key}") + sys.exit(1) + + keys = [wif] + for account in accounts: + keys.append(account["private_key"]) + + if node is not None: + node.run_steem_node(["--enable-stale-production"]) + try: + if node is None or node.is_running(): + node_client = Steem(nodes = [node_url], no_broadcast = False, + keys = keys + ) + + # create accounts + test_utils.create_accounts(node_client, args.creator, accounts) + # tranfer to vesting + test_utils.transfer_to_vesting(node_client, args.creator, accounts, "300.000", + "TESTS" + ) + # transfer assets to accounts + test_utils.transfer_assets_to_accounts(node_client, args.creator, accounts, + "400.000", "TESTS" + ) + + test_utils.transfer_assets_to_accounts(node_client, args.creator, accounts, + "400.000", "TBD" + ) + + logger.info("Balances for accounts after initial transfer") + test_utils.print_balance(node_client, accounts) + # transfer assets to treasury + test_utils.transfer_assets_to_treasury(node_client, args.creator, args.treasury, + "1000000.000", "TESTS" + ) + + test_utils.transfer_assets_to_treasury(node_client, args.creator, args.treasury, + "1000000.000", "TBD" + ) + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + # create post for valid permlinks + test_utils.create_posts(node_client, accounts) + + now = node_client.get_dynamic_global_properties().get('time', None) + if now is None: + raise ValueError("Head time is None") + now = test_utils.date_from_iso(now) + + proposal_data = [ + ['tester001', 1 + 0, 1, '24.000 TBD'], # starts 1 day from now and lasts 1 day + ['tester002', 1 + 1, 1, '24.000 TBD'], # starts 2 days from now and lasts 1 day + ['tester003', 1 + 2, 1, '24.000 TBD'], # starts 3 days from now and lasts 1 day + ['tester004', 1 + 0, 3, '240000.000 TBD'], # starts one day from now and lasts 3 days + ] + + proposals = [ + # pace proposals here in the format: {'creator' : creator, 'receiver' : receiver, 'start_date' : start-date, 'end_date' : end_date} + + ] + + for pd in proposal_data: + start_date, end_date = test_utils.get_start_and_end_date(now, pd[1], pd[2]) + proposal = {'creator' : pd[0], 'receiver' : pd[0], 'start_date' : start_date, 'end_date' : end_date, 'daily_pay' : pd[3]} + proposals.append(proposal) + + import datetime + test_start_date = now + datetime.timedelta(days = 1) + test_start_date_iso = test_utils.date_to_iso(test_start_date) + + test_end_date = test_start_date + datetime.timedelta(days = 4, hours = 1) + test_end_date_iso = test_utils.date_to_iso(test_end_date) + + test_utils.create_proposals(node_client, proposals) + + # list proposals with inactive status, it shoud be list of pairs id:total_votes + test_utils.list_proposals(node_client, test_start_date_iso, "inactive") + + # each account is voting on proposal + test_utils.vote_proposals(node_client, accounts) + + # list proposals with inactive status, it shoud be list of pairs id:total_votes + votes = test_utils.list_proposals(node_client, test_start_date_iso, "inactive") + for vote in votes: + #should be 0 for all + assert vote == 0, "All votes should be equal to 0" + + logger.info("Balances for accounts after creating proposals") + balances = test_utils.print_balance(node_client, accounts) + for balance in balances: + #should be 390.000 TBD for all + assert balance == '390.000 TBD', "All balances should be equal to 390.000 TBD" + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + # move forward in time to see if proposals are paid + # moving is made in 1h increments at a time, after each + # increment balance is printed + logger.info("Moving to date: {}".format(test_start_date_iso)) + node_client.debug_generate_blocks_until(wif, test_start_date_iso, False) + current_date = test_start_date + while current_date < test_end_date: + current_date = current_date + datetime.timedelta(hours = 1) + current_date_iso = test_utils.date_to_iso(current_date) + + logger.info("Moving to date: {}".format(current_date_iso)) + node_client.debug_generate_blocks_until(wif, current_date_iso, False) + + logger.info("Balances for accounts at time: {}".format(current_date_iso)) + test_utils.print_balance(node_client, accounts) + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + votes = test_utils.list_proposals(node_client, test_start_date_iso, "active") + votes = test_utils.list_proposals(node_client, test_start_date_iso, "expired") + votes = test_utils.list_proposals(node_client, test_start_date_iso, "all") + + # move additional hour to ensure that all proposals ended + logger.info("Moving to date: {}".format(test_end_date_iso)) + node_client.debug_generate_blocks_until(wif, test_end_date_iso, False) + logger.info("Balances for accounts at time: {}".format(test_end_date_iso)) + balances = test_utils.print_balance(node_client, accounts) + test_balances = [ + '414.000 TBD', + '390.000 TBD', + '290.000 TBD', + '29927.682 TBD', + ] + for idx in range(0, len(test_balances)): + assert balances[idx] == test_balances[idx], "Balances dont match {} != {}".format(balances[idx], test_balances[idx]) + + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + if node is not None: + node.stop_steem_node() + sys.exit(0) + sys.exit(1) + except Exception as ex: + logger.error("Exception: {}".format(ex)) + if node is not None: + node.stop_steem_node() + sys.exit(1) diff --git a/python_scripts/tests/steempy_sps_tests/steempy_sps_tests.py b/python_scripts/tests/steempy_sps_tests/steempy_sps_tests.py index e21fca2ef2..4da01c78e5 100755 --- a/python_scripts/tests/steempy_sps_tests/steempy_sps_tests.py +++ b/python_scripts/tests/steempy_sps_tests/steempy_sps_tests.py @@ -13,10 +13,6 @@ LOG_FORMAT = "%(asctime)-15s - %(name)s - %(levelname)s - %(message)s" MAIN_LOG_PATH = "./sps_test.log" -steem_utils.steem_runner.initialize_logging(MAIN_LOG_PATH) -steem_utils.steem_tools.initialize_logging(MAIN_LOG_PATH) -test_utils.initialize_logging(MAIN_LOG_PATH) - MODULE_NAME = "SPS-Tester-via-steempy" logger = logging.getLogger(MODULE_NAME) logger.setLevel(LOG_LEVEL) @@ -333,16 +329,16 @@ def test_iterate_results_test(node, creator_account, receiver_account, wif, subj try: if node is None or node.is_running(): test_create_proposal(node_url, args.creator, args.receiver, wif, subject) - steem_utils.steem_tools.wait_for_blocks_produced(2, node) + steem_utils.steem_tools.wait_for_blocks_produced(2, node_url) test_list_proposals(node_url, args.creator, wif, subject) test_find_proposals(node_url, args.creator, wif, subject) test_vote_proposal(node_url, args.creator, wif, subject) test_list_voter_proposals(node_url, args.creator, wif, subject) - steem_utils.steem_tools.wait_for_blocks_produced(2, node) + steem_utils.steem_tools.wait_for_blocks_produced(2, node_url) if args.no_erase_proposal: test_remove_proposal(node_url, args.creator, wif, subject) - test_iterate_results_test(args.node_url, args.creator, args.receiver, args.wif, str(uuid4()), args.no_erase_proposal) - steem_utils.steem_tools.wait_for_blocks_produced(2, node) + test_iterate_results_test(node_url, args.creator, args.receiver, args.wif, str(uuid4()), args.no_erase_proposal) + steem_utils.steem_tools.wait_for_blocks_produced(2, node_url) if node is not None: node.stop_steem_node() sys.exit(0) From 42cda75e3144d078cf26837acb27987a2dc915a5 Mon Sep 17 00:00:00 2001 From: Dariusz Kedzierski Date: Wed, 10 Apr 2019 15:13:26 +0200 Subject: [PATCH 4/5] More proposal tests --- .../proposal_payment_test_005.py | 2 +- .../proposal_payment_test_006.py | 2 +- .../proposal_payment_test_007.py | 264 ++++++++++++++++++ .../proposal_payment_test_008.py | 254 +++++++++++++++++ 4 files changed, 520 insertions(+), 2 deletions(-) create mode 100755 python_scripts/tests/steempy_sps_tests/proposal_payment_test_007.py create mode 100755 python_scripts/tests/steempy_sps_tests/proposal_payment_test_008.py diff --git a/python_scripts/tests/steempy_sps_tests/proposal_payment_test_005.py b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_005.py index 95bca631db..6739da55e2 100755 --- a/python_scripts/tests/steempy_sps_tests/proposal_payment_test_005.py +++ b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_005.py @@ -11,7 +11,7 @@ LOG_LEVEL = logging.INFO LOG_FORMAT = "%(asctime)-15s - %(name)s - %(levelname)s - %(message)s" -MAIN_LOG_PATH = "./sps_proposal_payment_003.log" +MAIN_LOG_PATH = "./sps_proposal_payment_005.log" MODULE_NAME = "SPS-Tester-via-steempy" logger = logging.getLogger(MODULE_NAME) diff --git a/python_scripts/tests/steempy_sps_tests/proposal_payment_test_006.py b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_006.py index 234a9b92cb..59197af6d0 100755 --- a/python_scripts/tests/steempy_sps_tests/proposal_payment_test_006.py +++ b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_006.py @@ -11,7 +11,7 @@ LOG_LEVEL = logging.INFO LOG_FORMAT = "%(asctime)-15s - %(name)s - %(levelname)s - %(message)s" -MAIN_LOG_PATH = "./sps_proposal_payment_004.log" +MAIN_LOG_PATH = "./sps_proposal_payment_006.log" MODULE_NAME = "SPS-Tester-via-steempy" logger = logging.getLogger(MODULE_NAME) diff --git a/python_scripts/tests/steempy_sps_tests/proposal_payment_test_007.py b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_007.py new file mode 100755 index 0000000000..5e31d7c572 --- /dev/null +++ b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_007.py @@ -0,0 +1,264 @@ +#!/usr/bin/python3 + +from uuid import uuid4 +from time import sleep +import logging +import sys +import steem_utils.steem_runner +import steem_utils.steem_tools +import test_utils + + +LOG_LEVEL = logging.INFO +LOG_FORMAT = "%(asctime)-15s - %(name)s - %(levelname)s - %(message)s" +MAIN_LOG_PATH = "./sps_proposal_payment_007.log" + +MODULE_NAME = "SPS-Tester-via-steempy" +logger = logging.getLogger(MODULE_NAME) +logger.setLevel(LOG_LEVEL) + +ch = logging.StreamHandler(sys.stdout) +ch.setLevel(LOG_LEVEL) +ch.setFormatter(logging.Formatter(LOG_FORMAT)) + +fh = logging.FileHandler(MAIN_LOG_PATH) +fh.setLevel(LOG_LEVEL) +fh.setFormatter(logging.Formatter(LOG_FORMAT)) + +if not logger.hasHandlers(): + logger.addHandler(ch) + logger.addHandler(fh) + +try: + from steem import Steem +except Exception as ex: + logger.error("SteemPy library is not installed.") + sys.exit(1) + +# Unvote proposal during payment +# 1. create few proposals - in this scenario proposals have the same starting and ending dates +# 2. vote on them to show differences in asset distribution (depending on collected votes) +# 3. wait for proposal payment phase +# 4. Unvote one of the proposal duting payment phase +# 4. verify (using account history and by checking regular account balance) that given accounts have been correctly paid. + +# Expected result: all got paid. + +def unvote_proposals(node, accounts, debug_key): + logger.info("Unvoting proposals...") + for acnt in accounts: + proposal_set = [0] + logger.info("Account {} unvoted proposals: {}".format(acnt["name"], ",".join(str(x) for x in proposal_set))) + node.commit.update_proposal_votes(acnt["name"], proposal_set, False) + node.debug_generate_blocks(debug_key, 3) + + +if __name__ == '__main__': + logger.info("Performing SPS tests") + import argparse + parser = argparse.ArgumentParser() + parser.add_argument("creator", help = "Account to create test accounts with") + parser.add_argument("treasury", help = "Treasury account") + parser.add_argument("wif", help="Private key for creator account") + parser.add_argument("--node-url", dest="node_url", default="http://127.0.0.1:8090", help="Url of working steem node") + parser.add_argument("--run-steemd", dest="steemd_path", help = "Path to steemd executable. Warning: using this option will erase contents of selected steemd working directory.") + parser.add_argument("--working_dir", dest="steemd_working_dir", default="/tmp/steemd-data/", help = "Path to steemd working directory") + parser.add_argument("--config_path", dest="steemd_config_path", default="./steem_utils/resources/config.ini.in",help = "Path to source config.ini file") + parser.add_argument("--no-erase-proposal", action='store_false', dest = "no_erase_proposal", help = "Do not erase proposal created with this test") + + + args = parser.parse_args() + + node = None + + if args.steemd_path: + logger.info("Running steemd via {} in {} with config {}".format(args.steemd_path, + args.steemd_working_dir, + args.steemd_config_path) + ) + + node = steem_utils.steem_runner.SteemNode( + args.steemd_path, + args.steemd_working_dir, + args.steemd_config_path + ) + + node_url = args.node_url + wif = args.wif + + if len(wif) == 0: + logger.error("Private-key is not set in config.ini") + sys.exit(1) + + logger.info("Using node at: {}".format(node_url)) + logger.info("Using private-key: {}".format(wif)) + + accounts = [ + # place accounts here in the format: {'name' : name, 'private_key' : private-key, 'public_key' : public-key} + {"name" : "tester001", "private_key" : "5JBuekd1sVXXK3wBu6nvPB1LWypZ83BYdu7tGcUNYVd42xQGGh1", "public_key" : "TST5kSj1yTzBz3PDoJ5QUyVVagdgYfs8Y4vVsZG3dqKJU8hg7WmQN"}, + {"name" : "tester002", "private_key" : "5KgfcV9bgEen3v9mxkoGw6Rhuf2giDRZTHZjzwisjkrpF4FUh3N", "public_key" : "TST5gQPYm5bs9dRPHpqBy6dU32M8FcoKYFdF4YWEChUarc9FdYHzn"}, + {"name" : "tester003", "private_key" : "5Jz3fcrrgKMbL8ncpzTdQmdRVHdxMhi8qScoxSR3TnAFUcdyD5N", "public_key" : "TST57wy5bXyJ4Z337Bo6RbinR6NyTRJxzond5dmGsP4gZ51yN6Zom"}, + {"name" : "tester004", "private_key" : "5KcmobLVMSAVzETrZxfEGG73Zvi5SKTgJuZXtNgU3az2VK3Krye", "public_key" : "TST8dPte853xAuLMDV7PTVmiNMRwP6itMyvSmaht7J5tVczkDLa5K"}, + ] + + if not accounts: + logger.error("Accounts array is empty, please add accounts in a form {\"name\" : name, \"private_key\" : private_key, \"public_key\" : public_key}") + sys.exit(1) + + keys = [wif] + for account in accounts: + keys.append(account["private_key"]) + + if node is not None: + node.run_steem_node(["--enable-stale-production"]) + try: + if node is None or node.is_running(): + node_client = Steem(nodes = [node_url], no_broadcast = False, + keys = keys + ) + + # create accounts + test_utils.create_accounts(node_client, args.creator, accounts) + # tranfer to vesting + test_utils.transfer_to_vesting(node_client, args.creator, accounts, "300.000", + "TESTS" + ) + # transfer assets to accounts + test_utils.transfer_assets_to_accounts(node_client, args.creator, accounts, + "400.000", "TESTS" + ) + + test_utils.transfer_assets_to_accounts(node_client, args.creator, accounts, + "400.000", "TBD" + ) + + logger.info("Balances for accounts after initial transfer") + test_utils.print_balance(node_client, accounts) + # transfer assets to treasury + test_utils.transfer_assets_to_treasury(node_client, args.creator, args.treasury, + "1000000.000", "TESTS" + ) + + test_utils.transfer_assets_to_treasury(node_client, args.creator, args.treasury, + "1000000.000", "TBD" + ) + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + # create post for valid permlinks + test_utils.create_posts(node_client, accounts) + + now = node_client.get_dynamic_global_properties().get('time', None) + if now is None: + raise ValueError("Head time is None") + now = test_utils.date_from_iso(now) + + proposal_data = [ + ['tester001', 1 + 0, 4, '24.000 TBD'], # starts 1 day from now and lasts 3 day + ['tester002', 1 + 0, 4, '24.000 TBD'], # starts 1 days from now and lasts 3 day + ['tester003', 1 + 0, 4, '24.000 TBD'], # starts 1 days from now and lasts 3 day + ['tester004', 1 + 0, 4, '24.000 TBD'], # starts 1 day from now and lasts 3 days + ] + + proposals = [ + # pace proposals here in the format: {'creator' : creator, 'receiver' : receiver, 'start_date' : start-date, 'end_date' : end_date} + + ] + + for pd in proposal_data: + start_date, end_date = test_utils.get_start_and_end_date(now, pd[1], pd[2]) + proposal = {'creator' : pd[0], 'receiver' : pd[0], 'start_date' : start_date, 'end_date' : end_date, 'daily_pay' : pd[3]} + proposals.append(proposal) + + import datetime + test_start_date = now + datetime.timedelta(days = 1) + test_start_date_iso = test_utils.date_to_iso(test_start_date) + + test_mid_date = test_start_date + datetime.timedelta(days = 3, hours = 1) + + test_end_date = test_start_date + datetime.timedelta(days = 5, hours = 1) + test_end_date_iso = test_utils.date_to_iso(test_end_date) + + test_utils.create_proposals(node_client, proposals) + + # list proposals with inactive status, it shoud be list of pairs id:total_votes + test_utils.list_proposals(node_client, test_start_date_iso, "inactive") + + # each account is voting on proposal + test_utils.vote_proposals(node_client, accounts) + + # list proposals with inactive status, it shoud be list of pairs id:total_votes + votes = test_utils.list_proposals(node_client, test_start_date_iso, "inactive") + for vote in votes: + #should be 0 for all + assert vote == 0, "All votes should be equal to 0" + + logger.info("Balances for accounts after creating proposals") + balances = test_utils.print_balance(node_client, accounts) + for balance in balances: + #should be 390.000 TBD for all + assert balance == '390.000 TBD', "All balances should be equal to 390.000 TBD" + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + # move forward in time to see if proposals are paid + # moving is made in 1h increments at a time, after each + # increment balance is printed + logger.info("Moving to date: {}".format(test_start_date_iso)) + node_client.debug_generate_blocks_until(wif, test_start_date_iso, False) + current_date = test_start_date + while current_date < test_mid_date: + current_date = current_date + datetime.timedelta(hours = 1) + current_date_iso = test_utils.date_to_iso(current_date) + + logger.info("Moving to date: {}".format(current_date_iso)) + node_client.debug_generate_blocks_until(wif, current_date_iso, False) + + logger.info("Balances for accounts at time: {}".format(current_date_iso)) + test_utils.print_balance(node_client, accounts) + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + votes = test_utils.list_proposals(node_client, test_start_date_iso, "active") + votes = test_utils.list_proposals(node_client, test_start_date_iso, "expired") + votes = test_utils.list_proposals(node_client, test_start_date_iso, "all") + + unvote_proposals(node_client, accounts, wif) + + while current_date < test_end_date: + current_date = current_date + datetime.timedelta(hours = 1) + current_date_iso = test_utils.date_to_iso(current_date) + + logger.info("Moving to date: {}".format(current_date_iso)) + node_client.debug_generate_blocks_until(wif, current_date_iso, False) + + logger.info("Balances for accounts at time: {}".format(current_date_iso)) + test_utils.print_balance(node_client, accounts) + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + votes = test_utils.list_proposals(node_client, test_start_date_iso, "active") + votes = test_utils.list_proposals(node_client, test_start_date_iso, "expired") + votes = test_utils.list_proposals(node_client, test_start_date_iso, "all") + + # move additional hour to ensure that all proposals ended + logger.info("Moving to date: {}".format(test_end_date_iso)) + node_client.debug_generate_blocks_until(wif, test_end_date_iso, False) + logger.info("Balances for accounts at time: {}".format(test_end_date_iso)) + balances = test_utils.print_balance(node_client, accounts) + test_balances = [ + '463.000 TBD', + '486.000 TBD', + '486.000 TBD', + '486.000 TBD', + ] + for idx in range(0, len(test_balances)): + assert balances[idx] == test_balances[idx], "Balances dont match {} != {}".format(balances[idx], test_balances[idx]) + + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + if node is not None: + node.stop_steem_node() + sys.exit(0) + sys.exit(1) + except Exception as ex: + logger.error("Exception: {}".format(ex)) + if node is not None: + node.stop_steem_node() + sys.exit(1) diff --git a/python_scripts/tests/steempy_sps_tests/proposal_payment_test_008.py b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_008.py new file mode 100755 index 0000000000..92c9e6b19c --- /dev/null +++ b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_008.py @@ -0,0 +1,254 @@ +#!/usr/bin/python3 + +from uuid import uuid4 +from time import sleep +import logging +import sys +import steem_utils.steem_runner +import steem_utils.steem_tools +import test_utils + + +LOG_LEVEL = logging.INFO +LOG_FORMAT = "%(asctime)-15s - %(name)s - %(levelname)s - %(message)s" +MAIN_LOG_PATH = "./sps_proposal_payment_008.log" + +MODULE_NAME = "SPS-Tester-via-steempy" +logger = logging.getLogger(MODULE_NAME) +logger.setLevel(LOG_LEVEL) + +ch = logging.StreamHandler(sys.stdout) +ch.setLevel(LOG_LEVEL) +ch.setFormatter(logging.Formatter(LOG_FORMAT)) + +fh = logging.FileHandler(MAIN_LOG_PATH) +fh.setLevel(LOG_LEVEL) +fh.setFormatter(logging.Formatter(LOG_FORMAT)) + +if not logger.hasHandlers(): + logger.addHandler(ch) + logger.addHandler(fh) + +try: + from steem import Steem +except Exception as ex: + logger.error("SteemPy library is not installed.") + sys.exit(1) + +# Circular payment +# 1. create few proposals - in this scenario proposals have the same starting and ending dates +# one of the proposals will by paying to the treasury +# 2. vote on them to show differences in asset distribution (depending on collected votes) +# 3. wait for proposal payment phase +# 4. verify (using account history and by checking regular account balance) that given accounts have been correctly paid. + +# Expected result: all got paid. + +def vote_proposals(node, accounts): + logger.info("Voting proposals...") + for acnt in accounts: + proposal_set = [0,1,2,3,4] + logger.info("Account {} voted for proposals: {}".format(acnt["name"], ",".join(str(x) for x in proposal_set))) + node.commit.update_proposal_votes(acnt["name"], proposal_set, True) + steem_utils.steem_tools.wait_for_blocks_produced(5, node.url) + +if __name__ == '__main__': + logger.info("Performing SPS tests") + import argparse + parser = argparse.ArgumentParser() + parser.add_argument("creator", help = "Account to create test accounts with") + parser.add_argument("treasury", help = "Treasury account") + parser.add_argument("wif", help="Private key for creator account") + parser.add_argument("--node-url", dest="node_url", default="http://127.0.0.1:8090", help="Url of working steem node") + parser.add_argument("--run-steemd", dest="steemd_path", help = "Path to steemd executable. Warning: using this option will erase contents of selected steemd working directory.") + parser.add_argument("--working_dir", dest="steemd_working_dir", default="/tmp/steemd-data/", help = "Path to steemd working directory") + parser.add_argument("--config_path", dest="steemd_config_path", default="./steem_utils/resources/config.ini.in",help = "Path to source config.ini file") + parser.add_argument("--no-erase-proposal", action='store_false', dest = "no_erase_proposal", help = "Do not erase proposal created with this test") + + + args = parser.parse_args() + + node = None + + if args.steemd_path: + logger.info("Running steemd via {} in {} with config {}".format(args.steemd_path, + args.steemd_working_dir, + args.steemd_config_path) + ) + + node = steem_utils.steem_runner.SteemNode( + args.steemd_path, + args.steemd_working_dir, + args.steemd_config_path + ) + + node_url = args.node_url + wif = args.wif + + if len(wif) == 0: + logger.error("Private-key is not set in config.ini") + sys.exit(1) + + logger.info("Using node at: {}".format(node_url)) + logger.info("Using private-key: {}".format(wif)) + + accounts = [ + # place accounts here in the format: {'name' : name, 'private_key' : private-key, 'public_key' : public-key} + {"name" : "tester001", "private_key" : "5JBuekd1sVXXK3wBu6nvPB1LWypZ83BYdu7tGcUNYVd42xQGGh1", "public_key" : "TST5kSj1yTzBz3PDoJ5QUyVVagdgYfs8Y4vVsZG3dqKJU8hg7WmQN"}, + {"name" : "tester002", "private_key" : "5KgfcV9bgEen3v9mxkoGw6Rhuf2giDRZTHZjzwisjkrpF4FUh3N", "public_key" : "TST5gQPYm5bs9dRPHpqBy6dU32M8FcoKYFdF4YWEChUarc9FdYHzn"}, + {"name" : "tester003", "private_key" : "5Jz3fcrrgKMbL8ncpzTdQmdRVHdxMhi8qScoxSR3TnAFUcdyD5N", "public_key" : "TST57wy5bXyJ4Z337Bo6RbinR6NyTRJxzond5dmGsP4gZ51yN6Zom"}, + {"name" : "tester004", "private_key" : "5KcmobLVMSAVzETrZxfEGG73Zvi5SKTgJuZXtNgU3az2VK3Krye", "public_key" : "TST8dPte853xAuLMDV7PTVmiNMRwP6itMyvSmaht7J5tVczkDLa5K"}, + ] + + if not accounts: + logger.error("Accounts array is empty, please add accounts in a form {\"name\" : name, \"private_key\" : private_key, \"public_key\" : public_key}") + sys.exit(1) + + keys = [wif] + for account in accounts: + keys.append(account["private_key"]) + + if node is not None: + node.run_steem_node(["--enable-stale-production"]) + try: + if node is None or node.is_running(): + node_client = Steem(nodes = [node_url], no_broadcast = False, + keys = keys + ) + + # create accounts + test_utils.create_accounts(node_client, args.creator, accounts) + # tranfer to vesting + test_utils.transfer_to_vesting(node_client, args.creator, accounts, "300.000", + "TESTS" + ) + # transfer assets to accounts + test_utils.transfer_assets_to_accounts(node_client, args.creator, accounts, + "400.000", "TESTS" + ) + + test_utils.transfer_assets_to_accounts(node_client, args.creator, accounts, + "400.000", "TBD" + ) + + logger.info("Balances for accounts after initial transfer") + test_utils.print_balance(node_client, accounts) + # transfer assets to treasury + test_utils.transfer_assets_to_treasury(node_client, args.creator, args.treasury, + "999950.000", "TESTS" + ) + + test_utils.transfer_assets_to_treasury(node_client, args.creator, args.treasury, + "999950.000", "TBD" + ) + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + # create post for valid permlinks + test_utils.create_posts(node_client, accounts) + + now = node_client.get_dynamic_global_properties().get('time', None) + if now is None: + raise ValueError("Head time is None") + now = test_utils.date_from_iso(now) + + proposal_data = [ + ['tester001', 1 + 0, 4, '24.000 TBD'], # starts 1 day from now and lasts 3 day + ['tester002', 1 + 0, 4, '24.000 TBD'], # starts 1 days from now and lasts 3 day + ['tester003', 1 + 0, 4, '24.000 TBD'], # starts 1 days from now and lasts 3 day + ['tester004', 1 + 0, 4, '24.000 TBD'], # starts 1 day from now and lasts 3 days + ] + + proposals = [ + # pace proposals here in the format: {'creator' : creator, 'receiver' : receiver, 'start_date' : start-date, 'end_date' : end_date} + + ] + + for pd in proposal_data: + start_date, end_date = test_utils.get_start_and_end_date(now, pd[1], pd[2]) + proposal = {'creator' : pd[0], 'receiver' : pd[0], 'start_date' : start_date, 'end_date' : end_date, 'daily_pay' : pd[3]} + proposals.append(proposal) + + start_date, end_date = test_utils.get_start_and_end_date(now, 1, 4) + proposals.append({'creator' : 'tester001', 'receiver' : 'steem.dao', 'start_date' : start_date, 'end_date' : end_date, 'daily_pay' : '96.000 TBD'}) + + import datetime + test_start_date = now + datetime.timedelta(days = 1) + test_start_date_iso = test_utils.date_to_iso(test_start_date) + + test_mid_date = test_start_date + datetime.timedelta(days = 3, hours = 1) + + test_end_date = test_start_date + datetime.timedelta(days = 5, hours = 1) + test_end_date_iso = test_utils.date_to_iso(test_end_date) + + test_utils.create_proposals(node_client, proposals) + + # list proposals with inactive status, it shoud be list of pairs id:total_votes + test_utils.list_proposals(node_client, test_start_date_iso, "inactive") + + # each account is voting on proposal + vote_proposals(node_client, accounts) + + # list proposals with inactive status, it shoud be list of pairs id:total_votes + votes = test_utils.list_proposals(node_client, test_start_date_iso, "inactive") + for vote in votes: + #should be 0 for all + assert vote == 0, "All votes should be equal to 0" + + logger.info("Balances for accounts after creating proposals") + test_balances = [ + '380.000 TBD', + '390.000 TBD', + '390.000 TBD', + '390.000 TBD', + ] + balances = test_utils.print_balance(node_client, accounts) + for idx in range(0, len(test_balances)): + assert balances[idx] == test_balances[idx], "Balances dont match {} != {}".format(balances[idx], test_balances[idx]) + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + # move forward in time to see if proposals are paid + # moving is made in 1h increments at a time, after each + # increment balance is printed + logger.info("Moving to date: {}".format(test_start_date_iso)) + node_client.debug_generate_blocks_until(wif, test_start_date_iso, False) + current_date = test_start_date + while current_date < test_end_date: + current_date = current_date + datetime.timedelta(hours = 1) + current_date_iso = test_utils.date_to_iso(current_date) + + logger.info("Moving to date: {}".format(current_date_iso)) + node_client.debug_generate_blocks_until(wif, current_date_iso, False) + + logger.info("Balances for accounts at time: {}".format(current_date_iso)) + test_utils.print_balance(node_client, accounts) + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + votes = test_utils.list_proposals(node_client, test_start_date_iso, "active") + votes = test_utils.list_proposals(node_client, test_start_date_iso, "expired") + votes = test_utils.list_proposals(node_client, test_start_date_iso, "all") + + # move additional hour to ensure that all proposals ended + logger.info("Moving to date: {}".format(test_end_date_iso)) + node_client.debug_generate_blocks_until(wif, test_end_date_iso, False) + logger.info("Balances for accounts at time: {}".format(test_end_date_iso)) + balances = test_utils.print_balance(node_client, accounts) + test_balances = [ + '476.000 TBD', + '486.000 TBD', + '486.000 TBD', + '486.000 TBD', + ] + for idx in range(0, len(test_balances)): + assert balances[idx] == test_balances[idx], "Balances dont match {} != {}".format(balances[idx], test_balances[idx]) + + test_utils.print_balance(node_client, [{'name' : args.treasury}]) + + if node is not None: + node.stop_steem_node() + sys.exit(0) + sys.exit(1) + except Exception as ex: + logger.error("Exception: {}".format(ex)) + if node is not None: + node.stop_steem_node() + sys.exit(1) From d0b3876cd20c39d6245fc91700410041e3ec02ae Mon Sep 17 00:00:00 2001 From: Dariusz Kedzierski Date: Thu, 11 Apr 2019 10:44:15 +0200 Subject: [PATCH 5/5] Sorting order fix and some fixes in test --- libraries/chain/sps_objects/sps_processor.cpp | 4 ++++ .../tests/steempy_sps_tests/proposal_payment_test_006.py | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/libraries/chain/sps_objects/sps_processor.cpp b/libraries/chain/sps_objects/sps_processor.cpp index e42a2052ba..fd4054ec28 100644 --- a/libraries/chain/sps_objects/sps_processor.cpp +++ b/libraries/chain/sps_objects/sps_processor.cpp @@ -95,6 +95,10 @@ void sps_processor::sort_by_votes( t_proposals& proposals ) { std::sort( proposals.begin(), proposals.end(), []( const proposal_object& a, const proposal_object& b ) { + if (a.total_votes == b.total_votes) + { + return a.id < b.id; + } return a.total_votes > b.total_votes; } ); } diff --git a/python_scripts/tests/steempy_sps_tests/proposal_payment_test_006.py b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_006.py index 59197af6d0..38a74f699a 100755 --- a/python_scripts/tests/steempy_sps_tests/proposal_payment_test_006.py +++ b/python_scripts/tests/steempy_sps_tests/proposal_payment_test_006.py @@ -218,9 +218,9 @@ balances = test_utils.print_balance(node_client, accounts) test_balances = [ '414.000 TBD', - '390.000 TBD', - '290.000 TBD', - '29927.682 TBD', + '414.000 TBD', + '414.000 TBD', + '29879.682 TBD', ] for idx in range(0, len(test_balances)): assert balances[idx] == test_balances[idx], "Balances dont match {} != {}".format(balances[idx], test_balances[idx])