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