Extract AuditWriter and make the plugin testable

Refactoring the way that audit messages are generated
and start creating the overall infrastructure to make
the plugin testable automatically at build time.

Change-Id: I00198eb94c8a391e6e1675b142d8a8d1f6435f9e
diff --git a/BUILD b/BUILD
index f75e83a..669b735 100644
--- a/BUILD
+++ b/BUILD
@@ -12,9 +12,19 @@
     manifest_entries = [
         "Gerrit-PluginName: audit-sl4j",
         "Gerrit-ReloadMode: reload",
+        "Gerrit-Module: com.googlesource.gerrit.plugins.auditsl4j.LoggerAudit$Module",
         "Implementation-Title: Gerrit Audit provider for SLF4J",
         "Implementation-URL: https://gerrit.googlesource.com/plugins/audit-sl4j/",
     ],
     resources = glob(["src/main/resources/**/*"]),
     deps = [ ],
 )
+
+junit_tests(
+    name = "audit_sl4j_tests",
+    srcs = glob(["src/test/java/**/*.java"]),
+    visibility = ["//visibility:public"],
+    deps = PLUGIN_TEST_DEPS + PLUGIN_DEPS + [
+        ":audit-sl4j__plugin",
+    ],
+)
diff --git a/src/main/java/com/googlesource/gerrit/plugins/auditsl4j/AuditWriter.java b/src/main/java/com/googlesource/gerrit/plugins/auditsl4j/AuditWriter.java
new file mode 100644
index 0000000..32866a0
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/auditsl4j/AuditWriter.java
@@ -0,0 +1,23 @@
+// 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.auditsl4j;
+
+import com.google.inject.ImplementedBy;
+
+@ImplementedBy(AuditWriterToLogger.class)
+public interface AuditWriter {
+
+  void write(String msg);
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/auditsl4j/AuditWriterToLogger.java b/src/main/java/com/googlesource/gerrit/plugins/auditsl4j/AuditWriterToLogger.java
new file mode 100644
index 0000000..51d4629
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/auditsl4j/AuditWriterToLogger.java
@@ -0,0 +1,27 @@
+// 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.auditsl4j;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AuditWriterToLogger implements AuditWriter {
+  private static final Logger log = LoggerFactory.getLogger(LoggerAudit.AUDIT_LOGGER_NAME);
+
+  @Override
+  public void write(String auditBody) {
+    log.info(auditBody);
+  }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/auditsl4j/LoggerAudit.java b/src/main/java/com/googlesource/gerrit/plugins/auditsl4j/LoggerAudit.java
index 1a0d3c9..bca501e 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/auditsl4j/LoggerAudit.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/auditsl4j/LoggerAudit.java
@@ -17,7 +17,9 @@
 import com.google.common.collect.Multimap;
 import com.google.gerrit.audit.AuditEvent;
 import com.google.gerrit.audit.AuditListener;
-import com.google.gerrit.extensions.annotations.Listen;
+import com.google.gerrit.extensions.registration.DynamicSet;
+import com.google.inject.AbstractModule;
+import com.google.inject.Inject;
 import com.google.inject.Singleton;
 import java.text.SimpleDateFormat;
 import java.util.Collection;
@@ -27,14 +29,13 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
-@Listen
 @Singleton
 public class LoggerAudit implements AuditListener {
-  private static final Logger log = LoggerFactory.getLogger(LoggerAudit.class);
   private final SimpleDateFormat dateFmt = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss.SSSS");
+  private final AuditWriter auditWriter;
+
+  public static final String AUDIT_LOGGER_NAME = LoggerAudit.class.getName();
 
   @SuppressWarnings("serial")
   private static final Map<Class<?>, AuditFormatter<?>> AUDIT_FORMATTERS =
@@ -48,14 +49,27 @@
             }
           });
 
-  static {
-    log.info(
+  @Inject
+  LoggerAudit(AuditWriter auditWriter) {
+    this.auditWriter = auditWriter;
+    writeHeaders(auditWriter);
+  }
+
+  private void writeHeaders(AuditWriter auditWriter) {
+    auditWriter.write(
         "EventId | EventTS | SessionId | User | Protocol data | Action | Parameters | Result | StartTS | Elapsed");
   }
 
+  public static class Module extends AbstractModule {
+    @Override
+    protected void configure() {
+      DynamicSet.bind(binder(), AuditListener.class).to(LoggerAudit.class);
+    }
+  }
+
   @Override
   public void onAuditableAction(AuditEvent action) {
-    log.info(getFormattedAudit(action));
+    auditWriter.write(getFormattedAudit(action));
   }
 
   private String getFormattedAudit(AuditEvent action) {
diff --git a/src/test/java/com/googlesource/gerrit/plugins/auditsl4j/LoggerAuditTest.java b/src/test/java/com/googlesource/gerrit/plugins/auditsl4j/LoggerAuditTest.java
new file mode 100644
index 0000000..19a86e9
--- /dev/null
+++ b/src/test/java/com/googlesource/gerrit/plugins/auditsl4j/LoggerAuditTest.java
@@ -0,0 +1,69 @@
+// 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.auditsl4j;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.gerrit.acceptance.LightweightPluginDaemonTest;
+import com.google.gerrit.acceptance.TestPlugin;
+import com.google.gerrit.common.Version;
+import com.google.gerrit.server.config.CanonicalWebUrl;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.http.client.fluent.Request;
+import org.junit.Test;
+
+@TestPlugin(
+    name = "audit-sl4j",
+    sysModule = "com.googlesource.gerrit.plugins.auditsl4j.LoggerAuditTest$Module")
+public class LoggerAuditTest extends LightweightPluginDaemonTest {
+
+  @Inject @CanonicalWebUrl private String webUrl;
+
+  public static class Module extends LoggerAudit.Module {
+
+    @Override
+    protected void configure() {
+      bind(AuditWriter.class).to(AuditWriterToStringList.class);
+      super.configure();
+    }
+  }
+
+  @Singleton
+  public static class AuditWriterToStringList implements AuditWriter {
+    public final List<String> strings = new ArrayList<>();
+
+    @Override
+    public void write(String msg) {
+      strings.add(msg);
+    }
+  }
+
+  @Test
+  public void testHttpAudit() throws Exception {
+    AuditWriterToStringList auditStrings = getPluginInstance(AuditWriterToStringList.class);
+
+    Request.Get(webUrl + "config/server/version").execute().returnResponse();
+
+    assertThat(auditStrings.strings).hasSize(2);
+    assertThat(auditStrings.strings.get(1)).contains(Version.getVersion());
+  }
+
+  private <T> T getPluginInstance(Class<T> clazz) {
+    return plugin.getSysInjector().getInstance(clazz);
+  }
+}