github.com/abayer/test-infra@v0.0.5/mungegithub/mungers/approvers/approvers_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 approvers
    18  
    19  import (
    20  	"testing"
    21  
    22  	"reflect"
    23  
    24  	"k8s.io/apimachinery/pkg/util/sets"
    25  )
    26  
    27  func TestUnapprovedFiles(t *testing.T) {
    28  	rootApprovers := sets.NewString("Alice", "Bob")
    29  	aApprovers := sets.NewString("Art", "Anne")
    30  	bApprovers := sets.NewString("Bill", "Ben", "Barbara")
    31  	cApprovers := sets.NewString("Chris", "Carol")
    32  	dApprovers := sets.NewString("David", "Dan", "Debbie")
    33  	eApprovers := sets.NewString("Eve", "Erin")
    34  	edcApprovers := eApprovers.Union(dApprovers).Union(cApprovers)
    35  	FakeRepoMap := map[string]sets.String{
    36  		"":        rootApprovers,
    37  		"a":       aApprovers,
    38  		"b":       bApprovers,
    39  		"c":       cApprovers,
    40  		"a/d":     dApprovers,
    41  		"a/combo": edcApprovers,
    42  	}
    43  	tests := []struct {
    44  		testName           string
    45  		filenames          []string
    46  		currentlyApproved  sets.String
    47  		expectedUnapproved sets.String
    48  	}{
    49  		{
    50  			testName:           "Empty PR",
    51  			filenames:          []string{},
    52  			currentlyApproved:  sets.NewString(),
    53  			expectedUnapproved: sets.NewString(),
    54  		},
    55  		{
    56  			testName:           "Single Root File PR Approved",
    57  			filenames:          []string{"kubernetes.go"},
    58  			currentlyApproved:  sets.NewString(rootApprovers.List()[0]),
    59  			expectedUnapproved: sets.NewString(),
    60  		},
    61  		{
    62  			testName:           "Single Root File PR No One Approved",
    63  			filenames:          []string{"kubernetes.go"},
    64  			currentlyApproved:  sets.NewString(),
    65  			expectedUnapproved: sets.NewString(""),
    66  		},
    67  		{
    68  			testName:           "B Only UnApproved",
    69  			currentlyApproved:  bApprovers,
    70  			expectedUnapproved: sets.NewString(),
    71  		},
    72  		{
    73  			testName:           "B Files Approved at Root",
    74  			filenames:          []string{"b/test.go", "b/test_1.go"},
    75  			currentlyApproved:  rootApprovers,
    76  			expectedUnapproved: sets.NewString(),
    77  		},
    78  		{
    79  			testName:           "B Only UnApproved",
    80  			filenames:          []string{"b/test_1.go", "b/test.go"},
    81  			currentlyApproved:  sets.NewString(),
    82  			expectedUnapproved: sets.NewString("b"),
    83  		},
    84  		{
    85  			testName:           "Combo and Other; Neither Approved",
    86  			filenames:          []string{"a/combo/test.go", "a/d/test.go"},
    87  			currentlyApproved:  sets.NewString(),
    88  			expectedUnapproved: sets.NewString("a/combo", "a/d"),
    89  		},
    90  		{
    91  			testName:           "Combo and Other; Combo Approved",
    92  			filenames:          []string{"a/combo/test.go", "a/d/test.go"},
    93  			currentlyApproved:  edcApprovers.Difference(dApprovers),
    94  			expectedUnapproved: sets.NewString("a/d"),
    95  		},
    96  		{
    97  			testName:           "Combo and Other; Both Approved",
    98  			filenames:          []string{"a/combo/test.go", "a/d/test.go"},
    99  			currentlyApproved:  edcApprovers.Intersection(dApprovers),
   100  			expectedUnapproved: sets.NewString(),
   101  		},
   102  	}
   103  
   104  	for _, test := range tests {
   105  		testApprovers := NewApprovers(Owners{filenames: test.filenames, repo: createFakeRepo(FakeRepoMap), seed: TEST_SEED})
   106  		testApprovers.RequireIssue = false
   107  		for approver := range test.currentlyApproved {
   108  			testApprovers.AddApprover(approver, "REFERENCE", false)
   109  		}
   110  		calculated := testApprovers.UnapprovedFiles()
   111  		if !test.expectedUnapproved.Equal(calculated) {
   112  			t.Errorf("Failed for test %v.  Expected unapproved files: %v. Found %v", test.testName, test.expectedUnapproved, calculated)
   113  		}
   114  	}
   115  }
   116  
   117  func TestGetFiles(t *testing.T) {
   118  	rootApprovers := sets.NewString("Alice", "Bob")
   119  	aApprovers := sets.NewString("Art", "Anne")
   120  	bApprovers := sets.NewString("Bill", "Ben", "Barbara")
   121  	cApprovers := sets.NewString("Chris", "Carol")
   122  	dApprovers := sets.NewString("David", "Dan", "Debbie")
   123  	eApprovers := sets.NewString("Eve", "Erin")
   124  	edcApprovers := eApprovers.Union(dApprovers).Union(cApprovers)
   125  	FakeRepoMap := map[string]sets.String{
   126  		"":        rootApprovers,
   127  		"a":       aApprovers,
   128  		"b":       bApprovers,
   129  		"c":       cApprovers,
   130  		"a/d":     dApprovers,
   131  		"a/combo": edcApprovers,
   132  	}
   133  	tests := []struct {
   134  		testName          string
   135  		filenames         []string
   136  		currentlyApproved sets.String
   137  		expectedFiles     []File
   138  	}{
   139  		{
   140  			testName:          "Empty PR",
   141  			filenames:         []string{},
   142  			currentlyApproved: sets.NewString(),
   143  			expectedFiles:     []File{},
   144  		},
   145  		{
   146  			testName:          "Single Root File PR Approved",
   147  			filenames:         []string{"kubernetes.go"},
   148  			currentlyApproved: sets.NewString(rootApprovers.List()[0]),
   149  			expectedFiles:     []File{ApprovedFile{"", sets.NewString(rootApprovers.List()[0]), "org", "project"}},
   150  		},
   151  		{
   152  			testName:          "Single File PR in B No One Approved",
   153  			filenames:         []string{"b/test.go"},
   154  			currentlyApproved: sets.NewString(),
   155  			expectedFiles:     []File{UnapprovedFile{"b", "org", "project"}},
   156  		},
   157  		{
   158  			testName:          "Single File PR in B Fully Approved",
   159  			filenames:         []string{"b/test.go"},
   160  			currentlyApproved: bApprovers,
   161  			expectedFiles:     []File{ApprovedFile{"b", bApprovers, "org", "project"}},
   162  		},
   163  		{
   164  			testName:          "Single Root File PR No One Approved",
   165  			filenames:         []string{"kubernetes.go"},
   166  			currentlyApproved: sets.NewString(),
   167  			expectedFiles:     []File{UnapprovedFile{"", "org", "project"}},
   168  		},
   169  		{
   170  			testName:          "Combo and Other; Neither Approved",
   171  			filenames:         []string{"a/combo/test.go", "a/d/test.go"},
   172  			currentlyApproved: sets.NewString(),
   173  			expectedFiles: []File{
   174  				UnapprovedFile{"a/combo", "org", "project"},
   175  				UnapprovedFile{"a/d", "org", "project"},
   176  			},
   177  		},
   178  		{
   179  			testName:          "Combo and Other; Combo Approved",
   180  			filenames:         []string{"a/combo/test.go", "a/d/test.go"},
   181  			currentlyApproved: eApprovers,
   182  			expectedFiles: []File{
   183  				ApprovedFile{"a/combo", eApprovers, "org", "project"},
   184  				UnapprovedFile{"a/d", "org", "project"},
   185  			},
   186  		},
   187  		{
   188  			testName:          "Combo and Other; Both Approved",
   189  			filenames:         []string{"a/combo/test.go", "a/d/test.go"},
   190  			currentlyApproved: edcApprovers.Intersection(dApprovers),
   191  			expectedFiles: []File{
   192  				ApprovedFile{"a/combo", edcApprovers.Intersection(dApprovers), "org", "project"},
   193  				ApprovedFile{"a/d", edcApprovers.Intersection(dApprovers), "org", "project"},
   194  			},
   195  		},
   196  		{
   197  			testName:          "Combo, C, D; Combo and C Approved",
   198  			filenames:         []string{"a/combo/test.go", "a/d/test.go", "c/test"},
   199  			currentlyApproved: cApprovers,
   200  			expectedFiles: []File{
   201  				ApprovedFile{"a/combo", cApprovers, "org", "project"},
   202  				UnapprovedFile{"a/d", "org", "project"},
   203  				ApprovedFile{"c", cApprovers, "org", "project"},
   204  			},
   205  		},
   206  		{
   207  			testName:          "Files Approved Multiple times",
   208  			filenames:         []string{"a/test.go", "a/d/test.go", "b/test"},
   209  			currentlyApproved: rootApprovers.Union(aApprovers).Union(bApprovers),
   210  			expectedFiles: []File{
   211  				ApprovedFile{"a", rootApprovers.Union(aApprovers), "org", "project"},
   212  				ApprovedFile{"b", rootApprovers.Union(bApprovers), "org", "project"},
   213  			},
   214  		},
   215  	}
   216  
   217  	for _, test := range tests {
   218  		testApprovers := NewApprovers(Owners{filenames: test.filenames, repo: createFakeRepo(FakeRepoMap), seed: TEST_SEED})
   219  		testApprovers.RequireIssue = false
   220  		for approver := range test.currentlyApproved {
   221  			testApprovers.AddApprover(approver, "REFERENCE", false)
   222  		}
   223  		calculated := testApprovers.GetFiles("org", "project")
   224  		if !reflect.DeepEqual(test.expectedFiles, calculated) {
   225  			t.Errorf("Failed for test %v.  Expected files: %v. Found %v", test.testName, test.expectedFiles, calculated)
   226  		}
   227  	}
   228  }
   229  
   230  func TestGetCCs(t *testing.T) {
   231  	rootApprovers := sets.NewString("Alice", "Bob")
   232  	aApprovers := sets.NewString("Art", "Anne")
   233  	bApprovers := sets.NewString("Bill", "Ben", "Barbara")
   234  	cApprovers := sets.NewString("Chris", "Carol")
   235  	dApprovers := sets.NewString("David", "Dan", "Debbie")
   236  	eApprovers := sets.NewString("Eve", "Erin")
   237  	edcApprovers := eApprovers.Union(dApprovers).Union(cApprovers)
   238  	FakeRepoMap := map[string]sets.String{
   239  		"":        rootApprovers,
   240  		"a":       aApprovers,
   241  		"b":       bApprovers,
   242  		"c":       cApprovers,
   243  		"a/d":     dApprovers,
   244  		"a/combo": edcApprovers,
   245  	}
   246  	tests := []struct {
   247  		testName          string
   248  		filenames         []string
   249  		currentlyApproved sets.String
   250  		// testSeed affects who is chosen for CC
   251  		testSeed  int64
   252  		assignees []string
   253  		// order matters for CCs
   254  		expectedCCs []string
   255  	}{
   256  		{
   257  			testName:          "Empty PR",
   258  			filenames:         []string{},
   259  			currentlyApproved: sets.NewString(),
   260  			testSeed:          0,
   261  			expectedCCs:       []string{},
   262  		},
   263  		{
   264  			testName:          "Single Root FFile PR Approved",
   265  			filenames:         []string{"kubernetes.go"},
   266  			currentlyApproved: sets.NewString(rootApprovers.List()[0]),
   267  			testSeed:          13,
   268  			expectedCCs:       []string{},
   269  		},
   270  		{
   271  			testName:          "Single Root File PR Unapproved Seed = 13",
   272  			filenames:         []string{"kubernetes.go"},
   273  			currentlyApproved: sets.NewString(),
   274  			testSeed:          13,
   275  			expectedCCs:       []string{"alice"},
   276  		},
   277  		{
   278  			testName:          "Single Root File PR No One Seed = 10",
   279  			filenames:         []string{"kubernetes.go"},
   280  			testSeed:          10,
   281  			currentlyApproved: sets.NewString(),
   282  			expectedCCs:       []string{"bob"},
   283  		},
   284  		{
   285  			testName:          "Combo and Other; Neither Approved",
   286  			filenames:         []string{"a/combo/test.go", "a/d/test.go"},
   287  			testSeed:          0,
   288  			currentlyApproved: sets.NewString(),
   289  			expectedCCs:       []string{"dan"},
   290  		},
   291  		{
   292  			testName:          "Combo and Other; Combo Approved",
   293  			filenames:         []string{"a/combo/test.go", "a/d/test.go"},
   294  			testSeed:          0,
   295  			currentlyApproved: eApprovers,
   296  			expectedCCs:       []string{"dan"},
   297  		},
   298  		{
   299  			testName:          "Combo and Other; Both Approved",
   300  			filenames:         []string{"a/combo/test.go", "a/d/test.go"},
   301  			testSeed:          0,
   302  			currentlyApproved: dApprovers, // dApprovers can approve combo and d directory
   303  			expectedCCs:       []string{},
   304  		},
   305  		{
   306  			testName:          "Combo, C, D; None Approved",
   307  			filenames:         []string{"a/combo/test.go", "a/d/test.go", "c/test"},
   308  			testSeed:          0,
   309  			currentlyApproved: sets.NewString(),
   310  			// chris can approve c and combo, debbie can approve d
   311  			expectedCCs: []string{"chris", "debbie"},
   312  		},
   313  		{
   314  			testName:          "A, B, C; Nothing Approved",
   315  			filenames:         []string{"a/test.go", "b/test.go", "c/test"},
   316  			testSeed:          0,
   317  			currentlyApproved: sets.NewString(),
   318  			// Need an approver from each of the three owners files
   319  			expectedCCs: []string{"anne", "bill", "carol"},
   320  		},
   321  		{
   322  			testName:  "A, B, C; Partially approved by non-suggested approvers",
   323  			filenames: []string{"a/test.go", "b/test.go", "c/test"},
   324  			testSeed:  0,
   325  			// Approvers are valid approvers, but not the one we would suggest
   326  			currentlyApproved: sets.NewString("Art", "Ben"),
   327  			// We don't suggest approvers for a and b, only for unapproved c.
   328  			expectedCCs: []string{"carol"},
   329  		},
   330  		{
   331  			testName:  "A, B, C; Nothing approved, but assignees can approve",
   332  			filenames: []string{"a/test.go", "b/test.go", "c/test"},
   333  			testSeed:  0,
   334  			// Approvers are valid approvers, but not the one we would suggest
   335  			currentlyApproved: sets.NewString(),
   336  			assignees:         []string{"Art", "Ben"},
   337  			// We suggest assigned people rather than "suggested" people
   338  			// Suggested would be "Anne", "Bill", "Carol" if no one was assigned.
   339  			expectedCCs: []string{"art", "ben", "carol"},
   340  		},
   341  		{
   342  			testName:          "A, B, C; Nothing approved, but SOME assignees can approve",
   343  			filenames:         []string{"a/test.go", "b/test.go", "c/test"},
   344  			testSeed:          0,
   345  			currentlyApproved: sets.NewString(),
   346  			// Assignees are a mix of potential approvers and random people
   347  			assignees: []string{"Art", "Ben", "John", "Jack"},
   348  			// We suggest assigned people rather than "suggested" people
   349  			expectedCCs: []string{"art", "ben", "carol"},
   350  		},
   351  		{
   352  			testName:          "Assignee is top OWNER, No one has approved",
   353  			filenames:         []string{"a/test.go"},
   354  			testSeed:          0,
   355  			currentlyApproved: sets.NewString(),
   356  			// Assignee is a root approver
   357  			assignees:   []string{"alice"},
   358  			expectedCCs: []string{"alice"},
   359  		},
   360  	}
   361  
   362  	for _, test := range tests {
   363  		testApprovers := NewApprovers(Owners{filenames: test.filenames, repo: createFakeRepo(FakeRepoMap), seed: test.testSeed})
   364  		testApprovers.RequireIssue = false
   365  		for approver := range test.currentlyApproved {
   366  			testApprovers.AddApprover(approver, "REFERENCE", false)
   367  		}
   368  		testApprovers.AddAssignees(test.assignees...)
   369  		calculated := testApprovers.GetCCs()
   370  		if !reflect.DeepEqual(test.expectedCCs, calculated) {
   371  			t.Errorf("Failed for test %v.  Expected CCs: %v. Found %v", test.testName, test.expectedCCs, calculated)
   372  		}
   373  	}
   374  }
   375  
   376  func TestIsApproved(t *testing.T) {
   377  	rootApprovers := sets.NewString("Alice", "Bob")
   378  	aApprovers := sets.NewString("Art", "Anne")
   379  	bApprovers := sets.NewString("Bill", "Ben", "Barbara")
   380  	cApprovers := sets.NewString("Chris", "Carol")
   381  	dApprovers := sets.NewString("David", "Dan", "Debbie")
   382  	eApprovers := sets.NewString("Eve", "Erin")
   383  	edcApprovers := eApprovers.Union(dApprovers).Union(cApprovers)
   384  	FakeRepoMap := map[string]sets.String{
   385  		"":        rootApprovers,
   386  		"a":       aApprovers,
   387  		"b":       bApprovers,
   388  		"c":       cApprovers,
   389  		"a/d":     dApprovers,
   390  		"a/combo": edcApprovers,
   391  	}
   392  	tests := []struct {
   393  		testName          string
   394  		filenames         []string
   395  		currentlyApproved sets.String
   396  		testSeed          int64
   397  		isApproved        bool
   398  	}{
   399  		{
   400  			testName:          "Empty PR",
   401  			filenames:         []string{},
   402  			currentlyApproved: sets.NewString(),
   403  			testSeed:          0,
   404  			isApproved:        true,
   405  		},
   406  		{
   407  			testName:          "Single Root File PR Approved",
   408  			filenames:         []string{"kubernetes.go"},
   409  			currentlyApproved: sets.NewString(rootApprovers.List()[0]),
   410  			testSeed:          3,
   411  			isApproved:        true,
   412  		},
   413  		{
   414  			testName:          "Single Root File PR No One Approved",
   415  			filenames:         []string{"kubernetes.go"},
   416  			testSeed:          0,
   417  			currentlyApproved: sets.NewString(),
   418  			isApproved:        false,
   419  		},
   420  		{
   421  			testName:          "Combo and Other; Neither Approved",
   422  			filenames:         []string{"a/combo/test.go", "a/d/test.go"},
   423  			testSeed:          0,
   424  			currentlyApproved: sets.NewString(),
   425  			isApproved:        false,
   426  		},
   427  		{
   428  			testName:          "Combo and Other; Both Approved",
   429  			filenames:         []string{"a/combo/test.go", "a/d/test.go"},
   430  			testSeed:          0,
   431  			currentlyApproved: edcApprovers.Intersection(dApprovers),
   432  			isApproved:        true,
   433  		},
   434  		{
   435  			testName:          "A, B, C; Nothing Approved",
   436  			filenames:         []string{"a/test.go", "b/test.go", "c/test"},
   437  			testSeed:          0,
   438  			currentlyApproved: sets.NewString(),
   439  			isApproved:        false,
   440  		},
   441  		{
   442  			testName:          "A, B, C; Partially Approved",
   443  			filenames:         []string{"a/test.go", "b/test.go", "c/test"},
   444  			testSeed:          0,
   445  			currentlyApproved: aApprovers.Union(bApprovers),
   446  			isApproved:        false,
   447  		},
   448  		{
   449  			testName:          "A, B, C; Approved At the Root",
   450  			filenames:         []string{"a/test.go", "b/test.go", "c/test"},
   451  			testSeed:          0,
   452  			currentlyApproved: rootApprovers,
   453  			isApproved:        true,
   454  		},
   455  		{
   456  			testName:          "A, B, C; Approved At the Leaves",
   457  			filenames:         []string{"a/test.go", "b/test.go", "c/test"},
   458  			testSeed:          0,
   459  			currentlyApproved: sets.NewString("Anne", "Ben", "Carol"),
   460  			isApproved:        true,
   461  		},
   462  	}
   463  
   464  	for _, test := range tests {
   465  		testApprovers := NewApprovers(Owners{filenames: test.filenames, repo: createFakeRepo(FakeRepoMap), seed: test.testSeed})
   466  		for approver := range test.currentlyApproved {
   467  			testApprovers.AddApprover(approver, "REFERENCE", false)
   468  		}
   469  		calculated := testApprovers.IsApproved()
   470  		if test.isApproved != calculated {
   471  			t.Errorf("Failed for test %v.  Expected Approval Status: %v. Found %v", test.testName, test.isApproved, calculated)
   472  		}
   473  	}
   474  }
   475  
   476  func TestIsApprovedWithIssue(t *testing.T) {
   477  	aApprovers := sets.NewString("Author", "Anne", "Carl")
   478  	bApprovers := sets.NewString("Bill", "Carl")
   479  	FakeRepoMap := map[string]sets.String{"a": aApprovers, "b": bApprovers}
   480  	tests := []struct {
   481  		testName          string
   482  		filenames         []string
   483  		currentlyApproved map[string]bool
   484  		associatedIssue   int
   485  		isApproved        bool
   486  	}{
   487  		{
   488  			testName:          "Empty PR",
   489  			filenames:         []string{},
   490  			currentlyApproved: map[string]bool{},
   491  			associatedIssue:   0,
   492  			isApproved:        false,
   493  		},
   494  		{
   495  			testName:          "Single file missing issue",
   496  			filenames:         []string{"a/file.go"},
   497  			currentlyApproved: map[string]bool{"Carl": false},
   498  			associatedIssue:   0,
   499  			isApproved:        false,
   500  		},
   501  		{
   502  			testName:          "Single file no-issue",
   503  			filenames:         []string{"a/file.go"},
   504  			currentlyApproved: map[string]bool{"Carl": true},
   505  			associatedIssue:   0,
   506  			isApproved:        true,
   507  		},
   508  		{
   509  			testName:          "Single file with issue",
   510  			filenames:         []string{"a/file.go"},
   511  			currentlyApproved: map[string]bool{"Carl": false},
   512  			associatedIssue:   100,
   513  			isApproved:        true,
   514  		},
   515  		{
   516  			testName:          "Two files missing issue",
   517  			filenames:         []string{"a/file.go", "b/file2.go"},
   518  			currentlyApproved: map[string]bool{"Carl": false},
   519  			associatedIssue:   0,
   520  			isApproved:        false,
   521  		},
   522  		{
   523  			testName:          "Two files no-issue",
   524  			filenames:         []string{"a/file.go", "b/file2.go"},
   525  			currentlyApproved: map[string]bool{"Carl": true},
   526  			associatedIssue:   0,
   527  			isApproved:        true,
   528  		},
   529  		{
   530  			testName:          "Two files two no-issue two approvers",
   531  			filenames:         []string{"a/file.go", "b/file2.go"},
   532  			currentlyApproved: map[string]bool{"Anne": true, "Bill": true},
   533  			associatedIssue:   0,
   534  			isApproved:        true,
   535  		},
   536  		{
   537  			testName:          "Two files one no-issue two approvers",
   538  			filenames:         []string{"a/file.go", "b/file2.go"},
   539  			currentlyApproved: map[string]bool{"Anne": true, "Bill": false},
   540  			associatedIssue:   0,
   541  			isApproved:        true,
   542  		},
   543  		{
   544  			testName:          "Two files missing issue two approvers",
   545  			filenames:         []string{"a/file.go", "b/file2.go"},
   546  			currentlyApproved: map[string]bool{"Anne": false, "Bill": false},
   547  			associatedIssue:   0,
   548  			isApproved:        false,
   549  		},
   550  		{
   551  			testName:          "Self approval (implicit) missing issue",
   552  			filenames:         []string{"a/file.go"},
   553  			currentlyApproved: map[string]bool{},
   554  			associatedIssue:   0,
   555  			isApproved:        false,
   556  		},
   557  		{
   558  			testName:          "Self approval (implicit) with issue",
   559  			filenames:         []string{"a/file.go"},
   560  			currentlyApproved: map[string]bool{},
   561  			associatedIssue:   10,
   562  			isApproved:        true,
   563  		},
   564  		{
   565  			testName:          "Self approval (explicit) missing issue",
   566  			filenames:         []string{"a/file.go"},
   567  			currentlyApproved: map[string]bool{"Author": false},
   568  			associatedIssue:   0,
   569  			isApproved:        false,
   570  		},
   571  		{
   572  			testName:          "Self approval (explicit) no-issue",
   573  			filenames:         []string{"a/file.go"},
   574  			currentlyApproved: map[string]bool{"Author": true},
   575  			associatedIssue:   0,
   576  			isApproved:        true,
   577  		},
   578  		{
   579  			testName:          "Self approval (explicit) missing issue, two files",
   580  			filenames:         []string{"a/file.go", "b/file2.go"},
   581  			currentlyApproved: map[string]bool{"Author": false, "Bill": false},
   582  			associatedIssue:   0,
   583  			isApproved:        false,
   584  		},
   585  		{
   586  			testName:          "Self approval (explicit) no-issue from author, two files",
   587  			filenames:         []string{"a/file.go", "b/file2.go"},
   588  			currentlyApproved: map[string]bool{"Author": true, "Bill": false},
   589  			associatedIssue:   0,
   590  			isApproved:        true,
   591  		},
   592  		{
   593  			testName:          "Self approval (explicit) no-issue from friend, two files",
   594  			filenames:         []string{"a/file.go", "b/file2.go"},
   595  			currentlyApproved: map[string]bool{"Author": false, "Bill": true},
   596  			associatedIssue:   0,
   597  			isApproved:        true,
   598  		},
   599  	}
   600  
   601  	for _, test := range tests {
   602  		testApprovers := NewApprovers(Owners{filenames: test.filenames, repo: createFakeRepo(FakeRepoMap), seed: 0})
   603  		testApprovers.RequireIssue = true
   604  		testApprovers.AssociatedIssue = test.associatedIssue
   605  		for approver, noissue := range test.currentlyApproved {
   606  			testApprovers.AddApprover(approver, "REFERENCE", noissue)
   607  		}
   608  		testApprovers.AddAuthorSelfApprover("Author", "REFERENCE")
   609  		calculated := testApprovers.IsApproved()
   610  		if test.isApproved != calculated {
   611  			t.Errorf("Failed for test %v.  Expected Approval Status: %v. Found %v", test.testName, test.isApproved, calculated)
   612  		}
   613  	}
   614  }
   615  
   616  func TestGetFilesApprovers(t *testing.T) {
   617  	tests := []struct {
   618  		testName       string
   619  		filenames      []string
   620  		approvers      []string
   621  		owners         map[string]sets.String
   622  		expectedStatus map[string]sets.String
   623  	}{
   624  		{
   625  			testName:       "Empty PR",
   626  			filenames:      []string{},
   627  			approvers:      []string{},
   628  			owners:         map[string]sets.String{},
   629  			expectedStatus: map[string]sets.String{},
   630  		},
   631  		{
   632  			testName:       "No approvers",
   633  			filenames:      []string{"a/a", "c"},
   634  			approvers:      []string{},
   635  			owners:         map[string]sets.String{"": sets.NewString("RootOwner")},
   636  			expectedStatus: map[string]sets.String{"": {}},
   637  		},
   638  		{
   639  			testName: "Approvers approves some",
   640  			filenames: []string{
   641  				"a/a",
   642  				"c/c",
   643  			},
   644  			approvers: []string{"CApprover"},
   645  			owners: map[string]sets.String{
   646  				"a": sets.NewString("AApprover"),
   647  				"c": sets.NewString("CApprover"),
   648  			},
   649  			expectedStatus: map[string]sets.String{
   650  				"a": {},
   651  				"c": sets.NewString("CApprover"),
   652  			},
   653  		},
   654  		{
   655  			testName: "Multiple approvers",
   656  			filenames: []string{
   657  				"a/a",
   658  				"c/c",
   659  			},
   660  			approvers: []string{"RootApprover", "CApprover"},
   661  			owners: map[string]sets.String{
   662  				"":  sets.NewString("RootApprover"),
   663  				"a": sets.NewString("AApprover"),
   664  				"c": sets.NewString("CApprover"),
   665  			},
   666  			expectedStatus: map[string]sets.String{
   667  				"a": sets.NewString("RootApprover"),
   668  				"c": sets.NewString("RootApprover", "CApprover"),
   669  			},
   670  		},
   671  		{
   672  			testName:       "Case-insensitive approvers",
   673  			filenames:      []string{"file"},
   674  			approvers:      []string{"RootApprover"},
   675  			owners:         map[string]sets.String{"": sets.NewString("rOOtaPProver")},
   676  			expectedStatus: map[string]sets.String{"": sets.NewString("RootApprover")},
   677  		},
   678  	}
   679  
   680  	for _, test := range tests {
   681  		testApprovers := NewApprovers(Owners{filenames: test.filenames, repo: createFakeRepo(test.owners)})
   682  		for _, approver := range test.approvers {
   683  			testApprovers.AddApprover(approver, "REFERENCE", false)
   684  		}
   685  		calculated := testApprovers.GetFilesApprovers()
   686  		if !reflect.DeepEqual(test.expectedStatus, calculated) {
   687  			t.Errorf("Failed for test %v.  Expected approval status: %v. Found %v", test.testName, test.expectedStatus, calculated)
   688  		}
   689  	}
   690  }