github.com/abayer/test-infra@v0.0.5/prow/report/report_test.go (about)

     1  /*
     2  Copyright 2017 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 report
    18  
    19  import (
    20  	"fmt"
    21  	"strings"
    22  	"testing"
    23  
    24  	"k8s.io/test-infra/prow/github"
    25  	"k8s.io/test-infra/prow/kube"
    26  )
    27  
    28  func TestParseIssueComment(t *testing.T) {
    29  	var testcases = []struct {
    30  		name             string
    31  		context          string
    32  		state            string
    33  		ics              []github.IssueComment
    34  		expectedDeletes  []int
    35  		expectedContexts []string
    36  		expectedUpdate   int
    37  	}{
    38  		{
    39  			name:    "should delete old style comments",
    40  			context: "Jenkins foo test",
    41  			state:   github.StatusSuccess,
    42  			ics: []github.IssueComment{
    43  				{
    44  					User: github.User{Login: "k8s-ci-robot"},
    45  					Body: "Jenkins foo test **failed** for such-and-such.",
    46  					ID:   12345,
    47  				},
    48  				{
    49  					User: github.User{Login: "someone-else"},
    50  					Body: "Jenkins foo test **failed**!? Why?",
    51  					ID:   12356,
    52  				},
    53  				{
    54  					User: github.User{Login: "k8s-ci-robot"},
    55  					Body: "Jenkins foo test **failed** for so-and-so.",
    56  					ID:   12367,
    57  				},
    58  				{
    59  					User: github.User{Login: "k8s-ci-robot"},
    60  					Body: "Jenkins bar test **failed** for something-or-other.",
    61  					ID:   12378,
    62  				},
    63  			},
    64  			expectedDeletes: []int{12345, 12367},
    65  		},
    66  		{
    67  			name:             "should create a new comment",
    68  			context:          "bla test",
    69  			state:            github.StatusFailure,
    70  			expectedContexts: []string{"bla test"},
    71  		},
    72  		{
    73  			name:    "should not delete an up-to-date comment",
    74  			context: "bla test",
    75  			state:   github.StatusSuccess,
    76  			ics: []github.IssueComment{
    77  				{
    78  					User: github.User{Login: "k8s-ci-robot"},
    79  					Body: "--- | --- | ---\nfoo test | something | or other\n\n",
    80  				},
    81  			},
    82  		},
    83  		{
    84  			name:    "should delete when all tests pass",
    85  			context: "bla test",
    86  			state:   github.StatusSuccess,
    87  			ics: []github.IssueComment{
    88  				{
    89  					User: github.User{Login: "k8s-ci-robot"},
    90  					Body: "--- | --- | ---\nbla test | something | or other\n\n" + commentTag,
    91  					ID:   123,
    92  				},
    93  			},
    94  			expectedDeletes:  []int{123},
    95  			expectedContexts: []string{},
    96  		},
    97  		{
    98  			name:    "should delete a passing test with \\r",
    99  			context: "bla test",
   100  			state:   github.StatusSuccess,
   101  			ics: []github.IssueComment{
   102  				{
   103  					User: github.User{Login: "k8s-ci-robot"},
   104  					Body: "--- | --- | ---\r\nbla test | something | or other\r\n\r\n" + commentTag,
   105  					ID:   123,
   106  				},
   107  			},
   108  			expectedDeletes:  []int{123},
   109  			expectedContexts: []string{},
   110  		},
   111  
   112  		{
   113  			name:    "should update a failed test",
   114  			context: "bla test",
   115  			state:   github.StatusFailure,
   116  			ics: []github.IssueComment{
   117  				{
   118  					User: github.User{Login: "k8s-ci-robot"},
   119  					Body: "--- | --- | ---\nbla test | something | or other\n\n" + commentTag,
   120  					ID:   123,
   121  				},
   122  			},
   123  			expectedDeletes:  []int{123},
   124  			expectedContexts: []string{"bla test"},
   125  		},
   126  		{
   127  			name:    "should preserve old results when updating",
   128  			context: "bla test",
   129  			state:   github.StatusFailure,
   130  			ics: []github.IssueComment{
   131  				{
   132  					User: github.User{Login: "k8s-ci-robot"},
   133  					Body: "--- | --- | ---\nbla test | something | or other\nfoo test | wow | aye\n\n" + commentTag,
   134  					ID:   123,
   135  				},
   136  			},
   137  			expectedDeletes:  []int{123},
   138  			expectedContexts: []string{"bla test", "foo test"},
   139  		},
   140  		{
   141  			name:    "should merge duplicates",
   142  			context: "bla test",
   143  			state:   github.StatusFailure,
   144  			ics: []github.IssueComment{
   145  				{
   146  					User: github.User{Login: "k8s-ci-robot"},
   147  					Body: "--- | --- | ---\nbla test | something | or other\nfoo test | wow such\n\n" + commentTag,
   148  					ID:   123,
   149  				},
   150  				{
   151  					User: github.User{Login: "k8s-ci-robot"},
   152  					Body: "--- | --- | ---\nfoo test | beep | boop\n\n" + commentTag,
   153  					ID:   124,
   154  				},
   155  			},
   156  			expectedDeletes:  []int{123, 124},
   157  			expectedContexts: []string{"bla test", "foo test"},
   158  		},
   159  		{
   160  			name:    "should update an old comment when a test passes",
   161  			context: "bla test",
   162  			state:   github.StatusSuccess,
   163  			ics: []github.IssueComment{
   164  				{
   165  					User: github.User{Login: "k8s-ci-robot"},
   166  					Body: "--- | --- | ---\nbla test | something | or other\nfoo test | wow | aye\n\n" + commentTag,
   167  					ID:   123,
   168  				},
   169  			},
   170  			expectedDeletes:  []int{},
   171  			expectedContexts: []string{"foo test"},
   172  			expectedUpdate:   123,
   173  		},
   174  	}
   175  	for _, tc := range testcases {
   176  		pj := kube.ProwJob{
   177  			Spec: kube.ProwJobSpec{
   178  				Context: tc.context,
   179  				Refs:    &kube.Refs{Pulls: []kube.Pull{{}}},
   180  			},
   181  			Status: kube.ProwJobStatus{
   182  				State: kube.ProwJobState(tc.state),
   183  			},
   184  		}
   185  		deletes, entries, update := parseIssueComments(pj, "k8s-ci-robot", tc.ics)
   186  		if len(deletes) != len(tc.expectedDeletes) {
   187  			t.Errorf("It %s: wrong number of deletes. Got %v, expected %v", tc.name, deletes, tc.expectedDeletes)
   188  		} else {
   189  			for _, edel := range tc.expectedDeletes {
   190  				found := false
   191  				for _, del := range deletes {
   192  					if del == edel {
   193  						found = true
   194  						break
   195  					}
   196  				}
   197  				if !found {
   198  					t.Errorf("It %s: expected to find %d in %v", tc.name, edel, deletes)
   199  				}
   200  			}
   201  		}
   202  		if len(entries) != len(tc.expectedContexts) {
   203  			t.Errorf("It %s: wrong number of entries. Got %v, expected %v", tc.name, entries, tc.expectedContexts)
   204  		} else {
   205  			for _, econt := range tc.expectedContexts {
   206  				found := false
   207  				for _, ent := range entries {
   208  					if strings.Contains(ent, econt) {
   209  						found = true
   210  						break
   211  					}
   212  				}
   213  				if !found {
   214  					t.Errorf("It %s: expected to find %s in %v", tc.name, econt, entries)
   215  				}
   216  			}
   217  		}
   218  		if tc.expectedUpdate != update {
   219  			t.Errorf("It %s: expected update %d, got %d", tc.name, tc.expectedUpdate, update)
   220  		}
   221  	}
   222  }
   223  
   224  type fakeGhClient struct {
   225  	status []github.Status
   226  }
   227  
   228  func (gh fakeGhClient) BotName() (string, error) {
   229  	return "BotName", nil
   230  }
   231  func (gh *fakeGhClient) CreateStatus(org, repo, ref string, s github.Status) error {
   232  	gh.status = append(gh.status, s)
   233  	return nil
   234  
   235  }
   236  func (gh fakeGhClient) ListIssueComments(org, repo string, number int) ([]github.IssueComment, error) {
   237  	return nil, nil
   238  }
   239  func (gh fakeGhClient) CreateComment(org, repo string, number int, comment string) error {
   240  	return nil
   241  }
   242  func (gh fakeGhClient) DeleteComment(org, repo string, ID int) error {
   243  	return nil
   244  }
   245  func (gh fakeGhClient) EditComment(org, repo string, ID int, comment string) error {
   246  	return nil
   247  }
   248  
   249  func createChildren(pj *kube.ProwJobSpec, d int) {
   250  	for i := 0; i < d; i++ {
   251  		npj := &kube.ProwJobSpec{
   252  			// TODO: Support testing this via defining expected behavior in TestReportStatus
   253  			Type:    kube.PresubmitJob,
   254  			Report:  true,
   255  			Context: fmt.Sprintf("%s/child_%d", pj.Context, i),
   256  			Refs: &kube.Refs{
   257  				Org:  "k8s",
   258  				Repo: "test-infra",
   259  				Pulls: []kube.Pull{{
   260  					Author: "me",
   261  					Number: 1,
   262  					SHA:    "abcdef",
   263  				}},
   264  			},
   265  		}
   266  		pj.RunAfterSuccess = append(pj.RunAfterSuccess, *npj)
   267  	}
   268  }
   269  
   270  func TestReportStatus(t *testing.T) {
   271  	tests := []struct {
   272  		name string
   273  
   274  		// TODO: This should be the RunAfterSuccess spec and not a single int.
   275  		children int
   276  		state    kube.ProwJobState
   277  		report   bool
   278  
   279  		expectedStatuses []string
   280  	}{
   281  		{
   282  			name: "successful_job-report_true",
   283  
   284  			children: 3,
   285  			state:    kube.SuccessState,
   286  			report:   true,
   287  
   288  			expectedStatuses: []string{"success"},
   289  		},
   290  		{
   291  			name: "successful_job-report_false",
   292  
   293  			children: 3,
   294  			state:    kube.SuccessState,
   295  			report:   false,
   296  
   297  			expectedStatuses: []string{},
   298  		},
   299  		{
   300  			name: "pending_job-report_true",
   301  
   302  			children: 3,
   303  			state:    kube.PendingState,
   304  			report:   true,
   305  
   306  			expectedStatuses: []string{"pending", "pending", "pending", "pending"},
   307  		},
   308  		{
   309  			name: "pending_job-report_false",
   310  
   311  			children: 3,
   312  			state:    kube.PendingState,
   313  			report:   false,
   314  
   315  			expectedStatuses: []string{"pending", "pending", "pending"},
   316  		},
   317  		{
   318  			name: "aborted_job-report_true",
   319  
   320  			state:  kube.AbortedState,
   321  			report: true,
   322  
   323  			expectedStatuses: []string{"failure"},
   324  		},
   325  	}
   326  
   327  	createPJ := func(state kube.ProwJobState, report bool, children int) kube.ProwJob {
   328  		pj := kube.ProwJob{
   329  			Status: kube.ProwJobStatus{
   330  				State:       state,
   331  				Description: "message",
   332  				URL:         "http://mytest.com",
   333  			},
   334  			Spec: kube.ProwJobSpec{
   335  				Job:     "job-name",
   336  				Type:    kube.PresubmitJob,
   337  				Context: "parent",
   338  				Report:  report,
   339  				Refs: &kube.Refs{
   340  					Org:  "k8s",
   341  					Repo: "test-infra",
   342  					Pulls: []kube.Pull{{
   343  						Author: "me",
   344  						Number: 1,
   345  						SHA:    "abcdef",
   346  					}},
   347  				},
   348  			},
   349  		}
   350  		createChildren(&pj.Spec, children)
   351  		return pj
   352  	}
   353  	for _, tc := range tests {
   354  		t.Logf("Running scenario %q", tc.name)
   355  		// Setup
   356  		ghc := &fakeGhClient{}
   357  		pj := createPJ(tc.state, tc.report, tc.children)
   358  		// Run
   359  		if err := reportStatus(ghc, pj, "Parent Status Changed"); err != nil {
   360  			t.Error(err)
   361  		}
   362  		// Check
   363  		if len(ghc.status) != len(tc.expectedStatuses) {
   364  			t.Errorf("expected %d status(es), found %d", len(tc.expectedStatuses), len(ghc.status))
   365  			continue
   366  		}
   367  		for i, status := range ghc.status {
   368  			if status.State != tc.expectedStatuses[i] {
   369  				t.Errorf("unexpected status: %s, expected: %s", status.State, tc.expectedStatuses[i])
   370  			}
   371  		}
   372  	}
   373  }