Merge branch 'stable-2.13'

* stable-2.13:
  Don't perform REST calls when remote PeerInfo not available
  Set the timeout in CacheEvictionIT back to 5 seconds

Change-Id: Iaf0ecd2cc5cb565197aa036a561e8b213bd0d972
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpSession.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpSession.java
index 7a95f44..6e2c7a8 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpSession.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/HttpSession.java
@@ -14,6 +14,7 @@
 
 package com.ericsson.gerrit.plugins.highavailability.forwarder.rest;
 
+import com.google.common.base.Optional;
 import com.google.common.base.Strings;
 import com.google.common.net.MediaType;
 import com.google.inject.Inject;
@@ -32,11 +33,11 @@
 
 class HttpSession {
   private final CloseableHttpClient httpClient;
-  private final Provider<PeerInfo> peerInfo;
+  private final Provider<Optional<PeerInfo>> peerInfo;
 
   @Inject
   HttpSession(CloseableHttpClient httpClient,
-      Provider<PeerInfo> peerInfo) {
+      Provider<Optional<PeerInfo>> peerInfo) {
     this.httpClient = httpClient;
     this.peerInfo = peerInfo;
   }
@@ -46,7 +47,7 @@
   }
 
   HttpResult post(String endpoint, String content) throws IOException {
-    HttpPost post = new HttpPost(peerInfo.get().getDirectUrl() + endpoint);
+    HttpPost post = new HttpPost(getPeerInfo().getDirectUrl() + endpoint);
     if (!Strings.isNullOrEmpty(content)) {
       post.addHeader("Content-Type", MediaType.JSON_UTF_8.toString());
       post.setEntity(new StringEntity(content, StandardCharsets.UTF_8));
@@ -56,7 +57,15 @@
 
   HttpResult delete(String endpoint) throws IOException {
     return httpClient.execute(
-        new HttpDelete(peerInfo.get().getDirectUrl() + endpoint),
+        new HttpDelete(getPeerInfo().getDirectUrl() + endpoint),
         new HttpResponseHandler());
   }
+
+  private PeerInfo getPeerInfo() throws PeerInfoNotAvailableException {
+    PeerInfo info = peerInfo.get().orNull();
+    if (info == null) {
+      throw new PeerInfoNotAvailableException();
+    }
+    return info;
+  }
 }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/PeerInfoNotAvailableException.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/PeerInfoNotAvailableException.java
new file mode 100644
index 0000000..df94f52
--- /dev/null
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/PeerInfoNotAvailableException.java
@@ -0,0 +1,21 @@
+// 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.forwarder.rest;
+
+import java.io.IOException;
+
+public class PeerInfoNotAvailableException extends IOException {
+  private static final long serialVersionUID = 1L;
+}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/PeerInfoModule.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/PeerInfoModule.java
index 2384b3b..c4f38ce 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/PeerInfoModule.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/PeerInfoModule.java
@@ -14,11 +14,14 @@
 
 package com.ericsson.gerrit.plugins.highavailability.peers;
 
+import com.google.common.base.Optional;
 import com.google.inject.AbstractModule;
+import com.google.inject.TypeLiteral;
 
 public class PeerInfoModule extends AbstractModule {
   @Override
   protected void configure() {
-    bind(PeerInfo.class).toProvider(PluginConfigPeerInfoProvider.class);
+    bind(new TypeLiteral<Optional<PeerInfo>>() {})
+        .toProvider(PluginConfigPeerInfoProvider.class);
   }
 }
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 9e937ac..076115b 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
@@ -14,22 +14,23 @@
 
 package com.ericsson.gerrit.plugins.highavailability.peers;
 
+import com.google.common.base.Optional;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
 import com.ericsson.gerrit.plugins.highavailability.Configuration;
 
-public class PluginConfigPeerInfoProvider implements Provider<PeerInfo> {
+public class PluginConfigPeerInfoProvider implements Provider<Optional<PeerInfo>> {
 
-  private final PeerInfo peerInfo;
+  private final Optional<PeerInfo> peerInfo;
 
   @Inject
   PluginConfigPeerInfoProvider(Configuration cfg) {
-    peerInfo = new PeerInfo(cfg.getUrl());
+    peerInfo = Optional.of(new PeerInfo(cfg.getUrl()));
   }
 
   @Override
-  public PeerInfo get() {
+  public Optional<PeerInfo> get() {
     return peerInfo;
   }
 }
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheEvictionIT.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheEvictionIT.java
index 0efc17c..cdd70ea 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheEvictionIT.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheEvictionIT.java
@@ -81,7 +81,7 @@
 
     adminSshSession
         .exec("gerrit flush-caches --cache " + Constants.PROJECT_LIST);
-    checkPoint.await(50, TimeUnit.SECONDS);
+    checkPoint.await(5, TimeUnit.SECONDS);
     verify(postRequestedFor(urlEqualTo(flushRequest)));
   }
 }
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 ca59f8d..bbf7800 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
@@ -15,26 +15,34 @@
 package com.ericsson.gerrit.plugins.highavailability.forwarder.rest;
 
 import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.anyRequestedFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.anyUrl;
 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.exactly;
 import static com.github.tomakehurst.wiremock.client.WireMock.post;
 import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
+import static com.github.tomakehurst.wiremock.client.WireMock.verify;
 import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import com.google.common.base.Optional;
+import com.google.inject.util.Providers;
+
 import com.ericsson.gerrit.plugins.highavailability.Configuration;
 import com.ericsson.gerrit.plugins.highavailability.forwarder.rest.HttpResponseHandler.HttpResult;
 import com.ericsson.gerrit.plugins.highavailability.peers.PeerInfo;
 import com.github.tomakehurst.wiremock.http.Fault;
 import com.github.tomakehurst.wiremock.junit.WireMockRule;
 import com.github.tomakehurst.wiremock.stubbing.Scenario;
-import com.google.inject.util.Providers;
 
 import org.junit.Before;
-import org.junit.ClassRule;
+import org.junit.Rule;
 import org.junit.Test;
 
+import java.io.IOException;
 import java.net.SocketTimeoutException;
 
 public class HttpSessionTest {
@@ -56,13 +64,15 @@
 
   private HttpSession httpSession;
 
-  @ClassRule
-  public static WireMockRule wireMockRule = new WireMockRule(0);
+  @Rule
+  public WireMockRule wireMockRule = new WireMockRule(0);
+
+  private Configuration cfg;
 
   @Before
   public void setUp() throws Exception {
     String url = "http://localhost:" + wireMockRule.port();
-    Configuration cfg = mock(Configuration.class);
+    cfg = mock(Configuration.class);
     when(cfg.getUser()).thenReturn("user");
     when(cfg.getPassword()).thenReturn("pass");
     when(cfg.getMaxTries()).thenReturn(MAX_TRIES);
@@ -74,8 +84,7 @@
     when(peerInfo.getDirectUrl()).thenReturn(url);
     httpSession = new HttpSession(
         new HttpClientProvider(cfg).get(),
-        Providers.of(peerInfo));
-    wireMockRule.resetRequests();
+        Providers.of(Optional.of(peerInfo)));
   }
 
   @Test
@@ -158,4 +167,18 @@
 
     assertThat(httpSession.post(ENDPOINT).isSuccessful()).isFalse();
   }
+
+  @Test
+  public void testNoRequestWhenPeerInfoUnknown() throws IOException {
+    httpSession = new HttpSession(
+        new HttpClientProvider(cfg).get(),
+        Providers.of(Optional.<PeerInfo> absent()));
+    try {
+      httpSession.post(ENDPOINT);
+      fail("Expected PeerInfoNotAvailableException");
+    } catch (PeerInfoNotAvailableException e) {
+      // good
+    }
+    verify(exactly(0), anyRequestedFor(anyUrl()));
+  }
 }