Compare commits

..

9 Commits

Author SHA1 Message Date
c160c73353 Merge pull request #438 from jose-bigio/18.03_changelog
[18.03] Changelog for 18.03
2018-02-21 18:31:04 -08:00
5c06a61da4 Merge pull request #437 from andrewhsu/t
[18.03] skip DockerTrustSuite tests for 18.03
2018-02-21 18:30:37 -08:00
9d7d57c20f Merge pull request #439 from andrewhsu/taad
[18.03] Fix TestAttachAfterDetach to work with latest client
2018-02-21 18:30:27 -08:00
138ca8c7ad Deleted the delete section and the triage sections
Signed-off-by: jose-bigio <jose.bigio@docker.com>
2018-02-21 17:50:55 -08:00
9dd6df6ee4 Fix TestAttachAfterDetach to work with latest client
Signed-off-by: Daniel Nephin <dnephin@docker.com>
(cherry picked from commit 847b610620a8b8294d61c717d3c4aa13cb7a8b33)
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
2018-02-21 17:50:33 -08:00
9d4514861f 18.03 Changelog
Signed-off-by: jose-bigio <jose.bigio@docker.com>
2018-02-21 17:33:48 -08:00
d5f8753b88 update integration-cli tests for stderr output
Signed-off-by: Riyaz Faizullabhoy <riyaz.faizullabhoy@docker.com>
(cherry picked from commit 250b84ee88)
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
(cherry picked from commit d256539bf4)
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
(cherry picked from commit 5742bd3ccf)
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
(cherry picked from commit 1a2098cecf)
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
2018-02-21 16:23:44 -08:00
a720337d2e Blacklist tests, will be rewritten later on
Signed-off-by: Eli Uriegas <eli.uriegas@docker.com>
(cherry picked from commit 4e81e4fa4e)
Signed-off-by: Riyaz Faizullabhoy <riyaz.faizullabhoy@docker.com>
(cherry picked from commit ec6b0a1a4a)
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
(cherry picked from commit fbfecebc0a)
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
(cherry picked from commit e3571070d5)
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
(cherry picked from commit 9d7b9c23f5)
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
2018-02-21 16:23:44 -08:00
5ff63c0239 Bump version to 18.03.0-ce-rc1
Signed-off-by: GordonTheTurtle <engine-team@docker.com>
2018-02-21 23:59:01 +00:00
833 changed files with 20911 additions and 22081 deletions

View File

@ -1,73 +1,120 @@
# Changelog
# Changelog
Items starting with `DEPRECATE` are important deprecation notices. For more
information on the list of deprecated flags and APIs please have a look at
https://docs.docker.com/engine/deprecated/ where target removal dates can also
be found.
For more information on the list of deprecated flags and APIs, have a look at
https://docs.docker.com/engine/deprecated/ where you can find the target removal dates
## 18.03.0-ce (2018-03-DD)
## 18.04.0-ce (2018-04-DD)
### Builder
- Fix typos in builder and client. [moby/moby#36424](https://github.com/moby/moby/pull/36424)
* switch to -buildmode=pie [moby/moby#34369](https://github.com/moby/moby/pull/34369)
* Allow Dockerfile from outside build-context [docker/cli#886](https://github.com/docker/cli/pull/886)
* Builder: fix wrong cache hits building from tars [moby/moby#36329](https://github.com/moby/moby/pull/36329)
* Update containerd/continuity to fix ARM 32-bit builds [moby/moby#36339](https://github.com/moby/moby/pull/36339)
* Updated docker-on-docker build-notes. [moby/moby#35892](https://github.com/moby/moby/pull/35892)
- Fix string type for buildargs API definition [moby/moby#36246](https://github.com/moby/moby/pull/36246)
### Client
* Print Stack API and Kubernetes versions in version command. [docker/cli#898](https://github.com/docker/cli/pull/898)
- Fix Kubernetes duplication in version command. [docker/cli#953](https://github.com/docker/cli/pull/953)
* Use HasAvailableFlags instead of HasFlags for Options in help. [docker/cli#959](https://github.com/docker/cli/pull/959)
+ Add support for mandatory variables to stack deploy. [docker/cli#893](https://github.com/docker/cli/pull/893)
- Fix docker stack services command Port output. [docker/cli#943](https://github.com/docker/cli/pull/943)
* Deprecate unencrypted storage. [docker/cli#561](https://github.com/docker/cli/pull/561)
* Don't set a default filename for ConfigFile. [docker/cli#917](https://github.com/docker/cli/pull/917)
- Fix compose network name. [docker/cli#941](https://github.com/docker/cli/pull/941)
* Simplify the marshaling of compose types.Config [docker/cli#895](https://github.com/docker/cli/pull/895)
* Update reference docs for docker stack deploy [docker/cli#871](https://github.com/docker/cli/pull/871)
+ Add support for multiple composefile when deploying [docker/cli#569](https://github.com/docker/cli/pull/569)
- Fix broken Kubernetes stack flags [docker/cli#831](https://github.com/docker/cli/pull/831)
- Fix stack marshaling for Kubernetes [docker/cli#890](https://github.com/docker/cli/pull/890)
- Fix and simplify bash completion for service env, mounts and labels [docker/cli#682](https://github.com/docker/cli/pull/682)
- Fix `before` and `since` filter for `docker ps` [moby/moby#35938](https://github.com/moby/moby/pull/35938)
- Fix `--label-file` weird behavior [docker/cli#838](https://github.com/docker/cli/pull/838)
- Fix compilation of defaultCredentialStore() on unsupported platforms [docker/cli#872](https://github.com/docker/cli/pull/872)
* Improve and fix bash completion for images [docker/cli#717](https://github.com/docker/cli/pull/717)
+ Added check for empty source in bind mount [docker/cli#824](https://github.com/docker/cli/pull/824)
- Fix TLS from environment variables in client [moby/moby#36270](https://github.com/moby/moby/pull/36270)
* Explain the columns shown in docker stats [docker/cli#860](https://github.com/docker/cli/pull/860)
* GetAll -> Get to retrieve credentials from credential helpers [docker/cli#840](https://github.com/docker/cli/pull/840)
+ Add Engine version to docker node ls [docker/cli#885](https://github.com/docker/cli/pull/885)
* Update event filter zsh completion with `disable`, `enable`, `install` and `remove` [docker/cli#372](https://github.com/docker/cli/pull/372)
* Produce errors when empty ids are passed into inspect calls. [moby/moby#36144](https://github.com/moby/moby/pull/36144)
* Marshall version [docker/cli#891](https://github.com/docker/cli/pull/891)
* Replace go-bindata with esc [docker/cli#874](https://github.com/docker/cli/pull/874)
* Set a non-zero timeout for HTTP client communication with plugin backend. [docker/cli#883](https://github.com/docker/cli/pull/883)
+ Add DOCKER_TLS environment variable for --tls option [docker/cli#863](https://github.com/docker/cli/pull/863)
### Logging
* Make LogFile perms configurable. [moby/moby#36523](https://github.com/moby/moby/pull/36523)
* Silent login: use credentials from cred store to login. [docker/cli#139](https://github.com/docker/cli/pull/139)
+ Add support for compressibility of log file. [moby/moby#29932](https://github.com/moby/moby/pull/29932)
- Fix empty LogPath with non-blocking logging mode. [moby/moby#36272](https://github.com/moby/moby/pull/36272)
* Awslogs - don't add new lines to maximum sized events [moby/moby#36078](https://github.com/moby/moby/pull/36078)
* Move log validator logic after plugins are loaded [moby/moby#36306](https://github.com/moby/moby/pull/36306)
* Support a proxy in splunk log driver [moby/moby#36220](https://github.com/moby/moby/pull/36220)
- Fix log tail with empty logs [moby/moby#36305](https://github.com/moby/moby/pull/36305)
### Networking
- Prevent explicit removal of ingress network. [moby/moby#36538](https://github.com/moby/moby/pull/36538)
* Bump libnetwork to 5ab4ab830062fe8a30a44b75b0bda6b1f4f166a4 [moby/moby#36099](https://github.com/moby/moby/pull/36099)
* Document long form of --network and --network-add [docker/cli#843](https://github.com/docker/cli/pull/843)
* Libnetwork revendoring [moby/moby#36137](https://github.com/moby/moby/pull/36137)
* Migrates TestContainersAPINetworkMountsNoChown to api tests [moby/moby#36198](https://github.com/moby/moby/pull/36198)
* Verify NetworkingConfig to make sure EndpointSettings is not nil [moby/moby#36077](https://github.com/moby/moby/pull/36077)
+ Add description to TestContainerNetworkMountsNoChown [moby/moby#36226](https://github.com/moby/moby/pull/36226)
- Fix `DockerNetworkInternalMode` issue [moby/moby#36298](https://github.com/moby/moby/pull/36298)
- Fix race in attachable network attachment [moby/moby#36191](https://github.com/moby/moby/pull/36191)
- Fix the network option table [docker/cli#848](https://github.com/docker/cli/pull/848)
- Fix timeout issue of `InspectNetwork` on AArch64 [moby/moby#36257](https://github.com/moby/moby/pull/36257)
* Verbose info is missing for partial overlay ID [moby/moby#35989](https://github.com/moby/moby/pull/35989)
### Runtime
* Devmapper cleanup improvements. [moby/moby#36307](https://github.com/moby/moby/pull/36307)
* Devmapper.Mounted: remove. [moby/moby#36437](https://github.com/moby/moby/pull/36437)
* Devmapper/Remove(): use Rmdir, ignore errors. [moby/moby#36438](https://github.com/moby/moby/pull/36438)
* LCOW - Change platform parser directive to FROM statement flag. [moby/moby#35089](https://github.com/moby/moby/pull/35089)
* Split daemon service code to windows file. [moby/moby#36653](https://github.com/moby/moby/pull/36653)
* Windows: Block pulling uplevel images. [moby/moby#36327](https://github.com/moby/moby/pull/36327)
* Windows: Hyper-V containers are broken after 36586 was merged. [moby/moby#36610](https://github.com/moby/moby/pull/36610)
* Windows: Move kernel_windows to use golang registry functions. [moby/moby#36617](https://github.com/moby/moby/pull/36617)
* Windows: Pass back system errors on container exit. [moby/moby#35967](https://github.com/moby/moby/pull/35967)
* Windows: Remove servicing mode. [moby/moby#36267](https://github.com/moby/moby/pull/36267)
* Windows: Report Version and UBR. [moby/moby#36451](https://github.com/moby/moby/pull/36451)
* Bump Runc to 1.0.0-rc5. [moby/moby#36449](https://github.com/moby/moby/pull/36449)
* Mount failure indicates the path that failed. [moby/moby#36407](https://github.com/moby/moby/pull/36407)
* Change return for errdefs.getImplementer(). [moby/moby#36489](https://github.com/moby/moby/pull/36489)
* Client: fix hijackedconn reading from buffer. [moby/moby#36663](https://github.com/moby/moby/pull/36663)
* Content encoding negotiation added to archive request. [moby/moby#36164](https://github.com/moby/moby/pull/36164)
* Daemon/stats: more resilient cpu sampling. [moby/moby#36519](https://github.com/moby/moby/pull/36519)
* Daemon/stats: remove obnoxious types file. [moby/moby#36494](https://github.com/moby/moby/pull/36494)
* Daemon: use context error rather than inventing new one. [moby/moby#36670](https://github.com/moby/moby/pull/36670)
* Enable CRIU on non-amd64 architectures (v2). [moby/moby#36676](https://github.com/moby/moby/pull/36676)
- Fixes intermittent client hang after closing stdin to attached container [moby/moby#36517](https://github.com/moby/moby/pull/36517)
- Fix daemon panic on container export after restart [moby/moby#36586](https://github.com/moby/moby/pull/36586)
- Follow-up fixes on multi-stage moby's Dockerfile. [moby/moby#36425](https://github.com/moby/moby/pull/36425)
* Freeze busybox and latest glibc in Docker image. [moby/moby#36375](https://github.com/moby/moby/pull/36375)
* If container will run as non root user, drop permitted, effective caps early. [moby/moby#36587](https://github.com/moby/moby/pull/36587)
* Layer: remove metadata store interface. [moby/moby#36504](https://github.com/moby/moby/pull/36504)
* Minor optimizations to dockerd. [moby/moby#36577](https://github.com/moby/moby/pull/36577)
* Whitelist statx syscall. [moby/moby#36417](https://github.com/moby/moby/pull/36417)
+ Add missing error return for plugin creation. [moby/moby#36646](https://github.com/moby/moby/pull/36646)
- Fix AppArmor not being applied to Exec processes. [moby/moby#36466](https://github.com/moby/moby/pull/36466)
* Daemon/logger/ring.go: log error not instance. [moby/moby#36475](https://github.com/moby/moby/pull/36475)
- Fix stats collector spinning CPU if no stats are collected. [moby/moby#36609](https://github.com/moby/moby/pull/36609)
- Fix(distribution): digest cache should not be moved if it was an auth. [moby/moby#36509](https://github.com/moby/moby/pull/36509)
* Enable HotAdd for Windows [moby/moby#35414](https://github.com/moby/moby/pull/35414)
* LCOW: Graphdriver fix deadlock in hotRemoveVHDs [moby/moby#36114](https://github.com/moby/moby/pull/36114)
* LCOW: Regular mount if only one layer [moby/moby#36052](https://github.com/moby/moby/pull/36052)
* Remove interim env var LCOW_API_PLATFORM_IF_OMITTED [moby/moby#36269](https://github.com/moby/moby/pull/36269)
* Revendor Microsoft/opengcs @ v0.3.6 [moby/moby#36108](https://github.com/moby/moby/pull/36108)
* Windows: Bump to final RS3 build number [moby/moby#36268](https://github.com/moby/moby/pull/36268)
- Fix issue of ExitCode and PID not show up in Task.Status.ContainerStatus [moby/moby#36150](https://github.com/moby/moby/pull/36150)
- Fix issue with plugin scanner going to deep [moby/moby#36119](https://github.com/moby/moby/pull/36119)
* Do not make graphdriver homes private mounts. [moby/moby#36047](https://github.com/moby/moby/pull/36047)
* Do not recursive unmount on cleanup of zfs/btrfs [moby/moby#36237](https://github.com/moby/moby/pull/36237)
* Don't restore image if layer does not exist [moby/moby#36304](https://github.com/moby/moby/pull/36304)
** Adjust minimum API version for templated configs/secrets [moby/moby#36366](https://github.com/moby/moby/pull/36366)
* Bump containerd to 1.0.2 (cfd04396dc68220d1cecbe686a6cc3aa5ce3667c) [moby/moby#36308](https://github.com/moby/moby/pull/36308)
* Bump Golang to 1.9.4 [moby/moby#36243](https://github.com/moby/moby/pull/36243)
* Ensure daemon root is unmounted on shutdown [moby/moby#36107](https://github.com/moby/moby/pull/36107)
- Fix import path [moby/moby#36322](https://github.com/moby/moby/pull/36322)
* Update runc to 6c55f98695e902427906eed2c799e566e3d3dfb5 [moby/moby#36222](https://github.com/moby/moby/pull/36222)
- Fix container cleanup on daemon restart [moby/moby#36249](https://github.com/moby/moby/pull/36249)
* Bump golang to 1.9.4 [docker/cli#868](https://github.com/docker/cli/pull/868)
* Support SCTP port mapping (bump up API to v1.37) [moby/moby#33922](https://github.com/moby/moby/pull/33922)
* Support SCTP port mapping [docker/cli#278](https://github.com/docker/cli/pull/278)
- Fix Volumes property definition in ContainerConfig [moby/moby#35946](https://github.com/moby/moby/pull/35946)
* Bump moby and dependencies [docker/cli#829](https://github.com/docker/cli/pull/829)
* Bump moby to 0ede01237c9ab871f1b8db0364427407f3e46541 [docker/cli#894](https://github.com/docker/cli/pull/894)
* Bump moby vendor and dependencies [docker/cli#892](https://github.com/docker/cli/pull/892)
* C.RWLayer: check for nil before use [moby/moby#36242](https://github.com/moby/moby/pull/36242)
+ Add `REMOVE` and `ORPHANED` to TaskState [moby/moby#36146](https://github.com/moby/moby/pull/36146)
+ Add an integration/internal/container helper package [moby/moby#36266](https://github.com/moby/moby/pull/36266)
+ Add canonical import path [moby/moby#36194](https://github.com/moby/moby/pull/36194)
+ Add/use container.Exec() to integration [moby/moby#36326](https://github.com/moby/moby/pull/36326)
- Fix "--node-generic-resource" singular/plural [moby/moby#36125](https://github.com/moby/moby/pull/36125)
* Daemon.cleanupContainer: nullify container RWLayer upon release [moby/moby#36160](https://github.com/moby/moby/pull/36160)
* Daemon: passdown the `--oom-kill-disable` option to containerd [moby/moby#36201](https://github.com/moby/moby/pull/36201)
* Display a warn message when there is binding ports and net mode is host [moby/moby#35510](https://github.com/moby/moby/pull/35510)
* Refresh containerd remotes on containerd restarted [moby/moby#36173](https://github.com/moby/moby/pull/36173)
* Set daemon root to use shared propagation [moby/moby#36096](https://github.com/moby/moby/pull/36096)
* Optimizations for recursive unmount [moby/moby#34379](https://github.com/moby/moby/pull/34379)
* Perform plugin mounts in the runtime [moby/moby#35829](https://github.com/moby/moby/pull/35829)
* Graphdriver: Fix RefCounter memory leak [moby/moby#36256](https://github.com/moby/moby/pull/36256)
* Use continuity fs package for volume copy [moby/moby#36290](https://github.com/moby/moby/pull/36290)
* Use proc/exe for reexec [moby/moby#36124](https://github.com/moby/moby/pull/36124)
* Templated secrets and configs [moby/moby#33702](https://github.com/moby/moby/pull/33702)
* Use rslave propagation for mounts from daemon root [moby/moby#36055](https://github.com/moby/moby/pull/36055)
+ Add /proc/keys to masked paths [moby/moby#36368](https://github.com/moby/moby/pull/36368)
### Swarm Mode
* Fixes for synchronizing the dispatcher shutdown with in-progress rpcs. [moby/moby#36371](https://github.com/moby/moby/pull/36371)
* Increase raft ElectionTick to 10xHeartbeatTick. [moby/moby#36672](https://github.com/moby/moby/pull/36672)
* Bump SwarmKit to f74983e7c015a38a81c8642803a78b8322cf7eac [moby/moby#36274](https://github.com/moby/moby/pull/36274)
* Clarify network plugins and swarm mode [docker/cli#869](https://github.com/docker/cli/pull/869)
* Migrates several swarm configs tests from integration-cli to api tests [moby/moby#36291](https://github.com/moby/moby/pull/36291)
* Migrates several swarm secrets from integration-cli to api tests [moby/moby#36283](https://github.com/moby/moby/pull/36283)
* Update swarmkit to 68a376dc30d8c4001767c39456b990dbd821371b [moby/moby#36131](https://github.com/moby/moby/pull/36131)
* [compose] Share the compose loading code between swarm and k8s stack deploy [docker/cli#845](https://github.com/docker/cli/pull/845)
+ Add swarm types to bash completion event type filter [docker/cli#888](https://github.com/docker/cli/pull/888)
- Fix issue where network inspect does not show Created time for networks in swarm scope [moby/moby#36095](https://github.com/moby/moby/pull/36095)

View File

@ -1 +1 @@
18.04.0-ce-rc1
18.03.0-ce-rc1

View File

@ -1 +1 @@
18.04.0-ce-rc1
18.03.0-ce-rc1

View File

@ -1,23 +0,0 @@
version: "{build}"
clone_folder: c:\gopath\src\github.com\docker\cli
environment:
GOPATH: c:\gopath
GOVERSION: 1.10
DEPVERSION: v0.4.1
install:
- rmdir c:\go /s /q
- appveyor DownloadFile https://storage.googleapis.com/golang/go%GOVERSION%.windows-amd64.msi
- msiexec /i go%GOVERSION%.windows-amd64.msi /q
- go version
- go env
deploy: false
build_script:
- ps: .\scripts\make.ps1 -Binary
test_script:
- ps: .\scripts\make.ps1 -TestUnit

View File

@ -128,7 +128,7 @@ Examples:
{{ .Example }}
{{- end}}
{{- if .HasAvailableFlags}}
{{- if .HasFlags}}
Options:
{{ wrappedFlagUsages . | trimRightSpace}}

View File

@ -5,8 +5,7 @@ import (
"strings"
"testing"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/stretchr/testify/assert"
)
func TestLoadFileV01Success(t *testing.T) {
@ -26,9 +25,9 @@ func TestLoadFileV01Success(t *testing.T) {
}`)
bundle, err := LoadFile(reader)
assert.NilError(t, err)
assert.Check(t, is.Equal("0.1", bundle.Version))
assert.Check(t, is.Len(bundle.Services, 2))
assert.NoError(t, err)
assert.Equal(t, "0.1", bundle.Version)
assert.Len(t, bundle.Services, 2)
}
func TestLoadFileSyntaxError(t *testing.T) {
@ -38,7 +37,7 @@ func TestLoadFileSyntaxError(t *testing.T) {
}`)
_, err := LoadFile(reader)
assert.Error(t, err, "JSON syntax error at byte 37: invalid character 'u' looking for beginning of value")
assert.EqualError(t, err, "JSON syntax error at byte 37: invalid character 'u' looking for beginning of value")
}
func TestLoadFileTypeError(t *testing.T) {
@ -53,7 +52,7 @@ func TestLoadFileTypeError(t *testing.T) {
}`)
_, err := LoadFile(reader)
assert.Error(t, err, "Unexpected type at byte 94. Expected []string but received string.")
assert.EqualError(t, err, "Unexpected type at byte 94. Expected []string but received string.")
}
func TestPrint(t *testing.T) {
@ -67,12 +66,12 @@ func TestPrint(t *testing.T) {
},
},
}
assert.Check(t, Print(&buffer, bundle))
assert.NoError(t, Print(&buffer, bundle))
output := buffer.String()
assert.Check(t, is.Contains(output, "\"Image\": \"image\""))
assert.Check(t, is.Contains(output,
assert.Contains(t, output, "\"Image\": \"image\"")
assert.Contains(t, output,
`"Command": [
"echo",
"something"
]`))
]`)
}

View File

@ -6,10 +6,10 @@ import (
"testing"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/docker/api/types"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
)
func TestCheckpointCreateErrors(t *testing.T) {
@ -42,7 +42,7 @@ func TestCheckpointCreateErrors(t *testing.T) {
cmd := newCreateCommand(cli)
cmd.SetArgs(tc.args)
cmd.SetOutput(ioutil.Discard)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
@ -63,10 +63,10 @@ func TestCheckpointCreateWithOptions(t *testing.T) {
cmd.SetArgs([]string{"container-foo", checkpoint})
cmd.Flags().Set("leave-running", "true")
cmd.Flags().Set("checkpoint-dir", "/dir/foo")
assert.NilError(t, cmd.Execute())
assert.Check(t, is.Equal("container-foo", containerID))
assert.Check(t, is.Equal(checkpoint, checkpointID))
assert.Check(t, is.Equal("/dir/foo", checkpointDir))
assert.Check(t, is.Equal(false, exit))
assert.Check(t, is.Equal(checkpoint, strings.TrimSpace(cli.OutBuffer().String())))
assert.NoError(t, cmd.Execute())
assert.Equal(t, "container-foo", containerID)
assert.Equal(t, checkpoint, checkpointID)
assert.Equal(t, "/dir/foo", checkpointDir)
assert.Equal(t, false, exit)
assert.Equal(t, checkpoint, strings.TrimSpace(cli.OutBuffer().String()))
}

View File

@ -5,11 +5,11 @@ import (
"testing"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/docker/api/types"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/gotestyourself/gotestyourself/golden"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
)
func TestCheckpointListErrors(t *testing.T) {
@ -42,7 +42,7 @@ func TestCheckpointListErrors(t *testing.T) {
cmd := newListCommand(cli)
cmd.SetArgs(tc.args)
cmd.SetOutput(ioutil.Discard)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
@ -60,8 +60,8 @@ func TestCheckpointListWithOptions(t *testing.T) {
cmd := newListCommand(cli)
cmd.SetArgs([]string{"container-foo"})
cmd.Flags().Set("checkpoint-dir", "/dir/foo")
assert.NilError(t, cmd.Execute())
assert.Check(t, is.Equal("container-foo", containerID))
assert.Check(t, is.Equal("/dir/foo", checkpointDir))
assert.NoError(t, cmd.Execute())
assert.Equal(t, "container-foo", containerID)
assert.Equal(t, "/dir/foo", checkpointDir)
golden.Assert(t, cli.OutBuffer().String(), "checkpoint-list-with-options.golden")
}

View File

@ -5,10 +5,10 @@ import (
"testing"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/docker/api/types"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
)
func TestCheckpointRemoveErrors(t *testing.T) {
@ -41,7 +41,7 @@ func TestCheckpointRemoveErrors(t *testing.T) {
cmd := newRemoveCommand(cli)
cmd.SetArgs(tc.args)
cmd.SetOutput(ioutil.Discard)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
@ -58,8 +58,8 @@ func TestCheckpointRemoveWithOptions(t *testing.T) {
cmd := newRemoveCommand(cli)
cmd.SetArgs([]string{"container-foo", "checkpoint-bar"})
cmd.Flags().Set("checkpoint-dir", "/dir/foo")
assert.NilError(t, cmd.Execute())
assert.Check(t, is.Equal("container-foo", containerID))
assert.Check(t, is.Equal("checkpoint-bar", checkpointID))
assert.Check(t, is.Equal("/dir/foo", checkpointDir))
assert.NoError(t, cmd.Execute())
assert.Equal(t, "container-foo", containerID)
assert.Equal(t, "checkpoint-bar", checkpointID)
assert.Equal(t, "/dir/foo", checkpointDir)
}

View File

@ -22,6 +22,7 @@ import (
"github.com/docker/docker/api/types"
registrytypes "github.com/docker/docker/api/types/registry"
"github.com/docker/docker/client"
"github.com/docker/go-connections/sockets"
"github.com/docker/go-connections/tlsconfig"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@ -52,20 +53,18 @@ type Cli interface {
DefaultVersion() string
ManifestStore() manifeststore.Store
RegistryClient(bool) registryclient.RegistryClient
ContentTrustEnabled() bool
}
// DockerCli is an instance the docker command line client.
// Instances of the client can be returned from NewDockerCli.
type DockerCli struct {
configFile *configfile.ConfigFile
in *InStream
out *OutStream
err io.Writer
client client.APIClient
serverInfo ServerInfo
clientInfo ClientInfo
contentTrust bool
configFile *configfile.ConfigFile
in *InStream
out *OutStream
err io.Writer
client client.APIClient
serverInfo ServerInfo
clientInfo ClientInfo
}
// DefaultVersion returns api.defaultVersion or DOCKER_API_VERSION if specified.
@ -123,12 +122,6 @@ func (cli *DockerCli) ClientInfo() ClientInfo {
return cli.clientInfo
}
// ContentTrustEnabled returns whether content trust has been enabled by an
// environment variable.
func (cli *DockerCli) ContentTrustEnabled() bool {
return cli.contentTrust
}
// ManifestStore returns a store for local manifests
func (cli *DockerCli) ManifestStore() manifeststore.Store {
// TODO: support override default location from config file
@ -245,8 +238,8 @@ func (c ClientInfo) HasKubernetes() bool {
}
// NewDockerCli returns a DockerCli instance with IO output and error streams set by in, out and err.
func NewDockerCli(in io.ReadCloser, out, err io.Writer, isTrusted bool) *DockerCli {
return &DockerCli{in: NewInStream(in), out: NewOutStream(out), err: err, contentTrust: isTrusted}
func NewDockerCli(in io.ReadCloser, out, err io.Writer) *DockerCli {
return &DockerCli{in: NewInStream(in), out: NewOutStream(out), err: err}
}
// NewAPIClientFromFlags creates a new APIClient from command line flags
@ -267,12 +260,12 @@ func NewAPIClientFromFlags(opts *cliflags.CommonOptions, configFile *configfile.
verStr = tmpStr
}
return client.NewClientWithOpts(
withHTTPClient(opts.TLSOptions),
client.WithHTTPHeaders(customHeaders),
client.WithVersion(verStr),
client.WithHost(host),
)
httpClient, err := newHTTPClient(host, opts.TLSOptions)
if err != nil {
return &client.Client{}, err
}
return client.NewClient(host, verStr, httpClient, customHeaders)
}
func getServerHost(hosts []string, tlsOptions *tlsconfig.Options) (string, error) {
@ -289,32 +282,35 @@ func getServerHost(hosts []string, tlsOptions *tlsconfig.Options) (string, error
return dopts.ParseHost(tlsOptions != nil, host)
}
func withHTTPClient(tlsOpts *tlsconfig.Options) func(*client.Client) error {
return func(c *client.Client) error {
if tlsOpts == nil {
// Use the default HTTPClient
return nil
}
opts := *tlsOpts
opts.ExclusiveRootPools = true
tlsConfig, err := tlsconfig.Client(opts)
if err != nil {
return err
}
httpClient := &http.Client{
Transport: &http.Transport{
TLSClientConfig: tlsConfig,
DialContext: (&net.Dialer{
KeepAlive: 30 * time.Second,
Timeout: 30 * time.Second,
}).DialContext,
},
CheckRedirect: client.CheckRedirect,
}
return client.WithHTTPClient(httpClient)(c)
func newHTTPClient(host string, tlsOptions *tlsconfig.Options) (*http.Client, error) {
if tlsOptions == nil {
// let the api client configure the default transport.
return nil, nil
}
opts := *tlsOptions
opts.ExclusiveRootPools = true
config, err := tlsconfig.Client(opts)
if err != nil {
return nil, err
}
tr := &http.Transport{
TLSClientConfig: config,
DialContext: (&net.Dialer{
KeepAlive: 30 * time.Second,
Timeout: 30 * time.Second,
}).DialContext,
}
hostURL, err := client.ParseHostURL(host)
if err != nil {
return nil, err
}
sockets.ConfigureTransport(tr, hostURL.Scheme, hostURL.Host)
return &http.Client{
Transport: tr,
CheckRedirect: client.CheckRedirect,
}, nil
}
// UserAgent returns the user agent string used for making API requests

View File

@ -3,27 +3,24 @@ package command
import (
"crypto/x509"
"os"
"runtime"
"testing"
cliconfig "github.com/docker/cli/cli/config"
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/cli/flags"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/docker/api"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/gotestyourself/gotestyourself/fs"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/net/context"
)
func TestNewAPIClientFromFlags(t *testing.T) {
host := "unix://path"
if runtime.GOOS == "windows" {
host = "npipe://./"
}
opts := &flags.CommonOptions{Hosts: []string{host}}
configFile := &configfile.ConfigFile{
HTTPHeaders: map[string]string{
@ -31,15 +28,15 @@ func TestNewAPIClientFromFlags(t *testing.T) {
},
}
apiclient, err := NewAPIClientFromFlags(opts, configFile)
assert.NilError(t, err)
assert.Check(t, is.Equal(host, apiclient.DaemonHost()))
require.NoError(t, err)
assert.Equal(t, host, apiclient.DaemonHost())
expectedHeaders := map[string]string{
"My-Header": "Custom-Value",
"User-Agent": UserAgent(),
}
assert.Check(t, is.DeepEqual(expectedHeaders, apiclient.(*client.Client).CustomHTTPHeaders()))
assert.Check(t, is.Equal(api.DefaultVersion, apiclient.ClientVersion()))
assert.Equal(t, expectedHeaders, apiclient.(*client.Client).CustomHTTPHeaders())
assert.Equal(t, api.DefaultVersion, apiclient.ClientVersion())
}
func TestNewAPIClientFromFlagsWithAPIVersionFromEnv(t *testing.T) {
@ -49,20 +46,20 @@ func TestNewAPIClientFromFlagsWithAPIVersionFromEnv(t *testing.T) {
opts := &flags.CommonOptions{}
configFile := &configfile.ConfigFile{}
apiclient, err := NewAPIClientFromFlags(opts, configFile)
assert.NilError(t, err)
assert.Check(t, is.Equal(customVersion, apiclient.ClientVersion()))
require.NoError(t, err)
assert.Equal(t, customVersion, apiclient.ClientVersion())
}
// TODO: use gotestyourself/env.Patch
func patchEnvVariable(t *testing.T, key, value string) func() {
oldValue, ok := os.LookupEnv(key)
assert.NilError(t, os.Setenv(key, value))
require.NoError(t, os.Setenv(key, value))
return func() {
if !ok {
assert.NilError(t, os.Unsetenv(key))
require.NoError(t, os.Unsetenv(key))
return
}
assert.NilError(t, os.Setenv(key, oldValue))
require.NoError(t, os.Setenv(key, oldValue))
}
}
@ -128,8 +125,8 @@ func TestInitializeFromClient(t *testing.T) {
cli := &DockerCli{client: apiclient}
cli.initializeFromClient()
assert.Check(t, is.DeepEqual(testcase.expectedServer, cli.serverInfo))
assert.Check(t, is.Equal(testcase.negotiated, apiclient.negotiated))
assert.Equal(t, testcase.expectedServer, cli.serverInfo)
assert.Equal(t, testcase.negotiated, apiclient.negotiated)
})
}
}
@ -167,8 +164,8 @@ func TestExperimentalCLI(t *testing.T) {
cli := &DockerCli{client: apiclient, err: os.Stderr}
cliconfig.SetDir(dir.Path())
err := cli.Initialize(flags.NewClientOptions())
assert.NilError(t, err)
assert.Check(t, is.Equal(testcase.expectedExperimentalCLI, cli.ClientInfo().HasExperimental))
assert.NoError(t, err)
assert.Equal(t, testcase.expectedExperimentalCLI, cli.ClientInfo().HasExperimental)
})
}
}
@ -270,9 +267,9 @@ func TestOrchestratorSwitch(t *testing.T) {
options.Common.Orchestrator = testcase.flagOrchestrator
}
err := cli.Initialize(options)
assert.NilError(t, err)
assert.Check(t, is.Equal(testcase.expectedKubernetes, cli.ClientInfo().HasKubernetes()))
assert.Check(t, is.Equal(testcase.expectedOrchestrator, string(cli.ClientInfo().Orchestrator)))
assert.NoError(t, err)
assert.Equal(t, testcase.expectedKubernetes, cli.ClientInfo().HasKubernetes())
assert.Equal(t, testcase.expectedOrchestrator, string(cli.ClientInfo().Orchestrator))
})
}
}
@ -334,11 +331,11 @@ func TestGetClientWithPassword(t *testing.T) {
_, err := getClientWithPassword(passRetriever, newClient)
if testcase.expectedErr != "" {
assert.ErrorContains(t, err, testcase.expectedErr)
testutil.ErrorContains(t, err, testcase.expectedErr)
return
}
assert.NilError(t, err)
assert.NoError(t, err)
})
}
}

View File

@ -16,10 +16,9 @@ import (
)
type createOptions struct {
name string
templateDriver string
file string
labels opts.ListOpts
name string
file string
labels opts.ListOpts
}
func newConfigCreateCommand(dockerCli command.Cli) *cobra.Command {
@ -39,8 +38,6 @@ func newConfigCreateCommand(dockerCli command.Cli) *cobra.Command {
}
flags := cmd.Flags()
flags.VarP(&createOpts.labels, "label", "l", "Config labels")
flags.StringVar(&createOpts.templateDriver, "template-driver", "", "Template driver")
flags.SetAnnotation("driver", "version", []string{"1.37"})
return cmd
}
@ -71,11 +68,7 @@ func runConfigCreate(dockerCli command.Cli, options createOptions) error {
},
Data: configData,
}
if options.templateDriver != "" {
spec.Templating = &swarm.Driver{
Name: options.templateDriver,
}
}
r, err := client.ConfigCreate(ctx, spec)
if err != nil {
return err

View File

@ -8,12 +8,12 @@ import (
"testing"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/gotestyourself/gotestyourself/golden"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
)
const configDataFile = "config-create-with-name.golden"
@ -47,7 +47,7 @@ func TestConfigCreateErrors(t *testing.T) {
)
cmd.SetArgs(tc.args)
cmd.SetOutput(ioutil.Discard)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
@ -70,9 +70,9 @@ func TestConfigCreateWithName(t *testing.T) {
cmd := newConfigCreateCommand(cli)
cmd.SetArgs([]string{name, filepath.Join("testdata", configDataFile)})
assert.NilError(t, cmd.Execute())
assert.NoError(t, cmd.Execute())
golden.Assert(t, string(actual), configDataFile)
assert.Check(t, is.Equal("ID-"+name, strings.TrimSpace(cli.OutBuffer().String())))
assert.Equal(t, "ID-"+name, strings.TrimSpace(cli.OutBuffer().String()))
}
func TestConfigCreateWithLabels(t *testing.T) {
@ -82,21 +82,14 @@ func TestConfigCreateWithLabels(t *testing.T) {
}
name := "foo"
data, err := ioutil.ReadFile(filepath.Join("testdata", configDataFile))
assert.NilError(t, err)
expected := swarm.ConfigSpec{
Annotations: swarm.Annotations{
Name: name,
Labels: expectedLabels,
},
Data: data,
}
cli := test.NewFakeCli(&fakeClient{
configCreateFunc: func(spec swarm.ConfigSpec) (types.ConfigCreateResponse, error) {
if !reflect.DeepEqual(spec, expected) {
return types.ConfigCreateResponse{}, errors.Errorf("expected %+v, got %+v", expected, spec)
if spec.Name != name {
return types.ConfigCreateResponse{}, errors.Errorf("expected name %q, got %q", name, spec.Name)
}
if !reflect.DeepEqual(spec.Labels, expectedLabels) {
return types.ConfigCreateResponse{}, errors.Errorf("expected labels %v, got %v", expectedLabels, spec.Labels)
}
return types.ConfigCreateResponse{
@ -109,35 +102,6 @@ func TestConfigCreateWithLabels(t *testing.T) {
cmd.SetArgs([]string{name, filepath.Join("testdata", configDataFile)})
cmd.Flags().Set("label", "lbl1=Label-foo")
cmd.Flags().Set("label", "lbl2=Label-bar")
assert.NilError(t, cmd.Execute())
assert.Check(t, is.Equal("ID-"+name, strings.TrimSpace(cli.OutBuffer().String())))
}
func TestConfigCreateWithTemplatingDriver(t *testing.T) {
expectedDriver := &swarm.Driver{
Name: "template-driver",
}
name := "foo"
cli := test.NewFakeCli(&fakeClient{
configCreateFunc: func(spec swarm.ConfigSpec) (types.ConfigCreateResponse, error) {
if spec.Name != name {
return types.ConfigCreateResponse{}, errors.Errorf("expected name %q, got %q", name, spec.Name)
}
if spec.Templating.Name != expectedDriver.Name {
return types.ConfigCreateResponse{}, errors.Errorf("expected driver %v, got %v", expectedDriver, spec.Labels)
}
return types.ConfigCreateResponse{
ID: "ID-" + spec.Name,
}, nil
},
})
cmd := newConfigCreateCommand(cli)
cmd.SetArgs([]string{name, filepath.Join("testdata", configDataFile)})
cmd.Flags().Set("template-driver", expectedDriver.Name)
assert.NilError(t, cmd.Execute())
assert.Check(t, is.Equal("ID-"+name, strings.TrimSpace(cli.OutBuffer().String())))
assert.NoError(t, cmd.Execute())
assert.Equal(t, "ID-"+name, strings.TrimSpace(cli.OutBuffer().String()))
}

View File

@ -11,8 +11,9 @@ import (
"github.com/pkg/errors"
// Import builders to get the builder function as package function
. "github.com/docker/cli/internal/test/builders"
"github.com/gotestyourself/gotestyourself/assert"
"github.com/docker/cli/internal/test/testutil"
"github.com/gotestyourself/gotestyourself/golden"
"github.com/stretchr/testify/assert"
)
func TestConfigInspectErrors(t *testing.T) {
@ -61,7 +62,7 @@ func TestConfigInspectErrors(t *testing.T) {
cmd.Flags().Set(key, value)
}
cmd.SetOutput(ioutil.Discard)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
@ -95,7 +96,7 @@ func TestConfigInspectWithoutFormat(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{configInspectFunc: tc.configInspectFunc})
cmd := newConfigInspectCommand(cli)
cmd.SetArgs(tc.args)
assert.NilError(t, cmd.Execute())
assert.NoError(t, cmd.Execute())
golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("config-inspect-without-format.%s.golden", tc.name))
}
}
@ -132,7 +133,7 @@ func TestConfigInspectWithFormat(t *testing.T) {
cmd := newConfigInspectCommand(cli)
cmd.SetArgs(tc.args)
cmd.Flags().Set("format", tc.format)
assert.NilError(t, cmd.Execute())
assert.NoError(t, cmd.Execute())
golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("config-inspect-with-format.%s.golden", tc.name))
}
}
@ -166,7 +167,7 @@ func TestConfigInspectPretty(t *testing.T) {
cmd.SetArgs([]string{"configID"})
cmd.Flags().Set("pretty", "true")
assert.NilError(t, cmd.Execute())
assert.NoError(t, cmd.Execute())
golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("config-inspect-pretty.%s.golden", tc.name))
}
}

View File

@ -12,9 +12,9 @@ import (
"github.com/pkg/errors"
// Import builders to get the builder function as package function
. "github.com/docker/cli/internal/test/builders"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/docker/cli/internal/test/testutil"
"github.com/gotestyourself/gotestyourself/golden"
"github.com/stretchr/testify/assert"
)
func TestConfigListErrors(t *testing.T) {
@ -42,7 +42,7 @@ func TestConfigListErrors(t *testing.T) {
)
cmd.SetArgs(tc.args)
cmd.SetOutput(ioutil.Discard)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
@ -72,7 +72,7 @@ func TestConfigList(t *testing.T) {
},
})
cmd := newConfigListCommand(cli)
assert.NilError(t, cmd.Execute())
assert.NoError(t, cmd.Execute())
golden.Assert(t, cli.OutBuffer().String(), "config-list-sort.golden")
}
@ -89,7 +89,7 @@ func TestConfigListWithQuietOption(t *testing.T) {
})
cmd := newConfigListCommand(cli)
cmd.Flags().Set("quiet", "true")
assert.NilError(t, cmd.Execute())
assert.NoError(t, cmd.Execute())
golden.Assert(t, cli.OutBuffer().String(), "config-list-with-quiet-option.golden")
}
@ -108,7 +108,7 @@ func TestConfigListWithConfigFormat(t *testing.T) {
ConfigFormat: "{{ .Name }} {{ .Labels }}",
})
cmd := newConfigListCommand(cli)
assert.NilError(t, cmd.Execute())
assert.NoError(t, cmd.Execute())
golden.Assert(t, cli.OutBuffer().String(), "config-list-with-config-format.golden")
}
@ -125,15 +125,15 @@ func TestConfigListWithFormat(t *testing.T) {
})
cmd := newConfigListCommand(cli)
cmd.Flags().Set("format", "{{ .Name }} {{ .Labels }}")
assert.NilError(t, cmd.Execute())
assert.NoError(t, cmd.Execute())
golden.Assert(t, cli.OutBuffer().String(), "config-list-with-format.golden")
}
func TestConfigListWithFilter(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{
configListFunc: func(options types.ConfigListOptions) ([]swarm.Config, error) {
assert.Check(t, is.Equal("foo", options.Filters.Get("name")[0]))
assert.Check(t, is.Equal("lbl1=Label-bar", options.Filters.Get("label")[0]))
assert.Equal(t, "foo", options.Filters.Get("name")[0])
assert.Equal(t, "lbl1=Label-bar", options.Filters.Get("label")[0])
return []swarm.Config{
*Config(ConfigID("ID-foo"),
ConfigName("foo"),
@ -153,6 +153,6 @@ func TestConfigListWithFilter(t *testing.T) {
cmd := newConfigListCommand(cli)
cmd.Flags().Set("filter", "name=foo")
cmd.Flags().Set("filter", "label=lbl1=Label-bar")
assert.NilError(t, cmd.Execute())
assert.NoError(t, cmd.Execute())
golden.Assert(t, cli.OutBuffer().String(), "config-list-with-filter.golden")
}

View File

@ -6,9 +6,9 @@ import (
"testing"
"github.com/docker/cli/internal/test"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/docker/cli/internal/test/testutil"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
)
func TestConfigRemoveErrors(t *testing.T) {
@ -37,7 +37,7 @@ func TestConfigRemoveErrors(t *testing.T) {
)
cmd.SetArgs(tc.args)
cmd.SetOutput(ioutil.Discard)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
@ -52,9 +52,9 @@ func TestConfigRemoveWithName(t *testing.T) {
})
cmd := newConfigRemoveCommand(cli)
cmd.SetArgs(names)
assert.NilError(t, cmd.Execute())
assert.Check(t, is.DeepEqual(names, strings.Split(strings.TrimSpace(cli.OutBuffer().String()), "\n")))
assert.Check(t, is.DeepEqual(names, removedConfigs))
assert.NoError(t, cmd.Execute())
assert.Equal(t, names, strings.Split(strings.TrimSpace(cli.OutBuffer().String()), "\n"))
assert.Equal(t, names, removedConfigs)
}
func TestConfigRemoveContinueAfterError(t *testing.T) {
@ -74,6 +74,6 @@ func TestConfigRemoveContinueAfterError(t *testing.T) {
cmd := newConfigRemoveCommand(cli)
cmd.SetArgs(names)
cmd.SetOutput(ioutil.Discard)
assert.Error(t, cmd.Execute(), "error removing config: foo")
assert.Check(t, is.DeepEqual(names, removedConfigs))
assert.EqualError(t, cmd.Execute(), "error removing config: foo")
assert.Equal(t, names, removedConfigs)
}

View File

@ -7,10 +7,11 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/gotestyourself/gotestyourself/assert"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
)
func TestNewAttachCommandErrors(t *testing.T) {
@ -73,7 +74,7 @@ func TestNewAttachCommandErrors(t *testing.T) {
cmd := NewAttachCommand(test.NewFakeCli(&fakeClient{inspectFunc: tc.containerInspectFunc}))
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs(tc.args)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
@ -100,7 +101,9 @@ func TestGetExitStatus(t *testing.T) {
},
{
result: &container.ContainerWaitOKBody{
Error: &container.ContainerWaitOKBodyError{expectedErr.Error()},
Error: &container.ContainerWaitOKBodyError{
expectedErr.Error(),
},
},
expectedError: expectedErr,
},
@ -120,10 +123,6 @@ func TestGetExitStatus(t *testing.T) {
resultC <- *testcase.result
}
err := getExitStatus(errC, resultC)
if testcase.expectedError == nil {
assert.NilError(t, err)
} else {
assert.Error(t, err, testcase.expectedError.Error())
}
assert.Equal(t, testcase.expectedError, err)
}
}

View File

@ -16,7 +16,6 @@ type fakeClient struct {
execInspectFunc func(execID string) (types.ContainerExecInspect, error)
execCreateFunc func(container string, config types.ExecConfig) (types.IDResponse, error)
createContainerFunc func(config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, containerName string) (container.ContainerCreateCreatedBody, error)
containerStartFunc func(container string, options types.ContainerStartOptions) error
imageCreateFunc func(parentReference string, options types.ImageCreateOptions) (io.ReadCloser, error)
infoFunc func() (types.Info, error)
containerStatPathFunc func(container, path string) (types.ContainerPathStat, error)
@ -117,10 +116,3 @@ func (f *fakeClient) ContainerWait(_ context.Context, container string, _ contai
}
return nil, nil
}
func (f *fakeClient) ContainerStart(_ context.Context, container string, options types.ContainerStartOptions) error {
if f.containerStartFunc != nil {
return f.containerStartFunc(container, options)
}
return nil
}

View File

@ -3,18 +3,18 @@ package container
import (
"io"
"io/ioutil"
"os"
"runtime"
"strings"
"testing"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/archive"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/gotestyourself/gotestyourself/fs"
"github.com/gotestyourself/gotestyourself/skip"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestRunCopyWithInvalidArguments(t *testing.T) {
@ -43,7 +43,7 @@ func TestRunCopyWithInvalidArguments(t *testing.T) {
for _, testcase := range testcases {
t.Run(testcase.doc, func(t *testing.T) {
err := runCopy(test.NewFakeCli(nil), testcase.options)
assert.Error(t, err, testcase.expectedErr)
assert.EqualError(t, err, testcase.expectedErr)
})
}
}
@ -53,16 +53,16 @@ func TestRunCopyFromContainerToStdout(t *testing.T) {
fakeClient := &fakeClient{
containerCopyFromFunc: func(container, srcPath string) (io.ReadCloser, types.ContainerPathStat, error) {
assert.Check(t, is.Equal("container", container))
assert.Equal(t, "container", container)
return ioutil.NopCloser(strings.NewReader(tarContent)), types.ContainerPathStat{}, nil
},
}
options := copyOptions{source: "container:/path", destination: "-"}
cli := test.NewFakeCli(fakeClient)
err := runCopy(cli, options)
assert.NilError(t, err)
assert.Check(t, is.Equal(tarContent, cli.OutBuffer().String()))
assert.Check(t, is.Equal("", cli.ErrBuffer().String()))
require.NoError(t, err)
assert.Equal(t, tarContent, cli.OutBuffer().String())
assert.Equal(t, "", cli.ErrBuffer().String())
}
func TestRunCopyFromContainerToFilesystem(t *testing.T) {
@ -72,7 +72,7 @@ func TestRunCopyFromContainerToFilesystem(t *testing.T) {
fakeClient := &fakeClient{
containerCopyFromFunc: func(container, srcPath string) (io.ReadCloser, types.ContainerPathStat, error) {
assert.Check(t, is.Equal("container", container))
assert.Equal(t, "container", container)
readCloser, err := archive.TarWithOptions(destDir.Path(), &archive.TarOptions{})
return readCloser, types.ContainerPathStat{}, err
},
@ -80,13 +80,13 @@ func TestRunCopyFromContainerToFilesystem(t *testing.T) {
options := copyOptions{source: "container:/path", destination: destDir.Path()}
cli := test.NewFakeCli(fakeClient)
err := runCopy(cli, options)
assert.NilError(t, err)
assert.Check(t, is.Equal("", cli.OutBuffer().String()))
assert.Check(t, is.Equal("", cli.ErrBuffer().String()))
require.NoError(t, err)
assert.Equal(t, "", cli.OutBuffer().String())
assert.Equal(t, "", cli.ErrBuffer().String())
content, err := ioutil.ReadFile(destDir.Join("file1"))
assert.NilError(t, err)
assert.Check(t, is.Equal("content\n", string(content)))
require.NoError(t, err)
assert.Equal(t, "content\n", string(content))
}
func TestRunCopyFromContainerToFilesystemMissingDestinationDirectory(t *testing.T) {
@ -96,7 +96,7 @@ func TestRunCopyFromContainerToFilesystemMissingDestinationDirectory(t *testing.
fakeClient := &fakeClient{
containerCopyFromFunc: func(container, srcPath string) (io.ReadCloser, types.ContainerPathStat, error) {
assert.Check(t, is.Equal("container", container))
assert.Equal(t, "container", container)
readCloser, err := archive.TarWithOptions(destDir.Path(), &archive.TarOptions{})
return readCloser, types.ContainerPathStat{}, err
},
@ -108,39 +108,7 @@ func TestRunCopyFromContainerToFilesystemMissingDestinationDirectory(t *testing.
}
cli := test.NewFakeCli(fakeClient)
err := runCopy(cli, options)
assert.ErrorContains(t, err, destDir.Join("missing"))
}
func TestRunCopyToContainerFromFileWithTrailingSlash(t *testing.T) {
srcFile := fs.NewFile(t, t.Name())
defer srcFile.Remove()
options := copyOptions{
source: srcFile.Path() + string(os.PathSeparator),
destination: "container:/path",
}
cli := test.NewFakeCli(&fakeClient{})
err := runCopy(cli, options)
expectedError := "not a directory"
if runtime.GOOS == "windows" {
expectedError = "The filename, directory name, or volume label syntax is incorrect"
}
assert.ErrorContains(t, err, expectedError)
}
func TestRunCopyToContainerSourceDoesNotExist(t *testing.T) {
options := copyOptions{
source: "/does/not/exist",
destination: "container:/path",
}
cli := test.NewFakeCli(&fakeClient{})
err := runCopy(cli, options)
expected := "no such file or directory"
if runtime.GOOS == "windows" {
expected = "cannot find the file specified"
}
assert.ErrorContains(t, err, expected)
testutil.ErrorContains(t, err, destDir.Join("missing"))
}
func TestSplitCpArg(t *testing.T) {
@ -185,8 +153,8 @@ func TestSplitCpArg(t *testing.T) {
skip.IfCondition(t, testcase.os != "" && testcase.os != runtime.GOOS)
container, path := splitCpArg(testcase.path)
assert.Check(t, is.Equal(testcase.expectedContainer, container))
assert.Check(t, is.Equal(testcase.expectedPath, path))
assert.Equal(t, testcase.expectedContainer, container)
assert.Equal(t, testcase.expectedPath, path)
})
}
}

View File

@ -21,9 +21,8 @@ import (
)
type createOptions struct {
name string
platform string
untrusted bool
name string
platform string
}
// NewCreateCommand creates a new cobra.Command for `docker create`
@ -54,7 +53,7 @@ func NewCreateCommand(dockerCli command.Cli) *cobra.Command {
flags.Bool("help", false, "Print usage")
command.AddPlatformFlag(flags, &opts.platform)
command.AddTrustVerificationFlags(flags, &opts.untrusted, dockerCli.ContentTrustEnabled())
command.AddTrustVerificationFlags(flags)
copts = addFlags(flags)
return cmd
}
@ -65,7 +64,7 @@ func runCreate(dockerCli command.Cli, flags *pflag.FlagSet, opts *createOptions,
reportError(dockerCli.Err(), "create", err.Error(), true)
return cli.StatusError{StatusCode: 125}
}
response, err := createContainer(context.Background(), dockerCli, containerConfig, opts)
response, err := createContainer(context.Background(), dockerCli, containerConfig, opts.name, opts.platform)
if err != nil {
return err
}
@ -159,7 +158,7 @@ func newCIDFile(path string) (*cidFile, error) {
return &cidFile{path: path, file: f}, nil
}
func createContainer(ctx context.Context, dockerCli command.Cli, containerConfig *containerConfig, opts *createOptions) (*container.ContainerCreateCreatedBody, error) {
func createContainer(ctx context.Context, dockerCli command.Cli, containerConfig *containerConfig, name string, platform string) (*container.ContainerCreateCreatedBody, error) {
config := containerConfig.Config
hostConfig := containerConfig.HostConfig
networkingConfig := containerConfig.NetworkingConfig
@ -183,7 +182,7 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerConfig
if named, ok := ref.(reference.Named); ok {
namedRef = reference.TagNameOnly(named)
if taggedRef, ok := namedRef.(reference.NamedTagged); ok && !opts.untrusted {
if taggedRef, ok := namedRef.(reference.NamedTagged); ok && command.IsTrusted() {
var err error
trustedRef, err = image.TrustedReference(ctx, dockerCli, taggedRef, nil)
if err != nil {
@ -194,7 +193,7 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerConfig
}
//create the container
response, err := dockerCli.Client().ContainerCreate(ctx, config, hostConfig, networkingConfig, opts.name)
response, err := dockerCli.Client().ContainerCreate(ctx, config, hostConfig, networkingConfig, name)
//if image not found try to pull it
if err != nil {
@ -202,7 +201,7 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerConfig
fmt.Fprintf(stderr, "Unable to find image '%s' locally\n", reference.FamiliarString(namedRef))
// we don't want to write to stdout anything apart from container.ID
if err := pullImage(ctx, dockerCli, config.Image, opts.platform, stderr); err != nil {
if err := pullImage(ctx, dockerCli, config.Image, platform, stderr); err != nil {
return nil, err
}
if taggedRef, ok := namedRef.(reference.NamedTagged); ok && trustedRef != nil {
@ -212,7 +211,7 @@ func createContainer(ctx context.Context, dockerCli command.Cli, containerConfig
}
// Retry
var retryErr error
response, retryErr = dockerCli.Client().ContainerCreate(ctx, config, hostConfig, networkingConfig, opts.name)
response, retryErr = dockerCli.Client().ContainerCreate(ctx, config, hostConfig, networkingConfig, name)
if retryErr != nil {
return nil, retryErr
}

View File

@ -2,7 +2,6 @@ package container
import (
"context"
"fmt"
"io"
"io/ioutil"
"os"
@ -11,24 +10,23 @@ import (
"testing"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/notary"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/network"
"github.com/google/go-cmp/cmp"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/gotestyourself/gotestyourself/fs"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestCIDFileNoOPWithNoFilename(t *testing.T) {
file, err := newCIDFile("")
assert.NilError(t, err)
assert.DeepEqual(t, &cidFile{}, file, cmp.AllowUnexported(cidFile{}))
require.NoError(t, err)
assert.Equal(t, &cidFile{}, file)
assert.NilError(t, file.Write("id"))
assert.NilError(t, file.Close())
assert.NoError(t, file.Write("id"))
assert.NoError(t, file.Close())
}
func TestNewCIDFileWhenFileAlreadyExists(t *testing.T) {
@ -36,7 +34,7 @@ func TestNewCIDFileWhenFileAlreadyExists(t *testing.T) {
defer tempfile.Remove()
_, err := newCIDFile(tempfile.Path())
assert.ErrorContains(t, err, "Container ID file found")
testutil.ErrorContains(t, err, "Container ID file found")
}
func TestCIDFileCloseWithNoWrite(t *testing.T) {
@ -45,12 +43,12 @@ func TestCIDFileCloseWithNoWrite(t *testing.T) {
path := tempdir.Join("cidfile")
file, err := newCIDFile(path)
assert.NilError(t, err)
assert.Check(t, is.Equal(file.path, path))
require.NoError(t, err)
assert.Equal(t, file.path, path)
assert.NilError(t, file.Close())
assert.NoError(t, file.Close())
_, err = os.Stat(path)
assert.Check(t, os.IsNotExist(err))
assert.True(t, os.IsNotExist(err))
}
func TestCIDFileCloseWithWrite(t *testing.T) {
@ -59,18 +57,18 @@ func TestCIDFileCloseWithWrite(t *testing.T) {
path := tempdir.Join("cidfile")
file, err := newCIDFile(path)
assert.NilError(t, err)
require.NoError(t, err)
content := "id"
assert.NilError(t, file.Write(content))
assert.NoError(t, file.Write(content))
actual, err := ioutil.ReadFile(path)
assert.NilError(t, err)
assert.Check(t, is.Equal(content, string(actual)))
require.NoError(t, err)
assert.Equal(t, content, string(actual))
assert.NilError(t, file.Close())
assert.NoError(t, file.Close())
_, err = os.Stat(path)
assert.NilError(t, err)
require.NoError(t, err)
}
func TestCreateContainerPullsImageIfMissing(t *testing.T) {
@ -109,61 +107,12 @@ func TestCreateContainerPullsImageIfMissing(t *testing.T) {
},
HostConfig: &container.HostConfig{},
}
body, err := createContainer(context.Background(), cli, config, &createOptions{
name: "name",
platform: runtime.GOOS,
untrusted: true,
})
assert.NilError(t, err)
body, err := createContainer(context.Background(), cli, config, "name", runtime.GOOS)
require.NoError(t, err)
expected := container.ContainerCreateCreatedBody{ID: containerID}
assert.Check(t, is.DeepEqual(expected, *body))
assert.Equal(t, expected, *body)
stderr := cli.ErrBuffer().String()
assert.Check(t, is.Contains(stderr, "Unable to find image 'does-not-exist-locally:latest' locally"))
}
func TestNewCreateCommandWithContentTrustErrors(t *testing.T) {
testCases := []struct {
name string
args []string
expectedError string
notaryFunc test.NotaryClientFuncType
}{
{
name: "offline-notary-server",
notaryFunc: notary.GetOfflineNotaryRepository,
expectedError: "client is offline",
args: []string{"image:tag"},
},
{
name: "uninitialized-notary-server",
notaryFunc: notary.GetUninitializedNotaryRepository,
expectedError: "remote trust data does not exist",
args: []string{"image:tag"},
},
{
name: "empty-notary-server",
notaryFunc: notary.GetEmptyTargetsNotaryRepository,
expectedError: "No valid trust data for tag",
args: []string{"image:tag"},
},
}
for _, tc := range testCases {
cli := test.NewFakeCli(&fakeClient{
createContainerFunc: func(config *container.Config,
hostConfig *container.HostConfig,
networkingConfig *network.NetworkingConfig,
containerName string,
) (container.ContainerCreateCreatedBody, error) {
return container.ContainerCreateCreatedBody{}, fmt.Errorf("shouldn't try to pull image")
},
}, test.EnableContentTrust)
cli.SetNotaryClient(tc.notaryFunc)
cmd := NewCreateCommand(cli)
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs(tc.args)
err := cmd.Execute()
assert.ErrorContains(t, err, tc.expectedError)
}
assert.Contains(t, stderr, "Unable to find image 'does-not-exist-locally:latest' locally")
}
type fakeNotFound struct{}

View File

@ -7,11 +7,11 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/cli/opts"
"github.com/docker/docker/api/types"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"golang.org/x/net/context"
)
@ -106,7 +106,7 @@ func TestParseExec(t *testing.T) {
for _, testcase := range testcases {
execConfig := parseExec(testcase.options, &testcase.configFile)
assert.Check(t, is.DeepEqual(testcase.expected, *execConfig))
assert.Equal(t, testcase.expected, *execConfig)
}
}
@ -150,14 +150,14 @@ func TestRunExec(t *testing.T) {
err := runExec(cli, testcase.options)
if testcase.expectedError != "" {
assert.ErrorContains(t, err, testcase.expectedError)
testutil.ErrorContains(t, err, testcase.expectedError)
} else {
if !assert.Check(t, err) {
if !assert.NoError(t, err) {
return
}
}
assert.Check(t, is.Equal(testcase.expectedOut, cli.OutBuffer().String()))
assert.Check(t, is.Equal(testcase.expectedErr, cli.ErrBuffer().String()))
assert.Equal(t, testcase.expectedOut, cli.OutBuffer().String())
assert.Equal(t, testcase.expectedErr, cli.ErrBuffer().String())
})
}
}
@ -192,12 +192,12 @@ func TestGetExecExitStatus(t *testing.T) {
for _, testcase := range testcases {
client := &fakeClient{
execInspectFunc: func(id string) (types.ContainerExecInspect, error) {
assert.Check(t, is.Equal(execID, id))
assert.Equal(t, execID, id)
return types.ContainerExecInspect{ExitCode: testcase.exitCode}, testcase.inspectError
},
}
err := getExecExitStatus(context.Background(), client, execID)
assert.Check(t, is.Equal(testcase.expectedError, err))
assert.Equal(t, testcase.expectedError, err)
}
}
@ -222,6 +222,6 @@ func TestNewExecCommandErrors(t *testing.T) {
cmd := NewExecCommand(cli)
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs(tc.args)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}

View File

@ -7,10 +7,11 @@ import (
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/docker/api/types"
"github.com/stretchr/testify/assert"
// Import builders to get the builder function as package function
. "github.com/docker/cli/internal/test/builders"
"github.com/gotestyourself/gotestyourself/assert"
"github.com/gotestyourself/gotestyourself/golden"
)
@ -51,7 +52,7 @@ func TestContainerListErrors(t *testing.T) {
cmd.Flags().Set(key, value)
}
cmd.SetOutput(ioutil.Discard)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
@ -68,7 +69,7 @@ func TestContainerListWithoutFormat(t *testing.T) {
},
})
cmd := newListCommand(cli)
assert.NilError(t, cmd.Execute())
assert.NoError(t, cmd.Execute())
golden.Assert(t, cli.OutBuffer().String(), "container-list-without-format.golden")
}
@ -83,7 +84,7 @@ func TestContainerListNoTrunc(t *testing.T) {
})
cmd := newListCommand(cli)
cmd.Flags().Set("no-trunc", "true")
assert.NilError(t, cmd.Execute())
assert.NoError(t, cmd.Execute())
golden.Assert(t, cli.OutBuffer().String(), "container-list-without-format-no-trunc.golden")
}
@ -99,7 +100,7 @@ func TestContainerListNamesMultipleTime(t *testing.T) {
})
cmd := newListCommand(cli)
cmd.Flags().Set("format", "{{.Names}} {{.Names}}")
assert.NilError(t, cmd.Execute())
assert.NoError(t, cmd.Execute())
golden.Assert(t, cli.OutBuffer().String(), "container-list-format-name-name.golden")
}
@ -115,20 +116,20 @@ func TestContainerListFormatTemplateWithArg(t *testing.T) {
})
cmd := newListCommand(cli)
cmd.Flags().Set("format", `{{.Names}} {{.Label "some.label"}}`)
assert.NilError(t, cmd.Execute())
assert.NoError(t, cmd.Execute())
golden.Assert(t, cli.OutBuffer().String(), "container-list-format-with-arg.golden")
}
func TestContainerListFormatSizeSetsOption(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{
containerListFunc: func(options types.ContainerListOptions) ([]types.Container, error) {
assert.Check(t, options.Size)
assert.True(t, options.Size)
return []types.Container{}, nil
},
})
cmd := newListCommand(cli)
cmd.Flags().Set("format", `{{.Size}}`)
assert.NilError(t, cmd.Execute())
assert.NoError(t, cmd.Execute())
}
func TestContainerListWithConfigFormat(t *testing.T) {
@ -144,7 +145,7 @@ func TestContainerListWithConfigFormat(t *testing.T) {
PsFormat: "{{ .Names }} {{ .Image }} {{ .Labels }}",
})
cmd := newListCommand(cli)
assert.NilError(t, cmd.Execute())
assert.NoError(t, cmd.Execute())
golden.Assert(t, cli.OutBuffer().String(), "container-list-with-config-format.golden")
}
@ -159,6 +160,6 @@ func TestContainerListWithFormat(t *testing.T) {
})
cmd := newListCommand(cli)
cmd.Flags().Set("format", "{{ .Names }} {{ .Image }} {{ .Labels }}")
assert.NilError(t, cmd.Execute())
assert.NoError(t, cmd.Execute())
golden.Assert(t, cli.OutBuffer().String(), "container-list-with-format.golden")
}

View File

@ -7,10 +7,10 @@ import (
"testing"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/stretchr/testify/assert"
)
var logFn = func(expectedOut string) func(string, types.ContainerLogsOptions) (io.ReadCloser, error) {
@ -49,14 +49,14 @@ func TestRunLogs(t *testing.T) {
err := runLogs(cli, testcase.options)
if testcase.expectedError != "" {
assert.ErrorContains(t, err, testcase.expectedError)
testutil.ErrorContains(t, err, testcase.expectedError)
} else {
if !assert.Check(t, err) {
if !assert.NoError(t, err) {
return
}
}
assert.Check(t, is.Equal(testcase.expectedOut, cli.OutBuffer().String()))
assert.Check(t, is.Equal(testcase.expectedErr, cli.ErrBuffer().String()))
assert.Equal(t, testcase.expectedOut, cli.OutBuffer().String())
assert.Equal(t, testcase.expectedErr, cli.ErrBuffer().String())
})
}
}

View File

@ -145,7 +145,7 @@ func addFlags(flags *pflag.FlagSet) *containerOptions {
expose: opts.NewListOpts(nil),
extraHosts: opts.NewListOpts(opts.ValidateExtraHost),
groupAdd: opts.NewListOpts(nil),
labels: opts.NewListOpts(nil),
labels: opts.NewListOpts(opts.ValidateLabel),
labelsFile: opts.NewListOpts(nil),
linkLocalIPs: opts.NewListOpts(nil),
links: opts.NewListOpts(opts.ValidateLink),

View File

@ -9,13 +9,14 @@ import (
"testing"
"time"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/docker/api/types/container"
networktypes "github.com/docker/docker/api/types/network"
"github.com/docker/go-connections/nat"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/pkg/errors"
"github.com/spf13/pflag"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestValidateAttach(t *testing.T) {
@ -66,12 +67,12 @@ func setupRunFlags() (*pflag.FlagSet, *containerOptions) {
func parseMustError(t *testing.T, args string) {
_, _, _, err := parseRun(strings.Split(args+" ubuntu bash", " "))
assert.ErrorContains(t, err, "", args)
assert.Error(t, err, args)
}
func mustParse(t *testing.T, args string) (*container.Config, *container.HostConfig) {
config, hostConfig, _, err := parseRun(append(strings.Split(args, " "), "ubuntu", "bash"))
assert.NilError(t, err)
assert.NoError(t, err)
return config, hostConfig
}
@ -235,23 +236,23 @@ func TestRunFlagsParseWithMemory(t *testing.T) {
flags, _ := setupRunFlags()
args := []string{"--memory=invalid", "img", "cmd"}
err := flags.Parse(args)
assert.ErrorContains(t, err, `invalid argument "invalid" for "-m, --memory" flag`)
testutil.ErrorContains(t, err, `invalid argument "invalid" for "-m, --memory" flag`)
_, hostconfig := mustParse(t, "--memory=1G")
assert.Check(t, is.Equal(int64(1073741824), hostconfig.Memory))
assert.Equal(t, int64(1073741824), hostconfig.Memory)
}
func TestParseWithMemorySwap(t *testing.T) {
flags, _ := setupRunFlags()
args := []string{"--memory-swap=invalid", "img", "cmd"}
err := flags.Parse(args)
assert.ErrorContains(t, err, `invalid argument "invalid" for "--memory-swap" flag`)
testutil.ErrorContains(t, err, `invalid argument "invalid" for "--memory-swap" flag`)
_, hostconfig := mustParse(t, "--memory-swap=1G")
assert.Check(t, is.Equal(int64(1073741824), hostconfig.MemorySwap))
assert.Equal(t, int64(1073741824), hostconfig.MemorySwap)
_, hostconfig = mustParse(t, "--memory-swap=-1")
assert.Check(t, is.Equal(int64(-1), hostconfig.MemorySwap))
assert.Equal(t, int64(-1), hostconfig.MemorySwap)
}
func TestParseHostname(t *testing.T) {
@ -372,24 +373,24 @@ func TestParseModes(t *testing.T) {
// pid ko
flags, copts := setupRunFlags()
args := []string{"--pid=container:", "img", "cmd"}
assert.NilError(t, flags.Parse(args))
require.NoError(t, flags.Parse(args))
_, err := parse(flags, copts)
assert.ErrorContains(t, err, "--pid: invalid PID mode")
testutil.ErrorContains(t, err, "--pid: invalid PID mode")
// pid ok
_, hostconfig, _, err := parseRun([]string{"--pid=host", "img", "cmd"})
assert.NilError(t, err)
require.NoError(t, err)
if !hostconfig.PidMode.Valid() {
t.Fatalf("Expected a valid PidMode, got %v", hostconfig.PidMode)
}
// uts ko
_, _, _, err = parseRun([]string{"--uts=container:", "img", "cmd"})
assert.ErrorContains(t, err, "--uts: invalid UTS mode")
testutil.ErrorContains(t, err, "--uts: invalid UTS mode")
// uts ok
_, hostconfig, _, err = parseRun([]string{"--uts=host", "img", "cmd"})
assert.NilError(t, err)
require.NoError(t, err)
if !hostconfig.UTSMode.Valid() {
t.Fatalf("Expected a valid UTSMode, got %v", hostconfig.UTSMode)
}
@ -401,11 +402,11 @@ func TestRunFlagsParseShmSize(t *testing.T) {
args := []string{"--shm-size=a128m", "img", "cmd"}
expectedErr := `invalid argument "a128m" for "--shm-size" flag: invalid size: 'a128m'`
err := flags.Parse(args)
assert.ErrorContains(t, err, expectedErr)
testutil.ErrorContains(t, err, expectedErr)
// shm-size ok
_, hostconfig, _, err := parseRun([]string{"--shm-size=128m", "img", "cmd"})
assert.NilError(t, err)
require.NoError(t, err)
if hostconfig.ShmSize != 134217728 {
t.Fatalf("Expected a valid ShmSize, got %d", hostconfig.ShmSize)
}

View File

@ -4,14 +4,13 @@ import (
"testing"
"github.com/docker/cli/opts"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/stretchr/testify/assert"
)
func TestBuildContainerListOptions(t *testing.T) {
filters := opts.NewFilterOpt()
assert.NilError(t, filters.Set("foo=bar"))
assert.NilError(t, filters.Set("baz=foo"))
assert.NoError(t, filters.Set("foo=bar"))
assert.NoError(t, filters.Set("baz=foo"))
contexts := []struct {
psOpts *psOptions
@ -102,12 +101,12 @@ func TestBuildContainerListOptions(t *testing.T) {
for _, c := range contexts {
options, err := buildContainerListOptions(c.psOpts)
assert.NilError(t, err)
assert.NoError(t, err)
assert.Check(t, is.Equal(c.expectedAll, options.All))
assert.Check(t, is.Equal(c.expectedSize, options.Size))
assert.Check(t, is.Equal(c.expectedLimit, options.Limit))
assert.Check(t, is.Equal(len(c.expectedFilters), options.Filters.Len()))
assert.Equal(t, c.expectedAll, options.All)
assert.Equal(t, c.expectedSize, options.Size)
assert.Equal(t, c.expectedLimit, options.Limit)
assert.Equal(t, len(c.expectedFilters), options.Filters.Len())
for k, v := range c.expectedFilters {
f := options.Filters

View File

@ -25,10 +25,11 @@ import (
)
type runOptions struct {
createOptions
detach bool
sigProxy bool
name string
detachKeys string
platform string
}
// NewRunCommand create a new `docker run` command
@ -63,7 +64,7 @@ func NewRunCommand(dockerCli command.Cli) *cobra.Command {
flags.Bool("help", false, "Print usage")
command.AddPlatformFlag(flags, &opts.platform)
command.AddTrustVerificationFlags(flags, &opts.untrusted, dockerCli.ContentTrustEnabled())
command.AddTrustVerificationFlags(flags)
copts = addFlags(flags)
return cmd
}
@ -161,7 +162,7 @@ func runContainer(dockerCli command.Cli, opts *runOptions, copts *containerOptio
ctx, cancelFun := context.WithCancel(context.Background())
createResponse, err := createContainer(ctx, dockerCli, containerConfig, &opts.createOptions)
createResponse, err := createContainer(ctx, dockerCli, containerConfig, opts.name, opts.platform)
if err != nil {
reportError(stderr, cmdPath, err.Error(), true)
return runStartContainerErr(err)

View File

@ -1,73 +0,0 @@
package container
import (
"fmt"
"testing"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/notary"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/network"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
)
func TestRunLabel(t *testing.T) {
cli := test.NewFakeCli(&fakeClient{
createContainerFunc: func(_ *container.Config, _ *container.HostConfig, _ *network.NetworkingConfig, _ string) (container.ContainerCreateCreatedBody, error) {
return container.ContainerCreateCreatedBody{
ID: "id",
}, nil
},
Version: "1.36",
})
cmd := NewRunCommand(cli)
cmd.Flags().Set("detach", "true")
cmd.SetArgs([]string{"--label", "foo", "busybox"})
assert.NilError(t, cmd.Execute())
}
func TestRunCommandWithContentTrustErrors(t *testing.T) {
testCases := []struct {
name string
args []string
expectedError string
notaryFunc test.NotaryClientFuncType
}{
{
name: "offline-notary-server",
notaryFunc: notary.GetOfflineNotaryRepository,
expectedError: "client is offline",
args: []string{"image:tag"},
},
{
name: "uninitialized-notary-server",
notaryFunc: notary.GetUninitializedNotaryRepository,
expectedError: "remote trust data does not exist",
args: []string{"image:tag"},
},
{
name: "empty-notary-server",
notaryFunc: notary.GetEmptyTargetsNotaryRepository,
expectedError: "No valid trust data for tag",
args: []string{"image:tag"},
},
}
for _, tc := range testCases {
cli := test.NewFakeCli(&fakeClient{
createContainerFunc: func(config *container.Config,
hostConfig *container.HostConfig,
networkingConfig *network.NetworkingConfig,
containerName string,
) (container.ContainerCreateCreatedBody, error) {
return container.ContainerCreateCreatedBody{}, fmt.Errorf("shouldn't try to pull image")
},
}, test.EnableContentTrust)
cli.SetNotaryClient(tc.notaryFunc)
cmd := NewRunCommand(cli)
cmd.SetArgs(tc.args)
err := cmd.Execute()
assert.Assert(t, err != nil)
assert.Assert(t, is.Contains(cli.ErrBuffer().String(), tc.expectedError))
}
}

View File

@ -1,11 +1,10 @@
package container
import (
"fmt"
"testing"
"github.com/docker/docker/api/types"
"github.com/gotestyourself/gotestyourself/assert"
"github.com/stretchr/testify/assert"
)
func TestCalculateMemUsageUnixNoCache(t *testing.T) {
@ -16,7 +15,7 @@ func TestCalculateMemUsageUnixNoCache(t *testing.T) {
result := calculateMemUsageUnixNoCache(stats)
// Then
assert.Assert(t, inDelta(100.0, result, 1e-6))
assert.InDelta(t, 100.0, result, 1e-6)
}
func TestCalculateMemPercentUnixNoCache(t *testing.T) {
@ -28,20 +27,10 @@ func TestCalculateMemPercentUnixNoCache(t *testing.T) {
// When and Then
t.Run("Limit is set", func(t *testing.T) {
result := calculateMemPercentUnixNoCache(someLimit, used)
assert.Assert(t, inDelta(70.0, result, 1e-6))
assert.InDelta(t, 70.0, result, 1e-6)
})
t.Run("No limit, no cgroup data", func(t *testing.T) {
result := calculateMemPercentUnixNoCache(noLimit, used)
assert.Assert(t, inDelta(0.0, result, 1e-6))
assert.InDelta(t, 0.0, result, 1e-6)
})
}
func inDelta(x, y, delta float64) func() (bool, string) {
return func() (bool, string) {
diff := x - y
if diff < -delta || diff > delta {
return false, fmt.Sprintf("%f != %f within %f", x, y, delta)
}
return true, ""
}
}

View File

@ -7,9 +7,8 @@ import (
"github.com/docker/cli/internal/test"
"github.com/docker/docker/api"
"github.com/docker/docker/api/types/container"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"golang.org/x/net/context"
)
@ -65,6 +64,6 @@ func TestWaitExitOrRemoved(t *testing.T) {
for _, testcase := range testcases {
statusC := waitExitOrRemoved(context.Background(), client, testcase.cid, true)
exitCode := <-statusC
assert.Check(t, is.Equal(testcase.exitCode, exitCode))
assert.Equal(t, testcase.exitCode, exitCode)
}
}

View File

@ -5,7 +5,7 @@ import (
"testing"
"github.com/docker/docker/api/types"
"github.com/gotestyourself/gotestyourself/assert"
"github.com/stretchr/testify/assert"
)
func TestCheckpointContextFormatWrite(t *testing.T) {
@ -46,7 +46,10 @@ checkpoint-3:
out := bytes.NewBufferString("")
testcase.context.Output = out
err := CheckpointWrite(testcase.context, checkpoints)
assert.NilError(t, err)
assert.Equal(t, out.String(), testcase.expected)
if err != nil {
assert.Error(t, err, testcase.expected)
} else {
assert.Equal(t, out.String(), testcase.expected)
}
}
}

View File

@ -6,8 +6,7 @@ import (
"time"
"github.com/docker/docker/api/types/swarm"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/stretchr/testify/assert"
)
func TestConfigContextFormatWrite(t *testing.T) {
@ -56,9 +55,9 @@ id_rsa
out := bytes.NewBufferString("")
testcase.context.Output = out
if err := ConfigWrite(testcase.context, configs); err != nil {
assert.ErrorContains(t, err, testcase.expected)
assert.Error(t, err, testcase.expected)
} else {
assert.Check(t, is.Equal(out.String(), testcase.expected))
assert.Equal(t, out.String(), testcase.expected)
}
}
}

View File

@ -10,9 +10,9 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/stringid"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/gotestyourself/gotestyourself/golden"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestContainerPsContext(t *testing.T) {
@ -244,9 +244,9 @@ size: 0B
testcase.context.Output = out
err := ContainerWrite(testcase.context, containers)
if err != nil {
assert.Error(t, err, testcase.expected)
assert.EqualError(t, err, testcase.expected)
} else {
assert.Check(t, is.Equal(testcase.expected, out.String()))
assert.Equal(t, testcase.expected, out.String())
}
}
}
@ -305,7 +305,7 @@ func TestContainerContextWriteWithNoContainers(t *testing.T) {
for _, context := range contexts {
ContainerWrite(context.context, containers)
assert.Check(t, is.Equal(context.expected, out.String()))
assert.Equal(t, context.expected, out.String())
// Clean buffer
out.Reset()
}
@ -359,8 +359,8 @@ func TestContainerContextWriteJSON(t *testing.T) {
msg := fmt.Sprintf("Output: line %d: %s", i, line)
var m map[string]interface{}
err := json.Unmarshal([]byte(line), &m)
assert.NilError(t, err, msg)
assert.Check(t, is.DeepEqual(expectedJSONs[i], m), msg)
require.NoError(t, err, msg)
assert.Equal(t, expectedJSONs[i], m, msg)
}
}
@ -378,8 +378,8 @@ func TestContainerContextWriteJSONField(t *testing.T) {
msg := fmt.Sprintf("Output: line %d: %s", i, line)
var s string
err := json.Unmarshal([]byte(line), &s)
assert.NilError(t, err, msg)
assert.Check(t, is.Equal(containers[i].ID, s), msg)
require.NoError(t, err, msg)
assert.Equal(t, containers[i].ID, s, msg)
}
}
@ -653,6 +653,6 @@ func TestDisplayablePorts(t *testing.T) {
for _, port := range cases {
actual := DisplayablePorts(port.ports)
assert.Check(t, is.Equal(port.expected, actual))
assert.Equal(t, port.expected, actual)
}
}

View File

@ -4,8 +4,7 @@ import (
"strings"
"testing"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/stretchr/testify/assert"
)
func compareMultipleValues(t *testing.T, value, expected string) {
@ -24,5 +23,5 @@ func compareMultipleValues(t *testing.T, value, expected string) {
keyval := strings.Split(expected, "=")
expMap[keyval[0]] = keyval[1]
}
assert.Check(t, is.DeepEqual(expMap, entriesMap))
assert.Equal(t, expMap, entriesMap)
}

View File

@ -6,8 +6,7 @@ import (
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/pkg/archive"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/stretchr/testify/assert"
)
func TestDiffContextFormatWrite(t *testing.T) {
@ -52,9 +51,9 @@ D: /usr/app/old_app.js
testcase.context.Output = out
err := DiffWrite(testcase.context, diffs)
if err != nil {
assert.Error(t, err, testcase.expected)
assert.EqualError(t, err, testcase.expected)
} else {
assert.Check(t, is.Equal(testcase.expected, out.String()))
assert.Equal(t, testcase.expected, out.String())
}
}
}

View File

@ -4,9 +4,8 @@ import (
"bytes"
"testing"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/gotestyourself/gotestyourself/golden"
"github.com/stretchr/testify/assert"
)
func TestDiskUsageContextFormatWrite(t *testing.T) {
@ -102,9 +101,9 @@ Build Cache 0B
out := bytes.NewBufferString("")
testcase.context.Output = out
if err := testcase.context.Write(); err != nil {
assert.Check(t, is.Equal(testcase.expected, err.Error()))
assert.Equal(t, testcase.expected, err.Error())
} else {
assert.Check(t, is.Equal(testcase.expected, out.String()))
assert.Equal(t, testcase.expected, out.String())
}
}
}

View File

@ -3,8 +3,7 @@ package formatter
import (
"testing"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/stretchr/testify/assert"
)
func TestEllipsis(t *testing.T) {
@ -26,6 +25,6 @@ func TestEllipsis(t *testing.T) {
}
for _, testcase := range testcases {
assert.Check(t, is.Equal(testcase.expected, Ellipsis(testcase.source, testcase.width)))
assert.Equal(t, testcase.expected, Ellipsis(testcase.source, testcase.width))
}
}

View File

@ -1,16 +1,16 @@
package formatter
import (
"bytes"
"strconv"
"strings"
"testing"
"time"
"bytes"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/pkg/stringid"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/stretchr/testify/assert"
)
type historyCase struct {
@ -50,7 +50,6 @@ func TestHistoryContext_ID(t *testing.T) {
}
func TestHistoryContext_CreatedSince(t *testing.T) {
dateStr := "2009-11-10T23:00:00Z"
var ctx historyContext
cases := []historyCase{
{
@ -65,7 +64,7 @@ func TestHistoryContext_CreatedSince(t *testing.T) {
h: image.HistoryResponseItem{Created: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC).Unix()},
trunc: false,
human: false,
}, dateStr, ctx.CreatedSince,
}, "2009-11-10T23:00:00Z", ctx.CreatedSince,
},
}
@ -219,7 +218,7 @@ imageID4 24 hours ago /bin/bash grep
for _, context := range contexts {
HistoryWrite(context.context, true, histories)
assert.Check(t, is.Equal(context.expected, out.String()))
assert.Equal(t, context.expected, out.String())
// Clean buffer
out.Reset()
}

View File

@ -9,8 +9,7 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/stringid"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/stretchr/testify/assert"
)
func TestImageContext(t *testing.T) {
@ -84,7 +83,7 @@ func TestImageContext(t *testing.T) {
if strings.Contains(v, ",") {
compareMultipleValues(t, v, c.expValue)
} else {
assert.Check(t, is.Equal(c.expValue, v))
assert.Equal(t, c.expValue, v)
}
}
}
@ -294,9 +293,9 @@ image_id: imageID3
testcase.context.Output = out
err := ImageWrite(testcase.context, images)
if err != nil {
assert.Error(t, err, testcase.expected)
assert.EqualError(t, err, testcase.expected)
} else {
assert.Check(t, is.Equal(testcase.expected, out.String()))
assert.Equal(t, testcase.expected, out.String())
}
}
}
@ -349,7 +348,7 @@ func TestImageContextWriteWithNoImage(t *testing.T) {
for _, context := range contexts {
ImageWrite(context.context, images)
assert.Check(t, is.Equal(context.expected, out.String()))
assert.Equal(t, context.expected, out.String())
// Clean buffer
out.Reset()
}

View File

@ -10,8 +10,8 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/stringid"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestNetworkContext(t *testing.T) {
@ -162,9 +162,9 @@ foobar_bar 2017-01-01 00:00:00 +0000 UTC
testcase.context.Output = out
err := NetworkWrite(testcase.context, networks)
if err != nil {
assert.Error(t, err, testcase.expected)
assert.EqualError(t, err, testcase.expected)
} else {
assert.Check(t, is.Equal(testcase.expected, out.String()))
assert.Equal(t, testcase.expected, out.String())
}
}
}
@ -188,8 +188,8 @@ func TestNetworkContextWriteJSON(t *testing.T) {
msg := fmt.Sprintf("Output: line %d: %s", i, line)
var m map[string]interface{}
err := json.Unmarshal([]byte(line), &m)
assert.NilError(t, err, msg)
assert.Check(t, is.DeepEqual(expectedJSONs[i], m), msg)
require.NoError(t, err, msg)
assert.Equal(t, expectedJSONs[i], m, msg)
}
}
@ -207,7 +207,7 @@ func TestNetworkContextWriteJSONField(t *testing.T) {
msg := fmt.Sprintf("Output: line %d: %s", i, line)
var s string
err := json.Unmarshal([]byte(line), &s)
assert.NilError(t, err, msg)
assert.Check(t, is.Equal(networks[i].ID, s), msg)
require.NoError(t, err, msg)
assert.Equal(t, networks[i].ID, s, msg)
}
}

View File

@ -10,8 +10,8 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/pkg/stringid"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestNodeContext(t *testing.T) {
@ -203,9 +203,9 @@ foobar_boo Unknown
testcase.context.Output = out
err := NodeWrite(testcase.context, nodes, types.Info{Swarm: swarm.Info{Cluster: &testcase.clusterInfo}})
if err != nil {
assert.Error(t, err, testcase.expected)
assert.EqualError(t, err, testcase.expected)
} else {
assert.Check(t, is.Equal(testcase.expected, out.String()))
assert.Equal(t, testcase.expected, out.String())
}
}
}
@ -255,8 +255,8 @@ func TestNodeContextWriteJSON(t *testing.T) {
msg := fmt.Sprintf("Output: line %d: %s", i, line)
var m map[string]interface{}
err := json.Unmarshal([]byte(line), &m)
assert.NilError(t, err, msg)
assert.Check(t, is.DeepEqual(testcase.expected[i], m), msg)
require.NoError(t, err, msg)
assert.Equal(t, testcase.expected[i], m, msg)
}
}
}
@ -275,8 +275,8 @@ func TestNodeContextWriteJSONField(t *testing.T) {
msg := fmt.Sprintf("Output: line %d: %s", i, line)
var s string
err := json.Unmarshal([]byte(line), &s)
assert.NilError(t, err, msg)
assert.Check(t, is.Equal(nodes[i].ID, s), msg)
require.NoError(t, err, msg)
assert.Equal(t, nodes[i].ID, s, msg)
}
}
@ -344,5 +344,5 @@ data
Issuer Subject: c3ViamVjdA==
Issuer Public Key: cHViS2V5
`
assert.Check(t, is.Equal(expected, out.String()))
assert.Equal(t, expected, out.String())
}

View File

@ -8,8 +8,7 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/stringid"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/stretchr/testify/assert"
)
func TestPluginContext(t *testing.T) {
@ -132,9 +131,9 @@ foobar_bar
testcase.context.Output = out
err := PluginWrite(testcase.context, plugins)
if err != nil {
assert.Error(t, err, testcase.expected)
assert.EqualError(t, err, testcase.expected)
} else {
assert.Check(t, is.Equal(testcase.expected, out.String()))
assert.Equal(t, testcase.expected, out.String())
}
}
}
@ -159,7 +158,7 @@ func TestPluginContextWriteJSON(t *testing.T) {
if err := json.Unmarshal([]byte(line), &m); err != nil {
t.Fatal(err)
}
assert.Check(t, is.DeepEqual(expectedJSONs[i], m))
assert.Equal(t, expectedJSONs[i], m)
}
}
@ -178,6 +177,6 @@ func TestPluginContextWriteJSONField(t *testing.T) {
if err := json.Unmarshal([]byte(line), &s); err != nil {
t.Fatal(err)
}
assert.Check(t, is.Equal(plugins[i].ID, s))
assert.Equal(t, plugins[i].ID, s)
}
}

View File

@ -7,9 +7,8 @@ import (
"testing"
registrytypes "github.com/docker/docker/api/types/registry"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/gotestyourself/gotestyourself/golden"
"github.com/stretchr/testify/assert"
)
func TestSearchContext(t *testing.T) {
@ -155,9 +154,9 @@ result2 5
testcase.context.Output = out
err := SearchWrite(testcase.context, results, false, 0)
if err != nil {
assert.Check(t, is.ErrorContains(err, testcase.expected))
assert.Error(t, err, testcase.expected)
} else {
assert.Check(t, is.Equal(out.String(), testcase.expected))
assert.Equal(t, out.String(), testcase.expected)
}
}
}
@ -192,9 +191,9 @@ result2
testcase.context.Output = out
err := SearchWrite(testcase.context, results, true, 0)
if err != nil {
assert.Check(t, is.ErrorContains(err, testcase.expected))
assert.Error(t, err, testcase.expected)
} else {
assert.Check(t, is.Equal(out.String(), testcase.expected))
assert.Equal(t, out.String(), testcase.expected)
}
}
}
@ -227,9 +226,9 @@ result1
testcase.context.Output = out
err := SearchWrite(testcase.context, results, false, 6)
if err != nil {
assert.Check(t, is.ErrorContains(err, testcase.expected))
assert.Error(t, err, testcase.expected)
} else {
assert.Check(t, is.Equal(out.String(), testcase.expected))
assert.Equal(t, out.String(), testcase.expected)
}
}
}
@ -255,7 +254,7 @@ func TestSearchContextWriteJSON(t *testing.T) {
if err := json.Unmarshal([]byte(line), &m); err != nil {
t.Fatal(err)
}
assert.Check(t, is.DeepEqual(m, expectedJSONs[i]))
assert.Equal(t, m, expectedJSONs[i])
}
}
@ -275,6 +274,6 @@ func TestSearchContextWriteJSONField(t *testing.T) {
if err := json.Unmarshal([]byte(line), &s); err != nil {
t.Fatal(err)
}
assert.Check(t, is.Equal(s, results[i].Name))
assert.Equal(t, s, results[i].Name)
}
}

View File

@ -6,8 +6,7 @@ import (
"time"
"github.com/docker/docker/api/types/swarm"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/stretchr/testify/assert"
)
func TestSecretContextFormatWrite(t *testing.T) {
@ -56,9 +55,9 @@ id_rsa
out := bytes.NewBufferString("")
testcase.context.Output = out
if err := SecretWrite(testcase.context, secrets); err != nil {
assert.Error(t, err, testcase.expected)
assert.EqualError(t, err, testcase.expected)
} else {
assert.Check(t, is.Equal(testcase.expected, out.String()))
assert.Equal(t, testcase.expected, out.String())
}
}
}

View File

@ -8,9 +8,9 @@ import (
"testing"
"github.com/docker/docker/api/types/swarm"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/gotestyourself/gotestyourself/golden"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestServiceContextWrite(t *testing.T) {
@ -126,9 +126,9 @@ bar
testcase.context.Output = out
err := ServiceListWrite(testcase.context, services, info)
if err != nil {
assert.Error(t, err, testcase.expected)
assert.EqualError(t, err, testcase.expected)
} else {
assert.Check(t, is.Equal(testcase.expected, out.String()))
assert.Equal(t, testcase.expected, out.String())
}
}
}
@ -192,8 +192,8 @@ func TestServiceContextWriteJSON(t *testing.T) {
msg := fmt.Sprintf("Output: line %d: %s", i, line)
var m map[string]interface{}
err := json.Unmarshal([]byte(line), &m)
assert.NilError(t, err, msg)
assert.Check(t, is.DeepEqual(expectedJSONs[i], m), msg)
require.NoError(t, err, msg)
assert.Equal(t, expectedJSONs[i], m, msg)
}
}
func TestServiceContextWriteJSONField(t *testing.T) {
@ -220,8 +220,8 @@ func TestServiceContextWriteJSONField(t *testing.T) {
msg := fmt.Sprintf("Output: line %d: %s", i, line)
var s string
err := json.Unmarshal([]byte(line), &s)
assert.NilError(t, err, msg)
assert.Check(t, is.Equal(services[i].Spec.Name, s), msg)
require.NoError(t, err, msg)
assert.Equal(t, services[i].Spec.Name, s, msg)
}
}
@ -355,5 +355,5 @@ func TestServiceContext_Ports(t *testing.T) {
},
}
assert.Check(t, is.Equal("*:97-98->97-98/sctp, *:60-61->60-61/tcp, *:62->61/tcp, *:80-81->80/tcp, *:90-95->90-95/tcp, *:90-96->90-96/udp", c.Ports()))
assert.Equal(t, "*:97-98->97-98/sctp, *:60-61->60-61/tcp, *:62->61/tcp, *:80-81->80/tcp, *:90-95->90-95/tcp, *:90-96->90-96/udp", c.Ports())
}

View File

@ -4,8 +4,7 @@ import (
"bytes"
"testing"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/stretchr/testify/assert"
)
func TestStackContextWrite(t *testing.T) {
@ -57,9 +56,9 @@ bar
testcase.context.Output = out
err := StackWrite(testcase.context, stacks)
if err != nil {
assert.Check(t, is.ErrorContains(err, testcase.expected))
assert.Error(t, err, testcase.expected)
} else {
assert.Check(t, is.Equal(out.String(), testcase.expected))
assert.Equal(t, out.String(), testcase.expected)
}
}
}

View File

@ -5,8 +5,7 @@ import (
"testing"
"github.com/docker/docker/pkg/stringid"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/stretchr/testify/assert"
)
func TestContainerStatsContext(t *testing.T) {
@ -117,9 +116,9 @@ container2 --
te.context.Output = &out
err := ContainerStatsWrite(te.context, stats, "linux", false)
if err != nil {
assert.Error(t, err, te.expected)
assert.EqualError(t, err, te.expected)
} else {
assert.Check(t, is.Equal(te.expected, out.String()))
assert.Equal(t, te.expected, out.String())
}
}
}
@ -183,9 +182,9 @@ container2 -- --
te.context.Output = &out
err := ContainerStatsWrite(te.context, stats, "windows", false)
if err != nil {
assert.Error(t, err, te.expected)
assert.EqualError(t, err, te.expected)
} else {
assert.Check(t, is.Equal(te.expected, out.String()))
assert.Equal(t, te.expected, out.String())
}
}
}
@ -222,7 +221,7 @@ func TestContainerStatsContextWriteWithNoStats(t *testing.T) {
for _, context := range contexts {
ContainerStatsWrite(context.context, []StatsEntry{}, "linux", false)
assert.Check(t, is.Equal(context.expected, out.String()))
assert.Equal(t, context.expected, out.String())
// Clean buffer
out.Reset()
}
@ -260,7 +259,7 @@ func TestContainerStatsContextWriteWithNoStatsWindows(t *testing.T) {
for _, context := range contexts {
ContainerStatsWrite(context.context, []StatsEntry{}, "windows", false)
assert.Check(t, is.Equal(context.expected, out.String()))
assert.Equal(t, context.expected, out.String())
// Clean buffer
out.Reset()
}
@ -294,7 +293,7 @@ func TestContainerStatsContextWriteTrunc(t *testing.T) {
for _, context := range contexts {
ContainerStatsWrite(context.context, []StatsEntry{{ID: "b95a83497c9161c9b444e3d70e1a9dfba0c1840d41720e146a95a08ebf938afc"}}, "linux", context.trunc)
assert.Check(t, is.Equal(context.expected, out.String()))
assert.Equal(t, context.expected, out.String())
// Clean buffer
out.Reset()
}

View File

@ -7,9 +7,8 @@ import (
"testing"
"github.com/docker/docker/api/types/swarm"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/gotestyourself/gotestyourself/golden"
"github.com/stretchr/testify/assert"
)
func TestTaskContextWrite(t *testing.T) {
@ -75,9 +74,9 @@ foobar_bar foo2
testcase.context.Output = out
err := TaskWrite(testcase.context, tasks, names, nodes)
if err != nil {
assert.Error(t, err, testcase.expected)
assert.EqualError(t, err, testcase.expected)
} else {
assert.Check(t, is.Equal(testcase.expected, out.String()))
assert.Equal(t, testcase.expected, out.String())
}
}
}
@ -101,6 +100,6 @@ func TestTaskContextWriteJSONField(t *testing.T) {
if err := json.Unmarshal([]byte(line), &s); err != nil {
t.Fatal(err)
}
assert.Check(t, is.Equal(tasks[i].ID, s))
assert.Equal(t, tasks[i].ID, s)
}
}

View File

@ -5,8 +5,7 @@ import (
"testing"
"github.com/docker/docker/pkg/stringid"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/stretchr/testify/assert"
)
func TestTrustTag(t *testing.T) {
@ -127,9 +126,9 @@ tag3 bbbbbbbb
testcase.context.Output = out
err := TrustTagWrite(testcase.context, signedTags)
if err != nil {
assert.Error(t, err, testcase.expected)
assert.EqualError(t, err, testcase.expected)
} else {
assert.Check(t, is.Equal(testcase.expected, out.String()))
assert.Equal(t, testcase.expected, out.String())
}
}
}
@ -153,8 +152,8 @@ func TestTrustTagContextEmptyWrite(t *testing.T) {
out := bytes.NewBufferString("")
emptyCase.context.Output = out
err := TrustTagWrite(emptyCase.context, emptySignedTags)
assert.NilError(t, err)
assert.Check(t, is.Equal(emptyCase.expected, out.String()))
assert.NoError(t, err)
assert.Equal(t, emptyCase.expected, out.String())
}
func TestSignerInfoContextEmptyWrite(t *testing.T) {
@ -172,8 +171,8 @@ func TestSignerInfoContextEmptyWrite(t *testing.T) {
out := bytes.NewBufferString("")
emptyCase.context.Output = out
err := SignerInfoWrite(emptyCase.context, emptySignerInfo)
assert.NilError(t, err)
assert.Check(t, is.Equal(emptyCase.expected, out.String()))
assert.NoError(t, err)
assert.Equal(t, emptyCase.expected, out.String())
}
func TestSignerInfoContextWrite(t *testing.T) {
@ -231,9 +230,9 @@ eve foobarbazquxquux, key31, key32
testcase.context.Output = out
err := SignerInfoWrite(testcase.context, signerInfo)
if err != nil {
assert.Error(t, err, testcase.expected)
assert.EqualError(t, err, testcase.expected)
} else {
assert.Check(t, is.Equal(testcase.expected, out.String()))
assert.Equal(t, testcase.expected, out.String())
}
}
}

View File

@ -9,8 +9,8 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/stringid"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestVolumeContext(t *testing.T) {
@ -133,9 +133,9 @@ foobar_bar
testcase.context.Output = out
err := VolumeWrite(testcase.context, volumes)
if err != nil {
assert.Error(t, err, testcase.expected)
assert.EqualError(t, err, testcase.expected)
} else {
assert.Check(t, is.Equal(testcase.expected, out.String()))
assert.Equal(t, testcase.expected, out.String())
}
}
}
@ -158,8 +158,8 @@ func TestVolumeContextWriteJSON(t *testing.T) {
msg := fmt.Sprintf("Output: line %d: %s", i, line)
var m map[string]interface{}
err := json.Unmarshal([]byte(line), &m)
assert.NilError(t, err, msg)
assert.Check(t, is.DeepEqual(expectedJSONs[i], m), msg)
require.NoError(t, err, msg)
assert.Equal(t, expectedJSONs[i], m, msg)
}
}
@ -177,7 +177,7 @@ func TestVolumeContextWriteJSONField(t *testing.T) {
msg := fmt.Sprintf("Output: line %d: %s", i, line)
var s string
err := json.Unmarshal([]byte(line), &s)
assert.NilError(t, err, msg)
assert.Check(t, is.Equal(volumes[i].Name, s), msg)
require.NoError(t, err, msg)
assert.Equal(t, volumes[i].Name, s, msg)
}
}

View File

@ -4,11 +4,10 @@ import (
"testing"
"github.com/docker/docker/api/types/swarm"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
// Import builders to get the builder function as package function
. "github.com/docker/cli/internal/test/builders"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"golang.org/x/net/context"
)
@ -22,7 +21,7 @@ func TestResolveError(t *testing.T) {
idResolver := New(cli, false)
_, err := idResolver.Resolve(context.Background(), struct{}{}, "nodeID")
assert.Error(t, err, "unsupported type")
assert.EqualError(t, err, "unsupported type")
}
func TestResolveWithNoResolveOption(t *testing.T) {
@ -41,9 +40,9 @@ func TestResolveWithNoResolveOption(t *testing.T) {
idResolver := New(cli, true)
id, err := idResolver.Resolve(context.Background(), swarm.Node{}, "nodeID")
assert.NilError(t, err)
assert.Check(t, is.Equal("nodeID", id))
assert.Check(t, !resolved)
assert.NoError(t, err)
assert.Equal(t, "nodeID", id)
assert.False(t, resolved)
}
func TestResolveWithCache(t *testing.T) {
@ -60,11 +59,11 @@ func TestResolveWithCache(t *testing.T) {
ctx := context.Background()
for i := 0; i < 2; i++ {
id, err := idResolver.Resolve(ctx, swarm.Node{}, "nodeID")
assert.NilError(t, err)
assert.Check(t, is.Equal("node-foo", id))
assert.NoError(t, err)
assert.Equal(t, "node-foo", id)
}
assert.Check(t, is.Equal(1, inspectCounter))
assert.Equal(t, 1, inspectCounter)
}
func TestResolveNode(t *testing.T) {
@ -104,8 +103,8 @@ func TestResolveNode(t *testing.T) {
idResolver := New(cli, false)
id, err := idResolver.Resolve(ctx, swarm.Node{}, tc.nodeID)
assert.NilError(t, err)
assert.Check(t, is.Equal(tc.expectedID, id))
assert.NoError(t, err)
assert.Equal(t, tc.expectedID, id)
}
}
@ -139,7 +138,7 @@ func TestResolveService(t *testing.T) {
idResolver := New(cli, false)
id, err := idResolver.Resolve(ctx, swarm.Service{}, tc.serviceID)
assert.NilError(t, err)
assert.Check(t, is.Equal(tc.expectedID, id))
assert.NoError(t, err)
assert.Equal(t, tc.expectedID, id)
}
}

View File

@ -67,7 +67,6 @@ type buildOptions struct {
imageIDFile string
stream bool
platform string
untrusted bool
}
// dockerfileFromStdin returns true when the user specified that the Dockerfile
@ -138,7 +137,7 @@ func NewBuildCommand(dockerCli command.Cli) *cobra.Command {
flags.StringVar(&options.target, "target", "", "Set the target build stage to build.")
flags.StringVar(&options.imageIDFile, "iidfile", "", "Write the image ID to the file")
command.AddTrustVerificationFlags(flags, &options.untrusted, dockerCli.ContentTrustEnabled())
command.AddTrustVerificationFlags(flags)
command.AddPlatformFlag(flags, &options.platform)
flags.BoolVar(&options.squash, "squash", false, "Squash newly built layers into a single new layer")
@ -286,7 +285,7 @@ func runBuild(dockerCli command.Cli, options buildOptions) error {
defer cancel()
var resolvedTags []*resolvedTag
if !options.untrusted {
if command.IsTrusted() {
translator := func(ctx context.Context, ref reference.NamedTagged) (reference.Canonical, error) {
return TrustedReference(ctx, dockerCli, ref, nil)
}
@ -294,10 +293,10 @@ func runBuild(dockerCli command.Cli, options buildOptions) error {
if buildCtx != nil {
// Wrap the tar archive to replace the Dockerfile entry with the rewritten
// Dockerfile which uses trusted pulls.
buildCtx = replaceDockerfileForContentTrust(ctx, buildCtx, relDockerfile, translator, &resolvedTags)
buildCtx = replaceDockerfileTarWrapper(ctx, buildCtx, relDockerfile, translator, &resolvedTags)
} else if dockerfileCtx != nil {
// if there was not archive context still do the possible replacements in Dockerfile
newDockerfile, _, err := rewriteDockerfileFromForContentTrust(ctx, dockerfileCtx, translator)
newDockerfile, _, err := rewriteDockerfileFrom(ctx, dockerfileCtx, translator)
if err != nil {
return err
}
@ -461,7 +460,7 @@ func runBuild(dockerCli command.Cli, options buildOptions) error {
return err
}
}
if !options.untrusted {
if command.IsTrusted() {
// Since the build was successful, now we must tag any of the resolved
// images from the above Dockerfile rewrite.
for _, resolved := range resolvedTags {
@ -500,12 +499,11 @@ type resolvedTag struct {
tagRef reference.NamedTagged
}
// rewriteDockerfileFromForContentTrust rewrites the given Dockerfile by resolving images in
// rewriteDockerfileFrom rewrites the given Dockerfile by resolving images in
// "FROM <image>" instructions to a digest reference. `translator` is a
// function that takes a repository name and tag reference and returns a
// trusted digest reference.
// This should be called *only* when content trust is enabled
func rewriteDockerfileFromForContentTrust(ctx context.Context, dockerfile io.Reader, translator translatorFunc) (newDockerfile []byte, resolvedTags []*resolvedTag, err error) {
func rewriteDockerfileFrom(ctx context.Context, dockerfile io.Reader, translator translatorFunc) (newDockerfile []byte, resolvedTags []*resolvedTag, err error) {
scanner := bufio.NewScanner(dockerfile)
buf := bytes.NewBuffer(nil)
@ -522,7 +520,7 @@ func rewriteDockerfileFromForContentTrust(ctx context.Context, dockerfile io.Rea
return nil, nil, err
}
ref = reference.TagNameOnly(ref)
if ref, ok := ref.(reference.NamedTagged); ok {
if ref, ok := ref.(reference.NamedTagged); ok && command.IsTrusted() {
trustedRef, err := translator(ctx, ref)
if err != nil {
return nil, nil, err
@ -545,10 +543,11 @@ func rewriteDockerfileFromForContentTrust(ctx context.Context, dockerfile io.Rea
return buf.Bytes(), resolvedTags, scanner.Err()
}
// replaceDockerfileForContentTrust wraps the given input tar archive stream and
// uses the translator to replace the Dockerfile which uses a trusted reference.
// Returns a new tar archive stream with the replaced Dockerfile.
func replaceDockerfileForContentTrust(ctx context.Context, inputTarStream io.ReadCloser, dockerfileName string, translator translatorFunc, resolvedTags *[]*resolvedTag) io.ReadCloser {
// replaceDockerfileTarWrapper wraps the given input tar archive stream and
// replaces the entry with the given Dockerfile name with the contents of the
// new Dockerfile. Returns a new tar archive stream with the replaced
// Dockerfile.
func replaceDockerfileTarWrapper(ctx context.Context, inputTarStream io.ReadCloser, dockerfileName string, translator translatorFunc, resolvedTags *[]*resolvedTag) io.ReadCloser {
pipeReader, pipeWriter := io.Pipe()
go func() {
tarReader := tar.NewReader(inputTarStream)
@ -575,7 +574,7 @@ func replaceDockerfileForContentTrust(ctx context.Context, inputTarStream io.Rea
// generated from a directory on the local filesystem, the
// Dockerfile will only appear once in the archive.
var newDockerfile []byte
newDockerfile, *resolvedTags, err = rewriteDockerfileFromForContentTrust(ctx, content, translator)
newDockerfile, *resolvedTags, err = rewriteDockerfileFrom(ctx, content, translator)
if err != nil {
pipeWriter.CloseWithError(err)
return

View File

@ -11,9 +11,10 @@ import (
"strings"
"testing"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/docker/pkg/archive"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
const dockerfileContents = "FROM busybox"
@ -37,7 +38,7 @@ func testValidateContextDirectory(t *testing.T, prepare func(t *testing.T) (stri
defer cleanup()
err := ValidateContextDirectory(contextDir, excludes)
assert.NilError(t, err)
require.NoError(t, err)
}
func TestGetContextFromLocalDirNoDockerfile(t *testing.T) {
@ -45,7 +46,7 @@ func TestGetContextFromLocalDirNoDockerfile(t *testing.T) {
defer cleanup()
_, _, err := GetContextFromLocalDir(contextDir, "")
assert.ErrorContains(t, err, "Dockerfile")
testutil.ErrorContains(t, err, "Dockerfile")
}
func TestGetContextFromLocalDirNotExistingDir(t *testing.T) {
@ -55,7 +56,7 @@ func TestGetContextFromLocalDirNotExistingDir(t *testing.T) {
fakePath := filepath.Join(contextDir, "fake")
_, _, err := GetContextFromLocalDir(fakePath, "")
assert.ErrorContains(t, err, "fake")
testutil.ErrorContains(t, err, "fake")
}
func TestGetContextFromLocalDirNotExistingDockerfile(t *testing.T) {
@ -65,7 +66,7 @@ func TestGetContextFromLocalDirNotExistingDockerfile(t *testing.T) {
fakePath := filepath.Join(contextDir, "fake")
_, _, err := GetContextFromLocalDir(contextDir, fakePath)
assert.ErrorContains(t, err, "fake")
testutil.ErrorContains(t, err, "fake")
}
func TestGetContextFromLocalDirWithNoDirectory(t *testing.T) {
@ -78,10 +79,10 @@ func TestGetContextFromLocalDirWithNoDirectory(t *testing.T) {
defer chdirCleanup()
absContextDir, relDockerfile, err := GetContextFromLocalDir(contextDir, "")
assert.NilError(t, err)
require.NoError(t, err)
assert.Check(t, is.Equal(contextDir, absContextDir))
assert.Check(t, is.Equal(DefaultDockerfileName, relDockerfile))
assert.Equal(t, contextDir, absContextDir)
assert.Equal(t, DefaultDockerfileName, relDockerfile)
}
func TestGetContextFromLocalDirWithDockerfile(t *testing.T) {
@ -91,10 +92,10 @@ func TestGetContextFromLocalDirWithDockerfile(t *testing.T) {
createTestTempFile(t, contextDir, DefaultDockerfileName, dockerfileContents, 0777)
absContextDir, relDockerfile, err := GetContextFromLocalDir(contextDir, "")
assert.NilError(t, err)
require.NoError(t, err)
assert.Check(t, is.Equal(contextDir, absContextDir))
assert.Check(t, is.Equal(DefaultDockerfileName, relDockerfile))
assert.Equal(t, contextDir, absContextDir)
assert.Equal(t, DefaultDockerfileName, relDockerfile)
}
func TestGetContextFromLocalDirLocalFile(t *testing.T) {
@ -129,10 +130,10 @@ func TestGetContextFromLocalDirWithCustomDockerfile(t *testing.T) {
createTestTempFile(t, contextDir, DefaultDockerfileName, dockerfileContents, 0777)
absContextDir, relDockerfile, err := GetContextFromLocalDir(contextDir, DefaultDockerfileName)
assert.NilError(t, err)
require.NoError(t, err)
assert.Check(t, is.Equal(contextDir, absContextDir))
assert.Check(t, is.Equal(DefaultDockerfileName, relDockerfile))
assert.Equal(t, contextDir, absContextDir)
assert.Equal(t, DefaultDockerfileName, relDockerfile)
}
func TestGetContextFromReaderString(t *testing.T) {
@ -160,7 +161,7 @@ func TestGetContextFromReaderString(t *testing.T) {
t.Fatalf("Tar stream too long: %s", err)
}
assert.NilError(t, tarArchive.Close())
require.NoError(t, tarArchive.Close())
if dockerfileContents != contents {
t.Fatalf("Uncompressed tar archive does not equal: %s, got: %s", dockerfileContents, contents)
@ -178,15 +179,15 @@ func TestGetContextFromReaderTar(t *testing.T) {
createTestTempFile(t, contextDir, DefaultDockerfileName, dockerfileContents, 0777)
tarStream, err := archive.Tar(contextDir, archive.Uncompressed)
assert.NilError(t, err)
require.NoError(t, err)
tarArchive, relDockerfile, err := GetContextFromReader(tarStream, DefaultDockerfileName)
assert.NilError(t, err)
require.NoError(t, err)
tarReader := tar.NewReader(tarArchive)
header, err := tarReader.Next()
assert.NilError(t, err)
require.NoError(t, err)
if header.Name != DefaultDockerfileName {
t.Fatalf("Dockerfile name should be: %s, got: %s", DefaultDockerfileName, header.Name)
@ -202,7 +203,7 @@ func TestGetContextFromReaderTar(t *testing.T) {
t.Fatalf("Tar stream too long: %s", err)
}
assert.NilError(t, tarArchive.Close())
require.NoError(t, tarArchive.Close())
if dockerfileContents != contents {
t.Fatalf("Uncompressed tar archive does not equal: %s, got: %s", dockerfileContents, contents)
@ -242,8 +243,8 @@ func TestValidateContextDirectoryWithOneFileExcludes(t *testing.T) {
// When an error occurs, it terminates the test.
func createTestTempDir(t *testing.T, dir, prefix string) (string, func()) {
path, err := ioutil.TempDir(dir, prefix)
assert.NilError(t, err)
return path, func() { assert.NilError(t, os.RemoveAll(path)) }
require.NoError(t, err)
return path, func() { require.NoError(t, os.RemoveAll(path)) }
}
// createTestTempFile creates a temporary file within dir with specific contents and permissions.
@ -251,7 +252,7 @@ func createTestTempDir(t *testing.T, dir, prefix string) (string, func()) {
func createTestTempFile(t *testing.T, dir, filename, contents string, perm os.FileMode) string {
filePath := filepath.Join(dir, filename)
err := ioutil.WriteFile(filePath, []byte(contents), perm)
assert.NilError(t, err)
require.NoError(t, err)
return filePath
}
@ -261,9 +262,9 @@ func createTestTempFile(t *testing.T, dir, filename, contents string, perm os.Fi
// When an error occurs, it terminates the test.
func chdir(t *testing.T, dir string) func() {
workingDirectory, err := os.Getwd()
assert.NilError(t, err)
assert.NilError(t, os.Chdir(dir))
return func() { assert.NilError(t, os.Chdir(workingDirectory)) }
require.NoError(t, err)
require.NoError(t, os.Chdir(dir))
return func() { require.NoError(t, os.Chdir(workingDirectory)) }
}
func TestIsArchive(t *testing.T) {
@ -294,6 +295,6 @@ func TestIsArchive(t *testing.T) {
},
}
for _, testcase := range testcases {
assert.Check(t, is.Equal(testcase.expected, IsArchive(testcase.header)), testcase.doc)
assert.Equal(t, testcase.expected, IsArchive(testcase.header), testcase.doc)
}
}

View File

@ -1,66 +1,39 @@
package image
import (
"archive/tar"
"bytes"
"compress/gzip"
"io"
"io/ioutil"
"os"
"path/filepath"
"runtime"
"sort"
"syscall"
"testing"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/archive"
"github.com/google/go-cmp/cmp"
"github.com/gotestyourself/gotestyourself/assert"
"github.com/gotestyourself/gotestyourself/fs"
"github.com/gotestyourself/gotestyourself/skip"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/net/context"
)
func TestRunBuildDockerfileFromStdinWithCompress(t *testing.T) {
buffer := new(bytes.Buffer)
fakeBuild := newFakeBuild()
fakeImageBuild := func(ctx context.Context, context io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error) {
tee := io.TeeReader(context, buffer)
gzipReader, err := gzip.NewReader(tee)
assert.NilError(t, err)
return fakeBuild.build(ctx, gzipReader, options)
}
cli := test.NewFakeCli(&fakeClient{imageBuildFunc: fakeImageBuild})
dockerfile := bytes.NewBufferString(`
FROM alpine:3.6
COPY foo /
`)
cli.SetIn(command.NewInStream(ioutil.NopCloser(dockerfile)))
dir := fs.NewDir(t, t.Name(),
fs.WithFile("foo", "some content"))
defer dir.Remove()
options := newBuildOptions()
options.compress = true
options.dockerfileName = "-"
options.context = dir.Path()
options.untrusted = true
assert.NilError(t, runBuild(cli, options))
expected := []string{fakeBuild.options.Dockerfile, ".dockerignore", "foo"}
assert.DeepEqual(t, expected, fakeBuild.filenames(t))
header := buffer.Bytes()[:10]
assert.Equal(t, archive.Gzip, archive.DetectCompression(header))
}
func TestRunBuildResetsUidAndGidInContext(t *testing.T) {
skip.If(t, os.Getuid() != 0, "root is required to chown files")
fakeBuild := newFakeBuild()
cli := test.NewFakeCli(&fakeClient{imageBuildFunc: fakeBuild.build})
skip.IfCondition(t, runtime.GOOS == "windows", "uid and gid not relevant on windows")
dest := fs.NewDir(t, "test-build-context-dest")
defer dest.Remove()
fakeImageBuild := func(_ context.Context, context io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error) {
assert.NoError(t, archive.Untar(context, dest.Path(), nil))
body := new(bytes.Buffer)
return types.ImageBuildResponse{Body: ioutil.NopCloser(body)}, nil
}
cli := test.NewFakeCli(&fakeClient{imageBuildFunc: fakeImageBuild})
dir := fs.NewDir(t, "test-build-context",
fs.WithFile("foo", "some content", fs.AsUser(65534, 65534)),
@ -73,23 +46,72 @@ func TestRunBuildResetsUidAndGidInContext(t *testing.T) {
options := newBuildOptions()
options.context = dir.Path()
options.untrusted = true
assert.NilError(t, runBuild(cli, options))
headers := fakeBuild.headers(t)
expected := []*tar.Header{
{Name: "Dockerfile"},
{Name: "foo"},
err := runBuild(cli, options)
require.NoError(t, err)
files, err := ioutil.ReadDir(dest.Path())
require.NoError(t, err)
for _, fileInfo := range files {
assert.Equal(t, uint32(0), fileInfo.Sys().(*syscall.Stat_t).Uid)
assert.Equal(t, uint32(0), fileInfo.Sys().(*syscall.Stat_t).Gid)
}
var cmpTarHeaderNameAndOwner = cmp.Comparer(func(x, y tar.Header) bool {
return x.Name == y.Name && x.Uid == y.Uid && x.Gid == y.Gid
})
assert.DeepEqual(t, expected, headers, cmpTarHeaderNameAndOwner)
}
func TestRunBuildDockerfileFromStdinWithCompress(t *testing.T) {
dest, err := ioutil.TempDir("", "test-build-compress-dest")
require.NoError(t, err)
defer os.RemoveAll(dest)
var dockerfileName string
fakeImageBuild := func(_ context.Context, context io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error) {
buffer := new(bytes.Buffer)
tee := io.TeeReader(context, buffer)
assert.NoError(t, archive.Untar(tee, dest, nil))
dockerfileName = options.Dockerfile
header := buffer.Bytes()[:10]
assert.Equal(t, archive.Gzip, archive.DetectCompression(header))
body := new(bytes.Buffer)
return types.ImageBuildResponse{Body: ioutil.NopCloser(body)}, nil
}
cli := test.NewFakeCli(&fakeClient{imageBuildFunc: fakeImageBuild})
dockerfile := bytes.NewBufferString(`
FROM alpine:3.6
COPY foo /
`)
cli.SetIn(command.NewInStream(ioutil.NopCloser(dockerfile)))
dir, err := ioutil.TempDir("", "test-build-compress")
require.NoError(t, err)
defer os.RemoveAll(dir)
ioutil.WriteFile(filepath.Join(dir, "foo"), []byte("some content"), 0644)
options := newBuildOptions()
options.compress = true
options.dockerfileName = "-"
options.context = dir
err = runBuild(cli, options)
require.NoError(t, err)
files, err := ioutil.ReadDir(dest)
require.NoError(t, err)
actual := []string{}
for _, fileInfo := range files {
actual = append(actual, fileInfo.Name())
}
sort.Strings(actual)
assert.Equal(t, []string{dockerfileName, ".dockerignore", "foo"}, actual)
}
func TestRunBuildDockerfileOutsideContext(t *testing.T) {
dir := fs.NewDir(t, t.Name(),
fs.WithFile("data", "data file"))
fs.WithFile("data", "data file"),
)
defer dir.Remove()
// Dockerfile outside of build-context
@ -101,32 +123,51 @@ COPY data /data
)
defer df.Remove()
fakeBuild := newFakeBuild()
cli := test.NewFakeCli(&fakeClient{imageBuildFunc: fakeBuild.build})
dest, err := ioutil.TempDir("", t.Name())
require.NoError(t, err)
defer os.RemoveAll(dest)
var dockerfileName string
fakeImageBuild := func(_ context.Context, context io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error) {
buffer := new(bytes.Buffer)
tee := io.TeeReader(context, buffer)
assert.NoError(t, archive.Untar(tee, dest, nil))
dockerfileName = options.Dockerfile
body := new(bytes.Buffer)
return types.ImageBuildResponse{Body: ioutil.NopCloser(body)}, nil
}
cli := test.NewFakeCli(&fakeClient{imageBuildFunc: fakeImageBuild})
options := newBuildOptions()
options.context = dir.Path()
options.dockerfileName = df.Path()
options.untrusted = true
assert.NilError(t, runBuild(cli, options))
expected := []string{fakeBuild.options.Dockerfile, ".dockerignore", "data"}
assert.DeepEqual(t, expected, fakeBuild.filenames(t))
err = runBuild(cli, options)
require.NoError(t, err)
files, err := ioutil.ReadDir(dest)
require.NoError(t, err)
var actual []string
for _, fileInfo := range files {
actual = append(actual, fileInfo.Name())
}
sort.Strings(actual)
assert.Equal(t, []string{dockerfileName, ".dockerignore", "data"}, actual)
}
// TestRunBuildFromLocalGitHubDirNonExistingRepo tests that build contexts
// starting with `github.com/` are special-cased, and the build command attempts
// to clone the remote repo.
// TODO: test "context selection" logic directly when runBuild is refactored
// to support testing (ex: docker/cli#294)
func TestRunBuildFromGitHubSpecialCase(t *testing.T) {
cmd := NewBuildCommand(test.NewFakeCli(nil))
// Clone a small repo that exists so git doesn't prompt for credentials
cmd.SetArgs([]string{"github.com/docker/for-win"})
cmd.SetArgs([]string{"github.com/docker/no-such-repository"})
cmd.SetOutput(ioutil.Discard)
err := cmd.Execute()
assert.ErrorContains(t, err, "unable to prepare context")
assert.ErrorContains(t, err, "docker-build-git")
assert.Error(t, err)
assert.Contains(t, err.Error(), "unable to prepare context: unable to 'git clone'")
}
// TestRunBuildFromLocalGitHubDirNonExistingRepo tests that a local directory
@ -134,83 +175,19 @@ func TestRunBuildFromGitHubSpecialCase(t *testing.T) {
// case.
func TestRunBuildFromLocalGitHubDir(t *testing.T) {
tmpDir, err := ioutil.TempDir("", "docker-build-from-local-dir-")
assert.NilError(t, err)
require.NoError(t, err)
defer os.RemoveAll(tmpDir)
buildDir := filepath.Join(tmpDir, "github.com", "docker", "no-such-repository")
err = os.MkdirAll(buildDir, 0777)
assert.NilError(t, err)
require.NoError(t, err)
err = ioutil.WriteFile(filepath.Join(buildDir, "Dockerfile"), []byte("FROM busybox\n"), 0644)
assert.NilError(t, err)
require.NoError(t, err)
client := test.NewFakeCli(&fakeClient{})
cmd := NewBuildCommand(client)
cmd.SetArgs([]string{buildDir})
cmd.SetOutput(ioutil.Discard)
err = cmd.Execute()
assert.NilError(t, err)
}
func TestRunBuildWithSymlinkedContext(t *testing.T) {
dockerfile := `
FROM alpine:3.6
RUN echo hello world
`
tmpDir := fs.NewDir(t, t.Name(),
fs.WithDir("context",
fs.WithFile("Dockerfile", dockerfile)),
fs.WithSymlink("context-link", "context"))
defer tmpDir.Remove()
fakeBuild := newFakeBuild()
cli := test.NewFakeCli(&fakeClient{imageBuildFunc: fakeBuild.build})
options := newBuildOptions()
options.context = tmpDir.Join("context-link")
options.untrusted = true
assert.NilError(t, runBuild(cli, options))
assert.DeepEqual(t, fakeBuild.filenames(t), []string{"Dockerfile"})
}
type fakeBuild struct {
context *tar.Reader
options types.ImageBuildOptions
}
func newFakeBuild() *fakeBuild {
return &fakeBuild{}
}
func (f *fakeBuild) build(_ context.Context, context io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error) {
f.context = tar.NewReader(context)
f.options = options
body := new(bytes.Buffer)
return types.ImageBuildResponse{Body: ioutil.NopCloser(body)}, nil
}
func (f *fakeBuild) headers(t *testing.T) []*tar.Header {
t.Helper()
headers := []*tar.Header{}
for {
hdr, err := f.context.Next()
switch err {
case io.EOF:
return headers
case nil:
headers = append(headers, hdr)
default:
assert.NilError(t, err)
}
}
}
func (f *fakeBuild) filenames(t *testing.T) []string {
t.Helper()
names := []string{}
for _, header := range f.headers(t) {
names = append(names, header.Name)
}
sort.Strings(names)
return names
require.NoError(t, err)
}

View File

@ -7,11 +7,11 @@ import (
"time"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/docker/api/types/image"
"github.com/gotestyourself/gotestyourself/assert"
"github.com/gotestyourself/gotestyourself/golden"
"github.com/gotestyourself/gotestyourself/skip"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
)
func TestNewHistoryCommandErrors(t *testing.T) {
@ -39,20 +39,15 @@ func TestNewHistoryCommandErrors(t *testing.T) {
cmd := NewHistoryCommand(test.NewFakeCli(&fakeClient{imageHistoryFunc: tc.imageHistoryFunc}))
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs(tc.args)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
func notUTCTimezone() bool {
now := time.Now()
return now != now.UTC()
}
func TestNewHistoryCommandSuccess(t *testing.T) {
skip.If(t, notUTCTimezone, "expected output requires UTC timezone")
testCases := []struct {
name string
args []string
outputRegex string
imageHistoryFunc func(img string) ([]image.HistoryResponseItem, error)
}{
{
@ -69,17 +64,16 @@ func TestNewHistoryCommandSuccess(t *testing.T) {
name: "quiet",
args: []string{"--quiet", "image:tag"},
},
// TODO: This test is failing since the output does not contain an RFC3339 date
//{
// name: "non-human",
// args: []string{"--human=false", "image:tag"},
// outputRegex: "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}", // RFC3339 date format match
//},
{
name: "non-human",
args: []string{"--human=false", "image:tag"},
imageHistoryFunc: func(img string) ([]image.HistoryResponseItem, error) {
return []image.HistoryResponseItem{{
ID: "abcdef",
Created: time.Date(2017, 1, 1, 12, 0, 3, 0, time.UTC).Unix(),
CreatedBy: "rose",
Comment: "new history item!",
}}, nil
},
name: "non-human-header",
args: []string{"--human=false", "image:tag"},
outputRegex: "CREATED\\sAT",
},
{
name: "quiet-no-trunc",
@ -98,8 +92,12 @@ func TestNewHistoryCommandSuccess(t *testing.T) {
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs(tc.args)
err := cmd.Execute()
assert.NilError(t, err)
assert.NoError(t, err)
actual := cli.OutBuffer().String()
golden.Assert(t, actual, fmt.Sprintf("history-command-success.%s.golden", tc.name))
if tc.outputRegex == "" {
golden.Assert(t, actual, fmt.Sprintf("history-command-success.%s.golden", tc.name))
} else {
assert.Regexp(t, tc.outputRegex, actual)
}
}
}

View File

@ -7,10 +7,10 @@ import (
"testing"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/docker/api/types"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
)
func TestNewImportCommandErrors(t *testing.T) {
@ -38,7 +38,7 @@ func TestNewImportCommandErrors(t *testing.T) {
cmd := NewImportCommand(test.NewFakeCli(&fakeClient{imageImportFunc: tc.imageImportFunc}))
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs(tc.args)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
@ -46,7 +46,7 @@ func TestNewImportCommandInvalidFile(t *testing.T) {
cmd := NewImportCommand(test.NewFakeCli(&fakeClient{}))
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs([]string{"testdata/import-command-success.unexistent-file"})
assert.ErrorContains(t, cmd.Execute(), "testdata/import-command-success.unexistent-file")
testutil.ErrorContains(t, cmd.Execute(), "testdata/import-command-success.unexistent-file")
}
func TestNewImportCommandSuccess(t *testing.T) {
@ -67,7 +67,7 @@ func TestNewImportCommandSuccess(t *testing.T) {
name: "double",
args: []string{"-", "image:local"},
imageImportFunc: func(source types.ImageImportSource, ref string, options types.ImageImportOptions) (io.ReadCloser, error) {
assert.Check(t, is.Equal("image:local", ref))
assert.Equal(t, "image:local", ref)
return ioutil.NopCloser(strings.NewReader("")), nil
},
},
@ -75,7 +75,7 @@ func TestNewImportCommandSuccess(t *testing.T) {
name: "message",
args: []string{"--message", "test message", "-"},
imageImportFunc: func(source types.ImageImportSource, ref string, options types.ImageImportOptions) (io.ReadCloser, error) {
assert.Check(t, is.Equal("test message", options.Message))
assert.Equal(t, "test message", options.Message)
return ioutil.NopCloser(strings.NewReader("")), nil
},
},
@ -83,7 +83,7 @@ func TestNewImportCommandSuccess(t *testing.T) {
name: "change",
args: []string{"--change", "ENV DEBUG true", "-"},
imageImportFunc: func(source types.ImageImportSource, ref string, options types.ImageImportOptions) (io.ReadCloser, error) {
assert.Check(t, is.Equal("ENV DEBUG true", options.Changes[0]))
assert.Equal(t, "ENV DEBUG true", options.Changes[0])
return ioutil.NopCloser(strings.NewReader("")), nil
},
},
@ -92,6 +92,6 @@ func TestNewImportCommandSuccess(t *testing.T) {
cmd := NewImportCommand(test.NewFakeCli(&fakeClient{imageImportFunc: tc.imageImportFunc}))
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs(tc.args)
assert.NilError(t, cmd.Execute())
assert.NoError(t, cmd.Execute())
}
}

View File

@ -6,10 +6,10 @@ import (
"testing"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/docker/api/types"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/gotestyourself/gotestyourself/golden"
"github.com/stretchr/testify/assert"
)
func TestNewInspectCommandErrors(t *testing.T) {
@ -28,7 +28,7 @@ func TestNewInspectCommandErrors(t *testing.T) {
cmd := newInspectCommand(test.NewFakeCli(&fakeClient{}))
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs(tc.args)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
@ -46,7 +46,7 @@ func TestNewInspectCommandSuccess(t *testing.T) {
imageCount: 1,
imageInspectFunc: func(image string) (types.ImageInspect, []byte, error) {
imageInspectInvocationCount++
assert.Check(t, is.Equal("image", image))
assert.Equal(t, "image", image)
return types.ImageInspect{}, nil, nil
},
},
@ -66,9 +66,9 @@ func TestNewInspectCommandSuccess(t *testing.T) {
imageInspectFunc: func(image string) (types.ImageInspect, []byte, error) {
imageInspectInvocationCount++
if imageInspectInvocationCount == 1 {
assert.Check(t, is.Equal("image1", image))
assert.Equal(t, "image1", image)
} else {
assert.Check(t, is.Equal("image2", image))
assert.Equal(t, "image2", image)
}
return types.ImageInspect{}, nil, nil
},
@ -81,8 +81,8 @@ func TestNewInspectCommandSuccess(t *testing.T) {
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs(tc.args)
err := cmd.Execute()
assert.NilError(t, err)
assert.NoError(t, err)
golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("inspect-command-success.%s.golden", tc.name))
assert.Check(t, is.Equal(imageInspectInvocationCount, tc.imageCount))
assert.Equal(t, imageInspectInvocationCount, tc.imageCount)
}
}

View File

@ -7,11 +7,11 @@ import (
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/docker/api/types"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/gotestyourself/gotestyourself/golden"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
)
func TestNewImagesCommandErrors(t *testing.T) {
@ -38,7 +38,7 @@ func TestNewImagesCommandErrors(t *testing.T) {
cmd := NewImagesCommand(test.NewFakeCli(&fakeClient{imageListFunc: tc.imageListFunc}))
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs(tc.args)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
@ -65,7 +65,7 @@ func TestNewImagesCommandSuccess(t *testing.T) {
name: "match-name",
args: []string{"image"},
imageListFunc: func(options types.ImageListOptions) ([]types.ImageSummary, error) {
assert.Check(t, is.Equal("image", options.Filters.Get("reference")[0]))
assert.Equal(t, "image", options.Filters.Get("reference")[0])
return []types.ImageSummary{{}}, nil
},
},
@ -73,7 +73,7 @@ func TestNewImagesCommandSuccess(t *testing.T) {
name: "filters",
args: []string{"--filter", "name=value"},
imageListFunc: func(options types.ImageListOptions) ([]types.ImageSummary, error) {
assert.Check(t, is.Equal("value", options.Filters.Get("name")[0]))
assert.Equal(t, "value", options.Filters.Get("name")[0])
return []types.ImageSummary{{}}, nil
},
},
@ -85,14 +85,14 @@ func TestNewImagesCommandSuccess(t *testing.T) {
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs(tc.args)
err := cmd.Execute()
assert.NilError(t, err)
assert.NoError(t, err)
golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("list-command-success.%s.golden", tc.name))
}
}
func TestNewListCommandAlias(t *testing.T) {
cmd := newListCommand(test.NewFakeCli(&fakeClient{}))
assert.Check(t, cmd.HasAlias("images"))
assert.Check(t, cmd.HasAlias("list"))
assert.Check(t, !cmd.HasAlias("other"))
assert.True(t, cmd.HasAlias("images"))
assert.True(t, cmd.HasAlias("list"))
assert.False(t, cmd.HasAlias("other"))
}

View File

@ -8,10 +8,11 @@ import (
"testing"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/docker/api/types"
"github.com/gotestyourself/gotestyourself/assert"
"github.com/gotestyourself/gotestyourself/golden"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
)
func TestNewLoadCommandErrors(t *testing.T) {
@ -46,7 +47,7 @@ func TestNewLoadCommandErrors(t *testing.T) {
cmd := NewLoadCommand(cli)
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs(tc.args)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
@ -56,7 +57,7 @@ func TestNewLoadCommandInvalidInput(t *testing.T) {
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs([]string{"--input", "*"})
err := cmd.Execute()
assert.ErrorContains(t, err, expectedError)
testutil.ErrorContains(t, err, expectedError)
}
func TestNewLoadCommandSuccess(t *testing.T) {
@ -95,7 +96,7 @@ func TestNewLoadCommandSuccess(t *testing.T) {
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs(tc.args)
err := cmd.Execute()
assert.NilError(t, err)
assert.NoError(t, err)
golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("load-command-success.%s.golden", tc.name))
}
}

View File

@ -6,12 +6,12 @@ import (
"testing"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/gotestyourself/gotestyourself/golden"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
)
func TestNewPruneCommandErrors(t *testing.T) {
@ -41,7 +41,7 @@ func TestNewPruneCommandErrors(t *testing.T) {
}))
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs(tc.args)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
@ -55,7 +55,7 @@ func TestNewPruneCommandSuccess(t *testing.T) {
name: "all",
args: []string{"--all"},
imagesPruneFunc: func(pruneFilter filters.Args) (types.ImagesPruneReport, error) {
assert.Check(t, is.Equal("false", pruneFilter.Get("dangling")[0]))
assert.Equal(t, "false", pruneFilter.Get("dangling")[0])
return types.ImagesPruneReport{}, nil
},
},
@ -63,7 +63,7 @@ func TestNewPruneCommandSuccess(t *testing.T) {
name: "force-deleted",
args: []string{"--force"},
imagesPruneFunc: func(pruneFilter filters.Args) (types.ImagesPruneReport, error) {
assert.Check(t, is.Equal("true", pruneFilter.Get("dangling")[0]))
assert.Equal(t, "true", pruneFilter.Get("dangling")[0])
return types.ImagesPruneReport{
ImagesDeleted: []types.ImageDeleteResponseItem{{Deleted: "image1"}},
SpaceReclaimed: 1,
@ -74,7 +74,7 @@ func TestNewPruneCommandSuccess(t *testing.T) {
name: "force-untagged",
args: []string{"--force"},
imagesPruneFunc: func(pruneFilter filters.Args) (types.ImagesPruneReport, error) {
assert.Check(t, is.Equal("true", pruneFilter.Get("dangling")[0]))
assert.Equal(t, "true", pruneFilter.Get("dangling")[0])
return types.ImagesPruneReport{
ImagesDeleted: []types.ImageDeleteResponseItem{{Untagged: "image1"}},
SpaceReclaimed: 2,
@ -88,7 +88,7 @@ func TestNewPruneCommandSuccess(t *testing.T) {
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs(tc.args)
err := cmd.Execute()
assert.NilError(t, err)
assert.NoError(t, err)
golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("prune-command-success.%s.golden", tc.name))
}
}

View File

@ -14,10 +14,9 @@ import (
)
type pullOptions struct {
remote string
all bool
platform string
untrusted bool
remote string
all bool
platform string
}
// NewPullCommand creates a new `docker pull` command
@ -39,7 +38,7 @@ func NewPullCommand(dockerCli command.Cli) *cobra.Command {
flags.BoolVarP(&opts.all, "all-tags", "a", false, "Download all tagged images in the repository")
command.AddPlatformFlag(flags, &opts.platform)
command.AddTrustVerificationFlags(flags, &opts.untrusted, dockerCli.ContentTrustEnabled())
command.AddTrustVerificationFlags(flags)
return cmd
}
@ -59,14 +58,14 @@ func runPull(cli command.Cli, opts pullOptions) error {
}
ctx := context.Background()
imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, nil, AuthResolver(cli), distributionRef.String())
imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, AuthResolver(cli), distributionRef.String())
if err != nil {
return err
}
// Check if reference has a digest
_, isCanonical := distributionRef.(reference.Canonical)
if !opts.untrusted && !isCanonical {
if command.IsTrusted() && !isCanonical {
err = trustedPull(ctx, cli, imgRefAndAuth, opts.platform)
} else {
err = imagePullPrivileged(ctx, cli, imgRefAndAuth, opts.all, opts.platform)

View File

@ -8,11 +8,10 @@ import (
"testing"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/notary"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/docker/api/types"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/gotestyourself/gotestyourself/golden"
"github.com/stretchr/testify/assert"
)
func TestNewPullCommandErrors(t *testing.T) {
@ -42,7 +41,7 @@ func TestNewPullCommandErrors(t *testing.T) {
cmd := NewPullCommand(cli)
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs(tc.args)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
@ -66,7 +65,7 @@ func TestNewPullCommandSuccess(t *testing.T) {
for _, tc := range testCases {
cli := test.NewFakeCli(&fakeClient{
imagePullFunc: func(ref string, options types.ImagePullOptions) (io.ReadCloser, error) {
assert.Check(t, is.Equal(tc.expectedTag, ref), tc.name)
assert.Equal(t, tc.expectedTag, ref, tc.name)
return ioutil.NopCloser(strings.NewReader("")), nil
},
})
@ -74,48 +73,7 @@ func TestNewPullCommandSuccess(t *testing.T) {
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs(tc.args)
err := cmd.Execute()
assert.NilError(t, err)
assert.NoError(t, err)
golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("pull-command-success.%s.golden", tc.name))
}
}
func TestNewPullCommandWithContentTrustErrors(t *testing.T) {
testCases := []struct {
name string
args []string
expectedError string
notaryFunc test.NotaryClientFuncType
}{
{
name: "offline-notary-server",
notaryFunc: notary.GetOfflineNotaryRepository,
expectedError: "client is offline",
args: []string{"image:tag"},
},
{
name: "uninitialized-notary-server",
notaryFunc: notary.GetUninitializedNotaryRepository,
expectedError: "remote trust data does not exist",
args: []string{"image:tag"},
},
{
name: "empty-notary-server",
notaryFunc: notary.GetEmptyTargetsNotaryRepository,
expectedError: "No valid trust data for tag",
args: []string{"image:tag"},
},
}
for _, tc := range testCases {
cli := test.NewFakeCli(&fakeClient{
imagePullFunc: func(ref string, options types.ImagePullOptions) (io.ReadCloser, error) {
return ioutil.NopCloser(strings.NewReader("")), fmt.Errorf("shouldn't try to pull image")
},
}, test.EnableContentTrust)
cli.SetNotaryClient(tc.notaryFunc)
cmd := NewPullCommand(cli)
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs(tc.args)
err := cmd.Execute()
assert.ErrorContains(t, err, tc.expectedError)
}
}

View File

@ -11,34 +11,26 @@ import (
"github.com/spf13/cobra"
)
type pushOptions struct {
remote string
untrusted bool
}
// NewPushCommand creates a new `docker push` command
func NewPushCommand(dockerCli command.Cli) *cobra.Command {
var opts pushOptions
cmd := &cobra.Command{
Use: "push [OPTIONS] NAME[:TAG]",
Short: "Push an image or a repository to a registry",
Args: cli.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
opts.remote = args[0]
return runPush(dockerCli, opts)
return runPush(dockerCli, args[0])
},
}
flags := cmd.Flags()
command.AddTrustSigningFlags(flags, &opts.untrusted, dockerCli.ContentTrustEnabled())
command.AddTrustSigningFlags(flags)
return cmd
}
func runPush(dockerCli command.Cli, opts pushOptions) error {
ref, err := reference.ParseNormalizedNamed(opts.remote)
func runPush(dockerCli command.Cli, remote string) error {
ref, err := reference.ParseNormalizedNamed(remote)
if err != nil {
return err
}
@ -55,7 +47,7 @@ func runPush(dockerCli command.Cli, opts pushOptions) error {
authConfig := command.ResolveAuthConfig(ctx, dockerCli, repoInfo.Index)
requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(dockerCli, repoInfo.Index, "push")
if !opts.untrusted {
if command.IsTrusted() {
return TrustedPush(ctx, dockerCli, repoInfo, ref, authConfig, requestPrivilege)
}

View File

@ -7,9 +7,10 @@ import (
"testing"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/docker/api/types"
"github.com/gotestyourself/gotestyourself/assert"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
)
func TestNewPushCommandErrors(t *testing.T) {
@ -37,13 +38,18 @@ func TestNewPushCommandErrors(t *testing.T) {
return ioutil.NopCloser(strings.NewReader("")), errors.Errorf("Failed to push")
},
},
{
name: "trust-error",
args: []string{"--disable-content-trust=false", "image:repo"},
expectedError: "you are not authorized to perform this operation: server returned 401.",
},
}
for _, tc := range testCases {
cli := test.NewFakeCli(&fakeClient{imagePushFunc: tc.imagePushFunc})
cmd := NewPushCommand(cli)
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs(tc.args)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
@ -66,6 +72,6 @@ func TestNewPushCommandSuccess(t *testing.T) {
cmd := NewPushCommand(cli)
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs(tc.args)
assert.NilError(t, cmd.Execute())
assert.NoError(t, cmd.Execute())
}
}

View File

@ -6,11 +6,11 @@ import (
"testing"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/docker/api/types"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/gotestyourself/gotestyourself/golden"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
)
type notFound struct {
@ -27,9 +27,9 @@ func (n notFound) NotFound() bool {
func TestNewRemoveCommandAlias(t *testing.T) {
cmd := newRemoveCommand(test.NewFakeCli(&fakeClient{}))
assert.Check(t, cmd.HasAlias("rmi"))
assert.Check(t, cmd.HasAlias("remove"))
assert.Check(t, !cmd.HasAlias("other"))
assert.True(t, cmd.HasAlias("rmi"))
assert.True(t, cmd.HasAlias("remove"))
assert.False(t, cmd.HasAlias("other"))
}
func TestNewRemoveCommandErrors(t *testing.T) {
@ -48,7 +48,7 @@ func TestNewRemoveCommandErrors(t *testing.T) {
args: []string{"-f", "image1"},
expectedError: "error removing image",
imageRemoveFunc: func(image string, options types.ImageRemoveOptions) ([]types.ImageDeleteResponseItem, error) {
assert.Check(t, is.Equal("image1", image))
assert.Equal(t, "image1", image)
return []types.ImageDeleteResponseItem{}, errors.Errorf("error removing image")
},
},
@ -57,8 +57,8 @@ func TestNewRemoveCommandErrors(t *testing.T) {
args: []string{"arg1"},
expectedError: "error removing image",
imageRemoveFunc: func(image string, options types.ImageRemoveOptions) ([]types.ImageDeleteResponseItem, error) {
assert.Check(t, !options.Force)
assert.Check(t, options.PruneChildren)
assert.False(t, options.Force)
assert.True(t, options.PruneChildren)
return []types.ImageDeleteResponseItem{}, errors.Errorf("error removing image")
},
},
@ -70,7 +70,7 @@ func TestNewRemoveCommandErrors(t *testing.T) {
}))
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs(tc.args)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
})
}
}
@ -86,7 +86,7 @@ func TestNewRemoveCommandSuccess(t *testing.T) {
name: "Image Deleted",
args: []string{"image1"},
imageRemoveFunc: func(image string, options types.ImageRemoveOptions) ([]types.ImageDeleteResponseItem, error) {
assert.Check(t, is.Equal("image1", image))
assert.Equal(t, "image1", image)
return []types.ImageDeleteResponseItem{{Deleted: image}}, nil
},
},
@ -94,8 +94,8 @@ func TestNewRemoveCommandSuccess(t *testing.T) {
name: "Image not found with force option",
args: []string{"-f", "image1"},
imageRemoveFunc: func(image string, options types.ImageRemoveOptions) ([]types.ImageDeleteResponseItem, error) {
assert.Check(t, is.Equal("image1", image))
assert.Check(t, is.Equal(true, options.Force))
assert.Equal(t, "image1", image)
assert.Equal(t, true, options.Force)
return []types.ImageDeleteResponseItem{}, notFound{"image1"}
},
expectedStderr: "Error: No such image: image1\n",
@ -105,7 +105,7 @@ func TestNewRemoveCommandSuccess(t *testing.T) {
name: "Image Untagged",
args: []string{"image1"},
imageRemoveFunc: func(image string, options types.ImageRemoveOptions) ([]types.ImageDeleteResponseItem, error) {
assert.Check(t, is.Equal("image1", image))
assert.Equal(t, "image1", image)
return []types.ImageDeleteResponseItem{{Untagged: image}}, nil
},
},
@ -126,8 +126,8 @@ func TestNewRemoveCommandSuccess(t *testing.T) {
cmd := NewRemoveCommand(cli)
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs(tc.args)
assert.NilError(t, cmd.Execute())
assert.Check(t, is.Equal(tc.expectedStderr, cli.ErrBuffer().String()))
assert.NoError(t, cmd.Execute())
assert.Equal(t, tc.expectedStderr, cli.ErrBuffer().String())
golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("remove-command-success.%s.golden", tc.name))
})
}

View File

@ -8,9 +8,10 @@ import (
"testing"
"github.com/docker/cli/internal/test"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/docker/cli/internal/test/testutil"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestNewSaveCommandErrors(t *testing.T) {
@ -53,7 +54,7 @@ func TestNewSaveCommandErrors(t *testing.T) {
cmd := NewSaveCommand(cli)
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs(tc.args)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
@ -68,8 +69,8 @@ func TestNewSaveCommandSuccess(t *testing.T) {
args: []string{"-o", "save_tmp_file", "arg1"},
isTerminal: true,
imageSaveFunc: func(images []string) (io.ReadCloser, error) {
assert.Assert(t, is.Len(images, 1))
assert.Check(t, is.Equal("arg1", images[0]))
require.Len(t, images, 1)
assert.Equal(t, "arg1", images[0])
return ioutil.NopCloser(strings.NewReader("")), nil
},
deferredFunc: func() {
@ -80,9 +81,9 @@ func TestNewSaveCommandSuccess(t *testing.T) {
args: []string{"arg1", "arg2"},
isTerminal: false,
imageSaveFunc: func(images []string) (io.ReadCloser, error) {
assert.Assert(t, is.Len(images, 2))
assert.Check(t, is.Equal("arg1", images[0]))
assert.Check(t, is.Equal("arg2", images[1]))
require.Len(t, images, 2)
assert.Equal(t, "arg1", images[0])
assert.Equal(t, "arg2", images[1])
return ioutil.NopCloser(strings.NewReader("")), nil
},
},
@ -95,7 +96,7 @@ func TestNewSaveCommandSuccess(t *testing.T) {
}))
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs(tc.args)
assert.NilError(t, cmd.Execute())
assert.NoError(t, cmd.Execute())
if tc.deferredFunc != nil {
tc.deferredFunc()
}

View File

@ -5,8 +5,8 @@ import (
"testing"
"github.com/docker/cli/internal/test"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/docker/cli/internal/test/testutil"
"github.com/stretchr/testify/assert"
)
func TestCliNewTagCommandErrors(t *testing.T) {
@ -20,7 +20,7 @@ func TestCliNewTagCommandErrors(t *testing.T) {
cmd := NewTagCommand(test.NewFakeCli(&fakeClient{}))
cmd.SetArgs(args)
cmd.SetOutput(ioutil.Discard)
assert.ErrorContains(t, cmd.Execute(), expectedError)
testutil.ErrorContains(t, cmd.Execute(), expectedError)
}
}
@ -28,14 +28,14 @@ func TestCliNewTagCommand(t *testing.T) {
cmd := NewTagCommand(
test.NewFakeCli(&fakeClient{
imageTagFunc: func(image string, ref string) error {
assert.Check(t, is.Equal("image1", image))
assert.Check(t, is.Equal("image2", ref))
assert.Equal(t, "image1", image)
assert.Equal(t, "image2", ref)
return nil
},
}))
cmd.SetArgs([]string{"image1", "image2"})
cmd.SetOutput(ioutil.Discard)
assert.NilError(t, cmd.Execute())
assert.NoError(t, cmd.Execute())
value, _ := cmd.Flags().GetBool("interspersed")
assert.Check(t, !value)
assert.False(t, value)
}

View File

@ -1,2 +0,0 @@
IMAGE CREATED AT CREATED BY SIZE COMMENT
abcdef 2017-01-01T12:00:03Z rose 0 new history item!

View File

@ -198,7 +198,7 @@ func trustedPull(ctx context.Context, cli command.Cli, imgRefAndAuth trust.Image
if err != nil {
return err
}
updatedImgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, nil, AuthResolver(cli), trustedRef.String())
updatedImgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, AuthResolver(cli), trustedRef.String())
if err != nil {
return err
}
@ -293,24 +293,35 @@ func imagePullPrivileged(ctx context.Context, cli command.Cli, imgRefAndAuth tru
// TrustedReference returns the canonical trusted reference for an image reference
func TrustedReference(ctx context.Context, cli command.Cli, ref reference.NamedTagged, rs registry.Service) (reference.Canonical, error) {
imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, rs, AuthResolver(cli), ref.String())
var (
repoInfo *registry.RepositoryInfo
err error
)
if rs != nil {
repoInfo, err = rs.ResolveRepository(ref)
} else {
repoInfo, err = registry.ParseRepositoryInfo(ref)
}
if err != nil {
return nil, err
}
notaryRepo, err := cli.NotaryClient(imgRefAndAuth, []string{"pull"})
// Resolve the Auth config relevant for this server
authConfig := command.ResolveAuthConfig(ctx, cli, repoInfo.Index)
notaryRepo, err := trust.GetNotaryRepository(cli.In(), cli.Out(), command.UserAgent(), repoInfo, &authConfig, "pull")
if err != nil {
return nil, errors.Wrap(err, "error establishing connection to trust repository")
}
t, err := notaryRepo.GetTargetByName(ref.Tag(), trust.ReleasesRole, data.CanonicalTargetsRole)
if err != nil {
return nil, trust.NotaryError(imgRefAndAuth.RepoInfo().Name.Name(), err)
return nil, trust.NotaryError(repoInfo.Name.Name(), err)
}
// Only list tags in the top level targets role or the releases delegation role - ignore
// all other delegation roles
if t.Role != trust.ReleasesRole && t.Role != data.CanonicalTargetsRole {
return nil, trust.NotaryError(imgRefAndAuth.RepoInfo().Name.Name(), client.ErrNoSuchTarget(ref.Tag()))
return nil, trust.NotaryError(repoInfo.Name.Name(), client.ErrNoSuchTarget(ref.Tag()))
}
r, err := convertTarget(t.Target)
if err != nil {

View File

@ -7,7 +7,9 @@ import (
"github.com/docker/cli/cli/trust"
registrytypes "github.com/docker/docker/api/types/registry"
"github.com/gotestyourself/gotestyourself/assert"
"github.com/docker/docker/registry"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/theupdateframework/notary/client"
"github.com/theupdateframework/notary/passphrase"
"github.com/theupdateframework/notary/trustpinning"
@ -46,8 +48,8 @@ func TestHTTPENVTrustServer(t *testing.T) {
func TestOfficialTrustServer(t *testing.T) {
indexInfo := &registrytypes.IndexInfo{Name: "testserver", Official: true}
output, err := trust.Server(indexInfo)
if err != nil || output != trust.NotaryServer {
t.Fatalf("Expected server to be %s, got %s", trust.NotaryServer, output)
if err != nil || output != registry.NotaryServer {
t.Fatalf("Expected server to be %s, got %s", registry.NotaryServer, output)
}
}
@ -62,12 +64,12 @@ func TestNonOfficialTrustServer(t *testing.T) {
func TestAddTargetToAllSignableRolesError(t *testing.T) {
tmpDir, err := ioutil.TempDir("", "notary-test-")
assert.NilError(t, err)
assert.NoError(t, err)
defer os.RemoveAll(tmpDir)
notaryRepo, err := client.NewFileCachedRepository(tmpDir, "gun", "https://localhost", nil, passphrase.ConstantRetriever("password"), trustpinning.TrustPinConfig{})
assert.NilError(t, err)
require.NoError(t, err)
target := client.Target{}
err = AddTargetToAllSignableRoles(notaryRepo, &target)
assert.Error(t, err, "client is offline")
assert.EqualError(t, err, "client is offline")
}

View File

@ -6,8 +6,8 @@ import (
"testing"
"github.com/docker/cli/templates"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type testElement struct {
@ -243,17 +243,17 @@ func TestTemplateInspectorRawFallbackNumber(t *testing.T) {
}
b := new(bytes.Buffer)
tmpl, err := templates.Parse("{{.Size}} {{.Id}}")
assert.NilError(t, err)
require.NoError(t, err)
i := NewTemplateInspector(b, tmpl)
for _, tc := range testcases {
err = i.Inspect(typedElem, tc.raw)
assert.NilError(t, err)
require.NoError(t, err)
err = i.Flush()
assert.NilError(t, err)
require.NoError(t, err)
assert.Check(t, is.Equal(tc.exp, b.String()))
assert.Equal(t, tc.exp, b.String())
b.Reset()
}
}

View File

@ -5,9 +5,10 @@ import (
"testing"
"github.com/docker/cli/internal/test"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/docker/cli/internal/test/testutil"
"github.com/gotestyourself/gotestyourself/golden"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestManifestAnnotateError(t *testing.T) {
@ -34,7 +35,7 @@ func TestManifestAnnotateError(t *testing.T) {
cmd := newAnnotateCommand(cli)
cmd.SetArgs(tc.args)
cmd.SetOutput(ioutil.Discard)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
@ -47,13 +48,13 @@ func TestManifestAnnotate(t *testing.T) {
namedRef := ref(t, "alpine:3.0")
imageManifest := fullImageManifest(t, namedRef)
err := store.Save(ref(t, "list:v1"), namedRef, imageManifest)
assert.NilError(t, err)
require.NoError(t, err)
cmd := newAnnotateCommand(cli)
cmd.SetArgs([]string{"example.com/list:v1", "example.com/fake:0.0"})
cmd.SetOutput(ioutil.Discard)
expectedError := "manifest for image example.com/fake:0.0 does not exist"
assert.ErrorContains(t, cmd.Execute(), expectedError)
testutil.ErrorContains(t, cmd.Execute(), expectedError)
cmd.SetArgs([]string{"example.com/list:v1", "example.com/alpine:3.0"})
cmd.Flags().Set("os", "freebsd")
@ -61,17 +62,17 @@ func TestManifestAnnotate(t *testing.T) {
cmd.Flags().Set("os-features", "feature1")
cmd.Flags().Set("variant", "v7")
expectedError = "manifest entry for image has unsupported os/arch combination"
assert.ErrorContains(t, cmd.Execute(), expectedError)
testutil.ErrorContains(t, cmd.Execute(), expectedError)
cmd.Flags().Set("arch", "arm")
assert.NilError(t, cmd.Execute())
require.NoError(t, cmd.Execute())
cmd = newInspectCommand(cli)
err = cmd.Flags().Set("verbose", "true")
assert.NilError(t, err)
require.NoError(t, err)
cmd.SetArgs([]string{"example.com/list:v1", "example.com/alpine:3.0"})
assert.NilError(t, cmd.Execute())
require.NoError(t, cmd.Execute())
actual := cli.OutBuffer()
expected := golden.Get(t, "inspect-annotate.golden")
assert.Check(t, is.Equal(string(expected), actual.String()))
assert.Equal(t, string(expected), actual.String())
}

View File

@ -10,6 +10,7 @@ import (
)
type fakeRegistryClient struct {
client.RegistryClient
getManifestFunc func(ctx context.Context, ref reference.Named) (manifesttypes.ImageManifest, error)
getManifestListFunc func(ctx context.Context, ref reference.Named) ([]manifesttypes.ImageManifest, error)
mountBlobFunc func(ctx context.Context, source reference.Canonical, target reference.Named) error
@ -43,5 +44,3 @@ func (c *fakeRegistryClient) PutManifest(ctx context.Context, ref reference.Name
}
return digest.Digest(""), nil
}
var _ client.RegistryClient = &fakeRegistryClient{}

View File

@ -6,11 +6,12 @@ import (
manifesttypes "github.com/docker/cli/cli/manifest/types"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/distribution/reference"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/gotestyourself/gotestyourself/golden"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/net/context"
)
@ -34,7 +35,7 @@ func TestManifestCreateErrors(t *testing.T) {
cmd := newCreateListCommand(cli)
cmd.SetArgs(tc.args)
cmd.SetOutput(ioutil.Discard)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
@ -49,28 +50,28 @@ func TestManifestCreateAmend(t *testing.T) {
namedRef := ref(t, "alpine:3.0")
imageManifest := fullImageManifest(t, namedRef)
err := store.Save(ref(t, "list:v1"), namedRef, imageManifest)
assert.NilError(t, err)
require.NoError(t, err)
namedRef = ref(t, "alpine:3.1")
imageManifest = fullImageManifest(t, namedRef)
err = store.Save(ref(t, "list:v1"), namedRef, imageManifest)
assert.NilError(t, err)
require.NoError(t, err)
cmd := newCreateListCommand(cli)
cmd.SetArgs([]string{"example.com/list:v1", "example.com/alpine:3.1"})
cmd.Flags().Set("amend", "true")
cmd.SetOutput(ioutil.Discard)
err = cmd.Execute()
assert.NilError(t, err)
require.NoError(t, err)
// make a new cli to clear the buffers
cli = test.NewFakeCli(nil)
cli.SetManifestStore(store)
inspectCmd := newInspectCommand(cli)
inspectCmd.SetArgs([]string{"example.com/list:v1"})
assert.NilError(t, inspectCmd.Execute())
require.NoError(t, inspectCmd.Execute())
actual := cli.OutBuffer()
expected := golden.Get(t, "inspect-manifest-list.golden")
assert.Check(t, is.Equal(string(expected), actual.String()))
assert.Equal(t, string(expected), actual.String())
}
// attempt to overwrite a saved manifest and get refused
@ -83,13 +84,13 @@ func TestManifestCreateRefuseAmend(t *testing.T) {
namedRef := ref(t, "alpine:3.0")
imageManifest := fullImageManifest(t, namedRef)
err := store.Save(ref(t, "list:v1"), namedRef, imageManifest)
assert.NilError(t, err)
require.NoError(t, err)
cmd := newCreateListCommand(cli)
cmd.SetArgs([]string{"example.com/list:v1", "example.com/alpine:3.0"})
cmd.SetOutput(ioutil.Discard)
err = cmd.Execute()
assert.Error(t, err, "refusing to amend an existing manifest list with no --amend flag")
assert.EqualError(t, err, "refusing to amend an existing manifest list with no --amend flag")
}
// attempt to make a manifest list without valid images
@ -112,5 +113,5 @@ func TestManifestCreateNoManifest(t *testing.T) {
cmd.SetArgs([]string{"example.com/list:v1", "example.com/alpine:3.0"})
cmd.SetOutput(ioutil.Discard)
err := cmd.Execute()
assert.Error(t, err, "No such image: example.com/alpine:3.0")
assert.EqualError(t, err, "No such image: example.com/alpine:3.0")
}

View File

@ -12,24 +12,24 @@ import (
"github.com/docker/distribution"
"github.com/docker/distribution/manifest/schema2"
"github.com/docker/distribution/reference"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/gotestyourself/gotestyourself/golden"
digest "github.com/opencontainers/go-digest"
"github.com/opencontainers/go-digest"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/net/context"
)
func newTempManifestStore(t *testing.T) (store.Store, func()) {
tmpdir, err := ioutil.TempDir("", "test-manifest-storage")
assert.NilError(t, err)
require.NoError(t, err)
return store.NewStore(tmpdir), func() { os.RemoveAll(tmpdir) }
}
func ref(t *testing.T, name string) reference.Named {
named, err := reference.ParseNamed("example.com/" + name)
assert.NilError(t, err)
require.NoError(t, err)
return named
}
@ -49,7 +49,7 @@ func fullImageManifest(t *testing.T, ref reference.Named) types.ImageManifest {
},
},
})
assert.NilError(t, err)
require.NoError(t, err)
// TODO: include image data for verbose inspect
return types.NewImageManifest(ref, digest.Digest("sha256:7328f6f8b41890597575cbaadc884e7386ae0acc53b747401ebce5cf0d62abcd"), types.Image{OS: "linux", Architecture: "amd64"}, man)
}
@ -65,7 +65,7 @@ func TestInspectCommandLocalManifestNotFound(t *testing.T) {
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs([]string{"example.com/list:v1", "example.com/alpine:3.0"})
err := cmd.Execute()
assert.Error(t, err, "No such manifest: example.com/alpine:3.0")
assert.EqualError(t, err, "No such manifest: example.com/alpine:3.0")
}
func TestInspectCommandNotFound(t *testing.T) {
@ -87,7 +87,7 @@ func TestInspectCommandNotFound(t *testing.T) {
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs([]string{"example.com/alpine:3.0"})
err := cmd.Execute()
assert.Error(t, err, "No such manifest: example.com/alpine:3.0")
assert.EqualError(t, err, "No such manifest: example.com/alpine:3.0")
}
func TestInspectCommandLocalManifest(t *testing.T) {
@ -99,14 +99,14 @@ func TestInspectCommandLocalManifest(t *testing.T) {
namedRef := ref(t, "alpine:3.0")
imageManifest := fullImageManifest(t, namedRef)
err := store.Save(ref(t, "list:v1"), namedRef, imageManifest)
assert.NilError(t, err)
require.NoError(t, err)
cmd := newInspectCommand(cli)
cmd.SetArgs([]string{"example.com/list:v1", "example.com/alpine:3.0"})
assert.NilError(t, cmd.Execute())
require.NoError(t, cmd.Execute())
actual := cli.OutBuffer()
expected := golden.Get(t, "inspect-manifest.golden")
assert.Check(t, is.Equal(string(expected), actual.String()))
assert.Equal(t, string(expected), actual.String())
}
func TestInspectcommandRemoteManifest(t *testing.T) {
@ -124,8 +124,8 @@ func TestInspectcommandRemoteManifest(t *testing.T) {
cmd := newInspectCommand(cli)
cmd.SetOutput(ioutil.Discard)
cmd.SetArgs([]string{"example.com/alpine:3.0"})
assert.NilError(t, cmd.Execute())
require.NoError(t, cmd.Execute())
actual := cli.OutBuffer()
expected := golden.Get(t, "inspect-manifest.golden")
assert.Check(t, is.Equal(string(expected), actual.String()))
assert.Equal(t, string(expected), actual.String())
}

View File

@ -6,13 +6,16 @@ import (
manifesttypes "github.com/docker/cli/cli/manifest/types"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/distribution/reference"
"github.com/gotestyourself/gotestyourself/assert"
"github.com/pkg/errors"
"github.com/stretchr/testify/require"
"golang.org/x/net/context"
)
func newFakeRegistryClient() *fakeRegistryClient {
func newFakeRegistryClient(t *testing.T) *fakeRegistryClient {
require.NoError(t, nil)
return &fakeRegistryClient{
getManifestFunc: func(_ context.Context, _ reference.Named) (manifesttypes.ImageManifest, error) {
return manifesttypes.ImageManifest{}, errors.New("")
@ -43,15 +46,16 @@ func TestManifestPushErrors(t *testing.T) {
cmd := newPushListCommand(cli)
cmd.SetArgs(tc.args)
cmd.SetOutput(ioutil.Discard)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
// store a one-image manifest list and puah it
func TestManifestPush(t *testing.T) {
store, sCleanup := newTempManifestStore(t)
defer sCleanup()
registry := newFakeRegistryClient()
registry := newFakeRegistryClient(t)
cli := test.NewFakeCli(nil)
cli.SetManifestStore(store)
@ -60,10 +64,10 @@ func TestManifestPush(t *testing.T) {
namedRef := ref(t, "alpine:3.0")
imageManifest := fullImageManifest(t, namedRef)
err := store.Save(ref(t, "list:v1"), namedRef, imageManifest)
assert.NilError(t, err)
require.NoError(t, err)
cmd := newPushListCommand(cli)
cmd.SetArgs([]string{"example.com/list:v1"})
err = cmd.Execute()
assert.NilError(t, err)
require.NoError(t, err)
}

View File

@ -5,10 +5,10 @@ import (
"testing"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/docker/api/types/network"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"golang.org/x/net/context"
)
@ -38,7 +38,7 @@ func TestNetworkConnectErrors(t *testing.T) {
)
cmd.SetArgs(tc.args)
cmd.SetOutput(ioutil.Discard)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
@ -54,7 +54,7 @@ func TestNetworkConnectWithFlags(t *testing.T) {
}
cli := test.NewFakeCli(&fakeClient{
networkConnectFunc: func(ctx context.Context, networkID, container string, config *network.EndpointSettings) error {
assert.Check(t, is.DeepEqual(expectedOpts, config.IPAMConfig), "not expected driver error")
assert.Equal(t, expectedOpts, config.IPAMConfig, "not expected driver error")
return nil
},
})
@ -66,5 +66,5 @@ func TestNetworkConnectWithFlags(t *testing.T) {
cmd.Flags().Set("ip-range", "192.168.4.0/24")
cmd.Flags().Set("gateway", "192.168.4.1/24")
cmd.Flags().Set("subnet", "192.168.4.0/24")
assert.NilError(t, cmd.Execute())
assert.NoError(t, cmd.Execute())
}

View File

@ -6,11 +6,12 @@ import (
"testing"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/network"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/net/context"
)
@ -135,10 +136,10 @@ func TestNetworkCreateErrors(t *testing.T) {
)
cmd.SetArgs(tc.args)
for key, value := range tc.flags {
assert.NilError(t, cmd.Flags().Set(key, value))
require.NoError(t, cmd.Flags().Set(key, value))
}
cmd.SetOutput(ioutil.Discard)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
@ -154,8 +155,8 @@ func TestNetworkCreateWithFlags(t *testing.T) {
}
cli := test.NewFakeCli(&fakeClient{
networkCreateFunc: func(ctx context.Context, name string, createBody types.NetworkCreate) (types.NetworkCreateResponse, error) {
assert.Check(t, is.Equal(expectedDriver, createBody.Driver), "not expected driver error")
assert.Check(t, is.DeepEqual(expectedOpts, createBody.IPAM.Config), "not expected driver error")
assert.Equal(t, expectedDriver, createBody.Driver, "not expected driver error")
assert.Equal(t, expectedOpts, createBody.IPAM.Config, "not expected driver error")
return types.NetworkCreateResponse{
ID: name,
}, nil
@ -169,6 +170,6 @@ func TestNetworkCreateWithFlags(t *testing.T) {
cmd.Flags().Set("ip-range", "192.168.4.0/24")
cmd.Flags().Set("gateway", "192.168.4.1/24")
cmd.Flags().Set("subnet", "192.168.4.0/24")
assert.NilError(t, cmd.Execute())
assert.Check(t, is.Equal("banana", strings.TrimSpace(cli.OutBuffer().String())))
assert.NoError(t, cmd.Execute())
assert.Equal(t, "banana", strings.TrimSpace(cli.OutBuffer().String()))
}

View File

@ -5,7 +5,7 @@ import (
"testing"
"github.com/docker/cli/internal/test"
"github.com/gotestyourself/gotestyourself/assert"
"github.com/docker/cli/internal/test/testutil"
"github.com/pkg/errors"
"golang.org/x/net/context"
)
@ -36,6 +36,6 @@ func TestNetworkDisconnectErrors(t *testing.T) {
)
cmd.SetArgs(tc.args)
cmd.SetOutput(ioutil.Discard)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}

View File

@ -1,19 +1,20 @@
package network
import (
"io/ioutil"
"strings"
"testing"
"io/ioutil"
"strings"
"github.com/docker/cli/internal/test"
. "github.com/docker/cli/internal/test/builders"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/google/go-cmp/cmp"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/gotestyourself/gotestyourself/golden"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"golang.org/x/net/context"
)
@ -37,18 +38,23 @@ func TestNetworkListErrors(t *testing.T) {
}),
)
cmd.SetOutput(ioutil.Discard)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
func TestNetworkListWithFlags(t *testing.T) {
filterArgs := filters.NewArgs()
filterArgs.Add("image.name", "ubuntu")
expectedOpts := types.NetworkListOptions{
Filters: filters.NewArgs(filters.Arg("image.name", "ubuntu")),
Filters: filterArgs,
}
cli := test.NewFakeCli(&fakeClient{
networkListFunc: func(ctx context.Context, options types.NetworkListOptions) ([]types.NetworkResource, error) {
assert.Check(t, is.DeepEqual(expectedOpts, options, cmp.AllowUnexported(filters.Args{})))
assert.Equal(t, expectedOpts, options, "not expected options error")
return []types.NetworkResource{*NetworkResource(NetworkResourceID("123454321"),
NetworkResourceName("network_1"),
NetworkResourceDriver("09.7.01"),
@ -58,6 +64,6 @@ func TestNetworkListWithFlags(t *testing.T) {
cmd := newListCommand(cli)
cmd.Flags().Set("filter", "image.name=ubuntu")
assert.NilError(t, cmd.Execute())
assert.NoError(t, cmd.Execute())
golden.Assert(t, strings.TrimSpace(cli.OutBuffer().String()), "network-list.golden")
}

View File

@ -6,10 +6,11 @@ import (
"github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types/swarm"
"github.com/gotestyourself/gotestyourself/assert"
"github.com/pkg/errors"
// Import builders to get the builder function as package function
. "github.com/docker/cli/internal/test/builders"
"github.com/docker/cli/internal/test/testutil"
"github.com/stretchr/testify/assert"
)
func TestNodeDemoteErrors(t *testing.T) {
@ -45,7 +46,7 @@ func TestNodeDemoteErrors(t *testing.T) {
}))
cmd.SetArgs(tc.args)
cmd.SetOutput(ioutil.Discard)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
@ -63,7 +64,7 @@ func TestNodeDemoteNoChange(t *testing.T) {
},
}))
cmd.SetArgs([]string{"nodeID"})
assert.NilError(t, cmd.Execute())
assert.NoError(t, cmd.Execute())
}
func TestNodeDemoteMultipleNode(t *testing.T) {
@ -80,5 +81,5 @@ func TestNodeDemoteMultipleNode(t *testing.T) {
},
}))
cmd.SetArgs([]string{"nodeID1", "nodeID2"})
assert.NilError(t, cmd.Execute())
assert.NoError(t, cmd.Execute())
}

View File

@ -11,8 +11,9 @@ import (
"github.com/pkg/errors"
// Import builders to get the builder function as package function
. "github.com/docker/cli/internal/test/builders"
"github.com/gotestyourself/gotestyourself/assert"
"github.com/docker/cli/internal/test/testutil"
"github.com/gotestyourself/gotestyourself/golden"
"github.com/stretchr/testify/assert"
)
func TestNodeInspectErrors(t *testing.T) {
@ -75,7 +76,7 @@ func TestNodeInspectErrors(t *testing.T) {
cmd.Flags().Set(key, value)
}
cmd.SetOutput(ioutil.Discard)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
@ -112,7 +113,7 @@ func TestNodeInspectPretty(t *testing.T) {
cmd := newInspectCommand(cli)
cmd.SetArgs([]string{"nodeID"})
cmd.Flags().Set("pretty", "true")
assert.NilError(t, cmd.Execute())
assert.NoError(t, cmd.Execute())
golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("node-inspect-pretty.%s.golden", tc.name))
}
}

View File

@ -8,12 +8,11 @@ import (
"github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/gotestyourself/gotestyourself/golden"
"github.com/pkg/errors"
// Import builders to get the builder function as package function
. "github.com/docker/cli/internal/test/builders"
"github.com/stretchr/testify/assert"
)
func TestNodeListErrorOnAPIFailure(t *testing.T) {
@ -49,7 +48,7 @@ func TestNodeListErrorOnAPIFailure(t *testing.T) {
})
cmd := newListCommand(cli)
cmd.SetOutput(ioutil.Discard)
assert.Error(t, cmd.Execute(), tc.expectedError)
assert.EqualError(t, cmd.Execute(), tc.expectedError)
}
}
@ -72,7 +71,7 @@ func TestNodeList(t *testing.T) {
})
cmd := newListCommand(cli)
assert.NilError(t, cmd.Execute())
assert.NoError(t, cmd.Execute())
golden.Assert(t, cli.OutBuffer().String(), "node-list-sort.golden")
}
@ -86,8 +85,8 @@ func TestNodeListQuietShouldOnlyPrintIDs(t *testing.T) {
})
cmd := newListCommand(cli)
cmd.Flags().Set("quiet", "true")
assert.NilError(t, cmd.Execute())
assert.Check(t, is.Equal(cli.OutBuffer().String(), "nodeID1\n"))
assert.NoError(t, cmd.Execute())
assert.Equal(t, cli.OutBuffer().String(), "nodeID1\n")
}
func TestNodeListDefaultFormatFromConfig(t *testing.T) {
@ -111,7 +110,7 @@ func TestNodeListDefaultFormatFromConfig(t *testing.T) {
NodesFormat: "{{.ID}}: {{.Hostname}} {{.Status}}/{{.ManagerStatus}}",
})
cmd := newListCommand(cli)
assert.NilError(t, cmd.Execute())
assert.NoError(t, cmd.Execute())
golden.Assert(t, cli.OutBuffer().String(), "node-list-format-from-config.golden")
}
@ -136,6 +135,6 @@ func TestNodeListFormat(t *testing.T) {
})
cmd := newListCommand(cli)
cmd.Flags().Set("format", "{{.Hostname}}: {{.ManagerStatus}}")
assert.NilError(t, cmd.Execute())
assert.NoError(t, cmd.Execute())
golden.Assert(t, cli.OutBuffer().String(), "node-list-format-flag.golden")
}

View File

@ -6,10 +6,11 @@ import (
"github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types/swarm"
"github.com/gotestyourself/gotestyourself/assert"
"github.com/pkg/errors"
// Import builders to get the builder function as package function
. "github.com/docker/cli/internal/test/builders"
"github.com/docker/cli/internal/test/testutil"
"github.com/stretchr/testify/assert"
)
func TestNodePromoteErrors(t *testing.T) {
@ -45,7 +46,7 @@ func TestNodePromoteErrors(t *testing.T) {
}))
cmd.SetArgs(tc.args)
cmd.SetOutput(ioutil.Discard)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
@ -63,7 +64,7 @@ func TestNodePromoteNoChange(t *testing.T) {
},
}))
cmd.SetArgs([]string{"nodeID"})
assert.NilError(t, cmd.Execute())
assert.NoError(t, cmd.Execute())
}
func TestNodePromoteMultipleNode(t *testing.T) {
@ -80,5 +81,5 @@ func TestNodePromoteMultipleNode(t *testing.T) {
},
}))
cmd.SetArgs([]string{"nodeID1", "nodeID2"})
assert.NilError(t, cmd.Execute())
assert.NoError(t, cmd.Execute())
}

View File

@ -12,8 +12,8 @@ import (
"github.com/pkg/errors"
// Import builders to get the builder function as package function
. "github.com/docker/cli/internal/test/builders"
"github.com/gotestyourself/gotestyourself/assert"
"github.com/gotestyourself/gotestyourself/golden"
"github.com/stretchr/testify/assert"
)
func TestNodePsErrors(t *testing.T) {
@ -60,7 +60,7 @@ func TestNodePsErrors(t *testing.T) {
cmd.Flags().Set(key, value)
}
cmd.SetOutput(ioutil.Discard)
assert.Error(t, cmd.Execute(), tc.expectedError)
assert.EqualError(t, cmd.Execute(), tc.expectedError)
}
}
@ -122,7 +122,7 @@ func TestNodePs(t *testing.T) {
for key, value := range tc.flags {
cmd.Flags().Set(key, value)
}
assert.NilError(t, cmd.Execute())
assert.NoError(t, cmd.Execute())
golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("node-ps.%s.golden", tc.name))
}
}

View File

@ -5,8 +5,9 @@ import (
"testing"
"github.com/docker/cli/internal/test"
"github.com/gotestyourself/gotestyourself/assert"
"github.com/docker/cli/internal/test/testutil"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
)
func TestNodeRemoveErrors(t *testing.T) {
@ -33,12 +34,12 @@ func TestNodeRemoveErrors(t *testing.T) {
}))
cmd.SetArgs(tc.args)
cmd.SetOutput(ioutil.Discard)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
func TestNodeRemoveMultiple(t *testing.T) {
cmd := newRemoveCommand(test.NewFakeCli(&fakeClient{}))
cmd.SetArgs([]string{"nodeID1", "nodeID2"})
assert.NilError(t, cmd.Execute())
assert.NoError(t, cmd.Execute())
}

View File

@ -6,10 +6,11 @@ import (
"github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types/swarm"
"github.com/gotestyourself/gotestyourself/assert"
"github.com/pkg/errors"
// Import builders to get the builder function as package function
. "github.com/docker/cli/internal/test/builders"
"github.com/docker/cli/internal/test/testutil"
"github.com/stretchr/testify/assert"
)
func TestNodeUpdateErrors(t *testing.T) {
@ -65,7 +66,7 @@ func TestNodeUpdateErrors(t *testing.T) {
cmd.Flags().Set(key, value)
}
cmd.SetOutput(ioutil.Discard)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
@ -164,6 +165,6 @@ func TestNodeUpdate(t *testing.T) {
for key, value := range tc.flags {
cmd.Flags().Set(key, value)
}
assert.NilError(t, cmd.Execute())
assert.NoError(t, cmd.Execute())
}
}

View File

@ -4,21 +4,17 @@ import (
"fmt"
"io"
"io/ioutil"
"runtime"
"testing"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/docker/api/types"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/gotestyourself/gotestyourself/fs"
"github.com/stretchr/testify/assert"
)
func TestCreateErrors(t *testing.T) {
noSuchFile := "no such file or directory"
if runtime.GOOS == "windows" {
noSuchFile = "The system cannot find the file specified."
}
testCases := []struct {
args []string
expectedError string
@ -33,7 +29,7 @@ func TestCreateErrors(t *testing.T) {
},
{
args: []string{"plugin-foo", "nonexistent_context_dir"},
expectedError: noSuchFile,
expectedError: "no such file or directory",
},
}
@ -42,7 +38,7 @@ func TestCreateErrors(t *testing.T) {
cmd := newCreateCommand(cli)
cmd.SetArgs(tc.args)
cmd.SetOutput(ioutil.Discard)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
@ -54,7 +50,7 @@ func TestCreateErrorOnFileAsContextDir(t *testing.T) {
cmd := newCreateCommand(cli)
cmd.SetArgs([]string{"plugin-foo", tmpFile.Path()})
cmd.SetOutput(ioutil.Discard)
assert.ErrorContains(t, cmd.Execute(), "context must be a directory")
testutil.ErrorContains(t, cmd.Execute(), "context must be a directory")
}
func TestCreateErrorOnContextDirWithoutConfig(t *testing.T) {
@ -65,12 +61,7 @@ func TestCreateErrorOnContextDirWithoutConfig(t *testing.T) {
cmd := newCreateCommand(cli)
cmd.SetArgs([]string{"plugin-foo", tmpDir.Path()})
cmd.SetOutput(ioutil.Discard)
expectedErr := "config.json: no such file or directory"
if runtime.GOOS == "windows" {
expectedErr = "config.json: The system cannot find the file specified."
}
assert.ErrorContains(t, cmd.Execute(), expectedErr)
testutil.ErrorContains(t, cmd.Execute(), "config.json: no such file or directory")
}
func TestCreateErrorOnInvalidConfig(t *testing.T) {
@ -83,7 +74,7 @@ func TestCreateErrorOnInvalidConfig(t *testing.T) {
cmd := newCreateCommand(cli)
cmd.SetArgs([]string{"plugin-foo", tmpDir.Path()})
cmd.SetOutput(ioutil.Discard)
assert.ErrorContains(t, cmd.Execute(), "invalid")
testutil.ErrorContains(t, cmd.Execute(), "invalid")
}
func TestCreateErrorFromDaemon(t *testing.T) {
@ -101,7 +92,7 @@ func TestCreateErrorFromDaemon(t *testing.T) {
cmd := newCreateCommand(cli)
cmd.SetArgs([]string{"plugin-foo", tmpDir.Path()})
cmd.SetOutput(ioutil.Discard)
assert.ErrorContains(t, cmd.Execute(), "Error creating plugin")
testutil.ErrorContains(t, cmd.Execute(), "Error creating plugin")
}
func TestCreatePlugin(t *testing.T) {
@ -118,6 +109,6 @@ func TestCreatePlugin(t *testing.T) {
cmd := newCreateCommand(cli)
cmd.SetArgs([]string{"plugin-foo", tmpDir.Path()})
assert.NilError(t, cmd.Execute())
assert.Check(t, is.Equal("plugin-foo\n", cli.OutBuffer().String()))
assert.NoError(t, cmd.Execute())
assert.Equal(t, "plugin-foo\n", cli.OutBuffer().String())
}

View File

@ -6,9 +6,9 @@ import (
"testing"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/docker/api/types"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/stretchr/testify/assert"
)
func TestPluginDisableErrors(t *testing.T) {
@ -41,7 +41,7 @@ func TestPluginDisableErrors(t *testing.T) {
}))
cmd.SetArgs(tc.args)
cmd.SetOutput(ioutil.Discard)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
@ -53,6 +53,6 @@ func TestPluginDisable(t *testing.T) {
})
cmd := newDisableCommand(cli)
cmd.SetArgs([]string{"plugin-foo"})
assert.NilError(t, cmd.Execute())
assert.Check(t, is.Equal("plugin-foo\n", cli.OutBuffer().String()))
assert.NoError(t, cmd.Execute())
assert.Equal(t, "plugin-foo\n", cli.OutBuffer().String())
}

View File

@ -6,9 +6,9 @@ import (
"testing"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/docker/api/types"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/stretchr/testify/assert"
)
func TestPluginEnableErrors(t *testing.T) {
@ -52,7 +52,7 @@ func TestPluginEnableErrors(t *testing.T) {
cmd.Flags().Set(key, value)
}
cmd.SetOutput(ioutil.Discard)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
@ -65,6 +65,6 @@ func TestPluginEnable(t *testing.T) {
cmd := newEnableCommand(cli)
cmd.SetArgs([]string{"plugin-foo"})
assert.NilError(t, cmd.Execute())
assert.Check(t, is.Equal("plugin-foo\n", cli.OutBuffer().String()))
assert.NoError(t, cmd.Execute())
assert.Equal(t, "plugin-foo\n", cli.OutBuffer().String())
}

View File

@ -24,12 +24,11 @@ type pluginOptions struct {
disable bool
args []string
skipRemoteCheck bool
untrusted bool
}
func loadPullFlags(dockerCli command.Cli, opts *pluginOptions, flags *pflag.FlagSet) {
func loadPullFlags(opts *pluginOptions, flags *pflag.FlagSet) {
flags.BoolVar(&opts.grantPerms, "grant-all-permissions", false, "Grant all permissions necessary to run the plugin")
command.AddTrustVerificationFlags(flags, &opts.untrusted, dockerCli.ContentTrustEnabled())
command.AddTrustVerificationFlags(flags)
}
func newInstallCommand(dockerCli command.Cli) *cobra.Command {
@ -48,7 +47,7 @@ func newInstallCommand(dockerCli command.Cli) *cobra.Command {
}
flags := cmd.Flags()
loadPullFlags(dockerCli, &options, flags)
loadPullFlags(&options, flags)
flags.BoolVar(&options.disable, "disable", false, "Do not enable the plugin on install")
flags.StringVar(&options.localName, "alias", "", "Local name for plugin")
return cmd
@ -91,7 +90,7 @@ func buildPullConfig(ctx context.Context, dockerCli command.Cli, opts pluginOpti
remote := ref.String()
_, isCanonical := ref.(reference.Canonical)
if !opts.untrusted && !isCanonical {
if command.IsTrusted() && !isCanonical {
ref = reference.TagNameOnly(ref)
nt, ok := ref.(reference.NamedTagged)
if !ok {

View File

@ -13,37 +13,30 @@ import (
"github.com/spf13/cobra"
)
type pushOptions struct {
name string
untrusted bool
}
func newPushCommand(dockerCli command.Cli) *cobra.Command {
var opts pushOptions
cmd := &cobra.Command{
Use: "push [OPTIONS] PLUGIN[:TAG]",
Short: "Push a plugin to a registry",
Args: cli.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
opts.name = args[0]
return runPush(dockerCli, opts)
return runPush(dockerCli, args[0])
},
}
flags := cmd.Flags()
command.AddTrustSigningFlags(flags, &opts.untrusted, dockerCli.ContentTrustEnabled())
command.AddTrustSigningFlags(flags)
return cmd
}
func runPush(dockerCli command.Cli, opts pushOptions) error {
named, err := reference.ParseNormalizedNamed(opts.name)
func runPush(dockerCli command.Cli, name string) error {
named, err := reference.ParseNormalizedNamed(name)
if err != nil {
return err
}
if _, ok := named.(reference.Canonical); ok {
return errors.Errorf("invalid name: %s", opts.name)
return errors.Errorf("invalid name: %s", name)
}
named = reference.TagNameOnly(named)
@ -67,7 +60,7 @@ func runPush(dockerCli command.Cli, opts pushOptions) error {
}
defer responseBody.Close()
if !opts.untrusted {
if command.IsTrusted() {
repoInfo.Class = "plugin"
return image.PushTrustedReference(dockerCli, repoInfo, named, authConfig, responseBody)
}

View File

@ -6,9 +6,9 @@ import (
"testing"
"github.com/docker/cli/internal/test"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/docker/api/types"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/stretchr/testify/assert"
)
func TestRemoveErrors(t *testing.T) {
@ -38,7 +38,7 @@ func TestRemoveErrors(t *testing.T) {
cmd := newRemoveCommand(cli)
cmd.SetArgs(tc.args)
cmd.SetOutput(ioutil.Discard)
assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
testutil.ErrorContains(t, cmd.Execute(), tc.expectedError)
}
}
@ -50,8 +50,8 @@ func TestRemove(t *testing.T) {
})
cmd := newRemoveCommand(cli)
cmd.SetArgs([]string{"plugin-foo"})
assert.NilError(t, cmd.Execute())
assert.Check(t, is.Equal("plugin-foo\n", cli.OutBuffer().String()))
assert.NoError(t, cmd.Execute())
assert.Equal(t, "plugin-foo\n", cli.OutBuffer().String())
}
func TestRemoveWithForceOption(t *testing.T) {
@ -65,7 +65,7 @@ func TestRemoveWithForceOption(t *testing.T) {
cmd := newRemoveCommand(cli)
cmd.SetArgs([]string{"plugin-foo"})
cmd.Flags().Set("force", "true")
assert.NilError(t, cmd.Execute())
assert.Check(t, force)
assert.Check(t, is.Equal("plugin-foo\n", cli.OutBuffer().String()))
assert.NoError(t, cmd.Execute())
assert.True(t, force)
assert.Equal(t, "plugin-foo\n", cli.OutBuffer().String())
}

View File

@ -30,7 +30,7 @@ func newUpgradeCommand(dockerCli command.Cli) *cobra.Command {
}
flags := cmd.Flags()
loadPullFlags(dockerCli, &options, flags)
loadPullFlags(&options, flags)
flags.BoolVar(&options.skipRemoteCheck, "skip-remote-check", false, "Do not check if specified remote plugin matches existing plugin image")
return cmd
}

View File

@ -52,15 +52,11 @@ func RegistryAuthenticationPrivilegedFunc(cli Cli, index *registrytypes.IndexInf
fmt.Fprintf(cli.Out(), "\nPlease login prior to %s:\n", cmdName)
indexServer := registry.GetAuthConfigKey(index)
isDefaultRegistry := indexServer == ElectAuthServer(context.Background(), cli)
authConfig, err := GetDefaultAuthConfig(cli, true, indexServer, isDefaultRegistry)
if err != nil {
fmt.Fprintf(cli.Err(), "Unable to retrieve stored credentials for %s, error: %s.\n", indexServer, err)
}
err = ConfigureAuth(cli, "", "", authConfig, isDefaultRegistry)
authConfig, err := ConfigureAuth(cli, "", "", indexServer, isDefaultRegistry)
if err != nil {
return "", err
}
return EncodeAuthToBase64(*authConfig)
return EncodeAuthToBase64(authConfig)
}
}
@ -77,31 +73,22 @@ func ResolveAuthConfig(ctx context.Context, cli Cli, index *registrytypes.IndexI
return a
}
// GetDefaultAuthConfig gets the default auth config given a serverAddress
// If credentials for given serverAddress exists in the credential store, the configuration will be populated with values in it
func GetDefaultAuthConfig(cli Cli, checkCredStore bool, serverAddress string, isDefaultRegistry bool) (*types.AuthConfig, error) {
if !isDefaultRegistry {
serverAddress = registry.ConvertToHostname(serverAddress)
}
var authconfig types.AuthConfig
var err error
if checkCredStore {
authconfig, err = cli.ConfigFile().GetAuthConfig(serverAddress)
} else {
authconfig = types.AuthConfig{}
}
authconfig.ServerAddress = serverAddress
authconfig.IdentityToken = ""
return &authconfig, err
}
// ConfigureAuth handles prompting of user's username and password if needed
func ConfigureAuth(cli Cli, flUser, flPassword string, authconfig *types.AuthConfig, isDefaultRegistry bool) error {
// ConfigureAuth returns an AuthConfig from the specified user, password and server.
func ConfigureAuth(cli Cli, flUser, flPassword, serverAddress string, isDefaultRegistry bool) (types.AuthConfig, error) {
// On Windows, force the use of the regular OS stdin stream. Fixes #14336/#14210
if runtime.GOOS == "windows" {
cli.SetIn(NewInStream(os.Stdin))
}
if !isDefaultRegistry {
serverAddress = registry.ConvertToHostname(serverAddress)
}
authconfig, err := cli.ConfigFile().GetAuthConfig(serverAddress)
if err != nil {
return authconfig, err
}
// Some links documenting this:
// - https://code.google.com/archive/p/mintty/issues/56
// - https://github.com/docker/docker/issues/15272
@ -110,7 +97,7 @@ func ConfigureAuth(cli Cli, flUser, flPassword string, authconfig *types.AuthCon
// will hit this if you attempt docker login from mintty where stdin
// is a pipe, not a character based console.
if flPassword == "" && !cli.In().IsTerminal() {
return errors.Errorf("Error: Cannot perform an interactive login from a non TTY device")
return authconfig, errors.Errorf("Error: Cannot perform an interactive login from a non TTY device")
}
authconfig.Username = strings.TrimSpace(authconfig.Username)
@ -128,12 +115,12 @@ func ConfigureAuth(cli Cli, flUser, flPassword string, authconfig *types.AuthCon
}
}
if flUser == "" {
return errors.Errorf("Error: Non-null Username Required")
return authconfig, errors.Errorf("Error: Non-null Username Required")
}
if flPassword == "" {
oldState, err := term.SaveState(cli.In().FD())
if err != nil {
return err
return authconfig, err
}
fmt.Fprintf(cli.Out(), "Password: ")
term.DisableEcho(cli.In().FD(), oldState)
@ -143,14 +130,16 @@ func ConfigureAuth(cli Cli, flUser, flPassword string, authconfig *types.AuthCon
term.RestoreTerminal(cli.In().FD(), oldState)
if flPassword == "" {
return errors.Errorf("Error: Password Required")
return authconfig, errors.Errorf("Error: Password Required")
}
}
authconfig.Username = flUser
authconfig.Password = flPassword
authconfig.ServerAddress = serverAddress
authconfig.IdentityToken = ""
return nil
return authconfig, nil
}
func readInput(in io.Reader, out io.Writer) string {

View File

@ -9,19 +9,11 @@ import (
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/docker/api/types"
registrytypes "github.com/docker/docker/api/types/registry"
"github.com/docker/docker/client"
"github.com/docker/docker/registry"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
const unencryptedWarning = `WARNING! Your password will be stored unencrypted in %s.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
`
type loginOptions struct {
serverAddress string
user string
@ -55,30 +47,10 @@ func NewLoginCommand(dockerCli command.Cli) *cobra.Command {
return cmd
}
// unencryptedPrompt prompts the user to find out whether they want to continue
// with insecure credential storage. If stdin is not a terminal, we assume they
// want it (sadly), because people may have been scripting insecure logins and
// we don't want to break them. Maybe they'll see the warning in their logs and
// fix things.
func unencryptedPrompt(dockerCli command.Streams, filename string) error {
fmt.Fprintln(dockerCli.Err(), fmt.Sprintf(unencryptedWarning, filename))
func runLogin(dockerCli command.Cli, opts loginOptions) error {
ctx := context.Background()
clnt := dockerCli.Client()
if dockerCli.In().IsTerminal() {
if command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), "") {
return nil
}
return errors.Errorf("User refused unencrypted credentials storage.")
}
return nil
}
type isFileStore interface {
IsFileStore() bool
GetFilename() string
}
func verifyloginOptions(dockerCli command.Cli, opts *loginOptions) error {
if opts.password != "" {
fmt.Fprintln(dockerCli.Err(), "WARNING! Using --password via the CLI is insecure. Use --password-stdin.")
if opts.passwordStdin {
@ -99,15 +71,7 @@ func verifyloginOptions(dockerCli command.Cli, opts *loginOptions) error {
opts.password = strings.TrimSuffix(string(contents), "\n")
opts.password = strings.TrimSuffix(opts.password, "\r")
}
return nil
}
func runLogin(dockerCli command.Cli, opts loginOptions) error { //nolint: gocyclo
ctx := context.Background()
clnt := dockerCli.Client()
if err := verifyloginOptions(dockerCli, &opts); err != nil {
return err
}
var (
serverAddress string
authServer = command.ElectAuthServer(ctx, dockerCli)
@ -118,41 +82,21 @@ func runLogin(dockerCli command.Cli, opts loginOptions) error { //nolint: gocycl
serverAddress = authServer
}
var err error
var authConfig *types.AuthConfig
var response registrytypes.AuthenticateOKBody
isDefaultRegistry := serverAddress == authServer
authConfig, err = command.GetDefaultAuthConfig(dockerCli, opts.user == "" && opts.password == "", serverAddress, isDefaultRegistry)
if err == nil && authConfig.Username != "" && authConfig.Password != "" {
response, err = loginWithCredStoreCreds(ctx, dockerCli, authConfig)
}
if err != nil || authConfig.Username == "" || authConfig.Password == "" {
err = command.ConfigureAuth(dockerCli, opts.user, opts.password, authConfig, isDefaultRegistry)
if err != nil {
return err
}
response, err = clnt.RegistryLogin(ctx, *authConfig)
if err != nil {
return err
}
authConfig, err := command.ConfigureAuth(dockerCli, opts.user, opts.password, serverAddress, isDefaultRegistry)
if err != nil {
return err
}
response, err := clnt.RegistryLogin(ctx, authConfig)
if err != nil {
return err
}
if response.IdentityToken != "" {
authConfig.Password = ""
authConfig.IdentityToken = response.IdentityToken
}
creds := dockerCli.ConfigFile().GetCredentialsStore(serverAddress)
store, isDefault := creds.(isFileStore)
if isDefault {
err = unencryptedPrompt(dockerCli, store.GetFilename())
if err != nil {
return err
}
}
if err := creds.Store(*authConfig); err != nil {
if err := dockerCli.ConfigFile().GetCredentialsStore(serverAddress).Store(authConfig); err != nil {
return errors.Errorf("Error saving credentials: %v", err)
}
@ -161,17 +105,3 @@ func runLogin(dockerCli command.Cli, opts loginOptions) error { //nolint: gocycl
}
return nil
}
func loginWithCredStoreCreds(ctx context.Context, dockerCli command.Cli, authConfig *types.AuthConfig) (registrytypes.AuthenticateOKBody, error) {
fmt.Fprintf(dockerCli.Out(), "Authenticating with existing credentials...\n")
cliClient := dockerCli.Client()
response, err := cliClient.RegistryLogin(ctx, *authConfig)
if err != nil {
if client.IsErrUnauthorized(err) {
fmt.Fprintf(dockerCli.Err(), "Stored credentials invalid or expired\n")
} else {
fmt.Fprintf(dockerCli.Err(), "Login did not succeed, error: %s\n", err)
}
}
return response, err
}

View File

@ -1,157 +0,0 @@
package registry
import (
"bytes"
"fmt"
"testing"
"github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types"
registrytypes "github.com/docker/docker/api/types/registry"
"github.com/docker/docker/client"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/gotestyourself/gotestyourself/fs"
"golang.org/x/net/context"
)
const userErr = "userunknownError"
const testAuthErrMsg = "UNKNOWN_ERR"
var testAuthErrors = map[string]error{
userErr: fmt.Errorf(testAuthErrMsg),
}
var expiredPassword = "I_M_EXPIRED"
type fakeClient struct {
client.Client
}
// nolint: unparam
func (c fakeClient) RegistryLogin(ctx context.Context, auth types.AuthConfig) (registrytypes.AuthenticateOKBody, error) {
if auth.Password == expiredPassword {
return registrytypes.AuthenticateOKBody{}, fmt.Errorf("Invalid Username or Password")
}
err := testAuthErrors[auth.Username]
return registrytypes.AuthenticateOKBody{}, err
}
func TestLoginWithCredStoreCreds(t *testing.T) {
testCases := []struct {
inputAuthConfig types.AuthConfig
expectedMsg string
expectedErr string
}{
{
inputAuthConfig: types.AuthConfig{},
expectedMsg: "Authenticating with existing credentials...\n",
},
{
inputAuthConfig: types.AuthConfig{
Username: userErr,
},
expectedMsg: "Authenticating with existing credentials...\n",
expectedErr: fmt.Sprintf("Login did not succeed, error: %s\n", testAuthErrMsg),
},
// can't easily test the 401 case because client.IsErrUnauthorized(err) involving
// creating an error of a private type
}
ctx := context.Background()
for _, tc := range testCases {
cli := (*test.FakeCli)(test.NewFakeCli(&fakeClient{}))
errBuf := new(bytes.Buffer)
cli.SetErr(errBuf)
loginWithCredStoreCreds(ctx, cli, &tc.inputAuthConfig)
outputString := cli.OutBuffer().String()
assert.Check(t, is.Equal(tc.expectedMsg, outputString))
errorString := errBuf.String()
assert.Check(t, is.Equal(tc.expectedErr, errorString))
}
}
func TestRunLogin(t *testing.T) {
const storedServerAddress = "reg1"
const validUsername = "u1"
const validPassword = "p1"
const validPassword2 = "p2"
validAuthConfig := types.AuthConfig{
ServerAddress: storedServerAddress,
Username: validUsername,
Password: validPassword,
}
expiredAuthConfig := types.AuthConfig{
ServerAddress: storedServerAddress,
Username: validUsername,
Password: expiredPassword,
}
testCases := []struct {
inputLoginOption loginOptions
inputStoredCred *types.AuthConfig
expectedErr string
expectedSavedCred types.AuthConfig
}{
{
inputLoginOption: loginOptions{
serverAddress: storedServerAddress,
},
inputStoredCred: &validAuthConfig,
expectedErr: "",
expectedSavedCred: validAuthConfig,
},
{
inputLoginOption: loginOptions{
serverAddress: storedServerAddress,
},
inputStoredCred: &expiredAuthConfig,
expectedErr: "Error: Cannot perform an interactive login from a non TTY device",
},
{
inputLoginOption: loginOptions{
serverAddress: storedServerAddress,
user: validUsername,
password: validPassword2,
},
inputStoredCred: &validAuthConfig,
expectedErr: "",
expectedSavedCred: types.AuthConfig{
ServerAddress: storedServerAddress,
Username: validUsername,
Password: validPassword2,
},
},
{
inputLoginOption: loginOptions{
serverAddress: storedServerAddress,
user: userErr,
password: validPassword,
},
inputStoredCred: &validAuthConfig,
expectedErr: testAuthErrMsg,
},
}
for i, tc := range testCases {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
tmpFile := fs.NewFile(t, "test-run-login")
defer tmpFile.Remove()
cli := test.NewFakeCli(&fakeClient{})
configfile := cli.ConfigFile()
configfile.Filename = tmpFile.Path()
if tc.inputStoredCred != nil {
cred := *tc.inputStoredCred
configfile.GetCredentialsStore(cred.ServerAddress).Store(cred)
}
loginErr := runLogin(cli, tc.inputLoginOption)
if tc.expectedErr != "" {
assert.Error(t, loginErr, tc.expectedErr)
return
}
assert.NilError(t, loginErr)
savedCred, credStoreErr := configfile.GetCredentialsStore(tc.inputStoredCred.ServerAddress).Get(tc.inputStoredCred.ServerAddress)
assert.Check(t, credStoreErr)
assert.DeepEqual(t, tc.expectedSavedCred, savedCred)
})
}
}

View File

@ -1,17 +1,13 @@
package command_test
import (
"bytes"
"fmt"
"testing"
"github.com/gotestyourself/gotestyourself/assert"
is "github.com/gotestyourself/gotestyourself/assert/cmp"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"golang.org/x/net/context"
// Prevents a circular import with "github.com/docker/cli/internal/test"
. "github.com/docker/cli/cli/command"
"github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types"
@ -23,19 +19,6 @@ type fakeClient struct {
infoFunc func() (types.Info, error)
}
var testAuthConfigs = []types.AuthConfig{
{
ServerAddress: "https://index.docker.io/v1/",
Username: "u0",
Password: "p0",
},
{
ServerAddress: "server1.io",
Username: "u1",
Password: "p1",
},
}
func (cli *fakeClient) Info(_ context.Context) (types.Info, error) {
if cli.infoFunc != nil {
return cli.infoFunc()
@ -81,67 +64,12 @@ func TestElectAuthServer(t *testing.T) {
for _, tc := range testCases {
cli := test.NewFakeCli(&fakeClient{infoFunc: tc.infoFunc})
server := ElectAuthServer(context.Background(), cli)
assert.Check(t, is.Equal(tc.expectedAuthServer, server))
assert.Equal(t, tc.expectedAuthServer, server)
actual := cli.ErrBuffer().String()
if tc.expectedWarning == "" {
assert.Check(t, is.Len(actual, 0))
assert.Empty(t, actual)
} else {
assert.Check(t, is.Contains(actual, tc.expectedWarning))
}
}
}
func TestGetDefaultAuthConfig(t *testing.T) {
testCases := []struct {
checkCredStore bool
inputServerAddress string
expectedErr string
expectedAuthConfig types.AuthConfig
}{
{
checkCredStore: false,
inputServerAddress: "",
expectedErr: "",
expectedAuthConfig: types.AuthConfig{
ServerAddress: "",
Username: "",
Password: "",
},
},
{
checkCredStore: true,
inputServerAddress: testAuthConfigs[0].ServerAddress,
expectedErr: "",
expectedAuthConfig: testAuthConfigs[0],
},
{
checkCredStore: true,
inputServerAddress: testAuthConfigs[1].ServerAddress,
expectedErr: "",
expectedAuthConfig: testAuthConfigs[1],
},
{
checkCredStore: true,
inputServerAddress: fmt.Sprintf("https://%s", testAuthConfigs[1].ServerAddress),
expectedErr: "",
expectedAuthConfig: testAuthConfigs[1],
},
}
cli := test.NewFakeCli(&fakeClient{})
errBuf := new(bytes.Buffer)
cli.SetErr(errBuf)
for _, authconfig := range testAuthConfigs {
cli.ConfigFile().GetCredentialsStore(authconfig.ServerAddress).Store(authconfig)
}
for _, tc := range testCases {
serverAddress := tc.inputServerAddress
authconfig, err := GetDefaultAuthConfig(cli, tc.checkCredStore, serverAddress, serverAddress == "https://index.docker.io/v1/")
if tc.expectedErr != "" {
assert.Check(t, err != nil)
assert.Check(t, is.Equal(tc.expectedErr, err.Error()))
} else {
assert.NilError(t, err)
assert.Check(t, is.DeepEqual(tc.expectedAuthConfig, *authconfig))
assert.Contains(t, actual, tc.expectedWarning)
}
}
}

View File

@ -16,11 +16,10 @@ import (
)
type createOptions struct {
name string
driver string
templateDriver string
file string
labels opts.ListOpts
name string
driver string
file string
labels opts.ListOpts
}
func newSecretCreateCommand(dockerCli command.Cli) *cobra.Command {
@ -44,8 +43,6 @@ func newSecretCreateCommand(dockerCli command.Cli) *cobra.Command {
flags.VarP(&options.labels, "label", "l", "Secret labels")
flags.StringVarP(&options.driver, "driver", "d", "", "Secret driver")
flags.SetAnnotation("driver", "version", []string{"1.31"})
flags.StringVar(&options.templateDriver, "template-driver", "", "Template driver")
flags.SetAnnotation("driver", "version", []string{"1.37"})
return cmd
}
@ -74,11 +71,7 @@ func runSecretCreate(dockerCli command.Cli, options createOptions) error {
Name: options.driver,
}
}
if options.templateDriver != "" {
spec.Templating = &swarm.Driver{
Name: options.templateDriver,
}
}
r, err := client.SecretCreate(ctx, spec)
if err != nil {
return err

Some files were not shown because too many files have changed in this diff Show More