Refactor and extract TestRequire functionality

This will help when extracting suites in their own package.

Signed-off-by: Vincent Demeester <vincent@sbr.pm>
This commit is contained in:
Vincent Demeester 2016-12-16 15:13:23 +01:00
parent ba1c20f8d6
commit 930a9869f6
No known key found for this signature in database
GPG Key ID: 083CC6FD6EB699A3
10 changed files with 402 additions and 453 deletions

View File

@ -1665,7 +1665,7 @@ func (s *DockerSuite) TestContainersAPICreateMountsValidation(c *check.C) {
},
}
if SameHostDaemon.Condition() {
if SameHostDaemon() {
tmpDir, err := ioutils.TempDir("", "test-mounts-api")
c.Assert(err, checker.IsNil)
defer os.RemoveAll(tmpDir)
@ -1696,7 +1696,7 @@ func (s *DockerSuite) TestContainersAPICreateMountsValidation(c *check.C) {
}...)
}
if DaemonIsLinux.Condition() {
if DaemonIsLinux() {
cases = append(cases, []testCase{
{
config: cfg{
@ -1823,7 +1823,7 @@ func (s *DockerSuite) TestContainersAPICreateMountsCreate(c *check.C) {
{mounttypes.Mount{Type: "volume", Target: destPath, Source: "test3", VolumeOptions: &mounttypes.VolumeOptions{DriverConfig: &mounttypes.Driver{Name: volume.DefaultDriverName}}}, types.MountPoint{Driver: volume.DefaultDriverName, Type: "volume", Name: "test3", RW: true, Destination: destPath}},
}
if SameHostDaemon.Condition() {
if SameHostDaemon() {
// setup temp dir for testing binds
tmpDir1, err := ioutil.TempDir("", "test-mounts-api-1")
c.Assert(err, checker.IsNil)
@ -1834,7 +1834,7 @@ func (s *DockerSuite) TestContainersAPICreateMountsCreate(c *check.C) {
}...)
// for modes only supported on Linux
if DaemonIsLinux.Condition() {
if DaemonIsLinux() {
tmpDir3, err := ioutils.TempDir("", "test-mounts-api-3")
c.Assert(err, checker.IsNil)
defer os.RemoveAll(tmpDir3)

View File

@ -289,7 +289,7 @@ func containerStartOutputEquals(c *check.C, containerID, contents string) (err e
}
func defaultVolumes(tmpDir string) []string {
if SameHostDaemon.Condition() {
if SameHostDaemon() {
return []string{
"/vol1",
fmt.Sprintf("%s:/vol2", tmpDir),

View File

@ -40,7 +40,7 @@ func (s *DockerSuite) TestInfoEnsureSucceeds(c *check.C) {
stringsToCheck = append(stringsToCheck, "Init Binary:", "Security Options:", "containerd version:", "runc version:", "init version:")
}
if DaemonIsLinux.Condition() {
if DaemonIsLinux() {
stringsToCheck = append(stringsToCheck, "Runtimes:", "Default Runtime: runc")
}

View File

@ -749,7 +749,7 @@ func (s *DockerSuite) TestPsShowMounts(c *check.C) {
// bind mount container
var bindMountSource string
var bindMountDestination string
if DaemonIsWindows.Condition() {
if DaemonIsWindows() {
bindMountSource = "c:\\"
bindMountDestination = "c:\\t"
} else {

View File

@ -13,44 +13,37 @@ import (
"github.com/go-check/check"
)
var (
MacvlanKernelSupport = testRequirement{
func() bool {
const macvlanKernelVer = 3 // minimum macvlan kernel support
const macvlanMajorVer = 9 // minimum macvlan major kernel support
kv, err := kernel.GetKernelVersion()
if err != nil {
return false
}
// ensure Kernel version is >= v3.9 for macvlan support
if kv.Kernel < macvlanKernelVer || (kv.Kernel == macvlanKernelVer && kv.Major < macvlanMajorVer) {
return false
}
return true
},
"kernel version failed to meet the minimum macvlan kernel requirement of 3.9",
func macvlanKernelSupport() bool {
const macvlanKernelVer = 3 // minimum macvlan kernel support
const macvlanMajorVer = 9 // minimum macvlan major kernel support
kv, err := kernel.GetKernelVersion()
if err != nil {
return false
}
IpvlanKernelSupport = testRequirement{
func() bool {
const ipvlanKernelVer = 4 // minimum ipvlan kernel support
const ipvlanMajorVer = 2 // minimum ipvlan major kernel support
kv, err := kernel.GetKernelVersion()
if err != nil {
return false
}
// ensure Kernel version is >= v4.2 for ipvlan support
if kv.Kernel < ipvlanKernelVer || (kv.Kernel == ipvlanKernelVer && kv.Major < ipvlanMajorVer) {
return false
}
return true
},
"kernel version failed to meet the minimum ipvlan kernel requirement of 4.0.0",
// ensure Kernel version is >= v3.9 for macvlan support
if kv.Kernel < macvlanKernelVer || (kv.Kernel == macvlanKernelVer && kv.Major < macvlanMajorVer) {
return false
}
)
return true
}
func ipvlanKernelSupport() bool {
const ipvlanKernelVer = 4 // minimum ipvlan kernel support
const ipvlanMajorVer = 2 // minimum ipvlan major kernel support
kv, err := kernel.GetKernelVersion()
if err != nil {
return false
}
// ensure Kernel version is >= v4.2 for ipvlan support
if kv.Kernel < ipvlanKernelVer || (kv.Kernel == ipvlanKernelVer && kv.Major < ipvlanMajorVer) {
return false
}
return true
}
func (s *DockerNetworkSuite) TestDockerNetworkMacvlanPersistance(c *check.C) {
// verify the driver automatically provisions the 802.1q link (dm-dummy0.60)
testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
testRequires(c, DaemonIsLinux, macvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
// master dummy interface 'dm' abbreviation represents 'docker macvlan'
master := "dm-dummy0"
@ -70,7 +63,7 @@ func (s *DockerNetworkSuite) TestDockerNetworkMacvlanPersistance(c *check.C) {
func (s *DockerNetworkSuite) TestDockerNetworkIpvlanPersistance(c *check.C) {
// verify the driver automatically provisions the 802.1q link (di-dummy0.70)
testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
testRequires(c, DaemonIsLinux, ipvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
// master dummy interface 'di' notation represent 'docker ipvlan'
master := "di-dummy0"
// simulate the master link the vlan tagged subinterface parent link will use
@ -89,7 +82,7 @@ func (s *DockerNetworkSuite) TestDockerNetworkIpvlanPersistance(c *check.C) {
func (s *DockerNetworkSuite) TestDockerNetworkMacvlanSubIntCreate(c *check.C) {
// verify the driver automatically provisions the 802.1q link (dm-dummy0.50)
testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
testRequires(c, DaemonIsLinux, macvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
// master dummy interface 'dm' abbreviation represents 'docker macvlan'
master := "dm-dummy0"
// simulate the master link the vlan tagged subinterface parent link will use
@ -104,7 +97,7 @@ func (s *DockerNetworkSuite) TestDockerNetworkMacvlanSubIntCreate(c *check.C) {
func (s *DockerNetworkSuite) TestDockerNetworkIpvlanSubIntCreate(c *check.C) {
// verify the driver automatically provisions the 802.1q link (di-dummy0.50)
testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
testRequires(c, DaemonIsLinux, ipvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
// master dummy interface 'dm' abbreviation represents 'docker ipvlan'
master := "di-dummy0"
// simulate the master link the vlan tagged subinterface parent link will use
@ -119,7 +112,7 @@ func (s *DockerNetworkSuite) TestDockerNetworkIpvlanSubIntCreate(c *check.C) {
func (s *DockerNetworkSuite) TestDockerNetworkMacvlanOverlapParent(c *check.C) {
// verify the same parent interface cannot be used if already in use by an existing network
testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
testRequires(c, DaemonIsLinux, macvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
// master dummy interface 'dm' abbreviation represents 'docker macvlan'
master := "dm-dummy0"
out, err := createMasterDummy(c, master)
@ -139,7 +132,7 @@ func (s *DockerNetworkSuite) TestDockerNetworkMacvlanOverlapParent(c *check.C) {
func (s *DockerNetworkSuite) TestDockerNetworkIpvlanOverlapParent(c *check.C) {
// verify the same parent interface cannot be used if already in use by an existing network
testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
testRequires(c, DaemonIsLinux, ipvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
// master dummy interface 'dm' abbreviation represents 'docker ipvlan'
master := "di-dummy0"
out, err := createMasterDummy(c, master)
@ -159,7 +152,7 @@ func (s *DockerNetworkSuite) TestDockerNetworkIpvlanOverlapParent(c *check.C) {
func (s *DockerNetworkSuite) TestDockerNetworkMacvlanMultiSubnet(c *check.C) {
// create a dual stack multi-subnet Macvlan bridge mode network and validate connectivity between four containers, two on each subnet
testRequires(c, DaemonIsLinux, IPv6, MacvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
testRequires(c, DaemonIsLinux, IPv6, macvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
dockerCmd(c, "network", "create", "--driver=macvlan", "--ipv6", "--subnet=172.28.100.0/24", "--subnet=172.28.102.0/24", "--gateway=172.28.102.254",
"--subnet=2001:db8:abc2::/64", "--subnet=2001:db8:abc4::/64", "--gateway=2001:db8:abc4::254", "dualstackbridge")
// Ensure the network was created
@ -214,7 +207,7 @@ func (s *DockerNetworkSuite) TestDockerNetworkMacvlanMultiSubnet(c *check.C) {
func (s *DockerNetworkSuite) TestDockerNetworkIpvlanL2MultiSubnet(c *check.C) {
// create a dual stack multi-subnet Ipvlan L2 network and validate connectivity within the subnets, two on each subnet
testRequires(c, DaemonIsLinux, IPv6, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
testRequires(c, DaemonIsLinux, IPv6, ipvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
dockerCmd(c, "network", "create", "--driver=ipvlan", "--ipv6", "--subnet=172.28.200.0/24", "--subnet=172.28.202.0/24", "--gateway=172.28.202.254",
"--subnet=2001:db8:abc8::/64", "--subnet=2001:db8:abc6::/64", "--gateway=2001:db8:abc6::254", "dualstackl2")
// Ensure the network was created
@ -268,7 +261,7 @@ func (s *DockerNetworkSuite) TestDockerNetworkIpvlanL2MultiSubnet(c *check.C) {
func (s *DockerNetworkSuite) TestDockerNetworkIpvlanL3MultiSubnet(c *check.C) {
// create a dual stack multi-subnet Ipvlan L3 network and validate connectivity between all four containers per L3 mode
testRequires(c, DaemonIsLinux, IPv6, IpvlanKernelSupport, NotUserNamespace, NotArm, IPv6, ExperimentalDaemon)
testRequires(c, DaemonIsLinux, IPv6, ipvlanKernelSupport, NotUserNamespace, NotArm, IPv6, ExperimentalDaemon)
dockerCmd(c, "network", "create", "--driver=ipvlan", "--ipv6", "--subnet=172.28.10.0/24", "--subnet=172.28.12.0/24", "--gateway=172.28.12.254",
"--subnet=2001:db8:abc9::/64", "--subnet=2001:db8:abc7::/64", "--gateway=2001:db8:abc7::254", "-o", "ipvlan_mode=l3", "dualstackl3")
// Ensure the network was created
@ -327,7 +320,7 @@ func (s *DockerNetworkSuite) TestDockerNetworkIpvlanL3MultiSubnet(c *check.C) {
func (s *DockerNetworkSuite) TestDockerNetworkIpvlanAddressing(c *check.C) {
// Ensure the default gateways, next-hops and default dev devices are properly set
testRequires(c, DaemonIsLinux, IPv6, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
testRequires(c, DaemonIsLinux, IPv6, ipvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
dockerCmd(c, "network", "create", "--driver=macvlan", "--ipv6", "--subnet=172.28.130.0/24",
"--subnet=2001:db8:abca::/64", "--gateway=2001:db8:abca::254", "-o", "macvlan_mode=bridge", "dualstackbridge")
assertNwIsAvailable(c, "dualstackbridge")
@ -373,7 +366,7 @@ func (s *DockerNetworkSuite) TestDockerNetworkIpvlanAddressing(c *check.C) {
func (s *DockerSuite) TestDockerNetworkMacVlanBridgeNilParent(c *check.C) {
// macvlan bridge mode - dummy parent interface is provisioned dynamically
testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
testRequires(c, DaemonIsLinux, macvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
dockerCmd(c, "network", "create", "--driver=macvlan", "dm-nil-parent")
assertNwIsAvailable(c, "dm-nil-parent")
@ -390,7 +383,7 @@ func (s *DockerSuite) TestDockerNetworkMacVlanBridgeNilParent(c *check.C) {
func (s *DockerSuite) TestDockerNetworkMacVlanBridgeInternalMode(c *check.C) {
// macvlan bridge mode --internal containers can communicate inside the network but not externally
testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
testRequires(c, DaemonIsLinux, macvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
dockerCmd(c, "network", "create", "--driver=macvlan", "--internal", "dm-internal")
assertNwIsAvailable(c, "dm-internal")
nr := getNetworkResource(c, "dm-internal")
@ -413,7 +406,7 @@ func (s *DockerSuite) TestDockerNetworkMacVlanBridgeInternalMode(c *check.C) {
func (s *DockerSuite) TestDockerNetworkIpvlanL2NilParent(c *check.C) {
// ipvlan l2 mode - dummy parent interface is provisioned dynamically
testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
testRequires(c, DaemonIsLinux, ipvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
dockerCmd(c, "network", "create", "--driver=ipvlan", "di-nil-parent")
assertNwIsAvailable(c, "di-nil-parent")
@ -430,7 +423,7 @@ func (s *DockerSuite) TestDockerNetworkIpvlanL2NilParent(c *check.C) {
func (s *DockerSuite) TestDockerNetworkIpvlanL2InternalMode(c *check.C) {
// ipvlan l2 mode --internal containers can communicate inside the network but not externally
testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
testRequires(c, DaemonIsLinux, ipvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
dockerCmd(c, "network", "create", "--driver=ipvlan", "--internal", "di-internal")
assertNwIsAvailable(c, "di-internal")
nr := getNetworkResource(c, "di-internal")
@ -452,7 +445,7 @@ func (s *DockerSuite) TestDockerNetworkIpvlanL2InternalMode(c *check.C) {
func (s *DockerSuite) TestDockerNetworkIpvlanL3NilParent(c *check.C) {
// ipvlan l3 mode - dummy parent interface is provisioned dynamically
testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
testRequires(c, DaemonIsLinux, ipvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
dockerCmd(c, "network", "create", "--driver=ipvlan", "--subnet=172.28.230.0/24",
"--subnet=172.28.220.0/24", "-o", "ipvlan_mode=l3", "di-nil-parent-l3")
assertNwIsAvailable(c, "di-nil-parent-l3")
@ -470,7 +463,7 @@ func (s *DockerSuite) TestDockerNetworkIpvlanL3NilParent(c *check.C) {
func (s *DockerSuite) TestDockerNetworkIpvlanL3InternalMode(c *check.C) {
// ipvlan l3 mode --internal containers can communicate inside the network but not externally
testRequires(c, DaemonIsLinux, IpvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
testRequires(c, DaemonIsLinux, ipvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
dockerCmd(c, "network", "create", "--driver=ipvlan", "--subnet=172.28.230.0/24",
"--subnet=172.28.220.0/24", "-o", "ipvlan_mode=l3", "--internal", "di-internal-l3")
assertNwIsAvailable(c, "di-internal-l3")
@ -493,7 +486,7 @@ func (s *DockerSuite) TestDockerNetworkIpvlanL3InternalMode(c *check.C) {
func (s *DockerSuite) TestDockerNetworkMacVlanExistingParent(c *check.C) {
// macvlan bridge mode - empty parent interface containers can reach each other internally but not externally
testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
testRequires(c, DaemonIsLinux, macvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
netName := "dm-parent-exists"
out, err := createMasterDummy(c, "dm-dummy0")
//out, err := createVlanInterface(c, "dm-parent", "dm-slave", "macvlan", "bridge")
@ -513,7 +506,7 @@ func (s *DockerSuite) TestDockerNetworkMacVlanExistingParent(c *check.C) {
func (s *DockerSuite) TestDockerNetworkMacVlanSubinterface(c *check.C) {
// macvlan bridge mode - empty parent interface containers can reach each other internally but not externally
testRequires(c, DaemonIsLinux, MacvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
testRequires(c, DaemonIsLinux, macvlanKernelSupport, NotUserNamespace, NotArm, ExperimentalDaemon)
netName := "dm-subinterface"
out, err := createMasterDummy(c, "dm-dummy0")
c.Assert(err, check.IsNil, check.Commentf(out))

View File

@ -0,0 +1,26 @@
package requirement
import (
"fmt"
"reflect"
"runtime"
)
type skipT interface {
Skip(reason string)
}
// Test represent a function that can be used as a requirement validation.
type Test func() bool
// Is checks if the environment satisfies the requirements
// for the test to run or skips the tests.
func Is(s skipT, requirements ...Test) {
for _, r := range requirements {
isValid := r()
if !isValid {
requirementFunc := runtime.FuncForPC(reflect.ValueOf(r).Pointer()).Name()
s.Skip(fmt.Sprintf("unmatched requirement %s", requirementFunc))
}
}
}

View File

@ -1,237 +0,0 @@
package main
import (
"fmt"
"io/ioutil"
"net/http"
"os"
"os/exec"
"strings"
"time"
"github.com/go-check/check"
)
type testCondition func() bool
type testRequirement struct {
Condition testCondition
SkipMessage string
}
// List test requirements
var (
DaemonIsWindows = testRequirement{
func() bool { return daemonPlatform == "windows" },
"Test requires a Windows daemon",
}
DaemonIsLinux = testRequirement{
func() bool { return daemonPlatform == "linux" },
"Test requires a Linux daemon",
}
ExperimentalDaemon = testRequirement{
func() bool { return experimentalDaemon },
"Test requires an experimental daemon",
}
NotExperimentalDaemon = testRequirement{
func() bool { return !experimentalDaemon },
"Test requires a non experimental daemon",
}
IsAmd64 = testRequirement{
func() bool { return os.Getenv("DOCKER_ENGINE_GOARCH") == "amd64" },
"Test requires a daemon running on amd64",
}
NotArm = testRequirement{
func() bool { return os.Getenv("DOCKER_ENGINE_GOARCH") != "arm" },
"Test requires a daemon not running on ARM",
}
NotArm64 = testRequirement{
func() bool { return os.Getenv("DOCKER_ENGINE_GOARCH") != "arm64" },
"Test requires a daemon not running on arm64",
}
NotPpc64le = testRequirement{
func() bool { return os.Getenv("DOCKER_ENGINE_GOARCH") != "ppc64le" },
"Test requires a daemon not running on ppc64le",
}
NotS390X = testRequirement{
func() bool { return os.Getenv("DOCKER_ENGINE_GOARCH") != "s390x" },
"Test requires a daemon not running on s390x",
}
SameHostDaemon = testRequirement{
func() bool { return isLocalDaemon },
"Test requires docker daemon to run on the same machine as CLI",
}
UnixCli = testRequirement{
func() bool { return isUnixCli },
"Test requires posix utilities or functionality to run.",
}
ExecSupport = testRequirement{
func() bool { return supportsExec },
"Test requires 'docker exec' capabilities on the tested daemon.",
}
Network = testRequirement{
func() bool {
// Set a timeout on the GET at 15s
var timeout = time.Duration(15 * time.Second)
var url = "https://hub.docker.com"
client := http.Client{
Timeout: timeout,
}
resp, err := client.Get(url)
if err != nil && strings.Contains(err.Error(), "use of closed network connection") {
panic(fmt.Sprintf("Timeout for GET request on %s", url))
}
if resp != nil {
resp.Body.Close()
}
return err == nil
},
"Test requires network availability, environment variable set to none to run in a non-network enabled mode.",
}
Apparmor = testRequirement{
func() bool {
buf, err := ioutil.ReadFile("/sys/module/apparmor/parameters/enabled")
return err == nil && len(buf) > 1 && buf[0] == 'Y'
},
"Test requires apparmor is enabled.",
}
RegistryHosting = testRequirement{
func() bool {
// for now registry binary is built only if we're running inside
// container through `make test`. Figure that out by testing if
// registry binary is in PATH.
_, err := exec.LookPath(v2binary)
return err == nil
},
fmt.Sprintf("Test requires an environment that can host %s in the same host", v2binary),
}
NotaryHosting = testRequirement{
func() bool {
// for now notary binary is built only if we're running inside
// container through `make test`. Figure that out by testing if
// notary-server binary is in PATH.
_, err := exec.LookPath(notaryServerBinary)
return err == nil
},
fmt.Sprintf("Test requires an environment that can host %s in the same host", notaryServerBinary),
}
NotaryServerHosting = testRequirement{
func() bool {
// for now notary-server binary is built only if we're running inside
// container through `make test`. Figure that out by testing if
// notary-server binary is in PATH.
_, err := exec.LookPath(notaryServerBinary)
return err == nil
},
fmt.Sprintf("Test requires an environment that can host %s in the same host", notaryServerBinary),
}
NotOverlay = testRequirement{
func() bool {
return !strings.HasPrefix(daemonStorageDriver, "overlay")
},
"Test requires underlying root filesystem not be backed by overlay.",
}
Devicemapper = testRequirement{
func() bool {
return strings.HasPrefix(daemonStorageDriver, "devicemapper")
},
"Test requires underlying root filesystem to be backed by devicemapper.",
}
IPv6 = testRequirement{
func() bool {
cmd := exec.Command("test", "-f", "/proc/net/if_inet6")
if err := cmd.Run(); err != nil {
return true
}
return false
},
"Test requires support for IPv6",
}
UserNamespaceROMount = testRequirement{
func() bool {
// quick case--userns not enabled in this test run
if os.Getenv("DOCKER_REMAP_ROOT") == "" {
return true
}
if _, _, err := dockerCmdWithError("run", "--rm", "--read-only", "busybox", "date"); err != nil {
return false
}
return true
},
"Test cannot be run if user namespaces enabled but readonly mounts fail on this kernel.",
}
UserNamespaceInKernel = testRequirement{
func() bool {
if _, err := os.Stat("/proc/self/uid_map"); os.IsNotExist(err) {
/*
* This kernel-provided file only exists if user namespaces are
* supported
*/
return false
}
// We need extra check on redhat based distributions
if f, err := os.Open("/sys/module/user_namespace/parameters/enable"); err == nil {
defer f.Close()
b := make([]byte, 1)
_, _ = f.Read(b)
return string(b) != "N"
}
return true
},
"Kernel must have user namespaces configured and enabled.",
}
NotUserNamespace = testRequirement{
func() bool {
root := os.Getenv("DOCKER_REMAP_ROOT")
return root == ""
},
"Test cannot be run when remapping root",
}
IsPausable = testRequirement{
func() bool {
if daemonPlatform == "windows" {
return isolation == "hyperv"
}
return true
},
"Test requires containers are pausable.",
}
NotPausable = testRequirement{
func() bool {
if daemonPlatform == "windows" {
return isolation == "process"
}
return false
},
"Test requires containers are not pausable.",
}
IsolationIsHyperv = testRequirement{
func() bool {
return daemonPlatform == "windows" && isolation == "hyperv"
},
"Test requires a Windows daemon running default isolation mode of hyperv.",
}
IsolationIsProcess = testRequirement{
func() bool {
return daemonPlatform == "windows" && isolation == "process"
},
"Test requires a Windows daemon running default isolation mode of process.",
}
)
// testRequires checks if the environment satisfies the requirements
// for the test to run or skips the tests.
func testRequires(c *check.C, requirements ...testRequirement) {
for _, r := range requirements {
if !r.Condition() {
c.Skip(r.SkipMessage)
}
}
}

View File

@ -0,0 +1,211 @@
package main
import (
"fmt"
"io/ioutil"
"net/http"
"os"
"os/exec"
"strings"
"time"
"github.com/docker/docker/integration-cli/requirement"
"github.com/go-check/check"
)
func PlatformIs(platform string) bool {
return daemonPlatform == platform
}
func ArchitectureIs(arch string) bool {
return os.Getenv("DOCKER_ENGINE_GOARCH") == arch
}
func ArchitectureIsNot(arch string) bool {
return os.Getenv("DOCKER_ENGINE_GOARCH") != arch
}
func StorageDriverIs(storageDriver string) bool {
return strings.HasPrefix(daemonStorageDriver, storageDriver)
}
func StorageDriverIsNot(storageDriver string) bool {
return !strings.HasPrefix(daemonStorageDriver, storageDriver)
}
func DaemonIsWindows() bool {
return PlatformIs("windows")
}
func DaemonIsLinux() bool {
return PlatformIs("linux")
}
func ExperimentalDaemon() bool {
return experimentalDaemon
}
func NotExperimentalDaemon() bool {
return !experimentalDaemon
}
func IsAmd64() bool {
return ArchitectureIs("amd64")
}
func NotArm() bool {
return ArchitectureIsNot("arm")
}
func NotArm64() bool {
return ArchitectureIsNot("arm64")
}
func NotPpc64le() bool {
return ArchitectureIsNot("ppc64le")
}
func NotS390X() bool {
return ArchitectureIsNot("s390x")
}
func SameHostDaemon() bool {
return isLocalDaemon
}
func UnixCli() bool {
return isUnixCli
}
func ExecSupport() bool {
return supportsExec
}
func Network() bool {
// Set a timeout on the GET at 15s
var timeout = time.Duration(15 * time.Second)
var url = "https://hub.docker.com"
client := http.Client{
Timeout: timeout,
}
resp, err := client.Get(url)
if err != nil && strings.Contains(err.Error(), "use of closed network connection") {
panic(fmt.Sprintf("Timeout for GET request on %s", url))
}
if resp != nil {
resp.Body.Close()
}
return err == nil
}
func Apparmor() bool {
buf, err := ioutil.ReadFile("/sys/module/apparmor/parameters/enabled")
return err == nil && len(buf) > 1 && buf[0] == 'Y'
}
func RegistryHosting() bool {
// for now registry binary is built only if we're running inside
// container through `make test`. Figure that out by testing if
// registry binary is in PATH.
_, err := exec.LookPath(v2binary)
return err == nil
}
func NotaryHosting() bool {
// for now notary binary is built only if we're running inside
// container through `make test`. Figure that out by testing if
// notary-server binary is in PATH.
_, err := exec.LookPath(notaryServerBinary)
return err == nil
}
func NotaryServerHosting() bool {
// for now notary-server binary is built only if we're running inside
// container through `make test`. Figure that out by testing if
// notary-server binary is in PATH.
_, err := exec.LookPath(notaryServerBinary)
return err == nil
}
func NotOverlay() bool {
return StorageDriverIsNot("overlay")
}
func Devicemapper() bool {
return StorageDriverIs("devicemapper")
}
func IPv6() bool {
cmd := exec.Command("test", "-f", "/proc/net/if_inet6")
return cmd.Run() != nil
}
func UserNamespaceROMount() bool {
// quick case--userns not enabled in this test run
if os.Getenv("DOCKER_REMAP_ROOT") == "" {
return true
}
if _, _, err := dockerCmdWithError("run", "--rm", "--read-only", "busybox", "date"); err != nil {
return false
}
return true
}
func NotUserNamespace() bool {
root := os.Getenv("DOCKER_REMAP_ROOT")
return root == ""
}
func UserNamespaceInKernel() bool {
if _, err := os.Stat("/proc/self/uid_map"); os.IsNotExist(err) {
/*
* This kernel-provided file only exists if user namespaces are
* supported
*/
return false
}
// We need extra check on redhat based distributions
if f, err := os.Open("/sys/module/user_namespace/parameters/enable"); err == nil {
defer f.Close()
b := make([]byte, 1)
_, _ = f.Read(b)
return string(b) != "N"
}
return true
}
func IsPausable() bool {
if daemonPlatform == "windows" {
return isolation == "hyperv"
}
return true
}
func NotPausable() bool {
if daemonPlatform == "windows" {
return isolation == "process"
}
return false
}
func IsolationIs(expectedIsolation string) bool {
return daemonPlatform == "windows" && string(isolation) == expectedIsolation
}
func IsolationIsHyperv() bool {
return IsolationIs("hyperv")
}
func IsolationIsProcess() bool {
return IsolationIs("process")
}
// testRequires checks if the environment satisfies the requirements
// for the test to run or skips the tests.
func testRequires(c *check.C, requirements ...requirement.Test) {
requirement.Is(c, requirements...)
}

View File

@ -1,159 +0,0 @@
// +build !windows
package main
import (
"bytes"
"io/ioutil"
"os/exec"
"strings"
"github.com/docker/docker/pkg/parsers/kernel"
"github.com/docker/docker/pkg/sysinfo"
)
var (
// SysInfo stores information about which features a kernel supports.
SysInfo *sysinfo.SysInfo
cpuCfsPeriod = testRequirement{
func() bool {
return SysInfo.CPUCfsPeriod
},
"Test requires an environment that supports cgroup cfs period.",
}
cpuCfsQuota = testRequirement{
func() bool {
return SysInfo.CPUCfsQuota
},
"Test requires an environment that supports cgroup cfs quota.",
}
cpuShare = testRequirement{
func() bool {
return SysInfo.CPUShares
},
"Test requires an environment that supports cgroup cpu shares.",
}
oomControl = testRequirement{
func() bool {
return SysInfo.OomKillDisable
},
"Test requires Oom control enabled.",
}
pidsLimit = testRequirement{
func() bool {
return SysInfo.PidsLimit
},
"Test requires pids limit enabled.",
}
kernelMemorySupport = testRequirement{
func() bool {
return SysInfo.KernelMemory
},
"Test requires an environment that supports cgroup kernel memory.",
}
memoryLimitSupport = testRequirement{
func() bool {
return SysInfo.MemoryLimit
},
"Test requires an environment that supports cgroup memory limit.",
}
memoryReservationSupport = testRequirement{
func() bool {
return SysInfo.MemoryReservation
},
"Test requires an environment that supports cgroup memory reservation.",
}
swapMemorySupport = testRequirement{
func() bool {
return SysInfo.SwapLimit
},
"Test requires an environment that supports cgroup swap memory limit.",
}
memorySwappinessSupport = testRequirement{
func() bool {
return SysInfo.MemorySwappiness
},
"Test requires an environment that supports cgroup memory swappiness.",
}
blkioWeight = testRequirement{
func() bool {
return SysInfo.BlkioWeight
},
"Test requires an environment that supports blkio weight.",
}
cgroupCpuset = testRequirement{
func() bool {
return SysInfo.Cpuset
},
"Test requires an environment that supports cgroup cpuset.",
}
seccompEnabled = testRequirement{
func() bool {
return supportsSeccomp && SysInfo.Seccomp
},
"Test requires that seccomp support be enabled in the daemon.",
}
bridgeNfIptables = testRequirement{
func() bool {
return !SysInfo.BridgeNFCallIPTablesDisabled
},
"Test requires that bridge-nf-call-iptables support be enabled in the daemon.",
}
bridgeNfIP6tables = testRequirement{
func() bool {
return !SysInfo.BridgeNFCallIP6TablesDisabled
},
"Test requires that bridge-nf-call-ip6tables support be enabled in the daemon.",
}
unprivilegedUsernsClone = testRequirement{
func() bool {
content, err := ioutil.ReadFile("/proc/sys/kernel/unprivileged_userns_clone")
if err == nil && strings.Contains(string(content), "0") {
return false
}
return true
},
"Test cannot be run with 'sysctl kernel.unprivileged_userns_clone' = 0",
}
ambientCapabilities = testRequirement{
func() bool {
content, err := ioutil.ReadFile("/proc/self/status")
if err == nil && strings.Contains(string(content), "CapAmb:") {
return true
}
return false
},
"Test cannot be run without a kernel (4.3+) supporting ambient capabilities",
}
overlayFSSupported = testRequirement{
func() bool {
cmd := exec.Command(dockerBinary, "run", "--rm", "busybox", "/bin/sh", "-c", "cat /proc/filesystems")
out, err := cmd.CombinedOutput()
if err != nil {
return false
}
return bytes.Contains(out, []byte("overlay\n"))
},
"Test cannot be run without suppport for overlayfs",
}
overlay2Supported = testRequirement{
func() bool {
if !overlayFSSupported.Condition() {
return false
}
daemonV, err := kernel.ParseRelease(daemonKernelVersion)
if err != nil {
return false
}
requiredV := kernel.VersionInfo{Kernel: 4}
return kernel.CompareKernelVersion(*daemonV, requiredV) > -1
},
"Test cannot be run without overlay2 support (kernel 4.0+)",
}
)
func init() {
SysInfo = sysinfo.New(true)
}

View File

@ -0,0 +1,115 @@
// +build !windows
package main
import (
"bytes"
"io/ioutil"
"os/exec"
"strings"
"github.com/docker/docker/pkg/parsers/kernel"
"github.com/docker/docker/pkg/sysinfo"
)
var (
// SysInfo stores information about which features a kernel supports.
SysInfo *sysinfo.SysInfo
)
func cpuCfsPeriod() bool {
return SysInfo.CPUCfsPeriod
}
func cpuCfsQuota() bool {
return SysInfo.CPUCfsQuota
}
func cpuShare() bool {
return SysInfo.CPUShares
}
func oomControl() bool {
return SysInfo.OomKillDisable
}
func pidsLimit() bool {
return SysInfo.PidsLimit
}
func kernelMemorySupport() bool {
return SysInfo.KernelMemory
}
func memoryLimitSupport() bool {
return SysInfo.MemoryLimit
}
func memoryReservationSupport() bool {
return SysInfo.MemoryReservation
}
func swapMemorySupport() bool {
return SysInfo.SwapLimit
}
func memorySwappinessSupport() bool {
return SysInfo.MemorySwappiness
}
func blkioWeight() bool {
return SysInfo.BlkioWeight
}
func cgroupCpuset() bool {
return SysInfo.Cpuset
}
func seccompEnabled() bool {
return supportsSeccomp && SysInfo.Seccomp
}
func bridgeNfIptables() bool {
return !SysInfo.BridgeNFCallIPTablesDisabled
}
func bridgeNfIP6tables() bool {
return !SysInfo.BridgeNFCallIP6TablesDisabled
}
func unprivilegedUsernsClone() bool {
content, err := ioutil.ReadFile("/proc/sys/kernel/unprivileged_userns_clone")
return err != nil || !strings.Contains(string(content), "0")
}
func ambientCapabilities() bool {
content, err := ioutil.ReadFile("/proc/self/status")
return err != nil || strings.Contains(string(content), "CapAmb:")
}
func overlayFSSupported() bool {
cmd := exec.Command(dockerBinary, "run", "--rm", "busybox", "/bin/sh", "-c", "cat /proc/filesystems")
out, err := cmd.CombinedOutput()
if err != nil {
return false
}
return bytes.Contains(out, []byte("overlay\n"))
}
func overlay2Supported() bool {
if !overlayFSSupported() {
return false
}
daemonV, err := kernel.ParseRelease(daemonKernelVersion)
if err != nil {
return false
}
requiredV := kernel.VersionInfo{Kernel: 4}
return kernel.CompareKernelVersion(*daemonV, requiredV) > -1
}
func init() {
SysInfo = sysinfo.New(true)
}