concourse/worker/backend/spec/spec_test.go

300 lines
6.1 KiB
Go

package spec_test
import (
"testing"
"code.cloudfoundry.org/garden"
"github.com/concourse/concourse/worker/backend/spec"
specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
)
type Suite struct {
suite.Suite
*require.Assertions
}
func (s *Suite) TestContainerSpecValidations() {
for _, tc := range []struct {
desc string
spec garden.ContainerSpec
}{
{
desc: "no handle specified",
spec: garden.ContainerSpec{},
},
{
desc: "rootfsPath not specified",
spec: garden.ContainerSpec{
Handle: "handle",
},
},
{
desc: "rootfsPath without scheme",
spec: garden.ContainerSpec{
Handle: "handle",
RootFSPath: "foo",
},
},
{
desc: "rootfsPath with unknown scheme",
spec: garden.ContainerSpec{
Handle: "handle",
RootFSPath: "weird://foo",
},
},
{
desc: "rootfsPath not being absolute",
spec: garden.ContainerSpec{
Handle: "handle",
RootFSPath: "raw://../not/absolute/at/all",
},
},
{
desc: "both rootfsPath and image specified",
spec: garden.ContainerSpec{
Handle: "handle",
RootFSPath: "foo",
Image: garden.ImageRef{URI: "bar"},
},
},
{
desc: "no rootfsPath, but image specified w/out scheme",
spec: garden.ContainerSpec{
Handle: "handle",
Image: garden.ImageRef{URI: "bar"},
},
},
{
desc: "no rootfsPath, but image specified w/ unknown scheme",
spec: garden.ContainerSpec{
Handle: "handle",
Image: garden.ImageRef{URI: "weird://bar"},
},
},
} {
s.T().Run(tc.desc, func(t *testing.T) {
_, err := spec.OciSpec(tc.spec)
s.Error(err)
})
}
}
func (s *Suite) TestOciSpecBindMounts() {
for _, tc := range []struct {
desc string
mounts []garden.BindMount
expected []specs.Mount
succeeds bool
}{
{
desc: "unknown mode",
succeeds: false,
mounts: []garden.BindMount{
{
SrcPath: "/a",
DstPath: "/b",
Mode: 123,
Origin: garden.BindMountOriginHost,
},
},
},
{
desc: "unknown origin",
succeeds: false,
mounts: []garden.BindMount{
{
SrcPath: "/a",
DstPath: "/b",
Mode: garden.BindMountModeRO,
Origin: 123,
},
},
},
{
desc: "w/out src",
succeeds: false,
mounts: []garden.BindMount{
{
DstPath: "/b",
Mode: garden.BindMountModeRO,
Origin: garden.BindMountOriginHost,
},
},
},
{
desc: "non-absolute src",
succeeds: false,
mounts: []garden.BindMount{
{
DstPath: "/b",
Mode: garden.BindMountModeRO,
Origin: garden.BindMountOriginHost,
},
},
},
{
desc: "w/out dest",
succeeds: false,
mounts: []garden.BindMount{
{
SrcPath: "/a",
Mode: garden.BindMountModeRO,
Origin: garden.BindMountOriginHost,
},
},
},
{
desc: "non-absolute dest",
succeeds: false,
mounts: []garden.BindMount{
{
DstPath: "/b",
Mode: garden.BindMountModeRO,
Origin: garden.BindMountOriginHost,
},
},
},
} {
s.T().Run(tc.desc, func(t *testing.T) {
actual, err := spec.OciSpecBindMounts(tc.mounts)
if !tc.succeeds {
s.Error(err)
return
}
s.NoError(err)
s.Equal(tc.expected, actual)
})
}
}
func (s *Suite) TestOciNamespaces() {
for _, tc := range []struct {
desc string
privileged bool
expected []specs.LinuxNamespace
}{
{
desc: "privileged",
privileged: true,
expected: spec.PrivilegedContainerNamespaces,
},
{
desc: "unprivileged",
privileged: false,
expected: spec.UnprivilegedContainerNamespaces,
},
} {
s.T().Run(tc.desc, func(t *testing.T) {
s.Equal(tc.expected, spec.OciNamespaces(tc.privileged))
})
}
}
func (s *Suite) TestOciCapabilities() {
for _, tc := range []struct {
desc string
privileged bool
expected specs.LinuxCapabilities
}{
{
desc: "privileged",
privileged: true,
expected: spec.PrivilegedContainerCapabilities,
},
{
desc: "unprivileged",
privileged: false,
expected: spec.UnprivilegedContainerCapabilities,
},
} {
s.T().Run(tc.desc, func(t *testing.T) {
s.Equal(tc.expected, spec.OciCapabilities(tc.privileged))
})
}
}
func (s *Suite) TestContainerSpec() {
var minimalContainerSpec = garden.ContainerSpec{
Handle: "handle", RootFSPath: "raw:///rootfs",
}
for _, tc := range []struct {
desc string
gdn garden.ContainerSpec
check func(*specs.Spec)
}{
{
desc: "defaults",
gdn: minimalContainerSpec,
check: func(oci *specs.Spec) {
s.Equal("/", oci.Process.Cwd)
s.Equal([]string{"/tmp/gdn-init"}, oci.Process.Args)
s.Equal(oci.Mounts, spec.AnyContainerMounts)
s.Equal(minimalContainerSpec.Handle, oci.Hostname)
s.Equal(spec.AnyContainerDevices, oci.Linux.Resources.Devices)
},
},
{
desc: "env",
gdn: garden.ContainerSpec{
Handle: "handle", RootFSPath: "raw:///rootfs",
Env: []string{"foo=bar"},
},
check: func(oci *specs.Spec) {
s.Equal([]string{"foo=bar"}, oci.Process.Env)
},
},
{
desc: "mounts",
gdn: garden.ContainerSpec{
Handle: "handle", RootFSPath: "raw:///rootfs",
BindMounts: []garden.BindMount{
{ // ro mount
SrcPath: "/a",
DstPath: "/b",
Mode: garden.BindMountModeRO,
Origin: garden.BindMountOriginHost,
},
{ // rw mount
SrcPath: "/a",
DstPath: "/b",
Mode: garden.BindMountModeRW,
Origin: garden.BindMountOriginHost,
},
},
},
check: func(oci *specs.Spec) {
s.Contains(oci.Mounts, specs.Mount{
Source: "/a",
Destination: "/b",
Type: "bind",
Options: []string{"bind", "ro"},
})
s.Contains(oci.Mounts, specs.Mount{
Source: "/a",
Destination: "/b",
Type: "bind",
Options: []string{"bind", "rw"},
})
},
},
} {
s.T().Run(tc.desc, func(t *testing.T) {
actual, err := spec.OciSpec(tc.gdn)
s.NoError(err)
tc.check(actual)
})
}
}
func TestSuite(t *testing.T) {
suite.Run(t, &Suite{
Assertions: require.New(t),
})
}