Update integration test to support windows
Signed-off-by: Kenfe-Mickael Laventure <mickael.laventure@gmail.com>
This commit is contained in:
parent
79d04ded4e
commit
651aaff74e
@ -20,7 +20,7 @@ func BenchmarkContainerCreate(b *testing.B) {
|
|||||||
b.Error(err)
|
b.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
spec, err := GenerateSpec(WithImageConfig(ctx, image), WithProcessArgs("true"))
|
spec, err := GenerateSpec(WithImageConfig(ctx, image), withTrue())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Error(err)
|
b.Error(err)
|
||||||
return
|
return
|
||||||
@ -63,7 +63,7 @@ func BenchmarkContainerStart(b *testing.B) {
|
|||||||
b.Error(err)
|
b.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
spec, err := GenerateSpec(WithImageConfig(ctx, image), WithProcessArgs("true"))
|
spec, err := GenerateSpec(WithImageConfig(ctx, image), withTrue())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Error(err)
|
b.Error(err)
|
||||||
return
|
return
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// +build !windows
|
||||||
|
|
||||||
package containerd
|
package containerd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"runtime"
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@ -17,11 +18,6 @@ import (
|
|||||||
"github.com/containerd/containerd/testutil"
|
"github.com/containerd/containerd/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
defaultRoot = "/var/lib/containerd-test"
|
|
||||||
testImage = "docker.io/library/alpine:latest"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
address string
|
address string
|
||||||
noDaemon bool
|
noDaemon bool
|
||||||
@ -29,7 +25,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
flag.StringVar(&address, "address", "/run/containerd-test/containerd.sock", "The address to the containerd socket for use in the tests")
|
flag.StringVar(&address, "address", defaultAddress, "The address to the containerd socket for use in the tests")
|
||||||
flag.BoolVar(&noDaemon, "no-daemon", false, "Do not start a dedicated daemon for the tests")
|
flag.BoolVar(&noDaemon, "no-daemon", false, "Do not start a dedicated daemon for the tests")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
}
|
}
|
||||||
@ -57,11 +53,15 @@ func TestMain(m *testing.M) {
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if !noDaemon {
|
if !noDaemon {
|
||||||
|
os.RemoveAll(defaultRoot)
|
||||||
|
|
||||||
// setup a new containerd daemon if !testing.Short
|
// setup a new containerd daemon if !testing.Short
|
||||||
cmd = exec.Command("containerd",
|
cmd = exec.Command("containerd",
|
||||||
"--root", defaultRoot,
|
"--root", defaultRoot,
|
||||||
"--address", address,
|
"--address", address,
|
||||||
|
"--log-level", "debug",
|
||||||
)
|
)
|
||||||
|
cmd.Stdout = buf
|
||||||
cmd.Stderr = buf
|
cmd.Stderr = buf
|
||||||
if err := cmd.Start(); err != nil {
|
if err := cmd.Start(); err != nil {
|
||||||
cmd.Wait()
|
cmd.Wait()
|
||||||
@ -94,14 +94,22 @@ func TestMain(m *testing.M) {
|
|||||||
}).Info("running tests against containerd")
|
}).Info("running tests against containerd")
|
||||||
|
|
||||||
// pull a seed image
|
// pull a seed image
|
||||||
if _, err = client.Pull(ctx, testImage, WithPullUnpack); err != nil {
|
if runtime.GOOS != "windows" { // TODO: remove once pull is supported on windows
|
||||||
cmd.Process.Signal(syscall.SIGTERM)
|
if _, err = client.Pull(ctx, testImage, WithPullUnpack); err != nil {
|
||||||
cmd.Wait()
|
cmd.Process.Signal(syscall.SIGTERM)
|
||||||
fmt.Fprintf(os.Stderr, "%s: %s", err, buf.String())
|
cmd.Wait()
|
||||||
|
fmt.Fprintf(os.Stderr, "%s: %s", err, buf.String())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := platformTestSetup(client); err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, "platform test setup failed", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := client.Close(); err != nil {
|
if err := client.Close(); err != nil {
|
||||||
fmt.Fprintln(os.Stderr, err)
|
fmt.Fprintln(os.Stderr, "failed to close client", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// run the test
|
// run the test
|
||||||
@ -110,13 +118,15 @@ func TestMain(m *testing.M) {
|
|||||||
if !noDaemon {
|
if !noDaemon {
|
||||||
// tear down the daemon and resources created
|
// tear down the daemon and resources created
|
||||||
if err := cmd.Process.Signal(syscall.SIGTERM); err != nil {
|
if err := cmd.Process.Signal(syscall.SIGTERM); err != nil {
|
||||||
fmt.Fprintln(os.Stderr, err)
|
if err := cmd.Process.Kill(); err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, "failed to signal containerd", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err := cmd.Wait(); err != nil {
|
if err := cmd.Wait(); err != nil {
|
||||||
fmt.Fprintln(os.Stderr, err)
|
fmt.Fprintln(os.Stderr, "failed to wait for containerd", err)
|
||||||
}
|
}
|
||||||
if err := os.RemoveAll(defaultRoot); err != nil {
|
if err := os.RemoveAll(defaultRoot); err != nil {
|
||||||
fmt.Fprintln(os.Stderr, err)
|
fmt.Fprintln(os.Stderr, "failed to remove test root dir", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
// only print containerd logs if the test failed
|
// only print containerd logs if the test failed
|
||||||
@ -171,6 +181,11 @@ func TestNewClient(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestImagePull(t *testing.T) {
|
func TestImagePull(t *testing.T) {
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
// TODO: remove once Windows has a snapshotter
|
||||||
|
t.Skip("Windows does not have a snapshotter yet")
|
||||||
|
}
|
||||||
|
|
||||||
client, err := newClient(t, address)
|
client, err := newClient(t, address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
13
client_unix_test.go
Normal file
13
client_unix_test.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package containerd
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultRoot = "/var/lib/containerd-test"
|
||||||
|
defaultAddress = "/run/containerd-test/containerd.sock"
|
||||||
|
testImage = "docker.io/library/alpine:latest"
|
||||||
|
)
|
||||||
|
|
||||||
|
func platformTestSetup(client *Client) error {
|
||||||
|
return nil
|
||||||
|
}
|
87
client_windows_test.go
Normal file
87
client_windows_test.go
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
package containerd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultAddress = `\\.\pipe\containerd-containerd-test`
|
||||||
|
testImage = "docker.io/library/go:nanoserver"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
dockerLayerFolders []string
|
||||||
|
|
||||||
|
defaultRoot = filepath.Join(os.Getenv("programfiles"), "containerd", "root-test")
|
||||||
|
)
|
||||||
|
|
||||||
|
func platformTestSetup(client *Client) error {
|
||||||
|
var (
|
||||||
|
roots []string
|
||||||
|
layerChains = make(map[string]string)
|
||||||
|
)
|
||||||
|
// Since we can't pull images yet, we'll piggyback on the default
|
||||||
|
// docker's images
|
||||||
|
wfPath := `C:\ProgramData\docker\windowsfilter`
|
||||||
|
wf, err := os.Open(wfPath)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to access docker layers @ %s", wfPath)
|
||||||
|
}
|
||||||
|
defer wf.Close()
|
||||||
|
entries, err := wf.Readdirnames(0)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to read %s entries", wfPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, fn := range entries {
|
||||||
|
layerChainPath := filepath.Join(wfPath, fn, "layerchain.json")
|
||||||
|
lfi, err := os.Stat(layerChainPath)
|
||||||
|
switch {
|
||||||
|
case err == nil && lfi.Mode().IsRegular():
|
||||||
|
f, err := os.OpenFile(layerChainPath, os.O_RDONLY, 0660)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr,
|
||||||
|
errors.Wrapf(err, "failed to open %s", layerChainPath))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
l := make([]string, 0)
|
||||||
|
if err := json.NewDecoder(f).Decode(&l); err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr,
|
||||||
|
errors.Wrapf(err, "failed to decode %s", layerChainPath))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case len(l) == 1:
|
||||||
|
layerChains[l[0]] = filepath.Join(wfPath, fn)
|
||||||
|
case len(l) > 1:
|
||||||
|
fmt.Fprintf(os.Stderr, "Too many entries in %s: %d", layerChainPath, len(l))
|
||||||
|
case len(l) == 0:
|
||||||
|
roots = append(roots, filepath.Join(wfPath, fn))
|
||||||
|
}
|
||||||
|
case os.IsNotExist(err):
|
||||||
|
// keep on going
|
||||||
|
default:
|
||||||
|
return errors.Wrapf(err, "error trying to access %s", layerChainPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// They'll be 2 roots, just take the first one
|
||||||
|
l := roots[0]
|
||||||
|
dockerLayerFolders = append(dockerLayerFolders, l)
|
||||||
|
for {
|
||||||
|
l = layerChains[l]
|
||||||
|
if l == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
dockerLayerFolders = append([]string{l}, dockerLayerFolders...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
100
container_linux_test.go
Normal file
100
container_linux_test.go
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
// +build linux
|
||||||
|
|
||||||
|
package containerd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/containerd/cgroups"
|
||||||
|
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestContainerUpdate(t *testing.T) {
|
||||||
|
client, err := newClient(t, address)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer client.Close()
|
||||||
|
|
||||||
|
var (
|
||||||
|
ctx, cancel = testContext()
|
||||||
|
id = t.Name()
|
||||||
|
)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
image, err := client.GetImage(ctx, testImage)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
spec, err := generateSpec(WithImageConfig(ctx, image), withProcessArgs("sleep", "30"))
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
limit := int64(32 * 1024 * 1024)
|
||||||
|
spec.Linux.Resources.Memory = &specs.LinuxMemory{
|
||||||
|
Limit: &limit,
|
||||||
|
}
|
||||||
|
container, err := client.NewContainer(ctx, id, WithSpec(spec), WithNewRootFS(id, image))
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer container.Delete(ctx, WithRootFSDeletion)
|
||||||
|
|
||||||
|
task, err := container.NewTask(ctx, empty())
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer task.Delete(ctx)
|
||||||
|
|
||||||
|
statusC := make(chan uint32, 1)
|
||||||
|
go func() {
|
||||||
|
status, err := task.Wait(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
statusC <- status
|
||||||
|
}()
|
||||||
|
|
||||||
|
// check that the task has a limit of 32mb
|
||||||
|
cgroup, err := cgroups.Load(cgroups.V1, cgroups.PidPath(int(task.Pid())))
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
stat, err := cgroup.Stat(cgroups.IgnoreNotExist)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if int64(stat.Memory.Usage.Limit) != limit {
|
||||||
|
t.Errorf("expected memory limit to be set to %d but received %d", limit, stat.Memory.Usage.Limit)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
limit = 64 * 1024 * 1024
|
||||||
|
if err := task.Update(ctx, WithResources(&specs.LinuxResources{
|
||||||
|
Memory: &specs.LinuxMemory{
|
||||||
|
Limit: &limit,
|
||||||
|
},
|
||||||
|
})); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
// check that the task has a limit of 64mb
|
||||||
|
if stat, err = cgroup.Stat(cgroups.IgnoreNotExist); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if int64(stat.Memory.Usage.Limit) != limit {
|
||||||
|
t.Errorf("expected memory limit to be set to %d but received %d", limit, stat.Memory.Usage.Limit)
|
||||||
|
}
|
||||||
|
if err := task.Kill(ctx, syscall.SIGKILL); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
<-statusC
|
||||||
|
}
|
@ -6,13 +6,16 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/containerd/cgroups"
|
// Register the typeurl
|
||||||
|
_ "github.com/containerd/containerd/runtime"
|
||||||
|
|
||||||
"github.com/containerd/containerd/errdefs"
|
"github.com/containerd/containerd/errdefs"
|
||||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func empty() IOCreation {
|
func empty() IOCreation {
|
||||||
@ -48,7 +51,7 @@ func TestNewContainer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer client.Close()
|
defer client.Close()
|
||||||
|
|
||||||
spec, err := GenerateSpec()
|
spec, err := generateSpec()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
@ -84,22 +87,26 @@ func TestContainerStart(t *testing.T) {
|
|||||||
defer client.Close()
|
defer client.Close()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
image Image
|
||||||
ctx, cancel = testContext()
|
ctx, cancel = testContext()
|
||||||
id = t.Name()
|
id = t.Name()
|
||||||
)
|
)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
image, err := client.GetImage(ctx, testImage)
|
if runtime.GOOS != "windows" {
|
||||||
|
image, err = client.GetImage(ctx, testImage)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spec, err := generateSpec(withImageConfig(ctx, image), withExitStatus(7))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
spec, err := GenerateSpec(WithImageConfig(ctx, image), WithProcessArgs("sh", "-c", "exit 7"))
|
container, err := client.NewContainer(ctx, id, WithSpec(spec), withNewRootFS(id, image))
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
container, err := client.NewContainer(ctx, id, WithSpec(spec), WithNewRootFS(id, image))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
@ -151,23 +158,27 @@ func TestContainerOutput(t *testing.T) {
|
|||||||
defer client.Close()
|
defer client.Close()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
image Image
|
||||||
ctx, cancel = testContext()
|
ctx, cancel = testContext()
|
||||||
id = t.Name()
|
id = t.Name()
|
||||||
expected = "kingkoye"
|
expected = "kingkoye"
|
||||||
)
|
)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
image, err := client.GetImage(ctx, testImage)
|
if runtime.GOOS != "windows" {
|
||||||
|
image, err = client.GetImage(ctx, testImage)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spec, err := generateSpec(withImageConfig(ctx, image), withProcessArgs("echo", expected))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
spec, err := GenerateSpec(WithImageConfig(ctx, image), WithProcessArgs("echo", expected))
|
container, err := client.NewContainer(ctx, id, WithSpec(spec), withNewRootFS(id, image))
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
container, err := client.NewContainer(ctx, id, WithSpec(spec), WithNewRootFS(id, image))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
@ -207,7 +218,7 @@ func TestContainerOutput(t *testing.T) {
|
|||||||
|
|
||||||
actual := stdout.String()
|
actual := stdout.String()
|
||||||
// echo adds a new line
|
// echo adds a new line
|
||||||
expected = expected + "\n"
|
expected = expected + newLine
|
||||||
if actual != expected {
|
if actual != expected {
|
||||||
t.Errorf("expected output %q but received %q", expected, actual)
|
t.Errorf("expected output %q but received %q", expected, actual)
|
||||||
}
|
}
|
||||||
@ -221,22 +232,26 @@ func TestContainerExec(t *testing.T) {
|
|||||||
defer client.Close()
|
defer client.Close()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
image Image
|
||||||
ctx, cancel = testContext()
|
ctx, cancel = testContext()
|
||||||
id = t.Name()
|
id = t.Name()
|
||||||
)
|
)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
image, err := client.GetImage(ctx, testImage)
|
if runtime.GOOS != "windows" {
|
||||||
|
image, err = client.GetImage(ctx, testImage)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spec, err := generateSpec(withImageConfig(ctx, image), withProcessArgs("sleep", "100"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
spec, err := GenerateSpec(WithImageConfig(ctx, image), WithProcessArgs("sleep", "100"))
|
container, err := client.NewContainer(ctx, id, WithSpec(spec), withNewRootFS(id, image))
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
container, err := client.NewContainer(ctx, id, WithSpec(spec), WithNewRootFS(id, image))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
@ -260,10 +275,7 @@ func TestContainerExec(t *testing.T) {
|
|||||||
|
|
||||||
// start an exec process without running the original container process info
|
// start an exec process without running the original container process info
|
||||||
processSpec := spec.Process
|
processSpec := spec.Process
|
||||||
processSpec.Args = []string{
|
withExecExitStatus(processSpec, 6)
|
||||||
"sh", "-c",
|
|
||||||
"exit 6",
|
|
||||||
}
|
|
||||||
execID := t.Name() + "_exec"
|
execID := t.Name() + "_exec"
|
||||||
process, err := task.Exec(ctx, execID, processSpec, empty())
|
process, err := task.Exec(ctx, execID, processSpec, empty())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -305,7 +317,7 @@ func TestContainerExec(t *testing.T) {
|
|||||||
<-finished
|
<-finished
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContainerProcesses(t *testing.T) {
|
func TestContainerPids(t *testing.T) {
|
||||||
client, err := newClient(t, address)
|
client, err := newClient(t, address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -313,22 +325,26 @@ func TestContainerProcesses(t *testing.T) {
|
|||||||
defer client.Close()
|
defer client.Close()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
image Image
|
||||||
ctx, cancel = testContext()
|
ctx, cancel = testContext()
|
||||||
id = t.Name()
|
id = t.Name()
|
||||||
)
|
)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
image, err := client.GetImage(ctx, testImage)
|
if runtime.GOOS != "windows" {
|
||||||
|
image, err = client.GetImage(ctx, testImage)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spec, err := generateSpec(withImageConfig(ctx, image), withProcessArgs("sleep", "100"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
spec, err := GenerateSpec(WithImageConfig(ctx, image), WithProcessArgs("sleep", "100"))
|
container, err := client.NewContainer(ctx, id, WithSpec(spec), withNewRootFS(id, image))
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
container, err := client.NewContainer(ctx, id, WithSpec(spec), WithNewRootFS(id, image))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
@ -383,29 +399,33 @@ func TestContainerCloseIO(t *testing.T) {
|
|||||||
defer client.Close()
|
defer client.Close()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
image Image
|
||||||
ctx, cancel = testContext()
|
ctx, cancel = testContext()
|
||||||
id = t.Name()
|
id = t.Name()
|
||||||
)
|
)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
image, err := client.GetImage(ctx, testImage)
|
if runtime.GOOS != "windows" {
|
||||||
|
image, err = client.GetImage(ctx, testImage)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spec, err := generateSpec(withImageConfig(ctx, image), withCat())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
spec, err := GenerateSpec(WithImageConfig(ctx, image), WithProcessArgs("cat"))
|
container, err := client.NewContainer(ctx, id, WithSpec(spec), withNewRootFS(id, image))
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
container, err := client.NewContainer(ctx, id, WithSpec(spec), WithNewRootFS(id, image))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer container.Delete(ctx, WithRootFSDeletion)
|
defer container.Delete(ctx, WithRootFSDeletion)
|
||||||
|
|
||||||
const expected = "hello\n"
|
const expected = "hello" + newLine
|
||||||
stdout := bytes.NewBuffer(nil)
|
stdout := bytes.NewBuffer(nil)
|
||||||
|
|
||||||
r, w, err := os.Pipe()
|
r, w, err := os.Pipe()
|
||||||
@ -451,12 +471,25 @@ func TestContainerCloseIO(t *testing.T) {
|
|||||||
|
|
||||||
output := stdout.String()
|
output := stdout.String()
|
||||||
|
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
// On windows we use more and it always adds an extra newline
|
||||||
|
// remove it here
|
||||||
|
output = strings.TrimSuffix(output, newLine)
|
||||||
|
}
|
||||||
|
|
||||||
if output != expected {
|
if output != expected {
|
||||||
t.Errorf("expected output %q but received %q", expected, output)
|
t.Errorf("expected output %q but received %q", expected, output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContainerAttach(t *testing.T) {
|
func TestContainerAttach(t *testing.T) {
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
// On windows, closing the write side of the pipe closes the read
|
||||||
|
// side, sending an EOF to it and preventing reopening it.
|
||||||
|
// Hence this test will always fails on windows
|
||||||
|
t.Skip("invalid logic on windows")
|
||||||
|
}
|
||||||
|
|
||||||
client, err := newClient(t, address)
|
client, err := newClient(t, address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -464,29 +497,33 @@ func TestContainerAttach(t *testing.T) {
|
|||||||
defer client.Close()
|
defer client.Close()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
image Image
|
||||||
ctx, cancel = testContext()
|
ctx, cancel = testContext()
|
||||||
id = t.Name()
|
id = t.Name()
|
||||||
)
|
)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
image, err := client.GetImage(ctx, testImage)
|
if runtime.GOOS != "windows" {
|
||||||
|
image, err = client.GetImage(ctx, testImage)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spec, err := generateSpec(withImageConfig(ctx, image), withCat())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
spec, err := GenerateSpec(WithImageConfig(ctx, image), WithProcessArgs("cat"))
|
container, err := client.NewContainer(ctx, id, WithSpec(spec), withNewRootFS(id, image))
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
container, err := client.NewContainer(ctx, id, WithSpec(spec), WithNewRootFS(id, image))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer container.Delete(ctx, WithRootFSDeletion)
|
defer container.Delete(ctx, WithRootFSDeletion)
|
||||||
|
|
||||||
expected := "hello\n"
|
expected := "hello" + newLine
|
||||||
stdout := bytes.NewBuffer(nil)
|
stdout := bytes.NewBuffer(nil)
|
||||||
|
|
||||||
r, w, err := os.Pipe()
|
r, w, err := os.Pipe()
|
||||||
@ -586,22 +623,26 @@ func TestDeleteRunningContainer(t *testing.T) {
|
|||||||
defer client.Close()
|
defer client.Close()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
image Image
|
||||||
ctx, cancel = testContext()
|
ctx, cancel = testContext()
|
||||||
id = t.Name()
|
id = t.Name()
|
||||||
)
|
)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
image, err := client.GetImage(ctx, testImage)
|
if runtime.GOOS != "windows" {
|
||||||
|
image, err = client.GetImage(ctx, testImage)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spec, err := generateSpec(withImageConfig(ctx, image), withProcessArgs("sleep", "100"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
spec, err := GenerateSpec(WithImageConfig(ctx, image), WithProcessArgs("sleep", "100"))
|
container, err := client.NewContainer(ctx, id, WithSpec(spec), withNewRootFS(id, image))
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
container, err := client.NewContainer(ctx, id, WithSpec(spec), WithImage(image), WithNewRootFS(id, image))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
@ -651,22 +692,26 @@ func TestContainerKill(t *testing.T) {
|
|||||||
defer client.Close()
|
defer client.Close()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
image Image
|
||||||
ctx, cancel = testContext()
|
ctx, cancel = testContext()
|
||||||
id = t.Name()
|
id = t.Name()
|
||||||
)
|
)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
image, err := client.GetImage(ctx, testImage)
|
if runtime.GOOS != "windows" {
|
||||||
|
image, err = client.GetImage(ctx, testImage)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spec, err := generateSpec(withImageConfig(ctx, image), withCat())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
spec, err := GenerateSpec(WithImageConfig(ctx, image), WithProcessArgs("sh", "-c", "cat"))
|
container, err := client.NewContainer(ctx, id, WithSpec(spec), withNewRootFS(id, image))
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
container, err := client.NewContainer(ctx, id, WithSpec(spec), WithImage(image), WithNewRootFS(id, image))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
@ -709,95 +754,6 @@ func TestContainerKill(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContainerUpdate(t *testing.T) {
|
|
||||||
client, err := newClient(t, address)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer client.Close()
|
|
||||||
|
|
||||||
var (
|
|
||||||
ctx, cancel = testContext()
|
|
||||||
id = t.Name()
|
|
||||||
)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
image, err := client.GetImage(ctx, testImage)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
spec, err := GenerateSpec(WithImageConfig(ctx, image), WithProcessArgs("sleep", "30"))
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
limit := int64(32 * 1024 * 1024)
|
|
||||||
spec.Linux.Resources.Memory = &specs.LinuxMemory{
|
|
||||||
Limit: &limit,
|
|
||||||
}
|
|
||||||
container, err := client.NewContainer(ctx, id, WithSpec(spec), WithNewRootFS(id, image))
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer container.Delete(ctx, WithRootFSDeletion)
|
|
||||||
|
|
||||||
task, err := container.NewTask(ctx, empty())
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer task.Delete(ctx)
|
|
||||||
|
|
||||||
statusC := make(chan uint32, 1)
|
|
||||||
go func() {
|
|
||||||
status, err := task.Wait(ctx)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
statusC <- status
|
|
||||||
}()
|
|
||||||
|
|
||||||
// check that the task has a limit of 32mb
|
|
||||||
cgroup, err := cgroups.Load(cgroups.V1, cgroups.PidPath(int(task.Pid())))
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
stat, err := cgroup.Stat(cgroups.IgnoreNotExist)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if int64(stat.Memory.Usage.Limit) != limit {
|
|
||||||
t.Errorf("expected memory limit to be set to %d but received %d", limit, stat.Memory.Usage.Limit)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
limit = 64 * 1024 * 1024
|
|
||||||
if err := task.Update(ctx, WithResources(&specs.LinuxResources{
|
|
||||||
Memory: &specs.LinuxMemory{
|
|
||||||
Limit: &limit,
|
|
||||||
},
|
|
||||||
})); err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
// check that the task has a limit of 64mb
|
|
||||||
if stat, err = cgroup.Stat(cgroups.IgnoreNotExist); err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if int64(stat.Memory.Usage.Limit) != limit {
|
|
||||||
t.Errorf("expected memory limit to be set to %d but received %d", limit, stat.Memory.Usage.Limit)
|
|
||||||
}
|
|
||||||
if err := task.Kill(ctx, syscall.SIGKILL); err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
<-statusC
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestContainerNoBinaryExists(t *testing.T) {
|
func TestContainerNoBinaryExists(t *testing.T) {
|
||||||
client, err := newClient(t, address)
|
client, err := newClient(t, address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -806,30 +762,47 @@ func TestContainerNoBinaryExists(t *testing.T) {
|
|||||||
defer client.Close()
|
defer client.Close()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
image Image
|
||||||
ctx, cancel = testContext()
|
ctx, cancel = testContext()
|
||||||
id = t.Name()
|
id = t.Name()
|
||||||
)
|
)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
image, err := client.GetImage(ctx, testImage)
|
if runtime.GOOS != "windows" {
|
||||||
|
image, err = client.GetImage(ctx, testImage)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spec, err := generateSpec(withImageConfig(ctx, image), withProcessArgs("nothing"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
spec, err := GenerateSpec(WithImageConfig(ctx, image), WithProcessArgs("nothing"))
|
container, err := client.NewContainer(ctx, id, WithSpec(spec), withNewRootFS(id, image))
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
container, err := client.NewContainer(ctx, id, WithSpec(spec), WithNewRootFS(id, image))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer container.Delete(ctx, WithRootFSDeletion)
|
defer container.Delete(ctx, WithRootFSDeletion)
|
||||||
|
|
||||||
if _, err := container.NewTask(ctx, Stdio); err == nil {
|
task, err := container.NewTask(ctx, Stdio)
|
||||||
t.Error("NewTask should return an error when binary does not exist")
|
switch runtime.GOOS {
|
||||||
|
case "windows":
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed to create task %v", err)
|
||||||
|
}
|
||||||
|
if err := task.Start(ctx); err != nil {
|
||||||
|
t.Error("task.Start() should return an error when binary does not exist")
|
||||||
|
task.Delete(ctx)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if err == nil {
|
||||||
|
t.Error("NewTask should return an error when binary does not exist")
|
||||||
|
task.Delete(ctx)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -841,22 +814,26 @@ func TestContainerExecNoBinaryExists(t *testing.T) {
|
|||||||
defer client.Close()
|
defer client.Close()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
image Image
|
||||||
ctx, cancel = testContext()
|
ctx, cancel = testContext()
|
||||||
id = t.Name()
|
id = t.Name()
|
||||||
)
|
)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
image, err := client.GetImage(ctx, testImage)
|
if runtime.GOOS != "windows" {
|
||||||
|
image, err = client.GetImage(ctx, testImage)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spec, err := generateSpec(withImageConfig(ctx, image), withProcessArgs("sleep", "100"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
spec, err := GenerateSpec(WithImageConfig(ctx, image), WithProcessArgs("sleep", "100"))
|
container, err := client.NewContainer(ctx, id, WithSpec(spec), withNewRootFS(id, image))
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
container, err := client.NewContainer(ctx, id, WithSpec(spec), WithNewRootFS(id, image))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
|
@ -258,9 +258,11 @@ func checkBlobPath(t *testing.T, cs Store, dgst digest.Digest) string {
|
|||||||
t.Fatalf("error stating blob path: %v", err)
|
t.Fatalf("error stating blob path: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure that only read bits are set.
|
if runtime.GOOS != "windows" {
|
||||||
if ((fi.Mode() & os.ModePerm) & 0333) != 0 {
|
// ensure that only read bits are set.
|
||||||
t.Fatalf("incorrect permissions: %v", fi.Mode())
|
if ((fi.Mode() & os.ModePerm) & 0333) != 0 {
|
||||||
|
t.Fatalf("incorrect permissions: %v", fi.Mode())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return path
|
return path
|
||||||
|
@ -3,6 +3,7 @@ package content
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/containerd/containerd/errdefs"
|
"github.com/containerd/containerd/errdefs"
|
||||||
@ -67,8 +68,12 @@ func (w *writer) Commit(size int64, expected digest.Digest) error {
|
|||||||
// only allowing reads honoring the umask on creation.
|
// only allowing reads honoring the umask on creation.
|
||||||
//
|
//
|
||||||
// This removes write and exec, only allowing read per the creation umask.
|
// This removes write and exec, only allowing read per the creation umask.
|
||||||
if err := w.fp.Chmod((fi.Mode() & os.ModePerm) &^ 0333); err != nil {
|
//
|
||||||
return errors.Wrap(err, "failed to change ingest file permissions")
|
// NOTE: Windows does not support this operation
|
||||||
|
if runtime.GOOS != "windows" {
|
||||||
|
if err := w.fp.Chmod((fi.Mode() & os.ModePerm) &^ 0333); err != nil {
|
||||||
|
return errors.Wrap(err, "failed to change ingest file permissions")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if size > 0 && size != fi.Size() {
|
if size > 0 && size != fi.Size() {
|
||||||
|
51
helpers_unix_test.go
Normal file
51
helpers_unix_test.go
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package containerd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
const newLine = "\n"
|
||||||
|
|
||||||
|
func generateSpec(opts ...SpecOpts) (*specs.Spec, error) {
|
||||||
|
return GenerateSpec(opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func withExitStatus(es int) SpecOpts {
|
||||||
|
return func(s *specs.Spec) error {
|
||||||
|
s.Process.Args = []string{"sh", "-c", fmt.Sprintf("exit %d", es)}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func withProcessArgs(args ...string) SpecOpts {
|
||||||
|
return WithProcessArgs(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func withCat() SpecOpts {
|
||||||
|
return WithProcessArgs("cat")
|
||||||
|
}
|
||||||
|
|
||||||
|
func withTrue() SpecOpts {
|
||||||
|
return WithProcessArgs("true")
|
||||||
|
}
|
||||||
|
|
||||||
|
func withExecExitStatus(s *specs.Process, es int) {
|
||||||
|
s.Args = []string{"sh", "-c", fmt.Sprintf("exit %d", es)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func withExecArgs(s *specs.Process, args ...string) {
|
||||||
|
s.Args = args
|
||||||
|
}
|
||||||
|
|
||||||
|
func withImageConfig(ctx context.Context, i Image) SpecOpts {
|
||||||
|
return WithImageConfig(ctx, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
func withNewRootFS(id string, i Image) NewContainerOpts {
|
||||||
|
return WithNewRootFS(id, i)
|
||||||
|
}
|
65
helpers_windows_test.go
Normal file
65
helpers_windows_test.go
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package containerd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/containerd/containerd/containers"
|
||||||
|
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
const newLine = "\r\n"
|
||||||
|
|
||||||
|
func generateSpec(opts ...SpecOpts) (*specs.Spec, error) {
|
||||||
|
spec, err := GenerateSpec(opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
spec.Windows.LayerFolders = dockerLayerFolders
|
||||||
|
|
||||||
|
return spec, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func withExitStatus(es int) SpecOpts {
|
||||||
|
return func(s *specs.Spec) error {
|
||||||
|
s.Process.Args = []string{"powershell", "-noprofile", "exit", strconv.Itoa(es)}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func withProcessArgs(args ...string) SpecOpts {
|
||||||
|
return WithProcessArgs(append([]string{"powershell", "-noprofile"}, args...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func withCat() SpecOpts {
|
||||||
|
return WithProcessArgs("cmd", "/c", "more")
|
||||||
|
}
|
||||||
|
|
||||||
|
func withTrue() SpecOpts {
|
||||||
|
return WithProcessArgs("cmd", "/c")
|
||||||
|
}
|
||||||
|
|
||||||
|
func withExecExitStatus(s *specs.Process, es int) {
|
||||||
|
s.Args = []string{"powershell", "-noprofile", "exit", strconv.Itoa(es)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func withExecArgs(s *specs.Process, args ...string) {
|
||||||
|
s.Args = append([]string{"powershell", "-noprofile"}, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func withImageConfig(ctx context.Context, i Image) SpecOpts {
|
||||||
|
// TODO: when windows has a snapshotter remove the withImageConfig helper
|
||||||
|
return func(s *specs.Spec) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func withNewRootFS(id string, i Image) NewContainerOpts {
|
||||||
|
// TODO: when windows has a snapshotter remove the withNewRootFS helper
|
||||||
|
return func(ctx context.Context, client *Client, c *containers.Container) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
@ -2,15 +2,11 @@ package testutil
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/containerd/containerd/mount"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var rootEnabled bool
|
var rootEnabled bool
|
||||||
@ -19,36 +15,6 @@ func init() {
|
|||||||
flag.BoolVar(&rootEnabled, "test.root", false, "enable tests that require root")
|
flag.BoolVar(&rootEnabled, "test.root", false, "enable tests that require root")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unmount unmounts a given mountPoint and sets t.Error if it fails
|
|
||||||
func Unmount(t *testing.T, mountPoint string) {
|
|
||||||
t.Log("unmount", mountPoint)
|
|
||||||
if err := mount.Unmount(mountPoint, 0); err != nil {
|
|
||||||
t.Error("Could not umount", mountPoint, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RequiresRoot skips tests that require root, unless the test.root flag has
|
|
||||||
// been set
|
|
||||||
func RequiresRoot(t testing.TB) {
|
|
||||||
if !rootEnabled {
|
|
||||||
t.Skip("skipping test that requires root")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
assert.Equal(t, 0, os.Getuid(), "This test must be run as root.")
|
|
||||||
}
|
|
||||||
|
|
||||||
// RequiresRootM is similar to RequiresRoot but intended to be called from *testing.M.
|
|
||||||
func RequiresRootM() {
|
|
||||||
if !rootEnabled {
|
|
||||||
fmt.Fprintln(os.Stderr, "skipping test that requires root")
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
if 0 != os.Getuid() {
|
|
||||||
fmt.Fprintln(os.Stderr, "This test must be run as root.")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DumpDir will log out all of the contents of the provided directory to
|
// DumpDir will log out all of the contents of the provided directory to
|
||||||
// testing logger.
|
// testing logger.
|
||||||
//
|
//
|
||||||
|
42
testutil/helpers_unix.go
Normal file
42
testutil/helpers_unix.go
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package testutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/containerd/containerd/mount"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Unmount unmounts a given mountPoint and sets t.Error if it fails
|
||||||
|
func Unmount(t *testing.T, mountPoint string) {
|
||||||
|
t.Log("unmount", mountPoint)
|
||||||
|
if err := mount.Unmount(mountPoint, 0); err != nil {
|
||||||
|
t.Error("Could not umount", mountPoint, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequiresRoot skips tests that require root, unless the test.root flag has
|
||||||
|
// been set
|
||||||
|
func RequiresRoot(t testing.TB) {
|
||||||
|
if !rootEnabled {
|
||||||
|
t.Skip("skipping test that requires root")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
assert.Equal(t, 0, os.Getuid(), "This test must be run as root.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequiresRootM is similar to RequiresRoot but intended to be called from *testing.M.
|
||||||
|
func RequiresRootM() {
|
||||||
|
if !rootEnabled {
|
||||||
|
fmt.Fprintln(os.Stderr, "skipping test that requires root")
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
if 0 != os.Getuid() {
|
||||||
|
fmt.Fprintln(os.Stderr, "This test must be run as root.")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
16
testutil/helpers_windows.go
Normal file
16
testutil/helpers_windows.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package testutil
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
// RequiresRoot does nothing on Windows
|
||||||
|
func RequiresRoot(t testing.TB) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequiresRootM is similar to RequiresRoot but intended to be called from *testing.M.
|
||||||
|
func RequiresRootM() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmount unmounts a given mountPoint and sets t.Error if it fails
|
||||||
|
// Does nothing on Windows
|
||||||
|
func Unmount(t *testing.T, mountPoint string) {
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user