github.com/argoproj/argo-cd/v3@v3.2.1/applicationset/generators/generator_spec_processor_test.go (about)

     1  package generators
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  
     7  	log "github.com/sirupsen/logrus"
     8  	"github.com/stretchr/testify/assert"
     9  	"github.com/stretchr/testify/require"
    10  	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
    11  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    12  
    13  	"github.com/argoproj/argo-cd/v3/applicationset/services/mocks"
    14  
    15  	argov1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
    16  
    17  	"github.com/stretchr/testify/mock"
    18  	corev1 "k8s.io/api/core/v1"
    19  	"k8s.io/apimachinery/pkg/runtime"
    20  	kubefake "k8s.io/client-go/kubernetes/fake"
    21  	crtclient "sigs.k8s.io/controller-runtime/pkg/client"
    22  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    23  )
    24  
    25  func TestMatchValues(t *testing.T) {
    26  	testCases := []struct {
    27  		name     string
    28  		elements []apiextensionsv1.JSON
    29  		selector *metav1.LabelSelector
    30  		expected []map[string]any
    31  	}{
    32  		{
    33  			name:     "no filter",
    34  			elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url"}`)}},
    35  			selector: &metav1.LabelSelector{},
    36  			expected: []map[string]any{{"cluster": "cluster", "url": "url"}},
    37  		},
    38  		{
    39  			name:     "nil",
    40  			elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url"}`)}},
    41  			selector: nil,
    42  			expected: []map[string]any{{"cluster": "cluster", "url": "url"}},
    43  		},
    44  		{
    45  			name:     "values.foo should be foo but is ignore element",
    46  			elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url","values":{"foo":"bar"}}`)}},
    47  			selector: &metav1.LabelSelector{
    48  				MatchLabels: map[string]string{
    49  					"values.foo": "foo",
    50  				},
    51  			},
    52  			expected: []map[string]any{},
    53  		},
    54  		{
    55  			name:     "values.foo should be bar",
    56  			elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url","values":{"foo":"bar"}}`)}},
    57  			selector: &metav1.LabelSelector{
    58  				MatchLabels: map[string]string{
    59  					"values.foo": "bar",
    60  				},
    61  			},
    62  			expected: []map[string]any{{"cluster": "cluster", "url": "url", "values.foo": "bar"}},
    63  		},
    64  	}
    65  
    66  	for _, testCase := range testCases {
    67  		t.Run(testCase.name, func(t *testing.T) {
    68  			listGenerator := NewListGenerator()
    69  			data := map[string]Generator{
    70  				"List": listGenerator,
    71  			}
    72  
    73  			applicationSetInfo := argov1alpha1.ApplicationSet{
    74  				ObjectMeta: metav1.ObjectMeta{
    75  					Name: "set",
    76  				},
    77  				Spec: argov1alpha1.ApplicationSetSpec{
    78  					GoTemplate: false,
    79  				},
    80  			}
    81  
    82  			results, err := Transform(argov1alpha1.ApplicationSetGenerator{
    83  				Selector: testCase.selector,
    84  				List: &argov1alpha1.ListGenerator{
    85  					Elements: testCase.elements,
    86  					Template: emptyTemplate(),
    87  				},
    88  			},
    89  				data,
    90  				emptyTemplate(),
    91  				&applicationSetInfo, nil, nil)
    92  
    93  			require.NoError(t, err)
    94  			assert.ElementsMatch(t, testCase.expected, results[0].Params)
    95  		})
    96  	}
    97  }
    98  
    99  func TestMatchValuesGoTemplate(t *testing.T) {
   100  	testCases := []struct {
   101  		name     string
   102  		elements []apiextensionsv1.JSON
   103  		selector *metav1.LabelSelector
   104  		expected []map[string]any
   105  	}{
   106  		{
   107  			name:     "no filter",
   108  			elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url"}`)}},
   109  			selector: &metav1.LabelSelector{},
   110  			expected: []map[string]any{{"cluster": "cluster", "url": "url"}},
   111  		},
   112  		{
   113  			name:     "nil",
   114  			elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url"}`)}},
   115  			selector: nil,
   116  			expected: []map[string]any{{"cluster": "cluster", "url": "url"}},
   117  		},
   118  		{
   119  			name:     "values.foo should be foo but is ignore element",
   120  			elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url","values":{"foo":"bar"}}`)}},
   121  			selector: &metav1.LabelSelector{
   122  				MatchLabels: map[string]string{
   123  					"values.foo": "foo",
   124  				},
   125  			},
   126  			expected: []map[string]any{},
   127  		},
   128  		{
   129  			name:     "values.foo should be bar",
   130  			elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url","values":{"foo":"bar"}}`)}},
   131  			selector: &metav1.LabelSelector{
   132  				MatchLabels: map[string]string{
   133  					"values.foo": "bar",
   134  				},
   135  			},
   136  			expected: []map[string]any{{"cluster": "cluster", "url": "url", "values": map[string]any{"foo": "bar"}}},
   137  		},
   138  		{
   139  			name:     "values.0 should be bar",
   140  			elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url","values":["bar"]}`)}},
   141  			selector: &metav1.LabelSelector{
   142  				MatchLabels: map[string]string{
   143  					"values.0": "bar",
   144  				},
   145  			},
   146  			expected: []map[string]any{{"cluster": "cluster", "url": "url", "values": []any{"bar"}}},
   147  		},
   148  	}
   149  
   150  	for _, testCase := range testCases {
   151  		t.Run(testCase.name, func(t *testing.T) {
   152  			listGenerator := NewListGenerator()
   153  			data := map[string]Generator{
   154  				"List": listGenerator,
   155  			}
   156  
   157  			applicationSetInfo := argov1alpha1.ApplicationSet{
   158  				ObjectMeta: metav1.ObjectMeta{
   159  					Name: "set",
   160  				},
   161  				Spec: argov1alpha1.ApplicationSetSpec{
   162  					GoTemplate: true,
   163  				},
   164  			}
   165  
   166  			results, err := Transform(argov1alpha1.ApplicationSetGenerator{
   167  				Selector: testCase.selector,
   168  				List: &argov1alpha1.ListGenerator{
   169  					Elements: testCase.elements,
   170  					Template: emptyTemplate(),
   171  				},
   172  			},
   173  				data,
   174  				emptyTemplate(),
   175  				&applicationSetInfo, nil, nil)
   176  
   177  			require.NoError(t, err)
   178  			assert.ElementsMatch(t, testCase.expected, results[0].Params)
   179  		})
   180  	}
   181  }
   182  
   183  func TestTransForm(t *testing.T) {
   184  	testCases := []struct {
   185  		name     string
   186  		selector *metav1.LabelSelector
   187  		expected []map[string]any
   188  	}{
   189  		{
   190  			name: "server filter",
   191  			selector: &metav1.LabelSelector{
   192  				MatchLabels: map[string]string{"server": "https://production-01.example.com"},
   193  			},
   194  			expected: []map[string]any{{
   195  				"metadata.annotations.foo.argoproj.io":           "production",
   196  				"metadata.labels.argocd.argoproj.io/secret-type": "cluster",
   197  				"metadata.labels.environment":                    "production",
   198  				"metadata.labels.org":                            "bar",
   199  				"name":                                           "production_01/west",
   200  				"nameNormalized":                                 "production-01-west",
   201  				"server":                                         "https://production-01.example.com",
   202  				"project":                                        "",
   203  			}},
   204  		},
   205  		{
   206  			name: "server filter with long url",
   207  			selector: &metav1.LabelSelector{
   208  				MatchLabels: map[string]string{"server": "https://some-really-long-url-that-will-exceed-63-characters.com"},
   209  			},
   210  			expected: []map[string]any{{
   211  				"metadata.annotations.foo.argoproj.io":           "production",
   212  				"metadata.labels.argocd.argoproj.io/secret-type": "cluster",
   213  				"metadata.labels.environment":                    "production",
   214  				"metadata.labels.org":                            "bar",
   215  				"name":                                           "some-really-long-server-url",
   216  				"nameNormalized":                                 "some-really-long-server-url",
   217  				"server":                                         "https://some-really-long-url-that-will-exceed-63-characters.com",
   218  				"project":                                        "",
   219  			}},
   220  		},
   221  	}
   222  
   223  	for _, testCase := range testCases {
   224  		t.Run(testCase.name, func(t *testing.T) {
   225  			testGenerators := map[string]Generator{
   226  				"Clusters": getMockClusterGenerator(),
   227  			}
   228  
   229  			applicationSetInfo := argov1alpha1.ApplicationSet{
   230  				ObjectMeta: metav1.ObjectMeta{
   231  					Name: "set",
   232  				},
   233  				Spec: argov1alpha1.ApplicationSetSpec{},
   234  			}
   235  
   236  			results, err := Transform(
   237  				argov1alpha1.ApplicationSetGenerator{
   238  					Selector: testCase.selector,
   239  					Clusters: &argov1alpha1.ClusterGenerator{
   240  						Selector: metav1.LabelSelector{},
   241  						Template: argov1alpha1.ApplicationSetTemplate{},
   242  						Values:   nil,
   243  					},
   244  				},
   245  				testGenerators,
   246  				emptyTemplate(),
   247  				&applicationSetInfo, nil, nil)
   248  
   249  			require.NoError(t, err)
   250  			assert.ElementsMatch(t, testCase.expected, results[0].Params)
   251  		})
   252  	}
   253  }
   254  
   255  func emptyTemplate() argov1alpha1.ApplicationSetTemplate {
   256  	return argov1alpha1.ApplicationSetTemplate{
   257  		Spec: argov1alpha1.ApplicationSpec{
   258  			Project: "project",
   259  		},
   260  	}
   261  }
   262  
   263  func getMockClusterGenerator() Generator {
   264  	clusters := []crtclient.Object{
   265  		&corev1.Secret{
   266  			TypeMeta: metav1.TypeMeta{
   267  				Kind:       "Secret",
   268  				APIVersion: "v1",
   269  			},
   270  			ObjectMeta: metav1.ObjectMeta{
   271  				Name:      "staging-01",
   272  				Namespace: "namespace",
   273  				Labels: map[string]string{
   274  					"argocd.argoproj.io/secret-type": "cluster",
   275  					"environment":                    "staging",
   276  					"org":                            "foo",
   277  				},
   278  				Annotations: map[string]string{
   279  					"foo.argoproj.io": "staging",
   280  				},
   281  			},
   282  			Data: map[string][]byte{
   283  				"config": []byte("{}"),
   284  				"name":   []byte("staging-01"),
   285  				"server": []byte("https://staging-01.example.com"),
   286  			},
   287  			Type: corev1.SecretType("Opaque"),
   288  		},
   289  		&corev1.Secret{
   290  			TypeMeta: metav1.TypeMeta{
   291  				Kind:       "Secret",
   292  				APIVersion: "v1",
   293  			},
   294  			ObjectMeta: metav1.ObjectMeta{
   295  				Name:      "production-01",
   296  				Namespace: "namespace",
   297  				Labels: map[string]string{
   298  					"argocd.argoproj.io/secret-type": "cluster",
   299  					"environment":                    "production",
   300  					"org":                            "bar",
   301  				},
   302  				Annotations: map[string]string{
   303  					"foo.argoproj.io": "production",
   304  				},
   305  			},
   306  			Data: map[string][]byte{
   307  				"config": []byte("{}"),
   308  				"name":   []byte("production_01/west"),
   309  				"server": []byte("https://production-01.example.com"),
   310  			},
   311  			Type: corev1.SecretType("Opaque"),
   312  		},
   313  		&corev1.Secret{
   314  			TypeMeta: metav1.TypeMeta{
   315  				Kind:       "Secret",
   316  				APIVersion: "v1",
   317  			},
   318  			ObjectMeta: metav1.ObjectMeta{
   319  				Name:      "some-really-long-server-url",
   320  				Namespace: "namespace",
   321  				Labels: map[string]string{
   322  					"argocd.argoproj.io/secret-type": "cluster",
   323  					"environment":                    "production",
   324  					"org":                            "bar",
   325  				},
   326  				Annotations: map[string]string{
   327  					"foo.argoproj.io": "production",
   328  				},
   329  			},
   330  			Data: map[string][]byte{
   331  				"config": []byte("{}"),
   332  				"name":   []byte("some-really-long-server-url"),
   333  				"server": []byte("https://some-really-long-url-that-will-exceed-63-characters.com"),
   334  			},
   335  			Type: corev1.SecretType("Opaque"),
   336  		},
   337  	}
   338  	runtimeClusters := []runtime.Object{}
   339  	for _, clientCluster := range clusters {
   340  		runtimeClusters = append(runtimeClusters, clientCluster)
   341  	}
   342  	appClientset := kubefake.NewSimpleClientset(runtimeClusters...)
   343  
   344  	fakeClient := fake.NewClientBuilder().WithObjects(clusters...).Build()
   345  	return NewClusterGenerator(context.Background(), fakeClient, appClientset, "namespace")
   346  }
   347  
   348  func getMockGitGenerator() Generator {
   349  	argoCDServiceMock := mocks.Repos{}
   350  	argoCDServiceMock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything).Return([]string{"app1", "app2", "app_3", "p1/app4"}, nil)
   351  	gitGenerator := NewGitGenerator(&argoCDServiceMock, "namespace")
   352  	return gitGenerator
   353  }
   354  
   355  func TestGetRelevantGenerators(t *testing.T) {
   356  	testGenerators := map[string]Generator{
   357  		"Clusters": getMockClusterGenerator(),
   358  		"Git":      getMockGitGenerator(),
   359  	}
   360  
   361  	testGenerators["Matrix"] = NewMatrixGenerator(testGenerators)
   362  	testGenerators["Merge"] = NewMergeGenerator(testGenerators)
   363  	testGenerators["List"] = NewListGenerator()
   364  
   365  	requestedGenerator := &argov1alpha1.ApplicationSetGenerator{
   366  		List: &argov1alpha1.ListGenerator{
   367  			Elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url","values":{"foo":"bar"}}`)}},
   368  		},
   369  	}
   370  
   371  	relevantGenerators := GetRelevantGenerators(requestedGenerator, testGenerators)
   372  	assert.Len(t, relevantGenerators, 1)
   373  	assert.IsType(t, &ListGenerator{}, relevantGenerators[0])
   374  
   375  	requestedGenerator = &argov1alpha1.ApplicationSetGenerator{
   376  		Clusters: &argov1alpha1.ClusterGenerator{
   377  			Selector: metav1.LabelSelector{},
   378  			Template: argov1alpha1.ApplicationSetTemplate{},
   379  			Values:   nil,
   380  		},
   381  	}
   382  
   383  	relevantGenerators = GetRelevantGenerators(requestedGenerator, testGenerators)
   384  	assert.Len(t, relevantGenerators, 1)
   385  	assert.IsType(t, &ClusterGenerator{}, relevantGenerators[0])
   386  
   387  	requestedGenerator = &argov1alpha1.ApplicationSetGenerator{
   388  		Git: &argov1alpha1.GitGenerator{
   389  			RepoURL:             "",
   390  			Directories:         nil,
   391  			Files:               nil,
   392  			Revision:            "",
   393  			RequeueAfterSeconds: nil,
   394  			Template:            argov1alpha1.ApplicationSetTemplate{},
   395  		},
   396  	}
   397  
   398  	relevantGenerators = GetRelevantGenerators(requestedGenerator, testGenerators)
   399  	assert.Len(t, relevantGenerators, 1)
   400  	assert.IsType(t, &GitGenerator{}, relevantGenerators[0])
   401  }
   402  
   403  func TestInterpolateGenerator(t *testing.T) {
   404  	requestedGenerator := &argov1alpha1.ApplicationSetGenerator{
   405  		Clusters: &argov1alpha1.ClusterGenerator{
   406  			Selector: metav1.LabelSelector{
   407  				MatchLabels: map[string]string{
   408  					"argocd.argoproj.io/secret-type": "cluster",
   409  					"path-basename":                  "{{path.basename}}",
   410  					"path-zero":                      "{{path[0]}}",
   411  					"path-full":                      "{{path}}",
   412  				},
   413  			},
   414  		},
   415  	}
   416  	gitGeneratorParams := map[string]any{
   417  		"path":                    "p1/p2/app3",
   418  		"path.basename":           "app3",
   419  		"path[0]":                 "p1",
   420  		"path[1]":                 "p2",
   421  		"path.basenameNormalized": "app3",
   422  	}
   423  	interpolatedGenerator, err := InterpolateGenerator(requestedGenerator, gitGeneratorParams, false, nil)
   424  	if err != nil {
   425  		log.WithError(err).WithField("requestedGenerator", requestedGenerator).Error("error interpolating Generator")
   426  		return
   427  	}
   428  	assert.Equal(t, "app3", interpolatedGenerator.Clusters.Selector.MatchLabels["path-basename"])
   429  	assert.Equal(t, "p1", interpolatedGenerator.Clusters.Selector.MatchLabels["path-zero"])
   430  	assert.Equal(t, "p1/p2/app3", interpolatedGenerator.Clusters.Selector.MatchLabels["path-full"])
   431  
   432  	fileNamePath := argov1alpha1.GitFileGeneratorItem{
   433  		Path: "{{name}}",
   434  	}
   435  	fileServerPath := argov1alpha1.GitFileGeneratorItem{
   436  		Path: "{{server}}",
   437  	}
   438  
   439  	requestedGenerator = &argov1alpha1.ApplicationSetGenerator{
   440  		Git: &argov1alpha1.GitGenerator{
   441  			Files:    append([]argov1alpha1.GitFileGeneratorItem{}, fileNamePath, fileServerPath),
   442  			Template: argov1alpha1.ApplicationSetTemplate{},
   443  		},
   444  	}
   445  	clusterGeneratorParams := map[string]any{
   446  		"name": "production_01/west", "server": "https://production-01.example.com",
   447  	}
   448  	interpolatedGenerator, err = InterpolateGenerator(requestedGenerator, clusterGeneratorParams, false, nil)
   449  	if err != nil {
   450  		log.WithError(err).WithField("requestedGenerator", requestedGenerator).Error("error interpolating Generator")
   451  		return
   452  	}
   453  	assert.Equal(t, "production_01/west", interpolatedGenerator.Git.Files[0].Path)
   454  	assert.Equal(t, "https://production-01.example.com", interpolatedGenerator.Git.Files[1].Path)
   455  }
   456  
   457  func TestInterpolateGenerator_go(t *testing.T) {
   458  	requestedGenerator := &argov1alpha1.ApplicationSetGenerator{
   459  		Clusters: &argov1alpha1.ClusterGenerator{
   460  			Selector: metav1.LabelSelector{
   461  				MatchLabels: map[string]string{
   462  					"argocd.argoproj.io/secret-type": "cluster",
   463  					"path-basename":                  "{{base .path.path}}",
   464  					"path-zero":                      "{{index .path.segments 0}}",
   465  					"path-full":                      "{{.path.path}}",
   466  					"kubernetes.io/environment":      `{{default "foo" .my_label}}`,
   467  				},
   468  			},
   469  		},
   470  	}
   471  	gitGeneratorParams := map[string]any{
   472  		"path": map[string]any{
   473  			"path":     "p1/p2/app3",
   474  			"segments": []string{"p1", "p2", "app3"},
   475  		},
   476  	}
   477  	interpolatedGenerator, err := InterpolateGenerator(requestedGenerator, gitGeneratorParams, true, nil)
   478  	require.NoError(t, err)
   479  	if err != nil {
   480  		log.WithError(err).WithField("requestedGenerator", requestedGenerator).Error("error interpolating Generator")
   481  		return
   482  	}
   483  	assert.Equal(t, "app3", interpolatedGenerator.Clusters.Selector.MatchLabels["path-basename"])
   484  	assert.Equal(t, "p1", interpolatedGenerator.Clusters.Selector.MatchLabels["path-zero"])
   485  	assert.Equal(t, "p1/p2/app3", interpolatedGenerator.Clusters.Selector.MatchLabels["path-full"])
   486  
   487  	fileNamePath := argov1alpha1.GitFileGeneratorItem{
   488  		Path: "{{.name}}",
   489  	}
   490  	fileServerPath := argov1alpha1.GitFileGeneratorItem{
   491  		Path: "{{.server}}",
   492  	}
   493  
   494  	requestedGenerator = &argov1alpha1.ApplicationSetGenerator{
   495  		Git: &argov1alpha1.GitGenerator{
   496  			Files:    append([]argov1alpha1.GitFileGeneratorItem{}, fileNamePath, fileServerPath),
   497  			Template: argov1alpha1.ApplicationSetTemplate{},
   498  		},
   499  	}
   500  	clusterGeneratorParams := map[string]any{
   501  		"name": "production_01/west", "server": "https://production-01.example.com",
   502  	}
   503  	interpolatedGenerator, err = InterpolateGenerator(requestedGenerator, clusterGeneratorParams, true, nil)
   504  	if err != nil {
   505  		log.WithError(err).WithField("requestedGenerator", requestedGenerator).Error("error interpolating Generator")
   506  		return
   507  	}
   508  	assert.Equal(t, "production_01/west", interpolatedGenerator.Git.Files[0].Path)
   509  	assert.Equal(t, "https://production-01.example.com", interpolatedGenerator.Git.Files[1].Path)
   510  }
   511  
   512  func TestInterpolateGeneratorError(t *testing.T) {
   513  	type args struct {
   514  		requestedGenerator *argov1alpha1.ApplicationSetGenerator
   515  		params             map[string]any
   516  		useGoTemplate      bool
   517  		goTemplateOptions  []string
   518  	}
   519  	tests := []struct {
   520  		name           string
   521  		args           args
   522  		want           argov1alpha1.ApplicationSetGenerator
   523  		expectedErrStr string
   524  	}{
   525  		{name: "Empty Gen", args: args{
   526  			requestedGenerator: nil,
   527  			params:             nil,
   528  			useGoTemplate:      false,
   529  			goTemplateOptions:  nil,
   530  		}, want: argov1alpha1.ApplicationSetGenerator{}, expectedErrStr: "generator is empty"},
   531  		{name: "No Params", args: args{
   532  			requestedGenerator: &argov1alpha1.ApplicationSetGenerator{},
   533  			params:             map[string]any{},
   534  			useGoTemplate:      false,
   535  			goTemplateOptions:  nil,
   536  		}, want: argov1alpha1.ApplicationSetGenerator{}, expectedErrStr: ""},
   537  		{name: "Error templating", args: args{
   538  			requestedGenerator: &argov1alpha1.ApplicationSetGenerator{Git: &argov1alpha1.GitGenerator{
   539  				RepoURL:  "foo",
   540  				Files:    []argov1alpha1.GitFileGeneratorItem{{Path: "bar/"}},
   541  				Revision: "main",
   542  				Values: map[string]string{
   543  					"git_test":  "{{ toPrettyJson . }}",
   544  					"selection": "{{ default .override .test }}",
   545  					"resolved":  "{{ index .rmap (default .override .test) }}",
   546  				},
   547  			}},
   548  			params: map[string]any{
   549  				"name":     "in-cluster",
   550  				"override": "foo",
   551  			},
   552  			useGoTemplate:     true,
   553  			goTemplateOptions: []string{},
   554  		}, want: argov1alpha1.ApplicationSetGenerator{}, expectedErrStr: "failed to replace parameters in generator: failed to execute go template {{ index .rmap (default .override .test) }}: template: :1:3: executing \"\" at <index .rmap (default .override .test)>: error calling index: index of untyped nil"},
   555  	}
   556  	for _, tt := range tests {
   557  		t.Run(tt.name, func(t *testing.T) {
   558  			got, err := InterpolateGenerator(tt.args.requestedGenerator, tt.args.params, tt.args.useGoTemplate, tt.args.goTemplateOptions)
   559  			if tt.expectedErrStr != "" {
   560  				require.EqualError(t, err, tt.expectedErrStr)
   561  			} else {
   562  				require.NoError(t, err)
   563  			}
   564  			assert.Equalf(t, tt.want, got, "InterpolateGenerator(%v, %v, %v, %v)", tt.args.requestedGenerator, tt.args.params, tt.args.useGoTemplate, tt.args.goTemplateOptions)
   565  		})
   566  	}
   567  }