github.com/abayer/test-infra@v0.0.5/prow/plugins/approve/approvers/owners_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  	"github.com/sirupsen/logrus"
    23  
    24  	"k8s.io/apimachinery/pkg/util/sets"
    25  
    26  	"path/filepath"
    27  	"reflect"
    28  	"strings"
    29  )
    30  
    31  const (
    32  	TEST_SEED = int64(0)
    33  )
    34  
    35  type FakeRepo struct {
    36  	approversMap      map[string]sets.String
    37  	leafApproversMap  map[string]sets.String
    38  	noParentOwnersMap map[string]bool
    39  }
    40  
    41  func (f FakeRepo) Approvers(path string) sets.String {
    42  	return f.approversMap[path]
    43  }
    44  
    45  func (f FakeRepo) LeafApprovers(path string) sets.String {
    46  	return f.leafApproversMap[path]
    47  }
    48  
    49  func (f FakeRepo) FindApproverOwnersForFile(path string) string {
    50  	for dir := path; dir != "."; dir = filepath.Dir(dir) {
    51  		if _, ok := f.leafApproversMap[dir]; ok {
    52  			return dir
    53  		}
    54  	}
    55  	return ""
    56  }
    57  
    58  func (f FakeRepo) IsNoParentOwners(path string) bool {
    59  	return f.noParentOwnersMap[path]
    60  }
    61  
    62  type dir struct {
    63  	fullPath  string
    64  	approvers sets.String
    65  }
    66  
    67  func canonicalize(path string) string {
    68  	if path == "." {
    69  		return ""
    70  	}
    71  	return strings.TrimSuffix(path, "/")
    72  }
    73  
    74  func createFakeRepo(la map[string]sets.String) FakeRepo {
    75  	// github doesn't use / at the root
    76  	a := map[string]sets.String{}
    77  	for dir, approvers := range la {
    78  		la[dir] = setToLower(approvers)
    79  		a[dir] = setToLower(approvers)
    80  		starting_path := dir
    81  		for {
    82  			dir = canonicalize(filepath.Dir(dir))
    83  			if parent_approvers, ok := la[dir]; ok {
    84  				a[starting_path] = a[starting_path].Union(setToLower(parent_approvers))
    85  			}
    86  			if dir == "" {
    87  				break
    88  			}
    89  		}
    90  	}
    91  
    92  	return FakeRepo{approversMap: a, leafApproversMap: la}
    93  }
    94  
    95  func setToLower(s sets.String) sets.String {
    96  	lowered := sets.NewString()
    97  	for _, elem := range s.List() {
    98  		lowered.Insert(strings.ToLower(elem))
    99  	}
   100  	return lowered
   101  }
   102  
   103  func TestCreateFakeRepo(t *testing.T) {
   104  	rootApprovers := sets.NewString("Alice", "Bob")
   105  	aApprovers := sets.NewString("Art", "Anne")
   106  	bApprovers := sets.NewString("Bill", "Ben", "Barbara")
   107  	cApprovers := sets.NewString("Chris", "Carol")
   108  	eApprovers := sets.NewString("Eve", "Erin")
   109  	edcApprovers := eApprovers.Union(cApprovers)
   110  	FakeRepoMap := map[string]sets.String{
   111  		"":        rootApprovers,
   112  		"a":       aApprovers,
   113  		"b":       bApprovers,
   114  		"c":       cApprovers,
   115  		"a/combo": edcApprovers,
   116  	}
   117  	fake_repo := createFakeRepo(FakeRepoMap)
   118  
   119  	tests := []struct {
   120  		testName              string
   121  		ownersFile            string
   122  		expectedLeafApprovers sets.String
   123  		expectedApprovers     sets.String
   124  	}{
   125  		{
   126  			testName:              "Root Owners",
   127  			ownersFile:            "",
   128  			expectedApprovers:     rootApprovers,
   129  			expectedLeafApprovers: rootApprovers,
   130  		},
   131  		{
   132  			testName:              "A Owners",
   133  			ownersFile:            "a",
   134  			expectedLeafApprovers: aApprovers,
   135  			expectedApprovers:     aApprovers.Union(rootApprovers),
   136  		},
   137  		{
   138  			testName:              "B Owners",
   139  			ownersFile:            "b",
   140  			expectedLeafApprovers: bApprovers,
   141  			expectedApprovers:     bApprovers.Union(rootApprovers),
   142  		},
   143  		{
   144  			testName:              "C Owners",
   145  			ownersFile:            "c",
   146  			expectedLeafApprovers: cApprovers,
   147  			expectedApprovers:     cApprovers.Union(rootApprovers),
   148  		},
   149  		{
   150  			testName:              "Combo Owners",
   151  			ownersFile:            "a/combo",
   152  			expectedLeafApprovers: edcApprovers,
   153  			expectedApprovers:     edcApprovers.Union(aApprovers).Union(rootApprovers),
   154  		},
   155  	}
   156  
   157  	for _, test := range tests {
   158  		calculated_leaf_approvers := fake_repo.LeafApprovers(test.ownersFile)
   159  		calculated_approvers := fake_repo.Approvers(test.ownersFile)
   160  
   161  		test.expectedLeafApprovers = setToLower(test.expectedLeafApprovers)
   162  		if !calculated_leaf_approvers.Equal(test.expectedLeafApprovers) {
   163  			t.Errorf("Failed for test %v.  Expected Leaf Approvers: %v. Actual Leaf Approvers %v", test.testName, test.expectedLeafApprovers, calculated_leaf_approvers)
   164  		}
   165  
   166  		test.expectedApprovers = setToLower(test.expectedApprovers)
   167  		if !calculated_approvers.Equal(test.expectedApprovers) {
   168  			t.Errorf("Failed for test %v.  Expected Approvers: %v. Actual Approvers %v", test.testName, test.expectedApprovers, calculated_approvers)
   169  		}
   170  	}
   171  }
   172  
   173  func TestGetLeafApprovers(t *testing.T) {
   174  	rootApprovers := sets.NewString("Alice", "Bob")
   175  	aApprovers := sets.NewString("Art", "Anne")
   176  	bApprovers := sets.NewString("Bill", "Ben", "Barbara")
   177  	dApprovers := sets.NewString("David", "Dan", "Debbie")
   178  	FakeRepoMap := map[string]sets.String{
   179  		"":    rootApprovers,
   180  		"a":   aApprovers,
   181  		"b":   bApprovers,
   182  		"a/d": dApprovers,
   183  	}
   184  
   185  	tests := []struct {
   186  		testName    string
   187  		filenames   []string
   188  		expectedMap map[string]sets.String
   189  	}{
   190  		{
   191  			testName:    "Empty PR",
   192  			filenames:   []string{},
   193  			expectedMap: map[string]sets.String{},
   194  		},
   195  		{
   196  			testName:    "Single Root File PR",
   197  			filenames:   []string{"kubernetes.go"},
   198  			expectedMap: map[string]sets.String{"": setToLower(rootApprovers)},
   199  		},
   200  		{
   201  			testName:    "Internal Node File PR",
   202  			filenames:   []string{"a/test.go"},
   203  			expectedMap: map[string]sets.String{"a": setToLower(aApprovers)},
   204  		},
   205  		{
   206  			testName:  "Two Leaf File PR",
   207  			filenames: []string{"a/d/test.go", "b/test.go"},
   208  			expectedMap: map[string]sets.String{
   209  				"a/d": setToLower(dApprovers),
   210  				"b":   setToLower(bApprovers)},
   211  		},
   212  		{
   213  			testName:  "Leaf and Parent 2 File PR",
   214  			filenames: []string{"a/test.go", "a/d/test.go"},
   215  			expectedMap: map[string]sets.String{
   216  				"a": setToLower(aApprovers),
   217  			},
   218  		},
   219  	}
   220  
   221  	for _, test := range tests {
   222  		testOwners := Owners{
   223  			filenames: test.filenames,
   224  			repo:      createFakeRepo(FakeRepoMap),
   225  			seed:      TEST_SEED,
   226  			log:       logrus.WithField("plugin", "some_plugin"),
   227  		}
   228  		oMap := testOwners.GetLeafApprovers()
   229  		if !reflect.DeepEqual(test.expectedMap, oMap) {
   230  			t.Errorf("Failed for test %v.  Expected Owners: %v. Actual Owners %v", test.testName, test.expectedMap, oMap)
   231  		}
   232  	}
   233  }
   234  func TestGetOwnersSet(t *testing.T) {
   235  	rootApprovers := sets.NewString("Alice", "Bob")
   236  	aApprovers := sets.NewString("Art", "Anne")
   237  	bApprovers := sets.NewString("Bill", "Ben", "Barbara")
   238  	dApprovers := sets.NewString("David", "Dan", "Debbie")
   239  	FakeRepoMap := map[string]sets.String{
   240  		"":    rootApprovers,
   241  		"a":   aApprovers,
   242  		"b":   bApprovers,
   243  		"a/d": dApprovers,
   244  	}
   245  
   246  	tests := []struct {
   247  		testName            string
   248  		filenames           []string
   249  		expectedOwnersFiles sets.String
   250  	}{
   251  		{
   252  			testName:            "Empty PR",
   253  			filenames:           []string{},
   254  			expectedOwnersFiles: sets.NewString(),
   255  		},
   256  		{
   257  			testName:            "Single Root File PR",
   258  			filenames:           []string{"kubernetes.go"},
   259  			expectedOwnersFiles: sets.NewString(""),
   260  		},
   261  		{
   262  			testName:            "Multiple Root File PR",
   263  			filenames:           []string{"test.go", "kubernetes.go"},
   264  			expectedOwnersFiles: sets.NewString(""),
   265  		},
   266  		{
   267  			testName:            "Internal Node File PR",
   268  			filenames:           []string{"a/test.go"},
   269  			expectedOwnersFiles: sets.NewString("a"),
   270  		},
   271  		{
   272  			testName:            "Two Leaf File PR",
   273  			filenames:           []string{"a/test.go", "b/test.go"},
   274  			expectedOwnersFiles: sets.NewString("a", "b"),
   275  		},
   276  		{
   277  			testName:            "Leaf and Parent 2 File PR",
   278  			filenames:           []string{"a/test.go", "a/c/test.go"},
   279  			expectedOwnersFiles: sets.NewString("a"),
   280  		},
   281  	}
   282  
   283  	for _, test := range tests {
   284  		testOwners := Owners{
   285  			filenames: test.filenames,
   286  			repo:      createFakeRepo(FakeRepoMap),
   287  			seed:      TEST_SEED,
   288  			log:       logrus.WithField("plugin", "some_plugin"),
   289  		}
   290  		oSet := testOwners.GetOwnersSet()
   291  		if !oSet.Equal(test.expectedOwnersFiles) {
   292  			t.Errorf("Failed for test %v.  Expected Owners: %v. Actual Owners %v", test.testName, test.expectedOwnersFiles, oSet)
   293  		}
   294  	}
   295  }
   296  
   297  func TestGetSuggestedApprovers(t *testing.T) {
   298  	var rootApprovers = sets.NewString("Alice", "Bob")
   299  	var aApprovers = sets.NewString("Art", "Anne")
   300  	var bApprovers = sets.NewString("Bill", "Ben", "Barbara")
   301  	var dApprovers = sets.NewString("David", "Dan", "Debbie")
   302  	var eApprovers = sets.NewString("Eve", "Erin")
   303  	var edcApprovers = eApprovers.Union(dApprovers)
   304  	var FakeRepoMap = map[string]sets.String{
   305  		"":        rootApprovers,
   306  		"a":       aApprovers,
   307  		"b":       bApprovers,
   308  		"a/d":     dApprovers,
   309  		"a/combo": edcApprovers,
   310  	}
   311  	tests := []struct {
   312  		testName  string
   313  		filenames []string
   314  		// need at least one person from each set
   315  		expectedOwners []sets.String
   316  	}{
   317  		{
   318  			testName:       "Empty PR",
   319  			filenames:      []string{},
   320  			expectedOwners: []sets.String{},
   321  		},
   322  		{
   323  			testName:       "Single Root File PR",
   324  			filenames:      []string{"kubernetes.go"},
   325  			expectedOwners: []sets.String{setToLower(rootApprovers)},
   326  		},
   327  		{
   328  			testName:       "Internal Node File PR",
   329  			filenames:      []string{"a/test.go"},
   330  			expectedOwners: []sets.String{setToLower(aApprovers)},
   331  		},
   332  		{
   333  			testName:       "Multiple Files Internal Node File PR",
   334  			filenames:      []string{"a/test.go", "a/test1.go"},
   335  			expectedOwners: []sets.String{setToLower(aApprovers)},
   336  		},
   337  		{
   338  			testName:       "Two Leaf File PR",
   339  			filenames:      []string{"a/test.go", "b/test.go"},
   340  			expectedOwners: []sets.String{setToLower(aApprovers), setToLower(bApprovers)},
   341  		},
   342  		{
   343  			testName:       "Leaf and Parent 2 File PR",
   344  			filenames:      []string{"a/test.go", "a/d/test.go"},
   345  			expectedOwners: []sets.String{setToLower(aApprovers)},
   346  		},
   347  		{
   348  			testName:       "Combo and B",
   349  			filenames:      []string{"a/combo/test.go", "b/test.go"},
   350  			expectedOwners: []sets.String{setToLower(edcApprovers), setToLower(bApprovers)},
   351  		},
   352  		{
   353  			testName:       "Lowest Leaf",
   354  			filenames:      []string{"a/combo/test.go"},
   355  			expectedOwners: []sets.String{setToLower(edcApprovers)},
   356  		},
   357  	}
   358  
   359  	for _, test := range tests {
   360  		testOwners := Owners{
   361  			filenames: test.filenames,
   362  			repo:      createFakeRepo(FakeRepoMap),
   363  			seed:      TEST_SEED,
   364  			log:       logrus.WithField("plugin", "some_plugin"),
   365  		}
   366  		suggested := testOwners.GetSuggestedApprovers(testOwners.GetReverseMap(testOwners.GetLeafApprovers()), testOwners.GetShuffledApprovers())
   367  		for _, ownersSet := range test.expectedOwners {
   368  			if ownersSet.Intersection(suggested).Len() == 0 {
   369  				t.Errorf("Failed for test %v.  Didn't find an approver from: %v. Actual Owners %v", test.testName, ownersSet, suggested)
   370  				t.Errorf("%v", test.filenames)
   371  			}
   372  		}
   373  	}
   374  }
   375  
   376  func TestGetAllPotentialApprovers(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  		// use an array because we expected output of this function to be sorted
   396  		expectedApprovers []string
   397  	}{
   398  		{
   399  			testName:          "Empty PR",
   400  			filenames:         []string{},
   401  			expectedApprovers: []string{},
   402  		},
   403  		{
   404  			testName:          "Single Root File PR",
   405  			filenames:         []string{"kubernetes.go"},
   406  			expectedApprovers: setToLower(rootApprovers).List(),
   407  		},
   408  		{
   409  			testName:          "Internal Node File PR",
   410  			filenames:         []string{"a/test.go"},
   411  			expectedApprovers: setToLower(aApprovers).List(),
   412  		},
   413  		{
   414  			testName:          "One Leaf One Internal Node File PR",
   415  			filenames:         []string{"a/test.go", "b/test.go"},
   416  			expectedApprovers: setToLower(aApprovers.Union(bApprovers)).List(),
   417  		},
   418  		{
   419  			testName:          "Two Leaf Files PR",
   420  			filenames:         []string{"a/d/test.go", "c/test.go"},
   421  			expectedApprovers: setToLower(dApprovers.Union(cApprovers)).List(),
   422  		},
   423  		{
   424  			testName:          "Leaf and Parent 2 File PR",
   425  			filenames:         []string{"a/test.go", "a/combo/test.go"},
   426  			expectedApprovers: setToLower(aApprovers).List(),
   427  		},
   428  		{
   429  			testName:          "Two Leafs",
   430  			filenames:         []string{"a/d/test.go", "b/test.go"},
   431  			expectedApprovers: setToLower(dApprovers.Union(bApprovers)).List(),
   432  		},
   433  		{
   434  			testName:          "Lowest Leaf",
   435  			filenames:         []string{"a/combo/test.go"},
   436  			expectedApprovers: setToLower(edcApprovers).List(),
   437  		},
   438  		{
   439  			testName:          "Root And Everything Else PR",
   440  			filenames:         []string{"a/combo/test.go", "b/test.go", "c/test.go", "d/test.go"},
   441  			expectedApprovers: setToLower(rootApprovers).List(),
   442  		},
   443  	}
   444  
   445  	for _, test := range tests {
   446  		testOwners := Owners{
   447  			filenames: test.filenames,
   448  			repo:      createFakeRepo(FakeRepoMap),
   449  			seed:      TEST_SEED,
   450  			log:       logrus.WithField("plugin", "some_plugin"),
   451  		}
   452  		all := testOwners.GetAllPotentialApprovers()
   453  		if !reflect.DeepEqual(all, test.expectedApprovers) {
   454  			t.Errorf("Failed for test %v.  Didn't correct approvers list.  Expected: %v. Found %v", test.testName, test.expectedApprovers, all)
   455  		}
   456  	}
   457  }
   458  
   459  func TestFindMostCoveringApprover(t *testing.T) {
   460  	rootApprovers := sets.NewString("Alice", "Bob")
   461  	aApprovers := sets.NewString("Art", "Anne")
   462  	bApprovers := sets.NewString("Bill", "Ben", "Barbara")
   463  	cApprovers := sets.NewString("Chris", "Carol")
   464  	dApprovers := sets.NewString("David", "Dan", "Debbie")
   465  	eApprovers := sets.NewString("Eve", "Erin")
   466  	edcApprovers := eApprovers.Union(dApprovers).Union(cApprovers)
   467  	FakeRepoMap := map[string]sets.String{
   468  		"":        rootApprovers,
   469  		"a":       aApprovers,
   470  		"b":       bApprovers,
   471  		"c":       cApprovers,
   472  		"a/d":     dApprovers,
   473  		"a/combo": edcApprovers,
   474  	}
   475  	tests := []struct {
   476  		testName   string
   477  		filenames  []string
   478  		unapproved sets.String
   479  		// because most covering could be two or more people
   480  		expectedMostCovering sets.String
   481  	}{
   482  		{
   483  			testName:             "Empty PR",
   484  			filenames:            []string{},
   485  			unapproved:           sets.String{},
   486  			expectedMostCovering: sets.NewString(""),
   487  		},
   488  		{
   489  			testName:             "Single Root File PR",
   490  			filenames:            []string{"kubernetes.go"},
   491  			unapproved:           sets.NewString(""),
   492  			expectedMostCovering: setToLower(rootApprovers),
   493  		},
   494  		{
   495  			testName:             "Internal Node File PR",
   496  			filenames:            []string{"a/test.go"},
   497  			unapproved:           sets.NewString("a"),
   498  			expectedMostCovering: setToLower(aApprovers),
   499  		},
   500  		{
   501  			testName:             "Combo and Intersecting Leaf PR",
   502  			filenames:            []string{"a/combo/test.go", "a/d/test.go"},
   503  			unapproved:           sets.NewString("a/combo", "a/d"),
   504  			expectedMostCovering: setToLower(edcApprovers.Intersection(dApprovers)),
   505  		},
   506  		{
   507  			testName:             "Three Leaf PR Only B Approved",
   508  			filenames:            []string{"a/combo/test.go", "c/test.go", "b/test.go"},
   509  			unapproved:           sets.NewString("a/combo", "c/"),
   510  			expectedMostCovering: setToLower(edcApprovers.Intersection(cApprovers)),
   511  		},
   512  		{
   513  			testName:             "Three Leaf PR Only B Left Unapproved",
   514  			filenames:            []string{"a/combo/test.go", "a/d/test.go", "b/test.go"},
   515  			unapproved:           sets.NewString("b"),
   516  			expectedMostCovering: setToLower(bApprovers),
   517  		},
   518  		{
   519  			testName:             "Leaf and Parent 2 File PR",
   520  			filenames:            []string{"a/test.go", "a/d/test.go"},
   521  			unapproved:           sets.NewString("a", "a/d"),
   522  			expectedMostCovering: setToLower(aApprovers.Union(dApprovers)),
   523  		},
   524  	}
   525  
   526  	for _, test := range tests {
   527  		testOwners := Owners{
   528  			filenames: test.filenames,
   529  			repo:      createFakeRepo(FakeRepoMap),
   530  			seed:      TEST_SEED,
   531  			log:       logrus.WithField("plugin", "some_plugin"),
   532  		}
   533  		bestPerson := findMostCoveringApprover(testOwners.GetAllPotentialApprovers(), testOwners.GetReverseMap(testOwners.GetLeafApprovers()), test.unapproved)
   534  		if test.expectedMostCovering.Intersection(sets.NewString(bestPerson)).Len() != 1 {
   535  			t.Errorf("Failed for test %v.  Didn't correct approvers list.  Expected: %v. Found %v", test.testName, test.expectedMostCovering, bestPerson)
   536  		}
   537  	}
   538  }
   539  
   540  func TestGetReverseMap(t *testing.T) {
   541  	rootApprovers := sets.NewString("Alice", "Bob")
   542  	aApprovers := sets.NewString("Art", "Anne")
   543  	cApprovers := sets.NewString("Chris", "Carol")
   544  	dApprovers := sets.NewString("David", "Dan", "Debbie")
   545  	eApprovers := sets.NewString("Eve", "Erin")
   546  	edcApprovers := eApprovers.Union(dApprovers).Union(cApprovers)
   547  	FakeRepoMap := map[string]sets.String{
   548  		"":        rootApprovers,
   549  		"a":       aApprovers,
   550  		"c":       cApprovers,
   551  		"a/d":     dApprovers,
   552  		"a/combo": edcApprovers,
   553  	}
   554  	tests := []struct {
   555  		testName       string
   556  		filenames      []string
   557  		expectedRevMap map[string]sets.String // people -> files they can approve
   558  	}{
   559  		{
   560  			testName:       "Empty PR",
   561  			filenames:      []string{},
   562  			expectedRevMap: map[string]sets.String{},
   563  		},
   564  		{
   565  			testName:  "Single Root File PR",
   566  			filenames: []string{"kubernetes.go"},
   567  			expectedRevMap: map[string]sets.String{
   568  				"alice": sets.NewString(""),
   569  				"bob":   sets.NewString(""),
   570  			},
   571  		},
   572  		{
   573  			testName:  "Two Leaf PRs",
   574  			filenames: []string{"a/combo/test.go", "a/d/test.go"},
   575  			expectedRevMap: map[string]sets.String{
   576  				"david":  sets.NewString("a/d", "a/combo"),
   577  				"dan":    sets.NewString("a/d", "a/combo"),
   578  				"debbie": sets.NewString("a/d", "a/combo"),
   579  				"eve":    sets.NewString("a/combo"),
   580  				"erin":   sets.NewString("a/combo"),
   581  				"chris":  sets.NewString("a/combo"),
   582  				"carol":  sets.NewString("a/combo"),
   583  			},
   584  		},
   585  	}
   586  
   587  	for _, test := range tests {
   588  		testOwners := Owners{
   589  			filenames: test.filenames,
   590  			repo:      createFakeRepo(FakeRepoMap),
   591  			seed:      TEST_SEED,
   592  			log:       logrus.WithField("plugin", "some_plugin"),
   593  		}
   594  		calculatedRevMap := testOwners.GetReverseMap(testOwners.GetLeafApprovers())
   595  		if !reflect.DeepEqual(calculatedRevMap, test.expectedRevMap) {
   596  			t.Errorf("Failed for test %v.  Didn't find correct reverse map.", test.testName)
   597  			t.Errorf("Person \t\t Expected \t\tFound ")
   598  			// printing the calculated vs expected in a nicer way for debugging
   599  			for k, v := range test.expectedRevMap {
   600  				if calcVal, ok := calculatedRevMap[k]; ok {
   601  					t.Errorf("%v\t\t%v\t\t%v ", k, v, calcVal)
   602  				} else {
   603  					t.Errorf("%v\t\t%v", k, v)
   604  				}
   605  			}
   606  		}
   607  	}
   608  }
   609  
   610  func TestGetShuffledApprovers(t *testing.T) {
   611  	rootApprovers := sets.NewString("Alice", "Bob")
   612  	aApprovers := sets.NewString("Art", "Anne")
   613  	bApprovers := sets.NewString("Bill", "Ben", "Barbara")
   614  	cApprovers := sets.NewString("Chris", "Carol")
   615  	dApprovers := sets.NewString("David", "Dan", "Debbie")
   616  	eApprovers := sets.NewString("Eve", "Erin")
   617  	edcApprovers := eApprovers.Union(dApprovers).Union(cApprovers)
   618  	FakeRepoMap := map[string]sets.String{
   619  		"":        rootApprovers,
   620  		"a":       aApprovers,
   621  		"b":       bApprovers,
   622  		"c":       cApprovers,
   623  		"a/d":     dApprovers,
   624  		"a/combo": edcApprovers,
   625  	}
   626  	tests := []struct {
   627  		testName      string
   628  		filenames     []string
   629  		seed          int64
   630  		expectedOrder []string
   631  	}{
   632  		{
   633  			testName:      "Empty PR",
   634  			filenames:     []string{},
   635  			seed:          0,
   636  			expectedOrder: []string{},
   637  		},
   638  		{
   639  			testName:      "Single Root File PR Approved",
   640  			filenames:     []string{"kubernetes.go"},
   641  			seed:          0,
   642  			expectedOrder: []string{"bob", "alice"},
   643  		},
   644  		{
   645  			testName:      "Combo And B PR",
   646  			filenames:     []string{"a/combo/test.go", "b/test.go"},
   647  			seed:          0,
   648  			expectedOrder: []string{"erin", "bill", "carol", "barbara", "dan", "debbie", "ben", "david", "eve", "chris"},
   649  		},
   650  		{
   651  			testName:      "Combo and D, Seed 0",
   652  			filenames:     []string{"a/combo/test.go", "a/d/test.go"},
   653  			seed:          0,
   654  			expectedOrder: []string{"erin", "dan", "dan", "carol", "david", "debbie", "chris", "debbie", "eve", "david"},
   655  		},
   656  		{
   657  			testName:      "Combo and D, Seed 2",
   658  			filenames:     []string{"a/combo/test.go", "a/d/test.go"},
   659  			seed:          2,
   660  			expectedOrder: []string{"dan", "carol", "debbie", "dan", "erin", "chris", "eve", "david", "debbie", "david"},
   661  		},
   662  	}
   663  
   664  	for _, test := range tests {
   665  		testOwners := Owners{
   666  			filenames: test.filenames,
   667  			repo:      createFakeRepo(FakeRepoMap),
   668  			seed:      test.seed,
   669  			log:       logrus.WithField("plugin", "some_plugin"),
   670  		}
   671  		calculated := testOwners.GetShuffledApprovers()
   672  		if !reflect.DeepEqual(test.expectedOrder, calculated) {
   673  			t.Errorf("Failed for test %v.  Expected unapproved files: %v. Found %v", test.testName, test.expectedOrder, calculated)
   674  		}
   675  	}
   676  }
   677  
   678  func TestRemoveSubdirs(t *testing.T) {
   679  	tests := []struct {
   680  		testName       string
   681  		directories    sets.String
   682  		noParentOwners map[string]bool
   683  
   684  		expected sets.String
   685  	}{
   686  		{
   687  			testName:    "Empty PR",
   688  			directories: sets.NewString(),
   689  			expected:    sets.NewString(),
   690  		},
   691  		{
   692  			testName:    "Root and One Level Below PR",
   693  			directories: sets.NewString("", "a/"),
   694  			expected:    sets.NewString(""),
   695  		},
   696  		{
   697  			testName:    "Two Separate Branches",
   698  			directories: sets.NewString("a/", "c/"),
   699  			expected:    sets.NewString("a/", "c/"),
   700  		},
   701  		{
   702  			testName:    "Lots of Branches and Leaves",
   703  			directories: sets.NewString("a", "a/combo", "a/d", "b", "c"),
   704  			expected:    sets.NewString("a", "b", "c"),
   705  		},
   706  		{
   707  			testName:       "NoParentOwners",
   708  			directories:    sets.NewString("a", "a/combo"),
   709  			noParentOwners: map[string]bool{"a/combo": true},
   710  			expected:       sets.NewString("a", "a/combo"),
   711  		},
   712  		{
   713  			testName:       "NoParentOwners in relative path",
   714  			directories:    sets.NewString("a", "a/b/combo"),
   715  			noParentOwners: map[string]bool{"a/b": true},
   716  			expected:       sets.NewString("a", "a/b/combo"),
   717  		},
   718  		{
   719  			testName:       "NoParentOwners with child",
   720  			directories:    sets.NewString("a", "a/b", "a/b/combo"),
   721  			noParentOwners: map[string]bool{"a/b": true},
   722  			expected:       sets.NewString("a", "a/b"),
   723  		},
   724  	}
   725  
   726  	for _, test := range tests {
   727  		if test.noParentOwners == nil {
   728  			test.noParentOwners = map[string]bool{}
   729  		}
   730  		o := &Owners{repo: FakeRepo{noParentOwnersMap: test.noParentOwners}}
   731  		o.removeSubdirs(test.directories)
   732  		if !reflect.DeepEqual(test.expected, test.directories) {
   733  			t.Errorf("Failed to remove subdirectories for test %v.  Expected files: %q. Found %q", test.testName, test.expected.List(), test.directories.List())
   734  
   735  		}
   736  	}
   737  }