github.com/abayer/test-infra@v0.0.5/mungegithub/github/github_test.go (about)

     1  /*
     2  Copyright 2015 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  	"encoding/json"
    21  	"fmt"
    22  	"net/http"
    23  	"strconv"
    24  	"testing"
    25  	"time"
    26  
    27  	github_test "k8s.io/test-infra/mungegithub/github/testing"
    28  
    29  	"github.com/google/go-github/github"
    30  )
    31  
    32  func timePtr(val time.Time) *time.Time { return &val }
    33  func intPtr(val int) *int              { return &val }
    34  
    35  func TestHasLabel(t *testing.T) {
    36  	tests := []struct {
    37  		obj      MungeObject
    38  		label    string
    39  		hasLabel bool
    40  	}{
    41  		{
    42  			obj: MungeObject{
    43  				Issue: github_test.Issue("", 1, []string{"foo"}, true),
    44  			},
    45  			label:    "foo",
    46  			hasLabel: true,
    47  		},
    48  		{
    49  			obj: MungeObject{
    50  				Issue: github_test.Issue("", 1, []string{"bar"}, true),
    51  			},
    52  			label:    "foo",
    53  			hasLabel: false,
    54  		},
    55  		{
    56  			obj: MungeObject{
    57  				Issue: github_test.Issue("", 1, []string{"bar", "foo"}, true),
    58  			},
    59  			label:    "foo",
    60  			hasLabel: true,
    61  		},
    62  		{
    63  			obj: MungeObject{
    64  				Issue: github_test.Issue("", 1, []string{"bar", "baz"}, true),
    65  			},
    66  			label:    "foo",
    67  			hasLabel: false,
    68  		},
    69  	}
    70  
    71  	for _, test := range tests {
    72  		if test.hasLabel != test.obj.HasLabel(test.label) {
    73  			t.Errorf("Unexpected output: %v", test)
    74  		}
    75  	}
    76  }
    77  
    78  func TestHasLabels(t *testing.T) {
    79  	tests := []struct {
    80  		obj        MungeObject
    81  		seekLabels []string
    82  		hasLabel   bool
    83  	}{
    84  		{
    85  			obj: MungeObject{
    86  				Issue: github_test.Issue("", 1, []string{"foo"}, true),
    87  			},
    88  			seekLabels: []string{"foo"},
    89  			hasLabel:   true,
    90  		},
    91  		{
    92  			obj: MungeObject{
    93  				Issue: github_test.Issue("", 1, []string{"bar"}, true),
    94  			},
    95  			seekLabels: []string{"foo"},
    96  			hasLabel:   false,
    97  		},
    98  		{
    99  			obj: MungeObject{
   100  				Issue: github_test.Issue("", 1, []string{"bar", "foo"}, true),
   101  			},
   102  			seekLabels: []string{"foo"},
   103  			hasLabel:   true,
   104  		},
   105  		{
   106  			obj: MungeObject{
   107  				Issue: github_test.Issue("", 1, []string{"bar", "baz"}, true),
   108  			},
   109  			seekLabels: []string{"foo"},
   110  			hasLabel:   false,
   111  		},
   112  		{
   113  			obj: MungeObject{
   114  				Issue: github_test.Issue("", 1, []string{"foo"}, true),
   115  			},
   116  			seekLabels: []string{"foo", "bar"},
   117  			hasLabel:   false,
   118  		},
   119  	}
   120  
   121  	for _, test := range tests {
   122  		if test.hasLabel != test.obj.HasLabels(test.seekLabels) {
   123  			t.Errorf("Unexpected output: %v", test)
   124  		}
   125  	}
   126  }
   127  
   128  func TestForEachIssueDo(t *testing.T) {
   129  	issue1 := github_test.Issue("bob", 1, nil, true)
   130  	issue5 := github_test.Issue("bob", 5, nil, true)
   131  	issue6 := github_test.Issue("bob", 6, nil, true)
   132  	issue7 := github_test.Issue("bob", 7, nil, true)
   133  	issue20 := github_test.Issue("bob", 20, nil, true)
   134  
   135  	user := github.User{Login: stringPtr("bob")}
   136  	tests := []struct {
   137  		Issues      [][]github.Issue
   138  		Pages       []int
   139  		ValidIssues int
   140  	}{
   141  		{
   142  			Issues: [][]github.Issue{
   143  				{*issue5},
   144  			},
   145  			Pages:       []int{0},
   146  			ValidIssues: 1,
   147  		},
   148  		{
   149  			Issues: [][]github.Issue{
   150  				{*issue5},
   151  				{*issue6},
   152  				{*issue7},
   153  				{
   154  					{
   155  						Number: intPtr(8),
   156  						// no User, invalid
   157  					},
   158  				},
   159  			},
   160  			Pages:       []int{4, 4, 4, 0},
   161  			ValidIssues: 3,
   162  		},
   163  		{
   164  			Issues: [][]github.Issue{
   165  				// Invalid 1 < MinPRNumber
   166  				// Invalid 20 > MaxPRNumber
   167  				{*issue1, *issue20},
   168  				// two valid issues
   169  				{*issue5, *issue6},
   170  				{
   171  					{
   172  						// no Number, invalid
   173  						User: &user,
   174  					},
   175  				},
   176  			},
   177  			Pages:       []int{3, 3, 0},
   178  			ValidIssues: 2,
   179  		},
   180  	}
   181  
   182  	for i, test := range tests {
   183  		client, server, mux := github_test.InitServer(t, nil, nil, nil, nil, nil, nil, nil)
   184  		config := &Config{
   185  			client:      client,
   186  			Org:         "foo",
   187  			Project:     "bar",
   188  			MinPRNumber: 5,
   189  			MaxPRNumber: 15,
   190  		}
   191  		count := 0
   192  		mux.HandleFunc("/repos/foo/bar/issues", func(w http.ResponseWriter, r *http.Request) {
   193  			if r.Method != "GET" {
   194  				t.Errorf("Unexpected method: %s", r.Method)
   195  			}
   196  			// this means page 0, return page 1
   197  			page := r.URL.Query().Get("page")
   198  			if page == "" {
   199  				t.Errorf("Should not get page 0, start with page 1")
   200  			}
   201  			if page != strconv.Itoa(count+1) {
   202  				t.Errorf("Unexpected page: %s", r.URL.Query().Get("page"))
   203  			}
   204  			if r.URL.Query().Get("sort") != "created" {
   205  				t.Errorf("Unexpected sort: %s", r.URL.Query().Get("sort"))
   206  			}
   207  			if r.URL.Query().Get("per_page") != "100" {
   208  				t.Errorf("Unexpected per_page: %s", r.URL.Query().Get("per_page"))
   209  			}
   210  			w.Header().Add("Link",
   211  				fmt.Sprintf("<https://api.github.com/?page=%d>; rel=\"last\"", test.Pages[count]))
   212  			w.WriteHeader(http.StatusOK)
   213  			data, err := json.Marshal(test.Issues[count])
   214  			if err != nil {
   215  				t.Errorf("Unexpected error: %v", err)
   216  			}
   217  
   218  			w.Write(data)
   219  			count++
   220  		})
   221  		objects := []*MungeObject{}
   222  		handle := func(obj *MungeObject) error {
   223  			objects = append(objects, obj)
   224  			return nil
   225  		}
   226  		err := config.ForEachIssueDo(handle)
   227  		if err != nil {
   228  			t.Errorf("unexpected error: %v", err)
   229  		}
   230  		if len(objects) != test.ValidIssues {
   231  			t.Errorf("Test: %d Unexpected output %d vs %d", i, len(objects), test.ValidIssues)
   232  		}
   233  
   234  		if count != len(test.Issues) {
   235  			t.Errorf("Test: %d Unexpected number of fetches: %d", i, count)
   236  		}
   237  		server.Close()
   238  	}
   239  }
   240  
   241  func TestComputeStatus(t *testing.T) {
   242  	contextS := []string{"context"}
   243  	otherS := []string{"other context"}
   244  	bothS := []string{"context", "other context"}
   245  	firstS := []string{"context", "crap"}
   246  
   247  	tests := []struct {
   248  		combinedStatus   *github.CombinedStatus
   249  		requiredContexts []string
   250  		expected         string
   251  	}{
   252  		// test no context specified
   253  		{
   254  			combinedStatus: github_test.Status("mysha", nil, nil, nil, nil),
   255  			expected:       "success",
   256  		},
   257  		{
   258  			combinedStatus: &github.CombinedStatus{
   259  				State: stringPtr("pending"),
   260  				SHA:   stringPtr("mysha"),
   261  			},
   262  			expected: "pending",
   263  		},
   264  		{
   265  			combinedStatus: &github.CombinedStatus{
   266  				State: stringPtr("failure"),
   267  				SHA:   stringPtr("mysha"),
   268  			},
   269  			expected: "failure",
   270  		},
   271  		{
   272  			combinedStatus: &github.CombinedStatus{
   273  				State: stringPtr("error"),
   274  				SHA:   stringPtr("mysha"),
   275  			},
   276  			expected: "error",
   277  		},
   278  		// test missing subcontext requested but missing
   279  		{
   280  			combinedStatus:   github_test.Status("mysha", otherS, nil, nil, nil),
   281  			requiredContexts: contextS,
   282  			expected:         "incomplete",
   283  		},
   284  		{
   285  			combinedStatus:   github_test.Status("mysha", nil, otherS, nil, nil),
   286  			requiredContexts: contextS,
   287  			expected:         "incomplete",
   288  		},
   289  		{
   290  			combinedStatus:   github_test.Status("mysha", nil, nil, otherS, nil),
   291  			requiredContexts: contextS,
   292  			expected:         "incomplete",
   293  		},
   294  		{
   295  			combinedStatus:   github_test.Status("mysha", nil, nil, nil, otherS),
   296  			requiredContexts: contextS,
   297  			expected:         "incomplete",
   298  		},
   299  		// test subcontext present and requested
   300  		{
   301  			combinedStatus:   github_test.Status("mysha", contextS, nil, nil, nil),
   302  			requiredContexts: contextS,
   303  			expected:         "success",
   304  		},
   305  		{
   306  			combinedStatus:   github_test.Status("mysha", nil, nil, contextS, nil),
   307  			requiredContexts: contextS,
   308  			expected:         "pending",
   309  		},
   310  		{
   311  			combinedStatus:   github_test.Status("mysha", nil, nil, nil, contextS),
   312  			requiredContexts: contextS,
   313  			expected:         "error",
   314  		},
   315  		{
   316  			combinedStatus:   github_test.Status("mysha", nil, contextS, nil, nil),
   317  			requiredContexts: contextS,
   318  			expected:         "failure",
   319  		},
   320  		// test failed PR but the one we care about is passed
   321  		{
   322  			combinedStatus:   github_test.Status("mysha", contextS, otherS, nil, nil),
   323  			requiredContexts: contextS,
   324  			expected:         "success",
   325  		},
   326  		// test failed because we need both, but one is failed
   327  		{
   328  			combinedStatus:   github_test.Status("mysha", contextS, otherS, nil, nil),
   329  			requiredContexts: bothS,
   330  			expected:         "failure",
   331  		},
   332  		// test failed because we need both, bot one isn't present
   333  		{
   334  			combinedStatus:   github_test.Status("mysha", firstS, nil, nil, nil),
   335  			requiredContexts: bothS,
   336  			expected:         "incomplete",
   337  		},
   338  	}
   339  
   340  	for _, test := range tests {
   341  		// ease of use, reduce boilerplate in test cases
   342  		if test.requiredContexts == nil {
   343  			test.requiredContexts = []string{}
   344  		}
   345  		status := computeStatus(test.combinedStatus, test.requiredContexts)
   346  		if test.expected != status {
   347  			t.Errorf("expected: %s, saw %s for %v", test.expected, status, test.combinedStatus)
   348  		}
   349  	}
   350  }
   351  
   352  func TestGetLastModified(t *testing.T) {
   353  	tests := []struct {
   354  		commits      []*github.RepositoryCommit
   355  		expectedTime *time.Time
   356  	}{
   357  		{
   358  			commits:      github_test.Commits(1, 10),
   359  			expectedTime: timePtr(time.Unix(10, 0)),
   360  		},
   361  		{
   362  			// remember the order of github_test.Commits() is non-deterministic
   363  			commits:      github_test.Commits(3, 10),
   364  			expectedTime: timePtr(time.Unix(12, 0)),
   365  		},
   366  		{
   367  			// so this is probably not quite the same test...
   368  			commits:      github_test.Commits(3, 8),
   369  			expectedTime: timePtr(time.Unix(10, 0)),
   370  		},
   371  		{
   372  			//  We can't represent the same time in 2 commits using github_test.Commits()
   373  			commits: []*github.RepositoryCommit{
   374  				{
   375  					SHA: stringPtr("mysha1"),
   376  					Commit: &github.Commit{
   377  						SHA: stringPtr("mysha1"),
   378  						Committer: &github.CommitAuthor{
   379  							Date: timePtr(time.Unix(9, 0)),
   380  						},
   381  					},
   382  				},
   383  				{
   384  					SHA: stringPtr("mysha2"),
   385  					Commit: &github.Commit{
   386  						SHA: stringPtr("mysha2"),
   387  						Committer: &github.CommitAuthor{
   388  							Date: timePtr(time.Unix(10, 0)),
   389  						},
   390  					},
   391  				},
   392  				{
   393  					SHA: stringPtr("mysha3"),
   394  					Commit: &github.Commit{
   395  						SHA: stringPtr("mysha3"),
   396  						Committer: &github.CommitAuthor{
   397  							Date: timePtr(time.Unix(9, 0)),
   398  						},
   399  					},
   400  				},
   401  			},
   402  			expectedTime: timePtr(time.Unix(10, 0)),
   403  		},
   404  	}
   405  	for _, test := range tests {
   406  		client, server, _ := github_test.InitServer(t, nil, nil, nil, test.commits, nil, nil, nil)
   407  		config := &Config{
   408  			client:  client,
   409  			Org:     "o",
   410  			Project: "r",
   411  		}
   412  
   413  		obj := &MungeObject{
   414  			config: config,
   415  			Issue:  github_test.Issue("bob", 1, nil, true),
   416  		}
   417  		ts, ok := obj.LastModifiedTime()
   418  		if !ok || !ts.Equal(*test.expectedTime) {
   419  			t.Errorf("expected: %v, saw: %v for: %v", test.expectedTime, ts, test)
   420  		}
   421  		server.Close()
   422  	}
   423  }
   424  
   425  func TestRemoveLabel(t *testing.T) {
   426  	tests := []struct {
   427  		issue    *github.Issue
   428  		remove   string
   429  		expected []string
   430  	}{
   431  		{
   432  			issue:    github_test.Issue("", 1, []string{"label1"}, false),
   433  			remove:   "label1",
   434  			expected: []string{},
   435  		},
   436  		{
   437  			issue:    github_test.Issue("", 1, []string{"label2", "label1"}, false),
   438  			remove:   "label1",
   439  			expected: []string{"label2"},
   440  		},
   441  		{
   442  			issue:    github_test.Issue("", 1, []string{"label2"}, false),
   443  			remove:   "label1",
   444  			expected: []string{"label2"},
   445  		},
   446  		{
   447  			issue:    github_test.Issue("", 1, []string{}, false),
   448  			remove:   "label1",
   449  			expected: []string{},
   450  		},
   451  	}
   452  	for testNum, test := range tests {
   453  		client, server, mux := github_test.InitServer(t, test.issue, nil, nil, nil, nil, nil, nil)
   454  		config := &Config{
   455  			client:  client,
   456  			Org:     "o",
   457  			Project: "r",
   458  		}
   459  		mux.HandleFunc(fmt.Sprintf("/repos/o/r/issues/1/labels/%s", test.remove), func(w http.ResponseWriter, r *http.Request) {
   460  			w.WriteHeader(http.StatusOK)
   461  		})
   462  
   463  		obj, err := config.GetObject(*test.issue.Number)
   464  		if err != nil {
   465  			t.Fatalf("%d: unable to get issue: %v", testNum, *test.issue.Number)
   466  		}
   467  		obj.RemoveLabel(test.remove)
   468  		if len(test.expected) != len(obj.Issue.Labels) {
   469  			t.Errorf("%d: len(labels) not equal, expected labels: %v but got labels: %v", testNum, test.expected, obj.Issue.Labels)
   470  			return
   471  		}
   472  		for i, l := range test.expected {
   473  			if l != *obj.Issue.Labels[i].Name {
   474  				t.Errorf("%d: expected labels: %v but got labels: %v", testNum, test.expected, obj.Issue.Labels)
   475  			}
   476  		}
   477  		server.Close()
   478  	}
   479  }
   480  
   481  func TestPRGetFixesList(t *testing.T) {
   482  	tests := []struct {
   483  		issue    *github.Issue
   484  		body     string
   485  		expected []int
   486  	}{
   487  		{
   488  			issue: github_test.Issue("", 1, []string{"label1"}, false),
   489  			body: `bla resolve
   490  this pr closes #45545 and also fixes #679
   491  bla, some more bla with close here and there.
   492  some suggest that it resolved #5643`,
   493  			expected: []int{45545, 679, 5643},
   494  		},
   495  		{
   496  			issue: github_test.Issue("", 2, []string{"label1"}, false),
   497  			body: `bla resolve 345
   498  some suggest that it also closes #892`,
   499  			expected: []int{892},
   500  		},
   501  		{
   502  			issue: github_test.Issue("", 3, []string{"label1"}, false),
   503  			body: `bla resolve
   504  this pr closes and fixes nothing`,
   505  			expected: nil,
   506  		},
   507  		{
   508  			issue: github_test.Issue("", 4, []string{"label1"}, false),
   509  			body: `bla bla
   510  this pr Fixes #23 and FIXES #45 but not fixxx #99`,
   511  			expected: []int{23, 45},
   512  		},
   513  	}
   514  	for testNum, test := range tests {
   515  		client, server, _ := github_test.InitServer(t, test.issue, nil, nil, nil, nil, nil, nil)
   516  		config := &Config{
   517  			client:  client,
   518  			Org:     "o",
   519  			Project: "r",
   520  		}
   521  
   522  		obj, err := config.GetObject(*test.issue.Number)
   523  		if err != nil {
   524  			t.Fatalf("%d: unable to get issue: %v", testNum, *test.issue.Number)
   525  		}
   526  		obj.Issue.Body = &test.body
   527  		fixes := obj.GetPRFixesList()
   528  		if len(test.expected) != len(fixes) {
   529  			t.Errorf("%d: len(fixes) not equal, expected: %v but got: %v", testNum, test.expected, fixes)
   530  			return
   531  		}
   532  		for i, n := range test.expected {
   533  			if n != fixes[i] {
   534  				t.Errorf("%d: expected fixes: %v but got fixes: %v", testNum, test.expected, fixes)
   535  			}
   536  		}
   537  		server.Close()
   538  	}
   539  }
   540  
   541  func TestCleanIssueBody(t *testing.T) {
   542  	tests := []struct {
   543  		body, expected string
   544  	}{
   545  		{"foo", "foo"},
   546  		{"    bar   ", "bar"},
   547  		{
   548  			`Some message
   549  
   550  <!-- Reviewable:start -->
   551  gratuitous href
   552  <!-- Reviewable:end -->`,
   553  			"Some message",
   554  		},
   555  		{
   556  			`Merge pull request #1234 from user/master
   557  
   558  Automatic merge from submit-queue (batch tested with PRs 1, 2, 1234, 57)
   559  
   560  [Part 2] Adding s390x cross-compilation support for gcr.io images in this repo
   561  
   562  <!--  Thanks for sending a pull request!  Here are some tips for you:
   563  1. If this is your first time, read our contributor guidelines https://github.com/kubernetes/kubernetes/blob/master/CONTRIBUTING.md and developer guide https://github.com/kubernetes/kubernetes/blob/master/docs/devel/development.md
   564  2. If you want *faster* PR reviews, read how: https://github.com/kubernetes/kubernetes/blob/master/docs/devel/faster_reviews.md
   565  3. Follow the instructions for writing a release note: https://github.com/kubernetes/kubernetes/blob/master/docs/devel/pull-requests.md#release-notes
   566  -->
   567  
   568  **What this PR does / why we need it**: This PR enables s390x support.
   569  
   570  **Which issue this PR fixes #34328
   571  
   572  **Special notes for your reviewer**:  I am enabling cross compilation for s390x.
   573  
   574  **Release note**:
   575  <!--  Steps to write your release note:
   576  1. Use the release-note-* labels to set the release note state (if you have access)
   577  2. Enter your extended release note in the below block; leaving it blank means using the PR title as the release note. If no release note is required, just write` +
   578  				" `NONE`.\n-->\n```\nAllows cross compilation of Kubernetes on x86 host for s390x also enables s390x support to kube-dns , pause, addon-manager, etcd, hyperkube, kube-discovery etc\n```\n",
   579  			`Merge pull request #1234 from user/master
   580  
   581  Automatic merge from submit-queue (batch tested with PRs 1, 2, 1234, 57)
   582  
   583  [Part 2] Adding s390x cross-compilation support for gcr.io images in this repo
   584  
   585  
   586  **What this PR does / why we need it**: This PR enables s390x support.
   587  
   588  **Which issue this PR fixes #34328
   589  
   590  **Special notes for your reviewer**:  I am enabling cross compilation for s390x.
   591  
   592  **Release note**:
   593  ` + "```\nAllows cross compilation of Kubernetes on x86 host for s390x also enables s390x support to kube-dns , pause, addon-manager, etcd, hyperkube, kube-discovery etc\n```",
   594  		},
   595  	}
   596  	for testNum, test := range tests {
   597  		body := cleanIssueBody(test.body)
   598  		if body != test.expected {
   599  			t.Errorf("%d: cleanIssueBody(%#v) == %#v != %#v",
   600  				testNum, test.body, body, test.expected)
   601  		}
   602  	}
   603  }
   604  
   605  func TestClearMilestone(t *testing.T) {
   606  	issue := github_test.Issue("", 1, []string{}, false)
   607  	issue.Milestone = &github.Milestone{Title: stringPtr("v1.2"), Number: intPtr(1)}
   608  
   609  	client, server, _ := github_test.InitServer(t, issue, nil, nil, nil, nil, nil, nil)
   610  	config := &Config{
   611  		client:  client,
   612  		Org:     "o",
   613  		Project: "r",
   614  	}
   615  
   616  	obj, err := config.GetObject(*issue.Number)
   617  	if err != nil {
   618  		t.Fatalf("Unable to get issue")
   619  	}
   620  
   621  	if !obj.ClearMilestone() || obj.Issue.Milestone != nil {
   622  		t.Fatalf("Unable to clear milestone for issue")
   623  	}
   624  
   625  	server.Close()
   626  }