| // 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.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.reviewdb.client.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.PrepareForTest; |
| import org.powermock.modules.junit4.PowerMockRunner; |
| |
| @RunWith(PowerMockRunner.class) |
| @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 = new Account.Id(1); |
| private static final Account.Id ACCOUNT_B_ID = new Account.Id(2); |
| private static final Account.Id ACCOUNT_C_ID = new Account.Id(3); |
| private static final Account.Id ACCOUNT_D_ID = new Account.Id(4); |
| private static final Account.Id ACCOUNT_E_ID = new Account.Id(5); |
| private static final Account.Id ACCOUNT_F_ID = new 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 |
| assertTrue(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()).named("ownersConfig").isTrue(); |
| 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"); |
| } |
| } |