github.1git.de/docker/cli@v26.1.3+incompatible/cli/command/service/create_test.go (about) 1 package service 2 3 import ( 4 "context" 5 "testing" 6 7 "github.com/docker/docker/api/types" 8 "github.com/docker/docker/api/types/swarm" 9 "gotest.tools/v3/assert" 10 is "gotest.tools/v3/assert/cmp" 11 12 cliopts "github.com/docker/cli/opts" 13 ) 14 15 // fakeConfigAPIClientList is used to let us pass a closure as a 16 // ConfigAPIClient, to use as ConfigList. for all the other methods in the 17 // interface, it does nothing, not even return an error, so don't use them 18 type fakeConfigAPIClientList func(context.Context, types.ConfigListOptions) ([]swarm.Config, error) 19 20 func (f fakeConfigAPIClientList) ConfigList(ctx context.Context, opts types.ConfigListOptions) ([]swarm.Config, error) { 21 return f(ctx, opts) 22 } 23 24 func (f fakeConfigAPIClientList) ConfigCreate(_ context.Context, _ swarm.ConfigSpec) (types.ConfigCreateResponse, error) { 25 return types.ConfigCreateResponse{}, nil 26 } 27 28 func (f fakeConfigAPIClientList) ConfigRemove(_ context.Context, _ string) error { 29 return nil 30 } 31 32 func (f fakeConfigAPIClientList) ConfigInspectWithRaw(_ context.Context, _ string) (swarm.Config, []byte, error) { 33 return swarm.Config{}, nil, nil 34 } 35 36 func (f fakeConfigAPIClientList) ConfigUpdate(_ context.Context, _ string, _ swarm.Version, _ swarm.ConfigSpec) error { 37 return nil 38 } 39 40 // TestSetConfigsWithCredSpecAndConfigs tests that the setConfigs function for 41 // create correctly looks up the right configs, and correctly handles the 42 // credentialSpec 43 func TestSetConfigsWithCredSpecAndConfigs(t *testing.T) { 44 // we can't directly access the internal fields of the ConfigOpt struct, so 45 // we need to let it do the parsing 46 configOpt := &cliopts.ConfigOpt{} 47 configOpt.Set("bar") 48 opts := &serviceOptions{ 49 credentialSpec: credentialSpecOpt{ 50 value: &swarm.CredentialSpec{ 51 Config: "foo", 52 }, 53 source: "config://foo", 54 }, 55 configs: *configOpt, 56 } 57 58 // create a service spec. we need to be sure to fill in the nullable 59 // fields, like the code expects 60 service := &swarm.ServiceSpec{ 61 TaskTemplate: swarm.TaskSpec{ 62 ContainerSpec: &swarm.ContainerSpec{ 63 Privileges: &swarm.Privileges{ 64 CredentialSpec: opts.credentialSpec.value, 65 }, 66 }, 67 }, 68 } 69 70 // set up a function to use as the list function 71 var fakeClient fakeConfigAPIClientList = func(_ context.Context, opts types.ConfigListOptions) ([]swarm.Config, error) { 72 f := opts.Filters 73 74 // we're expecting the filter to have names "foo" and "bar" 75 names := f.Get("name") 76 assert.Equal(t, len(names), 2) 77 assert.Assert(t, is.Contains(names, "foo")) 78 assert.Assert(t, is.Contains(names, "bar")) 79 80 return []swarm.Config{ 81 { 82 ID: "fooID", 83 Spec: swarm.ConfigSpec{ 84 Annotations: swarm.Annotations{ 85 Name: "foo", 86 }, 87 }, 88 }, { 89 ID: "barID", 90 Spec: swarm.ConfigSpec{ 91 Annotations: swarm.Annotations{ 92 Name: "bar", 93 }, 94 }, 95 }, 96 }, nil 97 } 98 99 ctx := context.Background() 100 101 // now call setConfigs 102 err := setConfigs(ctx, fakeClient, service, opts) 103 // verify no error is returned 104 assert.NilError(t, err) 105 106 credSpecConfigValue := service.TaskTemplate.ContainerSpec.Privileges.CredentialSpec.Config 107 assert.Equal(t, credSpecConfigValue, "fooID") 108 109 configRefs := service.TaskTemplate.ContainerSpec.Configs 110 assert.Assert(t, is.Contains(configRefs, &swarm.ConfigReference{ 111 ConfigID: "fooID", 112 ConfigName: "foo", 113 Runtime: &swarm.ConfigReferenceRuntimeTarget{}, 114 }), "expected configRefs to contain foo config") 115 assert.Assert(t, is.Contains(configRefs, &swarm.ConfigReference{ 116 ConfigID: "barID", 117 ConfigName: "bar", 118 File: &swarm.ConfigReferenceFileTarget{ 119 Name: "bar", 120 // these are the default field values 121 UID: "0", 122 GID: "0", 123 Mode: 0o444, 124 }, 125 }), "expected configRefs to contain bar config") 126 } 127 128 // TestSetConfigsOnlyCredSpec tests that even if a CredentialSpec is the only 129 // config needed, setConfigs still works 130 func TestSetConfigsOnlyCredSpec(t *testing.T) { 131 opts := &serviceOptions{ 132 credentialSpec: credentialSpecOpt{ 133 value: &swarm.CredentialSpec{ 134 Config: "foo", 135 }, 136 source: "config://foo", 137 }, 138 } 139 140 service := &swarm.ServiceSpec{ 141 TaskTemplate: swarm.TaskSpec{ 142 ContainerSpec: &swarm.ContainerSpec{ 143 Privileges: &swarm.Privileges{ 144 CredentialSpec: opts.credentialSpec.value, 145 }, 146 }, 147 }, 148 } 149 150 // set up a function to use as the list function 151 var fakeClient fakeConfigAPIClientList = func(_ context.Context, opts types.ConfigListOptions) ([]swarm.Config, error) { 152 f := opts.Filters 153 154 names := f.Get("name") 155 assert.Equal(t, len(names), 1) 156 assert.Assert(t, is.Contains(names, "foo")) 157 158 return []swarm.Config{ 159 { 160 ID: "fooID", 161 Spec: swarm.ConfigSpec{ 162 Annotations: swarm.Annotations{ 163 Name: "foo", 164 }, 165 }, 166 }, 167 }, nil 168 } 169 170 // now call setConfigs 171 ctx := context.Background() 172 err := setConfigs(ctx, fakeClient, service, opts) 173 // verify no error is returned 174 assert.NilError(t, err) 175 176 credSpecConfigValue := service.TaskTemplate.ContainerSpec.Privileges.CredentialSpec.Config 177 assert.Equal(t, credSpecConfigValue, "fooID") 178 179 configRefs := service.TaskTemplate.ContainerSpec.Configs 180 assert.Assert(t, is.Contains(configRefs, &swarm.ConfigReference{ 181 ConfigID: "fooID", 182 ConfigName: "foo", 183 Runtime: &swarm.ConfigReferenceRuntimeTarget{}, 184 })) 185 } 186 187 // TestSetConfigsOnlyConfigs verifies setConfigs when only configs (and not a 188 // CredentialSpec) is needed. 189 func TestSetConfigsOnlyConfigs(t *testing.T) { 190 configOpt := &cliopts.ConfigOpt{} 191 configOpt.Set("bar") 192 opts := &serviceOptions{ 193 configs: *configOpt, 194 } 195 196 service := &swarm.ServiceSpec{ 197 TaskTemplate: swarm.TaskSpec{ 198 ContainerSpec: &swarm.ContainerSpec{}, 199 }, 200 } 201 202 var fakeClient fakeConfigAPIClientList = func(_ context.Context, opts types.ConfigListOptions) ([]swarm.Config, error) { 203 f := opts.Filters 204 205 names := f.Get("name") 206 assert.Equal(t, len(names), 1) 207 assert.Assert(t, is.Contains(names, "bar")) 208 209 return []swarm.Config{ 210 { 211 ID: "barID", 212 Spec: swarm.ConfigSpec{ 213 Annotations: swarm.Annotations{ 214 Name: "bar", 215 }, 216 }, 217 }, 218 }, nil 219 } 220 221 // now call setConfigs 222 ctx := context.Background() 223 err := setConfigs(ctx, fakeClient, service, opts) 224 // verify no error is returned 225 assert.NilError(t, err) 226 227 configRefs := service.TaskTemplate.ContainerSpec.Configs 228 assert.Assert(t, is.Contains(configRefs, &swarm.ConfigReference{ 229 ConfigID: "barID", 230 ConfigName: "bar", 231 File: &swarm.ConfigReferenceFileTarget{ 232 Name: "bar", 233 // these are the default field values 234 UID: "0", 235 GID: "0", 236 Mode: 0o444, 237 }, 238 })) 239 } 240 241 // TestSetConfigsNoConfigs checks that setConfigs works when there are no 242 // configs of any kind needed 243 func TestSetConfigsNoConfigs(t *testing.T) { 244 // add a credentialSpec that isn't a config 245 opts := &serviceOptions{ 246 credentialSpec: credentialSpecOpt{ 247 value: &swarm.CredentialSpec{ 248 File: "foo", 249 }, 250 source: "file://foo", 251 }, 252 } 253 service := &swarm.ServiceSpec{ 254 TaskTemplate: swarm.TaskSpec{ 255 ContainerSpec: &swarm.ContainerSpec{ 256 Privileges: &swarm.Privileges{ 257 CredentialSpec: opts.credentialSpec.value, 258 }, 259 }, 260 }, 261 } 262 263 var fakeClient fakeConfigAPIClientList = func(_ context.Context, opts types.ConfigListOptions) ([]swarm.Config, error) { 264 // assert false -- we should never call this function 265 assert.Assert(t, false, "we should not be listing configs") 266 return nil, nil 267 } 268 269 ctx := context.Background() 270 err := setConfigs(ctx, fakeClient, service, opts) 271 assert.NilError(t, err) 272 273 // ensure that the value of the credentialspec has not changed 274 assert.Equal(t, service.TaskTemplate.ContainerSpec.Privileges.CredentialSpec.File, "foo") 275 assert.Equal(t, service.TaskTemplate.ContainerSpec.Privileges.CredentialSpec.Config, "") 276 }