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  }