Merge branch 'stable-2.15' into stable-2.16
* stable-2.15:
Upgrade bazlets to latest stable-2.15 to build with 2.15.19 API
Upgrade bazlets to latest stable-2.14 to build with 2.14.21 API
Change-Id: I4274206d5a8b80c5777f443f07db9fe4d02b38d6
diff --git a/.bazelversion b/.bazelversion
index 9084fa2..fd2a018 100644
--- a/.bazelversion
+++ b/.bazelversion
@@ -1 +1 @@
-1.1.0
+3.1.0
diff --git a/WORKSPACE b/WORKSPACE
index cb3dc08..714fe3b 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -3,7 +3,7 @@
load("//:bazlets.bzl", "load_bazlets")
load_bazlets(
- commit = "9af263722b7eafe99af079d6ef7cf1de23e6f8d7",
+ commit = "fff6f20bb2eceaf872a8acf8ad51471c25a82d38",
#local_path = "/home/<user>/projects/bazlets",
)
diff --git a/external_plugin_deps.bzl b/external_plugin_deps.bzl
index 2aecc68..12bf919 100644
--- a/external_plugin_deps.bzl
+++ b/external_plugin_deps.bzl
@@ -3,8 +3,8 @@
def external_plugin_deps():
maven_jar(
name = "wiremock",
- artifact = "com.github.tomakehurst:wiremock-standalone:2.25.1",
- sha1 = "bf46d41a76c274522a8b88eb5b054edca630b089",
+ artifact = "com.github.tomakehurst:wiremock-standalone:2.26.3",
+ sha1 = "245c6efae2cbcb4e4f3457caf3d1c030cbaf2eb5",
)
maven_jar(
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java
index edd96d7..58a21b6 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java
@@ -21,6 +21,7 @@
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
+import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gerrit.server.config.ConfigUtil;
@@ -39,12 +40,10 @@
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.eclipse.jgit.lib.Config;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
@Singleton
public class Configuration {
- private static final Logger log = LoggerFactory.getLogger(Configuration.class);
+ private static final FluentLogger log = FluentLogger.forEnclosingClass();
// common parameter to peerInfo section
static final String PEER_INFO_SECTION = "peerInfo";
@@ -153,8 +152,8 @@
try {
return cfg.getInt(section, name, defaultValue);
} catch (IllegalArgumentException e) {
- log.error("invalid value for {}; using default value {}", name, defaultValue);
- log.debug("Failed to retrieve integer value: {}", e.getMessage(), e);
+ log.atSevere().log("invalid value for %s; using default value %d", name, defaultValue);
+ log.atFine().withCause(e).log("Failed to retrieve integer value");
return defaultValue;
}
}
@@ -234,9 +233,7 @@
private PeerInfo(Config cfg) {
strategy = cfg.getEnum(PEER_INFO_SECTION, null, STRATEGY_KEY, DEFAULT_PEER_INFO_STRATEGY);
- if (log.isDebugEnabled()) {
- log.debug("Strategy: {}", strategy.name());
- }
+ log.atFine().log("Strategy: %s", strategy.name());
}
public PeerInfoStrategy strategy() {
@@ -257,7 +254,7 @@
.filter(s -> !s.isEmpty())
.map(s -> CharMatcher.is('/').trimTrailingFrom(s))
.collect(Collectors.toSet());
- log.debug("Urls: {}", urls);
+ log.atFine().log("Urls: %s", urls);
}
public Set<String> urls() {
@@ -273,7 +270,7 @@
private PeerInfoJGroups(Config cfg) {
myUrl = trimTrailingSlash(cfg.getString(PEER_INFO_SECTION, JGROUPS_SUBSECTION, MY_URL_KEY));
- log.debug("My Url: {}", myUrl);
+ log.atFine().log("My Url: %s", myUrl);
}
public String myUrl() {
@@ -302,12 +299,12 @@
private JGroups(SitePaths site, Config cfg) {
String[] skip = cfg.getStringList(JGROUPS_SECTION, null, SKIP_INTERFACE_KEY);
skipInterface = skip.length == 0 ? DEFAULT_SKIP_INTERFACE_LIST : ImmutableList.copyOf(skip);
- log.debug("Skip interface(s): {}", skipInterface);
+ log.atFine().log("Skip interface(s): %s", skipInterface);
clusterName = getString(cfg, JGROUPS_SECTION, null, CLUSTER_NAME_KEY, DEFAULT_CLUSTER_NAME);
- log.debug("Cluster name: {}", clusterName);
+ log.atFine().log("Cluster name: %s", clusterName);
protocolStack = getProtocolStack(cfg, site);
- log.debug(
- "Protocol stack config {}",
+ log.atFine().log(
+ "Protocol stack config %s",
protocolStack.isPresent() ? protocolStack.get() : "not configured, using default stack.");
}
@@ -405,8 +402,8 @@
try {
return cfg.getBoolean(section, name, defaultValue);
} catch (IllegalArgumentException e) {
- log.error("invalid value for {}; using default value {}", name, defaultValue);
- log.debug("Failed to retrieve boolean value: {}", e.getMessage(), e);
+ log.atSevere().log("invalid value for %s; using default value %s", name, defaultValue);
+ log.atFine().withCause(e).log("Failed to retrieve boolean value");
return defaultValue;
}
}
@@ -450,12 +447,14 @@
static final String INDEX_SECTION = "index";
static final String MAX_TRIES_KEY = "maxTries";
static final String RETRY_INTERVAL_KEY = "retryInterval";
+ static final String SYNCHRONIZE_FORCED_KEY = "synchronizeForced";
+ static final boolean DEFAULT_SYNCHRONIZE_FORCED = true;
private final int threadPoolSize;
private final int retryInterval;
private final int maxTries;
-
private final int numStripedLocks;
+ private final boolean synchronizeForced;
private Index(Config cfg) {
super(cfg, INDEX_SECTION);
@@ -463,6 +462,8 @@
numStripedLocks = getInt(cfg, INDEX_SECTION, NUM_STRIPED_LOCKS, DEFAULT_NUM_STRIPED_LOCKS);
retryInterval = getInt(cfg, INDEX_SECTION, RETRY_INTERVAL_KEY, DEFAULT_INDEX_RETRY_INTERVAL);
maxTries = getInt(cfg, INDEX_SECTION, MAX_TRIES_KEY, DEFAULT_INDEX_MAX_TRIES);
+ synchronizeForced =
+ cfg.getBoolean(INDEX_SECTION, SYNCHRONIZE_FORCED_KEY, DEFAULT_SYNCHRONIZE_FORCED);
}
public int threadPoolSize() {
@@ -480,6 +481,10 @@
public int maxTries() {
return maxTries;
}
+
+ public boolean synchronizeForced() {
+ return synchronizeForced;
+ }
}
public static class Websession extends Forwarding {
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Setup.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Setup.java
index 165b0dd..6635b80 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Setup.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Setup.java
@@ -105,9 +105,11 @@
ui.message("\n");
ui.header("%s Plugin", pluginName);
- if (ui.yesno(true, "Configure %s", pluginName)) {
+ Path pluginConfigFile = site.etc_dir.resolve(pluginName + ".config");
+ boolean autoConfigure = !pluginConfigFile.toFile().exists();
+
+ if (ui.yesno(autoConfigure, "Configure %s", pluginName)) {
ui.header("Configuring %s", pluginName);
- Path pluginConfigFile = site.etc_dir.resolve(pluginName + ".config");
config = new FileBasedConfig(pluginConfigFile.toFile(), FS.DETECTED);
config.load();
configureAutoReindexSection();
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/AccountReindexRunnable.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/AccountReindexRunnable.java
index 487f3da..de156a2 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/AccountReindexRunnable.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/AccountReindexRunnable.java
@@ -17,8 +17,10 @@
import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwardedIndexAccountHandler;
import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwardedIndexingHandler.Operation;
import com.ericsson.gerrit.plugins.highavailability.forwarder.rest.AbstractIndexRestApiServlet;
+import com.google.common.flogger.FluentLogger;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.account.Accounts;
import com.google.gerrit.server.util.OneOffRequestContext;
import com.google.gwtorm.server.OrmException;
@@ -26,11 +28,9 @@
import java.io.IOException;
import java.sql.Timestamp;
import java.util.Optional;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-public class AccountReindexRunnable extends ReindexRunnable<Account> {
- private static final Logger log = LoggerFactory.getLogger(AccountReindexRunnable.class);
+public class AccountReindexRunnable extends ReindexRunnable<AccountState> {
+ private static final FluentLogger log = FluentLogger.forEnclosingClass();
private final ForwardedIndexAccountHandler accountIdx;
@@ -48,21 +48,23 @@
}
@Override
- protected Iterable<Account> fetchItems(ReviewDb db) throws Exception {
+ protected Iterable<AccountState> fetchItems(ReviewDb db) throws Exception {
return accounts.all();
}
@Override
- protected Optional<Timestamp> indexIfNeeded(ReviewDb db, Account a, Timestamp sinceTs) {
+ protected Optional<Timestamp> indexIfNeeded(ReviewDb db, AccountState as, Timestamp sinceTs) {
try {
+ Account a = as.getAccount();
Timestamp accountTs = a.getRegisteredOn();
if (accountTs.after(sinceTs)) {
- log.info("Index {}/{}/{}/{}", a.getId(), a.getFullName(), a.getPreferredEmail(), accountTs);
+ log.atInfo().log(
+ "Index %s/%s/%s/%s", a.getId(), a.getFullName(), a.getPreferredEmail(), accountTs);
accountIdx.index(a.getId(), Operation.INDEX, Optional.empty());
return Optional.of(accountTs);
}
} catch (IOException | OrmException e) {
- log.error("Reindex failed", e);
+ log.atSevere().withCause(e).log("Reindex failed");
}
return Optional.empty();
}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/AutoReindexScheduler.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/AutoReindexScheduler.java
index c0d90d1..ef7ae86 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/AutoReindexScheduler.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/AutoReindexScheduler.java
@@ -15,6 +15,7 @@
package com.ericsson.gerrit.plugins.highavailability.autoreindex;
import com.ericsson.gerrit.plugins.highavailability.Configuration;
+import com.google.common.flogger.FluentLogger;
import com.google.gerrit.extensions.events.LifecycleListener;
import com.google.gerrit.server.git.WorkQueue;
import com.google.inject.Inject;
@@ -24,16 +25,15 @@
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
@Singleton
public class AutoReindexScheduler implements LifecycleListener {
- private static final Logger log = LoggerFactory.getLogger(AutoReindexScheduler.class);
+ private static final FluentLogger log = FluentLogger.forEnclosingClass();
private final Configuration.AutoReindex cfg;
private final ChangeReindexRunnable changeReindex;
private final AccountReindexRunnable accountReindex;
private final GroupReindexRunnable groupReindex;
+ private final ProjectReindexRunnable projectReindex;
private final ScheduledExecutorService executor;
private final List<Future<?>> futureTasks = new ArrayList<>();
@@ -43,18 +43,21 @@
WorkQueue workQueue,
ChangeReindexRunnable changeReindex,
AccountReindexRunnable accountReindex,
- GroupReindexRunnable groupReindex) {
+ GroupReindexRunnable groupReindex,
+ ProjectReindexRunnable projectReindex) {
this.cfg = cfg.autoReindex();
this.changeReindex = changeReindex;
this.accountReindex = accountReindex;
this.groupReindex = groupReindex;
+ this.projectReindex = projectReindex;
this.executor = workQueue.createQueue(1, "HighAvailability-AutoReindex");
}
@Override
public void start() {
if (cfg.pollSec() > 0) {
- log.info("Scheduling auto-reindex after {}s and every {}s", cfg.delaySec(), cfg.pollSec());
+ log.atInfo().log(
+ "Scheduling auto-reindex after %ds and every %ds", cfg.delaySec(), cfg.pollSec());
futureTasks.add(
executor.scheduleAtFixedRate(
changeReindex, cfg.delaySec(), cfg.pollSec(), TimeUnit.SECONDS));
@@ -64,11 +67,15 @@
futureTasks.add(
executor.scheduleAtFixedRate(
groupReindex, cfg.delaySec(), cfg.pollSec(), TimeUnit.SECONDS));
+ futureTasks.add(
+ executor.scheduleAtFixedRate(
+ projectReindex, cfg.delaySec(), cfg.pollSec(), TimeUnit.SECONDS));
} else {
- log.info("Scheduling auto-reindex after {}s", cfg.delaySec());
+ log.atInfo().log("Scheduling auto-reindex after %ds", cfg.delaySec());
futureTasks.add(executor.schedule(changeReindex, cfg.delaySec(), TimeUnit.SECONDS));
futureTasks.add(executor.schedule(accountReindex, cfg.delaySec(), TimeUnit.SECONDS));
futureTasks.add(executor.schedule(groupReindex, cfg.delaySec(), TimeUnit.SECONDS));
+ futureTasks.add(executor.schedule(projectReindex, cfg.delaySec(), TimeUnit.SECONDS));
}
}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/ChangeReindexRunnable.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/ChangeReindexRunnable.java
index 1f5b56e..67c8325 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/ChangeReindexRunnable.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/ChangeReindexRunnable.java
@@ -18,6 +18,7 @@
import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwardedIndexingHandler.Operation;
import com.ericsson.gerrit.plugins.highavailability.forwarder.rest.AbstractIndexRestApiServlet;
import com.google.common.collect.Streams;
+import com.google.common.flogger.FluentLogger;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.server.ReviewDb;
@@ -34,11 +35,9 @@
import java.util.Optional;
import java.util.stream.Stream;
import org.eclipse.jgit.lib.Repository;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
public class ChangeReindexRunnable extends ReindexRunnable<Change> {
- private static final Logger log = LoggerFactory.getLogger(ChangeReindexRunnable.class);
+ private static final FluentLogger log = FluentLogger.forEnclosingClass();
private final ForwardedIndexChangeHandler changeIdx;
@@ -98,13 +97,13 @@
try {
Timestamp changeTs = c.getLastUpdatedOn();
if (changeTs.after(sinceTs)) {
- log.info(
- "Index {}/{}/{} was updated after {}", c.getProject(), c.getId(), changeTs, sinceTs);
+ log.atInfo().log(
+ "Index %s/%s/%s was updated after %s", c.getProject(), c.getId(), changeTs, sinceTs);
changeIdx.index(c.getProject() + "~" + c.getId(), Operation.INDEX, Optional.empty());
return Optional.of(changeTs);
}
} catch (OrmException | IOException e) {
- log.error("Reindex failed", e);
+ log.atSevere().withCause(e).log("Reindex failed");
}
return Optional.empty();
}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/GroupReindexRunnable.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/GroupReindexRunnable.java
index 640457d..71a0280 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/GroupReindexRunnable.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/GroupReindexRunnable.java
@@ -14,74 +14,32 @@
package com.ericsson.gerrit.plugins.highavailability.autoreindex;
-import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwardedIndexGroupHandler;
-import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwardedIndexingHandler.Operation;
import com.ericsson.gerrit.plugins.highavailability.forwarder.rest.AbstractIndexRestApiServlet;
-import com.google.common.collect.Streams;
-import com.google.gerrit.reviewdb.client.AccountGroup;
-import com.google.gerrit.reviewdb.client.AccountGroup.Id;
-import com.google.gerrit.reviewdb.client.AccountGroupByIdAud;
-import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit;
+import com.google.gerrit.common.data.GroupReference;
import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.group.db.Groups;
import com.google.gerrit.server.util.OneOffRequestContext;
-import com.google.gwtorm.server.OrmException;
-import com.google.gwtorm.server.ResultSet;
import com.google.inject.Inject;
-import java.io.IOException;
import java.sql.Timestamp;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Objects;
import java.util.Optional;
-import java.util.stream.Stream;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-public class GroupReindexRunnable extends ReindexRunnable<AccountGroup> {
- private static final Logger log = LoggerFactory.getLogger(GroupReindexRunnable.class);
+public class GroupReindexRunnable extends ReindexRunnable<GroupReference> {
- private final ForwardedIndexGroupHandler indexer;
+ private final Groups groups;
@Inject
- public GroupReindexRunnable(
- ForwardedIndexGroupHandler indexer, IndexTs indexTs, OneOffRequestContext ctx) {
+ public GroupReindexRunnable(IndexTs indexTs, OneOffRequestContext ctx, Groups groups) {
super(AbstractIndexRestApiServlet.IndexName.GROUP, indexTs, ctx);
- this.indexer = indexer;
+ this.groups = groups;
}
@Override
- protected ResultSet<AccountGroup> fetchItems(ReviewDb db) throws OrmException {
- return db.accountGroups().all();
+ protected Iterable<GroupReference> fetchItems(ReviewDb db) throws Exception {
+ return groups.getAllGroupReferences()::iterator;
}
@Override
- protected Optional<Timestamp> indexIfNeeded(ReviewDb db, AccountGroup g, Timestamp sinceTs) {
- try {
- Id groupId = g.getId();
- Stream<Timestamp> groupIdAudTs =
- db.accountGroupByIdAud().byGroup(g.getId()).toList().stream()
- .map(AccountGroupByIdAud::getRemovedOn)
- .filter(Objects::nonNull);
- List<AccountGroupMemberAudit> groupMembersAud =
- db.accountGroupMembersAudit().byGroup(groupId).toList();
- Stream<Timestamp> groupMemberAudAddedTs =
- groupMembersAud.stream().map(ga -> ga.getKey().getAddedOn()).filter(Objects::nonNull);
- Stream<Timestamp> groupMemberAudRemovedTs =
- groupMembersAud.stream()
- .map(AccountGroupMemberAudit::getRemovedOn)
- .filter(Objects::nonNull);
- Optional<Timestamp> groupLastTs =
- Streams.concat(groupIdAudTs, groupMemberAudAddedTs, groupMemberAudRemovedTs)
- .max(Comparator.naturalOrder());
-
- if (groupLastTs.isPresent() && groupLastTs.get().after(sinceTs)) {
- log.info("Index {}/{}/{}", g.getGroupUUID(), g.getName(), groupLastTs.get());
- indexer.index(g.getGroupUUID(), Operation.INDEX, Optional.empty());
- return groupLastTs;
- }
- } catch (OrmException | IOException e) {
- log.error("Reindex failed", e);
- }
+ protected Optional<Timestamp> indexIfNeeded(ReviewDb db, GroupReference g, Timestamp sinceTs) {
return Optional.empty();
}
}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/IndexTs.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/IndexTs.java
index 952fcd1..0e0602a 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/IndexTs.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/IndexTs.java
@@ -16,12 +16,15 @@
import com.ericsson.gerrit.plugins.highavailability.forwarder.rest.AbstractIndexRestApiServlet;
import com.ericsson.gerrit.plugins.highavailability.forwarder.rest.AbstractIndexRestApiServlet.IndexName;
+import com.ericsson.gerrit.plugins.highavailability.index.CurrentRequestContext;
+import com.google.common.flogger.FluentLogger;
import com.google.gerrit.extensions.annotations.PluginData;
import com.google.gerrit.extensions.events.AccountIndexedListener;
import com.google.gerrit.extensions.events.ChangeIndexedListener;
import com.google.gerrit.extensions.events.GroupIndexedListener;
+import com.google.gerrit.extensions.events.ProjectIndexedListener;
import com.google.gerrit.reviewdb.server.ReviewDb;
-import com.google.gerrit.server.ChangeFinder;
+import com.google.gerrit.server.change.ChangeFinder;
import com.google.gerrit.server.git.WorkQueue;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gwtorm.server.SchemaFactory;
@@ -35,13 +38,14 @@
import java.time.format.DateTimeFormatter;
import java.util.Optional;
import java.util.concurrent.ScheduledExecutorService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
@Singleton
public class IndexTs
- implements ChangeIndexedListener, AccountIndexedListener, GroupIndexedListener {
- private static final Logger log = LoggerFactory.getLogger(IndexTs.class);
+ implements ChangeIndexedListener,
+ AccountIndexedListener,
+ GroupIndexedListener,
+ ProjectIndexedListener {
+ private static final FluentLogger log = FluentLogger.forEnclosingClass();
private static final DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME;
private final Path dataDir;
@@ -49,10 +53,12 @@
private final FlusherRunner flusher;
private final SchemaFactory<ReviewDb> schemaFactory;
private final ChangeFinder changeFinder;
+ private final CurrentRequestContext currCtx;
private volatile LocalDateTime changeTs;
private volatile LocalDateTime accountTs;
private volatile LocalDateTime groupTs;
+ private volatile LocalDateTime projectTs;
class FlusherRunner implements Runnable {
@@ -61,6 +67,7 @@
store(AbstractIndexRestApiServlet.IndexName.CHANGE, changeTs);
store(AbstractIndexRestApiServlet.IndexName.ACCOUNT, accountTs);
store(AbstractIndexRestApiServlet.IndexName.GROUP, groupTs);
+ store(AbstractIndexRestApiServlet.IndexName.PROJECT, projectTs);
}
private void store(AbstractIndexRestApiServlet.IndexName index, LocalDateTime latestTs) {
@@ -70,7 +77,7 @@
try {
Files.write(indexTsFile, latestTs.format(formatter).getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
- log.error("Unable to update last timestamp for index {}", index, e);
+ log.atSevere().withCause(e).log("Unable to update last timestamp for index %s", index);
}
}
}
@@ -81,41 +88,51 @@
@PluginData Path dataDir,
WorkQueue queue,
SchemaFactory<ReviewDb> schemaFactory,
- ChangeFinder changeFinder) {
+ ChangeFinder changeFinder,
+ CurrentRequestContext currCtx) {
this.dataDir = dataDir;
this.exec = queue.getDefaultQueue();
this.flusher = new FlusherRunner();
this.schemaFactory = schemaFactory;
this.changeFinder = changeFinder;
+ this.currCtx = currCtx;
+ }
+
+ @Override
+ public void onProjectIndexed(String project) {
+ currCtx.onlyWithContext((ctx) -> update(IndexName.PROJECT, LocalDateTime.now()));
}
@Override
public void onGroupIndexed(String uuid) {
- update(IndexName.GROUP, LocalDateTime.now());
+ currCtx.onlyWithContext((ctx) -> update(IndexName.GROUP, LocalDateTime.now()));
}
@Override
public void onAccountIndexed(int id) {
- update(IndexName.ACCOUNT, LocalDateTime.now());
+ currCtx.onlyWithContext((ctx) -> update(IndexName.ACCOUNT, LocalDateTime.now()));
}
@Override
public void onChangeIndexed(String projectName, int id) {
- try (ReviewDb db = schemaFactory.open()) {
- ChangeNotes changeNotes = changeFinder.findOne(projectName + "~" + id);
- update(
- IndexName.CHANGE,
- changeNotes == null
- ? LocalDateTime.now()
- : changeNotes.getChange().getLastUpdatedOn().toLocalDateTime());
- } catch (Exception e) {
- log.warn("Unable to update the latest TS for change {}", id, e);
- }
+ currCtx.onlyWithContext(
+ (ctx) -> {
+ try (ReviewDb db = schemaFactory.open()) {
+ ChangeNotes changeNotes = changeFinder.findOne(projectName + "~" + id);
+ update(
+ IndexName.CHANGE,
+ changeNotes == null
+ ? LocalDateTime.now()
+ : changeNotes.getChange().getLastUpdatedOn().toLocalDateTime());
+ } catch (Exception e) {
+ log.atWarning().withCause(e).log("Unable to update the latest TS for change %d", id);
+ }
+ });
}
@Override
public void onChangeDeleted(int id) {
- update(IndexName.CHANGE, LocalDateTime.now());
+ currCtx.onlyWithContext((ctx) -> update(IndexName.CHANGE, LocalDateTime.now()));
}
public Optional<LocalDateTime> getUpdateTs(AbstractIndexRestApiServlet.IndexName index) {
@@ -126,7 +143,7 @@
return Optional.of(LocalDateTime.parse(tsString, formatter));
}
} catch (Exception e) {
- log.warn("Unable to read last timestamp for index {}", index, e);
+ log.atWarning().withCause(e).log("Unable to read last timestamp for index %s", index);
}
return Optional.empty();
}
@@ -142,6 +159,9 @@
case GROUP:
groupTs = dateTime;
break;
+ case PROJECT:
+ projectTs = dateTime;
+ break;
default:
throw new IllegalArgumentException("Unsupported index " + index);
}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/ProjectReindexRunnable.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/ProjectReindexRunnable.java
new file mode 100644
index 0000000..582227d
--- /dev/null
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/ProjectReindexRunnable.java
@@ -0,0 +1,46 @@
+// Copyright (C) 2018 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.ericsson.gerrit.plugins.highavailability.autoreindex;
+
+import com.ericsson.gerrit.plugins.highavailability.forwarder.rest.AbstractIndexRestApiServlet;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.project.ProjectCache;
+import com.google.gerrit.server.util.OneOffRequestContext;
+import com.google.inject.Inject;
+import java.sql.Timestamp;
+import java.util.Optional;
+
+public class ProjectReindexRunnable extends ReindexRunnable<Project.NameKey> {
+
+ private final ProjectCache projectCache;
+
+ @Inject
+ public ProjectReindexRunnable(
+ IndexTs indexTs, OneOffRequestContext ctx, ProjectCache projectCache) {
+ super(AbstractIndexRestApiServlet.IndexName.PROJECT, indexTs, ctx);
+ this.projectCache = projectCache;
+ }
+
+ @Override
+ protected Iterable<Project.NameKey> fetchItems(ReviewDb db) {
+ return projectCache.all();
+ }
+
+ @Override
+ protected Optional<Timestamp> indexIfNeeded(ReviewDb db, Project.NameKey g, Timestamp sinceTs) {
+ return Optional.empty();
+ }
+}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/ReindexRunnable.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/ReindexRunnable.java
index df3a0fd..7a5669e 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/ReindexRunnable.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/ReindexRunnable.java
@@ -16,6 +16,7 @@
import com.ericsson.gerrit.plugins.highavailability.forwarder.rest.AbstractIndexRestApiServlet;
import com.google.common.base.Stopwatch;
+import com.google.common.flogger.FluentLogger;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.util.ManualRequestContext;
import com.google.gerrit.server.util.OneOffRequestContext;
@@ -24,11 +25,9 @@
import java.time.LocalDateTime;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
abstract class ReindexRunnable<T> implements Runnable {
- private static final Logger log = LoggerFactory.getLogger(ReindexRunnable.class);
+ private static final FluentLogger log = FluentLogger.forEnclosingClass();
private final AbstractIndexRestApiServlet.IndexName itemName;
private final OneOffRequestContext ctx;
@@ -49,7 +48,7 @@
String itemNameString = itemName.name().toLowerCase();
if (maybeIndexTs.isPresent()) {
newLastIndexTs = maxTimestamp(newLastIndexTs, Timestamp.valueOf(maybeIndexTs.get()));
- log.debug("Scanning for all the {}s after {}", itemNameString, newLastIndexTs);
+ log.atFine().log("Scanning for all the %ss after %s", itemNameString, newLastIndexTs);
try (ManualRequestContext mctx = ctx.open();
ReviewDb db = mctx.getReviewDbProvider().get()) {
int count = 0;
@@ -63,27 +62,27 @@
newLastIndexTs = maxTimestamp(newLastIndexTs, itemTs.get());
}
} catch (Exception e) {
- log.error("Unable to reindex {} {}", itemNameString, c, e);
+ log.atSevere().withCause(e).log("Unable to reindex %s %s", itemNameString, c);
errors++;
}
}
long elapsedNanos = stopwatch.stop().elapsed(TimeUnit.NANOSECONDS);
if (count > 0) {
- log.info(
- "{} {}s reindexed in {} msec ({}/sec), {} failed",
+ log.atInfo().log(
+ "%d %ss reindexed in %d msec (%d/sec), %d failed",
count,
itemNameString,
elapsedNanos / 1000000L,
(count * 1000L) / (elapsedNanos / 1000000L),
errors);
} else if (errors > 0) {
- log.info("{} {}s failed to reindex", errors, itemNameString);
+ log.atInfo().log("%d %ss failed to reindex", errors, itemNameString);
} else {
- log.debug("Scanning finished");
+ log.atFine().log("Scanning finished");
}
indexTs.update(itemName, newLastIndexTs.toLocalDateTime());
} catch (Exception e) {
- log.error("Unable to scan " + itemNameString + "s", e);
+ log.atSevere().withCause(e).log("Unable to scan %ss", itemNameString);
}
}
}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/event/EventHandler.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/event/EventHandler.java
index f42d115..025115c 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/event/EventHandler.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/event/EventHandler.java
@@ -16,9 +16,9 @@
import com.ericsson.gerrit.plugins.highavailability.forwarder.Context;
import com.ericsson.gerrit.plugins.highavailability.forwarder.Forwarder;
-import com.google.gerrit.common.EventListener;
import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gerrit.server.events.Event;
+import com.google.gerrit.server.events.EventListener;
import com.google.gerrit.server.events.ProjectEvent;
import com.google.inject.Inject;
import java.util.concurrent.Executor;
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/event/EventModule.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/event/EventModule.java
index a848c20..28a9e8e 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/event/EventModule.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/event/EventModule.java
@@ -14,9 +14,9 @@
package com.ericsson.gerrit.plugins.highavailability.event;
-import com.google.gerrit.common.EventListener;
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.lifecycle.LifecycleModule;
+import com.google.gerrit.server.events.EventListener;
import java.util.concurrent.Executor;
public class EventModule extends LifecycleModule {
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedAwareEventBroker.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedAwareEventBroker.java
index b3696fb..3d9fd60 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedAwareEventBroker.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedAwareEventBroker.java
@@ -14,14 +14,14 @@
package com.ericsson.gerrit.plugins.highavailability.forwarder;
-import com.google.gerrit.common.EventBroker;
-import com.google.gerrit.common.EventListener;
-import com.google.gerrit.common.UserScopedEventListener;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.events.Event;
+import com.google.gerrit.server.events.EventBroker;
+import com.google.gerrit.server.events.EventListener;
+import com.google.gerrit.server.events.UserScopedEventListener;
import com.google.gerrit.server.notedb.ChangeNotes.Factory;
import com.google.gerrit.server.permissions.PermissionBackend;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gerrit.server.project.ProjectCache;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -30,8 +30,8 @@
@Inject
ForwardedAwareEventBroker(
- DynamicSet<UserScopedEventListener> listeners,
- DynamicSet<EventListener> unrestrictedListeners,
+ PluginSetContext<UserScopedEventListener> listeners,
+ PluginSetContext<EventListener> unrestrictedListeners,
PermissionBackend permissionBackend,
ProjectCache projectCache,
Factory notesFactory,
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedCacheEvictionHandler.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedCacheEvictionHandler.java
index c4c2219..27531b0 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedCacheEvictionHandler.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedCacheEvictionHandler.java
@@ -16,11 +16,10 @@
import com.ericsson.gerrit.plugins.highavailability.cache.Constants;
import com.google.common.cache.Cache;
+import com.google.common.flogger.FluentLogger;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.inject.Inject;
import com.google.inject.Singleton;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* Evict cache entries. This class is meant to be used on the receiving side of the {@link
@@ -29,7 +28,7 @@
*/
@Singleton
public class ForwardedCacheEvictionHandler {
- private static final Logger log = LoggerFactory.getLogger(ForwardedCacheEvictionHandler.class);
+ private static final FluentLogger log = FluentLogger.forEnclosingClass();
private final DynamicMap<Cache<?, ?>> cacheMap;
@@ -55,10 +54,10 @@
if (Constants.PROJECT_LIST.equals(entry.getCacheName())) {
// One key is holding the list of projects
cache.invalidateAll();
- log.debug("Invalidated cache {}", entry.getCacheName());
+ log.atFine().log("Invalidated cache %s", entry.getCacheName());
} else {
cache.invalidate(entry.getKey());
- log.debug("Invalidated cache {}[{}]", entry.getCacheName(), entry.getKey());
+ log.atFine().log("Invalidated cache %s[%s]", entry.getCacheName(), entry.getKey());
}
} finally {
Context.unsetForwardedEvent();
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedEventHandler.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedEventHandler.java
index 4e01abf..51db006 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedEventHandler.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedEventHandler.java
@@ -14,14 +14,13 @@
package com.ericsson.gerrit.plugins.highavailability.forwarder;
-import com.google.gerrit.common.EventDispatcher;
+import com.google.common.flogger.FluentLogger;
import com.google.gerrit.server.events.Event;
+import com.google.gerrit.server.events.EventDispatcher;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* Dispatch event to the {@link EventDispatcher}. This class is meant to be used on the receiving
@@ -30,7 +29,7 @@
*/
@Singleton
public class ForwardedEventHandler {
- private static final Logger log = LoggerFactory.getLogger(ForwardedEventHandler.class);
+ private static final FluentLogger log = FluentLogger.forEnclosingClass();
private final EventDispatcher dispatcher;
@@ -48,7 +47,7 @@
public void dispatch(Event event) throws OrmException, PermissionBackendException {
try {
Context.setForwardedEvent(true);
- log.debug("dispatching event {}", event.getType());
+ log.atFine().log("dispatching event %s", event.getType());
dispatcher.postEvent(event);
} finally {
Context.unsetForwardedEvent();
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexAccountHandler.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexAccountHandler.java
index 649ffc8..ba60830 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexAccountHandler.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexAccountHandler.java
@@ -41,7 +41,7 @@
@Override
protected void doIndex(Account.Id id, Optional<IndexEvent> indexEvent) throws IOException {
indexer.index(id);
- log.debug("Account {} successfully indexed", id);
+ log.atFine().log("Account %s successfully indexed", id);
}
@Override
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexChangeHandler.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexChangeHandler.java
index d34959c..d7c7e88 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexChangeHandler.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexChangeHandler.java
@@ -89,29 +89,31 @@
if (checker.isChangeUpToDate(indexEvent)) {
if (retryCount > 0) {
- log.warn("Change {} has been eventually indexed after {} attempt(s)", id, retryCount);
+ log.atWarning().log(
+ "Change %s has been eventually indexed after %d attempt(s)", id, retryCount);
} else {
- log.debug("Change {} successfully indexed", id);
+ log.atFine().log("Change %s successfully indexed", id);
}
} else {
- log.warn(
- "Change {} seems too old compared to the event timestamp (event-Ts={} >> change-Ts={})",
- id,
- indexEvent,
- checker);
+ log.atWarning().log(
+ "Change %s seems too old compared to the event timestamp (event-Ts=%s >> change-Ts=%s)",
+ id, indexEvent, checker);
rescheduleIndex(id, indexEvent, retryCount + 1);
}
} else {
- indexer.delete(parseChangeId(id));
- log.warn(
- "Change {} could not be found in the local Git repository (eventTs={}), deleted from index",
- id,
- indexEvent);
+ log.atWarning().log(
+ "Change %s not present yet in local Git repository (event=%s) after %d attempt(s)",
+ id, indexEvent, retryCount);
+ if (!rescheduleIndex(id, indexEvent, retryCount + 1)) {
+ log.atSevere().log(
+ "Change %s could not be found in the local Git repository (event=%s)",
+ id, indexEvent);
+ }
}
} catch (Exception e) {
if (isCausedByNoSuchChangeException(e)) {
indexer.delete(parseChangeId(id));
- log.warn("Error trying to index Change {}. Deleted from index", id, e);
+ log.atWarning().withCause(e).log("Error trying to index Change %s. Deleted from index", id);
return;
}
@@ -126,37 +128,35 @@
}
}
- private void rescheduleIndex(String id, Optional<IndexEvent> indexEvent, int retryCount) {
+ private boolean rescheduleIndex(String id, Optional<IndexEvent> indexEvent, int retryCount) {
if (retryCount > maxTries) {
- log.error(
- "Change {} could not be indexed after {} retries. Change index could be stale.",
- id,
- retryCount);
- return;
+ log.atSevere().log(
+ "Change %s could not be indexed after %d retries. Change index could be stale.",
+ id, retryCount);
+ return false;
}
- log.warn(
- "Retrying for the #{} time to index Change {} after {} msecs",
- retryCount,
- id,
- retryInterval);
+ log.atWarning().log(
+ "Retrying for the #%d time to index Change %s after %d msecs",
+ retryCount, id, retryInterval);
indexExecutor.schedule(
() -> {
try (ManualRequestContext ctx = oneOffCtx.open()) {
Context.setForwardedEvent(true);
doIndex(id, indexEvent, retryCount);
} catch (Exception e) {
- log.warn("Change {} could not be indexed", id, e);
+ log.atWarning().withCause(e).log("Change %s could not be indexed", id);
}
},
retryInterval,
TimeUnit.MILLISECONDS);
+ return true;
}
@Override
protected void doDelete(String id, Optional<IndexEvent> indexEvent) throws IOException {
indexer.delete(parseChangeId(id));
- log.debug("Change {} successfully deleted from index", id);
+ log.atFine().log("Change %s successfully deleted from index", id);
}
private static Change.Id parseChangeId(String id) {
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexGroupHandler.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexGroupHandler.java
index 7c6d723..fb4d2f2 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexGroupHandler.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexGroupHandler.java
@@ -42,7 +42,7 @@
protected void doIndex(AccountGroup.UUID uuid, Optional<IndexEvent> indexEvent)
throws IOException {
indexer.index(uuid);
- log.debug("Group {} successfully indexed", uuid);
+ log.atFine().log("Group %s successfully indexed", uuid);
}
@Override
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexProjectHandler.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexProjectHandler.java
new file mode 100644
index 0000000..5ae4cc0
--- /dev/null
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexProjectHandler.java
@@ -0,0 +1,52 @@
+// Copyright (C) 2018 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.ericsson.gerrit.plugins.highavailability.forwarder;
+
+import com.ericsson.gerrit.plugins.highavailability.Configuration;
+import com.google.gerrit.index.project.ProjectIndexer;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import java.io.IOException;
+import java.util.Optional;
+
+/**
+ * Index a project using {@link ProjectIndexer}. This class is meant to be used on the receiving
+ * side of the {@link Forwarder} since it will prevent indexed project to be forwarded again causing
+ * an infinite forwarding loop between the 2 nodes. It will also make sure no concurrent indexing is
+ * done for the same project name.
+ */
+@Singleton
+public class ForwardedIndexProjectHandler extends ForwardedIndexingHandler<Project.NameKey> {
+ private final ProjectIndexer indexer;
+
+ @Inject
+ ForwardedIndexProjectHandler(ProjectIndexer indexer, Configuration config) {
+ super(config.index());
+ this.indexer = indexer;
+ }
+
+ @Override
+ protected void doIndex(Project.NameKey projectName, Optional<IndexEvent> indexEvent)
+ throws IOException {
+ indexer.index(projectName);
+ log.atFine().log("Project %s successfully indexed", projectName);
+ }
+
+ @Override
+ protected void doDelete(Project.NameKey projectName, Optional<IndexEvent> indexEvent) {
+ throw new UnsupportedOperationException("Delete from project index not supported");
+ }
+}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexingHandler.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexingHandler.java
index bfedf3f..78e103d 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexingHandler.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexingHandler.java
@@ -15,13 +15,12 @@
package com.ericsson.gerrit.plugins.highavailability.forwarder;
import com.ericsson.gerrit.plugins.highavailability.Configuration;
+import com.google.common.flogger.FluentLogger;
import com.google.common.util.concurrent.Striped;
import com.google.gwtorm.server.OrmException;
import java.io.IOException;
import java.util.Optional;
import java.util.concurrent.locks.Lock;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* Base class to handle forwarded indexing. This class is meant to be extended by classes used on
@@ -30,7 +29,7 @@
* indexing is done for the same id.
*/
public abstract class ForwardedIndexingHandler<T> {
- protected final Logger log = LoggerFactory.getLogger(getClass());
+ protected static final FluentLogger log = FluentLogger.forEnclosingClass();
public enum Operation {
INDEX,
@@ -64,7 +63,7 @@
*/
public void index(T id, Operation operation, Optional<IndexEvent> indexEvent)
throws IOException, OrmException {
- log.debug("{} {} {}", operation, id, indexEvent);
+ log.atFine().log("%s %s %s", operation, id, indexEvent);
try {
Context.setForwardedEvent(true);
Lock idLock = idLocks.get(id);
@@ -78,7 +77,7 @@
doDelete(id, indexEvent);
break;
default:
- log.error("unexpected operation: {}", operation);
+ log.atSevere().log("unexpected operation: %s", operation);
break;
}
} finally {
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedProjectListUpdateHandler.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedProjectListUpdateHandler.java
index 93e1186..84f4675 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedProjectListUpdateHandler.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedProjectListUpdateHandler.java
@@ -14,12 +14,12 @@
package com.ericsson.gerrit.plugins.highavailability.forwarder;
+import com.google.common.flogger.FluentLogger;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.project.ProjectCache;
import com.google.inject.Inject;
import com.google.inject.Singleton;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import java.io.IOException;
/**
* Update project list cache. This class is meant to be used on the receiving side of the {@link
@@ -28,8 +28,7 @@
*/
@Singleton
public class ForwardedProjectListUpdateHandler {
- private static final Logger log =
- LoggerFactory.getLogger(ForwardedProjectListUpdateHandler.class);
+ private static final FluentLogger log = FluentLogger.forEnclosingClass();
private final ProjectCache projectCache;
@@ -43,17 +42,18 @@
*
* @param projectName the name of the project to add or remove.
* @param remove true to remove, false to add project.
+ * @throws IOException
*/
- public void update(String projectName, boolean remove) {
+ public void update(String projectName, boolean remove) throws IOException {
Project.NameKey projectKey = new Project.NameKey(projectName);
try {
Context.setForwardedEvent(true);
if (remove) {
projectCache.remove(projectKey);
- log.debug("Removed {} from project list", projectName);
+ log.atFine().log("Removed %s from project list", projectName);
} else {
projectCache.onCreateProject(projectKey);
- log.debug("Added {} to project list", projectName);
+ log.atFine().log("Added %s to project list", projectName);
}
} finally {
Context.unsetForwardedEvent();
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/Forwarder.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/Forwarder.java
index b156563..49cdc8b 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/Forwarder.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/Forwarder.java
@@ -57,6 +57,15 @@
boolean indexGroup(String uuid, IndexEvent indexEvent);
/**
+ * Forward a project indexing event to the other master.
+ *
+ * @param projectName the project to index.
+ * @param indexEvent the details of the index event.
+ * @return true if successful, otherwise false.
+ */
+ boolean indexProject(String projectName, IndexEvent indexEvent);
+
+ /**
* Forward a stream event to the other master.
*
* @param event the event to forward.
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwarderModule.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwarderModule.java
index 15fdcfd..99a820e 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwarderModule.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwarderModule.java
@@ -14,8 +14,8 @@
package com.ericsson.gerrit.plugins.highavailability.forwarder;
-import com.google.gerrit.common.EventDispatcher;
import com.google.gerrit.extensions.registration.DynamicItem;
+import com.google.gerrit.server.events.EventDispatcher;
import com.google.inject.AbstractModule;
public class ForwarderModule extends AbstractModule {
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/AbstractIndexRestApiServlet.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/AbstractIndexRestApiServlet.java
index 8c429de..410aa23 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/AbstractIndexRestApiServlet.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/AbstractIndexRestApiServlet.java
@@ -43,7 +43,8 @@
public enum IndexName {
CHANGE,
ACCOUNT,
- GROUP;
+ GROUP,
+ PROJECT;
@Override
public String toString() {
@@ -91,11 +92,11 @@
rsp.setStatus(SC_NO_CONTENT);
} catch (IOException e) {
sendError(rsp, SC_CONFLICT, e.getMessage());
- log.error("Unable to update {} index", indexName, e);
+ log.atSevere().withCause(e).log("Unable to update %s index", indexName);
} catch (OrmException e) {
String msg = String.format("Error trying to find %s", indexName);
sendError(rsp, SC_NOT_FOUND, msg);
- log.debug(msg, e);
+ log.atFine().withCause(e).log(msg);
}
}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/AbstractRestApiServlet.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/AbstractRestApiServlet.java
index 054f640..a76d8ea 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/AbstractRestApiServlet.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/AbstractRestApiServlet.java
@@ -16,15 +16,14 @@
import static java.nio.charset.StandardCharsets.UTF_8;
+import com.google.common.flogger.FluentLogger;
import java.io.IOException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletResponse;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
public abstract class AbstractRestApiServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
- protected final Logger log = LoggerFactory.getLogger(getClass());
+ protected static final FluentLogger log = FluentLogger.forEnclosingClass();
protected static void setHeaders(HttpServletResponse rsp) {
rsp.setContentType("text/plain");
@@ -35,7 +34,7 @@
try {
rsp.sendError(statusCode, message);
} catch (IOException e) {
- log.error("Failed to send error messsage: {}", e.getMessage(), e);
+ log.atSevere().withCause(e).log("Failed to send error messsage");
}
}
}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/CacheRestApiServlet.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/CacheRestApiServlet.java
index fb49cf2..60e782f 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/CacheRestApiServlet.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/CacheRestApiServlet.java
@@ -54,10 +54,10 @@
CacheEntry.from(cacheName, gson.fromJson(cacheName, json)));
rsp.setStatus(SC_NO_CONTENT);
} catch (CacheNotFoundException e) {
- log.error("Failed to process eviction request: {}", e.getMessage());
+ log.atSevere().log("Failed to process eviction request: %s", e.getMessage());
sendError(rsp, SC_BAD_REQUEST, e.getMessage());
} catch (IOException e) {
- log.error("Failed to process eviction request: {}", e.getMessage(), e);
+ log.atSevere().withCause(e).log("Failed to process eviction request");
sendError(rsp, SC_BAD_REQUEST, e.getMessage());
}
}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/EventRestApiServlet.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/EventRestApiServlet.java
index 3da5081..61b714c 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/EventRestApiServlet.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/EventRestApiServlet.java
@@ -56,10 +56,10 @@
forwardedEventHandler.dispatch(getEventFromRequest(req));
rsp.setStatus(SC_NO_CONTENT);
} catch (OrmException e) {
- log.debug("Error trying to find a change ", e);
+ log.atFine().withCause(e).log("Error trying to find a change");
sendError(rsp, SC_NOT_FOUND, "Change not found\n");
} catch (IOException | PermissionBackendException e) {
- log.error("Unable to re-trigger event", e);
+ log.atSevere().withCause(e).log("Unable to re-trigger event");
sendError(rsp, SC_BAD_REQUEST, e.getMessage());
}
}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpClientProvider.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpClientProvider.java
index 26943c2..0510aed 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpClientProvider.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpClientProvider.java
@@ -15,6 +15,7 @@
package com.ericsson.gerrit.plugins.highavailability.forwarder.rest;
import com.ericsson.gerrit.plugins.highavailability.Configuration;
+import com.google.common.flogger.FluentLogger;
import com.google.inject.Inject;
import com.google.inject.Provider;
import java.security.KeyManagementException;
@@ -37,12 +38,10 @@
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/** Provides an HTTP client with SSL capabilities. */
class HttpClientProvider implements Provider<CloseableHttpClient> {
- private static final Logger log = LoggerFactory.getLogger(HttpClientProvider.class);
+ private static final FluentLogger log = FluentLogger.forEnclosingClass();
private static final int CONNECTIONS_PER_ROUTE = 100;
// Up to 2 target instances with the max number of connections per host:
private static final int MAX_CONNECTIONS = 2 * CONNECTIONS_PER_ROUTE;
@@ -101,7 +100,7 @@
context.init(null, trustAllCerts, null);
return context;
} catch (KeyManagementException | NoSuchAlgorithmException e) {
- log.warn("Error building SSLContext object", e);
+ log.atWarning().withCause(e).log("Error building SSLContext object");
return null;
}
}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpResponseHandler.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpResponseHandler.java
index cfcd519..9a1e635 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpResponseHandler.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpResponseHandler.java
@@ -17,13 +17,12 @@
import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
import com.ericsson.gerrit.plugins.highavailability.forwarder.rest.HttpResponseHandler.HttpResult;
+import com.google.common.flogger.FluentLogger;
import java.io.IOException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ResponseHandler;
import org.apache.http.util.EntityUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
class HttpResponseHandler implements ResponseHandler<HttpResult> {
@@ -45,7 +44,7 @@
}
}
- private static final Logger log = LoggerFactory.getLogger(HttpResponseHandler.class);
+ private static final FluentLogger log = FluentLogger.forEnclosingClass();
@Override
public HttpResult handleResponse(HttpResponse response) {
@@ -63,7 +62,7 @@
try {
asString = EntityUtils.toString(entity);
} catch (IOException e) {
- log.error("Error parsing entity", e);
+ log.atSevere().withCause(e).log("Error parsing entity");
}
}
return asString;
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/IndexProjectRestApiServlet.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/IndexProjectRestApiServlet.java
new file mode 100644
index 0000000..cc87442
--- /dev/null
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/IndexProjectRestApiServlet.java
@@ -0,0 +1,36 @@
+// Copyright (C) 2018 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.ericsson.gerrit.plugins.highavailability.forwarder.rest;
+
+import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwardedIndexProjectHandler;
+import com.google.gerrit.extensions.restapi.Url;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+@Singleton
+class IndexProjectRestApiServlet extends AbstractIndexRestApiServlet<Project.NameKey> {
+ private static final long serialVersionUID = -1L;
+
+ @Inject
+ IndexProjectRestApiServlet(ForwardedIndexProjectHandler handler) {
+ super(handler, IndexName.PROJECT);
+ }
+
+ @Override
+ Project.NameKey parse(String projectName) {
+ return new Project.NameKey(Url.decode(projectName));
+ }
+}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/ProjectListApiServlet.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/ProjectListApiServlet.java
index e781a10..7a31ea0 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/ProjectListApiServlet.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/ProjectListApiServlet.java
@@ -14,12 +14,14 @@
package com.ericsson.gerrit.plugins.highavailability.forwarder.rest;
+import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwardedProjectListUpdateHandler;
import com.google.gerrit.extensions.restapi.Url;
import com.google.inject.Inject;
import com.google.inject.Singleton;
+import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -48,7 +50,12 @@
setHeaders(rsp);
String requestURI = req.getRequestURI();
String projectName = requestURI.substring(requestURI.lastIndexOf('/') + 1);
- forwardedProjectListUpdateHandler.update(Url.decode(projectName), delete);
- rsp.setStatus(SC_NO_CONTENT);
+ try {
+ forwardedProjectListUpdateHandler.update(Url.decode(projectName), delete);
+ rsp.setStatus(SC_NO_CONTENT);
+ } catch (IOException e) {
+ log.atSevere().withCause(e).log("Unable to update project list");
+ sendError(rsp, SC_BAD_REQUEST, e.getMessage());
+ }
}
}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarder.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarder.java
index ef1b26d..fb3aba9 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarder.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarder.java
@@ -21,6 +21,7 @@
import com.ericsson.gerrit.plugins.highavailability.forwarder.rest.HttpResponseHandler.HttpResult;
import com.ericsson.gerrit.plugins.highavailability.peers.PeerInfo;
import com.google.common.base.Joiner;
+import com.google.common.flogger.FluentLogger;
import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gerrit.extensions.restapi.Url;
import com.google.gerrit.server.events.Event;
@@ -34,8 +35,6 @@
import javax.net.ssl.SSLException;
import org.apache.http.HttpException;
import org.apache.http.client.ClientProtocolException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
class RestForwarder implements Forwarder {
enum RequestMethod {
@@ -43,7 +42,7 @@
DELETE
}
- private static final Logger log = LoggerFactory.getLogger(RestForwarder.class);
+ private static final FluentLogger log = FluentLogger.forEnclosingClass();
private final HttpSession httpSession;
private final String pluginRelativePath;
@@ -101,6 +100,12 @@
}
@Override
+ public boolean indexProject(String projectName, IndexEvent event) {
+ return execute(
+ RequestMethod.POST, "index project", "index/project", Url.encode(projectName), event);
+ }
+
+ @Override
public boolean send(final Event event) {
return execute(RequestMethod.POST, "send event", "event", event.type, event);
}
@@ -185,41 +190,36 @@
}
boolean execute() {
- log.debug("Executing {} {} towards {}", action, key, destination);
+ log.atFine().log("Executing %s %s towards %s", action, key, destination);
for (; ; ) {
try {
execCnt++;
tryOnce();
- log.debug("{} {} towards {} OK", action, key, destination);
+ log.atFine().log("%s %s towards %s OK", action, key, destination);
return true;
} catch (ForwardingException e) {
int maxTries = cfg.http().maxTries();
- log.debug(
- "Failed to {} {} on {} [{}/{}]", action, key, destination, execCnt, maxTries, e);
+ log.atFine().withCause(e).log(
+ "Failed to %s %s on %s [%d/%d]", action, key, destination, execCnt, maxTries);
if (!e.isRecoverable()) {
- log.error(
- "{} {} towards {} failed with unrecoverable error; giving up",
- action,
- key,
- destination,
- e);
+ log.atSevere().withCause(e).log(
+ "%s %s towards %s failed with unrecoverable error; giving up",
+ action, key, destination);
return false;
}
if (execCnt >= maxTries) {
- log.error(
- "Failed to {} {} on {} after {} tries; giving up",
- action,
- key,
- destination,
- maxTries);
+ log.atSevere().log(
+ "Failed to %s %s on %s after %d tries; giving up",
+ action, key, destination, maxTries);
return false;
}
- log.debug("Retrying to {} {} on {}", action, key, destination);
+ log.atFine().log("Retrying to %s %s on %s", action, key, destination);
try {
Thread.sleep(cfg.http().retryInterval());
} catch (InterruptedException ie) {
- log.error("{} {} towards {} was interrupted; giving up", action, key, destination, ie);
+ log.atSevere().withCause(ie).log(
+ "%s %s towards %s was interrupted; giving up", action, key, destination);
Thread.currentThread().interrupt();
return false;
}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarderServletModule.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarderServletModule.java
index 184157d..589bbef 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarderServletModule.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarderServletModule.java
@@ -22,6 +22,7 @@
serveRegex("/index/account/\\d+$").with(IndexAccountRestApiServlet.class);
serveRegex("/index/change/.*$").with(IndexChangeRestApiServlet.class);
serveRegex("/index/group/\\w+$").with(IndexGroupRestApiServlet.class);
+ serveRegex("/index/project/.*$").with(IndexProjectRestApiServlet.class);
serve("/event/*").with(EventRestApiServlet.class);
serve("/cache/project_list/*").with(ProjectListApiServlet.class);
serve("/cache/*").with(CacheRestApiServlet.class);
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/health/HealthServlet.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/health/HealthServlet.java
index 6d98d83..0f8125e 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/health/HealthServlet.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/health/HealthServlet.java
@@ -20,6 +20,7 @@
import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
import static javax.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE;
+import com.google.common.flogger.FluentLogger;
import com.google.gerrit.extensions.annotations.PluginData;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.permissions.PermissionBackend;
@@ -34,12 +35,10 @@
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
@Singleton
public class HealthServlet extends HttpServlet {
- private static final Logger log = LoggerFactory.getLogger(HealthServlet.class);
+ private static final FluentLogger log = FluentLogger.forEnclosingClass();
private static final long serialVersionUID = -1L;
private final Provider<CurrentUser> currentUserProvider;
@@ -66,7 +65,7 @@
setHealthy();
rsp.setStatus(SC_NO_CONTENT);
} catch (IOException e) {
- log.error("Failed to set healthy", e);
+ log.atSevere().withCause(e).log("Failed to set healthy");
sendError(rsp, SC_INTERNAL_SERVER_ERROR);
}
}
@@ -81,7 +80,7 @@
setUnhealthy();
rsp.setStatus(SC_NO_CONTENT);
} catch (IOException e) {
- log.error("Failed to set unhealthy", e);
+ log.atSevere().withCause(e).log("Failed to set unhealthy");
sendError(rsp, SC_INTERNAL_SERVER_ERROR);
}
}
@@ -100,7 +99,7 @@
rsp.sendError(statusCode);
} catch (IOException e) {
rsp.setStatus(SC_INTERNAL_SERVER_ERROR);
- log.error("Failed to send error response", e);
+ log.atSevere().withCause(e).log("Failed to send error response");
}
}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/ChangeCheckerImpl.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/ChangeCheckerImpl.java
index 9dca6dd..4cdf431 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/ChangeCheckerImpl.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/ChangeCheckerImpl.java
@@ -15,11 +15,12 @@
package com.ericsson.gerrit.plugins.highavailability.index;
import com.ericsson.gerrit.plugins.highavailability.forwarder.IndexEvent;
+import com.google.common.flogger.FluentLogger;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Comment;
import com.google.gerrit.reviewdb.server.ReviewDb;
-import com.google.gerrit.server.ChangeFinder;
import com.google.gerrit.server.CommentsUtil;
+import com.google.gerrit.server.change.ChangeFinder;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.util.ManualRequestContext;
@@ -33,11 +34,9 @@
import java.util.Optional;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
public class ChangeCheckerImpl implements ChangeChecker {
- private static final Logger log = LoggerFactory.getLogger(ChangeCheckerImpl.class);
+ private static final FluentLogger log = FluentLogger.forEnclosingClass();
private final GitRepositoryManager gitRepoMgr;
private final CommentsUtil commentsUtil;
private final ChangeDb changeDb;
@@ -91,9 +90,9 @@
public boolean isChangeUpToDate(Optional<IndexEvent> indexEvent)
throws IOException, OrmException {
getComputedChangeTs();
- log.debug("Checking change {} against index event {}", this, indexEvent);
+ log.atFine().log("Checking change %s against index event %s", this, indexEvent);
if (!computedChangeTs.isPresent()) {
- log.warn("Unable to compute last updated ts for change {}", changeId);
+ log.atWarning().log("Unable to compute last updated ts for change %s", changeId);
return false;
}
@@ -128,7 +127,7 @@
+ "/"
+ getBranchTargetSha();
} catch (IOException | OrmException e) {
- log.error("Unable to render change {}", changeId, e);
+ log.atSevere().withCause(e).log("Unable to render change %s", changeId);
return "change-id=" + changeId;
}
}
@@ -138,12 +137,13 @@
String refName = changeNotes.get().getChange().getDest().get();
Ref ref = repo.exactRef(refName);
if (ref == null) {
- log.warn("Unable to find target ref {} for change {}", refName, changeId);
+ log.atWarning().log("Unable to find target ref %s for change %s", refName, changeId);
return null;
}
return ref.getTarget().getObjectId().getName();
} catch (IOException e) {
- log.warn("Unable to resolve target branch SHA for change {}", changeId, e);
+ log.atWarning().withCause(e).log(
+ "Unable to resolve target branch SHA for change %s", changeId);
return null;
}
}
@@ -163,7 +163,7 @@
changeTs = commentTs.after(changeTs) ? commentTs : changeTs;
}
} catch (OrmException e) {
- log.warn("Unable to access draft comments for change {}", change, e);
+ log.atWarning().withCause(e).log("Unable to access draft comments for change %s", change);
}
return changeTs.getTime() / 1000;
}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/CurrentRequestContext.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/CurrentRequestContext.java
new file mode 100644
index 0000000..f8c6e31
--- /dev/null
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/CurrentRequestContext.java
@@ -0,0 +1,61 @@
+// 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.ericsson.gerrit.plugins.highavailability.index;
+
+import com.ericsson.gerrit.plugins.highavailability.Configuration;
+import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.server.util.ManualRequestContext;
+import com.google.gerrit.server.util.OneOffRequestContext;
+import com.google.gerrit.server.util.RequestContext;
+import com.google.gerrit.server.util.ThreadLocalRequestContext;
+import com.google.gwtorm.server.OrmException;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import java.util.function.Consumer;
+
+@Singleton
+public class CurrentRequestContext {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
+ private ThreadLocalRequestContext threadLocalCtx;
+ private Configuration cfg;
+ private OneOffRequestContext oneOffCtx;
+
+ @Inject
+ public CurrentRequestContext(
+ ThreadLocalRequestContext threadLocalCtx, Configuration cfg, OneOffRequestContext oneOffCtx) {
+ this.threadLocalCtx = threadLocalCtx;
+ this.cfg = cfg;
+ this.oneOffCtx = oneOffCtx;
+ }
+
+ public void onlyWithContext(Consumer<RequestContext> body) {
+ RequestContext ctx = threadLocalCtx.getContext();
+ if (ctx == null && !cfg.index().synchronizeForced()) {
+ logger.atFine().log("No context, skipping event (index.synchronizeForced is false)");
+ return;
+ }
+
+ if (ctx == null) {
+ try (ManualRequestContext manualCtx = oneOffCtx.open()) {
+ body.accept(manualCtx);
+ } catch (OrmException e) {
+ logger.atSevere().withCause(e).log("Unable to open request context");
+ }
+ } else {
+ body.accept(ctx);
+ }
+ }
+}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/DisabledReviewDb.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/DisabledReviewDb.java
index 192ee8c..48c6ecb 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/DisabledReviewDb.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/DisabledReviewDb.java
@@ -16,13 +16,6 @@
import com.google.common.util.concurrent.CheckedFuture;
import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.reviewdb.client.Change.Id;
-import com.google.gerrit.reviewdb.server.AccountGroupAccess;
-import com.google.gerrit.reviewdb.server.AccountGroupByIdAccess;
-import com.google.gerrit.reviewdb.server.AccountGroupByIdAudAccess;
-import com.google.gerrit.reviewdb.server.AccountGroupMemberAccess;
-import com.google.gerrit.reviewdb.server.AccountGroupMemberAuditAccess;
-import com.google.gerrit.reviewdb.server.AccountGroupNameAccess;
import com.google.gerrit.reviewdb.server.ChangeAccess;
import com.google.gerrit.reviewdb.server.ChangeMessageAccess;
import com.google.gerrit.reviewdb.server.PatchLineCommentAccess;
@@ -30,7 +23,6 @@
import com.google.gerrit.reviewdb.server.PatchSetApprovalAccess;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.reviewdb.server.SchemaVersionAccess;
-import com.google.gerrit.reviewdb.server.SystemConfigAccess;
import com.google.gwtorm.server.Access;
import com.google.gwtorm.server.AtomicUpdate;
import com.google.gwtorm.server.OrmException;
@@ -67,22 +59,22 @@
}
@Override
- public Id primaryKey(Change entity) {
+ public Change.Id primaryKey(Change entity) {
throw new Disabled();
}
@Override
- public Map<Id, Change> toMap(Iterable<Change> c) {
+ public Map<Change.Id, Change> toMap(Iterable<Change> c) {
throw new Disabled();
}
@Override
- public CheckedFuture<Change, OrmException> getAsync(Id key) {
+ public CheckedFuture<Change, OrmException> getAsync(Change.Id key) {
throw new Disabled();
}
@Override
- public ResultSet<Change> get(Iterable<Id> keys) throws OrmException {
+ public ResultSet<Change> get(Iterable<Change.Id> keys) throws OrmException {
throw new Disabled();
}
@@ -102,7 +94,7 @@
}
@Override
- public void deleteKeys(Iterable<Id> keys) throws OrmException {
+ public void deleteKeys(Iterable<Change.Id> keys) throws OrmException {
throw new Disabled();
}
@@ -112,17 +104,17 @@
}
@Override
- public void beginTransaction(Id key) throws OrmException {
+ public void beginTransaction(Change.Id key) throws OrmException {
throw new Disabled();
}
@Override
- public Change atomicUpdate(Id key, AtomicUpdate<Change> update) throws OrmException {
+ public Change atomicUpdate(Change.Id key, AtomicUpdate<Change> update) throws OrmException {
throw new Disabled();
}
@Override
- public Change get(Id id) throws OrmException {
+ public Change get(Change.Id id) throws OrmException {
return null;
}
@@ -168,31 +160,6 @@
}
@Override
- public SystemConfigAccess systemConfig() {
- throw new Disabled();
- }
-
- @Override
- public AccountGroupAccess accountGroups() {
- throw new Disabled();
- }
-
- @Override
- public AccountGroupNameAccess accountGroupNames() {
- throw new Disabled();
- }
-
- @Override
- public AccountGroupMemberAccess accountGroupMembers() {
- throw new Disabled();
- }
-
- @Override
- public AccountGroupMemberAuditAccess accountGroupMembersAudit() {
- throw new Disabled();
- }
-
- @Override
public ChangeAccess changes() {
return new DisabledChangeAccess();
}
@@ -218,16 +185,6 @@
}
@Override
- public AccountGroupByIdAccess accountGroupById() {
- throw new Disabled();
- }
-
- @Override
- public AccountGroupByIdAudAccess accountGroupByIdAud() {
- throw new Disabled();
- }
-
- @Override
public int nextAccountId() {
throw new Disabled();
}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/IndexEventHandler.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/IndexEventHandler.java
index 3922f54..0697ad7 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/IndexEventHandler.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/IndexEventHandler.java
@@ -18,51 +18,65 @@
import com.ericsson.gerrit.plugins.highavailability.forwarder.Forwarder;
import com.ericsson.gerrit.plugins.highavailability.forwarder.IndexEvent;
import com.google.common.base.Objects;
+import com.google.common.flogger.FluentLogger;
import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gerrit.extensions.events.AccountIndexedListener;
import com.google.gerrit.extensions.events.ChangeIndexedListener;
import com.google.gerrit.extensions.events.GroupIndexedListener;
+import com.google.gerrit.extensions.events.ProjectIndexedListener;
import com.google.inject.Inject;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
class IndexEventHandler
- implements ChangeIndexedListener, AccountIndexedListener, GroupIndexedListener {
- private static final Logger log = LoggerFactory.getLogger(IndexEventHandler.class);
+ implements ChangeIndexedListener,
+ AccountIndexedListener,
+ GroupIndexedListener,
+ ProjectIndexedListener {
+ private static final FluentLogger log = FluentLogger.forEnclosingClass();
private final Executor executor;
private final Forwarder forwarder;
private final String pluginName;
private final Set<IndexTask> queuedTasks = Collections.newSetFromMap(new ConcurrentHashMap<>());
private final ChangeCheckerImpl.Factory changeChecker;
+ private final CurrentRequestContext currCtx;
@Inject
IndexEventHandler(
@IndexExecutor Executor executor,
@PluginName String pluginName,
Forwarder forwarder,
- ChangeCheckerImpl.Factory changeChecker) {
+ ChangeCheckerImpl.Factory changeChecker,
+ CurrentRequestContext currCtx) {
this.forwarder = forwarder;
this.executor = executor;
this.pluginName = pluginName;
this.changeChecker = changeChecker;
+ this.currCtx = currCtx;
}
@Override
public void onAccountIndexed(int id) {
- if (!Context.isForwardedEvent()) {
- IndexAccountTask task = new IndexAccountTask(id);
- if (queuedTasks.add(task)) {
- executor.execute(task);
- }
- }
+ currCtx.onlyWithContext(
+ (ctx) -> {
+ if (!Context.isForwardedEvent()) {
+ IndexAccountTask task = new IndexAccountTask(id);
+ if (queuedTasks.add(task)) {
+ executor.execute(task);
+ }
+ }
+ });
}
@Override
public void onChangeIndexed(String projectName, int id) {
+ currCtx.onlyWithContext((ctx) -> executeIndexChangeTask(projectName, id));
+ }
+
+ private void executeIndexChangeTask(String projectName, int id) {
+
if (!Context.isForwardedEvent()) {
String changeId = projectName + "~" + id;
try {
@@ -77,7 +91,7 @@
}
});
} catch (Exception e) {
- log.warn("Unable to create task to reindex change {}", changeId, e);
+ log.atWarning().withCause(e).log("Unable to create task to reindex change {}", changeId);
}
}
}
@@ -93,6 +107,16 @@
}
@Override
+ public void onProjectIndexed(String projectName) {
+ if (!Context.isForwardedEvent()) {
+ IndexProjectTask task = new IndexProjectTask(projectName);
+ if (queuedTasks.add(task)) {
+ executor.execute(task);
+ }
+ }
+ }
+
+ @Override
public void onGroupIndexed(String groupUUID) {
if (!Context.isForwardedEvent()) {
IndexGroupTask task = new IndexGroupTask(groupUUID);
@@ -253,4 +277,36 @@
return String.format("[%s] Index group %s in target instance", pluginName, groupUUID);
}
}
+
+ class IndexProjectTask extends IndexTask {
+ private final String projectName;
+
+ IndexProjectTask(String projectName) {
+ this.projectName = projectName;
+ }
+
+ @Override
+ public void execute() {
+ forwarder.indexProject(projectName, indexEvent);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(IndexProjectTask.class, projectName);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof IndexProjectTask)) {
+ return false;
+ }
+ IndexProjectTask other = (IndexProjectTask) obj;
+ return projectName.equals(other.projectName);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("[%s] Index project %s in target instance", pluginName, projectName);
+ }
+ }
}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/IndexModule.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/IndexModule.java
index ebf8fdf..c17731f 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/IndexModule.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/IndexModule.java
@@ -17,6 +17,7 @@
import com.google.gerrit.extensions.events.AccountIndexedListener;
import com.google.gerrit.extensions.events.ChangeIndexedListener;
import com.google.gerrit.extensions.events.GroupIndexedListener;
+import com.google.gerrit.extensions.events.ProjectIndexedListener;
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.lifecycle.LifecycleModule;
import com.google.inject.assistedinject.FactoryModuleBuilder;
@@ -35,6 +36,7 @@
DynamicSet.bind(binder(), ChangeIndexedListener.class).to(IndexEventHandler.class);
DynamicSet.bind(binder(), AccountIndexedListener.class).to(IndexEventHandler.class);
DynamicSet.bind(binder(), GroupIndexedListener.class).to(IndexEventHandler.class);
+ DynamicSet.bind(binder(), ProjectIndexedListener.class).to(IndexEventHandler.class);
install(
new FactoryModuleBuilder()
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/JGroupsPeerInfoProvider.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/JGroupsPeerInfoProvider.java
index 596f86e..ce47390 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/JGroupsPeerInfoProvider.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/JGroupsPeerInfoProvider.java
@@ -17,6 +17,7 @@
import com.ericsson.gerrit.plugins.highavailability.Configuration;
import com.ericsson.gerrit.plugins.highavailability.peers.PeerInfo;
import com.google.common.collect.ImmutableSet;
+import com.google.common.flogger.FluentLogger;
import com.google.gerrit.extensions.events.LifecycleListener;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -30,8 +31,6 @@
import org.jgroups.Message;
import org.jgroups.ReceiverAdapter;
import org.jgroups.View;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* Provider which uses JGroups to find the peer gerrit instances. On startup every gerrit instance
@@ -46,7 +45,7 @@
@Singleton
public class JGroupsPeerInfoProvider extends ReceiverAdapter
implements Provider<Set<PeerInfo>>, LifecycleListener {
- private static final Logger log = LoggerFactory.getLogger(JGroupsPeerInfoProvider.class);
+ private static final FluentLogger log = FluentLogger.forEnclosingClass();
private static final String JGROUPS_LOG_FACTORY_PROPERTY = "jgroups.logging.log_factory_class";
static {
@@ -80,25 +79,25 @@
peerAddress = msg.getSrc();
String url = (String) msg.getObject();
peerInfo = Optional.of(new PeerInfo(url));
- log.info("receive(): Set new peerInfo: {}", url);
+ log.atInfo().log("receive(): Set new peerInfo: %s", url);
}
}
@Override
public void viewAccepted(View view) {
- log.info("viewAccepted(view: {}) called", view);
+ log.atInfo().log("viewAccepted(view: %s) called", view);
synchronized (this) {
if (view.getMembers().size() > 2) {
- log.warn(
- "{} members joined the jgroups cluster {} ({}). "
- + " Only two members are supported. Members: {}",
+ log.atWarning().log(
+ "%d members joined the jgroups cluster %s (%s). "
+ + " Only two members are supported. Members: %s",
view.getMembers().size(),
jgroupsConfig.clusterName(),
channel.getName(),
view.getMembers());
}
if (peerAddress != null && !view.getMembers().contains(peerAddress)) {
- log.info("viewAccepted(): removed peerInfo");
+ log.atInfo().log("viewAccepted(): removed peerInfo");
peerAddress = null;
peerInfo = Optional.empty();
}
@@ -108,11 +107,9 @@
channel.send(new Message(null, myUrl));
} catch (Exception e) {
// channel communication caused an error. Can't do much about it.
- log.error(
- "Sending a message over channel {} to cluster {} failed",
- channel.getName(),
- jgroupsConfig.clusterName(),
- e);
+ log.atSevere().withCause(e).log(
+ "Sending a message over channel %s to cluster %s failed",
+ channel.getName(), jgroupsConfig.clusterName());
}
}
}
@@ -122,28 +119,25 @@
channel = getChannel();
Optional<InetAddress> address = finder.findAddress();
if (address.isPresent()) {
- log.debug("Protocol stack: " + channel.getProtocolStack());
+ log.atFine().log("Protocol stack: %s", channel.getProtocolStack());
channel.getProtocolStack().getTransport().setBindAddress(address.get());
- log.debug("Channel bound to {}", address.get());
+ log.atFine().log("Channel bound to %s", address.get());
} else {
- log.warn("Channel not bound: address not present");
+ log.atWarning().log("Channel not bound: address not present");
}
channel.setReceiver(this);
channel.setDiscardOwnMessages(true);
channel.connect(jgroupsConfig.clusterName());
- log.info(
- "Channel {} successfully joined jgroups cluster {}",
- channel.getName(),
- jgroupsConfig.clusterName());
+ log.atInfo().log(
+ "Channel %s successfully joined jgroups cluster %s",
+ channel.getName(), jgroupsConfig.clusterName());
} catch (Exception e) {
if (channel != null) {
- log.error(
- "joining cluster {} (channel {}) failed",
- jgroupsConfig.clusterName(),
- channel.getName(),
- e);
+ log.atSevere().withCause(e).log(
+ "joining cluster %s (channel %s) failed",
+ jgroupsConfig.clusterName(), channel.getName());
} else {
- log.error("joining cluster {} failed", jgroupsConfig.clusterName(), e);
+ log.atSevere().withCause(e).log("joining cluster %s failed", jgroupsConfig.clusterName());
}
}
}
@@ -156,10 +150,9 @@
}
return new JChannel();
} catch (Exception e) {
- log.error(
- "Unable to create a channel with protocol stack: {}",
- protocolStack.isPresent() ? protocolStack : "default",
- e);
+ log.atSevere().withCause(e).log(
+ "Unable to create a channel with protocol stack: %s",
+ protocolStack.isPresent() ? protocolStack : "default");
throw e;
}
}
@@ -177,10 +170,9 @@
@Override
public void stop() {
if (channel != null) {
- log.info(
- "closing jgroups channel {} (cluster {})",
- channel.getName(),
- jgroupsConfig.clusterName());
+ log.atInfo().log(
+ "closing jgroups channel %s (cluster %s)",
+ channel.getName(), jgroupsConfig.clusterName());
channel.close();
}
peerInfo = Optional.empty();
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/MyUrlProvider.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/MyUrlProvider.java
index adf7d2e..a257eb3 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/MyUrlProvider.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/MyUrlProvider.java
@@ -16,6 +16,7 @@
import com.ericsson.gerrit.plugins.highavailability.Configuration;
import com.google.common.base.CharMatcher;
+import com.google.common.flogger.FluentLogger;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -26,12 +27,10 @@
import java.net.UnknownHostException;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.transport.URIish;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
@Singleton
class MyUrlProvider implements Provider<String> {
- private static final Logger log = LoggerFactory.getLogger(MyUrlProvider.class);
+ private static final FluentLogger log = FluentLogger.forEnclosingClass();
private static final String HTTPD_SECTION = "httpd";
private static final String LISTEN_URL_KEY = "listenUrl";
@@ -44,7 +43,7 @@
MyUrlProvider(@GerritServerConfig Config srvConfig, Configuration pluginConfiguration) {
String url = pluginConfiguration.peerInfoJGroups().myUrl();
if (url == null) {
- log.info("myUrl not configured; attempting to determine from {}", LISTEN_URL);
+ log.atInfo().log("myUrl not configured; attempting to determine from %s", LISTEN_URL);
try {
url = CharMatcher.is('/').trimTrailingFrom(getMyUrlFromListenUrl(srvConfig));
} catch (MyUrlProviderException e) {
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/websession/file/FileBasedWebSessionCacheCleaner.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/websession/file/FileBasedWebSessionCacheCleaner.java
index b9dc245..afc6568 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/websession/file/FileBasedWebSessionCacheCleaner.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/websession/file/FileBasedWebSessionCacheCleaner.java
@@ -18,6 +18,7 @@
import static java.util.concurrent.TimeUnit.SECONDS;
import com.ericsson.gerrit.plugins.highavailability.Configuration;
+import com.google.common.flogger.FluentLogger;
import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gerrit.extensions.events.LifecycleListener;
import com.google.gerrit.server.git.WorkQueue;
@@ -25,8 +26,6 @@
import com.google.inject.Provider;
import com.google.inject.Singleton;
import java.util.concurrent.ScheduledFuture;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
@Singleton
class FileBasedWebSessionCacheCleaner implements LifecycleListener {
@@ -37,7 +36,7 @@
private ScheduledFuture<?> scheduledCleanupTask;
static class CleanupTask implements Runnable {
- private static final Logger log = LoggerFactory.getLogger(CleanupTask.class);
+ private static final FluentLogger log = FluentLogger.forEnclosingClass();
private final FileBasedWebsessionCache fileBasedWebSessionCache;
private final String pluginName;
@@ -49,9 +48,9 @@
@Override
public void run() {
- log.info("Cleaning up expired file based websessions...");
+ log.atInfo().log("Cleaning up expired file based websessions...");
fileBasedWebSessionCache.cleanUp();
- log.info("Cleaning up expired file based websessions...Done");
+ log.atInfo().log("Cleaning up expired file based websessions...Done");
}
@Override
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/websession/file/FileBasedWebsessionCache.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/websession/file/FileBasedWebsessionCache.java
index b4c99b5..674de10 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/websession/file/FileBasedWebsessionCache.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/websession/file/FileBasedWebsessionCache.java
@@ -18,6 +18,7 @@
import com.google.common.cache.Cache;
import com.google.common.cache.CacheStats;
import com.google.common.collect.ImmutableMap;
+import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.httpd.WebSessionManager;
import com.google.gerrit.httpd.WebSessionManager.Val;
@@ -44,8 +45,6 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
@Singleton
public class FileBasedWebsessionCache implements Cache<String, WebSessionManager.Val> {
@@ -74,7 +73,7 @@
}
}
- private static final Logger log = LoggerFactory.getLogger(FileBasedWebsessionCache.class);
+ private static final FluentLogger log = FluentLogger.forEnclosingClass();
private final Path websessionsDir;
@@ -179,7 +178,7 @@
StandardCopyOption.ATOMIC_MOVE);
}
} catch (IOException e) {
- log.warn("Cannot put into cache {}", websessionsDir, e);
+ log.atWarning().withCause(e).log("Cannot put into cache %s", websessionsDir);
}
}
@@ -197,7 +196,7 @@
@Override
public CacheStats stats() {
- log.warn("stats() unimplemented");
+ log.atWarning().log("stats() unimplemented");
return null;
}
@@ -207,15 +206,14 @@
ObjectInputStream objStream = new ObjectInputStream(fileStream)) {
return (Val) objStream.readObject();
} catch (ClassNotFoundException e) {
- log.warn(
- "Entry {} in cache {} has an incompatible class and can't be"
+ log.atWarning().log(
+ "Entry %s in cache %s has an incompatible class and can't be"
+ " deserialized. Invalidating entry.",
- path,
- websessionsDir);
- log.debug(e.getMessage(), e);
+ path, websessionsDir);
+ log.atFine().withCause(e).log(e.getMessage());
invalidate(path.getFileName().toString());
} catch (IOException e) {
- log.warn("Cannot read cache {}", websessionsDir, e);
+ log.atWarning().withCause(e).log("Cannot read cache %s", websessionsDir);
}
}
return null;
@@ -225,7 +223,7 @@
try {
Files.deleteIfExists(path);
} catch (IOException e) {
- log.error("Error trying to delete {} from {}", path, websessionsDir, e);
+ log.atSevere().withCause(e).log("Error trying to delete %s from %s", path, websessionsDir);
}
}
@@ -236,7 +234,7 @@
files.add(path);
}
} catch (IOException e) {
- log.error("Cannot list files in cache {}", websessionsDir, e);
+ log.atSevere().withCause(e).log("Cannot list files in cache %s", websessionsDir);
}
return files;
}
diff --git a/src/main/resources/Documentation/build.md b/src/main/resources/Documentation/build.md
index 38084d6..1d86dd0 100644
--- a/src/main/resources/Documentation/build.md
+++ b/src/main/resources/Documentation/build.md
@@ -71,6 +71,13 @@
bazel-bin/plugins/@PLUGIN@/@PLUGIN@.jar
```
+To execute the tests run either one of:
+
+```
+ bazel test --test_tag_filters=@PLUGIN@ //...
+ bazel test plugins/@PLUGIN@:@PLUGIN@_tests
+```
+
This project can be imported into the Eclipse IDE:
Add the plugin name to the `CUSTOM_PLUGINS` and to the
`CUSTOM_PLUGINS_TEST_DEPS` set in Gerrit core in
@@ -80,12 +87,6 @@
./tools/eclipse/project.py
```
-To execute the tests run:
-
-```
- bazel test --test_tag_filters=@PLUGIN@ //...
-```
-
How to build the Gerrit Plugin API is described in the [Gerrit
documentation](../../../Documentation/dev-bazel.html#_extension_and_plugin_api_jar_files).
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index bb72501..e79cbdd 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -191,6 +191,11 @@
: Whether to synchronize secondary indexes.
Defaults to true.
+```index.synchronizeForced```
+: Whether to synchronize forced index events. E.g. on-line reindex
+ automatically triggered upon version upgrades.
+ Defaults to true.
+
```index.threadPoolSize```
: Maximum number of threads used to send index events to the target instance.
Defaults to 4.
diff --git a/src/test/README.md b/src/test/README.md
new file mode 100644
index 0000000..c7a5225
--- /dev/null
+++ b/src/test/README.md
@@ -0,0 +1,8 @@
+# About this directory structure
+
+Refer to docker/README.md for more about these directory structures:
+
+```
+ ./resources/com
+ ./scala
+```
diff --git a/src/test/docker/README.md b/src/test/docker/README.md
index 68030ae..d97e929 100644
--- a/src/test/docker/README.md
+++ b/src/test/docker/README.md
@@ -39,6 +39,30 @@
$ docker-compose up
```
+## How to test
+
+Consider the
+[instructions](https://gerrit-review.googlesource.com/Documentation/dev-e2e-tests.html)
+on how to use Gerrit core's Gatling framework, to run non-core test
+scenarios such as this plugin one below:
+
+```
+ $ sbt "gatling:testOnly com.ericsson.gerrit.plugins.highavailability.scenarios.CloneUsingHAGerrit2"
+```
+
+This is a scenario that can serve as an example for how to start
+testing an HA Gerrit system. That scenario tries to clone a project
+created on gerrit 1 (port 8081) but from gerrit 2 (on 8082). The
+scenario therefore expects Gerrit HA to have properly synchronized
+the new project from 1 to 2. That project gets deleted after, here
+using HA Gerrit straight (no specific port).
+
+Scenario scala source files and their companion json resource ones are
+stored under the usual src/test directories. That structure follows the
+scala package one from the scenario classes. The core framework expects
+such a directory structure for both the scala and resources (json data)
+files.
+
## How to stop
Simply type CTRL+C on the window that started the environment
@@ -53,4 +77,3 @@
```
$ docker-compose down
```
-
diff --git a/src/test/docker/etc/gerrit.config b/src/test/docker/etc/gerrit.config
index f7ee7ec..c110835 100644
--- a/src/test/docker/etc/gerrit.config
+++ b/src/test/docker/etc/gerrit.config
@@ -27,5 +27,3 @@
scheme = http
scheme = ssh
scheme = anon_http
-[plugin "plugin-manager"]
- jenkinsUrl = https://archive-ci.gerritforge.com
diff --git a/src/test/docker/gerrit/Dockerfile b/src/test/docker/gerrit/Dockerfile
index fb4ab9c..0328827 100644
--- a/src/test/docker/gerrit/Dockerfile
+++ b/src/test/docker/gerrit/Dockerfile
@@ -1,18 +1,19 @@
-FROM gerritcodereview/gerrit:2.15.18
+FROM gerritcodereview/gerrit:2.16.19
-ENV GERRIT_BRANCH=stable-2.15
+ENV GERRIT_BRANCH=stable-2.16
-ENV GERRIT_CI_URL=https://archive-ci.gerritforge.com/job
+ENV GERRIT_CI_URL=https://gerrit-ci.gerritforge.com/job
USER root
-RUN yum install -y iputils-ping netcat postgresql curl lsof gettext moreutils net-tools netcat inetutils-ping
+RUN yum install -y iputils-ping netcat postgresql curl lsof gettext moreutils net-tools netcat inetutils-ping sudo
USER gerrit
-ADD $GERRIT_CI_URL/plugin-javamelody-bazel-$GERRIT_BRANCH/lastSuccessfulBuild/artifact/bazel-bin/plugins/javamelody/javamelody.jar /var/gerrit/plugins/javamelody.jar
-ADD $GERRIT_CI_URL/plugin-javamelody-bazel-$GERRIT_BRANCH/lastSuccessfulBuild/artifact/bazel-bin/plugins/javamelody/javamelody-deps_deploy.jar /var/gerrit/lib/javamelody-deps_deploy.jar
-ADD $GERRIT_CI_URL/plugin-high-availability-bazel-$GERRIT_BRANCH/lastSuccessfulBuild/artifact/bazel-bin/plugins/high-availability/high-availability.jar /var/gerrit/plugins/high-availability.jar
+ADD --chown=gerrit:gerrit $GERRIT_CI_URL/plugin-javamelody-bazel-$GERRIT_BRANCH/lastSuccessfulBuild/artifact/bazel-bin/plugins/javamelody/javamelody.jar /var/gerrit/plugins/javamelody.jar
+ADD --chown=gerrit:gerrit $GERRIT_CI_URL/plugin-javamelody-bazel-$GERRIT_BRANCH/lastSuccessfulBuild/artifact/bazel-bin/plugins/javamelody/javamelody-deps_deploy.jar /var/gerrit/lib/javamelody-deps_deploy.jar
+ADD --chown=gerrit:gerrit $GERRIT_CI_URL/plugin-high-availability-bazel-$GERRIT_BRANCH/lastSuccessfulBuild/artifact/bazel-bin/plugins/high-availability/high-availability.jar /var/gerrit/plugins/high-availability.jar
+ADD --chown=gerrit:gerrit $GERRIT_CI_URL/plugin-delete-project-bazel-$GERRIT_BRANCH/lastSuccessfulBuild/artifact/bazel-bin/plugins/delete-project/delete-project.jar /var/gerrit/plugins/delete-project.jar
USER root
diff --git a/src/test/docker/gerrit/start.sh b/src/test/docker/gerrit/start.sh
index f3d4560..7aa3550 100755
--- a/src/test/docker/gerrit/start.sh
+++ b/src/test/docker/gerrit/start.sh
@@ -25,4 +25,4 @@
sudo -u gerrit touch /var/gerrit/logs/{gc_log,error_log,httpd_log,sshd_log,replication_log} && tail -f /var/gerrit/logs/* | grep --line-buffered -v 'HEAD /' &
echo "Running Gerrit ..."
-sudo -u gerrit /etc/init.d/gerrit run
+sudo -u gerrit /var/gerrit/bin/gerrit.sh run
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java
index 63ab408..2cf12fc 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java
@@ -34,7 +34,9 @@
import static com.ericsson.gerrit.plugins.highavailability.Configuration.Http.RETRY_INTERVAL_KEY;
import static com.ericsson.gerrit.plugins.highavailability.Configuration.Http.SOCKET_TIMEOUT_KEY;
import static com.ericsson.gerrit.plugins.highavailability.Configuration.Http.USER_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Index.DEFAULT_SYNCHRONIZE_FORCED;
import static com.ericsson.gerrit.plugins.highavailability.Configuration.Index.INDEX_SECTION;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.Index.SYNCHRONIZE_FORCED_KEY;
import static com.ericsson.gerrit.plugins.highavailability.Configuration.JGroups.CLUSTER_NAME_KEY;
import static com.ericsson.gerrit.plugins.highavailability.Configuration.JGroups.DEFAULT_CLUSTER_NAME;
import static com.ericsson.gerrit.plugins.highavailability.Configuration.JGroups.DEFAULT_SKIP_INTERFACE_LIST;
@@ -384,4 +386,13 @@
globalPluginConfig.setInt(INDEX_SECTION, null, NUM_STRIPED_LOCKS, 100);
assertThat(getConfiguration().index().numStripedLocks()).isEqualTo(100);
}
+
+ @Test
+ public void testGetIndexSynchronizeForced() throws Exception {
+ assertThat(getConfiguration().index().synchronizeForced())
+ .isEqualTo(DEFAULT_SYNCHRONIZE_FORCED);
+
+ globalPluginConfig.setBoolean(INDEX_SECTION, null, SYNCHRONIZE_FORCED_KEY, false);
+ assertThat(getConfiguration().index().synchronizeForced()).isFalse();
+ }
}
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheEvictionIT.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheEvictionIT.java
index 7299238..7233aac 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheEvictionIT.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheEvictionIT.java
@@ -64,9 +64,9 @@
private final CountDownLatch expectedRequestLatch = new CountDownLatch(1);
@Override
- public void setUp() throws Exception {
+ public void setUpTestPlugin() throws Exception {
givenThat(any(anyUrl()).willReturn(aResponse().withStatus(HttpStatus.SC_NO_CONTENT)));
- super.setUp();
+ super.setUpTestPlugin();
}
@Test
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/ProjectListIT.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/ProjectListIT.java
index 9d08f15..22ef89e 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/ProjectListIT.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/ProjectListIT.java
@@ -49,9 +49,9 @@
@Rule public WireMockRule wireMockRule = new WireMockRule(options().port(PORT));
@Override
- public void setUp() throws Exception {
+ public void setUpTestPlugin() throws Exception {
givenThat(any(anyUrl()).willReturn(aResponse().withStatus(HttpStatus.SC_NO_CONTENT)));
- super.setUp();
+ super.setUpTestPlugin();
}
@Test
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedAwareEventBrokerTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedAwareEventBrokerTest.java
index 02b4a47..ec5b1de 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedAwareEventBrokerTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedAwareEventBrokerTest.java
@@ -18,9 +18,11 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
-import com.google.gerrit.common.EventListener;
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.server.events.Event;
+import com.google.gerrit.server.events.EventListener;
+import com.google.gerrit.server.plugincontext.PluginContext.PluginMetrics;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import org.junit.Before;
import org.junit.Test;
@@ -32,9 +34,11 @@
@Before
public void setUp() {
+ PluginMetrics mockMetrics = mock(PluginMetrics.class);
listenerMock = mock(EventListener.class);
- DynamicSet<EventListener> listeners = DynamicSet.emptySet();
- listeners.add(listenerMock);
+ DynamicSet<EventListener> set = DynamicSet.emptySet();
+ set.add("high-availability", listenerMock);
+ PluginSetContext<EventListener> listeners = new PluginSetContext<>(set, mockMetrics);
broker = new ForwardedAwareEventBroker(null, listeners, null, null, null, null);
}
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedCacheEvictionHandlerTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedCacheEvictionHandlerTest.java
index 3426b05..44bb1ea 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedCacheEvictionHandlerTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedCacheEvictionHandlerTest.java
@@ -15,6 +15,7 @@
package com.ericsson.gerrit.plugins.highavailability.forwarder;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.testing.GerritJUnit.assertThrows;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;
@@ -24,9 +25,7 @@
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.reviewdb.client.Account;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
-import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
@@ -35,7 +34,6 @@
@RunWith(MockitoJUnitRunner.class)
public class ForwardedCacheEvictionHandlerTest {
- @Rule public ExpectedException exception = ExpectedException.none();
@Mock private DynamicMap<Cache<?, ?>> cacheMapMock;
@Mock private Cache<?, ?> cacheMock;
private ForwardedCacheEvictionHandler handler;
@@ -48,11 +46,11 @@
@Test
public void shouldThrowAnExceptionWhenCacheNotFound() throws Exception {
CacheEntry entry = new CacheEntry("somePlugin", "unexistingCache", null);
-
- exception.expect(CacheNotFoundException.class);
- exception.expectMessage(
- String.format("cache %s.%s not found", entry.getPluginName(), entry.getCacheName()));
- handler.evict(entry);
+ String expectedMessage =
+ String.format("cache %s.%s not found", entry.getPluginName(), entry.getCacheName());
+ CacheNotFoundException thrown =
+ assertThrows(CacheNotFoundException.class, () -> handler.evict(entry));
+ assertThat(thrown).hasMessageThat().contains(expectedMessage);
}
@Test
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedEventHandlerTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedEventHandlerTest.java
index ecb976e..a855c5e 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedEventHandlerTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedEventHandlerTest.java
@@ -15,18 +15,16 @@
package com.ericsson.gerrit.plugins.highavailability.forwarder;
import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
+import static com.google.gerrit.testing.GerritJUnit.assertThrows;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
-import com.google.gerrit.common.EventDispatcher;
import com.google.gerrit.server.events.Event;
+import com.google.gerrit.server.events.EventDispatcher;
import com.google.gerrit.server.events.ProjectCreatedEvent;
import com.google.gwtorm.server.OrmException;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
-import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
@@ -35,7 +33,6 @@
@RunWith(MockitoJUnitRunner.class)
public class ForwardedEventHandlerTest {
- @Rule public ExpectedException exception = ExpectedException.none();
@Mock private EventDispatcher dispatcherMock;
private ForwardedEventHandler handler;
@@ -85,12 +82,8 @@
.postEvent(event);
assertThat(Context.isForwardedEvent()).isFalse();
- try {
- handler.dispatch(event);
- fail("should have throw an OrmException");
- } catch (OrmException e) {
- assertThat(e.getMessage()).isEqualTo("someMessage");
- }
+ OrmException thrown = assertThrows(OrmException.class, () -> handler.dispatch(event));
+ assertThat(thrown).hasMessageThat().contains("someMessage");
assertThat(Context.isForwardedEvent()).isFalse();
verify(dispatcherMock).postEvent(event);
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexAccountHandlerTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexAccountHandlerTest.java
index c2d3659..b88e9c0 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexAccountHandlerTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexAccountHandlerTest.java
@@ -15,6 +15,7 @@
package com.ericsson.gerrit.plugins.highavailability.forwarder;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.testing.GerritJUnit.assertThrows;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
@@ -27,9 +28,7 @@
import java.io.IOException;
import java.util.Optional;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
-import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
@@ -38,7 +37,6 @@
@RunWith(MockitoJUnitRunner.class)
public class ForwardedIndexAccountHandlerTest {
- @Rule public ExpectedException exception = ExpectedException.none();
@Mock private AccountIndexer indexerMock;
@Mock private Configuration configMock;
@Mock private Configuration.Index indexMock;
@@ -61,9 +59,11 @@
@Test
public void deleteIsNotSupported() throws Exception {
- exception.expect(UnsupportedOperationException.class);
- exception.expectMessage("Delete from account index not supported");
- handler.index(id, Operation.DELETE, Optional.empty());
+ UnsupportedOperationException thrown =
+ assertThrows(
+ UnsupportedOperationException.class,
+ () -> handler.index(id, Operation.DELETE, Optional.empty()));
+ assertThat(thrown).hasMessageThat().contains("Delete from account index not supported");
}
@Test
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexChangeHandlerTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexChangeHandlerTest.java
index 8bfe47d..6bfd47d 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexChangeHandlerTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexChangeHandlerTest.java
@@ -15,6 +15,7 @@
package com.ericsson.gerrit.plugins.highavailability.forwarder;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.testing.GerritJUnit.assertThrows;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
@@ -28,20 +29,18 @@
import com.ericsson.gerrit.plugins.highavailability.index.ChangeChecker;
import com.ericsson.gerrit.plugins.highavailability.index.ChangeCheckerImpl;
import com.ericsson.gerrit.plugins.highavailability.index.ChangeDb;
-import com.google.gerrit.common.TimeUtil;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.index.change.ChangeIndexer;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.util.OneOffRequestContext;
+import com.google.gerrit.server.util.time.TimeUtil;
import com.google.gwtorm.server.OrmException;
import java.io.IOException;
import java.util.Optional;
import java.util.concurrent.ScheduledExecutorService;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
-import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
@@ -62,7 +61,6 @@
private static final boolean CHANGE_UP_TO_DATE = true;
private static final boolean CHANGE_OUTDATED = false;
- @Rule public ExpectedException exception = ExpectedException.none();
@Mock private ChangeIndexer indexerMock;
@Mock private ChangeDb changeDbMock;
@Mock private ReviewDb dbMock;
@@ -120,22 +118,22 @@
public void changeToIndexDoesNotExist() throws Exception {
setupChangeAccessRelatedMocks(CHANGE_DOES_NOT_EXIST, CHANGE_OUTDATED);
handler.index(TEST_CHANGE_ID, Operation.INDEX, Optional.empty());
- verify(indexerMock, times(1)).delete(id);
+ verify(indexerMock, times(0)).delete(id);
}
@Test
public void schemaThrowsExceptionWhenLookingUpForChange() throws Exception {
setupChangeAccessRelatedMocks(CHANGE_EXISTS, THROW_ORM_EXCEPTION, CHANGE_UP_TO_DATE);
- exception.expect(OrmException.class);
- handler.index(TEST_CHANGE_ID, Operation.INDEX, Optional.empty());
+ assertThrows(
+ OrmException.class, () -> handler.index(TEST_CHANGE_ID, Operation.INDEX, Optional.empty()));
}
@Test
public void indexerThrowsIOExceptionTryingToIndexChange() throws Exception {
setupChangeAccessRelatedMocks(
CHANGE_EXISTS, DO_NOT_THROW_ORM_EXCEPTION, THROW_IO_EXCEPTION, CHANGE_UP_TO_DATE);
- exception.expect(IOException.class);
- handler.index(TEST_CHANGE_ID, Operation.INDEX, Optional.empty());
+ assertThrows(
+ IOException.class, () -> handler.index(TEST_CHANGE_ID, Operation.INDEX, Optional.empty()));
}
@Test
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexGroupHandlerTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexGroupHandlerTest.java
index ab55b73..845abb0 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexGroupHandlerTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexGroupHandlerTest.java
@@ -15,6 +15,7 @@
package com.ericsson.gerrit.plugins.highavailability.forwarder;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.testing.GerritJUnit.assertThrows;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
@@ -27,9 +28,7 @@
import java.io.IOException;
import java.util.Optional;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
-import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
@@ -38,7 +37,6 @@
@RunWith(MockitoJUnitRunner.class)
public class ForwardedIndexGroupHandlerTest {
- @Rule public ExpectedException exception = ExpectedException.none();
@Mock private GroupIndexer indexerMock;
@Mock private Configuration configMock;
@Mock private Configuration.Index indexMock;
@@ -61,9 +59,11 @@
@Test
public void deleteIsNotSupported() throws Exception {
- exception.expect(UnsupportedOperationException.class);
- exception.expectMessage("Delete from group index not supported");
- handler.index(uuid, Operation.DELETE, Optional.empty());
+ UnsupportedOperationException thrown =
+ assertThrows(
+ UnsupportedOperationException.class,
+ () -> handler.index(uuid, Operation.DELETE, Optional.empty()));
+ assertThat(thrown).hasMessageThat().contains("Delete from group index not supported");
}
@Test
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexProjectHandlerTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexProjectHandlerTest.java
new file mode 100644
index 0000000..a0c6979
--- /dev/null
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedIndexProjectHandlerTest.java
@@ -0,0 +1,111 @@
+// Copyright (C) 2018 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.ericsson.gerrit.plugins.highavailability.forwarder;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.testing.GerritJUnit.assertThrows;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import com.ericsson.gerrit.plugins.highavailability.Configuration;
+import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwardedIndexingHandler.Operation;
+import com.google.gerrit.index.project.ProjectIndexer;
+import com.google.gerrit.reviewdb.client.Project;
+import java.io.IOException;
+import java.util.Optional;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.mockito.stubbing.Answer;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ForwardedIndexProjectHandlerTest {
+
+ @Mock private ProjectIndexer indexerMock;
+ @Mock private Configuration configMock;
+ @Mock private Configuration.Index indexMock;
+ private ForwardedIndexProjectHandler handler;
+ private Project.NameKey nameKey;
+
+ @Before
+ public void setUp() {
+ when(configMock.index()).thenReturn(indexMock);
+ when(indexMock.numStripedLocks()).thenReturn(10);
+ handler = new ForwardedIndexProjectHandler(indexerMock, configMock);
+ nameKey = new Project.NameKey("project/name");
+ }
+
+ @Test
+ public void testSuccessfulIndexing() throws Exception {
+ handler.index(nameKey, Operation.INDEX, Optional.empty());
+ verify(indexerMock).index(nameKey);
+ }
+
+ @Test
+ public void deleteIsNotSupported() throws Exception {
+ UnsupportedOperationException thrown =
+ assertThrows(
+ UnsupportedOperationException.class,
+ () -> handler.index(nameKey, Operation.DELETE, Optional.empty()));
+ assertThat(thrown).hasMessageThat().contains("Delete from project index not supported");
+ }
+
+ @Test
+ public void shouldSetAndUnsetForwardedContext() throws Exception {
+ // this doAnswer is to allow to assert that context is set to forwarded
+ // while cache eviction is called.
+ doAnswer(
+ (Answer<Void>)
+ invocation -> {
+ assertThat(Context.isForwardedEvent()).isTrue();
+ return null;
+ })
+ .when(indexerMock)
+ .index(nameKey);
+
+ assertThat(Context.isForwardedEvent()).isFalse();
+ handler.index(nameKey, Operation.INDEX, Optional.empty());
+ assertThat(Context.isForwardedEvent()).isFalse();
+
+ verify(indexerMock).index(nameKey);
+ }
+
+ @Test
+ public void shouldSetAndUnsetForwardedContextEvenIfExceptionIsThrown() throws Exception {
+ doAnswer(
+ (Answer<Void>)
+ invocation -> {
+ assertThat(Context.isForwardedEvent()).isTrue();
+ throw new IOException("someMessage");
+ })
+ .when(indexerMock)
+ .index(nameKey);
+
+ assertThat(Context.isForwardedEvent()).isFalse();
+ try {
+ handler.index(nameKey, Operation.INDEX, Optional.empty());
+ fail("should have thrown an IOException");
+ } catch (IOException e) {
+ assertThat(e.getMessage()).isEqualTo("someMessage");
+ }
+ assertThat(Context.isForwardedEvent()).isFalse();
+
+ verify(indexerMock).index(nameKey);
+ }
+}
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedProjectListUpdateHandlerTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedProjectListUpdateHandlerTest.java
index 3ee8581..f5521c5 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedProjectListUpdateHandlerTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedProjectListUpdateHandlerTest.java
@@ -15,16 +15,14 @@
package com.ericsson.gerrit.plugins.highavailability.forwarder;
import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
+import static com.google.gerrit.testing.GerritJUnit.assertThrows;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.project.ProjectCache;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
-import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
@@ -36,7 +34,6 @@
private static final String PROJECT_NAME = "someProject";
private static final String SOME_MESSAGE = "someMessage";
private static final Project.NameKey PROJECT_KEY = new Project.NameKey(PROJECT_NAME);
- @Rule public ExpectedException exception = ExpectedException.none();
@Mock private ProjectCache projectCacheMock;
private ForwardedProjectListUpdateHandler handler;
@@ -109,12 +106,9 @@
.onCreateProject(PROJECT_KEY);
assertThat(Context.isForwardedEvent()).isFalse();
- try {
- handler.update(PROJECT_NAME, false);
- fail("should have thrown a RuntimeException");
- } catch (RuntimeException e) {
- assertThat(e.getMessage()).isEqualTo(SOME_MESSAGE);
- }
+ RuntimeException thrown =
+ assertThrows(RuntimeException.class, () -> handler.update(PROJECT_NAME, false));
+ assertThat(thrown).hasMessageThat().contains(SOME_MESSAGE);
assertThat(Context.isForwardedEvent()).isFalse();
verify(projectCacheMock).onCreateProject(PROJECT_KEY);
@@ -132,12 +126,9 @@
.remove(PROJECT_KEY);
assertThat(Context.isForwardedEvent()).isFalse();
- try {
- handler.update(PROJECT_NAME, true);
- fail("should have thrown a RuntimeException");
- } catch (RuntimeException e) {
- assertThat(e.getMessage()).isEqualTo(SOME_MESSAGE);
- }
+ RuntimeException thrown =
+ assertThrows(RuntimeException.class, () -> handler.update(PROJECT_NAME, true));
+ assertThat(thrown).hasMessageThat().contains(SOME_MESSAGE);
assertThat(Context.isForwardedEvent()).isFalse();
verify(projectCacheMock).remove(PROJECT_KEY);
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/IndexProjectRestApiServletTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/IndexProjectRestApiServletTest.java
new file mode 100644
index 0000000..83420b9
--- /dev/null
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/IndexProjectRestApiServletTest.java
@@ -0,0 +1,91 @@
+// Copyright (C) 2018 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.ericsson.gerrit.plugins.highavailability.forwarder.rest;
+
+import static javax.servlet.http.HttpServletResponse.SC_CONFLICT;
+import static javax.servlet.http.HttpServletResponse.SC_METHOD_NOT_ALLOWED;
+import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwardedIndexProjectHandler;
+import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwardedIndexingHandler.Operation;
+import com.google.gerrit.extensions.restapi.Url;
+import com.google.gerrit.reviewdb.client.Project;
+import java.io.IOException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class IndexProjectRestApiServletTest {
+ private static final String IO_ERROR = "io-error";
+ private static final String PROJECT_NAME = "test/project";
+
+ @Mock private ForwardedIndexProjectHandler handlerMock;
+ @Mock private HttpServletRequest requestMock;
+ @Mock private HttpServletResponse responseMock;
+
+ private Project.NameKey nameKey;
+ private IndexProjectRestApiServlet servlet;
+
+ @Before
+ public void setUpMocks() {
+ servlet = new IndexProjectRestApiServlet(handlerMock);
+ nameKey = new Project.NameKey(PROJECT_NAME);
+ when(requestMock.getRequestURI())
+ .thenReturn("http://gerrit.com/index/project/" + Url.encode(nameKey.get()));
+ }
+
+ @Test
+ public void projectIsIndexed() throws Exception {
+ servlet.doPost(requestMock, responseMock);
+ verify(handlerMock, times(1)).index(eq(nameKey), eq(Operation.INDEX), any());
+ verify(responseMock).setStatus(SC_NO_CONTENT);
+ }
+
+ @Test
+ public void cannotDeleteProject() throws Exception {
+ servlet.doDelete(requestMock, responseMock);
+ verify(responseMock).sendError(SC_METHOD_NOT_ALLOWED, "cannot delete project from index");
+ }
+
+ @Test
+ public void indexerThrowsIOExceptionTryingToIndexProject() throws Exception {
+ doThrow(new IOException(IO_ERROR))
+ .when(handlerMock)
+ .index(eq(nameKey), eq(Operation.INDEX), any());
+ servlet.doPost(requestMock, responseMock);
+ verify(responseMock).sendError(SC_CONFLICT, IO_ERROR);
+ }
+
+ @Test
+ public void sendErrorThrowsIOException() throws Exception {
+ doThrow(new IOException(IO_ERROR))
+ .when(handlerMock)
+ .index(eq(nameKey), eq(Operation.INDEX), any());
+ doThrow(new IOException("someError")).when(responseMock).sendError(SC_CONFLICT, IO_ERROR);
+ servlet.doPost(requestMock, responseMock);
+ verify(responseMock).sendError(SC_CONFLICT, IO_ERROR);
+ }
+}
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/AbstractIndexForwardingIT.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/AbstractIndexForwardingIT.java
index 2eee205..af4637e 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/AbstractIndexForwardingIT.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/AbstractIndexForwardingIT.java
@@ -51,10 +51,10 @@
@Rule public WireMockRule wireMockRule = new WireMockRule(options().port(PORT));
@Override
- public void setUp() throws Exception {
+ public void setUpTestPlugin() throws Exception {
givenThat(any(anyUrl()).willReturn(aResponse().withStatus(HttpStatus.SC_NO_CONTENT)));
beforeAction();
- super.setUp();
+ super.setUpTestPlugin();
}
@Test
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/IndexEventHandlerTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/IndexEventHandlerTest.java
index d9e1b22..2d12ca8 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/IndexEventHandlerTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/IndexEventHandlerTest.java
@@ -18,11 +18,13 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
+import com.ericsson.gerrit.plugins.highavailability.Configuration;
import com.ericsson.gerrit.plugins.highavailability.forwarder.Context;
import com.ericsson.gerrit.plugins.highavailability.forwarder.Forwarder;
import com.ericsson.gerrit.plugins.highavailability.forwarder.IndexEvent;
@@ -34,8 +36,12 @@
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.server.util.OneOffRequestContext;
+import com.google.gerrit.server.util.RequestContext;
+import com.google.gerrit.server.util.ThreadLocalRequestContext;
import java.util.Optional;
import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.function.Consumer;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -58,6 +64,15 @@
private Change.Id changeId;
private Account.Id accountId;
private AccountGroup.UUID accountGroupUUID;
+ @Mock private RequestContext mockCtx;
+
+ private CurrentRequestContext currCtx =
+ new CurrentRequestContext(null, null, null) {
+ @Override
+ public void onlyWithContext(Consumer<RequestContext> body) {
+ body.accept(mockCtx);
+ }
+ };
@Before
public void setUpMocks() throws Exception {
@@ -66,9 +81,18 @@
accountGroupUUID = new AccountGroup.UUID(UUID);
when(changeCheckerFactoryMock.create(any())).thenReturn(changeCheckerMock);
when(changeCheckerMock.newIndexEvent()).thenReturn(Optional.of(new IndexEvent()));
+
+ setUpIndexEventHandler(currCtx);
+ }
+
+ public void setUpIndexEventHandler(CurrentRequestContext currCtx) throws Exception {
indexEventHandler =
new IndexEventHandler(
- MoreExecutors.directExecutor(), PLUGIN_NAME, forwarder, changeCheckerFactoryMock);
+ MoreExecutors.directExecutor(),
+ PLUGIN_NAME,
+ forwarder,
+ changeCheckerFactoryMock,
+ currCtx);
}
@Test
@@ -78,6 +102,33 @@
}
@Test
+ public void shouldNotIndexInRemoteWhenContextIsMissing() throws Exception {
+ ThreadLocalRequestContext threadLocalCtxMock = mock(ThreadLocalRequestContext.class);
+ OneOffRequestContext oneOffCtxMock = mock(OneOffRequestContext.class);
+ Configuration cfgMock = mock(Configuration.class);
+ Configuration.Index cfgIndex = mock(Configuration.Index.class);
+ when(cfgMock.index()).thenReturn(cfgIndex);
+
+ setUpIndexEventHandler(new CurrentRequestContext(threadLocalCtxMock, cfgMock, oneOffCtxMock));
+ indexEventHandler.onChangeIndexed(PROJECT_NAME, changeId.get());
+ verify(forwarder, never()).indexChange(eq(PROJECT_NAME), eq(CHANGE_ID), any());
+ }
+
+ @Test
+ public void shouldReindexInRemoteWhenContextIsMissingButForcedIndexingEnabled() throws Exception {
+ ThreadLocalRequestContext threadLocalCtxMock = mock(ThreadLocalRequestContext.class);
+ OneOffRequestContext oneOffCtxMock = mock(OneOffRequestContext.class);
+ Configuration cfgMock = mock(Configuration.class);
+ Configuration.Index cfgIndex = mock(Configuration.Index.class);
+ when(cfgMock.index()).thenReturn(cfgIndex);
+ when(cfgIndex.synchronizeForced()).thenReturn(true);
+
+ setUpIndexEventHandler(new CurrentRequestContext(threadLocalCtxMock, cfgMock, oneOffCtxMock));
+ indexEventHandler.onChangeIndexed(PROJECT_NAME, changeId.get());
+ verify(forwarder).indexChange(eq(PROJECT_NAME), eq(CHANGE_ID), any());
+ }
+
+ @Test
public void shouldIndexInRemoteOnAccountIndexedEvent() throws Exception {
indexEventHandler.onAccountIndexed(accountId.get());
verify(forwarder).indexAccount(eq(ACCOUNT_ID), any());
@@ -128,7 +179,7 @@
public void duplicateChangeEventOfAQueuedEventShouldGetDiscarded() {
ScheduledThreadPoolExecutor poolMock = mock(ScheduledThreadPoolExecutor.class);
indexEventHandler =
- new IndexEventHandler(poolMock, PLUGIN_NAME, forwarder, changeCheckerFactoryMock);
+ new IndexEventHandler(poolMock, PLUGIN_NAME, forwarder, changeCheckerFactoryMock, currCtx);
indexEventHandler.onChangeIndexed(PROJECT_NAME, changeId.get());
indexEventHandler.onChangeIndexed(PROJECT_NAME, changeId.get());
verify(poolMock, times(1))
@@ -139,7 +190,7 @@
public void duplicateAccountEventOfAQueuedEventShouldGetDiscarded() {
ScheduledThreadPoolExecutor poolMock = mock(ScheduledThreadPoolExecutor.class);
indexEventHandler =
- new IndexEventHandler(poolMock, PLUGIN_NAME, forwarder, changeCheckerFactoryMock);
+ new IndexEventHandler(poolMock, PLUGIN_NAME, forwarder, changeCheckerFactoryMock, currCtx);
indexEventHandler.onAccountIndexed(accountId.get());
indexEventHandler.onAccountIndexed(accountId.get());
verify(poolMock, times(1)).execute(indexEventHandler.new IndexAccountTask(ACCOUNT_ID));
@@ -149,7 +200,7 @@
public void duplicateGroupEventOfAQueuedEventShouldGetDiscarded() {
ScheduledThreadPoolExecutor poolMock = mock(ScheduledThreadPoolExecutor.class);
indexEventHandler =
- new IndexEventHandler(poolMock, PLUGIN_NAME, forwarder, changeCheckerFactoryMock);
+ new IndexEventHandler(poolMock, PLUGIN_NAME, forwarder, changeCheckerFactoryMock, currCtx);
indexEventHandler.onGroupIndexed(accountGroupUUID.get());
indexEventHandler.onGroupIndexed(accountGroupUUID.get());
verify(poolMock, times(1)).execute(indexEventHandler.new IndexGroupTask(UUID));
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/ProjectIndexForwardingIT.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/ProjectIndexForwardingIT.java
new file mode 100644
index 0000000..951e4f6
--- /dev/null
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/ProjectIndexForwardingIT.java
@@ -0,0 +1,36 @@
+// Copyright (C) 2018 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.ericsson.gerrit.plugins.highavailability.index;
+
+import com.google.gerrit.extensions.restapi.Url;
+
+public class ProjectIndexForwardingIT extends AbstractIndexForwardingIT {
+ private String someProjectName;
+
+ @Override
+ public void beforeAction() throws Exception {
+ someProjectName = gApi.projects().create("someProject").get().name;
+ }
+
+ @Override
+ public String getExpectedRequest() {
+ return "/plugins/high-availability/index/project/" + Url.encode(someProjectName);
+ }
+
+ @Override
+ public void doAction() throws Exception {
+ gApi.projects().name(someProjectName).index(false);
+ }
+}
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/MyUrlProviderTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/MyUrlProviderTest.java
index f3e8b7d..c337947 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/MyUrlProviderTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/MyUrlProviderTest.java
@@ -15,6 +15,7 @@
package com.ericsson.gerrit.plugins.highavailability.peers.jgroups;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.testing.GerritJUnit.assertThrows;
import static java.net.InetAddress.getLocalHost;
import static org.mockito.Answers.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.when;
@@ -23,9 +24,7 @@
import com.google.inject.ProvisionException;
import org.eclipse.jgit.lib.Config;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
-import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
@@ -38,8 +37,6 @@
private static final String HTTPS = "https://";
private static final String LISTEN_URL = "listenUrl";
- @Rule public ExpectedException exception = ExpectedException.none();
-
@Mock(answer = RETURNS_DEEP_STUBS)
private Configuration configurationMock;
@@ -70,33 +67,29 @@
@Test
public void testGetJGroupsMyUrlFromListenUrlWhenNoListenUrlSpecified() throws Exception {
- exception.expect(ProvisionException.class);
- exception.expectMessage("exactly 1 value configured; found 0");
- getMyUrlProvider();
+ ProvisionException thrown = assertThrows(ProvisionException.class, () -> getMyUrlProvider());
+ assertThat(thrown).hasMessageThat().contains("exactly 1 value configured; found 0");
}
@Test
public void testGetJGroupsMyUrlFromListenUrlWhenMultipleListenUrlsSpecified() throws Exception {
gerritServerConfig.setStringList(HTTPD, null, LISTEN_URL, Lists.newArrayList("a", "b"));
- exception.expect(ProvisionException.class);
- exception.expectMessage("exactly 1 value configured; found 2");
- getMyUrlProvider();
+ ProvisionException thrown = assertThrows(ProvisionException.class, () -> getMyUrlProvider());
+ assertThat(thrown).hasMessageThat().contains("exactly 1 value configured; found 2");
}
@Test
public void testGetJGroupsMyUrlFromListenUrlWhenReverseProxyConfigured() throws Exception {
gerritServerConfig.setString(HTTPD, null, LISTEN_URL, "proxy-https://foo");
- exception.expect(ProvisionException.class);
- exception.expectMessage("when configured as reverse-proxy");
- getMyUrlProvider();
+ ProvisionException thrown = assertThrows(ProvisionException.class, () -> getMyUrlProvider());
+ assertThat(thrown).hasMessageThat().contains("when configured as reverse-proxy");
}
@Test
public void testGetJGroupsMyUrlFromListenUrlWhenWildcardConfigured() throws Exception {
gerritServerConfig.setString(HTTPD, null, LISTEN_URL, "https://*");
- exception.expect(ProvisionException.class);
- exception.expectMessage("when configured with wildcard");
- getMyUrlProvider();
+ ProvisionException thrown = assertThrows(ProvisionException.class, () -> getMyUrlProvider());
+ assertThat(thrown).hasMessageThat().contains("when configured with wildcard");
}
@Test
diff --git a/src/test/resources/com/ericsson/gerrit/plugins/highavailability/scenarios/CheckProjectsCacheFlushEntriesUsingHAGerrit1.json b/src/test/resources/com/ericsson/gerrit/plugins/highavailability/scenarios/CheckProjectsCacheFlushEntriesUsingHAGerrit1.json
new file mode 100644
index 0000000..281515d
--- /dev/null
+++ b/src/test/resources/com/ericsson/gerrit/plugins/highavailability/scenarios/CheckProjectsCacheFlushEntriesUsingHAGerrit1.json
@@ -0,0 +1,6 @@
+[
+ {
+ "url": "http://HOSTNAME:HTTP_PORT1/a/config/server/caches/projects",
+ "entries": "PROJECTS_ENTRIES"
+ }
+]
diff --git a/src/test/resources/com/ericsson/gerrit/plugins/highavailability/scenarios/CloneUsingHAGerrit2.json b/src/test/resources/com/ericsson/gerrit/plugins/highavailability/scenarios/CloneUsingHAGerrit2.json
new file mode 100644
index 0000000..3fd506d
--- /dev/null
+++ b/src/test/resources/com/ericsson/gerrit/plugins/highavailability/scenarios/CloneUsingHAGerrit2.json
@@ -0,0 +1,6 @@
+[
+ {
+ "url": "http://HOSTNAME:HTTP_PORT2/_PROJECT",
+ "cmd": "clone"
+ }
+]
diff --git a/src/test/resources/com/ericsson/gerrit/plugins/highavailability/scenarios/CreateChangeUsingHAGerrit1-body.json b/src/test/resources/com/ericsson/gerrit/plugins/highavailability/scenarios/CreateChangeUsingHAGerrit1-body.json
new file mode 100644
index 0000000..23bf26c
--- /dev/null
+++ b/src/test/resources/com/ericsson/gerrit/plugins/highavailability/scenarios/CreateChangeUsingHAGerrit1-body.json
@@ -0,0 +1,5 @@
+{
+ "project": "${project}",
+ "branch": "master",
+ "subject": "Change"
+}
diff --git a/src/test/resources/com/ericsson/gerrit/plugins/highavailability/scenarios/CreateChangeUsingHAGerrit1.json b/src/test/resources/com/ericsson/gerrit/plugins/highavailability/scenarios/CreateChangeUsingHAGerrit1.json
new file mode 100644
index 0000000..b535c1d
--- /dev/null
+++ b/src/test/resources/com/ericsson/gerrit/plugins/highavailability/scenarios/CreateChangeUsingHAGerrit1.json
@@ -0,0 +1,6 @@
+[
+ {
+ "url": "http://HOSTNAME:HTTP_PORT1/a/changes/",
+ "project": "_PROJECT"
+ }
+]
diff --git a/src/test/resources/com/ericsson/gerrit/plugins/highavailability/scenarios/CreateProjectUsingHAGerrit1-body.json b/src/test/resources/com/ericsson/gerrit/plugins/highavailability/scenarios/CreateProjectUsingHAGerrit1-body.json
new file mode 100644
index 0000000..bcf4708
--- /dev/null
+++ b/src/test/resources/com/ericsson/gerrit/plugins/highavailability/scenarios/CreateProjectUsingHAGerrit1-body.json
@@ -0,0 +1,3 @@
+{
+ "create_empty_commit": "true"
+}
diff --git a/src/test/resources/com/ericsson/gerrit/plugins/highavailability/scenarios/CreateProjectUsingHAGerrit1.json b/src/test/resources/com/ericsson/gerrit/plugins/highavailability/scenarios/CreateProjectUsingHAGerrit1.json
new file mode 100644
index 0000000..da3f028
--- /dev/null
+++ b/src/test/resources/com/ericsson/gerrit/plugins/highavailability/scenarios/CreateProjectUsingHAGerrit1.json
@@ -0,0 +1,5 @@
+[
+ {
+ "url": "http://HOSTNAME:HTTP_PORT1/a/projects/PROJECT"
+ }
+]
diff --git a/src/test/resources/com/ericsson/gerrit/plugins/highavailability/scenarios/CreateProjectUsingHAGerritTwice.json b/src/test/resources/com/ericsson/gerrit/plugins/highavailability/scenarios/CreateProjectUsingHAGerritTwice.json
new file mode 100644
index 0000000..da1a058
--- /dev/null
+++ b/src/test/resources/com/ericsson/gerrit/plugins/highavailability/scenarios/CreateProjectUsingHAGerritTwice.json
@@ -0,0 +1,4 @@
+[
+ {
+ }
+]
diff --git a/src/test/resources/com/ericsson/gerrit/plugins/highavailability/scenarios/DeleteChangeUsingHAGerrit2.json b/src/test/resources/com/ericsson/gerrit/plugins/highavailability/scenarios/DeleteChangeUsingHAGerrit2.json
new file mode 100644
index 0000000..8e0a304
--- /dev/null
+++ b/src/test/resources/com/ericsson/gerrit/plugins/highavailability/scenarios/DeleteChangeUsingHAGerrit2.json
@@ -0,0 +1,6 @@
+[
+ {
+ "url": "http://HOSTNAME:HTTP_PORT2/a/changes/",
+ "number": "NUMBER"
+ }
+]
diff --git a/src/test/resources/com/ericsson/gerrit/plugins/highavailability/scenarios/DeleteProjectUsingHAGerrit.json b/src/test/resources/com/ericsson/gerrit/plugins/highavailability/scenarios/DeleteProjectUsingHAGerrit.json
new file mode 100644
index 0000000..be47699
--- /dev/null
+++ b/src/test/resources/com/ericsson/gerrit/plugins/highavailability/scenarios/DeleteProjectUsingHAGerrit.json
@@ -0,0 +1,5 @@
+[
+ {
+ "url": "http://HOSTNAME/a/projects/PROJECT/delete-project~delete"
+ }
+]
diff --git a/src/test/resources/com/ericsson/gerrit/plugins/highavailability/scenarios/FlushProjectsCacheUsingHAGerrit2.json b/src/test/resources/com/ericsson/gerrit/plugins/highavailability/scenarios/FlushProjectsCacheUsingHAGerrit2.json
new file mode 100644
index 0000000..c938973
--- /dev/null
+++ b/src/test/resources/com/ericsson/gerrit/plugins/highavailability/scenarios/FlushProjectsCacheUsingHAGerrit2.json
@@ -0,0 +1,5 @@
+[
+ {
+ "url": "http://HOSTNAME:HTTP_PORT2/a/config/server/caches/projects/flush"
+ }
+]
diff --git a/src/test/resources/com/ericsson/gerrit/plugins/highavailability/scenarios/GetProjectsCacheEntries.json b/src/test/resources/com/ericsson/gerrit/plugins/highavailability/scenarios/GetProjectsCacheEntries.json
new file mode 100644
index 0000000..f7450a4
--- /dev/null
+++ b/src/test/resources/com/ericsson/gerrit/plugins/highavailability/scenarios/GetProjectsCacheEntries.json
@@ -0,0 +1,5 @@
+[
+ {
+ "url": "http://HOSTNAME/a/config/server/caches/projects"
+ }
+]
diff --git a/src/test/scala/com/ericsson/gerrit/plugins/highavailability/scenarios/CheckProjectsCacheFlushEntriesUsingHAGerrit1.scala b/src/test/scala/com/ericsson/gerrit/plugins/highavailability/scenarios/CheckProjectsCacheFlushEntriesUsingHAGerrit1.scala
new file mode 100644
index 0000000..10374f8
--- /dev/null
+++ b/src/test/scala/com/ericsson/gerrit/plugins/highavailability/scenarios/CheckProjectsCacheFlushEntriesUsingHAGerrit1.scala
@@ -0,0 +1,52 @@
+// Copyright (C) 2020 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.ericsson.gerrit.plugins.highavailability.scenarios
+
+import com.google.gerrit.scenarios.CacheFlushSimulation
+import io.gatling.core.Predef.{atOnceUsers, _}
+import io.gatling.core.feeder.FeederBuilder
+import io.gatling.core.structure.ScenarioBuilder
+import io.gatling.http.Predef._
+
+class CheckProjectsCacheFlushEntriesUsingHAGerrit1 extends CacheFlushSimulation {
+ private val data: FeederBuilder = jsonFile(resource).convert(keys).queue
+
+ override def replaceOverride(in: String): String = {
+ replaceProperty("http_port1", 8081, in)
+ }
+
+ def this(producer: CacheFlushSimulation) {
+ this()
+ this.producer = Some(producer)
+ }
+
+ val test: ScenarioBuilder = scenario(unique)
+ .feed(data)
+ .exec(session => {
+ if (producer.nonEmpty) {
+ session.set(entriesKey, producer.get.expectedEntriesAfterFlush())
+ } else {
+ session
+ }
+ })
+ .exec(http(unique).get("${url}")
+ .check(regex("\"" + memKey + "\": (\\d+)")
+ .is(session => session(entriesKey).as[String])))
+
+ setUp(
+ test.inject(
+ atOnceUsers(1)
+ )).protocols(httpProtocol)
+}
diff --git a/src/test/scala/com/ericsson/gerrit/plugins/highavailability/scenarios/CloneUsingHAGerrit2.scala b/src/test/scala/com/ericsson/gerrit/plugins/highavailability/scenarios/CloneUsingHAGerrit2.scala
new file mode 100644
index 0000000..13a741a
--- /dev/null
+++ b/src/test/scala/com/ericsson/gerrit/plugins/highavailability/scenarios/CloneUsingHAGerrit2.scala
@@ -0,0 +1,59 @@
+// Copyright (C) 2020 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.ericsson.gerrit.plugins.highavailability.scenarios
+
+import com.google.gerrit.scenarios.GitSimulation
+import io.gatling.core.Predef.{atOnceUsers, _}
+import io.gatling.core.feeder.FeederBuilder
+import io.gatling.core.structure.ScenarioBuilder
+
+import scala.concurrent.duration._
+
+class CloneUsingHAGerrit2 extends GitSimulation {
+ private val data: FeederBuilder = jsonFile(resource).convert(keys).queue
+ private var default: String = name
+
+ def this(default: String) {
+ this()
+ this.default = default
+ }
+
+ override def replaceOverride(in: String): String = {
+ val next = replaceProperty("http_port2", 8082, in)
+ replaceKeyWith("_project", default, next)
+ }
+
+ val test: ScenarioBuilder = scenario(unique)
+ .feed(data)
+ .exec(gitRequest)
+
+ private val createProject = new CreateProjectUsingHAGerrit1(default)
+ private val deleteProject = new DeleteProjectUsingHAGerrit(default)
+
+ setUp(
+ createProject.test.inject(
+ nothingFor(stepWaitTime(createProject) seconds),
+ atOnceUsers(1)
+ ),
+ test.inject(
+ nothingFor(stepWaitTime(this) seconds),
+ atOnceUsers(1)
+ ),
+ deleteProject.test.inject(
+ nothingFor(stepWaitTime(deleteProject) seconds),
+ atOnceUsers(1)
+ ),
+ ).protocols(gitProtocol, httpProtocol)
+}
diff --git a/src/test/scala/com/ericsson/gerrit/plugins/highavailability/scenarios/CreateChangeUsingHAGerrit1.scala b/src/test/scala/com/ericsson/gerrit/plugins/highavailability/scenarios/CreateChangeUsingHAGerrit1.scala
new file mode 100644
index 0000000..f07aabd
--- /dev/null
+++ b/src/test/scala/com/ericsson/gerrit/plugins/highavailability/scenarios/CreateChangeUsingHAGerrit1.scala
@@ -0,0 +1,68 @@
+// Copyright (C) 2020 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.ericsson.gerrit.plugins.highavailability.scenarios
+
+import com.google.gerrit.scenarios.GerritSimulation
+import io.gatling.core.Predef.{atOnceUsers, _}
+import io.gatling.core.feeder.FeederBuilder
+import io.gatling.core.structure.ScenarioBuilder
+import io.gatling.http.Predef._
+
+import scala.concurrent.duration._
+
+class CreateChangeUsingHAGerrit1 extends GerritSimulation {
+ private val data: FeederBuilder = jsonFile(resource).convert(keys).queue
+ private val default: String = name
+ private val numberKey = "_number"
+
+ override def relativeRuntimeWeight = 10
+
+ override def replaceOverride(in: String): String = {
+ replaceProperty("http_port1", 8081, in)
+ }
+
+ private val test: ScenarioBuilder = scenario(unique)
+ .feed(data)
+ .exec(httpRequest
+ .body(ElFileBody(body)).asJson
+ .check(regex("\"" + numberKey + "\":(\\d+),").saveAs(numberKey)))
+ .exec(session => {
+ deleteChange.number = Some(session(numberKey).as[Int])
+ session
+ })
+
+ private val createProject = new CreateProjectUsingHAGerrit1(default)
+ private val deleteProject = new DeleteProjectUsingHAGerrit(default)
+ private val deleteChange = new DeleteChangeUsingHAGerrit2
+
+ setUp(
+ createProject.test.inject(
+ nothingFor(stepWaitTime(createProject) seconds),
+ atOnceUsers(1)
+ ),
+ test.inject(
+ nothingFor(stepWaitTime(this) seconds),
+ atOnceUsers(1)
+ ),
+ deleteChange.test.inject(
+ nothingFor(stepWaitTime(deleteChange) seconds),
+ atOnceUsers(1)
+ ),
+ deleteProject.test.inject(
+ nothingFor(stepWaitTime(deleteProject) seconds),
+ atOnceUsers(1)
+ ),
+ ).protocols(httpProtocol)
+}
diff --git a/src/test/scala/com/ericsson/gerrit/plugins/highavailability/scenarios/CreateProjectUsingHAGerrit1.scala b/src/test/scala/com/ericsson/gerrit/plugins/highavailability/scenarios/CreateProjectUsingHAGerrit1.scala
new file mode 100644
index 0000000..964aadb
--- /dev/null
+++ b/src/test/scala/com/ericsson/gerrit/plugins/highavailability/scenarios/CreateProjectUsingHAGerrit1.scala
@@ -0,0 +1,43 @@
+// Copyright (C) 2020 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.ericsson.gerrit.plugins.highavailability.scenarios
+
+import com.google.gerrit.scenarios.ProjectSimulation
+import io.gatling.core.Predef._
+import io.gatling.core.feeder.FeederBuilder
+import io.gatling.core.structure.ScenarioBuilder
+
+class CreateProjectUsingHAGerrit1 extends ProjectSimulation {
+ private val data: FeederBuilder = jsonFile(resource).convert(keys).queue
+
+ def this(default: String) {
+ this()
+ this.default = default
+ }
+
+ override def replaceOverride(in: String): String = {
+ val next = replaceProperty("http_port1", 8081, in)
+ super.replaceOverride(next)
+ }
+
+ val test: ScenarioBuilder = scenario(unique)
+ .feed(data)
+ .exec(httpRequest.body(RawFileBody(body)).asJson)
+
+ setUp(
+ test.inject(
+ atOnceUsers(1)
+ )).protocols(httpProtocol)
+}
diff --git a/src/test/scala/com/ericsson/gerrit/plugins/highavailability/scenarios/CreateProjectUsingHAGerritTwice.scala b/src/test/scala/com/ericsson/gerrit/plugins/highavailability/scenarios/CreateProjectUsingHAGerritTwice.scala
new file mode 100644
index 0000000..a4da93c
--- /dev/null
+++ b/src/test/scala/com/ericsson/gerrit/plugins/highavailability/scenarios/CreateProjectUsingHAGerritTwice.scala
@@ -0,0 +1,53 @@
+// Copyright (C) 2020 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.ericsson.gerrit.plugins.highavailability.scenarios
+
+import com.google.gerrit.scenarios.GitSimulation
+import io.gatling.core.Predef.{atOnceUsers, _}
+
+import scala.concurrent.duration._
+
+class CreateProjectUsingHAGerritTwice extends GitSimulation {
+ private val default: String = name
+
+ private val createProject = new CreateProjectUsingHAGerrit1(default)
+ private val deleteProject = new DeleteProjectUsingHAGerrit(default)
+ private val createItAgain = new CreateProjectUsingHAGerrit1(default)
+ private val verifyProject = new CloneUsingHAGerrit2(default)
+ private val deleteItAfter = new DeleteProjectUsingHAGerrit(default)
+
+ setUp(
+ createProject.test.inject(
+ nothingFor(stepWaitTime(createProject) seconds),
+ atOnceUsers(1)
+ ),
+ deleteProject.test.inject(
+ nothingFor(stepWaitTime(deleteProject) seconds),
+ atOnceUsers(1)
+ ),
+ createItAgain.test.inject(
+ nothingFor(stepWaitTime(createItAgain) seconds),
+ atOnceUsers(1)
+ ),
+ verifyProject.test.inject(
+ nothingFor(stepWaitTime(verifyProject) seconds),
+ atOnceUsers(1)
+ ),
+ deleteItAfter.test.inject(
+ nothingFor(stepWaitTime(deleteItAfter) seconds),
+ atOnceUsers(1)
+ ),
+ ).protocols(gitProtocol, httpProtocol)
+}
diff --git a/src/test/scala/com/ericsson/gerrit/plugins/highavailability/scenarios/DeleteChangeUsingHAGerrit2.scala b/src/test/scala/com/ericsson/gerrit/plugins/highavailability/scenarios/DeleteChangeUsingHAGerrit2.scala
new file mode 100644
index 0000000..5b0f461
--- /dev/null
+++ b/src/test/scala/com/ericsson/gerrit/plugins/highavailability/scenarios/DeleteChangeUsingHAGerrit2.scala
@@ -0,0 +1,48 @@
+// Copyright (C) 2020 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.ericsson.gerrit.plugins.highavailability.scenarios
+
+import com.google.gerrit.scenarios.GerritSimulation
+import io.gatling.core.Predef.{atOnceUsers, _}
+import io.gatling.core.feeder.FeederBuilder
+import io.gatling.core.structure.ScenarioBuilder
+import io.gatling.http.Predef.http
+
+class DeleteChangeUsingHAGerrit2 extends GerritSimulation {
+ private val data: FeederBuilder = jsonFile(resource).convert(keys).queue
+ var number: Option[Int] = None
+
+ override def relativeRuntimeWeight = 10
+
+ override def replaceOverride(in: String): String = {
+ replaceProperty("http_port2", 8082, in)
+ }
+
+ val test: ScenarioBuilder = scenario(unique)
+ .feed(data)
+ .exec(session => {
+ if (number.nonEmpty) {
+ session.set("number", number.get)
+ } else {
+ session
+ }
+ })
+ .exec(http(unique).delete("${url}${number}"))
+
+ setUp(
+ test.inject(
+ atOnceUsers(1)
+ )).protocols(httpProtocol)
+}
diff --git a/src/test/scala/com/ericsson/gerrit/plugins/highavailability/scenarios/DeleteProjectUsingHAGerrit.scala b/src/test/scala/com/ericsson/gerrit/plugins/highavailability/scenarios/DeleteProjectUsingHAGerrit.scala
new file mode 100644
index 0000000..428085d
--- /dev/null
+++ b/src/test/scala/com/ericsson/gerrit/plugins/highavailability/scenarios/DeleteProjectUsingHAGerrit.scala
@@ -0,0 +1,38 @@
+// Copyright (C) 2020 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.ericsson.gerrit.plugins.highavailability.scenarios
+
+import com.google.gerrit.scenarios.ProjectSimulation
+import io.gatling.core.Predef._
+import io.gatling.core.feeder.FeederBuilder
+import io.gatling.core.structure.ScenarioBuilder
+
+class DeleteProjectUsingHAGerrit extends ProjectSimulation {
+ private val data: FeederBuilder = jsonFile(resource).convert(keys).queue
+
+ def this(default: String) {
+ this()
+ this.default = default
+ }
+
+ val test: ScenarioBuilder = scenario(unique)
+ .feed(data)
+ .exec(httpRequest)
+
+ setUp(
+ test.inject(
+ atOnceUsers(1)
+ )).protocols(httpProtocol)
+}
diff --git a/src/test/scala/com/ericsson/gerrit/plugins/highavailability/scenarios/FlushProjectsCacheUsingHAGerrit2.scala b/src/test/scala/com/ericsson/gerrit/plugins/highavailability/scenarios/FlushProjectsCacheUsingHAGerrit2.scala
new file mode 100644
index 0000000..9c317d4
--- /dev/null
+++ b/src/test/scala/com/ericsson/gerrit/plugins/highavailability/scenarios/FlushProjectsCacheUsingHAGerrit2.scala
@@ -0,0 +1,65 @@
+// Copyright (C) 2020 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.ericsson.gerrit.plugins.highavailability.scenarios
+
+import com.google.gerrit.scenarios.CacheFlushSimulation
+import io.gatling.core.Predef._
+import io.gatling.core.feeder.FeederBuilder
+import io.gatling.core.structure.ScenarioBuilder
+
+import scala.concurrent.duration._
+
+class FlushProjectsCacheUsingHAGerrit2 extends CacheFlushSimulation {
+ private val data: FeederBuilder = jsonFile(resource).convert(keys).queue
+ private val default: String = name
+
+ override def relativeRuntimeWeight = 2
+
+ override def replaceOverride(in: String): String = {
+ replaceProperty("http_port2", 8082, in)
+ }
+
+ private val flushCache: ScenarioBuilder = scenario(unique)
+ .feed(data)
+ .exec(httpRequest)
+
+ private val createProject = new CreateProjectUsingHAGerrit1(default)
+ private val getCacheEntriesAfterProject = new GetProjectsCacheEntries(this)
+ private val checkCacheEntriesAfterFlush = new CheckProjectsCacheFlushEntriesUsingHAGerrit1(this)
+ private val deleteProject = new DeleteProjectUsingHAGerrit(default)
+
+ setUp(
+ createProject.test.inject(
+ nothingFor(stepWaitTime(createProject) seconds),
+ atOnceUsers(1)
+ ),
+ getCacheEntriesAfterProject.test.inject(
+ nothingFor(stepWaitTime(getCacheEntriesAfterProject) seconds),
+ atOnceUsers(1)
+ ),
+ flushCache.inject(
+ nothingFor(stepWaitTime(this) seconds),
+ atOnceUsers(1)
+ ),
+ checkCacheEntriesAfterFlush.test.inject(
+ nothingFor(stepWaitTime(checkCacheEntriesAfterFlush) seconds),
+ atOnceUsers(1)
+ ),
+ deleteProject.test.inject(
+ nothingFor(stepWaitTime(deleteProject) seconds),
+ atOnceUsers(1)
+ ),
+ ).protocols(httpProtocol)
+}
diff --git a/src/test/scala/com/ericsson/gerrit/plugins/highavailability/scenarios/GetProjectsCacheEntries.scala b/src/test/scala/com/ericsson/gerrit/plugins/highavailability/scenarios/GetProjectsCacheEntries.scala
new file mode 100644
index 0000000..9565365
--- /dev/null
+++ b/src/test/scala/com/ericsson/gerrit/plugins/highavailability/scenarios/GetProjectsCacheEntries.scala
@@ -0,0 +1,46 @@
+// Copyright (C) 2020 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.ericsson.gerrit.plugins.highavailability.scenarios
+
+import com.google.gerrit.scenarios.CacheFlushSimulation
+import io.gatling.core.Predef._
+import io.gatling.core.feeder.FeederBuilder
+import io.gatling.core.structure.ScenarioBuilder
+import io.gatling.http.Predef.{http, _}
+
+class GetProjectsCacheEntries extends CacheFlushSimulation {
+ private val data: FeederBuilder = jsonFile(resource).convert(keys).queue
+
+ def this(consumer: CacheFlushSimulation) {
+ this()
+ this.consumer = Some(consumer)
+ }
+
+ val test: ScenarioBuilder = scenario(unique)
+ .feed(data)
+ .exec(http(unique).get("${url}")
+ .check(regex("\"" + memKey + "\": (\\d+)").saveAs(entriesKey)))
+ .exec(session => {
+ if (consumer.nonEmpty) {
+ consumer.get.entriesBeforeFlush(session(entriesKey).as[Int])
+ }
+ session
+ })
+
+ setUp(
+ test.inject(
+ atOnceUsers(1)
+ )).protocols(httpProtocol)
+}