Skip to content

Commit

Permalink
test: use Podman container checkpoint
Browse files Browse the repository at this point in the history
Previously, we were only using a local process (piggie) to generate the
checkpoint for tests. Doing this with a container ensures more accurate
tests and higher coverage of edge cases in the implementation of
checkpointctl.

Signed-off-by: Prajwal S N <[email protected]>
  • Loading branch information
snprajwal committed Jun 18, 2023
1 parent 9e95a30 commit 505fc53
Show file tree
Hide file tree
Showing 6 changed files with 308 additions and 19 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
# needed for codecov
fetch-depth: 0
- name: Install tools
run: sudo dnf -y install bats golang criu
run: sudo dnf -y install bats golang criu podman
- name: Run make coverage
run: sudo -E make coverage
- name: Run make codecov
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Install tools
run: sudo dnf -y install ShellCheck bats golang criu
run: sudo dnf -y install ShellCheck bats golang criu podman
- name: Run make shellcheck
run: make shellcheck
- name: Run make all
Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ checkpointctl.coverage
.coverage
junit.xml
test/piggie/piggie
test/test-imgs
test/piggie-test-imgs
test/podman-test-imgs
test/podman-chkpt.tar.gz
36 changes: 26 additions & 10 deletions test/Makefile
Original file line number Diff line number Diff line change
@@ -1,17 +1,29 @@
CRIU ?= criu
CC ?= gcc
PODMAN ?= podman
PODMAN_IMAGE ?= looper

all: test clean
all: piggie-test podman-test clean

test: test-imgs
@echo "Running BATS tests..."
bats checkpointctl.bats
piggie-test: piggie-test-imgs
@echo "Running BATS tests with piggie..."
bats piggie.bats

test-junit: test-imgs
podman-test: podman-test-imgs
@echo "Running BATS tests with Podman checkpoint..."
bats podman.bats

podman-test-imgs:
$(PODMAN) run -d --name $(PODMAN_IMAGE) busybox /bin/sh -c 'i=0; while true; do echo $i; i=$(expr $i + 1); sleep 1; done'
podman container checkpoint -l --export=podman-chkpt.tar.gz
mkdir -p $@
tar -xvf podman-chkpt.tar.gz -C $@

test-junit: piggie-test-imgs podman-test-imgs
@echo "Running BATS tests with JUnit results..."
bats -F junit checkpointctl.bats > junit.xml
bats -F junit *.bats > junit.xml

test-imgs: piggie/piggie
piggie-test-imgs: piggie/piggie
$(eval PID := $(shell piggie/piggie))
mkdir -p $@
$(CRIU) dump -v4 -o dump.log -D $@ -t $(PID)
Expand All @@ -20,7 +32,11 @@ piggie/piggie: piggie/piggie.c
$(CC) $^ -o $@

clean:
@echo "Cleaning up test files..."
@rm -rf test-imgs piggie/piggie
@echo "Cleaning up piggie test files..."
@rm -rf piggie-test-imgs piggie/piggie
@echo "cleaning up podman image..."
@podman container rm $(PODMAN_IMAGE) || true
@echo "Cleaning up podman test files..."
@rm -rf podman-chkpt.tar.gz podman-test-imgs

.PHONY: all test test-junit clean
.PHONY: all piggie-test podman-test test-junit clean
12 changes: 6 additions & 6 deletions test/checkpointctl.bats → test/piggie.bats
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ function teardown() {
@test "Run checkpointctl show with tar file and --stats and valid stats-dump" {
cp data/config.dump "$TEST_TMP_DIR1"
cp data/spec.dump "$TEST_TMP_DIR1"
cp test-imgs/stats-dump "$TEST_TMP_DIR1"
cp piggie-test-imgs/stats-dump "$TEST_TMP_DIR1"
mkdir "$TEST_TMP_DIR1"/checkpoint
( cd "$TEST_TMP_DIR1" && tar cf "$TEST_TMP_DIR2"/test.tar . )
checkpointctl show "$TEST_TMP_DIR2"/test.tar --stats
Expand Down Expand Up @@ -167,10 +167,10 @@ function teardown() {
@test "Run checkpointctl show with tar file and --all and valid spec.dump and valid stats-dump" {
cp data/config.dump "$TEST_TMP_DIR1"
cp data/spec.dump "$TEST_TMP_DIR1"
cp test-imgs/stats-dump "$TEST_TMP_DIR1"
cp piggie-test-imgs/stats-dump "$TEST_TMP_DIR1"
mkdir "$TEST_TMP_DIR1"/checkpoint
cp test-imgs/pstree.img \
test-imgs/core-*.img "$TEST_TMP_DIR1"/checkpoint
cp piggie-test-imgs/pstree.img \
piggie-test-imgs/core-*.img "$TEST_TMP_DIR1"/checkpoint
( cd "$TEST_TMP_DIR1" && tar cf "$TEST_TMP_DIR2"/test.tar . )
checkpointctl show "$TEST_TMP_DIR2"/test.tar --all
[ "$status" -eq 0 ]
Expand Down Expand Up @@ -262,8 +262,8 @@ function teardown() {
cp data/config.dump \
data/spec.dump "$TEST_TMP_DIR1"
mkdir "$TEST_TMP_DIR1"/checkpoint
cp test-imgs/pstree.img \
test-imgs/core-*.img "$TEST_TMP_DIR1"/checkpoint
cp piggie-test-imgs/pstree.img \
piggie-test-imgs/core-*.img "$TEST_TMP_DIR1"/checkpoint
( cd "$TEST_TMP_DIR1" && tar cf "$TEST_TMP_DIR2"/test.tar . )
checkpointctl show "$TEST_TMP_DIR2"/test.tar --ps-tree
[ "$status" -eq 0 ]
Expand Down
271 changes: 271 additions & 0 deletions test/podman.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
if [ -n "$COVERAGE" ]; then
export GOCOVERDIR="${COVERAGE_PATH}"
CHECKPOINTCTL="../checkpointctl.coverage"
else
CHECKPOINTCTL="../checkpointctl"
fi

TEST_TMP_DIR1=""
TEST_TMP_DIR2=""

function checkpointctl() {
# shellcheck disable=SC2086
run $CHECKPOINTCTL "$@"
echo "$output"
}

function setup() {
TEST_TMP_DIR1=$(mktemp -d)
TEST_TMP_DIR2=$(mktemp -d)
}

function teardown() {
[ "$TEST_TMP_DIR1" != "" ] && rm -rf "$TEST_TMP_DIR1"
[ "$TEST_TMP_DIR2" != "" ] && rm -rf "$TEST_TMP_DIR2"
}

@test "Run checkpointctl" {
checkpointctl
[ "$status" -eq 0 ]
}

@test "Run checkpointctl with wrong parameter" {
checkpointctl --wrong-parameter
[ "$status" -eq 1 ]
[ "$output" = "Error: unknown flag: --wrong-parameter" ]
}

@test "Run checkpointctl show with non existing directory" {
checkpointctl show /does-not-exist
[ "$status" -eq 1 ]
[[ ${lines[0]} = "Error: stat /does-not-exist: no such file or directory" ]]
}

@test "Run checkpointctl show with empty tar file" {
touch "$TEST_TMP_DIR1"/empty.tar
checkpointctl show "$TEST_TMP_DIR1"/empty.tar
[ "$status" -eq 1 ]
[[ ${lines[0]} == *"checkpoint directory is missing in the archive file"* ]]
}

@test "Run checkpointctl show with tar file with empty config.dump" {
touch "$TEST_TMP_DIR1"/config.dump
mkdir "$TEST_TMP_DIR1"/checkpoint
( cd "$TEST_TMP_DIR1" && tar cf "$TEST_TMP_DIR2"/test.tar . )
checkpointctl show "$TEST_TMP_DIR2"/test.tar
[ "$status" -eq 1 ]
[[ ${lines[0]} == *"config.dump: unexpected end of JSON input" ]]
}

@test "Run checkpointctl show with tar file with valid config.dump and no spec.dump" {
cp data/config.dump "$TEST_TMP_DIR1"
mkdir "$TEST_TMP_DIR1"/checkpoint
( cd "$TEST_TMP_DIR1" && tar cf "$TEST_TMP_DIR2"/test.tar . )
checkpointctl show "$TEST_TMP_DIR2"/test.tar
[ "$status" -eq 1 ]
[[ ${lines[0]} == *"spec.dump: no such file or directory" ]]
}

@test "Run checkpointctl show with tar file with valid config.dump and empty spec.dump" {
cp data/config.dump "$TEST_TMP_DIR1"
mkdir "$TEST_TMP_DIR1"/checkpoint
touch "$TEST_TMP_DIR1"/spec.dump
( cd "$TEST_TMP_DIR1" && tar cf "$TEST_TMP_DIR2"/test.tar . )
checkpointctl show "$TEST_TMP_DIR2"/test.tar
[ "$status" -eq 1 ]
[[ ${lines[0]} == *"spec.dump: unexpected end of JSON input" ]]
}

@test "Run checkpointctl show with tar file with valid config.dump and valid spec.dump and no checkpoint directory" {
cp data/config.dump "$TEST_TMP_DIR1"
cp data/spec.dump "$TEST_TMP_DIR1"
( cd "$TEST_TMP_DIR1" && tar cf "$TEST_TMP_DIR2"/test.tar . )
checkpointctl show "$TEST_TMP_DIR2"/test.tar
[ "$status" -eq 1 ]
[[ ${lines[0]} == *"Error: checkpoint directory is missing in the archive file"* ]]
}

@test "Run checkpointctl show with tar file with valid config.dump and valid spec.dump and checkpoint directory" {
cp data/config.dump "$TEST_TMP_DIR1"
cp data/spec.dump "$TEST_TMP_DIR1"
mkdir "$TEST_TMP_DIR1"/checkpoint
( cd "$TEST_TMP_DIR1" && tar cf "$TEST_TMP_DIR2"/test.tar . )
checkpointctl show "$TEST_TMP_DIR2"/test.tar
[ "$status" -eq 0 ]
[[ ${lines[4]} == *"Podman"* ]]
}

@test "Run checkpointctl show with tar file from containerd with valid config.dump and valid spec.dump and checkpoint directory" {
cp data/config.dump "$TEST_TMP_DIR1"
mkdir "$TEST_TMP_DIR1"/checkpoint
echo "{}" > "$TEST_TMP_DIR1"/status
echo "{}" > "$TEST_TMP_DIR1"/spec.dump
( cd "$TEST_TMP_DIR1" && tar cf "$TEST_TMP_DIR2"/test.tar . )
checkpointctl show "$TEST_TMP_DIR2"/test.tar
[ "$status" -eq 0 ]
[[ ${lines[4]} == *"containerd"* ]]
}

@test "Run checkpointctl show with tar file and --stats and missing stats-dump" {
cp data/config.dump "$TEST_TMP_DIR1"
cp data/spec.dump "$TEST_TMP_DIR1"
mkdir "$TEST_TMP_DIR1"/checkpoint
( cd "$TEST_TMP_DIR1" && tar cf "$TEST_TMP_DIR2"/test.tar . )
checkpointctl show "$TEST_TMP_DIR2"/test.tar --stats
[ "$status" -eq 1 ]
[[ ${lines[6]} == *"failed to get dump statistics"* ]]
}

@test "Run checkpointctl show with tar file and --stats and invalid stats-dump" {
cp data/config.dump "$TEST_TMP_DIR1"
cp data/spec.dump "$TEST_TMP_DIR1"
cp data/spec.dump "$TEST_TMP_DIR1"/stats-dump
mkdir "$TEST_TMP_DIR1"/checkpoint
( cd "$TEST_TMP_DIR1" && tar cf "$TEST_TMP_DIR2"/test.tar . )
checkpointctl show "$TEST_TMP_DIR2"/test.tar --stats
[ "$status" -eq 1 ]
[[ ${lines[6]} == *"Unknown magic"* ]]
}

@test "Run checkpointctl show with tar file and --stats and valid stats-dump" {
cp data/config.dump "$TEST_TMP_DIR1"
cp data/spec.dump "$TEST_TMP_DIR1"
cp podman-test-imgs/stats-dump "$TEST_TMP_DIR1"
mkdir "$TEST_TMP_DIR1"/checkpoint
( cd "$TEST_TMP_DIR1" && tar cf "$TEST_TMP_DIR2"/test.tar . )
checkpointctl show "$TEST_TMP_DIR2"/test.tar --stats
[ "$status" -eq 0 ]
[[ ${lines[6]} == *"CRIU dump statistics"* ]]
[[ ${lines[8]} == *"MEMWRITE TIME"* ]]
[[ ${lines[10]} =~ [1-9]+" us" ]]
}

@test "Run checkpointctl show with tar file and --mounts and valid spec.dump" {
cp data/config.dump "$TEST_TMP_DIR1"
cp data/spec.dump "$TEST_TMP_DIR1"
mkdir "$TEST_TMP_DIR1"/checkpoint
( cd "$TEST_TMP_DIR1" && tar cf "$TEST_TMP_DIR2"/test.tar . )
checkpointctl show "$TEST_TMP_DIR2"/test.tar --mounts
[ "$status" -eq 0 ]
[[ ${lines[6]} == *"Overview of Mounts"* ]]
[[ ${lines[8]} == *"DESTINATION"* ]]
[[ ${lines[10]} == *"/proc"* ]]
}

@test "Run checkpointctl show with tar file and --mounts and --full-paths and valid spec.dump" {
cp data/config.dump "$TEST_TMP_DIR1"
cp data/spec.dump "$TEST_TMP_DIR1"
mkdir "$TEST_TMP_DIR1"/checkpoint
( cd "$TEST_TMP_DIR1" && tar cf "$TEST_TMP_DIR2"/test.tar . )
checkpointctl show "$TEST_TMP_DIR2"/test.tar --mounts --full-paths
[ "$status" -eq 0 ]
[[ ${lines[6]} == *"Overview of Mounts"* ]]
[[ ${lines[8]} == *"DESTINATION"* ]]
[[ ${lines[10]} == *"/proc"* ]]
}

@test "Run checkpointctl show with tar file and --all and valid spec.dump and valid stats-dump" {
cp data/config.dump "$TEST_TMP_DIR1"
cp data/spec.dump "$TEST_TMP_DIR1"
cp podman-test-imgs/stats-dump "$TEST_TMP_DIR1"
mkdir "$TEST_TMP_DIR1"/checkpoint
cp podman-test-imgs/checkpoint/pstree.img \
podman-test-imgs/checkpoint/core-*.img "$TEST_TMP_DIR1"/checkpoint
( cd "$TEST_TMP_DIR1" && tar cf "$TEST_TMP_DIR2"/test.tar . )
checkpointctl show "$TEST_TMP_DIR2"/test.tar --all
[ "$status" -eq 0 ]
[[ ${lines[6]} == *"Overview of Mounts"* ]]
[[ ${lines[8]} == *"DESTINATION"* ]]
[[ ${lines[10]} == *"/proc"* ]]
[[ ${lines[11]} == *"/etc/hostname"* ]]
[[ ${lines[13]} == *"CRIU dump statistics"* ]]
[[ ${lines[15]} == *"MEMWRITE TIME"* ]]
[[ ${lines[17]} =~ [1-9]+" us" ]]
[[ ${lines[19]} == *"Process tree"* ]]
[[ ${lines[21]} == *"sh"* ]]
}

@test "Run checkpointctl show with tar file and missing --mounts/--all and --full-paths" {
cp data/config.dump "$TEST_TMP_DIR1"
cp data/spec.dump "$TEST_TMP_DIR1"
mkdir "$TEST_TMP_DIR1"/checkpoint
( cd "$TEST_TMP_DIR1" && tar cf "$TEST_TMP_DIR2"/test.tar . )
checkpointctl show "$TEST_TMP_DIR2"/test.tar --full-paths
[ "$status" -eq 1 ]
[[ ${lines[0]} == *"Error: Cannot use --full-paths without --mounts/--all option"* ]]
}

@test "Run checkpointctl show with tar file with valid config.dump and valid spec.dump (CRI-O) and no checkpoint directory" {
cp data/config.dump "$TEST_TMP_DIR1"
cp data/spec.dump.cri-o "$TEST_TMP_DIR1"/spec.dump
( cd "$TEST_TMP_DIR1" && tar cf "$TEST_TMP_DIR2"/test.tar . )
checkpointctl show "$TEST_TMP_DIR2"/test.tar
[ "$status" -eq 1 ]
[[ ${lines[0]} == *"Error: checkpoint directory is missing in the archive file"* ]]
}

@test "Run checkpointctl show with tar file with valid config.dump and valid spec.dump (CRI-O) and checkpoint directory" {
cp data/config.dump "$TEST_TMP_DIR1"
cp data/spec.dump.cri-o "$TEST_TMP_DIR1"/spec.dump
mkdir "$TEST_TMP_DIR1"/checkpoint
( cd "$TEST_TMP_DIR1" && tar cf "$TEST_TMP_DIR2"/test.tar . )
checkpointctl show "$TEST_TMP_DIR2"/test.tar
[ "$status" -eq 0 ]
[[ ${lines[4]} == *"CRI-O"* ]]
}

@test "Run checkpointctl show with tar file compressed" {
cp data/config.dump "$TEST_TMP_DIR1"
cp data/spec.dump "$TEST_TMP_DIR1"
mkdir "$TEST_TMP_DIR1"/checkpoint
( cd "$TEST_TMP_DIR1" && tar czf "$TEST_TMP_DIR2"/test.tar.gz . )
checkpointctl show "$TEST_TMP_DIR2"/test.tar.gz
[ "$status" -eq 0 ]
[[ ${lines[4]} == *"Podman"* ]]
}

@test "Run checkpointctl show with tar file corrupted" {
cp data/config.dump "$TEST_TMP_DIR1"
cp data/spec.dump "$TEST_TMP_DIR1"
mkdir "$TEST_TMP_DIR1"/checkpoint
( cd "$TEST_TMP_DIR1" && tar cf "$TEST_TMP_DIR2"/test.tar . )
dd if=/dev/urandom of="$TEST_TMP_DIR2"/test.tar bs=1 count=10 seek=2 conv=notrunc
checkpointctl show "$TEST_TMP_DIR2"/test.tar
[ "$status" -eq 1 ]
[[ ${lines[0]} == *"Error: archive/tar: invalid tar header"* ]]
}

@test "Run checkpointctl show with tar file compressed and corrupted" {
cp data/config.dump "$TEST_TMP_DIR1"
cp data/spec.dump "$TEST_TMP_DIR1"
mkdir "$TEST_TMP_DIR1"/checkpoint
( cd "$TEST_TMP_DIR1" && tar czf "$TEST_TMP_DIR2"/test.tar.gz . )
dd if=/dev/urandom of="$TEST_TMP_DIR2"/test.tar.gz bs=1 count=10 seek=2 conv=notrunc
checkpointctl show "$TEST_TMP_DIR2"/test.tar.gz
[ "$status" -eq 1 ]
[[ ${lines[0]} == *"Error: unexpected EOF"* ]]
}

@test "Run checkpointctl show with tar file and rootfs-diff tar file" {
cp data/config.dump "$TEST_TMP_DIR1"
cp data/spec.dump "$TEST_TMP_DIR1"
mkdir "$TEST_TMP_DIR1"/checkpoint
echo 1 > "$TEST_TMP_DIR1"/test.pid
tar -cf "$TEST_TMP_DIR1"/rootfs-diff.tar -C "$TEST_TMP_DIR1" test.pid
( cd "$TEST_TMP_DIR1" && tar cf "$TEST_TMP_DIR2"/test.tar . )
checkpointctl show "$TEST_TMP_DIR2"/test.tar
[ "$status" -eq 0 ]
[[ ${lines[2]} == *"ROOT FS DIFF SIZE"* ]]
}

@test "Run checkpointctl show with tar file and --ps-tree" {
cp data/config.dump \
data/spec.dump "$TEST_TMP_DIR1"
mkdir "$TEST_TMP_DIR1"/checkpoint
cp podman-test-imgs/checkpoint/pstree.img \
podman-test-imgs/checkpoint/core-*.img "$TEST_TMP_DIR1"/checkpoint
( cd "$TEST_TMP_DIR1" && tar cf "$TEST_TMP_DIR2"/test.tar . )
checkpointctl show "$TEST_TMP_DIR2"/test.tar --ps-tree
[ "$status" -eq 0 ]
[[ ${lines[8]} == *"sh"* ]]
}

0 comments on commit 505fc53

Please sign in to comment.