1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Merge pull request #31460 from vdemeester/integration-clean-in-env-p1

Move TearDownTest cleaning to environment package
This commit is contained in:
Sebastiaan van Stijn 2017-03-02 09:51:46 +01:00 committed by GitHub
commit 1a412a0470
7 changed files with 257 additions and 175 deletions

View file

@ -34,9 +34,6 @@ const (
var ( var (
testEnv *environment.Execution testEnv *environment.Execution
// FIXME(vdemeester) remove these and use environmentdaemonPid
protectedImages = map[string]struct{}{}
// the docker client binary to use // the docker client binary to use
dockerBinary = "docker" dockerBinary = "docker"
) )
@ -64,16 +61,6 @@ func TestMain(m *testing.M) {
os.Exit(1) os.Exit(1)
} }
cmd := exec.Command(dockerBinary, "images", "-f", "dangling=false", "--format", "{{.Repository}}:{{.Tag}}")
cmd.Env = appendBaseEnv(true)
out, err := cmd.CombinedOutput()
if err != nil {
panic(fmt.Errorf("err=%v\nout=%s\n", err, out))
}
images := strings.Split(strings.TrimSpace(string(out)), "\n")
for _, img := range images {
protectedImages[img] = struct{}{}
}
if testEnv.LocalDaemon() { if testEnv.LocalDaemon() {
fmt.Println("INFO: Testing against a local daemon") fmt.Println("INFO: Testing against a local daemon")
} else { } else {
@ -84,6 +71,14 @@ func TestMain(m *testing.M) {
} }
func Test(t *testing.T) { func Test(t *testing.T) {
cmd := exec.Command(dockerBinary, "images", "-f", "dangling=false", "--format", "{{.Repository}}:{{.Tag}}")
cmd.Env = appendBaseEnv(true)
out, err := cmd.CombinedOutput()
if err != nil {
panic(fmt.Errorf("err=%v\nout=%s\n", err, out))
}
images := strings.Split(strings.TrimSpace(string(out)), "\n")
testEnv.ProtectImage(t, images...)
if testEnv.DaemonPlatform() == "linux" { if testEnv.DaemonPlatform() == "linux" {
ensureFrozenImagesLinux(t) ensureFrozenImagesLinux(t)
} }
@ -104,14 +99,7 @@ func (s *DockerSuite) OnTimeout(c *check.C) {
} }
func (s *DockerSuite) TearDownTest(c *check.C) { func (s *DockerSuite) TearDownTest(c *check.C) {
unpauseAllContainers(c) testEnv.Clean(c, dockerBinary)
deleteAllContainers(c)
deleteAllImages(c)
deleteAllVolumes(c)
deleteAllNetworks(c)
if testEnv.DaemonPlatform() == "linux" {
deleteAllPlugins(c)
}
} }
func init() { func init() {

View file

@ -20,23 +20,19 @@ import (
"time" "time"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
volumetypes "github.com/docker/docker/api/types/volume"
"github.com/docker/docker/integration-cli/checker" "github.com/docker/docker/integration-cli/checker"
"github.com/docker/docker/integration-cli/daemon" "github.com/docker/docker/integration-cli/daemon"
"github.com/docker/docker/integration-cli/environment"
"github.com/docker/docker/integration-cli/registry" "github.com/docker/docker/integration-cli/registry"
"github.com/docker/docker/integration-cli/request" "github.com/docker/docker/integration-cli/request"
"github.com/docker/docker/opts"
"github.com/docker/docker/pkg/stringutils" "github.com/docker/docker/pkg/stringutils"
icmd "github.com/docker/docker/pkg/testutil/cmd" icmd "github.com/docker/docker/pkg/testutil/cmd"
"github.com/go-check/check" "github.com/go-check/check"
) )
// Deprecated
func daemonHost() string { func daemonHost() string {
daemonURLStr := "unix://" + opts.DefaultUnixSocket return environment.DaemonHost()
if daemonHostVar := os.Getenv("DOCKER_HOST"); daemonHostVar != "" {
daemonURLStr = daemonHostVar
}
return daemonURLStr
} }
// FIXME(vdemeester) move this away are remove ignoreNoSuchContainer bool // FIXME(vdemeester) move this away are remove ignoreNoSuchContainer bool
@ -58,6 +54,7 @@ func getAllContainers(c *check.C) string {
return result.Combined() return result.Combined()
} }
// Deprecated
func deleteAllContainers(c *check.C) { func deleteAllContainers(c *check.C) {
containers := getAllContainers(c) containers := getAllContainers(c)
if containers != "" { if containers != "" {
@ -66,136 +63,6 @@ func deleteAllContainers(c *check.C) {
} }
} }
func deleteAllNetworks(c *check.C) {
networks, err := getAllNetworks()
c.Assert(err, check.IsNil)
var errs []string
for _, n := range networks {
if n.Name == "bridge" || n.Name == "none" || n.Name == "host" {
continue
}
if testEnv.DaemonPlatform() == "windows" && strings.ToLower(n.Name) == "nat" {
// nat is a pre-defined network on Windows and cannot be removed
continue
}
status, b, err := request.SockRequest("DELETE", "/networks/"+n.Name, nil, daemonHost())
if err != nil {
errs = append(errs, err.Error())
continue
}
if status != http.StatusNoContent {
errs = append(errs, fmt.Sprintf("error deleting network %s: %s", n.Name, string(b)))
}
}
c.Assert(errs, checker.HasLen, 0, check.Commentf(strings.Join(errs, "\n")))
}
func getAllNetworks() ([]types.NetworkResource, error) {
var networks []types.NetworkResource
_, b, err := request.SockRequest("GET", "/networks", nil, daemonHost())
if err != nil {
return nil, err
}
if err := json.Unmarshal(b, &networks); err != nil {
return nil, err
}
return networks, nil
}
func deleteAllPlugins(c *check.C) {
plugins, err := getAllPlugins()
c.Assert(err, checker.IsNil)
var errs []string
for _, p := range plugins {
pluginName := p.Name
status, b, err := request.SockRequest("DELETE", "/plugins/"+pluginName+"?force=1", nil, daemonHost())
if err != nil {
errs = append(errs, err.Error())
continue
}
if status != http.StatusOK {
errs = append(errs, fmt.Sprintf("error deleting plugin %s: %s", p.Name, string(b)))
}
}
c.Assert(errs, checker.HasLen, 0, check.Commentf(strings.Join(errs, "\n")))
}
func getAllPlugins() (types.PluginsListResponse, error) {
var plugins types.PluginsListResponse
_, b, err := request.SockRequest("GET", "/plugins", nil, daemonHost())
if err != nil {
return nil, err
}
if err := json.Unmarshal(b, &plugins); err != nil {
return nil, err
}
return plugins, nil
}
func deleteAllVolumes(c *check.C) {
volumes, err := getAllVolumes()
c.Assert(err, checker.IsNil)
var errs []string
for _, v := range volumes {
status, b, err := request.SockRequest("DELETE", "/volumes/"+v.Name, nil, daemonHost())
if err != nil {
errs = append(errs, err.Error())
continue
}
if status != http.StatusNoContent {
errs = append(errs, fmt.Sprintf("error deleting volume %s: %s", v.Name, string(b)))
}
}
c.Assert(errs, checker.HasLen, 0, check.Commentf(strings.Join(errs, "\n")))
}
func getAllVolumes() ([]*types.Volume, error) {
var volumes volumetypes.VolumesListOKBody
_, b, err := request.SockRequest("GET", "/volumes", nil, daemonHost())
if err != nil {
return nil, err
}
if err := json.Unmarshal(b, &volumes); err != nil {
return nil, err
}
return volumes.Volumes, nil
}
func deleteAllImages(c *check.C) {
cmd := exec.Command(dockerBinary, "images", "--digests")
cmd.Env = appendBaseEnv(true)
out, err := cmd.CombinedOutput()
c.Assert(err, checker.IsNil)
lines := strings.Split(string(out), "\n")[1:]
imgMap := map[string]struct{}{}
for _, l := range lines {
if l == "" {
continue
}
fields := strings.Fields(l)
imgTag := fields[0] + ":" + fields[1]
if _, ok := protectedImages[imgTag]; !ok {
if fields[0] == "<none>" || fields[1] == "<none>" {
if fields[2] != "<none>" {
imgMap[fields[0]+"@"+fields[2]] = struct{}{}
} else {
imgMap[fields[3]] = struct{}{}
}
// continue
} else {
imgMap[imgTag] = struct{}{}
}
}
}
if len(imgMap) != 0 {
imgs := make([]string, 0, len(imgMap))
for k := range imgMap {
imgs = append(imgs, k)
}
dockerCmd(c, append([]string{"rmi", "-f"}, imgs...)...)
}
}
func getPausedContainers(c *check.C) []string { func getPausedContainers(c *check.C) []string {
result := icmd.RunCommand(dockerBinary, "ps", "-f", "status=paused", "-q", "-a") result := icmd.RunCommand(dockerBinary, "ps", "-f", "status=paused", "-q", "-a")
result.Assert(c, icmd.Success) result.Assert(c, icmd.Success)
@ -206,6 +73,7 @@ func unpauseContainer(c *check.C, container string) {
dockerCmd(c, "unpause", container) dockerCmd(c, "unpause", container)
} }
// Deprecated
func unpauseAllContainers(c *check.C) { func unpauseAllContainers(c *check.C) {
containers := getPausedContainers(c) containers := getPausedContainers(c)
for _, value := range containers { for _, value := range containers {
@ -487,7 +355,7 @@ func newRemoteFileServer(c *check.C, ctx *FakeContext) *remoteFileServer {
container = fmt.Sprintf("fileserver-cnt-%s", strings.ToLower(stringutils.GenerateRandomAlphaOnlyString(10))) container = fmt.Sprintf("fileserver-cnt-%s", strings.ToLower(stringutils.GenerateRandomAlphaOnlyString(10)))
) )
c.Assert(ensureHTTPServerImage(), checker.IsNil) ensureHTTPServerImage(c)
// Build the image // Build the image
fakeContextAddDockerfile(c, ctx, `FROM httpserver fakeContextAddDockerfile(c, ctx, `FROM httpserver

View file

@ -0,0 +1,213 @@
package environment
import (
"encoding/json"
"fmt"
"net/http"
"os"
"strings"
"github.com/docker/docker/api/types"
volumetypes "github.com/docker/docker/api/types/volume"
"github.com/docker/docker/integration-cli/request"
"github.com/docker/docker/opts"
icmd "github.com/docker/docker/pkg/testutil/cmd"
)
type testingT interface {
logT
Fatalf(string, ...interface{})
}
type logT interface {
Logf(string, ...interface{})
}
// Clean the environment, preserving protected objects (images, containers, ...)
// and removing everything else. It's meant to run after any tests so that they don't
// depend on each others.
func (e *Execution) Clean(t testingT, dockerBinary string) {
unpauseAllContainers(t, dockerBinary)
deleteAllContainers(t, dockerBinary)
deleteAllImages(t, dockerBinary, e.protectedElements.images)
deleteAllVolumes(t, dockerBinary)
deleteAllNetworks(t, dockerBinary, e.DaemonPlatform())
if e.DaemonPlatform() == "linux" {
deleteAllPlugins(t, dockerBinary)
}
}
func unpauseAllContainers(t testingT, dockerBinary string) {
containers := getPausedContainers(t, dockerBinary)
if len(containers) > 0 {
icmd.RunCommand(dockerBinary, append([]string{"unpause"}, containers...)...).Assert(t, icmd.Success)
}
}
func getPausedContainers(t testingT, dockerBinary string) []string {
result := icmd.RunCommand(dockerBinary, "ps", "-f", "status=paused", "-q", "-a")
result.Assert(t, icmd.Success)
return strings.Fields(result.Combined())
}
func deleteAllContainers(t testingT, dockerBinary string) {
containers := getAllContainers(t, dockerBinary)
if len(containers) > 0 {
icmd.RunCommand(dockerBinary, append([]string{"rm", "-fv"}, containers...)...).Assert(t, icmd.Success)
}
}
func getAllContainers(t testingT, dockerBinary string) []string {
result := icmd.RunCommand(dockerBinary, "ps", "-q", "-a")
result.Assert(t, icmd.Success)
return strings.Fields(result.Combined())
}
func deleteAllImages(t testingT, dockerBinary string, protectedImages map[string]struct{}) {
result := icmd.RunCommand(dockerBinary, "images", "--digests")
result.Assert(t, icmd.Success)
lines := strings.Split(string(result.Combined()), "\n")[1:]
imgMap := map[string]struct{}{}
for _, l := range lines {
if l == "" {
continue
}
fields := strings.Fields(l)
imgTag := fields[0] + ":" + fields[1]
if _, ok := protectedImages[imgTag]; !ok {
if fields[0] == "<none>" || fields[1] == "<none>" {
if fields[2] != "<none>" {
imgMap[fields[0]+"@"+fields[2]] = struct{}{}
} else {
imgMap[fields[3]] = struct{}{}
}
// continue
} else {
imgMap[imgTag] = struct{}{}
}
}
}
if len(imgMap) != 0 {
imgs := make([]string, 0, len(imgMap))
for k := range imgMap {
imgs = append(imgs, k)
}
icmd.RunCommand(dockerBinary, append([]string{"rmi", "-f"}, imgs...)...).Assert(t, icmd.Success)
}
}
func deleteAllVolumes(t testingT, dockerBinary string) {
volumes, err := getAllVolumes()
if err != nil {
t.Fatalf("%v", err)
}
var errs []string
for _, v := range volumes {
status, b, err := request.SockRequest("DELETE", "/volumes/"+v.Name, nil, DaemonHost())
if err != nil {
errs = append(errs, err.Error())
continue
}
if status != http.StatusNoContent {
errs = append(errs, fmt.Sprintf("error deleting volume %s: %s", v.Name, string(b)))
}
}
if len(errs) > 0 {
t.Fatalf("%v", strings.Join(errs, "\n"))
}
}
func getAllVolumes() ([]*types.Volume, error) {
var volumes volumetypes.VolumesListOKBody
_, b, err := request.SockRequest("GET", "/volumes", nil, DaemonHost())
if err != nil {
return nil, err
}
if err := json.Unmarshal(b, &volumes); err != nil {
return nil, err
}
return volumes.Volumes, nil
}
func deleteAllNetworks(t testingT, dockerBinary string, daemonPlatform string) {
networks, err := getAllNetworks()
if err != nil {
t.Fatalf("%v", err)
}
var errs []string
for _, n := range networks {
if n.Name == "bridge" || n.Name == "none" || n.Name == "host" {
continue
}
if daemonPlatform == "windows" && strings.ToLower(n.Name) == "nat" {
// nat is a pre-defined network on Windows and cannot be removed
continue
}
status, b, err := request.SockRequest("DELETE", "/networks/"+n.Name, nil, DaemonHost())
if err != nil {
errs = append(errs, err.Error())
continue
}
if status != http.StatusNoContent {
errs = append(errs, fmt.Sprintf("error deleting network %s: %s", n.Name, string(b)))
}
}
if len(errs) > 0 {
t.Fatalf("%v", strings.Join(errs, "\n"))
}
}
func getAllNetworks() ([]types.NetworkResource, error) {
var networks []types.NetworkResource
_, b, err := request.SockRequest("GET", "/networks", nil, DaemonHost())
if err != nil {
return nil, err
}
if err := json.Unmarshal(b, &networks); err != nil {
return nil, err
}
return networks, nil
}
func deleteAllPlugins(t testingT, dockerBinary string) {
plugins, err := getAllPlugins()
if err != nil {
t.Fatalf("%v", err)
}
var errs []string
for _, p := range plugins {
pluginName := p.Name
status, b, err := request.SockRequest("DELETE", "/plugins/"+pluginName+"?force=1", nil, DaemonHost())
if err != nil {
errs = append(errs, err.Error())
continue
}
if status != http.StatusOK {
errs = append(errs, fmt.Sprintf("error deleting plugin %s: %s", p.Name, string(b)))
}
}
if len(errs) > 0 {
t.Fatalf("%v", strings.Join(errs, "\n"))
}
}
func getAllPlugins() (types.PluginsListResponse, error) {
var plugins types.PluginsListResponse
_, b, err := request.SockRequest("GET", "/plugins", nil, DaemonHost())
if err != nil {
return nil, err
}
if err := json.Unmarshal(b, &plugins); err != nil {
return nil, err
}
return plugins, nil
}
// DaemonHost return the daemon host string for this test execution
func DaemonHost() string {
daemonURLStr := "unix://" + opts.DefaultUnixSocket
if daemonHostVar := os.Getenv("DOCKER_HOST"); daemonHostVar != "" {
daemonURLStr = daemonHostVar
}
return daemonURLStr
}

View file

@ -32,6 +32,8 @@ type Execution struct {
// baseImage is the name of the base image for testing // baseImage is the name of the base image for testing
// Environment variable WINDOWS_BASE_IMAGE can override this // Environment variable WINDOWS_BASE_IMAGE can override this
baseImage string baseImage string
protectedElements protectedElements
} }
// New creates a new Execution struct // New creates a new Execution struct
@ -100,6 +102,9 @@ func New() (*Execution, error) {
daemonPid: daemonPid, daemonPid: daemonPid,
experimentalDaemon: info.ExperimentalBuild, experimentalDaemon: info.ExperimentalBuild,
baseImage: baseImage, baseImage: baseImage,
protectedElements: protectedElements{
images: map[string]struct{}{},
},
}, nil }, nil
} }
func getDaemonDockerInfo() (types.Info, error) { func getDaemonDockerInfo() (types.Info, error) {

View file

@ -0,0 +1,12 @@
package environment
// ProtectImage adds the specified image(s) to be protected in case of clean
func (e *Execution) ProtectImage(t testingT, images ...string) {
for _, image := range images {
e.protectedElements.images[image] = struct{}{}
}
}
type protectedElements struct {
images map[string]struct{}
}

View file

@ -31,9 +31,7 @@ func ensureFrozenImagesLinux(t testingT) {
t.Logf(dockerCmdWithError("images")) t.Logf(dockerCmdWithError("images"))
t.Fatalf("%+v", err) t.Fatalf("%+v", err)
} }
for _, img := range images { defer testEnv.ProtectImage(t, images...)
protectedImages[img] = struct{}{}
}
} }
var ensureSyscallTestOnce sync.Once var ensureSyscallTestOnce sync.Once
@ -46,7 +44,7 @@ func ensureSyscallTest(c *check.C) {
if !doIt { if !doIt {
return return
} }
protectedImages["syscall-test:latest"] = struct{}{} defer testEnv.ProtectImage(c, "syscall-test:latest")
// if no match, must build in docker, which is significantly slower // if no match, must build in docker, which is significantly slower
// (slower mostly because of the vfs graphdriver) // (slower mostly because of the vfs graphdriver)
@ -104,7 +102,7 @@ func ensureSyscallTestBuild(c *check.C) {
} }
func ensureNNPTest(c *check.C) { func ensureNNPTest(c *check.C) {
protectedImages["nnp-test:latest"] = struct{}{} defer testEnv.ProtectImage(c, "nnp-test:latest")
if testEnv.DaemonPlatform() != runtime.GOOS { if testEnv.DaemonPlatform() != runtime.GOOS {
ensureNNPTestBuild(c) ensureNNPTestBuild(c)
return return

View file

@ -1,7 +1,6 @@
package main package main
import ( import (
"fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"os/exec" "os/exec"
@ -11,21 +10,21 @@ import (
var ensureHTTPServerOnce sync.Once var ensureHTTPServerOnce sync.Once
func ensureHTTPServerImage() error { func ensureHTTPServerImage(t testingT) {
var doIt bool var doIt bool
ensureHTTPServerOnce.Do(func() { ensureHTTPServerOnce.Do(func() {
doIt = true doIt = true
}) })
if !doIt { if !doIt {
return nil return
} }
protectedImages["httpserver:latest"] = struct{}{} defer testEnv.ProtectImage(t, "httpserver:latest")
tmp, err := ioutil.TempDir("", "docker-http-server-test") tmp, err := ioutil.TempDir("", "docker-http-server-test")
if err != nil { if err != nil {
return fmt.Errorf("could not build http server: %v", err) t.Fatalf("could not build http server: %v", err)
} }
defer os.RemoveAll(tmp) defer os.RemoveAll(tmp)
@ -40,7 +39,7 @@ func ensureHTTPServerImage() error {
goCmd, lookErr := exec.LookPath("go") goCmd, lookErr := exec.LookPath("go")
if lookErr != nil { if lookErr != nil {
return fmt.Errorf("could not build http server: %v", lookErr) t.Fatalf("could not build http server: %v", lookErr)
} }
cmd := exec.Command(goCmd, "build", "-o", filepath.Join(tmp, "httpserver"), "github.com/docker/docker/contrib/httpserver") cmd := exec.Command(goCmd, "build", "-o", filepath.Join(tmp, "httpserver"), "github.com/docker/docker/contrib/httpserver")
@ -51,19 +50,18 @@ func ensureHTTPServerImage() error {
}...) }...)
var out []byte var out []byte
if out, err = cmd.CombinedOutput(); err != nil { if out, err = cmd.CombinedOutput(); err != nil {
return fmt.Errorf("could not build http server: %s", string(out)) t.Fatalf("could not build http server: %s", string(out))
} }
cpCmd, lookErr := exec.LookPath("cp") cpCmd, lookErr := exec.LookPath("cp")
if lookErr != nil { if lookErr != nil {
return fmt.Errorf("could not build http server: %v", lookErr) t.Fatalf("could not build http server: %v", lookErr)
} }
if out, err = exec.Command(cpCmd, "../contrib/httpserver/Dockerfile", filepath.Join(tmp, "Dockerfile")).CombinedOutput(); err != nil { if out, err = exec.Command(cpCmd, "../contrib/httpserver/Dockerfile", filepath.Join(tmp, "Dockerfile")).CombinedOutput(); err != nil {
return fmt.Errorf("could not build http server: %v", string(out)) t.Fatalf("could not build http server: %v", string(out))
} }
if out, err = exec.Command(dockerBinary, "build", "-q", "-t", "httpserver", tmp).CombinedOutput(); err != nil { if out, err = exec.Command(dockerBinary, "build", "-q", "-t", "httpserver", tmp).CombinedOutput(); err != nil {
return fmt.Errorf("could not build http server: %v", string(out)) t.Fatalf("could not build http server: %v", string(out))
} }
return nil
} }