diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 5dd23bf2..79fff902 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -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 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5ffc2254..0bff6b00 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -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 diff --git a/.gitignore b/.gitignore index 87ddda7c..d0a7b06d 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/test/Makefile b/test/Makefile index 5dc1ad1f..cedb40fb 100644 --- a/test/Makefile +++ b/test/Makefile @@ -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) @@ -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 diff --git a/test/checkpointctl.bats b/test/piggie.bats similarity index 97% rename from test/checkpointctl.bats rename to test/piggie.bats index c974e731..91549654 100644 --- a/test/checkpointctl.bats +++ b/test/piggie.bats @@ -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 @@ -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 ] @@ -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 ] diff --git a/test/podman.bats b/test/podman.bats new file mode 100644 index 00000000..9d6bf158 --- /dev/null +++ b/test/podman.bats @@ -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"* ]] +}