Extract Jira configuration

Instead of reading the plugin configuration in the facade, extract the
handling of the configuration to its own class (with its corresponding
tests).

Besides keeping the separation of concerns between classes, this helps
implementing multi Jira server capabilities, which is done in a follow
up commit.

Change-Id: I63a0b997d241fb520715c29bc8bd46e3907168a9
diff --git a/BUILD b/BUILD
index d6afabb..c22e753 100644
--- a/BUILD
+++ b/BUILD
@@ -1,4 +1,10 @@
-load("//tools/bzl:plugin.bzl", "gerrit_plugin")
+load("//tools/bzl:junit.bzl", "junit_tests")
+load(
+    "//tools/bzl:plugin.bzl",
+    "gerrit_plugin",
+    "PLUGIN_DEPS",
+    "PLUGIN_TEST_DEPS",
+)
 
 gerrit_plugin(
     name = "its-jira",
@@ -17,3 +23,25 @@
     ],
 )
 
+junit_tests(
+    name = "its_jira_tests",
+    testonly = 1,
+    srcs = glob(
+        ["src/test/java/**/*.java"],
+    ),
+    tags = ["its-jira"],
+    deps = [
+        "its-jira__plugin_test_deps",
+    ],
+)
+
+java_library(
+    name = "its-jira__plugin_test_deps",
+    testonly = 1,
+    visibility = ["//visibility:public"],
+    exports = PLUGIN_DEPS + PLUGIN_TEST_DEPS + [
+        ":its-jira__plugin",
+        "//plugins/its-base",
+        "@mockito//jar",
+    ],
+)
diff --git a/external_plugin_deps.bzl b/external_plugin_deps.bzl
new file mode 100644
index 0000000..2709df3
--- /dev/null
+++ b/external_plugin_deps.bzl
@@ -0,0 +1,25 @@
+load("//tools/bzl:maven_jar.bzl", "maven_jar")
+
+def external_plugin_deps():
+  maven_jar(
+    name = "mockito",
+    artifact = "org.mockito:mockito-core:2.13.0",
+    sha1 = "8e372943974e4a121fb8617baced8ebfe46d54f0",
+    deps = [
+      '@byte-buddy//jar',
+      '@objenesis//jar',
+    ],
+  )
+
+  maven_jar(
+    name = "byte-buddy",
+    artifact = "net.bytebuddy:byte-buddy:1.7.9",
+    sha1 = "51218a01a882c04d0aba8c028179cce488bbcb58",
+  )
+
+  maven_jar(
+    name = "objenesis",
+    artifact = "org.objenesis:objenesis:2.6",
+    sha1 = "639033469776fd37c08358c6b92a4761feb2af4b",
+  )
+
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraConfig.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraConfig.java
new file mode 100644
index 0000000..b757b65
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraConfig.java
@@ -0,0 +1,79 @@
+// 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.its.jira;
+
+import static java.lang.String.format;
+
+import com.google.gerrit.extensions.annotations.PluginName;
+import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import org.eclipse.jgit.lib.Config;
+
+/** The JIRA plugin configuration as read from Gerrit config. */
+@Singleton
+public class JiraConfig {
+  static final String ERROR_MSG = "Unable to load plugin %s. Cause: Wrong configuration ";
+  static final String GERRIT_CONFIG_URL = "url";
+  static final String GERRIT_CONFIG_USERNAME = "username";
+  static final String GERRIT_CONFIG_PASSWORD = "password";
+
+  private final String jiraUrl;
+  private final String jiraUsername;
+  private final String jiraPassword;
+
+  /**
+   * Builds an JiraConfig.
+   *
+   * @param config the gerrit server config
+   * @param pluginName the name of this very plugin
+   */
+  @Inject
+  JiraConfig(@GerritServerConfig Config config, @PluginName String pluginName) {
+    jiraUrl = config.getString(pluginName, null, GERRIT_CONFIG_URL);
+    jiraUsername = config.getString(pluginName, null, GERRIT_CONFIG_USERNAME);
+    jiraPassword = config.getString(pluginName, null, GERRIT_CONFIG_PASSWORD);
+    if (jiraUrl == null || jiraUsername == null || jiraPassword == null) {
+      throw new RuntimeException(format(ERROR_MSG, pluginName));
+    }
+  }
+
+  /**
+   * The Jira url to connect to.
+   *
+   * @return the jira url
+   */
+  public String getJiraUrl() {
+    return jiraUrl;
+  }
+
+  /**
+   * The username to connect to a Jira server.
+   *
+   * @return the username
+   */
+  public String getUsername() {
+    return jiraUsername;
+  }
+
+  /**
+   * The password to connect to a Jira server.
+   *
+   * @return the password
+   */
+  public String getPassword() {
+    return jiraPassword;
+  }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraItsFacade.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraItsFacade.java
index 7e44ffc..790cefd 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraItsFacade.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraItsFacade.java
@@ -14,8 +14,6 @@
 
 package com.googlesource.gerrit.plugins.its.jira;
 
-import com.google.gerrit.extensions.annotations.PluginName;
-import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.inject.Inject;
 import com.googlesource.gerrit.plugins.its.base.its.InvalidTransitionException;
 import com.googlesource.gerrit.plugins.its.base.its.ItsFacade;
@@ -25,30 +23,23 @@
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.concurrent.Callable;
-import org.eclipse.jgit.lib.Config;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class JiraItsFacade implements ItsFacade {
 
-  private static final String GERRIT_CONFIG_USERNAME = "username";
-  private static final String GERRIT_CONFIG_PASSWORD = "password";
-  private static final String GERRIT_CONFIG_URL = "url";
-
   private static final int MAX_ATTEMPTS = 3;
 
   private Logger log = LoggerFactory.getLogger(JiraItsFacade.class);
 
-  private final String pluginName;
-  private Config gerritConfig;
+  private final JiraConfig jiraConfig;
 
   private JiraClient client;
 
   @Inject
-  public JiraItsFacade(@PluginName String pluginName, @GerritServerConfig Config cfg) {
-    this.pluginName = pluginName;
+  public JiraItsFacade(JiraConfig jiraConfig) {
+    this.jiraConfig = jiraConfig;
     try {
-      this.gerritConfig = cfg;
       JiraServerInfo info = client().sysInfo();
       log.info(
           "Connected to JIRA at {}, reported version is {}", info.getBaseUri(), info.getVersion());
@@ -120,9 +111,11 @@
 
   private JiraClient client() throws MalformedURLException {
     if (client == null) {
-      log.debug("Connecting to jira at {}", getUrl());
-      client = new JiraClient(getUrl(), getUsername(), getPassword());
-      log.debug("Authenticating as User {}", getUsername());
+      log.debug("Connecting to jira at {}", jiraConfig.getJiraUrl());
+      client =
+          new JiraClient(
+              jiraConfig.getJiraUrl(), jiraConfig.getUsername(), jiraConfig.getPassword());
+      log.debug("Authenticating as User {}", jiraConfig.getUsername());
     }
     return client;
   }
@@ -148,18 +141,6 @@
     return className.startsWith("java.net");
   }
 
-  private String getPassword() {
-    return gerritConfig.getString(pluginName, null, GERRIT_CONFIG_PASSWORD);
-  }
-
-  private String getUsername() {
-    return gerritConfig.getString(pluginName, null, GERRIT_CONFIG_USERNAME);
-  }
-
-  private String getUrl() {
-    return gerritConfig.getString(pluginName, null, GERRIT_CONFIG_URL);
-  }
-
   @Override
   public String createLinkForWebui(String url, String text) {
     return "[" + text + "|" + url + "]";
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraModule.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraModule.java
index 2b1119e..ac3889a 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraModule.java
@@ -47,7 +47,7 @@
   protected void configure() {
     if (gerritConfig.getString(pluginName, null, "url") != null) {
       LOG.info("JIRA is configured as ITS");
-      bind(ItsFacade.class).toInstance(new JiraItsFacade(pluginName, gerritConfig));
+      bind(ItsFacade.class).to(JiraItsFacade.class).asEagerSingleton();
 
       install(new ItsHookModule(pluginName, pluginCfgFactory));
     }
diff --git a/src/main/resources/Documentation/build.md b/src/main/resources/Documentation/build.md
index 1235321..4e44633 100644
--- a/src/main/resources/Documentation/build.md
+++ b/src/main/resources/Documentation/build.md
@@ -7,6 +7,14 @@
 [plugins/its-base](https://gerrit-review.googlesource.com/#/admin/projects/plugins/its-base)
 to the `plugins` directory of Gerrit's source tree.
 
+Put the external dependency Bazel build file into the Gerrit plugins directory,
+replacing the existing empty one.
+
+```
+  cd gerrit/plugins
+  ln -sf @PLUGIN@/external_plugin_deps.bzl .
+```
+
 Then issue
 
 ```
@@ -22,13 +30,20 @@
 ```
 
 This project can be imported into the Eclipse IDE.
-Add the plugin name to the `CUSTOM_PLUGINS` set in
-Gerrit core in `tools/bzl/plugins.bzl`, and execute:
+Add the plugin name to the `CUSTOM_PLUGINS` and
+`CUSTOM_PLUGINS_TEST_DEPS` sets in the file
+`<gerrit_source_code>/tools/bzl/plugins.bzl` and execute:
 
 ```
   ./tools/eclipse/project.py
 ```
 
+To execute the tests run:
+
+```
+  bazel test plugins/@PLUGIN@:its_jira_tests
+```
+
 [Back to @PLUGIN@ documentation index][index]
 
 [index]: index.html
\ No newline at end of file
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/jira/JiraConfigTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/jira/JiraConfigTest.java
new file mode 100644
index 0000000..f7f5a40
--- /dev/null
+++ b/src/test/java/com/googlesource/gerrit/plugins/its/jira/JiraConfigTest.java
@@ -0,0 +1,63 @@
+// Copyright (C) 2018 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.its.jira;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.googlesource.gerrit.plugins.its.jira.JiraConfig.ERROR_MSG;
+import static com.googlesource.gerrit.plugins.its.jira.JiraConfig.GERRIT_CONFIG_PASSWORD;
+import static com.googlesource.gerrit.plugins.its.jira.JiraConfig.GERRIT_CONFIG_URL;
+import static com.googlesource.gerrit.plugins.its.jira.JiraConfig.GERRIT_CONFIG_USERNAME;
+import static java.lang.String.format;
+import static org.mockito.Mockito.when;
+
+import org.eclipse.jgit.lib.Config;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class JiraConfigTest {
+
+  private static final String PASS = "pass";
+  private static final String URL = "http://jira_example.com";
+  private static final String USER = "user";
+  private static final String PLUGIN_NAME = "its-jira";
+
+  @Rule public ExpectedException thrown = ExpectedException.none();
+  @Mock private Config cfg;
+
+  private JiraConfig jiraConfig;
+
+  @Test
+  public void gerritConfigContainsSaneValues() throws Exception {
+    when(cfg.getString(PLUGIN_NAME, null, GERRIT_CONFIG_URL)).thenReturn(URL);
+    when(cfg.getString(PLUGIN_NAME, null, GERRIT_CONFIG_USERNAME)).thenReturn(USER);
+    when(cfg.getString(PLUGIN_NAME, null, GERRIT_CONFIG_PASSWORD)).thenReturn(PASS);
+    jiraConfig = new JiraConfig(cfg, PLUGIN_NAME);
+    assertThat(jiraConfig.getUsername()).isEqualTo(USER);
+    assertThat(jiraConfig.getPassword()).isEqualTo(PASS);
+    assertThat(jiraConfig.getJiraUrl()).isEqualTo(URL);
+  }
+
+  @Test
+  public void gerritConfigContainsNullValues() throws Exception {
+    thrown.expect(RuntimeException.class);
+    thrown.expectMessage(format(ERROR_MSG, PLUGIN_NAME));
+    jiraConfig = new JiraConfig(cfg, PLUGIN_NAME);
+  }
+}