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..ee6cd59 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,35 @@
package com.googlesource.gerrit.plugins.webhooks;
+import java.util.Collections;
+import java.util.Map;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Optional;
import com.google.gerrit.server.events.ProjectEvent;
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.fromNullable(headers).or(Collections.<String, String>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 14c2edf..6d9bc6b 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/webhooks/HttpSession.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/webhooks/HttpSession.java
@@ -16,6 +16,7 @@
import java.io.IOException;
import java.nio.charset.StandardCharsets;
+import java.util.Map.Entry;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
@@ -33,10 +34,13 @@
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));
+ for (Entry<String, String> header : request.headers.entrySet()) {
+ post.addHeader(header.getKey(), header.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 2a8df46..1bd8d6c 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/webhooks/PostTask.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/webhooks/PostTask.java
@@ -23,7 +23,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.base.Strings;
+import com.google.common.base.Optional;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.gerrit.server.events.ProjectEvent;
@@ -43,7 +43,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
@@ -57,9 +57,9 @@
this.session = session;
this.cfg = cfg;
this.url = remote.getUrl();
- this.body = Suppliers.memoize(new Supplier<String>() {
+ this.processor = Suppliers.memoize(new Supplier<Optional<EventProcessor.Request>>() {
@Override
- public String get() {
+ public Optional<EventProcessor.Request> get() {
return processor.process(event, remote);
}
});
@@ -76,14 +76,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();
@@ -116,6 +116,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..5303180 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
@@ -14,6 +14,7 @@
package com.googlesource.gerrit.plugins.webhooks.processors;
+import com.google.common.base.Optional;
import com.google.common.base.Strings;
import com.google.gerrit.server.events.ProjectEvent;
import com.googlesource.gerrit.plugins.webhooks.EventProcessor;
@@ -21,7 +22,7 @@
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..bf67ce9 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
@@ -14,11 +14,13 @@
package com.googlesource.gerrit.plugins.webhooks.processors;
+import com.google.common.base.Optional;
import com.google.common.base.Supplier;
import com.google.gerrit.server.events.ProjectEvent;
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;
public class GerritEventProcessor extends AbstractEventProcessor {
@@ -26,7 +28,7 @@
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 6acd767..1f0cf45 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/webhooks/PostTaskTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/webhooks/PostTaskTest.java
@@ -20,6 +20,7 @@
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
+import com.google.common.base.Optional;
import com.google.gerrit.server.events.ProjectCreatedEvent;
import java.io.IOException;
import java.util.concurrent.ScheduledThreadPoolExecutor;
@@ -41,7 +42,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;
@@ -65,6 +65,8 @@
@Mock
private EventProcessor processor;
+ @Mock private EventProcessor.Request content;
+
private PostTask task;
@Before
@@ -72,13 +74,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.<EventProcessor.Request>absent());
task.run();
verifyZeroInteractions(session);
verifyZeroInteractions(executor);
@@ -86,35 +88,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>() {
@Override
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 d461487..eee004a 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
@@ -23,11 +23,13 @@
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
+import com.google.common.base.Optional;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.Project.NameKey;
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;
@RunWith(MockitoJUnitRunner.class)
@@ -86,9 +88,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.absent();
}
}
}