github.com/shashidharatd/test-infra@v0.0.0-20171006011030-71304e1ca560/prow/plugins/assign/assign_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 assign
    18  
    19  import (
    20  	"testing"
    21  
    22  	"github.com/sirupsen/logrus"
    23  
    24  	"k8s.io/test-infra/prow/github"
    25  )
    26  
    27  type fakeClient struct {
    28  	assigned   map[string]int
    29  	unassigned map[string]int
    30  
    31  	requested    map[string]int
    32  	unrequested  map[string]int
    33  	contributors map[string]bool
    34  
    35  	commented bool
    36  }
    37  
    38  func (c *fakeClient) UnassignIssue(owner, repo string, number int, assignees []string) error {
    39  	for _, who := range assignees {
    40  		c.unassigned[who]++
    41  	}
    42  
    43  	return nil
    44  }
    45  
    46  func (c *fakeClient) AssignIssue(owner, repo string, number int, assignees []string) error {
    47  	var missing github.MissingUsers
    48  	for _, who := range assignees {
    49  		if who != "evil" {
    50  			c.assigned[who]++
    51  		} else {
    52  			missing.Users = append(missing.Users, who)
    53  		}
    54  	}
    55  
    56  	if len(missing.Users) == 0 {
    57  		return nil
    58  	}
    59  	return missing
    60  }
    61  
    62  func (c *fakeClient) RequestReview(org, repo string, number int, logins []string) error {
    63  	var missing github.MissingUsers
    64  	for _, user := range logins {
    65  		if c.contributors[user] {
    66  			c.requested[user]++
    67  		} else {
    68  			missing.Users = append(missing.Users, user)
    69  		}
    70  	}
    71  	if len(missing.Users) > 0 {
    72  		return missing
    73  	}
    74  	return nil
    75  }
    76  
    77  func (c *fakeClient) UnrequestReview(org, repo string, number int, logins []string) error {
    78  	for _, user := range logins {
    79  		c.unrequested[user]++
    80  	}
    81  	return nil
    82  }
    83  
    84  func (c *fakeClient) CreateComment(owner, repo string, number int, comment string) error {
    85  	c.commented = comment != ""
    86  	return nil
    87  }
    88  
    89  func newFakeClient(contribs []string) *fakeClient {
    90  	c := &fakeClient{
    91  		contributors: make(map[string]bool),
    92  		requested:    make(map[string]int),
    93  		unrequested:  make(map[string]int),
    94  		assigned:     make(map[string]int),
    95  		unassigned:   make(map[string]int),
    96  	}
    97  	for _, user := range contribs {
    98  		c.contributors[user] = true
    99  	}
   100  	return c
   101  }
   102  
   103  func TestParseLogins(t *testing.T) {
   104  	var testcases = []struct {
   105  		name   string
   106  		text   string
   107  		logins []string
   108  	}{
   109  		{
   110  			name: "empty",
   111  			text: "",
   112  		},
   113  		{
   114  			name:   "one",
   115  			text:   " @jungle",
   116  			logins: []string{"jungle"},
   117  		},
   118  		{
   119  			name:   "two",
   120  			text:   " @erick @fejta",
   121  			logins: []string{"erick", "fejta"},
   122  		},
   123  	}
   124  	for _, tc := range testcases {
   125  		l := parseLogins(tc.text)
   126  		if len(l) != len(tc.logins) {
   127  			t.Errorf("For case %s, expected %s and got %s", tc.name, tc.logins, l)
   128  		}
   129  		for n, who := range l {
   130  			if tc.logins[n] != who {
   131  				t.Errorf("For case %s, expected %s and got %s", tc.name, tc.logins, l)
   132  			}
   133  		}
   134  	}
   135  }
   136  
   137  // TestAssignAndReview tests that the handle function uses the github client
   138  // to correctly create and/or delete assignments and PR review requests.
   139  func TestAssignAndReview(t *testing.T) {
   140  	var testcases = []struct {
   141  		name        string
   142  		body        string
   143  		commenter   string
   144  		assigned    []string
   145  		unassigned  []string
   146  		requested   []string
   147  		unrequested []string
   148  		commented   bool
   149  	}{
   150  		{
   151  			name:      "unrelated comment",
   152  			body:      "uh oh",
   153  			commenter: "o",
   154  		},
   155  		{
   156  			name:      "assign on open",
   157  			body:      "/assign",
   158  			commenter: "rando",
   159  			assigned:  []string{"rando"},
   160  		},
   161  		{
   162  			name:      "assign me",
   163  			body:      "/assign",
   164  			commenter: "rando",
   165  			assigned:  []string{"rando"},
   166  		},
   167  		{
   168  			name:       "unassign myself",
   169  			body:       "/unassign",
   170  			commenter:  "rando",
   171  			unassigned: []string{"rando"},
   172  		},
   173  		{
   174  			name:      "tab completion",
   175  			body:      "/assign @fejta ",
   176  			commenter: "rando",
   177  			assigned:  []string{"fejta"},
   178  		},
   179  		{
   180  			name:      "no @ works too",
   181  			body:      "/assign fejta",
   182  			commenter: "rando",
   183  			assigned:  []string{"fejta"},
   184  		},
   185  		{
   186  			name:       "multi commands",
   187  			body:       "/assign @fejta\n/unassign @spxtr",
   188  			commenter:  "rando",
   189  			assigned:   []string{"fejta"},
   190  			unassigned: []string{"spxtr"},
   191  		},
   192  		{
   193  			name:      "interesting names",
   194  			body:      "/assign @hello-world @allow_underscore",
   195  			commenter: "rando",
   196  			assigned:  []string{"hello-world", "allow_underscore"},
   197  		},
   198  		{
   199  			name:      "bad login",
   200  			commenter: "rando",
   201  			body:      "/assign @Invalid$User",
   202  		},
   203  		{
   204  			name:      "bad login, no @",
   205  			commenter: "rando",
   206  			body:      "/assign Invalid$User",
   207  		},
   208  		{
   209  			name:      "assign friends",
   210  			body:      "/assign @bert @ernie",
   211  			commenter: "rando",
   212  			assigned:  []string{"bert", "ernie"},
   213  		},
   214  		{
   215  			name:       "unassign buddies",
   216  			body:       "/unassign @ashitaka @eboshi",
   217  			commenter:  "san",
   218  			unassigned: []string{"ashitaka", "eboshi"},
   219  		},
   220  		{
   221  			name:       "unassign buddies, trailing space.",
   222  			body:       "/unassign @ashitaka @eboshi \r",
   223  			commenter:  "san",
   224  			unassigned: []string{"ashitaka", "eboshi"},
   225  		},
   226  		{
   227  			name:      "evil commenter",
   228  			body:      "/assign @merlin",
   229  			commenter: "evil",
   230  			assigned:  []string{"merlin"},
   231  		},
   232  		{
   233  			name:      "evil commenter self assign",
   234  			body:      "/assign",
   235  			commenter: "evil",
   236  			commented: true,
   237  		},
   238  		{
   239  			name:      "evil assignee",
   240  			body:      "/assign @evil @merlin",
   241  			commenter: "innocent",
   242  			assigned:  []string{"merlin"},
   243  			commented: true,
   244  		},
   245  		{
   246  			name:       "evil unassignee",
   247  			body:       "/unassign @evil @merlin",
   248  			commenter:  "innocent",
   249  			unassigned: []string{"evil", "merlin"},
   250  		},
   251  		{
   252  			name:      "review on open",
   253  			body:      "/cc @merlin",
   254  			commenter: "rando",
   255  			requested: []string{"merlin"},
   256  		},
   257  		{
   258  			name:      "tab completion",
   259  			body:      "/cc @cjwagner ",
   260  			commenter: "rando",
   261  			requested: []string{"cjwagner"},
   262  		},
   263  		{
   264  			name:      "no @ works too",
   265  			body:      "/cc cjwagner ",
   266  			commenter: "rando",
   267  			requested: []string{"cjwagner"},
   268  		},
   269  		{
   270  			name:        "multi commands",
   271  			body:        "/cc @cjwagner\n/uncc @spxtr",
   272  			commenter:   "rando",
   273  			requested:   []string{"cjwagner"},
   274  			unrequested: []string{"spxtr"},
   275  		},
   276  		{
   277  			name:      "interesting names",
   278  			body:      "/cc @hello-world @allow_underscore",
   279  			commenter: "rando",
   280  			requested: []string{"hello-world", "allow_underscore"},
   281  		},
   282  		{
   283  			name:      "bad login",
   284  			commenter: "rando",
   285  			body:      "/cc @Invalid$User",
   286  		},
   287  		{
   288  			name:      "bad login",
   289  			commenter: "rando",
   290  			body:      "/cc Invalid$User",
   291  		},
   292  		{
   293  			name:      "request multiple",
   294  			body:      "/cc @cjwagner @merlin",
   295  			commenter: "rando",
   296  			requested: []string{"cjwagner", "merlin"},
   297  		},
   298  		{
   299  			name:        "unrequest buddies",
   300  			body:        "/uncc @ashitaka @eboshi",
   301  			commenter:   "san",
   302  			unrequested: []string{"ashitaka", "eboshi"},
   303  		},
   304  		{
   305  			name:      "evil commenter",
   306  			body:      "/cc @merlin",
   307  			commenter: "evil",
   308  			requested: []string{"merlin"},
   309  		},
   310  		{
   311  			name:      "evil reviewer requested",
   312  			body:      "/cc @evil @merlin",
   313  			commenter: "innocent",
   314  			requested: []string{"merlin"},
   315  			commented: true,
   316  		},
   317  		{
   318  			name:        "evil reviewer unrequested",
   319  			body:        "/uncc @evil @merlin",
   320  			commenter:   "innocent",
   321  			unrequested: []string{"evil", "merlin"},
   322  		},
   323  		{
   324  			name:        "multi command types",
   325  			body:        "/assign @fejta\n/unassign @spxtr @cjwagner\n/uncc @merlin \n/cc @cjwagner",
   326  			commenter:   "rando",
   327  			assigned:    []string{"fejta"},
   328  			unassigned:  []string{"spxtr", "cjwagner"},
   329  			requested:   []string{"cjwagner"},
   330  			unrequested: []string{"merlin"},
   331  		},
   332  		{
   333  			name:      "request review self",
   334  			body:      "/cc",
   335  			commenter: "cjwagner",
   336  			requested: []string{"cjwagner"},
   337  		},
   338  		{
   339  			name:        "unrequest review self",
   340  			body:        "/uncc",
   341  			commenter:   "cjwagner",
   342  			unrequested: []string{"cjwagner"},
   343  		},
   344  		{
   345  			name:        "request review self, with unrequest friend, with trailing space.",
   346  			body:        "/cc \n/uncc @spxtr ",
   347  			commenter:   "cjwagner",
   348  			requested:   []string{"cjwagner"},
   349  			unrequested: []string{"spxtr"},
   350  		},
   351  	}
   352  	for _, tc := range testcases {
   353  		fc := newFakeClient([]string{"hello-world", "allow_underscore", "cjwagner", "merlin"})
   354  		e := github.GenericCommentEvent{
   355  			Body:   tc.body,
   356  			User:   github.User{Login: tc.commenter},
   357  			Repo:   github.Repo{Name: "repo", Owner: github.User{Login: "org"}},
   358  			Number: 5,
   359  		}
   360  		if err := handle(newAssignHandler(e, fc, logrus.WithField("plugin", pluginName))); err != nil {
   361  			t.Errorf("For case %s, didn't expect error from handle: %v", tc.name, err)
   362  			continue
   363  		}
   364  		if err := handle(newReviewHandler(e, fc, logrus.WithField("plugin", pluginName))); err != nil {
   365  			t.Errorf("For case %s, didn't expect error from handle: %v", tc.name, err)
   366  			continue
   367  		}
   368  
   369  		if tc.commented != fc.commented {
   370  			t.Errorf("For case %s, expect commented: %v, got commented %v", tc.name, tc.commented, fc.commented)
   371  		}
   372  
   373  		if len(fc.assigned) != len(tc.assigned) {
   374  			t.Errorf("For case %s, assigned actual %v != expected %s", tc.name, fc.assigned, tc.assigned)
   375  		} else {
   376  			for _, who := range tc.assigned {
   377  				if n, ok := fc.assigned[who]; !ok || n < 1 {
   378  					t.Errorf("For case %s, assigned actual %v != expected %s", tc.name, fc.assigned, tc.assigned)
   379  					break
   380  				}
   381  			}
   382  		}
   383  		if len(fc.unassigned) != len(tc.unassigned) {
   384  			t.Errorf("For case %s, unassigned %v != %s", tc.name, fc.unassigned, tc.unassigned)
   385  		} else {
   386  			for _, who := range tc.unassigned {
   387  				if n, ok := fc.unassigned[who]; !ok || n < 1 {
   388  					t.Errorf("For case %s, unassigned %v != %s", tc.name, fc.unassigned, tc.unassigned)
   389  					break
   390  				}
   391  			}
   392  		}
   393  
   394  		if len(fc.requested) != len(tc.requested) {
   395  			t.Errorf("For case %s, requested actual %v != expected %s", tc.name, fc.requested, tc.requested)
   396  		} else {
   397  			for _, who := range tc.requested {
   398  				if n, ok := fc.requested[who]; !ok || n < 1 {
   399  					t.Errorf("For case %s, requested actual %v != expected %s", tc.name, fc.requested, tc.requested)
   400  					break
   401  				}
   402  			}
   403  		}
   404  		if len(fc.unrequested) != len(tc.unrequested) {
   405  			t.Errorf("For case %s, unrequested %v != %s", tc.name, fc.unrequested, tc.unrequested)
   406  		} else {
   407  			for _, who := range tc.unrequested {
   408  				if n, ok := fc.unrequested[who]; !ok || n < 1 {
   409  					t.Errorf("For case %s, unrequested %v != %s", tc.name, fc.unrequested, tc.unrequested)
   410  					break
   411  				}
   412  			}
   413  		}
   414  	}
   415  }