sigs.k8s.io/prow@v0.0.0-20240503223140-c5e374dc7eb1/pkg/crier/reporters/github/reporter_test.go (about)

     1  /*
     2  Copyright 2018 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 github
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"sync"
    23  	"testing"
    24  	"time"
    25  
    26  	"github.com/google/go-cmp/cmp"
    27  	"github.com/google/go-cmp/cmp/cmpopts"
    28  	"github.com/sirupsen/logrus"
    29  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    30  
    31  	v1 "sigs.k8s.io/prow/pkg/apis/prowjobs/v1"
    32  	"sigs.k8s.io/prow/pkg/config"
    33  	"sigs.k8s.io/prow/pkg/github/fakegithub"
    34  	"sigs.k8s.io/prow/pkg/kube"
    35  
    36  	fakectrlruntimeclient "sigs.k8s.io/controller-runtime/pkg/client/fake"
    37  )
    38  
    39  func TestShouldReport(t *testing.T) {
    40  	var testcases = []struct {
    41  		name        string
    42  		pj          v1.ProwJob
    43  		report      bool
    44  		reportAgent v1.ProwJobAgent
    45  	}{
    46  		{
    47  			name: "should not report periodic job",
    48  			pj: v1.ProwJob{
    49  				Spec: v1.ProwJobSpec{
    50  					Type:   v1.PeriodicJob,
    51  					Report: true,
    52  				},
    53  			},
    54  			report: false,
    55  		},
    56  		{
    57  			name: "should report postsubmit job",
    58  			pj: v1.ProwJob{
    59  				Spec: v1.ProwJobSpec{
    60  					Type:   v1.PostsubmitJob,
    61  					Report: true,
    62  				},
    63  			},
    64  			report: true,
    65  		},
    66  		{
    67  			name: "should not report batch job",
    68  			pj: v1.ProwJob{
    69  				Spec: v1.ProwJobSpec{
    70  					Type:   v1.BatchJob,
    71  					Report: true,
    72  				},
    73  			},
    74  			report: false,
    75  		},
    76  		{
    77  			name: "should report presubmit job",
    78  			pj: v1.ProwJob{
    79  				Spec: v1.ProwJobSpec{
    80  					Type:   v1.PresubmitJob,
    81  					Report: true,
    82  				},
    83  			},
    84  			report: true,
    85  		},
    86  		{
    87  			name: "github should not report gerrit jobs",
    88  			pj: v1.ProwJob{
    89  				ObjectMeta: metav1.ObjectMeta{
    90  					Labels: map[string]string{
    91  						kube.GerritReportLabel: "plus-one-this-gerrit-label-please",
    92  					},
    93  				},
    94  				Spec: v1.ProwJobSpec{
    95  					Type:   v1.PresubmitJob,
    96  					Report: true,
    97  				},
    98  			},
    99  		},
   100  	}
   101  
   102  	for _, tc := range testcases {
   103  		t.Run(tc.name, func(t *testing.T) {
   104  			c := NewReporter(nil, nil, tc.reportAgent, nil)
   105  			if r := c.ShouldReport(context.Background(), logrus.NewEntry(logrus.StandardLogger()), &tc.pj); r == tc.report {
   106  				return
   107  			}
   108  			if tc.report {
   109  				t.Error("failed to report")
   110  			} else {
   111  				t.Error("unexpectedly reported")
   112  			}
   113  		})
   114  	}
   115  }
   116  
   117  // TestPresumitReportingLocks verifies locking happens
   118  // for Presubmit reporting. Must be run with -race, relies
   119  // on sigs.k8s.io/prow/pkg/github/fakegithub not being
   120  // threadsafe.
   121  func TestPresumitReportingLocks(t *testing.T) {
   122  	reporter := NewReporter(
   123  		fakegithub.NewFakeClient(),
   124  		func() *config.Config {
   125  			return &config.Config{
   126  				ProwConfig: config.ProwConfig{
   127  					GitHubReporter: config.GitHubReporter{
   128  						JobTypesToReport: []v1.ProwJobType{v1.PresubmitJob},
   129  					},
   130  				},
   131  			}
   132  		},
   133  		v1.ProwJobAgent(""),
   134  		nil,
   135  	)
   136  
   137  	pj := &v1.ProwJob{
   138  		Spec: v1.ProwJobSpec{
   139  			Refs: &v1.Refs{
   140  				Org:   "org",
   141  				Repo:  "repo",
   142  				Pulls: []v1.Pull{{Number: 1}},
   143  			},
   144  			Type:   v1.PresubmitJob,
   145  			Report: true,
   146  		},
   147  		Status: v1.ProwJobStatus{
   148  			State:          v1.ErrorState,
   149  			CompletionTime: &metav1.Time{},
   150  		},
   151  	}
   152  
   153  	wg := &sync.WaitGroup{}
   154  	wg.Add(2)
   155  	go func() {
   156  		if _, _, err := reporter.Report(context.Background(), logrus.NewEntry(logrus.StandardLogger()), pj); err != nil {
   157  			t.Errorf("error reporting: %v", err)
   158  		}
   159  		wg.Done()
   160  	}()
   161  	go func() {
   162  		if _, _, err := reporter.Report(context.Background(), logrus.NewEntry(logrus.StandardLogger()), pj); err != nil {
   163  			t.Errorf("error reporting: %v", err)
   164  		}
   165  		wg.Done()
   166  	}()
   167  
   168  	wg.Wait()
   169  }
   170  
   171  func TestReport(t *testing.T) {
   172  	t.Parallel()
   173  	testCases := []struct {
   174  		name                              string
   175  		createStatusContextError          error
   176  		listIssueCommentsWithContextError error
   177  		expectedError                     string
   178  	}{
   179  		{
   180  			name: "Success",
   181  		},
   182  		{
   183  			name:                     "Maximum sha error gets swallowed",
   184  			createStatusContextError: errors.New(`This SHA and context has reached the maximum number of statuses`),
   185  		},
   186  		{
   187  			name:                     "Error from user side gets swallowed",
   188  			createStatusContextError: errors.New(`error setting status: status code 404 not one of [201], body: {"message":"Not Found","documentation_url":"https://docs.github.com/rest/reference/repos#create-a-commit-status"}`),
   189  		},
   190  		{
   191  			name:                     "Error from user side gets swallowed2",
   192  			createStatusContextError: errors.New(`failed to report job: error setting status: status code 422 not one of [201], body: {"message":"No commit found for SHA: 9d04799d1a22e9e604c50f6bbbec067aaccc1b32","documentation_url":"https://docs.github.com/rest/reference/repos#create-a-commit-status"}`),
   193  		},
   194  		{
   195  			name:                     "Other error get returned",
   196  			createStatusContextError: errors.New("something went wrong :("),
   197  			expectedError:            "error setting status: something went wrong :(",
   198  		},
   199  		{
   200  			name:                              "Comment error_Maximum sha error gets swallowed",
   201  			listIssueCommentsWithContextError: errors.New(`This SHA and context has reached the maximum number of statuses`),
   202  			expectedError:                     "error listing comments: This SHA and context has reached the maximum number of statuses",
   203  		},
   204  		{
   205  			name:                              "Comment error_Error from user side gets swallowed",
   206  			listIssueCommentsWithContextError: errors.New(`error setting status: status code 404 not one of [201], body: {"message":"Not Found","documentation_url":"https://docs.github.com/rest/reference/repos#create-a-commit-status"}`),
   207  			expectedError:                     "error listing comments: error setting status: status code 404 not one of [201], body: {\"message\":\"Not Found\",\"documentation_url\":\"https://docs.github.com/rest/reference/repos#create-a-commit-status\"}",
   208  		},
   209  		{
   210  			name:                              "Comment error_Error from user side gets swallowed2",
   211  			listIssueCommentsWithContextError: errors.New(`failed to report job: error setting status: status code 422 not one of [201], body: {"message":"No commit found for SHA: 9d04799d1a22e9e604c50f6bbbec067aaccc1b32","documentation_url":"https://docs.github.com/rest/reference/repos#create-a-commit-status"}`),
   212  			expectedError:                     "error listing comments: failed to report job: error setting status: status code 422 not one of [201], body: {\"message\":\"No commit found for SHA: 9d04799d1a22e9e604c50f6bbbec067aaccc1b32\",\"documentation_url\":\"https://docs.github.com/rest/reference/repos#create-a-commit-status\"}",
   213  		},
   214  		{
   215  			name:                              "Comment error_Other error get returned",
   216  			listIssueCommentsWithContextError: errors.New("something went wrong :("),
   217  			expectedError:                     "error listing comments: something went wrong :(",
   218  		},
   219  	}
   220  
   221  	for _, tc := range testCases {
   222  		t.Run(tc.name, func(t *testing.T) {
   223  			fghc := fakegithub.NewFakeClient()
   224  			fghc.Error = tc.createStatusContextError
   225  			fghc.ListIssueCommentsWithContextError = tc.listIssueCommentsWithContextError
   226  			c := Client{
   227  				gc: fghc,
   228  				config: func() *config.Config {
   229  					return &config.Config{
   230  						ProwConfig: config.ProwConfig{
   231  							GitHubReporter: config.GitHubReporter{
   232  								JobTypesToReport: []v1.ProwJobType{v1.PostsubmitJob},
   233  							},
   234  						},
   235  					}
   236  				},
   237  			}
   238  			pj := &v1.ProwJob{
   239  				Spec: v1.ProwJobSpec{
   240  					Type:   v1.PostsubmitJob,
   241  					Report: true,
   242  					Refs: &v1.Refs{
   243  						Pulls: []v1.Pull{
   244  							{},
   245  						},
   246  					},
   247  				},
   248  				Status: v1.ProwJobStatus{
   249  					State:          v1.SuccessState,
   250  					CompletionTime: &metav1.Time{},
   251  				},
   252  			}
   253  
   254  			errMsg := ""
   255  			_, _, err := c.Report(context.Background(), logrus.NewEntry(logrus.StandardLogger()), pj)
   256  			if err != nil {
   257  				errMsg = err.Error()
   258  			}
   259  			if errMsg != tc.expectedError {
   260  				t.Errorf("expected error %q got error %q", tc.expectedError, errMsg)
   261  			}
   262  		})
   263  	}
   264  }
   265  
   266  func TestPjsToReport(t *testing.T) {
   267  	timeNow := time.Now().Truncate(time.Second) // Truncate so that comparison works.
   268  	var testcases = []struct {
   269  		name        string
   270  		pj          *v1.ProwJob
   271  		existingPJs []*v1.ProwJob
   272  		wantPjs     []v1.ProwJob
   273  		wantErr     bool
   274  	}{
   275  		{
   276  			name: "two-jobs-finished",
   277  			pj: &v1.ProwJob{
   278  				ObjectMeta: metav1.ObjectMeta{
   279  					Name: "0",
   280  					Labels: map[string]string{
   281  						kube.ProwJobTypeLabel: "presubmit",
   282  						kube.OrgLabel:         "org",
   283  						kube.RepoLabel:        "repo",
   284  						kube.PullLabel:        "123",
   285  					},
   286  					CreationTimestamp: metav1.Time{
   287  						Time: timeNow.Add(-time.Hour),
   288  					},
   289  				},
   290  				Status: v1.ProwJobStatus{
   291  					State:          v1.SuccessState,
   292  					CompletionTime: &metav1.Time{Time: timeNow.Add(-time.Minute)},
   293  				},
   294  				Spec: v1.ProwJobSpec{
   295  					Type: v1.PresubmitJob,
   296  					Refs: &v1.Refs{
   297  						Repo: "foo",
   298  						Pulls: []v1.Pull{
   299  							{
   300  								Number: 123,
   301  							},
   302  						},
   303  					},
   304  					Job:    "ci-foo",
   305  					Report: true,
   306  				},
   307  			},
   308  			existingPJs: []*v1.ProwJob{
   309  				{
   310  					ObjectMeta: metav1.ObjectMeta{
   311  						Name: "1",
   312  						Labels: map[string]string{
   313  							kube.ProwJobTypeLabel: "presubmit",
   314  							kube.OrgLabel:         "org",
   315  							kube.RepoLabel:        "repo",
   316  							kube.PullLabel:        "123",
   317  						},
   318  						CreationTimestamp: metav1.Time{
   319  							Time: timeNow.Add(-time.Hour),
   320  						},
   321  					},
   322  					Status: v1.ProwJobStatus{
   323  						State: v1.FailureState,
   324  						PrevReportStates: map[string]v1.ProwJobState{
   325  							"github-reporter": v1.FailureState,
   326  						},
   327  						CompletionTime: &metav1.Time{Time: timeNow.Add(-time.Minute)},
   328  					},
   329  					Spec: v1.ProwJobSpec{
   330  						Refs: &v1.Refs{
   331  							Repo: "bar",
   332  							Pulls: []v1.Pull{
   333  								{
   334  									Number: 123,
   335  								},
   336  							},
   337  						},
   338  						Job:    "ci-bar",
   339  						Type:   v1.PresubmitJob,
   340  						Report: true,
   341  					},
   342  				},
   343  			},
   344  			wantPjs: []v1.ProwJob{
   345  				{
   346  					ObjectMeta: metav1.ObjectMeta{
   347  						Name: "0",
   348  						Labels: map[string]string{
   349  							kube.ProwJobTypeLabel: "presubmit",
   350  							kube.OrgLabel:         "org",
   351  							kube.RepoLabel:        "repo",
   352  							kube.PullLabel:        "123",
   353  						},
   354  						CreationTimestamp: metav1.Time{
   355  							Time: timeNow.Add(-time.Hour),
   356  						},
   357  						ResourceVersion: "999",
   358  					},
   359  					Status: v1.ProwJobStatus{
   360  						State:          v1.SuccessState,
   361  						CompletionTime: &metav1.Time{Time: timeNow.Add(-time.Minute)},
   362  					},
   363  					Spec: v1.ProwJobSpec{
   364  						Type: v1.PresubmitJob,
   365  						Refs: &v1.Refs{
   366  							Repo: "foo",
   367  							Pulls: []v1.Pull{
   368  								{
   369  									Number: 123,
   370  								},
   371  							},
   372  						},
   373  						Job:    "ci-foo",
   374  						Report: true,
   375  					},
   376  				},
   377  				{
   378  					ObjectMeta: metav1.ObjectMeta{
   379  						Name: "1",
   380  						Labels: map[string]string{
   381  							kube.ProwJobTypeLabel: "presubmit",
   382  							kube.OrgLabel:         "org",
   383  							kube.RepoLabel:        "repo",
   384  							kube.PullLabel:        "123",
   385  						},
   386  						CreationTimestamp: metav1.Time{
   387  							Time: timeNow.Add(-time.Hour),
   388  						},
   389  						ResourceVersion: "999",
   390  					},
   391  					Status: v1.ProwJobStatus{
   392  						State: v1.FailureState,
   393  						PrevReportStates: map[string]v1.ProwJobState{
   394  							"github-reporter": v1.FailureState,
   395  						},
   396  						CompletionTime: &metav1.Time{Time: timeNow.Add(-time.Minute)},
   397  					},
   398  					Spec: v1.ProwJobSpec{
   399  						Refs: &v1.Refs{
   400  							Repo: "bar",
   401  							Pulls: []v1.Pull{
   402  								{
   403  									Number: 123,
   404  								},
   405  							},
   406  						},
   407  						Job:    "ci-bar",
   408  						Type:   v1.PresubmitJob,
   409  						Report: true,
   410  					},
   411  				},
   412  			},
   413  		},
   414  		{
   415  			name: "one-job-still-running",
   416  			pj: &v1.ProwJob{
   417  				ObjectMeta: metav1.ObjectMeta{
   418  					Name: "0",
   419  					Labels: map[string]string{
   420  						kube.ProwJobTypeLabel: "presubmit",
   421  						kube.OrgLabel:         "org",
   422  						kube.RepoLabel:        "repo",
   423  						kube.PullLabel:        "123",
   424  					},
   425  					CreationTimestamp: metav1.Time{
   426  						Time: timeNow.Add(-time.Hour),
   427  					},
   428  				},
   429  				Status: v1.ProwJobStatus{
   430  					State:          v1.SuccessState,
   431  					CompletionTime: &metav1.Time{Time: timeNow.Add(-time.Minute)},
   432  				},
   433  				Spec: v1.ProwJobSpec{
   434  					Type: v1.PresubmitJob,
   435  					Refs: &v1.Refs{
   436  						Repo: "foo",
   437  						Pulls: []v1.Pull{
   438  							{
   439  								Number: 123,
   440  							},
   441  						},
   442  					},
   443  					Job:    "ci-foo",
   444  					Report: true,
   445  				},
   446  			},
   447  			existingPJs: []*v1.ProwJob{
   448  				{
   449  					ObjectMeta: metav1.ObjectMeta{
   450  						Name: "1",
   451  						Labels: map[string]string{
   452  							kube.ProwJobTypeLabel: "presubmit",
   453  							kube.OrgLabel:         "org",
   454  							kube.RepoLabel:        "repo",
   455  							kube.PullLabel:        "123",
   456  						},
   457  						CreationTimestamp: metav1.Time{
   458  							Time: timeNow.Add(-time.Hour),
   459  						},
   460  					},
   461  					Status: v1.ProwJobStatus{
   462  						State: v1.FailureState,
   463  						PrevReportStates: map[string]v1.ProwJobState{
   464  							"github-reporter": v1.FailureState,
   465  						},
   466  					},
   467  					Spec: v1.ProwJobSpec{
   468  						Refs: &v1.Refs{
   469  							Repo: "bar",
   470  							Pulls: []v1.Pull{
   471  								{
   472  									Number: 123,
   473  								},
   474  							},
   475  						},
   476  						Job:    "ci-bar",
   477  						Type:   v1.PresubmitJob,
   478  						Report: true,
   479  					},
   480  				},
   481  			},
   482  		},
   483  		{
   484  			name: "mix-of-finished-and-running",
   485  			pj: &v1.ProwJob{
   486  				ObjectMeta: metav1.ObjectMeta{
   487  					Name: "0",
   488  					Labels: map[string]string{
   489  						kube.ProwJobTypeLabel: "presubmit",
   490  						kube.OrgLabel:         "org",
   491  						kube.RepoLabel:        "repo",
   492  						kube.PullLabel:        "123",
   493  					},
   494  					CreationTimestamp: metav1.Time{
   495  						Time: timeNow.Add(-time.Hour),
   496  					},
   497  				},
   498  				Status: v1.ProwJobStatus{
   499  					State:          v1.SuccessState,
   500  					CompletionTime: &metav1.Time{Time: timeNow.Add(-time.Minute)},
   501  				},
   502  				Spec: v1.ProwJobSpec{
   503  					Type: v1.PresubmitJob,
   504  					Refs: &v1.Refs{
   505  						Repo: "foo",
   506  						Pulls: []v1.Pull{
   507  							{
   508  								Number: 123,
   509  							},
   510  						},
   511  					},
   512  					Job:    "ci-foo",
   513  					Report: true,
   514  				},
   515  			},
   516  			existingPJs: []*v1.ProwJob{
   517  				{
   518  					ObjectMeta: metav1.ObjectMeta{
   519  						Name: "1",
   520  						Labels: map[string]string{
   521  							kube.ProwJobTypeLabel: "presubmit",
   522  							kube.OrgLabel:         "org",
   523  							kube.RepoLabel:        "repo",
   524  							kube.PullLabel:        "123",
   525  						},
   526  						CreationTimestamp: metav1.Time{
   527  							Time: timeNow.Add(-time.Hour),
   528  						},
   529  					},
   530  					Status: v1.ProwJobStatus{
   531  						State: v1.FailureState,
   532  						PrevReportStates: map[string]v1.ProwJobState{
   533  							"github-reporter": v1.FailureState,
   534  						},
   535  						CompletionTime: &metav1.Time{Time: timeNow.Add(-time.Minute)},
   536  					},
   537  					Spec: v1.ProwJobSpec{
   538  						Refs: &v1.Refs{
   539  							Repo: "bar",
   540  							Pulls: []v1.Pull{
   541  								{
   542  									Number: 123,
   543  								},
   544  							},
   545  						},
   546  						Job:    "ci-bar",
   547  						Type:   v1.PresubmitJob,
   548  						Report: true,
   549  					},
   550  				},
   551  				{
   552  					ObjectMeta: metav1.ObjectMeta{
   553  						Name: "2",
   554  						Labels: map[string]string{
   555  							kube.ProwJobTypeLabel: "presubmit",
   556  							kube.OrgLabel:         "org",
   557  							kube.RepoLabel:        "repo",
   558  							kube.PullLabel:        "123",
   559  						},
   560  						CreationTimestamp: metav1.Time{
   561  							Time: timeNow.Add(-time.Hour),
   562  						},
   563  					},
   564  					Status: v1.ProwJobStatus{
   565  						State: v1.PendingState,
   566  					},
   567  					Spec: v1.ProwJobSpec{
   568  						Refs: &v1.Refs{
   569  							Repo: "bar",
   570  							Pulls: []v1.Pull{
   571  								{
   572  									Number: 123,
   573  								},
   574  							},
   575  						},
   576  						Job:    "ci-baz",
   577  						Type:   v1.PresubmitJob,
   578  						Report: true,
   579  					},
   580  				},
   581  			},
   582  		},
   583  		{
   584  			name: "current-job-only",
   585  			pj: &v1.ProwJob{
   586  				ObjectMeta: metav1.ObjectMeta{
   587  					Name: "0",
   588  					Labels: map[string]string{
   589  						kube.ProwJobTypeLabel: "presubmit",
   590  						kube.OrgLabel:         "org",
   591  						kube.RepoLabel:        "repo",
   592  						kube.PullLabel:        "123",
   593  					},
   594  					CreationTimestamp: metav1.Time{
   595  						Time: timeNow.Add(-time.Hour),
   596  					},
   597  				},
   598  				Status: v1.ProwJobStatus{
   599  					State:          v1.SuccessState,
   600  					CompletionTime: &metav1.Time{Time: timeNow.Add(-time.Minute)},
   601  				},
   602  				Spec: v1.ProwJobSpec{
   603  					Type: v1.PresubmitJob,
   604  					Refs: &v1.Refs{
   605  						Repo: "foo",
   606  						Pulls: []v1.Pull{
   607  							{
   608  								Number: 123,
   609  							},
   610  						},
   611  					},
   612  					Job:    "ci-foo",
   613  					Report: true,
   614  				},
   615  			},
   616  			wantPjs: []v1.ProwJob{
   617  				{
   618  					ObjectMeta: metav1.ObjectMeta{
   619  						Name: "0",
   620  						Labels: map[string]string{
   621  							kube.ProwJobTypeLabel: "presubmit",
   622  							kube.OrgLabel:         "org",
   623  							kube.RepoLabel:        "repo",
   624  							kube.PullLabel:        "123",
   625  						},
   626  						CreationTimestamp: metav1.Time{
   627  							Time: timeNow.Add(-time.Hour),
   628  						},
   629  						ResourceVersion: "999",
   630  					},
   631  					Status: v1.ProwJobStatus{
   632  						State:          v1.SuccessState,
   633  						CompletionTime: &metav1.Time{Time: timeNow.Add(-time.Minute)},
   634  					},
   635  					Spec: v1.ProwJobSpec{
   636  						Type: v1.PresubmitJob,
   637  						Refs: &v1.Refs{
   638  							Repo: "foo",
   639  							Pulls: []v1.Pull{
   640  								{
   641  									Number: 123,
   642  								},
   643  							},
   644  						},
   645  						Job:    "ci-foo",
   646  						Report: true,
   647  					},
   648  				},
   649  			},
   650  		},
   651  		{
   652  			name: "current-job-not-finished",
   653  			pj: &v1.ProwJob{
   654  				ObjectMeta: metav1.ObjectMeta{
   655  					Name: "0",
   656  					Labels: map[string]string{
   657  						kube.ProwJobTypeLabel: "presubmit",
   658  						kube.OrgLabel:         "org",
   659  						kube.RepoLabel:        "repo",
   660  						kube.PullLabel:        "123",
   661  					},
   662  					CreationTimestamp: metav1.Time{
   663  						Time: timeNow.Add(-time.Hour),
   664  					},
   665  				},
   666  				Status: v1.ProwJobStatus{
   667  					State: v1.SuccessState,
   668  				},
   669  				Spec: v1.ProwJobSpec{
   670  					Type: v1.PresubmitJob,
   671  					Refs: &v1.Refs{
   672  						Repo: "foo",
   673  						Pulls: []v1.Pull{
   674  							{
   675  								Number: 123,
   676  							},
   677  						},
   678  					},
   679  					Job:    "ci-foo",
   680  					Report: true,
   681  				},
   682  			},
   683  		},
   684  		{
   685  			name: "job-not-same-pr",
   686  			pj: &v1.ProwJob{
   687  				ObjectMeta: metav1.ObjectMeta{
   688  					Name: "0",
   689  					Labels: map[string]string{
   690  						kube.ProwJobTypeLabel: "presubmit",
   691  						kube.OrgLabel:         "org",
   692  						kube.RepoLabel:        "repo",
   693  						kube.PullLabel:        "456",
   694  					},
   695  					CreationTimestamp: metav1.Time{
   696  						Time: timeNow.Add(-time.Hour),
   697  					},
   698  				},
   699  				Status: v1.ProwJobStatus{
   700  					State:          v1.SuccessState,
   701  					CompletionTime: &metav1.Time{Time: timeNow.Add(-time.Minute)},
   702  				},
   703  				Spec: v1.ProwJobSpec{
   704  					Type: v1.PresubmitJob,
   705  					Refs: &v1.Refs{
   706  						Repo: "foo",
   707  						Pulls: []v1.Pull{
   708  							{
   709  								Number: 123,
   710  							},
   711  						},
   712  					},
   713  					Job:    "ci-foo",
   714  					Report: true,
   715  				},
   716  			},
   717  			existingPJs: []*v1.ProwJob{
   718  				{
   719  					ObjectMeta: metav1.ObjectMeta{
   720  						Name: "1",
   721  						Labels: map[string]string{
   722  							kube.ProwJobTypeLabel: "presubmit",
   723  							kube.OrgLabel:         "org",
   724  							kube.RepoLabel:        "repo",
   725  							kube.PullLabel:        "123",
   726  						},
   727  						CreationTimestamp: metav1.Time{
   728  							Time: timeNow.Add(-time.Hour),
   729  						},
   730  					},
   731  					Status: v1.ProwJobStatus{
   732  						State: v1.FailureState,
   733  						PrevReportStates: map[string]v1.ProwJobState{
   734  							"github-reporter": v1.FailureState,
   735  						},
   736  						CompletionTime: &metav1.Time{Time: timeNow.Add(-time.Minute)},
   737  					},
   738  					Spec: v1.ProwJobSpec{
   739  						Refs: &v1.Refs{
   740  							Repo: "bar",
   741  							Pulls: []v1.Pull{
   742  								{
   743  									Number: 123,
   744  								},
   745  							},
   746  						},
   747  						Job:    "ci-bar",
   748  						Type:   v1.PresubmitJob,
   749  						Report: true,
   750  					},
   751  				},
   752  			},
   753  			wantPjs: []v1.ProwJob{
   754  				{
   755  					ObjectMeta: metav1.ObjectMeta{
   756  						Name: "0",
   757  						Labels: map[string]string{
   758  							kube.ProwJobTypeLabel: "presubmit",
   759  							kube.OrgLabel:         "org",
   760  							kube.RepoLabel:        "repo",
   761  							kube.PullLabel:        "456",
   762  						},
   763  						CreationTimestamp: metav1.Time{
   764  							Time: timeNow.Add(-time.Hour),
   765  						},
   766  						ResourceVersion: "999",
   767  					},
   768  					Status: v1.ProwJobStatus{
   769  						State:          v1.SuccessState,
   770  						CompletionTime: &metav1.Time{Time: timeNow.Add(-time.Minute)},
   771  					},
   772  					Spec: v1.ProwJobSpec{
   773  						Type: v1.PresubmitJob,
   774  						Refs: &v1.Refs{
   775  							Repo: "foo",
   776  							Pulls: []v1.Pull{
   777  								{
   778  									Number: 123,
   779  								},
   780  							},
   781  						},
   782  						Job:    "ci-foo",
   783  						Report: true,
   784  					},
   785  				},
   786  			},
   787  		},
   788  		{
   789  			name: "job-not-same-org",
   790  			pj: &v1.ProwJob{
   791  				ObjectMeta: metav1.ObjectMeta{
   792  					Name: "0",
   793  					Labels: map[string]string{
   794  						kube.ProwJobTypeLabel: "presubmit",
   795  						kube.OrgLabel:         "org-different",
   796  						kube.RepoLabel:        "repo",
   797  						kube.PullLabel:        "123",
   798  					},
   799  					CreationTimestamp: metav1.Time{
   800  						Time: timeNow.Add(-time.Hour),
   801  					},
   802  				},
   803  				Status: v1.ProwJobStatus{
   804  					State:          v1.SuccessState,
   805  					CompletionTime: &metav1.Time{Time: timeNow.Add(-time.Minute)},
   806  				},
   807  				Spec: v1.ProwJobSpec{
   808  					Type: v1.PresubmitJob,
   809  					Refs: &v1.Refs{
   810  						Repo: "foo",
   811  						Pulls: []v1.Pull{
   812  							{
   813  								Number: 123,
   814  							},
   815  						},
   816  					},
   817  					Job:    "ci-foo",
   818  					Report: true,
   819  				},
   820  			},
   821  			existingPJs: []*v1.ProwJob{
   822  				{
   823  					ObjectMeta: metav1.ObjectMeta{
   824  						Name: "1",
   825  						Labels: map[string]string{
   826  							kube.ProwJobTypeLabel: "presubmit",
   827  							kube.OrgLabel:         "org",
   828  							kube.RepoLabel:        "repo",
   829  							kube.PullLabel:        "123",
   830  						},
   831  						CreationTimestamp: metav1.Time{
   832  							Time: timeNow.Add(-time.Hour),
   833  						},
   834  					},
   835  					Status: v1.ProwJobStatus{
   836  						State: v1.FailureState,
   837  						PrevReportStates: map[string]v1.ProwJobState{
   838  							"github-reporter": v1.FailureState,
   839  						},
   840  						CompletionTime: &metav1.Time{Time: timeNow.Add(-time.Minute)},
   841  					},
   842  					Spec: v1.ProwJobSpec{
   843  						Refs: &v1.Refs{
   844  							Repo: "bar",
   845  							Pulls: []v1.Pull{
   846  								{
   847  									Number: 123,
   848  								},
   849  							},
   850  						},
   851  						Job:    "ci-bar",
   852  						Type:   v1.PresubmitJob,
   853  						Report: true,
   854  					},
   855  				},
   856  			},
   857  			wantPjs: []v1.ProwJob{
   858  				{
   859  					ObjectMeta: metav1.ObjectMeta{
   860  						Name: "0",
   861  						Labels: map[string]string{
   862  							kube.ProwJobTypeLabel: "presubmit",
   863  							kube.OrgLabel:         "org-different",
   864  							kube.RepoLabel:        "repo",
   865  							kube.PullLabel:        "123",
   866  						},
   867  						CreationTimestamp: metav1.Time{
   868  							Time: timeNow.Add(-time.Hour),
   869  						},
   870  						ResourceVersion: "999",
   871  					},
   872  					Status: v1.ProwJobStatus{
   873  						State:          v1.SuccessState,
   874  						CompletionTime: &metav1.Time{Time: timeNow.Add(-time.Minute)},
   875  					},
   876  					Spec: v1.ProwJobSpec{
   877  						Type: v1.PresubmitJob,
   878  						Refs: &v1.Refs{
   879  							Repo: "foo",
   880  							Pulls: []v1.Pull{
   881  								{
   882  									Number: 123,
   883  								},
   884  							},
   885  						},
   886  						Job:    "ci-foo",
   887  						Report: true,
   888  					},
   889  				},
   890  			},
   891  		},
   892  		{
   893  			name: "job-not-same-pr",
   894  			pj: &v1.ProwJob{
   895  				ObjectMeta: metav1.ObjectMeta{
   896  					Name: "0",
   897  					Labels: map[string]string{
   898  						kube.ProwJobTypeLabel: "presubmit",
   899  						kube.OrgLabel:         "org",
   900  						kube.RepoLabel:        "repo-different",
   901  						kube.PullLabel:        "123",
   902  					},
   903  					CreationTimestamp: metav1.Time{
   904  						Time: timeNow.Add(-time.Hour),
   905  					},
   906  				},
   907  				Status: v1.ProwJobStatus{
   908  					State:          v1.SuccessState,
   909  					CompletionTime: &metav1.Time{Time: timeNow.Add(-time.Minute)},
   910  				},
   911  				Spec: v1.ProwJobSpec{
   912  					Type: v1.PresubmitJob,
   913  					Refs: &v1.Refs{
   914  						Repo: "foo",
   915  						Pulls: []v1.Pull{
   916  							{
   917  								Number: 123,
   918  							},
   919  						},
   920  					},
   921  					Job:    "ci-foo",
   922  					Report: true,
   923  				},
   924  			},
   925  			existingPJs: []*v1.ProwJob{
   926  				{
   927  					ObjectMeta: metav1.ObjectMeta{
   928  						Name: "1",
   929  						Labels: map[string]string{
   930  							kube.ProwJobTypeLabel: "presubmit",
   931  							kube.OrgLabel:         "org",
   932  							kube.RepoLabel:        "repo",
   933  							kube.PullLabel:        "123",
   934  						},
   935  						CreationTimestamp: metav1.Time{
   936  							Time: timeNow.Add(-time.Hour),
   937  						},
   938  					},
   939  					Status: v1.ProwJobStatus{
   940  						State: v1.FailureState,
   941  						PrevReportStates: map[string]v1.ProwJobState{
   942  							"github-reporter": v1.FailureState,
   943  						},
   944  						CompletionTime: &metav1.Time{Time: timeNow.Add(-time.Minute)},
   945  					},
   946  					Spec: v1.ProwJobSpec{
   947  						Refs: &v1.Refs{
   948  							Repo: "bar",
   949  							Pulls: []v1.Pull{
   950  								{
   951  									Number: 123,
   952  								},
   953  							},
   954  						},
   955  						Job:    "ci-bar",
   956  						Type:   v1.PresubmitJob,
   957  						Report: true,
   958  					},
   959  				},
   960  			},
   961  			wantPjs: []v1.ProwJob{
   962  				{
   963  					ObjectMeta: metav1.ObjectMeta{
   964  						Name: "0",
   965  						Labels: map[string]string{
   966  							kube.ProwJobTypeLabel: "presubmit",
   967  							kube.OrgLabel:         "org",
   968  							kube.RepoLabel:        "repo-different",
   969  							kube.PullLabel:        "123",
   970  						},
   971  						CreationTimestamp: metav1.Time{
   972  							Time: timeNow.Add(-time.Hour),
   973  						},
   974  						ResourceVersion: "999",
   975  					},
   976  					Status: v1.ProwJobStatus{
   977  						State:          v1.SuccessState,
   978  						CompletionTime: &metav1.Time{Time: timeNow.Add(-time.Minute)},
   979  					},
   980  					Spec: v1.ProwJobSpec{
   981  						Type: v1.PresubmitJob,
   982  						Refs: &v1.Refs{
   983  							Repo: "foo",
   984  							Pulls: []v1.Pull{
   985  								{
   986  									Number: 123,
   987  								},
   988  							},
   989  						},
   990  						Job:    "ci-foo",
   991  						Report: true,
   992  					},
   993  				},
   994  			},
   995  		},
   996  	}
   997  
   998  	for _, tc := range testcases {
   999  		t.Run(tc.name, func(t *testing.T) {
  1000  			builder := fakectrlruntimeclient.NewClientBuilder().WithObjects(tc.pj)
  1001  			for _, pj := range tc.existingPJs {
  1002  				builder.WithObjects(pj)
  1003  			}
  1004  
  1005  			lister := builder.Build()
  1006  
  1007  			gotPjs, gotErr := pjsToReport(context.Background(), &logrus.Entry{}, lister, tc.pj)
  1008  			if (gotErr != nil && !tc.wantErr) || (gotErr == nil && tc.wantErr) {
  1009  				t.Fatalf("error mismatch. got: %v, want: %v", gotErr, tc.wantErr)
  1010  			}
  1011  			if diff := cmp.Diff(tc.wantPjs, gotPjs, cmpopts.SortSlices(func(a, b v1.ProwJob) bool {
  1012  				return a.Name > b.Name
  1013  			})); diff != "" {
  1014  				t.Fatalf("pjs mismatch. got(+), want(-):\n%s", diff)
  1015  			}
  1016  		})
  1017  	}
  1018  }