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 (
testEnv *environment.Execution
// FIXME(vdemeester) remove these and use environmentdaemonPid
protectedImages = map[string]struct{}{}
// the docker client binary to use
dockerBinary = "docker"
)
@ -64,16 +61,6 @@ func TestMain(m *testing.M) {
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() {
fmt.Println("INFO: Testing against a local daemon")
} else {
@ -84,6 +71,14 @@ func TestMain(m *testing.M) {
}
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" {
ensureFrozenImagesLinux(t)
}
@ -104,14 +99,7 @@ func (s *DockerSuite) OnTimeout(c *check.C) {
}
func (s *DockerSuite) TearDownTest(c *check.C) {
unpauseAllContainers(c)
deleteAllContainers(c)
deleteAllImages(c)
deleteAllVolumes(c)
deleteAllNetworks(c)
if testEnv.DaemonPlatform() == "linux" {
deleteAllPlugins(c)
}
testEnv.Clean(c, dockerBinary)
}
func init() {

View file

@ -20,23 +20,19 @@ import (
"time"
"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/daemon"
"github.com/docker/docker/integration-cli/environment"
"github.com/docker/docker/integration-cli/registry"
"github.com/docker/docker/integration-cli/request"
"github.com/docker/docker/opts"
"github.com/docker/docker/pkg/stringutils"
icmd "github.com/docker/docker/pkg/testutil/cmd"
"github.com/go-check/check"
)
// Deprecated
func daemonHost() string {
daemonURLStr := "unix://" + opts.DefaultUnixSocket
if daemonHostVar := os.Getenv("DOCKER_HOST"); daemonHostVar != "" {
daemonURLStr = daemonHostVar
}
return daemonURLStr
return environment.DaemonHost()
}
// FIXME(vdemeester) move this away are remove ignoreNoSuchContainer bool
@ -58,6 +54,7 @@ func getAllContainers(c *check.C) string {
return result.Combined()
}
// Deprecated
func deleteAllContainers(c *check.C) {
containers := getAllContainers(c)
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 {
result := icmd.RunCommand(dockerBinary, "ps", "-f", "status=paused", "-q", "-a")
result.Assert(c, icmd.Success)
@ -206,6 +73,7 @@ func unpauseContainer(c *check.C, container string) {
dockerCmd(c, "unpause", container)
}
// Deprecated
func unpauseAllContainers(c *check.C) {
containers := getPausedContainers(c)
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)))
)
c.Assert(ensureHTTPServerImage(), checker.IsNil)
ensureHTTPServerImage(c)
// Build the image
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
// Environment variable WINDOWS_BASE_IMAGE can override this
baseImage string
protectedElements protectedElements
}
// New creates a new Execution struct
@ -100,6 +102,9 @@ func New() (*Execution, error) {
daemonPid: daemonPid,
experimentalDaemon: info.ExperimentalBuild,
baseImage: baseImage,
protectedElements: protectedElements{
images: map[string]struct{}{},
},
}, nil
}
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.Fatalf("%+v", err)
}
for _, img := range images {
protectedImages[img] = struct{}{}
}
defer testEnv.ProtectImage(t, images...)
}
var ensureSyscallTestOnce sync.Once
@ -46,7 +44,7 @@ func ensureSyscallTest(c *check.C) {
if !doIt {
return
}
protectedImages["syscall-test:latest"] = struct{}{}
defer testEnv.ProtectImage(c, "syscall-test:latest")
// if no match, must build in docker, which is significantly slower
// (slower mostly because of the vfs graphdriver)
@ -104,7 +102,7 @@ func ensureSyscallTestBuild(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 {
ensureNNPTestBuild(c)
return

View file

@ -1,7 +1,6 @@
package main
import (
"fmt"
"io/ioutil"
"os"
"os/exec"
@ -11,21 +10,21 @@ import (
var ensureHTTPServerOnce sync.Once
func ensureHTTPServerImage() error {
func ensureHTTPServerImage(t testingT) {
var doIt bool
ensureHTTPServerOnce.Do(func() {
doIt = true
})
if !doIt {
return nil
return
}
protectedImages["httpserver:latest"] = struct{}{}
defer testEnv.ProtectImage(t, "httpserver:latest")
tmp, err := ioutil.TempDir("", "docker-http-server-test")
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)
@ -40,7 +39,7 @@ func ensureHTTPServerImage() error {
goCmd, lookErr := exec.LookPath("go")
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")
@ -51,19 +50,18 @@ func ensureHTTPServerImage() error {
}...)
var out []byte
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")
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 {
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 {
return fmt.Errorf("could not build http server: %v", string(out))
t.Fatalf("could not build http server: %v", string(out))
}
return nil
}