sigs.k8s.io/prow@v0.0.0-20240503223140-c5e374dc7eb1/pkg/plugins/cla/cla_test.go (about)

     1  /*
     2  Copyright 2016 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package cla
    18  
    19  import (
    20  	"fmt"
    21  	"reflect"
    22  	"testing"
    23  
    24  	"github.com/sirupsen/logrus"
    25  
    26  	"sigs.k8s.io/prow/pkg/github"
    27  	"sigs.k8s.io/prow/pkg/github/fakegithub"
    28  	"sigs.k8s.io/prow/pkg/labels"
    29  )
    30  
    31  func TestCLALabels(t *testing.T) {
    32  	var testcases = []struct {
    33  		name          string
    34  		context       string
    35  		state         string
    36  		statusSHA     string
    37  		issues        []github.Issue
    38  		pullRequests  []github.PullRequest
    39  		labels        []string
    40  		addedLabels   []string
    41  		removedLabels []string
    42  	}{
    43  		{
    44  			name:          "unrecognized status context has no effect",
    45  			context:       "unknown",
    46  			state:         "success",
    47  			addedLabels:   nil,
    48  			removedLabels: nil,
    49  		},
    50  		{
    51  			name:          "EasyCLA status pending has no effect",
    52  			context:       "EasyCLA",
    53  			state:         "pending",
    54  			addedLabels:   nil,
    55  			removedLabels: nil,
    56  		},
    57  		{
    58  			name: "EasyCLA status success does not add/remove labels " +
    59  				"when not the head commit in a PR",
    60  			context:   "EasyCLA",
    61  			state:     "success",
    62  			statusSHA: "a",
    63  			issues: []github.Issue{
    64  				{Number: 3, State: "open", Labels: []github.Label{}},
    65  			},
    66  			pullRequests: []github.PullRequest{
    67  				{Number: 3, Head: github.PullRequestBranch{SHA: "b"}},
    68  			},
    69  			addedLabels:   nil,
    70  			removedLabels: nil,
    71  		},
    72  		{
    73  			name: "EasyCLA status failure does not add/remove labels " +
    74  				"when not the head commit in a PR",
    75  			context:   "EasyCLA",
    76  			state:     "failure",
    77  			statusSHA: "a",
    78  			issues: []github.Issue{
    79  				{Number: 3, State: "open", Labels: []github.Label{{Name: labels.ClaYes}}},
    80  			},
    81  			pullRequests: []github.PullRequest{
    82  				{Number: 3, Head: github.PullRequestBranch{SHA: "b"}},
    83  			},
    84  			addedLabels:   nil,
    85  			removedLabels: nil,
    86  		},
    87  		{
    88  			name:      "EasyCLA status on head commit of PR adds the cla-yes label when its state is \"success\"",
    89  			context:   "EasyCLA",
    90  			state:     "success",
    91  			statusSHA: "a",
    92  			issues: []github.Issue{
    93  				{Number: 3, State: "open", Labels: []github.Label{}},
    94  			},
    95  			pullRequests: []github.PullRequest{
    96  				{Number: 3, Head: github.PullRequestBranch{SHA: "a"}},
    97  			},
    98  			addedLabels:   []string{fmt.Sprintf("/#3:%s", labels.ClaYes)},
    99  			removedLabels: nil,
   100  		},
   101  		{
   102  			name:      "EasyCLA status on head commit of PR does nothing when pending",
   103  			context:   "EasyCLA",
   104  			state:     "pending",
   105  			statusSHA: "a",
   106  			issues: []github.Issue{
   107  				{Number: 3, State: "open", Labels: []github.Label{}},
   108  			},
   109  			pullRequests: []github.PullRequest{
   110  				{Number: 3, Head: github.PullRequestBranch{SHA: "a"}},
   111  			},
   112  			addedLabels:   nil,
   113  			removedLabels: nil,
   114  		},
   115  		{
   116  			name:      "EasyCLA status success removes \"cncf-cla: no\" label",
   117  			context:   "EasyCLA",
   118  			state:     "success",
   119  			statusSHA: "a",
   120  			issues: []github.Issue{
   121  				{Number: 3, State: "open", Labels: []github.Label{{Name: labels.ClaNo}}},
   122  			},
   123  			pullRequests: []github.PullRequest{
   124  				{Number: 3, Head: github.PullRequestBranch{SHA: "a"}},
   125  			},
   126  			addedLabels:   []string{fmt.Sprintf("/#3:%s", labels.ClaYes)},
   127  			removedLabels: []string{fmt.Sprintf("/#3:%s", labels.ClaNo)},
   128  		},
   129  		{
   130  			name:      "EasyCLA status failure removes \"cncf-cla: yes\" label",
   131  			context:   "EasyCLA",
   132  			state:     "failure",
   133  			statusSHA: "a",
   134  			issues: []github.Issue{
   135  				{Number: 3, State: "open", Labels: []github.Label{{Name: labels.ClaYes}}},
   136  			},
   137  			pullRequests: []github.PullRequest{
   138  				{Number: 3, Head: github.PullRequestBranch{SHA: "a"}},
   139  			},
   140  			addedLabels:   []string{fmt.Sprintf("/#3:%s", labels.ClaNo)},
   141  			removedLabels: []string{fmt.Sprintf("/#3:%s", labels.ClaYes)},
   142  		},
   143  	}
   144  	for _, tc := range testcases {
   145  		pullRequests := make(map[int]*github.PullRequest)
   146  		for _, pr := range tc.pullRequests {
   147  			pr := pr
   148  			pullRequests[pr.Number] = &pr
   149  		}
   150  
   151  		issues := make(map[int]*github.Issue)
   152  		for _, issue := range tc.issues {
   153  			issue := issue
   154  			issues[issue.Number] = &issue
   155  		}
   156  
   157  		fc := fakegithub.NewFakeClient()
   158  		fc.PullRequests = pullRequests
   159  		fc.Issues = issues
   160  		fc.IssueComments = make(map[int][]github.IssueComment)
   161  		se := github.StatusEvent{
   162  			Context: tc.context,
   163  			SHA:     tc.statusSHA,
   164  			State:   tc.state,
   165  		}
   166  		if err := handle(fc, logrus.WithField("plugin", pluginName), se); err != nil {
   167  			t.Errorf("For case %s, didn't expect error from cla plugin: %v", tc.name, err)
   168  			continue
   169  		}
   170  
   171  		if !reflect.DeepEqual(fc.IssueLabelsAdded, tc.addedLabels) {
   172  			t.Errorf("Expected: %#v, Got %#v in case %s.", tc.addedLabels, fc.IssueLabelsAdded, tc.name)
   173  		}
   174  
   175  		if !reflect.DeepEqual(fc.IssueLabelsRemoved, tc.removedLabels) {
   176  			t.Errorf("Expected: %#v, Got %#v in case %s.", tc.removedLabels, fc.IssueLabelsRemoved, tc.name)
   177  		}
   178  	}
   179  }
   180  
   181  func TestCheckCLA(t *testing.T) {
   182  	var testcases = []struct {
   183  		name         string
   184  		context      string
   185  		state        string
   186  		issueState   string
   187  		SHA          string
   188  		action       string
   189  		body         string
   190  		pullRequests []github.PullRequest
   191  		hasCLAYes    bool
   192  		hasCLANo     bool
   193  
   194  		addedLabel   string
   195  		removedLabel string
   196  	}{
   197  		{
   198  			name:       "ignore non EasyCLA context",
   199  			context:    "random/context",
   200  			state:      "success",
   201  			issueState: "open",
   202  			SHA:        "sha",
   203  			action:     "created",
   204  			body:       "/check-cla",
   205  			pullRequests: []github.PullRequest{
   206  				{Number: 3, Head: github.PullRequestBranch{SHA: "sha"}},
   207  			},
   208  		},
   209  		{
   210  			name:       "ignore non open PRs",
   211  			context:    "EasyCLA",
   212  			state:      "success",
   213  			issueState: "closed",
   214  			SHA:        "sha",
   215  			action:     "created",
   216  			body:       "/check-cla",
   217  			pullRequests: []github.PullRequest{
   218  				{Number: 3, Head: github.PullRequestBranch{SHA: "sha"}},
   219  			},
   220  		},
   221  		{
   222  			name:       "ignore non /check-cla comments",
   223  			context:    "EasyCLA",
   224  			state:      "success",
   225  			issueState: "open",
   226  			SHA:        "sha",
   227  			action:     "created",
   228  			body:       "/shrug",
   229  			pullRequests: []github.PullRequest{
   230  				{Number: 3, Head: github.PullRequestBranch{SHA: "sha"}},
   231  			},
   232  		},
   233  		{
   234  			name:       "do nothing on when status state is \"pending\"",
   235  			context:    "EasyCLA",
   236  			state:      "pending",
   237  			issueState: "open",
   238  			SHA:        "sha",
   239  			action:     "created",
   240  			body:       "/shrug",
   241  			pullRequests: []github.PullRequest{
   242  				{Number: 3, Head: github.PullRequestBranch{SHA: "sha"}},
   243  			},
   244  		},
   245  		{
   246  			name:       "EasyCLA status adds the cla-yes label when its state is \"success\"",
   247  			context:    "EasyCLA",
   248  			state:      "success",
   249  			issueState: "open",
   250  			SHA:        "sha",
   251  			action:     "created",
   252  			body:       "/check-cla",
   253  			pullRequests: []github.PullRequest{
   254  				{Number: 3, Head: github.PullRequestBranch{SHA: "sha"}},
   255  			},
   256  
   257  			addedLabel: fmt.Sprintf("/#3:%s", labels.ClaYes),
   258  		},
   259  		{
   260  			name:       "EasyCLA status adds the cla-yes label and removes cla-no label when its state is \"success\"",
   261  			context:    "EasyCLA",
   262  			state:      "success",
   263  			issueState: "open",
   264  			SHA:        "sha",
   265  			action:     "created",
   266  			body:       "/check-cla",
   267  			pullRequests: []github.PullRequest{
   268  				{Number: 3, Head: github.PullRequestBranch{SHA: "sha"}},
   269  			},
   270  			hasCLANo: true,
   271  
   272  			addedLabel:   fmt.Sprintf("/#3:%s", labels.ClaYes),
   273  			removedLabel: fmt.Sprintf("/#3:%s", labels.ClaNo),
   274  		},
   275  		{
   276  			name:       "EasyCLA status adds the cla-no label when its state is \"failure\"",
   277  			context:    "EasyCLA",
   278  			state:      "failure",
   279  			issueState: "open",
   280  			SHA:        "sha",
   281  			action:     "created",
   282  			body:       "/check-cla",
   283  			pullRequests: []github.PullRequest{
   284  				{Number: 3, Head: github.PullRequestBranch{SHA: "sha"}},
   285  			},
   286  
   287  			addedLabel: fmt.Sprintf("/#3:%s", labels.ClaNo),
   288  		},
   289  		{
   290  			name:       "EasyCLA status adds the cla-no label and removes cla-yes label when its state is \"failure\"",
   291  			context:    "EasyCLA",
   292  			state:      "failure",
   293  			issueState: "open",
   294  			SHA:        "sha",
   295  			action:     "created",
   296  			body:       "/check-cla",
   297  			pullRequests: []github.PullRequest{
   298  				{Number: 3, Head: github.PullRequestBranch{SHA: "sha"}},
   299  			},
   300  			hasCLAYes: true,
   301  
   302  			addedLabel:   fmt.Sprintf("/#3:%s", labels.ClaNo),
   303  			removedLabel: fmt.Sprintf("/#3:%s", labels.ClaYes),
   304  		},
   305  		{
   306  			name:       "EasyCLA status retains the cla-yes label and removes cla-no label when its state is \"success\"",
   307  			context:    "EasyCLA",
   308  			state:      "success",
   309  			issueState: "open",
   310  			SHA:        "sha",
   311  			action:     "created",
   312  			body:       "/check-cla",
   313  			pullRequests: []github.PullRequest{
   314  				{Number: 3, Head: github.PullRequestBranch{SHA: "sha"}},
   315  			},
   316  			hasCLANo:  true,
   317  			hasCLAYes: true,
   318  
   319  			removedLabel: fmt.Sprintf("/#3:%s", labels.ClaNo),
   320  		},
   321  		{
   322  			name:       "EasyCLA status retains the cla-no label and removes cla-yes label when its state is \"failure\"",
   323  			context:    "EasyCLA",
   324  			state:      "failure",
   325  			issueState: "open",
   326  			SHA:        "sha",
   327  			action:     "created",
   328  			body:       "/check-cla",
   329  			pullRequests: []github.PullRequest{
   330  				{Number: 3, Head: github.PullRequestBranch{SHA: "sha"}},
   331  			},
   332  			hasCLANo:  true,
   333  			hasCLAYes: true,
   334  
   335  			removedLabel: fmt.Sprintf("/#3:%s", labels.ClaYes),
   336  		},
   337  	}
   338  	for _, tc := range testcases {
   339  		t.Run(tc.name, func(t *testing.T) {
   340  			pullRequests := make(map[int]*github.PullRequest)
   341  			for _, pr := range tc.pullRequests {
   342  				pr := pr
   343  				pullRequests[pr.Number] = &pr
   344  			}
   345  			fc := fakegithub.NewFakeClient()
   346  			fc.CreatedStatuses = make(map[string][]github.Status)
   347  			fc.PullRequests = pullRequests
   348  			e := &github.GenericCommentEvent{
   349  				Action:     github.GenericCommentEventAction(tc.action),
   350  				Body:       tc.body,
   351  				Number:     3,
   352  				IssueState: tc.issueState,
   353  			}
   354  			fc.CombinedStatuses = map[string]*github.CombinedStatus{
   355  				tc.SHA: {
   356  					Statuses: []github.Status{
   357  						{State: tc.state, Context: tc.context},
   358  					},
   359  				},
   360  			}
   361  			if tc.hasCLAYes {
   362  				fc.IssueLabelsAdded = append(fc.IssueLabelsAdded, fmt.Sprintf("/#3:%s", labels.ClaYes))
   363  			}
   364  			if tc.hasCLANo {
   365  				fc.IssueLabelsAdded = append(fc.IssueLabelsAdded, fmt.Sprintf("/#3:%s", labels.ClaNo))
   366  			}
   367  			if err := handleComment(fc, logrus.WithField("plugin", pluginName), e); err != nil {
   368  				t.Errorf("For case %s, didn't expect error from cla plugin: %v", tc.name, err)
   369  			}
   370  			ok := tc.addedLabel == ""
   371  			if !ok {
   372  				for _, label := range fc.IssueLabelsAdded {
   373  					if reflect.DeepEqual(tc.addedLabel, label) {
   374  						ok = true
   375  						break
   376  					}
   377  				}
   378  			}
   379  			if !ok {
   380  				t.Errorf("Expected to add: %#v, Got %#v in case %s.", tc.addedLabel, fc.IssueLabelsAdded, tc.name)
   381  			}
   382  			ok = tc.removedLabel == ""
   383  			if !ok {
   384  				for _, label := range fc.IssueLabelsRemoved {
   385  					if reflect.DeepEqual(tc.removedLabel, label) {
   386  						ok = true
   387  						break
   388  					}
   389  				}
   390  			}
   391  			if !ok {
   392  				t.Errorf("Expected to remove: %#v, Got %#v in case %s.", tc.removedLabel, fc.IssueLabelsRemoved, tc.name)
   393  			}
   394  		})
   395  	}
   396  }