2020-05-20 18:05:32 +02:00
/ *
Copyright ( c ) 2020 Docker Inc .
Permission is hereby granted , free of charge , to any person
obtaining a copy of this software and associated documentation
files ( the "Software" ) , to deal in the Software without
restriction , including without limitation the rights to use , copy ,
modify , merge , publish , distribute , sublicense , and / or sell copies
of the Software , and to permit persons to whom the Software is
furnished to do so , subject to the following conditions :
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software .
THE SOFTWARE IS PROVIDED "AS IS" , WITHOUT WARRANTY OF ANY KIND ,
EXPRESS OR IMPLIED ,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT .
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM ,
DAMAGES OR OTHER LIABILITY ,
WHETHER IN AN ACTION OF CONTRACT ,
TORT OR OTHERWISE ,
ARISING FROM , OUT OF OR IN CONNECTION WITH
THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE .
* /
2020-05-04 15:10:28 +02:00
package main
import (
2020-05-20 15:57:10 +02:00
"fmt"
2020-05-27 18:38:51 +02:00
"io/ioutil"
"log"
2020-05-18 15:55:21 +02:00
"os"
"os/exec"
2020-05-26 22:59:52 +02:00
"path/filepath"
2020-05-27 18:38:51 +02:00
"strings"
2020-05-20 15:57:10 +02:00
"testing"
2020-05-04 15:10:28 +02:00
"time"
2020-05-06 15:28:03 +02:00
2020-05-27 18:39:17 +02:00
. "github.com/onsi/gomega"
"github.com/stretchr/testify/suite"
2020-05-26 23:34:38 +02:00
"gotest.tools/golden"
2020-05-13 07:52:43 +02:00
. "github.com/docker/api/tests/framework"
2020-05-04 15:10:28 +02:00
)
2020-05-20 15:57:10 +02:00
type E2eSuite struct {
Suite
}
2020-05-04 15:10:28 +02:00
2020-05-20 15:57:10 +02:00
func ( s * E2eSuite ) TestContextHelp ( ) {
2020-05-04 15:10:28 +02:00
It ( "ensures context command includes azure-login and aci-create" , func ( ) {
2020-05-20 15:57:10 +02:00
output := s . NewDockerCommand ( "context" , "create" , "--help" ) . ExecOrDie ( )
2020-05-05 17:55:53 +02:00
Expect ( output ) . To ( ContainSubstring ( "docker context create CONTEXT BACKEND [OPTIONS] [flags]" ) )
Expect ( output ) . To ( ContainSubstring ( "--aci-location" ) )
Expect ( output ) . To ( ContainSubstring ( "--aci-subscription-id" ) )
Expect ( output ) . To ( ContainSubstring ( "--aci-resource-group" ) )
2020-05-04 15:10:28 +02:00
} )
2020-05-20 15:57:10 +02:00
}
2020-05-04 15:10:28 +02:00
2020-05-20 15:57:10 +02:00
func ( s * E2eSuite ) TestContextDefault ( ) {
2020-05-04 15:10:28 +02:00
It ( "should be initialized with default context" , func ( ) {
2020-05-20 15:57:10 +02:00
output := s . NewDockerCommand ( "context" , "show" ) . ExecOrDie ( )
2020-05-18 13:57:38 +02:00
Expect ( output ) . To ( ContainSubstring ( "default" ) )
2020-05-20 15:57:10 +02:00
output = s . NewCommand ( "docker" , "context" , "ls" ) . ExecOrDie ( )
2020-06-08 14:43:51 +02:00
golden . Assert ( s . T ( ) , output , GoldenFile ( "ls-out-default" ) )
2020-05-04 15:10:28 +02:00
} )
2020-05-20 15:57:10 +02:00
}
2020-05-04 15:10:28 +02:00
2020-05-29 12:02:07 +02:00
func ( s * E2eSuite ) TestContextLegacy ( ) {
It ( "should inspect default" , func ( ) {
output := s . NewDockerCommand ( "context" , "inspect" , "default" ) . ExecOrDie ( )
Expect ( output ) . To ( ContainSubstring ( ` "Name": "default" ` ) )
} )
}
2020-06-10 17:24:13 +02:00
func ( s * E2eSuite ) TestContextCreateParseErrorDoesNotDelegateToLegacy ( ) {
It ( "should dispay new cli error when parsing context create flags" , func ( ) {
_ , err := s . NewDockerCommand ( "context" , "create" , "--aci-subscription-id" , "titi" ) . Exec ( )
Expect ( err . Error ( ) ) . NotTo ( ContainSubstring ( "unknown flag" ) )
Expect ( err . Error ( ) ) . To ( ContainSubstring ( "accepts 2 arg(s), received 0" ) )
} )
}
2020-05-29 17:07:48 +02:00
func ( s * E2eSuite ) TestClassicLoginWithparameters ( ) {
output , err := s . NewDockerCommand ( "login" , "-u" , "nouser" , "-p" , "wrongpasword" ) . Exec ( )
Expect ( output ) . To ( ContainSubstring ( "Get https://registry-1.docker.io/v2/: unauthorized: incorrect username or password" ) )
Expect ( err ) . NotTo ( BeNil ( ) )
}
func ( s * E2eSuite ) TestClassicLogin ( ) {
output , err := s . NewDockerCommand ( "login" , "someregistry.docker.io" ) . Exec ( )
Expect ( output ) . To ( ContainSubstring ( "Cannot perform an interactive login from a non TTY device" ) )
Expect ( err ) . NotTo ( BeNil ( ) )
}
func ( s * E2eSuite ) TestCloudLogin ( ) {
output , err := s . NewDockerCommand ( "login" , "mycloudbackend" ) . Exec ( )
2020-05-22 13:38:30 +02:00
Expect ( output ) . To ( ContainSubstring ( "unknown backend type for cloud login: mycloudbackend" ) )
2020-05-29 17:07:48 +02:00
Expect ( err ) . NotTo ( BeNil ( ) )
}
2020-05-26 22:59:52 +02:00
func ( s * E2eSuite ) TestSetupError ( ) {
It ( "should display an error if cannot shell out to docker-classic" , func ( ) {
err := os . Setenv ( "PATH" , s . BinDir )
Expect ( err ) . To ( BeNil ( ) )
2020-06-08 16:50:47 +02:00
err = os . Remove ( filepath . Join ( s . BinDir , DockerClassicExecutable ( ) ) )
2020-05-26 22:59:52 +02:00
Expect ( err ) . To ( BeNil ( ) )
output , err := s . NewDockerCommand ( "ps" ) . Exec ( )
Expect ( output ) . To ( ContainSubstring ( "docker-classic" ) )
Expect ( output ) . To ( ContainSubstring ( "not found" ) )
Expect ( err ) . NotTo ( BeNil ( ) )
} )
}
2020-05-27 18:38:51 +02:00
func ( s * E2eSuite ) TestKillChildOnCancel ( ) {
It ( "should kill docker-classic if parent command is cancelled" , func ( ) {
2020-06-04 16:31:06 +02:00
out := s . ListProcessesCommand ( ) . ExecOrDie ( )
2020-05-27 18:38:51 +02:00
Expect ( out ) . NotTo ( ContainSubstring ( "docker-classic" ) )
dir := s . ConfigDir
Expect ( ioutil . WriteFile ( filepath . Join ( dir , "Dockerfile" ) , [ ] byte ( ` FROM alpine : 3.10
RUN sleep 100 ` ) , 0644 ) ) . To ( Succeed ( ) )
shutdown := make ( chan time . Time )
errs := make ( chan error )
2020-05-27 18:39:17 +02:00
ctx := s . NewDockerCommand ( "build" , "--no-cache" , "-t" , "test-sleep-image" , "." ) . WithinDirectory ( dir ) . WithTimeout ( shutdown )
2020-05-27 18:38:51 +02:00
go func ( ) {
_ , err := ctx . Exec ( )
errs <- err
} ( )
2020-06-04 16:31:06 +02:00
err := WaitFor ( time . Second , 10 * time . Second , errs , func ( ) bool {
out := s . ListProcessesCommand ( ) . ExecOrDie ( )
2020-05-27 18:38:51 +02:00
return strings . Contains ( out , "docker-classic" )
} )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
log . Println ( "Killing docker process" )
close ( shutdown )
2020-06-04 16:31:06 +02:00
err = WaitFor ( time . Second , 12 * time . Second , nil , func ( ) bool {
out := s . ListProcessesCommand ( ) . ExecOrDie ( )
2020-05-27 18:38:51 +02:00
return ! strings . Contains ( out , "docker-classic" )
} )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
} )
}
2020-05-20 15:57:10 +02:00
func ( s * E2eSuite ) TestLegacy ( ) {
2020-05-04 15:10:28 +02:00
It ( "should list all legacy commands" , func ( ) {
2020-05-20 15:57:10 +02:00
output := s . NewDockerCommand ( "--help" ) . ExecOrDie ( )
2020-05-05 17:55:53 +02:00
Expect ( output ) . To ( ContainSubstring ( "swarm" ) )
2020-05-04 15:10:28 +02:00
} )
It ( "should execute legacy commands" , func ( ) {
2020-05-20 15:57:10 +02:00
output , _ := s . NewDockerCommand ( "swarm" , "join" ) . Exec ( )
2020-05-05 17:55:53 +02:00
Expect ( output ) . To ( ContainSubstring ( "\"docker swarm join\" requires exactly 1 argument." ) )
2020-05-04 15:10:28 +02:00
} )
2020-05-20 15:57:10 +02:00
It ( "should run local container in less than 10 secs" , func ( ) {
s . NewDockerCommand ( "pull" , "hello-world" ) . ExecOrDie ( )
output := s . NewDockerCommand ( "run" , "--rm" , "hello-world" ) . WithTimeout ( time . NewTimer ( 10 * time . Second ) . C ) . ExecOrDie ( )
2020-05-05 17:55:53 +02:00
Expect ( output ) . To ( ContainSubstring ( "Hello from Docker!" ) )
2020-05-04 15:10:28 +02:00
} )
2020-05-20 15:57:10 +02:00
}
2020-05-04 15:10:28 +02:00
2020-06-05 17:08:42 +02:00
func ( s * E2eSuite ) TestLeaveLegacyErrorMessagesUnchanged ( ) {
output , err := s . NewDockerCommand ( "foo" ) . Exec ( )
golden . Assert ( s . T ( ) , output , "unknown-foo-command.golden" )
Expect ( err ) . NotTo ( BeNil ( ) )
}
2020-06-05 17:30:27 +02:00
func ( s * E2eSuite ) TestDisplayFriendlyErrorMessageForLegacyCommands ( ) {
s . NewDockerCommand ( "context" , "create" , "test-example" , "example" ) . ExecOrDie ( )
output , err := s . NewDockerCommand ( "--context" , "test-example" , "images" ) . Exec ( )
Expect ( output ) . To ( Equal ( "Command \"images\" not available in current context (test-example), you can use the \"default\" context to run this command\n" ) )
Expect ( err ) . NotTo ( BeNil ( ) )
}
2020-05-20 15:57:10 +02:00
func ( s * E2eSuite ) TestMockBackend ( ) {
2020-05-04 15:10:28 +02:00
It ( "creates a new test context to hardcoded example backend" , func ( ) {
2020-05-20 15:57:10 +02:00
s . NewDockerCommand ( "context" , "create" , "test-example" , "example" ) . ExecOrDie ( )
2020-05-14 13:01:05 +02:00
// Expect(output).To(ContainSubstring("test-example context acitest created"))
2020-05-04 15:10:28 +02:00
} )
It ( "uses the test context" , func ( ) {
2020-05-20 15:57:10 +02:00
currentContext := s . NewDockerCommand ( "context" , "use" , "test-example" ) . ExecOrDie ( )
2020-05-05 17:55:53 +02:00
Expect ( currentContext ) . To ( ContainSubstring ( "test-example" ) )
2020-05-20 15:57:10 +02:00
output := s . NewDockerCommand ( "context" , "ls" ) . ExecOrDie ( )
2020-06-08 14:43:51 +02:00
golden . Assert ( s . T ( ) , output , GoldenFile ( "ls-out-test-example" ) )
2020-05-20 15:57:10 +02:00
output = s . NewDockerCommand ( "context" , "show" ) . ExecOrDie ( )
2020-05-18 13:57:38 +02:00
Expect ( output ) . To ( ContainSubstring ( "test-example" ) )
2020-05-04 15:10:28 +02:00
} )
It ( "can run ps command" , func ( ) {
2020-05-20 15:57:10 +02:00
output := s . NewDockerCommand ( "ps" ) . ExecOrDie ( )
2020-05-05 17:55:53 +02:00
lines := Lines ( output )
Expect ( len ( lines ) ) . To ( Equal ( 3 ) )
2020-05-15 17:52:19 +02:00
Expect ( lines [ 2 ] ) . To ( ContainSubstring ( "1234 alpine" ) )
2020-05-04 15:10:28 +02:00
} )
2020-05-06 09:37:52 +02:00
It ( "can run quiet ps command" , func ( ) {
2020-05-20 15:57:10 +02:00
output := s . NewDockerCommand ( "ps" , "-q" ) . ExecOrDie ( )
2020-05-05 17:55:53 +02:00
lines := Lines ( output )
Expect ( len ( lines ) ) . To ( Equal ( 2 ) )
Expect ( lines [ 0 ] ) . To ( Equal ( "id" ) )
Expect ( lines [ 1 ] ) . To ( Equal ( "1234" ) )
2020-05-06 09:37:52 +02:00
} )
2020-05-18 14:16:32 +02:00
It ( "can run ps command with all " , func ( ) {
2020-05-20 15:57:10 +02:00
output := s . NewDockerCommand ( "ps" , "-q" , "--all" ) . ExecOrDie ( )
2020-05-18 14:16:32 +02:00
lines := Lines ( output )
Expect ( len ( lines ) ) . To ( Equal ( 3 ) )
Expect ( lines [ 0 ] ) . To ( Equal ( "id" ) )
Expect ( lines [ 1 ] ) . To ( Equal ( "1234" ) )
Expect ( lines [ 2 ] ) . To ( Equal ( "stopped" ) )
} )
2020-05-04 15:10:28 +02:00
It ( "can run 'run' command" , func ( ) {
2020-05-20 15:57:10 +02:00
output := s . NewDockerCommand ( "run" , "nginx" , "-p" , "80:80" ) . ExecOrDie ( )
2020-05-05 17:55:53 +02:00
Expect ( output ) . To ( ContainSubstring ( "Running container \"nginx\" with name" ) )
2020-05-04 15:10:28 +02:00
} )
2020-05-20 15:57:10 +02:00
}
2020-05-18 15:55:21 +02:00
2020-05-20 15:57:10 +02:00
func ( s * E2eSuite ) TestAPIServer ( ) {
_ , err := exec . LookPath ( "yarn" )
if err != nil || os . Getenv ( "SKIP_NODE" ) != "" {
s . T ( ) . Skip ( "skipping, yarn not installed" )
}
2020-05-18 15:55:21 +02:00
It ( "can run 'serve' command" , func ( ) {
2020-05-20 15:57:10 +02:00
cName := "test-example"
s . NewDockerCommand ( "context" , "create" , cName , "example" ) . ExecOrDie ( )
2020-06-08 17:08:54 +02:00
//sPath := fmt.Sprintf("unix:///%s/docker.sock", s.ConfigDir)
sPath , cliAddress := s . getGrpcServerAndCLientAddress ( )
2020-05-20 15:57:10 +02:00
server , err := serveAPI ( s . ConfigDir , sPath )
2020-05-18 15:55:21 +02:00
Expect ( err ) . To ( BeNil ( ) )
2020-05-20 15:57:10 +02:00
defer killProcess ( server )
2020-05-18 15:55:21 +02:00
2020-05-20 15:57:10 +02:00
s . NewCommand ( "yarn" , "install" ) . WithinDirectory ( "../node-client" ) . ExecOrDie ( )
2020-06-08 17:08:54 +02:00
output := s . NewCommand ( "yarn" , "run" , "start" , cName , cliAddress ) . WithinDirectory ( "../node-client" ) . ExecOrDie ( )
2020-05-18 15:55:21 +02:00
Expect ( output ) . To ( ContainSubstring ( "nginx" ) )
} )
}
2020-06-08 17:08:54 +02:00
func ( s * E2eSuite ) getGrpcServerAndCLientAddress ( ) ( string , string ) {
if IsWindows ( ) {
return "npipe:////./pipe/clibackend" , "unix:////./pipe/clibackend"
}
socketName := fmt . Sprintf ( "unix:///%s/docker.sock" , s . ConfigDir )
return socketName , socketName
}
2020-05-20 15:57:10 +02:00
func TestE2e ( t * testing . T ) {
suite . Run ( t , new ( E2eSuite ) )
}
func killProcess ( process * os . Process ) {
2020-05-18 15:55:21 +02:00
err := process . Kill ( )
Expect ( err ) . To ( BeNil ( ) )
}
2020-05-20 15:57:10 +02:00
func serveAPI ( configDir string , address string ) ( * os . Process , error ) {
cmd := exec . Command ( "../../bin/docker" , "--config" , configDir , "serve" , "--address" , address )
2020-05-18 15:55:21 +02:00
err := cmd . Start ( )
if err != nil {
return nil , err
}
return cmd . Process , nil
2020-05-04 15:10:28 +02:00
}