github.com/abayer/test-infra@v0.0.5/prow/plugins/trigger/ic_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 trigger
    18  
    19  import (
    20  	"testing"
    21  
    22  	"github.com/sirupsen/logrus"
    23  
    24  	"k8s.io/test-infra/prow/config"
    25  	"k8s.io/test-infra/prow/github"
    26  	"k8s.io/test-infra/prow/github/fakegithub"
    27  	"k8s.io/test-infra/prow/kube"
    28  )
    29  
    30  type fkc struct {
    31  	started []string
    32  }
    33  
    34  func (c *fkc) CreateProwJob(pj kube.ProwJob) (kube.ProwJob, error) {
    35  	c.started = append(c.started, pj.Spec.Context)
    36  	return pj, nil
    37  }
    38  
    39  func TestHandleIssueComment(t *testing.T) {
    40  	var testcases = []struct {
    41  		name string
    42  
    43  		Author        string
    44  		PRAuthor      string
    45  		Body          string
    46  		State         string
    47  		IsPR          bool
    48  		Branch        string
    49  		ShouldBuild   bool
    50  		ShouldReport  bool
    51  		HasOkToTest   bool
    52  		IsOkToTest    bool
    53  		StartsExactly string
    54  		Presubmits    map[string][]config.Presubmit
    55  		IssueLabels   []github.Label
    56  	}{
    57  		{
    58  			name: "Not a PR.",
    59  
    60  			Author:      "t",
    61  			Body:        "/ok-to-test",
    62  			State:       "open",
    63  			IsPR:        false,
    64  			ShouldBuild: false,
    65  		},
    66  		{
    67  			name: "Closed PR.",
    68  
    69  			Author:      "t",
    70  			Body:        "/ok-to-test",
    71  			State:       "closed",
    72  			IsPR:        true,
    73  			ShouldBuild: false,
    74  		},
    75  		{
    76  			name: "Comment by a bot.",
    77  
    78  			Author:      "k8s-bot",
    79  			Body:        "/ok-to-test",
    80  			State:       "open",
    81  			IsPR:        true,
    82  			ShouldBuild: false,
    83  		},
    84  		{
    85  			name: "Non-trusted member's ok to test.",
    86  
    87  			Author:      "u",
    88  			Body:        "/ok-to-test",
    89  			State:       "open",
    90  			IsPR:        true,
    91  			ShouldBuild: false,
    92  		},
    93  		{
    94  			name:        "accept /test from non-trusted member if PR author is trusted",
    95  			Author:      "u",
    96  			PRAuthor:    "t",
    97  			Body:        "/test all",
    98  			State:       "open",
    99  			IsPR:        true,
   100  			ShouldBuild: true,
   101  		},
   102  		{
   103  			name:        "reject /test from non-trusted member when PR author is untrusted",
   104  			Author:      "u",
   105  			PRAuthor:    "u",
   106  			Body:        "/test all",
   107  			State:       "open",
   108  			IsPR:        true,
   109  			ShouldBuild: false,
   110  		},
   111  		{
   112  			name: `Non-trusted member after "/ok-to-test".`,
   113  
   114  			Author:      "u",
   115  			Body:        "/test all",
   116  			State:       "open",
   117  			IsPR:        true,
   118  			HasOkToTest: true,
   119  			ShouldBuild: true,
   120  		},
   121  		{
   122  			name: "Trusted member's ok to test",
   123  
   124  			Author:      "t",
   125  			Body:        "looks great, thanks!\n/ok-to-test",
   126  			State:       "open",
   127  			IsPR:        true,
   128  			ShouldBuild: true,
   129  		},
   130  		{
   131  			name: "Trusted member's ok to test, trailing space.",
   132  
   133  			Author:      "t",
   134  			Body:        "looks great, thanks!\n/ok-to-test \r",
   135  			State:       "open",
   136  			IsPR:        true,
   137  			ShouldBuild: true,
   138  		},
   139  		{
   140  			name: "Trusted member's not ok to test.",
   141  
   142  			Author:      "t",
   143  			Body:        "not /ok-to-test",
   144  			State:       "open",
   145  			IsPR:        true,
   146  			ShouldBuild: false,
   147  		},
   148  		{
   149  			name: "Trusted member's test this.",
   150  
   151  			Author:      "t",
   152  			Body:        "/test all",
   153  			State:       "open",
   154  			IsPR:        true,
   155  			ShouldBuild: true,
   156  		},
   157  		{
   158  			name: "Wrong branch.",
   159  
   160  			Author:       "t",
   161  			Body:         "/test all",
   162  			State:        "open",
   163  			IsPR:         true,
   164  			Branch:       "other",
   165  			ShouldBuild:  false,
   166  			ShouldReport: true,
   167  		},
   168  		{
   169  			name: "Retest with one running and one failed",
   170  
   171  			Author:        "t",
   172  			Body:          "/retest",
   173  			State:         "open",
   174  			IsPR:          true,
   175  			ShouldBuild:   true,
   176  			StartsExactly: "pull-jib",
   177  		},
   178  		{
   179  			name: "Retest with one running and one failed, trailing space.",
   180  
   181  			Author:        "t",
   182  			Body:          "/retest \r",
   183  			State:         "open",
   184  			IsPR:          true,
   185  			ShouldBuild:   true,
   186  			StartsExactly: "pull-jib",
   187  		},
   188  		{
   189  			name: "needs-ok-to-test label is removed when no presubmit runs by default",
   190  
   191  			Author:      "t",
   192  			Body:        "/ok-to-test",
   193  			State:       "open",
   194  			IsPR:        true,
   195  			IsOkToTest:  true,
   196  			ShouldBuild: false,
   197  			Presubmits: map[string][]config.Presubmit{
   198  				"org/repo": {
   199  					{
   200  						Name:         "job",
   201  						AlwaysRun:    false,
   202  						Context:      "pull-job",
   203  						Trigger:      `/test all`,
   204  						RerunCommand: `/test all`,
   205  					},
   206  					{
   207  						Name:         "jib",
   208  						AlwaysRun:    false,
   209  						Context:      "pull-jib",
   210  						Trigger:      `/test jib`,
   211  						RerunCommand: `/test jib`,
   212  					},
   213  				},
   214  			},
   215  			IssueLabels: []github.Label{{Name: "needs-ok-to-test"}},
   216  		},
   217  		{
   218  			name:   "Wrong branch w/ SkipReport",
   219  			Author: "t",
   220  			Body:   "/test all",
   221  			Branch: "other",
   222  			State:  "open",
   223  			IsPR:   true,
   224  			Presubmits: map[string][]config.Presubmit{
   225  				"org/repo": {
   226  					{
   227  						Name:         "job",
   228  						AlwaysRun:    true,
   229  						SkipReport:   true,
   230  						Context:      "pull-job",
   231  						Trigger:      `/test all`,
   232  						RerunCommand: `/test all`,
   233  						Brancher:     config.Brancher{Branches: []string{"master"}},
   234  					},
   235  				},
   236  			},
   237  		},
   238  		{
   239  			name:   "Retest of run_if_changed job that hasn't run. Changes require job",
   240  			Author: "t",
   241  			Body:   "/retest",
   242  			State:  "open",
   243  			IsPR:   true,
   244  			Presubmits: map[string][]config.Presubmit{
   245  				"org/repo": {
   246  					{
   247  						Name:         "jab",
   248  						RunIfChanged: "CHANGED",
   249  						SkipReport:   true,
   250  						Context:      "pull-jab",
   251  						Trigger:      `/test all`,
   252  						RerunCommand: `/test all`,
   253  					},
   254  				},
   255  			},
   256  			ShouldBuild:   true,
   257  			StartsExactly: "pull-jab",
   258  		},
   259  		{
   260  			name:   "Retest of run_if_changed job that failed. Changes require job",
   261  			Author: "t",
   262  			Body:   "/retest",
   263  			State:  "open",
   264  			IsPR:   true,
   265  			Presubmits: map[string][]config.Presubmit{
   266  				"org/repo": {
   267  					{
   268  						Name:         "jib",
   269  						RunIfChanged: "CHANGED",
   270  						Context:      "pull-jib",
   271  						Trigger:      `/test all`,
   272  						RerunCommand: `/test all`,
   273  					},
   274  				},
   275  			},
   276  			ShouldBuild:   true,
   277  			StartsExactly: "pull-jib",
   278  		},
   279  		{
   280  			name:   "/test of run_if_changed job that has passed",
   281  			Author: "t",
   282  			Body:   "/test jub",
   283  			State:  "open",
   284  			IsPR:   true,
   285  			Presubmits: map[string][]config.Presubmit{
   286  				"org/repo": {
   287  					{
   288  						Name:         "jub",
   289  						RunIfChanged: "CHANGED",
   290  						Context:      "pull-jub",
   291  						Trigger:      `/test jub`,
   292  						RerunCommand: `/test jub`,
   293  					},
   294  				},
   295  			},
   296  			ShouldBuild:   true,
   297  			StartsExactly: "pull-jub",
   298  		},
   299  		{
   300  			name:   "Retest of run_if_changed job that failed. Changes do not require the job",
   301  			Author: "t",
   302  			Body:   "/retest",
   303  			State:  "open",
   304  			IsPR:   true,
   305  			Presubmits: map[string][]config.Presubmit{
   306  				"org/repo": {
   307  					{
   308  						Name:         "jib",
   309  						RunIfChanged: "CHANGED2",
   310  						Context:      "pull-jib",
   311  						Trigger:      `/test all`,
   312  						RerunCommand: `/test all`,
   313  					},
   314  				},
   315  			},
   316  			ShouldBuild: true,
   317  		},
   318  		{
   319  			name:       "Run if changed job triggered by /ok-to-test",
   320  			Author:     "t",
   321  			Body:       "/ok-to-test",
   322  			State:      "open",
   323  			IsPR:       true,
   324  			IsOkToTest: true,
   325  			Presubmits: map[string][]config.Presubmit{
   326  				"org/repo": {
   327  					{
   328  						Name:         "jab",
   329  						RunIfChanged: "CHANGED",
   330  						Context:      "pull-jab",
   331  						Trigger:      `/test all`,
   332  						RerunCommand: `/test all`,
   333  					},
   334  				},
   335  			},
   336  			ShouldBuild:   true,
   337  			StartsExactly: "pull-jab",
   338  			IssueLabels:   []github.Label{{Name: "needs-ok-to-test"}},
   339  		},
   340  		{
   341  			name:   "/test of branch-sharded job",
   342  			Author: "t",
   343  			Body:   "/test jab",
   344  			State:  "open",
   345  			IsPR:   true,
   346  			Presubmits: map[string][]config.Presubmit{
   347  				"org/repo": {
   348  					{
   349  						Name:         "jab",
   350  						Brancher:     config.Brancher{Branches: []string{"master"}},
   351  						Context:      "pull-jab",
   352  						Trigger:      `/test jab`,
   353  						RerunCommand: `/test jab`,
   354  					},
   355  					{
   356  						Name:         "jab",
   357  						Brancher:     config.Brancher{Branches: []string{"release"}},
   358  						Context:      "pull-jab",
   359  						Trigger:      `/test jab`,
   360  						RerunCommand: `/test jab`,
   361  					},
   362  				},
   363  			},
   364  			ShouldBuild:   true,
   365  			StartsExactly: "pull-jab",
   366  		},
   367  		{
   368  			name:   "branch-sharded job. no shard matches base branch",
   369  			Author: "t",
   370  			Branch: "branch",
   371  			Body:   "/test jab",
   372  			State:  "open",
   373  			IsPR:   true,
   374  			Presubmits: map[string][]config.Presubmit{
   375  				"org/repo": {
   376  					{
   377  						Name:         "jab",
   378  						Brancher:     config.Brancher{Branches: []string{"master"}},
   379  						Context:      "pull-jab",
   380  						Trigger:      `/test jab`,
   381  						RerunCommand: `/test jab`,
   382  					},
   383  					{
   384  						Name:         "jab",
   385  						Brancher:     config.Brancher{Branches: []string{"release"}},
   386  						Context:      "pull-jab",
   387  						Trigger:      `/test jab`,
   388  						RerunCommand: `/test jab`,
   389  					},
   390  				},
   391  			},
   392  			ShouldReport: true,
   393  		},
   394  		{
   395  			name: "/retest of RunIfChanged job that doesn't need to run and hasn't run",
   396  
   397  			Author: "t",
   398  			Body:   "/retest",
   399  			State:  "open",
   400  			IsPR:   true,
   401  			Presubmits: map[string][]config.Presubmit{
   402  				"org/repo": {
   403  					{
   404  						Name:         "jeb",
   405  						RunIfChanged: "CHANGED2",
   406  						Context:      "pull-jeb",
   407  						Trigger:      `/test all`,
   408  						RerunCommand: `/test all`,
   409  					},
   410  				},
   411  			},
   412  			ShouldReport: true,
   413  		},
   414  		{
   415  			name: "explicit /test for RunIfChanged job that doesn't need to run",
   416  
   417  			Author: "t",
   418  			Body:   "/test pull-jeb",
   419  			State:  "open",
   420  			IsPR:   true,
   421  			Presubmits: map[string][]config.Presubmit{
   422  				"org/repo": {
   423  					{
   424  						Name:         "jeb",
   425  						RunIfChanged: "CHANGED2",
   426  						Context:      "pull-jib",
   427  						Trigger:      `/test (all|pull-jeb)`,
   428  						RerunCommand: `/test pull-jeb`,
   429  					},
   430  				},
   431  			},
   432  			ShouldBuild: true,
   433  		},
   434  		{
   435  			name:   "/test all of run_if_changed job that has passed and needs to run",
   436  			Author: "t",
   437  			Body:   "/test all",
   438  			State:  "open",
   439  			IsPR:   true,
   440  			Presubmits: map[string][]config.Presubmit{
   441  				"org/repo": {
   442  					{
   443  						Name:         "jub",
   444  						RunIfChanged: "CHANGED",
   445  						Context:      "pull-jub",
   446  						Trigger:      `/test jub`,
   447  						RerunCommand: `/test jub`,
   448  					},
   449  				},
   450  			},
   451  			ShouldBuild:   true,
   452  			StartsExactly: "pull-jub",
   453  		},
   454  		{
   455  			name:   "/test all of run_if_changed job that has passed and doesnt need to run",
   456  			Author: "t",
   457  			Body:   "/test all",
   458  			State:  "open",
   459  			IsPR:   true,
   460  			Presubmits: map[string][]config.Presubmit{
   461  				"org/repo": {
   462  					{
   463  						Name:         "jub",
   464  						RunIfChanged: "CHANGED2",
   465  						Context:      "pull-jub",
   466  						Trigger:      `/test jub`,
   467  						RerunCommand: `/test jub`,
   468  					},
   469  				},
   470  			},
   471  			ShouldReport: true,
   472  		},
   473  	}
   474  	for _, tc := range testcases {
   475  		t.Logf("running scenario %q", tc.name)
   476  		if tc.Branch == "" {
   477  			tc.Branch = "master"
   478  		}
   479  		g := &fakegithub.FakeClient{
   480  			CreatedStatuses: map[string][]github.Status{},
   481  			IssueComments:   map[int][]github.IssueComment{},
   482  			OrgMembers:      map[string][]string{"org": {"t"}},
   483  			PullRequests: map[int]*github.PullRequest{
   484  				0: {
   485  					Number: 0,
   486  					Head: github.PullRequestBranch{
   487  						SHA: "cafe",
   488  					},
   489  					Base: github.PullRequestBranch{
   490  						Ref: tc.Branch,
   491  						Repo: github.Repo{
   492  							Owner: github.User{Login: "org"},
   493  							Name:  "repo",
   494  						},
   495  					},
   496  				},
   497  			},
   498  			PullRequestChanges: map[int][]github.PullRequestChange{0: {{Filename: "CHANGED"}}},
   499  			CombinedStatuses: map[string]*github.CombinedStatus{
   500  				"cafe": {
   501  					Statuses: []github.Status{
   502  						{State: "pending", Context: "pull-job"},
   503  						{State: "failure", Context: "pull-jib"},
   504  						{State: "success", Context: "pull-jub"},
   505  					},
   506  				},
   507  			},
   508  		}
   509  		kc := &fkc{}
   510  		c := client{
   511  			GitHubClient: g,
   512  			KubeClient:   kc,
   513  			Config:       &config.Config{},
   514  			Logger:       logrus.WithField("plugin", pluginName),
   515  		}
   516  		presubmits := tc.Presubmits
   517  		if presubmits == nil {
   518  			presubmits = map[string][]config.Presubmit{
   519  				"org/repo": {
   520  					{
   521  						Name:         "job",
   522  						AlwaysRun:    true,
   523  						Context:      "pull-job",
   524  						Trigger:      `/test all`,
   525  						RerunCommand: `/test all`,
   526  						Brancher:     config.Brancher{Branches: []string{"master"}},
   527  					},
   528  					{
   529  						Name:         "jib",
   530  						AlwaysRun:    false,
   531  						Context:      "pull-jib",
   532  						Trigger:      `/test jib`,
   533  						RerunCommand: `/test jib`,
   534  					},
   535  				},
   536  			}
   537  		}
   538  		if err := c.Config.SetPresubmits(presubmits); err != nil {
   539  			t.Fatalf("failed to set presubmits: %v", err)
   540  		}
   541  
   542  		var pr *struct{}
   543  		if tc.IsPR {
   544  			pr = &struct{}{}
   545  		}
   546  		if tc.HasOkToTest {
   547  			g.IssueComments[0] = []github.IssueComment{{
   548  				Body: "/ok-to-test",
   549  				User: github.User{Login: "t"},
   550  			}}
   551  		}
   552  		event := github.IssueCommentEvent{
   553  			Action: github.IssueCommentActionCreated,
   554  			Repo: github.Repo{
   555  				Owner:    github.User{Login: "org"},
   556  				Name:     "repo",
   557  				FullName: "org/repo",
   558  			},
   559  			Comment: github.IssueComment{
   560  				Body: tc.Body,
   561  				User: github.User{Login: tc.Author},
   562  			},
   563  			Issue: github.Issue{
   564  				User:        github.User{Login: tc.PRAuthor},
   565  				PullRequest: pr,
   566  				State:       tc.State,
   567  			},
   568  		}
   569  		if len(tc.IssueLabels) > 0 {
   570  			event.Issue.Labels = tc.IssueLabels
   571  		}
   572  
   573  		if err := handleIC(c, nil, event); err != nil {
   574  			t.Fatalf("Didn't expect error: %s", err)
   575  		}
   576  		if len(kc.started) > 0 && !tc.ShouldBuild {
   577  			t.Errorf("Built but should not have: %+v", tc)
   578  		} else if len(kc.started) == 0 && tc.ShouldBuild {
   579  			t.Errorf("Not built but should have: %+v", tc)
   580  		}
   581  		if tc.StartsExactly != "" && (len(kc.started) != 1 || kc.started[0] != tc.StartsExactly) {
   582  			t.Errorf("Didn't build expected context %v, instead built %v", tc.StartsExactly, kc.started)
   583  		}
   584  		if tc.ShouldReport && len(g.CreatedStatuses) == 0 {
   585  			t.Error("Expected report to github")
   586  		} else if !tc.ShouldReport && len(g.CreatedStatuses) > 0 {
   587  			t.Errorf("Expected no reports to github, but got %d", len(g.CreatedStatuses))
   588  		}
   589  		if tc.IsOkToTest {
   590  			if len(g.LabelsRemoved) != 1 {
   591  				t.Errorf("expected a label to be removed")
   592  				continue
   593  			}
   594  			expected := "org/repo#0:needs-ok-to-test"
   595  			if g.LabelsRemoved[0] != expected {
   596  				t.Errorf("expected %q to be removed, got %q", expected, g.LabelsRemoved[0])
   597  			}
   598  		}
   599  	}
   600  }