blob: e911f1be3a6a402d8db06e77a87d576c361a8ee6 [file] [log] [blame]
// Copyright (C) 2017 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.googlesource.gerrit.owners.common;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;
import static com.googlesource.gerrit.owners.common.MatcherConfig.exactMatcher;
import static com.googlesource.gerrit.owners.common.MatcherConfig.partialRegexMatcher;
import static com.googlesource.gerrit.owners.common.MatcherConfig.regexMatcher;
import static com.googlesource.gerrit.owners.common.MatcherConfig.suffixMatcher;
import static com.googlesource.gerrit.owners.common.StreamUtils.iteratorStream;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.powermock.api.easymock.PowerMock.replayAll;
import com.google.gerrit.entities.Account;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
@PowerMockIgnore("jdk.internal.reflect.*")
@PrepareForTest(JgitWrapper.class)
public class RegexTest extends Config {
private static final String ACCOUNT_A = "a";
private static final String ACCOUNT_B = "b";
private static final String ACCOUNT_C = "c";
private static final String ACCOUNT_D = "d";
private static final String ACCOUNT_E = "e";
private static final String ACCOUNT_F = "f";
private static final Account.Id ACCOUNT_A_ID = Account.id(1);
private static final Account.Id ACCOUNT_B_ID = Account.id(2);
private static final Account.Id ACCOUNT_C_ID = Account.id(3);
private static final Account.Id ACCOUNT_D_ID = Account.id(4);
private static final Account.Id ACCOUNT_E_ID = Account.id(5);
private static final Account.Id ACCOUNT_F_ID = Account.id(6);
@Override
@Before
public void setup() throws Exception {
accounts.put(ACCOUNT_A, ACCOUNT_A_ID);
accounts.put(ACCOUNT_B, ACCOUNT_B_ID);
accounts.put(ACCOUNT_C, ACCOUNT_C_ID);
accounts.put(ACCOUNT_D, ACCOUNT_D_ID);
accounts.put(ACCOUNT_E, ACCOUNT_E_ID);
accounts.put(ACCOUNT_F, ACCOUNT_F_ID);
super.setup();
}
@Test
public void testNewParsingYaml() throws Exception {
replayAll();
String fullConfig =
createConfig(
true,
owners(ACCOUNT_A),
suffixMatcher(".sql", ACCOUNT_B, ACCOUNT_C),
regexMatcher(".*/a.*", ACCOUNT_D),
partialRegexMatcher("Product.sql", ACCOUNT_A));
// the function to test
Optional<OwnersConfig> configNullable = getOwnersConfig(fullConfig);
// check classical configuration
assertThat(configNullable).isPresent();
OwnersConfig config = configNullable.get();
assertTrue(config.isInherited());
Set<String> owners = config.getOwners();
assertEquals(1, owners.size());
assertTrue(owners.contains(ACCOUNT_A));
// check matchers
Map<String, Matcher> matchers = config.getMatchers();
assertEquals(3, matchers.size());
assertTrue(matchers.containsKey(".sql"));
assertTrue(matchers.containsKey(".*/a.*"));
assertTrue(matchers.containsKey("Product.sql"));
// suffix .sql matcher
Matcher advMatcher = matchers.get(".sql");
assertEquals(2, advMatcher.getOwners().size());
Set<Account.Id> advOwners = advMatcher.getOwners();
assertTrue(advOwners.contains(ACCOUNT_B_ID));
assertTrue(advOwners.contains(ACCOUNT_C_ID));
// regex matcher
Matcher dbMatcher = matchers.get(".*/a.*");
assertEquals(1, dbMatcher.getOwners().size());
Set<Account.Id> dbOwners = dbMatcher.getOwners();
assertTrue(dbOwners.contains(ACCOUNT_D_ID));
// partial_regex matcher
Matcher partial = matchers.get("Product.sql");
assertEquals(1, partial.getOwners().size());
Set<Account.Id> partialOwners = partial.getOwners();
assertTrue(partialOwners.contains(ACCOUNT_A_ID));
}
@Test
public void checkMatchers() throws Exception {
String parentConfig =
createConfig(
true,
owners(ACCOUNT_A),
suffixMatcher(".sql", ACCOUNT_B, ACCOUNT_C),
regexMatcher(".*/a.*", ACCOUNT_D));
String childConfig =
createConfig(
true,
owners(ACCOUNT_F),
exactMatcher("project/file.txt", ACCOUNT_D, ACCOUNT_E),
partialRegexMatcher("alfa", ACCOUNT_A));
expectConfig("OWNERS", parentConfig);
expectConfig("project/OWNERS", childConfig);
creatingPatchList(
Arrays.asList(
"project/file.txt", // matches exact in
// project owners d,e
"file1.txt", // no matches so nothing for this
"project/afile2.sql", // matches two matchers so we have b,c,d
"project/bfile.txt", // no matching
"projectalfa", // matches PartialRegex
"project/file.sql")); // only .sql matching b,c
replayAll();
// function under test
PathOwners owners = new PathOwners(accounts, repository, branch, patchList);
// assertions on classic owners
Set<Account.Id> ownersSet = owners.get().get("project/OWNERS");
assertEquals(2, ownersSet.size());
// get matchers
Map<String, Matcher> matchers = owners.getMatchers();
assertEquals(4, matchers.size());
// asserts we have 1 exact matcher
List<Entry<String, Matcher>> onlyExacts =
iteratorStream(matchers.entrySet().iterator())
.filter(entry -> entry.getValue() instanceof ExactMatcher)
.collect(Collectors.toList());
assertEquals(1, onlyExacts.size());
assertEquals("project/file.txt", onlyExacts.get(0).getKey());
// ... 1 regex matcher
List<Entry<String, Matcher>> regexList =
StreamUtils.iteratorStream(matchers.entrySet().iterator())
.filter(entry -> entry.getValue() instanceof RegExMatcher)
.collect(Collectors.toList());
assertEquals(1, regexList.size());
assertEquals(".*/a.*", regexList.get(0).getKey());
// ... 1 partial regex matcher
List<Entry<String, Matcher>> partialRegexList =
iteratorStream(matchers.entrySet().iterator())
.filter(entry -> entry.getValue() instanceof PartialRegExMatcher)
.collect(Collectors.toList());
assertEquals(1, partialRegexList.size());
assertEquals("alfa", partialRegexList.get(0).getKey());
// .... 1 suffix matcher
List<Entry<String, Matcher>> suffixList =
iteratorStream(matchers.entrySet().iterator())
.filter(entry -> entry.getValue() instanceof SuffixMatcher)
.collect(Collectors.toList());
assertEquals(1, suffixList.size());
assertEquals(".sql", suffixList.get(0).getKey());
// now checks file owners as well
Map<String, Set<Account.Id>> fileOwners = owners.getFileOwners();
assertEquals(6, fileOwners.size());
Set<Account.Id> set1 = fileOwners.get("project/file.txt");
assertEquals(4, set1.size()); // includes classic owners a and f
assertTrue(set1.contains(ACCOUNT_A_ID));
assertTrue(set1.contains(ACCOUNT_D_ID));
assertTrue(set1.contains(ACCOUNT_E_ID));
assertTrue(set1.contains(ACCOUNT_F_ID));
Set<Account.Id> set2 = fileOwners.get("project/afile2.sql");
assertEquals(5, set2.size());
assertTrue(set2.contains(ACCOUNT_A_ID));
assertTrue(set2.contains(ACCOUNT_B_ID));
assertTrue(set2.contains(ACCOUNT_C_ID));
assertTrue(set2.contains(ACCOUNT_D_ID));
assertTrue(set2.contains(ACCOUNT_F_ID));
Set<Account.Id> set3 = fileOwners.get("project/file.sql");
assertEquals(4, set3.size());
assertTrue(set3.contains(ACCOUNT_A_ID));
assertTrue(set3.contains(ACCOUNT_B_ID));
assertTrue(set3.contains(ACCOUNT_C_ID));
assertTrue(set3.contains(ACCOUNT_F_ID));
Set<Account.Id> set4 = fileOwners.get("projectalfa");
assertEquals(1, set4.size()); // only 1 because a is class and alfa owner
assertTrue(set4.contains(ACCOUNT_A_ID));
}
@Test
public void testMatchersOnlyConfig() throws Exception {
replayAll();
Optional<OwnersConfig> ownersConfigOpt =
getOwnersConfig(createConfig(false, new String[0], suffixMatcher(".txt", ACCOUNT_B)));
assertThat(ownersConfigOpt).isPresent();
OwnersConfig ownersConfig = ownersConfigOpt.get();
assertThat(ownersConfig.getOwners()).isEmpty();
assertThat(ownersConfig.getMatchers()).isNotEmpty();
}
@Test
public void testkRegexShouldMatchOnlyOnSuffix() throws Exception {
String configString = createConfig(false, new String[0], suffixMatcher(".sql", ACCOUNT_B));
expectConfig("OWNERS", configString);
expectNoConfig("project/OWNERS");
creatingPatch("project/file.sql", "another.txt");
replayAll();
PathOwners owners = new PathOwners(accounts, repository, branch, patchList);
Set<String> ownedFiles = owners.getFileOwners().keySet();
assertThat(ownedFiles).containsExactly("project/file.sql");
}
}