Skip to content

Commit

Permalink
Refactor basic_container_tests
Browse files Browse the repository at this point in the history
The basic_container_tests subroutine has historically grown and needed a
tidy. In this commit I

* reorganized the blocks into logical tests
* Reduced the scope to only run tests on one container
* Removed duplicate checks within the routine
* Simplified several checks for reduced code
  • Loading branch information
grisu48 committed Mar 7, 2024
1 parent 8fbff93 commit 4f216c7
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 109 deletions.
109 changes: 1 addition & 108 deletions lib/containers/utils.pm
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use warnings;
use version_utils;
use Mojo::Util 'trim';

our @EXPORT = qw(runtime_smoke_tests basic_container_tests get_vars
our @EXPORT = qw(runtime_smoke_tests get_vars
can_build_sle_base get_docker_version get_podman_version check_runtime_version
check_min_runtime_version container_ip container_route registry_url reset_container_network_if_needed
);
Expand Down Expand Up @@ -160,113 +160,6 @@ sub runtime_smoke_tests {
assert_script_run("$runtime rmi $image");
}

sub basic_container_tests {
my %args = @_;
my $runtime = $args{runtime};
die "You must define the runtime!" unless $runtime;
my $alpine_image_version = '3.6';
my $alpine = registry_url('alpine', $alpine_image_version);
my $hello_world = registry_url('hello-world');
my $leap = "registry.opensuse.org/opensuse/leap";
my $tumbleweed = "registry.opensuse.org/opensuse/tumbleweed";

# Test search feature
validate_script_output("$runtime search --no-trunc --format \"table {{.Name}} {{.Description}}\" tumbleweed", sub { m/Official openSUSE Tumbleweed images/ }, timeout => 200);
# This should be conditional based on the needed time, but that's currently not possible.
record_info('Softfail', 'Searching registry.suse.com is too slow (https://sd.suse.com/servicedesk/customer/portal/1/SD-106252)');

# - pull minimalistic alpine image of declared version using tag
# - https://store.docker.com/images/alpine
assert_script_run("$runtime image pull $alpine", timeout => 300);
# - pull typical docker demo image without tag. Should be latest.
# - https://store.docker.com/images/hello-world
assert_script_run("$runtime image pull $hello_world", timeout => 300);
# - pull image of last released version of openSUSE Leap
assert_script_run("$runtime image pull $leap", timeout => 600);
# - pull image of openSUSE Tumbleweed
assert_script_run("$runtime image pull $tumbleweed", timeout => 600);

# All images can be listed
assert_script_run("$runtime image ls");
# Local images can be listed
assert_script_run("$runtime image ls none");
# - filter with tag
assert_script_run(qq{$runtime image ls $alpine | grep "alpine\\s*$alpine_image_version"});
# - filter without tag
assert_script_run(qq{$runtime image ls $hello_world | grep "hello-world\\s*latest"});
# - all local images
my $local_images_list = script_output("$runtime image ls");
die("$runtime image $tumbleweed not found") unless ($local_images_list =~ /opensuse\/tumbleweed\s*latest/);
die("$runtime image $leap not found") if (!is_s390x && !$local_images_list =~ /opensuse\/leap\s*latest/);

# Containers can be spawned
# - using 'run'
assert_script_run("$runtime container run --name test_1 $hello_world | grep 'Hello from Docker\!'");
# - using 'create', 'start' and 'logs' (background container)
assert_script_run("$runtime container create --name test_2 $alpine /bin/echo Hello world");
assert_script_run("$runtime container start test_2 | grep test_2");
assert_script_run("$runtime container logs test_2 | grep 'Hello world'");
# - using 'run --rm'
assert_script_run(qq{$runtime container run --name test_ephemeral --rm $alpine /bin/echo Hello world | grep "Hello world"});
# - using 'run -d' and 'inspect' (background container)
my $container_name = 'tw';
assert_script_run("$runtime container run -d --name $container_name $tumbleweed tail -f /dev/null");
assert_script_run("$runtime container inspect --format='{{.State.Running}}' $container_name | grep true");
my $output_containers = script_output("$runtime container ls -a");
die('error: missing container test_1') unless ($output_containers =~ m/test_1/);
die('error: missing container test_2') unless ($output_containers =~ m/test_2/);
die('error: ephemeral container was not removed') if ($output_containers =~ m/test_ephemeral/);
die("error: missing container $container_name") unless ($output_containers =~ m/$container_name/);

# Containers' state can be saved to a docker image
my $ret = script_run("$runtime container exec $container_name zypper -n in curl", 600);
die('zypper inside container timed out') if (!defined($ret));
if ($ret != 0) {
my $output = script_output("$runtime container exec $container_name zypper in --force-resolution -y -n curl", 600);
die('error: curl not installed in the container') unless (($output =~ m/Installing: curl.*done/) || ($output =~ m/\'curl\' .* already installed/));
}
assert_script_run("$runtime container commit $container_name tw:saved", 240);

# Network is working inside of the containers
my $output = script_output("$runtime container run tw:saved curl -sI google.de");
die("network is not working inside of the container tw:saved") unless ($output =~ m{Location: http://www\.google\.de/});

# Using an init process as PID 1
assert_script_run "$runtime run --rm --init $tumbleweed ps --no-headers -xo 'pid args' | grep '1 .*init'";

if (script_run('test -x /usr/bin/man') == 0) {
# Note: The output of man contains non-ASCII characters. Even a dash (`-`) imposes difficulties here, so it's best to stay with letters
if ($runtime eq 'podman') {
validate_script_output("man -P cat $runtime-build", sub { m/Build a container image using a Containerfile/ }, fail_message => "`man $runtime build` contents not validating");
} elsif ($runtime eq 'docker') {
validate_script_output("man -P cat $runtime-build", sub { m/Build an image from a Dockerfile/ }, fail_message => "`man $runtime build` contents not validating");
}
}

# Containers can be stopped
assert_script_run("$runtime container stop $container_name");
assert_script_run("$runtime container inspect --format='{{.State.Running}}' $container_name | grep false");

# Containers can be deleted
my $cmd_docker_rm = "$runtime rm test_1";
assert_script_run("$cmd_docker_rm");
$output_containers = script_output("$runtime container ls -a");
die("error: container was not removed: $cmd_docker_rm") if ($output_containers =~ m/test_1/);
my $cmd_docker_container_prune = "$runtime container prune -f";
assert_script_run("$cmd_docker_container_prune");
$output_containers = script_output("$runtime container ls -a");
die("error: container was not removed: $cmd_docker_container_prune") if ($output_containers =~ m/test_2/);

# Images can be deleted
my $cmd_runtime_rmi = "$runtime rmi -a";
$output_containers = script_output("$runtime container ls -a");
die("error: $runtime image rmi -a $leap") if ($output_containers =~ m/Untagged:.*opensuse\/leap/);
die("error: $runtime image rmi -a $tumbleweed") if ($output_containers =~ m/Untagged:.*opensuse\/tumbleweed/);
die("error: $runtime image rmi -a tw:saved") if ($output_containers =~ m/Untagged:.*tw:saved/);
record_info('Softfail', "error: $runtime image rmi -a $alpine", result => 'softfail') if ($output_containers =~ m/Untagged:.*alpine/);
record_info('Softfail', "error: $runtime image rmi -a $hello_world:latest", result => 'softfail') if ($output_containers =~ m/Untagged:.*hello-world:latest/);
}

=head2 can_build_sle_base
C<can_build_sle_base> should be used to identify if sle base image runs against a
Expand Down
83 changes: 82 additions & 1 deletion tests/containers/container_engine.pm
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,88 @@ use containers::common;
use containers::utils;
use containers::container_images;

sub basic_container_tests {
my %args = @_;
my $runtime = $args{runtime};
die "Undefined container runtime" unless $runtime;
my $image = "registry.opensuse.org/opensuse/tumbleweed";

## Test search feature
validate_script_output("$runtime search --no-trunc --format 'table {{.Name}} {{.Description}}' tumbleweed", sub { m/Official openSUSE Tumbleweed images/ }, timeout => 300);

# Test pulling and display of images
script_retry("$runtime image pull $image", timeout => 600, retry => 3, delay => 120);
validate_script_output("$runtime image ls", qr/tumbleweed/);

## Create test container
assert_script_run("$runtime create --name basic_test_container $image sleep infinity");
validate_script_output("$runtime container ls --all", qr/basic_test_container/);

## Test start/stop/pause
assert_script_run("$runtime container start basic_test_container");
validate_script_output("$runtime ps", qr/basic_test_container/);
validate_script_output("$runtime container inspect --format='{{.State.Running}}' basic_test_container", qr/true/);
assert_script_run("$runtime pause basic_test_container");
# docker and podman differ here - in docker paused containers are still in State.Running = true, in podman not
if ($runtime eq 'docker') {
validate_script_output("$runtime ps", sub { $_ =~ m/.*(Paused).*basic_test_container.*/ });
validate_script_output("$runtime container inspect --format='{{.State.Running}}' basic_test_container", qr/true/);
} else {
validate_script_output("$runtime ps", sub { $_ !~ m/basic_test_container/ });
validate_script_output("$runtime container inspect --format='{{.State.Running}}' basic_test_container", qr/false/);
}
assert_script_run("$runtime unpause basic_test_container");
validate_script_output("$runtime ps", qr/basic_test_container/);
validate_script_output("$runtime container inspect --format='{{.State.Running}}' basic_test_container", qr/true/);
assert_script_run("$runtime stop basic_test_container");
validate_script_output("$runtime ps", sub { $_ !~ m/basic_test_container/ });
validate_script_output("$runtime container inspect --format='{{.State.Running}}' basic_test_container", qr/false/);
assert_script_run("$runtime container start basic_test_container");
validate_script_output("$runtime ps", qr/basic_test_container/);
validate_script_output("$runtime container inspect --format='{{.State.Running}}' basic_test_container", qr/true/);
assert_script_run("$runtime container restart basic_test_container");
validate_script_output("$runtime ps", qr/basic_test_container/);
validate_script_output("$runtime container inspect --format='{{.State.Running}}' basic_test_container", qr/true/);

## Test logs
assert_script_run("$runtime run -d --name logs_test $image echo 'log test canary string'");
# retry because it could be that the log is not yet collected after the previous command completes
validate_script_output_retry("$runtime logs logs_test", qr/log test canary string/, retry => 3, delay => 60);
assert_script_run("$runtime container stop logs_test");
assert_script_run("$runtime container rm logs_test");

## Test exec and image creation
assert_script_run("$runtime container exec basic_test_container touch /canary");
assert_script_run("$runtime container commit basic_test_container example.com/tw-commit_test");
validate_script_output("$runtime image ls --all", qr?example.com/tw-commit_test?);
assert_script_run("$runtime run --rm example.com/tw-commit_test stat /canary", fail_message => "canary file not present in generated container");
assert_script_run("$runtime image rm example.com/tw-commit_test");

## Test connectivity inside the container
assert_script_run("$runtime container exec basic_test_container curl -sfI https://opensuse.org", fail_message => "cannot reach opensuse.org");

## Test `--init`, i.e. the container process won't be PID 1 (to avoid zombie processes)
# expected output: the `ps` command is not running as PID 1.
validate_script_output("$runtime run --rm --init $image ps --no-headers -xo 'pid args'", sub { $_ !~ m/ 1 .*ps.*/ });

## Test prune
assert_script_run("$runtime container commit basic_test_container example.com/prune-test");
validate_script_output("$runtime image ls --all", qr?example.com/prune-test?);
assert_script_run("$runtime image prune -af");
validate_script_output("$runtime ps", sub { $_ !~ m?example.com/prune-test? });
validate_script_output("$runtime image ls", qr/tumbleweed/, fail_message => "Tumbleweed image removed, despite being in use");
assert_script_run("$runtime system prune -f");
validate_script_output("$runtime image ls", qr/tumbleweed/, fail_message => "Tumbleweed image removed, despite being in use");
assert_script_run("! $runtime rmi -a"); # should not be possible because image is in use

## Removing containers
assert_script_run("$runtime container stop basic_test_container");
assert_script_run("$runtime container rm basic_test_container");
validate_script_output("$runtime container ls --all", sub { $_ !~ m/basic_test_container/ });

## Note: Leave the tumbleweed container to save some bandwidth. It is used in other test modules as well.
}

sub run {
my ($self, $args) = @_;
die('You must define a engine') unless ($args->{runtime});
Expand All @@ -49,7 +131,6 @@ sub run {
# Test the connectivity of Docker containers
check_containers_connectivity($engine);

# Run basic runtime tests
basic_container_tests(runtime => $self->{runtime});
# Build an image from Dockerfile and run it
build_and_run_image(runtime => $engine, dockerfile => 'Dockerfile.python3', base => registry_url('python', '3'));
Expand Down

0 comments on commit 4f216c7

Please sign in to comment.