Use BaseConfig instead of raw PluginConfig. * Pass to the Config class more Gerrit environment variables, including AccountCache, PatchListCache, Emails, to have more environment-dependent interpretation of config key values in the future. * Use BaseConfig in Config instead of raw PluginConfig to allow future extension with more dynamic key values. * Simplify Checker methods; remove redundant exception specifications. Change-Id: I50b274aa7220f566288194a8fd219336536f0ac8
diff --git a/src/main/java/com/googlesource/gerrit/plugins/findowners/Action.java b/src/main/java/com/googlesource/gerrit/plugins/findowners/Action.java index c97b9f8..0e80906 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/findowners/Action.java +++ b/src/main/java/com/googlesource/gerrit/plugins/findowners/Action.java
@@ -33,6 +33,7 @@ import com.google.gerrit.server.change.RevisionResource; import com.google.gerrit.server.config.PluginConfigFactory; import com.google.gerrit.server.git.GitRepositoryManager; +import com.google.gerrit.server.patch.PatchListCache; import com.google.gerrit.server.permissions.PermissionBackend; import com.google.gerrit.server.project.ProjectCache; import com.google.gerrit.server.project.ProjectState; @@ -75,6 +76,7 @@ Provider<CurrentUser> userProvider, ChangeData.Factory changeDataFactory, AccountCache accountCache, + PatchListCache patchListCache, Emails emails, GitRepositoryManager repoManager, ProjectCache projectCache) { @@ -85,7 +87,7 @@ this.emails = emails; this.repoManager = repoManager; this.projectCache = projectCache; - this.config = new Config(configFactory); + this.config = new Config(configFactory, null, accountCache, patchListCache, emails); } private String getUserName() {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/findowners/BaseConfig.java b/src/main/java/com/googlesource/gerrit/plugins/findowners/BaseConfig.java new file mode 100644 index 0000000..a390bf2 --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/findowners/BaseConfig.java
@@ -0,0 +1,68 @@ +// Copyright (C) 2019 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.plugins.findowners; + +import com.google.gerrit.server.config.PluginConfig; + +/** + * BaseConfig wraps Gerrit PluginConfig for find-owners Config. + * + * <p>This base class provides a subset of PluginConfig methods for find-owners Config. It could be + * extended in the future to provide more dynamic evaluation of key values. Its contructor keeps and + * delegates all methods to a PluginConfig. + */ +class BaseConfig { + protected final String name; // name of this plugin + protected final PluginConfig config; // wrapped PluginConfig + + public BaseConfig(String name, PluginConfig config) { + this.name = name; + this.config = config; + } + + // Return the uninterpreted string value of a key. + public String getRawString(String name) { + return config.getString(name); + } + + // Return the uninterpreted string value of a key with default value. + public String getRawString(String name, String defaultValue) { + return config.getString(name, defaultValue); + } + + public String getString(String name) { + return config.getString(name); + } + + public String getString(String name, String defaultValue) { + return config.getString(name, defaultValue); + } + + public int getInt(String name, int defaultValue) { + return config.getInt(name, defaultValue); + } + + public boolean getBoolean(String name, boolean defaultValue) { + return config.getBoolean(name, defaultValue); + } + + public <T extends Enum<?>> T getEnum(String name, T defaultValue) { + return config.getEnum(name, defaultValue); + } + + public <T extends Enum<?>> T getEnum(T[] all, String name, T defaultValue) { + return config.getEnum(all, name, defaultValue); + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/findowners/Checker.java b/src/main/java/com/googlesource/gerrit/plugins/findowners/Checker.java index 0004bf2..53bf34d 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/findowners/Checker.java +++ b/src/main/java/com/googlesource/gerrit/plugins/findowners/Checker.java
@@ -22,8 +22,10 @@ import com.google.gerrit.server.account.Emails; import com.google.gerrit.server.config.PluginConfigFactory; import com.google.gerrit.server.git.GitRepositoryManager; +import com.google.gerrit.server.patch.PatchListCache; import com.google.gerrit.server.project.ProjectState; import com.google.gerrit.server.query.change.ChangeData; +import com.google.gerrit.server.rules.PrologEnvironment; import com.google.gerrit.server.rules.StoredValues; import com.googlecode.prolog_cafe.lang.Prolog; import java.util.HashMap; @@ -39,28 +41,34 @@ private static final String EXEMPT_MESSAGE1 = "Exempt-From-Owner-Approval:"; private static final String EXEMPT_MESSAGE2 = "Exempted-From-Owner-Approval:"; + private final AccountCache accountCache; private final GitRepositoryManager repoManager; + private final Emails emails; private final Config config; private final ProjectState projectState; // could be null when used by FindOwnersIT private final ChangeData changeData; private int minVoteLevel; Checker( + AccountCache accountCache, + PatchListCache patchListCache, GitRepositoryManager repoManager, + Emails emails, PluginConfigFactory configFactory, ProjectState projectState, ChangeData changeData, int v) { + this.accountCache = accountCache; this.repoManager = repoManager; + this.emails = emails; this.projectState = projectState; this.changeData = changeData; - this.config = new Config(configFactory); + this.config = new Config(configFactory, null, accountCache, patchListCache, emails); minVoteLevel = v; } /** Returns a map from reviewer email to vote value. */ - Map<String, Integer> getVotes(AccountCache accountCache, ChangeData changeData) - throws StorageException { + Map<String, Integer> getVotes(ChangeData changeData) { Map<String, Integer> map = new HashMap<>(); for (PatchSetApproval p : changeData.currentApprovals()) { // Only collect non-zero Code-Review votes. @@ -110,12 +118,12 @@ } /** Returns 1 if owner approval is found, -1 if missing, 0 if unneeded. */ - int findApproval(AccountCache accountCache, OwnersDb db) throws StorageException { + int findApproval(OwnersDb db) { Map<String, Set<String>> file2Owners = db.findOwners(changeData.currentFilePaths()); if (file2Owners.isEmpty()) { // do not need owner approval return 0; } - Map<String, Integer> votes = getVotes(accountCache, changeData); + Map<String, Integer> votes = getVotes(changeData); for (Set<String> owners : file2Owners.values()) { if (!findOwnersInVotes(owners, votes)) { return -1; @@ -129,15 +137,18 @@ ChangeData changeData = null; try { changeData = StoredValues.CHANGE_DATA.get(engine); + PrologEnvironment env = (PrologEnvironment) engine.control; Checker checker = new Checker( + StoredValues.ACCOUNT_CACHE.get(engine), + env.getArgs().getPatchListCache(), StoredValues.REPO_MANAGER.get(engine), + StoredValues.EMAILS.get(engine), StoredValues.PLUGIN_CONFIG_FACTORY.get(engine), StoredValues.PROJECT_STATE.get(engine), changeData, minVoteLevel); - return checker.findApproval( - StoredValues.ACCOUNT_CACHE.get(engine), StoredValues.EMAILS.get(engine)); + return checker.findApproval(); } catch (StorageException e) { logger.atSevere().withCause(e).log("Exception for %s ", Config.getChangeId(changeData)); return 0; // owner approval may or may not be required. @@ -145,7 +156,7 @@ } /** Returns 1 if owner approval is found, -1 if missing, 0 if unneeded. */ - int findApproval(AccountCache accountCache, Emails emails) throws StorageException { + int findApproval() { if (isExemptFromOwnerApproval(changeData)) { return 0; } @@ -168,11 +179,11 @@ minVoteLevel = config.getMinOwnerVoteLevel(projectState, changeData); } logger.atFiner().log("findApproval db key = %s", db.key); - return findApproval(accountCache, db); + return findApproval(db); } /** Returns true if exempt from owner approval. */ - static boolean isExemptFromOwnerApproval(ChangeData changeData) throws StorageException { + static boolean isExemptFromOwnerApproval(ChangeData changeData) { try { String message = changeData.commitMessage(); if (message.contains(EXEMPT_MESSAGE1) || message.contains(EXEMPT_MESSAGE2)) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/findowners/Config.java b/src/main/java/com/googlesource/gerrit/plugins/findowners/Config.java index 6a35190..24402e8 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/findowners/Config.java +++ b/src/main/java/com/googlesource/gerrit/plugins/findowners/Config.java
@@ -17,8 +17,11 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.flogger.FluentLogger; import com.google.gerrit.reviewdb.client.Project; +import com.google.gerrit.server.account.AccountCache; +import com.google.gerrit.server.account.Emails; import com.google.gerrit.server.config.PluginConfig; import com.google.gerrit.server.config.PluginConfigFactory; +import com.google.gerrit.server.patch.PatchListCache; import com.google.gerrit.server.project.NoSuchProjectException; import com.google.gerrit.server.project.ProjectState; import com.google.gerrit.server.query.change.ChangeData; @@ -48,10 +51,10 @@ private final PluginConfigFactory configFactory; // Each call to API entry point creates one new Config and parses gerrit.config. - private final PluginConfig gerritConfig; + private final BaseConfig gerritConfig; // Each Config has a cache of project.config, with projectName:changeId key. - private final Map<String, PluginConfig> projectConfigMap; + private final Map<String, BaseConfig> projectConfigMap; // Global/plugin config parameters. private boolean addDebugMsg = false; @@ -60,27 +63,35 @@ private int maxCacheSize = 1000; private boolean reportSyntaxError = false; + // Gerrit server objects to set up JS initcode for JSEConfig. + private final AccountCache accountCache; + private final PatchListCache patchListCache; + private final Emails emails; + private static final FluentLogger logger = FluentLogger.forEnclosingClass(); - Config(PluginConfigFactory configFactory) { - // Called by Action() and Checker.findApproval, through Prolog submit filter. - this(configFactory, null); - } - - @VisibleForTesting - Config(PluginConfig rawConfig) { - this(null, rawConfig); - } - - Config(PluginConfigFactory configFactory, PluginConfig config) { + Config( + PluginConfigFactory configFactory, // null when called from unit tests + PluginConfig config, // null when called by Action and Checker + AccountCache accountCache, + PatchListCache patchListCache, + Emails emails) { this.configFactory = configFactory; - this.projectConfigMap = new HashMap<>(); + this.accountCache = accountCache; + this.patchListCache = patchListCache; + this.emails = emails; + projectConfigMap = new HashMap<>(); if (configFactory == null && config == null) { // When called from integration tests. - this.gerritConfig = config; + gerritConfig = null; return; } - this.gerritConfig = config == null ? configFactory.getFromGerritConfig(PLUGIN_NAME) : config; - // Get config variables from the plugin section of gerrit.config. + if (config == null) { + config = configFactory.getFromGerritConfig(PLUGIN_NAME); + } + // Get config variables from the plugin section of gerrit.config + // It could use JS in value expressions, if useJSE key value is true + // and JSEPluginConfig is available. + gerritConfig = newConfig(PLUGIN_NAME, config, null, null, null); addDebugMsg = gerritConfig.getBoolean(ADD_DEBUG_MSG, false); minOwnerVoteLevel = gerritConfig.getInt(MIN_OWNER_VOTE_LEVEL, 1); maxCacheAge = gerritConfig.getInt(MAX_CACHE_AGE, 0); @@ -88,6 +99,36 @@ reportSyntaxError = gerritConfig.getBoolean(REPORT_SYNTAX_ERROR, false); } + AccountCache accountCache() { + return accountCache; + } + + Emails emails() { + return emails; + } + + PatchListCache patchListCache() { + return patchListCache; + } + + private static BaseConfig newConfig( + String name, PluginConfig cfg, Project project, ProjectState state, ChangeData changeData) { + // This function is called + // (1) per Config (global gerrit.config), when Action or Checker API is called, + // with null project, state, and changeData. + // (2) per ProjectState and ChangeData, for project.config, when getProjectConfig is called. + // with null project and non-null state and changeData. + // (3) per Project, for project.config, by OwnersValidator, + // with non-null project and null state and changeData. + // Now only BaseConfig is returned. + // In the future, other child class of BaseConfig could be returned, + // depending on project, state, and changeData.. + if (changeData != null && state == null && project == null) { + logger.atSevere().log("Unexpected null pointer for change %s", getChangeId(changeData)); + } + return new BaseConfig(name, cfg); + } + boolean getAddDebugMsg() { return addDebugMsg; // defined globally, not per-project } @@ -143,6 +184,12 @@ return reportSyntaxError; } + static String getProjectName(ProjectState state, Project project) { + return state != null + ? state.getProject().getName() + : (project != null ? project.getName() : "(unknown project)"); + } + static String getChangeId(ChangeData data) { return data == null ? "(unknown change)" : ("c/" + data.getId().get()); } @@ -152,20 +199,32 @@ } // This is per ProjectState and ChangeData. - private PluginConfig getProjectConfig(ProjectState state, ChangeData data) { + BaseConfig getProjectConfig(ProjectState state, ChangeData data) { // A new Config object is created for every call to Action or Checker. - // So it is okay to reuse a PluginConfig per (ProjectState:ChangeData). + // So it is okay to reuse a BaseConfig per (ProjectState:ChangeData). // ProjectState parameter must not be null. - // The data parameter could be used in the future to generate change - // dependent PluginConfig. + // When the ChangeData parameter is null, the BaseConfig is created + // with a dummy CL info for the JS expression evaluator. String key = state.getName() + ":" + getChangeId(data); return projectConfigMap.computeIfAbsent( - key, (String k) -> configFactory.getFromProjectConfigWithInheritance(state, PLUGIN_NAME)); + key, + (String k) -> + newConfig( + PLUGIN_NAME, + configFactory.getFromProjectConfigWithInheritance(state, PLUGIN_NAME), + null, + state, + data)); } // Used by OwnersValidator and tests, not cached. - PluginConfig getProjectConfig(Project project) throws NoSuchProjectException { - return configFactory.getFromProjectConfigWithInheritance(project.getNameKey(), PLUGIN_NAME); + BaseConfig getProjectConfig(Project project) throws NoSuchProjectException { + return newConfig( + PLUGIN_NAME, + configFactory.getFromProjectConfigWithInheritance(project.getNameKey(), PLUGIN_NAME), + project, + null, + null); } String getOwnersFileName() {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/findowners/GetOwners.java b/src/main/java/com/googlesource/gerrit/plugins/findowners/GetOwners.java index ce3fdef..b786ecc 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/findowners/GetOwners.java +++ b/src/main/java/com/googlesource/gerrit/plugins/findowners/GetOwners.java
@@ -25,6 +25,7 @@ import com.google.gerrit.server.change.ChangeResource; import com.google.gerrit.server.config.PluginConfigFactory; import com.google.gerrit.server.git.GitRepositoryManager; +import com.google.gerrit.server.patch.PatchListCache; import com.google.gerrit.server.permissions.PermissionBackend; import com.google.gerrit.server.project.ProjectCache; import com.google.gerrit.server.query.change.ChangeData; @@ -58,6 +59,7 @@ Provider<CurrentUser> userProvider, ChangeData.Factory dataFactory, AccountCache accountCache, + PatchListCache patchListCache, Emails emails, GitRepositoryManager repoManager, ProjectCache projectCache) { @@ -68,6 +70,7 @@ userProvider, dataFactory, accountCache, + patchListCache, emails, repoManager, projectCache);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/findowners/OwnersValidator.java b/src/main/java/com/googlesource/gerrit/plugins/findowners/OwnersValidator.java index aa69aa9..9ef1893 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/findowners/OwnersValidator.java +++ b/src/main/java/com/googlesource/gerrit/plugins/findowners/OwnersValidator.java
@@ -25,6 +25,7 @@ import com.google.gerrit.extensions.registration.DynamicSet; import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.reviewdb.client.Project; +import com.google.gerrit.server.account.AccountCache; import com.google.gerrit.server.account.Emails; import com.google.gerrit.server.config.PluginConfig; import com.google.gerrit.server.config.PluginConfigFactory; @@ -34,6 +35,7 @@ import com.google.gerrit.server.git.validators.CommitValidationException; import com.google.gerrit.server.git.validators.CommitValidationListener; import com.google.gerrit.server.git.validators.CommitValidationMessage; +import com.google.gerrit.server.patch.PatchListCache; import com.google.inject.AbstractModule; import com.google.inject.Inject; import java.io.BufferedReader; @@ -91,17 +93,33 @@ private final Emails emails; @Inject - OwnersValidator(PluginConfigFactory cfgFactory, GitRepositoryManager repoManager, Emails emails) { - this(new Config(cfgFactory), repoManager, emails); + OwnersValidator( + PluginConfigFactory cfgFactory, + AccountCache accountCache, + PatchListCache patchListCache, + GitRepositoryManager repoManager, + Emails emails) { + this(cfgFactory, null, accountCache, patchListCache, repoManager, emails); } @VisibleForTesting - OwnersValidator(PluginConfig config, GitRepositoryManager repoManager, Emails emails) { - this(new Config(config), repoManager, emails); + OwnersValidator( + PluginConfig config, + AccountCache accountCache, + PatchListCache patchListCache, + GitRepositoryManager repoManager, + Emails emails) { + this(null, config, accountCache, patchListCache, repoManager, emails); } - private OwnersValidator(Config config, GitRepositoryManager repoManager, Emails emails) { - this.config = config; + private OwnersValidator( + PluginConfigFactory cfgFactory, + PluginConfig config, + AccountCache accountCache, + PatchListCache patchListCache, + GitRepositoryManager repoManager, + Emails emails) { + this.config = new Config(cfgFactory, config, accountCache, patchListCache, emails); this.repoManager = repoManager; this.emails = emails; }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/findowners/ApiIT.java b/src/test/java/com/googlesource/gerrit/plugins/findowners/ApiIT.java index ecd1401..7481b06 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/findowners/ApiIT.java +++ b/src/test/java/com/googlesource/gerrit/plugins/findowners/ApiIT.java
@@ -115,6 +115,7 @@ null, changeDataFactory, accountCache, + patchListCache, emails, repoManager, projectCache);
diff --git a/src/test/java/com/googlesource/gerrit/plugins/findowners/BaseConfigTest.java b/src/test/java/com/googlesource/gerrit/plugins/findowners/BaseConfigTest.java new file mode 100644 index 0000000..ca5ec1f --- /dev/null +++ b/src/test/java/com/googlesource/gerrit/plugins/findowners/BaseConfigTest.java
@@ -0,0 +1,70 @@ +// Copyright (C) 2019 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.plugins.findowners; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import com.google.gerrit.server.config.PluginConfig; +import org.eclipse.jgit.errors.ConfigInvalidException; +import org.eclipse.jgit.lib.Config; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public final class BaseConfigTest { + + private static BaseConfig createConfig(String name, String content) + throws ConfigInvalidException { + Config cfg = new Config(); + cfg.fromText(content); // could throw ConfigInvalidException + return new BaseConfig(name, new PluginConfig(name, cfg)); + } + + private static String pluginSection(String name) { + return "[plugin \"" + name + "\"]\n"; + } + + private static void sanityChecks(BaseConfig cfg) throws ConfigInvalidException { + assertEquals("string", "1+1", cfg.getString("k1")); + assertEquals("string", "'t'+k1", cfg.getString("v1")); + assertEquals("int", 2, cfg.getInt("v2", 1)); + assertNull(cfg.getString("k3")); + assertTrue("boolean", cfg.getBoolean("k2", false)); + assertEquals("string", "1+1", cfg.getRawString("k1")); + assertEquals("string", "'t'+k1", cfg.getRawString("v1")); + assertEquals("string", "true", cfg.getRawString("k2")); + assertEquals("string", "2", cfg.getRawString("v2")); + } + + @Test + public void sanity() throws ConfigInvalidException { + String name = "find-owners"; + String content0 = pluginSection(name) + "k1=1+1\nk2=true\nv1='t'+k1\nv2=2\n"; + String content1 = pluginSection("other") + "k3='abc'\n"; + BaseConfig cfg = createConfig(name, content0 + content1); + sanityChecks(cfg); + assertFalse("boolean", cfg.getBoolean("useJSE", false)); + assertTrue("boolean", cfg.getBoolean("useJSE", true)); + // Config contains useJSE=true, but BaseConfig does not use it. + cfg = createConfig(name, content0 + "useJSE=true\n" + content1); + sanityChecks(cfg); + assertTrue("boolean", cfg.getBoolean("useJSE", false)); + assertTrue("boolean", cfg.getBoolean("useJSE", true)); + } +}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/findowners/FindOwners.java b/src/test/java/com/googlesource/gerrit/plugins/findowners/FindOwners.java index 872cda4..293ce02 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/findowners/FindOwners.java +++ b/src/test/java/com/googlesource/gerrit/plugins/findowners/FindOwners.java
@@ -34,6 +34,7 @@ import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.client.RefNames; import com.google.gerrit.server.account.Emails; +import com.google.gerrit.server.patch.PatchListCache; import com.google.gerrit.server.permissions.PermissionBackend; import com.google.inject.Inject; import org.eclipse.jgit.lib.ObjectLoader; @@ -51,13 +52,14 @@ @Inject protected Emails emails; @Inject protected PermissionBackend permissionBackend; @Inject protected ProjectOperations projectOperations; + @Inject protected PatchListCache patchListCache; protected static final String PLUGIN_NAME = "find-owners"; protected Config config; @Before public void setConfig() { - config = new Config(pluginConfig); + config = new Config(pluginConfig, null, null, null, null); } protected String oneOwnerList(String email) { @@ -163,6 +165,7 @@ .to("refs/for/" + REFS_CONFIG); commit.assertOkStatus(); approveSubmit(commit); + testRepo = cloneProject(project); // reset the testRepo after cfg change } protected int checkApproval(PushOneCommit.Result r) throws Exception { @@ -178,8 +181,17 @@ repoManager, r.getChange(), 1); - Checker c = new Checker(repoManager, pluginConfig, null, r.getChange(), 1); - return c.findApproval(accountCache, db); + Checker c = + new Checker( + accountCache, + patchListCache, + repoManager, + emails, + pluginConfig, + null, + r.getChange(), + 1); + return c.findApproval(db); } // To simplify test case code, the REST API returned JSON string is filtered to
diff --git a/src/test/java/com/googlesource/gerrit/plugins/findowners/OwnersValidatorIT.java b/src/test/java/com/googlesource/gerrit/plugins/findowners/OwnersValidatorIT.java index 0eb7df1..8b6b3f2 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/findowners/OwnersValidatorIT.java +++ b/src/test/java/com/googlesource/gerrit/plugins/findowners/OwnersValidatorIT.java
@@ -127,7 +127,7 @@ private static final PluginConfig DISABLED_CONFIG = createDisabledConfig(); private OwnersValidator newOwnersValidator(PluginConfig cfg) { - return new OwnersValidator(cfg, repoManager, new MockedEmails()); + return new OwnersValidator(cfg, accountCache, patchListCache, repoManager, new MockedEmails()); } @Test