Skip to content

Commit cfcbd23

Browse files
committed
Add notifycommand and test
1 parent 7790f01 commit cfcbd23

File tree

5 files changed

+224
-4
lines changed

5 files changed

+224
-4
lines changed

java-components/build-request-processor/pom.xml

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,13 @@
108108
<artifactId>pom-manipulation-common</artifactId>
109109
</dependency>
110110

111+
<dependency>
112+
<groupId>org.projectlombok</groupId>
113+
<artifactId>lombok</artifactId>
114+
<version>1.18.34</version>
115+
<scope>provided</scope>
116+
</dependency>
117+
111118
<dependency>
112119
<groupId>io.quarkus</groupId>
113120
<artifactId>quarkus-junit5</artifactId>
@@ -129,10 +136,9 @@
129136
<scope>test</scope>
130137
</dependency>
131138
<dependency>
132-
<groupId>org.projectlombok</groupId>
133-
<artifactId>lombok</artifactId>
134-
<version>1.18.34</version>
135-
<scope>provided</scope>
139+
<groupId>org.wiremock</groupId>
140+
<artifactId>wiremock</artifactId>
141+
<scope>test</scope>
136142
</dependency>
137143
</dependencies>
138144
<build>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package com.redhat.hacbs.container.notification;
2+
3+
import static org.apache.commons.lang3.StringUtils.isEmpty;
4+
5+
import java.net.http.HttpClient;
6+
import java.net.http.HttpRequest;
7+
import java.net.http.HttpResponse;
8+
import java.time.Duration;
9+
import java.util.Optional;
10+
11+
import jakarta.inject.Inject;
12+
13+
import org.eclipse.microprofile.config.inject.ConfigProperty;
14+
import org.jboss.pnc.api.dto.Request;
15+
16+
import com.fasterxml.jackson.databind.ObjectMapper;
17+
18+
import io.quarkus.logging.Log;
19+
import picocli.CommandLine;
20+
21+
@CommandLine.Command(name = "notify")
22+
public class NotifyCommand implements Runnable {
23+
24+
@CommandLine.Option(names = "--build-id", required = true)
25+
String buildId;
26+
27+
@CommandLine.Option(names = "--status", required = true)
28+
String status;
29+
30+
@CommandLine.Option(names = "--context", required = true)
31+
String context;
32+
33+
@CommandLine.Option(names = "--request-timeout")
34+
int requestTimeout = 15;
35+
36+
// TODO: do we need this...
37+
@ConfigProperty(name = "access.token")
38+
Optional<String> accessToken;
39+
40+
@Inject
41+
ObjectMapper objectMapper;
42+
43+
public void run() {
44+
try {
45+
46+
if (isEmpty(context)) {
47+
Log.infof("No callback configured ; unable to notify.");
48+
return;
49+
}
50+
51+
Request callback = objectMapper.readValue(context, Request.class );
52+
53+
Log.infof("Notification for build %s with status %s and callback %s", buildId, status, callback);
54+
PipelineNotification notification = PipelineNotification.builder().buildId(buildId).status(status).completionCallback((Request) callback.getAttachment()).build();
55+
String body = objectMapper.writeValueAsString(notification);
56+
57+
HttpRequest.Builder builder = HttpRequest.newBuilder()
58+
.uri(callback.getUri())
59+
.method(callback.getMethod().name(), HttpRequest.BodyPublishers.ofString(body))
60+
.timeout(Duration.ofSeconds(requestTimeout));
61+
callback.getHeaders().forEach(h -> builder.header(h.getName(), h.getValue()));
62+
63+
64+
HttpRequest request = builder.build();
65+
// TODO: Retry? Send async? Some useful mutiny examples from quarkus in https://gist.github.com/cescoffier/e9abce907a1c3d05d70bea3dae6dc3d5
66+
HttpResponse<String> response;
67+
try (HttpClient httpClient = HttpClient.newHttpClient()) {
68+
response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
69+
}
70+
Log.infof("Response %s", response);
71+
72+
} catch (Exception e) {
73+
Log.error("Notification failed", e);
74+
throw new RuntimeException(e);
75+
}
76+
}
77+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.redhat.hacbs.container.notification;
2+
3+
import org.jboss.pnc.api.dto.Request;
4+
5+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
6+
7+
import lombok.Builder;
8+
9+
// TODO: This is a direct copy of the same class in konflux-build-driver. Both need moved to pnc-api to
10+
// avoid clashes and duplication. For instance, we can't depend upon konflux-build-driver as that
11+
// then leads to oidc client issues.
12+
@Builder(builderClassName = "Builder")
13+
@JsonIgnoreProperties(ignoreUnknown = true)
14+
public record PipelineNotification(
15+
String status,
16+
String buildId,
17+
Request completionCallback) {
18+
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package com.redhat.hacbs.container.notification;
2+
3+
import static org.junit.jupiter.api.Assertions.assertTrue;
4+
5+
import java.io.IOException;
6+
import java.net.URI;
7+
import java.net.URISyntaxException;
8+
import java.util.List;
9+
import java.util.logging.LogRecord;
10+
11+
import javax.ws.rs.core.MediaType;
12+
13+
import org.jboss.pnc.api.constants.HttpHeaders;
14+
import org.jboss.pnc.api.dto.Request;
15+
import org.junit.jupiter.api.BeforeEach;
16+
import org.junit.jupiter.api.Test;
17+
18+
import com.fasterxml.jackson.databind.ObjectMapper;
19+
import com.github.tomakehurst.wiremock.WireMockServer;
20+
21+
import io.quarkus.test.LogCollectingTestResource;
22+
import io.quarkus.test.common.QuarkusTestResource;
23+
import io.quarkus.test.common.ResourceArg;
24+
import io.quarkus.test.junit.QuarkusTest;
25+
26+
@QuarkusTest
27+
@QuarkusTestResource(value = LogCollectingTestResource.class, restrictToAnnotatedClass = true, initArgs = @ResourceArg(name = LogCollectingTestResource.LEVEL, value = "FINE"))
28+
@QuarkusTestResource(WireMockExtensions.class)
29+
public class NotificationTest {
30+
31+
private WireMockServer wireMockServer;
32+
33+
@BeforeEach
34+
public void clearLogs() {
35+
LogCollectingTestResource.current().clear();
36+
}
37+
38+
@Test
39+
public void testNoNotify() {
40+
NotifyCommand notifyCommand = new NotifyCommand();
41+
notifyCommand.status = "Succeeded";
42+
notifyCommand.buildId = "1234";
43+
notifyCommand.run();
44+
List<LogRecord> logRecords = LogCollectingTestResource.current().getRecords();
45+
assertTrue(logRecords.stream()
46+
.anyMatch(r -> LogCollectingTestResource.format(r).contains("No callback configured ; unable to notify")));
47+
}
48+
49+
@Test
50+
public void testNotify() throws IOException, URISyntaxException {
51+
52+
Request request = Request.builder()
53+
.method(Request.Method.PUT)
54+
.header(new Request.Header(HttpHeaders.CONTENT_TYPE_STRING, MediaType.APPLICATION_JSON))
55+
.attachment(null)
56+
.uri(new URI(wireMockServer.baseUrl() + "/internal/completed"))
57+
.build();
58+
59+
System.err.println("### wiremock uri: " + wireMockServer.baseUrl());
60+
// {"method":"PUT","uri":"http://localhost:8081/internal/completed","headers":[{"name":"Content-Type","value":"application/json"}],"attachment":null}
61+
62+
NotifyCommand notifyCommand = new NotifyCommand();
63+
notifyCommand.status = "Succeeded";
64+
notifyCommand.buildId = "1234";
65+
notifyCommand.objectMapper = new ObjectMapper();
66+
notifyCommand.context = notifyCommand.objectMapper.writeValueAsString(request);
67+
notifyCommand.run();
68+
69+
List<LogRecord> logRecords = LogCollectingTestResource.current().getRecords();
70+
assertTrue(logRecords.stream()
71+
.anyMatch(r -> LogCollectingTestResource.format(r).contains("Response (PUT http://localhost:8080/internal/completed) 200")));
72+
}
73+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.redhat.hacbs.container.notification;
2+
3+
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
4+
import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson;
5+
import static com.github.tomakehurst.wiremock.client.WireMock.put;
6+
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
7+
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
8+
9+
import java.util.Map;
10+
11+
import com.github.tomakehurst.wiremock.WireMockServer;
12+
import com.github.tomakehurst.wiremock.common.ConsoleNotifier;
13+
14+
import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
15+
16+
public class WireMockExtensions implements QuarkusTestResourceLifecycleManager {
17+
private WireMockServer wireMockServer;
18+
19+
@Override
20+
public Map<String, String> start() {
21+
wireMockServer = new WireMockServer(wireMockConfig().notifier(new ConsoleNotifier(true)));
22+
wireMockServer.start();
23+
24+
wireMockServer.stubFor(
25+
put(urlEqualTo("/internal/completed"))
26+
.withRequestBody(
27+
equalToJson("{\"status\":\"Succeeded\",\"buildId\":\"1234\",\"completionCallback\":null}"))
28+
.willReturn(aResponse()
29+
.withStatus(200)));
30+
31+
return Map.of("quarkus.rest-client.wiremockextensions.url", wireMockServer.baseUrl());
32+
}
33+
34+
@Override
35+
public void stop() {
36+
if (wireMockServer != null) {
37+
wireMockServer.stop();
38+
}
39+
}
40+
41+
@Override
42+
public void inject(TestInjector testInjector) {
43+
testInjector.injectIntoFields(wireMockServer, new TestInjector.MatchesType(WireMockServer.class));
44+
}
45+
}

0 commit comments

Comments
 (0)