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

     1  package webhook
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"net/http"
     8  	"net/http/httptest"
     9  	"os"
    10  	"path/filepath"
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/stretchr/testify/assert"
    15  	"github.com/stretchr/testify/mock"
    16  	"github.com/stretchr/testify/require"
    17  	corev1 "k8s.io/api/core/v1"
    18  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    19  	"k8s.io/apimachinery/pkg/runtime"
    20  	kubefake "k8s.io/client-go/kubernetes/fake"
    21  	"sigs.k8s.io/controller-runtime/pkg/client"
    22  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    23  
    24  	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
    25  
    26  	"github.com/argoproj/argo-cd/v3/applicationset/generators"
    27  	"github.com/argoproj/argo-cd/v3/applicationset/services/scm_provider"
    28  	"github.com/argoproj/argo-cd/v3/common"
    29  	"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
    30  	argosettings "github.com/argoproj/argo-cd/v3/util/settings"
    31  )
    32  
    33  type generatorMock struct {
    34  	mock.Mock
    35  }
    36  
    37  func (g *generatorMock) GetTemplate(_ *v1alpha1.ApplicationSetGenerator) *v1alpha1.ApplicationSetTemplate {
    38  	return &v1alpha1.ApplicationSetTemplate{}
    39  }
    40  
    41  func (g *generatorMock) GenerateParams(_ *v1alpha1.ApplicationSetGenerator, _ *v1alpha1.ApplicationSet, _ client.Client) ([]map[string]any, error) {
    42  	return []map[string]any{}, nil
    43  }
    44  
    45  func (g *generatorMock) GetRequeueAfter(_ *v1alpha1.ApplicationSetGenerator) time.Duration {
    46  	d, _ := time.ParseDuration("10s")
    47  	return d
    48  }
    49  
    50  func TestWebhookHandler(t *testing.T) {
    51  	tt := []struct {
    52  		desc               string
    53  		headerKey          string
    54  		headerValue        string
    55  		effectedAppSets    []string
    56  		payloadFile        string
    57  		expectedStatusCode int
    58  		expectedRefresh    bool
    59  	}{
    60  		{
    61  			desc:               "WebHook from a GitHub repository via Commit",
    62  			headerKey:          "X-GitHub-Event",
    63  			headerValue:        "push",
    64  			payloadFile:        "github-commit-event.json",
    65  			effectedAppSets:    []string{"git-github", "git-github-ssh", "git-github-alt-ssh", "matrix-git-github", "merge-git-github", "matrix-scm-git-github", "matrix-nested-git-github", "merge-nested-git-github", "plugin", "matrix-pull-request-github-plugin"},
    66  			expectedStatusCode: http.StatusOK,
    67  			expectedRefresh:    true,
    68  		},
    69  		{
    70  			desc:               "WebHook from a GitHub repository via Commit shorthand",
    71  			headerKey:          "X-GitHub-Event",
    72  			headerValue:        "push",
    73  			payloadFile:        "github-commit-event-feature-branch.json",
    74  			effectedAppSets:    []string{"github-shorthand", "matrix-pull-request-github-plugin", "plugin"},
    75  			expectedStatusCode: http.StatusOK,
    76  			expectedRefresh:    true,
    77  		},
    78  		{
    79  			desc:               "WebHook from a GitHub repository via Commit to branch",
    80  			headerKey:          "X-GitHub-Event",
    81  			headerValue:        "push",
    82  			payloadFile:        "github-commit-branch-event.json",
    83  			effectedAppSets:    []string{"git-github", "git-github-ssh", "git-github-alt-ssh", "plugin", "matrix-pull-request-github-plugin"},
    84  			expectedStatusCode: http.StatusOK,
    85  			expectedRefresh:    true,
    86  		},
    87  		{
    88  			desc:               "WebHook from a GitHub ping event",
    89  			headerKey:          "X-GitHub-Event",
    90  			headerValue:        "ping",
    91  			payloadFile:        "github-ping-event.json",
    92  			effectedAppSets:    []string{"git-github", "git-github-ssh", "git-github-alt-ssh", "plugin"},
    93  			expectedStatusCode: http.StatusOK,
    94  			expectedRefresh:    false,
    95  		},
    96  		{
    97  			desc:               "WebHook from a GitLab repository via Commit",
    98  			headerKey:          "X-Gitlab-Event",
    99  			headerValue:        "Push Hook",
   100  			payloadFile:        "gitlab-event.json",
   101  			effectedAppSets:    []string{"git-gitlab", "git-gitlab-ssh", "git-gitlab-alt-ssh", "plugin", "matrix-pull-request-github-plugin"},
   102  			expectedStatusCode: http.StatusOK,
   103  			expectedRefresh:    true,
   104  		},
   105  		{
   106  			desc:               "WebHook from a System Hook via Commit",
   107  			headerKey:          "X-Gitlab-Event",
   108  			headerValue:        "System Hook",
   109  			payloadFile:        "gitlab-event.json",
   110  			effectedAppSets:    []string{"git-gitlab", "git-gitlab-ssh", "git-gitlab-alt-ssh", "plugin", "matrix-pull-request-github-plugin"},
   111  			expectedStatusCode: http.StatusOK,
   112  			expectedRefresh:    true,
   113  		},
   114  		{
   115  			desc:               "WebHook with an unknown event",
   116  			headerKey:          "X-Random-Event",
   117  			headerValue:        "Push Hook",
   118  			payloadFile:        "gitlab-event.json",
   119  			effectedAppSets:    []string{"git-gitlab", "git-gitlab-ssh", "git-gitlab-alt-ssh", "plugin"},
   120  			expectedStatusCode: http.StatusBadRequest,
   121  			expectedRefresh:    false,
   122  		},
   123  		{
   124  			desc:               "WebHook with an invalid event",
   125  			headerKey:          "X-Random-Event",
   126  			headerValue:        "Push Hook",
   127  			payloadFile:        "invalid-event.json",
   128  			effectedAppSets:    []string{"git-gitlab", "git-gitlab-ssh", "git-gitlab-alt-ssh", "plugin"},
   129  			expectedStatusCode: http.StatusBadRequest,
   130  			expectedRefresh:    false,
   131  		},
   132  		{
   133  			desc:               "WebHook from a GitHub repository via pull_request opened event",
   134  			headerKey:          "X-GitHub-Event",
   135  			headerValue:        "pull_request",
   136  			payloadFile:        "github-pull-request-opened-event.json",
   137  			effectedAppSets:    []string{"pull-request-github", "matrix-pull-request-github", "matrix-scm-pull-request-github", "merge-pull-request-github", "plugin", "matrix-pull-request-github-plugin"},
   138  			expectedStatusCode: http.StatusOK,
   139  			expectedRefresh:    true,
   140  		},
   141  		{
   142  			desc:               "WebHook from a GitHub repository via pull_request assigned event",
   143  			headerKey:          "X-GitHub-Event",
   144  			headerValue:        "pull_request",
   145  			payloadFile:        "github-pull-request-assigned-event.json",
   146  			effectedAppSets:    []string{"pull-request-github", "matrix-pull-request-github", "matrix-scm-pull-request-github", "merge-pull-request-github", "plugin", "matrix-pull-request-github-plugin"},
   147  			expectedStatusCode: http.StatusOK,
   148  			expectedRefresh:    false,
   149  		},
   150  		{
   151  			desc:               "WebHook from a GitHub repository via pull_request labeled event",
   152  			headerKey:          "X-GitHub-Event",
   153  			headerValue:        "pull_request",
   154  			payloadFile:        "github-pull-request-labeled-event.json",
   155  			effectedAppSets:    []string{"pull-request-github", "matrix-pull-request-github", "matrix-scm-pull-request-github", "merge-pull-request-github", "plugin", "matrix-pull-request-github-plugin"},
   156  			expectedStatusCode: http.StatusOK,
   157  			expectedRefresh:    true,
   158  		},
   159  		{
   160  			desc:               "WebHook from a GitLab repository via open merge request event",
   161  			headerKey:          "X-Gitlab-Event",
   162  			headerValue:        "Merge Request Hook",
   163  			payloadFile:        "gitlab-merge-request-open-event.json",
   164  			effectedAppSets:    []string{"pull-request-gitlab", "plugin", "matrix-pull-request-github-plugin"},
   165  			expectedStatusCode: http.StatusOK,
   166  			expectedRefresh:    true,
   167  		},
   168  		{
   169  			desc:               "WebHook from a GitLab repository via approval merge request event",
   170  			headerKey:          "X-Gitlab-Event",
   171  			headerValue:        "Merge Request Hook",
   172  			payloadFile:        "gitlab-merge-request-approval-event.json",
   173  			effectedAppSets:    []string{"pull-request-gitlab", "plugin"},
   174  			expectedStatusCode: http.StatusOK,
   175  			expectedRefresh:    false,
   176  		},
   177  		{
   178  			desc:               "WebHook from a Azure DevOps repository via Commit",
   179  			headerKey:          "X-Vss-Activityid",
   180  			headerValue:        "Push Hook",
   181  			payloadFile:        "azuredevops-push.json",
   182  			effectedAppSets:    []string{"git-azure-devops", "plugin", "matrix-pull-request-github-plugin"},
   183  			expectedStatusCode: http.StatusOK,
   184  			expectedRefresh:    true,
   185  		},
   186  		{
   187  			desc:               "WebHook from a Azure DevOps repository via pull request event",
   188  			headerKey:          "X-Vss-Activityid",
   189  			headerValue:        "Pull Request Hook",
   190  			payloadFile:        "azuredevops-pull-request.json",
   191  			effectedAppSets:    []string{"pull-request-azure-devops", "plugin", "matrix-pull-request-github-plugin"},
   192  			expectedStatusCode: http.StatusOK,
   193  			expectedRefresh:    true,
   194  		},
   195  	}
   196  
   197  	namespace := "test"
   198  	webhookParallelism := 10
   199  	fakeClient := newFakeClient(namespace)
   200  	scheme := runtime.NewScheme()
   201  	err := v1alpha1.AddToScheme(scheme)
   202  	require.NoError(t, err)
   203  	err = v1alpha1.AddToScheme(scheme)
   204  	require.NoError(t, err)
   205  
   206  	for _, test := range tt {
   207  		t.Run(test.desc, func(t *testing.T) {
   208  			fc := fake.NewClientBuilder().WithScheme(scheme).WithObjects(
   209  				fakeAppWithGitGenerator("git-github", namespace, "https://github.com/org/repo"),
   210  				fakeAppWithGitGenerator("git-github-copy", namespace, "https://github.com/org/repo-copy"),
   211  				fakeAppWithGitGenerator("git-github-ssh", namespace, "ssh://git@github.com/org/repo"),
   212  				fakeAppWithGitGenerator("git-github-alt-ssh", namespace, "ssh://git@ssh.github.com:443/org/repo"),
   213  				fakeAppWithGitGenerator("git-gitlab", namespace, "https://gitlab.com/group/name"),
   214  				fakeAppWithGitGenerator("git-gitlab-ssh", namespace, "ssh://git@gitlab.com/group/name"),
   215  				fakeAppWithGitGenerator("git-gitlab-alt-ssh", namespace, "ssh://git@altssh.gitlab.com:443/group/name"),
   216  				fakeAppWithGitGenerator("git-azure-devops", namespace, "https://dev.azure.com/fabrikam-fiber-inc/DefaultCollection/_git/Fabrikam-Fiber-Git"),
   217  				fakeAppWithGitGeneratorWithRevision("github-shorthand", namespace, "https://github.com/org/repo", "env/dev"),
   218  				fakeAppWithGithubPullRequestGenerator("pull-request-github", namespace, "CodErTOcat", "Hello-World"),
   219  				fakeAppWithGitlabPullRequestGenerator("pull-request-gitlab", namespace, "100500"),
   220  				fakeAppWithAzureDevOpsPullRequestGenerator("pull-request-azure-devops", namespace, "DefaultCollection", "Fabrikam"),
   221  				fakeAppWithPluginGenerator("plugin", namespace),
   222  				fakeAppWithMatrixAndGitGenerator("matrix-git-github", namespace, "https://github.com/org/repo"),
   223  				fakeAppWithMatrixAndPullRequestGenerator("matrix-pull-request-github", namespace, "Codertocat", "Hello-World"),
   224  				fakeAppWithMatrixAndScmWithGitGenerator("matrix-scm-git-github", namespace, "org"),
   225  				fakeAppWithMatrixAndScmWithPullRequestGenerator("matrix-scm-pull-request-github", namespace, "Codertocat"),
   226  				fakeAppWithMatrixAndNestedGitGenerator("matrix-nested-git-github", namespace, "https://github.com/org/repo"),
   227  				fakeAppWithMatrixAndPullRequestGeneratorWithPluginGenerator("matrix-pull-request-github-plugin", namespace, "coDErtoCat", "HeLLO-WorLD", "plugin-cm"),
   228  				fakeAppWithMergeAndGitGenerator("merge-git-github", namespace, "https://github.com/org/repo"),
   229  				fakeAppWithMergeAndPullRequestGenerator("merge-pull-request-github", namespace, "Codertocat", "Hello-World"),
   230  				fakeAppWithMergeAndNestedGitGenerator("merge-nested-git-github", namespace, "https://github.com/org/repo"),
   231  			).Build()
   232  			set := argosettings.NewSettingsManager(t.Context(), fakeClient, namespace)
   233  			h, err := NewWebhookHandler(webhookParallelism, set, fc, mockGenerators())
   234  			require.NoError(t, err)
   235  
   236  			req := httptest.NewRequest(http.MethodPost, "/api/webhook", http.NoBody)
   237  			req.Header.Set(test.headerKey, test.headerValue)
   238  			eventJSON, err := os.ReadFile(filepath.Join("testdata", test.payloadFile))
   239  			require.NoError(t, err)
   240  			req.Body = io.NopCloser(bytes.NewReader(eventJSON))
   241  			w := httptest.NewRecorder()
   242  
   243  			h.Handler(w, req)
   244  			close(h.queue)
   245  			h.Wait()
   246  			assert.Equal(t, test.expectedStatusCode, w.Code)
   247  
   248  			list := &v1alpha1.ApplicationSetList{}
   249  			err = fc.List(t.Context(), list)
   250  			require.NoError(t, err)
   251  			effectedAppSetsAsExpected := make(map[string]bool)
   252  			for _, appSetName := range test.effectedAppSets {
   253  				effectedAppSetsAsExpected[appSetName] = false
   254  			}
   255  			for i := range list.Items {
   256  				gotAppSet := &list.Items[i]
   257  				if _, isEffected := effectedAppSetsAsExpected[gotAppSet.Name]; isEffected {
   258  					expected, got := test.expectedRefresh, gotAppSet.RefreshRequired()
   259  					require.Equalf(t, expected, got, "unexpected RefreshRequired() for appset '%s' expect: %v got: %v", gotAppSet.Name, expected, got)
   260  					effectedAppSetsAsExpected[gotAppSet.Name] = true
   261  				} else {
   262  					assert.False(t, gotAppSet.RefreshRequired())
   263  				}
   264  			}
   265  			for appSetName, checked := range effectedAppSetsAsExpected {
   266  				assert.True(t, checked, "appset %s not found", appSetName)
   267  			}
   268  		})
   269  	}
   270  }
   271  
   272  func mockGenerators() map[string]generators.Generator {
   273  	// generatorMockList := generatorMock{}
   274  	generatorMockGit := &generatorMock{}
   275  	generatorMockPR := &generatorMock{}
   276  	generatorMockPlugin := &generatorMock{}
   277  	mockSCMProvider := &scm_provider.MockProvider{
   278  		Repos: []*scm_provider.Repository{
   279  			{
   280  				Organization: "myorg",
   281  				Repository:   "repo1",
   282  				URL:          "git@github.com:org/repo.git",
   283  				Branch:       "main",
   284  				SHA:          "0bc57212c3cbbec69d20b34c507284bd300def5b",
   285  			},
   286  			{
   287  				Organization: "Codertocat",
   288  				Repository:   "Hello-World",
   289  				URL:          "git@github.com:Codertocat/Hello-World.git",
   290  				Branch:       "main",
   291  				SHA:          "59d0",
   292  			},
   293  		},
   294  	}
   295  	generatorMockSCM := generators.NewTestSCMProviderGenerator(mockSCMProvider)
   296  
   297  	terminalMockGenerators := map[string]generators.Generator{
   298  		"List":        generators.NewListGenerator(),
   299  		"Git":         generatorMockGit,
   300  		"SCMProvider": generatorMockSCM,
   301  		"PullRequest": generatorMockPR,
   302  		"Plugin":      generatorMockPlugin,
   303  	}
   304  
   305  	nestedGenerators := map[string]generators.Generator{
   306  		"List":        terminalMockGenerators["List"],
   307  		"Git":         terminalMockGenerators["Git"],
   308  		"SCMProvider": terminalMockGenerators["SCMProvider"],
   309  		"PullRequest": terminalMockGenerators["PullRequest"],
   310  		"Plugin":      terminalMockGenerators["Plugin"],
   311  		"Matrix":      generators.NewMatrixGenerator(terminalMockGenerators),
   312  		"Merge":       generators.NewMergeGenerator(terminalMockGenerators),
   313  	}
   314  
   315  	return map[string]generators.Generator{
   316  		"List":        terminalMockGenerators["List"],
   317  		"Git":         terminalMockGenerators["Git"],
   318  		"SCMProvider": terminalMockGenerators["SCMProvider"],
   319  		"PullRequest": terminalMockGenerators["PullRequest"],
   320  		"Plugin":      terminalMockGenerators["Plugin"],
   321  		"Matrix":      generators.NewMatrixGenerator(nestedGenerators),
   322  		"Merge":       generators.NewMergeGenerator(nestedGenerators),
   323  	}
   324  }
   325  
   326  func TestGenRevisionHasChanged(t *testing.T) {
   327  	type args struct {
   328  		gen         *v1alpha1.GitGenerator
   329  		revision    string
   330  		touchedHead bool
   331  	}
   332  	tests := []struct {
   333  		name string
   334  		args args
   335  		want bool
   336  	}{
   337  		{name: "touchedHead", args: args{
   338  			gen:         &v1alpha1.GitGenerator{},
   339  			revision:    "main",
   340  			touchedHead: true,
   341  		}, want: true},
   342  		{name: "didntTouchHead", args: args{
   343  			gen:         &v1alpha1.GitGenerator{},
   344  			revision:    "main",
   345  			touchedHead: false,
   346  		}, want: false},
   347  		{name: "foundEqualShort", args: args{
   348  			gen:         &v1alpha1.GitGenerator{Revision: "dev"},
   349  			revision:    "dev",
   350  			touchedHead: true,
   351  		}, want: true},
   352  		{name: "foundEqualLongGen", args: args{
   353  			gen:         &v1alpha1.GitGenerator{Revision: "refs/heads/dev"},
   354  			revision:    "dev",
   355  			touchedHead: true,
   356  		}, want: true},
   357  		{name: "foundNotEqualLongGen", args: args{
   358  			gen:         &v1alpha1.GitGenerator{Revision: "refs/heads/dev"},
   359  			revision:    "main",
   360  			touchedHead: true,
   361  		}, want: false},
   362  		{name: "foundNotEqualShort", args: args{
   363  			gen:         &v1alpha1.GitGenerator{Revision: "dev"},
   364  			revision:    "main",
   365  			touchedHead: false,
   366  		}, want: false},
   367  		{name: "foundEqualTag", args: args{
   368  			gen:         &v1alpha1.GitGenerator{Revision: "v3.14.1"},
   369  			revision:    "v3.14.1",
   370  			touchedHead: false,
   371  		}, want: true},
   372  		{name: "foundEqualTagLongGen", args: args{
   373  			gen:         &v1alpha1.GitGenerator{Revision: "refs/tags/v3.14.1"},
   374  			revision:    "v3.14.1",
   375  			touchedHead: false,
   376  		}, want: true},
   377  	}
   378  	for _, tt := range tests {
   379  		t.Run(tt.name, func(t *testing.T) {
   380  			assert.Equalf(t, tt.want, genRevisionHasChanged(tt.args.gen, tt.args.revision, tt.args.touchedHead), "genRevisionHasChanged(%v, %v, %v)", tt.args.gen, tt.args.revision, tt.args.touchedHead)
   381  		})
   382  	}
   383  }
   384  
   385  func fakeAppWithGitGenerator(name, namespace, repo string) *v1alpha1.ApplicationSet {
   386  	return &v1alpha1.ApplicationSet{
   387  		ObjectMeta: metav1.ObjectMeta{
   388  			Name:      name,
   389  			Namespace: namespace,
   390  		},
   391  		Spec: v1alpha1.ApplicationSetSpec{
   392  			Generators: []v1alpha1.ApplicationSetGenerator{
   393  				{
   394  					Git: &v1alpha1.GitGenerator{
   395  						RepoURL:  repo,
   396  						Revision: "master",
   397  					},
   398  				},
   399  			},
   400  		},
   401  	}
   402  }
   403  
   404  func fakeAppWithGitGeneratorWithRevision(name, namespace, repo, revision string) *v1alpha1.ApplicationSet {
   405  	appSet := fakeAppWithGitGenerator(name, namespace, repo)
   406  	appSet.Spec.Generators[0].Git.Revision = revision
   407  	return appSet
   408  }
   409  
   410  func fakeAppWithGitlabPullRequestGenerator(name, namespace, projectId string) *v1alpha1.ApplicationSet {
   411  	return &v1alpha1.ApplicationSet{
   412  		ObjectMeta: metav1.ObjectMeta{
   413  			Name:      name,
   414  			Namespace: namespace,
   415  		},
   416  		Spec: v1alpha1.ApplicationSetSpec{
   417  			Generators: []v1alpha1.ApplicationSetGenerator{
   418  				{
   419  					PullRequest: &v1alpha1.PullRequestGenerator{
   420  						GitLab: &v1alpha1.PullRequestGeneratorGitLab{
   421  							Project: projectId,
   422  						},
   423  					},
   424  				},
   425  			},
   426  		},
   427  	}
   428  }
   429  
   430  func fakeAppWithGithubPullRequestGenerator(name, namespace, owner, repo string) *v1alpha1.ApplicationSet {
   431  	return &v1alpha1.ApplicationSet{
   432  		ObjectMeta: metav1.ObjectMeta{
   433  			Name:      name,
   434  			Namespace: namespace,
   435  		},
   436  		Spec: v1alpha1.ApplicationSetSpec{
   437  			Generators: []v1alpha1.ApplicationSetGenerator{
   438  				{
   439  					PullRequest: &v1alpha1.PullRequestGenerator{
   440  						Github: &v1alpha1.PullRequestGeneratorGithub{
   441  							Owner: owner,
   442  							Repo:  repo,
   443  						},
   444  					},
   445  				},
   446  			},
   447  		},
   448  	}
   449  }
   450  
   451  func fakeAppWithAzureDevOpsPullRequestGenerator(name, namespace, project, repo string) *v1alpha1.ApplicationSet {
   452  	return &v1alpha1.ApplicationSet{
   453  		ObjectMeta: metav1.ObjectMeta{
   454  			Name:      name,
   455  			Namespace: namespace,
   456  		},
   457  		Spec: v1alpha1.ApplicationSetSpec{
   458  			Generators: []v1alpha1.ApplicationSetGenerator{
   459  				{
   460  					PullRequest: &v1alpha1.PullRequestGenerator{
   461  						AzureDevOps: &v1alpha1.PullRequestGeneratorAzureDevOps{
   462  							Project: project,
   463  							Repo:    repo,
   464  						},
   465  					},
   466  				},
   467  			},
   468  		},
   469  	}
   470  }
   471  
   472  func fakeAppWithMatrixAndGitGenerator(name, namespace, repo string) *v1alpha1.ApplicationSet {
   473  	return &v1alpha1.ApplicationSet{
   474  		ObjectMeta: metav1.ObjectMeta{
   475  			Name:      name,
   476  			Namespace: namespace,
   477  		},
   478  		Spec: v1alpha1.ApplicationSetSpec{
   479  			Generators: []v1alpha1.ApplicationSetGenerator{
   480  				{
   481  					Matrix: &v1alpha1.MatrixGenerator{
   482  						Generators: []v1alpha1.ApplicationSetNestedGenerator{
   483  							{
   484  								List: &v1alpha1.ListGenerator{},
   485  							},
   486  							{
   487  								Git: &v1alpha1.GitGenerator{
   488  									RepoURL: repo,
   489  								},
   490  							},
   491  						},
   492  					},
   493  				},
   494  			},
   495  		},
   496  	}
   497  }
   498  
   499  func fakeAppWithMatrixAndPullRequestGenerator(name, namespace, owner, repo string) *v1alpha1.ApplicationSet {
   500  	return &v1alpha1.ApplicationSet{
   501  		ObjectMeta: metav1.ObjectMeta{
   502  			Name:      name,
   503  			Namespace: namespace,
   504  		},
   505  		Spec: v1alpha1.ApplicationSetSpec{
   506  			Generators: []v1alpha1.ApplicationSetGenerator{
   507  				{
   508  					Matrix: &v1alpha1.MatrixGenerator{
   509  						Generators: []v1alpha1.ApplicationSetNestedGenerator{
   510  							{
   511  								List: &v1alpha1.ListGenerator{},
   512  							},
   513  							{
   514  								PullRequest: &v1alpha1.PullRequestGenerator{
   515  									Github: &v1alpha1.PullRequestGeneratorGithub{
   516  										Owner: owner,
   517  										Repo:  repo,
   518  									},
   519  								},
   520  							},
   521  						},
   522  					},
   523  				},
   524  			},
   525  		},
   526  	}
   527  }
   528  
   529  func fakeAppWithMatrixAndScmWithGitGenerator(name, namespace, owner string) *v1alpha1.ApplicationSet {
   530  	return &v1alpha1.ApplicationSet{
   531  		ObjectMeta: metav1.ObjectMeta{
   532  			Name:      name,
   533  			Namespace: namespace,
   534  		},
   535  		Spec: v1alpha1.ApplicationSetSpec{
   536  			Generators: []v1alpha1.ApplicationSetGenerator{
   537  				{
   538  					Matrix: &v1alpha1.MatrixGenerator{
   539  						Generators: []v1alpha1.ApplicationSetNestedGenerator{
   540  							{
   541  								SCMProvider: &v1alpha1.SCMProviderGenerator{
   542  									CloneProtocol: "ssh",
   543  									Github: &v1alpha1.SCMProviderGeneratorGithub{
   544  										Organization: owner,
   545  									},
   546  								},
   547  							},
   548  							{
   549  								Git: &v1alpha1.GitGenerator{
   550  									RepoURL: "{{ url }}",
   551  								},
   552  							},
   553  						},
   554  					},
   555  				},
   556  			},
   557  		},
   558  	}
   559  }
   560  
   561  func fakeAppWithMatrixAndScmWithPullRequestGenerator(name, namespace, owner string) *v1alpha1.ApplicationSet {
   562  	return &v1alpha1.ApplicationSet{
   563  		ObjectMeta: metav1.ObjectMeta{
   564  			Name:      name,
   565  			Namespace: namespace,
   566  		},
   567  		Spec: v1alpha1.ApplicationSetSpec{
   568  			Generators: []v1alpha1.ApplicationSetGenerator{
   569  				{
   570  					Matrix: &v1alpha1.MatrixGenerator{
   571  						Generators: []v1alpha1.ApplicationSetNestedGenerator{
   572  							{
   573  								SCMProvider: &v1alpha1.SCMProviderGenerator{
   574  									CloneProtocol: "https",
   575  									Github: &v1alpha1.SCMProviderGeneratorGithub{
   576  										Organization: owner,
   577  									},
   578  								},
   579  							},
   580  							{
   581  								PullRequest: &v1alpha1.PullRequestGenerator{
   582  									Github: &v1alpha1.PullRequestGeneratorGithub{
   583  										Owner: "{{ organization }}",
   584  										Repo:  "{{ repository }}",
   585  									},
   586  								},
   587  							},
   588  						},
   589  					},
   590  				},
   591  			},
   592  		},
   593  	}
   594  }
   595  
   596  func fakeAppWithMatrixAndNestedGitGenerator(name, namespace, repo string) *v1alpha1.ApplicationSet {
   597  	return &v1alpha1.ApplicationSet{
   598  		ObjectMeta: metav1.ObjectMeta{
   599  			Name:      name,
   600  			Namespace: namespace,
   601  		},
   602  		Spec: v1alpha1.ApplicationSetSpec{
   603  			Generators: []v1alpha1.ApplicationSetGenerator{
   604  				{
   605  					Matrix: &v1alpha1.MatrixGenerator{
   606  						Generators: []v1alpha1.ApplicationSetNestedGenerator{
   607  							{
   608  								List: &v1alpha1.ListGenerator{},
   609  							},
   610  							{
   611  								Matrix: &apiextensionsv1.JSON{
   612  									Raw: []byte(fmt.Sprintf(`{
   613  										"Generators": [
   614  											{
   615  												"List": {
   616  													"Elements": [
   617  														{
   618  															"repository": "%s"
   619  														}
   620  													]
   621  												}
   622  											},
   623  											{
   624  												"Git": {
   625  													"RepoURL": "{{ repository }}"
   626  												}
   627  											}
   628  										]
   629  									}`, repo)),
   630  								},
   631  							},
   632  						},
   633  					},
   634  				},
   635  			},
   636  		},
   637  	}
   638  }
   639  
   640  func fakeAppWithMergeAndGitGenerator(name, namespace, repo string) *v1alpha1.ApplicationSet {
   641  	return &v1alpha1.ApplicationSet{
   642  		ObjectMeta: metav1.ObjectMeta{
   643  			Name:      name,
   644  			Namespace: namespace,
   645  		},
   646  		Spec: v1alpha1.ApplicationSetSpec{
   647  			Generators: []v1alpha1.ApplicationSetGenerator{
   648  				{
   649  					Merge: &v1alpha1.MergeGenerator{
   650  						Generators: []v1alpha1.ApplicationSetNestedGenerator{
   651  							{
   652  								Git: &v1alpha1.GitGenerator{
   653  									RepoURL: repo,
   654  								},
   655  							},
   656  						},
   657  					},
   658  				},
   659  			},
   660  		},
   661  	}
   662  }
   663  
   664  func fakeAppWithMergeAndPullRequestGenerator(name, namespace, owner, repo string) *v1alpha1.ApplicationSet {
   665  	return &v1alpha1.ApplicationSet{
   666  		ObjectMeta: metav1.ObjectMeta{
   667  			Name:      name,
   668  			Namespace: namespace,
   669  		},
   670  		Spec: v1alpha1.ApplicationSetSpec{
   671  			Generators: []v1alpha1.ApplicationSetGenerator{
   672  				{
   673  					Merge: &v1alpha1.MergeGenerator{
   674  						Generators: []v1alpha1.ApplicationSetNestedGenerator{
   675  							{
   676  								PullRequest: &v1alpha1.PullRequestGenerator{
   677  									Github: &v1alpha1.PullRequestGeneratorGithub{
   678  										Owner: owner,
   679  										Repo:  repo,
   680  									},
   681  								},
   682  							},
   683  						},
   684  					},
   685  				},
   686  			},
   687  		},
   688  	}
   689  }
   690  
   691  func fakeAppWithMergeAndNestedGitGenerator(name, namespace, repo string) *v1alpha1.ApplicationSet {
   692  	return &v1alpha1.ApplicationSet{
   693  		ObjectMeta: metav1.ObjectMeta{
   694  			Name:      name,
   695  			Namespace: namespace,
   696  		},
   697  		Spec: v1alpha1.ApplicationSetSpec{
   698  			Generators: []v1alpha1.ApplicationSetGenerator{
   699  				{
   700  					Merge: &v1alpha1.MergeGenerator{
   701  						MergeKeys: []string{
   702  							"server",
   703  						},
   704  						Generators: []v1alpha1.ApplicationSetNestedGenerator{
   705  							{
   706  								List: &v1alpha1.ListGenerator{},
   707  							},
   708  							{
   709  								Merge: &apiextensionsv1.JSON{
   710  									Raw: []byte(fmt.Sprintf(`{
   711  										"MergeKeys": ["server"],
   712  										"Generators": [
   713  											{
   714  												"List": {}
   715  											},
   716  											{
   717  												"Git": {
   718  													"RepoURL": "%s"
   719  												}
   720  											}
   721  										]
   722  									}`, repo)),
   723  								},
   724  							},
   725  						},
   726  					},
   727  				},
   728  			},
   729  		},
   730  	}
   731  }
   732  
   733  func fakeAppWithPluginGenerator(name, namespace string) *v1alpha1.ApplicationSet {
   734  	return &v1alpha1.ApplicationSet{
   735  		ObjectMeta: metav1.ObjectMeta{
   736  			Name:      name,
   737  			Namespace: namespace,
   738  		},
   739  		Spec: v1alpha1.ApplicationSetSpec{
   740  			Generators: []v1alpha1.ApplicationSetGenerator{
   741  				{
   742  					Plugin: &v1alpha1.PluginGenerator{
   743  						ConfigMapRef: v1alpha1.PluginConfigMapRef{
   744  							Name: "test",
   745  						},
   746  					},
   747  				},
   748  			},
   749  		},
   750  	}
   751  }
   752  
   753  func fakeAppWithMatrixAndPullRequestGeneratorWithPluginGenerator(name, namespace, owner, repo, configmapName string) *v1alpha1.ApplicationSet {
   754  	return &v1alpha1.ApplicationSet{
   755  		ObjectMeta: metav1.ObjectMeta{
   756  			Name:      name,
   757  			Namespace: namespace,
   758  		},
   759  		Spec: v1alpha1.ApplicationSetSpec{
   760  			Generators: []v1alpha1.ApplicationSetGenerator{
   761  				{
   762  					Matrix: &v1alpha1.MatrixGenerator{
   763  						Generators: []v1alpha1.ApplicationSetNestedGenerator{
   764  							{
   765  								PullRequest: &v1alpha1.PullRequestGenerator{
   766  									Github: &v1alpha1.PullRequestGeneratorGithub{
   767  										Owner: owner,
   768  										Repo:  repo,
   769  									},
   770  								},
   771  							},
   772  							{
   773  								Plugin: &v1alpha1.PluginGenerator{
   774  									ConfigMapRef: v1alpha1.PluginConfigMapRef{
   775  										Name: configmapName,
   776  									},
   777  								},
   778  							},
   779  						},
   780  					},
   781  				},
   782  			},
   783  		},
   784  	}
   785  }
   786  
   787  func newFakeClient(ns string) *kubefake.Clientset {
   788  	s := runtime.NewScheme()
   789  	s.AddKnownTypes(v1alpha1.SchemeGroupVersion, &v1alpha1.ApplicationSet{})
   790  	return kubefake.NewClientset(&corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "argocd-cm", Namespace: ns, Labels: map[string]string{
   791  		"app.kubernetes.io/part-of": "argocd",
   792  	}}}, &corev1.Secret{
   793  		ObjectMeta: metav1.ObjectMeta{
   794  			Name:      common.ArgoCDSecretName,
   795  			Namespace: ns,
   796  			Labels: map[string]string{
   797  				"app.kubernetes.io/part-of": "argocd",
   798  			},
   799  		},
   800  		Data: map[string][]byte{
   801  			"server.secretkey": nil,
   802  		},
   803  	})
   804  }