diff --git a/.github/workflows/ghcr-image-build-and-publish.yml b/.github/workflows/ghcr-image-build-and-publish.yml deleted file mode 100644 index 47084653b93..00000000000 --- a/.github/workflows/ghcr-image-build-and-publish.yml +++ /dev/null @@ -1,69 +0,0 @@ -name: image - -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. - -on: - push: - branches: [main] - # Publish semver tags as releases. - tags: ['v*.*.*'] - pull_request: - branches: [main] - paths-ignore: - - '**.md' - -env: - # Use docker.io for Docker Hub if empty - REGISTRY: ghcr.io - # github.repository as / - IMAGE_NAME: ${{ github.repository }} - -jobs: - build: - - runs-on: ubuntu-24.04 - permissions: - contents: read - packages: write - - steps: - - name: Checkout repository - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - - name: Set up QEMU - uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 - - # Login against a Docker registry except on PR - # https://github.com/docker/login-action - - name: Log into registry ${{ env.REGISTRY }} - if: github.event_name != 'pull_request' - uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - # Extract metadata (tags, labels) for Docker - # https://github.com/docker/metadata-action - - name: Extract Docker metadata - id: meta - uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - - # Build and push Docker image with Buildx (don't push on PR) - # https://github.com/docker/build-push-action - - name: Build and push Docker image - uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6.16.0 - with: - context: . - platforms: linux/amd64,linux/arm64 - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 72587a7227d..00000000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,60 +0,0 @@ -# See https://github.com/containerd/nerdctl/blob/main/MAINTAINERS_GUIDE.md for how to make a release. -name: Release -on: - push: - tags: - - 'v*' - - 'test-action-release-*' - -env: - GOTOOLCHAIN: local - -jobs: - release: - runs-on: ubuntu-24.04 - timeout-minutes: 40 - # The maximum access is "read" for PRs from public forked repos - # https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token - permissions: - contents: write # for releases - id-token: write # for provenances - attestations: write # for provenances - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - name: "Install go" - uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0 - with: - go-version: "1.24" - check-latest: true - - name: "Compile binaries" - run: make artifacts - - name: "SHA256SUMS" - run: | - ( cd _output; sha256sum nerdctl-* ) | tee /tmp/SHA256SUMS - mv /tmp/SHA256SUMS _output/SHA256SUMS - - name: "The sha256sum of the SHA256SUMS file" - run: (cd _output; sha256sum SHA256SUMS) - - name: "Prepare the release note" - run: | - shasha=$(sha256sum _output/SHA256SUMS | awk '{print $1}') - cat <<-EOF | tee /tmp/release-note.txt - $(hack/generate-release-note.sh) - - - - - The binaries were built automatically on GitHub Actions. - The build log is available for 90 days: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} - - The sha256sum of the SHA256SUMS file itself is \`${shasha}\` . - - - - - Release manager: [ADD YOUR NAME HERE] (@[ADD YOUR GITHUB ID HERE]) - EOF - - name: "Generate artifact attestation" - uses: actions/attest-build-provenance@db473fddc028af60658334401dc6fa3ffd8669fd # v2.3.0 - if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') - with: - subject-path: _output/* - - name: "Create release" - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - tag="${GITHUB_REF##*/}" - gh release create -F /tmp/release-note.txt --draft --title "${tag}" "${tag}" _output/* diff --git a/.github/workflows/test-canary.yml b/.github/workflows/test-canary.yml deleted file mode 100644 index b23dc91f63f..00000000000 --- a/.github/workflows/test-canary.yml +++ /dev/null @@ -1,47 +0,0 @@ -# This pipeline purpose is solely meant to run a subset of our test suites against upcoming or unreleased dependencies versions -name: "[flaky, see #3988] canary" - -on: - push: - branches: - - main - - 'release/**' - pull_request: - paths-ignore: - - '**.md' - -env: - UBUNTU_VERSION: "24.04" - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - -jobs: - linux: - runs-on: "ubuntu-24.04" - timeout-minutes: 40 - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - fetch-depth: 1 - - name: "Prepare integration test environment" - run: | - . ./hack/build-integration-canary.sh - canary::build::integration - - name: "Remove snap loopback devices (conflicts with our loopback devices in TestRunDevice)" - run: | - sudo systemctl disable --now snapd.service snapd.socket - sudo apt-get purge -qq snapd - sudo losetup -Dv - sudo losetup -lv - - name: "Register QEMU (tonistiigi/binfmt)" - run: | - # `--install all` will only install emulation for architectures that cannot be natively executed - # Since some arm64 platforms do provide native fallback execution for 32 bits, - # armv7 emulation may or may not be installed, causing variance in the result of `uname -m`. - # To avoid that, we explicitly list the architectures we do want emulation for. - docker run --privileged --rm tonistiigi/binfmt --install linux/amd64 - docker run --privileged --rm tonistiigi/binfmt --install linux/arm64 - docker run --privileged --rm tonistiigi/binfmt --install linux/arm/v7 - - name: "Run integration tests" - run: docker run -t --rm --privileged test-integration ./hack/test-integration.sh -test.only-flaky=false - - name: "Run integration tests (flaky)" - run: docker run -t --rm --privileged test-integration ./hack/test-integration.sh -test.only-flaky=true diff --git a/.github/workflows/workflow-flaky.yml b/.github/workflows/workflow-flaky.yml deleted file mode 100644 index 85b5c1dd650..00000000000 --- a/.github/workflows/workflow-flaky.yml +++ /dev/null @@ -1,56 +0,0 @@ -# This workflow puts together all known "flaky" and experimental targets -name: "[flaky, see #3988]" - -on: - push: - branches: - - main - - 'release/**' - pull_request: - paths-ignore: - - '**.md' - -jobs: - test-integration-el: - name: "EL${{ inputs.hack }}" - uses: ./.github/workflows/job-test-in-lima.yml - strategy: - fail-fast: false - # EL8 is used for testing compatibility with cgroup v1. - # Unfortunately, EL8 is hard to debug for M1 users (as Lima+M1+EL8 is not runnable because of page size), - # and it currently shows numerous issues. - # Thus, EL9 is also added as target (for a limited time?) so that we can figure out which issues are EL8 specific, - # and which issues could be reproduced on EL9 as well (which would be easier to debug). - matrix: - guest: ["almalinux-8", "almalinux-9"] - target: ["rootful", "rootless"] - with: - timeout: 60 - runner: ubuntu-24.04 - guest: ${{ matrix.guest }} - target: ${{ matrix.target }} - - test-integration-freebsd: - name: "FreeBSD" - uses: ./.github/workflows/job-test-in-vagrant.yml - with: - timeout: 15 - runner: ubuntu-24.04 - - kube: - name: "kubernetes" - runs-on: ubuntu-24.04 - timeout-minutes: 15 - env: - ROOTFUL: true - steps: - - name: "Init: checkout" - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - fetch-depth: 1 - - name: "Run" - run: | - # FIXME: this should be a bit more elegant to use. - ./hack/provisioning/kube/kind.sh - # See https://github.com/containerd/nerdctl/blob/main/docs/testing/README.md#about-parallelization - sudo ./_output/nerdctl exec nerdctl-test-control-plane bash -c -- 'export TMPDIR="$HOME"/tmp; mkdir -p "$TMPDIR"; cd /nerdctl-source; /usr/local/go/bin/go test -p 1 ./cmd/nerdctl/... -test.only-kubernetes' diff --git a/.github/workflows/workflow-lint.yml b/.github/workflows/workflow-lint.yml deleted file mode 100644 index 5462b8e5d86..00000000000 --- a/.github/workflows/workflow-lint.yml +++ /dev/null @@ -1,80 +0,0 @@ -name: lint - -on: - push: - branches: - - main - - 'release/**' - pull_request: - -jobs: - # Runs golangci to ensure that: - # 1. the tooling is working on the target platform - # 2. the linter is happy - # 3. for canary (if there is a canary go version), does lint for all supported goos - lint-go: - name: "go${{ inputs.hack }}" - uses: ./.github/workflows/job-lint-go.yml - strategy: - fail-fast: false - matrix: - include: - - runner: ubuntu-24.04 - goos: linux - - runner: ubuntu-24.04 - goos: freebsd - - runner: macos-15 - goos: darwin - # FIXME: this is currently failing in a nonsensical way, so, running on linux instead... - # - runner: windows-2022 - - runner: ubuntu-24.04 - goos: windows - # Additionally lint for canary - - runner: ubuntu-24.04 - goos: linux - canary: true - with: - timeout: 5 - go-version: "1.24" - runner: ubuntu-24.04 - # Note: in GitHub yaml world, if `matrix.canary` is undefined, and is passed to `inputs.canary`, the job - # will not run. However, if you test it, it will coerce to `false`, hence: - canary: ${{ matrix.canary && true || false }} - goos: ${{ matrix.goos }} - - # Run common project checks (commits, licenses, etc) - lint-project-checks: - name: "project checks" - uses: ./.github/workflows/job-lint-project.yml - with: - timeout: 5 - go-version: "1.24" - runner: ubuntu-24.04 - - # Lint for shell and yaml files - lint-other: - name: "other" - uses: ./.github/workflows/job-lint-other.yml - with: - timeout: 5 - runner: ubuntu-24.04 - - # Verify we can actually build on all supported platforms, and a bunch of architectures - build-for-go: - name: "build for${{ inputs.hack }}" - uses: ./.github/workflows/job-build.yml - strategy: - fail-fast: false - matrix: - include: - # Build for both old and stable go - - go-version: "1.23" - - go-version: "1.24" - # Additionally build for canary - - go-version: "1.24" - canary: true - with: - timeout: 5 - go-version: ${{ matrix.go-version }} - runner: ubuntu-24.04 - canary: ${{ matrix.canary && true || false }} diff --git a/.github/workflows/workflow-mod-proofing.yml b/.github/workflows/workflow-mod-proofing.yml new file mode 100644 index 00000000000..0e3072e7acb --- /dev/null +++ b/.github/workflows/workflow-mod-proofing.yml @@ -0,0 +1,64 @@ +name: proofing + +on: + push: + branches: + - main + - 'release/**' + pull_request: + +env: + GOTOOLCHAIN: local + +jobs: + proofing: + name: "proofing" + timeout-minutes: 15 + runs-on: ubuntu-24.04 + defaults: + run: + shell: bash + steps: + - name: "Checkout project" + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 1 + + - name: "Install go" + uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0 + with: + go-version: 1.24 + check-latest: true + + - name: setup + run: | + set -x + + CLI=docker ./mod/proofing/spoof.sh server::start ./pkg/testutil/images.env + + # Check the server is reachable + # This is working + # curl -iv https://proofing:443/v2 || true + + # Restart services so they catch-up on the system store changes? + sudo systemctl stop containerd || true + sudo systemctl start containerd || true + systemctl --user stop containerd || true + systemctl --user start containerd || true + sudo systemctl stop docker || true + sudo systemctl start docker || true + + make binaries + sudo cp _output/nerdctl /usr/local/bin + sudo nerdctl pull --quiet debian + sudo nerdctl tag debian proofing:443/debian || true + # sudo nerdctl --insecure-registry push proofing:443/debian || true + sudo nerdctl push --quiet proofing:443/debian || true + +# sudo -E PATH="_output:$PATH" ./mod/proofing/spoof.sh server::seed ./pkg/testutil/images.env + - name: test in container + run: | + set -x + + docker ps -a + docker run -v $(pwd):/src --link proofing debian sh -c -- 'cd /src; apt-get -qq update; apt-get -qq install curl; ./mod/proofing/spoof.sh guest::configure ./pkg/testutil/images.env; curl -iv "https://docker.io/v2"; echo BOOO; cat /etc/hosts; echo BOOO; curl -iv https://proofing/v2/' diff --git a/.github/workflows/workflow-test.yml b/.github/workflows/workflow-test.yml deleted file mode 100644 index 1262c33e6fc..00000000000 --- a/.github/workflows/workflow-test.yml +++ /dev/null @@ -1,330 +0,0 @@ -name: test - -on: - push: - branches: - - main - - 'release/**' - pull_request: - paths-ignore: - - '**.md' - -env: - GO_VERSION: "1.24" - GOTOOLCHAIN: local - SHORT_TIMEOUT: 5 - LONG_TIMEOUT: 60 - -jobs: - # This job builds the dependency target of the test docker image for all supported architectures and cache it in GHA - build-dependencies: - timeout-minutes: 15 - name: dependencies | ${{ matrix.containerd }} | ${{ matrix.arch }} - runs-on: "${{ matrix.runner }}" - strategy: - fail-fast: false - matrix: - include: - - runner: ubuntu-24.04 - containerd: v1.6.38 - arch: amd64 - - runner: ubuntu-24.04 - containerd: v2.0.5 - arch: amd64 - - runner: ubuntu-24.04-arm - containerd: v2.0.5 - arch: arm64 - env: - CONTAINERD_VERSION: "${{ matrix.containerd }}" - ARCH: "${{ matrix.arch }}" - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - fetch-depth: 1 - - name: "Expose GitHub Runtime variables for gha" - uses: crazy-max/ghaction-github-runtime@3cb05d89e1f492524af3d41a1c98c83bc3025124 # v3.1.0 - - name: "Build dependencies for the integration test environment image" - run: | - docker buildx create --name with-gha --use - docker buildx build \ - --cache-to type=gha,compression=zstd,mode=max,scope=test-integration-dependencies-${ARCH} \ - --cache-from type=gha,scope=test-integration-dependencies-${ARCH} \ - --target build-dependencies --build-arg CONTAINERD_VERSION=${CONTAINERD_VERSION} . - - test-unit: - name: "unit${{ inputs.hack }}" - uses: ./.github/workflows/job-test-unit.yml - strategy: - fail-fast: false - matrix: - # Run on all supported platforms but freebsd - # Additionally run on canary for linux - include: - - runner: "ubuntu-24.04" - - runner: "macos-15" - - runner: "windows-2025" - - runner: "ubuntu-24.04" - canary: true - with: - runner: ${{ matrix.runner }} - canary: ${{ matrix.canary && true || false }} - # Windows routinely go over 5 minutes - timeout: 10 - go-version: 1.24 - windows-cni-version: v0.3.1 - linux-cni-version: v1.7.1 - linux-cni-sha: 1a28a0506bfe5bcdc981caf1a49eeab7e72da8321f1119b7be85f22621013098 - - test-integration: - needs: build-dependencies - timeout-minutes: 40 - name: rootful | ${{ matrix.containerd }} | ${{ matrix.runner }} - runs-on: "${{ matrix.runner }}" - strategy: - fail-fast: false - matrix: - include: - - ubuntu: 22.04 - containerd: v1.6.38 - runner: "ubuntu-22.04" - arch: amd64 - - ubuntu: 24.04 - containerd: v2.0.5 - runner: "ubuntu-24.04" - arch: amd64 - - ubuntu: 24.04 - containerd: v2.0.5 - runner: "ubuntu-24.04-arm" - arch: arm64 - env: - CONTAINERD_VERSION: "${{ matrix.containerd }}" - ARCH: "${{ matrix.arch }}" - UBUNTU_VERSION: "${{ matrix.ubuntu }}" - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - fetch-depth: 1 - - name: "Expose GitHub Runtime variables for gha" - uses: crazy-max/ghaction-github-runtime@3cb05d89e1f492524af3d41a1c98c83bc3025124 # v3.1.0 - - name: "Prepare integration test environment" - run: | - docker buildx create --name with-gha --use - docker buildx build \ - --output=type=docker \ - --cache-from type=gha,scope=test-integration-dependencies-${ARCH} \ - -t test-integration --target test-integration --build-arg UBUNTU_VERSION=${UBUNTU_VERSION} --build-arg CONTAINERD_VERSION=${CONTAINERD_VERSION} . - - name: "Remove snap loopback devices (conflicts with our loopback devices in TestRunDevice)" - run: | - sudo systemctl disable --now snapd.service snapd.socket - sudo apt-get purge -qq snapd - sudo losetup -Dv - sudo losetup -lv - - name: "Register QEMU (tonistiigi/binfmt)" - run: | - # `--install all` will only install emulation for architectures that cannot be natively executed - # Since some arm64 platforms do provide native fallback execution for 32 bits, - # armv7 emulation may or may not be installed, causing variance in the result of `uname -m`. - # To avoid that, we explicitly list the architectures we do want emulation for. - docker run --privileged --rm tonistiigi/binfmt --install linux/amd64 - docker run --privileged --rm tonistiigi/binfmt --install linux/arm64 - docker run --privileged --rm tonistiigi/binfmt --install linux/arm/v7 - - name: "Run integration tests" - run: docker run -t --rm --privileged test-integration ./hack/test-integration.sh -test.only-flaky=false - - name: "Run integration tests (flaky)" - run: docker run -t --rm --privileged test-integration ./hack/test-integration.sh -test.only-flaky=true - - test-integration-ipv6: - needs: build-dependencies - timeout-minutes: 15 - name: ipv6 | ${{ matrix.containerd }} | ${{ matrix.ubuntu }} - runs-on: "ubuntu-${{ matrix.ubuntu }}" - strategy: - fail-fast: false - matrix: - include: - - ubuntu: 24.04 - containerd: v2.0.5 - arch: amd64 - env: - CONTAINERD_VERSION: "${{ matrix.containerd }}" - ARCH: "${{ matrix.arch }}" - UBUNTU_VERSION: "${{ matrix.ubuntu }}" - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - fetch-depth: 1 - - name: Enable ipv4 and ipv6 forwarding - run: | - sudo sysctl -w net.ipv6.conf.all.forwarding=1 - sudo sysctl -w net.ipv4.ip_forward=1 - - name: "Expose GitHub Runtime variables for gha" - uses: crazy-max/ghaction-github-runtime@3cb05d89e1f492524af3d41a1c98c83bc3025124 # v3.1.0 - - name: Enable IPv6 for Docker, and configure docker to use containerd for gha - run: | - sudo mkdir -p /etc/docker - echo '{"ipv6": true, "fixed-cidr-v6": "2001:db8:1::/64", "experimental": true, "ip6tables": true}' | sudo tee /etc/docker/daemon.json - sudo systemctl restart docker - - name: "Prepare integration test environment" - run: | - docker buildx create --name with-gha --use - docker buildx build \ - --output=type=docker \ - --cache-from type=gha,scope=test-integration-dependencies-${ARCH} \ - -t test-integration --target test-integration --build-arg UBUNTU_VERSION=${UBUNTU_VERSION} --build-arg CONTAINERD_VERSION=${CONTAINERD_VERSION} . - - name: "Remove snap loopback devices (conflicts with our loopback devices in TestRunDevice)" - run: | - sudo systemctl disable --now snapd.service snapd.socket - sudo apt-get purge -qq snapd - sudo losetup -Dv - sudo losetup -lv - - name: "Register QEMU (tonistiigi/binfmt)" - run: | - # `--install all` will only install emulation for architectures that cannot be natively executed - # Since some arm64 platforms do provide native fallback execution for 32 bits, - # armv7 emulation may or may not be installed, causing variance in the result of `uname -m`. - # To avoid that, we explicitly list the architectures we do want emulation for. - docker run --privileged --rm tonistiigi/binfmt --install linux/amd64 - docker run --privileged --rm tonistiigi/binfmt --install linux/arm64 - docker run --privileged --rm tonistiigi/binfmt --install linux/arm/v7 - - name: "Run integration tests" - # The nested IPv6 network inside docker and qemu is complex and needs a bunch of sysctl config. - # Therefore, it's hard to debug why the IPv6 tests fail in such an isolation layer. - # On the other side, using the host network is easier at configuration. - # Besides, each job is running on a different instance, which means using host network here - # is safe and has no side effects on others. - run: docker run --network host -t --rm --privileged test-integration ./hack/test-integration.sh -test.only-ipv6 - - test-integration-rootless: - needs: build-dependencies - timeout-minutes: 40 - name: "${{ matrix.target }} | ${{ matrix.containerd }} | ${{ matrix.rootlesskit }} | ${{ matrix.ubuntu }} || ${{ matrix.nerdctl }}" - runs-on: "${{ matrix.runner }}" - strategy: - fail-fast: false - matrix: - include: - - ubuntu: 22.04 - containerd: v1.6.38 - rootlesskit: v1.1.1 # Deprecated - target: rootless - runner: "ubuntu-22.04" - arch: amd64 - - ubuntu: 24.04 - containerd: v2.0.5 - rootlesskit: v2.3.4 - target: rootless - arch: amd64 - runner: "ubuntu-24.04" - - ubuntu: 24.04 - containerd: v2.0.5 - rootlesskit: v2.3.4 - target: rootless - arch: arm64 - runner: "ubuntu-24.04-arm" - - ubuntu: 24.04 - containerd: v2.0.5 - rootlesskit: v2.3.4 - target: rootless-port-slirp4netns - arch: amd64 - runner: "ubuntu-24.04" - - ubuntu: 24.04 - containerd: v2.0.5 - rootlesskit: v2.3.4 - target: rootless - arch: amd64 - runner: "ubuntu-24.04" - nerdctl: "nerdctl.gomodjail" - comment: "Flaky, not a blocker for merging PRs" - env: - CONTAINERD_VERSION: "${{ matrix.containerd }}" - ARCH: "${{ matrix.arch }}" - UBUNTU_VERSION: "${{ matrix.ubuntu }}" - ROOTLESSKIT_VERSION: "${{ matrix.rootlesskit }}" - TEST_TARGET: "test-integration-${{ matrix.target }}" - NERDCTL: "${{ matrix.nerdctl }}" - steps: - - name: "Set up AppArmor" - if: matrix.ubuntu == '24.04' - run: | - cat <, - include - - /usr/local/bin/rootlesskit flags=(unconfined) { - userns, - - # Site-specific additions and overrides. See local/README for details. - include if exists - } - EOT - sudo systemctl restart apparmor.service - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - fetch-depth: 1 - - name: "Register QEMU (tonistiigi/binfmt)" - run: | - # `--install all` will only install emulation for architectures that cannot be natively executed - # Since some arm64 platforms do provide native fallback execution for 32 bits, - # armv7 emulation may or may not be installed, causing variance in the result of `uname -m`. - # To avoid that, we explicitly list the architectures we do want emulation for. - docker run --privileged --rm tonistiigi/binfmt --install linux/amd64 - docker run --privileged --rm tonistiigi/binfmt --install linux/arm64 - docker run --privileged --rm tonistiigi/binfmt --install linux/arm/v7 - - name: "Expose GitHub Runtime variables for gha" - uses: crazy-max/ghaction-github-runtime@3cb05d89e1f492524af3d41a1c98c83bc3025124 # v3.1.0 - - name: "Prepare (network driver=slirp4netns, port driver=builtin)" - run: | - docker buildx create --name with-gha --use - docker buildx build \ - --output=type=docker \ - --cache-from type=gha,scope=test-integration-dependencies-${ARCH} \ - -t ${TEST_TARGET} --target ${TEST_TARGET} --build-arg UBUNTU_VERSION=${UBUNTU_VERSION} --build-arg CONTAINERD_VERSION=${CONTAINERD_VERSION} --build-arg ROOTLESSKIT_VERSION=${ROOTLESSKIT_VERSION} . - - name: "Disable BuildKit for RootlessKit v1 (workaround for issue #622)" - run: | - # https://github.com/containerd/nerdctl/issues/622 - WORKAROUND_ISSUE_622= - if echo "${ROOTLESSKIT_VERSION}" | grep -q v1; then - WORKAROUND_ISSUE_622=1 - fi - echo "WORKAROUND_ISSUE_622=${WORKAROUND_ISSUE_622}" >> "$GITHUB_ENV" - - name: "Test (network driver=slirp4netns, port driver=builtin)" - run: docker run -t --rm --privileged -e WORKAROUND_ISSUE_622=${WORKAROUND_ISSUE_622} ${TEST_TARGET} /test-integration-rootless.sh ./hack/test-integration.sh -test.only-flaky=false -test.target=${NERDCTL} - - name: "Test (network driver=slirp4netns, port driver=builtin) (flaky)" - if: matrix.nerdctl != 'nerdctl.gomodjail' - run: docker run -t --rm --privileged -e WORKAROUND_ISSUE_622=${WORKAROUND_ISSUE_622} ${TEST_TARGET} /test-integration-rootless.sh ./hack/test-integration.sh -test.only-flaky=true -test.target=${NERDCTL} - - test-integration-host: - name: "in-host${{ inputs.hack }}" - uses: ./.github/workflows/job-test-in-host.yml - strategy: - fail-fast: false - matrix: - include: - # Test on windows w/o canary - - runner: windows-2022 - - runner: windows-2025 - canary: true - # Test docker on linux - - runner: ubuntu-24.04 - binary: docker - - # FIXME: running nerdctl on the host is work in progress - # (we miss runc to be installed on the host - and obviously other deps) - # Plan is to pause this for now and first consolidate dependencies management (wrt Dockerfile vs. host-testing CI) - # before we can really start testing linux nerdctl on the host. - # - runner: ubuntu-24.04 - # - runner: ubuntu-24.04 - # canary: true - with: - timeout: 45 - runner: ${{ matrix.runner }} - binary: ${{ matrix.binary != '' && matrix.binary || 'nerdctl' }} - canary: ${{ matrix.canary && true || false }} - go-version: 1.24 - windows-cni-version: v0.3.1 - containerd-version: 2.0.5 - # Note: these as for amd64 - containerd-sha: 88ab31f3e78e4d2fa12dcb933032122d11d441c83b79a89c6c8076f871e50df8 - containerd-service-sha: 12a76c13cad132222d2b3d2025e56212d205d37eca77508dbbfcdf6ababbf70a - linux-cni-version: v1.7.1 - linux-cni-sha: 1a28a0506bfe5bcdc981caf1a49eeab7e72da8321f1119b7be85f22621013098 diff --git a/.github/workflows/workflow-tigron.yml b/.github/workflows/workflow-tigron.yml deleted file mode 100644 index 81ddbac1e75..00000000000 --- a/.github/workflows/workflow-tigron.yml +++ /dev/null @@ -1,91 +0,0 @@ -name: tigron - -on: - push: - branches: - - main - - 'release/**' - pull_request: - paths: 'mod/tigron/**' - -env: - GO_VERSION: "1.24" - GOTOOLCHAIN: local - -jobs: - lint: - timeout-minutes: 15 - name: "${{ matrix.goos }} ${{ matrix.runner }} | go ${{ matrix.canary }}" - runs-on: ${{ matrix.runner }} - defaults: - run: - shell: bash - strategy: - matrix: - include: - - runner: ubuntu-24.04 - - runner: macos-15 - - runner: windows-2022 - - runner: ubuntu-24.04 - goos: freebsd - - runner: ubuntu-24.04 - canary: go-canary - steps: - - name: "Checkout project" - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - fetch-depth: 100 - - if: ${{ matrix.canary }} - name: "Init (canary): retrieve GO_VERSION" - run: | - latest_go="$(. ./hack/provisioning/version/fetch.sh; go::canary::for::go-setup)" - printf "GO_VERSION=%s\n" "$latest_go" >> "$GITHUB_ENV" - [ "$latest_go" != "" ] || \ - echo "::warning title=No canary go::There is currently no canary go version to test. Steps will not run." - - if: ${{ env.GO_VERSION != '' }} - name: "Install go" - uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0 - with: - go-version: ${{ env.GO_VERSION }} - check-latest: true - - if: ${{ env.GO_VERSION != '' }} - name: "Install tools" - run: | - cd mod/tigron - echo "::group:: make install-dev-tools" - make install-dev-tools - if [ "$RUNNER_OS" == macOS ]; then - brew install yamllint shellcheck - fi - echo "::endgroup::" - - if: ${{ env.GO_VERSION != '' && env.RUNNER_OS == 'Linux' && matrix.goos == '' }} - name: "lint" - env: - NO_COLOR: true - run: | - echo "::group:: lint" - cd mod/tigron - export LINT_COMMIT_RANGE="$(jq -r '.after + "..HEAD"' ${GITHUB_EVENT_PATH})" - make lint - echo "::endgroup::" - - if: ${{ env.GO_VERSION != '' }} - name: "test-unit" - run: | - echo "::group:: unit test" - cd mod/tigron - make test-unit - echo "::endgroup::" - - if: ${{ env.GO_VERSION != '' }} - name: "test-unit-race" - run: | - echo "::group:: race test" - cd mod/tigron - make test-unit-race - echo "::endgroup::" - - if: ${{ env.GO_VERSION != '' }} - name: "test-unit-bench" - run: | - echo "::group:: bench" - cd mod/tigron - make test-unit-bench - echo "::endgroup::" diff --git a/Makefile b/Makefile index d7dce5f0fd3..9352ae93e66 100644 --- a/Makefile +++ b/Makefile @@ -135,8 +135,9 @@ lint-go-all: $(call title, $@) @cd $(MAKEFILE_DIR) \ && GOOS=linux make lint-go \ - && GOOS=windows make lint-go \ - && GOOS=freebsd make lint-go + && GOOS=freebsd make lint-go \ + && GOOS=darwin make lint-go \ + && GOOS=windows make lint-go $(call footer, $@) lint-yaml: @@ -180,6 +181,7 @@ lint-licenses-all: @cd $(MAKEFILE_DIR) \ && GOOS=linux make lint-licenses \ && GOOS=freebsd make lint-licenses \ + && GOOS=darwin make lint-licenses \ && GOOS=windows make lint-licenses $(call footer, $@) @@ -197,6 +199,7 @@ fix-go-all: @cd $(MAKEFILE_DIR) \ && GOOS=linux make fix-go \ && GOOS=freebsd make fix-go \ + && GOOS=darwin make fix-go \ && GOOS=windows make fix-go $(call footer, $@) diff --git a/cmd/nerdctl/builder/builder_build_oci_layout_test.go b/cmd/nerdctl/builder/builder_build_oci_layout_test.go index 758675e85a1..38ae05004e5 100644 --- a/cmd/nerdctl/builder/builder_build_oci_layout_test.go +++ b/cmd/nerdctl/builder/builder_build_oci_layout_test.go @@ -27,6 +27,7 @@ import ( "github.com/containerd/nerdctl/mod/tigron/expect" "github.com/containerd/nerdctl/mod/tigron/require" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/pkg/testutil" "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" @@ -100,14 +101,13 @@ CMD ["echo", "test-nerdctl-build-context-oci-layout"]` }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { assert.Assert( t, strings.Contains( helpers.Capture("run", "--rm", data.Identifier("child")), "test-nerdctl-build-context-oci-layout", ), - info, ) }, } diff --git a/cmd/nerdctl/builder/builder_build_test.go b/cmd/nerdctl/builder/builder_build_test.go index 09ff4bfc8b4..abcbde859d8 100644 --- a/cmd/nerdctl/builder/builder_build_test.go +++ b/cmd/nerdctl/builder/builder_build_test.go @@ -29,6 +29,7 @@ import ( "github.com/containerd/nerdctl/mod/tigron/expect" "github.com/containerd/nerdctl/mod/tigron/require" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/pkg/buildkitutil" "github.com/containerd/nerdctl/v2/pkg/platformutil" @@ -339,7 +340,7 @@ COPY %s /`, testFileName) }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { // Expecting testFileName to exist inside the output target directory assert.Equal(t, data.Temp().Load(testFileName), testContent, "file content is identical") }, @@ -353,7 +354,7 @@ COPY %s /`, testFileName) }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { assert.Equal(t, data.Temp().Load(testFileName), testContent, "file content is identical") }, } @@ -890,7 +891,7 @@ func TestBuildAttestation(t *testing.T) { }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { data.Temp().Exists("dir-for-bom", testSBOMFileName) }, } @@ -912,7 +913,7 @@ func TestBuildAttestation(t *testing.T) { }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { data.Temp().Exists("dir-for-prov", testProvenanceFileName) }, } @@ -935,7 +936,7 @@ func TestBuildAttestation(t *testing.T) { }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { data.Temp().Exists("dir-for-attest", testSBOMFileName) data.Temp().Exists("dir-for-attest", testProvenanceFileName) }, diff --git a/cmd/nerdctl/builder/builder_builder_test.go b/cmd/nerdctl/builder/builder_builder_test.go index da912cc0af9..75100795e70 100644 --- a/cmd/nerdctl/builder/builder_builder_test.go +++ b/cmd/nerdctl/builder/builder_builder_test.go @@ -30,6 +30,7 @@ import ( "github.com/containerd/nerdctl/mod/tigron/test" "github.com/containerd/nerdctl/v2/pkg/buildkitutil" + "github.com/containerd/nerdctl/v2/pkg/referenceutil" "github.com/containerd/nerdctl/v2/pkg/testutil" "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" ) @@ -152,14 +153,19 @@ CMD ["echo", "nerdctl-builder-debug-test-string"]`, testutil.CommonImage) // FIXME: this test should be rewritten to dynamically retrieve the ids, and use images // available on all platforms oldImage := testutil.BusyboxImage - oldImageSha := "7b3ccabffc97de872a30dfd234fd972a66d247c8cfc69b0550f276481852627c" + parsedOldImage, err := referenceutil.Parse(oldImage) + assert.NilError(helpers.T(), err) + oldImageSha := parsedOldImage.Digest.String() + newImage := testutil.AlpineImage - newImageSha := "ec14c7992a97fc11425907e908340c6c3d6ff602f5f13d899e6b7027c9b4133a" + parsedNewImage, err := referenceutil.Parse(newImage) + assert.NilError(helpers.T(), err) + newImageSha := parsedNewImage.Digest.String() helpers.Ensure("pull", "--quiet", oldImage) - helpers.Ensure("tag", oldImage, newImage) + helpers.Ensure("tag", oldImage, parsedNewImage.Domain+"/"+parsedNewImage.Path+":"+parsedNewImage.Tag) - dockerfile := fmt.Sprintf(`FROM %s`, newImage) + dockerfile := fmt.Sprintf(`FROM %s`, parsedNewImage.Domain+"/"+parsedNewImage.Path+":"+parsedNewImage.Tag) data.Temp().Save(dockerfile, "Dockerfile") data.Labels().Set("oldImageSha", oldImageSha) data.Labels().Set("newImageSha", newImageSha) diff --git a/cmd/nerdctl/compose/compose_config_test.go b/cmd/nerdctl/compose/compose_config_test.go index e9f16c6a92d..20f4789bff4 100644 --- a/cmd/nerdctl/compose/compose_config_test.go +++ b/cmd/nerdctl/compose/compose_config_test.go @@ -24,6 +24,7 @@ import ( "github.com/containerd/nerdctl/mod/tigron/expect" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" ) @@ -111,7 +112,7 @@ services: testCase.Expected = func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ ExitCode: 0, - Output: func(stdout, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { assert.Assert(t, data.Labels().Get("hash") != stdout, "hash should be different") }, } diff --git a/cmd/nerdctl/compose/compose_cp_linux_test.go b/cmd/nerdctl/compose/compose_cp_linux_test.go index 7d5dea8502c..7d3d0ab61e7 100644 --- a/cmd/nerdctl/compose/compose_cp_linux_test.go +++ b/cmd/nerdctl/compose/compose_cp_linux_test.go @@ -24,6 +24,7 @@ import ( "github.com/containerd/nerdctl/mod/tigron/expect" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/pkg/testutil" "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" @@ -79,7 +80,7 @@ services: }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { copied := data.Temp().Load("test-file2") assert.Equal(t, copied, testFileContent) }, diff --git a/cmd/nerdctl/compose/compose_create_linux_test.go b/cmd/nerdctl/compose/compose_create_linux_test.go index c1a94dfd2c6..61ca348acd3 100644 --- a/cmd/nerdctl/compose/compose_create_linux_test.go +++ b/cmd/nerdctl/compose/compose_create_linux_test.go @@ -25,6 +25,7 @@ import ( "github.com/containerd/nerdctl/mod/tigron/expect" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/pkg/testutil" "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" @@ -66,7 +67,7 @@ services: Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { return helpers.Command("compose", "-f", data.Labels().Get("composeYaml"), "ps", "svc0", "-a") }, - Expected: test.Expects(expect.ExitCodeSuccess, nil, func(stdout, info string, t *testing.T) { + Expected: test.Expects(expect.ExitCodeSuccess, nil, func(stdout string, t tig.T) { assert.Assert(t, strings.Contains(stdout, "created") || strings.Contains(stdout, "Created"), "stdout should contain `created`") @@ -125,7 +126,7 @@ services: Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { return helpers.Command("compose", "-f", data.Labels().Get("composeYaml"), "ps", "svc0", "-a") }, - Expected: test.Expects(expect.ExitCodeSuccess, nil, func(stdout, info string, t *testing.T) { + Expected: test.Expects(expect.ExitCodeSuccess, nil, func(stdout string, t tig.T) { assert.Assert(t, strings.Contains(stdout, "created") || strings.Contains(stdout, "Created"), "stdout should contain `created`") @@ -137,7 +138,7 @@ services: Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { return helpers.Command("compose", "-f", data.Labels().Get("composeYaml"), "ps", "svc1", "-a") }, - Expected: test.Expects(expect.ExitCodeSuccess, nil, func(stdout, info string, t *testing.T) { + Expected: test.Expects(expect.ExitCodeSuccess, nil, func(stdout string, t tig.T) { assert.Assert(t, strings.Contains(stdout, "created") || strings.Contains(stdout, "Created"), "stdout should contain `created`") diff --git a/cmd/nerdctl/container/container_attach_linux_test.go b/cmd/nerdctl/container/container_attach_linux_test.go index 083fd4a194e..8f5208512fa 100644 --- a/cmd/nerdctl/container/container_attach_linux_test.go +++ b/cmd/nerdctl/container/container_attach_linux_test.go @@ -28,6 +28,7 @@ import ( "github.com/containerd/nerdctl/mod/tigron/expect" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/pkg/testutil" "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" @@ -64,7 +65,7 @@ func TestAttach(t *testing.T) { cmd.Run(&test.Expected{ ExitCode: 0, Errors: []error{errors.New("read detach keys")}, - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { assert.Assert(t, strings.Contains(helpers.Capture("inspect", "--format", "json", data.Identifier()), "\"Running\":true")) }, }) @@ -93,7 +94,7 @@ func TestAttach(t *testing.T) { Errors: []error{errors.New("read detach keys")}, Output: expect.All( expect.Contains("markmark"), - func(stdout string, info string, t *testing.T) { + func(stdout string, t tig.T) { assert.Assert(t, strings.Contains(helpers.Capture("inspect", "--format", "json", data.Identifier()), "\"Running\":true")) }, ), @@ -125,7 +126,7 @@ func TestAttachDetachKeys(t *testing.T) { cmd.Run(&test.Expected{ ExitCode: 0, Errors: []error{errors.New("read detach keys")}, - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { assert.Assert(t, strings.Contains(helpers.Capture("inspect", "--format", "json", data.Identifier()), "\"Running\":true")) }, }) @@ -153,7 +154,7 @@ func TestAttachDetachKeys(t *testing.T) { Errors: []error{errors.New("read detach keys")}, Output: expect.All( expect.Contains("markmark"), - func(stdout string, info string, t *testing.T) { + func(stdout string, t tig.T) { assert.Assert(t, strings.Contains(helpers.Capture("inspect", "--format", "json", data.Identifier()), "\"Running\":true")) }, ), @@ -182,8 +183,8 @@ func TestAttachForAutoRemovedContainer(t *testing.T) { cmd.Run(&test.Expected{ ExitCode: 0, Errors: []error{errors.New("read detach keys")}, - Output: func(stdout string, info string, t *testing.T) { - assert.Assert(t, strings.Contains(helpers.Capture("inspect", "--format", "json", data.Identifier()), "\"Running\":true"), info) + Output: func(stdout string, t tig.T) { + assert.Assert(t, strings.Contains(helpers.Capture("inspect", "--format", "json", data.Identifier()), "\"Running\":true")) }, }) } @@ -202,7 +203,7 @@ func TestAttachForAutoRemovedContainer(t *testing.T) { ExitCode: 42, Output: expect.All( expect.Contains("markmark"), - func(stdout string, info string, t *testing.T) { + func(stdout string, t tig.T) { assert.Assert(t, !strings.Contains(helpers.Capture("ps", "-a"), data.Identifier())) }, ), diff --git a/cmd/nerdctl/container/container_commit_linux_test.go b/cmd/nerdctl/container/container_commit_linux_test.go index e1a167c0633..fb5c96367c4 100644 --- a/cmd/nerdctl/container/container_commit_linux_test.go +++ b/cmd/nerdctl/container/container_commit_linux_test.go @@ -21,6 +21,7 @@ import ( "testing" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/pkg/testutil" "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" @@ -41,7 +42,7 @@ func TestKubeCommitSave(t *testing.T) { nerdtest.KubeCtlCommand(helpers, "wait", "pod", identifier, "--for=condition=ready", "--timeout=1m").Run(&test.Expected{}) nerdtest.KubeCtlCommand(helpers, "exec", identifier, "--", "mkdir", "-p", "/tmp/whatever").Run(&test.Expected{}) nerdtest.KubeCtlCommand(helpers, "get", "pods", identifier, "-o", "jsonpath={ .status.containerStatuses[0].containerID }").Run(&test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { containerID = strings.TrimPrefix(stdout, "containerd://") }, }) @@ -73,7 +74,7 @@ func TestKubeCommitSave(t *testing.T) { cmd = nerdtest.KubeCtlCommand(helpers, "get", "pods", tID, "-o", "jsonpath={ .status.hostIPs[0].ip }") cmd.Run(&test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { registryIP = stdout }, }) diff --git a/cmd/nerdctl/container/container_create_linux_test.go b/cmd/nerdctl/container/container_create_linux_test.go index d6a4e91e0f2..4b6192e6049 100644 --- a/cmd/nerdctl/container/container_create_linux_test.go +++ b/cmd/nerdctl/container/container_create_linux_test.go @@ -30,6 +30,7 @@ import ( "github.com/containerd/containerd/v2/defaults" "github.com/containerd/nerdctl/mod/tigron/require" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/cmd/nerdctl/helpers" "github.com/containerd/nerdctl/v2/pkg/testutil" @@ -231,7 +232,7 @@ func TestIssue2993(t *testing.T) { return &test.Expected{ ExitCode: 1, Errors: []error{errors.New("is already used by ID")}, - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { containersDirs, err := os.ReadDir(data.Labels().Get(containersPathKey)) assert.NilError(t, err) assert.Equal(t, len(containersDirs), 1) @@ -278,7 +279,7 @@ func TestIssue2993(t *testing.T) { return &test.Expected{ ExitCode: 0, Errors: []error{}, - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { containersDirs, err := os.ReadDir(data.Labels().Get(containersPathKey)) assert.NilError(t, err) assert.Equal(t, len(containersDirs), 0) diff --git a/cmd/nerdctl/container/container_create_test.go b/cmd/nerdctl/container/container_create_test.go index f10536eecce..a22a33d18f5 100644 --- a/cmd/nerdctl/container/container_create_test.go +++ b/cmd/nerdctl/container/container_create_test.go @@ -25,6 +25,7 @@ import ( "github.com/containerd/nerdctl/mod/tigron/expect" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/pkg/inspecttypes/dockercompat" "github.com/containerd/nerdctl/v2/pkg/testutil" @@ -104,13 +105,13 @@ func TestCreateHyperVContainer(t *testing.T) { helpers.Command("container", "inspect", data.Labels().Get("cID")). Run(&test.Expected{ ExitCode: expect.ExitCodeNoCheck, - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { var dc []dockercompat.Container err := json.Unmarshal([]byte(stdout), &dc) if err != nil || len(dc) == 0 { return } - assert.Equal(t, len(dc), 1, "Unexpectedly got multiple results\n"+info) + assert.Equal(t, len(dc), 1, "Unexpectedly got multiple results\n") ran = dc[0].State.Status == "exited" }, }) diff --git a/cmd/nerdctl/container/container_restart_linux_test.go b/cmd/nerdctl/container/container_restart_linux_test.go index f4d82482f1f..954c9760db7 100644 --- a/cmd/nerdctl/container/container_restart_linux_test.go +++ b/cmd/nerdctl/container/container_restart_linux_test.go @@ -28,6 +28,7 @@ import ( "github.com/containerd/nerdctl/mod/tigron/expect" "github.com/containerd/nerdctl/mod/tigron/require" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/pkg/testutil" "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" @@ -153,12 +154,12 @@ func TestRestartWithSignal(t *testing.T) { Output: expect.All( // Check that we saw SIGUSR1 inside the container expect.Contains(nerdtest.SignalCaught), - func(stdout string, info string, t *testing.T) { + func(stdout string, t tig.T) { // Ensure the container was restarted nerdtest.EnsureContainerStarted(helpers, data.Identifier()) // Check the new pid is different newpid := strconv.Itoa(nerdtest.InspectContainer(helpers, data.Identifier()).State.Pid) - assert.Assert(helpers.T(), newpid != data.Labels().Get("oldpid"), info) + assert.Assert(helpers.T(), newpid != data.Labels().Get("oldpid")) }, ), } diff --git a/cmd/nerdctl/container/container_run_cgroup_linux_test.go b/cmd/nerdctl/container/container_run_cgroup_linux_test.go index 9f9e9812f13..ab981f4a3dd 100644 --- a/cmd/nerdctl/container/container_run_cgroup_linux_test.go +++ b/cmd/nerdctl/container/container_run_cgroup_linux_test.go @@ -35,6 +35,7 @@ import ( "github.com/containerd/nerdctl/mod/tigron/expect" "github.com/containerd/nerdctl/mod/tigron/require" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/pkg/cmd/container" "github.com/containerd/nerdctl/v2/pkg/idutil/containerwalker" @@ -310,7 +311,7 @@ func TestRunDevice(t *testing.T) { Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { return helpers.Command("exec", data.Labels().Get("id"), "sh", "-ec", "echo -n \"overwritten-lo1-content\">"+lo[1].Device) }, - Expected: test.Expects(expect.ExitCodeSuccess, nil, func(stdout string, info string, t *testing.T) { + Expected: test.Expects(expect.ExitCodeSuccess, nil, func(stdout string, t tig.T) { lo1Read, err := os.ReadFile(lo[1].Device) assert.NilError(t, err) assert.Equal(t, string(bytes.Trim(lo1Read, "\x00")), "overwritten-lo1-content") @@ -523,7 +524,7 @@ func TestRunBlkioSettingCgroupV2(t *testing.T) { return &test.Expected{ ExitCode: 0, Output: expect.All( - func(stdout string, info string, t *testing.T) { + func(stdout string, t tig.T) { assert.Assert(t, strings.Contains(helpers.Capture("inspect", "--format", "{{.HostConfig.BlkioWeight}}", data.Identifier()), "150")) }, ), @@ -545,7 +546,7 @@ func TestRunBlkioSettingCgroupV2(t *testing.T) { return &test.Expected{ ExitCode: 0, Output: expect.All( - func(stdout string, info string, t *testing.T) { + func(stdout string, t tig.T) { inspectOut := helpers.Capture("inspect", "--format", "{{range .HostConfig.BlkioWeightDevice}}{{.Weight}}{{end}}", data.Identifier()) assert.Assert(t, strings.Contains(inspectOut, "100")) }, @@ -574,7 +575,7 @@ func TestRunBlkioSettingCgroupV2(t *testing.T) { return &test.Expected{ ExitCode: 0, Output: expect.All( - func(stdout string, info string, t *testing.T) { + func(stdout string, t tig.T) { inspectOut := helpers.Capture("inspect", "--format", "{{range .HostConfig.BlkioDeviceReadBps}}{{.Rate}}{{end}}", data.Identifier()) assert.Assert(t, strings.Contains(inspectOut, "1048576")) }, @@ -603,7 +604,7 @@ func TestRunBlkioSettingCgroupV2(t *testing.T) { return &test.Expected{ ExitCode: 0, Output: expect.All( - func(stdout string, info string, t *testing.T) { + func(stdout string, t tig.T) { inspectOut := helpers.Capture("inspect", "--format", "{{range .HostConfig.BlkioDeviceWriteBps}}{{.Rate}}{{end}}", data.Identifier()) assert.Assert(t, strings.Contains(inspectOut, "2097152")) }, @@ -632,7 +633,7 @@ func TestRunBlkioSettingCgroupV2(t *testing.T) { return &test.Expected{ ExitCode: 0, Output: expect.All( - func(stdout string, info string, t *testing.T) { + func(stdout string, t tig.T) { inspectOut := helpers.Capture("inspect", "--format", "{{range .HostConfig.BlkioDeviceReadIOps}}{{.Rate}}{{end}}", data.Identifier()) assert.Assert(t, strings.Contains(inspectOut, "1000")) }, @@ -661,7 +662,7 @@ func TestRunBlkioSettingCgroupV2(t *testing.T) { return &test.Expected{ ExitCode: 0, Output: expect.All( - func(stdout string, info string, t *testing.T) { + func(stdout string, t tig.T) { inspectOut := helpers.Capture("inspect", "--format", "{{range .HostConfig.BlkioDeviceWriteIOps}}{{.Rate}}{{end}}", data.Identifier()) assert.Assert(t, strings.Contains(inspectOut, "2000")) }, @@ -696,7 +697,7 @@ func TestRunCPURealTimeSettingCgroupV1(t *testing.T) { return &test.Expected{ ExitCode: 0, Output: expect.All( - func(stdout string, info string, t *testing.T) { + func(stdout string, t tig.T) { rtRuntime := helpers.Capture("inspect", "--format", "{{.HostConfig.CPURealtimeRuntime}}", data.Identifier()) rtPeriod := helpers.Capture("inspect", "--format", "{{.HostConfig.CPURealtimePeriod}}", data.Identifier()) assert.Assert(t, strings.Contains(rtRuntime, "950000")) diff --git a/cmd/nerdctl/container/container_run_linux_test.go b/cmd/nerdctl/container/container_run_linux_test.go index 736a346ac07..02c0ab97714 100644 --- a/cmd/nerdctl/container/container_run_linux_test.go +++ b/cmd/nerdctl/container/container_run_linux_test.go @@ -36,6 +36,7 @@ import ( "github.com/containerd/nerdctl/mod/tigron/expect" "github.com/containerd/nerdctl/mod/tigron/require" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/cmd/nerdctl/helpers" "github.com/containerd/nerdctl/v2/pkg/rootlessutil" @@ -544,7 +545,7 @@ func TestRunWithDetachKeys(t *testing.T) { Errors: []error{errors.New("detach keys")}, Output: expect.All( expect.Contains("markmark"), - func(stdout string, info string, t *testing.T) { + func(stdout string, t tig.T) { assert.Assert(t, strings.Contains(helpers.Capture("inspect", "--format", "json", data.Identifier()), "\"Running\":true")) }, ), @@ -612,7 +613,7 @@ func TestIssue3568(t *testing.T) { Errors: []error{errors.New("detach keys")}, Output: expect.All( expect.Contains("markmark"), - func(stdout string, info string, t *testing.T) { + func(stdout string, t tig.T) { assert.Assert(t, strings.Contains(helpers.Capture("inspect", "--format", "json", data.Identifier()), "\"Running\":true")) }, ), @@ -647,7 +648,7 @@ func TestPortBindingWithCustomHost(t *testing.T) { ExitCode: 0, Errors: []error{}, Output: expect.All( - func(stdout string, info string, t *testing.T) { + func(stdout string, t tig.T) { resp, err := nettestutil.HTTPGet(address, 30, false) assert.NilError(t, err) diff --git a/cmd/nerdctl/container/container_run_mount_linux_test.go b/cmd/nerdctl/container/container_run_mount_linux_test.go index c941d8d39fb..3ac50387b29 100644 --- a/cmd/nerdctl/container/container_run_mount_linux_test.go +++ b/cmd/nerdctl/container/container_run_mount_linux_test.go @@ -29,6 +29,7 @@ import ( "github.com/containerd/containerd/v2/core/mount" "github.com/containerd/nerdctl/mod/tigron/expect" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/cmd/nerdctl/helpers" "github.com/containerd/nerdctl/v2/pkg/rootlessutil" @@ -307,7 +308,7 @@ func TestRunBindMountTmpfs(t *testing.T) { } func mountExistsWithOpt(mountPoint, mountOpt string) test.Comparator { - return func(stdout, info string, t *testing.T) { + return func(stdout string, t tig.T) { lines := strings.Split(strings.TrimSpace(stdout), "\n") mountOutput := []string{} for _, line := range lines { diff --git a/cmd/nerdctl/container/container_run_network_linux_test.go b/cmd/nerdctl/container/container_run_network_linux_test.go index 46b9057e11a..737f9a425c9 100644 --- a/cmd/nerdctl/container/container_run_network_linux_test.go +++ b/cmd/nerdctl/container/container_run_network_linux_test.go @@ -40,6 +40,7 @@ import ( "github.com/containerd/nerdctl/mod/tigron/expect" "github.com/containerd/nerdctl/mod/tigron/require" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/pkg/rootlessutil" "github.com/containerd/nerdctl/v2/pkg/testutil" @@ -371,7 +372,7 @@ func TestRunWithInvalidPortThenCleanUp(t *testing.T) { return &test.Expected{ ExitCode: 1, Errors: []error{errdefs.ErrInvalidArgument}, - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { getAddrHash := func(addr string) string { const addrHashLen = 8 @@ -543,13 +544,13 @@ func TestSharedNetworkSetup(t *testing.T) { }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { containerName2 := data.Identifier() - assert.Assert(t, strings.Contains(helpers.Capture("exec", containerName2, "wget", "-qO-", "http://127.0.0.1:80"), testutil.NginxAlpineIndexHTMLSnippet), info) + assert.Assert(t, strings.Contains(helpers.Capture("exec", containerName2, "wget", "-qO-", "http://127.0.0.1:80"), testutil.NginxAlpineIndexHTMLSnippet)) helpers.Ensure("restart", data.Labels().Get("containerName1")) helpers.Ensure("stop", "--time=1", containerName2) helpers.Ensure("start", containerName2) - assert.Assert(t, strings.Contains(helpers.Capture("exec", containerName2, "wget", "-qO-", "http://127.0.0.1:80"), testutil.NginxAlpineIndexHTMLSnippet), info) + assert.Assert(t, strings.Contains(helpers.Capture("exec", containerName2, "wget", "-qO-", "http://127.0.0.1:80"), testutil.NginxAlpineIndexHTMLSnippet)) }, } }, @@ -615,8 +616,8 @@ func TestSharedNetworkSetup(t *testing.T) { // The Option doesnt throw an error but is never inserted to the resolv.conf return &test.Expected{ ExitCode: 0, - Output: func(stdout string, info string, t *testing.T) { - assert.Assert(t, !strings.Contains(stdout, "attempts:5"), info) + Output: func(stdout string, t tig.T) { + assert.Assert(t, !strings.Contains(stdout, "attempts:5")) }, } }, @@ -938,9 +939,6 @@ func TestHostNetworkHostName(t *testing.T) { nerdtest.Setup() testCase := &test.Case{ Require: require.Not(require.Windows), - Setup: func(data test.Data, helpers test.Helpers) { - data.Labels().Set("containerName1", data.Identifier()) - }, Cleanup: func(data test.Data, helpers test.Helpers) { helpers.Anyhow("rm", "-f", data.Identifier()) }, @@ -949,9 +947,14 @@ func TestHostNetworkHostName(t *testing.T) { }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { - hostname := stdout - assert.Assert(t, strings.Compare(strings.TrimSpace(helpers.Capture("run", "--name", data.Identifier(), "--network", "host", testutil.AlpineImage, "cat", "/etc/hostname")), strings.TrimSpace(hostname)) == 0, info) + Output: func(stdout string, t tig.T) { + hostHostname := stdout + containerHostname := helpers.Capture("run", "--name", data.Identifier(), "--network", "host", testutil.AlpineImage, "cat", "/etc/hostname") + assert.Equal( + t, + strings.TrimSpace(containerHostname), + strings.TrimSpace(hostHostname), + ) }, } }, @@ -964,26 +967,27 @@ func TestNoneNetworkDnsConfigs(t *testing.T) { testCase := &test.Case{ Require: require.Not(require.Windows), Setup: func(data test.Data, helpers test.Helpers) { - data.Labels().Set("containerName1", data.Identifier()) + helpers.Ensure( + "run", "-d", "--name", data.Identifier(), + "--network", "none", + "--dns", "0.1.2.3", + "--dns-search", "example.com", + "--dns-option", "timeout:3", + "--dns-option", "attempts:5", + testutil.NginxAlpineImage) }, Cleanup: func(data test.Data, helpers test.Helpers) { helpers.Anyhow("rm", "-f", data.Identifier()) }, Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { - return helpers.Command("run", "-d", "--name", data.Identifier(), "--network", "none", "--dns", "0.1.2.3", "--dns-search", "example.com", "--dns-option", "timeout:3", "--dns-option", "attempts:5", testutil.NginxAlpineImage) - }, - Expected: func(data test.Data, helpers test.Helpers) *test.Expected { - return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { - out := helpers.Capture("exec", data.Identifier(), "cat", "/etc/resolv.conf") - assert.Assert(t, strings.Contains(out, "0.1.2.3"), info) - assert.Assert(t, strings.Contains(out, "example.com"), info) - assert.Assert(t, strings.Contains(out, "attempts:5"), info) - assert.Assert(t, strings.Contains(out, "timeout:3"), info) - - }, - } + return helpers.Command("exec", data.Identifier(), "cat", "/etc/resolv.conf") }, + Expected: test.Expects(expect.ExitCodeSuccess, nil, expect.Contains( + "0.1.2.3", + "example.com", + "attempts:5", + "timeout:3", + )), } testCase.Run(t) } @@ -993,26 +997,28 @@ func TestHostNetworkDnsConfigs(t *testing.T) { testCase := &test.Case{ Require: require.Not(require.Windows), Setup: func(data test.Data, helpers test.Helpers) { - data.Labels().Set("containerName1", data.Identifier()) + helpers.Ensure( + "run", "-d", "--name", data.Identifier(), + "--network", "host", + "--dns", "0.1.2.3", + "--dns-search", "example.com", + "--dns-option", "timeout:3", + "--dns-option", "attempts:5", + testutil.NginxAlpineImage, + ) }, Cleanup: func(data test.Data, helpers test.Helpers) { helpers.Anyhow("rm", "-f", data.Identifier()) }, Command: func(data test.Data, helpers test.Helpers) test.TestableCommand { - return helpers.Command("run", "-d", "--name", data.Identifier(), "--network", "host", "--dns", "0.1.2.3", "--dns-search", "example.com", "--dns-option", "timeout:3", "--dns-option", "attempts:5", testutil.NginxAlpineImage) - }, - Expected: func(data test.Data, helpers test.Helpers) *test.Expected { - return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { - out := helpers.Capture("exec", data.Identifier(), "cat", "/etc/resolv.conf") - assert.Assert(t, strings.Contains(out, "0.1.2.3"), info) - assert.Assert(t, strings.Contains(out, "example.com"), info) - assert.Assert(t, strings.Contains(out, "attempts:5"), info) - assert.Assert(t, strings.Contains(out, "timeout:3"), info) - - }, - } + return helpers.Command("exec", data.Identifier(), "cat", "/etc/resolv.conf") }, + Expected: test.Expects(expect.ExitCodeSuccess, nil, expect.Contains( + "0.1.2.3", + "example.com", + "attempts:5", + "timeout:3", + )), } testCase.Run(t) } diff --git a/cmd/nerdctl/container/container_run_soci_linux_test.go b/cmd/nerdctl/container/container_run_soci_linux_test.go index 670a15dc7de..07ad11a0f50 100644 --- a/cmd/nerdctl/container/container_run_soci_linux_test.go +++ b/cmd/nerdctl/container/container_run_soci_linux_test.go @@ -25,6 +25,7 @@ import ( "github.com/containerd/nerdctl/mod/tigron/require" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/pkg/testutil" "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" @@ -44,7 +45,7 @@ func TestRunSoci(t *testing.T) { testCase.Setup = func(data test.Data, helpers test.Helpers) { helpers.Custom("mount").Run(&test.Expected{ ExitCode: 0, - Output: func(stdout, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { data.Labels().Set("beforeCount", strconv.Itoa(strings.Count(stdout, "fuse.rawBridge"))) }, }) @@ -60,12 +61,12 @@ func TestRunSoci(t *testing.T) { testCase.Expected = func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { var afterCount int beforeCount, _ := strconv.Atoi(data.Labels().Get("beforeCount")) helpers.Custom("mount").Run(&test.Expected{ - Output: func(stdout, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { afterCount = strings.Count(stdout, "fuse.rawBridge") }, }) diff --git a/cmd/nerdctl/container/container_run_test.go b/cmd/nerdctl/container/container_run_test.go index 23b74b97714..161f4bc67d3 100644 --- a/cmd/nerdctl/container/container_run_test.go +++ b/cmd/nerdctl/container/container_run_test.go @@ -37,6 +37,7 @@ import ( "github.com/containerd/nerdctl/mod/tigron/expect" "github.com/containerd/nerdctl/mod/tigron/require" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/cmd/nerdctl/helpers" "github.com/containerd/nerdctl/v2/pkg/testutil" @@ -156,7 +157,7 @@ func TestRunExitCode(t *testing.T) { Output: expect.All( expect.Match(regexp.MustCompile("Exited [(]123[)][A-Za-z0-9 ]+"+data.Identifier("exit123"))), expect.Match(regexp.MustCompile("Exited [(]0[)][A-Za-z0-9 ]+"+data.Identifier("exit0"))), - func(stdout, info string, t *testing.T) { + func(stdout string, t tig.T) { assert.Equal(t, nerdtest.InspectContainer(helpers, data.Identifier("exit0")).State.Status, "exited") assert.Equal(t, nerdtest.InspectContainer(helpers, data.Identifier("exit123")).State.Status, "exited") }, diff --git a/cmd/nerdctl/container/container_start_linux_test.go b/cmd/nerdctl/container/container_start_linux_test.go index 4f56cc9d679..690d4f8dc12 100644 --- a/cmd/nerdctl/container/container_start_linux_test.go +++ b/cmd/nerdctl/container/container_start_linux_test.go @@ -27,6 +27,7 @@ import ( "github.com/containerd/nerdctl/mod/tigron/expect" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/pkg/testutil" "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" @@ -73,7 +74,7 @@ func TestStartDetachKeys(t *testing.T) { ExitCode: 0, Errors: []error{errors.New("detach keys")}, Output: expect.All( - func(stdout string, info string, t *testing.T) { + func(stdout string, t tig.T) { assert.Assert(t, strings.Contains(helpers.Capture("inspect", "--format", "json", data.Identifier()), "\"Running\":true")) }, ), diff --git a/cmd/nerdctl/container/multi_platform_linux_test.go b/cmd/nerdctl/container/multi_platform_linux_test.go index eeb7c9f9004..668d8d93cc9 100644 --- a/cmd/nerdctl/container/multi_platform_linux_test.go +++ b/cmd/nerdctl/container/multi_platform_linux_test.go @@ -32,13 +32,12 @@ import ( func testMultiPlatformRun(base *testutil.Base, alpineImage string) { t := base.T - testutil.RequireExecPlatform(t, "linux/amd64", "linux/arm64", "linux/arm/v7") + testutil.RequireExecPlatform(t, "linux/amd64", "linux/arm64") testCases := map[string]string{ - "amd64": "x86_64", - "arm64": "aarch64", - "arm": "armv7l", - "linux/arm": "armv7l", - "linux/arm/v7": "armv7l", + "amd64": "x86_64", + "arm64": "aarch64", + "linux/arm64": "aarch64", + "linux/arm64/v8": "aarch64", } for plat, expectedUnameM := range testCases { t.Logf("Testing %q (%q)", plat, expectedUnameM) @@ -56,7 +55,7 @@ func TestMultiPlatformBuildPush(t *testing.T) { testutil.DockerIncompatible(t) // non-buildx version of `docker build` lacks multi-platform. Also, `docker push` lacks --platform. testutil.RequiresBuild(t) testutil.RegisterBuildCacheCleanup(t) - testutil.RequireExecPlatform(t, "linux/amd64", "linux/arm64", "linux/arm/v7") + testutil.RequireExecPlatform(t, "linux/amd64", "linux/arm64") base := testutil.NewBase(t) tID := testutil.Identifier(t) reg := testregistry.NewWithNoAuth(base, 0, false) @@ -71,9 +70,9 @@ RUN echo dummy buildCtx := helpers.CreateBuildContext(t, dockerfile) - base.Cmd("build", "-t", imageName, "--platform=amd64,arm64,linux/arm/v7", buildCtx).AssertOK() + base.Cmd("build", "-t", imageName, "--platform=amd64,linux/arm64/v8", buildCtx).AssertOK() testMultiPlatformRun(base, imageName) - base.Cmd("push", "--platform=amd64,arm64,linux/arm/v7", imageName).AssertOK() + base.Cmd("push", "--platform=amd64,linux/arm64/v8", imageName).AssertOK() } // TestMultiPlatformBuildPushNoRun tests if the push succeeds in a situation where nerdctl builds @@ -83,7 +82,7 @@ func TestMultiPlatformBuildPushNoRun(t *testing.T) { testutil.DockerIncompatible(t) // non-buildx version of `docker build` lacks multi-platform. Also, `docker push` lacks --platform. testutil.RequiresBuild(t) testutil.RegisterBuildCacheCleanup(t) - testutil.RequireExecPlatform(t, "linux/amd64", "linux/arm64", "linux/arm/v7") + testutil.RequireExecPlatform(t, "linux/amd64", "linux/arm64") base := testutil.NewBase(t) tID := testutil.Identifier(t) reg := testregistry.NewWithNoAuth(base, 0, false) @@ -98,9 +97,9 @@ CMD echo dummy buildCtx := helpers.CreateBuildContext(t, dockerfile) - base.Cmd("build", "-t", imageName, "--platform=amd64,arm64,linux/arm/v7", buildCtx).AssertOK() + base.Cmd("build", "-t", imageName, "--platform=amd64,linux/arm64/v8", buildCtx).AssertOK() testMultiPlatformRun(base, imageName) - base.Cmd("push", "--platform=amd64,arm64,linux/arm/v7", imageName).AssertOK() + base.Cmd("push", "--platform=amd64,linux/arm64/v8", imageName).AssertOK() } func TestMultiPlatformPullPushAllPlatforms(t *testing.T) { @@ -123,7 +122,7 @@ func TestMultiPlatformComposeUpBuild(t *testing.T) { testutil.DockerIncompatible(t) testutil.RequiresBuild(t) testutil.RegisterBuildCacheCleanup(t) - testutil.RequireExecPlatform(t, "linux/amd64", "linux/arm64", "linux/arm/v7") + testutil.RequireExecPlatform(t, "linux/amd64", "linux/arm64") base := testutil.NewBase(t) const dockerComposeYAML = ` @@ -135,14 +134,9 @@ services: - 8080:80 svc1: build: . - platform: arm64 + platform: linux/arm64/v8 ports: - 8081:80 - svc2: - build: . - platform: linux/arm/v7 - ports: - - 8082:80 ` dockerfile := fmt.Sprintf(`FROM %s RUN uname -m > /usr/share/nginx/html/index.html @@ -159,7 +153,6 @@ RUN uname -m > /usr/share/nginx/html/index.html testCases := map[string]string{ "http://127.0.0.1:8080": "x86_64", "http://127.0.0.1:8081": "aarch64", - "http://127.0.0.1:8082": "armv7l", } for testURL, expectedIndexHTML := range testCases { diff --git a/cmd/nerdctl/image/image_history_test.go b/cmd/nerdctl/image/image_history_test.go index 1281c00fa47..ffdf1030ed4 100644 --- a/cmd/nerdctl/image/image_history_test.go +++ b/cmd/nerdctl/image/image_history_test.go @@ -28,6 +28,7 @@ import ( "github.com/containerd/nerdctl/mod/tigron/require" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/pkg/formatter" "github.com/containerd/nerdctl/v2/pkg/testutil" @@ -90,65 +91,65 @@ func TestImageHistory(t *testing.T) { { Description: "trunc, no quiet, human", Command: test.Command("image", "history", "--human=true", "--format=json", testutil.CommonImage), - Expected: test.Expects(0, nil, func(stdout string, info string, t *testing.T) { + Expected: test.Expects(0, nil, func(stdout string, t tig.T) { history, err := decode(stdout) - assert.NilError(t, err, info) - assert.Equal(t, len(history), 2, info) + assert.NilError(t, err, "decode should not fail") + assert.Equal(t, len(history), 2, "history should be 2 in length") localTimeL1, _ := time.Parse(time.RFC3339, "2021-03-31T10:21:23-07:00") localTimeL2, _ := time.Parse(time.RFC3339, "2021-03-31T10:21:21-07:00") compTime1, _ := time.Parse(time.RFC3339, history[0].CreatedAt) compTime2, _ := time.Parse(time.RFC3339, history[1].CreatedAt) - assert.Equal(t, compTime1.UTC().String(), localTimeL1.UTC().String(), info) - assert.Equal(t, history[0].CreatedBy, "/bin/sh -c #(nop) CMD [\"/bin/sh\"]", info) - assert.Equal(t, compTime2.UTC().String(), localTimeL2.UTC().String(), info) - assert.Equal(t, history[1].CreatedBy, "/bin/sh -c #(nop) ADD file:3b16ffee2b26d8af5…", info) - - assert.Equal(t, history[0].Size, "0B", info) - assert.Equal(t, history[0].CreatedSince, formatter.TimeSinceInHuman(compTime1), info) - assert.Equal(t, history[0].Snapshot, "", info) - assert.Equal(t, history[0].Comment, "", info) - - assert.Equal(t, history[1].Size, "5.947MB", info) - assert.Equal(t, history[1].CreatedSince, formatter.TimeSinceInHuman(compTime2), info) - assert.Equal(t, history[1].Snapshot, "sha256:56bf55b8eed1f0b4794a30386e4d1d3da949c…", info) - assert.Equal(t, history[1].Comment, "", info) + assert.Equal(t, compTime1.UTC().String(), localTimeL1.UTC().String()) + assert.Equal(t, history[0].CreatedBy, "/bin/sh -c #(nop) CMD [\"/bin/sh\"]") + assert.Equal(t, compTime2.UTC().String(), localTimeL2.UTC().String()) + assert.Equal(t, history[1].CreatedBy, "/bin/sh -c #(nop) ADD file:3b16ffee2b26d8af5…") + + assert.Equal(t, history[0].Size, "0B") + assert.Equal(t, history[0].CreatedSince, formatter.TimeSinceInHuman(compTime1)) + assert.Equal(t, history[0].Snapshot, "") + assert.Equal(t, history[0].Comment, "") + + assert.Equal(t, history[1].Size, "5.947MB") + assert.Equal(t, history[1].CreatedSince, formatter.TimeSinceInHuman(compTime2)) + assert.Equal(t, history[1].Snapshot, "sha256:56bf55b8eed1f0b4794a30386e4d1d3da949c…") + assert.Equal(t, history[1].Comment, "") }), }, { Description: "no human - dates and sizes and not prettyfied", Command: test.Command("image", "history", "--human=false", "--format=json", testutil.CommonImage), - Expected: test.Expects(0, nil, func(stdout string, info string, t *testing.T) { + Expected: test.Expects(0, nil, func(stdout string, t tig.T) { history, err := decode(stdout) - assert.NilError(t, err, info) - assert.Equal(t, history[0].Size, "0", info) - assert.Equal(t, history[0].CreatedSince, history[0].CreatedAt, info) - assert.Equal(t, history[1].Size, "5947392", info) - assert.Equal(t, history[1].CreatedSince, history[1].CreatedAt, info) + assert.NilError(t, err, "decode should not fail") + assert.Equal(t, history[0].Size, "0") + assert.Equal(t, history[0].CreatedSince, history[0].CreatedAt) + assert.Equal(t, history[1].Size, "5947392") + assert.Equal(t, history[1].CreatedSince, history[1].CreatedAt) }), }, { Description: "no trunc - do not truncate sha or cmd", Command: test.Command("image", "history", "--human=false", "--no-trunc", "--format=json", testutil.CommonImage), - Expected: test.Expects(0, nil, func(stdout string, info string, t *testing.T) { + Expected: test.Expects(0, nil, func(stdout string, t tig.T) { history, err := decode(stdout) - assert.NilError(t, err, info) - assert.Equal(t, history[1].Snapshot, "sha256:56bf55b8eed1f0b4794a30386e4d1d3da949c25bcb5155e898097cd75dc77c2a") + assert.NilError(t, err, "decode should not fail") + assert.Equal(t, history[1].Snapshot, "sha256:a16e98724c05975ee8c40d8fe389c3481373d34ab20a1cf52ea2accc43f71f4c") assert.Equal(t, history[1].CreatedBy, "/bin/sh -c #(nop) ADD file:3b16ffee2b26d8af5db152fcc582aaccd9e1ec9e3343874e9969a205550fe07d in / ") }), }, { Description: "Quiet has no effect with format, so, go no-json, no-trunc", Command: test.Command("image", "history", "--human=false", "--no-trunc", "--quiet", testutil.CommonImage), - Expected: test.Expects(0, nil, func(stdout string, info string, t *testing.T) { - assert.Equal(t, stdout, "\nsha256:56bf55b8eed1f0b4794a30386e4d1d3da949c25bcb5155e898097cd75dc77c2a\n") + Expected: test.Expects(0, nil, func(stdout string, t tig.T) { + assert.Equal(t, stdout, "\nsha256:a16e98724c05975ee8c40d8fe389c3481373d34ab20a1cf52ea2accc43f71f4c\n") }), }, { Description: "With quiet, trunc has no effect", Command: test.Command("image", "history", "--human=false", "--no-trunc", "--quiet", testutil.CommonImage), - Expected: test.Expects(0, nil, func(stdout string, info string, t *testing.T) { - assert.Equal(t, stdout, "\nsha256:56bf55b8eed1f0b4794a30386e4d1d3da949c25bcb5155e898097cd75dc77c2a\n") + Expected: test.Expects(0, nil, func(stdout string, t tig.T) { + assert.Equal(t, stdout, "\nsha256:a16e98724c05975ee8c40d8fe389c3481373d34ab20a1cf52ea2accc43f71f4c\n") }), }, }, diff --git a/cmd/nerdctl/image/image_inspect_test.go b/cmd/nerdctl/image/image_inspect_test.go index f0c53db2346..5ee549686c6 100644 --- a/cmd/nerdctl/image/image_inspect_test.go +++ b/cmd/nerdctl/image/image_inspect_test.go @@ -28,6 +28,7 @@ import ( "github.com/containerd/nerdctl/mod/tigron/require" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/pkg/inspecttypes/dockercompat" "github.com/containerd/nerdctl/v2/pkg/testutil" @@ -45,14 +46,14 @@ func TestImageInspectSimpleCases(t *testing.T) { { Description: "Contains some stuff", Command: test.Command("image", "inspect", testutil.CommonImage), - Expected: test.Expects(0, nil, func(stdout string, info string, t *testing.T) { + Expected: test.Expects(0, nil, func(stdout string, t tig.T) { var dc []dockercompat.Image err := json.Unmarshal([]byte(stdout), &dc) - assert.NilError(t, err, "Unable to unmarshal output\n"+info) - assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results\n"+info) - assert.Assert(t, len(dc[0].RootFS.Layers) > 0, info) - assert.Assert(t, dc[0].Architecture != "", info) - assert.Assert(t, dc[0].Size > 0, info) + assert.NilError(t, err, "Unable to unmarshal output\n") + assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results\n") + assert.Assert(t, len(dc[0].RootFS.Layers) > 0, "there should be at least one rootfs layer\n") + assert.Assert(t, dc[0].Architecture != "", "architecture should be set\n") + assert.Assert(t, dc[0].Size > 0, "size should be > 0 \n") }), }, { @@ -115,11 +116,11 @@ func TestImageInspectDifferentValidReferencesForTheSameImage(t *testing.T) { Command: test.Command("image", "inspect", "busybox"), Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { var dc []dockercompat.Image err := json.Unmarshal([]byte(stdout), &dc) - assert.NilError(t, err, "Unable to unmarshal output\n"+info) - assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results\n"+info) + assert.NilError(t, err, "Unable to unmarshal output\n") + assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results\n") reference := dc[0].ID sha := strings.TrimPrefix(dc[0].RepoDigests[0], "busybox@sha256:") @@ -140,11 +141,11 @@ func TestImageInspectDifferentValidReferencesForTheSameImage(t *testing.T) { Command: test.Command("image", "inspect", "busybox"), Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { var dc []dockercompat.Image err := json.Unmarshal([]byte(stdout), &dc) - assert.NilError(t, err, "Unable to unmarshal output\n"+info) - assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results\n"+info) + assert.NilError(t, err, "Unable to unmarshal output\n") + assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results\n") reference := dc[0].ID sha := strings.TrimPrefix(dc[0].RepoDigests[0], "busybox@sha256:") @@ -173,11 +174,11 @@ func TestImageInspectDifferentValidReferencesForTheSameImage(t *testing.T) { Command: test.Command("image", "inspect", "busybox"), Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { var dc []dockercompat.Image err := json.Unmarshal([]byte(stdout), &dc) - assert.NilError(t, err, "Unable to unmarshal output\n"+info) - assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results\n"+info) + assert.NilError(t, err, "Unable to unmarshal output\n") + assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results\n") sha := strings.TrimPrefix(dc[0].RepoDigests[0], "busybox@sha256:") for _, id := range []string{"doesnotexist", "doesnotexist:either", "busybox:bogustag"} { @@ -196,11 +197,11 @@ func TestImageInspectDifferentValidReferencesForTheSameImage(t *testing.T) { Command: test.Command("image", "inspect", "busybox"), Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { var dc []dockercompat.Image err := json.Unmarshal([]byte(stdout), &dc) - assert.NilError(t, err, "Unable to unmarshal output\n"+info) - assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results\n"+info) + assert.NilError(t, err, "Unable to unmarshal output\n") + assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results\n") for _, id := range []string{"∞∞∞∞∞∞∞∞∞∞", "busybox:∞∞∞∞∞∞∞∞∞∞"} { cmd := helpers.Command("image", "inspect", id) @@ -218,11 +219,11 @@ func TestImageInspectDifferentValidReferencesForTheSameImage(t *testing.T) { Command: test.Command("image", "inspect", "busybox", "busybox"), Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { var dc []dockercompat.Image err := json.Unmarshal([]byte(stdout), &dc) - assert.NilError(t, err, "Unable to unmarshal output\n"+info) - assert.Equal(t, 2, len(dc), "Unexpectedly did not get 2 results\n"+info) + assert.NilError(t, err, "Unable to unmarshal output\n") + assert.Equal(t, 2, len(dc), "Unexpectedly did not get 2 results\n") reference := nerdtest.InspectImage(helpers, "busybox") assert.Equal(t, dc[0].ID, reference.ID) assert.Equal(t, dc[1].ID, reference.ID) diff --git a/cmd/nerdctl/image/image_list_test.go b/cmd/nerdctl/image/image_list_test.go index 6eba01c84c5..80a6d24379b 100644 --- a/cmd/nerdctl/image/image_list_test.go +++ b/cmd/nerdctl/image/image_list_test.go @@ -31,6 +31,7 @@ import ( "github.com/containerd/nerdctl/mod/tigron/expect" "github.com/containerd/nerdctl/mod/tigron/require" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/pkg/tabutil" "github.com/containerd/nerdctl/v2/pkg/testutil" @@ -52,16 +53,16 @@ func TestImages(t *testing.T) { Command: test.Command("images"), Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { lines := strings.Split(strings.TrimSpace(stdout), "\n") - assert.Assert(t, len(lines) >= 2, info) + assert.Assert(t, len(lines) >= 2, "there should be at least two lines\n") header := "REPOSITORY\tTAG\tIMAGE ID\tCREATED\tPLATFORM\tSIZE\tBLOB SIZE" if nerdtest.IsDocker() { header = "REPOSITORY\tTAG\tIMAGE ID\tCREATED\tSIZE" } tab := tabutil.NewReader(header) err := tab.ParseHeader(lines[0]) - assert.NilError(t, err, info) + assert.NilError(t, err, "ParseHeader should not fail\n") found := false for _, line := range lines[1:] { repo, _ := tab.ReadRow(line, "REPOSITORY") @@ -71,7 +72,7 @@ func TestImages(t *testing.T) { break } } - assert.Assert(t, found, info) + assert.Assert(t, found, "we should have found an image\n") }, } }, @@ -83,12 +84,12 @@ func TestImages(t *testing.T) { return &test.Expected{ Output: expect.All( expect.Contains(testutil.CommonImage), - func(stdout string, info string, t *testing.T) { + func(stdout string, t tig.T) { lines := strings.Split(strings.TrimSpace(stdout), "\n") - assert.Assert(t, len(lines) >= 2, info) + assert.Assert(t, len(lines) >= 2, "there should be at least two lines\n") tab := tabutil.NewReader("NAME\tIMAGE ID\tCREATED\tPLATFORM\tSIZE\tBLOB SIZE") err := tab.ParseHeader(lines[0]) - assert.NilError(t, err, info) + assert.NilError(t, err, "ParseHeader should not fail\n") found := false for _, line := range lines[1:] { name, _ := tab.ReadRow(line, "NAME") @@ -98,7 +99,7 @@ func TestImages(t *testing.T) { } } - assert.Assert(t, found, info) + assert.Assert(t, found, "we should have found an image\n") }, ), } @@ -109,12 +110,12 @@ func TestImages(t *testing.T) { Command: test.Command("images", "--format", "'{{json .CreatedAt}}'"), Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { lines := strings.Split(strings.TrimSpace(stdout), "\n") - assert.Assert(t, len(lines) >= 2, info) + assert.Assert(t, len(lines) >= 2, "there should be at least two lines\n") createdTimes := lines slices.Reverse(createdTimes) - assert.Assert(t, slices.IsSorted(createdTimes), info) + assert.Assert(t, slices.IsSorted(createdTimes), "created times should be sorted\n") }, } }, @@ -343,7 +344,7 @@ func TestImagesKubeWithKubeHideDupe(t *testing.T) { Command: test.Command("--kube-hide-dupe", "images"), Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { var imageID string var skipLine int lines := strings.Split(strings.TrimSpace(stdout), "\n") @@ -353,7 +354,7 @@ func TestImagesKubeWithKubeHideDupe(t *testing.T) { } tab := tabutil.NewReader(header) err := tab.ParseHeader(lines[0]) - assert.NilError(t, err, info) + assert.NilError(t, err, "ParseHeader should not fail\n") found := true for i, line := range lines[1:] { repo, _ := tab.ReadRow(line, "REPOSITORY") @@ -374,7 +375,7 @@ func TestImagesKubeWithKubeHideDupe(t *testing.T) { break } } - assert.Assert(t, found, info) + assert.Assert(t, found, "We should have found the image\n") }, } }, diff --git a/cmd/nerdctl/image/image_load_test.go b/cmd/nerdctl/image/image_load_test.go index 6598ab93db5..2618b81c64f 100644 --- a/cmd/nerdctl/image/image_load_test.go +++ b/cmd/nerdctl/image/image_load_test.go @@ -28,6 +28,7 @@ import ( "github.com/containerd/nerdctl/mod/tigron/expect" "github.com/containerd/nerdctl/mod/tigron/require" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/pkg/testutil" "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" @@ -61,7 +62,7 @@ func TestLoadStdinFromPipe(t *testing.T) { return &test.Expected{ Output: expect.All( expect.Contains(fmt.Sprintf("Loaded image: %s:latest", identifier)), - func(stdout string, info string, t *testing.T) { + func(stdout string, t tig.T) { assert.Assert(t, strings.Contains(helpers.Capture("images"), identifier)) }, ), diff --git a/cmd/nerdctl/image/image_prune_test.go b/cmd/nerdctl/image/image_prune_test.go index 402ea7bb94a..f745534e363 100644 --- a/cmd/nerdctl/image/image_prune_test.go +++ b/cmd/nerdctl/image/image_prune_test.go @@ -29,6 +29,7 @@ import ( "github.com/containerd/nerdctl/mod/tigron/expect" "github.com/containerd/nerdctl/mod/tigron/require" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/pkg/testutil" "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" @@ -87,13 +88,13 @@ func TestImagePrune(t *testing.T) { identifier := data.Identifier() return &test.Expected{ Output: expect.All( - func(stdout string, info string, t *testing.T) { - assert.Assert(t, !strings.Contains(stdout, identifier), info) + func(stdout string, t tig.T) { + assert.Assert(t, !strings.Contains(stdout, identifier)) }, - func(stdout string, info string, t *testing.T) { + func(stdout string, t tig.T) { imgList := helpers.Capture("images") assert.Assert(t, !strings.Contains(imgList, ""), imgList) - assert.Assert(t, strings.Contains(imgList, identifier), info) + assert.Assert(t, strings.Contains(imgList, identifier)) }, ), } @@ -133,18 +134,18 @@ func TestImagePrune(t *testing.T) { Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ Output: expect.All( - func(stdout string, info string, t *testing.T) { - assert.Assert(t, !strings.Contains(stdout, data.Identifier()), info) + func(stdout string, t tig.T) { + assert.Assert(t, !strings.Contains(stdout, data.Identifier())) }, - func(stdout string, info string, t *testing.T) { + func(stdout string, t tig.T) { imgList := helpers.Capture("images") - assert.Assert(t, strings.Contains(imgList, data.Identifier()), info) + assert.Assert(t, strings.Contains(imgList, data.Identifier())) assert.Assert(t, !strings.Contains(imgList, ""), imgList) helpers.Ensure("rm", "-f", data.Identifier()) removed := helpers.Capture("image", "prune", "--force", "--all") - assert.Assert(t, strings.Contains(removed, data.Identifier()), info) + assert.Assert(t, strings.Contains(removed, data.Identifier())) imgList = helpers.Capture("images") - assert.Assert(t, !strings.Contains(imgList, data.Identifier()), info) + assert.Assert(t, !strings.Contains(imgList, data.Identifier())) }, ), } @@ -174,18 +175,18 @@ LABEL version=0.1`, testutil.CommonImage) Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ Output: expect.All( - func(stdout string, info string, t *testing.T) { - assert.Assert(t, !strings.Contains(stdout, data.Identifier()), info) + func(stdout string, t tig.T) { + assert.Assert(t, !strings.Contains(stdout, data.Identifier())) }, - func(stdout string, info string, t *testing.T) { + func(stdout string, t tig.T) { imgList := helpers.Capture("images") - assert.Assert(t, strings.Contains(imgList, data.Identifier()), info) + assert.Assert(t, strings.Contains(imgList, data.Identifier())) }, - func(stdout string, info string, t *testing.T) { + func(stdout string, t tig.T) { prune := helpers.Capture("image", "prune", "--force", "--all", "--filter", "label=foo=bar") - assert.Assert(t, strings.Contains(prune, data.Identifier()), info) + assert.Assert(t, strings.Contains(prune, data.Identifier())) imgList := helpers.Capture("images") - assert.Assert(t, !strings.Contains(imgList, data.Identifier()), info) + assert.Assert(t, !strings.Contains(imgList, data.Identifier())) }, ), } @@ -216,9 +217,9 @@ CMD ["echo", "nerdctl-test-image-prune-until"]`, testutil.CommonImage) return &test.Expected{ Output: expect.All( expect.DoesNotContain(data.Labels().Get("imageID")), - func(stdout string, info string, t *testing.T) { + func(stdout string, t tig.T) { imgList := helpers.Capture("images") - assert.Assert(t, strings.Contains(imgList, data.Labels().Get("imageID")), info) + assert.Assert(t, strings.Contains(imgList, data.Labels().Get("imageID"))) }, ), } @@ -235,9 +236,9 @@ CMD ["echo", "nerdctl-test-image-prune-until"]`, testutil.CommonImage) return &test.Expected{ Output: expect.All( expect.Contains(data.Labels().Get("imageID")), - func(stdout string, info string, t *testing.T) { + func(stdout string, t tig.T) { imgList := helpers.Capture("images") - assert.Assert(t, !strings.Contains(imgList, data.Labels().Get("imageID")), imgList, info) + assert.Assert(t, !strings.Contains(imgList, data.Labels().Get("imageID")), imgList) }, ), } diff --git a/cmd/nerdctl/image/image_pull_linux_test.go b/cmd/nerdctl/image/image_pull_linux_test.go index 6dd12b34aba..8631085dd5f 100644 --- a/cmd/nerdctl/image/image_pull_linux_test.go +++ b/cmd/nerdctl/image/image_pull_linux_test.go @@ -27,7 +27,9 @@ import ( "github.com/containerd/nerdctl/mod/tigron/expect" "github.com/containerd/nerdctl/mod/tigron/require" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" + "github.com/containerd/nerdctl/v2/pkg/referenceutil" "github.com/containerd/nerdctl/v2/pkg/testutil" "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest/registry" @@ -113,6 +115,7 @@ func TestImagePullPlainHttpWithDefaultPort(t *testing.T) { nerdtest.Setup() var reg *registry.Server + im, _ := referenceutil.Parse(testutil.CommonImage) dockerfile := fmt.Sprintf(`FROM %s CMD ["echo", "nerdctl-build-test-string"] `, testutil.CommonImage) @@ -130,7 +133,7 @@ CMD ["echo", "nerdctl-build-test-string"] reg = nerdtest.RegistryWithNoAuth(data, helpers, 80, false) reg.Setup(data, helpers) testImageRef := fmt.Sprintf("%s/%s:%s", - reg.IP.String(), data.Identifier(), strings.Split(testutil.CommonImage, ":")[1]) + reg.IP.String(), data.Identifier(), im.Tag) buildCtx := data.Temp().Path() helpers.Ensure("build", "-t", testImageRef, buildCtx) @@ -182,7 +185,7 @@ func TestImagePullSoci(t *testing.T) { Setup: func(data test.Data, helpers test.Helpers) { cmd := helpers.Custom("mount") cmd.Run(&test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { data.Labels().Set("remoteSnapshotsInitialCount", strconv.Itoa(strings.Count(stdout, "fuse.rawBridge"))) }, }) @@ -196,7 +199,7 @@ func TestImagePullSoci(t *testing.T) { }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, _ string, t *testing.T) { + Output: func(stdout string, t tig.T) { remoteSnapshotsInitialCount, _ := strconv.Atoi(data.Labels().Get("remoteSnapshotsInitialCount")) remoteSnapshotsActualCount := strings.Count(stdout, "fuse.rawBridge") assert.Equal(t, @@ -218,7 +221,7 @@ func TestImagePullSoci(t *testing.T) { Setup: func(data test.Data, helpers test.Helpers) { cmd := helpers.Custom("mount") cmd.Run(&test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { data.Labels().Set("remoteSnapshotsInitialCount", strconv.Itoa(strings.Count(stdout, "fuse.rawBridge"))) }, }) @@ -232,7 +235,7 @@ func TestImagePullSoci(t *testing.T) { }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { remoteSnapshotsInitialCount, _ := strconv.Atoi(data.Labels().Get("remoteSnapshotsInitialCount")) remoteSnapshotsActualCount := strings.Count(stdout, "fuse.rawBridge") assert.Equal(t, diff --git a/cmd/nerdctl/image/image_push_linux_test.go b/cmd/nerdctl/image/image_push_linux_test.go index bf10f371a23..47fd5f63605 100644 --- a/cmd/nerdctl/image/image_push_linux_test.go +++ b/cmd/nerdctl/image/image_push_linux_test.go @@ -27,7 +27,9 @@ import ( "github.com/containerd/nerdctl/mod/tigron/require" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" + "github.com/containerd/nerdctl/v2/pkg/referenceutil" "github.com/containerd/nerdctl/v2/pkg/testutil" "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" "github.com/containerd/nerdctl/v2/pkg/testutil/testregistry" @@ -37,6 +39,7 @@ func TestPush(t *testing.T) { nerdtest.Setup() var registryNoAuthHTTPRandom, registryNoAuthHTTPDefault, registryTokenAuthHTTPSRandom *testregistry.RegistryServer + commonImage, _ := referenceutil.Parse(testutil.CommonImage) testCase := &test.Case{ Require: require.Linux, @@ -66,7 +69,7 @@ func TestPush(t *testing.T) { Setup: func(data test.Data, helpers test.Helpers) { helpers.Ensure("pull", "--quiet", testutil.CommonImage) testImageRef := fmt.Sprintf("%s:%d/%s:%s", - registryNoAuthHTTPRandom.IP.String(), registryNoAuthHTTPRandom.Port, data.Identifier(), strings.Split(testutil.CommonImage, ":")[1]) + registryNoAuthHTTPRandom.IP.String(), registryNoAuthHTTPRandom.Port, data.Identifier(), commonImage.Tag) data.Labels().Set("testImageRef", testImageRef) helpers.Ensure("tag", testutil.CommonImage, testImageRef) }, @@ -200,7 +203,7 @@ func TestPush(t *testing.T) { }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { blobURL := fmt.Sprintf("http://%s:%d/v2/%s/blobs/%s", registryNoAuthHTTPRandom.IP.String(), registryNoAuthHTTPRandom.Port, data.Identifier(), testutil.NonDistBlobDigest) resp, err := http.Get(blobURL) assert.Assert(t, err, "error making http request") @@ -232,7 +235,7 @@ func TestPush(t *testing.T) { }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { blobURL := fmt.Sprintf("http://%s:%d/v2/%s/blobs/%s", registryNoAuthHTTPRandom.IP.String(), registryNoAuthHTTPRandom.Port, data.Identifier(), testutil.NonDistBlobDigest) resp, err := http.Get(blobURL) assert.Assert(t, err, "error making http request") diff --git a/cmd/nerdctl/image/image_remove_test.go b/cmd/nerdctl/image/image_remove_test.go index 11f2f050636..6e3f4ad3e36 100644 --- a/cmd/nerdctl/image/image_remove_test.go +++ b/cmd/nerdctl/image/image_remove_test.go @@ -26,6 +26,7 @@ import ( "github.com/containerd/nerdctl/mod/tigron/expect" "github.com/containerd/nerdctl/mod/tigron/require" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/pkg/imgutil" "github.com/containerd/nerdctl/v2/pkg/testutil" @@ -63,7 +64,7 @@ func TestRemove(t *testing.T) { return &test.Expected{ ExitCode: 1, Errors: []error{errors.New("image is being used")}, - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { helpers.Command("images").Run(&test.Expected{ Output: expect.Contains(repoName), }) @@ -83,7 +84,7 @@ func TestRemove(t *testing.T) { Command: test.Command("rmi", "-f", testutil.CommonImage), Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { helpers.Command("images").Run(&test.Expected{ Output: expect.DoesNotContain(repoName), }) @@ -108,7 +109,7 @@ func TestRemove(t *testing.T) { return &test.Expected{ ExitCode: 1, Errors: []error{errors.New("image is being used")}, - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { helpers.Command("images").Run(&test.Expected{ Output: expect.Contains(repoName), }) @@ -140,7 +141,7 @@ func TestRemove(t *testing.T) { return &test.Expected{ ExitCode: 0, Errors: []error{}, - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { helpers.Command("images").Run(&test.Expected{ Output: expect.Contains(""), }) @@ -162,7 +163,7 @@ func TestRemove(t *testing.T) { return &test.Expected{ ExitCode: 1, Errors: []error{errors.New("image is being used")}, - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { helpers.Command("images").Run(&test.Expected{ Output: expect.Contains(repoName), }) @@ -184,7 +185,7 @@ func TestRemove(t *testing.T) { Command: test.Command("rmi", "-f", testutil.CommonImage), Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { helpers.Command("images").Run(&test.Expected{ // a created container with removed image doesn't impact other `rmi` command Output: expect.DoesNotContain(repoName, nginxRepoName), @@ -212,7 +213,7 @@ func TestRemove(t *testing.T) { return &test.Expected{ ExitCode: 1, Errors: []error{errors.New("image is being used")}, - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { helpers.Command("images").Run(&test.Expected{ Output: expect.Contains(repoName), }) @@ -246,7 +247,7 @@ func TestRemove(t *testing.T) { return &test.Expected{ ExitCode: 0, Errors: []error{}, - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { helpers.Command("images").Run(&test.Expected{ Output: expect.Contains(""), }) @@ -272,7 +273,7 @@ func TestRemove(t *testing.T) { return &test.Expected{ ExitCode: 1, Errors: []error{errors.New("image is being used")}, - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { helpers.Command("images").Run(&test.Expected{ Output: expect.Contains(repoName), }) @@ -293,7 +294,7 @@ func TestRemove(t *testing.T) { Command: test.Command("rmi", "-f", testutil.CommonImage), Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { helpers.Command("images").Run(&test.Expected{ Output: expect.DoesNotContain(repoName), }) @@ -336,10 +337,10 @@ func TestIssue3016(t *testing.T) { return &test.Expected{ ExitCode: 0, Errors: []error{}, - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { helpers.Command("images", data.Labels().Get(tagIDKey)).Run(&test.Expected{ ExitCode: 0, - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { assert.Equal(t, len(strings.Split(stdout, "\n")), 2) }, }) @@ -378,17 +379,17 @@ func TestRemoveKubeWithKubeHideDupe(t *testing.T) { return &test.Expected{ ExitCode: 0, Errors: []error{}, - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { helpers.Command("--kube-hide-dupe", "images").Run(&test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { lines := strings.Split(strings.TrimSpace(stdout), "\n") - assert.Assert(t, len(lines) == numTags+1, info) + assert.Assert(t, len(lines) == numTags+1) }, }) helpers.Command("images").Run(&test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { lines := strings.Split(strings.TrimSpace(stdout), "\n") - assert.Assert(t, len(lines) == numNoTags+1, info) + assert.Assert(t, len(lines) == numNoTags+1) }, }) }, @@ -410,17 +411,17 @@ func TestRemoveKubeWithKubeHideDupe(t *testing.T) { return &test.Expected{ ExitCode: 0, Errors: []error{}, - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { helpers.Command("--kube-hide-dupe", "images").Run(&test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { lines := strings.Split(strings.TrimSpace(stdout), "\n") - assert.Assert(t, len(lines) == numTags+1, info) + assert.Assert(t, len(lines) == numTags+1) }, }) helpers.Command("images").Run(&test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { lines := strings.Split(strings.TrimSpace(stdout), "\n") - assert.Assert(t, len(lines) == numNoTags+2, info) + assert.Assert(t, len(lines) == numNoTags+2) }, }) }, @@ -440,17 +441,17 @@ func TestRemoveKubeWithKubeHideDupe(t *testing.T) { }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { helpers.Command("--kube-hide-dupe", "images").Run(&test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { lines := strings.Split(strings.TrimSpace(stdout), "\n") - assert.Assert(t, len(lines) == numTags, info) + assert.Assert(t, len(lines) == numTags) }, }) helpers.Command("images").Run(&test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { lines := strings.Split(strings.TrimSpace(stdout), "\n") - assert.Assert(t, len(lines) == numNoTags, info) + assert.Assert(t, len(lines) == numNoTags) }, }) }, @@ -469,7 +470,7 @@ func TestRemoveKubeWithKubeHideDupe(t *testing.T) { }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { helpers.Command("--kube-hide-dupe", "rmi", stdout[0:12]).Run(&test.Expected{ ExitCode: 1, Errors: []error{errors.New("multiple IDs found with provided prefix: ")}, @@ -478,9 +479,9 @@ func TestRemoveKubeWithKubeHideDupe(t *testing.T) { ExitCode: 0, }) helpers.Command("images").Run(&test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { lines := strings.Split(strings.TrimSpace(stdout), "\n") - assert.Assert(t, len(lines) == numNoTags, info) + assert.Assert(t, len(lines) == numNoTags) }, }) }, @@ -499,7 +500,7 @@ func TestRemoveKubeWithKubeHideDupe(t *testing.T) { }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { imgID := strings.Split(stdout, "\n") helpers.Command("--kube-hide-dupe", "rmi", imgID[0]).Run(&test.Expected{ ExitCode: 1, @@ -509,9 +510,9 @@ func TestRemoveKubeWithKubeHideDupe(t *testing.T) { ExitCode: 0, }) helpers.Command("images").Run(&test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { lines := strings.Split(strings.TrimSpace(stdout), "\n") - assert.Assert(t, len(lines) == numNoTags, info) + assert.Assert(t, len(lines) == numNoTags) }, }) }, diff --git a/cmd/nerdctl/image/image_save_test.go b/cmd/nerdctl/image/image_save_test.go index 4f3bf58de6a..7b97f523761 100644 --- a/cmd/nerdctl/image/image_save_test.go +++ b/cmd/nerdctl/image/image_save_test.go @@ -28,6 +28,7 @@ import ( "github.com/containerd/nerdctl/mod/tigron/expect" "github.com/containerd/nerdctl/mod/tigron/require" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" testhelpers "github.com/containerd/nerdctl/v2/cmd/nerdctl/helpers" "github.com/containerd/nerdctl/v2/pkg/testutil" @@ -48,7 +49,7 @@ func TestSaveContent(t *testing.T) { }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { rootfsPath := filepath.Join(data.Temp().Path(), "rootfs") err := testhelpers.ExtractDockerArchive(filepath.Join(data.Temp().Path(), "out.tar"), rootfsPath) assert.NilError(t, err) @@ -188,7 +189,7 @@ func TestSaveMultipleImagesWithSameIDAndLoad(t *testing.T) { return &test.Expected{ ExitCode: 0, Errors: []error{}, - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { assert.Equal(t, strings.Count(stdout, data.Labels().Get("id")), 2) }, } diff --git a/cmd/nerdctl/inspect/inspect_test.go b/cmd/nerdctl/inspect/inspect_test.go index 954b0e73eac..8047923efa8 100644 --- a/cmd/nerdctl/inspect/inspect_test.go +++ b/cmd/nerdctl/inspect/inspect_test.go @@ -23,6 +23,7 @@ import ( "gotest.tools/v3/assert" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/pkg/inspecttypes/dockercompat" "github.com/containerd/nerdctl/v2/pkg/testutil" @@ -50,23 +51,23 @@ func TestInspectSimpleCase(t *testing.T) { }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { var inspectResult []json.RawMessage err := json.Unmarshal([]byte(stdout), &inspectResult) - assert.NilError(t, err, "Unable to unmarshal output\n"+info) - assert.Equal(t, len(inspectResult), 2, "Unexpectedly got multiple results\n"+info) + assert.NilError(t, err, "Unable to unmarshal output\n") + assert.Equal(t, len(inspectResult), 2, "Unexpectedly got multiple results\n") var dci dockercompat.Image err = json.Unmarshal(inspectResult[0], &dci) - assert.NilError(t, err, "Unable to unmarshal output\n"+info) + assert.NilError(t, err, "Unable to unmarshal output\n") inspecti := nerdtest.InspectImage(helpers, testutil.CommonImage) - assert.Equal(t, dci.ID, inspecti.ID, info) + assert.Equal(t, dci.ID, inspecti.ID, "id should match\n") var dcc dockercompat.Container err = json.Unmarshal(inspectResult[1], &dcc) - assert.NilError(t, err, "Unable to unmarshal output\n"+info) + assert.NilError(t, err, "Unable to unmarshal output\n") inspectc := nerdtest.InspectContainer(helpers, data.Identifier()) - assert.Assert(t, dcc.ID == inspectc.ID, info) + assert.Equal(t, dcc.ID, inspectc.ID, "id should match\n") }, } }, diff --git a/cmd/nerdctl/ipfs/ipfs_compose_linux_test.go b/cmd/nerdctl/ipfs/ipfs_compose_linux_test.go index 9a7b09805b5..a06548b13aa 100644 --- a/cmd/nerdctl/ipfs/ipfs_compose_linux_test.go +++ b/cmd/nerdctl/ipfs/ipfs_compose_linux_test.go @@ -29,6 +29,7 @@ import ( "github.com/containerd/nerdctl/mod/tigron/require" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/pkg/testutil" "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" @@ -56,7 +57,7 @@ func TestIPFSCompNoBuild(t *testing.T) { testCase.Setup = func(data test.Data, helpers test.Helpers) { // Start Kubo - ipfsRegistry = registry.NewKuboRegistry(data, helpers, t, nil, 0, nil) + ipfsRegistry = registry.NewKuboRegistry(data, helpers, nil, 0, nil) ipfsRegistry.Setup(data, helpers) data.Labels().Set(ipfsAddrKey, fmt.Sprintf("/ip4/%s/tcp/%d", ipfsRegistry.IP, ipfsRegistry.Port)) @@ -254,12 +255,12 @@ COPY index.html /usr/share/nginx/html/index.html testCase.Expected = func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { resp, err := nettestutil.HTTPGet("http://127.0.0.1:8081", 10, false) assert.NilError(t, err) respBody, err := io.ReadAll(resp.Body) assert.NilError(t, err) - t.Logf("respBody=%q", respBody) + t.Log(fmt.Sprintf("respBody=%q", respBody)) assert.Assert(t, strings.Contains(string(respBody), data.Identifier("indexhtml"))) }, } @@ -269,6 +270,7 @@ COPY index.html /usr/share/nginx/html/index.html } func composeUP(data test.Data, helpers test.Helpers, dockerComposeYAML string, opts string) { + // FIXME: get rid of ComposeDir and remove the typecast comp := testutil.NewComposeDir(helpers.T(), dockerComposeYAML) // defer comp.CleanUp() @@ -318,9 +320,13 @@ func composeUP(data test.Data, helpers test.Helpers, dockerComposeYAML string, o if !wordpressWorking { ccc := helpers.Capture("ps", "-a") + stdout := helpers.Capture("logs", projectName+"-wordpress-1") + stderr := helpers.Err("logs", projectName+"-wordpress-1") helpers.T().Log(ccc) - helpers.T().Error(helpers.Err("logs", projectName+"-wordpress-1")) - helpers.T().Fatalf("wordpress is not working %v", err) + helpers.T().Log(stdout) + helpers.T().Log(stderr) + helpers.T().Log(fmt.Sprintf("wordpress is not working %v", err)) + helpers.T().FailNow() } helpers.Ensure("compose", "-f", comp.YAMLFullPath(), "down", "-v") diff --git a/cmd/nerdctl/ipfs/ipfs_kubo_linux_test.go b/cmd/nerdctl/ipfs/ipfs_kubo_linux_test.go index de1dc16d239..6c09875419d 100644 --- a/cmd/nerdctl/ipfs/ipfs_kubo_linux_test.go +++ b/cmd/nerdctl/ipfs/ipfs_kubo_linux_test.go @@ -48,7 +48,7 @@ func TestIPFSAddrWithKubo(t *testing.T) { testCase.Setup = func(data test.Data, helpers test.Helpers) { helpers.Ensure("pull", "--quiet", testutil.CommonImage) - ipfsRegistry = registry.NewKuboRegistry(data, helpers, t, nil, 0, nil) + ipfsRegistry = registry.NewKuboRegistry(data, helpers, nil, 0, nil) ipfsRegistry.Setup(data, helpers) ipfsAddr := fmt.Sprintf("/ip4/%s/tcp/%d", ipfsRegistry.IP, ipfsRegistry.Port) data.Labels().Set(ipfsAddrKey, ipfsAddr) diff --git a/cmd/nerdctl/ipfs/ipfs_registry_linux_test.go b/cmd/nerdctl/ipfs/ipfs_registry_linux_test.go index 5c044bf36af..d9a8d059fd0 100644 --- a/cmd/nerdctl/ipfs/ipfs_registry_linux_test.go +++ b/cmd/nerdctl/ipfs/ipfs_registry_linux_test.go @@ -30,6 +30,7 @@ import ( "github.com/containerd/nerdctl/mod/tigron/expect" "github.com/containerd/nerdctl/mod/tigron/require" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/pkg/testutil" "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" @@ -40,7 +41,7 @@ func pushToIPFS(helpers test.Helpers, name string, opts ...string) string { cmd := helpers.Command("push", "ipfs://"+name) cmd.WithArgs(opts...) cmd.Run(&test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { lines := strings.Split(stdout, "\n") assert.Equal(t, len(lines) >= 2, true) ipfsCID = lines[len(lines)-2] diff --git a/cmd/nerdctl/network/network_create_linux_test.go b/cmd/nerdctl/network/network_create_linux_test.go index 01ed943467f..6d42809f2ff 100644 --- a/cmd/nerdctl/network/network_create_linux_test.go +++ b/cmd/nerdctl/network/network_create_linux_test.go @@ -26,6 +26,7 @@ import ( "github.com/containerd/nerdctl/mod/tigron/expect" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/pkg/testutil" "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" @@ -58,9 +59,9 @@ func TestNetworkCreate(t *testing.T) { return &test.Expected{ ExitCode: 0, Errors: nil, - Output: func(stdout string, info string, t *testing.T) { - assert.Assert(t, strings.Contains(stdout, data.Labels().Get("subnet")), info) - assert.Assert(t, !strings.Contains(data.Labels().Get("container2"), data.Labels().Get("subnet")), info) + Output: func(stdout string, t tig.T) { + assert.Assert(t, strings.Contains(stdout, data.Labels().Get("subnet"))) + assert.Assert(t, !strings.Contains(data.Labels().Get("container2"), data.Labels().Get("subnet"))) }, } }, @@ -98,7 +99,7 @@ func TestNetworkCreate(t *testing.T) { Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ ExitCode: 0, - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { _, subnet, _ := net.ParseCIDR(data.Labels().Get("subnetStr")) ip := nerdtest.FindIPv6(stdout) assert.Assert(t, subnet.Contains(ip), fmt.Sprintf("subnet %s contains ip %s", subnet, ip)) diff --git a/cmd/nerdctl/network/network_inspect_test.go b/cmd/nerdctl/network/network_inspect_test.go index ed4bb00d1e5..6aafde54a38 100644 --- a/cmd/nerdctl/network/network_inspect_test.go +++ b/cmd/nerdctl/network/network_inspect_test.go @@ -28,6 +28,7 @@ import ( "github.com/containerd/nerdctl/mod/tigron/expect" "github.com/containerd/nerdctl/mod/tigron/require" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/pkg/inspecttypes/dockercompat" "github.com/containerd/nerdctl/v2/pkg/testutil" @@ -69,11 +70,11 @@ func TestNetworkInspect(t *testing.T) { Description: "none", Require: nerdtest.NerdctlNeedsFixing("no issue opened"), Command: test.Command("network", "inspect", "none"), - Expected: test.Expects(0, nil, func(stdout string, info string, t *testing.T) { + Expected: test.Expects(0, nil, func(stdout string, t tig.T) { var dc []dockercompat.Network err := json.Unmarshal([]byte(stdout), &dc) - assert.NilError(t, err, "Unable to unmarshal output\n"+info) - assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results\n"+info) + assert.NilError(t, err, "Unable to unmarshal output\n") + assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results\n") assert.Equal(t, dc[0].Name, "none") }), }, @@ -81,11 +82,11 @@ func TestNetworkInspect(t *testing.T) { Description: "host", Require: nerdtest.NerdctlNeedsFixing("no issue opened"), Command: test.Command("network", "inspect", "host"), - Expected: test.Expects(0, nil, func(stdout string, info string, t *testing.T) { + Expected: test.Expects(0, nil, func(stdout string, t tig.T) { var dc []dockercompat.Network err := json.Unmarshal([]byte(stdout), &dc) - assert.NilError(t, err, "Unable to unmarshal output\n"+info) - assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results\n"+info) + assert.NilError(t, err, "Unable to unmarshal output\n") + assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results\n") assert.Equal(t, dc[0].Name, "host") }), }, @@ -93,11 +94,11 @@ func TestNetworkInspect(t *testing.T) { Description: "bridge", Require: require.Not(require.Windows), Command: test.Command("network", "inspect", "bridge"), - Expected: test.Expects(0, nil, func(stdout string, info string, t *testing.T) { + Expected: test.Expects(0, nil, func(stdout string, t tig.T) { var dc []dockercompat.Network err := json.Unmarshal([]byte(stdout), &dc) - assert.NilError(t, err, "Unable to unmarshal output\n"+info) - assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results\n"+info) + assert.NilError(t, err, "Unable to unmarshal output\n") + assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results\n") assert.Equal(t, dc[0].Name, "bridge") }), }, @@ -105,11 +106,11 @@ func TestNetworkInspect(t *testing.T) { Description: "nat", Require: require.Windows, Command: test.Command("network", "inspect", "nat"), - Expected: test.Expects(0, nil, func(stdout string, info string, t *testing.T) { + Expected: test.Expects(0, nil, func(stdout string, t tig.T) { var dc []dockercompat.Network err := json.Unmarshal([]byte(stdout), &dc) - assert.NilError(t, err, "Unable to unmarshal output\n"+info) - assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results\n"+info) + assert.NilError(t, err, "Unable to unmarshal output\n") + assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results\n") assert.Equal(t, dc[0].Name, "nat") }), }, @@ -122,11 +123,11 @@ func TestNetworkInspect(t *testing.T) { helpers.Anyhow("network", "remove", "custom") }, Command: test.Command("network", "inspect", "custom"), - Expected: test.Expects(0, nil, func(stdout string, info string, t *testing.T) { + Expected: test.Expects(0, nil, func(stdout string, t tig.T) { var dc []dockercompat.Network err := json.Unmarshal([]byte(stdout), &dc) - assert.NilError(t, err, "Unable to unmarshal output\n"+info) - assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results\n"+info) + assert.NilError(t, err, "Unable to unmarshal output\n") + assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results\n") assert.Equal(t, dc[0].Name, "custom") }), }, @@ -139,11 +140,11 @@ func TestNetworkInspect(t *testing.T) { }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { var dc []dockercompat.Network err := json.Unmarshal([]byte(stdout), &dc) - assert.NilError(t, err, "Unable to unmarshal output\n"+info) - assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results\n"+info) + assert.NilError(t, err, "Unable to unmarshal output\n") + assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results\n") assert.Equal(t, dc[0].Name, data.Labels().Get("basenet")) }, } @@ -160,11 +161,11 @@ func TestNetworkInspect(t *testing.T) { }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { var dc []dockercompat.Network err := json.Unmarshal([]byte(stdout), &dc) - assert.NilError(t, err, "Unable to unmarshal output\n"+info) - assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results\n"+info) + assert.NilError(t, err, "Unable to unmarshal output\n") + assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results\n") assert.Equal(t, dc[0].Name, data.Labels().Get("basenet")) }, } @@ -188,11 +189,11 @@ func TestNetworkInspect(t *testing.T) { }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { var dc []dockercompat.Network err := json.Unmarshal([]byte(stdout), &dc) - assert.NilError(t, err, "Unable to unmarshal output\n"+info) - assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results\n"+info) + assert.NilError(t, err, "Unable to unmarshal output\n") + assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results\n") assert.Equal(t, dc[0].Name, data.Labels().Get("netname")) }, } @@ -215,20 +216,20 @@ func TestNetworkInspect(t *testing.T) { Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ ExitCode: 0, - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { var dc []dockercompat.Network err := json.Unmarshal([]byte(stdout), &dc) - assert.NilError(t, err, "Unable to unmarshal output\n"+info) - assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results\n"+info) + assert.NilError(t, err, "Unable to unmarshal output\n") + assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results\n") got := dc[0] - assert.Equal(t, got.Name, data.Identifier(), info) - assert.Equal(t, got.Labels["tag"], "testNetwork", info) - assert.Equal(t, len(got.IPAM.Config), 1, info) - assert.Equal(t, got.IPAM.Config[0].Subnet, testSubnet, info) - assert.Equal(t, got.IPAM.Config[0].Gateway, testGateway, info) - assert.Equal(t, got.IPAM.Config[0].IPRange, testIPRange, info) + assert.Equal(t, got.Name, data.Identifier()) + assert.Equal(t, got.Labels["tag"], "testNetwork") + assert.Equal(t, len(got.IPAM.Config), 1) + assert.Equal(t, got.IPAM.Config[0].Subnet, testSubnet) + assert.Equal(t, got.IPAM.Config[0].Gateway, testGateway) + assert.Equal(t, got.IPAM.Config[0].IPRange, testIPRange) }, } }, @@ -248,7 +249,7 @@ func TestNetworkInspect(t *testing.T) { Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ ExitCode: 0, - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { // Note: some functions need to be tested without the automatic --namespace nerdctl-test argument, so we need // to retrieve the binary name. // Note that we know this works already, so no need to assert err. @@ -307,11 +308,11 @@ func TestNetworkInspect(t *testing.T) { }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { var dc []dockercompat.Network err := json.Unmarshal([]byte(stdout), &dc) - assert.NilError(t, err, "Unable to unmarshal output\n"+info) - assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results\n"+info) + assert.NilError(t, err, "Unable to unmarshal output\n") + assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results\n") assert.Equal(t, dc[0].Name, data.Identifier("nginx-network-1")) // Assert only the "running" containers on the same network are returned. assert.Equal(t, 1, len(dc[0].Containers), "Expected a single container as per configuration, but got multiple.") diff --git a/cmd/nerdctl/network/network_list_linux_test.go b/cmd/nerdctl/network/network_list_linux_test.go index 3bf6f9e912f..fc186c1991a 100644 --- a/cmd/nerdctl/network/network_list_linux_test.go +++ b/cmd/nerdctl/network/network_list_linux_test.go @@ -23,6 +23,7 @@ import ( "gotest.tools/v3/assert" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" ) @@ -52,16 +53,16 @@ func TestNetworkLsFilter(t *testing.T) { }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { var lines = strings.Split(strings.TrimSpace(stdout), "\n") - assert.Assert(t, len(lines) >= 1, info) + assert.Assert(t, len(lines) >= 1, "expected at least one line\n") netNames := map[string]struct{}{ data.Labels().Get("netID1")[:12]: {}, } for _, name := range lines { _, ok := netNames[name] - assert.Assert(t, ok, info) + assert.Assert(t, ok, "expected to find name\n") } }, } @@ -74,16 +75,16 @@ func TestNetworkLsFilter(t *testing.T) { }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { var lines = strings.Split(strings.TrimSpace(stdout), "\n") - assert.Assert(t, len(lines) >= 1, info) + assert.Assert(t, len(lines) >= 1, "expected at least one line\n") netNames := map[string]struct{}{ data.Labels().Get("netID2")[:12]: {}, } for _, name := range lines { _, ok := netNames[name] - assert.Assert(t, ok, info) + assert.Assert(t, ok, "expected to find name\n") } }, } diff --git a/cmd/nerdctl/network/network_remove_linux_test.go b/cmd/nerdctl/network/network_remove_linux_test.go index 7a86ec37962..8e640c7a482 100644 --- a/cmd/nerdctl/network/network_remove_linux_test.go +++ b/cmd/nerdctl/network/network_remove_linux_test.go @@ -24,6 +24,7 @@ import ( "gotest.tools/v3/assert" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/pkg/testutil" "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" @@ -55,9 +56,9 @@ func TestNetworkRemove(t *testing.T) { Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ ExitCode: 0, - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { _, err := netlink.LinkByName("br-" + data.Labels().Get("netID")[:12]) - assert.Error(t, err, "Link not found", info) + assert.Error(t, err, "Link not found") }, } }, @@ -96,9 +97,9 @@ func TestNetworkRemove(t *testing.T) { Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ ExitCode: 0, - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { _, err := netlink.LinkByName("br-" + data.Labels().Get("netID")[:12]) - assert.Error(t, err, "Link not found", info) + assert.Error(t, err, "Link not found") }, } }, @@ -122,9 +123,9 @@ func TestNetworkRemove(t *testing.T) { Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ ExitCode: 0, - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { _, err := netlink.LinkByName("br-" + data.Labels().Get("netID")[:12]) - assert.Error(t, err, "Link not found", info) + assert.Error(t, err, "Link not found") }, } }, diff --git a/cmd/nerdctl/system/system_info_test.go b/cmd/nerdctl/system/system_info_test.go index 8c4bfe10041..e5e4d6e5e88 100644 --- a/cmd/nerdctl/system/system_info_test.go +++ b/cmd/nerdctl/system/system_info_test.go @@ -27,6 +27,7 @@ import ( "github.com/containerd/nerdctl/mod/tigron/expect" "github.com/containerd/nerdctl/mod/tigron/require" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/pkg/infoutil" "github.com/containerd/nerdctl/v2/pkg/inspecttypes/dockercompat" @@ -34,12 +35,12 @@ import ( "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" ) -func testInfoComparator(stdout string, info string, t *testing.T) { +func testInfoComparator(stdout string, t tig.T) { var dinf dockercompat.Info err := json.Unmarshal([]byte(stdout), &dinf) - assert.NilError(t, err, "failed to unmarshal stdout"+info) + assert.NilError(t, err, "failed to unmarshal stdout") unameM := infoutil.UnameM() - assert.Assert(t, dinf.Architecture == unameM, fmt.Sprintf("expected info.Architecture to be %q, got %q", unameM, dinf.Architecture)+info) + assert.Assert(t, dinf.Architecture == unameM, fmt.Sprintf("expected info.Architecture to be %q, got %q", unameM, dinf.Architecture)) } func TestInfo(t *testing.T) { diff --git a/cmd/nerdctl/system/system_prune_linux_test.go b/cmd/nerdctl/system/system_prune_linux_test.go index 70a4a9df651..7719ca7a373 100644 --- a/cmd/nerdctl/system/system_prune_linux_test.go +++ b/cmd/nerdctl/system/system_prune_linux_test.go @@ -26,6 +26,7 @@ import ( "github.com/containerd/nerdctl/mod/tigron/expect" "github.com/containerd/nerdctl/mod/tigron/require" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/pkg/testutil" "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" @@ -60,7 +61,7 @@ func TestSystemPrune(t *testing.T) { Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ ExitCode: 0, - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { volumes := helpers.Capture("volume", "ls") networks := helpers.Capture("network", "ls") images := helpers.Capture("images") diff --git a/cmd/nerdctl/volume/volume_inspect_test.go b/cmd/nerdctl/volume/volume_inspect_test.go index b42b3d41558..8bd545003ea 100644 --- a/cmd/nerdctl/volume/volume_inspect_test.go +++ b/cmd/nerdctl/volume/volume_inspect_test.go @@ -99,10 +99,10 @@ func TestVolumeInspect(t *testing.T) { return &test.Expected{ Output: expect.All( expect.Contains(data.Labels().Get("vol1")), - expect.JSON([]native.Volume{}, func(dc []native.Volume, info string, t tig.T) { - assert.Assert(t, len(dc) == 1, fmt.Sprintf("one result, not %d", len(dc))+info) - assert.Assert(t, dc[0].Name == data.Labels().Get("vol1"), fmt.Sprintf("expected name to be %q (was %q)", data.Labels().Get("vol1"), dc[0].Name)+info) - assert.Assert(t, dc[0].Labels == nil, fmt.Sprintf("expected labels to be nil and were %v", dc[0].Labels)+info) + expect.JSON([]native.Volume{}, func(dc []native.Volume, t tig.T) { + assert.Assert(t, len(dc) == 1, fmt.Sprintf("one result, not %d", len(dc))) + assert.Assert(t, dc[0].Name == data.Labels().Get("vol1"), fmt.Sprintf("expected name to be %q (was %q)", data.Labels().Get("vol1"), dc[0].Name)) + assert.Assert(t, dc[0].Labels == nil, fmt.Sprintf("expected labels to be nil and were %v", dc[0].Labels)) }), ), } @@ -117,7 +117,7 @@ func TestVolumeInspect(t *testing.T) { return &test.Expected{ Output: expect.All( expect.Contains(data.Labels().Get("vol2")), - expect.JSON([]native.Volume{}, func(dc []native.Volume, info string, t tig.T) { + expect.JSON([]native.Volume{}, func(dc []native.Volume, t tig.T) { labels := *dc[0].Labels assert.Assert(t, len(labels) == 2, fmt.Sprintf("two results, not %d", len(labels))) assert.Assert(t, labels["foo"] == "fooval", fmt.Sprintf("label foo should be fooval, not %s", labels["foo"])) @@ -137,7 +137,7 @@ func TestVolumeInspect(t *testing.T) { return &test.Expected{ Output: expect.All( expect.Contains(data.Labels().Get("vol1")), - expect.JSON([]native.Volume{}, func(dc []native.Volume, info string, t tig.T) { + expect.JSON([]native.Volume{}, func(dc []native.Volume, t tig.T) { assert.Assert(t, dc[0].Size == size, fmt.Sprintf("expected size to be %d (was %d)", size, dc[0].Size)) }), ), @@ -153,7 +153,7 @@ func TestVolumeInspect(t *testing.T) { return &test.Expected{ Output: expect.All( expect.Contains(data.Labels().Get("vol1"), data.Labels().Get("vol2")), - expect.JSON([]native.Volume{}, func(dc []native.Volume, info string, t tig.T) { + expect.JSON([]native.Volume{}, func(dc []native.Volume, t tig.T) { assert.Assert(t, len(dc) == 2, fmt.Sprintf("two results, not %d", len(dc))) assert.Assert(t, dc[0].Name == data.Labels().Get("vol1"), fmt.Sprintf("expected name to be %q (was %q)", data.Labels().Get("vol1"), dc[0].Name)) assert.Assert(t, dc[1].Name == data.Labels().Get("vol2"), fmt.Sprintf("expected name to be %q (was %q)", data.Labels().Get("vol2"), dc[1].Name)) @@ -173,7 +173,7 @@ func TestVolumeInspect(t *testing.T) { Errors: []error{errdefs.ErrNotFound, errdefs.ErrInvalidArgument}, Output: expect.All( expect.Contains(data.Labels().Get("vol1")), - expect.JSON([]native.Volume{}, func(dc []native.Volume, info string, t tig.T) { + expect.JSON([]native.Volume{}, func(dc []native.Volume, t tig.T) { assert.Assert(t, len(dc) == 1, fmt.Sprintf("one result, not %d", len(dc))) assert.Assert(t, dc[0].Name == data.Labels().Get("vol1"), fmt.Sprintf("expected name to be %q (was %q)", data.Labels().Get("vol1"), dc[0].Name)) }), diff --git a/cmd/nerdctl/volume/volume_list_test.go b/cmd/nerdctl/volume/volume_list_test.go index d666595abc6..7883368c746 100644 --- a/cmd/nerdctl/volume/volume_list_test.go +++ b/cmd/nerdctl/volume/volume_list_test.go @@ -26,6 +26,7 @@ import ( "github.com/containerd/nerdctl/mod/tigron/require" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/pkg/tabutil" "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" @@ -56,9 +57,9 @@ func TestVolumeLsSize(t *testing.T) { Command: test.Command("volume", "ls", "--size"), Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { var lines = strings.Split(strings.TrimSpace(stdout), "\n") - assert.Assert(t, len(lines) >= 4, "expected at least 4 lines"+info) + assert.Assert(t, len(lines) >= 4, "expected at least 4 lines") volSizes := map[string]string{ data.Identifier("1"): "100.0 KiB", data.Identifier("2"): "200.0 KiB", @@ -68,7 +69,7 @@ func TestVolumeLsSize(t *testing.T) { var numMatches = 0 var tab = tabutil.NewReader("VOLUME NAME\tDIRECTORY\tSIZE") var err = tab.ParseHeader(lines[0]) - assert.NilError(t, err, info) + assert.NilError(t, err, "ParseHeader should not fail\n") for _, line := range lines { name, _ := tab.ReadRow(line, "VOLUME NAME") @@ -77,10 +78,10 @@ func TestVolumeLsSize(t *testing.T) { if !ok { continue } - assert.Assert(t, size == expectSize, fmt.Sprintf("expected size %s for volume %s, got %s", expectSize, name, size)+info) + assert.Assert(t, size == expectSize, fmt.Sprintf("expected size %s for volume %s, got %s", expectSize, name, size)) numMatches++ } - assert.Assert(t, numMatches == len(volSizes), fmt.Sprintf("expected %d volumes, got: %d", len(volSizes), numMatches)+info) + assert.Assert(t, numMatches == len(volSizes), fmt.Sprintf("expected %d volumes, got: %d", len(volSizes), numMatches)) }, } }, @@ -145,9 +146,9 @@ func TestVolumeLsFilter(t *testing.T) { Command: test.Command("volume", "ls", "--quiet"), Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { var lines = strings.Split(strings.TrimSpace(stdout), "\n") - assert.Assert(t, len(lines) >= 4, "expected at least 4 lines"+info) + assert.Assert(t, len(lines) >= 4, "expected at least 4 lines") volNames := map[string]struct{}{ data.Labels().Get("vol1"): {}, data.Labels().Get("vol2"): {}, @@ -174,9 +175,9 @@ func TestVolumeLsFilter(t *testing.T) { }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { var lines = strings.Split(strings.TrimSpace(stdout), "\n") - assert.Assert(t, len(lines) >= 3, "expected at least 3 lines"+info) + assert.Assert(t, len(lines) >= 3, "expected at least 3 lines") volNames := map[string]struct{}{ data.Labels().Get("vol1"): {}, data.Labels().Get("vol2"): {}, @@ -184,7 +185,7 @@ func TestVolumeLsFilter(t *testing.T) { } for _, name := range lines { _, ok := volNames[name] - assert.Assert(t, ok, fmt.Sprintf("unexpected volume %s found", name)+info) + assert.Assert(t, ok, fmt.Sprintf("unexpected volume %s found", name)) } }, } @@ -197,15 +198,15 @@ func TestVolumeLsFilter(t *testing.T) { }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { var lines = strings.Split(strings.TrimSpace(stdout), "\n") - assert.Assert(t, len(lines) >= 1, "expected at least 1 lines"+info) + assert.Assert(t, len(lines) >= 1, "expected at least 1 lines") volNames := map[string]struct{}{ data.Labels().Get("vol2"): {}, } for _, name := range lines { _, ok := volNames[name] - assert.Assert(t, ok, fmt.Sprintf("unexpected volume %s found", name)+info) + assert.Assert(t, ok, fmt.Sprintf("unexpected volume %s found", name)) } }, } @@ -218,8 +219,8 @@ func TestVolumeLsFilter(t *testing.T) { }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { - assert.Assert(t, strings.TrimSpace(stdout) == "", "expected no result"+info) + Output: func(stdout string, t tig.T) { + assert.Assert(t, strings.TrimSpace(stdout) == "", "expected no result") }, } }, @@ -231,8 +232,8 @@ func TestVolumeLsFilter(t *testing.T) { }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { - assert.Assert(t, strings.TrimSpace(stdout) == "", "expected no result"+info) + Output: func(stdout string, t tig.T) { + assert.Assert(t, strings.TrimSpace(stdout) == "", "expected no result") }, } }, @@ -244,16 +245,16 @@ func TestVolumeLsFilter(t *testing.T) { }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { var lines = strings.Split(strings.TrimSpace(stdout), "\n") - assert.Assert(t, len(lines) >= 2, "expected at least 2 lines"+info) + assert.Assert(t, len(lines) >= 2, "expected at least 2 lines") volNames := map[string]struct{}{ data.Labels().Get("vol1"): {}, data.Labels().Get("vol2"): {}, } for _, name := range lines { _, ok := volNames[name] - assert.Assert(t, ok, fmt.Sprintf("unexpected volume %s found", name)+info) + assert.Assert(t, ok, fmt.Sprintf("unexpected volume %s found", name)) } }, } @@ -266,15 +267,15 @@ func TestVolumeLsFilter(t *testing.T) { }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { var lines = strings.Split(strings.TrimSpace(stdout), "\n") - assert.Assert(t, len(lines) >= 1, "expected at least 1 line"+info) + assert.Assert(t, len(lines) >= 1, "expected at least 1 line") volNames := map[string]struct{}{ data.Labels().Get("vol1"): {}, } for _, name := range lines { _, ok := volNames[name] - assert.Assert(t, ok, fmt.Sprintf("unexpected volume %s found", name)+info) + assert.Assert(t, ok, fmt.Sprintf("unexpected volume %s found", name)) } }, } @@ -289,16 +290,16 @@ func TestVolumeLsFilter(t *testing.T) { }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { var lines = strings.Split(strings.TrimSpace(stdout), "\n") - assert.Assert(t, len(lines) >= 2, "expected at least 2 lines"+info) + assert.Assert(t, len(lines) >= 2, "expected at least 2 lines") volNames := map[string]struct{}{ data.Labels().Get("vol1"): {}, data.Labels().Get("vol2"): {}, } for _, name := range lines { _, ok := volNames[name] - assert.Assert(t, ok, fmt.Sprintf("unexpected volume %s found", name)+info) + assert.Assert(t, ok, fmt.Sprintf("unexpected volume %s found", name)) } }, } @@ -312,9 +313,9 @@ func TestVolumeLsFilter(t *testing.T) { }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { var lines = strings.Split(strings.TrimSpace(stdout), "\n") - assert.Assert(t, len(lines) >= 3, "expected at least 3 lines"+info) + assert.Assert(t, len(lines) >= 3, "expected at least 3 lines") volNames := map[string]struct{}{ data.Labels().Get("vol2"): {}, data.Labels().Get("vol4"): {}, @@ -329,7 +330,7 @@ func TestVolumeLsFilter(t *testing.T) { continue } _, ok := volNames[name] - assert.Assert(t, ok, fmt.Sprintf("unexpected volume %s found", name)+info) + assert.Assert(t, ok, fmt.Sprintf("unexpected volume %s found", name)) } }, } @@ -343,9 +344,9 @@ func TestVolumeLsFilter(t *testing.T) { }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { var lines = strings.Split(strings.TrimSpace(stdout), "\n") - assert.Assert(t, len(lines) >= 3, "expected at least 3 lines"+info) + assert.Assert(t, len(lines) >= 3, "expected at least 3 lines") volNames := map[string]struct{}{ data.Labels().Get("vol2"): {}, data.Labels().Get("vol4"): {}, @@ -360,7 +361,7 @@ func TestVolumeLsFilter(t *testing.T) { continue } _, ok := volNames[name] - assert.Assert(t, ok, fmt.Sprintf("unexpected volume %s found", name)+info) + assert.Assert(t, ok, fmt.Sprintf("unexpected volume %s found", name)) } }, } @@ -374,9 +375,9 @@ func TestVolumeLsFilter(t *testing.T) { }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { var lines = strings.Split(strings.TrimSpace(stdout), "\n") - assert.Assert(t, len(lines) >= 3, "expected at least 3 lines"+info) + assert.Assert(t, len(lines) >= 3, "expected at least 3 lines") volNames := map[string]struct{}{ data.Labels().Get("vol1"): {}, data.Labels().Get("vol3"): {}, @@ -391,7 +392,7 @@ func TestVolumeLsFilter(t *testing.T) { continue } _, ok := volNames[name] - assert.Assert(t, ok, fmt.Sprintf("unexpected volume %s found", name)+info) + assert.Assert(t, ok, fmt.Sprintf("unexpected volume %s found", name)) } }, } diff --git a/cmd/nerdctl/volume/volume_namespace_test.go b/cmd/nerdctl/volume/volume_namespace_test.go index 341d2d37204..e91bc17c12b 100644 --- a/cmd/nerdctl/volume/volume_namespace_test.go +++ b/cmd/nerdctl/volume/volume_namespace_test.go @@ -23,6 +23,7 @@ import ( "github.com/containerd/nerdctl/mod/tigron/expect" "github.com/containerd/nerdctl/mod/tigron/require" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" ) @@ -76,7 +77,7 @@ func TestVolumeNamespace(t *testing.T) { return &test.Expected{ Output: expect.All( expect.DoesNotContain(data.Labels().Get("root_volume")), - func(stdout string, info string, t *testing.T) { + func(stdout string, t tig.T) { helpers.Ensure("--namespace", data.Labels().Get("root_namespace"), "volume", "inspect", data.Labels().Get("root_volume")) }, ), @@ -94,7 +95,7 @@ func TestVolumeNamespace(t *testing.T) { }, Expected: func(data test.Data, helpers test.Helpers) *test.Expected { return &test.Expected{ - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { helpers.Ensure("volume", "inspect", data.Labels().Get("root_volume")) helpers.Ensure("volume", "rm", data.Labels().Get("root_volume")) helpers.Ensure("--namespace", data.Labels().Get("root_namespace"), "volume", "inspect", data.Labels().Get("root_volume")) diff --git a/cmd/nerdctl/volume/volume_prune_linux_test.go b/cmd/nerdctl/volume/volume_prune_linux_test.go index 6565f578733..db81d1a1be4 100644 --- a/cmd/nerdctl/volume/volume_prune_linux_test.go +++ b/cmd/nerdctl/volume/volume_prune_linux_test.go @@ -22,6 +22,7 @@ import ( "github.com/containerd/nerdctl/mod/tigron/expect" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/pkg/testutil" "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest" @@ -75,7 +76,7 @@ func TestVolumePrune(t *testing.T) { data.Labels().Get("namedBusy"), data.Labels().Get("namedDangling"), ), - func(stdout string, info string, t *testing.T) { + func(stdout string, t tig.T) { helpers.Ensure("volume", "inspect", data.Labels().Get("anonIDBusy")) helpers.Fail("volume", "inspect", data.Labels().Get("anonIDDangling")) helpers.Ensure("volume", "inspect", data.Labels().Get("namedBusy")) @@ -96,7 +97,7 @@ func TestVolumePrune(t *testing.T) { Output: expect.All( expect.DoesNotContain(data.Labels().Get("anonIDBusy"), data.Labels().Get("namedBusy")), expect.Contains(data.Labels().Get("anonIDDangling"), data.Labels().Get("namedDangling")), - func(stdout string, info string, t *testing.T) { + func(stdout string, t tig.T) { helpers.Ensure("volume", "inspect", data.Labels().Get("anonIDBusy")) helpers.Fail("volume", "inspect", data.Labels().Get("anonIDDangling")) helpers.Ensure("volume", "inspect", data.Labels().Get("namedBusy")) diff --git a/docs/testing/tools.md b/docs/testing/tools.md index 9b4f0d9d1ad..ec1eb9056a7 100644 --- a/docs/testing/tools.md +++ b/docs/testing/tools.md @@ -88,17 +88,13 @@ import ( ) func MyComparator(compare string) test.Comparator { - return func(stdout string, info string, t *testing.T) { + return func(stdout string, t tig.T) { t.Helper() - assert.Assert(t, stdout == compare, info) + assert.Assert(t, stdout == compare) } } ``` -Note that you have access to an opaque `info` string. -It contains relevant debugging information in case your comparator is going to fail, -and you should make sure it is displayed. - ### Advanced expectations You may want to have expectations that contain a certain piece of data @@ -142,8 +138,8 @@ func TestMyThing(t *testing.T) { errors.New("foobla"), errdefs.ErrNotFound, }, - Output: func(stdout string, info string, t *testing.T) { - assert.Assert(t, stdout == data.Labels().Get("sometestdata"), info) + Output: func(stdout string, t tig.T) { + assert.Assert(t, stdout == data.Labels().Get("sometestdata")) }, } }, @@ -255,8 +251,8 @@ func TestMyThing(t *testing.T) { errors.New("foobla"), errdefs.ErrNotFound, }, - Output: func(stdout string, info string, t *testing.T) { - assert.Assert(t, stdout == data.Labels().Get("sometestdata"), info) + Output: func(stdout string, t tig.T) { + assert.Assert(t, stdout == data.Labels().Get("sometestdata")) }, } }, @@ -344,8 +340,8 @@ func TestMyThing(t *testing.T) { errors.New("foobla"), errdefs.ErrNotFound, }, - Output: func(stdout string, info string, t *testing.T) { - assert.Assert(t, stdout == data.Labels().Get("sometestdata"), info) + Output: func(stdout string, t tig.T) { + assert.Assert(t, stdout == data.Labels().Get("sometestdata")) }, } }, diff --git a/hack/provisioning/linux/containerd.sh b/hack/provisioning/linux/containerd.sh index e0c218ded6e..ae0e09287c8 100755 --- a/hack/provisioning/linux/containerd.sh +++ b/hack/provisioning/linux/containerd.sh @@ -42,8 +42,6 @@ provision::containerd::uninstall(){ provision::containerd::rootful(){ local version="$1" local arch="$2" - local bin_sha="$3" - local service_sha="$4" # Be tolerant with passed versions - with or without leading "v" [ "${version:0:1}" != "v" ] || version="${version:1}" @@ -51,24 +49,16 @@ provision::containerd::rootful(){ cd "$(fs::mktemp "containerd-install")" # Get the binary and install it - if [ "$bin_sha" == "canary is volatile and I accept the risk" ]; then - http::get \ - containerd.tar.gz \ - https://github.com/containerd/containerd/releases/download/v"$version"/containerd-"$version"-linux-"$arch".tar.gz - else - http::get::secure \ - containerd.tar.gz \ - https://github.com/containerd/containerd/releases/download/v"$version"/containerd-"$version"-linux-"$arch".tar.gz \ - "$bin_sha" - fi - - sudo tar -C /usr/local -xzf containerd.tar.gz + http::get \ + containerd.tar.gz \ + https://github.com/containerd/containerd/releases/download/v"$version"/containerd-"$version"-linux-"$arch".tar.gz + + sudo tar -C /usr/local -xvf containerd.tar.gz # Get the systemd unit - http::get::secure \ + http::get \ containerd.service \ - https://raw.githubusercontent.com/containerd/containerd/refs/tags/v"$version"/containerd.service \ - "$service_sha" + https://raw.githubusercontent.com/containerd/containerd/refs/tags/v"$version"/containerd.service sudo cp containerd.service /lib/systemd/system/containerd.service diff --git a/hack/test-integration.sh b/hack/test-integration.sh index 7834216b463..3496ed5c07d 100755 --- a/hack/test-integration.sh +++ b/hack/test-integration.sh @@ -26,6 +26,11 @@ if [[ "$(id -u)" = "0" ]]; then fi fi +# If we are being asked to use the proofing system, configure it +if [ "${PROOFING_IP:-}" != "" ]; then + "$root"/../mod/proofing/spoof.sh guest::configure "$root"/pkg/testutil/images.env "$PROOFING_IP" +fi + readonly timeout="60m" readonly retries="2" readonly needsudo="${WITH_SUDO:-}" diff --git a/mod/proofing/.env b/mod/proofing/.env new file mode 100644 index 00000000000..53c753b87b7 --- /dev/null +++ b/mod/proofing/.env @@ -0,0 +1,10 @@ +# This is the minimal env file you need to have +# You must at least point to a usable docker registry image +REGISTRY=registry:3.0.0@sha256:1fc7de654f2ac1247f0b67e8a459e273b0993be7d2beda1f3f56fbf1001ed3e7 + +# You can then add below whatever image you want mocked, for any origin. +# Short syntax is accepted (eg: `busybox`, or `library:busybox`) though you MUST provide a tag AND a digest + +# Examples: +# NANOSERVER=mcr.microsoft.com/windows/nanoserver:ltsc2022@sha256:16b61ffac72961551c4b5312a7ab3da7c3dc3258510e40bee309e6e51f006ac6 +# DEBIAN=debian:bookworm-slim@sha256:b1211f6d19afd012477bd34fdcabb6b663d680e0f4b0537da6e6b0fd057a3ec3 diff --git a/mod/proofing/forward.sh b/mod/proofing/forward.sh new file mode 100755 index 00000000000..b14390d526f --- /dev/null +++ b/mod/proofing/forward.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash + +# Copyright The containerd Authors. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# shellcheck disable=SC2034,SC2015 +set -o errexit -o errtrace -o functrace -o nounset -o pipefail + +# Extract the list of domains from image names in the environment +extract::domains(){ + local fd="$1" + + local image + local domain + local ignore + + while read -r image; do + IFS=" " read -r domain ignore <<<"$image" + printf "%s\n" "$domain" + done < <(extract::images "$1") | sort | uniq +} + +# Extract the list of images from the file. +extract::images(){ + local fd="$1" + local image + local ref + local domain + local owner + local name + local tag + local digest + + while read -r image; do + [ "$image" != "" ] && [ "${image:0:1}" != "#" ] || continue + image="${image#*=}" + digest="${image#*@}" + tag="${image#*:}" + tag="${tag%@*}" + ref="${image%%:*}" + + IFS=/ read -r domain owner name <<<"$ref" + [ "$owner" != "" ] || { + name="$domain" + owner=library + domain=docker.io + } + [ "$name" != "" ] || { + name="$owner" + owner="$domain" + domain=docker.io + } + + printf "%s %s %s %s\n" "$domain" "$owner/$name" "$tag" "$digest" + done <"$fd" | sort | uniq +} + +"extract::$1" "$2" diff --git a/mod/proofing/spoof.sh b/mod/proofing/spoof.sh new file mode 100755 index 00000000000..74efab856c9 --- /dev/null +++ b/mod/proofing/spoof.sh @@ -0,0 +1,266 @@ +#!/usr/bin/env bash + +# Copyright The containerd Authors. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -o errexit -o errtrace -o functrace -o nounset -o pipefail +root="$(cd "$(dirname "${BASH_SOURCE[0]:-$PWD}")" 2>/dev/null 1>&2 && pwd)" +readonly root + +# Cli to uses - nerdctl or docker +readonly cli="${CLI:-nerdctl}" +sudo= +! command -v sudo 1>/dev/null 2>&1 || sudo=sudo +readonly sudo + +readonly _prefix="proofing" +# Which platforms to copy over for images +readonly _platforms="linux/amd64,linux/arm64" +# Certificate lifetime, in days +readonly _lifetime="1" +# Certificates location, relative to pwd +_cert_root="$(pwd)/${_prefix}_certs" +readonly _cert_root +# Registry storage +_storage_root="$(pwd)/${_prefix}_data" +readonly _storage_root +# Name of the registry container +readonly _container_name="${_prefix}" + +mkdir -p "$_storage_root" + +# x509::reset does remove the local certificates folder +x509::reset(){ + # Remove local cert store + rm -Rf "$_cert_root" + mkdir -p "$_cert_root" +} + +# x509::ca::new generates a new CA +x509::ca::new(){ + # Gen a CA key + openssl genrsa -out "$_cert_root/ca.key" + + # Gen a CA pem, valid one day + openssl req \ + -new \ + -x509 \ + -days "$_lifetime" \ + -subj "/C=US/ST=CA/L=PlanetContainers/O=$_prefix/OU=ci/CN=$_prefix-ca/name=$_prefix CA/emailAddress=$_prefix@example.org" \ + -nameopt compat \ + -key "$_cert_root/ca.key" \ + -out "$_cert_root/ca.pem" + + # Convert to crt + openssl x509 -outform der -in "$_cert_root"/ca.pem -out "$_cert_root"/ca.crt +} + +# x509::cert::new generates and signs a new server certificate with the existing CA, adding as AltName any domain +# present in the file passed as the first argument (along with *.domain), along with localhost, 127.0.0.1, :::1 and +# $_prefix. +x509::cert::new(){ + local alts="$1" + local alters="DNS:$_prefix,DNS:localhost,IP:127.0.0.1,IP:::1" + + # Gen a server key + openssl genrsa -out "$_cert_root"/registry.key + + # Gen a csr + openssl req \ + -new \ + -subj "/C=US/ST=CA/L=PlanetContainers/O=$_prefix/OU=ci/CN=$_prefix-registry/name=$_container_name/emailAddress=$_prefix@example.org" \ + -key "$_cert_root/registry.key" \ + -out "$_cert_root/registry.csr" + + # Add spoofable domains + while read -r spoof; do + alters+=",DNS:$spoof,DNS:*.$spoof" + done <"$alts" + + cat > "$_cert_root/registry-options.cfg" << 'EOF' +basicConstraints=CA:FALSE +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer +extendedKeyUsage=serverAuth +EOF + echo "subjectAltName=$alters" >> "$_cert_root/registry-options.cfg" + + # Sign + openssl x509 \ + -req \ + -days "$_lifetime" \ + -extfile "$_cert_root/registry-options.cfg" \ + -CA "$_cert_root/ca.pem" \ + -CAkey "$_cert_root/ca.key" \ + -nameopt compat \ + -text \ + -in "$_cert_root/registry.csr" \ + -out "$_cert_root/registry.pem" + + # Get a crt + openssl x509 -outform der -in "$_cert_root/registry.pem" -out "$_cert_root/registry.crt" + + # Create a bundle + cat "$_cert_root/registry.pem" "$_cert_root/ca.pem" > "$_cert_root/bundle.pem" +} + +registry::stop(){ + "$cli" rm -f "$_container_name" 2>/dev/null || true +} + +registry::start(){ + local domain + local short + local tag + local digest + + read -r domain short tag digest <"$1" + + "$cli" run -d \ + --restart=always \ + --quiet \ + --name "$_container_name" \ + -p 443:443 \ + --env "OTEL_TRACES_EXPORTER=none" \ + --env "REGISTRY_HTTP_TLS_CERTIFICATE=/registry/domain.pem" \ + --env "REGISTRY_HTTP_TLS_KEY=/registry/domain.key" \ + --env "REGISTRY_HTTP_ADDR=:443" \ + -v "$_cert_root/bundle.pem:/registry/domain.pem" \ + -v "$_cert_root/registry.key:/registry/domain.key" \ + -v "$_storage_root:/var/lib/registry" \ + "$domain/$short:$tag@$digest" +} + +host::reset(){ + $sudo rm /usr/local/share/ca-certificates/"$_prefix"* 2>/dev/null || true + $sudo update-ca-certificates -f +} + +host::trust(){ + local ca_file="$1" + local cert + local dest + + cert="$(<"$ca_file")" + dest="$(sha256sum -b <<<"$cert")" + printf "%s" "$cert" | $sudo tee /usr/local/share/ca-certificates/"$_prefix-${dest:0:16}.crt" >/dev/null + $sudo update-ca-certificates +} + +remote::ca(){ + local ip_or_host="$1" + local ca + + while read -r line; do + [ "$line" == "-----BEGIN CERTIFICATE-----" ] && ca="$line"$'\n' || ca+="$line"$'\n' + done < <(true | openssl s_client -showcerts -connect "$ip_or_host:443" -servername "$_prefix" 2>/dev/null) + printf "%s\n" "$(echo "$ca" | openssl x509)" +} + +host::intercept(){ + local ip="$1" + local domains="$2" + + $sudo cp /etc/hosts /etc/hosts.backup + while read -r spoof; do + $sudo echo "$ip $spoof # -- mark $_prefix --" | $sudo tee -a /etc/hosts >/dev/null + done <"$domains" +} + +host::deintercept(){ + [ ! -e /etc/hosts.backup ] || $sudo mv /etc/hosts.backup /etc/hosts +} + +registry::seed(){ + local images="$1" + local platforms="$2" + local domain + local short + local tag + local digest + local fqim + + registry="$_prefix:443" + while read -r domain short tag digest; do + fqim="$domain/$short:$tag@$digest" + echo "Pulling $fqim" + "$cli" pull --quiet --platform="$platforms" "$fqim" + echo "Tagging $registry/$short:$tag" + "$cli" tag "$fqim" "$registry/$short:$tag" + echo "Pushing $registry/$short:$tag" + "$cli" push --quiet --platform="$platforms" "$registry/$short:$tag" + done <"$images" +} + +case "$1" in + server::reset) + # Stop registry + registry::stop + # Delete certificates + x509::reset + # Un-trust prior CAs + host::reset + # Remove the domain + host::deintercept + ;; + server::start) + env_file="$2" + + # Stop registry + registry::stop + # Delete certificates + x509::reset + # Un-trust prior CAs + host::reset + # Remove the domain + host::deintercept + + # Create new CA + x509::ca::new + # Create new server cert + x509::cert::new <("$root"/forward.sh domains "$env_file") + # Start the registry + registry::start <("$root"/forward.sh images "$env_file" | grep "library/registry") + # Trust the CA locally + host::trust <(remote::ca "localhost") + # Add the domain + host::intercept "127.0.0.1" <(printf "%s\n" "$_prefix") + ;; + server::seed) + env_file="$2" + + registry::seed <("$root"/forward.sh images "$env_file") "$_platforms" + ;; + guest::reset) + env_file="$2" + ip="$3" + + host::reset + host::deintercept + ;; + guest::configure) + env_file="$2" + ip="${3:-$(cat /etc/hosts | grep "$_prefix" | awk '{print $1}')}" + host::reset + host::deintercept + + host::intercept "$ip" <("$root"/forward.sh domains "$env_file") + host::trust <(remote::ca "$ip") + ;; + + *) + echo "unknown command" + exit 1 + ;; +esac diff --git a/mod/tigron/Makefile b/mod/tigron/Makefile index ba2bbf0d754..4a14d10e8cc 100644 --- a/mod/tigron/Makefile +++ b/mod/tigron/Makefile @@ -26,6 +26,10 @@ VERSION_TRIMMED := $(VERSION:v%=%) REVISION ?= $(shell git -C $(MAKEFILE_DIR) rev-parse HEAD)$(shell if ! git -C $(MAKEFILE_DIR) diff --no-ext-diff --quiet --exit-code; then echo .m; fi) LINT_COMMIT_RANGE ?= main..HEAD +# Remove when 1.23 is no longer supported. +# https://medium.com/@okoanton/generic-type-aliases-in-go-1-24-what-they-are-and-why-we-need-them-07ca05539500 +GOEXPERIMENT = aliastypeparams + ########################## # Helpers ########################## diff --git a/mod/tigron/expect/comparators.go b/mod/tigron/expect/comparators.go index 84f5fe13bd2..fa004051f8e 100644 --- a/mod/tigron/expect/comparators.go +++ b/mod/tigron/expect/comparators.go @@ -15,13 +15,12 @@ */ //revive:disable:package-comments // annoying false positive behavior -//nolint:thelper // FIXME: remove when we move to tig.T + package expect import ( "encoding/json" "regexp" - "testing" "github.com/containerd/nerdctl/mod/tigron/internal/assertive" "github.com/containerd/nerdctl/mod/tigron/test" @@ -30,11 +29,11 @@ import ( // All can be used as a parameter for expected.Output to group a set of comparators. func All(comparators ...test.Comparator) test.Comparator { - return func(stdout, _ string, t *testing.T) { + return func(stdout string, t tig.T) { t.Helper() for _, comparator := range comparators { - comparator(stdout, "", t) + comparator(stdout, t) } } } @@ -42,33 +41,43 @@ func All(comparators ...test.Comparator) test.Comparator { // Contains can be used as a parameter for expected.Output and ensures a comparison string is found contained in the // output. func Contains(compare string, more ...string) test.Comparator { - return func(stdout, _ string, t *testing.T) { - t.Helper() + return func(stdout string, testing tig.T) { + testing.Helper() - assertive.Contains(assertive.WithFailLater(t), stdout, compare, "Inspecting output (contains)") + assertive.Contains(assertive.WithFailLater(testing), stdout, compare, "Inspecting output (contains)") for _, m := range more { - assertive.Contains(assertive.WithFailLater(t), stdout, m, "Inspecting output (contains)") + assertive.Contains(assertive.WithFailLater(testing), stdout, m, "Inspecting output (contains)") } } } // DoesNotContain is to be used for expected.Output to ensure a comparison string is NOT found in the output. func DoesNotContain(compare string, more ...string) test.Comparator { - return func(stdout, _ string, t *testing.T) { - t.Helper() + return func(stdout string, testing tig.T) { + testing.Helper() - assertive.DoesNotContain(assertive.WithFailLater(t), stdout, compare, "Inspecting output (does not contain)") + assertive.DoesNotContain( + assertive.WithFailLater(testing), + stdout, + compare, + "Inspecting output (does not contain)", + ) for _, m := range more { - assertive.DoesNotContain(assertive.WithFailLater(t), stdout, m, "Inspecting output (does not contain)") + assertive.DoesNotContain( + assertive.WithFailLater(testing), + stdout, + m, + "Inspecting output (does not contain)", + ) } } } // Equals is to be used for expected.Output to ensure it is exactly the output. func Equals(compare string) test.Comparator { - return func(stdout, _ string, t *testing.T) { + return func(stdout string, t tig.T) { t.Helper() assertive.IsEqual(assertive.WithFailLater(t), stdout, compare, "Inspecting output (equals)") } @@ -76,7 +85,7 @@ func Equals(compare string) test.Comparator { // Match is to be used for expected.Output to ensure we match a regexp. func Match(reg *regexp.Regexp) test.Comparator { - return func(stdout, _ string, t *testing.T) { + return func(stdout string, t tig.T) { t.Helper() assertive.Match(assertive.WithFailLater(t), stdout, reg, "Inspecting output (match)") } @@ -84,15 +93,15 @@ func Match(reg *regexp.Regexp) test.Comparator { // JSON allows to verify that the output can be marshalled into T, and optionally can be further verified by a provided // method. -func JSON[T any](obj T, verifier func(T, string, tig.T)) test.Comparator { - return func(stdout, _ string, t *testing.T) { - t.Helper() +func JSON[T any](obj T, verifier func(T, tig.T)) test.Comparator { + return func(stdout string, testing tig.T) { + testing.Helper() err := json.Unmarshal([]byte(stdout), &obj) - assertive.ErrorIsNil(assertive.WithSilentSuccess(t), err, "Unmarshalling JSON from stdout must succeed") + assertive.ErrorIsNil(assertive.WithSilentSuccess(testing), err, "Unmarshalling JSON from stdout must succeed") if verifier != nil && err == nil { - verifier(obj, "Inspecting output (JSON)", t) + verifier(obj, testing) } } } diff --git a/mod/tigron/expect/comparators_test.go b/mod/tigron/expect/comparators_test.go index d0d76c3b701..306ebb28018 100644 --- a/mod/tigron/expect/comparators_test.go +++ b/mod/tigron/expect/comparators_test.go @@ -33,10 +33,10 @@ func TestExpect(t *testing.T) { // TODO: write more tests once we can mock t in Comparator signature t.Parallel() - expect.Contains("b")("a b c", "contains works", t) - expect.DoesNotContain("d")("a b c", "does not contain works", t) - expect.Equals("a b c")("a b c", "equals work", t) - expect.Match(regexp.MustCompile("[a-z ]+"))("a b c", "match works", t) + expect.Contains("b")("a b c", t) + expect.DoesNotContain("d")("a b c", t) + expect.Equals("a b c")("a b c", t) + expect.Match(regexp.MustCompile("[a-z ]+"))("a b c", t) expect.All( expect.Contains("b"), @@ -45,7 +45,7 @@ func TestExpect(t *testing.T) { expect.DoesNotContain("d", "e"), expect.Equals("a b c"), expect.Match(regexp.MustCompile("[a-z ]+")), - )("a b c", "all", t) + )("a b c", t) type foo struct { Foo map[string]string `json:"foo"` @@ -59,9 +59,9 @@ func TestExpect(t *testing.T) { assertive.ErrorIsNil(t, err) - expect.JSON(&foo{}, nil)(string(data), "json, no verifier", t) + expect.JSON(&foo{}, nil)(string(data), t) - expect.JSON(&foo{}, func(obj *foo, info string, t tig.T) { - assertive.IsEqual(t, obj.Foo["foo"], "bar", info) - })(string(data), "json, with verifier", t) + expect.JSON(&foo{}, func(obj *foo, t tig.T) { + assertive.IsEqual(t, obj.Foo["foo"], "bar") + })(string(data), t) } diff --git a/mod/tigron/expect/doc.md b/mod/tigron/expect/doc.md index 566f92d8c55..c8fa0b71c8f 100644 --- a/mod/tigron/expect/doc.md +++ b/mod/tigron/expect/doc.md @@ -58,7 +58,7 @@ The following ready-made `test.Comparator` generators are provided: - `expect.Equals(string)`: strict equality - `expect.Match(*regexp.Regexp)`: regexp matching - `expect.All(comparators ...Comparator)`: allows to bundle together a bunch of other comparators -- `expect.JSON[T any](obj T, verifier func(T, string, tig.T))`: allows to verify the output is valid JSON and optionally +- `expect.JSON[T any](obj T, verifier func(T, tig.T))`: allows to verify the output is valid JSON and optionally pass `verifier(T, string, tig.T)` extra validation ### A complete example @@ -93,8 +93,8 @@ func TestMyThing(t *testing.T) { expect.All( expect.Contains("out"), expect.DoesNotContain("something"), - expect.JSON(&Thing{}, func(obj *Thing, info string, t tig.T) { - assert.Equal(t, obj.Name, "something", info) + expect.JSON(&Thing{}, func(obj *Thing, t tig.T) { + assert.Equal(t, obj.Name, "something") }), ), ) @@ -131,7 +131,7 @@ func TestMyThing(t *testing.T) { myTest.Command = test.Custom("ls") // Set your expectations - myTest.Expected = test.Expects(0, nil, func(stdout, info string, t tig.T){ + myTest.Expected = test.Expects(0, nil, func(stdout string, t tig.T){ t.Helper() // Bla bla, do whatever advanced stuff and some asserts }) @@ -143,7 +143,7 @@ func TestMyThing(t *testing.T) { // You can of course generalize your comparator into a generator if it is going to be useful repeatedly func MyComparatorGenerator(param1, param2 any) test.Comparator { - return func(stdout, info string, t tig.T) { + return func(stdout string, t tig.T) { t.Helper() // Do your thing... // ... @@ -155,10 +155,6 @@ func MyComparatorGenerator(param1, param2 any) test.Comparator { You can now pass along `MyComparator(comparisonString)` as the third parameter of `test.Expects`, or compose it with other comparators using `expect.All(MyComparator(comparisonString), OtherComparator(somethingElse))` -Note that you have access to an opaque `info` string, that provides a brief formatted header message that assert -will use in case of failure to provide context on the error. -You may of course ignore it and write your own message. - ### Advanced expectations You may want to have expectations that contain a certain piece of data that is being used in the command or at @@ -180,6 +176,7 @@ import ( "gotest.tools/v3/assert" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/mod/tigron/test" ) @@ -206,11 +203,11 @@ func TestMyThing(t *testing.T) { Errors: []error{ errors.New("foobla"), }, - Output: func(stdout, info string, t tig.T) { + Output: func(stdout string, t tig.T) { t.Helper() // Retrieve the data that was set during the Setup phase. - assert.Assert(t, stdout == data.Labels().Get("sometestdata"), info) + assert.Assert(t, stdout == data.Labels().Get("sometestdata")) }, } } diff --git a/mod/tigron/internal/mocks/t.go b/mod/tigron/internal/mocks/t.go index 7665fd4fe3b..281913e0213 100644 --- a/mod/tigron/internal/mocks/t.go +++ b/mod/tigron/internal/mocks/t.go @@ -48,6 +48,9 @@ type ( TTempDirIn struct{} TTempDirOut = string + + TSkipIn []any + TSkipOut struct{} ) type MockT struct { @@ -93,3 +96,9 @@ func (m *MockT) TempDir() string { return "" } + +func (m *MockT) Skip(args ...any) { + if handler := m.Retrieve(); handler != nil { + handler.(mimicry.Function[TSkipIn, TSkipOut])(args) + } +} diff --git a/mod/tigron/test/case.go b/mod/tigron/test/case.go index 67846dfbb0f..f4c9c090d16 100644 --- a/mod/tigron/test/case.go +++ b/mod/tigron/test/case.go @@ -26,6 +26,7 @@ import ( "github.com/containerd/nerdctl/mod/tigron/internal/assertive" "github.com/containerd/nerdctl/mod/tigron/internal/formatter" + "github.com/containerd/nerdctl/mod/tigron/tig" ) // Case describes an entire test-case, including data, setup and cleanup routines, command and @@ -63,7 +64,7 @@ type Case struct { // Private helpers Helpers - t *testing.T + t tig.T parent *Case } @@ -151,7 +152,7 @@ func (test *Case) Run(t *testing.T) { if test.Require != nil { shouldRun, message := test.Require.Check(test.Data, test.helpers) if !shouldRun { - test.t.Skipf("test skipped as: %s", message) + test.t.Skip("test skipped as: " + message) } if test.Require.Setup != nil { @@ -180,7 +181,7 @@ func (test *Case) Run(t *testing.T) { // Set parallel unless asked not to if !test.NoParallel { - test.t.Parallel() + subT.Parallel() } // Execute cleanups now @@ -197,7 +198,7 @@ func (test *Case) Run(t *testing.T) { } // Register the cleanups, in reverse - test.t.Cleanup(func() { + subT.Cleanup(func() { test.t.Helper() test.t.Log( "\n\n" + formatter.Table( @@ -263,14 +264,14 @@ func (test *Case) Run(t *testing.T) { if len(test.SubTests) > 0 { // Now go for the subtests - test.t.Logf("\n%s️ %q: into subtests prep", subinDecorator, test.t.Name()) + test.t.Log(fmt.Sprintf("\n%s️ %q: into subtests prep", subinDecorator, test.t.Name())) for _, subTest := range test.SubTests { subTest.parent = test - subTest.Run(test.t) + subTest.Run(subT) } - test.t.Logf("\n%s️ %q: done with subtests prep", suboutDecorator, test.t.Name()) + test.t.Log(fmt.Sprintf("\n%s️ %q: done with subtests prep", suboutDecorator, test.t.Name())) } } diff --git a/mod/tigron/test/command.go b/mod/tigron/test/command.go index 23b3365016e..e146b5c9e80 100644 --- a/mod/tigron/test/command.go +++ b/mod/tigron/test/command.go @@ -23,13 +23,13 @@ import ( "os" "strconv" "strings" - "testing" "time" "github.com/containerd/nerdctl/mod/tigron/internal" "github.com/containerd/nerdctl/mod/tigron/internal/assertive" "github.com/containerd/nerdctl/mod/tigron/internal/com" "github.com/containerd/nerdctl/mod/tigron/internal/formatter" + "github.com/containerd/nerdctl/mod/tigron/tig" ) const ( @@ -59,7 +59,7 @@ type CustomizableCommand interface { // default it pass any that is defined by WithEnv WithBlacklist(env []string) // T returns the current testing object - T() *testing.T + T() tig.T // withEnv *copies* the passed map to the environment of the command to be executed // Note that this will override any variable defined in the embedding environment @@ -69,7 +69,7 @@ type CustomizableCommand interface { withTempDir(path string) // WithConfig allows passing custom config properties from the test to the base command withConfig(config Config) - withT(t *testing.T) + withT(t tig.T) // Clear does a clone, but will clear binary and arguments while retaining the env, or any other // custom properties Gotcha: if genericCommand is embedded with a custom Run and an overridden // clear to return the embedding type the result will be the embedding command, no longer the @@ -102,7 +102,7 @@ type GenericCommand struct { TempDir string Env map[string]string - t *testing.T + t tig.T cmd *com.Command async bool @@ -294,7 +294,6 @@ func (gc *GenericCommand) Run(expect *Expected) { if expect.Output != nil { expect.Output( result.Stdout, - "", gc.t, ) } @@ -338,7 +337,7 @@ func (gc *GenericCommand) Clone() TestableCommand { return &clone } -func (gc *GenericCommand) T() *testing.T { +func (gc *GenericCommand) T() tig.T { return gc.t } @@ -362,7 +361,7 @@ func (gc *GenericCommand) clear() TestableCommand { return &comcopy } -func (gc *GenericCommand) withT(t *testing.T) { +func (gc *GenericCommand) withT(t tig.T) { t.Helper() gc.t = t } diff --git a/mod/tigron/test/funct.go b/mod/tigron/test/funct.go index 45b4abbd9d9..f2be434e851 100644 --- a/mod/tigron/test/funct.go +++ b/mod/tigron/test/funct.go @@ -16,7 +16,9 @@ package test -import "testing" +import ( + "github.com/containerd/nerdctl/mod/tigron/tig" +) // An Evaluator is a function that decides whether a test should run or not. type Evaluator func(data Data, helpers Helpers) (bool, string) @@ -30,7 +32,7 @@ type Butler func(data Data, helpers Helpers) // - move to tig.T // A Comparator is the function signature to implement for the Output property of an Expected. -type Comparator func(stdout, info string, t *testing.T) +type Comparator func(stdout string, t tig.T) // A Manager is the function signature meant to produce expectations for a command. type Manager func(data Data, helpers Helpers) *Expected diff --git a/mod/tigron/test/helpers.go b/mod/tigron/test/helpers.go index c148be6e5ac..ce5c48cbea2 100644 --- a/mod/tigron/test/helpers.go +++ b/mod/tigron/test/helpers.go @@ -17,9 +17,8 @@ package test import ( - "testing" - "github.com/containerd/nerdctl/mod/tigron/internal" + "github.com/containerd/nerdctl/mod/tigron/tig" ) // This is the implementation of Helpers @@ -27,7 +26,7 @@ import ( type helpersInternal struct { cmdInternal CustomizableCommand - t *testing.T + t tig.T } // Ensure will run a command and make sure it is successful. @@ -60,8 +59,7 @@ func (help *helpersInternal) Capture(args ...string) string { help.t.Helper() help.Command(args...).Run(&Expected{ - //nolint:thelper - Output: func(stdout, _ string, _ *testing.T) { + Output: func(stdout string, _ tig.T) { ret = stdout }, }) @@ -104,6 +102,6 @@ func (help *helpersInternal) Write(key ConfigKey, value ConfigValue) { help.cmdInternal.write(key, value) } -func (help *helpersInternal) T() *testing.T { +func (help *helpersInternal) T() tig.T { return help.t } diff --git a/mod/tigron/test/interfaces.go b/mod/tigron/test/interfaces.go index 12df876747a..c7fefc95eb0 100644 --- a/mod/tigron/test/interfaces.go +++ b/mod/tigron/test/interfaces.go @@ -19,8 +19,9 @@ package test import ( "io" "os" - "testing" "time" + + "github.com/containerd/nerdctl/mod/tigron/tig" ) // DataLabels holds key-value test information set by the test authors. @@ -93,7 +94,7 @@ type Helpers interface { Write(key ConfigKey, value ConfigValue) // T returns the current testing object. - T() *testing.T + T() tig.T } // The TestableCommand interface represents a low-level command to execute, typically to be compared diff --git a/mod/tigron/test/test.go b/mod/tigron/test/test.go index 274a783b8b7..e83f05f86ed 100644 --- a/mod/tigron/test/test.go +++ b/mod/tigron/test/test.go @@ -17,13 +17,13 @@ package test import ( - "testing" + "github.com/containerd/nerdctl/mod/tigron/tig" ) // Testable TODO. type Testable interface { - CustomCommand(testCase *Case, t *testing.T) CustomizableCommand - AmbientRequirements(testCase *Case, t *testing.T) + CustomCommand(testCase *Case, t tig.T) CustomizableCommand + AmbientRequirements(testCase *Case, t tig.T) } // FIXME diff --git a/mod/tigron/tig/t.go b/mod/tigron/tig/t.go index f6256b72404..68293509731 100644 --- a/mod/tigron/tig/t.go +++ b/mod/tigron/tig/t.go @@ -37,4 +37,5 @@ type T interface { Log(args ...any) Name() string TempDir() string + Skip(args ...any) } diff --git a/pkg/testutil/compose.go b/pkg/testutil/compose.go index 2e5b55b056d..bd8413a9521 100644 --- a/pkg/testutil/compose.go +++ b/pkg/testutil/compose.go @@ -18,23 +18,26 @@ package testutil import ( "context" + "fmt" "os" "path/filepath" - "testing" "github.com/compose-spec/compose-go/v2/loader" compose "github.com/compose-spec/compose-go/v2/types" + + "github.com/containerd/nerdctl/mod/tigron/tig" ) type ComposeDir struct { - t testing.TB + t tig.T dir string yamlBasePath string } func (cd *ComposeDir) WriteFile(name, content string) { if err := os.WriteFile(filepath.Join(cd.dir, name), []byte(content), 0644); err != nil { - cd.t.Fatal(err) + cd.t.Log(fmt.Sprintf("Failed to create file %s", err)) + cd.t.FailNow() } } @@ -54,10 +57,11 @@ func (cd *ComposeDir) CleanUp() { os.RemoveAll(cd.dir) } -func NewComposeDir(t testing.TB, dockerComposeYAML string) *ComposeDir { +func NewComposeDir(t tig.T, dockerComposeYAML string) *ComposeDir { tmpDir, err := os.MkdirTemp("", "nerdctl-compose-test") if err != nil { - t.Fatal(err) + t.Log(fmt.Sprintf("Failed to create temp dir: %s", err)) + t.FailNow() } cd := &ComposeDir{ t: t, diff --git a/pkg/testutil/images.env b/pkg/testutil/images.env new file mode 100644 index 00000000000..ec41029684b --- /dev/null +++ b/pkg/testutil/images.env @@ -0,0 +1,15 @@ +ALPINE=alpine:3.21.3@sha256:a8560b36e8b8210634f77d9f7f9efd7ffa463e380b75e2e74aff4511df3ef88c +BUSYBOX=busybox:1.37.0@sha256:37f7b378a29ceb4c551b1b5582e27747b855bbfaa73fa11914fe0df028dc581f +DEBIAN=debian:bookworm-slim@sha256:b1211f6d19afd012477bd34fdcabb6b663d680e0f4b0537da6e6b0fd057a3ec3 +DOCKER_AUTH=cesanta/docker_auth:1.13.0@sha256:c2968eea28ff51b75b88e45147b1d5b8387fd7836400cb97d076c0feb4a451d9 +FLUENTD=fluentd:v1.18.0-debian-1.0@sha256:e7c937425430ad9a23123855379a144f5d079bed8d3b87342bf1e6babb4009fd +GITLAB=gitlab/gitlab-ee:17.11.0-ee.0@sha256:e0d9d5e0d0068f4b4bac3e15eb48313b5c3bb508425645f421bf2773a964c4ae +GOLANG=golang:1.23.8-bookworm@sha256:1a73e15c5a17855b58014aab45df0fdf8be778f12a62ed2a48009fe2c0022091 +HARBOR=bitnami/harbor-portal:v2.13.0@sha256:636f39610b359369aeeddd7859cb56274d9a1bc3e467e21d74ea89e1516c1a0c +KUBO=ipfs/kubo:v0.34.1@sha256:1cf421fbd881d01144c0da39aa1511c05f1ef3fd5eebee6ba7487ecc0f915a44 +MARIADB=mariadb:11.7.2@sha256:81e893032978c4bf8ad43710b7a979774ed90787fa32d199162148ce28fe3b76 +NANOSERVER=mcr.microsoft.com/windows/nanoserver:ltsc2022@sha256:16b61ffac72961551c4b5312a7ab3da7c3dc3258510e40bee309e6e51f006ac6 +NGINX=nginx:alpine3.21@sha256:65645c7bb6a0661892a8b03b89d0743208a18dd2f3f17a54ef4b76fb8e2f2a10 +REGISTRY=registry:3.0.0@sha256:1fc7de654f2ac1247f0b67e8a459e273b0993be7d2beda1f3f56fbf1001ed3e7 +SYSTEMD=ghcr.io/containerd/stargz-snapshotter:0.16.3-kind@sha256:c7c7de2af39f2373a89b6f993a81c9e19b65bf37a65ab14ef2791c97c07e530e +WORDPRESS=wordpress:6.8.0-php8.4-fpm-alpine@sha256:309b64fa4266d8a3fe6f0973ae3172fec1023c9b18242ccf1dffbff5dc8b81a8 diff --git a/pkg/testutil/images_linux.go b/pkg/testutil/images_linux.go new file mode 100644 index 00000000000..73fe7ea6c52 --- /dev/null +++ b/pkg/testutil/images_linux.go @@ -0,0 +1,68 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package testutil + +import ( + _ "embed" + "fmt" + "strings" + + "github.com/containerd/nerdctl/v2/pkg/referenceutil" +) + +//go:embed images.env +var imagesList string + +// getImage retrieves (from the env file) the fully qualified reference of an image, from its short name. +// No particular error handling effort is done here. +// If the env file is broken, or if the requested image does not exist, this is fatal. +func getImage(name string) string { + parsed, err := referenceutil.Parse(name) + + if err != nil { + panic(fmt.Errorf("malformed image name requested: %w", err)) + } + + // Ignore tag and digests for now - we currently support only one tag digest per image + name = parsed.Domain + "/" + parsed.Path + + for _, k := range strings.Split(imagesList, "\n") { + k = strings.TrimSpace(k) + if strings.HasPrefix(k, "#") || k == "" { + continue + } + + spl := strings.Split(k, "=") + if len(spl) != 2 { + continue + } + + item, err := referenceutil.Parse(spl[1]) + if err != nil { + panic(fmt.Errorf("malformed image found in env file: %w (%s)", err, spl[1])) + } + + if item.Domain+"/"+item.Path == name { + return spl[1] + } + } + + panic(fmt.Sprintf("no such test image is defined: %s", name)) + + //nolint:govet + return "" +} diff --git a/pkg/testutil/nerdtest/command.go b/pkg/testutil/nerdtest/command.go index e886514933f..7091015e1b1 100644 --- a/pkg/testutil/nerdtest/command.go +++ b/pkg/testutil/nerdtest/command.go @@ -17,15 +17,16 @@ package nerdtest import ( + "fmt" "os" "os/exec" "path/filepath" "strings" - "testing" "gotest.tools/v3/assert" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" "github.com/containerd/nerdctl/v2/pkg/rootlessutil" "github.com/containerd/nerdctl/v2/pkg/testutil" @@ -48,7 +49,7 @@ func isTargetNerdish() bool { return !strings.HasPrefix(filepath.Base(testutil.GetTarget()), "docker") } -func newNerdCommand(conf test.Config, t *testing.T) *nerdCommand { +func newNerdCommand(conf test.Config, t tig.T) *nerdCommand { // Decide what binary we are running var err error var binary string @@ -56,7 +57,8 @@ func newNerdCommand(conf test.Config, t *testing.T) *nerdCommand { binary, err = exec.LookPath(trgt) if err != nil { - t.Fatalf("unable to find binary %q: %v", trgt, err) + t.Log(fmt.Sprintf("unable to find binary %q: %v", trgt, err)) + t.FailNow() } if isTargetNerdish() { @@ -68,7 +70,8 @@ func newNerdCommand(conf test.Config, t *testing.T) *nerdCommand { } } else { if err = exec.Command(binary, "compose", "version").Run(); err != nil { - t.Fatalf("docker does not support compose: %v", err) + t.Log(fmt.Sprintf("docker does not support compose: %v", err)) + t.FailNow() } } diff --git a/pkg/testutil/nerdtest/registry/cesanta.go b/pkg/testutil/nerdtest/registry/cesanta.go index 1a83f73dfcb..ae79b4b9bc7 100644 --- a/pkg/testutil/nerdtest/registry/cesanta.go +++ b/pkg/testutil/nerdtest/registry/cesanta.go @@ -17,23 +17,18 @@ package registry import ( - "encoding/json" "fmt" + "io" "net" - "os" "strconv" - "testing" - "time" "golang.org/x/crypto/bcrypt" "gopkg.in/yaml.v3" "gotest.tools/v3/assert" - "github.com/containerd/nerdctl/mod/tigron/expect" "github.com/containerd/nerdctl/mod/tigron/test" "github.com/containerd/nerdctl/mod/tigron/utils/testca" - "github.com/containerd/nerdctl/v2/pkg/inspecttypes/dockercompat" "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest/platform" "github.com/containerd/nerdctl/v2/pkg/testutil/nettestutil" "github.com/containerd/nerdctl/v2/pkg/testutil/portlock" @@ -74,51 +69,6 @@ type CesantaConfig struct { ACL CesantaConfigACL `yaml:"acl,omitempty"` } -func (cc *CesantaConfig) Save(path string) error { - var err error - var r *os.File - if r, err = os.Create(path); err == nil { - defer r.Close() - err = yaml.NewEncoder(r).Encode(cc) - } - return err -} - -// FIXME: this is a copy of the utility method EnsureContainerStarted -// We cannot reference it (circular dep), so the copy. -// To be fixed later when we will be done migrating test helpers to the new framework and we can split them -// in meaningful subpackages. - -func ensureContainerStarted(helpers test.Helpers, con string) { - started := false - for i := 0; i < 5 && !started; i++ { - helpers.Command("container", "inspect", con). - Run(&test.Expected{ - ExitCode: expect.ExitCodeNoCheck, - Output: func(stdout string, info string, t *testing.T) { - var dc []dockercompat.Container - err := json.Unmarshal([]byte(stdout), &dc) - if err != nil || len(dc) == 0 { - return - } - assert.Equal(t, len(dc), 1, "Unexpectedly got multiple results\n"+info) - started = dc[0].State.Running - }, - }) - time.Sleep(time.Second) - } - - if !started { - ins := helpers.Capture("container", "inspect", con) - lgs := helpers.Capture("logs", con) - ps := helpers.Capture("ps", "-a") - helpers.T().Log(ins) - helpers.T().Log(lgs) - helpers.T().Log(ps) - helpers.T().Fatalf("container %s still not running after %d retries", con, 5) - } -} - func NewCesantaAuthServer(data test.Data, helpers test.Helpers, ca *testca.Cert, port int, user, pass string, tls bool) *TokenAuthServer { // listen on 0.0.0.0 to enable 127.0.0.1 listenIP := net.ParseIP("0.0.0.0") @@ -161,9 +111,9 @@ func NewCesantaAuthServer(data test.Data, helpers test.Helpers, ca *testca.Cert, cc.Token.Key = "/auth/domain.key" } - configFileName := data.Temp().Path("authconfig") - err = cc.Save(configFileName) - assert.NilError(helpers.T(), err, fmt.Errorf("failed writing configuration: %w", err)) + configFileName := data.Temp().SaveToWriter(func(file io.Writer) error { + return yaml.NewEncoder(file).Encode(cc) + }, "authconfig") cert := ca.GenerateServerX509(data, helpers, hostIP.String()) // FIXME: this will fail in many circumstances. Review strategy on how to acquire a free port. @@ -176,10 +126,10 @@ func NewCesantaAuthServer(data test.Data, helpers test.Helpers, ca *testca.Cert, cleanup := func(data test.Data, helpers test.Helpers) { helpers.Ensure("rm", "-f", containerName) - errPortRelease := portlock.Release(port) - if errPortRelease != nil { - helpers.T().Error(errPortRelease.Error()) - } + _ = portlock.Release(port) + //if errPortRelease != nil { + // helpers.T().Error(errPortRelease.Error()) + //} } setup := func(data test.Data, helpers test.Helpers) { @@ -195,21 +145,13 @@ func NewCesantaAuthServer(data test.Data, helpers test.Helpers, ca *testca.Cert, platform.DockerAuthImage, "/config/auth_config.yml", ) - ensureContainerStarted(helpers, containerName) - _, err = nettestutil.HTTPGet(fmt.Sprintf("%s://%s/auth", - scheme, - net.JoinHostPort(hostIP.String(), strconv.Itoa(port)), - ), - 10, - true) - assert.NilError(helpers.T(), err, fmt.Errorf("failed starting auth container in a timely manner: %w", err)) - + ensureServerStarted(helpers, containerName, scheme, hostIP, port) } return &TokenAuthServer{ + Scheme: scheme, IP: hostIP, Port: port, - Scheme: scheme, CertPath: cert.CertPath, Auth: &TokenAuth{ Address: scheme + "://" + net.JoinHostPort(hostIP.String(), strconv.Itoa(port)), @@ -217,8 +159,5 @@ func NewCesantaAuthServer(data test.Data, helpers test.Helpers, ca *testca.Cert, }, Setup: setup, Cleanup: cleanup, - Logs: func(data test.Data, helpers test.Helpers) { - helpers.T().Error(helpers.Err("logs", containerName)) - }, } } diff --git a/pkg/testutil/nerdtest/registry/common.go b/pkg/testutil/nerdtest/registry/common.go index 53877c0809d..537e1cf5052 100644 --- a/pkg/testutil/nerdtest/registry/common.go +++ b/pkg/testutil/nerdtest/registry/common.go @@ -17,12 +17,21 @@ package registry import ( + "encoding/json" "fmt" "net" + "strconv" + "time" "golang.org/x/crypto/bcrypt" + "gotest.tools/v3/assert" + "github.com/containerd/nerdctl/mod/tigron/expect" "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" + + "github.com/containerd/nerdctl/v2/pkg/inspecttypes/dockercompat" + "github.com/containerd/nerdctl/v2/pkg/testutil/nettestutil" ) // Auth describes a struct able to serialize authenticator information into arguments to be fed to a registry container run @@ -44,6 +53,7 @@ type TokenAuth struct { // FIXME: this is specific to Docker Registry // Like need something else for Harbor and Gitlab + func (ta *TokenAuth) Params(data test.Data) []string { return []string{ "--env", "REGISTRY_AUTH=token", @@ -99,6 +109,60 @@ type Server struct { Port int Cleanup func(data test.Data, helpers test.Helpers) Setup func(data test.Data, helpers test.Helpers) - Logs func(data test.Data, helpers test.Helpers) HostsDir string // contains ":/hosts.toml" } + +const ( + maxRetry = 20 + sleep = time.Second +) + +// Note this mostly duplicates EnsureContainerStarted +func ensureServerStarted(helpers test.Helpers, containerName string, scheme string, ip net.IP, port int) { + helpers.T().Helper() + + // First ensure the container has been started + started := false + for i := 0; i < maxRetry && !started; i++ { + helpers.Command("container", "inspect", containerName). + Run(&test.Expected{ + ExitCode: expect.ExitCodeNoCheck, + Output: func(stdout string, t tig.T) { + // Note: we can't use JSON comparator because it would hard fail if there is no content + var dc []dockercompat.Container + err := json.Unmarshal([]byte(stdout), &dc) + if err != nil || len(dc) == 0 { + return + } + assert.Equal(t, len(dc), 1, "Unexpectedly got multiple results\n") + started = dc[0].State.Running + }, + }) + time.Sleep(sleep) + } + + // Now, verify we can talk to it + var err error + if started { + _, err = nettestutil.HTTPGet(fmt.Sprintf("%s://%s/auth", + scheme, + net.JoinHostPort(ip.String(), strconv.Itoa(port)), + ), + 10, + true) + } + + if !started || err != nil { + ins := helpers.Capture("container", "inspect", containerName) + ps := helpers.Capture("ps", "-a") + stdout := helpers.Capture("logs", containerName) + stderr := helpers.Err("logs", containerName) + + helpers.T().Log(ins) + helpers.T().Log(ps) + helpers.T().Log(stdout) + helpers.T().Log(stderr) + helpers.T().Log(fmt.Sprintf("container %s still not running after %d retries", containerName, maxRetry)) + helpers.T().FailNow() + } +} diff --git a/pkg/testutil/nerdtest/registry/docker.go b/pkg/testutil/nerdtest/registry/docker.go index 6e90cdfcfc9..415c5789621 100644 --- a/pkg/testutil/nerdtest/registry/docker.go +++ b/pkg/testutil/nerdtest/registry/docker.go @@ -20,7 +20,6 @@ import ( "fmt" "net" "os" - "strconv" "gotest.tools/v3/assert" @@ -84,9 +83,7 @@ func NewDockerRegistry(data test.Data, helpers test.Helpers, currentCA *testca.C cleanup := func(data test.Data, helpers test.Helpers) { helpers.Anyhow("rm", "-f", containerName) - errPortRelease := portlock.Release(port) - - assert.NilError(helpers.T(), errPortRelease, fmt.Errorf("failed releasing port: %w", err)) + assert.NilError(helpers.T(), portlock.Release(port), fmt.Errorf("failed releasing port")) } // FIXME: in the future, we will want to further manipulate hosts toml file from the test @@ -127,25 +124,15 @@ func NewDockerRegistry(data test.Data, helpers test.Helpers, currentCA *testca.C setup := func(data test.Data, helpers test.Helpers) { helpers.Ensure(args...) - ensureContainerStarted(helpers, containerName) - _, err = nettestutil.HTTPGet(fmt.Sprintf("%s://%s/v2/", - scheme, - net.JoinHostPort(hostIP.String(), strconv.Itoa(port)), - ), - 10, - true) - assert.NilError(helpers.T(), err, fmt.Errorf("failed starting docker registry in a timely manner: %w", err)) + ensureServerStarted(helpers, containerName, scheme, hostIP, port) } return &Server{ - Scheme: scheme, - IP: hostIP, - Port: port, - Cleanup: cleanup, - Setup: setup, - Logs: func(data test.Data, helpers test.Helpers) { - helpers.T().Error(helpers.Err("logs", containerName)) - }, + Scheme: scheme, + IP: hostIP, + Port: port, + Setup: setup, + Cleanup: cleanup, HostsDir: hostsDir, } } diff --git a/pkg/testutil/nerdtest/registry/kubo.go b/pkg/testutil/nerdtest/registry/kubo.go index 40c0f67f798..8299dded9ea 100644 --- a/pkg/testutil/nerdtest/registry/kubo.go +++ b/pkg/testutil/nerdtest/registry/kubo.go @@ -19,8 +19,6 @@ package registry import ( "fmt" "net" - "strconv" - "testing" "gotest.tools/v3/assert" @@ -32,13 +30,13 @@ import ( "github.com/containerd/nerdctl/v2/pkg/testutil/portlock" ) -func NewKuboRegistry(data test.Data, helpers test.Helpers, t *testing.T, currentCA *testca.Cert, port int, auth Auth) *Server { +func NewKuboRegistry(data test.Data, helpers test.Helpers, currentCA *testca.Cert, port int, auth Auth) *Server { // listen on 0.0.0.0 to enable 127.0.0.1 listenIP := net.ParseIP("0.0.0.0") hostIP, err := nettestutil.NonLoopbackIPv4() - assert.NilError(t, err, fmt.Errorf("failed finding ipv4 non loopback interface: %w", err)) + assert.NilError(helpers.T(), err, fmt.Errorf("failed finding ipv4 non loopback interface: %w", err)) port, err = portlock.Acquire(port) - assert.NilError(t, err, fmt.Errorf("failed acquiring port: %w", err)) + assert.NilError(helpers.T(), err, fmt.Errorf("failed acquiring port: %w", err)) containerName := data.Identifier(fmt.Sprintf("kubo-registry-server-%d-%t", port, currentCA != nil)) // Cleanup possible leftovers first @@ -62,30 +60,19 @@ func NewKuboRegistry(data test.Data, helpers test.Helpers, t *testing.T, current helpers.Anyhow("rm", "-f", containerName) errPortRelease := portlock.Release(port) - assert.NilError(t, errPortRelease, fmt.Errorf("failed releasing port: %w", err)) + assert.NilError(helpers.T(), errPortRelease, fmt.Errorf("failed releasing port: %w", err)) } setup := func(data test.Data, helpers test.Helpers) { helpers.Ensure(args...) - ensureContainerStarted(helpers, containerName) - _, err = nettestutil.HTTPGet(fmt.Sprintf("%s://%s/api/v0", - scheme, - net.JoinHostPort(hostIP.String(), strconv.Itoa(port)), - ), - 30, - true) - logs := helpers.Capture("logs", containerName) - assert.NilError(t, err, fmt.Errorf("failed starting kubo registry in a timely manner: %w - logs: %s", err, logs)) + ensureServerStarted(helpers, containerName, scheme, hostIP, port) } return &Server{ + Scheme: scheme, IP: hostIP, Port: port, - Scheme: scheme, - Cleanup: cleanup, Setup: setup, - Logs: func(data test.Data, helpers test.Helpers) { - helpers.T().Error(helpers.Err("logs", containerName)) - }, + Cleanup: cleanup, } } diff --git a/pkg/testutil/nerdtest/test.go b/pkg/testutil/nerdtest/test.go index 94a42c459de..f9ef3321f91 100644 --- a/pkg/testutil/nerdtest/test.go +++ b/pkg/testutil/nerdtest/test.go @@ -17,9 +17,8 @@ package nerdtest import ( - "testing" - "github.com/containerd/nerdctl/mod/tigron/test" + "github.com/containerd/nerdctl/mod/tigron/tig" ) var DockerConfig test.ConfigKey = "DockerConfig" @@ -39,11 +38,11 @@ func Setup() *test.Case { type nerdctlSetup struct { } -func (ns *nerdctlSetup) CustomCommand(testCase *test.Case, t *testing.T) test.CustomizableCommand { +func (ns *nerdctlSetup) CustomCommand(testCase *test.Case, t tig.T) test.CustomizableCommand { return newNerdCommand(testCase.Config, t) } -func (ns *nerdctlSetup) AmbientRequirements(testCase *test.Case, t *testing.T) { +func (ns *nerdctlSetup) AmbientRequirements(testCase *test.Case, t tig.T) { // Ambient requirements, bail out now if these do not match if environmentHasIPv6() && testCase.Config.Read(ipv6) != only { t.Skip("runner skips non-IPv6 compatible tests in the IPv6 environment") diff --git a/pkg/testutil/nerdtest/utilities.go b/pkg/testutil/nerdtest/utilities.go index 6a52c4afe73..60cd118a4b6 100644 --- a/pkg/testutil/nerdtest/utilities.go +++ b/pkg/testutil/nerdtest/utilities.go @@ -18,10 +18,10 @@ package nerdtest import ( "encoding/json" + "fmt" "net" "path/filepath" "strings" - "testing" "time" "gotest.tools/v3/assert" @@ -54,7 +54,7 @@ func InspectContainer(helpers test.Helpers, name string) dockercompat.Container var res dockercompat.Container cmd := helpers.Command("container", "inspect", name) cmd.Run(&test.Expected{ - Output: expect.JSON([]dockercompat.Container{}, func(dc []dockercompat.Container, _ string, t tig.T) { + Output: expect.JSON([]dockercompat.Container{}, func(dc []dockercompat.Container, t tig.T) { assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results") res = dc[0] }), @@ -67,7 +67,7 @@ func InspectVolume(helpers test.Helpers, name string) native.Volume { var res native.Volume cmd := helpers.Command("volume", "inspect", name) cmd.Run(&test.Expected{ - Output: expect.JSON([]native.Volume{}, func(dc []native.Volume, _ string, t tig.T) { + Output: expect.JSON([]native.Volume{}, func(dc []native.Volume, t tig.T) { assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results") res = dc[0] }), @@ -80,7 +80,7 @@ func InspectNetwork(helpers test.Helpers, name string) dockercompat.Network { var res dockercompat.Network cmd := helpers.Command("network", "inspect", name) cmd.Run(&test.Expected{ - Output: expect.JSON([]dockercompat.Network{}, func(dc []dockercompat.Network, _ string, t tig.T) { + Output: expect.JSON([]dockercompat.Network{}, func(dc []dockercompat.Network, t tig.T) { assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results") res = dc[0] }), @@ -93,7 +93,7 @@ func InspectImage(helpers test.Helpers, name string) dockercompat.Image { var res dockercompat.Image cmd := helpers.Command("image", "inspect", name) cmd.Run(&test.Expected{ - Output: expect.JSON([]dockercompat.Image{}, func(dc []dockercompat.Image, _ string, t tig.T) { + Output: expect.JSON([]dockercompat.Image{}, func(dc []dockercompat.Image, t tig.T) { assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results") res = dc[0] }), @@ -106,20 +106,22 @@ const ( sleep = time.Second ) -func EnsureContainerStarted(helpers test.Helpers, con string) { +func EnsureContainerStarted(helpers test.Helpers, containerName string) { helpers.T().Helper() + started := false for i := 0; i < maxRetry && !started; i++ { - helpers.Command("container", "inspect", con). + helpers.Command("container", "inspect", containerName). Run(&test.Expected{ ExitCode: expect.ExitCodeNoCheck, - Output: func(stdout string, info string, t *testing.T) { + Output: func(stdout string, t tig.T) { + // Note: we can't use JSON comparator because it would hard fail if there is no content var dc []dockercompat.Container err := json.Unmarshal([]byte(stdout), &dc) if err != nil || len(dc) == 0 { return } - assert.Equal(t, len(dc), 1, "Unexpectedly got multiple results\n"+info) + assert.Equal(t, len(dc), 1, "Unexpectedly got multiple results\n") started = dc[0].State.Running }, }) @@ -127,13 +129,18 @@ func EnsureContainerStarted(helpers test.Helpers, con string) { } if !started { - ins := helpers.Capture("container", "inspect", con) - lgs := helpers.Capture("logs", con) + ins := helpers.Capture("container", "inspect", containerName) ps := helpers.Capture("ps", "-a") + stdout := helpers.Capture("logs", containerName) + stderr := helpers.Err("logs", containerName) + helpers.T().Log(ins) - helpers.T().Log(lgs) helpers.T().Log(ps) - helpers.T().Fatalf("container %s still not running after %d retries", con, maxRetry) + helpers.T().Log(stdout) + helpers.T().Log(stderr) + helpers.T().Log(fmt.Sprintf("container %s still not running after %d retries", containerName, maxRetry)) + helpers.T().FailNow() + } } diff --git a/pkg/testutil/testutil_linux.go b/pkg/testutil/testutil_linux.go index f7ab0688d42..91fcf89b8ee 100644 --- a/pkg/testutil/testutil_linux.go +++ b/pkg/testutil/testutil_linux.go @@ -17,20 +17,24 @@ package testutil var ( - BusyboxImage = "ghcr.io/containerd/busybox:1.36" - AlpineImage = mirrorOf("alpine:3.13") - NginxAlpineImage = mirrorOf("nginx:1.19-alpine") + AlpineImage = getImage("alpine") + BusyboxImage = getImage("busybox") + DockerAuthImage = getImage("cesanta/docker_auth") + FluentdImage = getImage("fluentd") + GolangImage = getImage("golang") + KuboImage = getImage("ipfs/kubo") + MariaDBImage = getImage("mariadb") + NginxAlpineImage = getImage("nginx") + RegistryImageStable = getImage("registry") + RegistryImageNext = getImage("registry") + SystemdImage = getImage("ghcr.io/containerd/stargz-snapshotter") + WordpressImage = getImage("wordpress") + + // Until we remove the helper + _ = mirrorOf("nblblbl") + NginxAlpineIndexHTMLSnippet = "Welcome to nginx!" - RegistryImageStable = mirrorOf("registry:2") - RegistryImageNext = "ghcr.io/distribution/distribution:" - WordpressImage = mirrorOf("wordpress:5.7") WordpressIndexHTMLSnippet = "WordPress › Installation" - MariaDBImage = mirrorOf("mariadb:10.5") - DockerAuthImage = mirrorOf("cesanta/docker_auth:1.7") - FluentdImage = "fluent/fluentd:v1.17.0-debian-1.0" - KuboImage = mirrorOf("ipfs/kubo:v0.16.0") - SystemdImage = "ghcr.io/containerd/stargz-snapshotter:0.15.1-kind" - GolangImage = mirrorOf("golang:1.18") // Source: https://gist.github.com/cpuguy83/fcf3041e5d8fb1bb5c340915aabeebe0 NonDistBlobImage = "ghcr.io/cpuguy83/non-dist-blob:latest"