diff --git a/.test-env b/.test-env index 3b17bb19..df783a4f 100644 --- a/.test-env +++ b/.test-env @@ -3,6 +3,8 @@ SDK_TESTING_URL="https://github.com/algorand/algorand-sdk-testing" SDK_TESTING_BRANCH="master" SDK_TESTING_HARNESS="test-harness" +INSTALL_ONLY=0 + VERBOSE_HARNESS=0 # WARNING: If set to 1, new features will be LOST when downloading the test harness. diff --git a/Makefile b/Makefile index 8b51618a..b2be49e1 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,10 @@ display-all-python-steps: find tests/steps -name "*.py" | xargs grep "behave" 2>/dev/null | cut -d: -f1 | sort | uniq | xargs awk "/@(given|step|then|when)/,/[)]/" | grep -E "(\".+\"|\'.+\')" harness: - ./test-harness.sh + ./test-harness.sh up + +harness-down: + ./test-harness.sh down PYTHON_VERSION ?= 3.8 docker-pysdk-build: diff --git a/algosdk/v2client/algod.py b/algosdk/v2client/algod.py index 67a21027..46d00214 100644 --- a/algosdk/v2client/algod.py +++ b/algosdk/v2client/algod.py @@ -440,6 +440,16 @@ def stateproofs(self, round_num, **kwargs): req = "/stateproofs/{}".format(round_num) return self.algod_request("GET", req, **kwargs) + def get_block_hash(self, round_num, **kwargs): + """ + Get the block hash for the block on the given round. + + Args: + round_num (int): The round in which the transaction appears. + """ + req = "/blocks/{}/hash".format(round_num) + return self.algod_request("GET", req, **kwargs) + def _specify_round_string(block, round_num): """ diff --git a/algosdk/v2client/indexer.py b/algosdk/v2client/indexer.py index f1d0da3a..4dd4bd1c 100644 --- a/algosdk/v2client/indexer.py +++ b/algosdk/v2client/indexer.py @@ -211,20 +211,26 @@ def asset_balances( query["include-all"] = include_all return self.indexer_request("GET", req, query, **kwargs) - def block_info(self, block=None, round_num=None, **kwargs): + def block_info( + self, block=None, round_num=None, header_only=None, **kwargs + ): """ Get the block for the given round. Args: block (int, optional): block number round_num (int, optional): alias for block; specify one of these + header_only (bool, optional): """ - req = "/blocks/" if block is None and round_num is None: raise error.UnderspecifiedRoundError req = "/blocks/" + _specify_round_string(block, round_num) - return self.indexer_request("GET", req, **kwargs) + query = dict() + if header_only: + query["header-only"] = "true" + + return self.indexer_request("GET", req, query, **kwargs) def account_info( self, diff --git a/setup.py b/setup.py index de62eb5e..76e49db5 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ description="Algorand SDK in Python", author="Algorand", author_email="pypiservice@algorand.com", - version="v1.18.0", + version="v1.19.0", long_description=long_description, long_description_content_type="text/markdown", license="MIT", diff --git a/test-harness.sh b/test-harness.sh index 9ddda66b..7e1a4f75 100755 --- a/test-harness.sh +++ b/test-harness.sh @@ -1,7 +1,47 @@ #!/usr/bin/env bash - set -euo pipefail +# test-harness.sh setup/start cucumber test environment. +# +# Configuration is managed with environment variables, the ones you +# are most likely to reconfigured are stored in '.test-env'. +# +# Variables: +# SDK_TESTING_URL - URL to algorand-sdk-testing, useful for forks. +# SDK_TESTING_BRANCH - branch to checkout, useful for new tests. +# SDK_TESTING_HARNESS - local directory that the algorand-sdk-testing repo is cloned into. +# VERBOSE_HARNESS - more output while the script runs. +# INSTALL_ONLY - installs feature files only, useful for unit tests. +# +# WARNING: If set to 1, new features will be LOST when downloading the test harness. +# REGARDLESS: modified features are ALWAYS overwritten. +# REMOVE_LOCAL_FEATURES - delete all local cucumber feature files before downloading these from github. +# +# WARNING: Be careful when turning on the next variable. +# In that case you'll need to provide all variables expected by `algorand-sdk-testing`'s `.env` +# OVERWRITE_TESTING_ENVIRONMENT=0 + +SHUTDOWN=0 +if [ $# -ne 0 ]; then + if [ $# -ne 1 ]; then + echo "this script accepts a single argument, which must be 'up' or 'down'." + exit 1 + fi + + case $1 in + 'up') + ;; # default. + 'down') + SHUTDOWN=1 + ;; + *) + echo "unknown parameter '$1'." + echo "this script accepts a single argument, which must be 'up' or 'down'." + exit 1 + ;; + esac +fi + START=$(date "+%s") THIS=$(basename "$0") @@ -23,12 +63,20 @@ if [ -d "$SDK_TESTING_HARNESS" ]; then ./scripts/down.sh popd rm -rf "$SDK_TESTING_HARNESS" + if [[ $SHUTDOWN == 1 ]]; then + echo "$THIS: network shutdown complete." + exit 0 + fi else echo "$THIS: directory $SDK_TESTING_HARNESS does not exist - NOOP" fi -git clone --depth 1 --single-branch --branch "$SDK_TESTING_BRANCH" "$SDK_TESTING_URL" "$SDK_TESTING_HARNESS" +if [[ $SHUTDOWN == 1 ]]; then + echo "$THIS: unable to shutdown network." + exit 1 +fi +git clone --depth 1 --single-branch --branch "$SDK_TESTING_BRANCH" "$SDK_TESTING_URL" "$SDK_TESTING_HARNESS" echo "$THIS: OVERWRITE_TESTING_ENVIRONMENT=$OVERWRITE_TESTING_ENVIRONMENT" if [[ $OVERWRITE_TESTING_ENVIRONMENT == 1 ]]; then @@ -53,6 +101,11 @@ if [[ $VERBOSE_HARNESS == 1 ]]; then fi echo "$THIS: seconds it took to get to end of cloning and copying: $(($(date "+%s") - START))s" +if [[ $INSTALL_ONLY == 1 ]]; then + echo "$THIS: configured to install feature files only. Not starting test harness environment." + exit 0 +fi + ## Start test harness environment pushd "$SDK_TESTING_HARNESS" diff --git a/tests/steps/other_v2_steps.py b/tests/steps/other_v2_steps.py index 58f6295c..578d2e6c 100644 --- a/tests/steps/other_v2_steps.py +++ b/tests/steps/other_v2_steps.py @@ -39,9 +39,9 @@ def parse_string(text): register_type(MaybeString=parse_string) -@parse.with_pattern(r"true|false") +@parse.with_pattern(r"true|false|") def parse_bool(value): - if value not in ("true", "false"): + if value not in ("true", "false", ""): raise ValueError("Unknown value for include_all: {}".format(value)) return value == "true" @@ -623,9 +623,19 @@ def parse_txns_by_addr(context, roundNum, length, idx, sender): assert context.response["transactions"][int(idx)]["sender"] == sender -@when("we make a Lookup Block call against round {block}") +@when( + 'we make a Lookup Block call against round {block:d} and header "{headerOnly:MaybeBool}"' +) +def lookup_block(context, block, headerOnly): + print("Header only = " + str(headerOnly)) + context.response = context.icl.block_info( + block=block, header_only=headerOnly + ) + + +@when("we make a Lookup Block call against round {block:d}") def lookup_block(context, block): - context.response = context.icl.block_info(int(block)) + context.response = context.icl.block_info(block) @when("we make any LookupBlock call") @@ -1392,3 +1402,8 @@ def transaction_proof(context, round, txid, hashtype): context.response = context.acl.transaction_proof( round, txid, hashtype, "msgpack" ) + + +@when("we make a Lookup Block Hash call against round {round}") +def get_block_hash(context, round): + context.response = context.acl.get_block_hash(round) diff --git a/tests/unit.tags b/tests/unit.tags index e9f95700..9ddbf8c2 100644 --- a/tests/unit.tags +++ b/tests/unit.tags @@ -5,6 +5,7 @@ @unit.applications @unit.atc_method_args @unit.atomic_transaction_composer +@unit.blocksummary @unit.dryrun @unit.dryrun.trace.application @unit.feetest @@ -16,6 +17,7 @@ @unit.rekey @unit.responses @unit.responses.231 +@unit.responses.blocksummary @unit.responses.participationupdates @unit.responses.unlimited_assets @unit.sourcemap