Skip to content

Commit e90e02c

Browse files
NO-ISSUE: Improving IT to check for duplicated headers (#1209)
Signed-off-by: Ricardo Zanini <[email protected]>
1 parent 16a0328 commit e90e02c

File tree

4 files changed

+211
-1
lines changed

4 files changed

+211
-1
lines changed
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
{
2+
"openapi": "3.0.1",
3+
"info": {
4+
"title": "Slack Actions for Slack API",
5+
"description": "Slack Actions Slack API",
6+
"version": "0.0.1"
7+
},
8+
"paths": {
9+
"/api/chat.postMessage": {
10+
"post": {
11+
"tags": [
12+
"Message"
13+
],
14+
"summary": "Send slack message",
15+
"description": "Send slack message to selected public channel",
16+
"operationId": "sendSlackMessage",
17+
"requestBody": {
18+
"description": "Input parameters for the action sendSlackMessage",
19+
"required": true,
20+
"content": {
21+
"application/json": {
22+
"schema": {
23+
"$ref": "#/components/schemas/SendMessageRequest"
24+
}
25+
}
26+
}
27+
},
28+
"responses": {
29+
"default": {
30+
"description": "Send Message Response",
31+
"content": {
32+
"application/json": {
33+
"schema": {
34+
"$ref": "#/components/schemas/SendMessageResponse"
35+
}
36+
}
37+
}
38+
}
39+
},
40+
"deprecated": false,
41+
"security": [
42+
{
43+
"bearerAuth": []
44+
}
45+
]
46+
}
47+
}
48+
},
49+
"components": {
50+
"securitySchemes": {
51+
"basicAuth": {
52+
"type": "http",
53+
"scheme": "basic"
54+
},
55+
"bearerAuth": {
56+
"type": "http",
57+
"scheme": "bearer"
58+
}
59+
},
60+
"schemas": {
61+
"ErrorCollection": {
62+
"type": "object"
63+
},
64+
"SendMessageRequest": {
65+
"type": "object",
66+
"properties": {
67+
"text": {
68+
"type": "string"
69+
},
70+
"channel": {
71+
"type": "string"
72+
}
73+
}
74+
},
75+
"SendMessageResponse": {
76+
"type": "object",
77+
"properties": {
78+
"ok": {
79+
"type": "boolean",
80+
"description": "Indicates if the message was posted.",
81+
"readOnly": true
82+
},
83+
"channel": {
84+
"type": "string",
85+
"description": "The ID of the channel the message was posted.",
86+
"readOnly": true
87+
},
88+
"response_metadata": {
89+
"type": "object",
90+
"description": "The metadata of response details",
91+
"readOnly": true
92+
}
93+
}
94+
}
95+
}
96+
}
97+
}

client/integration-tests/security/src/main/resources/application.properties

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,9 @@ quarkus.oidc-client.service5_oauth2.grant.type=client
7878
quarkus.oidc-client.service5_oauth2.credentials.client-secret.method=basic
7979
quarkus.oidc-client.service5_oauth2.credentials.client-secret.value=secret
8080

81-
quarkus.keycloak.devservices.enabled=false
81+
quarkus.keycloak.devservices.enabled=false
82+
83+
# Slack OpenAPI
84+
quarkus.openapi-generator.codegen.spec.slack_openapi_json.base-package=org.acme.openapi.slack
85+
quarkus.openapi-generator.slack_openapi_json.auth.bearerAuth.bearer-token=12345-TOKEN
86+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package io.quarkiverse.openapi.generator.it.security;
2+
3+
import java.util.List;
4+
5+
import jakarta.inject.Inject;
6+
7+
import org.acme.openapi.slack.api.MessageApi;
8+
import org.acme.openapi.slack.model.SendMessageRequest;
9+
import org.acme.openapi.slack.model.SendMessageResponse;
10+
import org.eclipse.microprofile.rest.client.inject.RestClient;
11+
import org.junit.jupiter.api.Assertions;
12+
import org.junit.jupiter.api.Test;
13+
14+
import com.github.tomakehurst.wiremock.WireMockServer;
15+
import com.github.tomakehurst.wiremock.client.WireMock;
16+
import com.github.tomakehurst.wiremock.verification.LoggedRequest;
17+
18+
import io.quarkus.test.common.QuarkusTestResource;
19+
import io.quarkus.test.junit.QuarkusTest;
20+
21+
@QuarkusTestResource(WiremockSlackServer.class)
22+
@QuarkusTest
23+
public class CheckHeadersBearerTokenTest {
24+
25+
// injected by quarkus test resource
26+
WireMockServer slackServer;
27+
28+
// generated by OpenAPI
29+
@RestClient
30+
@Inject
31+
MessageApi messageApi;
32+
33+
@Test
34+
void testNoDuplicateHeaders() {
35+
SendMessageRequest sendMessageRequest = new SendMessageRequest();
36+
sendMessageRequest.setChannel("#test");
37+
sendMessageRequest.setText("Hello World");
38+
SendMessageResponse response = messageApi.sendSlackMessage(sendMessageRequest);
39+
Assertions.assertNotNull(response, "Expected a non-null response");
40+
41+
List<LoggedRequest> requests = slackServer.findAll(
42+
WireMock.postRequestedFor(WireMock.urlEqualTo("/api/chat.postMessage")));
43+
Assertions.assertEquals(1, requests.size(), "Expected exactly one HTTP request");
44+
45+
LoggedRequest req = requests.get(0);
46+
47+
String contentLength = req.getHeader("Content-Length");
48+
Assertions.assertNotNull(contentLength, "Content-Length header should be present");
49+
Assertions.assertTrue(
50+
Integer.parseInt(contentLength) > 0,
51+
"Content-Length should be a positive integer");
52+
53+
for (String headerName : req.getAllHeaderKeys()) {
54+
List<String> values = req.getHeaders().getHeader(headerName).values();
55+
Assertions.assertEquals(
56+
1,
57+
values.size(),
58+
() -> String.format(
59+
"Header '%s' is duplicated; values: %s",
60+
headerName, values));
61+
}
62+
}
63+
64+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package io.quarkiverse.openapi.generator.it.security;
2+
3+
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
4+
import static com.github.tomakehurst.wiremock.client.WireMock.post;
5+
import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo;
6+
7+
import java.util.Map;
8+
9+
import com.github.tomakehurst.wiremock.WireMockServer;
10+
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
11+
12+
import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
13+
14+
public class WiremockSlackServer implements QuarkusTestResourceLifecycleManager {
15+
public static final String URL_KEY = "quarkus.rest-client.slack_openapi_json.url";
16+
private WireMockServer wireMockServer;
17+
18+
@Override
19+
public Map<String, String> start() {
20+
wireMockServer = new WireMockServer(WireMockConfiguration.wireMockConfig().dynamicPort());
21+
wireMockServer.start();
22+
23+
wireMockServer.stubFor(post(urlPathEqualTo("/api/chat.postMessage"))
24+
.willReturn(aResponse()
25+
.withStatus(200)
26+
.withHeader("Content-Type", "application/json")
27+
.withBody(
28+
"{\"ok\": \"true\", \"channel\": \"#test\", \"response_metadata\": {}}")));
29+
30+
return Map.of(URL_KEY, wireMockServer.baseUrl());
31+
}
32+
33+
@Override
34+
public void inject(TestInjector testInjector) {
35+
testInjector.injectIntoFields(wireMockServer, f -> f.getName().equals("slackServer"));
36+
}
37+
38+
@Override
39+
public void stop() {
40+
if (null != wireMockServer) {
41+
wireMockServer.stop();
42+
}
43+
}
44+
}

0 commit comments

Comments
 (0)