-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add testframework and version test as example
- Loading branch information
1 parent
41490bc
commit 11baed2
Showing
9 changed files
with
297 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
#!/usr/bin/env python3 | ||
# Copyright (c) 2021 The Dogecoin Core developers | ||
""" | ||
Test framework for end-to-end docker tests | ||
""" | ||
|
||
import subprocess | ||
import sys | ||
|
||
class DockerRunner: | ||
"""Run docker containers for testing""" | ||
|
||
def __init__(self, platform, image, verbose): | ||
"""Sets platform and image for all tests ran with this instance""" | ||
self.platform = platform | ||
self.image = image | ||
self.verbose = verbose | ||
|
||
def construct_docker_command(self, envs, args): | ||
""" | ||
Construct a docker command with env and args | ||
""" | ||
command = ["docker", "run", "--platform", self.platform] | ||
|
||
for env in envs: | ||
command.append("-e") | ||
command.append(env) | ||
|
||
command.append(self.image) | ||
|
||
for arg in args: | ||
command.append(arg) | ||
|
||
return command | ||
|
||
def run_interactive_command(self, envs, args): | ||
""" | ||
Run our target docker image with a list of | ||
environment variables and a list of arguments | ||
""" | ||
command = self.construct_docker_command(envs, args) | ||
|
||
if self.verbose: | ||
print(f"Running command: { ' '.join(command) }") | ||
|
||
try: | ||
output = subprocess.run(command, capture_output=True, check=True) | ||
except subprocess.CalledProcessError as docker_err: | ||
print(f"Error while running command: { ' '.join(command) }", file=sys.stderr) | ||
print(docker_err, file=sys.stderr) | ||
print(docker_err.stderr.decode("utf-8"), file=sys.stderr) | ||
print(docker_err.stdout.decode("utf-8"), file=sys.stdout) | ||
|
||
raise docker_err | ||
|
||
return output |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
#!/usr/bin/env python3 | ||
# Copyright (c) 2021 The Dogecoin Core developers | ||
""" | ||
Base class to define and run Dogecoin Core Docker tests with | ||
""" | ||
|
||
import argparse | ||
import sys | ||
|
||
from .docker_runner import DockerRunner | ||
|
||
class TestConfigurationError(Exception): | ||
"""Raised when the test is configured inconsistently""" | ||
|
||
class TestRunner: | ||
"""Base class to define and run Dogecoin Core Docker tests with""" | ||
def __init__(self): | ||
"""Make sure there is an options object""" | ||
self.options = {} | ||
|
||
def add_options(self, parser): | ||
"""Allow adding options in tests""" | ||
|
||
def run_test(self): | ||
"""Actual test, must be implemented by the final class""" | ||
raise NotImplementedError | ||
|
||
def run_command(self, envs, args): | ||
"""Run a docker command with env and args""" | ||
assert self.options.platform is not None | ||
assert self.options.image is not None | ||
|
||
runner = DockerRunner(self.options.platform, | ||
self.options.image, self.options.verbose) | ||
|
||
return runner.run_interactive_command(envs, args) | ||
|
||
def main(self): | ||
"""main loop""" | ||
parser = argparse.ArgumentParser() | ||
parser.add_argument("--platform", dest="platform", required=True, | ||
help="The platform to use for testing, eg: 'linux/amd64'") | ||
parser.add_argument("--image", dest="image", required=True, | ||
help="The image or tag to execute tests against, eg: 'verywowimage'") | ||
parser.add_argument("--verbose", dest="verbose", default=False, action="store_true", | ||
help="Verbosely output actions taken and print docker logs, regardless of outcome") | ||
|
||
self.add_options(parser) | ||
self.options = parser.parse_args() | ||
|
||
self.run_test() | ||
print("Tests successful") | ||
sys.exit(0) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
#!/usr/bin/env python3 | ||
# Copyright (c) 2021 The Dogecoin Core developers | ||
""" | ||
Test the version installed to be the expected version | ||
""" | ||
|
||
import re | ||
|
||
from .framework.test_runner import TestRunner | ||
|
||
class VersionTest(TestRunner): | ||
"""Versions test""" | ||
|
||
def __init__(self): | ||
"""Constructor""" | ||
TestRunner.__init__(self) | ||
self.version_expr = None | ||
|
||
def add_options(self, parser): | ||
"""Add test-specific --version option""" | ||
parser.add_argument("--version", dest="version", required=True, | ||
help="The version that is expected to be installed, eg: '1.14.5'") | ||
|
||
def run_test(self): | ||
"""Check the version of each executable""" | ||
|
||
self.version_expr = re.compile(f".*{ self.options.version }.*") | ||
|
||
# check dogecoind with only env | ||
dogecoind = self.run_command(["VERSION=1"], []) | ||
self.ensure_version_on_first_line(dogecoind.stdout) | ||
|
||
# check dogecoin-cli | ||
dogecoincli = self.run_command([], ["dogecoin-cli", "-?"]) | ||
self.ensure_version_on_first_line(dogecoincli.stdout) | ||
|
||
# check dogecoin-tx | ||
dogecointx = self.run_command([], ["dogecoin-tx", "-?"]) | ||
self.ensure_version_on_first_line(dogecointx.stdout) | ||
|
||
# make sure that we find version errors | ||
caught_error = False | ||
try: | ||
self.ensure_version_on_first_line("no version here".encode('utf-8')) | ||
except AssertionError: | ||
caught_error = True | ||
|
||
if not caught_error: | ||
raise AssertionError("Failed to catch a missing version") | ||
|
||
def ensure_version_on_first_line(self, cmd_output): | ||
"""Assert that the version is contained in the first line of output string""" | ||
first_line = cmd_output.decode("utf-8").split("\n")[0] | ||
|
||
if re.match(self.version_expr, first_line) is None: | ||
text = f"Could not find version { self.options.version } in { first_line }" | ||
raise AssertionError(text) | ||
|
||
if __name__ == '__main__': | ||
VersionTest().main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
#!/usr/bin/env python3 | ||
# Copyright (c) 2021 The Dogecoin Core developers | ||
""" | ||
Runs the integration tests | ||
""" | ||
|
||
import subprocess | ||
import sys | ||
|
||
from .integration.framework.test_runner import TestRunner | ||
|
||
def print_test_output(test_name, stdout, stderr=None): | ||
"""prints output from a test, including from stderr if provided""" | ||
print("\n") | ||
print(test_name) | ||
print("----------------------") | ||
|
||
if stderr is not None: | ||
print(stderr.decode("utf-8"), file=sys.stderr) | ||
|
||
print(stdout.decode("utf-8")) | ||
|
||
class IntegrationRunner(TestRunner): | ||
"""Runs the integration tests""" | ||
|
||
def __init__(self): | ||
"""Initializes the failure tracker and test result map""" | ||
TestRunner.__init__(self) | ||
self.found_failure = False | ||
self.result_map = {} | ||
|
||
|
||
def add_options(self, parser): | ||
"""Add test-specific --version option""" | ||
parser.add_argument("--version", dest="version", required=True, | ||
help="The version that is expected to be installed, eg: '1.14.5'") | ||
|
||
def run_test(self): | ||
"""Run all specified tests and inherit any failures""" | ||
|
||
#List of tests to run | ||
tests = [ | ||
[ "version", [ "--version", self.options.version ] ], | ||
] | ||
|
||
for test in tests: | ||
self.result_map[test[0]] = self.run_individual_test(test) | ||
|
||
self.print_summary() | ||
|
||
if self.found_failure: | ||
sys.exit(1) | ||
|
||
def run_individual_test(self, test): | ||
"""Run the actual test""" | ||
command = [ | ||
"/usr/bin/env", "python3", | ||
"-m", f"tests.integration.{ test[0] }", | ||
"--platform", self.options.platform, | ||
"--image", self.options.image, | ||
] | ||
|
||
if len(test) > 1 and len(test[1]) > 0: | ||
for arg in test[1]: | ||
command.append(arg) | ||
|
||
if self.options.verbose: | ||
command.append("--verbose") | ||
|
||
try: | ||
output = subprocess.run(command, capture_output=True, check=True) | ||
except subprocess.CalledProcessError as test_err: | ||
self.found_failure = True | ||
print_test_output(test[0], test_err.stdout, test_err.stderr) | ||
return False | ||
|
||
if self.options.verbose: | ||
print_test_output(test[0], output.stdout) | ||
|
||
return True | ||
|
||
def print_summary(self): | ||
"""Print a summary to stdout""" | ||
print("\n") | ||
print(f"RESULTS: for { self.options.image } on { self.options.platform }") | ||
|
||
successes = 0 | ||
failures = 0 | ||
for test, result in self.result_map.items(): | ||
if result: | ||
successes += 1 | ||
result_str = "Success" | ||
else: | ||
failures += 1 | ||
result_str = "Failure" | ||
|
||
print(f"{ test }: { result_str }") | ||
|
||
sum_str = f"{ successes } successful tests and { failures } failures" | ||
print(f"\nFinished test suite with { sum_str }") | ||
|
||
if __name__ == '__main__': | ||
IntegrationRunner().main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters