moby/integration-cli/check_test.go
Brian Goff 97433635a6
De-flake TestSwarmClusterRotateUnlockKey... again... maybe?
This hopefully makes the test less flakey (or removes any flake that
would be caused by the test itself).

1. Adds tail of cluster daemon logs when there is a test failure so we
   can more easily see what may be happening
2. Scans the daemon logs to check if the key is rotated before
   restarting the daemon. This is a little hacky but a little better
   than assuming it is done after a hard-coded 3 seconds.
3. Cleans up the `node ls` check such that it uses a poll function

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
(cherry picked from commit fbdc02534a)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2024-01-24 10:25:12 +01:00

632 lines
15 KiB
Go

package main
import (
"context"
"flag"
"fmt"
"net/http/httptest"
"os"
"path"
"path/filepath"
"strconv"
"sync"
"syscall"
"testing"
"time"
"github.com/docker/docker/integration-cli/cli"
"github.com/docker/docker/integration-cli/daemon"
"github.com/docker/docker/integration-cli/environment"
"github.com/docker/docker/internal/test/suite"
testdaemon "github.com/docker/docker/testutil/daemon"
ienv "github.com/docker/docker/testutil/environment"
"github.com/docker/docker/testutil/fakestorage"
"github.com/docker/docker/testutil/fixtures/plugin"
"github.com/docker/docker/testutil/registry"
"gotest.tools/v3/assert"
)
const (
// the private registry to use for tests
privateRegistryURL = registry.DefaultURL
// path to containerd's ctr binary
ctrBinary = "ctr"
// the docker daemon binary to use
dockerdBinary = "dockerd"
)
var (
testEnv *environment.Execution
// the docker client binary to use
dockerBinary = ""
testEnvOnce sync.Once
)
func init() {
var err error
testEnv, err = environment.New()
if err != nil {
panic(err)
}
}
func TestMain(m *testing.M) {
flag.Parse()
// Global set up
dockerBinary = testEnv.DockerBinary()
err := ienv.EnsureFrozenImagesLinux(&testEnv.Execution)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
testEnv.Print()
printCliVersion()
os.Exit(m.Run())
}
func printCliVersion() {
// Print output of "docker version"
cli.SetTestEnvironment(testEnv)
cmd := cli.Docker(cli.Args("version"))
if cmd.Error != nil {
fmt.Printf("WARNING: Failed to run 'docker version': %+v\n", cmd.Error)
return
}
fmt.Println("INFO: Testing with docker cli version:")
fmt.Println(cmd.Stdout())
}
func ensureTestEnvSetup(t *testing.T) {
testEnvOnce.Do(func() {
cli.SetTestEnvironment(testEnv)
fakestorage.SetTestEnvironment(&testEnv.Execution)
ienv.ProtectAll(t, &testEnv.Execution)
})
}
func TestDockerAPISuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerAPISuite{ds: &DockerSuite{}})
}
func TestDockerBenchmarkSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerBenchmarkSuite{ds: &DockerSuite{}})
}
func TestDockerCLIAttachSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLIAttachSuite{ds: &DockerSuite{}})
}
func TestDockerCLIBuildSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLIBuildSuite{ds: &DockerSuite{}})
}
func TestDockerCLICommitSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLICommitSuite{ds: &DockerSuite{}})
}
func TestDockerCLICpSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLICpSuite{ds: &DockerSuite{}})
}
func TestDockerCLICreateSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLICreateSuite{ds: &DockerSuite{}})
}
func TestDockerCLIEventSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLIEventSuite{ds: &DockerSuite{}})
}
func TestDockerCLIExecSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLIExecSuite{ds: &DockerSuite{}})
}
func TestDockerCLIHealthSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLIHealthSuite{ds: &DockerSuite{}})
}
func TestDockerCLIHistorySuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLIHistorySuite{ds: &DockerSuite{}})
}
func TestDockerCLIImagesSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLIImagesSuite{ds: &DockerSuite{}})
}
func TestDockerCLIImportSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLIImportSuite{ds: &DockerSuite{}})
}
func TestDockerCLIInfoSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLIInfoSuite{ds: &DockerSuite{}})
}
func TestDockerCLIInspectSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLIInspectSuite{ds: &DockerSuite{}})
}
func TestDockerCLILinksSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLILinksSuite{ds: &DockerSuite{}})
}
func TestDockerCLILoginSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLILoginSuite{ds: &DockerSuite{}})
}
func TestDockerCLILogsSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLILogsSuite{ds: &DockerSuite{}})
}
func TestDockerCLINetmodeSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLINetmodeSuite{ds: &DockerSuite{}})
}
func TestDockerCLINetworkSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLINetworkSuite{ds: &DockerSuite{}})
}
func TestDockerCLIPluginLogDriverSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLIPluginLogDriverSuite{ds: &DockerSuite{}})
}
func TestDockerCLIPluginsSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLIPluginsSuite{ds: &DockerSuite{}})
}
func TestDockerCLIPortSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLIPortSuite{ds: &DockerSuite{}})
}
func TestDockerCLIProxySuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLIProxySuite{ds: &DockerSuite{}})
}
func TestDockerCLIPruneSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLIPruneSuite{ds: &DockerSuite{}})
}
func TestDockerCLIPsSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLIPsSuite{ds: &DockerSuite{}})
}
func TestDockerCLIPullSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLIPullSuite{ds: &DockerSuite{}})
}
func TestDockerCLIPushSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLIPushSuite{ds: &DockerSuite{}})
}
func TestDockerCLIRestartSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLIRestartSuite{ds: &DockerSuite{}})
}
func TestDockerCLIRmiSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLIRmiSuite{ds: &DockerSuite{}})
}
func TestDockerCLIRunSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLIRunSuite{ds: &DockerSuite{}})
}
func TestDockerCLISaveLoadSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLISaveLoadSuite{ds: &DockerSuite{}})
}
func TestDockerCLISearchSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLISearchSuite{ds: &DockerSuite{}})
}
func TestDockerCLISNISuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLISNISuite{ds: &DockerSuite{}})
}
func TestDockerCLIStartSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLIStartSuite{ds: &DockerSuite{}})
}
func TestDockerCLIStatsSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLIStatsSuite{ds: &DockerSuite{}})
}
func TestDockerCLITopSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLITopSuite{ds: &DockerSuite{}})
}
func TestDockerCLIUpdateSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLIUpdateSuite{ds: &DockerSuite{}})
}
func TestDockerCLIVolumeSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerCLIVolumeSuite{ds: &DockerSuite{}})
}
func TestDockerRegistrySuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerRegistrySuite{ds: &DockerSuite{}})
}
func TestDockerSchema1RegistrySuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerSchema1RegistrySuite{ds: &DockerSuite{}})
}
func TestDockerRegistryAuthHtpasswdSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerRegistryAuthHtpasswdSuite{ds: &DockerSuite{}})
}
func TestDockerRegistryAuthTokenSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerRegistryAuthTokenSuite{ds: &DockerSuite{}})
}
func TestDockerDaemonSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerDaemonSuite{ds: &DockerSuite{}})
}
func TestDockerSwarmSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerSwarmSuite{ds: &DockerSuite{}})
}
func TestDockerPluginSuite(t *testing.T) {
ensureTestEnvSetup(t)
suite.Run(t, &DockerPluginSuite{ds: &DockerSuite{}})
}
func TestDockerExternalVolumeSuite(t *testing.T) {
ensureTestEnvSetup(t)
testRequires(t, DaemonIsLinux)
suite.Run(t, &DockerExternalVolumeSuite{ds: &DockerSuite{}})
}
func TestDockerNetworkSuite(t *testing.T) {
ensureTestEnvSetup(t)
testRequires(t, DaemonIsLinux)
suite.Run(t, &DockerNetworkSuite{ds: &DockerSuite{}})
}
func TestDockerHubPullSuite(t *testing.T) {
ensureTestEnvSetup(t)
// FIXME. Temporarily turning this off for Windows as GH16039 was breaking
// Windows to Linux CI @icecrime
testRequires(t, DaemonIsLinux)
suite.Run(t, newDockerHubPullSuite())
}
type DockerSuite struct {
}
func (s *DockerSuite) OnTimeout(c *testing.T) {
if testEnv.IsRemoteDaemon() {
return
}
path := filepath.Join(os.Getenv("DEST"), "docker.pid")
b, err := os.ReadFile(path)
if err != nil {
c.Fatalf("Failed to get daemon PID from %s\n", path)
}
rawPid, err := strconv.ParseInt(string(b), 10, 32)
if err != nil {
c.Fatalf("Failed to parse pid from %s: %s\n", path, err)
}
daemonPid := int(rawPid)
if daemonPid > 0 {
testdaemon.SignalDaemonDump(daemonPid)
}
}
func (s *DockerSuite) TearDownTest(c *testing.T) {
testEnv.Clean(c)
}
type DockerRegistrySuite struct {
ds *DockerSuite
reg *registry.V2
d *daemon.Daemon
}
func (s *DockerRegistrySuite) OnTimeout(c *testing.T) {
s.d.DumpStackAndQuit()
}
func (s *DockerRegistrySuite) SetUpTest(c *testing.T) {
testRequires(c, DaemonIsLinux, RegistryHosting, testEnv.IsLocalDaemon)
s.reg = registry.NewV2(c)
s.reg.WaitReady(c)
s.d = daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
}
func (s *DockerRegistrySuite) TearDownTest(c *testing.T) {
if s.reg != nil {
s.reg.Close()
}
if s.d != nil {
s.d.Stop(c)
}
s.ds.TearDownTest(c)
}
type DockerSchema1RegistrySuite struct {
ds *DockerSuite
reg *registry.V2
d *daemon.Daemon
}
func (s *DockerSchema1RegistrySuite) OnTimeout(c *testing.T) {
s.d.DumpStackAndQuit()
}
func (s *DockerSchema1RegistrySuite) SetUpTest(c *testing.T) {
testRequires(c, DaemonIsLinux, RegistryHosting, NotArm64, testEnv.IsLocalDaemon)
s.reg = registry.NewV2(c, registry.Schema1)
s.reg.WaitReady(c)
s.d = daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
}
func (s *DockerSchema1RegistrySuite) TearDownTest(c *testing.T) {
if s.reg != nil {
s.reg.Close()
}
if s.d != nil {
s.d.Stop(c)
}
s.ds.TearDownTest(c)
}
type DockerRegistryAuthHtpasswdSuite struct {
ds *DockerSuite
reg *registry.V2
d *daemon.Daemon
}
func (s *DockerRegistryAuthHtpasswdSuite) OnTimeout(c *testing.T) {
s.d.DumpStackAndQuit()
}
func (s *DockerRegistryAuthHtpasswdSuite) SetUpTest(c *testing.T) {
testRequires(c, DaemonIsLinux, RegistryHosting, testEnv.IsLocalDaemon)
s.reg = registry.NewV2(c, registry.Htpasswd)
s.reg.WaitReady(c)
s.d = daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
}
func (s *DockerRegistryAuthHtpasswdSuite) TearDownTest(c *testing.T) {
if s.reg != nil {
out, err := s.d.Cmd("logout", privateRegistryURL)
assert.NilError(c, err, out)
s.reg.Close()
}
if s.d != nil {
s.d.Stop(c)
}
s.ds.TearDownTest(c)
}
type DockerRegistryAuthTokenSuite struct {
ds *DockerSuite
reg *registry.V2
d *daemon.Daemon
}
func (s *DockerRegistryAuthTokenSuite) OnTimeout(c *testing.T) {
s.d.DumpStackAndQuit()
}
func (s *DockerRegistryAuthTokenSuite) SetUpTest(c *testing.T) {
testRequires(c, DaemonIsLinux, RegistryHosting, testEnv.IsLocalDaemon)
s.d = daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
}
func (s *DockerRegistryAuthTokenSuite) TearDownTest(c *testing.T) {
if s.reg != nil {
out, err := s.d.Cmd("logout", privateRegistryURL)
assert.NilError(c, err, out)
s.reg.Close()
}
if s.d != nil {
s.d.Stop(c)
}
s.ds.TearDownTest(c)
}
func (s *DockerRegistryAuthTokenSuite) setupRegistryWithTokenService(c *testing.T, tokenURL string) {
if s == nil {
c.Fatal("registry suite isn't initialized")
}
s.reg = registry.NewV2(c, registry.Token(tokenURL))
s.reg.WaitReady(c)
}
type DockerDaemonSuite struct {
ds *DockerSuite
d *daemon.Daemon
}
func (s *DockerDaemonSuite) OnTimeout(c *testing.T) {
s.d.DumpStackAndQuit()
}
func (s *DockerDaemonSuite) SetUpTest(c *testing.T) {
testRequires(c, DaemonIsLinux, testEnv.IsLocalDaemon)
s.d = daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
}
func (s *DockerDaemonSuite) TearDownTest(c *testing.T) {
testRequires(c, DaemonIsLinux, testEnv.IsLocalDaemon)
if s.d != nil {
s.d.Stop(c)
}
s.ds.TearDownTest(c)
}
func (s *DockerDaemonSuite) TearDownSuite(c *testing.T) {
filepath.Walk(testdaemon.SockRoot, func(path string, fi os.FileInfo, err error) error {
if err != nil {
// ignore errors here
// not cleaning up sockets is not really an error
return nil
}
if fi.Mode() == os.ModeSocket {
syscall.Unlink(path)
}
return nil
})
os.RemoveAll(testdaemon.SockRoot)
}
const defaultSwarmPort = 2477
type DockerSwarmSuite struct {
server *httptest.Server
ds *DockerSuite
daemonsLock sync.Mutex // protect access to daemons and portIndex
daemons []*daemon.Daemon
portIndex int
}
func (s *DockerSwarmSuite) OnTimeout(c *testing.T) {
s.daemonsLock.Lock()
defer s.daemonsLock.Unlock()
for _, d := range s.daemons {
d.DumpStackAndQuit()
}
}
func (s *DockerSwarmSuite) SetUpTest(c *testing.T) {
testRequires(c, DaemonIsLinux, testEnv.IsLocalDaemon)
}
func (s *DockerSwarmSuite) AddDaemon(c *testing.T, joinSwarm, manager bool) *daemon.Daemon {
c.Helper()
d := daemon.New(c, dockerBinary, dockerdBinary,
testdaemon.WithEnvironment(testEnv.Execution),
testdaemon.WithSwarmPort(defaultSwarmPort+s.portIndex),
)
if joinSwarm {
if len(s.daemons) > 0 {
d.StartAndSwarmJoin(c, s.daemons[0].Daemon, manager)
} else {
d.StartAndSwarmInit(c)
}
} else {
d.StartNodeWithBusybox(c)
}
s.daemonsLock.Lock()
s.portIndex++
s.daemons = append(s.daemons, d)
s.daemonsLock.Unlock()
return d
}
func (s *DockerSwarmSuite) TearDownTest(c *testing.T) {
testRequires(c, DaemonIsLinux)
s.daemonsLock.Lock()
for _, d := range s.daemons {
if d != nil {
if c.Failed() {
d.TailLogsT(c, 100)
}
d.Stop(c)
d.Cleanup(c)
}
}
s.daemons = nil
s.portIndex = 0
s.daemonsLock.Unlock()
s.ds.TearDownTest(c)
}
type DockerPluginSuite struct {
ds *DockerSuite
registry *registry.V2
}
func (ps *DockerPluginSuite) registryHost() string {
return privateRegistryURL
}
func (ps *DockerPluginSuite) getPluginRepo() string {
return path.Join(ps.registryHost(), "plugin", "basic")
}
func (ps *DockerPluginSuite) getPluginRepoWithTag() string {
return ps.getPluginRepo() + ":" + "latest"
}
func (ps *DockerPluginSuite) SetUpSuite(c *testing.T) {
testRequires(c, DaemonIsLinux, RegistryHosting)
ps.registry = registry.NewV2(c)
ps.registry.WaitReady(c)
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
err := plugin.CreateInRegistry(ctx, ps.getPluginRepo(), nil)
assert.NilError(c, err, "failed to create plugin")
}
func (ps *DockerPluginSuite) TearDownSuite(c *testing.T) {
if ps.registry != nil {
ps.registry.Close()
}
}
func (ps *DockerPluginSuite) TearDownTest(c *testing.T) {
ps.ds.TearDownTest(c)
}
func (ps *DockerPluginSuite) OnTimeout(c *testing.T) {
ps.ds.OnTimeout(c)
}