From 4a5c1a11d1ddf541adc4dd8e6f4ee57a3d0ec24e Mon Sep 17 00:00:00 2001 From: Nikita Tkachenko Date: Tue, 19 Nov 2024 14:53:26 +0100 Subject: [PATCH] Address review comments --- .../clients/CompressedBatchSender.java | 10 +- .../datadog/clients/DatadogAgentClient.java | 16 +-- .../datadog/clients/DatadogApiClient.java | 29 ++-- .../datadog/clients/JsonPayloadSender.java | 1 - .../plugins/datadog/clients/SimpleSender.java | 10 +- .../flare/ConnectivityChecksFlare.java | 2 +- .../datadog/flare/DatadogConfigFlare.java | 2 +- .../datadog/flare/DatadogEnvVarsFlare.java | 2 +- .../datadog/flare/ExceptionsFlare.java | 2 +- .../datadog/flare/FlareContributor.java | 13 ++ .../datadog/flare/JenkinsLogsFlare.java | 2 +- .../plugins/datadog/flare/JfrFlare.java | 2 +- .../datadog/flare/PluginLogsFlare.java | 2 +- .../datadog/flare/RuntimeInfoFlare.java | 2 +- .../datadog/flare/ThreadDumpFlare.java | 2 +- .../datadog/flare/WritersHealthFlare.java | 2 +- .../plugins/datadog/logs/DatadogWriter.java | 4 +- .../datadog/logs/LogWriteStrategy.java | 5 +- .../datadog/logs/LogWriterFactory.java | 5 +- .../clients/CompressedBatchSenderTest.java | 131 ++++++++++++++++++ .../datadog/clients/DatadogClientStub.java | 7 +- 21 files changed, 196 insertions(+), 55 deletions(-) create mode 100644 src/test/java/org/datadog/jenkins/plugins/datadog/clients/CompressedBatchSenderTest.java diff --git a/src/main/java/org/datadog/jenkins/plugins/datadog/clients/CompressedBatchSender.java b/src/main/java/org/datadog/jenkins/plugins/datadog/clients/CompressedBatchSender.java index 022cd052..23d99a0f 100644 --- a/src/main/java/org/datadog/jenkins/plugins/datadog/clients/CompressedBatchSender.java +++ b/src/main/java/org/datadog/jenkins/plugins/datadog/clients/CompressedBatchSender.java @@ -1,5 +1,6 @@ package org.datadog.jenkins.plugins.datadog.clients; +import net.sf.json.JSONObject; import java.io.ByteArrayOutputStream; import java.nio.charset.StandardCharsets; import java.util.Collection; @@ -20,18 +21,18 @@ public class CompressedBatchSender implements JsonPayloadSender { private final String url; private final Map headers; private final int batchLimitBytes; - private final Function payloadToString; + private final Function payloadToJson; public CompressedBatchSender(HttpClient httpClient, String url, Map headers, int batchLimitBytes, - Function payloadToString) { + Function payloadToJson) { this.httpClient = httpClient; this.url = url; this.headers = headers; this.batchLimitBytes = batchLimitBytes; - this.payloadToString = payloadToString; + this.payloadToJson = payloadToJson; } @Override @@ -42,7 +43,8 @@ public void send(Collection payloads) throws Exception { int uncompressedRequestLength = 0; for (T payload : payloads) { - byte[] body = payloadToString.apply(payload).getBytes(StandardCharsets.UTF_8); + JSONObject json = payloadToJson.apply(payload); + byte[] body = json.toString().getBytes(StandardCharsets.UTF_8); if (body.length + 2 > batchLimitBytes) { // + 2 is for array beginning and end: [] logger.severe("Dropping a payload because size (" + body.length + ") exceeds the allowed limit of " + batchLimitBytes); continue; diff --git a/src/main/java/org/datadog/jenkins/plugins/datadog/clients/DatadogAgentClient.java b/src/main/java/org/datadog/jenkins/plugins/datadog/clients/DatadogAgentClient.java index 77deb838..22be0603 100644 --- a/src/main/java/org/datadog/jenkins/plugins/datadog/clients/DatadogAgentClient.java +++ b/src/main/java/org/datadog/jenkins/plugins/datadog/clients/DatadogAgentClient.java @@ -303,7 +303,7 @@ private static final class AgentLogWriteStrategy implements LogWriteStrategy { private final String host; private final int port; - private final CircuitBreaker> circuitBreaker; + private final CircuitBreaker> circuitBreaker; private Socket socket; private OutputStream out; @@ -320,17 +320,17 @@ private AgentLogWriteStrategy(String host, int port) { CircuitBreaker.DEFAULT_DELAY_FACTOR); } - public void send(List payloads) { + public void send(List payloads) { circuitBreaker.accept(payloads); } - private void doSend(List payloads) throws Exception { + private void doSend(List payloads) throws Exception { if (socket == null || socket.isClosed() || !socket.isConnected()) { socket = new Socket(host, port); out = new BufferedOutputStream(socket.getOutputStream()); } - for (String payload : payloads) { - out.write(payload.getBytes(StandardCharsets.UTF_8)); + for (net.sf.json.JSONObject payload : payloads) { + out.write(payload.toString().getBytes(StandardCharsets.UTF_8)); out.write(LINE_SEPARATOR); } } @@ -340,7 +340,7 @@ private void handleError(Exception e) { DatadogUtilities.severe(logger, e, "Could not write logs to agent"); } - private void fallback(List payloads) { + private void fallback(List payloads) { // cannot establish connection to agent, do nothing } @@ -381,12 +381,12 @@ public TraceWriteStrategy createTraceWriteStrategy() { "X-Datadog-EVP-Subdomain", "webhook-intake", "DD-CI-PROVIDER-NAME", "jenkins", "Content-Encoding", "gzip"); - payloadSender = new CompressedBatchSender<>(client, url, headers, PAYLOAD_SIZE_LIMIT, p -> p.getJson().toString()); + payloadSender = new CompressedBatchSender<>(client, url, headers, PAYLOAD_SIZE_LIMIT, p -> p.getJson()); } else { Map headers = Map.of( "X-Datadog-EVP-Subdomain", "webhook-intake", "DD-CI-PROVIDER-NAME", "jenkins"); - payloadSender = new SimpleSender<>(client, url, headers, p -> p.getJson().toString()); + payloadSender = new SimpleSender<>(client, url, headers, p -> p.getJson()); } TraceWriteStrategyImpl evpStrategy = new TraceWriteStrategyImpl(Track.WEBHOOK, payloadSender::send); diff --git a/src/main/java/org/datadog/jenkins/plugins/datadog/clients/DatadogApiClient.java b/src/main/java/org/datadog/jenkins/plugins/datadog/clients/DatadogApiClient.java index f13aad2a..71ce4325 100644 --- a/src/main/java/org/datadog/jenkins/plugins/datadog/clients/DatadogApiClient.java +++ b/src/main/java/org/datadog/jenkins/plugins/datadog/clients/DatadogApiClient.java @@ -157,24 +157,17 @@ public static boolean validateWebhookIntakeConnection(String webhookIntakeUrl, S } public static boolean validateLogIntakeConnection(String logsIntakeUrl, Secret apiKey) { - String payload = "{\"message\":\"[datadog-plugin] Check connection\", " + - "\"ddsource\":\"Jenkins\", \"service\":\"Jenkins\", " + - "\"hostname\":\"" + DatadogUtilities.getHostname(null) + "\"}"; - return postLogs(new HttpClient(HTTP_TIMEOUT_MS), logsIntakeUrl, apiKey, payload); - } - - private static boolean postLogs(HttpClient httpClient, String logIntakeUrl, Secret apiKey, String payload) { - if(payload == null){ - logger.fine("No payload to post"); - return true; - } + HttpClient httpClient = new HttpClient(HTTP_TIMEOUT_MS); Map headers = new HashMap<>(); headers.put("DD-API-KEY", Secret.toString(apiKey)); + String payload = "{\"message\":\"[datadog-plugin] Check connection\", " + + "\"ddsource\":\"Jenkins\", \"service\":\"Jenkins\", " + + "\"hostname\":\"" + DatadogUtilities.getHostname(null) + "\"}"; byte[] body = payload.getBytes(StandardCharsets.UTF_8); try { - httpClient.post(logIntakeUrl, headers, "application/json", body, Function.identity()); + httpClient.post(logsIntakeUrl, headers, "application/json", body, Function.identity()); return true; } catch (Exception e) { DatadogUtilities.severe(logger, e, "Failed to post logs"); @@ -323,13 +316,13 @@ public LogWriteStrategy createLogWriteStrategy() { } private static final class ApiLogWriteStrategy implements LogWriteStrategy { - private final CircuitBreaker> circuitBreaker; + private final CircuitBreaker> circuitBreaker; public ApiLogWriteStrategy(String logIntakeUrl, Secret apiKey, HttpClient httpClient) { Map headers = Map.of( "DD-API-KEY", Secret.toString(apiKey), "Content-Encoding", "gzip"); - JsonPayloadSender payloadSender = new CompressedBatchSender<>( + JsonPayloadSender payloadSender = new CompressedBatchSender<>( httpClient, logIntakeUrl, headers, @@ -346,7 +339,7 @@ public ApiLogWriteStrategy(String logIntakeUrl, Secret apiKey, HttpClient httpCl } @Override - public void send(List logs) { + public void send(List logs) { circuitBreaker.accept(logs); } @@ -354,7 +347,7 @@ private void handleError(Exception e) { DatadogUtilities.severe(logger, e, "Failed to post logs"); } - private void fallback(List payloads) { + private void fallback(List payloads) { // cannot establish connection to API, do nothing } @@ -377,12 +370,12 @@ public TraceWriteStrategy createTraceWriteStrategy() { "DD-API-KEY", Secret.toString(apiKey), "DD-CI-PROVIDER-NAME", "jenkins", "Content-Encoding", "gzip"); - payloadSender = new CompressedBatchSender<>(httpClient, url, headers, PAYLOAD_SIZE_LIMIT, p -> p.getJson().toString()); + payloadSender = new CompressedBatchSender<>(httpClient, url, headers, PAYLOAD_SIZE_LIMIT, p -> p.getJson()); } else { Map headers = Map.of( "DD-API-KEY", Secret.toString(apiKey), "DD-CI-PROVIDER-NAME", "jenkins"); - payloadSender = new SimpleSender<>(httpClient, url, headers, p -> p.getJson().toString()); + payloadSender = new SimpleSender<>(httpClient, url, headers, p -> p.getJson()); } return new TraceWriteStrategyImpl(Track.WEBHOOK, payloadSender::send); diff --git a/src/main/java/org/datadog/jenkins/plugins/datadog/clients/JsonPayloadSender.java b/src/main/java/org/datadog/jenkins/plugins/datadog/clients/JsonPayloadSender.java index c2e6a323..3d2f412d 100644 --- a/src/main/java/org/datadog/jenkins/plugins/datadog/clients/JsonPayloadSender.java +++ b/src/main/java/org/datadog/jenkins/plugins/datadog/clients/JsonPayloadSender.java @@ -1,7 +1,6 @@ package org.datadog.jenkins.plugins.datadog.clients; import java.util.Collection; -import java.util.function.Function; public interface JsonPayloadSender { void send(Collection payloads) throws Exception; diff --git a/src/main/java/org/datadog/jenkins/plugins/datadog/clients/SimpleSender.java b/src/main/java/org/datadog/jenkins/plugins/datadog/clients/SimpleSender.java index 6ce300d4..1b168e3f 100644 --- a/src/main/java/org/datadog/jenkins/plugins/datadog/clients/SimpleSender.java +++ b/src/main/java/org/datadog/jenkins/plugins/datadog/clients/SimpleSender.java @@ -4,28 +4,30 @@ import java.util.Collection; import java.util.Map; import java.util.function.Function; +import net.sf.json.JSONObject; public class SimpleSender implements JsonPayloadSender { private final HttpClient httpClient; private final String url; private final Map headers; - private final Function payloadToString; + private final Function payloadToJson; public SimpleSender(HttpClient httpClient, String url, Map headers, - Function payloadToString) { + Function payloadToJson) { this.httpClient = httpClient; this.url = url; this.headers = headers; - this.payloadToString = payloadToString; + this.payloadToJson = payloadToJson; } @Override public void send(Collection payloads) throws Exception { for (T payload : payloads) { - byte[] body = payloadToString.apply(payload).getBytes(StandardCharsets.UTF_8); + JSONObject json = payloadToJson.apply(payload); + byte[] body = json.toString().getBytes(StandardCharsets.UTF_8); httpClient.postAsynchronously(url, headers, "application/json", body); } } diff --git a/src/main/java/org/datadog/jenkins/plugins/datadog/flare/ConnectivityChecksFlare.java b/src/main/java/org/datadog/jenkins/plugins/datadog/flare/ConnectivityChecksFlare.java index 7e455670..f607c6dc 100644 --- a/src/main/java/org/datadog/jenkins/plugins/datadog/flare/ConnectivityChecksFlare.java +++ b/src/main/java/org/datadog/jenkins/plugins/datadog/flare/ConnectivityChecksFlare.java @@ -17,7 +17,7 @@ public class ConnectivityChecksFlare implements FlareContributor { @Override public int order() { - return 2; + return ORDER.CONNECTIVITY_CHECKS; } @Override diff --git a/src/main/java/org/datadog/jenkins/plugins/datadog/flare/DatadogConfigFlare.java b/src/main/java/org/datadog/jenkins/plugins/datadog/flare/DatadogConfigFlare.java index f2a13911..e941ba25 100644 --- a/src/main/java/org/datadog/jenkins/plugins/datadog/flare/DatadogConfigFlare.java +++ b/src/main/java/org/datadog/jenkins/plugins/datadog/flare/DatadogConfigFlare.java @@ -21,7 +21,7 @@ public class DatadogConfigFlare implements FlareContributor { @Override public int order() { - return 1; + return ORDER.CONFIG; } @Override diff --git a/src/main/java/org/datadog/jenkins/plugins/datadog/flare/DatadogEnvVarsFlare.java b/src/main/java/org/datadog/jenkins/plugins/datadog/flare/DatadogEnvVarsFlare.java index e6582727..e7079d9c 100644 --- a/src/main/java/org/datadog/jenkins/plugins/datadog/flare/DatadogEnvVarsFlare.java +++ b/src/main/java/org/datadog/jenkins/plugins/datadog/flare/DatadogEnvVarsFlare.java @@ -12,7 +12,7 @@ public class DatadogEnvVarsFlare implements FlareContributor { @Override public int order() { - return 3; + return ORDER.ENV_VARS; } @Override diff --git a/src/main/java/org/datadog/jenkins/plugins/datadog/flare/ExceptionsFlare.java b/src/main/java/org/datadog/jenkins/plugins/datadog/flare/ExceptionsFlare.java index 372fe566..0bab729c 100644 --- a/src/main/java/org/datadog/jenkins/plugins/datadog/flare/ExceptionsFlare.java +++ b/src/main/java/org/datadog/jenkins/plugins/datadog/flare/ExceptionsFlare.java @@ -18,7 +18,7 @@ public class ExceptionsFlare implements FlareContributor { @Override public int order() { - return 4; + return ORDER.EXCEPTIONS; } @Override diff --git a/src/main/java/org/datadog/jenkins/plugins/datadog/flare/FlareContributor.java b/src/main/java/org/datadog/jenkins/plugins/datadog/flare/FlareContributor.java index fa10fe53..0accfe31 100644 --- a/src/main/java/org/datadog/jenkins/plugins/datadog/flare/FlareContributor.java +++ b/src/main/java/org/datadog/jenkins/plugins/datadog/flare/FlareContributor.java @@ -4,6 +4,19 @@ public interface FlareContributor { + interface ORDER { + int RUNTIME_INFO = 0; + int CONFIG = 1; + int CONNECTIVITY_CHECKS = 2; + int ENV_VARS = 3; + int WRITERS_HEALTH = 4; + int EXCEPTIONS = 5; + int PLUGIN_LOGS = 6; + int JENKINS_LOGS = 7; + int THREAD_DUMP = 8; + int JFR = 9; + } + default boolean isEnabledByDefault() { return true; } diff --git a/src/main/java/org/datadog/jenkins/plugins/datadog/flare/JenkinsLogsFlare.java b/src/main/java/org/datadog/jenkins/plugins/datadog/flare/JenkinsLogsFlare.java index 1130f176..087ee8e4 100644 --- a/src/main/java/org/datadog/jenkins/plugins/datadog/flare/JenkinsLogsFlare.java +++ b/src/main/java/org/datadog/jenkins/plugins/datadog/flare/JenkinsLogsFlare.java @@ -25,7 +25,7 @@ public class JenkinsLogsFlare implements FlareContributor { @Override public int order() { - return 6; + return ORDER.JENKINS_LOGS; } @Override diff --git a/src/main/java/org/datadog/jenkins/plugins/datadog/flare/JfrFlare.java b/src/main/java/org/datadog/jenkins/plugins/datadog/flare/JfrFlare.java index be6d4704..aa8a589f 100644 --- a/src/main/java/org/datadog/jenkins/plugins/datadog/flare/JfrFlare.java +++ b/src/main/java/org/datadog/jenkins/plugins/datadog/flare/JfrFlare.java @@ -21,7 +21,7 @@ public boolean isEnabledByDefault() { @Override public int order() { - return 8; + return ORDER.JFR; } @Override diff --git a/src/main/java/org/datadog/jenkins/plugins/datadog/flare/PluginLogsFlare.java b/src/main/java/org/datadog/jenkins/plugins/datadog/flare/PluginLogsFlare.java index 0b91d918..208af141 100644 --- a/src/main/java/org/datadog/jenkins/plugins/datadog/flare/PluginLogsFlare.java +++ b/src/main/java/org/datadog/jenkins/plugins/datadog/flare/PluginLogsFlare.java @@ -56,7 +56,7 @@ public void onStartup() { @Override public int order() { - return 5; + return ORDER.PLUGIN_LOGS; } @Override diff --git a/src/main/java/org/datadog/jenkins/plugins/datadog/flare/RuntimeInfoFlare.java b/src/main/java/org/datadog/jenkins/plugins/datadog/flare/RuntimeInfoFlare.java index 043eb833..bfcca612 100644 --- a/src/main/java/org/datadog/jenkins/plugins/datadog/flare/RuntimeInfoFlare.java +++ b/src/main/java/org/datadog/jenkins/plugins/datadog/flare/RuntimeInfoFlare.java @@ -15,7 +15,7 @@ public class RuntimeInfoFlare implements FlareContributor { @Override public int order() { - return 0; + return ORDER.RUNTIME_INFO; } @Override diff --git a/src/main/java/org/datadog/jenkins/plugins/datadog/flare/ThreadDumpFlare.java b/src/main/java/org/datadog/jenkins/plugins/datadog/flare/ThreadDumpFlare.java index 4ca9167d..74206ac0 100644 --- a/src/main/java/org/datadog/jenkins/plugins/datadog/flare/ThreadDumpFlare.java +++ b/src/main/java/org/datadog/jenkins/plugins/datadog/flare/ThreadDumpFlare.java @@ -12,7 +12,7 @@ public class ThreadDumpFlare implements FlareContributor { @Override public int order() { - return 7; + return ORDER.THREAD_DUMP; } @Override diff --git a/src/main/java/org/datadog/jenkins/plugins/datadog/flare/WritersHealthFlare.java b/src/main/java/org/datadog/jenkins/plugins/datadog/flare/WritersHealthFlare.java index 68e71fbb..bbce132f 100644 --- a/src/main/java/org/datadog/jenkins/plugins/datadog/flare/WritersHealthFlare.java +++ b/src/main/java/org/datadog/jenkins/plugins/datadog/flare/WritersHealthFlare.java @@ -24,7 +24,7 @@ public WritersHealthFlare() { @Override public int order() { - return 0; + return ORDER.WRITERS_HEALTH; } @Override diff --git a/src/main/java/org/datadog/jenkins/plugins/datadog/logs/DatadogWriter.java b/src/main/java/org/datadog/jenkins/plugins/datadog/logs/DatadogWriter.java index d96ea384..6794e6e0 100644 --- a/src/main/java/org/datadog/jenkins/plugins/datadog/logs/DatadogWriter.java +++ b/src/main/java/org/datadog/jenkins/plugins/datadog/logs/DatadogWriter.java @@ -72,9 +72,9 @@ public void write(String line) { payload.put("timestamp", System.currentTimeMillis()); payload.put(PipelineStepData.StepType.PIPELINE.getTagName() + CITags._NAME, this.buildData.getJobName()); - AsyncWriter logWriter = LogWriterFactory.getLogWriter(); + AsyncWriter logWriter = LogWriterFactory.getLogWriter(); if (logWriter != null) { - logWriter.submit(payload.toString()); + logWriter.submit(payload); } } catch (Exception e) { diff --git a/src/main/java/org/datadog/jenkins/plugins/datadog/logs/LogWriteStrategy.java b/src/main/java/org/datadog/jenkins/plugins/datadog/logs/LogWriteStrategy.java index 70d17751..771e2bf4 100644 --- a/src/main/java/org/datadog/jenkins/plugins/datadog/logs/LogWriteStrategy.java +++ b/src/main/java/org/datadog/jenkins/plugins/datadog/logs/LogWriteStrategy.java @@ -1,12 +1,13 @@ package org.datadog.jenkins.plugins.datadog.logs; +import net.sf.json.JSONObject; import java.util.List; public interface LogWriteStrategy { LogWriteStrategy NO_OP = new LogWriteStrategy() { @Override - public void send(List logs) { + public void send(List logs) { // no op } @@ -16,6 +17,6 @@ public void close() { } }; - void send(List logs); + void send(List logs); void close(); } diff --git a/src/main/java/org/datadog/jenkins/plugins/datadog/logs/LogWriterFactory.java b/src/main/java/org/datadog/jenkins/plugins/datadog/logs/LogWriterFactory.java index a2c071ae..7cb9aa46 100644 --- a/src/main/java/org/datadog/jenkins/plugins/datadog/logs/LogWriterFactory.java +++ b/src/main/java/org/datadog/jenkins/plugins/datadog/logs/LogWriterFactory.java @@ -1,6 +1,7 @@ package org.datadog.jenkins.plugins.datadog.logs; import hudson.init.Terminator; +import net.sf.json.JSONObject; import org.datadog.jenkins.plugins.datadog.util.AsyncWriter; import org.datadog.jenkins.plugins.datadog.DatadogClient; import org.datadog.jenkins.plugins.datadog.DatadogUtilities; @@ -21,7 +22,7 @@ public class LogWriterFactory { private static final int DEFAULT_POLLING_TIMEOUT_SECONDS = 2; private static final int DEFAULT_BATCH_SIZE_LIMIT = 500; - private static volatile AsyncWriter LOG_WRITER; + private static volatile AsyncWriter LOG_WRITER; public static synchronized void onDatadogClientUpdate(@Nullable DatadogClient client) { if (client == null) { @@ -57,7 +58,7 @@ public static synchronized void stop() throws InterruptedException { } @Nullable - public static AsyncWriter getLogWriter() { + public static AsyncWriter getLogWriter() { return LOG_WRITER; } } diff --git a/src/test/java/org/datadog/jenkins/plugins/datadog/clients/CompressedBatchSenderTest.java b/src/test/java/org/datadog/jenkins/plugins/datadog/clients/CompressedBatchSenderTest.java new file mode 100644 index 00000000..2ff3f3e4 --- /dev/null +++ b/src/test/java/org/datadog/jenkins/plugins/datadog/clients/CompressedBatchSenderTest.java @@ -0,0 +1,131 @@ +package org.datadog.jenkins.plugins.datadog.clients; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import java.io.ByteArrayInputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.zip.GZIPInputStream; +import net.sf.json.JSONArray; +import net.sf.json.JSONObject; +import org.apache.commons.io.IOUtils; +import org.jetbrains.annotations.NotNull; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +public class CompressedBatchSenderTest { + + private static final String URL = "dummyUrl"; + + public static final Map HEADERS; + static { + HEADERS = new HashMap<>(); + HEADERS.put("header1", "value1"); + HEADERS.put("header2", "value2"); + } + + private static final int BATCH_SIZE = 30; + + private final HttpClient httpClient = mock(HttpClient.class); + + private final CompressedBatchSender> sender = new CompressedBatchSender<>(httpClient, URL, HEADERS, BATCH_SIZE, JSONObject::fromObject); + + @Test + public void testOneElementBatch() throws Exception{ + List>> batches = whenSending(map("a", "b")); + + assertEquals(1, batches.size()); + assertEquals(Arrays.asList(map("a", "b")), batches.get(0)); + } + + @Test + public void testTwoElementBatch() throws Exception{ + List>> batches = whenSending(map("a", "b"), map("c", "d")); + + assertEquals(1, batches.size()); + assertEquals(Arrays.asList(map("a", "b"), map("c", "d")), batches.get(0)); + } + + @Test + public void testTwoBatches() throws Exception{ + List>> batches = whenSending(map("a", "b"), map("c", "d"), map("e", "f"), map("g", "h")); + + assertEquals(2, batches.size()); + assertEquals(Arrays.asList(map("a", "b"), map("c", "d")), batches.get(0)); + assertEquals(Arrays.asList(map("e", "f"), map("g", "h")), batches.get(1)); + } + + @Test + public void testBigElement() throws Exception{ + List>> batches = whenSending(map("a", "b"), map("abcdefghijk", "1234567890"), map("e", "f")); + + assertEquals(3, batches.size()); + assertEquals(Arrays.asList(map("a", "b")), batches.get(0)); + assertEquals(Arrays.asList(map("abcdefghijk", "1234567890")), batches.get(1)); + assertEquals(Arrays.asList(map("e", "f")), batches.get(2)); + } + + @Test + public void testHugeElementsAreDropped() throws Exception{ + List>> batches = whenSending(map("a", "b"), map("abcdefghijk", "12345678901234567890123456789012345678901234567890"), map("e", "f")); + + assertEquals(1, batches.size()); + assertEquals(Arrays.asList(map("a", "b"), map("e", "f")), batches.get(0)); + } + + @Test + public void testHugeElementsAreDroppedEdgeCase() throws Exception { + // second element size is 31, which is 1 byte more than the limit + List>> batches = whenSending(map("a", "b"), map("abcdefghijk", "12345678901"), map("e", "f")); + + assertEquals(1, batches.size()); + assertEquals(Arrays.asList(map("a", "b"), map("e", "f")), batches.get(0)); + } + + @Test + public void testTwoBatchesEdgeCase() throws Exception { + // sum of sizes of two elements is 31, which is 1 byte more than the limit + List>> batches = whenSending(map("a", "b"), map("cd", "1234567890")); + + assertEquals(2, batches.size()); + assertEquals(Arrays.asList(map("a", "b")), batches.get(0)); + assertEquals(Arrays.asList(map("cd", "1234567890")), batches.get(1)); + } + + private List>> whenSending(Map... payloads) throws Exception { + sender.send(Arrays.asList(payloads)); + + List>> batches = new ArrayList<>(); + ArgumentCaptor captor = ArgumentCaptor.forClass(byte[].class); + verify(httpClient, atLeast(1)).post(eq(URL), eq(HEADERS), eq("application/json"), captor.capture(), any()); + List requestsBytes = captor.getAllValues(); + for (byte[] requestBytes : requestsBytes) { + try (GZIPInputStream gzip = new GZIPInputStream(new ByteArrayInputStream(requestBytes))) { + byte[] uncompressedRequestBytes = IOUtils.toByteArray(gzip); + String uncompressedRequest = new String(uncompressedRequestBytes); + JSONArray requestJson = JSONArray.fromObject(uncompressedRequest); + + Collection> batch = new ArrayList<>(); + for(int i = 0; i < requestJson.size(); i++) { + batch.add((Map) requestJson.getJSONObject(i).toBean(Map.class)); + } + batches.add(batch); + } + } + return batches; + } + + private static @NotNull Map map(String key, String value) { + return Collections.singletonMap(key, value); + } +} diff --git a/src/test/java/org/datadog/jenkins/plugins/datadog/clients/DatadogClientStub.java b/src/test/java/org/datadog/jenkins/plugins/datadog/clients/DatadogClientStub.java index 2152e083..bde0ad85 100644 --- a/src/test/java/org/datadog/jenkins/plugins/datadog/clients/DatadogClientStub.java +++ b/src/test/java/org/datadog/jenkins/plugins/datadog/clients/DatadogClientStub.java @@ -336,10 +336,9 @@ private static final class StubLogWriteStrategy implements LogWriteStrategy { public final List logLines = new CopyOnWriteArrayList<>(); @Override - public void send(List logs) { - for (String log : logs) { - JSONObject payload = JSONObject.fromObject(log); - this.logLines.add(payload); + public void send(List logs) { + for (JSONObject log : logs) { + this.logLines.add(log); } }