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