Merge branch 'stable-2.13'

* stable-2.13:
  Add plugin's InitStep to configure plugin during site init
  Extract sharedDirectory config key into a constant
  Extract configuration keys into constants

Change-Id: I04db03871bd6cfaa51b1e7d7670e9a6f2b59d8f6
diff --git a/BUCK b/BUCK
index fd220a9..9d66122 100644
--- a/BUCK
+++ b/BUCK
@@ -26,6 +26,7 @@
     'Gerrit-ApiType: plugin',
     'Gerrit-Module: com.ericsson.gerrit.plugins.highavailability.Module',
     'Gerrit-HttpModule: com.ericsson.gerrit.plugins.highavailability.HttpModule',
+    'Gerrit-InitStep: com.ericsson.gerrit.plugins.highavailability.Setup',
     'Implementation-Title: high-availability plugin',
     'Implementation-URL: https://gerrit-review.googlesource.com/#/admin/projects/plugins/high-availability',
     'Implementation-Vendor: Ericsson',
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java
index 94a5945..5893715 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java
@@ -28,10 +28,21 @@
 public class Configuration {
   private static final Logger log = LoggerFactory.getLogger(Configuration.class);
 
-  private static final int DEFAULT_TIMEOUT_MS = 5000;
-  private static final int DEFAULT_MAX_TRIES = 5;
-  private static final int DEFAULT_RETRY_INTERVAL = 1000;
-  private static final int DEFAULT_THREAD_POOL_SIZE = 1;
+  static final String SHARED_DIRECTORY = "sharedDirectory";
+  static final String URL_KEY = "url";
+  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 String INDEX_THREAD_POOL_SIZE_KEY = "indexThreadPoolSize";
+  static final String CACHE_THREAD_POOL_SIZE_KEY = "cacheThreadPoolSize";
+
+  static final int DEFAULT_TIMEOUT_MS = 5000;
+  static final int DEFAULT_MAX_TRIES = 5;
+  static final int DEFAULT_RETRY_INTERVAL = 1000;
+  static final int DEFAULT_THREAD_POOL_SIZE = 1;
 
   private final String url;
   private final String user;
@@ -46,15 +57,15 @@
   @Inject
   Configuration(PluginConfigFactory config, @PluginName String pluginName) {
     PluginConfig cfg = config.getFromGerritConfig(pluginName, true);
-    url = Strings.nullToEmpty(cfg.getString("url"));
-    user = Strings.nullToEmpty(cfg.getString("user"));
-    password = Strings.nullToEmpty(cfg.getString("password"));
-    connectionTimeout = getInt(cfg, "connectionTimeout", DEFAULT_TIMEOUT_MS);
-    socketTimeout = getInt(cfg, "socketTimeout", DEFAULT_TIMEOUT_MS);
-    maxTries = getInt(cfg, "maxTries", DEFAULT_MAX_TRIES);
-    retryInterval = getInt(cfg, "retryInterval", DEFAULT_RETRY_INTERVAL);
-    indexThreadPoolSize = getInt(cfg, "indexThreadPoolSize", DEFAULT_THREAD_POOL_SIZE);
-    cacheThreadPoolSize = getInt(cfg, "cacheThreadPoolSize", DEFAULT_THREAD_POOL_SIZE);
+    url = Strings.nullToEmpty(cfg.getString(URL_KEY));
+    user = Strings.nullToEmpty(cfg.getString(USER_KEY));
+    password = Strings.nullToEmpty(cfg.getString(PASSWORD_KEY));
+    connectionTimeout = getInt(cfg, CONNECTION_TIMEOUT_KEY, DEFAULT_TIMEOUT_MS);
+    socketTimeout = getInt(cfg, SOCKET_TIMEOUT_KEY, DEFAULT_TIMEOUT_MS);
+    maxTries = getInt(cfg, MAX_TRIES_KEY, DEFAULT_MAX_TRIES);
+    retryInterval = getInt(cfg, RETRY_INTERVAL_KEY, DEFAULT_RETRY_INTERVAL);
+    indexThreadPoolSize = getInt(cfg, INDEX_THREAD_POOL_SIZE_KEY, DEFAULT_THREAD_POOL_SIZE);
+    cacheThreadPoolSize = getInt(cfg, CACHE_THREAD_POOL_SIZE_KEY, DEFAULT_THREAD_POOL_SIZE);
   }
 
   private int getInt(PluginConfig cfg, String name, int defaultValue) {
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Module.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Module.java
index f547260..a8d017c 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Module.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Module.java
@@ -14,6 +14,8 @@
 
 package com.ericsson.gerrit.plugins.highavailability;
 
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.SHARED_DIRECTORY;
+
 import com.ericsson.gerrit.plugins.highavailability.cache.CacheModule;
 import com.ericsson.gerrit.plugins.highavailability.event.EventModule;
 import com.ericsson.gerrit.plugins.highavailability.forwarder.rest.RestForwarderModule;
@@ -50,9 +52,9 @@
   Path getSharedDirectory(PluginConfigFactory cfg, @PluginName String pluginName)
       throws IOException {
     String sharedDirectory =
-        Strings.emptyToNull(cfg.getFromGerritConfig(pluginName, true).getString("sharedDirectory"));
+        Strings.emptyToNull(cfg.getFromGerritConfig(pluginName, true).getString(SHARED_DIRECTORY));
     if (sharedDirectory == null) {
-      throw new ProvisionException("sharedDirectory must be configured");
+      throw new ProvisionException(SHARED_DIRECTORY + " must be configured");
     }
     Path sharedDirectoryPath = Paths.get(sharedDirectory);
     Files.createDirectories(sharedDirectoryPath);
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Setup.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Setup.java
new file mode 100644
index 0000000..394f77a
--- /dev/null
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Setup.java
@@ -0,0 +1,97 @@
+// 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.ericsson.gerrit.plugins.highavailability;
+
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.*;
+
+import com.google.gerrit.common.FileUtil;
+import com.google.gerrit.extensions.annotations.PluginName;
+import com.google.gerrit.pgm.init.api.ConsoleUI;
+import com.google.gerrit.pgm.init.api.InitStep;
+import com.google.gerrit.pgm.init.api.Section;
+import com.google.gerrit.server.config.SitePaths;
+import com.google.inject.Inject;
+import java.nio.file.Path;
+
+public class Setup implements InitStep {
+
+  private final ConsoleUI ui;
+  private final Section mySection;
+  private final String pluginName;
+  private final SitePaths site;
+
+  @Inject
+  public Setup(
+      ConsoleUI ui, Section.Factory sections, @PluginName String pluginName, SitePaths site) {
+    this.ui = ui;
+    this.mySection = sections.get("plugin", pluginName);
+    this.pluginName = pluginName;
+    this.site = site;
+  }
+
+  @Override
+  public void run() throws Exception {
+    ui.message("\n");
+    ui.header("%s Plugin", pluginName);
+
+    if (ui.yesno(true, "Configure %s", pluginName)) {
+      ui.header("Configuring %s", pluginName);
+      configureSharedDir();
+      configurePeer();
+      configureTimeouts();
+      configureRetry();
+      configureThreadPools();
+    }
+  }
+
+  private void configureSharedDir() {
+    String sharedDir = mySection.string("Shared directory", SHARED_DIRECTORY, null);
+    if (sharedDir != null) {
+      Path shared = site.site_path.resolve(sharedDir);
+      FileUtil.mkdirsOrDie(shared, "cannot create " + shared);
+    }
+  }
+
+  private void configurePeer() {
+    mySection.string("Peer URL", URL_KEY, null);
+    mySection.string("User", USER_KEY, null);
+    mySection.string("Password", PASSWORD_KEY, null);
+  }
+
+  private void configureTimeouts() {
+    mySection.string("Connection timeout [ms]", CONNECTION_TIMEOUT_KEY, str(DEFAULT_TIMEOUT_MS));
+    mySection.string("Socket timeout [ms]", SOCKET_TIMEOUT_KEY, str(DEFAULT_TIMEOUT_MS));
+  }
+
+  private void configureRetry() {
+    mySection.string(
+        "Max number of tries to forward to remote peer", MAX_TRIES_KEY, str(DEFAULT_MAX_TRIES));
+    mySection.string("Retry interval [ms]", RETRY_INTERVAL_KEY, str(DEFAULT_RETRY_INTERVAL));
+  }
+
+  private void configureThreadPools() {
+    mySection.string(
+        "Index thread pool size", INDEX_THREAD_POOL_SIZE_KEY, str(DEFAULT_THREAD_POOL_SIZE));
+    mySection.string(
+        "Cache thread pool size", CACHE_THREAD_POOL_SIZE_KEY, str(DEFAULT_THREAD_POOL_SIZE));
+  }
+
+  private static String str(int n) {
+    return Integer.toString(n);
+  }
+
+  @Override
+  public void postRun() throws Exception {}
+}
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java
index 97a32a1..c0382d2 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java
@@ -14,6 +14,19 @@
 
 package com.ericsson.gerrit.plugins.highavailability;
 
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.CACHE_THREAD_POOL_SIZE_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.CONNECTION_TIMEOUT_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_MAX_TRIES;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_RETRY_INTERVAL;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_THREAD_POOL_SIZE;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_TIMEOUT_MS;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.INDEX_THREAD_POOL_SIZE_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.MAX_TRIES_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.PASSWORD_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.RETRY_INTERVAL_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.SOCKET_TIMEOUT_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.URL_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.USER_KEY;
 import static com.google.common.truth.Truth.assertThat;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
@@ -93,28 +106,26 @@
         .thenThrow(new IllegalArgumentException("some message"));
 
     configuration = new Configuration(cfgFactoryMock, pluginName);
-    assertThat(configuration.getConnectionTimeout()).isEqualTo(5000);
-    assertThat(configuration.getSocketTimeout()).isEqualTo(5000);
-    assertThat(configuration.getMaxTries()).isEqualTo(5);
-    assertThat(configuration.getRetryInterval()).isEqualTo(1000);
-    assertThat(configuration.getIndexThreadPoolSize()).isEqualTo(1);
-    assertThat(configuration.getCacheThreadPoolSize()).isEqualTo(1);
+    assertThat(configuration.getConnectionTimeout()).isEqualTo(DEFAULT_TIMEOUT_MS);
+    assertThat(configuration.getSocketTimeout()).isEqualTo(DEFAULT_TIMEOUT_MS);
+    assertThat(configuration.getMaxTries()).isEqualTo(DEFAULT_MAX_TRIES);
+    assertThat(configuration.getRetryInterval()).isEqualTo(DEFAULT_RETRY_INTERVAL);
+    assertThat(configuration.getIndexThreadPoolSize()).isEqualTo(DEFAULT_THREAD_POOL_SIZE);
+    assertThat(configuration.getCacheThreadPoolSize()).isEqualTo(DEFAULT_THREAD_POOL_SIZE);
   }
 
   private void buildMocks(boolean values) {
-    when(configMock.getString("url")).thenReturn(values ? URL : null);
-    when(configMock.getString("user")).thenReturn(values ? USER : null);
-    when(configMock.getString("password")).thenReturn(values ? PASS : null);
-    when(configMock.getInt("connectionTimeout", TIMEOUT)).thenReturn(values ? TIMEOUT : 0);
-    when(configMock.getInt("socketTimeout", TIMEOUT)).thenReturn(values ? TIMEOUT : 0);
-    when(configMock.getInt("maxTries", MAX_TRIES)).thenReturn(values ? MAX_TRIES : 0);
-    when(configMock.getInt("retryInterval", RETRY_INTERVAL))
+    when(configMock.getString(URL_KEY)).thenReturn(values ? URL : null);
+    when(configMock.getString(USER_KEY)).thenReturn(values ? USER : null);
+    when(configMock.getString(PASSWORD_KEY)).thenReturn(values ? PASS : null);
+    when(configMock.getInt(CONNECTION_TIMEOUT_KEY, TIMEOUT)).thenReturn(values ? TIMEOUT : 0);
+    when(configMock.getInt(SOCKET_TIMEOUT_KEY, TIMEOUT)).thenReturn(values ? TIMEOUT : 0);
+    when(configMock.getInt(MAX_TRIES_KEY, MAX_TRIES)).thenReturn(values ? MAX_TRIES : 0);
+    when(configMock.getInt(RETRY_INTERVAL_KEY, RETRY_INTERVAL))
         .thenReturn(values ? RETRY_INTERVAL : 0);
-    when(configMock.getInt("indexThreadPoolSize", THREAD_POOL_SIZE))
+    when(configMock.getInt(INDEX_THREAD_POOL_SIZE_KEY, THREAD_POOL_SIZE))
         .thenReturn(values ? THREAD_POOL_SIZE : 0);
-    when(configMock.getInt("eventThreadPoolSize", THREAD_POOL_SIZE))
-        .thenReturn(values ? THREAD_POOL_SIZE : 0);
-    when(configMock.getInt("cacheThreadPoolSize", THREAD_POOL_SIZE))
+    when(configMock.getInt(CACHE_THREAD_POOL_SIZE_KEY, THREAD_POOL_SIZE))
         .thenReturn(values ? THREAD_POOL_SIZE : 0);
 
     configuration = new Configuration(cfgFactoryMock, pluginName);
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/ModuleTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/ModuleTest.java
index b92da94..ff7c614 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/ModuleTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/ModuleTest.java
@@ -14,6 +14,7 @@
 
 package com.ericsson.gerrit.plugins.highavailability;
 
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.SHARED_DIRECTORY;
 import static com.google.common.truth.Truth.assertThat;
 import static org.mockito.Mockito.when;
 
@@ -59,7 +60,7 @@
   @Test
   public void shouldReturnConfiguredSharedDirectory() throws IOException {
     File configuredDirectory = tempFolder.newFolder();
-    when(pluginConfigMock.getString("sharedDirectory"))
+    when(pluginConfigMock.getString(SHARED_DIRECTORY))
         .thenReturn(configuredDirectory.getAbsolutePath());
 
     Path sharedDirectory = module.getSharedDirectory(pluginConfigFactoryMock, PLUGIN_NAME);
@@ -70,7 +71,7 @@
   public void shouldCreateSharedDirectoryIfItDoesNotExist() throws IOException {
     File configuredDirectory = tempFolder.newFolder();
     assertThat(configuredDirectory.delete()).isTrue();
-    when(pluginConfigMock.getString("sharedDirectory"))
+    when(pluginConfigMock.getString(SHARED_DIRECTORY))
         .thenReturn(configuredDirectory.getAbsolutePath());
 
     Path sharedDirectory = module.getSharedDirectory(pluginConfigFactoryMock, PLUGIN_NAME);
@@ -80,7 +81,7 @@
   @Test(expected = IOException.class)
   public void shouldThrowAnExceptionIfAnErrorOccurCreatingSharedDirectory() throws IOException {
     File configuredDirectory = tempFolder.newFile();
-    when(pluginConfigMock.getString("sharedDirectory"))
+    when(pluginConfigMock.getString(SHARED_DIRECTORY))
         .thenReturn(configuredDirectory.getAbsolutePath());
 
     module.getSharedDirectory(pluginConfigFactoryMock, PLUGIN_NAME);