github.com/argoproj/argo-cd/v2@v2.10.9/applicationset/generators/pull_request_test.go (about)

     1  package generators
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/assert"
     9  	corev1 "k8s.io/api/core/v1"
    10  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    11  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    12  
    13  	pullrequest "github.com/argoproj/argo-cd/v2/applicationset/services/pull_request"
    14  	argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
    15  )
    16  
    17  func TestPullRequestGithubGenerateParams(t *testing.T) {
    18  	ctx := context.Background()
    19  	cases := []struct {
    20  		selectFunc     func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error)
    21  		expected       []map[string]interface{}
    22  		expectedErr    error
    23  		applicationSet argoprojiov1alpha1.ApplicationSet
    24  	}{
    25  		{
    26  			selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) {
    27  				return pullrequest.NewFakeService(
    28  					ctx,
    29  					[]*pullrequest.PullRequest{
    30  						{
    31  							Number:       1,
    32  							Branch:       "branch1",
    33  							TargetBranch: "master",
    34  							HeadSHA:      "089d92cbf9ff857a39e6feccd32798ca700fb958",
    35  						},
    36  					},
    37  					nil,
    38  				)
    39  			},
    40  			expected: []map[string]interface{}{
    41  				{
    42  					"number":             "1",
    43  					"branch":             "branch1",
    44  					"branch_slug":        "branch1",
    45  					"target_branch":      "master",
    46  					"target_branch_slug": "master",
    47  					"head_sha":           "089d92cbf9ff857a39e6feccd32798ca700fb958",
    48  					"head_short_sha":     "089d92cb",
    49  					"head_short_sha_7":   "089d92c",
    50  				},
    51  			},
    52  			expectedErr: nil,
    53  		},
    54  		{
    55  			selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) {
    56  				return pullrequest.NewFakeService(
    57  					ctx,
    58  					[]*pullrequest.PullRequest{
    59  						{
    60  							Number:       2,
    61  							Branch:       "feat/areally+long_pull_request_name_to_test_argo_slugification_and_branch_name_shortening_feature",
    62  							TargetBranch: "feat/anotherreally+long_pull_request_name_to_test_argo_slugification_and_branch_name_shortening_feature",
    63  							HeadSHA:      "9b34ff5bd418e57d58891eb0aa0728043ca1e8be",
    64  						},
    65  					},
    66  					nil,
    67  				)
    68  			},
    69  			expected: []map[string]interface{}{
    70  				{
    71  					"number":             "2",
    72  					"branch":             "feat/areally+long_pull_request_name_to_test_argo_slugification_and_branch_name_shortening_feature",
    73  					"branch_slug":        "feat-areally-long-pull-request-name-to-test-argo",
    74  					"target_branch":      "feat/anotherreally+long_pull_request_name_to_test_argo_slugification_and_branch_name_shortening_feature",
    75  					"target_branch_slug": "feat-anotherreally-long-pull-request-name-to-test",
    76  					"head_sha":           "9b34ff5bd418e57d58891eb0aa0728043ca1e8be",
    77  					"head_short_sha":     "9b34ff5b",
    78  					"head_short_sha_7":   "9b34ff5",
    79  				},
    80  			},
    81  			expectedErr: nil,
    82  		},
    83  		{
    84  			selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) {
    85  				return pullrequest.NewFakeService(
    86  					ctx,
    87  					[]*pullrequest.PullRequest{
    88  						{
    89  							Number:       1,
    90  							Branch:       "a-very-short-sha",
    91  							TargetBranch: "master",
    92  							HeadSHA:      "abcd",
    93  						},
    94  					},
    95  					nil,
    96  				)
    97  			},
    98  			expected: []map[string]interface{}{
    99  				{
   100  					"number":             "1",
   101  					"branch":             "a-very-short-sha",
   102  					"branch_slug":        "a-very-short-sha",
   103  					"target_branch":      "master",
   104  					"target_branch_slug": "master",
   105  					"head_sha":           "abcd",
   106  					"head_short_sha":     "abcd",
   107  					"head_short_sha_7":   "abcd",
   108  				},
   109  			},
   110  			expectedErr: nil,
   111  		},
   112  		{
   113  			selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) {
   114  				return pullrequest.NewFakeService(
   115  					ctx,
   116  					nil,
   117  					fmt.Errorf("fake error"),
   118  				)
   119  			},
   120  			expected:    nil,
   121  			expectedErr: fmt.Errorf("error listing repos: fake error"),
   122  		},
   123  		{
   124  			selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) {
   125  				return pullrequest.NewFakeService(
   126  					ctx,
   127  					[]*pullrequest.PullRequest{
   128  						{
   129  							Number:       1,
   130  							Branch:       "branch1",
   131  							TargetBranch: "master",
   132  							HeadSHA:      "089d92cbf9ff857a39e6feccd32798ca700fb958",
   133  							Labels:       []string{"preview"},
   134  						},
   135  					},
   136  					nil,
   137  				)
   138  			},
   139  			expected: []map[string]interface{}{
   140  				{
   141  					"number":             "1",
   142  					"branch":             "branch1",
   143  					"branch_slug":        "branch1",
   144  					"target_branch":      "master",
   145  					"target_branch_slug": "master",
   146  					"head_sha":           "089d92cbf9ff857a39e6feccd32798ca700fb958",
   147  					"head_short_sha":     "089d92cb",
   148  					"head_short_sha_7":   "089d92c",
   149  					"labels":             []string{"preview"},
   150  				},
   151  			},
   152  			expectedErr: nil,
   153  			applicationSet: argoprojiov1alpha1.ApplicationSet{
   154  				Spec: argoprojiov1alpha1.ApplicationSetSpec{
   155  					// Application set is using Go Template.
   156  					GoTemplate: true,
   157  				},
   158  			},
   159  		},
   160  		{
   161  			selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) {
   162  				return pullrequest.NewFakeService(
   163  					ctx,
   164  					[]*pullrequest.PullRequest{
   165  						{
   166  							Number:       1,
   167  							Branch:       "branch1",
   168  							TargetBranch: "master",
   169  							HeadSHA:      "089d92cbf9ff857a39e6feccd32798ca700fb958",
   170  							Labels:       []string{"preview"},
   171  						},
   172  					},
   173  					nil,
   174  				)
   175  			},
   176  			expected: []map[string]interface{}{
   177  				{
   178  					"number":             "1",
   179  					"branch":             "branch1",
   180  					"branch_slug":        "branch1",
   181  					"target_branch":      "master",
   182  					"target_branch_slug": "master",
   183  					"head_sha":           "089d92cbf9ff857a39e6feccd32798ca700fb958",
   184  					"head_short_sha":     "089d92cb",
   185  					"head_short_sha_7":   "089d92c",
   186  				},
   187  			},
   188  			expectedErr: nil,
   189  			applicationSet: argoprojiov1alpha1.ApplicationSet{
   190  				Spec: argoprojiov1alpha1.ApplicationSetSpec{
   191  					// Application set is using fasttemplate.
   192  					GoTemplate: false,
   193  				},
   194  			},
   195  		},
   196  	}
   197  
   198  	for _, c := range cases {
   199  		gen := PullRequestGenerator{
   200  			selectServiceProviderFunc: c.selectFunc,
   201  		}
   202  		generatorConfig := argoprojiov1alpha1.ApplicationSetGenerator{
   203  			PullRequest: &argoprojiov1alpha1.PullRequestGenerator{},
   204  		}
   205  
   206  		got, gotErr := gen.GenerateParams(&generatorConfig, &c.applicationSet)
   207  		assert.Equal(t, c.expectedErr, gotErr)
   208  		assert.ElementsMatch(t, c.expected, got)
   209  	}
   210  }
   211  
   212  func TestPullRequestGetSecretRef(t *testing.T) {
   213  	secret := &corev1.Secret{
   214  		ObjectMeta: metav1.ObjectMeta{Name: "test-secret", Namespace: "test"},
   215  		Data: map[string][]byte{
   216  			"my-token": []byte("secret"),
   217  		},
   218  	}
   219  	gen := &PullRequestGenerator{client: fake.NewClientBuilder().WithObjects(secret).Build()}
   220  	ctx := context.Background()
   221  
   222  	cases := []struct {
   223  		name, namespace, token string
   224  		ref                    *argoprojiov1alpha1.SecretRef
   225  		hasError               bool
   226  	}{
   227  		{
   228  			name:      "valid ref",
   229  			ref:       &argoprojiov1alpha1.SecretRef{SecretName: "test-secret", Key: "my-token"},
   230  			namespace: "test",
   231  			token:     "secret",
   232  			hasError:  false,
   233  		},
   234  		{
   235  			name:      "nil ref",
   236  			ref:       nil,
   237  			namespace: "test",
   238  			token:     "",
   239  			hasError:  false,
   240  		},
   241  		{
   242  			name:      "wrong name",
   243  			ref:       &argoprojiov1alpha1.SecretRef{SecretName: "other", Key: "my-token"},
   244  			namespace: "test",
   245  			token:     "",
   246  			hasError:  true,
   247  		},
   248  		{
   249  			name:      "wrong key",
   250  			ref:       &argoprojiov1alpha1.SecretRef{SecretName: "test-secret", Key: "other-token"},
   251  			namespace: "test",
   252  			token:     "",
   253  			hasError:  true,
   254  		},
   255  		{
   256  			name:      "wrong namespace",
   257  			ref:       &argoprojiov1alpha1.SecretRef{SecretName: "test-secret", Key: "my-token"},
   258  			namespace: "other",
   259  			token:     "",
   260  			hasError:  true,
   261  		},
   262  	}
   263  
   264  	for _, c := range cases {
   265  		t.Run(c.name, func(t *testing.T) {
   266  			token, err := gen.getSecretRef(ctx, c.ref, c.namespace)
   267  			if c.hasError {
   268  				assert.NotNil(t, err)
   269  			} else {
   270  				assert.Nil(t, err)
   271  			}
   272  			assert.Equal(t, c.token, token)
   273  		})
   274  	}
   275  }
   276  
   277  func TestAllowedSCMProviderPullRequest(t *testing.T) {
   278  	cases := []struct {
   279  		name           string
   280  		providerConfig *argoprojiov1alpha1.PullRequestGenerator
   281  		expectedError  error
   282  	}{
   283  		{
   284  			name: "Error Github",
   285  			providerConfig: &argoprojiov1alpha1.PullRequestGenerator{
   286  				Github: &argoprojiov1alpha1.PullRequestGeneratorGithub{
   287  					API: "https://myservice.mynamespace.svc.cluster.local",
   288  				},
   289  			},
   290  			expectedError: &ErrDisallowedSCMProvider{},
   291  		},
   292  		{
   293  			name: "Error Gitlab",
   294  			providerConfig: &argoprojiov1alpha1.PullRequestGenerator{
   295  				GitLab: &argoprojiov1alpha1.PullRequestGeneratorGitLab{
   296  					API: "https://myservice.mynamespace.svc.cluster.local",
   297  				},
   298  			},
   299  			expectedError: &ErrDisallowedSCMProvider{},
   300  		},
   301  		{
   302  			name: "Error Gitea",
   303  			providerConfig: &argoprojiov1alpha1.PullRequestGenerator{
   304  				Gitea: &argoprojiov1alpha1.PullRequestGeneratorGitea{
   305  					API: "https://myservice.mynamespace.svc.cluster.local",
   306  				},
   307  			},
   308  			expectedError: &ErrDisallowedSCMProvider{},
   309  		},
   310  		{
   311  			name: "Error Bitbucket",
   312  			providerConfig: &argoprojiov1alpha1.PullRequestGenerator{
   313  				BitbucketServer: &argoprojiov1alpha1.PullRequestGeneratorBitbucketServer{
   314  					API: "https://myservice.mynamespace.svc.cluster.local",
   315  				},
   316  			},
   317  			expectedError: &ErrDisallowedSCMProvider{},
   318  		},
   319  	}
   320  
   321  	for _, testCase := range cases {
   322  		testCaseCopy := testCase
   323  
   324  		t.Run(testCaseCopy.name, func(t *testing.T) {
   325  			t.Parallel()
   326  
   327  			pullRequestGenerator := NewPullRequestGenerator(nil, SCMAuthProviders{}, "", []string{
   328  				"github.myorg.com",
   329  				"gitlab.myorg.com",
   330  				"gitea.myorg.com",
   331  				"bitbucket.myorg.com",
   332  				"azuredevops.myorg.com",
   333  			}, true)
   334  
   335  			applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
   336  				ObjectMeta: metav1.ObjectMeta{
   337  					Name: "set",
   338  				},
   339  				Spec: argoprojiov1alpha1.ApplicationSetSpec{
   340  					Generators: []argoprojiov1alpha1.ApplicationSetGenerator{{
   341  						PullRequest: testCaseCopy.providerConfig,
   342  					}},
   343  				},
   344  			}
   345  
   346  			_, err := pullRequestGenerator.GenerateParams(&applicationSetInfo.Spec.Generators[0], &applicationSetInfo)
   347  
   348  			assert.Error(t, err, "Must return an error")
   349  			assert.ErrorAs(t, err, testCaseCopy.expectedError)
   350  		})
   351  	}
   352  }
   353  
   354  func TestSCMProviderDisabled_PRGenerator(t *testing.T) {
   355  	generator := NewPullRequestGenerator(nil, SCMAuthProviders{}, "", []string{}, false)
   356  
   357  	applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
   358  		ObjectMeta: metav1.ObjectMeta{
   359  			Name: "set",
   360  		},
   361  		Spec: argoprojiov1alpha1.ApplicationSetSpec{
   362  			Generators: []argoprojiov1alpha1.ApplicationSetGenerator{{
   363  				PullRequest: &argoprojiov1alpha1.PullRequestGenerator{
   364  					Github: &argoprojiov1alpha1.PullRequestGeneratorGithub{
   365  						API: "https://myservice.mynamespace.svc.cluster.local",
   366  					},
   367  				},
   368  			}},
   369  		},
   370  	}
   371  
   372  	_, err := generator.GenerateParams(&applicationSetInfo.Spec.Generators[0], &applicationSetInfo)
   373  	assert.ErrorIs(t, err, ErrSCMProvidersDisabled)
   374  }