github.com/munnerz/test-infra@v0.0.0-20190108210205-ce3d181dc989/prow/plugins/label/label_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 label
    18  
    19  import (
    20  	"fmt"
    21  	"reflect"
    22  	"sort"
    23  	"testing"
    24  
    25  	"github.com/sirupsen/logrus"
    26  	"k8s.io/test-infra/prow/github"
    27  	"k8s.io/test-infra/prow/github/fakegithub"
    28  	"k8s.io/test-infra/prow/labels"
    29  )
    30  
    31  const (
    32  	orgMember    = "Alice"
    33  	nonOrgMember = "Bob"
    34  )
    35  
    36  func formatLabels(labels ...string) []string {
    37  	r := []string{}
    38  	for _, l := range labels {
    39  		r = append(r, fmt.Sprintf("%s/%s#%d:%s", "org", "repo", 1, l))
    40  	}
    41  	if len(r) == 0 {
    42  		return nil
    43  	}
    44  	return r
    45  }
    46  
    47  func TestLabel(t *testing.T) {
    48  	type testCase struct {
    49  		name                  string
    50  		body                  string
    51  		commenter             string
    52  		extraLabels           []string
    53  		expectedNewLabels     []string
    54  		expectedRemovedLabels []string
    55  		expectedBotComment    bool
    56  		repoLabels            []string
    57  		issueLabels           []string
    58  	}
    59  	testcases := []testCase{
    60  		{
    61  			name:                  "Irrelevant comment",
    62  			body:                  "irrelelvant",
    63  			expectedNewLabels:     []string{},
    64  			expectedRemovedLabels: []string{},
    65  			repoLabels:            []string{},
    66  			issueLabels:           []string{},
    67  			commenter:             orgMember,
    68  		},
    69  		{
    70  			name:                  "Empty Area",
    71  			body:                  "/area",
    72  			expectedNewLabels:     []string{},
    73  			expectedRemovedLabels: []string{},
    74  			repoLabels:            []string{"area/infra"},
    75  			issueLabels:           []string{"area/infra"},
    76  			commenter:             orgMember,
    77  		},
    78  		{
    79  			name:                  "Add Single Area Label",
    80  			body:                  "/area infra",
    81  			repoLabels:            []string{"area/infra"},
    82  			issueLabels:           []string{},
    83  			expectedNewLabels:     formatLabels("area/infra"),
    84  			expectedRemovedLabels: []string{},
    85  			commenter:             orgMember,
    86  		},
    87  		{
    88  			name:                  "Add Single Area Label when already present on Issue",
    89  			body:                  "/area infra",
    90  			repoLabels:            []string{"area/infra"},
    91  			issueLabels:           []string{"area/infra"},
    92  			expectedNewLabels:     []string{},
    93  			expectedRemovedLabels: []string{},
    94  			commenter:             orgMember,
    95  		},
    96  		{
    97  			name:                  "Add Single Priority Label",
    98  			body:                  "/priority critical",
    99  			repoLabels:            []string{"area/infra", "priority/critical"},
   100  			issueLabels:           []string{},
   101  			expectedNewLabels:     formatLabels("priority/critical"),
   102  			expectedRemovedLabels: []string{},
   103  			commenter:             orgMember,
   104  		},
   105  		{
   106  			name:                  "Add Single Kind Label",
   107  			body:                  "/kind bug",
   108  			repoLabels:            []string{"area/infra", "priority/critical", labels.Bug},
   109  			issueLabels:           []string{},
   110  			expectedNewLabels:     formatLabels(labels.Bug),
   111  			expectedRemovedLabels: []string{},
   112  			commenter:             orgMember,
   113  		},
   114  		{
   115  			name:                  "Add Single Triage Label",
   116  			body:                  "/triage needs-information",
   117  			repoLabels:            []string{"area/infra", "triage/needs-information"},
   118  			issueLabels:           []string{"area/infra"},
   119  			expectedNewLabels:     formatLabels("triage/needs-information"),
   120  			expectedRemovedLabels: []string{},
   121  			commenter:             orgMember,
   122  		},
   123  		{
   124  			name:                  "Adding Labels is Case Insensitive",
   125  			body:                  "/kind BuG",
   126  			repoLabels:            []string{"area/infra", "priority/critical", labels.Bug},
   127  			issueLabels:           []string{},
   128  			expectedNewLabels:     formatLabels(labels.Bug),
   129  			expectedRemovedLabels: []string{},
   130  			commenter:             orgMember,
   131  		},
   132  		{
   133  			name:                  "Adding Labels is Case Insensitive",
   134  			body:                  "/kind bug",
   135  			repoLabels:            []string{"area/infra", "priority/critical", labels.Bug},
   136  			issueLabels:           []string{},
   137  			expectedNewLabels:     formatLabels(labels.Bug),
   138  			expectedRemovedLabels: []string{},
   139  			commenter:             orgMember,
   140  		},
   141  		{
   142  			name:                  "Can't Add Non Existent Label",
   143  			body:                  "/priority critical",
   144  			repoLabels:            []string{"area/infra"},
   145  			issueLabels:           []string{},
   146  			expectedNewLabels:     formatLabels(),
   147  			expectedRemovedLabels: []string{},
   148  			commenter:             orgMember,
   149  		},
   150  		{
   151  			name:                  "Non Org Member Can't Add",
   152  			body:                  "/area infra",
   153  			repoLabels:            []string{"area/infra", "priority/critical", labels.Bug},
   154  			issueLabels:           []string{},
   155  			expectedNewLabels:     formatLabels("area/infra"),
   156  			expectedRemovedLabels: []string{},
   157  			commenter:             nonOrgMember,
   158  		},
   159  		{
   160  			name:                  "Command must start at the beginning of the line",
   161  			body:                  "  /area infra",
   162  			repoLabels:            []string{"area/infra", "area/api", "priority/critical", "priority/urgent", "priority/important", labels.Bug},
   163  			issueLabels:           []string{},
   164  			expectedNewLabels:     formatLabels(),
   165  			expectedRemovedLabels: []string{},
   166  			commenter:             orgMember,
   167  		},
   168  		{
   169  			name:                  "Can't Add Labels Non Existing Labels",
   170  			body:                  "/area lgtm",
   171  			repoLabels:            []string{"area/infra", "area/api", "priority/critical"},
   172  			issueLabels:           []string{},
   173  			expectedNewLabels:     formatLabels(),
   174  			expectedRemovedLabels: []string{},
   175  			commenter:             orgMember,
   176  		},
   177  		{
   178  			name:                  "Add Multiple Area Labels",
   179  			body:                  "/area api infra",
   180  			repoLabels:            []string{"area/infra", "area/api", "priority/critical", "priority/urgent"},
   181  			issueLabels:           []string{},
   182  			expectedNewLabels:     formatLabels("area/api", "area/infra"),
   183  			expectedRemovedLabels: []string{},
   184  			commenter:             orgMember,
   185  		},
   186  		{
   187  			name:                  "Add Multiple Area Labels one already present on Issue",
   188  			body:                  "/area api infra",
   189  			repoLabels:            []string{"area/infra", "area/api", "priority/critical", "priority/urgent"},
   190  			issueLabels:           []string{"area/api"},
   191  			expectedNewLabels:     formatLabels("area/infra"),
   192  			expectedRemovedLabels: []string{},
   193  			commenter:             orgMember,
   194  		},
   195  		{
   196  			name:                  "Add Multiple Priority Labels",
   197  			body:                  "/priority critical important",
   198  			repoLabels:            []string{"priority/critical", "priority/important"},
   199  			issueLabels:           []string{},
   200  			expectedNewLabels:     formatLabels("priority/critical", "priority/important"),
   201  			expectedRemovedLabels: []string{},
   202  			commenter:             orgMember,
   203  		},
   204  		{
   205  			name:                  "Label Prefix Must Match Command (Area-Priority Mismatch)",
   206  			body:                  "/area urgent",
   207  			repoLabels:            []string{"area/infra", "area/api", "priority/critical", "priority/urgent"},
   208  			issueLabels:           []string{},
   209  			expectedNewLabels:     formatLabels(),
   210  			expectedRemovedLabels: []string{},
   211  			commenter:             orgMember,
   212  		},
   213  		{
   214  			name:                  "Label Prefix Must Match Command (Priority-Area Mismatch)",
   215  			body:                  "/priority infra",
   216  			repoLabels:            []string{"area/infra", "area/api", "priority/critical", "priority/urgent"},
   217  			issueLabels:           []string{},
   218  			expectedNewLabels:     formatLabels(),
   219  			expectedRemovedLabels: []string{},
   220  			commenter:             orgMember,
   221  		},
   222  		{
   223  			name:                  "Add Multiple Area Labels (Some Valid)",
   224  			body:                  "/area lgtm infra",
   225  			repoLabels:            []string{"area/infra", "area/api"},
   226  			issueLabels:           []string{},
   227  			expectedNewLabels:     formatLabels("area/infra"),
   228  			expectedRemovedLabels: []string{},
   229  			commenter:             orgMember,
   230  		},
   231  		{
   232  			name:                  "Add Multiple Committee Labels (Some Valid)",
   233  			body:                  "/committee steering calamity",
   234  			repoLabels:            []string{"committee/conduct", "committee/steering"},
   235  			issueLabels:           []string{},
   236  			expectedNewLabels:     formatLabels("committee/steering"),
   237  			expectedRemovedLabels: []string{},
   238  			commenter:             orgMember,
   239  		},
   240  		{
   241  			name:                  "Add Multiple Types of Labels Different Lines",
   242  			body:                  "/priority urgent\n/area infra",
   243  			repoLabels:            []string{"area/infra", "priority/urgent"},
   244  			issueLabels:           []string{},
   245  			expectedNewLabels:     formatLabels("priority/urgent", "area/infra"),
   246  			expectedRemovedLabels: []string{},
   247  			commenter:             orgMember,
   248  		},
   249  		{
   250  			name:                  "Remove Area Label when no such Label on Repo",
   251  			body:                  "/remove-area infra",
   252  			repoLabels:            []string{},
   253  			issueLabels:           []string{},
   254  			expectedNewLabels:     []string{},
   255  			expectedRemovedLabels: []string{},
   256  			commenter:             orgMember,
   257  			expectedBotComment:    true,
   258  		},
   259  		{
   260  			name:                  "Remove Area Label when no such Label on Issue",
   261  			body:                  "/remove-area infra",
   262  			repoLabels:            []string{"area/infra"},
   263  			issueLabels:           []string{},
   264  			expectedNewLabels:     []string{},
   265  			expectedRemovedLabels: []string{},
   266  			commenter:             orgMember,
   267  			expectedBotComment:    true,
   268  		},
   269  		{
   270  			name:                  "Remove Area Label",
   271  			body:                  "/remove-area infra",
   272  			repoLabels:            []string{"area/infra"},
   273  			issueLabels:           []string{"area/infra"},
   274  			expectedNewLabels:     []string{},
   275  			expectedRemovedLabels: formatLabels("area/infra"),
   276  			commenter:             orgMember,
   277  		},
   278  		{
   279  			name:                  "Remove Committee Label",
   280  			body:                  "/remove-committee infinite-monkeys",
   281  			repoLabels:            []string{"area/infra", "sig/testing", "committee/infinite-monkeys"},
   282  			issueLabels:           []string{"area/infra", "sig/testing", "committee/infinite-monkeys"},
   283  			expectedNewLabels:     []string{},
   284  			expectedRemovedLabels: formatLabels("committee/infinite-monkeys"),
   285  			commenter:             orgMember,
   286  		},
   287  		{
   288  			name:                  "Remove Kind Label",
   289  			body:                  "/remove-kind api-server",
   290  			repoLabels:            []string{"area/infra", "priority/high", "kind/api-server"},
   291  			issueLabels:           []string{"area/infra", "priority/high", "kind/api-server"},
   292  			expectedNewLabels:     []string{},
   293  			expectedRemovedLabels: formatLabels("kind/api-server"),
   294  			commenter:             orgMember,
   295  		},
   296  		{
   297  			name:                  "Remove Priority Label",
   298  			body:                  "/remove-priority high",
   299  			repoLabels:            []string{"area/infra", "priority/high"},
   300  			issueLabels:           []string{"area/infra", "priority/high"},
   301  			expectedNewLabels:     []string{},
   302  			expectedRemovedLabels: formatLabels("priority/high"),
   303  			commenter:             orgMember,
   304  		},
   305  		{
   306  			name:                  "Remove SIG Label",
   307  			body:                  "/remove-sig testing",
   308  			repoLabels:            []string{"area/infra", "sig/testing"},
   309  			issueLabels:           []string{"area/infra", "sig/testing"},
   310  			expectedNewLabels:     []string{},
   311  			expectedRemovedLabels: formatLabels("sig/testing"),
   312  			commenter:             orgMember,
   313  		},
   314  		{
   315  			name:                  "Remove WG Policy",
   316  			body:                  "/remove-wg policy",
   317  			repoLabels:            []string{"area/infra", "wg/policy"},
   318  			issueLabels:           []string{"area/infra", "wg/policy"},
   319  			expectedNewLabels:     []string{},
   320  			expectedRemovedLabels: formatLabels("wg/policy"),
   321  			commenter:             orgMember,
   322  		},
   323  		{
   324  			name:                  "Remove Triage Label",
   325  			body:                  "/remove-triage needs-information",
   326  			repoLabels:            []string{"area/infra", "triage/needs-information"},
   327  			issueLabels:           []string{"area/infra", "triage/needs-information"},
   328  			expectedNewLabels:     []string{},
   329  			expectedRemovedLabels: formatLabels("triage/needs-information"),
   330  			commenter:             orgMember,
   331  		},
   332  		{
   333  			name:                  "Remove Multiple Labels",
   334  			body:                  "/remove-priority low high\n/remove-kind api-server\n/remove-area  infra",
   335  			repoLabels:            []string{"area/infra", "priority/high", "priority/low", "kind/api-server"},
   336  			issueLabels:           []string{"area/infra", "priority/high", "priority/low", "kind/api-server"},
   337  			expectedNewLabels:     []string{},
   338  			expectedRemovedLabels: formatLabels("priority/low", "priority/high", "kind/api-server", "area/infra"),
   339  			commenter:             orgMember,
   340  			expectedBotComment:    true,
   341  		},
   342  		{
   343  			name:                  "Add and Remove Label at the same time",
   344  			body:                  "/remove-area infra\n/area test",
   345  			repoLabels:            []string{"area/infra", "area/test"},
   346  			issueLabels:           []string{"area/infra"},
   347  			expectedNewLabels:     formatLabels("area/test"),
   348  			expectedRemovedLabels: formatLabels("area/infra"),
   349  			commenter:             orgMember,
   350  		},
   351  		{
   352  			name:                  "Add and Remove the same Label",
   353  			body:                  "/remove-area infra\n/area infra",
   354  			repoLabels:            []string{"area/infra"},
   355  			issueLabels:           []string{"area/infra"},
   356  			expectedNewLabels:     []string{},
   357  			expectedRemovedLabels: formatLabels("area/infra"),
   358  			commenter:             orgMember,
   359  		},
   360  		{
   361  			name:                  "Multiple Add and Delete Labels",
   362  			body:                  "/remove-area ruby\n/remove-kind srv\n/remove-priority l m\n/area go\n/kind cli\n/priority h",
   363  			repoLabels:            []string{"area/go", "area/ruby", "kind/cli", "kind/srv", "priority/h", "priority/m", "priority/l"},
   364  			issueLabels:           []string{"area/ruby", "kind/srv", "priority/l", "priority/m"},
   365  			expectedNewLabels:     formatLabels("area/go", "kind/cli", "priority/h"),
   366  			expectedRemovedLabels: formatLabels("area/ruby", "kind/srv", "priority/l", "priority/m"),
   367  			commenter:             orgMember,
   368  		},
   369  		{
   370  			name:                  "Do nothing with empty /label command",
   371  			body:                  "/label",
   372  			extraLabels:           []string{"orchestrator/foo", "orchestrator/bar"},
   373  			repoLabels:            []string{"orchestrator/foo"},
   374  			issueLabels:           []string{},
   375  			expectedNewLabels:     []string{},
   376  			expectedRemovedLabels: []string{},
   377  			commenter:             orgMember,
   378  		},
   379  		{
   380  			name:                  "Do nothing with empty /remove-label command",
   381  			body:                  "/remove-label",
   382  			extraLabels:           []string{"orchestrator/foo", "orchestrator/bar"},
   383  			repoLabels:            []string{"orchestrator/foo"},
   384  			issueLabels:           []string{},
   385  			expectedNewLabels:     []string{},
   386  			expectedRemovedLabels: []string{},
   387  			commenter:             orgMember,
   388  		},
   389  		{
   390  			name:                  "Add custom label",
   391  			body:                  "/label orchestrator/foo",
   392  			extraLabels:           []string{"orchestrator/foo", "orchestrator/bar"},
   393  			repoLabels:            []string{"orchestrator/foo"},
   394  			issueLabels:           []string{},
   395  			expectedNewLabels:     formatLabels("orchestrator/foo"),
   396  			expectedRemovedLabels: []string{},
   397  			commenter:             orgMember,
   398  		},
   399  		{
   400  			name:                  "Cannot add missing custom label",
   401  			body:                  "/label orchestrator/foo",
   402  			extraLabels:           []string{"orchestrator/jar", "orchestrator/bar"},
   403  			repoLabels:            []string{"orchestrator/foo"},
   404  			issueLabels:           []string{},
   405  			expectedNewLabels:     []string{},
   406  			expectedRemovedLabels: []string{},
   407  			commenter:             orgMember,
   408  		},
   409  		{
   410  			name:                  "Remove custom label",
   411  			body:                  "/remove-label orchestrator/foo",
   412  			extraLabels:           []string{"orchestrator/foo", "orchestrator/bar"},
   413  			repoLabels:            []string{"orchestrator/foo"},
   414  			issueLabels:           []string{"orchestrator/foo"},
   415  			expectedNewLabels:     []string{},
   416  			expectedRemovedLabels: formatLabels("orchestrator/foo"),
   417  			commenter:             orgMember,
   418  		},
   419  		{
   420  			name:                  "Cannot remove missing custom label",
   421  			body:                  "/remove-label orchestrator/jar",
   422  			extraLabels:           []string{"orchestrator/foo", "orchestrator/bar"},
   423  			repoLabels:            []string{"orchestrator/foo"},
   424  			issueLabels:           []string{"orchestrator/foo"},
   425  			expectedNewLabels:     []string{},
   426  			expectedRemovedLabels: []string{},
   427  			commenter:             orgMember,
   428  		},
   429  	}
   430  
   431  	for _, tc := range testcases {
   432  		t.Logf("Running scenario %q", tc.name)
   433  		sort.Strings(tc.expectedNewLabels)
   434  		fakeClient := &fakegithub.FakeClient{
   435  			Issues:             make([]github.Issue, 1),
   436  			IssueComments:      make(map[int][]github.IssueComment),
   437  			RepoLabelsExisting: tc.repoLabels,
   438  			OrgMembers:         map[string][]string{"org": {orgMember}},
   439  			IssueLabelsAdded:   []string{},
   440  			IssueLabelsRemoved: []string{},
   441  		}
   442  		// Add initial labels
   443  		for _, label := range tc.issueLabels {
   444  			fakeClient.AddLabel("org", "repo", 1, label)
   445  		}
   446  		e := &github.GenericCommentEvent{
   447  			Action: github.GenericCommentActionCreated,
   448  			Body:   tc.body,
   449  			Number: 1,
   450  			Repo:   github.Repo{Owner: github.User{Login: "org"}, Name: "repo"},
   451  			User:   github.User{Login: tc.commenter},
   452  		}
   453  		err := handle(fakeClient, logrus.WithField("plugin", pluginName), tc.extraLabels, e)
   454  		if err != nil {
   455  			t.Errorf("didn't expect error from label test: %v", err)
   456  			continue
   457  		}
   458  
   459  		// Check that all the correct labels (and only the correct labels) were added.
   460  		expectLabels := append(formatLabels(tc.issueLabels...), tc.expectedNewLabels...)
   461  		if expectLabels == nil {
   462  			expectLabels = []string{}
   463  		}
   464  		sort.Strings(expectLabels)
   465  		sort.Strings(fakeClient.IssueLabelsAdded)
   466  		if !reflect.DeepEqual(expectLabels, fakeClient.IssueLabelsAdded) {
   467  			t.Errorf("expected the labels %q to be added, but %q were added.", expectLabels, fakeClient.IssueLabelsAdded)
   468  		}
   469  
   470  		sort.Strings(tc.expectedRemovedLabels)
   471  		sort.Strings(fakeClient.IssueLabelsRemoved)
   472  		if !reflect.DeepEqual(tc.expectedRemovedLabels, fakeClient.IssueLabelsRemoved) {
   473  			t.Errorf("expected the labels %q to be removed, but %q were removed.", tc.expectedRemovedLabels, fakeClient.IssueLabelsRemoved)
   474  		}
   475  		if len(fakeClient.IssueCommentsAdded) > 0 && !tc.expectedBotComment {
   476  			t.Errorf("unexpected bot comments: %#v", fakeClient.IssueCommentsAdded)
   477  		}
   478  		if len(fakeClient.IssueCommentsAdded) == 0 && tc.expectedBotComment {
   479  			t.Error("expected a bot comment but got none")
   480  		}
   481  	}
   482  }