diff --git a/internal/modules/upgrade/query.py b/internal/modules/upgrade/query.py new file mode 100644 index 0000000..4cd651b --- /dev/null +++ b/internal/modules/upgrade/query.py @@ -0,0 +1,59 @@ +from internal.utils import exec_command, env + +DAEMON = env.DAEMON +RPC = env.RPC +CHAINID = env.CHAINID + +# 'query_module_version' quereis the respective module's consensus versions.. +def query_module_version(module_name): + command = ( + f"{DAEMON} q upgrade module_versions {module_name} --node {RPC} --output json" + ) + return exec_command(command) + + +# 'query_module_versions' quereis all the module's consensus versions.. +def query_module_versions(): + command = f"{DAEMON} q upgrade module_versions --node {RPC} --output json" + return exec_command(command) + + +# query_vote queries details of a vote with specific vote address and proposal id +def query_vote(proposal_id, vote_addr, extra_args=""): + command = f"{DAEMON} q gov vote {proposal_id} {vote_addr} --node {RPC} --chain-id {CHAINID} --output json" + return exec_command(command, extra_args) + +# 'query_block' quereis the verified data of a block. +def query_block(): + command = ( + f"{DAEMON} q block --node {RPC}" + ) + return exec_command(command) + +# 'query_proposals' quereis all proposal details. +def query_proposals(): + command = ( + f"{DAEMON} q gov proposals --node {RPC} --output json" + ) + return exec_command(command) + +# 'query_upgrade' quereis details of the header for the block at which it was applied. +def query_upgrade(upgrade_name): + command = ( + f"{DAEMON} q upgrade applied {upgrade_name} --node {RPC} --chain-id {CHAINID} --output json" + ) + return exec_command(command) + +# 'query_upgrade_plan' quereis the currently scheduled upgrade plan, if one exists. +def query_upgrade_plan(): + command = ( + f"{DAEMON} q upgrade plan --node {RPC} --chain-id {CHAINID} --output json" + ) + return exec_command(command) + +# 'query_proposal' quereis proposal details. +def query_proposal(porposal_id): + command = ( + f"{DAEMON} q gov proposal {porposal_id} --node {RPC} --chain-id {CHAINID} --output json" + ) + return exec_command(command) diff --git a/internal/modules/upgrade/test.py b/internal/modules/upgrade/test.py new file mode 100644 index 0000000..3ec4efb --- /dev/null +++ b/internal/modules/upgrade/test.py @@ -0,0 +1,78 @@ +import unittest, time +import logging +from modules.upgrade.query import * +from modules.upgrade.tx import * +from utils import exec_command, env + +logging.basicConfig(format="%(message)s", level=logging.DEBUG) + + +upgrade_name = "test_upgrade_tx" +from_key = "validator1" +num_vals = env.NUM_VALS + + +class TestUpgradeModuleQueries(unittest.TestCase): + def test_tx_upgrade_proposal(self): + # query block + status, block = query_block() + self.assertTrue(status) + block_height = int(block["block"]["header"]["height"]) + upgrade_height = block_height + 2000 + + # submit proposal + status, res = tx_submit_proposal(from_key, upgrade_name, upgrade_height) + self.assertTrue(status) + time.sleep(3) + + status, proposals = query_proposals() + self.assertTrue(status) + l = len(proposals) + self.assertIsNotNone(l, 0) + proposal_id = proposals["proposals"][0]["proposal_id"] + + # vote on the proposal + for i in range(1, int(num_vals)): + val = f"validator{i}" + home = f"{DAEMON_HOME}-{i}" + status, res = tx_vote(val, proposal_id, "yes", home) + self.assertTrue(status) + time.sleep(3) + + # waiting for proposal to pass + time.sleep(60) + + # check if the proposal passed or not + status, proposal = query_proposal(proposal_id) + self.assertTrue(status) + proposal_status = proposal["status"] + self.assertEqual(proposal_status, "PROPOSAL_STATUS_PASSED") + + # query upgrade plan + def test_query_upgrade_plan(self): + # query upgrade plan + status, plan = query_upgrade_plan() + self.assertTrue(status) + self.assertIsNotNone(plan["name"]) + self.assertIsNotNone(plan["height"]) + + # query module versions + def test_query_module_version(self): + status, modules_versions = query_module_versions() + self.assertTrue(status) + l = len(modules_versions["module_versions"]) + self.assertNotEqual(l, 0) + for module in modules_versions["module_versions"]: + module_name = module["name"] + self.assertIsNotNone(module_name) + status, version_res = query_module_version(module_name) + self.assertTrue(status) + version = version_res["module_versions"][0]["version"] + self.assertIsNotNone(version) + v = module["version"] + self.assertEqual(version, v) + + +if __name__ == "__main__": + logging.info("INFO: running upgrade module tests") + unittest.main() diff --git a/internal/modules/upgrade/tx.py b/internal/modules/upgrade/tx.py new file mode 100644 index 0000000..e40ecee --- /dev/null +++ b/internal/modules/upgrade/tx.py @@ -0,0 +1,31 @@ +import os +from internal.modules.staking.tx import DENOM +from utils import exec_command, env + +DAEMON = env.DAEMON +DAEMON_HOME = env.DAEMON_HOME +RPC = env.RPC +CHAINID = env.CHAINID +DEFAULT_GAS = env.DEFAULT_GAS + + +# tx_submit_proposal internally calls the submit proposal transaction with given proposal type +# and return the response in json format. +def tx_submit_proposal(from_key, UPGRADE_NAME, UPGRADE_HEIGHT, home=f"{DAEMON_HOME}-1"): + command = f"""{DAEMON} tx gov submit-proposal software-upgrade {UPGRADE_NAME} --title {UPGRADE_NAME} + --description upgrade --upgrade-height {UPGRADE_HEIGHT} --deposit 10000000{DENOM} --from {from_key} + --chain-id {CHAINID} --keyring-backend test --home {home} --node {RPC} --output json -y""" + return exec_command(command) + + +# tx_vote internally calls the 'gov vote' tx command and return the response in json format +def tx_vote( + from_key, + proposal_id, + option, + home, + gas=DEFAULT_GAS, +): + command = f"""{DAEMON} tx gov vote {proposal_id} {option} --chain-id {CHAINID} --keyring-backend test + --home {home} --from {from_key} --node {RPC} --output json -y --gas {gas}""" + return exec_command(command) diff --git a/internal/utils/env.py b/internal/utils/env.py index ec9dfb4..60885a1 100644 --- a/internal/utils/env.py +++ b/internal/utils/env.py @@ -14,6 +14,7 @@ URI = os.getenv("MONGO_URL") DB_NAME = os.getenv("DB_NAME", "qa_test") TEST_TYPE = os.getenv("TEST_TYPE", None) +NUM_VALS = os.getenv("NUM_VALS", 3) DEFAULT_GAS = int(os.getenv("DEFAULT_GAS", "2000000")) def get(env_var):