Migrate plugin config to own configuration file

Configuration in own file allows to organize parameters in sections.

To be able to remove naming redundancy between section and parameter
names, Configuration class need to be split. One class per section
allows to have same parameter name under different section, e.g.
threadPoolSize.

Change-Id: I063e6ee2517ea05688444d9a7abc74e3f3bc7d08
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 cd56982..680a8ce 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java
@@ -21,11 +21,11 @@
 import com.google.common.base.Strings;
 import com.google.gerrit.extensions.annotations.PluginName;
 import com.google.gerrit.server.config.ConfigUtil;
-import com.google.gerrit.server.config.PluginConfig;
 import com.google.gerrit.server.config.PluginConfigFactory;
 import com.google.inject.Inject;
 import com.google.inject.ProvisionException;
 import com.google.inject.Singleton;
+import org.eclipse.jgit.lib.Config;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -33,62 +33,88 @@
 public class Configuration {
   private static final Logger log = LoggerFactory.getLogger(Configuration.class);
 
+  // main section
+  static final String MAIN_SECTION = "main";
   static final String SHARED_DIRECTORY_KEY = "sharedDirectory";
+
+  // peerInfo section
+  static final String PEER_INFO_SECTION = "peerInfo";
   static final String URL_KEY = "url";
+
+  // http section
+  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 String INDEX_THREAD_POOL_SIZE_KEY = "indexThreadPoolSize";
-  static final String CACHE_THREAD_POOL_SIZE_KEY = "cacheThreadPoolSize";
+
+  // cache section
+  static final String CACHE_SECTION = "cache";
+
+  // index section
+  static final String INDEX_SECTION = "index";
+
+  // common parameters to cache and index section
+  static final String THREAD_POOL_SIZE_KEY = "threadPoolSize";
+
+  // websession section
+  static final String WEBSESSION_SECTION = "websession";
   static final String CLEANUP_INTERVAL_KEY = "cleanupInterval";
 
   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;
+  static final String DEFAULT_CLEANUP_INTERVAL = "24 hours";
   static final long DEFAULT_CLEANUP_INTERVAL_MS = HOURS.toMillis(24);
 
-  private final String url;
-  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 int indexThreadPoolSize;
-  private final int cacheThreadPoolSize;
-  private final String sharedDirectory;
-  private final long cleanupInterval;
+  private final Main main;
+  private final PeerInfo peerInfo;
+  private final Http http;
+  private final Cache cache;
+  private final Index index;
+  private final Websession websession;
 
   @Inject
-  Configuration(PluginConfigFactory config, @PluginName String pluginName) {
-    PluginConfig cfg = config.getFromGerritConfig(pluginName, true);
-    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);
-    sharedDirectory = Strings.emptyToNull(cfg.getString(SHARED_DIRECTORY_KEY));
-    if (sharedDirectory == null) {
-      throw new ProvisionException(SHARED_DIRECTORY_KEY + " must be configured");
-    }
-    cleanupInterval =
-        ConfigUtil.getTimeUnit(
-            Strings.nullToEmpty(cfg.getString(CLEANUP_INTERVAL_KEY)),
-            DEFAULT_CLEANUP_INTERVAL_MS,
-            MILLISECONDS);
+  Configuration(PluginConfigFactory pluginConfigFactory, @PluginName String pluginName) {
+    Config cfg = pluginConfigFactory.getGlobalPluginConfig(pluginName);
+    main = new Main(cfg);
+    peerInfo = new PeerInfo(cfg);
+    http = new Http(cfg);
+    cache = new Cache(cfg);
+    index = new Index(cfg);
+    websession = new Websession(cfg);
   }
 
-  private int getInt(PluginConfig cfg, String name, int defaultValue) {
+  public Main main() {
+    return main;
+  }
+
+  public PeerInfo peerInfo() {
+    return peerInfo;
+  }
+
+  public Http http() {
+    return http;
+  }
+
+  public Cache cache() {
+    return cache;
+  }
+
+  public Index index() {
+    return index;
+  }
+
+  public Websession websession() {
+    return websession;
+  }
+
+  private static int getInt(Config cfg, String section, String name, int defaultValue) {
     try {
-      return cfg.getInt(name, defaultValue);
+      return cfg.getInt(section, name, defaultValue);
     } catch (IllegalArgumentException e) {
       log.error(String.format("invalid value for %s; using default value %d", name, defaultValue));
       log.debug("Failed retrieve integer value: " + e.getMessage(), e);
@@ -96,47 +122,116 @@
     }
   }
 
-  public int getConnectionTimeout() {
-    return connectionTimeout;
+  public static class Main {
+    private final String sharedDirectory;
+
+    private Main(Config cfg) {
+      sharedDirectory =
+          Strings.emptyToNull(cfg.getString(MAIN_SECTION, null, SHARED_DIRECTORY_KEY));
+      if (sharedDirectory == null) {
+        throw new ProvisionException(SHARED_DIRECTORY_KEY + " must be configured");
+      }
+    }
+
+    public String sharedDirectory() {
+      return sharedDirectory;
+    }
   }
 
-  public int getMaxTries() {
-    return maxTries;
+  public static class PeerInfo {
+    private final String url;
+
+    private PeerInfo(Config cfg) {
+      url =
+          CharMatcher.is('/')
+              .trimTrailingFrom(
+                  Strings.nullToEmpty(cfg.getString(PEER_INFO_SECTION, null, URL_KEY)));
+    }
+
+    public String url() {
+      return url;
+    }
   }
 
-  public int getRetryInterval() {
-    return retryInterval;
+  public static class Http {
+    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 Http(Config cfg) {
+      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);
+    }
+
+    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 int getSocketTimeout() {
-    return socketTimeout;
+  public static class Cache {
+    private final int threadPoolSize;
+
+    private Cache(Config cfg) {
+      threadPoolSize = getInt(cfg, CACHE_SECTION, THREAD_POOL_SIZE_KEY, DEFAULT_THREAD_POOL_SIZE);
+    }
+
+    public int threadPoolSize() {
+      return threadPoolSize;
+    }
   }
 
-  public String getUrl() {
-    return CharMatcher.is('/').trimTrailingFrom(url);
+  public static class Index {
+    private final int threadPoolSize;
+
+    private Index(Config cfg) {
+      threadPoolSize = getInt(cfg, INDEX_SECTION, THREAD_POOL_SIZE_KEY, DEFAULT_THREAD_POOL_SIZE);
+    }
+
+    public int threadPoolSize() {
+      return threadPoolSize;
+    }
   }
 
-  public String getUser() {
-    return user;
-  }
+  public static class Websession {
+    private final long cleanupInterval;
 
-  public String getPassword() {
-    return password;
-  }
+    private Websession(Config cfg) {
+      this.cleanupInterval =
+          ConfigUtil.getTimeUnit(
+              Strings.nullToEmpty(cfg.getString(WEBSESSION_SECTION, null, CLEANUP_INTERVAL_KEY)),
+              DEFAULT_CLEANUP_INTERVAL_MS,
+              MILLISECONDS);
+    }
 
-  public int getIndexThreadPoolSize() {
-    return indexThreadPoolSize;
-  }
-
-  public int getCacheThreadPoolSize() {
-    return cacheThreadPoolSize;
-  }
-
-  public String getSharedDirectory() {
-    return sharedDirectory;
-  }
-
-  public Long getCleanupInterval() {
-    return cleanupInterval;
+    public long cleanupInterval() {
+      return cleanupInterval;
+    }
   }
 }
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 b1276ba..ecef7cd 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Module.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Module.java
@@ -44,7 +44,7 @@
   @Singleton
   @SharedDirectory
   Path getSharedDirectory(Configuration cfg) throws IOException {
-    Path sharedDirectoryPath = Paths.get(cfg.getSharedDirectory());
+    Path sharedDirectoryPath = Paths.get(cfg.main().sharedDirectory());
     Files.createDirectories(sharedDirectoryPath);
     return 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
index 82f52d7..ab9d0a4 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Setup.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Setup.java
@@ -16,27 +16,27 @@
 
 import static com.ericsson.gerrit.plugins.highavailability.Configuration.*;
 
+import com.google.common.base.Strings;
 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;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS;
 
 public class Setup implements InitStep {
 
   private final ConsoleUI ui;
-  private final Section mySection;
   private final String pluginName;
   private final SitePaths site;
+  private FileBasedConfig config;
 
   @Inject
-  public Setup(
-      ConsoleUI ui, Section.Factory sections, @PluginName String pluginName, SitePaths site) {
+  public Setup(ConsoleUI ui, @PluginName String pluginName, SitePaths site) {
     this.ui = ui;
-    this.mySection = sections.get("plugin", pluginName);
     this.pluginName = pluginName;
     this.site = site;
   }
@@ -48,44 +48,91 @@
 
     if (ui.yesno(true, "Configure %s", pluginName)) {
       ui.header("Configuring %s", pluginName);
-      configureSharedDir();
-      configurePeer();
-      configureTimeouts();
-      configureRetry();
-      configureThreadPools();
+      Path pluginConfigFile = site.etc_dir.resolve(pluginName + ".config");
+      config = new FileBasedConfig(pluginConfigFile.toFile(), FS.DETECTED);
+      config.load();
+      configureMainSection();
+      configurePeerInfoSection();
+      configureHttp();
+      configureCacheSection();
+      configureIndexSection();
+      configureWebsessiosSection();
+      config.save();
     }
   }
 
-  private void configureSharedDir() {
-    String sharedDir = mySection.string("Shared directory", SHARED_DIRECTORY_KEY, null);
+  private void configureMainSection() {
+    ui.header("Main section");
+    String sharedDir =
+        promptAndSetString("Shared directory", MAIN_SECTION, SHARED_DIRECTORY_KEY, 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 configurePeerInfoSection() {
+    ui.header("PeerInfo section");
+    promptAndSetString("Peer URL", PEER_INFO_SECTION, URL_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 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 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 configureCacheSection() {
+    ui.header("Cache section");
+    promptAndSetString(
+        "Cache thread pool size",
+        CACHE_SECTION,
+        THREAD_POOL_SIZE_KEY,
+        str(DEFAULT_THREAD_POOL_SIZE));
   }
 
-  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 void configureIndexSection() {
+    ui.header("Index section");
+    promptAndSetString(
+        "Index thread pool size",
+        INDEX_SECTION,
+        THREAD_POOL_SIZE_KEY,
+        str(DEFAULT_THREAD_POOL_SIZE));
+  }
+
+  private void configureWebsessiosSection() {
+    ui.header("Websession section");
+    promptAndSetString(
+        "Cleanup interval", WEBSESSION_SECTION, CLEANUP_INTERVAL_KEY, DEFAULT_CLEANUP_INTERVAL);
+  }
+
+  private String promptAndSetString(
+      String title, String section, String name, String defaultValue) {
+    String oldValue = Strings.emptyToNull(config.getString(section, null, name));
+    String newValue = ui.readString(oldValue != null ? oldValue : defaultValue, title);
+    if (!eq(oldValue, newValue)) {
+      if (newValue != null) {
+        config.setString(section, null, name, newValue);
+      } else {
+        config.unset(section, name, name);
+      }
+    }
+    return newValue;
+  }
+
+  private static boolean eq(String a, String b) {
+    return (a == null && b == null) || (a != null && a.equals(b));
   }
 
   private static String str(int n) {
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheExecutorProvider.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheExecutorProvider.java
index dd40155..aed590d 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheExecutorProvider.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheExecutorProvider.java
@@ -25,6 +25,6 @@
 
   @Inject
   CacheExecutorProvider(WorkQueue workQueue, Configuration config) {
-    super(workQueue, config.getCacheThreadPoolSize(), "Forward-cache-eviction-event");
+    super(workQueue, config.cache().threadPoolSize(), "Forward-cache-eviction-event");
   }
 }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpClientProvider.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpClientProvider.java
index e68875f..bd3077f 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpClientProvider.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpClientProvider.java
@@ -70,9 +70,9 @@
 
   private RequestConfig customRequestConfig() {
     return RequestConfig.custom()
-        .setConnectTimeout(cfg.getConnectionTimeout())
-        .setSocketTimeout(cfg.getSocketTimeout())
-        .setConnectionRequestTimeout(cfg.getConnectionTimeout())
+        .setConnectTimeout(cfg.http().connectionTimeout())
+        .setSocketTimeout(cfg.http().socketTimeout())
+        .setConnectionRequestTimeout(cfg.http().connectionTimeout())
         .build();
   }
 
@@ -109,7 +109,7 @@
   private BasicCredentialsProvider buildCredentials() {
     BasicCredentialsProvider creds = new BasicCredentialsProvider();
     creds.setCredentials(
-        AuthScope.ANY, new UsernamePasswordCredentials(cfg.getUser(), cfg.getPassword()));
+        AuthScope.ANY, new UsernamePasswordCredentials(cfg.http().user(), cfg.http().password()));
     return creds;
   }
 
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarder.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarder.java
index 49326cc..6d18be3 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarder.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarder.java
@@ -123,14 +123,14 @@
             log.error("Failed to {}", name, e);
             return false;
           }
-          if (execCnt >= cfg.getMaxTries()) {
-            log.error("Failed to {}, after {} tries", name, cfg.getMaxTries());
+          if (execCnt >= cfg.http().maxTries()) {
+            log.error("Failed to {}, after {} tries", name, cfg.http().maxTries());
             return false;
           }
 
           logRetry(e);
           try {
-            Thread.sleep(cfg.getRetryInterval());
+            Thread.sleep(cfg.http().retryInterval());
           } catch (InterruptedException ie) {
             log.error("{} was interrupted, giving up", name, ie);
             Thread.currentThread().interrupt();
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/IndexExecutorProvider.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/IndexExecutorProvider.java
index efe323e..7efcc3f 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/IndexExecutorProvider.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/IndexExecutorProvider.java
@@ -25,6 +25,6 @@
 
   @Inject
   IndexExecutorProvider(WorkQueue workQueue, Configuration config) {
-    super(workQueue, config.getIndexThreadPoolSize(), "Forward-index-event");
+    super(workQueue, config.index().threadPoolSize(), "Forward-index-event");
   }
 }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/PluginConfigPeerInfoProvider.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/PluginConfigPeerInfoProvider.java
index 74e148b..a78b397 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/PluginConfigPeerInfoProvider.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/PluginConfigPeerInfoProvider.java
@@ -25,7 +25,7 @@
 
   @Inject
   PluginConfigPeerInfoProvider(Configuration cfg) {
-    peerInfo = Optional.of(new PeerInfo(cfg.getUrl()));
+    peerInfo = Optional.of(new PeerInfo(cfg.peerInfo().url()));
   }
 
   @Override
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/websession/file/FileBasedWebSessionCacheCleaner.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/websession/file/FileBasedWebSessionCacheCleaner.java
index f6b5542..68ffd17 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/websession/file/FileBasedWebSessionCacheCleaner.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/websession/file/FileBasedWebSessionCacheCleaner.java
@@ -41,7 +41,7 @@
       WorkQueue queue, Provider<CleanupTask> cleanupTaskProvider, Configuration config) {
     this.queue = queue;
     this.cleanupTaskProvider = cleanupTaskProvider;
-    this.cleanupIntervalMillis = config.getCleanupInterval();
+    this.cleanupIntervalMillis = config.websession().cleanupInterval();
   }
 
   @Override
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index f894822..3290f1b 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -2,57 +2,71 @@
 =========================
 
 The @PLUGIN@ plugin must be installed in both instances and the following fields
-should be specified in the corresponding Gerrit configuration file:
+should be specified in `$site_path/etc/@PLUGIN@.config` file:
 
-File 'gerrit.config'
+File '@PLUGIN@.config'
 --------------------
 
-[plugin "@PLUGIN@"]
+[main]
+:  sharedDirectory = /directory/accessible/from/both/instances
+[peerInfo]
 :  url = target_instance_url
+[http]
 :  user = username
 :  password = password
-:  sharedDirectory = /directory/accessible/from/both/instances
 
-plugin.@PLUGIN@.url
+main.sharedDirectory
+:   Path to a directory accessible from both master instances.
+
+peerInfo.url
 :   Specify the URL for the secondary (target) instance.
 
-plugin.@PLUGIN@.user
+http.user
 :   Username to connect to the secondary (target) instance.
 
-plugin.@PLUGIN@.password
-:   Password to connect to the secondary (target) instance. This value can
-     also be defined in secure.config.
-
-plugin.@PLUGIN@.sharedDirectory
-:   Path to a directory accessible from both master instances.
+http.password
+:   Password to connect to the secondary (target) 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:
 
-@PLUGIN@.connectionTimeout
+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.
 
-@PLUGIN@.socketTimeout
+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.
 
-@PLUGIN@.maxTries
+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 5. After this number of failed tries, an
     error is logged.
 
-@PLUGIN@.retryInterval
+http.retryInterval
 :   The interval of time in milliseconds between the subsequent auto-retries.
     When not specified, the default value is set to 1000ms.
 
-@PLUGIN@.indexThreadPoolSize
+cache.threadPoolSize
+:   Maximum number of threads used to send cache evictions to the target instance.
+    Defaults to 1.
+
+index.threadPoolSize
 :   Maximum number of threads used to send index events to the target instance.
     Defaults to 1.
 
-@PLUGIN@.cacheThreadPoolSize
-:   Maximum number of threads used to send cache evictions to the target instance.
-    Defaults to 1.
\ No newline at end of file
+websession.cleanupInterval
+:   Frequency for deleting expired web sessions. Values should use common time
+    unit suffixes to express their setting:
+* 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.
\ No newline at end of file
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 a828fb2..31449e3 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java
@@ -14,7 +14,7 @@
 
 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.CACHE_SECTION;
 import static com.ericsson.gerrit.plugins.highavailability.Configuration.CLEANUP_INTERVAL_KEY;
 import static com.ericsson.gerrit.plugins.highavailability.Configuration.CONNECTION_TIMEOUT_KEY;
 import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_CLEANUP_INTERVAL_MS;
@@ -22,21 +22,26 @@
 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.HTTP_SECTION;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.INDEX_SECTION;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.MAIN_SECTION;
 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.PEER_INFO_SECTION;
 import static com.ericsson.gerrit.plugins.highavailability.Configuration.RETRY_INTERVAL_KEY;
 import static com.ericsson.gerrit.plugins.highavailability.Configuration.SHARED_DIRECTORY_KEY;
 import static com.ericsson.gerrit.plugins.highavailability.Configuration.SOCKET_TIMEOUT_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.THREAD_POOL_SIZE_KEY;
 import static com.ericsson.gerrit.plugins.highavailability.Configuration.URL_KEY;
 import static com.ericsson.gerrit.plugins.highavailability.Configuration.USER_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.WEBSESSION_SECTION;
 import static com.google.common.truth.Truth.assertThat;
 import static java.util.concurrent.TimeUnit.SECONDS;
 import static org.mockito.Mockito.when;
 
-import com.google.gerrit.server.config.PluginConfig;
 import com.google.gerrit.server.config.PluginConfigFactory;
 import com.google.inject.ProvisionException;
+import org.eclipse.jgit.lib.Config;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -57,14 +62,15 @@
   private static final String ERROR_MESSAGE = "some error message";
 
   @Mock private PluginConfigFactory cfgFactoryMock;
-  @Mock private PluginConfig configMock;
+  @Mock private Config configMock;
   private Configuration configuration;
   private String pluginName = "high-availability";
 
   @Before
   public void setUp() {
-    when(cfgFactoryMock.getFromGerritConfig(pluginName, true)).thenReturn(configMock);
-    when(configMock.getString(SHARED_DIRECTORY_KEY)).thenReturn(SHARED_DIRECTORY);
+    when(cfgFactoryMock.getGlobalPluginConfig(pluginName)).thenReturn(configMock);
+    when(configMock.getString(MAIN_SECTION, null, SHARED_DIRECTORY_KEY))
+        .thenReturn(SHARED_DIRECTORY);
   }
 
   private void initializeConfiguration() {
@@ -74,152 +80,156 @@
   @Test
   public void testGetUrl() throws Exception {
     initializeConfiguration();
-    assertThat(configuration.getUrl()).isEqualTo(EMPTY);
+    assertThat(configuration.peerInfo().url()).isEqualTo(EMPTY);
 
-    when(configMock.getString(URL_KEY)).thenReturn(URL);
+    when(configMock.getString(PEER_INFO_SECTION, null, URL_KEY)).thenReturn(URL);
     initializeConfiguration();
-    assertThat(configuration.getUrl()).isEqualTo(URL);
+    assertThat(configuration.peerInfo().url()).isEqualTo(URL);
   }
 
   @Test
   public void testGetUrlIsDroppingTrailingSlash() throws Exception {
-    when(configMock.getString("url")).thenReturn(URL + "/");
+    when(configMock.getString(PEER_INFO_SECTION, null, URL_KEY)).thenReturn(URL + "/");
     initializeConfiguration();
     assertThat(configuration).isNotNull();
-    assertThat(configuration.getUrl()).isEqualTo(URL);
+    assertThat(configuration.peerInfo().url()).isEqualTo(URL);
   }
 
   @Test
   public void testGetUser() throws Exception {
     initializeConfiguration();
-    assertThat(configuration.getUser()).isEqualTo(EMPTY);
+    assertThat(configuration.http().user()).isEqualTo(EMPTY);
 
-    when(configMock.getString(USER_KEY)).thenReturn(USER);
+    when(configMock.getString(HTTP_SECTION, null, USER_KEY)).thenReturn(USER);
     initializeConfiguration();
-    assertThat(configuration.getUser()).isEqualTo(USER);
+    assertThat(configuration.http().user()).isEqualTo(USER);
   }
 
   @Test
   public void testGetPassword() throws Exception {
     initializeConfiguration();
-    assertThat(configuration.getPassword()).isEqualTo(EMPTY);
+    assertThat(configuration.http().password()).isEqualTo(EMPTY);
 
-    when(configMock.getString(PASSWORD_KEY)).thenReturn(PASS);
+    when(configMock.getString(HTTP_SECTION, null, PASSWORD_KEY)).thenReturn(PASS);
     initializeConfiguration();
-    assertThat(configuration.getPassword()).isEqualTo(PASS);
+    assertThat(configuration.http().password()).isEqualTo(PASS);
   }
 
   @Test
   public void testGetConnectionTimeout() throws Exception {
     initializeConfiguration();
-    assertThat(configuration.getConnectionTimeout()).isEqualTo(0);
+    assertThat(configuration.http().connectionTimeout()).isEqualTo(0);
 
-    when(configMock.getInt(CONNECTION_TIMEOUT_KEY, DEFAULT_TIMEOUT_MS)).thenReturn(TIMEOUT);
+    when(configMock.getInt(HTTP_SECTION, CONNECTION_TIMEOUT_KEY, DEFAULT_TIMEOUT_MS))
+        .thenReturn(TIMEOUT);
     initializeConfiguration();
-    assertThat(configuration.getConnectionTimeout()).isEqualTo(TIMEOUT);
+    assertThat(configuration.http().connectionTimeout()).isEqualTo(TIMEOUT);
 
-    when(configMock.getInt(CONNECTION_TIMEOUT_KEY, DEFAULT_TIMEOUT_MS))
+    when(configMock.getInt(HTTP_SECTION, CONNECTION_TIMEOUT_KEY, DEFAULT_TIMEOUT_MS))
         .thenThrow(new IllegalArgumentException(ERROR_MESSAGE));
     initializeConfiguration();
-    assertThat(configuration.getConnectionTimeout()).isEqualTo(DEFAULT_TIMEOUT_MS);
+    assertThat(configuration.http().connectionTimeout()).isEqualTo(DEFAULT_TIMEOUT_MS);
   }
 
   @Test
   public void testGetSocketTimeout() throws Exception {
     initializeConfiguration();
-    assertThat(configuration.getSocketTimeout()).isEqualTo(0);
+    assertThat(configuration.http().socketTimeout()).isEqualTo(0);
 
-    when(configMock.getInt(SOCKET_TIMEOUT_KEY, DEFAULT_TIMEOUT_MS)).thenReturn(TIMEOUT);
+    when(configMock.getInt(HTTP_SECTION, SOCKET_TIMEOUT_KEY, DEFAULT_TIMEOUT_MS))
+        .thenReturn(TIMEOUT);
     initializeConfiguration();
-    assertThat(configuration.getSocketTimeout()).isEqualTo(TIMEOUT);
+    assertThat(configuration.http().socketTimeout()).isEqualTo(TIMEOUT);
 
-    when(configMock.getInt(SOCKET_TIMEOUT_KEY, DEFAULT_TIMEOUT_MS))
+    when(configMock.getInt(HTTP_SECTION, SOCKET_TIMEOUT_KEY, DEFAULT_TIMEOUT_MS))
         .thenThrow(new IllegalArgumentException(ERROR_MESSAGE));
     initializeConfiguration();
-    assertThat(configuration.getSocketTimeout()).isEqualTo(DEFAULT_TIMEOUT_MS);
+    assertThat(configuration.http().socketTimeout()).isEqualTo(DEFAULT_TIMEOUT_MS);
   }
 
   @Test
   public void testGetMaxTries() throws Exception {
     initializeConfiguration();
-    assertThat(configuration.getMaxTries()).isEqualTo(0);
+    assertThat(configuration.http().maxTries()).isEqualTo(0);
 
-    when(configMock.getInt(MAX_TRIES_KEY, DEFAULT_MAX_TRIES)).thenReturn(MAX_TRIES);
+    when(configMock.getInt(HTTP_SECTION, MAX_TRIES_KEY, DEFAULT_MAX_TRIES)).thenReturn(MAX_TRIES);
     initializeConfiguration();
-    assertThat(configuration.getMaxTries()).isEqualTo(MAX_TRIES);
+    assertThat(configuration.http().maxTries()).isEqualTo(MAX_TRIES);
 
-    when(configMock.getInt(MAX_TRIES_KEY, DEFAULT_MAX_TRIES))
+    when(configMock.getInt(HTTP_SECTION, MAX_TRIES_KEY, DEFAULT_MAX_TRIES))
         .thenThrow(new IllegalArgumentException(ERROR_MESSAGE));
     initializeConfiguration();
-    assertThat(configuration.getMaxTries()).isEqualTo(DEFAULT_MAX_TRIES);
+    assertThat(configuration.http().maxTries()).isEqualTo(DEFAULT_MAX_TRIES);
   }
 
   @Test
   public void testGetRetryInterval() throws Exception {
     initializeConfiguration();
-    assertThat(configuration.getRetryInterval()).isEqualTo(0);
+    assertThat(configuration.http().retryInterval()).isEqualTo(0);
 
-    when(configMock.getInt(RETRY_INTERVAL_KEY, DEFAULT_RETRY_INTERVAL)).thenReturn(RETRY_INTERVAL);
+    when(configMock.getInt(HTTP_SECTION, RETRY_INTERVAL_KEY, DEFAULT_RETRY_INTERVAL))
+        .thenReturn(RETRY_INTERVAL);
     initializeConfiguration();
-    assertThat(configuration.getRetryInterval()).isEqualTo(RETRY_INTERVAL);
+    assertThat(configuration.http().retryInterval()).isEqualTo(RETRY_INTERVAL);
 
-    when(configMock.getInt(RETRY_INTERVAL_KEY, DEFAULT_RETRY_INTERVAL))
+    when(configMock.getInt(HTTP_SECTION, RETRY_INTERVAL_KEY, DEFAULT_RETRY_INTERVAL))
         .thenThrow(new IllegalArgumentException(ERROR_MESSAGE));
     initializeConfiguration();
-    assertThat(configuration.getRetryInterval()).isEqualTo(DEFAULT_RETRY_INTERVAL);
+    assertThat(configuration.http().retryInterval()).isEqualTo(DEFAULT_RETRY_INTERVAL);
   }
 
   @Test
   public void testGetIndexThreadPoolSize() throws Exception {
     initializeConfiguration();
-    assertThat(configuration.getIndexThreadPoolSize()).isEqualTo(0);
+    assertThat(configuration.index().threadPoolSize()).isEqualTo(0);
 
-    when(configMock.getInt(INDEX_THREAD_POOL_SIZE_KEY, DEFAULT_THREAD_POOL_SIZE))
+    when(configMock.getInt(INDEX_SECTION, THREAD_POOL_SIZE_KEY, DEFAULT_THREAD_POOL_SIZE))
         .thenReturn(THREAD_POOL_SIZE);
     initializeConfiguration();
-    assertThat(configuration.getIndexThreadPoolSize()).isEqualTo(THREAD_POOL_SIZE);
+    assertThat(configuration.index().threadPoolSize()).isEqualTo(THREAD_POOL_SIZE);
 
-    when(configMock.getInt(INDEX_THREAD_POOL_SIZE_KEY, DEFAULT_THREAD_POOL_SIZE))
+    when(configMock.getInt(INDEX_SECTION, THREAD_POOL_SIZE_KEY, DEFAULT_THREAD_POOL_SIZE))
         .thenThrow(new IllegalArgumentException(ERROR_MESSAGE));
     initializeConfiguration();
-    assertThat(configuration.getIndexThreadPoolSize()).isEqualTo(DEFAULT_THREAD_POOL_SIZE);
+    assertThat(configuration.index().threadPoolSize()).isEqualTo(DEFAULT_THREAD_POOL_SIZE);
   }
 
   @Test
   public void testGetCacheThreadPoolSize() throws Exception {
     initializeConfiguration();
-    assertThat(configuration.getCacheThreadPoolSize()).isEqualTo(0);
+    assertThat(configuration.cache().threadPoolSize()).isEqualTo(0);
 
-    when(configMock.getInt(CACHE_THREAD_POOL_SIZE_KEY, DEFAULT_THREAD_POOL_SIZE))
+    when(configMock.getInt(CACHE_SECTION, THREAD_POOL_SIZE_KEY, DEFAULT_THREAD_POOL_SIZE))
         .thenReturn(THREAD_POOL_SIZE);
     initializeConfiguration();
-    assertThat(configuration.getCacheThreadPoolSize()).isEqualTo(THREAD_POOL_SIZE);
+    assertThat(configuration.cache().threadPoolSize()).isEqualTo(THREAD_POOL_SIZE);
 
-    when(configMock.getInt(CACHE_THREAD_POOL_SIZE_KEY, DEFAULT_THREAD_POOL_SIZE))
+    when(configMock.getInt(CACHE_SECTION, THREAD_POOL_SIZE_KEY, DEFAULT_THREAD_POOL_SIZE))
         .thenThrow(new IllegalArgumentException(ERROR_MESSAGE));
     initializeConfiguration();
-    assertThat(configuration.getCacheThreadPoolSize()).isEqualTo(DEFAULT_THREAD_POOL_SIZE);
+    assertThat(configuration.cache().threadPoolSize()).isEqualTo(DEFAULT_THREAD_POOL_SIZE);
   }
 
   @Test
   public void testGetSharedDirectory() throws Exception {
     initializeConfiguration();
-    assertThat(configuration.getSharedDirectory()).isEqualTo(SHARED_DIRECTORY);
+    assertThat(configuration.main().sharedDirectory()).isEqualTo(SHARED_DIRECTORY);
   }
 
   @Test(expected = ProvisionException.class)
   public void shouldThrowExceptionIfSharedDirectoryNotConfigured() throws Exception {
-    when(configMock.getString(SHARED_DIRECTORY_KEY)).thenReturn(null);
+    when(configMock.getString(MAIN_SECTION, null, SHARED_DIRECTORY_KEY)).thenReturn(null);
     initializeConfiguration();
   }
 
   @Test
   public void testGetCleanupInterval() throws Exception {
     initializeConfiguration();
-    assertThat(configuration.getCleanupInterval()).isEqualTo(DEFAULT_CLEANUP_INTERVAL_MS);
+    assertThat(configuration.websession().cleanupInterval()).isEqualTo(DEFAULT_CLEANUP_INTERVAL_MS);
 
-    when(configMock.getString(CLEANUP_INTERVAL_KEY)).thenReturn("30 seconds");
+    when(configMock.getString(WEBSESSION_SECTION, null, CLEANUP_INTERVAL_KEY))
+        .thenReturn("30 seconds");
     initializeConfiguration();
-    assertThat(configuration.getCleanupInterval()).isEqualTo(SECONDS.toMillis(30));
+    assertThat(configuration.websession().cleanupInterval()).isEqualTo(SECONDS.toMillis(30));
   }
 }
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 8af8c51..c577a01 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/ModuleTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/ModuleTest.java
@@ -25,13 +25,15 @@
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
 import org.junit.runner.RunWith;
+import org.mockito.Answers;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnitRunner;
 
 @RunWith(MockitoJUnitRunner.class)
 public class ModuleTest {
 
-  @Mock private Configuration config;
+  @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+  private Configuration configMock;
 
   @Rule public TemporaryFolder tempFolder = new TemporaryFolder();
 
@@ -46,17 +48,17 @@
   public void shouldCreateSharedDirectoryIfItDoesNotExist() throws Exception {
     File configuredDirectory = tempFolder.newFolder();
     assertThat(configuredDirectory.delete()).isTrue();
-    when(config.getSharedDirectory()).thenReturn(configuredDirectory.getAbsolutePath());
+    when(configMock.main().sharedDirectory()).thenReturn(configuredDirectory.getAbsolutePath());
 
-    Path sharedDirectory = module.getSharedDirectory(config);
+    Path sharedDirectory = module.getSharedDirectory(configMock);
     assertThat(sharedDirectory.toFile().exists()).isTrue();
   }
 
   @Test(expected = IOException.class)
   public void shouldThrowAnExceptionIfAnErrorOccurCreatingSharedDirectory() throws Exception {
     File configuredDirectory = tempFolder.newFile();
-    when(config.getSharedDirectory()).thenReturn(configuredDirectory.getAbsolutePath());
+    when(configMock.main().sharedDirectory()).thenReturn(configuredDirectory.getAbsolutePath());
 
-    module.getSharedDirectory(config);
+    module.getSharedDirectory(configMock);
   }
 }
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheExecutorProviderTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheExecutorProviderTest.java
index 08a1b19..fbc11e0 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheExecutorProviderTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheExecutorProviderTest.java
@@ -24,6 +24,7 @@
 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;
 
@@ -31,14 +32,15 @@
 public class CacheExecutorProviderTest {
 
   @Mock private WorkQueue.Executor executorMock;
+
   private CacheExecutorProvider cacheExecutorProvider;
 
   @Before
   public void setUp() throws Exception {
     WorkQueue workQueueMock = mock(WorkQueue.class);
     when(workQueueMock.createQueue(4, "Forward-cache-eviction-event")).thenReturn(executorMock);
-    Configuration configMock = mock(Configuration.class);
-    when(configMock.getCacheThreadPoolSize()).thenReturn(4);
+    Configuration configMock = mock(Configuration.class, Answers.RETURNS_DEEP_STUBS);
+    when(configMock.cache().threadPoolSize()).thenReturn(4);
 
     cacheExecutorProvider = new CacheExecutorProvider(workQueueMock, configMock);
   }
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpClientProviderTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpClientProviderTest.java
index ac14ce4..a2aec9d 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpClientProviderTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpClientProviderTest.java
@@ -26,6 +26,7 @@
 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;
 
@@ -34,14 +35,15 @@
   private static final int TIME_INTERVAL = 1000;
   private static final String EMPTY = "";
 
-  @Mock private Configuration config;
+  @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+  private Configuration configMock;
 
   @Before
   public void setUp() throws Exception {
-    when(config.getUser()).thenReturn(EMPTY);
-    when(config.getPassword()).thenReturn(EMPTY);
-    when(config.getConnectionTimeout()).thenReturn(TIME_INTERVAL);
-    when(config.getSocketTimeout()).thenReturn(TIME_INTERVAL);
+    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
@@ -58,7 +60,7 @@
   class TestModule extends AbstractModule {
     @Override
     protected void configure() {
-      bind(Configuration.class).toInstance(config);
+      bind(Configuration.class).toInstance(configMock);
       bind(CloseableHttpClient.class).toProvider(HttpClientProvider.class).in(Scopes.SINGLETON);
     }
   }
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpSessionTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpSessionTest.java
index 19a50df..d5e27b1 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpSessionTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpSessionTest.java
@@ -41,6 +41,7 @@
 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;
@@ -63,23 +64,24 @@
 
   @Rule public WireMockRule wireMockRule = new WireMockRule(0);
 
-  private Configuration cfg;
+  private Configuration configMock;
 
   @Before
   public void setUp() throws Exception {
     String url = "http://localhost:" + wireMockRule.port();
-    cfg = mock(Configuration.class);
-    when(cfg.getUser()).thenReturn("user");
-    when(cfg.getPassword()).thenReturn("pass");
-    when(cfg.getMaxTries()).thenReturn(MAX_TRIES);
-    when(cfg.getConnectionTimeout()).thenReturn(TIMEOUT);
-    when(cfg.getSocketTimeout()).thenReturn(TIMEOUT);
-    when(cfg.getRetryInterval()).thenReturn(RETRY_INTERVAL);
+    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);
 
     PeerInfo peerInfo = mock(PeerInfo.class);
     when(peerInfo.getDirectUrl()).thenReturn(url);
     httpSession =
-        new HttpSession(new HttpClientProvider(cfg).get(), Providers.of(Optional.of(peerInfo)));
+        new HttpSession(
+            new HttpClientProvider(configMock).get(), Providers.of(Optional.of(peerInfo)));
   }
 
   @Test
@@ -184,7 +186,7 @@
   public void testNoRequestWhenPeerInfoUnknown() throws IOException {
     httpSession =
         new HttpSession(
-            new HttpClientProvider(cfg).get(), Providers.of(Optional.<PeerInfo>absent()));
+            new HttpClientProvider(configMock).get(), Providers.of(Optional.<PeerInfo>absent()));
     try {
       httpSession.post(ENDPOINT);
       fail("Expected PeerInfoNotAvailableException");
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarderTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarderTest.java
index ce4d56b..3a736cb 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarderTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/RestForwarderTest.java
@@ -35,6 +35,7 @@
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.mockito.Answers;
 
 public class RestForwarderTest {
   private static final String PLUGIN_NAME = "high-availability";
@@ -58,7 +59,6 @@
 
   private RestForwarder forwarder;
   private HttpSession httpSessionMock;
-  private Configuration configurationMock;
 
   @BeforeClass
   public static void setup() {
@@ -68,10 +68,10 @@
   @Before
   public void setUp() {
     httpSessionMock = mock(HttpSession.class);
-    configurationMock = mock(Configuration.class);
-    when(configurationMock.getMaxTries()).thenReturn(3);
-    when(configurationMock.getRetryInterval()).thenReturn(10);
-    forwarder = new RestForwarder(httpSessionMock, PLUGIN_NAME, configurationMock);
+    Configuration configMock = mock(Configuration.class, Answers.RETURNS_DEEP_STUBS);
+    when(configMock.http().maxTries()).thenReturn(3);
+    when(configMock.http().retryInterval()).thenReturn(10);
+    forwarder = new RestForwarder(httpSessionMock, PLUGIN_NAME, configMock);
   }
 
   @Test
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/IndexExecutorProviderTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/IndexExecutorProviderTest.java
index 66b84f1..cc4ba99 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/IndexExecutorProviderTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/IndexExecutorProviderTest.java
@@ -24,6 +24,7 @@
 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;
 
@@ -37,8 +38,8 @@
     executorMock = mock(WorkQueue.Executor.class);
     WorkQueue workQueueMock = mock(WorkQueue.class);
     when(workQueueMock.createQueue(4, "Forward-index-event")).thenReturn(executorMock);
-    Configuration configMock = mock(Configuration.class);
-    when(configMock.getIndexThreadPoolSize()).thenReturn(4);
+    Configuration configMock = mock(Configuration.class, Answers.RETURNS_DEEP_STUBS);
+    when(configMock.index().threadPoolSize()).thenReturn(4);
     indexExecutorProvider = new IndexExecutorProvider(workQueueMock, configMock);
   }
 
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/websession/file/FileBasedWebSessionCacheCleanerTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/websession/file/FileBasedWebSessionCacheCleanerTest.java
index 61f6aa2..04c73d4 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/websession/file/FileBasedWebSessionCacheCleanerTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/websession/file/FileBasedWebSessionCacheCleanerTest.java
@@ -33,6 +33,7 @@
 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;
 
@@ -46,7 +47,9 @@
   @Mock private ScheduledFuture<?> scheduledFutureMock;
   @Mock private WorkQueue workQueueMock;
   @Mock private Provider<CleanupTask> cleanupTaskProviderMock;
-  @Mock private Configuration configMock;
+
+  @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+  private Configuration configMock;
 
   private FileBasedWebSessionCacheCleaner cleaner;
 
@@ -57,7 +60,7 @@
     doReturn(scheduledFutureMock)
         .when(executorMock)
         .scheduleAtFixedRate(isA(CleanupTask.class), anyLong(), anyLong(), isA(TimeUnit.class));
-    when(configMock.getCleanupInterval()).thenReturn(CLEANUP_INTERVAL);
+    when(configMock.websession().cleanupInterval()).thenReturn(CLEANUP_INTERVAL);
     cleaner =
         new FileBasedWebSessionCacheCleaner(workQueueMock, cleanupTaskProviderMock, configMock);
   }