Add headers to EventProcessor
Some webhooks require additional information as part of request headers
e.g. GitHub event type is provided in header:
X-GitHub-Event: push.
This patch extends EventProcessor processing result with headers and
wraps it into Request class.
Change-Id: I6eb42092c663bce475a52c0aa4f30ce3163399aa
Signed-off-by: Jacek Centkowski <jcentkowski@collab.net>
diff --git a/src/main/java/com/googlesource/gerrit/plugins/webhooks/EventProcessor.java b/src/main/java/com/googlesource/gerrit/plugins/webhooks/EventProcessor.java
index 866df37..1d52300 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/webhooks/EventProcessor.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/webhooks/EventProcessor.java
@@ -14,8 +14,31 @@
package com.googlesource.gerrit.plugins.webhooks;
+import com.google.common.base.MoreObjects;
import com.google.gerrit.server.events.ProjectEvent;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Optional;
public interface EventProcessor {
- String process(ProjectEvent event, RemoteConfig remote);
+ public class Request {
+ public final String body;
+ public final Map<String, String> headers;
+
+ public Request(String body) {
+ this(body, null);
+ }
+
+ public Request(String body, Map<String, String> headers) {
+ this.body = body;
+ this.headers = Optional.ofNullable(headers).orElse(Collections.emptyMap());
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this).add("headers", headers).add("body", body).toString();
+ }
+ }
+
+ Optional<Request> process(ProjectEvent event, RemoteConfig remote);
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/webhooks/HttpSession.java b/src/main/java/com/googlesource/gerrit/plugins/webhooks/HttpSession.java
index 8809f4d..f6b2b93 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/webhooks/HttpSession.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/webhooks/HttpSession.java
@@ -31,10 +31,18 @@
this.httpClient = httpClient;
}
- HttpResult post(String endpoint, String content) throws IOException {
+ HttpResult post(String endpoint, EventProcessor.Request request) throws IOException {
HttpPost post = new HttpPost(endpoint);
post.addHeader("Content-Type", MediaType.JSON_UTF_8.toString());
- post.setEntity(new StringEntity(content, StandardCharsets.UTF_8));
+ request
+ .headers
+ .entrySet()
+ .stream()
+ .forEach(
+ e -> {
+ post.addHeader(e.getKey(), e.getValue());
+ });
+ post.setEntity(new StringEntity(request.body, StandardCharsets.UTF_8));
return httpClient.execute(post, new HttpResponseHandler());
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/webhooks/PostTask.java b/src/main/java/com/googlesource/gerrit/plugins/webhooks/PostTask.java
index abdaf38..fbc386a 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/webhooks/PostTask.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/webhooks/PostTask.java
@@ -14,7 +14,6 @@
package com.googlesource.gerrit.plugins.webhooks;
-import com.google.common.base.Strings;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.gerrit.server.events.ProjectEvent;
@@ -22,6 +21,7 @@
import com.google.inject.assistedinject.AssistedInject;
import com.googlesource.gerrit.plugins.webhooks.HttpResponseHandler.HttpResult;
import java.io.IOException;
+import java.util.Optional;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLException;
@@ -39,7 +39,7 @@
private final HttpSession session;
private final Configuration cfg;
private final String url;
- private final Supplier<String> body;
+ private final Supplier<Optional<EventProcessor.Request>> processor;
private int execCnt;
@AssistedInject
@@ -54,7 +54,7 @@
this.session = session;
this.cfg = cfg;
this.url = remote.getUrl();
- this.body = Suppliers.memoize(() -> processor.process(event, remote));
+ this.processor = Suppliers.memoize(() -> processor.process(event, remote));
}
void schedule() {
@@ -68,14 +68,14 @@
@Override
public void run() {
try {
- String content = body.get();
- if (Strings.isNullOrEmpty(content)) {
+ Optional<EventProcessor.Request> content = processor.get();
+ if (!content.isPresent()) {
log.debug("No content. Webhook [{}] skipped.", url);
return;
}
execCnt++;
- HttpResult result = session.post(url, content);
+ HttpResult result = session.post(url, content.get());
if (!result.successful && execCnt < cfg.getMaxTries()) {
logRetry(result.message);
reschedule();
@@ -108,6 +108,7 @@
@Override
public String toString() {
- return body.get();
+ Optional<EventProcessor.Request> content = processor.get();
+ return content.isPresent() ? content.get().toString() : "no content";
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/webhooks/processors/AbstractEventProcessor.java b/src/main/java/com/googlesource/gerrit/plugins/webhooks/processors/AbstractEventProcessor.java
index 8c727e0..54ee74d 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/webhooks/processors/AbstractEventProcessor.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/webhooks/processors/AbstractEventProcessor.java
@@ -18,10 +18,11 @@
import com.google.gerrit.server.events.ProjectEvent;
import com.googlesource.gerrit.plugins.webhooks.EventProcessor;
import com.googlesource.gerrit.plugins.webhooks.RemoteConfig;
+import java.util.Optional;
public abstract class AbstractEventProcessor implements EventProcessor {
@Override
- public String process(ProjectEvent event, RemoteConfig remote) {
+ public Optional<EventProcessor.Request> process(ProjectEvent event, RemoteConfig remote) {
if (!shouldProcess(event, remote)) {
return null;
}
@@ -29,7 +30,8 @@
return doProcess(event, remote);
}
- protected abstract String doProcess(ProjectEvent event, RemoteConfig remote);
+ protected abstract Optional<EventProcessor.Request> doProcess(
+ ProjectEvent event, RemoteConfig remote);
protected boolean shouldProcess(ProjectEvent event, RemoteConfig remote) {
String[] wantedEvents = remote.getEvents();
diff --git a/src/main/java/com/googlesource/gerrit/plugins/webhooks/processors/GerritEventProcessor.java b/src/main/java/com/googlesource/gerrit/plugins/webhooks/processors/GerritEventProcessor.java
index b8532b4..e9c373c 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/webhooks/processors/GerritEventProcessor.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/webhooks/processors/GerritEventProcessor.java
@@ -19,14 +19,16 @@
import com.google.gerrit.server.events.SupplierSerializer;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
+import com.googlesource.gerrit.plugins.webhooks.EventProcessor;
import com.googlesource.gerrit.plugins.webhooks.RemoteConfig;
+import java.util.Optional;
public class GerritEventProcessor extends AbstractEventProcessor {
private static Gson GSON =
new GsonBuilder().registerTypeAdapter(Supplier.class, new SupplierSerializer()).create();
@Override
- public String doProcess(ProjectEvent event, RemoteConfig remote) {
- return GSON.toJson(event);
+ public Optional<EventProcessor.Request> doProcess(ProjectEvent event, RemoteConfig remote) {
+ return Optional.of(new EventProcessor.Request(GSON.toJson(event)));
}
}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/webhooks/PostTaskTest.java b/src/test/java/com/googlesource/gerrit/plugins/webhooks/PostTaskTest.java
index 043828f..f52969a 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/webhooks/PostTaskTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/webhooks/PostTaskTest.java
@@ -23,6 +23,7 @@
import com.google.gerrit.server.events.ProjectCreatedEvent;
import com.googlesource.gerrit.plugins.webhooks.HttpResponseHandler.HttpResult;
import java.io.IOException;
+import java.util.Optional;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLException;
@@ -38,7 +39,6 @@
public class PostTaskTest {
private static final String WEBHOOK_URL = "webhook-url";
- private static final String BODY = "body";
private static final HttpResult OK_RESULT = new HttpResult(true, "");
private static final HttpResult ERR_RESULT = new HttpResult(false, "");
private static final int RETRY_INTERVAL = 100;
@@ -56,6 +56,8 @@
@Mock private EventProcessor processor;
+ @Mock private EventProcessor.Request content;
+
private PostTask task;
@Before
@@ -63,13 +65,13 @@
when(cfg.getRetryInterval()).thenReturn(RETRY_INTERVAL);
when(cfg.getMaxTries()).thenReturn(MAX_TRIES);
when(remote.getUrl()).thenReturn(WEBHOOK_URL);
- when(processor.process(eq(projectCreated), eq(remote))).thenReturn(BODY);
+ when(processor.process(eq(projectCreated), eq(remote))).thenReturn(Optional.of(content));
task = new PostTask(executor, session, cfg, processor, projectCreated, remote);
}
@Test
public void noScheduleOnEmptyBody() throws Exception {
- when(processor.process(eq(projectCreated), eq(remote))).thenReturn(null);
+ when(processor.process(eq(projectCreated), eq(remote))).thenReturn(Optional.empty());
task.run();
verifyZeroInteractions(session);
verifyZeroInteractions(executor);
@@ -77,35 +79,35 @@
@Test
public void noRescheduleOnSuccess() throws IOException {
- when(session.post(WEBHOOK_URL, BODY)).thenReturn(OK_RESULT);
+ when(session.post(eq(WEBHOOK_URL), eq(content))).thenReturn(OK_RESULT);
task.run();
verifyZeroInteractions(executor);
}
@Test
public void noRescheduleOnNonRecoverableException() throws IOException {
- when(session.post(WEBHOOK_URL, BODY)).thenThrow(SSLException.class);
+ when(session.post(eq(WEBHOOK_URL), eq(content))).thenThrow(SSLException.class);
task.run();
verifyZeroInteractions(executor);
}
@Test
public void rescheduleOnError() throws IOException {
- when(session.post(WEBHOOK_URL, BODY)).thenReturn(ERR_RESULT);
+ when(session.post(eq(WEBHOOK_URL), eq(content))).thenReturn(ERR_RESULT);
task.run();
verify(executor, times(1)).schedule(task, RETRY_INTERVAL, TimeUnit.MILLISECONDS);
}
@Test
public void rescheduleOnRecoverableException() throws IOException {
- when(session.post(WEBHOOK_URL, BODY)).thenThrow(IOException.class);
+ when(session.post(eq(WEBHOOK_URL), eq(content))).thenThrow(IOException.class);
task.run();
verify(executor, times(1)).schedule(task, RETRY_INTERVAL, TimeUnit.MILLISECONDS);
}
@Test
public void keepReschedulingMaxTriesTimes() throws IOException {
- when(session.post(WEBHOOK_URL, BODY)).thenThrow(IOException.class);
+ when(session.post(eq(WEBHOOK_URL), eq(content))).thenThrow(IOException.class);
when(executor.schedule(task, RETRY_INTERVAL, TimeUnit.MILLISECONDS))
.then(
new Answer<Void>() {
diff --git a/src/test/java/com/googlesource/gerrit/plugins/webhooks/processors/AbstractEventProcessorTest.java b/src/test/java/com/googlesource/gerrit/plugins/webhooks/processors/AbstractEventProcessorTest.java
index e8c3391..f4c2ba0 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/webhooks/processors/AbstractEventProcessorTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/webhooks/processors/AbstractEventProcessorTest.java
@@ -22,7 +22,9 @@
import com.google.gerrit.server.events.ProjectCreatedEvent;
import com.google.gerrit.server.events.ProjectEvent;
import com.google.gerrit.server.events.RefUpdatedEvent;
+import com.googlesource.gerrit.plugins.webhooks.EventProcessor;
import com.googlesource.gerrit.plugins.webhooks.RemoteConfig;
+import java.util.Optional;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -85,9 +87,9 @@
private class TestEventProcessor extends AbstractEventProcessor {
@Override
- public String doProcess(ProjectEvent event, RemoteConfig remote) {
+ public Optional<EventProcessor.Request> doProcess(ProjectEvent event, RemoteConfig remote) {
// do nothing
- return null;
+ return Optional.empty();
}
}
}