Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test rework, part 4 #3492

Merged
merged 8 commits into from
Oct 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 26 additions & 33 deletions cmd/nerdctl/completion/completion_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ func TestCompletion(t *testing.T) {
nerdtest.Setup()

testCase := &test.Case{
Description: "Base completion",
Require: test.Not(nerdtest.Docker),
Require: test.Not(nerdtest.Docker),
Setup: func(data test.Data, helpers test.Helpers) {
helpers.Ensure("pull", testutil.AlpineImage)
helpers.Ensure("network", "create", data.Identifier())
Expand All @@ -43,37 +42,37 @@ func TestCompletion(t *testing.T) {
SubTests: []*test.Case{
{
Description: "--cgroup-manager",
Command: test.RunCommand("__complete", "--cgroup-manager", ""),
Command: test.Command("__complete", "--cgroup-manager", ""),
Expected: test.Expects(0, nil, test.Contains("cgroupfs\n")),
},
{
Description: "--snapshotter",
Command: test.RunCommand("__complete", "--snapshotter", ""),
Command: test.Command("__complete", "--snapshotter", ""),
Expected: test.Expects(0, nil, test.Contains("native\n")),
},
{
Description: "empty",
Command: test.RunCommand("__complete", ""),
Command: test.Command("__complete", ""),
Expected: test.Expects(0, nil, test.Contains("run\t")),
},
{
Description: "run -",
Command: test.RunCommand("__complete", "run", "-"),
Command: test.Command("__complete", "run", "-"),
Expected: test.Expects(0, nil, test.Contains("--network\t")),
},
{
Description: "run --n",
Command: test.RunCommand("__complete", "run", "--n"),
Command: test.Command("__complete", "run", "--n"),
Expected: test.Expects(0, nil, test.Contains("--network\t")),
},
{
Description: "run --ne",
Command: test.RunCommand("__complete", "run", "--ne"),
Command: test.Command("__complete", "run", "--ne"),
Expected: test.Expects(0, nil, test.Contains("--network\t")),
},
{
Description: "run --net",
Command: test.RunCommand("__complete", "run", "--net", ""),
Command: test.Command("__complete", "run", "--net", ""),
Expected: func(data test.Data, helpers test.Helpers) *test.Expected {
return &test.Expected{
Output: test.All(
Expand All @@ -85,7 +84,7 @@ func TestCompletion(t *testing.T) {
},
{
Description: "run -it --net",
Command: test.RunCommand("__complete", "run", "-it", "--net", ""),
Command: test.Command("__complete", "run", "-it", "--net", ""),
Expected: func(data test.Data, helpers test.Helpers) *test.Expected {
return &test.Expected{
Output: test.All(
Expand All @@ -97,7 +96,7 @@ func TestCompletion(t *testing.T) {
},
{
Description: "run -ti --rm --net",
Command: test.RunCommand("__complete", "run", "-it", "--rm", "--net", ""),
Command: test.Command("__complete", "run", "-it", "--rm", "--net", ""),
Expected: func(data test.Data, helpers test.Helpers) *test.Expected {
return &test.Expected{
Output: test.All(
Expand All @@ -109,12 +108,12 @@ func TestCompletion(t *testing.T) {
},
{
Description: "run --restart",
Command: test.RunCommand("__complete", "run", "--restart", ""),
Command: test.Command("__complete", "run", "--restart", ""),
Expected: test.Expects(0, nil, test.Contains("always\n")),
},
{
Description: "network --rm",
Command: test.RunCommand("__complete", "network", "rm", ""),
Command: test.Command("__complete", "network", "rm", ""),
Expected: func(data test.Data, helpers test.Helpers) *test.Expected {
return &test.Expected{
Output: test.All(
Expand All @@ -126,15 +125,15 @@ func TestCompletion(t *testing.T) {
},
{
Description: "run --cap-add",
Command: test.RunCommand("__complete", "run", "--cap-add", ""),
Command: test.Command("__complete", "run", "--cap-add", ""),
Expected: test.Expects(0, nil, test.All(
test.Contains("sys_admin\n"),
test.DoesNotContain("CAP_SYS_ADMIN\n"),
)),
},
{
Description: "volume inspect",
Command: test.RunCommand("__complete", "volume", "inspect", ""),
Command: test.Command("__complete", "volume", "inspect", ""),
Expected: func(data test.Data, helpers test.Helpers) *test.Expected {
return &test.Expected{
Output: test.Contains(data.Get("identifier") + "\n"),
Expand All @@ -143,7 +142,7 @@ func TestCompletion(t *testing.T) {
},
{
Description: "volume rm",
Command: test.RunCommand("__complete", "volume", "rm", ""),
Command: test.Command("__complete", "volume", "rm", ""),
Expected: func(data test.Data, helpers test.Helpers) *test.Expected {
return &test.Expected{
Output: test.Contains(data.Get("identifier") + "\n"),
Expand All @@ -152,52 +151,46 @@ func TestCompletion(t *testing.T) {
},
{
Description: "no namespace --cgroup-manager",
Command: func(data test.Data, helpers test.Helpers) test.Command {
cmd := helpers.Command()
cmd.Clear()
cmd.WithBinary("nerdctl")
cmd.WithArgs("__complete", "--cgroup-manager", "")
return cmd
Command: func(data test.Data, helpers test.Helpers) test.TestableCommand {
return helpers.Custom("nerdctl", "__complete", "--cgroup-manager", "")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leverage new Custom for much simpler syntax.

},
Expected: test.Expects(0, nil, test.Contains("cgroupfs\n")),
},
{
Description: "no namespace empty",
Command: func(data test.Data, helpers test.Helpers) test.Command {
return helpers.Command().Clear().WithBinary("nerdctl").WithArgs("__complete", "")
Command: func(data test.Data, helpers test.Helpers) test.TestableCommand {
return helpers.Custom("nerdctl", "__complete", "")
},
Expected: test.Expects(0, nil, test.Contains("run\t")),
},
{
Description: "namespace space empty",
Command: func(data test.Data, helpers test.Helpers) test.Command {
Command: func(data test.Data, helpers test.Helpers) test.TestableCommand {
// mind {"--namespace=nerdctl-test"} vs {"--namespace", "nerdctl-test"}
return helpers.Command().Clear().WithBinary("nerdctl").
WithArgs("__complete", "--namespace", testutil.Namespace, "")
return helpers.Custom("nerdctl", "__complete", "--namespace", string(helpers.Read(nerdtest.Namespace)), "")
},
Expected: test.Expects(0, nil, test.Contains("run\t")),
},
{
Description: "run -i",
Command: test.RunCommand("__complete", "run", "-i", ""),
Command: test.Command("__complete", "run", "-i", ""),
Expected: test.Expects(0, nil, test.Contains(testutil.AlpineImage)),
},
{
Description: "run -it",
Command: test.RunCommand("__complete", "run", "-it", ""),
Command: test.Command("__complete", "run", "-it", ""),
Expected: test.Expects(0, nil, test.Contains(testutil.AlpineImage)),
},
{
Description: "run -it --rm",
Command: test.RunCommand("__complete", "run", "-it", "--rm", ""),
Command: test.Command("__complete", "run", "-it", "--rm", ""),
Expected: test.Expects(0, nil, test.Contains(testutil.AlpineImage)),
},
{
Description: "namespace run -i",
Command: func(data test.Data, helpers test.Helpers) test.Command {
Command: func(data test.Data, helpers test.Helpers) test.TestableCommand {
// mind {"--namespace=nerdctl-test"} vs {"--namespace", "nerdctl-test"}
return helpers.Command().Clear().WithBinary("nerdctl").
WithArgs("__complete", "--namespace", testutil.Namespace, "run", "-i", "")
return helpers.Custom("nerdctl", "__complete", "--namespace", string(helpers.Read(nerdtest.Namespace)), "run", "-i", "")
},
Expected: test.Expects(0, nil, test.Contains(testutil.AlpineImage+"\n")),
},
Expand Down
10 changes: 5 additions & 5 deletions cmd/nerdctl/container/container_create_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,9 @@ func TestCreateWithTty(t *testing.T) {

// TestIssue2993 tests https://github.com/containerd/nerdctl/issues/2993
func TestIssue2993(t *testing.T) {
testutil.DockerIncompatible(t)
testCase := nerdtest.Setup()

nerdtest.Setup()
testCase.Require = test.Not(nerdtest.Docker)

const (
containersPathKey = "containersPath"
Expand All @@ -203,7 +203,7 @@ func TestIssue2993(t *testing.T) {
return h
}

testCase := &test.Group{
testCase.SubTests = []*test.Case{
{
Description: "Issue #2993 - nerdctl no longer leaks containers and etchosts directories and files when container creation fails.",
Setup: func(data test.Data, helpers test.Helpers) {
Expand Down Expand Up @@ -233,7 +233,7 @@ func TestIssue2993(t *testing.T) {
Cleanup: func(data test.Data, helpers test.Helpers) {
helpers.Anyhow("rm", "--data-root", data.TempDir(), "-f", data.Identifier())
},
Command: func(data test.Data, helpers test.Helpers) test.Command {
Command: func(data test.Data, helpers test.Helpers) test.TestableCommand {
return helpers.Command("run", "--data-root", data.TempDir(), "--name", data.Identifier(), "-d", testutil.AlpineImage, "sleep", "infinity")
},
Expected: func(data test.Data, helpers test.Helpers) *test.Expected {
Expand Down Expand Up @@ -281,7 +281,7 @@ func TestIssue2993(t *testing.T) {
Cleanup: func(data test.Data, helpers test.Helpers) {
helpers.Anyhow("--data-root", data.TempDir(), "rm", "-f", data.Identifier())
},
Command: func(data test.Data, helpers test.Helpers) test.Command {
Command: func(data test.Data, helpers test.Helpers) test.TestableCommand {
return helpers.Command("--data-root", data.TempDir(), "rm", "-f", data.Identifier())
},
Expected: func(data test.Data, helpers test.Helpers) *test.Expected {
Expand Down
105 changes: 105 additions & 0 deletions cmd/nerdctl/helpers/testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,22 @@
package helpers

import (
"context"
"encoding/json"
"errors"
"fmt"
"os"
"os/exec"
"path/filepath"
"testing"

"gotest.tools/v3/assert"

containerd "github.com/containerd/containerd/v2/client"
"github.com/containerd/containerd/v2/core/content"

"github.com/containerd/nerdctl/v2/pkg/buildkitutil"
"github.com/containerd/nerdctl/v2/pkg/testutil"
)

func CreateBuildContext(t *testing.T, dockerfile string) string {
Expand All @@ -30,3 +41,97 @@ func CreateBuildContext(t *testing.T, dockerfile string) string {
assert.NilError(t, err)
return tmpDir
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As explained in the commit message, we do currently have a mix of platform specific test files (eg: _platform_test - along with dependencies that may be platform limited too) and tests that call t.Skip on certain platforms.

These helpers here are moved around into the main helper file so that we can reduce a little bit the platform specific test files.

Either way, all of that has nothing to do here - unless they are used in live code, they should be ultimately moved to pkg/testutil (or subsumed / removed). Work for another PR.

func RmiAll(base *testutil.Base) {
base.T.Logf("Pruning images")
imageIDs := base.Cmd("images", "--no-trunc", "-a", "-q").OutLines()
// remove empty output line at the end
imageIDs = imageIDs[:len(imageIDs)-1]
// use `Run` on purpose (same below) because `rmi all` may fail on individual
// image id that has an expected running container (e.g. a registry)
base.Cmd(append([]string{"rmi", "-f"}, imageIDs...)...).Run()

base.T.Logf("Pruning build caches")
if _, err := buildkitutil.GetBuildkitHost(testutil.Namespace); err == nil {
base.Cmd("builder", "prune", "--force").AssertOK()
}

// For BuildKit >= 0.11, pruning cache isn't enough to remove manifest blobs that are referred by build history blobs
// https://github.com/containerd/nerdctl/pull/1833
if base.Target == testutil.Nerdctl {
base.T.Logf("Pruning all content blobs")
addr := base.ContainerdAddress()
client, err := containerd.New(addr, containerd.WithDefaultNamespace(testutil.Namespace))
assert.NilError(base.T, err)
cs := client.ContentStore()
ctx := context.TODO()
wf := func(info content.Info) error {
base.T.Logf("Pruning blob %+v", info)
if err := cs.Delete(ctx, info.Digest); err != nil {
base.T.Log(err)
}
return nil
}
if err := cs.Walk(ctx, wf); err != nil {
base.T.Log(err)
}

base.T.Logf("Pruning all images (again?)")
imageIDs = base.Cmd("images", "--no-trunc", "-a", "-q").OutLines()
base.T.Logf("pruning following images: %+v", imageIDs)
base.Cmd(append([]string{"rmi", "-f"}, imageIDs...)...).Run()
}
}

func ExtractDockerArchive(archiveTarPath, rootfsPath string) error {
if err := os.MkdirAll(rootfsPath, 0755); err != nil {
return err
}
workDir, err := os.MkdirTemp("", "extract-docker-archive")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use t.TempDir

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, all of that stuff inside cmd/helpers needs to be cleaned-up / rewritten and likely moved to testutil.
Suggesting we do that in another PR once I ll be done migrating all tests.

if err != nil {
return err
}
defer os.RemoveAll(workDir)
if err := ExtractTarFile(workDir, archiveTarPath); err != nil {
return err
}
manifestJSONPath := filepath.Join(workDir, "manifest.json")
manifestJSONBytes, err := os.ReadFile(manifestJSONPath)
if err != nil {
return err
}
var mani DockerArchiveManifestJSON
if err := json.Unmarshal(manifestJSONBytes, &mani); err != nil {
return err
}
if len(mani) > 1 {
return fmt.Errorf("multi-image archive cannot be extracted: contains %d images", len(mani))
}
if len(mani) < 1 {
return errors.New("invalid archive")
}
ent := mani[0]
for _, l := range ent.Layers {
layerTarPath := filepath.Join(workDir, l)
if err := ExtractTarFile(rootfsPath, layerTarPath); err != nil {
return err
}
}
return nil
}

type DockerArchiveManifestJSON []DockerArchiveManifestJSONEntry

type DockerArchiveManifestJSONEntry struct {
Config string
RepoTags []string
Layers []string
}

func ExtractTarFile(dirPath, tarFilePath string) error {
cmd := exec.Command("tar", "Cxf", dirPath, tarFilePath)
if out, err := cmd.CombinedOutput(); err != nil {
return fmt.Errorf("failed to run %v: %q: %w", cmd.Args, string(out), err)
}
return nil
}
Loading