github.1git.de/docker/cli@v26.1.3+incompatible/cli/command/volume/prune_test.go (about) 1 package volume 2 3 import ( 4 "context" 5 "fmt" 6 "io" 7 "runtime" 8 "strings" 9 "testing" 10 11 "github.com/docker/cli/cli/streams" 12 "github.com/docker/cli/internal/test" 13 "github.com/docker/docker/api/types" 14 "github.com/docker/docker/api/types/filters" 15 "github.com/pkg/errors" 16 "gotest.tools/v3/assert" 17 is "gotest.tools/v3/assert/cmp" 18 "gotest.tools/v3/golden" 19 "gotest.tools/v3/skip" 20 ) 21 22 func TestVolumePruneErrors(t *testing.T) { 23 testCases := []struct { 24 name string 25 args []string 26 flags map[string]string 27 volumePruneFunc func(args filters.Args) (types.VolumesPruneReport, error) 28 expectedError string 29 }{ 30 { 31 name: "accepts no arguments", 32 args: []string{"foo"}, 33 expectedError: "accepts no argument", 34 }, 35 { 36 name: "forced but other error", 37 flags: map[string]string{ 38 "force": "true", 39 }, 40 volumePruneFunc: func(args filters.Args) (types.VolumesPruneReport, error) { 41 return types.VolumesPruneReport{}, errors.Errorf("error pruning volumes") 42 }, 43 expectedError: "error pruning volumes", 44 }, 45 { 46 name: "conflicting options", 47 flags: map[string]string{ 48 "all": "true", 49 "filter": "all=1", 50 }, 51 expectedError: "conflicting options: cannot specify both --all and --filter all=1", 52 }, 53 } 54 for _, tc := range testCases { 55 tc := tc 56 t.Run(tc.name, func(t *testing.T) { 57 cmd := NewPruneCommand( 58 test.NewFakeCli(&fakeClient{ 59 volumePruneFunc: tc.volumePruneFunc, 60 }), 61 ) 62 cmd.SetArgs(tc.args) 63 for key, value := range tc.flags { 64 cmd.Flags().Set(key, value) 65 } 66 cmd.SetOut(io.Discard) 67 cmd.SetErr(io.Discard) 68 assert.ErrorContains(t, cmd.Execute(), tc.expectedError) 69 }) 70 } 71 } 72 73 func TestVolumePruneSuccess(t *testing.T) { 74 testCases := []struct { 75 name string 76 args []string 77 input string 78 volumePruneFunc func(args filters.Args) (types.VolumesPruneReport, error) 79 }{ 80 { 81 name: "all", 82 args: []string{"--all"}, 83 input: "y", 84 volumePruneFunc: func(pruneFilter filters.Args) (types.VolumesPruneReport, error) { 85 assert.Check(t, is.DeepEqual([]string{"true"}, pruneFilter.Get("all"))) 86 return types.VolumesPruneReport{}, nil 87 }, 88 }, 89 { 90 name: "all-forced", 91 args: []string{"--all", "--force"}, 92 volumePruneFunc: func(pruneFilter filters.Args) (types.VolumesPruneReport, error) { 93 return types.VolumesPruneReport{}, nil 94 }, 95 }, 96 { 97 name: "label-filter", 98 args: []string{"--filter", "label=foobar"}, 99 input: "y", 100 volumePruneFunc: func(pruneFilter filters.Args) (types.VolumesPruneReport, error) { 101 assert.Check(t, is.DeepEqual([]string{"foobar"}, pruneFilter.Get("label"))) 102 return types.VolumesPruneReport{}, nil 103 }, 104 }, 105 } 106 for _, tc := range testCases { 107 tc := tc 108 t.Run(tc.name, func(t *testing.T) { 109 cli := test.NewFakeCli(&fakeClient{volumePruneFunc: tc.volumePruneFunc}) 110 cmd := NewPruneCommand(cli) 111 if tc.input != "" { 112 cli.SetIn(streams.NewIn(io.NopCloser(strings.NewReader(tc.input)))) 113 } 114 cmd.SetOut(io.Discard) 115 cmd.SetArgs(tc.args) 116 err := cmd.Execute() 117 assert.NilError(t, err) 118 golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("volume-prune-success.%s.golden", tc.name)) 119 }) 120 } 121 } 122 123 func TestVolumePruneForce(t *testing.T) { 124 testCases := []struct { 125 name string 126 volumePruneFunc func(args filters.Args) (types.VolumesPruneReport, error) 127 }{ 128 { 129 name: "empty", 130 }, 131 { 132 name: "deletedVolumes", 133 volumePruneFunc: simplePruneFunc, 134 }, 135 } 136 for _, tc := range testCases { 137 cli := test.NewFakeCli(&fakeClient{ 138 volumePruneFunc: tc.volumePruneFunc, 139 }) 140 cmd := NewPruneCommand(cli) 141 cmd.Flags().Set("force", "true") 142 assert.NilError(t, cmd.Execute()) 143 golden.Assert(t, cli.OutBuffer().String(), fmt.Sprintf("volume-prune.%s.golden", tc.name)) 144 } 145 } 146 147 func TestVolumePrunePromptYes(t *testing.T) { 148 // FIXME(vdemeester) make it work.. 149 skip.If(t, runtime.GOOS == "windows", "TODO: fix test on windows") 150 151 for _, input := range []string{"y", "Y"} { 152 cli := test.NewFakeCli(&fakeClient{ 153 volumePruneFunc: simplePruneFunc, 154 }) 155 156 cli.SetIn(streams.NewIn(io.NopCloser(strings.NewReader(input)))) 157 cmd := NewPruneCommand(cli) 158 cmd.SetArgs([]string{}) 159 assert.NilError(t, cmd.Execute()) 160 golden.Assert(t, cli.OutBuffer().String(), "volume-prune-yes.golden") 161 } 162 } 163 164 func TestVolumePrunePromptNo(t *testing.T) { 165 // FIXME(vdemeester) make it work.. 166 skip.If(t, runtime.GOOS == "windows", "TODO: fix test on windows") 167 168 for _, input := range []string{"n", "N", "no", "anything", "really"} { 169 cli := test.NewFakeCli(&fakeClient{ 170 volumePruneFunc: simplePruneFunc, 171 }) 172 173 cli.SetIn(streams.NewIn(io.NopCloser(strings.NewReader(input)))) 174 cmd := NewPruneCommand(cli) 175 cmd.SetArgs([]string{}) 176 assert.ErrorContains(t, cmd.Execute(), "volume prune has been cancelled") 177 golden.Assert(t, cli.OutBuffer().String(), "volume-prune-no.golden") 178 } 179 } 180 181 func simplePruneFunc(filters.Args) (types.VolumesPruneReport, error) { 182 return types.VolumesPruneReport{ 183 VolumesDeleted: []string{ 184 "foo", "bar", "baz", 185 }, 186 SpaceReclaimed: 2000, 187 }, nil 188 } 189 190 func TestVolumePrunePromptTerminate(t *testing.T) { 191 ctx, cancel := context.WithCancel(context.Background()) 192 t.Cleanup(cancel) 193 194 cli := test.NewFakeCli(&fakeClient{ 195 volumePruneFunc: func(filter filters.Args) (types.VolumesPruneReport, error) { 196 return types.VolumesPruneReport{}, errors.New("fakeClient volumePruneFunc should not be called") 197 }, 198 }) 199 200 cmd := NewPruneCommand(cli) 201 cmd.SetArgs([]string{}) 202 test.TerminatePrompt(ctx, t, cmd, cli) 203 golden.Assert(t, cli.OutBuffer().String(), "volume-prune-terminate.golden") 204 }