Merge branch 'stable-2.16'
* stable-2.16:
Design documentation
Remove empty unused file
Healthcheck: remove from the configuration
AutoReindex: remove from the configuration
Fix eclipse warning about missing serialVersionUID
Remove obsolete configuration parameters
Delete rest forwarder and autoreindexer modules
ForwardedEventHandler: open request context when dispatching
Ensure proper context during deserialization
CacheEvictionEventRouter: Fix unneeded cast warning in eclipse
Allow configuration of kafka specific props
Flogger: rely on native cause formatting
Fix serialization of comment events
Change-Id: I7008a75bd1c98426f3c4d144e401482588ca0b9e
diff --git a/BUILD b/BUILD
index bab2335..08d9d5c 100644
--- a/BUILD
+++ b/BUILD
@@ -12,7 +12,6 @@
manifest_entries = [
"Gerrit-PluginName: multi-site",
"Gerrit-Module: com.googlesource.gerrit.plugins.multisite.Module",
- "Gerrit-HttpModule: com.googlesource.gerrit.plugins.multisite.HttpModule",
"Implementation-Title: multi-site plugin",
"Implementation-URL: https://review.gerrithub.io/admin/repos/GerritForge/plugins_multi-site",
],
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/Configuration.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/Configuration.java
index 483c3b2..f6c617d 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/Configuration.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/Configuration.java
@@ -15,12 +15,9 @@
package com.googlesource.gerrit.plugins.multisite;
import com.google.common.base.CaseFormat;
-import com.google.common.base.CharMatcher;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
import com.google.gerrit.extensions.annotations.PluginName;
-import com.google.gerrit.server.config.ConfigUtil;
import com.google.gerrit.server.config.PluginConfigFactory;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -30,12 +27,8 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.Properties;
-import java.util.Set;
import java.util.UUID;
-import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
import org.apache.kafka.common.serialization.StringSerializer;
import org.eclipse.jgit.lib.Config;
import org.slf4j.Logger;
@@ -46,14 +39,13 @@
private static final Logger log = LoggerFactory.getLogger(Configuration.class);
static final String INSTANCE_ID_FILE = "instanceId.data";
- // common parameter to peerInfo section
- static final String PEER_INFO_SECTION = "peerInfo";
// common parameters to cache and index sections
static final String THREAD_POOL_SIZE_KEY = "threadPoolSize";
static final int DEFAULT_INDEX_MAX_TRIES = 2;
static final int DEFAULT_INDEX_RETRY_INTERVAL = 30000;
+ private static final int DEFAULT_POLLING_INTERVAL_MS = 1000;
static final int DEFAULT_THREAD_POOL_SIZE = 4;
static final String NUM_STRIPED_LOCKS = "numStripedLocks";
static final int DEFAULT_NUM_STRIPED_LOCKS = 10;
@@ -61,18 +53,14 @@
static final String DEFAULT_KAFKA_BOOTSTRAP_SERVERS = "localhost:9092";
static final boolean DEFAULT_ENABLE_PROCESSING = true;
static final String KAFKA_SECTION = "kafka";
+ public static final String KAFKA_PROPERTY_PREFIX = "KafkaProp-";
- private final AutoReindex autoReindex;
- private final PeerInfo peerInfo;
private final KafkaPublisher publisher;
- private final Http http;
private final Cache cache;
private final Event event;
private final Index index;
private final KafkaSubscriber subscriber;
private final Kafka kafka;
- private PeerInfoStatic peerInfoStatic;
- private HealthCheck healthCheck;
public enum PeerInfoStrategy {
STATIC
@@ -81,23 +69,12 @@
@Inject
Configuration(PluginConfigFactory pluginConfigFactory, @PluginName String pluginName) {
Config cfg = pluginConfigFactory.getGlobalPluginConfig(pluginName);
- autoReindex = new AutoReindex(cfg);
- peerInfo = new PeerInfo(cfg);
- switch (peerInfo.strategy()) {
- case STATIC:
- peerInfoStatic = new PeerInfoStatic(cfg);
- break;
- default:
- throw new IllegalArgumentException("Not supported strategy: " + peerInfo.strategy);
- }
kafka = new Kafka(cfg);
publisher = new KafkaPublisher(cfg);
- http = new Http(cfg);
+ subscriber = new KafkaSubscriber(cfg);
cache = new Cache(cfg);
event = new Event(cfg);
index = new Index(cfg);
- healthCheck = new HealthCheck(cfg);
- subscriber = new KafkaSubscriber(cfg);
}
public Kafka getKafka() {
@@ -108,22 +85,6 @@
return publisher;
}
- public AutoReindex autoReindex() {
- return autoReindex;
- }
-
- public PeerInfo peerInfo() {
- return peerInfo;
- }
-
- public PeerInfoStatic peerInfoStatic() {
- return peerInfoStatic;
- }
-
- public Http http() {
- return http;
- }
-
public Cache cache() {
return cache;
}
@@ -136,10 +97,6 @@
return index;
}
- public HealthCheck healthCheck() {
- return healthCheck;
- }
-
public KafkaSubscriber kafkaSubscriber() {
return subscriber;
}
@@ -163,76 +120,6 @@
return defaultValue;
}
- public static class AutoReindex {
- static final String AUTO_REINDEX_SECTION = "autoReindex";
- static final String DELAY = "delay";
- static final String POLL_INTERVAL = "pollInterval";
-
- private final boolean enabled;
- private final long delaySec;
- private final long pollSec;
-
- public AutoReindex(Config cfg) {
- this.enabled = cfg.getBoolean(AUTO_REINDEX_SECTION, ENABLE_KEY, false);
- this.delaySec =
- ConfigUtil.getTimeUnit(cfg, AUTO_REINDEX_SECTION, null, DELAY, 10L, TimeUnit.SECONDS);
- this.pollSec =
- ConfigUtil.getTimeUnit(
- cfg, AUTO_REINDEX_SECTION, null, POLL_INTERVAL, 0L, TimeUnit.SECONDS);
- }
-
- public boolean enabled() {
- return enabled;
- }
-
- public long delaySec() {
- return delaySec;
- }
-
- public long pollSec() {
- return pollSec;
- }
- }
-
- public static class PeerInfo {
- static final PeerInfoStrategy DEFAULT_PEER_INFO_STRATEGY = PeerInfoStrategy.STATIC;
- static final String STRATEGY_KEY = "strategy";
-
- private final PeerInfoStrategy strategy;
-
- 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());
- }
- }
-
- public PeerInfoStrategy strategy() {
- return strategy;
- }
- }
-
- public static class PeerInfoStatic {
- public static final String STATIC_SUBSECTION = PeerInfoStrategy.STATIC.name().toLowerCase();
- public static final String URL_KEY = "url";
-
- private final Set<String> urls;
-
- private PeerInfoStatic(Config cfg) {
- urls =
- Arrays.stream(cfg.getStringList(PEER_INFO_SECTION, STATIC_SUBSECTION, URL_KEY))
- .filter(Objects::nonNull)
- .filter(s -> !s.isEmpty())
- .map(s -> CharMatcher.is('/').trimTrailingFrom(s))
- .collect(Collectors.toSet());
- log.debug("Urls: {}", urls);
- }
-
- public Set<String> urls() {
- return ImmutableSet.copyOf(urls);
- }
- }
-
private static Map<EventFamily, Boolean> eventsEnabled(Config config, String subsection) {
Map<EventFamily, Boolean> eventsEnabled = new HashMap<>();
for (EventFamily eventFamily : EventFamily.values()) {
@@ -250,10 +137,16 @@
for (String section : config.getSubsections(KAFKA_SECTION)) {
if (section.equals(subsectionName)) {
for (String name : config.getNames(KAFKA_SECTION, section, true)) {
- Object value = config.getString(KAFKA_SECTION, subsectionName, name);
- String propName =
- CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, name).replaceAll("-", ".");
- target.put(propName, value);
+ if (name.startsWith(KAFKA_PROPERTY_PREFIX)) {
+ Object value = config.getString(KAFKA_SECTION, subsectionName, name);
+ String configProperty = name.replaceFirst(KAFKA_PROPERTY_PREFIX, "");
+ String propName =
+ CaseFormat.LOWER_CAMEL
+ .to(CaseFormat.LOWER_HYPHEN, configProperty)
+ .replaceAll("-", ".");
+ log.info("[{}] Setting kafka property: {} = {}", subsectionName, propName, value);
+ target.put(propName, value);
+ }
}
}
}
@@ -341,25 +234,32 @@
}
}
- public class KafkaSubscriber {
+ public class KafkaSubscriber extends Properties {
+ private static final long serialVersionUID = 1L;
+
static final String KAFKA_SUBSCRIBER_SUBSECTION = "subscriber";
private final boolean enabled;
private final Integer pollingInterval;
- private final Properties props = new Properties();
private Map<EventFamily, Boolean> eventsEnabled;
private final Config cfg;
public KafkaSubscriber(Config cfg) {
this.pollingInterval =
- cfg.getInt(KAFKA_SECTION, KAFKA_SUBSCRIBER_SUBSECTION, "pollingIntervalMs", 1000);
+ cfg.getInt(
+ KAFKA_SECTION,
+ KAFKA_SUBSCRIBER_SUBSECTION,
+ "pollingIntervalMs",
+ DEFAULT_POLLING_INTERVAL_MS);
this.cfg = cfg;
enabled = cfg.getBoolean(KAFKA_SECTION, KAFKA_SUBSCRIBER_SUBSECTION, ENABLE_KEY, false);
eventsEnabled = eventsEnabled(cfg, KAFKA_SUBSCRIBER_SUBSECTION);
- applyKafkaConfig(cfg, KAFKA_SUBSCRIBER_SUBSECTION, props);
+ if (enabled) {
+ applyKafkaConfig(cfg, KAFKA_SUBSCRIBER_SUBSECTION, this);
+ }
}
public boolean enabled() {
@@ -370,13 +270,13 @@
return eventsEnabled.get(eventFamily);
}
- public Properties getProps(UUID instanceId) {
+ public Properties initPropsWith(UUID instanceId) {
String groupId =
getString(
cfg, KAFKA_SECTION, KAFKA_SUBSCRIBER_SUBSECTION, "groupId", instanceId.toString());
- props.put("group.id", groupId);
+ this.put("group.id", groupId);
- return props;
+ return this;
}
public Integer getPollingInterval() {
@@ -393,77 +293,6 @@
}
}
- public static class Http {
- static final String HTTP_SECTION = "http";
- static final String USER_KEY = "user";
- static final String PASSWORD_KEY = "password";
- static final String CONNECTION_TIMEOUT_KEY = "connectionTimeout";
- static final String SOCKET_TIMEOUT_KEY = "socketTimeout";
- static final String MAX_TRIES_KEY = "maxTries";
- static final String RETRY_INTERVAL_KEY = "retryInterval";
- static final boolean DEFAULT_HTTP_ENABLED = true;
-
- static final int DEFAULT_TIMEOUT_MS = 5000;
- static final int DEFAULT_MAX_TRIES = 360;
- static final int DEFAULT_RETRY_INTERVAL = 10000;
-
- private final boolean enabled;
- private final String user;
- private final String password;
- private final int connectionTimeout;
- private final int socketTimeout;
- private final int maxTries;
- private final int retryInterval;
- private final Map<EventFamily, Boolean> eventsEnabled;
-
- private Http(Config cfg) {
- enabled = cfg.getBoolean(HTTP_SECTION, ENABLE_KEY, DEFAULT_HTTP_ENABLED);
- user = Strings.nullToEmpty(cfg.getString(HTTP_SECTION, null, USER_KEY));
- password = Strings.nullToEmpty(cfg.getString(HTTP_SECTION, null, PASSWORD_KEY));
- connectionTimeout = getInt(cfg, HTTP_SECTION, CONNECTION_TIMEOUT_KEY, DEFAULT_TIMEOUT_MS);
- socketTimeout = getInt(cfg, HTTP_SECTION, SOCKET_TIMEOUT_KEY, DEFAULT_TIMEOUT_MS);
- maxTries = getInt(cfg, HTTP_SECTION, MAX_TRIES_KEY, DEFAULT_MAX_TRIES);
- retryInterval = getInt(cfg, HTTP_SECTION, RETRY_INTERVAL_KEY, DEFAULT_RETRY_INTERVAL);
- eventsEnabled = new HashMap<>();
- for (EventFamily eventFamily : EventFamily.values()) {
- String enabledConfigKey = eventFamily.lowerCamelName() + "Enabled";
- eventsEnabled.put(eventFamily, cfg.getBoolean(HTTP_SECTION, null, enabledConfigKey, true));
- }
- }
-
- public boolean enabled() {
- return enabled;
- }
-
- public String user() {
- return user;
- }
-
- public String password() {
- return password;
- }
-
- public int connectionTimeout() {
- return connectionTimeout;
- }
-
- public int socketTimeout() {
- return socketTimeout;
- }
-
- public int maxTries() {
- return maxTries;
- }
-
- public int retryInterval() {
- return retryInterval;
- }
-
- public boolean enabledEvent(EventFamily eventFamily) {
- return eventsEnabled.get(eventFamily);
- }
- }
-
/** Common parameters to cache, event, index */
public abstract static class Forwarding {
static final boolean DEFAULT_SYNCHRONIZE = true;
@@ -556,19 +385,4 @@
return numStripedLocks;
}
}
-
- public static class HealthCheck {
- static final String HEALTH_CHECK_SECTION = "healthCheck";
- static final boolean DEFAULT_HEALTH_CHECK_ENABLED = true;
-
- private final boolean enabled;
-
- private HealthCheck(Config cfg) {
- enabled = cfg.getBoolean(HEALTH_CHECK_SECTION, ENABLE_KEY, DEFAULT_HEALTH_CHECK_ENABLED);
- }
-
- public boolean enabled() {
- return enabled;
- }
- }
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/HttpModule.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/HttpModule.java
deleted file mode 100644
index c58eb90..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/HttpModule.java
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (C) 2015 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite;
-
-import com.google.gerrit.httpd.plugins.HttpPluginModule;
-import com.googlesource.gerrit.plugins.multisite.forwarder.rest.RestForwarderServletModule;
-
-class HttpModule extends HttpPluginModule {
- @Override
- protected void configureServlets() {
- install(new RestForwarderServletModule());
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/Module.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/Module.java
index 8bbf68b..0b4efaa 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/Module.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/Module.java
@@ -20,17 +20,14 @@
import com.google.inject.Inject;
import com.google.inject.Provides;
import com.google.inject.Singleton;
-import com.googlesource.gerrit.plugins.multisite.autoreindex.AutoReindexModule;
import com.googlesource.gerrit.plugins.multisite.broker.GsonProvider;
import com.googlesource.gerrit.plugins.multisite.cache.CacheModule;
import com.googlesource.gerrit.plugins.multisite.event.EventModule;
import com.googlesource.gerrit.plugins.multisite.forwarder.ForwarderModule;
import com.googlesource.gerrit.plugins.multisite.forwarder.broker.BrokerForwarderModule;
-import com.googlesource.gerrit.plugins.multisite.forwarder.rest.RestForwarderModule;
import com.googlesource.gerrit.plugins.multisite.index.IndexModule;
import com.googlesource.gerrit.plugins.multisite.kafka.consumer.KafkaConsumerModule;
import com.googlesource.gerrit.plugins.multisite.kafka.router.ForwardedEventRouterModule;
-import com.googlesource.gerrit.plugins.multisite.peers.PeerInfoModule;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
@@ -55,9 +52,6 @@
install(new ForwarderModule());
- if (config.http().enabled()) {
- install(new RestForwarderModule(config.http()));
- }
if (config.cache().synchronize()) {
install(new CacheModule());
}
@@ -67,10 +61,6 @@
if (config.index().synchronize()) {
install(new IndexModule());
}
- if (config.autoReindex().enabled()) {
- install(new AutoReindexModule());
- }
- install(new PeerInfoModule(config.peerInfo().strategy()));
if (config.kafkaSubscriber().enabled()) {
install(new KafkaConsumerModule(config.kafkaSubscriber()));
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/Setup.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/Setup.java
index d2f7456..c101dfd 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/Setup.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/Setup.java
@@ -16,21 +16,7 @@
import static com.googlesource.gerrit.plugins.multisite.Configuration.Cache.CACHE_SECTION;
import static com.googlesource.gerrit.plugins.multisite.Configuration.DEFAULT_THREAD_POOL_SIZE;
-import static com.googlesource.gerrit.plugins.multisite.Configuration.Http.CONNECTION_TIMEOUT_KEY;
-import static com.googlesource.gerrit.plugins.multisite.Configuration.Http.DEFAULT_MAX_TRIES;
-import static com.googlesource.gerrit.plugins.multisite.Configuration.Http.DEFAULT_RETRY_INTERVAL;
-import static com.googlesource.gerrit.plugins.multisite.Configuration.Http.DEFAULT_TIMEOUT_MS;
-import static com.googlesource.gerrit.plugins.multisite.Configuration.Http.HTTP_SECTION;
-import static com.googlesource.gerrit.plugins.multisite.Configuration.Http.PASSWORD_KEY;
-import static com.googlesource.gerrit.plugins.multisite.Configuration.Http.RETRY_INTERVAL_KEY;
-import static com.googlesource.gerrit.plugins.multisite.Configuration.Http.SOCKET_TIMEOUT_KEY;
-import static com.googlesource.gerrit.plugins.multisite.Configuration.Http.USER_KEY;
import static com.googlesource.gerrit.plugins.multisite.Configuration.Index.INDEX_SECTION;
-import static com.googlesource.gerrit.plugins.multisite.Configuration.Index.MAX_TRIES_KEY;
-import static com.googlesource.gerrit.plugins.multisite.Configuration.PEER_INFO_SECTION;
-import static com.googlesource.gerrit.plugins.multisite.Configuration.PeerInfo.STRATEGY_KEY;
-import static com.googlesource.gerrit.plugins.multisite.Configuration.PeerInfoStatic.STATIC_SUBSECTION;
-import static com.googlesource.gerrit.plugins.multisite.Configuration.PeerInfoStatic.URL_KEY;
import static com.googlesource.gerrit.plugins.multisite.Configuration.THREAD_POOL_SIZE_KEY;
import com.google.common.base.Strings;
@@ -40,9 +26,7 @@
import com.google.gerrit.pgm.init.api.InitStep;
import com.google.gerrit.server.config.SitePaths;
import com.google.inject.Inject;
-import com.googlesource.gerrit.plugins.multisite.Configuration.PeerInfoStrategy;
import java.nio.file.Path;
-import java.util.EnumSet;
import java.util.Objects;
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.eclipse.jgit.util.FS;
@@ -74,43 +58,12 @@
Path pluginConfigFile = site.etc_dir.resolve(pluginName + ".config");
config = new FileBasedConfig(pluginConfigFile.toFile(), FS.DETECTED);
config.load();
- configurePeerInfoSection();
- configureHttp();
configureCacheSection();
configureIndexSection();
flags.cfg.setBoolean("database", "h2", "autoServer", true);
}
}
- private void configurePeerInfoSection() {
- ui.header("PeerInfo section");
- PeerInfoStrategy strategy =
- ui.readEnum(
- PeerInfoStrategy.STATIC, EnumSet.allOf(PeerInfoStrategy.class), "Peer info strategy");
- config.setEnum(PEER_INFO_SECTION, null, STRATEGY_KEY, strategy);
- if (strategy == PeerInfoStrategy.STATIC) {
- promptAndSetString(
- titleWithNote("Peer URL", "urls"), PEER_INFO_SECTION, STATIC_SUBSECTION, URL_KEY, null);
- }
- }
-
- private void configureHttp() {
- ui.header("Http section");
- promptAndSetString("User", HTTP_SECTION, USER_KEY, null);
- promptAndSetString("Password", HTTP_SECTION, PASSWORD_KEY, null);
- promptAndSetString(
- "Max number of tries to forward to remote peer",
- HTTP_SECTION,
- MAX_TRIES_KEY,
- str(DEFAULT_MAX_TRIES));
- promptAndSetString(
- "Retry interval [ms]", HTTP_SECTION, RETRY_INTERVAL_KEY, str(DEFAULT_RETRY_INTERVAL));
- promptAndSetString(
- "Connection timeout [ms]", HTTP_SECTION, CONNECTION_TIMEOUT_KEY, str(DEFAULT_TIMEOUT_MS));
- promptAndSetString(
- "Socket timeout [ms]", HTTP_SECTION, SOCKET_TIMEOUT_KEY, str(DEFAULT_TIMEOUT_MS));
- }
-
private void configureCacheSection() {
ui.header("Cache section");
promptAndSetString(
@@ -152,10 +105,6 @@
return Integer.toString(n);
}
- private static String titleWithNote(String prefix, String suffix) {
- return prefix + "; manually repeat this line to configure more " + suffix;
- }
-
@Override
public void postRun() {}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/SetupLocalHAReplica.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/SetupLocalHAReplica.java
deleted file mode 100644
index ed927dc..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/SetupLocalHAReplica.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.googlesource.gerrit.plugins.multisite;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/autoreindex/AccountReindexRunnable.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/autoreindex/AccountReindexRunnable.java
deleted file mode 100644
index 3396301..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/autoreindex/AccountReindexRunnable.java
+++ /dev/null
@@ -1,71 +0,0 @@
-// 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.googlesource.gerrit.plugins.multisite.autoreindex;
-
-import com.google.gerrit.reviewdb.client.Account;
-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;
-import com.google.inject.Inject;
-import com.googlesource.gerrit.plugins.multisite.forwarder.ForwardedIndexAccountHandler;
-import com.googlesource.gerrit.plugins.multisite.forwarder.ForwardedIndexingHandler.Operation;
-import com.googlesource.gerrit.plugins.multisite.forwarder.rest.AbstractIndexRestApiServlet;
-
-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<AccountState> {
- private static final Logger log = LoggerFactory.getLogger(AccountReindexRunnable.class);
-
- private final ForwardedIndexAccountHandler accountIdx;
-
- private final Accounts accounts;
-
- @Inject
- public AccountReindexRunnable(
- ForwardedIndexAccountHandler accountIdx,
- IndexTs indexTs,
- OneOffRequestContext ctx,
- Accounts accounts) {
- super(AbstractIndexRestApiServlet.IndexName.ACCOUNT, indexTs, ctx);
- this.accountIdx = accountIdx;
- this.accounts = accounts;
- }
-
- @Override
- protected Iterable<AccountState> fetchItems() throws Exception {
- return accounts.all();
- }
-
- @Override
- protected Optional<Timestamp> indexIfNeeded(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);
- accountIdx.index(a.getId(), Operation.INDEX, Optional.empty());
- return Optional.of(accountTs);
- }
- } catch (IOException | OrmException e) {
- log.error("Reindex failed", e);
- }
- return Optional.empty();
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/autoreindex/AutoReindexModule.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/autoreindex/AutoReindexModule.java
deleted file mode 100644
index b78123e..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/autoreindex/AutoReindexModule.java
+++ /dev/null
@@ -1,33 +0,0 @@
-// 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.googlesource.gerrit.plugins.multisite.autoreindex;
-
-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.LifecycleListener;
-import com.google.gerrit.extensions.registration.DynamicSet;
-import com.google.inject.AbstractModule;
-
-public class AutoReindexModule extends AbstractModule {
-
- @Override
- protected void configure() {
- DynamicSet.bind(binder(), LifecycleListener.class).to(AutoReindexScheduler.class);
- DynamicSet.bind(binder(), ChangeIndexedListener.class).to(IndexTs.class);
- DynamicSet.bind(binder(), AccountIndexedListener.class).to(IndexTs.class);
- DynamicSet.bind(binder(), GroupIndexedListener.class).to(IndexTs.class);
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/autoreindex/AutoReindexScheduler.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/autoreindex/AutoReindexScheduler.java
deleted file mode 100644
index e7ee7a8..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/autoreindex/AutoReindexScheduler.java
+++ /dev/null
@@ -1,87 +0,0 @@
-// 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.googlesource.gerrit.plugins.multisite.autoreindex;
-
-import com.google.gerrit.extensions.events.LifecycleListener;
-import com.google.gerrit.server.git.WorkQueue;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import com.googlesource.gerrit.plugins.multisite.Configuration;
-import java.util.ArrayList;
-import java.util.List;
-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 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<>();
-
- @Inject
- public AutoReindexScheduler(
- Configuration cfg,
- WorkQueue workQueue,
- ChangeReindexRunnable changeReindex,
- AccountReindexRunnable accountReindex,
- 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, "MultiSite-AutoReindex");
- }
-
- @Override
- public void start() {
- if (cfg.pollSec() > 0) {
- log.info("Scheduling auto-reindex after {}s and every {}s", cfg.delaySec(), cfg.pollSec());
- futureTasks.add(
- executor.scheduleAtFixedRate(
- changeReindex, cfg.delaySec(), cfg.pollSec(), TimeUnit.SECONDS));
- futureTasks.add(
- executor.scheduleAtFixedRate(
- accountReindex, cfg.delaySec(), cfg.pollSec(), TimeUnit.SECONDS));
- 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());
- 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));
- }
- }
-
- @Override
- public void stop() {
- futureTasks.forEach(t -> t.cancel(true));
- executor.shutdown();
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/autoreindex/ChangeReindexRunnable.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/autoreindex/ChangeReindexRunnable.java
deleted file mode 100644
index a99efa6..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/autoreindex/ChangeReindexRunnable.java
+++ /dev/null
@@ -1,114 +0,0 @@
-// 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.googlesource.gerrit.plugins.multisite.autoreindex;
-
-import com.google.common.collect.Streams;
-import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.notedb.ChangeNotes;
-import com.google.gerrit.server.notedb.ChangeNotes.Factory.ChangeNotesResult;
-import com.google.gerrit.server.project.ProjectCache;
-import com.google.gerrit.server.util.OneOffRequestContext;
-import com.google.gwtorm.server.OrmException;
-import com.google.inject.Inject;
-import com.googlesource.gerrit.plugins.multisite.forwarder.ForwardedIndexChangeHandler;
-import com.googlesource.gerrit.plugins.multisite.forwarder.ForwardedIndexingHandler.Operation;
-import com.googlesource.gerrit.plugins.multisite.forwarder.rest.AbstractIndexRestApiServlet;
-
-import java.io.IOException;
-import java.sql.Timestamp;
-import java.util.Iterator;
-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 final ForwardedIndexChangeHandler changeIdx;
-
- private final ProjectCache projectCache;
-
- private final GitRepositoryManager repoManager;
-
- private final ChangeNotes.Factory notesFactory;
-
- private static class StreamIterable implements Iterable<Change> {
-
- private final Stream<Change> stream;
-
- public StreamIterable(Stream<Change> stream) {
- this.stream = stream;
- }
-
- @Override
- public Iterator<Change> iterator() {
- return stream.iterator();
- }
- }
-
- @Inject
- public ChangeReindexRunnable(
- ForwardedIndexChangeHandler changeIdx,
- IndexTs indexTs,
- OneOffRequestContext ctx,
- ProjectCache projectCache,
- GitRepositoryManager repoManager,
- ChangeNotes.Factory notesFactory) {
- super(AbstractIndexRestApiServlet.IndexName.CHANGE, indexTs, ctx);
- this.changeIdx = changeIdx;
- this.projectCache = projectCache;
- this.repoManager = repoManager;
- this.notesFactory = notesFactory;
- }
-
- @Override
- protected Iterable<Change> fetchItems() throws Exception {
- Stream<Change> allChangesStream = Stream.empty();
- Iterable<Project.NameKey> projects = projectCache.all();
- for (Project.NameKey projectName : projects) {
- try (Repository repo = repoManager.openRepository(projectName)) {
- Stream<Change> projectChangesStream =
- notesFactory
- .scan(repo, projectName)
- .map(
- (ChangeNotesResult changeNotes) -> {
- return changeNotes.notes().getChange();
- });
- allChangesStream = Streams.concat(allChangesStream, projectChangesStream);
- }
- }
- return new StreamIterable(allChangesStream);
- }
-
- @Override
- protected Optional<Timestamp> indexIfNeeded(Change c, Timestamp sinceTs) {
- try {
- Timestamp changeTs = c.getLastUpdatedOn();
- if (changeTs.after(sinceTs)) {
- log.info(
- "Index {}/{}/{} was updated after {}", 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);
- }
- return Optional.empty();
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/autoreindex/GroupReindexRunnable.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/autoreindex/GroupReindexRunnable.java
deleted file mode 100644
index 9990c26..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/autoreindex/GroupReindexRunnable.java
+++ /dev/null
@@ -1,43 +0,0 @@
-// 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.googlesource.gerrit.plugins.multisite.autoreindex;
-
-import com.google.gerrit.common.data.GroupReference;
-import com.google.gerrit.server.group.db.Groups;
-import com.google.gerrit.server.util.OneOffRequestContext;
-import com.google.inject.Inject;
-import com.googlesource.gerrit.plugins.multisite.forwarder.rest.AbstractIndexRestApiServlet;
-import java.sql.Timestamp;
-import java.util.Optional;
-
-public class GroupReindexRunnable extends ReindexRunnable<GroupReference> {
- private final Groups groups;
-
- @Inject
- public GroupReindexRunnable(IndexTs indexTs, OneOffRequestContext ctx, Groups groups) {
- super(AbstractIndexRestApiServlet.IndexName.GROUP, indexTs, ctx);
- this.groups = groups;
- }
-
- @Override
- protected Iterable<GroupReference> fetchItems() throws Exception {
- return groups.getAllGroupReferences()::iterator;
- }
-
- @Override
- protected Optional<Timestamp> indexIfNeeded(GroupReference g, Timestamp sinceTs) {
- return Optional.empty();
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/autoreindex/IndexTs.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/autoreindex/IndexTs.java
deleted file mode 100644
index e25adc2..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/autoreindex/IndexTs.java
+++ /dev/null
@@ -1,156 +0,0 @@
-// 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.googlesource.gerrit.plugins.multisite.autoreindex;
-
-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.server.change.ChangeFinder;
-import com.google.gerrit.server.git.WorkQueue;
-import com.google.gerrit.server.notedb.ChangeNotes;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import com.googlesource.gerrit.plugins.multisite.forwarder.rest.AbstractIndexRestApiServlet;
-import com.googlesource.gerrit.plugins.multisite.forwarder.rest.AbstractIndexRestApiServlet.IndexName;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-import java.util.Optional;
-import java.util.concurrent.ScheduledExecutorService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import com.google.gerrit.extensions.events.ProjectIndexedListener;
-
-@Singleton
-public class IndexTs
- implements ChangeIndexedListener,
- AccountIndexedListener,
- GroupIndexedListener,
- ProjectIndexedListener {
- private static final Logger log = LoggerFactory.getLogger(IndexTs.class);
- private static final DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME;
-
- private final Path dataDir;
- private final ScheduledExecutorService exec;
- private final FlusherRunner flusher;
- private final ChangeFinder changeFinder;
-
- private volatile LocalDateTime changeTs;
- private volatile LocalDateTime accountTs;
- private volatile LocalDateTime groupTs;
- private volatile LocalDateTime projectTs;
-
- class FlusherRunner implements Runnable {
-
- @Override
- public void run() {
- 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) {
- Optional<LocalDateTime> currTs = IndexTs.this.getUpdateTs(index);
- if (!currTs.isPresent() || latestTs.isAfter(currTs.get())) {
- Path indexTsFile = dataDir.resolve(index.name().toLowerCase());
- 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);
- }
- }
- }
- }
-
- @Inject
- public IndexTs(@PluginData Path dataDir, WorkQueue queue, ChangeFinder changeFinder) {
- this.dataDir = dataDir;
- this.exec = queue.getDefaultQueue();
- this.flusher = new FlusherRunner();
- this.changeFinder = changeFinder;
- }
-
- @Override
- public void onProjectIndexed(String project) {
- update(IndexName.PROJECT, LocalDateTime.now());
- }
-
- @Override
- public void onGroupIndexed(String uuid) {
- update(IndexName.GROUP, LocalDateTime.now());
- }
-
- @Override
- public void onAccountIndexed(int id) {
- update(IndexName.ACCOUNT, LocalDateTime.now());
- }
-
- @Override
- public void onChangeIndexed(String projectName, int id) {
- try {
- 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 {}", e);
- }
- }
-
- @Override
- public void onChangeDeleted(int id) {
- update(IndexName.CHANGE, LocalDateTime.now());
- }
-
- public Optional<LocalDateTime> getUpdateTs(AbstractIndexRestApiServlet.IndexName index) {
- try {
- Path indexTsFile = dataDir.resolve(index.name().toLowerCase());
- if (indexTsFile.toFile().exists()) {
- String tsString = Files.readAllLines(indexTsFile).get(0);
- return Optional.of(LocalDateTime.parse(tsString, formatter));
- }
- } catch (Exception e) {
- log.warn("Unable to read last timestamp for index {}", index, e);
- }
- return Optional.empty();
- }
-
- void update(AbstractIndexRestApiServlet.IndexName index, LocalDateTime dateTime) {
- switch (index) {
- case CHANGE:
- changeTs = dateTime;
- break;
- case ACCOUNT:
- accountTs = dateTime;
- break;
- case GROUP:
- groupTs = dateTime;
- break;
- case PROJECT:
- projectTs = dateTime;
- break;
- default:
- throw new IllegalArgumentException("Unsupported index " + index);
- }
- exec.execute(flusher);
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/autoreindex/ProjectReindexRunnable.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/autoreindex/ProjectReindexRunnable.java
deleted file mode 100644
index 8db9db0..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/autoreindex/ProjectReindexRunnable.java
+++ /dev/null
@@ -1,45 +0,0 @@
-// 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.googlesource.gerrit.plugins.multisite.autoreindex;
-
-import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.server.project.ProjectCache;
-import com.google.gerrit.server.util.OneOffRequestContext;
-import com.google.inject.Inject;
-import com.googlesource.gerrit.plugins.multisite.forwarder.rest.AbstractIndexRestApiServlet;
-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() {
- return projectCache.all();
- }
-
- @Override
- protected Optional<Timestamp> indexIfNeeded(Project.NameKey g, Timestamp sinceTs) {
- return Optional.empty();
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/autoreindex/ReindexRunnable.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/autoreindex/ReindexRunnable.java
deleted file mode 100644
index 44139a8..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/autoreindex/ReindexRunnable.java
+++ /dev/null
@@ -1,108 +0,0 @@
-// 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.googlesource.gerrit.plugins.multisite.autoreindex;
-
-import com.google.common.base.Stopwatch;
-import com.google.gerrit.server.util.ManualRequestContext;
-import com.google.gerrit.server.util.OneOffRequestContext;
-import com.google.inject.Inject;
-import com.googlesource.gerrit.plugins.multisite.forwarder.rest.AbstractIndexRestApiServlet;
-
-import java.sql.Timestamp;
-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 final AbstractIndexRestApiServlet.IndexName itemName;
- private final OneOffRequestContext ctx;
- private final IndexTs indexTs;
- private Timestamp newLastIndexTs;
-
- @Inject
- public ReindexRunnable(
- AbstractIndexRestApiServlet.IndexName itemName, IndexTs indexTs, OneOffRequestContext ctx) {
- this.itemName = itemName;
- this.ctx = ctx;
- this.indexTs = indexTs;
- }
-
- @Override
- public void run() {
- Optional<LocalDateTime> maybeIndexTs = indexTs.getUpdateTs(itemName);
- 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);
- try (ManualRequestContext mctx = ctx.open()) {
- int count = 0;
- int errors = 0;
- Stopwatch stopwatch = Stopwatch.createStarted();
- for (T c : fetchItems()) {
- try {
- Optional<Timestamp> itemTs = indexIfNeeded(c, newLastIndexTs);
- if (itemTs.isPresent()) {
- count++;
- newLastIndexTs = maxTimestamp(newLastIndexTs, itemTs.get());
- }
- } catch (Exception e) {
- log.error("Unable to reindex {} {}", itemNameString, c, e);
- errors++;
- }
- }
- long elapsedNanos = stopwatch.stop().elapsed(TimeUnit.NANOSECONDS);
- if (count > 0) {
- log.info(
- "{} {}s reindexed in {} msec ({}/sec), {} failed",
- count,
- itemNameString,
- elapsedNanos / 1000000L,
- (count * 1000L) / (elapsedNanos / 1000000L),
- errors);
- } else if (errors > 0) {
- log.info("{} {}s failed to reindex", errors, itemNameString);
- } else {
- log.debug("Scanning finished");
- }
- indexTs.update(itemName, newLastIndexTs.toLocalDateTime());
- } catch (Exception e) {
- log.error("Unable to scan " + itemNameString + "s", e);
- }
- }
- }
-
- protected abstract Iterable<T> fetchItems() throws Exception;
-
- protected abstract Optional<Timestamp> indexIfNeeded(T item, Timestamp sinceTs);
-
- private Timestamp maxTimestamp(Timestamp ts1, Timestamp ts2) {
- if (ts1 == null) {
- return ts2;
- }
-
- if (ts2 == null) {
- return ts1;
- }
-
- if (ts1.after(ts2)) {
- return ts1;
- }
- return ts2;
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/broker/BrokerPublisher.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/broker/BrokerPublisher.java
index cb84398..db13229 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/broker/BrokerPublisher.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/broker/BrokerPublisher.java
@@ -14,6 +14,7 @@
package com.googlesource.gerrit.plugins.multisite.broker;
+import com.google.common.annotations.VisibleForTesting;
import com.google.gerrit.extensions.events.LifecycleListener;
import com.google.gerrit.server.events.Event;
import com.google.gson.Gson;
@@ -72,7 +73,8 @@
body);
}
- private JsonObject eventToJson(Event event) {
+ @VisibleForTesting
+ public JsonObject eventToJson(Event event) {
return gson.toJsonTree(event).getAsJsonObject();
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/broker/GsonProvider.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/broker/GsonProvider.java
index bc15c4b..0791e6a 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/broker/GsonProvider.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/broker/GsonProvider.java
@@ -18,6 +18,7 @@
import com.google.gerrit.server.events.Event;
import com.google.gerrit.server.events.EventDeserializer;
import com.google.gerrit.server.events.SupplierDeserializer;
+import com.google.gerrit.server.events.SupplierSerializer;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.inject.Provider;
@@ -27,6 +28,7 @@
public Gson get() {
return new GsonBuilder()
.registerTypeAdapter(Event.class, new EventDeserializer())
+ .registerTypeAdapter(Supplier.class, new SupplierSerializer())
.registerTypeAdapter(Supplier.class, new SupplierDeserializer())
.create();
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/ForwardedEventHandler.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/ForwardedEventHandler.java
index e15b7e3..85dab30 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/ForwardedEventHandler.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/ForwardedEventHandler.java
@@ -17,6 +17,8 @@
import com.google.gerrit.server.events.Event;
import com.google.gerrit.server.events.EventDispatcher;
import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.util.ManualRequestContext;
+import com.google.gerrit.server.util.OneOffRequestContext;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -33,10 +35,12 @@
private static final Logger log = LoggerFactory.getLogger(ForwardedEventHandler.class);
private final EventDispatcher dispatcher;
+ private final OneOffRequestContext oneOffCtx;
@Inject
- public ForwardedEventHandler(EventDispatcher dispatcher) {
+ public ForwardedEventHandler(EventDispatcher dispatcher, OneOffRequestContext oneOffCtx) {
this.dispatcher = dispatcher;
+ this.oneOffCtx = oneOffCtx;
}
/**
@@ -46,7 +50,7 @@
* @throws OrmException If an error occur while retrieving the change the event belongs to.
*/
public void dispatch(Event event) throws OrmException, PermissionBackendException {
- try {
+ try (ManualRequestContext ctx = oneOffCtx.open()) {
Context.setForwardedEvent(true);
log.debug("dispatching event {}", event.getType());
dispatcher.postEvent(event);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/GsonParser.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/GsonParser.java
similarity index 97%
rename from src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/GsonParser.java
rename to src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/GsonParser.java
index dbd9175..7930207 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/GsonParser.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/GsonParser.java
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.googlesource.gerrit.plugins.multisite.forwarder.rest;
+package com.googlesource.gerrit.plugins.multisite.forwarder;
import com.google.common.base.Strings;
import com.google.gerrit.reviewdb.client.Account;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/AbstractIndexRestApiServlet.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/AbstractIndexRestApiServlet.java
deleted file mode 100644
index 2c3941a..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/AbstractIndexRestApiServlet.java
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.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_NOT_FOUND;
-import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
-
-import com.google.common.base.Charsets;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.google.gwtorm.server.OrmException;
-import com.googlesource.gerrit.plugins.multisite.forwarder.ForwardedIndexingHandler;
-import com.googlesource.gerrit.plugins.multisite.forwarder.ForwardedIndexingHandler.Operation;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.util.Optional;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-public abstract class AbstractIndexRestApiServlet<T, E> extends AbstractRestApiServlet {
- private static final long serialVersionUID = -1L;
- protected static final Gson gson = new GsonBuilder().create();
-
- private final ForwardedIndexingHandler<T, E> forwardedIndexingHandler;
- private final IndexName indexName;
- private final boolean allowDelete;
-
- public enum IndexName {
- CHANGE,
- ACCOUNT,
- GROUP,
- PROJECT;
-
- @Override
- public String toString() {
- return name().toLowerCase();
- }
- }
-
- abstract T parse(String id);
-
- AbstractIndexRestApiServlet(
- ForwardedIndexingHandler<T, E> forwardedIndexingHandler,
- IndexName indexName,
- boolean allowDelete) {
- this.forwardedIndexingHandler = forwardedIndexingHandler;
- this.indexName = indexName;
- this.allowDelete = allowDelete;
- }
-
- AbstractIndexRestApiServlet(
- ForwardedIndexingHandler<T, E> forwardedIndexingHandler, IndexName indexName) {
- this(forwardedIndexingHandler, indexName, false);
- }
-
- @Override
- protected void doPost(HttpServletRequest req, HttpServletResponse rsp) {
- process(req, rsp, Operation.INDEX);
- }
-
- @Override
- protected void doDelete(HttpServletRequest req, HttpServletResponse rsp) {
- if (!allowDelete) {
- sendError(
- rsp, SC_METHOD_NOT_ALLOWED, String.format("cannot delete %s from index", indexName));
- } else {
- process(req, rsp, Operation.DELETE);
- }
- }
-
- private void process(HttpServletRequest req, HttpServletResponse rsp, Operation operation) {
- setHeaders(rsp);
- String path = req.getRequestURI();
- T id = parse(path.substring(path.lastIndexOf('/') + 1));
- try {
- forwardedIndexingHandler.index(id, operation, parseBody(req));
- rsp.setStatus(SC_NO_CONTENT);
- } catch (IOException e) {
- sendError(rsp, SC_CONFLICT, e.getMessage());
- log.error("Unable to update {} index", indexName, e);
- } catch (OrmException e) {
- String msg = String.format("Error trying to find %s", indexName);
- sendError(rsp, SC_NOT_FOUND, msg);
- log.debug(msg, e);
- }
- }
-
- protected Optional<E> parseBody(HttpServletRequest req) throws IOException {
- String contentType = req.getContentType();
- if (contentType != null && contentType.contains("application/json")) {
- return Optional.ofNullable(
- fromJson(new InputStreamReader(req.getInputStream(), Charsets.UTF_8)));
- }
- return Optional.empty();
- }
-
- protected abstract E fromJson(Reader reader) throws IOException;
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/AbstractRestApiServlet.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/AbstractRestApiServlet.java
deleted file mode 100644
index 1646999..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/AbstractRestApiServlet.java
+++ /dev/null
@@ -1,41 +0,0 @@
-// 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.googlesource.gerrit.plugins.multisite.forwarder.rest;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
-
-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 void setHeaders(HttpServletResponse rsp) {
- rsp.setContentType("text/plain");
- rsp.setCharacterEncoding(UTF_8.name());
- }
-
- protected void sendError(HttpServletResponse rsp, int statusCode, String message) {
- try {
- rsp.sendError(statusCode, message);
- } catch (IOException e) {
- log.error("Failed to send error messsage: {}", e.getMessage(), e);
- }
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/AbstractRestForwarder.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/AbstractRestForwarder.java
deleted file mode 100644
index a82629b..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/AbstractRestForwarder.java
+++ /dev/null
@@ -1,180 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.forwarder.rest;
-
-import com.google.common.base.Joiner;
-import com.google.gerrit.extensions.annotations.PluginName;
-import com.google.inject.Provider;
-import com.googlesource.gerrit.plugins.multisite.Configuration;
-import com.googlesource.gerrit.plugins.multisite.forwarder.rest.HttpResponseHandler.HttpResult;
-import com.googlesource.gerrit.plugins.multisite.peers.PeerInfo;
-import java.io.IOException;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.stream.Collectors;
-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 AbstractRestForwarder {
- enum RequestMethod {
- POST,
- DELETE
- }
-
- private static final Logger log = LoggerFactory.getLogger(AbstractRestForwarder.class);
-
- private final HttpSession httpSession;
- private final String pluginRelativePath;
- private final Configuration cfg;
- private final Provider<Set<PeerInfo>> peerInfoProvider;
-
- AbstractRestForwarder(
- HttpSession httpClient,
- @PluginName String pluginName,
- Configuration cfg,
- Provider<Set<PeerInfo>> peerInfoProvider) {
- this.httpSession = httpClient;
- this.pluginRelativePath = Joiner.on("/").join("plugins", pluginName);
- this.cfg = cfg;
- this.peerInfoProvider = peerInfoProvider;
- }
-
- protected boolean post(String action, String endpoint, Object id, Object payload) {
- return execute(RequestMethod.POST, action, endpoint, id, payload);
- }
-
- protected boolean delete(String action, String endpoint, Object id, Object payload) {
- return execute(RequestMethod.DELETE, action, endpoint, id, payload);
- }
-
- protected boolean execute(RequestMethod method, String action, String endpoint, Object id) {
- return execute(method, action, endpoint, id, null);
- }
-
- private boolean execute(
- RequestMethod method, String action, String endpoint, Object id, Object payload) {
- List<CompletableFuture<Boolean>> futures =
- peerInfoProvider
- .get()
- .stream()
- .map(peer -> createRequest(method, peer, action, endpoint, id, payload))
- .map(request -> CompletableFuture.supplyAsync(() -> request.execute()))
- .collect(Collectors.toList());
- CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
- return futures.stream().allMatch(CompletableFuture::join);
- }
-
- private Request createRequest(
- RequestMethod method,
- PeerInfo peer,
- String action,
- String endpoint,
- Object id,
- Object payload) {
- String destination = peer.getDirectUrl();
- return new Request(action, id, destination) {
- @Override
- HttpResult send() throws IOException {
- String request = Joiner.on("/").join(destination, pluginRelativePath, endpoint, id);
- if (RequestMethod.POST == method) {
- return httpSession.post(request, payload);
- }
- return httpSession.delete(request, payload);
- }
- };
- }
-
- private abstract class Request {
- private final String action;
- private final Object key;
- private final String destination;
-
- private int execCnt;
-
- Request(String action, Object key, String destination) {
- this.action = action;
- this.key = key;
- this.destination = destination;
- }
-
- boolean execute() {
- log.debug("Executing {} {} towards {}", action, key, destination);
- for (; ; ) {
- try {
- execCnt++;
- tryOnce();
- log.debug("{} {} towards {} 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);
- if (!e.isRecoverable()) {
- log.error(
- "{} {} towards {} failed with unrecoverable error; giving up",
- action,
- key,
- destination,
- e);
- return false;
- }
- if (execCnt >= maxTries) {
- log.error(
- "Failed to {} {} on {} after {} tries; giving up",
- action,
- key,
- destination,
- maxTries);
- return false;
- }
-
- log.debug("Retrying to {} {} on {}", action, key, destination);
- try {
- Thread.sleep(cfg.http().retryInterval());
- } catch (InterruptedException ie) {
- log.error("{} {} towards {} was interrupted; giving up", action, key, destination, ie);
- Thread.currentThread().interrupt();
- return false;
- }
- }
- }
- }
-
- void tryOnce() throws ForwardingException {
- try {
- HttpResult result = send();
- if (!result.isSuccessful()) {
- throw new ForwardingException(
- true, String.format("Unable to %s %s : %s", action, key, result.getMessage()));
- }
- } catch (IOException e) {
- throw new ForwardingException(isRecoverable(e), e.getMessage(), e);
- }
- }
-
- abstract HttpResult send() throws IOException;
-
- boolean isRecoverable(IOException e) {
- Throwable cause = e.getCause();
- return !(e instanceof SSLException
- || cause instanceof HttpException
- || cause instanceof ClientProtocolException);
- }
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/CacheRestApiServlet.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/CacheRestApiServlet.java
deleted file mode 100644
index 53fe653..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/CacheRestApiServlet.java
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright (C) 2015 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.forwarder.rest;
-
-import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
-import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
-
-import com.google.common.base.Splitter;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import com.googlesource.gerrit.plugins.multisite.forwarder.CacheEntry;
-import com.googlesource.gerrit.plugins.multisite.forwarder.CacheNotFoundException;
-import com.googlesource.gerrit.plugins.multisite.forwarder.ForwardedCacheEvictionHandler;
-
-import java.io.IOException;
-import java.util.List;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-@Singleton
-class CacheRestApiServlet extends AbstractRestApiServlet {
- private static final int CACHENAME_INDEX = 1;
- private static final long serialVersionUID = -1L;
-
- private final ForwardedCacheEvictionHandler forwardedCacheEvictionHandler;
-
- @Inject
- CacheRestApiServlet(ForwardedCacheEvictionHandler forwardedCacheEvictionHandler) {
- this.forwardedCacheEvictionHandler = forwardedCacheEvictionHandler;
- }
-
- @Override
- protected void doPost(HttpServletRequest req, HttpServletResponse rsp) {
- setHeaders(rsp);
- try {
- List<String> params = Splitter.on('/').splitToList(req.getPathInfo());
- String cacheName = params.get(CACHENAME_INDEX);
- String json = req.getReader().readLine();
- forwardedCacheEvictionHandler.evict(
- CacheEntry.from(cacheName, GsonParser.fromJson(cacheName, json)));
- rsp.setStatus(SC_NO_CONTENT);
- } catch (CacheNotFoundException e) {
- log.error("Failed to process eviction request: {}", e.getMessage());
- sendError(rsp, SC_BAD_REQUEST, e.getMessage());
- } catch (IOException e) {
- log.error("Failed to process eviction request: {}", e.getMessage(), e);
- sendError(rsp, SC_BAD_REQUEST, e.getMessage());
- }
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/EventRestApiServlet.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/EventRestApiServlet.java
deleted file mode 100644
index 5298e05..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/EventRestApiServlet.java
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright (C) 2015 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.forwarder.rest;
-
-import static com.google.common.net.MediaType.JSON_UTF_8;
-import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
-import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
-import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
-import static javax.servlet.http.HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE;
-
-import com.google.common.base.Supplier;
-import com.google.common.io.CharStreams;
-import com.google.common.net.MediaType;
-import com.google.gerrit.server.events.Event;
-import com.google.gerrit.server.events.EventDeserializer;
-import com.google.gerrit.server.events.SupplierDeserializer;
-import com.google.gerrit.server.permissions.PermissionBackendException;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.google.gwtorm.server.OrmException;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import com.googlesource.gerrit.plugins.multisite.forwarder.ForwardedEventHandler;
-
-import java.io.IOException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-@Singleton
-class EventRestApiServlet extends AbstractRestApiServlet {
- private static final long serialVersionUID = -1L;
-
- private final ForwardedEventHandler forwardedEventHandler;
-
- @Inject
- EventRestApiServlet(ForwardedEventHandler forwardedEventHandler) {
- this.forwardedEventHandler = forwardedEventHandler;
- }
-
- @Override
- protected void doPost(HttpServletRequest req, HttpServletResponse rsp) {
- setHeaders(rsp);
- try {
- if (!MediaType.parse(req.getContentType()).is(JSON_UTF_8)) {
- sendError(rsp, SC_UNSUPPORTED_MEDIA_TYPE, "Expecting " + JSON_UTF_8 + " content type");
- return;
- }
- forwardedEventHandler.dispatch(getEventFromRequest(req));
- rsp.setStatus(SC_NO_CONTENT);
- } catch (OrmException e) {
- log.debug("Error trying to find a change ", e);
- sendError(rsp, SC_NOT_FOUND, "Change not found\n");
- } catch (IOException | PermissionBackendException e) {
- log.error("Unable to re-trigger event", e);
- sendError(rsp, SC_BAD_REQUEST, e.getMessage());
- }
- }
-
- private static Event getEventFromRequest(HttpServletRequest req) throws IOException {
- String jsonEvent = CharStreams.toString(req.getReader());
- Gson gson =
- new GsonBuilder()
- .registerTypeAdapter(Event.class, new EventDeserializer())
- .registerTypeAdapter(Supplier.class, new SupplierDeserializer())
- .create();
- return gson.fromJson(jsonEvent, Event.class);
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/ForwardingException.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/ForwardingException.java
deleted file mode 100644
index a902271..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/ForwardingException.java
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.forwarder.rest;
-
-class ForwardingException extends Exception {
- private static final long serialVersionUID = 1L;
-
- private final boolean isRecoverable;
-
- ForwardingException(boolean isRecoverable, String message) {
- super(message);
- this.isRecoverable = isRecoverable;
- }
-
- ForwardingException(boolean isRecoverable, String message, Throwable cause) {
- super(message, cause);
- this.isRecoverable = isRecoverable;
- }
-
- boolean isRecoverable() {
- return isRecoverable;
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/HttpClientProvider.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/HttpClientProvider.java
deleted file mode 100644
index b8b506e..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/HttpClientProvider.java
+++ /dev/null
@@ -1,133 +0,0 @@
-// Copyright (C) 2015 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.forwarder.rest;
-
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-import com.googlesource.gerrit.plugins.multisite.Configuration;
-
-import java.security.KeyManagementException;
-import java.security.NoSuchAlgorithmException;
-import java.security.cert.X509Certificate;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.X509TrustManager;
-import org.apache.http.auth.AuthScope;
-import org.apache.http.auth.UsernamePasswordCredentials;
-import org.apache.http.client.config.RequestConfig;
-import org.apache.http.config.Registry;
-import org.apache.http.config.RegistryBuilder;
-import org.apache.http.conn.HttpClientConnectionManager;
-import org.apache.http.conn.socket.ConnectionSocketFactory;
-import org.apache.http.conn.socket.PlainConnectionSocketFactory;
-import org.apache.http.conn.ssl.NoopHostnameVerifier;
-import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
-import org.apache.http.impl.client.BasicCredentialsProvider;
-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 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;
-
- private static final int MAX_CONNECTION_INACTIVITY = 10000;
-
- private final Configuration cfg;
- private final SSLConnectionSocketFactory sslSocketFactory;
-
- @Inject
- HttpClientProvider(Configuration cfg) {
- this.cfg = cfg;
- this.sslSocketFactory = buildSslSocketFactory();
- }
-
- @Override
- public CloseableHttpClient get() {
- return HttpClients.custom()
- .setSSLSocketFactory(sslSocketFactory)
- .setConnectionManager(customConnectionManager())
- .setDefaultCredentialsProvider(buildCredentials())
- .setDefaultRequestConfig(customRequestConfig())
- .build();
- }
-
- private RequestConfig customRequestConfig() {
- return RequestConfig.custom()
- .setConnectTimeout(cfg.http().connectionTimeout())
- .setSocketTimeout(cfg.http().socketTimeout())
- .setConnectionRequestTimeout(cfg.http().connectionTimeout())
- .build();
- }
-
- private HttpClientConnectionManager customConnectionManager() {
- Registry<ConnectionSocketFactory> socketFactoryRegistry =
- RegistryBuilder.<ConnectionSocketFactory>create()
- .register("https", sslSocketFactory)
- .register("http", PlainConnectionSocketFactory.INSTANCE)
- .build();
- PoolingHttpClientConnectionManager connManager =
- new PoolingHttpClientConnectionManager(socketFactoryRegistry);
- connManager.setDefaultMaxPerRoute(CONNECTIONS_PER_ROUTE);
- connManager.setMaxTotal(MAX_CONNECTIONS);
- connManager.setValidateAfterInactivity(MAX_CONNECTION_INACTIVITY);
- return connManager;
- }
-
- private static SSLConnectionSocketFactory buildSslSocketFactory() {
- return new SSLConnectionSocketFactory(buildSslContext(), NoopHostnameVerifier.INSTANCE);
- }
-
- private static SSLContext buildSslContext() {
- try {
- TrustManager[] trustAllCerts = new TrustManager[] {new DummyX509TrustManager()};
- SSLContext context = SSLContext.getInstance("TLS");
- context.init(null, trustAllCerts, null);
- return context;
- } catch (KeyManagementException | NoSuchAlgorithmException e) {
- log.warn("Error building SSLContext object", e);
- return null;
- }
- }
-
- private BasicCredentialsProvider buildCredentials() {
- BasicCredentialsProvider creds = new BasicCredentialsProvider();
- creds.setCredentials(
- AuthScope.ANY, new UsernamePasswordCredentials(cfg.http().user(), cfg.http().password()));
- return creds;
- }
-
- private static class DummyX509TrustManager implements X509TrustManager {
- @Override
- public X509Certificate[] getAcceptedIssuers() {
- return new X509Certificate[0];
- }
-
- @Override
- public void checkClientTrusted(X509Certificate[] certs, String authType) {
- // no check
- }
-
- @Override
- public void checkServerTrusted(X509Certificate[] certs, String authType) {
- // no check
- }
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/HttpResponseHandler.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/HttpResponseHandler.java
deleted file mode 100644
index 1a1d576..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/HttpResponseHandler.java
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright (C) 2015 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.forwarder.rest;
-
-import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
-
-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;
-
-import com.googlesource.gerrit.plugins.multisite.forwarder.rest.HttpResponseHandler.HttpResult;
-
-class HttpResponseHandler implements ResponseHandler<HttpResult> {
-
- static class HttpResult {
- private final boolean successful;
- private final String message;
-
- HttpResult(boolean successful, String message) {
- this.successful = successful;
- this.message = message;
- }
-
- boolean isSuccessful() {
- return successful;
- }
-
- String getMessage() {
- return message;
- }
- }
-
- private static final Logger log = LoggerFactory.getLogger(HttpResponseHandler.class);
-
- @Override
- public HttpResult handleResponse(HttpResponse response) {
- return new HttpResult(isSuccessful(response), parseResponse(response));
- }
-
- private static boolean isSuccessful(HttpResponse response) {
- return response.getStatusLine().getStatusCode() == SC_NO_CONTENT;
- }
-
- private static String parseResponse(HttpResponse response) {
- HttpEntity entity = response.getEntity();
- String asString = "";
- if (entity != null) {
- try {
- asString = EntityUtils.toString(entity);
- } catch (IOException e) {
- log.error("Error parsing entity", e);
- }
- }
- return asString;
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/HttpSession.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/HttpSession.java
deleted file mode 100644
index 8319d0d..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/HttpSession.java
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright (C) 2015 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.forwarder.rest;
-
-import com.google.common.base.Charsets;
-import com.google.common.base.Supplier;
-import com.google.common.net.MediaType;
-import com.google.gerrit.server.events.SupplierSerializer;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.google.inject.Inject;
-import com.googlesource.gerrit.plugins.multisite.forwarder.rest.HttpResponseHandler.HttpResult;
-
-import java.io.IOException;
-import java.net.URI;
-import org.apache.http.client.methods.HttpDelete;
-import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.entity.StringEntity;
-import org.apache.http.impl.client.CloseableHttpClient;
-
-class HttpSession {
- private final CloseableHttpClient httpClient;
- private final Gson gson =
- new GsonBuilder().registerTypeAdapter(Supplier.class, new SupplierSerializer()).create();
-
- @Inject
- HttpSession(CloseableHttpClient httpClient) {
- this.httpClient = httpClient;
- }
-
- HttpResult post(String endpoint) throws IOException {
- return post(endpoint, null);
- }
-
- HttpResult post(String uri, Object content) throws IOException {
- HttpPost post = new HttpPost(uri);
- setContent(post, content);
- return httpClient.execute(post, new HttpResponseHandler());
- }
-
- HttpResult delete(String uri) throws IOException {
- return httpClient.execute(new HttpDelete(uri), new HttpResponseHandler());
- }
-
- HttpResult delete(String uri, Object content) throws IOException {
- HttpDeleteWithBody delete = new HttpDeleteWithBody(uri);
- setContent(delete, content);
- return httpClient.execute(delete, new HttpResponseHandler());
- }
-
- private void setContent(HttpEntityEnclosingRequestBase request, Object content) {
- if (content != null) {
- request.addHeader("Content-Type", MediaType.JSON_UTF_8.toString());
- request.setEntity(new StringEntity(jsonEncode(content), Charsets.UTF_8));
- }
- }
-
- private String jsonEncode(Object content) {
- if (content instanceof String) {
- return (String) content;
- }
- return gson.toJson(content);
- }
-
- private class HttpDeleteWithBody extends HttpEntityEnclosingRequestBase {
- @Override
- public String getMethod() {
- return HttpDelete.METHOD_NAME;
- }
-
- private HttpDeleteWithBody(String uri) {
- setURI(URI.create(uri));
- }
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/IndexAccountRestApiServlet.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/IndexAccountRestApiServlet.java
deleted file mode 100644
index 8c63611..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/IndexAccountRestApiServlet.java
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.forwarder.rest;
-
-import com.google.gerrit.reviewdb.client.Account;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import com.googlesource.gerrit.plugins.multisite.forwarder.ForwardedIndexAccountHandler;
-import com.googlesource.gerrit.plugins.multisite.forwarder.events.AccountIndexEvent;
-import java.io.IOException;
-import java.io.Reader;
-
-@Singleton
-class IndexAccountRestApiServlet
- extends AbstractIndexRestApiServlet<Account.Id, AccountIndexEvent> {
- private static final long serialVersionUID = -1L;
-
- @Inject
- IndexAccountRestApiServlet(ForwardedIndexAccountHandler handler) {
- super(handler, IndexName.ACCOUNT);
- }
-
- @Override
- Account.Id parse(String id) {
- return new Account.Id(Integer.parseInt(id));
- }
-
- @Override
- protected AccountIndexEvent fromJson(Reader reader) throws IOException {
- return gson.fromJson(reader, AccountIndexEvent.class);
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/IndexChangeRestApiServlet.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/IndexChangeRestApiServlet.java
deleted file mode 100644
index 7ead4bd..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/IndexChangeRestApiServlet.java
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (C) 2015 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.forwarder.rest;
-
-import com.google.gerrit.extensions.restapi.Url;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import com.googlesource.gerrit.plugins.multisite.forwarder.ForwardedIndexChangeHandler;
-import com.googlesource.gerrit.plugins.multisite.forwarder.events.ChangeIndexEvent;
-import java.io.IOException;
-import java.io.Reader;
-
-@Singleton
-class IndexChangeRestApiServlet extends AbstractIndexRestApiServlet<String, ChangeIndexEvent> {
- private static final long serialVersionUID = -1L;
-
- @Inject
- IndexChangeRestApiServlet(ForwardedIndexChangeHandler handler) {
- super(handler, IndexName.CHANGE, true);
- }
-
- @Override
- String parse(String id) {
- return Url.decode(id);
- }
-
- @Override
- protected ChangeIndexEvent fromJson(Reader reader) throws IOException {
- return gson.fromJson(reader, ChangeIndexEvent.class);
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/IndexGroupRestApiServlet.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/IndexGroupRestApiServlet.java
deleted file mode 100644
index 51d64d5..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/IndexGroupRestApiServlet.java
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.forwarder.rest;
-
-import com.google.gerrit.reviewdb.client.AccountGroup;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import com.googlesource.gerrit.plugins.multisite.forwarder.ForwardedIndexGroupHandler;
-import com.googlesource.gerrit.plugins.multisite.forwarder.events.GroupIndexEvent;
-import java.io.IOException;
-import java.io.Reader;
-
-@Singleton
-class IndexGroupRestApiServlet
- extends AbstractIndexRestApiServlet<AccountGroup.UUID, GroupIndexEvent> {
- private static final long serialVersionUID = -1L;
-
- @Inject
- IndexGroupRestApiServlet(ForwardedIndexGroupHandler handler) {
- super(handler, IndexName.GROUP);
- }
-
- @Override
- AccountGroup.UUID parse(String id) {
- return new AccountGroup.UUID(id);
- }
-
- @Override
- protected GroupIndexEvent fromJson(Reader reader) throws IOException {
- return gson.fromJson(reader, GroupIndexEvent.class);
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/IndexProjectRestApiServlet.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/IndexProjectRestApiServlet.java
deleted file mode 100644
index dd94e3f..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/IndexProjectRestApiServlet.java
+++ /dev/null
@@ -1,45 +0,0 @@
-// 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.googlesource.gerrit.plugins.multisite.forwarder.rest;
-
-import com.google.gerrit.extensions.restapi.Url;
-import com.google.gerrit.reviewdb.client.Project;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import com.googlesource.gerrit.plugins.multisite.forwarder.ForwardedIndexProjectHandler;
-import com.googlesource.gerrit.plugins.multisite.forwarder.events.ProjectIndexEvent;
-import java.io.IOException;
-import java.io.Reader;
-
-@Singleton
-class IndexProjectRestApiServlet
- extends AbstractIndexRestApiServlet<Project.NameKey, ProjectIndexEvent> {
- 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));
- }
-
- @Override
- protected ProjectIndexEvent fromJson(Reader reader) throws IOException {
- return gson.fromJson(reader, ProjectIndexEvent.class);
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/PeerInfoNotAvailableException.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/PeerInfoNotAvailableException.java
deleted file mode 100644
index b656ebf..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/PeerInfoNotAvailableException.java
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.forwarder.rest;
-
-import java.io.IOException;
-
-public class PeerInfoNotAvailableException extends IOException {
- private static final long serialVersionUID = 1L;
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/ProjectListApiServlet.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/ProjectListApiServlet.java
deleted file mode 100644
index 9f55f32..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/ProjectListApiServlet.java
+++ /dev/null
@@ -1,63 +0,0 @@
-// 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.googlesource.gerrit.plugins.multisite.forwarder.rest;
-
-import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
-import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
-
-import com.google.gerrit.extensions.restapi.Url;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import com.googlesource.gerrit.plugins.multisite.forwarder.ForwardedProjectListUpdateHandler;
-import com.googlesource.gerrit.plugins.multisite.forwarder.events.ProjectListUpdateEvent;
-import java.io.IOException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-@Singleton
-class ProjectListApiServlet extends AbstractRestApiServlet {
- private static final long serialVersionUID = -1L;
-
- private final ForwardedProjectListUpdateHandler forwardedProjectListUpdateHandler;
-
- @Inject
- ProjectListApiServlet(ForwardedProjectListUpdateHandler forwardedProjectListUpdateHandler) {
- this.forwardedProjectListUpdateHandler = forwardedProjectListUpdateHandler;
- }
-
- @Override
- protected void doPost(HttpServletRequest req, HttpServletResponse rsp) {
- process(req, rsp, false);
- }
-
- @Override
- protected void doDelete(HttpServletRequest req, HttpServletResponse rsp) {
- process(req, rsp, true);
- }
-
- private void process(HttpServletRequest req, HttpServletResponse rsp, boolean delete) {
- setHeaders(rsp);
- String requestURI = req.getRequestURI();
- String projectName = requestURI.substring(requestURI.lastIndexOf('/') + 1);
- try {
- forwardedProjectListUpdateHandler.update(
- new ProjectListUpdateEvent(Url.decode(projectName), delete));
- rsp.setStatus(SC_NO_CONTENT);
- } catch (IOException e) {
- log.error("Unable to update project list", e);
- sendError(rsp, SC_BAD_REQUEST, e.getMessage());
- }
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/RestCacheEvictionForwarder.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/RestCacheEvictionForwarder.java
deleted file mode 100644
index 3277d71..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/RestCacheEvictionForwarder.java
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.forwarder.rest;
-
-import com.google.gerrit.extensions.annotations.PluginName;
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-import com.google.inject.Singleton;
-import com.googlesource.gerrit.plugins.multisite.Configuration;
-import com.googlesource.gerrit.plugins.multisite.forwarder.CacheEvictionForwarder;
-import com.googlesource.gerrit.plugins.multisite.forwarder.events.CacheEvictionEvent;
-import com.googlesource.gerrit.plugins.multisite.peers.PeerInfo;
-import java.util.Set;
-
-@Singleton
-public class RestCacheEvictionForwarder extends AbstractRestForwarder
- implements CacheEvictionForwarder {
- @Inject
- RestCacheEvictionForwarder(
- HttpSession httpClient,
- @PluginName String pluginName,
- Configuration cfg,
- Provider<Set<PeerInfo>> peerInfoProvider) {
- super(httpClient, pluginName, cfg, peerInfoProvider);
- }
-
- @Override
- public boolean evict(CacheEvictionEvent cacheEvictionEvent) {
- String json = GsonParser.toJson(cacheEvictionEvent.cacheName, cacheEvictionEvent.key);
- return post(
- "invalidate cache " + cacheEvictionEvent.cacheName,
- "cache",
- cacheEvictionEvent.cacheName,
- json);
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/RestForwarderModule.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/RestForwarderModule.java
deleted file mode 100644
index 834529d..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/RestForwarderModule.java
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.forwarder.rest;
-
-import com.google.gerrit.extensions.registration.DynamicSet;
-import com.google.inject.AbstractModule;
-import com.google.inject.Scopes;
-import com.googlesource.gerrit.plugins.multisite.Configuration.Http;
-import com.googlesource.gerrit.plugins.multisite.forwarder.CacheEvictionForwarder;
-import com.googlesource.gerrit.plugins.multisite.forwarder.IndexEventForwarder;
-import com.googlesource.gerrit.plugins.multisite.forwarder.events.EventFamily;
-import com.googlesource.gerrit.plugins.multisite.forwarder.ProjectListUpdateForwarder;
-import com.googlesource.gerrit.plugins.multisite.forwarder.StreamEventForwarder;
-import org.apache.http.impl.client.CloseableHttpClient;
-
-public class RestForwarderModule extends AbstractModule {
- private final Http http;
-
- public RestForwarderModule(Http http) {
- this.http = http;
- }
-
- @Override
- protected void configure() {
- bind(CloseableHttpClient.class).toProvider(HttpClientProvider.class).in(Scopes.SINGLETON);
- bind(HttpSession.class);
- DynamicSet.bind(binder(), ProjectListUpdateForwarder.class).to(RestProjectListUpdateForwarder.class);
- if (http.enabledEvent(EventFamily.INDEX_EVENT)) {
- DynamicSet.bind(binder(), IndexEventForwarder.class).to(RestIndexEventForwarder.class);
- }
- if (http.enabledEvent(EventFamily.CACHE_EVENT)) {
- DynamicSet.bind(binder(), CacheEvictionForwarder.class).to(RestCacheEvictionForwarder.class);
- }
- if (http.enabledEvent(EventFamily.STREAM_EVENT)) {
- DynamicSet.bind(binder(), ProjectListUpdateForwarder.class)
- .to(RestProjectListUpdateForwarder.class);
- }
- if (http.enabledEvent(EventFamily.STREAM_EVENT)) {
- DynamicSet.bind(binder(), StreamEventForwarder.class).to(RestStreamEventForwarder.class);
- }
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/RestForwarderServletModule.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/RestForwarderServletModule.java
deleted file mode 100644
index cd66c83..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/RestForwarderServletModule.java
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.forwarder.rest;
-
-import com.google.gerrit.httpd.plugins.HttpPluginModule;
-
-public class RestForwarderServletModule extends HttpPluginModule {
- @Override
- protected void configureServlets() {
- 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/googlesource/gerrit/plugins/multisite/forwarder/rest/RestIndexEventForwarder.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/RestIndexEventForwarder.java
deleted file mode 100644
index f2a4d21..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/RestIndexEventForwarder.java
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.forwarder.rest;
-
-import com.google.gerrit.extensions.annotations.PluginName;
-import com.google.gerrit.extensions.restapi.Url;
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-import com.google.inject.Singleton;
-import com.googlesource.gerrit.plugins.multisite.Configuration;
-import com.googlesource.gerrit.plugins.multisite.forwarder.IndexEventForwarder;
-import com.googlesource.gerrit.plugins.multisite.forwarder.events.AccountIndexEvent;
-import com.googlesource.gerrit.plugins.multisite.forwarder.events.ChangeIndexEvent;
-import com.googlesource.gerrit.plugins.multisite.forwarder.events.GroupIndexEvent;
-import com.googlesource.gerrit.plugins.multisite.forwarder.events.ProjectIndexEvent;
-import com.googlesource.gerrit.plugins.multisite.peers.PeerInfo;
-import java.util.Set;
-
-@Singleton
-public class RestIndexEventForwarder extends AbstractRestForwarder implements IndexEventForwarder {
- @Inject
- RestIndexEventForwarder(
- HttpSession httpClient,
- @PluginName String pluginName,
- Configuration cfg,
- Provider<Set<PeerInfo>> peerInfoProvider) {
- super(httpClient, pluginName, cfg, peerInfoProvider);
- }
-
- @Override
- public boolean indexAccount(AccountIndexEvent event) {
- return post("index account", "index/account", event.accountId, event);
- }
-
- @Override
- public boolean indexChange(ChangeIndexEvent event) {
- return post(
- "index change",
- "index/change",
- Url.encode(event.projectName) + "~" + event.changeId,
- event);
- }
-
- @Override
- public boolean deleteChangeFromIndex(ChangeIndexEvent event) {
- return delete("delete change", "index/change", "~" + event.changeId, event);
- }
-
- @Override
- public boolean indexGroup(GroupIndexEvent event) {
- return post("index group", "index/group", event.groupUUID, event);
- }
-
- @Override
- public boolean indexProject(ProjectIndexEvent event) {
- return post("index project", "index/project", Url.encode(event.projectName), event);
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/RestProjectListUpdateForwarder.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/RestProjectListUpdateForwarder.java
deleted file mode 100644
index 59cc288..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/RestProjectListUpdateForwarder.java
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright (C) 2015 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.forwarder.rest;
-
-import com.google.common.base.Joiner;
-import com.google.gerrit.extensions.annotations.PluginName;
-import com.google.gerrit.extensions.restapi.Url;
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-import com.google.inject.Singleton;
-import com.googlesource.gerrit.plugins.multisite.Configuration;
-import com.googlesource.gerrit.plugins.multisite.cache.Constants;
-import com.googlesource.gerrit.plugins.multisite.forwarder.ProjectListUpdateForwarder;
-import com.googlesource.gerrit.plugins.multisite.forwarder.events.ProjectListUpdateEvent;
-import com.googlesource.gerrit.plugins.multisite.peers.PeerInfo;
-import java.util.Set;
-
-@Singleton
-class RestProjectListUpdateForwarder extends AbstractRestForwarder
- implements ProjectListUpdateForwarder {
-
- @Inject
- RestProjectListUpdateForwarder(
- HttpSession httpClient,
- @PluginName String pluginName,
- Configuration cfg,
- Provider<Set<PeerInfo>> peerInfoProvider) {
- super(httpClient, pluginName, cfg, peerInfoProvider);
- }
-
- @Override
- public boolean updateProjectList(ProjectListUpdateEvent event) {
- return execute(
- event.remove ? RequestMethod.DELETE : RequestMethod.POST,
- String.format("Update project_list, %s ", event.remove ? "remove" : "add"),
- buildProjectListEndpoint(),
- Url.encode(event.projectName));
- }
-
- private static String buildProjectListEndpoint() {
- return Joiner.on("/").join("cache", Constants.PROJECT_LIST);
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/RestStreamEventForwarder.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/RestStreamEventForwarder.java
deleted file mode 100644
index 0f2e665..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/RestStreamEventForwarder.java
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.forwarder.rest;
-
-import com.google.gerrit.extensions.annotations.PluginName;
-import com.google.gerrit.server.events.Event;
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-import com.google.inject.Singleton;
-import com.googlesource.gerrit.plugins.multisite.Configuration;
-import com.googlesource.gerrit.plugins.multisite.forwarder.StreamEventForwarder;
-import com.googlesource.gerrit.plugins.multisite.peers.PeerInfo;
-import java.util.Set;
-
-@Singleton
-public class RestStreamEventForwarder extends AbstractRestForwarder
- implements StreamEventForwarder {
- @Inject
- RestStreamEventForwarder(
- HttpSession httpClient,
- @PluginName String pluginName,
- Configuration cfg,
- Provider<Set<PeerInfo>> peerInfoProvider) {
- super(httpClient, pluginName, cfg, peerInfoProvider);
- }
-
- @Override
- public boolean send(final Event event) {
- return post("send event", "event", event.type, event);
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/kafka/consumer/AbstractKafkaSubcriber.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/kafka/consumer/AbstractKafkaSubcriber.java
index bde629e..3af9047 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/kafka/consumer/AbstractKafkaSubcriber.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/kafka/consumer/AbstractKafkaSubcriber.java
@@ -16,6 +16,8 @@
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.util.ManualRequestContext;
+import com.google.gerrit.server.util.OneOffRequestContext;
import com.google.gson.Gson;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Provider;
@@ -45,6 +47,7 @@
private final AtomicBoolean closed = new AtomicBoolean(false);
private final Deserializer<SourceAwareEventWrapper> valueDeserializer;
private final Configuration configuration;
+ private final OneOffRequestContext oneOffCtx;
public AbstractKafkaSubcriber(
Configuration configuration,
@@ -52,17 +55,19 @@
Deserializer<SourceAwareEventWrapper> valueDeserializer,
ForwardedEventRouter eventRouter,
Provider<Gson> gsonProvider,
- @InstanceId UUID instanceId) {
+ @InstanceId UUID instanceId,
+ OneOffRequestContext oneOffCtx) {
this.configuration = configuration;
this.eventRouter = eventRouter;
this.gsonProvider = gsonProvider;
this.instanceId = instanceId;
+ this.oneOffCtx = oneOffCtx;
final ClassLoader previousClassLoader = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(AbstractKafkaSubcriber.class.getClassLoader());
this.consumer =
new KafkaConsumer<>(
- configuration.kafkaSubscriber().getProps(instanceId),
+ configuration.kafkaSubscriber().initPropsWith(instanceId),
keyDeserializer,
new ByteArrayDeserializer());
} finally {
@@ -95,7 +100,7 @@
protected abstract EventFamily getEventFamily();
private void processRecord(ConsumerRecord<byte[], byte[]> consumerRecord) {
- try {
+ try (ManualRequestContext ctx = oneOffCtx.open()) {
SourceAwareEventWrapper event =
valueDeserializer.deserialize(consumerRecord.topic(), consumerRecord.value());
@@ -109,16 +114,16 @@
logger.atInfo().log("Header[%s] Body[%s]", event.getHeader(), event.getBody());
eventRouter.route(event.getEventBody(gsonProvider));
} catch (IOException e) {
- logger.atSevere().log(
- "Malformed event '%s': [Exception: %s]", event.getHeader().getEventType(), e);
+ logger.atSevere().withCause(e).log(
+ "Malformed event '%s': [Exception: %s]", event.getHeader().getEventType());
} catch (PermissionBackendException | OrmException e) {
- logger.atSevere().log(
- "Cannot handle message %s: [Exception: %s]", event.getHeader().getEventType(), e);
+ logger.atSevere().withCause(e).log(
+ "Cannot handle message %s: [Exception: %s]", event.getHeader().getEventType());
}
}
} catch (Exception e) {
- logger.atSevere().log(
- "Malformed event '%s': [Exception: %s]", new String(consumerRecord.value()), e);
+ logger.atSevere().withCause(e).log(
+ "Malformed event '%s': [Exception: %s]", new String(consumerRecord.value()));
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/kafka/consumer/CacheEvictionEventSubscriber.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/kafka/consumer/CacheEvictionEventSubscriber.java
index 564a7d7..0c5dac9 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/kafka/consumer/CacheEvictionEventSubscriber.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/kafka/consumer/CacheEvictionEventSubscriber.java
@@ -14,6 +14,7 @@
package com.googlesource.gerrit.plugins.multisite.kafka.consumer;
+import com.google.gerrit.server.util.OneOffRequestContext;
import com.google.gson.Gson;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -34,8 +35,16 @@
Deserializer<SourceAwareEventWrapper> valueDeserializer,
StreamEventRouter eventRouter,
Provider<Gson> gsonProvider,
- @InstanceId UUID instanceId) {
- super(configuration, keyDeserializer, valueDeserializer, eventRouter, gsonProvider, instanceId);
+ @InstanceId UUID instanceId,
+ OneOffRequestContext oneOffCtx) {
+ super(
+ configuration,
+ keyDeserializer,
+ valueDeserializer,
+ eventRouter,
+ gsonProvider,
+ instanceId,
+ oneOffCtx);
}
@Override
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/kafka/consumer/IndexEventSubscriber.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/kafka/consumer/IndexEventSubscriber.java
index 7ee04b9..0720cf2 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/kafka/consumer/IndexEventSubscriber.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/kafka/consumer/IndexEventSubscriber.java
@@ -14,6 +14,7 @@
package com.googlesource.gerrit.plugins.multisite.kafka.consumer;
+import com.google.gerrit.server.util.OneOffRequestContext;
import com.google.gson.Gson;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -34,8 +35,16 @@
Deserializer<SourceAwareEventWrapper> valueDeserializer,
IndexEventRouter eventRouter,
Provider<Gson> gsonProvider,
- @InstanceId UUID instanceId) {
- super(configuration, keyDeserializer, valueDeserializer, eventRouter, gsonProvider, instanceId);
+ @InstanceId UUID instanceId,
+ OneOffRequestContext oneOffCtx) {
+ super(
+ configuration,
+ keyDeserializer,
+ valueDeserializer,
+ eventRouter,
+ gsonProvider,
+ instanceId,
+ oneOffCtx);
}
@Override
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/kafka/consumer/ProjectUpdateEventSubscriber.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/kafka/consumer/ProjectUpdateEventSubscriber.java
index 727bb91..581dc2f 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/kafka/consumer/ProjectUpdateEventSubscriber.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/kafka/consumer/ProjectUpdateEventSubscriber.java
@@ -14,6 +14,7 @@
package com.googlesource.gerrit.plugins.multisite.kafka.consumer;
+import com.google.gerrit.server.util.OneOffRequestContext;
import com.google.gson.Gson;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -34,8 +35,16 @@
Deserializer<SourceAwareEventWrapper> valueDeserializer,
ProjectListUpdateRouter eventRouter,
Provider<Gson> gsonProvider,
- @InstanceId UUID instanceId) {
- super(configuration, keyDeserializer, valueDeserializer, eventRouter, gsonProvider, instanceId);
+ @InstanceId UUID instanceId,
+ OneOffRequestContext oneOffCtx) {
+ super(
+ configuration,
+ keyDeserializer,
+ valueDeserializer,
+ eventRouter,
+ gsonProvider,
+ instanceId,
+ oneOffCtx);
}
@Override
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/kafka/consumer/SourceAwareEventWrapper.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/kafka/consumer/SourceAwareEventWrapper.java
index 47c06e4..4f3a4d6 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/kafka/consumer/SourceAwareEventWrapper.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/kafka/consumer/SourceAwareEventWrapper.java
@@ -76,12 +76,17 @@
@Override
public String toString() {
- return "{" +
- "eventId=" + eventId +
- ", eventType='" + eventType + '\'' +
- ", sourceInstanceId=" + sourceInstanceId +
- ", eventCreatedOn=" + eventCreatedOn +
- '}';
+ return "{"
+ + "eventId="
+ + eventId
+ + ", eventType='"
+ + eventType
+ + '\''
+ + ", sourceInstanceId="
+ + sourceInstanceId
+ + ", eventCreatedOn="
+ + eventCreatedOn
+ + '}';
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/kafka/consumer/StreamEventSubscriber.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/kafka/consumer/StreamEventSubscriber.java
index 29cc533..3ac08d5 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/kafka/consumer/StreamEventSubscriber.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/kafka/consumer/StreamEventSubscriber.java
@@ -14,6 +14,7 @@
package com.googlesource.gerrit.plugins.multisite.kafka.consumer;
+import com.google.gerrit.server.util.OneOffRequestContext;
import com.google.gson.Gson;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -34,8 +35,16 @@
Deserializer<SourceAwareEventWrapper> valueDeserializer,
StreamEventRouter eventRouter,
Provider<Gson> gsonProvider,
- @InstanceId UUID instanceId) {
- super(configuration, keyDeserializer, valueDeserializer, eventRouter, gsonProvider, instanceId);
+ @InstanceId UUID instanceId,
+ OneOffRequestContext oneOffCtx) {
+ super(
+ configuration,
+ keyDeserializer,
+ valueDeserializer,
+ eventRouter,
+ gsonProvider,
+ instanceId,
+ oneOffCtx);
}
@Override
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/kafka/router/CacheEvictionEventRouter.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/kafka/router/CacheEvictionEventRouter.java
index 95cef94..c2a06d2 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/kafka/router/CacheEvictionEventRouter.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/kafka/router/CacheEvictionEventRouter.java
@@ -19,8 +19,8 @@
import com.googlesource.gerrit.plugins.multisite.forwarder.CacheEntry;
import com.googlesource.gerrit.plugins.multisite.forwarder.CacheNotFoundException;
import com.googlesource.gerrit.plugins.multisite.forwarder.ForwardedCacheEvictionHandler;
+import com.googlesource.gerrit.plugins.multisite.forwarder.GsonParser;
import com.googlesource.gerrit.plugins.multisite.forwarder.events.CacheEvictionEvent;
-import com.googlesource.gerrit.plugins.multisite.forwarder.rest.GsonParser;
@Singleton
public class CacheEvictionEventRouter implements ForwardedCacheEvictionEventRouter {
@@ -32,8 +32,7 @@
}
@Override
- public void route(CacheEvictionEvent sourceEvent) throws CacheNotFoundException {
- CacheEvictionEvent cacheEvictionEvent = (CacheEvictionEvent) sourceEvent;
+ public void route(CacheEvictionEvent cacheEvictionEvent) throws CacheNotFoundException {
Object parsedKey =
GsonParser.fromJson(cacheEvictionEvent.cacheName, cacheEvictionEvent.key.toString());
cacheEvictionHanlder.evict(CacheEntry.from(cacheEvictionEvent.cacheName, parsedKey));
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/peers/PeerInfo.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/peers/PeerInfo.java
deleted file mode 100644
index 1cd2d0e..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/peers/PeerInfo.java
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.peers;
-
-public class PeerInfo {
-
- private final String directUrl;
-
- public PeerInfo(String directUrl) {
- this.directUrl = directUrl;
- }
-
- public String getDirectUrl() {
- return directUrl;
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/peers/PeerInfoModule.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/peers/PeerInfoModule.java
deleted file mode 100644
index 719b5a0..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/peers/PeerInfoModule.java
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.peers;
-
-import com.google.gerrit.lifecycle.LifecycleModule;
-import com.google.inject.TypeLiteral;
-import com.googlesource.gerrit.plugins.multisite.Configuration;
-
-import java.util.Set;
-
-public class PeerInfoModule extends LifecycleModule {
-
- private final Configuration.PeerInfoStrategy strategy;
-
- public PeerInfoModule(Configuration.PeerInfoStrategy strategy) {
- this.strategy = strategy;
- }
-
- @Override
- protected void configure() {
- switch (strategy) {
- case STATIC:
- bind(new TypeLiteral<Set<PeerInfo>>() {}).toProvider(PluginConfigPeerInfoProvider.class);
- break;
- default:
- throw new IllegalArgumentException("Unsupported peer info strategy: " + strategy);
- }
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/peers/PluginConfigPeerInfoProvider.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/peers/PluginConfigPeerInfoProvider.java
deleted file mode 100644
index f698002..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/peers/PluginConfigPeerInfoProvider.java
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.peers;
-
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-import com.google.inject.Singleton;
-import com.googlesource.gerrit.plugins.multisite.Configuration;
-
-import java.util.HashSet;
-import java.util.Set;
-
-@Singleton
-public class PluginConfigPeerInfoProvider implements Provider<Set<PeerInfo>> {
-
- private final Set<PeerInfo> peers = new HashSet<>();
-
- @Inject
- PluginConfigPeerInfoProvider(Configuration cfg) {
- for (String url : cfg.peerInfoStatic().urls()) {
- peers.add(new PeerInfo(url));
- }
- }
-
- @Override
- public Set<PeerInfo> get() {
- return peers;
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/peers/jgroups/JGroupsPeerInfoProvider.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/peers/jgroups/JGroupsPeerInfoProvider.java
deleted file mode 100644
index 803ad0c..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/peers/jgroups/JGroupsPeerInfoProvider.java
+++ /dev/null
@@ -1 +0,0 @@
-package com.googlesource.gerrit.plugins.multisite.peers.jgroups;
diff --git a/src/main/resources/Documentation/architecture-first-iteration.png b/src/main/resources/Documentation/architecture-first-iteration.png
new file mode 100644
index 0000000..1a9fe36
--- /dev/null
+++ b/src/main/resources/Documentation/architecture-first-iteration.png
Binary files differ
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index 3b22941..b10d790 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -8,22 +8,9 @@
File '@PLUGIN@.config'
--------------------
-### Static definition of the multi-site nodes.
+## Sample configuration.
```
-[autoReindex]
- enabled = false
-[peerInfo]
- strategy = static
-[peerInfo "static"]
- url = first_target_instance_url
- url = second_target_instance_url
-[http]
- enabled = true
-
- user = username
- password = password
-
[kafka]
bootstrapServers = kafka-1:9092,kafka-2:9092,kafka-3:9092
@@ -35,91 +22,29 @@
[kafka "publisher"]
enabled = true
+ indexEventEnabled = true
+ cacheEventEnabled = true
+ projectListEventEnabled = true
+ streamEventEnabled = true
+
+ KafkaProp-compressionType = none
+ KafkaProp-deliveryTimeoutMs = 60000
+
[kafka "subscriber"]
enabled = true
-
pollingIntervalMs = 1000
- autoCommitIntervalMs = 1000
+ KafkaProp-enableAutoCommit = true
+ KafkaProp-autoCommitIntervalMs = 1000
+ KafkaProp-autoCommitIntervalMs = 5000
+
+ indexEventEnabled = true
+ cacheEventEnabled = true
+ projectListEventEnabled = true
+ streamEventEnabled = true
```
-```autoReindex.enabled```
-: Enable the tracking of the latest change indexed under data/multi-site
- for each of the indexes. At startup scans all the changes, accounts and groups
- and reindex the ones that have been updated by other nodes while the server was down.
- When not specified, the default is "false", that means no automatic tracking
- and indexing at start.
-
-```autoReindex.delay```
-: When autoReindex is enabled, indicates the delay aftere the plugin startup,
- before triggering the conditional reindexing of all changes, accounts and groups.
- Delay is expressed in Gerrit time values:
- * s, sec, second, seconds
- * m, min, minute, minutes
- * h, hr, hour, hours
- * d, day, days
- * w, week, weeks (`1 week` is treated as `7 days`)
- * mon, month, months (`1 month` is treated as `30 days`)
- * y, year, years (`1 year` is treated as `365 days`)
- If a time unit suffix is not specified, `hours` is assumed.
- Defaults to 24 hours.
-
- When not specified, the default is "10 seconds".
-
-```autoReindex.pollInterval```
-: When autoReindex is enabled, indicates the interval between the conditional
- reindexing of all changes, accounts and groups.
- Delay is expressed in Gerrit time values as in [autoReindex.delay](#autoReindex.delay).
- When not specified, polling of conditional reindexing is disabled.
-
-```autoReindex.interval```
-: Enable the tracking of the latest change indexed under data/multi-site
- for each of the indexes. At startup scans all the changes, accounts and groups
- and reindex the ones that have been updated by other nodes while the server was down.
- When not specified, the default is "false", that means no automatic tracking
- and indexing at start.
-
-```peerInfo.strategy```
-: Strategy to find other peers. The only supported strategy is `static`.
- Defaults to `static`.
-* The `static` strategy allows to staticly configure the peer gerrit instance using
-the configuration parameter `peerInfo.static.url`.
-
-```peerInfo.static.url```
-: Specify the URL for the peer instance. If more than one peer instance is to be
- configured, add as many url entries as necessary.
-
-```http.user```
-: Username to connect to the peer instance.
-
-```http.password```
-: Password to connect to the peer instance.
-
-@PLUGIN@ plugin uses REST API calls to keep the target instance in-sync. It
-is possible to customize the parameters of the underlying http client doing these
-calls by specifying the following fields:
-
-```http.connectionTimeout```
-: Maximum interval of time in milliseconds the plugin waits for a connection
- to the target instance. When not specified, the default value is set to 5000ms.
-
-```http.socketTimeout```
-: Maximum interval of time in milliseconds the plugin waits for a response from the
- target instance once the connection has been established. When not specified,
- the default value is set to 5000ms.
-
-```http.maxTries```
-: Maximum number of times the plugin should attempt when calling a REST API in
- the target instance. Setting this value to 0 will disable retries. When not
- specified, the default value is 360. After this number of failed tries, an
- error is logged.
-
-```http.retryInterval```
-: The interval of time in milliseconds between the subsequent auto-retries.
- When not specified, the default value is set to 10000ms.
-
-NOTE: the default settings for `http.timeout` and `http.maxTries` ensure that
-the plugin will keep retrying to forward a message for one hour.
+## Configuration parameters
```cache.synchronize```
: Whether to synchronize cache evictions.
@@ -163,9 +88,6 @@
: The interval of time in milliseconds between the subsequent auto-retries.
Defaults to 30000 (30 seconds).
-```healthcheck.enable```
-: Whether to enable the health check endpoint. Defaults to 'true'.
-
```kafka.bootstrapServers```
: List of Kafka broker hosts:port to use for publishing events to the message broker
@@ -190,43 +112,58 @@
Defaults: false
```kafka.publisher.indexEventEnabled```
-: Enable publication of index events
+: Enable publication of index events, ignored when `kafka.publisher.enabled` is false
Defaults: true
```kafka.publisher.cacheEventEnabled```
-: Enable publication of cache events
+: Enable publication of cache events, ignored when `kafka.publisher.enabled` is false
Defaults: true
```kafka.publisher.projectListEventEnabled```
-: Enable publication of project list events
+: Enable publication of project list events, ignored when `kafka.publisher.enabled` is false
Defaults: true
```kafka.publisher.streamEventEnabled```
-: Enable publication of stream events
+: Enable publication of stream events, ignored when `kafka.publisher.enabled` is false
Defaults: true
```kafka.subscriber.enabled```
-: Enable consuming of Kafka events
+: Enable consuming of events from Kafka
Defaults: false
```kafka.subscriber.indexEventEnabled```
-: Enable consumption of index events
+: Enable consumption of index events, ignored when `kafka.subscriber.enabled` is false
Defaults: true
```kafka.subscriber.cacheEventEnabled```
-: Enable consumption of cache events
+: Enable consumption of cache events, ignored when `kafka.subscriber.enabled` is false
Defaults: true
```kafka.subscriber.projectListEventEnabled```
-: Enable consumption of project list events
+: Enable consumption of project list events, ignored when `kafka.subscriber.enabled` is false
Defaults: true
```kafka.subscriber.streamEventEnabled```
-: Enable consumption of stream events
+: Enable consumption of stream events, ignored when `kafka.subscriber.enabled` is false
Defaults: true
```kafka.subscriber.pollingIntervalMs```
: Polling interval for checking incoming events
+ Defaults: 1000
-```kafka.subscriber.autoCommitIntervalMs```
-: Interval for committing incoming events automatically after consumption
+#### Custom kafka properties:
+
+In addition to the above settings, custom Kafka properties can be explicitly set for `publisher` and `subscriber`.
+In order to be acknowledged, these properties need to be prefixed with the `KafkaProp-` prefix and then camelCased,
+as follows: `KafkaProp-yourPropertyValue`
+
+For example, if you want to set the `auto.commit.interval.ms` property for your consumers, you will need to configure
+this property as `KafkaProp-autoCommitIntervalMs`.
+
+**NOTE**: custom kafka properties will be ignored when the relevant subsection is disabled (i.e. `kafka.subscriber.enabled`
+and/or `kafka.publisher.enabled` are set to `false`).
+
+The complete list of available settings can be found directly in the kafka website:
+
+* **Publisher**: https://kafka.apache.org/documentation/#producerconfigs
+* **Subscriber**: https://kafka.apache.org/documentation/#consumerconfigs
\ No newline at end of file
diff --git a/src/main/resources/Documentation/design.md b/src/main/resources/Documentation/design.md
new file mode 100644
index 0000000..e3b7ecc
--- /dev/null
+++ b/src/main/resources/Documentation/design.md
@@ -0,0 +1,378 @@
+# Gerrit Multi-Site Plugin Design
+
+This document aims at helping in collecting and organizing the thoughts about
+the design of the Gerrit multi-site plugin and supporting the definition of the
+[implementation roadmap](#next-steps-in-the-road-map).
+
+It starts presenting a background of the problem that is trying to address and
+the tools currently available in the Gerrit ecosystem that helps to support the
+solution. It then gives an overall roadmap of the support for Gerrit
+multi-site and a snapshot of the current status of the design and its associated
+limitations and constraints.
+
+## Approaches to highly scalable and available Gerrit
+
+Offering a highly available and scalable service is a challenging problem. There
+are trade-offs to be made because of the constraints defined by the
+[CAP theorem](https://en.wikipedia.org/wiki/CAP_theorem), and therefore designing a
+performant and scalable solution is a real challenge.
+
+Companies that adopt Gerrit as the center of their development and review
+pipeline often have the requirement to be available on a 24/7 basis and possibly
+serving large and geographically distributed teams in different continents.
+
+### Vertical scaling and high-availability
+
+Vertical scaling is one of the options to support a high load and a large number
+of users. Having a big powerful server with multiple cores and plenty of RAM to
+potentially fit the most frequently used repositories simplifies the design and
+implementation of the system. Nowadays the cost of hardware and the availability
+of multi-core CPUs have made this solution highly attractive to some large
+Gerrit setups. The central Gerrit server can also be duplicated with an
+active/passive or active/active high-availability setup where the storage of the
+Git repositories is shared across nodes through dedicated fibre-channel lines or
+SANs.
+
+This approach can be suitable for mid to large-sized Gerrit Installations where
+teams are co-located or connected via high-speed dedicated networks. However,
+then teams can be located on the other side of the planet, the speed of light
+would still limit the highest theoretical fire-channel direct connection (e.g.,
+from San Francisco to Bangalore the theoretical absolute minimum latency is 50
+msec, but in practical terms, it is often around 150/200 msec in the best case
+scenarios).
+
+### Horizontal scaling and multi-site
+
+One alternative approach is horizontal scaling, where the workload can be spread
+across several nodes distributed to different locations. This solution offers a
+higher level of scalability and lower latency across locations but requires
+a more complex design.
+
+Two teams located one in San Francisco and the other in Bangalore would access a
+set of Gerrit masters located closer to their geographical position, with higher
+bandwidth and lower latency. The number of Gerrit masters can be scaled up and
+down on-demand, reducing the potential operational costs due to the
+proliferation of multiple servers.
+
+### Multi-master and multi-site, the best of both worlds
+
+The vertical and horizontal approaches can be also combined together to achieve
+both high performances on the same location and low latency across
+geographically distributed sites.
+
+The geographical locations with larger teams and projects can have a bigger
+Gerrit server in a high-availability configuration, while the ones that have
+less critical service levels can use a lower-spec setup.
+
+## Focus of the multi-site plugin
+
+The multi-site plugin is intended to enable the OpenSource version of Gerrit
+Code Review code-base to support horizontal scalability across sites.
+
+Gerrit has been already been deployed in a multi-site configuration at
+[Google](https://www.youtube.com/watch?v=wlHpqfnIBWE) and a multi-master fashion
+at [Qualcomm](https://www.youtube.com/watch?v=X_rmI8TbKmY). Both implementations
+included fixes and extensions that were focussed in addressing the specific
+infrastructure requirements of the Google and Qualcomm global networks. Those
+requirements may or may not be shared with the rest of the OpenSource Community.
+
+Qualcomm's version of Gerrit is a fork of v2.7, Google's deployment is
+proprietary and would not be suitable for any environment outside the Google's
+data-centers.
+
+The multi-site plugin, instead, is based on standard OpenSource components and
+is deployed on a standard cloud environment. It is currently used in a multi-
+master and multi-site deployment on GerritHub.io, serving two continents (Europe
+and Americas) in a high-availability setup on each site.
+
+# The road to multi-site
+
+The development of the multi-site support for Gerrit is complex and thus has
+been deliberately broken down into incremental steps. The starting point is a
+single Gerrit master deployment, and the end goal is a fully distributed set of
+cooperating Gerrit masters across the globe.
+
+1. 1x master / single location.
+2. 2x masters (active/standby) / single location - shared disks
+3. 2x masters (active/passive) / single location - shared disks
+4. 2x masters (active RW/active RO) / single location - shared disks
+5. 2x masters (active RW/active RO) / single location - separate disks
+6. 2x masters (active RW/active RO) / active + disaster recovery location
+7. 2x masters (active RW/active RO) / two locations
+8. 2x masters (active RW/active RW) sharded / two locations
+9. 3x masters (active RW/active RW) sharded with auto-election / two locations
+10. Multiple masters (active RW/active RW) with quorum / multiple locations
+
+The transition between steps does require not only an evolution of the Gerrit
+setup and the set of plugins but also a different maturity level in the way the
+servers are provision, maintained and versioned across the network. Qualcomm
+pointed out the evolution of the company culture and the ability to consistently
+version and provision the different server environments as a winning factor of
+their multi-master setup.
+
+Google is currently running at stage #10, Qualcomm is at stage #4 with the
+difference that both masters are serving RW traffic, due to the specifics
+of their underlying storage, NFS and JGit implementation that allows concurrent
+locking at filesystem level.
+
+## History and maturity level of the multi-site plugin
+
+This plugin is coming from the excellent work on the high-availability plugin,
+introduced by Ericsson for solving a mutli-master at stage #4. The git log history
+of this projects still shows the 'branching point' on where it started.
+
+The current version of the multi-site plugin is at stage #7, which is a pretty
+advanced stage in the Gerrit multi-master/multi-site configuration.
+
+Thanks to the multi-site plugin, it is possible to have Gerrit configured and
+available in two separate geo-locations (e.g. San Francisco and Bangalore),
+where both of them are serving local traffic through the local instances with
+minimum latency.
+
+### Why another plugin from a high-availability fork?
+
+By reading this design document you may be wondering the reason behind
+creating yet another plugin for solving multi-master instead of just keeping
+a single code-base with the high-availability plugin.
+The reason can be found in the initial part of design that described the two
+different approaches to scalability: vertical (single site) and horizonal (multi-site).
+
+You could in theory keep a single code-base to manage both of them, however the
+result would have been very complicated and difficult to configure and install.
+Having two more focussed plugins, one for high-availability and another for
+multi-site, would allow to have a simpler and more usable experience for developers
+of the plugin and for the Gerrit administrators using it.
+
+### Benefits
+
+There are some advantages in implementing multi-site at stage #7:
+
+- Optimal latency of the read-only operations on both sites, which makes around 90%
+ of the Gerrit traffic overall.
+
+- High SLA (99.99% or higher, source: GerritHub.io) due to the possibility of
+ implementing both high-availability inside the local site and automatic site
+ failover in case of a catastrophe in one of the two sites.
+
+- Transparency of access through a single Gerrit URL entry-point.
+
+- Automatic failover, disaster recovery and leader re-election.
+
+- The two sites have local consistency and, on a global level, eventual consistency.
+
+### Limitations
+
+The current limitations of stage #7 are:
+
+- Only one of the two sites can be RW and thus accepting modifications on the
+ Git repositories or the review data.
+
+- It can easily support only two sites.
+ You could potentially use it for more sites, however the configuration
+ and maintenance efforts are more than linear to the number of nodes.
+
+- Switch between the RO to RW site is defined by a unique decision point, which
+ is a Single-Point-of-Failure
+
+- Lack of transactionality between sites.
+ Data written to one site is acknowledged
+ before its replication to the other location.
+
+- The solution requires a Server completely based on NoteDb and thus requires
+ Gerrit v2.16 or later.
+
+**NOTE:** If you are not familiar with NoteDb, please read the relevant
+[section in the Gerrit documentation](https://gerrit-documentation.storage.googleapis.com/Documentation/2.16.5/note-db.html).
+
+### Example of multi-site operations
+
+Let's suppose the RW site is San Francisco and the RO site Bangalore. The
+modifications of data will always come to San Francisco and flow to Bangalore
+with a latency that can be anywhere between seconds and minutes, depending on
+the network infrastructure between the two sites. A developer located in
+Bangalore will always see a "snapshot in the past" of the data from both the
+Gerrit UI and on the Git repository served locally, while a developer located in
+San Francisco will always see the "latest and greatest" of everything.
+
+Should the central site in San Francisco collapse or not become available for a
+significant period of time, the Bangalore site will take over as main RW Gerrit
+site and will be able to serve any operation. The roles will then be inverted
+where the people in San Francisco will have to use the remote Gerrit server
+located in Bangalore while the local system is down. Once the San Francisco site
+is back, it will need to pass the "necessary checks" to be re-elected as the
+main RW site.
+
+# Plugin design
+
+This section goes into the high-level design of the current solution and lists
+the components involved and how they interact with each other.
+
+## What to replicate across Gerrit sites
+
+There are several distinct classes of information that have to be kept
+consistent across different sites to guarantee seamless operation of the
+distributed system.
+
+- Git repositories: they are stored on disk and are the most important
+Information to maintain.
+
+ * Git BLOBs, objects, refs and trees.
+
+ * NoteDb, including Groups, Accounts and review data
+
+ * Projects configuration and ACLs
+
+ * Projects submit rules
+
+- Indexes: this is a series of secondary indexes to allow search and quick access
+ to the Git repository data. Indexes are persistent across restarts.
+
+- Caches: is a set of in-memory and persisted designed to reduce CPU and disk
+ utilization and improve performance
+
+- Web Sessions: define an active user session with Gerrit allowing to reduce the
+ load to the underlying authentication system.
+ Sessions are stored by default on the local filesystem in an H2 table but can
+ be externalized via plugins, like the WebSession Flatfile.
+
+To achieve a stage #7 multi-site configuration, all the above information needs
+to replicate transparently across sites.
+
+## Overall high-level architecture
+
+The multi-site solution described here is based on the combined use of different
+components:
+
+- **multi-site plugin**: enables the replication of Gerrit _indexes_, _caches_,
+ and _stream events_ across sites
+
+- **replication plugin**: enables the replication of the _Git repositories_ across
+ sites
+
+- **web-session flat file plugin**: supports the storage of _active sessions_
+ to an external file that can be shared and synchronized across sites.
+
+- **health check plugin**: supports the automatic election of the RW site based
+ on a number of underlying conditions of the data and the systems.
+
+- **HA Proxy**: provides the single entry-point to all Gerrit functionality across sites.
+
+The combination of the above components makes the Gerrit multi-site
+configuration possible.
+
+![Initial Multi-Site Plugin Architecture](./architecture-first-iteration.png)
+
+## Current implementation Details
+
+The multi-site plugin adopts an event-sourcing pattern and is based on an
+external message broker. The current implementation is based on Apache Kafka,
+however, it is potentially extensible to many others like RabbitMQ or NATS.
+
+### Eventual consistency on Git, indexes, caches, and stream events
+
+The replication of the Git repositories, indexes, cache and stream events happen
+on different channels and at different speeds. Git data is typically larger than
+meta-data and has higher latency than reindexing, cache evictions or stream
+events. That means that when someone pushes a new change to Gerrit on one site,
+the Git data (commits, BLOBs, trees, and refs) may arrive later than the
+associated reindexing or cache eviction events.
+
+It is, therefore, necessary to handle the lack of synchronization of those
+channels in the multi-site plugin and reconcile the events at the destination
+ends.
+
+The solution adopted by the multi-site plugin supports eventual consistency at
+rest at the data level, thanks to the following two components:
+
+* A mechanism to recognize _not-yet-processable events_ related to data not yet
+available (based on the timestamp information available on both the metadata
+update and the data event)
+
+* A queue of *not-yet-processable events* and an *asynchronous processor*
+to check if they became processable. The system also is configured to discard
+events that have been in the queue for too long.
+
+### Avoiding event replication loops
+
+Stream events also are wrapped into an event header containing a source identifier,
+so that events originated by the same node in the broker-based channel are silently
+dropped to prevent the loop.
+The events originated by the same node in the broker-based channel are
+dropped to prevent the loop. Stream events also are wrapped into an event header
+containing a source identifier, so that they are not replicated multiple times.
+
+Gerrit has the concept of server-id, which, unfortunately, would not help us for
+solving this problem: all the nodes in a Gerrit cluster must have the same
+server-id to allow interoperability of the data stored in NoteDb.
+
+The multi-site plugin introduces a new concept of instance-id, which is a UUID
+generated during startup and saved into the data folder of the Gerrit site. If
+the Gerrit site is cleared or removed, a new id is generated and the multi-site
+plugin will start consuming all events that have been previously produced.
+
+The concept of the instance-id is very useful and other plugins could benefit
+from it. It would be the first candidate to be moved into the Gerrit core and
+generated and maintained with the rest of the configuration.
+
+Once Gerrit will start having an instance-id, that information could then be
+included in all stream events also, making the multi-site plugin "enveloping of
+events" redundant.
+
+### Managing failures
+
+The broker based solutions improve the resilience and scalability of the system,
+but still has a point of failure in the availability of the broker. However, the
+choice of the broker allows having a high-level of redundancy and a multi-master
+/ multi-site configuration at transport and storage level.
+
+At the moment the acknowledge level for publication can be controlled via
+configuration and allows to tune the QoS of the publication process. Failures
+are explicitly not handled at the moment, and they are just logged as errors.
+There is no retry mechanism to handle temporary failures.
+
+# Next steps in the road-map
+
+## Step-1: fill the gaps of multi-site stage #7:
+
+- Detection of a stale site. The health check plugin has no awareness that one
+ site that can be "too outdated" because it is still technically "healthy." A
+ stale site needs to be put outside the balancing and all traffic needs to go
+ to the more up-to-date site.
+
+- Web session replication. Currently needs to be implemented at filesystem level
+ using rsync across sites, which can be a problem because of the delay
+ introduced. Should a site fail, some of the users may lose their sessions
+ because the rsync was not executed yet.
+
+- Index rebuild in case of broker failure. In the catastrophic event of a global
+ failure at the broker level, the indexes of the two sites would be out of
+ sync. A mechanism is needed to be put in place to recover the situation
+ without having to necessarily reindex both sites offline, which would require
+ even days for huge installations.
+
+- Git/SSH redirection. Local users relying on Git/SSH protocol would not be able
+ to use the local site for serving their requests, because HAProxy would not be
+ able to understand the type of traffic and would be forced always to use the
+ RW site, even though the operation was RO.
+
+- Support for different brokers: the current multi-site plugin supports Kafka.
+ More brokers would need to be supported in a fashion similar to the
+ [ITS-* plugins framework](https://gerrit-review.googlesource.com/admin/repos/q/filter:plugins%252Fits).
+ The multi-site plugin would not have anymore the explicit
+ references to Kafka, but other plugins may contribute the implementation to
+ the broker extension point.
+
+- Splitting the publishing and subscribing part of this plugin in two separate
+ plugins: the generation of the events would be combined to the current kafka-
+ events plugin while the multi-site will be more focussed in supporting the
+ consumption and sorting out the replication issues.
+
+## Step-2: move to multi-site stage #8.
+
+- Auto-reconfigure HAProxy rules based on the projects sharding policy
+
+- Serve RW/RW traffic based on the project name/ref-name.
+
+- Balance traffic with "locally-aware" policies based on historical data
+
+- Preventing split-brain in case of temporary sites isolation
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/ConfigurationTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/ConfigurationTest.java
index 12c5142..a4bebb7 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/ConfigurationTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/multisite/ConfigurationTest.java
@@ -22,29 +22,16 @@
import static com.googlesource.gerrit.plugins.multisite.Configuration.Event.EVENT_SECTION;
import static com.googlesource.gerrit.plugins.multisite.Configuration.Forwarding.DEFAULT_SYNCHRONIZE;
import static com.googlesource.gerrit.plugins.multisite.Configuration.Forwarding.SYNCHRONIZE_KEY;
-import static com.googlesource.gerrit.plugins.multisite.Configuration.HealthCheck.DEFAULT_HEALTH_CHECK_ENABLED;
-import static com.googlesource.gerrit.plugins.multisite.Configuration.HealthCheck.HEALTH_CHECK_SECTION;
-import static com.googlesource.gerrit.plugins.multisite.Configuration.Http.CONNECTION_TIMEOUT_KEY;
-import static com.googlesource.gerrit.plugins.multisite.Configuration.Http.DEFAULT_MAX_TRIES;
-import static com.googlesource.gerrit.plugins.multisite.Configuration.Http.DEFAULT_RETRY_INTERVAL;
-import static com.googlesource.gerrit.plugins.multisite.Configuration.Http.DEFAULT_TIMEOUT_MS;
-import static com.googlesource.gerrit.plugins.multisite.Configuration.Http.HTTP_SECTION;
-import static com.googlesource.gerrit.plugins.multisite.Configuration.Http.MAX_TRIES_KEY;
-import static com.googlesource.gerrit.plugins.multisite.Configuration.Http.PASSWORD_KEY;
-import static com.googlesource.gerrit.plugins.multisite.Configuration.Http.RETRY_INTERVAL_KEY;
-import static com.googlesource.gerrit.plugins.multisite.Configuration.Http.SOCKET_TIMEOUT_KEY;
-import static com.googlesource.gerrit.plugins.multisite.Configuration.Http.USER_KEY;
import static com.googlesource.gerrit.plugins.multisite.Configuration.Index.INDEX_SECTION;
-import static com.googlesource.gerrit.plugins.multisite.Configuration.PEER_INFO_SECTION;
-import static com.googlesource.gerrit.plugins.multisite.Configuration.PeerInfoStatic.STATIC_SUBSECTION;
-import static com.googlesource.gerrit.plugins.multisite.Configuration.PeerInfoStatic.URL_KEY;
+import static com.googlesource.gerrit.plugins.multisite.Configuration.KAFKA_PROPERTY_PREFIX;
+import static com.googlesource.gerrit.plugins.multisite.Configuration.KAFKA_SECTION;
+import static com.googlesource.gerrit.plugins.multisite.Configuration.KafkaPublisher.KAFKA_PUBLISHER_SUBSECTION;
+import static com.googlesource.gerrit.plugins.multisite.Configuration.KafkaSubscriber.KAFKA_SUBSCRIBER_SUBSECTION;
import static com.googlesource.gerrit.plugins.multisite.Configuration.THREAD_POOL_SIZE_KEY;
import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableList;
import com.google.gerrit.server.config.PluginConfigFactory;
-import java.io.IOException;
-import java.util.List;
import org.eclipse.jgit.lib.Config;
import org.junit.Before;
import org.junit.Test;
@@ -57,20 +44,13 @@
private static final String INVALID_BOOLEAN = "invalidBoolean";
private static final String INVALID_INT = "invalidInt";
private static final String PLUGIN_NAME = "multi-site";
- private static final String PASS = "fakePass";
- private static final String USER = "fakeUser";
- private static final String URL = "http://fakeUrl";
- private static final List<String> URLS = ImmutableList.of(URL, "http://anotherUrl/");
- private static final int TIMEOUT = 5000;
- private static final int MAX_TRIES = 5;
- private static final int RETRY_INTERVAL = 1000;
private static final int THREAD_POOL_SIZE = 1;
@Mock private PluginConfigFactory pluginConfigFactoryMock;
private Config globalPluginConfig;
@Before
- public void setUp() throws IOException {
+ public void setUp() {
globalPluginConfig = new Config();
when(pluginConfigFactoryMock.getGlobalPluginConfig(PLUGIN_NAME)).thenReturn(globalPluginConfig);
}
@@ -80,75 +60,6 @@
}
@Test
- public void testGetUrls() throws Exception {
- assertThat(getConfiguration().peerInfoStatic().urls()).isEmpty();
-
- globalPluginConfig.setStringList(PEER_INFO_SECTION, STATIC_SUBSECTION, URL_KEY, URLS);
- assertThat(getConfiguration().peerInfoStatic().urls())
- .containsAllIn(ImmutableList.of(URL, "http://anotherUrl"));
- }
-
- @Test
- public void testGetUser() throws Exception {
- assertThat(getConfiguration().http().user()).isEmpty();
-
- globalPluginConfig.setString(HTTP_SECTION, null, USER_KEY, USER);
- assertThat(getConfiguration().http().user()).isEqualTo(USER);
- }
-
- @Test
- public void testGetPassword() throws Exception {
- assertThat(getConfiguration().http().password()).isEmpty();
-
- globalPluginConfig.setString(HTTP_SECTION, null, PASSWORD_KEY, PASS);
- assertThat(getConfiguration().http().password()).isEqualTo(PASS);
- }
-
- @Test
- public void testGetConnectionTimeout() throws Exception {
- assertThat(getConfiguration().http().connectionTimeout()).isEqualTo(DEFAULT_TIMEOUT_MS);
-
- globalPluginConfig.setInt(HTTP_SECTION, null, CONNECTION_TIMEOUT_KEY, TIMEOUT);
- assertThat(getConfiguration().http().connectionTimeout()).isEqualTo(TIMEOUT);
-
- globalPluginConfig.setString(HTTP_SECTION, null, CONNECTION_TIMEOUT_KEY, INVALID_INT);
- assertThat(getConfiguration().http().connectionTimeout()).isEqualTo(DEFAULT_TIMEOUT_MS);
- }
-
- @Test
- public void testGetSocketTimeout() throws Exception {
- assertThat(getConfiguration().http().socketTimeout()).isEqualTo(DEFAULT_TIMEOUT_MS);
-
- globalPluginConfig.setInt(HTTP_SECTION, null, SOCKET_TIMEOUT_KEY, TIMEOUT);
- assertThat(getConfiguration().http().socketTimeout()).isEqualTo(TIMEOUT);
-
- globalPluginConfig.setString(HTTP_SECTION, null, SOCKET_TIMEOUT_KEY, INVALID_INT);
- assertThat(getConfiguration().http().socketTimeout()).isEqualTo(DEFAULT_TIMEOUT_MS);
- }
-
- @Test
- public void testGetMaxTries() throws Exception {
- assertThat(getConfiguration().http().maxTries()).isEqualTo(DEFAULT_MAX_TRIES);
-
- globalPluginConfig.setInt(HTTP_SECTION, null, MAX_TRIES_KEY, MAX_TRIES);
- assertThat(getConfiguration().http().maxTries()).isEqualTo(MAX_TRIES);
-
- globalPluginConfig.setString(HTTP_SECTION, null, MAX_TRIES_KEY, INVALID_INT);
- assertThat(getConfiguration().http().maxTries()).isEqualTo(DEFAULT_MAX_TRIES);
- }
-
- @Test
- public void testGetRetryInterval() throws Exception {
- assertThat(getConfiguration().http().retryInterval()).isEqualTo(DEFAULT_RETRY_INTERVAL);
-
- globalPluginConfig.setInt(HTTP_SECTION, null, RETRY_INTERVAL_KEY, RETRY_INTERVAL);
- assertThat(getConfiguration().http().retryInterval()).isEqualTo(RETRY_INTERVAL);
-
- globalPluginConfig.setString(HTTP_SECTION, null, RETRY_INTERVAL_KEY, INVALID_INT);
- assertThat(getConfiguration().http().retryInterval()).isEqualTo(DEFAULT_RETRY_INTERVAL);
- }
-
- @Test
public void testGetIndexThreadPoolSize() throws Exception {
assertThat(getConfiguration().index().threadPoolSize()).isEqualTo(DEFAULT_THREAD_POOL_SIZE);
@@ -222,13 +133,80 @@
}
@Test
- public void testHealthCheckEnabled() throws Exception {
- assertThat(getConfiguration().healthCheck().enabled()).isEqualTo(DEFAULT_HEALTH_CHECK_ENABLED);
+ public void kafkaSubscriberPropertiesAreSetWhenSectionIsEnabled() {
+ final String kafkaPropertyName = KAFKA_PROPERTY_PREFIX + "fooBarBaz";
+ final String kafkaPropertyValue = "aValue";
+ globalPluginConfig.setBoolean(KAFKA_SECTION, KAFKA_SUBSCRIBER_SUBSECTION, ENABLE_KEY, true);
+ globalPluginConfig.setString(
+ KAFKA_SECTION, KAFKA_SUBSCRIBER_SUBSECTION, kafkaPropertyName, kafkaPropertyValue);
- globalPluginConfig.setBoolean(HEALTH_CHECK_SECTION, null, ENABLE_KEY, false);
- assertThat(getConfiguration().healthCheck().enabled()).isFalse();
+ final String property = getConfiguration().kafkaSubscriber().getProperty("foo.bar.baz");
- globalPluginConfig.setBoolean(HEALTH_CHECK_SECTION, null, ENABLE_KEY, true);
- assertThat(getConfiguration().healthCheck().enabled()).isTrue();
+ assertThat(property.equals(kafkaPropertyValue)).isTrue();
+ }
+
+ @Test
+ public void kafkaSubscriberPropertiesAreNotSetWhenSectionIsDisabled() {
+ final String kafkaPropertyName = KAFKA_PROPERTY_PREFIX + "fooBarBaz";
+ final String kafkaPropertyValue = "aValue";
+ globalPluginConfig.setBoolean(KAFKA_SECTION, KAFKA_SUBSCRIBER_SUBSECTION, ENABLE_KEY, false);
+ globalPluginConfig.setString(
+ KAFKA_SECTION, KAFKA_SUBSCRIBER_SUBSECTION, kafkaPropertyName, kafkaPropertyValue);
+
+ final String property = getConfiguration().kafkaSubscriber().getProperty("foo.bar.baz");
+
+ assertThat(property).isNull();
+ }
+
+ @Test
+ public void kafkaSubscriberPropertiesAreIgnoredWhenPrefixIsNotSet() {
+ final String kafkaPropertyName = "fooBarBaz";
+ final String kafkaPropertyValue = "aValue";
+ globalPluginConfig.setBoolean(KAFKA_SECTION, KAFKA_SUBSCRIBER_SUBSECTION, ENABLE_KEY, true);
+ globalPluginConfig.setString(
+ KAFKA_SECTION, KAFKA_SUBSCRIBER_SUBSECTION, kafkaPropertyName, kafkaPropertyValue);
+
+ final String property = getConfiguration().kafkaSubscriber().getProperty("foo.bar.baz");
+
+ assertThat(property).isNull();
+ }
+
+ @Test
+ public void kafkaPublisherPropertiesAreSetWhenSectionIsEnabled() {
+ final String kafkaPropertyName = KAFKA_PROPERTY_PREFIX + "fooBarBaz";
+ final String kafkaPropertyValue = "aValue";
+ globalPluginConfig.setBoolean(KAFKA_SECTION, KAFKA_PUBLISHER_SUBSECTION, ENABLE_KEY, true);
+ globalPluginConfig.setString(
+ KAFKA_SECTION, KAFKA_PUBLISHER_SUBSECTION, kafkaPropertyName, kafkaPropertyValue);
+
+ final String property = getConfiguration().kafkaPublisher().getProperty("foo.bar.baz");
+
+ assertThat(property.equals(kafkaPropertyValue)).isTrue();
+ }
+
+ @Test
+ public void kafkaPublisherPropertiesAreIgnoredWhenPrefixIsNotSet() {
+ final String kafkaPropertyName = "fooBarBaz";
+ final String kafkaPropertyValue = "aValue";
+ globalPluginConfig.setBoolean(KAFKA_SECTION, KAFKA_PUBLISHER_SUBSECTION, ENABLE_KEY, true);
+ globalPluginConfig.setString(
+ KAFKA_SECTION, KAFKA_PUBLISHER_SUBSECTION, kafkaPropertyName, kafkaPropertyValue);
+
+ final String property = getConfiguration().kafkaPublisher().getProperty("foo.bar.baz");
+
+ assertThat(property).isNull();
+ }
+
+ @Test
+ public void kafkaPublisherPropertiesAreNotSetWhenSectionIsDisabled() {
+ final String kafkaPropertyName = KAFKA_PROPERTY_PREFIX + "fooBarBaz";
+ final String kafkaPropertyValue = "aValue";
+ globalPluginConfig.setBoolean(KAFKA_SECTION, KAFKA_PUBLISHER_SUBSECTION, ENABLE_KEY, false);
+ globalPluginConfig.setString(
+ KAFKA_SECTION, KAFKA_PUBLISHER_SUBSECTION, kafkaPropertyName, kafkaPropertyValue);
+
+ final String property = getConfiguration().kafkaPublisher().getProperty("foo.bar.baz");
+
+ assertThat(property).isNull();
}
}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/broker/kafka/BrokerPublisherTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/broker/kafka/BrokerPublisherTest.java
new file mode 100644
index 0000000..329774e
--- /dev/null
+++ b/src/test/java/com/googlesource/gerrit/plugins/multisite/broker/kafka/BrokerPublisherTest.java
@@ -0,0 +1,158 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.googlesource.gerrit.plugins.multisite.broker.kafka;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.gerrit.extensions.client.ChangeKind;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Branch;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.server.data.AccountAttribute;
+import com.google.gerrit.server.data.ApprovalAttribute;
+import com.google.gerrit.server.events.CommentAddedEvent;
+import com.google.gerrit.server.util.time.TimeUtil;
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.googlesource.gerrit.plugins.multisite.broker.BrokerPublisher;
+import com.googlesource.gerrit.plugins.multisite.broker.BrokerSession;
+import com.googlesource.gerrit.plugins.multisite.broker.GsonProvider;
+import com.googlesource.gerrit.plugins.multisite.forwarder.events.EventFamily;
+import java.util.UUID;
+import org.junit.Before;
+import org.junit.Test;
+
+public class BrokerPublisherTest {
+ private BrokerPublisher publisher;
+ private Gson gson = new GsonProvider().get();
+
+ @Before
+ public void setUp() {
+ publisher = new BrokerPublisher(new TestBrokerSession(), gson, UUID.randomUUID());
+ }
+
+ @Test
+ public void shouldSerializeCommentAddedEvent() {
+
+ final String accountName = "Foo Bar";
+ final String accountEmail = "foo@bar.com";
+ final String accountUsername = "foobar";
+ final String approvalType = ChangeKind.REWORK.toString();
+
+ final String approvalDescription = "ApprovalDescription";
+ final String approvalValue = "+2";
+ final String oldApprovalValue = "+1";
+ final Long approvalGrantedOn = 123L;
+ final String commentDescription = "Patch Set 1: Code-Review+2";
+ final String projectName = "project";
+ final String refName = "refs/heads/master";
+ final String changeId = "Iabcd1234abcd1234abcd1234abcd1234abcd1234";
+ final Long eventCreatedOn = 123L;
+
+ final Change change =
+ new Change(
+ new Change.Key(changeId),
+ new Change.Id(1),
+ new Account.Id(1),
+ new Branch.NameKey(projectName, refName),
+ TimeUtil.nowTs());
+
+ CommentAddedEvent event = new CommentAddedEvent(change);
+ AccountAttribute accountAttribute = new AccountAttribute();
+ accountAttribute.email = accountEmail;
+ accountAttribute.name = accountName;
+ accountAttribute.username = accountUsername;
+
+ event.eventCreatedOn = eventCreatedOn;
+ event.approvals =
+ () -> {
+ ApprovalAttribute approvalAttribute = new ApprovalAttribute();
+ approvalAttribute.value = approvalValue;
+ approvalAttribute.oldValue = oldApprovalValue;
+ approvalAttribute.description = approvalDescription;
+ approvalAttribute.by = accountAttribute;
+ approvalAttribute.type = ChangeKind.REWORK.toString();
+ approvalAttribute.grantedOn = approvalGrantedOn;
+
+ return new ApprovalAttribute[] {approvalAttribute};
+ };
+
+ event.author = () -> accountAttribute;
+ event.comment = commentDescription;
+
+ String expectedSerializedCommentEvent =
+ "{\"author\": {\"name\": \""
+ + accountName
+ + "\",\"email\": \""
+ + accountEmail
+ + "\",\"username\": \""
+ + accountUsername
+ + "\"},\"approvals\": [{\"type\": \""
+ + approvalType
+ + "\",\"description\": \""
+ + approvalDescription
+ + "\",\"value\": \""
+ + approvalValue
+ + "\",\"oldValue\": \""
+ + oldApprovalValue
+ + "\",\"grantedOn\": "
+ + approvalGrantedOn
+ + ",\"by\": {\"name\": \""
+ + accountName
+ + "\",\"email\": \""
+ + accountEmail
+ + "\",\"username\": \""
+ + accountUsername
+ + "\"}}],\"comment\": \""
+ + commentDescription
+ + "\",\""
+ + projectName
+ + "\": {\"name\": \""
+ + projectName
+ + "\"},\"refName\": \""
+ + refName
+ + "\",\"changeKey\": {\"id\": \""
+ + changeId
+ + "\""
+ + " },\"type\": \"comment-added\",\"eventCreatedOn\": "
+ + eventCreatedOn
+ + "}";
+
+ JsonObject expectedCommentEventJsonObject =
+ gson.fromJson(expectedSerializedCommentEvent, JsonElement.class).getAsJsonObject();
+
+ assertThat(publisher.eventToJson(event).equals(expectedCommentEventJsonObject)).isTrue();
+ }
+
+ private class TestBrokerSession implements BrokerSession {
+
+ @Override
+ public boolean isOpen() {
+ return false;
+ }
+
+ @Override
+ public void connect() {}
+
+ @Override
+ public void disconnect() {}
+
+ @Override
+ public boolean publishEvent(EventFamily eventFamily, String payload) {
+ return false;
+ }
+ }
+}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/cache/CacheEvictionIT.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/cache/CacheEvictionIT.java
deleted file mode 100644
index 83ec0ff..0000000
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/cache/CacheEvictionIT.java
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright (C) 2015 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.cache;
-
-import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
-import static com.github.tomakehurst.wiremock.client.WireMock.any;
-import static com.github.tomakehurst.wiremock.client.WireMock.anyUrl;
-import static com.github.tomakehurst.wiremock.client.WireMock.givenThat;
-import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor;
-import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
-import static com.github.tomakehurst.wiremock.client.WireMock.verify;
-import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
-import static com.google.common.truth.Truth.assertThat;
-
-import com.github.tomakehurst.wiremock.junit.WireMockRule;
-import com.google.gerrit.acceptance.GlobalPluginConfig;
-import com.google.gerrit.acceptance.LightweightPluginDaemonTest;
-import com.google.gerrit.acceptance.NoHttpd;
-import com.google.gerrit.acceptance.TestPlugin;
-import com.google.gerrit.acceptance.UseLocalDisk;
-import com.google.gerrit.acceptance.UseSsh;
-import com.googlesource.gerrit.plugins.multisite.cache.Constants;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import org.apache.http.HttpStatus;
-import org.junit.Rule;
-import org.junit.Test;
-
-@NoHttpd
-@UseSsh
-@TestPlugin(
- name = "multi-site",
- sysModule = "com.googlesource.gerrit.plugins.multisite.Module",
- httpModule = "com.googlesource.gerrit.plugins.multisite.HttpModule")
-public class CacheEvictionIT extends LightweightPluginDaemonTest {
- private static final int PORT = 18888;
- private static final String URL = "http://localhost:" + PORT;
-
- @Rule public WireMockRule wireMockRule = new WireMockRule(options().port(PORT));
-
- @Override
- public void setUpTestPlugin() throws Exception {
- givenThat(any(anyUrl()).willReturn(aResponse().withStatus(HttpStatus.SC_NO_CONTENT)));
- super.setUpTestPlugin();
- }
-
- @Test
- @UseLocalDisk
- @GlobalPluginConfig(pluginName = "multi-site", name = "peerInfo.static.url", value = URL)
- @GlobalPluginConfig(pluginName = "multi-site", name = "http.retryInterval", value = "100")
- public void flushAndSendPost() throws Exception {
- final String flushRequest = "/plugins/multi-site/cache/" + Constants.PROJECTS;
- final CountDownLatch expectedRequestLatch = new CountDownLatch(1);
- wireMockRule.addMockServiceRequestListener(
- (request, response) -> {
- if (request.getAbsoluteUrl().contains(flushRequest)) {
- expectedRequestLatch.countDown();
- }
- });
-
- adminSshSession.exec("gerrit flush-caches --cache " + Constants.PROJECTS);
- assertThat(expectedRequestLatch.await(5, TimeUnit.SECONDS)).isTrue();
- verify(postRequestedFor(urlEqualTo(flushRequest)));
- }
-}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/cache/ProjectListIT.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/cache/ProjectListIT.java
deleted file mode 100644
index 9908618..0000000
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/cache/ProjectListIT.java
+++ /dev/null
@@ -1,79 +0,0 @@
-// 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.googlesource.gerrit.plugins.multisite.cache;
-
-import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
-import static com.github.tomakehurst.wiremock.client.WireMock.any;
-import static com.github.tomakehurst.wiremock.client.WireMock.anyUrl;
-import static com.github.tomakehurst.wiremock.client.WireMock.givenThat;
-import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor;
-import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
-import static com.github.tomakehurst.wiremock.client.WireMock.verify;
-import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
-import static com.google.common.truth.Truth.assertThat;
-
-import com.github.tomakehurst.wiremock.junit.WireMockRule;
-import com.google.gerrit.acceptance.GlobalPluginConfig;
-import com.google.gerrit.acceptance.LightweightPluginDaemonTest;
-import com.google.gerrit.acceptance.NoHttpd;
-import com.google.gerrit.acceptance.TestPlugin;
-import com.google.gerrit.acceptance.UseLocalDisk;
-import com.google.gerrit.extensions.restapi.Url;
-import com.googlesource.gerrit.plugins.multisite.cache.Constants;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import org.apache.http.HttpStatus;
-import org.junit.Rule;
-import org.junit.Test;
-
-@NoHttpd
-@TestPlugin(
- name = "multi-site",
- sysModule = "com.googlesource.gerrit.plugins.multisite.Module",
- httpModule = "com.googlesource.gerrit.plugins.multisite.HttpModule")
-public class ProjectListIT extends LightweightPluginDaemonTest {
- private static final int PORT = 18888;
- private static final String URL = "http://localhost:" + PORT;
-
- @Rule public WireMockRule wireMockRule = new WireMockRule(options().port(PORT));
-
- @Override
- public void setUpTestPlugin() throws Exception {
- givenThat(any(anyUrl()).willReturn(aResponse().withStatus(HttpStatus.SC_NO_CONTENT)));
- super.setUpTestPlugin();
- }
-
- @Test
- @UseLocalDisk
- @GlobalPluginConfig(pluginName = "multi-site", name = "peerInfo.static.url", value = URL)
- @GlobalPluginConfig(pluginName = "multi-site", name = "http.retryInterval", value = "100")
- public void addToProjectListAreForwarded() throws Exception {
- String createdProjectEncoded = Url.encode("org-a/some-project");
- String expectedRequest =
- "/plugins/multi-site/cache/" + Constants.PROJECT_LIST + "/" + createdProjectEncoded;
- CountDownLatch expectedRequestLatch = new CountDownLatch(1);
- wireMockRule.addMockServiceRequestListener(
- (request, response) -> {
- if (request.getAbsoluteUrl().contains(expectedRequest)) {
- expectedRequestLatch.countDown();
- }
- });
-
- adminRestSession.put("/projects/" + createdProjectEncoded).assertCreated();
- assertThat(expectedRequestLatch.await(5, TimeUnit.SECONDS)).isTrue();
- verify(postRequestedFor(urlEqualTo(expectedRequest)));
- }
-}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/ForwardedEventHandlerTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/ForwardedEventHandlerTest.java
index 8516ce4..3b01c61 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/ForwardedEventHandlerTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/ForwardedEventHandlerTest.java
@@ -22,10 +22,8 @@
import com.google.gerrit.server.events.Event;
import com.google.gerrit.server.events.EventDispatcher;
import com.google.gerrit.server.events.ProjectCreatedEvent;
+import com.google.gerrit.server.util.OneOffRequestContext;
import com.google.gwtorm.server.OrmException;
-import com.googlesource.gerrit.plugins.multisite.forwarder.Context;
-import com.googlesource.gerrit.plugins.multisite.forwarder.ForwardedEventHandler;
-
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -40,11 +38,12 @@
@Rule public ExpectedException exception = ExpectedException.none();
@Mock private EventDispatcher dispatcherMock;
+ @Mock OneOffRequestContext oneOffCtxMock;
private ForwardedEventHandler handler;
@Before
public void setUp() throws Exception {
- handler = new ForwardedEventHandler(dispatcherMock);
+ handler = new ForwardedEventHandler(dispatcherMock, oneOffCtxMock);
}
@Test
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/ForwardedIndexGroupHandlerTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/ForwardedIndexGroupHandlerTest.java
index ad2a770..68edd88 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/ForwardedIndexGroupHandlerTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/ForwardedIndexGroupHandlerTest.java
@@ -22,11 +22,10 @@
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.server.index.group.GroupIndexer;
+import com.google.gwtorm.client.KeyUtil;
+import com.google.gwtorm.server.StandardKeyEncoder;
import com.googlesource.gerrit.plugins.multisite.Configuration;
-import com.googlesource.gerrit.plugins.multisite.forwarder.Context;
-import com.googlesource.gerrit.plugins.multisite.forwarder.ForwardedIndexGroupHandler;
import com.googlesource.gerrit.plugins.multisite.forwarder.ForwardedIndexingHandler.Operation;
-
import java.io.IOException;
import java.util.Optional;
import org.junit.Before;
@@ -102,6 +101,8 @@
assertThat(Context.isForwardedEvent()).isFalse();
try {
+ // Had to put this here to avoid a NPE during the index call
+ KeyUtil.setEncoderImpl(new StandardKeyEncoder());
handler.index(uuid, Operation.INDEX, Optional.empty());
fail("should have thrown an IOException");
} catch (IOException e) {
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/GsonParserTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/GsonParserTest.java
similarity index 93%
rename from src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/GsonParserTest.java
rename to src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/GsonParserTest.java
index df6d618..0a1be19 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/GsonParserTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/GsonParserTest.java
@@ -12,15 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.googlesource.gerrit.plugins.multisite.forwarder.rest;
+package com.googlesource.gerrit.plugins.multisite.forwarder;
import static com.google.common.truth.Truth.assertThat;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.googlesource.gerrit.plugins.multisite.cache.Constants;
-import com.googlesource.gerrit.plugins.multisite.forwarder.rest.GsonParser;
-
import org.junit.Test;
public class GsonParserTest {
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/CacheRestApiServletTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/CacheRestApiServletTest.java
deleted file mode 100644
index 0c0e05c..0000000
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/CacheRestApiServletTest.java
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright (C) 2015 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.forwarder.rest;
-
-import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
-import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.io.BufferedReader;
-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;
-
-import com.googlesource.gerrit.plugins.multisite.cache.Constants;
-import com.googlesource.gerrit.plugins.multisite.forwarder.CacheNotFoundException;
-import com.googlesource.gerrit.plugins.multisite.forwarder.ForwardedCacheEvictionHandler;
-import com.googlesource.gerrit.plugins.multisite.forwarder.rest.CacheRestApiServlet;
-
-@RunWith(MockitoJUnitRunner.class)
-public class CacheRestApiServletTest {
- @Mock private HttpServletRequest requestMock;
- @Mock private HttpServletResponse responseMock;
- @Mock private BufferedReader readerMock;
- @Mock private ForwardedCacheEvictionHandler forwardedCacheEvictionHandlerMock;
- private CacheRestApiServlet servlet;
-
- @Before
- public void setUp() {
- servlet = new CacheRestApiServlet(forwardedCacheEvictionHandlerMock);
- }
-
- @Test
- public void evictAccounts() throws Exception {
- configureMocksFor(Constants.ACCOUNTS);
- verifyResponseIsOK();
- }
-
- @Test
- public void evictProjectList() throws Exception {
- configureMocksFor(Constants.PROJECT_LIST);
- verifyResponseIsOK();
- }
-
- @Test
- public void evictGroups() throws Exception {
- configureMocksFor(Constants.GROUPS);
- verifyResponseIsOK();
- }
-
- @Test
- public void evictGroupsByInclude() throws Exception {
- configureMocksFor(Constants.GROUPS_BYINCLUDE);
- verifyResponseIsOK();
- }
-
- @Test
- public void evictGroupsMembers() throws Exception {
- configureMocksFor(Constants.GROUPS_MEMBERS);
- verifyResponseIsOK();
- }
-
- @Test
- public void evictPluginCache() throws Exception {
- configureMocksFor("my-plugin", "my-cache");
- verifyResponseIsOK();
- }
-
- @Test
- public void evictDefault() throws Exception {
- configureMocksFor(Constants.PROJECTS);
- verifyResponseIsOK();
- }
-
- @Test
- public void badRequest() throws Exception {
- when(requestMock.getPathInfo()).thenReturn("/someCache");
- String errorMessage = "someError";
- doThrow(new IOException(errorMessage)).when(requestMock).getReader();
- servlet.doPost(requestMock, responseMock);
- verify(responseMock).sendError(SC_BAD_REQUEST, errorMessage);
- }
-
- @Test
- public void badRequestCausedByCacheNotFound() throws Exception {
- String pluginName = "somePlugin";
- String cacheName = "nonexistingCache";
- configureMocksFor(pluginName, cacheName);
- CacheNotFoundException e = new CacheNotFoundException(pluginName, cacheName);
- doThrow(e).when(forwardedCacheEvictionHandlerMock).evict(any());
- servlet.doPost(requestMock, responseMock);
- verify(responseMock).sendError(SC_BAD_REQUEST, e.getMessage());
- }
-
- private void verifyResponseIsOK() throws Exception {
- servlet.doPost(requestMock, responseMock);
- verify(responseMock).setStatus(SC_NO_CONTENT);
- }
-
- private void configureMocksFor(String cacheName) throws Exception {
- configureMocksFor(Constants.GERRIT, cacheName);
- }
-
- private void configureMocksFor(String pluginName, String cacheName) throws Exception {
- if (Constants.GERRIT.equals(pluginName)) {
- when(requestMock.getPathInfo()).thenReturn("/" + cacheName);
- } else {
- when(requestMock.getPathInfo()).thenReturn("/" + pluginName + "." + cacheName);
- }
- when(requestMock.getReader()).thenReturn(readerMock);
-
- if (Constants.PROJECTS.equals(cacheName)) {
- when(readerMock.readLine()).thenReturn("abc");
- } else if (Constants.GROUPS_BYINCLUDE.equals(cacheName)
- || Constants.GROUPS_MEMBERS.equals(cacheName)) {
- when(readerMock.readLine()).thenReturn("{\"uuid\":\"abcd1234\"}");
- } else {
- when(readerMock.readLine()).thenReturn("{}");
- }
- }
-}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/EventRestApiServletTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/EventRestApiServletTest.java
deleted file mode 100644
index a940c23..0000000
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/EventRestApiServletTest.java
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.forwarder.rest;
-
-import static com.google.common.net.MediaType.JSON_UTF_8;
-import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
-import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
-import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
-import static javax.servlet.http.HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import com.google.common.net.MediaType;
-import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.server.events.EventTypes;
-import com.google.gerrit.server.events.RefEvent;
-import com.google.gwtorm.server.OrmException;
-import com.googlesource.gerrit.plugins.multisite.forwarder.ForwardedEventHandler;
-import com.googlesource.gerrit.plugins.multisite.forwarder.rest.EventRestApiServlet;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.StringReader;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
-
-@RunWith(MockitoJUnitRunner.class)
-public class EventRestApiServletTest {
- private static final String ERR_MSG = "some Error";
-
- @Mock private ForwardedEventHandler forwardedEventHandlerMock;
- @Mock private HttpServletRequest requestMock;
- @Mock private HttpServletResponse responseMock;
- private EventRestApiServlet eventRestApiServlet;
-
- @BeforeClass
- public static void setup() {
- EventTypes.register(RefReplicationDoneEvent.TYPE, RefReplicationDoneEvent.class);
- }
-
- @Before
- public void createEventsRestApiServlet() throws Exception {
- eventRestApiServlet = new EventRestApiServlet(forwardedEventHandlerMock);
- when(requestMock.getContentType()).thenReturn(MediaType.JSON_UTF_8.toString());
- }
-
- @Test
- public void testDoPostRefReplicationDoneEvent() throws Exception {
- String event =
- "{\"project\":\"gerrit/some-project\",\"ref\":"
- + "\"refs/changes/76/669676/2\",\"nodesCount\":1,\"type\":"
- + "\"ref-replication-done\",\"eventCreatedOn\":1451415011}";
- when(requestMock.getReader()).thenReturn(new BufferedReader(new StringReader(event)));
-
- eventRestApiServlet.doPost(requestMock, responseMock);
-
- verify(forwardedEventHandlerMock).dispatch(any(RefReplicationDoneEvent.class));
- verify(responseMock).setStatus(SC_NO_CONTENT);
- }
-
- @Test
- public void testDoPostDispatcherFailure() throws Exception {
- String event =
- "{\"project\":\"gerrit/some-project\",\"ref\":"
- + "\"refs/changes/76/669676/2\",\"nodesCount\":1,\"type\":"
- + "\"ref-replication-done\",\"eventCreatedOn\":1451415011}";
- when(requestMock.getReader()).thenReturn(new BufferedReader(new StringReader(event)));
- doThrow(new OrmException(ERR_MSG))
- .when(forwardedEventHandlerMock)
- .dispatch(any(RefReplicationDoneEvent.class));
- eventRestApiServlet.doPost(requestMock, responseMock);
- verify(responseMock).sendError(SC_NOT_FOUND, "Change not found\n");
- }
-
- @Test
- public void testDoPostBadRequest() throws Exception {
- doThrow(new IOException(ERR_MSG)).when(requestMock).getReader();
- eventRestApiServlet.doPost(requestMock, responseMock);
- verify(responseMock).sendError(SC_BAD_REQUEST, ERR_MSG);
- }
-
- @Test
- public void testDoPostWrongMediaType() throws Exception {
- when(requestMock.getContentType()).thenReturn(MediaType.APPLICATION_XML_UTF_8.toString());
- eventRestApiServlet.doPost(requestMock, responseMock);
- verify(responseMock)
- .sendError(
- SC_UNSUPPORTED_MEDIA_TYPE, "Expecting " + JSON_UTF_8.toString() + " content type");
- }
-
- @Test
- public void testDoPostErrorWhileSendingErrorMessage() throws Exception {
- doThrow(new IOException(ERR_MSG)).when(requestMock).getReader();
- doThrow(new IOException("someOtherError"))
- .when(responseMock)
- .sendError(SC_BAD_REQUEST, ERR_MSG);
- eventRestApiServlet.doPost(requestMock, responseMock);
- }
-
- static class RefReplicationDoneEvent extends RefEvent {
- public static final String TYPE = "ref-replication-done";
- public final String project;
- public final String ref;
- public final int nodesCount;
-
- public RefReplicationDoneEvent(String project, String ref, int nodesCount) {
- super(TYPE);
- this.project = project;
- this.ref = ref;
- this.nodesCount = nodesCount;
- }
-
- @Override
- public Project.NameKey getProjectNameKey() {
- return new Project.NameKey(project);
- }
-
- @Override
- public String getRefName() {
- return ref;
- }
- }
-}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/HttpClientProviderTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/HttpClientProviderTest.java
deleted file mode 100644
index a326a3b..0000000
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/HttpClientProviderTest.java
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (C) 2015 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.forwarder.rest;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.when;
-
-import com.google.inject.AbstractModule;
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-import com.google.inject.Scopes;
-import com.googlesource.gerrit.plugins.multisite.Configuration;
-import com.googlesource.gerrit.plugins.multisite.forwarder.rest.HttpClientProvider;
-
-import org.apache.http.impl.client.CloseableHttpClient;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Answers;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
-
-@RunWith(MockitoJUnitRunner.class)
-public class HttpClientProviderTest {
- private static final int TIME_INTERVAL = 1000;
- private static final String EMPTY = "";
-
- @Mock(answer = Answers.RETURNS_DEEP_STUBS)
- private Configuration configMock;
-
- @Before
- public void setUp() throws Exception {
- when(configMock.http().user()).thenReturn(EMPTY);
- when(configMock.http().password()).thenReturn(EMPTY);
- when(configMock.http().connectionTimeout()).thenReturn(TIME_INTERVAL);
- when(configMock.http().socketTimeout()).thenReturn(TIME_INTERVAL);
- }
-
- @Test
- public void testGet() throws Exception {
- Injector injector = Guice.createInjector(new TestModule());
- try (CloseableHttpClient httpClient1 = injector.getInstance(CloseableHttpClient.class)) {
- assertThat(httpClient1).isNotNull();
- try (CloseableHttpClient httpClient2 = injector.getInstance(CloseableHttpClient.class)) {
- assertThat(httpClient1).isEqualTo(httpClient2);
- }
- }
- }
-
- class TestModule extends AbstractModule {
- @Override
- protected void configure() {
- bind(Configuration.class).toInstance(configMock);
- bind(CloseableHttpClient.class).toProvider(HttpClientProvider.class).in(Scopes.SINGLETON);
- }
- }
-}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/HttpResponseHandlerTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/HttpResponseHandlerTest.java
deleted file mode 100644
index 6e1d741..0000000
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/HttpResponseHandlerTest.java
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (C) 2015 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.forwarder.rest;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.io.UnsupportedEncodingException;
-import org.apache.http.HttpResponse;
-import org.apache.http.StatusLine;
-import org.apache.http.entity.StringEntity;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.googlesource.gerrit.plugins.multisite.forwarder.rest.HttpResponseHandler;
-import com.googlesource.gerrit.plugins.multisite.forwarder.rest.HttpResponseHandler.HttpResult;
-
-public class HttpResponseHandlerTest {
- private static final int ERROR = 400;
- private static final int NO_CONTENT = 204;
- private static final String EMPTY_ENTITY = "";
- private static final String ERROR_ENTITY = "Error";
-
- private HttpResponseHandler handler;
-
- @Before
- public void setUp() throws Exception {
- handler = new HttpResponseHandler();
- }
-
- @Test
- public void testIsSuccessful() throws Exception {
- HttpResponse response = setupMocks(NO_CONTENT, EMPTY_ENTITY);
- HttpResult result = handler.handleResponse(response);
- assertThat(result.isSuccessful()).isTrue();
- assertThat(result.getMessage()).isEmpty();
- }
-
- @Test
- public void testIsNotSuccessful() throws Exception {
- HttpResponse response = setupMocks(ERROR, ERROR_ENTITY);
- HttpResult result = handler.handleResponse(response);
- assertThat(result.isSuccessful()).isFalse();
- assertThat(result.getMessage()).contains(ERROR_ENTITY);
- }
-
- private static HttpResponse setupMocks(int httpCode, String entity)
- throws UnsupportedEncodingException {
- StatusLine status = mock(StatusLine.class);
- when(status.getStatusCode()).thenReturn(httpCode);
- HttpResponse response = mock(HttpResponse.class);
- when(response.getStatusLine()).thenReturn(status);
- when(response.getEntity()).thenReturn(new StringEntity(entity));
- return response;
- }
-}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/HttpSessionTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/HttpSessionTest.java
deleted file mode 100644
index 6381f8b..0000000
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/HttpSessionTest.java
+++ /dev/null
@@ -1,177 +0,0 @@
-// Copyright (C) 2015 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.forwarder.rest;
-
-import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
-import static com.github.tomakehurst.wiremock.client.WireMock.delete;
-import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
-import static com.github.tomakehurst.wiremock.client.WireMock.post;
-import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
-import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import com.github.tomakehurst.wiremock.http.Fault;
-import com.github.tomakehurst.wiremock.junit.WireMockRule;
-import com.github.tomakehurst.wiremock.stubbing.Scenario;
-import com.googlesource.gerrit.plugins.multisite.Configuration;
-import com.googlesource.gerrit.plugins.multisite.forwarder.rest.HttpClientProvider;
-import com.googlesource.gerrit.plugins.multisite.forwarder.rest.HttpSession;
-import com.googlesource.gerrit.plugins.multisite.forwarder.rest.HttpResponseHandler.HttpResult;
-
-import java.net.SocketTimeoutException;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.mockito.Answers;
-
-public class HttpSessionTest {
-
- private static final int MAX_TRIES = 3;
- private static final int RETRY_INTERVAL = 250;
- private static final int TIMEOUT = 500;
- private static final int ERROR = 500;
- private static final int NO_CONTENT = 204;
- private static final int NOT_FOUND = 404;
- private static final int UNAUTHORIZED = 401;
-
- private static final String ENDPOINT = "/plugins/multi-site/index/1";
- private static final String BODY = "SerializedEvent";
- private static final String ERROR_MESSAGE = "Error message";
- private static final String REQUEST_MADE = "Request made";
- private static final String SECOND_TRY = "Second try";
- private static final String THIRD_TRY = "Third try";
- private static final String RETRY_AT_DELAY = "Retry at delay";
-
- private HttpSession httpSession;
-
- @Rule public WireMockRule wireMockRule = new WireMockRule(0);
-
- private Configuration configMock;
- private String uri;
-
- @Before
- public void setUp() throws Exception {
- String url = "http://localhost:" + wireMockRule.port();
- uri = url + ENDPOINT;
- configMock = mock(Configuration.class, Answers.RETURNS_DEEP_STUBS);
- when(configMock.http().user()).thenReturn("user");
- when(configMock.http().password()).thenReturn("pass");
- when(configMock.http().maxTries()).thenReturn(MAX_TRIES);
- when(configMock.http().connectionTimeout()).thenReturn(TIMEOUT);
- when(configMock.http().socketTimeout()).thenReturn(TIMEOUT);
- when(configMock.http().retryInterval()).thenReturn(RETRY_INTERVAL);
-
- httpSession = new HttpSession(new HttpClientProvider(configMock).get());
- }
-
- @Test
- public void testPostResponseOK() throws Exception {
- wireMockRule.givenThat(
- post(urlEqualTo(ENDPOINT)).willReturn(aResponse().withStatus(NO_CONTENT)));
-
- assertThat(httpSession.post(uri).isSuccessful()).isTrue();
- }
-
- @Test
- public void testPostResponseWithContentOK() throws Exception {
- wireMockRule.givenThat(
- post(urlEqualTo(ENDPOINT))
- .withRequestBody(equalTo(BODY))
- .willReturn(aResponse().withStatus(NO_CONTENT)));
- assertThat(httpSession.post(uri, BODY).isSuccessful()).isTrue();
- }
-
- @Test
- public void testDeleteResponseOK() throws Exception {
- wireMockRule.givenThat(
- delete(urlEqualTo(ENDPOINT)).willReturn(aResponse().withStatus(NO_CONTENT)));
-
- assertThat(httpSession.delete(uri).isSuccessful()).isTrue();
- }
-
- @Test
- public void testNotAuthorized() throws Exception {
- String expected = "unauthorized";
- wireMockRule.givenThat(
- post(urlEqualTo(ENDPOINT))
- .willReturn(aResponse().withStatus(UNAUTHORIZED).withBody(expected)));
-
- HttpResult result = httpSession.post(uri);
- assertThat(result.isSuccessful()).isFalse();
- assertThat(result.getMessage()).isEqualTo(expected);
- }
-
- @Test
- public void testNotFound() throws Exception {
- String expected = "not found";
- wireMockRule.givenThat(
- post(urlEqualTo(ENDPOINT))
- .willReturn(aResponse().withStatus(NOT_FOUND).withBody(expected)));
-
- HttpResult result = httpSession.post(uri);
- assertThat(result.isSuccessful()).isFalse();
- assertThat(result.getMessage()).isEqualTo(expected);
- }
-
- @Test
- public void testBadResponseRetryThenGiveUp() throws Exception {
- wireMockRule.givenThat(
- post(urlEqualTo(ENDPOINT))
- .willReturn(aResponse().withStatus(ERROR).withBody(ERROR_MESSAGE)));
-
- HttpResult result = httpSession.post(uri);
- assertThat(result.isSuccessful()).isFalse();
- assertThat(result.getMessage()).isEqualTo(ERROR_MESSAGE);
- }
-
- @Test(expected = SocketTimeoutException.class)
- public void testMaxRetriesAfterTimeoutThenGiveUp() throws Exception {
- wireMockRule.givenThat(
- post(urlEqualTo(ENDPOINT))
- .inScenario(RETRY_AT_DELAY)
- .whenScenarioStateIs(Scenario.STARTED)
- .willSetStateTo(REQUEST_MADE)
- .willReturn(aResponse().withFixedDelay(TIMEOUT)));
- wireMockRule.givenThat(
- post(urlEqualTo(ENDPOINT))
- .inScenario(RETRY_AT_DELAY)
- .whenScenarioStateIs(REQUEST_MADE)
- .willSetStateTo(SECOND_TRY)
- .willReturn(aResponse().withFixedDelay(TIMEOUT)));
- wireMockRule.givenThat(
- post(urlEqualTo(ENDPOINT))
- .inScenario(RETRY_AT_DELAY)
- .whenScenarioStateIs(SECOND_TRY)
- .willSetStateTo(THIRD_TRY)
- .willReturn(aResponse().withFixedDelay(TIMEOUT)));
- wireMockRule.givenThat(
- post(urlEqualTo(ENDPOINT))
- .inScenario(RETRY_AT_DELAY)
- .whenScenarioStateIs(THIRD_TRY)
- .willReturn(aResponse().withFixedDelay(TIMEOUT)));
-
- httpSession.post(uri);
- }
-
- @Test
- public void testResponseWithMalformedResponse() throws Exception {
- wireMockRule.givenThat(
- post(urlEqualTo(ENDPOINT))
- .willReturn(aResponse().withFault(Fault.MALFORMED_RESPONSE_CHUNK)));
-
- assertThat(httpSession.post(uri).isSuccessful()).isFalse();
- }
-}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/IndexAccountRestApiServletTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/IndexAccountRestApiServletTest.java
deleted file mode 100644
index 070b62c..0000000
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/IndexAccountRestApiServletTest.java
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.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.google.gerrit.reviewdb.client.Account;
-import com.googlesource.gerrit.plugins.multisite.forwarder.ForwardedIndexAccountHandler;
-import com.googlesource.gerrit.plugins.multisite.forwarder.ForwardedIndexingHandler.Operation;
-import com.googlesource.gerrit.plugins.multisite.forwarder.rest.IndexAccountRestApiServlet;
-
-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 IndexAccountRestApiServletTest {
- private static final int ACCOUNT_NUMBER = 1;
- private static final String IO_ERROR = "io-error";
-
- @Mock private ForwardedIndexAccountHandler handlerMock;
- @Mock private HttpServletRequest requestMock;
- @Mock private HttpServletResponse responseMock;
-
- private Account.Id id;
- private IndexAccountRestApiServlet servlet;
-
- @Before
- public void setUpMocks() {
- servlet = new IndexAccountRestApiServlet(handlerMock);
- id = new Account.Id(ACCOUNT_NUMBER);
- when(requestMock.getRequestURI())
- .thenReturn("http://gerrit.com/index/account/" + ACCOUNT_NUMBER);
- }
-
- @Test
- public void accountIsIndexed() throws Exception {
- servlet.doPost(requestMock, responseMock);
- verify(handlerMock, times(1)).index(eq(id), eq(Operation.INDEX), any());
- verify(responseMock).setStatus(SC_NO_CONTENT);
- }
-
- @Test
- public void cannotDeleteAccount() throws Exception {
- servlet.doDelete(requestMock, responseMock);
- verify(responseMock).sendError(SC_METHOD_NOT_ALLOWED, "cannot delete account from index");
- }
-
- @Test
- public void indexerThrowsIOExceptionTryingToIndexAccount() throws Exception {
- doThrow(new IOException(IO_ERROR)).when(handlerMock).index(eq(id), 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(id), 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/googlesource/gerrit/plugins/multisite/forwarder/rest/IndexChangeRestApiServletTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/IndexChangeRestApiServletTest.java
deleted file mode 100644
index da001a9..0000000
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/IndexChangeRestApiServletTest.java
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright (C) 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.forwarder.rest;
-
-import static javax.servlet.http.HttpServletResponse.SC_CONFLICT;
-import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
-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.google.gwtorm.server.OrmException;
-import com.googlesource.gerrit.plugins.multisite.forwarder.ForwardedIndexChangeHandler;
-import com.googlesource.gerrit.plugins.multisite.forwarder.ForwardedIndexingHandler.Operation;
-import com.googlesource.gerrit.plugins.multisite.forwarder.rest.IndexChangeRestApiServlet;
-
-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 IndexChangeRestApiServletTest {
- private static final int CHANGE_NUMBER = 1;
- private static final String PROJECT_NAME = "test/project";
- private static final String PROJECT_NAME_URL_ENC = "test%2Fproject";
- private static final String CHANGE_ID = PROJECT_NAME + "~" + CHANGE_NUMBER;
- private static final String IO_ERROR = "io-error";
-
- @Mock private ForwardedIndexChangeHandler handlerMock;
- @Mock private HttpServletRequest requestMock;
- @Mock private HttpServletResponse responseMock;
-
- private IndexChangeRestApiServlet servlet;
-
- @Before
- public void setUpMocks() {
- servlet = new IndexChangeRestApiServlet(handlerMock);
- when(requestMock.getRequestURI())
- .thenReturn("http://gerrit.com/index/change/" + PROJECT_NAME_URL_ENC + "~" + CHANGE_NUMBER);
- }
-
- @Test
- public void changeIsIndexed() throws Exception {
- servlet.doPost(requestMock, responseMock);
- verify(handlerMock, times(1)).index(eq(CHANGE_ID), eq(Operation.INDEX), any());
- verify(responseMock).setStatus(SC_NO_CONTENT);
- }
-
- @Test
- public void changeIsDeletedFromIndex() throws Exception {
- servlet.doDelete(requestMock, responseMock);
- verify(handlerMock, times(1)).index(eq(CHANGE_ID), eq(Operation.DELETE), any());
- verify(responseMock).setStatus(SC_NO_CONTENT);
- }
-
- @Test
- public void indexerThrowsIOExceptionTryingToIndexChange() throws Exception {
- doThrow(new IOException(IO_ERROR))
- .when(handlerMock)
- .index(eq(CHANGE_ID), eq(Operation.INDEX), any());
- servlet.doPost(requestMock, responseMock);
- verify(responseMock).sendError(SC_CONFLICT, IO_ERROR);
- }
-
- @Test
- public void indexerThrowsOrmExceptionTryingToIndexChange() throws Exception {
- doThrow(new OrmException("some message"))
- .when(handlerMock)
- .index(eq(CHANGE_ID), eq(Operation.INDEX), any());
- servlet.doPost(requestMock, responseMock);
- verify(responseMock).sendError(SC_NOT_FOUND, "Error trying to find change");
- }
-
- @Test
- public void sendErrorThrowsIOException() throws Exception {
- doThrow(new IOException(IO_ERROR))
- .when(handlerMock)
- .index(eq(CHANGE_ID), 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/googlesource/gerrit/plugins/multisite/forwarder/rest/IndexGroupRestApiServletTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/IndexGroupRestApiServletTest.java
deleted file mode 100644
index c3b7737..0000000
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/IndexGroupRestApiServletTest.java
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.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.google.gerrit.reviewdb.client.AccountGroup;
-import com.googlesource.gerrit.plugins.multisite.forwarder.ForwardedIndexGroupHandler;
-import com.googlesource.gerrit.plugins.multisite.forwarder.ForwardedIndexingHandler.Operation;
-import com.googlesource.gerrit.plugins.multisite.forwarder.rest.IndexGroupRestApiServlet;
-
-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 IndexGroupRestApiServletTest {
- private static final String IO_ERROR = "io-error";
- private static final String UUID = "we235jdf92nfj2351";
-
- @Mock private ForwardedIndexGroupHandler handlerMock;
- @Mock private HttpServletRequest requestMock;
- @Mock private HttpServletResponse responseMock;
-
- private AccountGroup.UUID uuid;
- private IndexGroupRestApiServlet servlet;
-
- @Before
- public void setUpMocks() {
- servlet = new IndexGroupRestApiServlet(handlerMock);
- uuid = new AccountGroup.UUID(UUID);
- when(requestMock.getRequestURI()).thenReturn("http://gerrit.com/index/group/" + UUID);
- }
-
- @Test
- public void groupIsIndexed() throws Exception {
- servlet.doPost(requestMock, responseMock);
- verify(handlerMock, times(1)).index(eq(uuid), eq(Operation.INDEX), any());
- verify(responseMock).setStatus(SC_NO_CONTENT);
- }
-
- @Test
- public void cannotDeleteGroup() throws Exception {
- servlet.doDelete(requestMock, responseMock);
- verify(responseMock).sendError(SC_METHOD_NOT_ALLOWED, "cannot delete group from index");
- }
-
- @Test
- public void indexerThrowsIOExceptionTryingToIndexGroup() throws Exception {
- doThrow(new IOException(IO_ERROR))
- .when(handlerMock)
- .index(eq(uuid), 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(uuid), 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/googlesource/gerrit/plugins/multisite/forwarder/rest/IndexProjectRestApiServletTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/IndexProjectRestApiServletTest.java
deleted file mode 100644
index 704a1f8..0000000
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/IndexProjectRestApiServletTest.java
+++ /dev/null
@@ -1,91 +0,0 @@
-// 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.googlesource.gerrit.plugins.multisite.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.google.gerrit.extensions.restapi.Url;
-import com.google.gerrit.reviewdb.client.Project;
-import com.googlesource.gerrit.plugins.multisite.forwarder.ForwardedIndexProjectHandler;
-import com.googlesource.gerrit.plugins.multisite.forwarder.ForwardedIndexingHandler.Operation;
-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/googlesource/gerrit/plugins/multisite/forwarder/rest/ProjectListRestApiServletIT.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/ProjectListRestApiServletIT.java
deleted file mode 100644
index 8b27837..0000000
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/ProjectListRestApiServletIT.java
+++ /dev/null
@@ -1,55 +0,0 @@
-// 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.googlesource.gerrit.plugins.multisite.forwarder.rest;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import com.google.gerrit.acceptance.LightweightPluginDaemonTest;
-import com.google.gerrit.acceptance.NoHttpd;
-import com.google.gerrit.acceptance.TestPlugin;
-import com.google.gerrit.acceptance.UseLocalDisk;
-import com.google.gerrit.extensions.restapi.Url;
-import com.google.gerrit.reviewdb.client.Project;
-import org.junit.Test;
-
-@NoHttpd
-@TestPlugin(
- name = "multi-site",
- sysModule = "com.googlesource.gerrit.plugins.multisite.Module",
- httpModule = "com.googlesource.gerrit.plugins.multisite.HttpModule")
-public class ProjectListRestApiServletIT extends LightweightPluginDaemonTest {
- private static final Project.NameKey SOME_PROJECT = new Project.NameKey("org-a/some-project");
-
- @Test
- @UseLocalDisk
- public void addProject() throws Exception {
-
- assertThat(projectCache.all()).doesNotContain(SOME_PROJECT);
- adminRestSession
- .post("/plugins/multi-site/cache/project_list/" + Url.encode(SOME_PROJECT.get()))
- .assertNoContent();
- assertThat(projectCache.all()).contains(SOME_PROJECT);
- }
-
- @Test
- @UseLocalDisk
- public void removeProject() throws Exception {
- addProject();
- adminRestSession
- .delete("/plugins/multi-site/cache/project_list/" + Url.encode(SOME_PROJECT.get()))
- .assertNoContent();
- assertThat(projectCache.all()).doesNotContain(SOME_PROJECT);
- }
-}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/ProjectListRestApiServletTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/ProjectListRestApiServletTest.java
deleted file mode 100644
index 8d7ca0c..0000000
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/ProjectListRestApiServletTest.java
+++ /dev/null
@@ -1,64 +0,0 @@
-// 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.googlesource.gerrit.plugins.multisite.forwarder.rest;
-
-import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import com.google.gerrit.extensions.restapi.Url;
-import com.googlesource.gerrit.plugins.multisite.forwarder.ForwardedProjectListUpdateHandler;
-import com.googlesource.gerrit.plugins.multisite.forwarder.events.ProjectListUpdateEvent;
-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 ProjectListRestApiServletTest {
- private static final String PROJECT_NAME = "org-a/some-project";
-
- @Mock private ForwardedProjectListUpdateHandler handlerMock;
- @Mock private HttpServletRequest requestMock;
- @Mock private HttpServletResponse responseMock;
-
- private ProjectListApiServlet servlet;
-
- @Before
- public void setUpMocks() {
- servlet = new ProjectListApiServlet(handlerMock);
- when(requestMock.getRequestURI())
- .thenReturn(
- "http://hostname/plugins/multi-site/cache/project_list/" + Url.encode(PROJECT_NAME));
- }
-
- @Test
- public void addProject() throws Exception {
- servlet.doPost(requestMock, responseMock);
- verify(handlerMock, times(1)).update(new ProjectListUpdateEvent(PROJECT_NAME, false));
- verify(responseMock).setStatus(SC_NO_CONTENT);
- }
-
- @Test
- public void deleteProject() throws Exception {
- servlet.doDelete(requestMock, responseMock);
- verify(handlerMock, times(1)).update(new ProjectListUpdateEvent(PROJECT_NAME, true));
- verify(responseMock).setStatus(SC_NO_CONTENT);
- }
-}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/RestCacheEvictionForwarderTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/RestCacheEvictionForwarderTest.java
deleted file mode 100644
index b019c5a..0000000
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/RestCacheEvictionForwarderTest.java
+++ /dev/null
@@ -1,169 +0,0 @@
-package com.googlesource.gerrit.plugins.multisite.forwarder.rest;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableSet;
-import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.reviewdb.client.AccountGroup;
-import com.google.gson.GsonBuilder;
-import com.google.inject.Provider;
-import com.googlesource.gerrit.plugins.multisite.Configuration;
-import com.googlesource.gerrit.plugins.multisite.cache.Constants;
-import com.googlesource.gerrit.plugins.multisite.forwarder.CacheEvictionForwarder;
-import com.googlesource.gerrit.plugins.multisite.forwarder.events.CacheEvictionEvent;
-import com.googlesource.gerrit.plugins.multisite.forwarder.rest.HttpResponseHandler.HttpResult;
-import com.googlesource.gerrit.plugins.multisite.peers.PeerInfo;
-import java.io.IOException;
-import java.util.Set;
-import javax.net.ssl.SSLException;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Answers;
-
-public class RestCacheEvictionForwarderTest {
- private static final String URL = "http://fake.com";
- private static final String PLUGIN_NAME = "multi-site";
- private static final String EMPTY_MSG = "";
- private static final String ERROR = "Error";
- private static final String PLUGINS = "plugins";
- private static final String SUCCESS = "Success";
- private static final boolean SUCCESSFUL = true;
- private static final boolean FAILED = false;
-
- // Index
- private static final String PROJECT_NAME = "test/project";
-
- // Event
- private CacheEvictionForwarder forwarder;
- private HttpSession httpSessionMock;
-
- @SuppressWarnings("unchecked")
- @Before
- public void setUp() {
- httpSessionMock = mock(HttpSession.class);
- Configuration configMock = mock(Configuration.class, Answers.RETURNS_DEEP_STUBS);
- when(configMock.http().maxTries()).thenReturn(3);
- when(configMock.http().retryInterval()).thenReturn(10);
- Provider<Set<PeerInfo>> peersMock = mock(Provider.class);
- when(peersMock.get()).thenReturn(ImmutableSet.of(new PeerInfo(URL)));
- forwarder =
- new RestCacheEvictionForwarder(
- httpSessionMock, PLUGIN_NAME, configMock, peersMock); // TODO: Create provider
- }
-
- @Test
- public void testEvictProjectOK() throws Exception {
- String key = PROJECT_NAME;
- String keyJson = new GsonBuilder().create().toJson(key);
- when(httpSessionMock.post(buildCacheEndpoint(Constants.PROJECTS), keyJson))
- .thenReturn(new HttpResult(SUCCESSFUL, EMPTY_MSG));
- assertThat(forwarder.evict(new CacheEvictionEvent(Constants.PROJECTS, key))).isTrue();
- }
-
- @Test
- public void testEvictAccountsOK() throws Exception {
- Account.Id key = new Account.Id(123);
- String keyJson = new GsonBuilder().create().toJson(key);
- when(httpSessionMock.post(buildCacheEndpoint(Constants.ACCOUNTS), keyJson))
- .thenReturn(new HttpResult(SUCCESSFUL, EMPTY_MSG));
- assertThat(forwarder.evict(new CacheEvictionEvent(Constants.ACCOUNTS, key))).isTrue();
- }
-
- @Test
- public void testEvictGroupsOK() throws Exception {
- AccountGroup.Id key = new AccountGroup.Id(123);
- String keyJson = new GsonBuilder().create().toJson(key);
- String endpoint = buildCacheEndpoint(Constants.GROUPS);
- when(httpSessionMock.post(endpoint, keyJson)).thenReturn(new HttpResult(SUCCESSFUL, EMPTY_MSG));
- assertThat(forwarder.evict(new CacheEvictionEvent(Constants.GROUPS, key))).isTrue();
- }
-
- @Test
- public void testEvictGroupsByIncludeOK() throws Exception {
- AccountGroup.UUID key = new AccountGroup.UUID("90b3042d9094a37985f3f9281391dbbe9a5addad");
- String keyJson = new GsonBuilder().create().toJson(key);
- when(httpSessionMock.post(buildCacheEndpoint(Constants.GROUPS_BYINCLUDE), keyJson))
- .thenReturn(new HttpResult(SUCCESSFUL, EMPTY_MSG));
- assertThat(forwarder.evict(new CacheEvictionEvent(Constants.GROUPS_BYINCLUDE, key))).isTrue();
- }
-
- @Test
- public void testEvictGroupsMembersOK() throws Exception {
- AccountGroup.UUID key = new AccountGroup.UUID("90b3042d9094a37985f3f9281391dbbe9a5addad");
- String keyJson = new GsonBuilder().create().toJson(key);
- when(httpSessionMock.post(buildCacheEndpoint(Constants.GROUPS_MEMBERS), keyJson))
- .thenReturn(new HttpResult(SUCCESSFUL, EMPTY_MSG));
- assertThat(forwarder.evict(new CacheEvictionEvent(Constants.GROUPS_MEMBERS, key))).isTrue();
- }
-
- @Test
- public void testEvictCacheFailed() throws Exception {
- String key = PROJECT_NAME;
- String keyJson = new GsonBuilder().create().toJson(key);
- when(httpSessionMock.post(buildCacheEndpoint(Constants.PROJECTS), keyJson))
- .thenReturn(new HttpResult(FAILED, EMPTY_MSG));
- assertThat(forwarder.evict(new CacheEvictionEvent(Constants.PROJECTS, key))).isFalse();
- }
-
- @Test
- public void testEvictCacheThrowsException() throws Exception {
- String key = PROJECT_NAME;
- String keyJson = new GsonBuilder().create().toJson(key);
- doThrow(new IOException())
- .when(httpSessionMock)
- .post(buildCacheEndpoint(Constants.PROJECTS), keyJson);
- assertThat(forwarder.evict(new CacheEvictionEvent(Constants.PROJECTS, key))).isFalse();
- }
-
- @Test
- public void testRetryOnErrorThenSuccess() throws IOException {
- when(httpSessionMock.post(anyString(), anyString()))
- .thenReturn(new HttpResult(false, ERROR))
- .thenReturn(new HttpResult(false, ERROR))
- .thenReturn(new HttpResult(true, SUCCESS));
-
- assertThat(forwarder.evict(new CacheEvictionEvent(Constants.PROJECT_LIST, new Object())))
- .isTrue();
- }
-
- @Test
- public void testRetryOnIoExceptionThenSuccess() throws IOException {
- when(httpSessionMock.post(anyString(), anyString()))
- .thenThrow(new IOException())
- .thenThrow(new IOException())
- .thenReturn(new HttpResult(true, SUCCESS));
-
- assertThat(forwarder.evict(new CacheEvictionEvent(Constants.PROJECT_LIST, new Object())))
- .isTrue();
- }
-
- @Test
- public void testNoRetryAfterNonRecoverableException() throws IOException {
- when(httpSessionMock.post(anyString(), anyString()))
- .thenThrow(new SSLException("Non Recoverable"))
- .thenReturn(new HttpResult(true, SUCCESS));
-
- assertThat(forwarder.evict(new CacheEvictionEvent(Constants.PROJECT_LIST, new Object())))
- .isFalse();
- }
-
- @Test
- public void testFailureAfterMaxTries() throws IOException {
- when(httpSessionMock.post(anyString(), anyString()))
- .thenReturn(new HttpResult(false, ERROR))
- .thenReturn(new HttpResult(false, ERROR))
- .thenReturn(new HttpResult(false, ERROR));
-
- assertThat(forwarder.evict(new CacheEvictionEvent(Constants.PROJECT_LIST, new Object())))
- .isFalse();
- }
-
- private static String buildCacheEndpoint(String name) {
- return Joiner.on("/").join(URL, PLUGINS, PLUGIN_NAME, "cache", name);
- }
-}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/RestIndexEventForwarderTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/RestIndexEventForwarderTest.java
deleted file mode 100644
index 81ce6b3..0000000
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/RestIndexEventForwarderTest.java
+++ /dev/null
@@ -1,177 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.forwarder.rest;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableSet;
-import com.google.inject.Provider;
-import com.googlesource.gerrit.plugins.multisite.Configuration;
-import com.googlesource.gerrit.plugins.multisite.forwarder.IndexEventForwarder;
-import com.googlesource.gerrit.plugins.multisite.forwarder.events.AccountIndexEvent;
-import com.googlesource.gerrit.plugins.multisite.forwarder.events.ChangeIndexEvent;
-import com.googlesource.gerrit.plugins.multisite.forwarder.events.GroupIndexEvent;
-import com.googlesource.gerrit.plugins.multisite.forwarder.rest.HttpResponseHandler.HttpResult;
-import com.googlesource.gerrit.plugins.multisite.peers.PeerInfo;
-import java.io.IOException;
-import java.util.Set;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Answers;
-
-public class RestIndexEventForwarderTest {
- private static final String URL = "http://fake.com";
- private static final String PLUGIN_NAME = "multi-site";
- private static final String EMPTY_MSG = "";
- private static final String PLUGINS = "plugins";
- private static final boolean SUCCESSFUL = true;
- private static final boolean FAILED = false;
-
- // Index
- private static final int CHANGE_NUMBER = 1;
- private static final String PROJECT_NAME = "test/project";
- private static final String PROJECT_NAME_URL_END = "test%2Fproject";
- private static final String INDEX_CHANGE_ENDPOINT =
- Joiner.on("/")
- .join(
- URL,
- PLUGINS,
- PLUGIN_NAME,
- "index/change",
- PROJECT_NAME_URL_END + "~" + CHANGE_NUMBER);
- private static final String DELETE_CHANGE_ENDPOINT =
- Joiner.on("/").join(URL, PLUGINS, PLUGIN_NAME, "index/change", "~" + CHANGE_NUMBER);
- private static final int ACCOUNT_NUMBER = 2;
- private static final String INDEX_ACCOUNT_ENDPOINT =
- Joiner.on("/").join(URL, PLUGINS, PLUGIN_NAME, "index/account", ACCOUNT_NUMBER);
- private static final String UUID = "we235jdf92nfj2351";
- private static final String INDEX_GROUP_ENDPOINT =
- Joiner.on("/").join(URL, PLUGINS, PLUGIN_NAME, "index/group", UUID);
-
- private IndexEventForwarder indexForwarder;
- private HttpSession httpSessionMock;
-
- @SuppressWarnings("unchecked")
- @Before
- public void setUp() {
- httpSessionMock = mock(HttpSession.class);
- Configuration configMock = mock(Configuration.class, Answers.RETURNS_DEEP_STUBS);
- when(configMock.http().maxTries()).thenReturn(3);
- when(configMock.http().retryInterval()).thenReturn(10);
- Provider<Set<PeerInfo>> peersMock = mock(Provider.class);
- when(peersMock.get()).thenReturn(ImmutableSet.of(new PeerInfo(URL)));
- indexForwarder =
- new RestIndexEventForwarder(
- httpSessionMock, PLUGIN_NAME, configMock, peersMock); // TODO: Create provider
- }
-
- @Test
- public void testIndexAccountOK() throws Exception {
- when(httpSessionMock.post(eq(INDEX_ACCOUNT_ENDPOINT), any()))
- .thenReturn(new HttpResult(SUCCESSFUL, EMPTY_MSG));
- assertThat(indexForwarder.indexAccount(new AccountIndexEvent(ACCOUNT_NUMBER))).isTrue();
- }
-
- @Test
- public void testIndexAccountFailed() throws Exception {
- when(httpSessionMock.post(eq(INDEX_ACCOUNT_ENDPOINT), any()))
- .thenReturn(new HttpResult(FAILED, EMPTY_MSG));
- assertThat(indexForwarder.indexAccount(new AccountIndexEvent(ACCOUNT_NUMBER))).isFalse();
- }
-
- @Test
- public void testIndexAccountThrowsException() throws Exception {
- doThrow(new IOException()).when(httpSessionMock).post(eq(INDEX_ACCOUNT_ENDPOINT), any());
- assertThat(indexForwarder.indexAccount(new AccountIndexEvent(ACCOUNT_NUMBER))).isFalse();
- }
-
- @Test
- public void testIndexGroupOK() throws Exception {
- when(httpSessionMock.post(eq(INDEX_GROUP_ENDPOINT), any()))
- .thenReturn(new HttpResult(SUCCESSFUL, EMPTY_MSG));
- assertThat(indexForwarder.indexGroup(new GroupIndexEvent(UUID))).isTrue();
- }
-
- @Test
- public void testIndexGroupFailed() throws Exception {
- when(httpSessionMock.post(eq(INDEX_GROUP_ENDPOINT), any()))
- .thenReturn(new HttpResult(FAILED, EMPTY_MSG));
- assertThat(indexForwarder.indexGroup(new GroupIndexEvent(UUID))).isFalse();
- }
-
- @Test
- public void testIndexGroupThrowsException() throws Exception {
- doThrow(new IOException()).when(httpSessionMock).post(eq(INDEX_GROUP_ENDPOINT), any());
- assertThat(indexForwarder.indexGroup(new GroupIndexEvent(UUID))).isFalse();
- }
-
- @Test
- public void testIndexChangeOK() throws Exception {
- when(httpSessionMock.post(eq(INDEX_CHANGE_ENDPOINT), any()))
- .thenReturn(new HttpResult(SUCCESSFUL, EMPTY_MSG));
- assertThat(indexForwarder.indexChange(new ChangeIndexEvent(PROJECT_NAME, CHANGE_NUMBER, false)))
- .isTrue();
- }
-
- @Test
- public void testIndexChangeFailed() throws Exception {
- when(httpSessionMock.post(eq(INDEX_CHANGE_ENDPOINT), any()))
- .thenReturn(new HttpResult(FAILED, EMPTY_MSG));
- assertThat(indexForwarder.indexChange(new ChangeIndexEvent(PROJECT_NAME, CHANGE_NUMBER, false)))
- .isFalse();
- }
-
- @Test
- public void testIndexChangeThrowsException() throws Exception {
- doThrow(new IOException()).when(httpSessionMock).post(eq(INDEX_CHANGE_ENDPOINT), any());
- assertThat(indexForwarder.indexChange(new ChangeIndexEvent(PROJECT_NAME, CHANGE_NUMBER, false)))
- .isFalse();
- }
-
- @Test
- public void testChangeDeletedFromIndexOK() throws Exception {
- when(httpSessionMock.delete(eq(DELETE_CHANGE_ENDPOINT), any()))
- .thenReturn(new HttpResult(SUCCESSFUL, EMPTY_MSG));
- assertThat(
- indexForwarder.deleteChangeFromIndex(
- new ChangeIndexEvent(PROJECT_NAME, CHANGE_NUMBER, true)))
- .isTrue();
- }
-
- @Test
- public void testChangeDeletedFromIndexFailed() throws Exception {
- when(httpSessionMock.delete(eq(DELETE_CHANGE_ENDPOINT), any()))
- .thenReturn(new HttpResult(FAILED, EMPTY_MSG));
- assertThat(
- indexForwarder.deleteChangeFromIndex(
- new ChangeIndexEvent(PROJECT_NAME, CHANGE_NUMBER, false)))
- .isFalse();
- }
-
- @Test
- public void testChangeDeletedFromThrowsException() throws Exception {
- doThrow(new IOException()).when(httpSessionMock).delete(eq(DELETE_CHANGE_ENDPOINT), any());
- assertThat(
- indexForwarder.deleteChangeFromIndex(
- new ChangeIndexEvent(PROJECT_NAME, CHANGE_NUMBER, false)))
- .isFalse();
- }
-}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/RestProjectListUpdateForwarderTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/RestProjectListUpdateForwarderTest.java
deleted file mode 100644
index f4ea231..0000000
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/RestProjectListUpdateForwarderTest.java
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright (C) 2015 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.forwarder.rest;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableSet;
-import com.google.inject.Provider;
-import com.googlesource.gerrit.plugins.multisite.Configuration;
-import com.googlesource.gerrit.plugins.multisite.cache.Constants;
-import com.googlesource.gerrit.plugins.multisite.forwarder.events.ProjectListUpdateEvent;
-import com.googlesource.gerrit.plugins.multisite.forwarder.rest.HttpResponseHandler.HttpResult;
-import com.googlesource.gerrit.plugins.multisite.peers.PeerInfo;
-import java.io.IOException;
-import java.util.Set;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Answers;
-
-public class RestProjectListUpdateForwarderTest {
- private static final String URL = "http://fake.com";
- private static final String PLUGIN_NAME = "multi-site";
- private static final String EMPTY_MSG = "";
- private static final String PLUGINS = "plugins";
- private static final String PROJECT_TO_ADD = "projectToAdd";
- private static final String PROJECT_TO_DELETE = "projectToDelete";
- private static final boolean SUCCESSFUL = true;
- private static final boolean FAILED = false;
-
- // Event
- private RestProjectListUpdateForwarder forwarder;
- private HttpSession httpSessionMock;
-
- @SuppressWarnings("unchecked")
- @Before
- public void setUp() {
- httpSessionMock = mock(HttpSession.class);
- Configuration configMock = mock(Configuration.class, Answers.RETURNS_DEEP_STUBS);
- when(configMock.http().maxTries()).thenReturn(3);
- when(configMock.http().retryInterval()).thenReturn(10);
- Provider<Set<PeerInfo>> peersMock = mock(Provider.class);
- when(peersMock.get()).thenReturn(ImmutableSet.of(new PeerInfo(URL)));
- forwarder =
- new RestProjectListUpdateForwarder(
- httpSessionMock, PLUGIN_NAME, configMock, peersMock); // TODO: Create provider
- }
-
- private static String buildCacheEndpoint(String name) {
- return Joiner.on("/").join(URL, PLUGINS, PLUGIN_NAME, "cache", name);
- }
-
- @Test
- public void testAddToProjectListOK() throws Exception {
- String projectName = PROJECT_TO_ADD;
- when(httpSessionMock.post(buildProjectListCacheEndpoint(projectName), null))
- .thenReturn(new HttpResult(SUCCESSFUL, EMPTY_MSG));
- assertThat(forwarder.updateProjectList(new ProjectListUpdateEvent(projectName, false)))
- .isTrue();
- }
-
- @Test
- public void testAddToProjectListFailed() throws Exception {
- String projectName = PROJECT_TO_ADD;
- when(httpSessionMock.post(buildProjectListCacheEndpoint(projectName), null))
- .thenReturn(new HttpResult(FAILED, EMPTY_MSG));
- assertThat(forwarder.updateProjectList(new ProjectListUpdateEvent(projectName, false)))
- .isFalse();
- }
-
- @Test
- public void testAddToProjectListThrowsException() throws Exception {
- String projectName = PROJECT_TO_ADD;
- doThrow(new IOException())
- .when(httpSessionMock)
- .post(buildProjectListCacheEndpoint(projectName), null);
- assertThat(forwarder.updateProjectList(new ProjectListUpdateEvent(projectName, false)))
- .isFalse();
- }
-
- @Test
- public void testRemoveFromProjectListOK() throws Exception {
- String projectName = PROJECT_TO_DELETE;
- when(httpSessionMock.delete(eq(buildProjectListCacheEndpoint(projectName)), any()))
- .thenReturn(new HttpResult(SUCCESSFUL, EMPTY_MSG));
- assertThat(forwarder.updateProjectList(new ProjectListUpdateEvent(projectName, true))).isTrue();
- }
-
- @Test
- public void testRemoveToProjectListFailed() throws Exception {
- String projectName = PROJECT_TO_DELETE;
- when(httpSessionMock.delete(eq(buildProjectListCacheEndpoint(projectName)), any()))
- .thenReturn(new HttpResult(FAILED, EMPTY_MSG));
- assertThat(forwarder.updateProjectList(new ProjectListUpdateEvent(projectName, true)))
- .isFalse();
- }
-
- @Test
- public void testRemoveToProjectListThrowsException() throws Exception {
- String projectName = PROJECT_TO_DELETE;
- doThrow(new IOException())
- .when(httpSessionMock)
- .delete(eq(buildProjectListCacheEndpoint(projectName)), any());
- assertThat(forwarder.updateProjectList(new ProjectListUpdateEvent(projectName, true)))
- .isFalse();
- }
-
- private static String buildProjectListCacheEndpoint(String projectName) {
- return Joiner.on("/").join(buildCacheEndpoint(Constants.PROJECT_LIST), projectName);
- }
-}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/RestStreamEventForwarderTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/RestStreamEventForwarderTest.java
deleted file mode 100644
index fdd422a..0000000
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/rest/RestStreamEventForwarderTest.java
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.forwarder.rest;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableSet;
-import com.google.gerrit.server.events.Event;
-import com.google.inject.Provider;
-import com.googlesource.gerrit.plugins.multisite.Configuration;
-import com.googlesource.gerrit.plugins.multisite.forwarder.StreamEventForwarder;
-import com.googlesource.gerrit.plugins.multisite.forwarder.rest.HttpResponseHandler.HttpResult;
-import com.googlesource.gerrit.plugins.multisite.peers.PeerInfo;
-import java.io.IOException;
-import java.util.Set;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Answers;
-
-public class RestStreamEventForwarderTest {
- private static final String URL = "http://fake.com";
- private static final String PLUGIN_NAME = "multi-site";
- private static final String EMPTY_MSG = "";
- private static final String PLUGINS = "plugins";
- private static final boolean SUCCESSFUL = true;
- private static final boolean FAILED = false;
-
- // Event
- private static Event event = new Event("test-event") {};
- private static final String EVENT_ENDPOINT =
- Joiner.on("/").join(URL, PLUGINS, PLUGIN_NAME, "event", event.type);
-
- private StreamEventForwarder forwarder;
- private HttpSession httpSessionMock;
-
- @SuppressWarnings("unchecked")
- @Before
- public void setUp() {
- httpSessionMock = mock(HttpSession.class);
- Configuration configMock = mock(Configuration.class, Answers.RETURNS_DEEP_STUBS);
- when(configMock.http().maxTries()).thenReturn(3);
- when(configMock.http().retryInterval()).thenReturn(10);
- Provider<Set<PeerInfo>> peersMock = mock(Provider.class);
- when(peersMock.get()).thenReturn(ImmutableSet.of(new PeerInfo(URL)));
- forwarder =
- new RestStreamEventForwarder(
- httpSessionMock, PLUGIN_NAME, configMock, peersMock); // TODO: Create provider
- }
-
- @Test
- public void testEventSentOK() throws Exception {
- when(httpSessionMock.post(EVENT_ENDPOINT, event))
- .thenReturn(new HttpResult(SUCCESSFUL, EMPTY_MSG));
- assertThat(forwarder.send(event)).isTrue();
- }
-
- @Test
- public void testEventSentFailed() throws Exception {
- when(httpSessionMock.post(EVENT_ENDPOINT, event)).thenReturn(new HttpResult(FAILED, EMPTY_MSG));
- assertThat(forwarder.send(event)).isFalse();
- }
-
- @Test
- public void testEventSentThrowsException() throws Exception {
- doThrow(new IOException()).when(httpSessionMock).post(EVENT_ENDPOINT, event);
- assertThat(forwarder.send(event)).isFalse();
- }
-}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/index/AbstractIndexForwardingIT.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/index/AbstractIndexForwardingIT.java
deleted file mode 100644
index 9cf41f9..0000000
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/index/AbstractIndexForwardingIT.java
+++ /dev/null
@@ -1,93 +0,0 @@
-// 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.googlesource.gerrit.plugins.multisite.index;
-
-import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
-import static com.github.tomakehurst.wiremock.client.WireMock.any;
-import static com.github.tomakehurst.wiremock.client.WireMock.anyUrl;
-import static com.github.tomakehurst.wiremock.client.WireMock.givenThat;
-import static com.github.tomakehurst.wiremock.client.WireMock.post;
-import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor;
-import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
-import static com.github.tomakehurst.wiremock.client.WireMock.verify;
-import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
-import static com.google.common.truth.Truth.assertThat;
-
-import com.github.tomakehurst.wiremock.junit.WireMockRule;
-import com.google.gerrit.acceptance.GlobalPluginConfig;
-import com.google.gerrit.acceptance.LightweightPluginDaemonTest;
-import com.google.gerrit.acceptance.NoHttpd;
-import com.google.gerrit.acceptance.TestPlugin;
-import com.google.gerrit.acceptance.UseLocalDisk;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import org.apache.http.HttpStatus;
-import org.junit.Ignore;
-import org.junit.Rule;
-import org.junit.Test;
-
-@Ignore
-@NoHttpd
-@TestPlugin(
- name = "multi-site",
- sysModule = "com.googlesource.gerrit.plugins.multisite.Module",
- httpModule = "com.googlesource.gerrit.plugins.multisite.HttpModule")
-public abstract class AbstractIndexForwardingIT extends LightweightPluginDaemonTest {
- private static final int PORT = 18889;
- private static final String URL = "http://localhost:" + PORT;
-
- @Rule public WireMockRule wireMockRule = new WireMockRule(options().port(PORT));
-
- @Override
- public void setUpTestPlugin() throws Exception {
- givenThat(any(anyUrl()).willReturn(aResponse().withStatus(HttpStatus.SC_NO_CONTENT)));
- beforeAction();
- super.setUpTestPlugin();
- }
-
- @Test
- @UseLocalDisk
- @GlobalPluginConfig(pluginName = "multi-site", name = "peerInfo.static.url", value = URL)
- @GlobalPluginConfig(pluginName = "multi-site", name = "http.retryInterval", value = "100")
- public void testIndexForwarding() throws Exception {
- String expectedRequest = getExpectedRequest();
- CountDownLatch expectedRequestLatch = new CountDownLatch(1);
- wireMockRule.addMockServiceRequestListener(
- (request, response) -> {
- if (request.getAbsoluteUrl().contains(expectedRequest)) {
- expectedRequestLatch.countDown();
- }
- });
- givenThat(
- post(urlEqualTo(expectedRequest))
- .willReturn(aResponse().withStatus(HttpStatus.SC_NO_CONTENT)));
- doAction();
- assertThat(expectedRequestLatch.await(5, TimeUnit.SECONDS)).isTrue();
- verify(postRequestedFor(urlEqualTo(expectedRequest)));
- }
-
- /** Perform pre-test setup. */
- protected abstract void beforeAction() throws Exception;
-
- /**
- * Get the URL on which a request is expected.
- *
- * @return the URL.
- */
- protected abstract String getExpectedRequest();
-
- /** Perform the action that should cause an index operation to occur. */
- protected abstract void doAction() throws Exception;
-}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/index/AccountIndexForwardingIT.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/index/AccountIndexForwardingIT.java
deleted file mode 100644
index a9c1ef5..0000000
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/index/AccountIndexForwardingIT.java
+++ /dev/null
@@ -1,36 +0,0 @@
-// 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.googlesource.gerrit.plugins.multisite.index;
-
-import com.google.gerrit.acceptance.TestAccount;
-
-public class AccountIndexForwardingIT extends AbstractIndexForwardingIT {
- private TestAccount testAccount;
-
- @Override
- public void beforeAction() throws Exception {
- testAccount = accountCreator.create("someUser");
- }
-
- @Override
- public String getExpectedRequest() {
- return "/plugins/multi-site/index/account/" + testAccount.id;
- }
-
- @Override
- public void doAction() throws Exception {
- gApi.accounts().id(testAccount.id.get()).setActive(false);
- }
-}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/index/ChangeIndexForwardingIT.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/index/ChangeIndexForwardingIT.java
deleted file mode 100644
index 6725797..0000000
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/index/ChangeIndexForwardingIT.java
+++ /dev/null
@@ -1,34 +0,0 @@
-// 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.googlesource.gerrit.plugins.multisite.index;
-
-public class ChangeIndexForwardingIT extends AbstractIndexForwardingIT {
- private int changeId;
-
- @Override
- public void beforeAction() throws Exception {
- changeId = createChange().getChange().getId().get();
- }
-
- @Override
- public String getExpectedRequest() {
- return "/plugins/multi-site/index/change/" + project.get() + "~" + changeId;
- }
-
- @Override
- public void doAction() throws Exception {
- gApi.changes().id(changeId).abandon();
- }
-}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/index/GroupIndexForwardingIT.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/index/GroupIndexForwardingIT.java
deleted file mode 100644
index a5b32f1..0000000
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/index/GroupIndexForwardingIT.java
+++ /dev/null
@@ -1,34 +0,0 @@
-// 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.googlesource.gerrit.plugins.multisite.index;
-
-public class GroupIndexForwardingIT extends AbstractIndexForwardingIT {
- private String someGroupId;
-
- @Override
- public void beforeAction() throws Exception {
- someGroupId = gApi.groups().create("someGroup").get().id;
- }
-
- @Override
- public String getExpectedRequest() {
- return "/plugins/multi-site/index/group/" + someGroupId;
- }
-
- @Override
- public void doAction() throws Exception {
- gApi.groups().id(someGroupId).index();
- }
-}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/index/IndexEventHandlerTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/index/IndexEventHandlerTest.java
deleted file mode 100644
index 26a91be..0000000
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/index/IndexEventHandlerTest.java
+++ /dev/null
@@ -1,288 +0,0 @@
-// Copyright (C) 2015 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.multisite.index;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
-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.google.common.util.concurrent.MoreExecutors;
-import com.google.gerrit.extensions.registration.DynamicSet;
-import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.reviewdb.client.AccountGroup;
-import com.google.gerrit.reviewdb.client.Change;
-import com.googlesource.gerrit.plugins.multisite.forwarder.Context;
-import com.googlesource.gerrit.plugins.multisite.forwarder.IndexEventForwarder;
-import com.googlesource.gerrit.plugins.multisite.forwarder.events.AccountIndexEvent;
-import com.googlesource.gerrit.plugins.multisite.forwarder.events.ChangeIndexEvent;
-import com.googlesource.gerrit.plugins.multisite.forwarder.events.GroupIndexEvent;
-import com.googlesource.gerrit.plugins.multisite.index.IndexEventHandler.IndexAccountTask;
-import com.googlesource.gerrit.plugins.multisite.index.IndexEventHandler.IndexChangeTask;
-import com.googlesource.gerrit.plugins.multisite.index.IndexEventHandler.IndexGroupTask;
-import java.util.Optional;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
-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 IndexEventHandlerTest {
- private static final String PLUGIN_NAME = "multi-site";
- private static final String PROJECT_NAME = "test/project";
- private static final int CHANGE_ID = 1;
- private static final int ACCOUNT_ID = 2;
- private static final String UUID = "3";
- private static final String OTHER_UUID = "4";
-
- private IndexEventHandler indexEventHandler;
- @Mock private IndexEventForwarder forwarder;
- @Mock private ChangeCheckerImpl.Factory changeCheckerFactoryMock;
- @Mock private ChangeChecker changeCheckerMock;
- private Change.Id changeId;
- private Account.Id accountId;
- private AccountGroup.UUID accountGroupUUID;
-
- @Before
- public void setUpMocks() throws Exception {
- changeId = new Change.Id(CHANGE_ID);
- accountId = new Account.Id(ACCOUNT_ID);
- accountGroupUUID = new AccountGroup.UUID(UUID);
- when(changeCheckerFactoryMock.create(any())).thenReturn(changeCheckerMock);
- when(changeCheckerMock.newIndexEvent(PROJECT_NAME, CHANGE_ID, false))
- .thenReturn(Optional.of(new ChangeIndexEvent(PROJECT_NAME, CHANGE_ID, false)));
-
- indexEventHandler =
- new IndexEventHandler(
- MoreExecutors.directExecutor(),
- PLUGIN_NAME,
- asDynamicSet(forwarder),
- changeCheckerFactoryMock);
- }
-
- private DynamicSet<IndexEventForwarder> asDynamicSet(IndexEventForwarder forwarder) {
- DynamicSet<IndexEventForwarder> result = new DynamicSet<>();
- result.add("multi-site", forwarder);
- return result;
- }
-
- @Test
- public void shouldIndexInRemoteOnChangeIndexedEvent() throws Exception {
- indexEventHandler.onChangeIndexed(PROJECT_NAME, changeId.get());
- ChangeIndexEvent changeIndexEvent = new ChangeIndexEvent(PROJECT_NAME, CHANGE_ID, false);
- verify(forwarder).indexChange(changeIndexEvent);
- }
-
- @Test
- public void shouldIndexInRemoteOnAccountIndexedEvent() throws Exception {
- indexEventHandler.onAccountIndexed(accountId.get());
- AccountIndexEvent accountIndexEvent = new AccountIndexEvent(accountId.get());
- verify(forwarder).indexAccount(accountIndexEvent);
- }
-
- @Test
- public void shouldDeleteFromIndexInRemoteOnChangeDeletedEvent() throws Exception {
- indexEventHandler.onChangeDeleted(changeId.get());
- ChangeIndexEvent changeIndexEvent = new ChangeIndexEvent("", changeId.get(), true);
- verify(forwarder).deleteChangeFromIndex(changeIndexEvent);
- verifyZeroInteractions(
- changeCheckerMock); // Deleted changes should not be checked against NoteDb
- }
-
- @Test
- public void shouldIndexInRemoteOnGroupIndexedEvent() throws Exception {
- indexEventHandler.onGroupIndexed(accountGroupUUID.get());
- GroupIndexEvent groupIndexEvent = new GroupIndexEvent(UUID);
- verify(forwarder).indexGroup(groupIndexEvent);
- }
-
- @Test
- public void shouldNotCallRemoteWhenChangeEventIsForwarded() throws Exception {
- Context.setForwardedEvent(true);
- indexEventHandler.onChangeIndexed(PROJECT_NAME, changeId.get());
- indexEventHandler.onChangeDeleted(changeId.get());
- Context.unsetForwardedEvent();
- verifyZeroInteractions(forwarder);
- }
-
- @Test
- public void shouldNotCallRemoteWhenAccountEventIsForwarded() throws Exception {
- Context.setForwardedEvent(true);
- indexEventHandler.onAccountIndexed(accountId.get());
- indexEventHandler.onAccountIndexed(accountId.get());
- Context.unsetForwardedEvent();
- verifyZeroInteractions(forwarder);
- }
-
- @Test
- public void shouldNotCallRemoteWhenGroupEventIsForwarded() throws Exception {
- Context.setForwardedEvent(true);
- indexEventHandler.onGroupIndexed(accountGroupUUID.get());
- indexEventHandler.onGroupIndexed(accountGroupUUID.get());
- Context.unsetForwardedEvent();
- verifyZeroInteractions(forwarder);
- }
-
- @Test
- public void duplicateChangeEventOfAQueuedEventShouldGetDiscarded() {
- ScheduledThreadPoolExecutor poolMock = mock(ScheduledThreadPoolExecutor.class);
- indexEventHandler =
- new IndexEventHandler(
- poolMock, PLUGIN_NAME, asDynamicSet(forwarder), changeCheckerFactoryMock);
- indexEventHandler.onChangeIndexed(PROJECT_NAME, changeId.get());
- indexEventHandler.onChangeIndexed(PROJECT_NAME, changeId.get());
- verify(poolMock, times(1))
- .execute(
- indexEventHandler
- .new IndexChangeTask(new ChangeIndexEvent(PROJECT_NAME, CHANGE_ID, false)));
- }
-
- @Test
- public void duplicateAccountEventOfAQueuedEventShouldGetDiscarded() {
- ScheduledThreadPoolExecutor poolMock = mock(ScheduledThreadPoolExecutor.class);
- indexEventHandler =
- new IndexEventHandler(
- poolMock, PLUGIN_NAME, asDynamicSet(forwarder), changeCheckerFactoryMock);
- indexEventHandler.onAccountIndexed(accountId.get());
- indexEventHandler.onAccountIndexed(accountId.get());
- verify(poolMock, times(1))
- .execute(indexEventHandler.new IndexAccountTask(new AccountIndexEvent(ACCOUNT_ID)));
- }
-
- @Test
- public void duplicateGroupEventOfAQueuedEventShouldGetDiscarded() {
- ScheduledThreadPoolExecutor poolMock = mock(ScheduledThreadPoolExecutor.class);
- indexEventHandler =
- new IndexEventHandler(
- poolMock, PLUGIN_NAME, asDynamicSet(forwarder), changeCheckerFactoryMock);
- indexEventHandler.onGroupIndexed(accountGroupUUID.get());
- indexEventHandler.onGroupIndexed(accountGroupUUID.get());
- verify(poolMock, times(1))
- .execute(indexEventHandler.new IndexGroupTask(new GroupIndexEvent(UUID)));
- }
-
- @Test
- public void testIndexChangeTaskToString() throws Exception {
- IndexChangeTask task =
- indexEventHandler.new IndexChangeTask(new ChangeIndexEvent(PROJECT_NAME, CHANGE_ID, false));
- assertThat(task.toString())
- .isEqualTo(
- String.format("[%s] Index change %s in target instance", PLUGIN_NAME, CHANGE_ID));
- }
-
- @Test
- public void testIndexAccountTaskToString() throws Exception {
- IndexAccountTask task =
- indexEventHandler.new IndexAccountTask(new AccountIndexEvent(ACCOUNT_ID));
- assertThat(task.toString())
- .isEqualTo(
- String.format("[%s] Index account %s in target instance", PLUGIN_NAME, ACCOUNT_ID));
- }
-
- @Test
- public void testIndexGroupTaskToString() throws Exception {
- IndexGroupTask task = indexEventHandler.new IndexGroupTask(new GroupIndexEvent(UUID));
- assertThat(task.toString())
- .isEqualTo(String.format("[%s] Index group %s in target instance", PLUGIN_NAME, UUID));
- }
-
- @Test
- public void testIndexChangeTaskHashCodeAndEquals() {
- IndexChangeTask task =
- indexEventHandler.new IndexChangeTask(new ChangeIndexEvent(PROJECT_NAME, CHANGE_ID, false));
-
- IndexChangeTask sameTask = task;
- assertThat(task.equals(sameTask)).isTrue();
- assertThat(task.hashCode()).isEqualTo(sameTask.hashCode());
-
- IndexChangeTask identicalTask =
- indexEventHandler.new IndexChangeTask(new ChangeIndexEvent(PROJECT_NAME, CHANGE_ID, false));
- assertThat(task.equals(identicalTask)).isTrue();
- assertThat(task.hashCode()).isEqualTo(identicalTask.hashCode());
-
- assertThat(task.equals(null)).isFalse();
- assertThat(
- task.equals(
- indexEventHandler
- .new IndexChangeTask(new ChangeIndexEvent(PROJECT_NAME, CHANGE_ID + 1, false))))
- .isFalse();
- assertThat(task.hashCode()).isNotEqualTo("test".hashCode());
-
- IndexChangeTask differentChangeIdTask =
- indexEventHandler.new IndexChangeTask(new ChangeIndexEvent(PROJECT_NAME, 123, false));
- assertThat(task.equals(differentChangeIdTask)).isFalse();
- assertThat(task.hashCode()).isNotEqualTo(differentChangeIdTask.hashCode());
-
- IndexChangeTask removeTask =
- indexEventHandler.new IndexChangeTask(new ChangeIndexEvent("", CHANGE_ID, true));
- assertThat(task.equals(removeTask)).isFalse();
- assertThat(task.hashCode()).isNotEqualTo(removeTask.hashCode());
- }
-
- @Test
- public void testIndexAccountTaskHashCodeAndEquals() {
- IndexAccountTask task =
- indexEventHandler.new IndexAccountTask(new AccountIndexEvent(ACCOUNT_ID));
-
- IndexAccountTask sameTask = task;
- assertThat(task.equals(sameTask)).isTrue();
- assertThat(task.hashCode()).isEqualTo(sameTask.hashCode());
-
- IndexAccountTask identicalTask =
- indexEventHandler.new IndexAccountTask(new AccountIndexEvent(ACCOUNT_ID));
- assertThat(task.equals(identicalTask)).isTrue();
- assertThat(task.hashCode()).isEqualTo(identicalTask.hashCode());
-
- assertThat(task.equals(null)).isFalse();
- assertThat(
- task.equals(
- indexEventHandler.new IndexAccountTask(new AccountIndexEvent(ACCOUNT_ID + 1))))
- .isFalse();
- assertThat(task.hashCode()).isNotEqualTo("test".hashCode());
-
- IndexAccountTask differentAccountIdTask =
- indexEventHandler.new IndexAccountTask(new AccountIndexEvent(123));
- assertThat(task.equals(differentAccountIdTask)).isFalse();
- assertThat(task.hashCode()).isNotEqualTo(differentAccountIdTask.hashCode());
- }
-
- @Test
- public void testIndexGroupTaskHashCodeAndEquals() {
- IndexGroupTask task = indexEventHandler.new IndexGroupTask(new GroupIndexEvent(UUID));
-
- IndexGroupTask sameTask = task;
- assertThat(task.equals(sameTask)).isTrue();
- assertThat(task.hashCode()).isEqualTo(sameTask.hashCode());
-
- IndexGroupTask identicalTask = indexEventHandler.new IndexGroupTask(new GroupIndexEvent(UUID));
- assertThat(task.equals(identicalTask)).isTrue();
- assertThat(task.hashCode()).isEqualTo(identicalTask.hashCode());
-
- assertThat(task.equals(null)).isFalse();
- assertThat(task.equals(indexEventHandler.new IndexGroupTask(new GroupIndexEvent(OTHER_UUID))))
- .isFalse();
- assertThat(task.hashCode()).isNotEqualTo("test".hashCode());
-
- IndexGroupTask differentGroupIdTask =
- indexEventHandler.new IndexGroupTask(new GroupIndexEvent("123"));
- assertThat(task.equals(differentGroupIdTask)).isFalse();
- assertThat(task.hashCode()).isNotEqualTo(differentGroupIdTask.hashCode());
- }
-}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/index/ProjectIndexForwardingIT.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/index/ProjectIndexForwardingIT.java
deleted file mode 100644
index 5157c63..0000000
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/index/ProjectIndexForwardingIT.java
+++ /dev/null
@@ -1,36 +0,0 @@
-// 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.googlesource.gerrit.plugins.multisite.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/multi-site/index/project/" + Url.encode(someProjectName);
- }
-
- @Override
- public void doAction() throws Exception {
- gApi.projects().name(someProjectName).index(false);
- }
-}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/kafka/consumer/KafkaEventDeserializerTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/kafka/consumer/KafkaEventDeserializerTest.java
index e1601cd..4a3b466 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/kafka/consumer/KafkaEventDeserializerTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/multisite/kafka/consumer/KafkaEventDeserializerTest.java
@@ -16,13 +16,9 @@
import static com.google.common.truth.Truth.assertThat;
-import com.google.common.base.Supplier;
-import com.google.gerrit.server.events.Event;
-import com.google.gerrit.server.events.EventDeserializer;
-import com.google.gerrit.server.events.SupplierDeserializer;
import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
import com.google.inject.Provider;
+import com.googlesource.gerrit.plugins.multisite.broker.GsonProvider;
import java.util.UUID;
import org.junit.Before;
import org.junit.Test;
@@ -32,7 +28,7 @@
@Before
public void setUp() {
- final Provider<Gson> gsonProvider = buildGsonProvider();
+ final Provider<Gson> gsonProvider = new GsonProvider();
deserializer = new KafkaEventDeserializer(gsonProvider);
}
@@ -67,13 +63,4 @@
public void kafkaEventDeserializerShouldFailForInvalidObjectButValidJSON() {
deserializer.deserialize("ignored", "{}".getBytes());
}
-
- private Provider<Gson> buildGsonProvider() {
- Gson gson =
- new GsonBuilder()
- .registerTypeAdapter(Event.class, new EventDeserializer())
- .registerTypeAdapter(Supplier.class, new SupplierDeserializer())
- .create();
- return () -> gson;
- }
}