diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml deleted file mode 100644 index 0798bd9..0000000 --- a/.github/workflows/integration-test.yml +++ /dev/null @@ -1,19 +0,0 @@ -# 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 - -name: Integration tests -on: [push, pull_request] - -jobs: - test: - if: ${{ false } - runs-on: ubuntu-latest - - steps: - - name: Check out repository code - uses: actions/checkout@v3 - - - name: Start test run - run: docker-compose -f docker-compose.integration.yml up test diff --git a/Makefile b/Makefile index 8df153b..f6edb59 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: help run start stop logs lint test test-unit test-unit-watch test-integration cov docs clean reset release dist check-deps clean-build clean-pyc clean-test +.PHONY: help run start stop logs lint test test-unit test-unit-watch cov docs clean reset release dist check-deps clean-build clean-pyc clean-test .DEFAULT_GOAL := help @@ -72,16 +72,9 @@ test-unit: check-deps ## Run all tests once or specify a file/test with TEST=tes poetry run pytest -m abci @$(DC) down - - test-unit-watch: check-deps ## Run all tests and wait. Every time you change code, tests will be run again @$(DC) run --rm --no-deps planetmint pytest -f - - -test-integration: check-deps ## Run all integration tests - @./scripts/run-integration-test.sh - cov: check-deps ## Check code coverage and open the result in the browser @$(DC) run --rm planetmint pytest -v --cov=planetmint --cov-report html diff --git a/docker-compose.integration.yml b/docker-compose.integration.yml deleted file mode 100644 index 52ac541..0000000 --- a/docker-compose.integration.yml +++ /dev/null @@ -1,53 +0,0 @@ -# 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 - -version: '2.2' - -services: - clean-shared: - image: alpine - command: ["/scripts/clean-shared.sh"] - volumes: - - ./integration/scripts/clean-shared.sh:/scripts/clean-shared.sh - - shared:/shared - - planetmint-all-in-one: - build: - context: . - dockerfile: Dockerfile-all-in-one - depends_on: - - clean-shared - expose: - - "22" - - "9984" - - "9985" - - "26656" - - "26657" - - "26658" - command: ["/usr/src/app/scripts/pre-config-planetmint.sh", "/usr/src/app/scripts/all-in-one.bash"] - environment: - SCALE: ${SCALE:-4} - volumes: - - ./integration/scripts:/usr/src/app/scripts - - shared:/shared - scale: ${SCALE:-4} - - test: - build: - context: . - dockerfile: integration/python/Dockerfile - depends_on: - - planetmint-all-in-one - command: ["/scripts/pre-config-test.sh", "/scripts/wait-for-planetmint.sh", "/scripts/test.sh", "pytest", "/src"] - environment: - SCALE: ${SCALE:-4} - volumes: - - ./integration/python/src:/src - - ./integration/scripts:/scripts - - ./integration/cli:/tests - - shared:/shared - -volumes: - shared: diff --git a/integration/README.md b/integration/README.md deleted file mode 100644 index ba1e204..0000000 --- a/integration/README.md +++ /dev/null @@ -1,23 +0,0 @@ - - -# Integration test suite -This directory contains the integration test suite for Planetmint. - -The suite uses Docker Compose to spin up multiple Planetmint nodes, run tests with `pytest` as well as cli tests and teardown. - -## Running the tests -Run `make test-integration` in the project root directory. - -By default the integration test suite spins up four planetmint nodes. If you desire to run a different configuration you can pass `SCALE=` as an environmental variable. - -## Writing and documenting the tests -Tests are sometimes difficult to read. For integration tests, we try to be really explicit on what the test is doing, so please write code that is *simple* and easy to understand. We decided to use literate-programming documentation. To generate the documentation for python tests run: - -```bash -make docs-integration -``` diff --git a/integration/cli/chain-migration.sh b/integration/cli/chain-migration.sh deleted file mode 100755 index 448ffb1..0000000 --- a/integration/cli/chain-migration.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash -# 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 - -# Add chain migration test -check_status () { - status=$(ssh -o "StrictHostKeyChecking=no" -i \~/.ssh/id_rsa root@$1 'bash -s' < scripts/election.sh show_election $2 | tail -n 1) - status=${status#*=} - if [ $status != $3 ]; then - exit 1 - fi -} - -# Read host names from shared -readarray -t HOSTNAMES < /shared/hostnames - -# Split into proposer and approvers -PROPOSER=${HOSTNAMES[0]} -APPROVERS=${HOSTNAMES[@]:1} - -# Propose chain migration -result=$(ssh -o "StrictHostKeyChecking=no" -i \~/.ssh/id_rsa root@${PROPOSER} 'bash -s' < scripts/election.sh migrate) - -# Check if election is ongoing and approve chain migration -for APPROVER in ${APPROVERS[@]}; do - # Check if election is still ongoing - check_status ${APPROVER} $result ongoing - ssh -o "StrictHostKeyChecking=no" -i ~/.ssh/id_rsa root@${APPROVER} 'bash -s' < scripts/election.sh approve $result -done - -# Status of election should be concluded -status=$(ssh -o "StrictHostKeyChecking=no" -i \~/.ssh/id_rsa root@${PROPOSER} 'bash -s' < scripts/election.sh show_election $result) -status=${status#*INFO:planetmint.commands.planetmint:} -status=("$status[@]") - - -# TODO: Get status, chain_id, app_hash and validators to restore planetmint on all nodes -# References: -# https://github.com/bigchaindb/BEPs/tree/master/42 -# http://docs.bigchaindb.com/en/latest/installation/node-setup/bigchaindb-cli.html -for word in $status; do - echo $word -done - -echo ${status#*validators=} \ No newline at end of file diff --git a/integration/cli/upsert-new-validator.sh b/integration/cli/upsert-new-validator.sh deleted file mode 100755 index 4f63568..0000000 --- a/integration/cli/upsert-new-validator.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash -# 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 - -check_status () { - status=$(ssh -o "StrictHostKeyChecking=no" -i \~/.ssh/id_rsa root@$1 'bash -s' < scripts/election.sh show_election $2 | tail -n 1) - status=${status#*=} - if [ $status != $3 ]; then - exit 1 - fi -} - -# Read host names from shared -readarray -t HOSTNAMES < /shared/hostnames - -# Split into proposer and approvers -PROPOSER=${HOSTNAMES[0]} -APPROVERS=${HOSTNAMES[@]:1} - -# Propose validator upsert -result=$(ssh -o "StrictHostKeyChecking=no" -i \~/.ssh/id_rsa root@${PROPOSER} 'bash -s' < scripts/election.sh elect 2) - -# Check if election is ongoing and approve validator upsert -for APPROVER in ${APPROVERS[@]}; do - # Check if election is still ongoing - check_status ${APPROVER} $result ongoing - ssh -o "StrictHostKeyChecking=no" -i ~/.ssh/id_rsa root@${APPROVER} 'bash -s' < scripts/election.sh approve $result -done - -# Status of election should be concluded -check_status ${PROPOSER} $result concluded \ No newline at end of file diff --git a/integration/python/.gitignore b/integration/python/.gitignore deleted file mode 100644 index 5c457d7..0000000 --- a/integration/python/.gitignore +++ /dev/null @@ -1 +0,0 @@ -docs \ No newline at end of file diff --git a/integration/python/Dockerfile b/integration/python/Dockerfile deleted file mode 100644 index 77ac208..0000000 --- a/integration/python/Dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM python:3.9 - -RUN apt-get update \ - && pip install -U pip \ - && apt-get autoremove \ - && apt-get clean -RUN apt-get install -y vim -RUN apt-get update -RUN apt-get install -y build-essential cmake openssh-client openssh-server git -RUN apt-get install -y zsh - -RUN mkdir -p /src -RUN pip install --upgrade meson ninja -RUN pip install --upgrade \ - pytest~=6.2.5 \ - pycco \ - websocket-client~=0.47.0 \ - planetmint-driver>=9.2.0 \ - blns diff --git a/integration/python/src/__init__.py b/integration/python/src/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/integration/python/src/conftest.py b/integration/python/src/conftest.py deleted file mode 100644 index 747e527..0000000 --- a/integration/python/src/conftest.py +++ /dev/null @@ -1,86 +0,0 @@ -# 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 pytest - -CONDITION_SCRIPT = """Scenario 'ecdh': create the signature of an object - Given I have the 'keyring' - Given that I have a 'string dictionary' named 'houses' - When I create the signature of 'houses' - Then print the 'signature'""" - -FULFILL_SCRIPT = """Scenario 'ecdh': Bob verifies the signature from Alice - Given I have a 'ecdh public key' from 'Alice' - Given that I have a 'string dictionary' named 'houses' - Given I have a 'signature' named 'signature' - When I verify the 'houses' has a signature in 'signature' by 'Alice' - Then print the string 'ok'""" - -SK_TO_PK = """Scenario 'ecdh': Create the keypair - Given that I am known as '{}' - Given I have the 'keyring' - When I create the ecdh public key - When I create the bitcoin address - Then print my 'ecdh public key' - Then print my 'bitcoin address'""" - -GENERATE_KEYPAIR = """Scenario 'ecdh': Create the keypair - Given that I am known as 'Pippo' - When I create the ecdh key - When I create the bitcoin key - Then print data""" - -INITIAL_STATE = {"also": "more data"} -SCRIPT_INPUT = { - "houses": [ - { - "name": "Harry", - "team": "Gryffindor", - }, - { - "name": "Draco", - "team": "Slytherin", - }, - ], -} - -metadata = {"units": 300, "type": "KG"} - -ZENROOM_DATA = {"that": "is my data"} - - -@pytest.fixture -def gen_key_zencode(): - return GENERATE_KEYPAIR - - -@pytest.fixture -def secret_key_to_private_key_zencode(): - return SK_TO_PK - - -@pytest.fixture -def fulfill_script_zencode(): - return FULFILL_SCRIPT - - -@pytest.fixture -def condition_script_zencode(): - return CONDITION_SCRIPT - - -@pytest.fixture -def zenroom_house_assets(): - return SCRIPT_INPUT - - -@pytest.fixture -def zenroom_script_input(): - return SCRIPT_INPUT - - -@pytest.fixture -def zenroom_data(): - return ZENROOM_DATA diff --git a/integration/python/src/helper/__init__.py b/integration/python/src/helper/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/integration/python/src/helper/hosts.py b/integration/python/src/helper/hosts.py deleted file mode 100644 index a76e238..0000000 --- a/integration/python/src/helper/hosts.py +++ /dev/null @@ -1,35 +0,0 @@ -# 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 - -from typing import List - -from planetmint_driver import Planetmint - - -class Hosts: - hostnames = [] - connections = [] - - def __init__(self, filepath): - self.set_hostnames(filepath=filepath) - self.set_connections() - - def set_hostnames(self, filepath) -> None: - with open(filepath) as f: - self.hostnames = f.readlines() - - def set_connections(self) -> None: - self.connections = list(map(lambda h: Planetmint(h), self.hostnames)) - - def get_connection(self, index=0) -> Planetmint: - return self.connections[index] - - def get_transactions(self, tx_id) -> List: - return list(map(lambda connection: connection.transactions.retrieve(tx_id), self.connections)) - - def assert_transaction(self, tx_id) -> None: - txs = self.get_transactions(tx_id) - for tx in txs: - assert txs[0] == tx, "Cannot find transaction {}".format(tx_id) diff --git a/integration/python/src/test_basic.py b/integration/python/src/test_basic.py deleted file mode 100644 index d390932..0000000 --- a/integration/python/src/test_basic.py +++ /dev/null @@ -1,87 +0,0 @@ -# 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 Planetmint and create object -from planetmint_driver.crypto import generate_keypair - -# import helper to manage multiple nodes -from .helper.hosts import Hosts - -import time - - -def test_basic(): - # Setup up connection to Planetmint integration test nodes - hosts = Hosts("/shared/hostnames") - pm_alpha = hosts.get_connection() - - # genarate a keypair - alice = generate_keypair() - - # create a digital asset for Alice - game_boy_token = [ - { - "data": { - "hash": "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", - "storageID": "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", - }, - } - ] - - # prepare the transaction with the digital asset and issue 10 tokens to bob - prepared_creation_tx = pm_alpha.transactions.prepare( - operation="CREATE", - metadata={ - "hash": "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", - "storageID": "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", - }, - signers=alice.public_key, - recipients=[([alice.public_key], 10)], - assets=game_boy_token, - ) - - # fulfill and send the transaction - fulfilled_creation_tx = pm_alpha.transactions.fulfill(prepared_creation_tx, private_keys=alice.private_key) - pm_alpha.transactions.send_commit(fulfilled_creation_tx) - time.sleep(1) - - creation_tx_id = fulfilled_creation_tx["id"] - - # Assert that transaction is stored on all planetmint nodes - hosts.assert_transaction(creation_tx_id) - - # Transfer - # create the output and inout for the transaction - transfer_assets = [{"id": creation_tx_id}] - output_index = 0 - output = fulfilled_creation_tx["outputs"][output_index] - transfer_input = { - "fulfillment": output["condition"]["details"], - "fulfills": {"output_index": output_index, "transaction_id": transfer_assets[0]["id"]}, - "owners_before": output["public_keys"], - } - - # prepare the transaction and use 3 tokens - prepared_transfer_tx = pm_alpha.transactions.prepare( - operation="TRANSFER", - asset=transfer_assets, - inputs=transfer_input, - metadata={ - "hash": "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", - "storageID": "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", - }, - recipients=[([alice.public_key], 10)], - ) - - # fulfill and send the transaction - fulfilled_transfer_tx = pm_alpha.transactions.fulfill(prepared_transfer_tx, private_keys=alice.private_key) - sent_transfer_tx = pm_alpha.transactions.send_commit(fulfilled_transfer_tx) - - time.sleep(1) - - transfer_tx_id = sent_transfer_tx["id"] - - # Assert that transaction is stored on both planetmint nodes - hosts.assert_transaction(transfer_tx_id) diff --git a/integration/python/src/test_divisible_asset.py b/integration/python/src/test_divisible_asset.py deleted file mode 100644 index 378416e..0000000 --- a/integration/python/src/test_divisible_asset.py +++ /dev/null @@ -1,167 +0,0 @@ -# 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 - -# # Divisible assets integration testing -# This test checks if we can successfully divide assets. -# The script tests various things like: -# -# - create a transaction with a divisible asset and issue them to someone -# - check if the transaction is stored and has the right amount of tokens -# - spend some tokens -# - try to spend more tokens than available -# -# We run a series of checks for each step, that is retrieving -# the transaction from the remote system, and also checking the `amount` -# of a given transaction. - -# ## Imports -# We need the `pytest` package to catch the `BadRequest` exception properly. -# And of course, we also need the `BadRequest`. -import pytest -from planetmint_driver.exceptions import BadRequest - -# Import generate_keypair to create actors -from planetmint_driver.crypto import generate_keypair - -# import helper to manage multiple nodes -from .helper.hosts import Hosts - - -def test_divisible_assets(): - # ## Set up a connection to Planetmint - # Check [test_basic.py](./test_basic.html) to get some more details - # about the endpoint. - hosts = Hosts("/shared/hostnames") - pm = hosts.get_connection() - - # Oh look, it is Alice again and she brought her friend Bob along. - alice, bob = generate_keypair(), generate_keypair() - - # ## Alice creates a time sharing token - # Alice wants to go on vacation, while Bobs bike just broke down. - # Alice decides to rent her bike to Bob while she is gone. - # So she prepares a `CREATE` transaction to issues 10 tokens. - # First, she prepares an asset for a time sharing token. As you can see in - # the description, Bob and Alice agree that each token can be used to ride - # the bike for one hour. - - bike_token = [ - { - "data": { - "token_for": {"bike": {"serial_number": 420420}}, - "description": "Time share token. Each token equals one hour of riding.", - }, - } - ] - - # She prepares a `CREATE` transaction and issues 10 tokens. - # Here, Alice defines in a tuple that she wants to assign - # these 10 tokens to Bob. - prepared_token_tx = pm.transactions.prepare( - operation="CREATE", signers=alice.public_key, recipients=[([bob.public_key], 10)], assets=bike_token - ) - - # She fulfills and sends the transaction. - fulfilled_token_tx = pm.transactions.fulfill(prepared_token_tx, private_keys=alice.private_key) - - pm.transactions.send_commit(fulfilled_token_tx) - - # We store the `id` of the transaction to use it later on. - bike_token_id = fulfilled_token_tx["id"] - - # Let's check if the transaction was successful. - assert pm.transactions.retrieve(bike_token_id), "Cannot find transaction {}".format(bike_token_id) - - # Bob owns 10 tokens now. - assert pm.transactions.retrieve(bike_token_id)["outputs"][0]["amount"] == "10" - - # ## Bob wants to use the bike - # Now that Bob got the tokens and the sun is shining, he wants to get out - # with the bike for three hours. - # To use the bike he has to send the tokens back to Alice. - # To learn about the details of transferring a transaction check out - # [test_basic.py](./test_basic.html) - transfer_assets = [{"id": bike_token_id}] - - output_index = 0 - output = fulfilled_token_tx["outputs"][output_index] - transfer_input = { - "fulfillment": output["condition"]["details"], - "fulfills": {"output_index": output_index, "transaction_id": fulfilled_token_tx["id"]}, - "owners_before": output["public_keys"], - } - - # To use the tokens Bob has to reassign 7 tokens to himself and the - # amount he wants to use to Alice. - prepared_transfer_tx = pm.transactions.prepare( - operation="TRANSFER", - asset=transfer_assets, - inputs=transfer_input, - recipients=[([alice.public_key], 3), ([bob.public_key], 7)], - ) - - # He signs and sends the transaction. - fulfilled_transfer_tx = pm.transactions.fulfill(prepared_transfer_tx, private_keys=bob.private_key) - - sent_transfer_tx = pm.transactions.send_commit(fulfilled_transfer_tx) - - # First, Bob checks if the transaction was successful. - assert pm.transactions.retrieve(fulfilled_transfer_tx["id"]) == sent_transfer_tx - - hosts.assert_transaction(fulfilled_transfer_tx["id"]) - # There are two outputs in the transaction now. - # The first output shows that Alice got back 3 tokens... - assert pm.transactions.retrieve(fulfilled_transfer_tx["id"])["outputs"][0]["amount"] == "3" - - # ... while Bob still has 7 left. - assert pm.transactions.retrieve(fulfilled_transfer_tx["id"])["outputs"][1]["amount"] == "7" - - # ## Bob wants to ride the bike again - # It's been a week and Bob wants to right the bike again. - # Now he wants to ride for 8 hours, that's a lot Bob! - # He prepares the transaction again. - - transfer_assets = [{"id": bike_token_id}] - # This time we need an `output_index` of 1, since we have two outputs - # in the `fulfilled_transfer_tx` we created before. The first output with - # index 0 is for Alice and the second output is for Bob. - # Since Bob wants to spend more of his tokens he has to provide the - # correct output with the correct amount of tokens. - output_index = 1 - - output = fulfilled_transfer_tx["outputs"][output_index] - - transfer_input = { - "fulfillment": output["condition"]["details"], - "fulfills": {"output_index": output_index, "transaction_id": fulfilled_transfer_tx["id"]}, - "owners_before": output["public_keys"], - } - - # This time Bob only provides Alice in the `recipients` because he wants - # to spend all his tokens - prepared_transfer_tx = pm.transactions.prepare( - operation="TRANSFER", assets=transfer_assets, inputs=transfer_input, recipients=[([alice.public_key], 8)] - ) - - fulfilled_transfer_tx = pm.transactions.fulfill(prepared_transfer_tx, private_keys=bob.private_key) - - # Oh Bob, what have you done?! You tried to spend more tokens than you had. - # Remember Bob, last time you spent 3 tokens already, - # so you only have 7 left. - with pytest.raises(BadRequest) as error: - pm.transactions.send_commit(fulfilled_transfer_tx) - - # Now Bob gets an error saying that the amount he wanted to spent is - # higher than the amount of tokens he has left. - assert error.value.args[0] == 400 - message = ( - "Invalid transaction (AmountError): The amount used in the " - "inputs `7` needs to be same as the amount used in the " - "outputs `8`" - ) - assert error.value.args[2]["message"] == message - - # We have to stop this test now, I am sorry, but Bob is pretty upset - # about his mistake. See you next time :) diff --git a/integration/python/src/test_double_spend.py b/integration/python/src/test_double_spend.py deleted file mode 100644 index 181d290..0000000 --- a/integration/python/src/test_double_spend.py +++ /dev/null @@ -1,48 +0,0 @@ -# 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 - -# # Double Spend testing -# This test challenge the system with double spends. -from uuid import uuid4 -from threading import Thread -import queue - -import planetmint_driver.exceptions -from planetmint_driver.crypto import generate_keypair - -from .helper.hosts import Hosts - - -def test_double_create(): - hosts = Hosts("/shared/hostnames") - pm = hosts.get_connection() - alice = generate_keypair() - - results = queue.Queue() - - tx = pm.transactions.fulfill( - pm.transactions.prepare( - operation="CREATE", signers=alice.public_key, assets=[{"data": {"uuid": str(uuid4())}}] - ), - private_keys=alice.private_key, - ) - - def send_and_queue(tx): - try: - pm.transactions.send_commit(tx) - results.put("OK") - except planetmint_driver.exceptions.TransportError: - results.put("FAIL") - - t1 = Thread(target=send_and_queue, args=(tx,)) - t2 = Thread(target=send_and_queue, args=(tx,)) - - t1.start() - t2.start() - - results = [results.get(timeout=2), results.get(timeout=2)] - - assert results.count("OK") == 1 - assert results.count("FAIL") == 1 diff --git a/integration/python/src/test_multiple_owners.py b/integration/python/src/test_multiple_owners.py deleted file mode 100644 index d8e7f72..0000000 --- a/integration/python/src/test_multiple_owners.py +++ /dev/null @@ -1,115 +0,0 @@ -# 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 - -# # Multisignature integration testing -# This test checks if we can successfully create and transfer a transaction -# with multiple owners. -# The script tests various things like: -# -# - create a transaction with multiple owners -# - check if the transaction is stored and has the right amount of public keys -# - transfer the transaction to a third person -# -# We run a series of checks for each step, that is retrieving -# the transaction from the remote system, and also checking the public keys -# of a given transaction. - -# # Imports -import time - -# For this test case we need import and use the Python driver -from planetmint_driver.crypto import generate_keypair - -# Import helper to deal with multiple nodes -from .helper.hosts import Hosts - - -def test_multiple_owners(): - # Setup up connection to Planetmint integration test nodes - hosts = Hosts("/shared/hostnames") - pm_alpha = hosts.get_connection() - - # Generate Keypairs for Alice and Bob! - alice, bob = generate_keypair(), generate_keypair() - - # ## Alice and Bob create a transaction - # Alice and Bob just moved into a shared flat, no one can afford these - # high rents anymore. Bob suggests to get a dish washer for the - # kitchen. Alice agrees and here they go, creating the asset for their - # dish washer. - dw_asset = [{"data": {"dish washer": {"serial_number": 1337}}}] - - # They prepare a `CREATE` transaction. To have multiple owners, both - # Bob and Alice need to be the recipients. - prepared_dw_tx = pm_alpha.transactions.prepare( - operation="CREATE", signers=alice.public_key, recipients=(alice.public_key, bob.public_key), assets=dw_asset - ) - - # Now they both sign the transaction by providing their private keys. - # And send it afterwards. - fulfilled_dw_tx = pm_alpha.transactions.fulfill(prepared_dw_tx, private_keys=[alice.private_key, bob.private_key]) - - pm_alpha.transactions.send_commit(fulfilled_dw_tx) - - # We store the `id` of the transaction to use it later on. - dw_id = fulfilled_dw_tx["id"] - - time.sleep(1) - - # Use hosts to assert that the transaction is properly propagated to every node - hosts.assert_transaction(dw_id) - - # Let's check if the transaction was successful. - assert pm_alpha.transactions.retrieve(dw_id), "Cannot find transaction {}".format(dw_id) - - # The transaction should have two public keys in the outputs. - assert len(pm_alpha.transactions.retrieve(dw_id)["outputs"][0]["public_keys"]) == 2 - - # ## Alice and Bob transfer a transaction to Carol. - # Alice and Bob save a lot of money living together. They often go out - # for dinner and don't cook at home. But now they don't have any dishes to - # wash, so they decide to sell the dish washer to their friend Carol. - - # Hey Carol, nice to meet you! - carol = generate_keypair() - - # Alice and Bob prepare the transaction to transfer the dish washer to - # Carol. - transfer_assets = [{"id": dw_id}] - - output_index = 0 - output = fulfilled_dw_tx["outputs"][output_index] - transfer_input = { - "fulfillment": output["condition"]["details"], - "fulfills": {"output_index": output_index, "transaction_id": fulfilled_dw_tx["id"]}, - "owners_before": output["public_keys"], - } - - # Now they create the transaction... - prepared_transfer_tx = pm_alpha.transactions.prepare( - operation="TRANSFER", assets=transfer_assets, inputs=transfer_input, recipients=carol.public_key - ) - - # ... and sign it with their private keys, then send it. - fulfilled_transfer_tx = pm_alpha.transactions.fulfill( - prepared_transfer_tx, private_keys=[alice.private_key, bob.private_key] - ) - - sent_transfer_tx = pm_alpha.transactions.send_commit(fulfilled_transfer_tx) - time.sleep(1) - - # Now compare if both nodes returned the same transaction - hosts.assert_transaction(fulfilled_transfer_tx["id"]) - - # They check if the transaction was successful. - assert pm_alpha.transactions.retrieve(fulfilled_transfer_tx["id"]) == sent_transfer_tx - - # The owners before should include both Alice and Bob. - assert len(pm_alpha.transactions.retrieve(fulfilled_transfer_tx["id"])["inputs"][0]["owners_before"]) == 2 - - # While the new owner is Carol. - assert ( - pm_alpha.transactions.retrieve(fulfilled_transfer_tx["id"])["outputs"][0]["public_keys"][0] == carol.public_key - ) diff --git a/integration/python/src/test_naughty_strings.py b/integration/python/src/test_naughty_strings.py deleted file mode 100644 index 20f89e3..0000000 --- a/integration/python/src/test_naughty_strings.py +++ /dev/null @@ -1,129 +0,0 @@ -# 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 - -# ## Testing potentially hazardous strings -# This test uses a library of `naughty` strings (code injections, weird unicode chars., etc.) as both keys and values. -# We look for either a successful tx, or in the case that we use a naughty string as a key, and it violates some key -# constraints, we expect to receive a well formatted error message. - -# ## Imports -# Since the naughty strings get encoded and decoded in odd ways, -# we'll use a regex to sweep those details under the rug. -import re - -# We'll use a nice library of naughty strings... -from blns import blns - -# And parameterize our test so each one is treated as a separate test case -import pytest - -# For this test case we import and use the Python Driver. -from planetmint_driver.crypto import generate_keypair -from planetmint_driver.exceptions import BadRequest - -# import helper to manage multiple nodes -from .helper.hosts import Hosts - -naughty_strings = blns.all() -skipped_naughty_strings = [ - "1.00", - "$1.00", - "-1.00", - "-$1.00", - "0.00", - "0..0", - ".", - "0.0.0", - "-.", - ",./;'[]\\-=", - "ثم نفس سقطت وبالتحديد،, جزيرتي باستخدام أن دنو. إذ هنا؟ الستار وتنصيب كان. أهّل ايطاليا، بريطانيا-فرنسا قد أخذ. سليمان، إتفاقية بين ما, يذكر الحدود أي بعد, معاملة بولندا، الإطلاق عل إيو.", - "test\x00", - "Ṱ̺̺̕o͞ ̷i̲̬͇̪͙n̝̗͕v̟̜̘̦͟o̶̙̰̠kè͚̮̺̪̹̱̤ ̖t̝͕̳̣̻̪͞h̼͓̲̦̳̘̲e͇̣̰̦̬͎ ̢̼̻̱̘h͚͎͙̜̣̲ͅi̦̲̣̰̤v̻͍e̺̭̳̪̰-m̢iͅn̖̺̞̲̯̰d̵̼̟͙̩̼̘̳ ̞̥̱̳̭r̛̗̘e͙p͠r̼̞̻̭̗e̺̠̣͟s̘͇̳͍̝͉e͉̥̯̞̲͚̬͜ǹ̬͎͎̟̖͇̤t͍̬̤͓̼̭͘ͅi̪̱n͠g̴͉ ͏͉ͅc̬̟h͡a̫̻̯͘o̫̟̖͍̙̝͉s̗̦̲.̨̹͈̣", - "̡͓̞ͅI̗̘̦͝n͇͇͙v̮̫ok̲̫̙͈i̖͙̭̹̠̞n̡̻̮̣̺g̲͈͙̭͙̬͎ ̰t͔̦h̞̲e̢̤ ͍̬̲͖f̴̘͕̣è͖ẹ̥̩l͖͔͚i͓͚̦͠n͖͍̗͓̳̮g͍ ̨o͚̪͡f̘̣̬ ̖̘͖̟͙̮c҉͔̫͖͓͇͖ͅh̵̤̣͚͔á̗̼͕ͅo̼̣̥s̱͈̺̖̦̻͢.̛̖̞̠̫̰", - "̗̺͖̹̯͓Ṯ̤͍̥͇͈h̲́e͏͓̼̗̙̼̣͔ ͇̜̱̠͓͍ͅN͕͠e̗̱z̘̝̜̺͙p̤̺̹͍̯͚e̠̻̠͜r̨̤͍̺̖͔̖̖d̠̟̭̬̝͟i̦͖̩͓͔̤a̠̗̬͉̙n͚͜ ̻̞̰͚ͅh̵͉i̳̞v̢͇ḙ͎͟-҉̭̩̼͔m̤̭̫i͕͇̝̦n̗͙ḍ̟ ̯̲͕͞ǫ̟̯̰̲͙̻̝f ̪̰̰̗̖̭̘͘c̦͍̲̞͍̩̙ḥ͚a̮͎̟̙͜ơ̩̹͎s̤.̝̝ ҉Z̡̖̜͖̰̣͉̜a͖̰͙̬͡l̲̫̳͍̩g̡̟̼̱͚̞̬ͅo̗͜.̟", - "̦H̬̤̗̤͝e͜ ̜̥̝̻͍̟́w̕h̖̯͓o̝͙̖͎̱̮ ҉̺̙̞̟͈W̷̼̭a̺̪͍į͈͕̭͙̯̜t̶̼̮s̘͙͖̕ ̠̫̠B̻͍͙͉̳ͅe̵h̵̬͇̫͙i̹͓̳̳̮͎̫̕n͟d̴̪̜̖ ̰͉̩͇͙̲͞ͅT͖̼͓̪͢h͏͓̮̻e̬̝̟ͅ ̤̹̝W͙̞̝͔͇͝ͅa͏͓͔̹̼̣l̴͔̰̤̟͔ḽ̫.͕", - '">', - "'>", - ">", - "", - "< / script >< script >alert(document.title)< / script >", - " onfocus=alert(document.title) autofocus ", - '" onfocus=alert(document.title) autofocus ', - "' onfocus=alert(document.title) autofocus ", - "<script>alert(document.title)</script>", - "/dev/null; touch /tmp/blns.fail ; echo", - "../../../../../../../../../../../etc/passwd%00", - "../../../../../../../../../../../etc/hosts", - "() { 0; }; touch /tmp/blns.shellshock1.fail;", - "() { _; } >_[$($())] { touch /tmp/blns.shellshock2.fail; }", -] - -naughty_strings = [naughty for naughty in naughty_strings if naughty not in skipped_naughty_strings] - - -# This is our base test case, but we'll reuse it to send naughty strings as both keys and values. -def send_naughty_tx(assets, metadata): - # ## Set up a connection to Planetmint - # Check [test_basic.py](./test_basic.html) to get some more details - # about the endpoint. - hosts = Hosts("/shared/hostnames") - pm = hosts.get_connection() - - # Here's Alice. - alice = generate_keypair() - - # Alice is in a naughty mood today, so she creates a tx with some naughty strings - prepared_transaction = pm.transactions.prepare( - operation="CREATE", signers=alice.public_key, assets=assets, metadata=metadata - ) - - # She fulfills the transaction - fulfilled_transaction = pm.transactions.fulfill(prepared_transaction, private_keys=alice.private_key) - - # The fulfilled tx gets sent to the pm network - try: - sent_transaction = pm.transactions.send_commit(fulfilled_transaction) - except BadRequest as e: - sent_transaction = e - - # If her key contained a '.', began with a '$', or contained a NUL character - regex = r".*\..*|\$.*|.*\x00.*" - key = next(iter(metadata)) - if re.match(regex, key): - # Then she expects a nicely formatted error code - status_code = sent_transaction.status_code - error = sent_transaction.error - regex = ( - r"\{\s*\n*" - r'\s*"message":\s*"Invalid transaction \(ValidationError\):\s*' - r"Invalid key name.*The key name cannot contain characters.*\n*" - r'\s*"status":\s*400\n*' - r"\s*\}\n*" - ) - assert status_code == 400 - assert re.fullmatch(regex, error), sent_transaction - # Otherwise, she expects to see her transaction in the database - elif "id" in sent_transaction.keys(): - tx_id = sent_transaction["id"] - assert pm.transactions.retrieve(tx_id) - # If neither condition was true, then something weird happened... - else: - raise TypeError(sent_transaction) - - -@pytest.mark.parametrize("naughty_string", naughty_strings, ids=naughty_strings) -def test_naughty_keys(naughty_string): - assets = [{"data": {naughty_string: "nice_value"}}] - metadata = {naughty_string: "nice_value"} - - send_naughty_tx(assets, metadata) - - -@pytest.mark.parametrize("naughty_string", naughty_strings, ids=naughty_strings) -def test_naughty_values(naughty_string): - assets = [{"data": {"nice_key": naughty_string}}] - metadata = {"nice_key": naughty_string} - - send_naughty_tx(assets, metadata) diff --git a/integration/python/src/test_stream.py b/integration/python/src/test_stream.py deleted file mode 100644 index 15e1970..0000000 --- a/integration/python/src/test_stream.py +++ /dev/null @@ -1,131 +0,0 @@ -# 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 - -# # Stream Acceptance Test -# This test checks if the event stream works correctly. The basic idea of this -# test is to generate some random **valid** transaction, send them to a -# Planetmint node, and expect those transactions to be returned by the valid -# transactions Stream API. During this test, two threads work together, -# sharing a queue to exchange events. -# -# - The *main thread* first creates and sends the transactions to Planetmint; -# then it run through all events in the shared queue to check if all -# transactions sent have been validated by Planetmint. -# - The *listen thread* listens to the events coming from Planetmint and puts -# them in a queue shared with the main thread. -import queue -import json -from threading import Thread, Event -from uuid import uuid4 - -# For this script, we need to set up a websocket connection, that's the reason -# we import the -# [websocket](https://github.com/websocket-client/websocket-client) module -from websocket import create_connection - -from planetmint_driver.crypto import generate_keypair - -# import helper to manage multiple nodes -from .helper.hosts import Hosts - - -def test_stream(): - # ## Set up the test - # We use the env variable `BICHAINDB_ENDPOINT` to know where to connect. - # Check [test_basic.py](./test_basic.html) for more information. - hosts = Hosts("/shared/hostnames") - pm = hosts.get_connection() - - # *That's pretty bad, but let's do like this for now.* - WS_ENDPOINT = "ws://{}:9985/api/v1/streams/valid_transactions".format(hosts.hostnames[0]) - - # Hello to Alice again, she is pretty active in those tests, good job - # Alice! - alice = generate_keypair() - - # We need few variables to keep the state, specifically we need `sent` to - # keep track of all transactions Alice sent to Planetmint, while `received` - # are the transactions Planetmint validated and sent back to her. - sent = [] - received = queue.Queue() - - # In this test we use a websocket. The websocket must be started **before** - # sending transactions to Planetmint, otherwise we might lose some - # transactions. The `ws_ready` event is used to synchronize the main thread - # with the listen thread. - ws_ready = Event() - - # ## Listening to events - # This is the function run by the complementary thread. - def listen(): - # First we connect to the remote endpoint using the WebSocket protocol. - ws = create_connection(WS_ENDPOINT) - - # After the connection has been set up, we can signal the main thread - # to proceed (continue reading, it should make sense in a second.) - ws_ready.set() - - # It's time to consume all events coming from the Planetmint stream API. - # Every time a new event is received, it is put in the queue shared - # with the main thread. - while True: - result = ws.recv() - received.put(result) - - # Put `listen` in a thread, and start it. Note that `listen` is a local - # function and it can access all variables in the enclosing function. - t = Thread(target=listen, daemon=True) - t.start() - - # ## Pushing the transactions to Planetmint - # After starting the listen thread, we wait for it to connect, and then we - # proceed. - ws_ready.wait() - - # Here we prepare, sign, and send ten different `CREATE` transactions. To - # make sure each transaction is different from the other, we generate a - # random `uuid`. - for _ in range(10): - tx = pm.transactions.fulfill( - pm.transactions.prepare( - operation="CREATE", signers=alice.public_key, assets=[{"data": {"uuid": str(uuid4())}}] - ), - private_keys=alice.private_key, - ) - # We don't want to wait for each transaction to be in a block. By using - # `async` mode, we make sure that the driver returns as soon as the - # transaction is pushed to the Planetmint API. Remember: we expect all - # transactions to be in the shared queue: this is a two phase test, - # first we send a bunch of transactions, then we check if they are - # valid (and, in this case, they should). - pm.transactions.send_async(tx) - - # The `id` of every sent transaction is then stored in a list. - sent.append(tx["id"]) - - # ## Check the valid transactions coming from Planetmint - # Now we are ready to check if Planetmint did its job. A simple way to - # check if all sent transactions have been processed is to **remove** from - # `sent` the transactions we get from the *listen thread*. At one point in - # time, `sent` should be empty, and we exit the test. - while sent: - # To avoid waiting forever, we have an arbitrary timeout of 5 - # seconds: it should be enough time for Planetmint to create - # blocks, in fact a new block is created every second. If we hit - # the timeout, then game over ¯\\\_(ツ)\_/¯ - try: - event = received.get(timeout=5) - txid = json.loads(event)["transaction_id"] - except queue.Empty: - assert False, "Did not receive all expected transactions" - - # Last thing is to try to remove the `txid` from the set of sent - # transactions. If this test is running in parallel with others, we - # might get a transaction id of another test, and `remove` can fail. - # It's OK if this happens. - try: - sent.remove(txid) - except ValueError: - pass diff --git a/integration/python/src/test_threshold.py b/integration/python/src/test_threshold.py deleted file mode 100644 index 9e9a843..0000000 --- a/integration/python/src/test_threshold.py +++ /dev/null @@ -1,319 +0,0 @@ -# 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 - -# ## Imports -import time -import json - -# For this test case we need the planetmint_driver.crypto package -import base58 -import sha3 -from planetmint_cryptoconditions import Ed25519Sha256, ThresholdSha256 -from planetmint_driver.crypto import generate_keypair - -# Import helper to deal with multiple nodes -from .helper.hosts import Hosts - - -def prepare_condition_details(condition: ThresholdSha256): - condition_details = {"subconditions": [], "threshold": condition.threshold, "type": condition.TYPE_NAME} - - for s in condition.subconditions: - if s["type"] == "fulfillment" and s["body"].TYPE_NAME == "ed25519-sha-256": - condition_details["subconditions"].append( - {"type": s["body"].TYPE_NAME, "public_key": base58.b58encode(s["body"].public_key).decode()} - ) - else: - condition_details["subconditions"].append(prepare_condition_details(s["body"])) - - return condition_details - - -def test_threshold(): - # Setup connection to test nodes - hosts = Hosts("/shared/hostnames") - pm = hosts.get_connection() - - # Generate Keypars for Alice, Bob an Carol! - alice, bob, carol = generate_keypair(), generate_keypair(), generate_keypair() - - # ## Alice and Bob create a transaction - # Alice and Bob just moved into a shared flat, no one can afford these - # high rents anymore. Bob suggests to get a dish washer for the - # kitchen. Alice agrees and here they go, creating the asset for their - # dish washer. - dw_asset = [{"data": {"dish washer": {"serial_number": 1337}}}] - - # Create subfulfillments - alice_ed25519 = Ed25519Sha256(public_key=base58.b58decode(alice.public_key)) - bob_ed25519 = Ed25519Sha256(public_key=base58.b58decode(bob.public_key)) - carol_ed25519 = Ed25519Sha256(public_key=base58.b58decode(carol.public_key)) - - # Create threshold condition (2/3) and add subfulfillments - threshold_sha256 = ThresholdSha256(2) - threshold_sha256.add_subfulfillment(alice_ed25519) - threshold_sha256.add_subfulfillment(bob_ed25519) - threshold_sha256.add_subfulfillment(carol_ed25519) - - # Create a condition uri and details for the output object - condition_uri = threshold_sha256.condition.serialize_uri() - condition_details = prepare_condition_details(threshold_sha256) - - # Assemble output and input for the handcrafted tx - output = { - "amount": "1", - "condition": { - "details": condition_details, - "uri": condition_uri, - }, - "public_keys": (alice.public_key, bob.public_key, carol.public_key), - } - - # The yet to be fulfilled input: - input_ = { - "fulfillment": None, - "fulfills": None, - "owners_before": (alice.public_key, bob.public_key), - } - - # Assemble the handcrafted transaction - handcrafted_dw_tx = { - "operation": "CREATE", - "asset": dw_asset, - "metadata": None, - "outputs": (output,), - "inputs": (input_,), - "version": "2.0", - "id": None, - } - - # Create sha3-256 of message to sign - message = json.dumps( - handcrafted_dw_tx, - sort_keys=True, - separators=(",", ":"), - ensure_ascii=False, - ) - message = sha3.sha3_256(message.encode()) - - # Sign message with Alice's und Bob's private key - alice_ed25519.sign(message.digest(), base58.b58decode(alice.private_key)) - bob_ed25519.sign(message.digest(), base58.b58decode(bob.private_key)) - - # Create fulfillment and add uri to inputs - fulfillment_threshold = ThresholdSha256(2) - fulfillment_threshold.add_subfulfillment(alice_ed25519) - fulfillment_threshold.add_subfulfillment(bob_ed25519) - fulfillment_threshold.add_subcondition(carol_ed25519.condition) - - fulfillment_uri = fulfillment_threshold.serialize_uri() - - handcrafted_dw_tx["inputs"][0]["fulfillment"] = fulfillment_uri - - # Create tx_id for handcrafted_dw_tx and send tx commit - json_str_tx = json.dumps( - handcrafted_dw_tx, - sort_keys=True, - separators=(",", ":"), - ensure_ascii=False, - ) - - dw_creation_txid = sha3.sha3_256(json_str_tx.encode()).hexdigest() - - handcrafted_dw_tx["id"] = dw_creation_txid - - pm.transactions.send_commit(handcrafted_dw_tx) - - time.sleep(1) - - # Assert that the tx is propagated to all nodes - hosts.assert_transaction(dw_creation_txid) - - -def test_weighted_threshold(): - hosts = Hosts("/shared/hostnames") - pm = hosts.get_connection() - - alice, bob, carol = generate_keypair(), generate_keypair(), generate_keypair() - - assets = [{"data": {"trashcan": {"animals": ["racoon_1", "racoon_2"]}}}] - - alice_ed25519 = Ed25519Sha256(public_key=base58.b58decode(alice.public_key)) - bob_ed25519 = Ed25519Sha256(public_key=base58.b58decode(bob.public_key)) - carol_ed25519 = Ed25519Sha256(public_key=base58.b58decode(carol.public_key)) - - threshold = ThresholdSha256(1) - threshold.add_subfulfillment(alice_ed25519) - - sub_threshold = ThresholdSha256(2) - sub_threshold.add_subfulfillment(bob_ed25519) - sub_threshold.add_subfulfillment(carol_ed25519) - - threshold.add_subfulfillment(sub_threshold) - - condition_uri = threshold.condition.serialize_uri() - condition_details = prepare_condition_details(threshold) - - # Assemble output and input for the handcrafted tx - output = { - "amount": "1", - "condition": { - "details": condition_details, - "uri": condition_uri, - }, - "public_keys": (alice.public_key, bob.public_key, carol.public_key), - } - - # The yet to be fulfilled input: - input_ = { - "fulfillment": None, - "fulfills": None, - "owners_before": (alice.public_key, bob.public_key), - } - - # Assemble the handcrafted transaction - handcrafted_tx = { - "operation": "CREATE", - "asset": assets, - "metadata": None, - "outputs": (output,), - "inputs": (input_,), - "version": "2.0", - "id": None, - } - - # Create sha3-256 of message to sign - message = json.dumps( - handcrafted_tx, - sort_keys=True, - separators=(",", ":"), - ensure_ascii=False, - ) - message = sha3.sha3_256(message.encode()) - - # Sign message with Alice's und Bob's private key - alice_ed25519.sign(message.digest(), base58.b58decode(alice.private_key)) - - # Create fulfillment and add uri to inputs - sub_fulfillment_threshold = ThresholdSha256(2) - sub_fulfillment_threshold.add_subcondition(bob_ed25519.condition) - sub_fulfillment_threshold.add_subcondition(carol_ed25519.condition) - - fulfillment_threshold = ThresholdSha256(1) - fulfillment_threshold.add_subfulfillment(alice_ed25519) - fulfillment_threshold.add_subfulfillment(sub_fulfillment_threshold) - - fulfillment_uri = fulfillment_threshold.serialize_uri() - - handcrafted_tx["inputs"][0]["fulfillment"] = fulfillment_uri - - # Create tx_id for handcrafted_dw_tx and send tx commit - json_str_tx = json.dumps( - handcrafted_tx, - sort_keys=True, - separators=(",", ":"), - ensure_ascii=False, - ) - - creation_tx_id = sha3.sha3_256(json_str_tx.encode()).hexdigest() - - handcrafted_tx["id"] = creation_tx_id - - pm.transactions.send_commit(handcrafted_tx) - - time.sleep(1) - - # Assert that the tx is propagated to all nodes - hosts.assert_transaction(creation_tx_id) - - # Now transfer created asset - alice_transfer_ed25519 = Ed25519Sha256(public_key=base58.b58decode(alice.public_key)) - bob_transfer_ed25519 = Ed25519Sha256(public_key=base58.b58decode(bob.public_key)) - carol_transfer_ed25519 = Ed25519Sha256(public_key=base58.b58decode(carol.public_key)) - - transfer_condition_uri = alice_transfer_ed25519.condition.serialize_uri() - - # Assemble output and input for the handcrafted tx - transfer_output = { - "amount": "1", - "condition": { - "details": { - "type": alice_transfer_ed25519.TYPE_NAME, - "public_key": base58.b58encode(alice_transfer_ed25519.public_key).decode(), - }, - "uri": transfer_condition_uri, - }, - "public_keys": (alice.public_key,), - } - - # The yet to be fulfilled input: - transfer_input_ = { - "fulfillment": None, - "fulfills": {"transaction_id": creation_tx_id, "output_index": 0}, - "owners_before": (alice.public_key, bob.public_key, carol.public_key), - } - - # Assemble the handcrafted transaction - handcrafted_transfer_tx = { - "operation": "TRANSFER", - "assets": [{"id": creation_tx_id}], - "metadata": None, - "outputs": (transfer_output,), - "inputs": (transfer_input_,), - "version": "2.0", - "id": None, - } - - # Create sha3-256 of message to sign - message = json.dumps( - handcrafted_transfer_tx, - sort_keys=True, - separators=(",", ":"), - ensure_ascii=False, - ) - message = sha3.sha3_256(message.encode()) - - message.update( - "{}{}".format( - handcrafted_transfer_tx["inputs"][0]["fulfills"]["transaction_id"], - handcrafted_transfer_tx["inputs"][0]["fulfills"]["output_index"], - ).encode() - ) - - # Sign message with Alice's und Bob's private key - bob_transfer_ed25519.sign(message.digest(), base58.b58decode(bob.private_key)) - carol_transfer_ed25519.sign(message.digest(), base58.b58decode(carol.private_key)) - - sub_fulfillment_threshold = ThresholdSha256(2) - sub_fulfillment_threshold.add_subfulfillment(bob_transfer_ed25519) - sub_fulfillment_threshold.add_subfulfillment(carol_transfer_ed25519) - - # Create fulfillment and add uri to inputs - fulfillment_threshold = ThresholdSha256(1) - fulfillment_threshold.add_subcondition(alice_transfer_ed25519.condition) - fulfillment_threshold.add_subfulfillment(sub_fulfillment_threshold) - - fulfillment_uri = fulfillment_threshold.serialize_uri() - - handcrafted_transfer_tx["inputs"][0]["fulfillment"] = fulfillment_uri - - # Create tx_id for handcrafted_dw_tx and send tx commit - json_str_tx = json.dumps( - handcrafted_transfer_tx, - sort_keys=True, - separators=(",", ":"), - ensure_ascii=False, - ) - - transfer_tx_id = sha3.sha3_256(json_str_tx.encode()).hexdigest() - - handcrafted_transfer_tx["id"] = transfer_tx_id - - pm.transactions.send_commit(handcrafted_transfer_tx) - - time.sleep(1) - - # Assert that the tx is propagated to all nodes - hosts.assert_transaction(transfer_tx_id) diff --git a/integration/python/src/test_zenroom.py b/integration/python/src/test_zenroom.py deleted file mode 100644 index cc0f6b3..0000000 --- a/integration/python/src/test_zenroom.py +++ /dev/null @@ -1,130 +0,0 @@ -import json -import base58 -from hashlib import sha3_256 -from planetmint_cryptoconditions.types.zenroom import ZenroomSha256 -from planetmint_driver.crypto import generate_keypair -from .helper.hosts import Hosts -from zenroom import zencode_exec -import time - - -def test_zenroom_signing( - gen_key_zencode, - secret_key_to_private_key_zencode, - fulfill_script_zencode, - zenroom_data, - zenroom_house_assets, - zenroom_script_input, - condition_script_zencode, -): - biolabs = generate_keypair() - version = "2.0" - - alice = json.loads(zencode_exec(gen_key_zencode).output)["keyring"] - bob = json.loads(zencode_exec(gen_key_zencode).output)["keyring"] - - zen_public_keys = json.loads( - zencode_exec(secret_key_to_private_key_zencode.format("Alice"), keys=json.dumps({"keyring": alice})).output - ) - zen_public_keys.update( - json.loads( - zencode_exec(secret_key_to_private_key_zencode.format("Bob"), keys=json.dumps({"keyring": bob})).output - ) - ) - - zenroomscpt = ZenroomSha256(script=fulfill_script_zencode, data=zenroom_data, keys=zen_public_keys) - print(f"zenroom is: {zenroomscpt.script}") - - # CRYPTO-CONDITIONS: generate the condition uri - condition_uri_zen = zenroomscpt.condition.serialize_uri() - print(f"\nzenroom condition URI: {condition_uri_zen}") - - # CRYPTO-CONDITIONS: construct an unsigned fulfillment dictionary - unsigned_fulfillment_dict_zen = { - "type": zenroomscpt.TYPE_NAME, - "public_key": base58.b58encode(biolabs.public_key).decode(), - } - output = { - "amount": "10", - "condition": { - "details": unsigned_fulfillment_dict_zen, - "uri": condition_uri_zen, - }, - "public_keys": [ - biolabs.public_key, - ], - } - input_ = { - "fulfillment": None, - "fulfills": None, - "owners_before": [ - biolabs.public_key, - ], - } - metadata = {"result": {"output": ["ok"]}} - - script_ = { - "code": {"type": "zenroom", "raw": "test_string", "parameters": [{"obj": "1"}, {"obj": "2"}]}, - "state": "dd8bbd234f9869cab4cc0b84aa660e9b5ef0664559b8375804ee8dce75b10576", - "input": zenroom_script_input, - "output": ["ok"], - "policies": {}, - } - metadata = {"result": {"output": ["ok"]}} - token_creation_tx = { - "operation": "CREATE", - "asset": {"data": {"test": "my asset"}}, - "script": script_, - "metadata": metadata, - "outputs": [ - output, - ], - "inputs": [ - input_, - ], - "version": version, - "id": None, - } - - # JSON: serialize the transaction-without-id to a json formatted string - tx = json.dumps( - token_creation_tx, - sort_keys=True, - separators=(",", ":"), - ensure_ascii=False, - ) - script_ = json.dumps(script_) - # major workflow: - # we store the fulfill script in the transaction/message (zenroom-sha) - # the condition script is used to fulfill the transaction and create the signature - # - # the server should ick the fulfill script and recreate the zenroom-sha and verify the signature - - signed_input = zenroomscpt.sign(script_, condition_script_zencode, alice) - - input_signed = json.loads(signed_input) - input_signed["input"]["signature"] = input_signed["output"]["signature"] - del input_signed["output"]["signature"] - del input_signed["output"]["logs"] - input_signed["output"] = ["ok"] # define expected output that is to be compared - input_msg = json.dumps(input_signed) - - assert zenroomscpt.validate(message=input_msg) - - tx = json.loads(tx) - fulfillment_uri_zen = zenroomscpt.serialize_uri() - - tx["inputs"][0]["fulfillment"] = fulfillment_uri_zen - tx["script"] = input_signed - tx["id"] = None - json_str_tx = json.dumps(tx, sort_keys=True, skipkeys=False, separators=(",", ":")) - # SHA3: hash the serialized id-less transaction to generate the id - shared_creation_txid = sha3_256(json_str_tx.encode()).hexdigest() - tx["id"] = shared_creation_txid - hosts = Hosts("/shared/hostnames") - pm_alpha = hosts.get_connection() - sent_transfer_tx = pm_alpha.transactions.send_commit(tx) - time.sleep(1) - # Assert that transaction is stored on both planetmint nodes - hosts.assert_transaction(shared_creation_txid) - print(f"\n\nstatus and result : + {sent_transfer_tx}") diff --git a/integration/scripts/all-in-one.bash b/integration/scripts/all-in-one.bash deleted file mode 100755 index f60a581..0000000 --- a/integration/scripts/all-in-one.bash +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash -# 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 - -# Planetmint configuration -/usr/src/app/scripts/planetmint-monit-config - -# Tarantool startup and configuration -tarantool /usr/src/app/scripts/init.lua - -# Start services -monit -d 5 -I -B \ No newline at end of file diff --git a/integration/scripts/clean-shared.sh b/integration/scripts/clean-shared.sh deleted file mode 100755 index 7ba481e..0000000 --- a/integration/scripts/clean-shared.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh -# 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 - -rm /shared/hostnames -rm /shared/lock -rm /shared/*node_id -rm /shared/*.json -rm /shared/id_rsa.pub \ No newline at end of file diff --git a/integration/scripts/election.sh b/integration/scripts/election.sh deleted file mode 100755 index 65d39cb..0000000 --- a/integration/scripts/election.sh +++ /dev/null @@ -1,81 +0,0 @@ -#!/bin/bash -# 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 - -# Show tendermint node id -show_id () { - tendermint --home=/tendermint show_node_id | tail -n 1 -} - -# Show validator public key -show_validator () { - tendermint --home=/tendermint show_validator | tail -n 1 -} - -# Elect new voting power for node -elect_validator () { - planetmint election new upsert-validator $1 $2 $3 --private-key /tendermint/config/priv_validator_key.json 2>&1 -} - -# Propose new chain migration -propose_migration () { - planetmint election new chain-migration --private-key /tendermint/config/priv_validator_key.json 2>&1 -} - -# Show election state -show_election () { - planetmint election show $1 2>&1 -} - -# Approve election -approve_validator () { - planetmint election approve $1 --private-key /tendermint/config/priv_validator_key.json -} - -# Fetch tendermint id and pubkey and create upsert proposal -elect () { - node_id=$(show_id) - validator_pubkey=$(show_validator | jq -r .value) - proposal=$(elect_validator $validator_pubkey $1 $node_id | grep SUCCESS) - echo ${proposal##* } -} - -# Create chain migration proposal and return election id -migrate () { - proposal=$(propose_migration | grep SUCCESS) - echo ${proposal##* } -} - -usage () { - echo "usage: TODO" -} - -while [ "$1" != "" ]; do - case $1 in - show_id ) show_id - ;; - show_validator ) show_validator - ;; - elect ) shift - elect $1 - ;; - migrate ) shift - migrate - ;; - show_election ) shift - show_election $1 - ;; - approve ) shift - approve_validator $1 - ;; - * ) usage - exit 1 - esac - shift -done - -exitcode=$? - -exit $exitcode \ No newline at end of file diff --git a/integration/scripts/genesis.py b/integration/scripts/genesis.py deleted file mode 100755 index 8f21446..0000000 --- a/integration/scripts/genesis.py +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env python3 -# 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 sys - - -def edit_genesis() -> None: - file_names = sys.argv[1:] - - validators = [] - for file_name in file_names: - file = open(file_name) - genesis = json.load(file) - validators.extend(genesis["validators"]) - file.close() - - genesis_file = open(file_names[0]) - genesis_json = json.load(genesis_file) - genesis_json["validators"] = validators - genesis_file.close() - - with open("/shared/genesis.json", "w") as f: - json.dump(genesis_json, f, indent=True) - - return None - - -if __name__ == "__main__": - edit_genesis() diff --git a/integration/scripts/init.lua b/integration/scripts/init.lua deleted file mode 100644 index 87fba97..0000000 --- a/integration/scripts/init.lua +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/env tarantool -box.cfg { - listen = 3303, - background = true, - log = '.planetmint-monit/logs/tarantool.log', - pid_file = '.planetmint-monit/monit_processes/tarantool.pid' -} - -box.schema.user.grant('guest','read,write,execute,create,drop','universe') - -function indexed_pattern_search(space_name, field_no, pattern) - if (box.space[space_name] == nil) then - print("Error: Failed to find the specified space") - return nil - end - local index_no = -1 - for i=0,box.schema.INDEX_MAX,1 do - if (box.space[space_name].index[i] == nil) then break end - if (box.space[space_name].index[i].type == "TREE" - and box.space[space_name].index[i].parts[1].fieldno == field_no - and (box.space[space_name].index[i].parts[1].type == "scalar" - or box.space[space_name].index[i].parts[1].type == "string")) then - index_no = i - break - end - end - if (index_no == -1) then - print("Error: Failed to find an appropriate index") - return nil - end - local index_search_key = "" - local index_search_key_length = 0 - local last_character = "" - local c = "" - local c2 = "" - for i=1,string.len(pattern),1 do - c = string.sub(pattern, i, i) - if (last_character ~= "%") then - if (c == '^' or c == "$" or c == "(" or c == ")" or c == "." - or c == "[" or c == "]" or c == "*" or c == "+" - or c == "-" or c == "?") then - break - end - if (c == "%") then - c2 = string.sub(pattern, i + 1, i + 1) - if (string.match(c2, "%p") == nil) then break end - index_search_key = index_search_key .. c2 - else - index_search_key = index_search_key .. c - end - end - last_character = c - end - index_search_key_length = string.len(index_search_key) - local result_set = {} - local number_of_tuples_in_result_set = 0 - local previous_tuple_field = "" - while true do - local number_of_tuples_since_last_yield = 0 - local is_time_for_a_yield = false - for _,tuple in box.space[space_name].index[index_no]: - pairs(index_search_key,{iterator = box.index.GE}) do - if (string.sub(tuple[field_no], 1, index_search_key_length) - > index_search_key) then - break - end - number_of_tuples_since_last_yield = number_of_tuples_since_last_yield + 1 - if (number_of_tuples_since_last_yield >= 10 - and tuple[field_no] ~= previous_tuple_field) then - index_search_key = tuple[field_no] - is_time_for_a_yield = true - break - end - previous_tuple_field = tuple[field_no] - if (string.match(tuple[field_no], pattern) ~= nil) then - number_of_tuples_in_result_set = number_of_tuples_in_result_set + 1 - result_set[number_of_tuples_in_result_set] = tuple - end - end - if (is_time_for_a_yield ~= true) then - break - end - require('fiber').yield() - end - return result_set -end \ No newline at end of file diff --git a/integration/scripts/planetmint-monit-config b/integration/scripts/planetmint-monit-config deleted file mode 100755 index 82af9af..0000000 --- a/integration/scripts/planetmint-monit-config +++ /dev/null @@ -1,208 +0,0 @@ -#!/bin/bash -# 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 - -set -o nounset - -# Check if directory for monit logs exists -if [ ! -d "$HOME/.planetmint-monit" ]; then - mkdir -p "$HOME/.planetmint-monit" -fi - -monit_pid_path=${MONIT_PID_PATH:=$HOME/.planetmint-monit/monit_processes} -monit_script_path=${MONIT_SCRIPT_PATH:=$HOME/.planetmint-monit/monit_script} -monit_log_path=${MONIT_LOG_PATH:=$HOME/.planetmint-monit/logs} -monitrc_path=${MONITRC_PATH:=$HOME/.monitrc} - -function usage() { - cat <${monit_script_path} < /dev/null 2>&1 & - - echo \$! > \$2 - popd - - ;; - - stop_planetmint) - - kill -2 \`cat \$2\` - rm -f \$2 - - ;; - - start_tendermint) - - pushd \$4 - - nohup tendermint node \ - --p2p.laddr "tcp://0.0.0.0:26656" \ - --rpc.laddr "tcp://0.0.0.0:26657" \ - --proxy_app="tcp://0.0.0.0:26658" \ - --consensus.create_empty_blocks=false \ - --p2p.pex=false >> \$3/tendermint.out.log 2>> \$3/tendermint.err.log & - - echo \$! > \$2 - popd - - ;; - - stop_tendermint) - - kill -2 \`cat \$2\` - rm -f \$2 - - ;; - -esac -exit 0 -EOF -chmod +x ${monit_script_path} - -cat >${monit_script_path}_logrotate <${monitrc_path} < 200 MB then - exec "${monit_script_path}_logrotate rotate_tendermint_logs ${monit_log_path}/tendermint.out.log $monit_pid_path/tendermint.pid" - -check file tendermint.err.log with path ${monit_log_path}/tendermint.err.log - if size > 200 MB then - exec "${monit_script_path}_logrotate rotate_tendermint_logs ${monit_log_path}/tendermint.err.log $monit_pid_path/tendermint.pid" - -EOF - -# Setting permissions for control file -chmod 0700 ${monitrc_path} - -echo -e "Planetmint process manager configured!" -set -o errexit diff --git a/integration/scripts/pre-config-planetmint.sh b/integration/scripts/pre-config-planetmint.sh deleted file mode 100755 index ea15ea7..0000000 --- a/integration/scripts/pre-config-planetmint.sh +++ /dev/null @@ -1,83 +0,0 @@ -#!/bin/bash -# 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 - -# Write hostname to list -echo $(hostname) >> /shared/hostnames - -# Create ssh folder -mkdir ~/.ssh - -# Wait for test container pubkey -while [ ! -f /shared/id_rsa.pub ]; do - echo "WAIT FOR PUBKEY" - sleep 1 -done - -# Add pubkey to authorized keys -cat /shared/id_rsa.pub > ~/.ssh/authorized_keys - -# Allow root user login -sed -i "s/#PermitRootLogin prohibit-password/PermitRootLogin yes/" /etc/ssh/sshd_config - -# Restart ssh service -service ssh restart - -# Tendermint configuration -tendermint init - -# Write node id to shared folder -HOSTNAME=$(hostname) -NODE_ID=$(tendermint show_node_id | tail -n 1) -echo $NODE_ID > /shared/${HOSTNAME}_node_id - -# Wait for other node ids -FILES=() -while [ ! ${#FILES[@]} == $SCALE ]; do - echo "WAIT FOR NODE IDS" - sleep 1 - FILES=(/shared/*node_id) -done - -# Write node ids to persistent peers -PEERS="persistent_peers = \"" -for f in ${FILES[@]}; do - ID=$(cat $f) - HOST=$(echo $f | cut -c 9-20) - if [ ! $HOST == $HOSTNAME ]; then - PEERS+="${ID}@${HOST}:26656, " - fi -done -PEERS=$(echo $PEERS | rev | cut -c 2- | rev) -PEERS+="\"" -sed -i "/persistent_peers = \"\"/c\\${PEERS}" /tendermint/config/config.toml - -# Copy genesis.json to shared folder -cp /tendermint/config/genesis.json /shared/${HOSTNAME}_genesis.json - -# Await config file of all services to be present -FILES=() -while [ ! ${#FILES[@]} == $SCALE ]; do - echo "WAIT FOR GENESIS FILES" - sleep 1 - FILES=(/shared/*_genesis.json) -done - -# Create genesis.json for nodes -if [ ! -f /shared/lock ]; then - echo LOCKING - touch /shared/lock - /usr/src/app/scripts/genesis.py ${FILES[@]} -fi - -while [ ! -f /shared/genesis.json ]; do - echo "WAIT FOR GENESIS" - sleep 1 -done - -# Copy genesis.json to tendermint config -cp /shared/genesis.json /tendermint/config/genesis.json - -exec "$@" \ No newline at end of file diff --git a/integration/scripts/pre-config-test.sh b/integration/scripts/pre-config-test.sh deleted file mode 100755 index bd72913..0000000 --- a/integration/scripts/pre-config-test.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash -# 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 - -# Create ssh folder -mkdir ~/.ssh - -# Create ssh keys -ssh-keygen -q -t rsa -N '' -f ~/.ssh/id_rsa - -# Publish pubkey to shared folder -cp ~/.ssh/id_rsa.pub /shared - -exec "$@" \ No newline at end of file diff --git a/integration/scripts/test.sh b/integration/scripts/test.sh deleted file mode 100755 index 2d3b796..0000000 --- a/integration/scripts/test.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash -# 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 - -# Start CLI Tests - -# Test upsert new validator -/tests/upsert-new-validator.sh - -# Test chain migration -# TODO: implementation not finished -#/tests/chain-migration.sh - -# TODO: Implement test for voting edge cases or implicit in chain migration and upsert validator? - -exitcode=$? - -if [ $exitcode -ne 0 ]; then - exit $exitcode -fi - -exec "$@" \ No newline at end of file diff --git a/integration/scripts/wait-for-planetmint.sh b/integration/scripts/wait-for-planetmint.sh deleted file mode 100755 index 36c7794..0000000 --- a/integration/scripts/wait-for-planetmint.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash -# 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 - -# Only continue if all services are ready -HOSTNAMES=() -while [ ! ${#HOSTNAMES[@]} == $SCALE ]; do - echo "WAIT FOR HOSTNAMES" - sleep 1 - readarray -t HOSTNAMES < /shared/hostnames -done - -for host in ${HOSTNAMES[@]}; do - while [[ "$(curl -s -o /dev/null -w ''%{http_code}'' $host:9984)" != "200" ]]; do - echo "WAIT FOR PLANETMINT $host" - sleep 1 - done -done - -for host in ${HOSTNAMES[@]}; do - while [[ "$(curl -s -o /dev/null -w ''%{http_code}'' $host:26657)" != "200" ]]; do - echo "WAIT FOR TENDERMINT $host" - sleep 1 - done -done - -exec "$@" \ No newline at end of file diff --git a/scripts/run-integration-test.sh b/scripts/run-integration-test.sh deleted file mode 100755 index 1ec46d4..0000000 --- a/scripts/run-integration-test.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -# 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 - -run_test() { - docker-compose -f docker-compose.integration.yml up test -} - -teardown () { - docker-compose -f docker-compose.integration.yml down -} - -run_test -exitcode=$? -teardown - -exit $exitcode \ No newline at end of file