mirror of
https://github.com/planetmint/planetmint.git
synced 2025-03-30 15:08:31 +00:00

* creating first github action Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * fix syntax error Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * renamed action, using black stable Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * updated checkout action on workflow black Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * formatted code with black Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * replaced lint with black service Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * removed black service added black check to makefile Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * replaced flake8 with black Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * added pull_request to black actions trigger Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * replaced flake8 with black style checker (#212) * updated version number to 1.0.0 Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * creating first github action Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * fix syntax error Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * renamed action, using black stable Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * updated checkout action on workflow black Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * formatted code with black Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * version bumpt Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * removed some comments and unsused import Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * replaced lint with black service Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * removed black service added black check to makefile Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * replaced flake8 with black Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * added pull_request to black actions trigger Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * started on unit test workflow Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * removed run step Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * fixed typo Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * testing docker-compose Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * check docker-compose Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * try running pytest Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * check out -f Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * changed path Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * increased health check retries, added job dependency Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * added path to docker-compose.yml to test action Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * moved container startup to test step Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * added checkout step to test job Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * different kind of execution Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * checking build step Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * fixed missing keyword Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * added checkout to build step Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * storing artifacts Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * added needs Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * changed Dockerfile-dev to python-slim Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * added job matrix back in Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * added abci to build job matrix Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * updated test job steps Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * fixed typo Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * replaced docker exec with docker-compose exec for abci test Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * added first version of acceptance and integration test action Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * added runs-on Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * fixed syntax error Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * reverted to docker exec Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * added copyright notice and env to start container step Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * separated abci from non abci test job Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * renamed pytest workflow to unit-test Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * added codecov workflow Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * added pytest install to codecov step Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * added pip install Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * moved codecov to unit-test Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * show files Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * changed paths Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * removed debug job steps Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * renamed black to lint, added audit workflow Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * checking if dc down is necessary Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * removed dc down step from acceptance and integration Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * fixed lint error Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * added tox documentation to github acitons (#226) * added documentation job Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * added docs dependency install to docs workflow Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * add more dependencies Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * install rapidjson manually Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * added python-rapidjson to docs requirements text Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * changed gh config on tox.ini Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * added base58 to docs require Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * changed docs require to dev Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * reversed changes to docs require Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * changed gh to gh-actions Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * increased verbosity for debugging Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * added -e docsroot manually Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * removed verbosity Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * removed travis ci files Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> * changed audit step to trigger on schedule Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com> Co-authored-by: enesturk <enes.m.turk@gmail.com>
618 lines
22 KiB
Python
618 lines
22 KiB
Python
# Copyright © 2020 Interplanetary Database Association e.V.,
|
|
# Planetmint and IPDB software contributors.
|
|
# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
|
|
# Code is Apache-2.0 and docs are CC-BY-4.0
|
|
|
|
import json
|
|
import logging
|
|
|
|
from unittest.mock import Mock, patch
|
|
from argparse import Namespace
|
|
|
|
import pytest
|
|
|
|
from planetmint.config import Config
|
|
from planetmint import ValidatorElection
|
|
from planetmint.commands.planetmint import run_election_show
|
|
from planetmint.transactions.types.elections.election import Election
|
|
from planetmint.lib import Block
|
|
from planetmint.transactions.types.elections.chain_migration_election import ChainMigrationElection
|
|
|
|
from tests.utils import generate_election, generate_validators
|
|
|
|
|
|
def test_make_sure_we_dont_remove_any_command():
|
|
# thanks to: http://stackoverflow.com/a/18161115/597097
|
|
from planetmint.commands.planetmint import create_parser
|
|
|
|
parser = create_parser()
|
|
|
|
assert parser.parse_args(["configure", "tarantool_db"]).command
|
|
assert parser.parse_args(["show-config"]).command
|
|
assert parser.parse_args(["init"]).command
|
|
assert parser.parse_args(["drop"]).command
|
|
assert parser.parse_args(["start"]).command
|
|
assert parser.parse_args(
|
|
[
|
|
"election",
|
|
"new",
|
|
"upsert-validator",
|
|
"TEMP_PUB_KEYPAIR",
|
|
"10",
|
|
"TEMP_NODE_ID",
|
|
"--private-key",
|
|
"TEMP_PATH_TO_PRIVATE_KEY",
|
|
]
|
|
).command
|
|
assert parser.parse_args(
|
|
["election", "new", "chain-migration", "--private-key", "TEMP_PATH_TO_PRIVATE_KEY"]
|
|
).command
|
|
assert parser.parse_args(
|
|
["election", "approve", "ELECTION_ID", "--private-key", "TEMP_PATH_TO_PRIVATE_KEY"]
|
|
).command
|
|
assert parser.parse_args(["election", "show", "ELECTION_ID"]).command
|
|
assert parser.parse_args(["tendermint-version"]).command
|
|
|
|
|
|
@patch("planetmint.commands.utils.start")
|
|
def test_main_entrypoint(mock_start):
|
|
from planetmint.commands.planetmint import main
|
|
|
|
main()
|
|
|
|
assert mock_start.called
|
|
|
|
|
|
@patch("planetmint.log.setup_logging")
|
|
@patch("planetmint.commands.planetmint._run_init")
|
|
@patch("planetmint.config_utils.autoconfigure")
|
|
def test_bigchain_run_start(mock_setup_logging, mock_run_init, mock_autoconfigure, mock_processes_start):
|
|
from planetmint.commands.planetmint import run_start
|
|
|
|
args = Namespace(config=None, yes=True, skip_initialize_database=False)
|
|
run_start(args)
|
|
assert mock_setup_logging.called
|
|
|
|
|
|
# TODO Please beware, that if debugging, the "-s" switch for pytest will
|
|
# interfere with capsys.
|
|
# See related issue: https://github.com/pytest-dev/pytest/issues/128
|
|
@pytest.mark.usefixtures("ignore_local_config_file")
|
|
def test_bigchain_show_config(capsys):
|
|
from planetmint.commands.planetmint import run_show_config
|
|
|
|
args = Namespace(config=None)
|
|
_, _ = capsys.readouterr()
|
|
run_show_config(args)
|
|
output_config = json.loads(capsys.readouterr()[0])
|
|
sorted_output_config = json.dumps(output_config, indent=4, sort_keys=True)
|
|
print(f"config : {sorted_output_config}")
|
|
# Note: This test passed previously because we were always
|
|
# using the default configuration parameters, but since we
|
|
# are running with docker-compose now and expose parameters like
|
|
# PLANETMINT_SERVER_BIND, PLANETMINT_WSSERVER_HOST, PLANETMINT_WSSERVER_ADVERTISED_HOST
|
|
# the default comparison fails i.e. when config is imported at the beginning the
|
|
# dict returned is different that what is expected after run_show_config
|
|
# and run_show_config updates the planetmint.config
|
|
from planetmint.config import Config
|
|
|
|
_config = Config().get()
|
|
sorted_config = json.dumps(_config, indent=4, sort_keys=True)
|
|
print(f"_config : {sorted_config}")
|
|
# del sorted_config['CONFIGURED']
|
|
assert sorted_output_config == sorted_config
|
|
|
|
|
|
def test__run_init(mocker):
|
|
init_db_mock = mocker.patch("planetmint.backend.tarantool.connection.TarantoolDBConnection.init_database")
|
|
|
|
from planetmint.backend.connection import connect
|
|
|
|
conn = connect()
|
|
conn.init_database()
|
|
|
|
init_db_mock.assert_called_once_with()
|
|
|
|
|
|
@patch("planetmint.backend.schema.drop_database")
|
|
def test_drop_db_when_assumed_yes(mock_db_drop):
|
|
from planetmint.commands.planetmint import run_drop
|
|
|
|
args = Namespace(config=None, yes=True)
|
|
|
|
run_drop(args)
|
|
assert mock_db_drop.called
|
|
|
|
|
|
@patch("planetmint.backend.schema.drop_database")
|
|
def test_drop_db_when_interactive_yes(mock_db_drop, monkeypatch):
|
|
from planetmint.commands.planetmint import run_drop
|
|
|
|
args = Namespace(config=None, yes=False)
|
|
monkeypatch.setattr("planetmint.commands.planetmint.input_on_stderr", lambda x: "y")
|
|
|
|
run_drop(args)
|
|
assert mock_db_drop.called
|
|
|
|
|
|
@patch("planetmint.backend.schema.drop_database")
|
|
def test_drop_db_when_db_does_not_exist(mock_db_drop, capsys):
|
|
from planetmint.transactions.common.exceptions import DatabaseDoesNotExist
|
|
from planetmint.commands.planetmint import run_drop
|
|
|
|
args = Namespace(config=None, yes=True)
|
|
mock_db_drop.side_effect = DatabaseDoesNotExist
|
|
|
|
run_drop(args)
|
|
output_message = capsys.readouterr()[1]
|
|
assert output_message == "Drop was executed, but spaces doesn't exist.\n"
|
|
# assert output_message == "Cannot drop '{name}'. The database does not exist.\n".format(
|
|
# name=Config().get()['database']['name'])
|
|
|
|
|
|
@patch("planetmint.backend.schema.drop_database")
|
|
def test_drop_db_does_not_drop_when_interactive_no(mock_db_drop, monkeypatch):
|
|
from planetmint.commands.planetmint import run_drop
|
|
|
|
args = Namespace(config=None, yes=False)
|
|
monkeypatch.setattr("planetmint.commands.planetmint.input_on_stderr", lambda x: "n")
|
|
|
|
run_drop(args)
|
|
assert not mock_db_drop.called
|
|
|
|
|
|
# TODO Beware if you are putting breakpoints in there, and using the '-s'
|
|
# switch with pytest. It will just hang. Seems related to the monkeypatching of
|
|
# input_on_stderr.
|
|
def test_run_configure_when_config_does_not_exist(
|
|
monkeypatch, mock_write_config, mock_generate_key_pair, mock_planetmint_backup_config
|
|
):
|
|
from planetmint.commands.planetmint import run_configure
|
|
|
|
monkeypatch.setattr("os.path.exists", lambda path: False)
|
|
monkeypatch.setattr("builtins.input", lambda: "\n")
|
|
args = Namespace(config=None, backend="localmongodb", yes=True)
|
|
return_value = run_configure(args)
|
|
assert return_value is None
|
|
|
|
|
|
def test_run_configure_when_config_does_exist(
|
|
monkeypatch, mock_write_config, mock_generate_key_pair, mock_planetmint_backup_config
|
|
):
|
|
value = {}
|
|
|
|
def mock_write_config(newconfig):
|
|
value["return"] = newconfig
|
|
|
|
from planetmint.commands.planetmint import run_configure
|
|
|
|
monkeypatch.setattr("os.path.exists", lambda path: True)
|
|
monkeypatch.setattr("builtins.input", lambda: "\n")
|
|
monkeypatch.setattr("planetmint.config_utils.write_config", mock_write_config)
|
|
|
|
args = Namespace(config=None, yes=None)
|
|
run_configure(args)
|
|
assert value == {}
|
|
|
|
|
|
@pytest.mark.skip
|
|
@pytest.mark.parametrize("backend", ("localmongodb",))
|
|
def test_run_configure_with_backend(backend, monkeypatch, mock_write_config):
|
|
import planetmint
|
|
from planetmint.commands.planetmint import run_configure
|
|
|
|
value = {}
|
|
|
|
def mock_write_config(new_config, filename=None):
|
|
value["return"] = new_config
|
|
|
|
monkeypatch.setattr("os.path.exists", lambda path: False)
|
|
monkeypatch.setattr("builtins.input", lambda: "\n")
|
|
monkeypatch.setattr("planetmint.config_utils.write_config", mock_write_config)
|
|
|
|
args = Namespace(config=None, backend=backend, yes=True)
|
|
expected_config = Config().get()
|
|
run_configure(args)
|
|
|
|
# update the expected config with the correct backend and keypair
|
|
backend_conf = getattr(planetmint, "_database_" + backend)
|
|
expected_config.update({"database": backend_conf, "keypair": value["return"]["keypair"]})
|
|
|
|
assert value["return"] == expected_config
|
|
|
|
|
|
@patch("planetmint.commands.utils.start")
|
|
def test_calling_main(start_mock, monkeypatch):
|
|
from planetmint.commands.planetmint import main
|
|
|
|
argparser_mock = Mock()
|
|
parser = Mock()
|
|
subparsers = Mock()
|
|
subsubparsers = Mock()
|
|
subparsers.add_parser.return_value = subsubparsers
|
|
parser.add_subparsers.return_value = subparsers
|
|
argparser_mock.return_value = parser
|
|
monkeypatch.setattr("argparse.ArgumentParser", argparser_mock)
|
|
main()
|
|
|
|
assert argparser_mock.called is True
|
|
parser.add_subparsers.assert_called_with(title="Commands", dest="command")
|
|
subparsers.add_parser.assert_any_call("configure", help="Prepare the config file.")
|
|
subparsers.add_parser.assert_any_call("show-config", help="Show the current " "configuration")
|
|
subparsers.add_parser.assert_any_call("init", help="Init the database")
|
|
subparsers.add_parser.assert_any_call("drop", help="Drop the database")
|
|
|
|
subparsers.add_parser.assert_any_call("start", help="Start Planetmint")
|
|
subparsers.add_parser.assert_any_call("tendermint-version", help="Show the Tendermint supported " "versions")
|
|
|
|
assert start_mock.called is True
|
|
|
|
|
|
@patch("planetmint.commands.planetmint.run_recover")
|
|
@patch("planetmint.start.start")
|
|
def test_recover_db_on_start(mock_run_recover, mock_start, mocked_setup_logging):
|
|
from planetmint.commands.planetmint import run_start
|
|
|
|
args = Namespace(config=None, yes=True, skip_initialize_database=False)
|
|
run_start(args)
|
|
|
|
assert mock_run_recover.called
|
|
assert mock_start.called
|
|
|
|
|
|
@pytest.mark.bdb
|
|
def test_run_recover(b, alice, bob):
|
|
from planetmint.commands.planetmint import run_recover
|
|
from planetmint.transactions.types.assets.create import Create
|
|
from planetmint.lib import Block
|
|
from planetmint.backend import query
|
|
|
|
tx1 = Create.generate(
|
|
[alice.public_key], [([alice.public_key], 1)], asset={"cycle": "hero"}, metadata={"name": "hohenheim"}
|
|
).sign([alice.private_key])
|
|
tx2 = Create.generate(
|
|
[bob.public_key], [([bob.public_key], 1)], asset={"cycle": "hero"}, metadata={"name": "hohenheim"}
|
|
).sign([bob.private_key])
|
|
print(tx1.id)
|
|
print(tx2.id)
|
|
# store the transactions
|
|
b.store_bulk_transactions([tx1, tx2])
|
|
|
|
# create a random block
|
|
block8 = Block(app_hash="random_app_hash1", height=8, transactions=["txid_doesnt_matter"])._asdict()
|
|
b.store_block(block8)
|
|
|
|
# create the next block
|
|
block9 = Block(app_hash="random_app_hash1", height=9, transactions=[tx1.id])._asdict()
|
|
b.store_block(block9)
|
|
|
|
# create a pre_commit state which is ahead of the commit state
|
|
pre_commit_state = dict(height=10, transactions=[tx2.id])
|
|
b.store_pre_commit_state(pre_commit_state)
|
|
|
|
run_recover(b)
|
|
|
|
assert not query.get_transaction(b.connection, tx2.id)
|
|
|
|
|
|
# Helper
|
|
class MockResponse:
|
|
def __init__(self, height):
|
|
self.height = height
|
|
|
|
def json(self):
|
|
return {"result": {"latest_block_height": self.height}}
|
|
|
|
|
|
@pytest.mark.abci
|
|
def test_election_new_upsert_validator_with_tendermint(b, priv_validator_path, user_sk, validators):
|
|
from planetmint.commands.planetmint import run_election_new_upsert_validator
|
|
|
|
new_args = Namespace(
|
|
action="new",
|
|
election_type="upsert-validator",
|
|
public_key="HHG0IQRybpT6nJMIWWFWhMczCLHt6xcm7eP52GnGuPY=",
|
|
power=1,
|
|
node_id="unique_node_id_for_test_upsert_validator_new_with_tendermint",
|
|
sk=priv_validator_path,
|
|
config={},
|
|
)
|
|
|
|
election_id = run_election_new_upsert_validator(new_args, b)
|
|
|
|
assert b.get_transaction(election_id)
|
|
|
|
|
|
@pytest.mark.bdb
|
|
def test_election_new_upsert_validator_without_tendermint(caplog, b, priv_validator_path, user_sk):
|
|
from planetmint.commands.planetmint import run_election_new_upsert_validator
|
|
|
|
def mock_write(tx, mode):
|
|
b.store_bulk_transactions([tx])
|
|
return (202, "")
|
|
|
|
b.get_validators = mock_get_validators
|
|
b.write_transaction = mock_write
|
|
|
|
args = Namespace(
|
|
action="new",
|
|
election_type="upsert-validator",
|
|
public_key="CJxdItf4lz2PwEf4SmYNAu/c/VpmX39JEgC5YpH7fxg=",
|
|
power=1,
|
|
node_id="fb7140f03a4ffad899fabbbf655b97e0321add66",
|
|
sk=priv_validator_path,
|
|
config={},
|
|
)
|
|
|
|
with caplog.at_level(logging.INFO):
|
|
election_id = run_election_new_upsert_validator(args, b)
|
|
assert caplog.records[0].msg == "[SUCCESS] Submitted proposal with id: " + election_id
|
|
assert b.get_transaction(election_id)
|
|
|
|
|
|
@pytest.mark.abci
|
|
def test_election_new_chain_migration_with_tendermint(b, priv_validator_path, user_sk, validators):
|
|
from planetmint.commands.planetmint import run_election_new_chain_migration
|
|
|
|
new_args = Namespace(action="new", election_type="migration", sk=priv_validator_path, config={})
|
|
|
|
election_id = run_election_new_chain_migration(new_args, b)
|
|
|
|
assert b.get_transaction(election_id)
|
|
|
|
|
|
@pytest.mark.bdb
|
|
def test_election_new_chain_migration_without_tendermint(caplog, b, priv_validator_path, user_sk):
|
|
from planetmint.commands.planetmint import run_election_new_chain_migration
|
|
|
|
def mock_write(tx, mode):
|
|
b.store_bulk_transactions([tx])
|
|
return (202, "")
|
|
|
|
b.get_validators = mock_get_validators
|
|
b.write_transaction = mock_write
|
|
|
|
args = Namespace(action="new", election_type="migration", sk=priv_validator_path, config={})
|
|
|
|
with caplog.at_level(logging.INFO):
|
|
election_id = run_election_new_chain_migration(args, b)
|
|
assert caplog.records[0].msg == "[SUCCESS] Submitted proposal with id: " + election_id
|
|
assert b.get_transaction(election_id)
|
|
|
|
|
|
@pytest.mark.bdb
|
|
def test_election_new_upsert_validator_invalid_election(caplog, b, priv_validator_path, user_sk):
|
|
from planetmint.commands.planetmint import run_election_new_upsert_validator
|
|
|
|
args = Namespace(
|
|
action="new",
|
|
election_type="upsert-validator",
|
|
public_key="CJxdItf4lz2PwEf4SmYNAu/c/VpmX39JEgC5YpH7fxg=",
|
|
power=10,
|
|
node_id="fb7140f03a4ffad899fabbbf655b97e0321add66",
|
|
sk="/tmp/invalid/path/key.json",
|
|
config={},
|
|
)
|
|
|
|
with caplog.at_level(logging.ERROR):
|
|
assert not run_election_new_upsert_validator(args, b)
|
|
assert caplog.records[0].msg.__class__ == FileNotFoundError
|
|
|
|
|
|
@pytest.mark.bdb
|
|
def test_election_new_upsert_validator_invalid_power(caplog, b, priv_validator_path, user_sk):
|
|
from planetmint.commands.planetmint import run_election_new_upsert_validator
|
|
from planetmint.transactions.common.exceptions import InvalidPowerChange
|
|
|
|
def mock_write(tx, mode):
|
|
b.store_bulk_transactions([tx])
|
|
return (400, "")
|
|
|
|
b.write_transaction = mock_write
|
|
b.get_validators = mock_get_validators
|
|
args = Namespace(
|
|
action="new",
|
|
election_type="upsert-validator",
|
|
public_key="CJxdItf4lz2PwEf4SmYNAu/c/VpmX39JEgC5YpH7fxg=",
|
|
power=10,
|
|
node_id="fb7140f03a4ffad899fabbbf655b97e0321add66",
|
|
sk=priv_validator_path,
|
|
config={},
|
|
)
|
|
|
|
with caplog.at_level(logging.ERROR):
|
|
assert not run_election_new_upsert_validator(args, b)
|
|
assert caplog.records[0].msg.__class__ == InvalidPowerChange
|
|
|
|
|
|
@pytest.mark.abci
|
|
def test_election_approve_with_tendermint(b, priv_validator_path, user_sk, validators):
|
|
from planetmint.commands.planetmint import run_election_new_upsert_validator, run_election_approve
|
|
|
|
public_key = "CJxdItf4lz2PwEf4SmYNAu/c/VpmX39JEgC5YpH7fxg="
|
|
new_args = Namespace(
|
|
action="new",
|
|
election_type="upsert-validator",
|
|
public_key=public_key,
|
|
power=1,
|
|
node_id="fb7140f03a4ffad899fabbbf655b97e0321add66",
|
|
sk=priv_validator_path,
|
|
config={},
|
|
)
|
|
|
|
election_id = run_election_new_upsert_validator(new_args, b)
|
|
assert election_id
|
|
|
|
args = Namespace(action="approve", election_id=election_id, sk=priv_validator_path, config={})
|
|
approve = run_election_approve(args, b)
|
|
|
|
assert b.get_transaction(approve)
|
|
|
|
|
|
@pytest.mark.bdb
|
|
def test_election_approve_without_tendermint(caplog, b, priv_validator_path, new_validator, node_key):
|
|
from planetmint.commands.planetmint import run_election_approve
|
|
from argparse import Namespace
|
|
|
|
b, election_id = call_election(b, new_validator, node_key)
|
|
|
|
# call run_election_approve with args that point to the election
|
|
args = Namespace(action="approve", election_id=election_id, sk=priv_validator_path, config={})
|
|
|
|
# assert returned id is in the db
|
|
with caplog.at_level(logging.INFO):
|
|
approval_id = run_election_approve(args, b)
|
|
assert caplog.records[0].msg == "[SUCCESS] Your vote has been submitted"
|
|
assert b.get_transaction(approval_id)
|
|
|
|
|
|
@pytest.mark.bdb
|
|
def test_election_approve_failure(caplog, b, priv_validator_path, new_validator, node_key):
|
|
from planetmint.commands.planetmint import run_election_approve
|
|
from argparse import Namespace
|
|
|
|
b, election_id = call_election(b, new_validator, node_key)
|
|
|
|
def mock_write(tx, mode):
|
|
b.store_bulk_transactions([tx])
|
|
return (400, "")
|
|
|
|
b.write_transaction = mock_write
|
|
|
|
# call run_upsert_validator_approve with args that point to the election
|
|
args = Namespace(action="approve", election_id=election_id, sk=priv_validator_path, config={})
|
|
|
|
with caplog.at_level(logging.ERROR):
|
|
assert not run_election_approve(args, b)
|
|
assert caplog.records[0].msg == "Failed to commit vote"
|
|
|
|
|
|
@pytest.mark.bdb
|
|
def test_election_approve_called_with_bad_key(caplog, b, bad_validator_path, new_validator, node_key):
|
|
from planetmint.commands.planetmint import run_election_approve
|
|
from argparse import Namespace
|
|
|
|
b, election_id = call_election(b, new_validator, node_key)
|
|
|
|
# call run_upsert_validator_approve with args that point to the election, but a bad signing key
|
|
args = Namespace(action="approve", election_id=election_id, sk=bad_validator_path, config={})
|
|
|
|
with caplog.at_level(logging.ERROR):
|
|
assert not run_election_approve(args, b)
|
|
assert (
|
|
caplog.records[0].msg == "The key you provided does not match any of "
|
|
"the eligible voters in this election."
|
|
)
|
|
|
|
|
|
@pytest.mark.bdb
|
|
def test_chain_migration_election_show_shows_inconclusive(b):
|
|
validators = generate_validators([1] * 4)
|
|
b.store_validator_set(1, [v["storage"] for v in validators])
|
|
|
|
public_key = validators[0]["public_key"]
|
|
private_key = validators[0]["private_key"]
|
|
voter_keys = [v["private_key"] for v in validators]
|
|
|
|
election, votes = generate_election(b, ChainMigrationElection, public_key, private_key, {}, voter_keys)
|
|
|
|
assert not run_election_show(Namespace(election_id=election.id), b)
|
|
|
|
Election.process_block(b, 1, [election])
|
|
b.store_bulk_transactions([election])
|
|
|
|
assert run_election_show(Namespace(election_id=election.id), b) == "status=ongoing"
|
|
|
|
b.store_block(Block(height=1, transactions=[], app_hash="")._asdict())
|
|
b.store_validator_set(2, [v["storage"] for v in validators])
|
|
|
|
assert run_election_show(Namespace(election_id=election.id), b) == "status=ongoing"
|
|
|
|
b.store_block(Block(height=2, transactions=[], app_hash="")._asdict())
|
|
# TODO insert yet another block here when upgrading to Tendermint 0.22.4.
|
|
|
|
assert run_election_show(Namespace(election_id=election.id), b) == "status=inconclusive"
|
|
|
|
|
|
@pytest.mark.bdb
|
|
def test_chain_migration_election_show_shows_concluded(b):
|
|
validators = generate_validators([1] * 4)
|
|
b.store_validator_set(1, [v["storage"] for v in validators])
|
|
|
|
public_key = validators[0]["public_key"]
|
|
private_key = validators[0]["private_key"]
|
|
voter_keys = [v["private_key"] for v in validators]
|
|
|
|
election, votes = generate_election(b, ChainMigrationElection, public_key, private_key, {}, voter_keys)
|
|
|
|
assert not run_election_show(Namespace(election_id=election.id), b)
|
|
|
|
b.store_bulk_transactions([election])
|
|
Election.process_block(b, 1, [election])
|
|
|
|
assert run_election_show(Namespace(election_id=election.id), b) == "status=ongoing"
|
|
|
|
b.store_abci_chain(1, "chain-X")
|
|
b.store_block(Block(height=1, transactions=[v.id for v in votes], app_hash="last_app_hash")._asdict())
|
|
Election.process_block(b, 2, votes)
|
|
|
|
assert (
|
|
run_election_show(Namespace(election_id=election.id), b)
|
|
== f'''status=concluded
|
|
chain_id=chain-X-migrated-at-height-1
|
|
app_hash=last_app_hash
|
|
validators=[{''.join([f"""
|
|
{{
|
|
"pub_key": {{
|
|
"type": "tendermint/PubKeyEd25519",
|
|
"value": "{v['public_key']}"
|
|
}},
|
|
"power": {v['storage']['voting_power']}
|
|
}}{',' if i + 1 != len(validators) else ''}""" for i, v in enumerate(validators)])}
|
|
]'''
|
|
)
|
|
|
|
|
|
def test_bigchain_tendermint_version(capsys):
|
|
from planetmint.commands.planetmint import run_tendermint_version
|
|
|
|
args = Namespace(config=None)
|
|
_, _ = capsys.readouterr()
|
|
run_tendermint_version(args)
|
|
output_config = json.loads(capsys.readouterr()[0])
|
|
from planetmint.version import __tm_supported_versions__
|
|
|
|
assert len(output_config["tendermint"]) == len(__tm_supported_versions__)
|
|
assert sorted(output_config["tendermint"]) == sorted(__tm_supported_versions__)
|
|
|
|
|
|
def mock_get_validators(height):
|
|
return [
|
|
{
|
|
"public_key": {"value": "zL/DasvKulXZzhSNFwx4cLRXKkSM9GPK7Y0nZ4FEylM=", "type": "ed25519-base64"},
|
|
"voting_power": 10,
|
|
}
|
|
]
|
|
|
|
|
|
def call_election(b, new_validator, node_key):
|
|
def mock_write(tx, mode):
|
|
b.store_bulk_transactions([tx])
|
|
return (202, "")
|
|
|
|
# patch the validator set. We now have one validator with power 10
|
|
b.get_validators = mock_get_validators
|
|
b.write_transaction = mock_write
|
|
|
|
# our voters is a list of length 1, populated from our mocked validator
|
|
voters = ValidatorElection.recipients(b)
|
|
# and our voter is the public key from the voter list
|
|
voter = node_key.public_key
|
|
valid_election = ValidatorElection.generate([voter], voters, new_validator, None).sign([node_key.private_key])
|
|
|
|
# patch in an election with a vote issued to the user
|
|
election_id = valid_election.id
|
|
b.store_bulk_transactions([valid_election])
|
|
|
|
return b, election_id
|