Skip to content

Commit

Permalink
DockerRunner: Enable background container to run commands against
Browse files Browse the repository at this point in the history
  • Loading branch information
AbcSxyZ committed Dec 18, 2021
1 parent 334736d commit 02a9074
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 38 deletions.
90 changes: 62 additions & 28 deletions tests/integration/framework/docker_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,49 +8,83 @@
import sys

class DockerRunner:
"""Run docker containers for testing"""
"""Run a docker container in background to execute testing commands"""

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
self.container_id = None

def construct_docker_command(self, envs, args):
# Launch the container
self._start()

def execute(self, envs, args):
"""
Construct a docker command with env and args
Run our target docker image with a list of
environment variables and a list of arguments
"""
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)
command = self._construct_command(envs, args)
return self._shell(command)

return command
def __del__(self):
"""Remove test container"""
stop_command = ["docker", "rm", "-f", self.container_id]
self._shell(stop_command, silent=True)

def run_interactive_command(self, envs, args):
def _start(self):
"""
Run our target docker image with a list of
environment variables and a list of arguments
Launch a docker container. Done in 2 step using create + start.
Keep the container running with a shell open thanks to `--interactive`,
having stdin open keep the process running.
"""
command = self.construct_docker_command(envs, args)
create_command = [
"docker", "create",
"--platform", self.platform,
"--interactive",
self.image,
"/bin/bash",
]
self.container_id = self._shell(create_command, silent=True)

start_command = [
"docker", "start", self.container_id
]
self._shell(start_command, silent=True)

if self.verbose:
print(f"Running command: { ' '.join(command) }")
def _shell(self, command, silent=False):
"""Run an arbitrary shell command and return its output"""
if self.verbose and not silent:
print(f"$ { ' '.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)
result = subprocess.run(command, capture_output=True, check=True)
except subprocess.CalledProcessError as command_err:
print(command_err.stdout.decode("utf-8"), file=sys.stdout)
print(command_err.stderr.decode("utf-8"), file=sys.stderr)
raise command_err

return result.stdout.decode("utf-8").strip()

def _construct_command(self, envs, args):
"""Construct a docker command with env and args"""
command = ["docker", "exec"]

for env in envs:
command.append("-e")
command.append(env)

command.append(self.container_id)

raise docker_err
# Launch all shell commands using entrypoint.py only
command.append("entrypoint.py")

return output
# Need to add a default executables added by CMD normally
if len(args) == 0 or args[0].startswith("-"):
command.append("dogecoind")

command.extend(args)

return command
10 changes: 5 additions & 5 deletions tests/integration/framework/test_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ class TestConfigurationError(Exception):
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 = {}
self.container = None

def add_options(self, parser):
"""Allow adding options in tests"""
Expand All @@ -30,10 +30,7 @@ def run_command(self, envs, 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)
return self.container.execute(envs, args)

def main(self):
"""main loop"""
Expand All @@ -48,6 +45,9 @@ def main(self):
self.add_options(parser)
self.options = parser.parse_args()

self.container = DockerRunner(self.options.platform,
self.options.image, self.options.verbose)

self.run_test()
print("Tests successful")
sys.exit(0)
10 changes: 5 additions & 5 deletions tests/integration/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,20 @@ def run_test(self):

# check dogecoind with only env
dogecoind = self.run_command(["VERSION=1"], [])
self.ensure_version_on_first_line(dogecoind.stdout)
self.ensure_version_on_first_line(dogecoind)

# check dogecoin-cli
dogecoincli = self.run_command([], ["dogecoin-cli", "-?"])
self.ensure_version_on_first_line(dogecoincli.stdout)
self.ensure_version_on_first_line(dogecoincli)

# check dogecoin-tx
dogecointx = self.run_command([], ["dogecoin-tx", "-?"])
self.ensure_version_on_first_line(dogecointx.stdout)
self.ensure_version_on_first_line(dogecointx)

# make sure that we find version errors
caught_error = False
try:
self.ensure_version_on_first_line("no version here".encode('utf-8'))
self.ensure_version_on_first_line("no version here")
except AssertionError:
caught_error = True

Expand All @@ -50,7 +50,7 @@ def run_test(self):

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]
first_line = cmd_output.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 }"
Expand Down

0 comments on commit 02a9074

Please sign in to comment.