Skip to content

Commit 65919a6

Browse files
committed
Add TCKs for PathItem annotations
- Define a PathItem under Components - test all parameters - Define Operations under a Path Item - test all parameters - Define a webhook - Reference a Path Item from a webhook - Reference a Path Item from a callback - Reference a Path Item from another Path Item under Components
1 parent 042f241 commit 65919a6

File tree

2 files changed

+175
-1
lines changed

2 files changed

+175
-1
lines changed

tck/src/main/java/org/eclipse/microprofile/openapi/apps/airlines/JAXRSApp.java

Lines changed: 102 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import org.eclipse.microprofile.openapi.annotations.Components;
2121
import org.eclipse.microprofile.openapi.annotations.ExternalDocumentation;
2222
import org.eclipse.microprofile.openapi.annotations.OpenAPIDefinition;
23+
import org.eclipse.microprofile.openapi.annotations.PathItem;
24+
import org.eclipse.microprofile.openapi.annotations.PathItemOperation;
2325
import org.eclipse.microprofile.openapi.annotations.callbacks.Callback;
2426
import org.eclipse.microprofile.openapi.annotations.callbacks.CallbackOperation;
2527
import org.eclipse.microprofile.openapi.annotations.enums.ParameterIn;
@@ -60,6 +62,7 @@
6062
import jakarta.ws.rs.core.Application;
6163
import jakarta.ws.rs.core.MediaType;
6264

65+
@SuppressWarnings("checkstyle:linelength") // indentation of annotations leads to long lines
6366
@ApplicationPath("/")
6467
@OpenAPIDefinition(
6568
tags = {@Tag(name = "user", description = "Operations about user"),
@@ -107,6 +110,27 @@
107110
extensions = @Extension(name = "x-server", value = "test-server")),
108111
@Server(url = "https://test-server.com:80/basePath", description = "The test API server")
109112
},
113+
webhooks = {
114+
@PathItem(name = "bookingEvent",
115+
description = "Notifies about booking creation and deletion",
116+
summary = "Booking Events",
117+
operations = {
118+
@PathItemOperation(method = "put",
119+
summary = "Notifies that a booking has been created",
120+
requestBody = @RequestBody(content = @Content(mediaType = "application/json",
121+
schema = @Schema(ref = "#/components/schemas/Booking"))),
122+
responses = @APIResponse(responseCode = "204",
123+
description = "Indicates that the creation event was processed successfully")),
124+
@PathItemOperation(method = "delete",
125+
summary = "Notifies that a booking has been deleted",
126+
requestBody = @RequestBody(content = @Content(mediaType = "application/json",
127+
schema = @Schema(ref = "#/components/schemas/Booking"))),
128+
responses = @APIResponse(responseCode = "204",
129+
description = "Indicates that the deletion event was processed successfully"))
130+
},
131+
extensions = @Extension(name = "x-webhook", value = "test-webhook")),
132+
@PathItem(name = "userEvent", ref = "UserEvent")
133+
},
110134
components = @Components(
111135
schemas = {
112136
@Schema(name = "Bookings", title = "Bookings",
@@ -219,7 +243,84 @@
219243
@APIResponse(ref = "FoundBookings")
220244
})),
221245
@Callback(name = "GetBookingsARef",
222-
ref = "#/components/callbacks/GetBookings")
246+
ref = "#/components/callbacks/GetBookings"),
247+
@Callback(name = "UserEvents",
248+
callbackUrlExpression = "http://localhost:9080/users/events",
249+
pathItemRef = "UserEvent")
250+
},
251+
pathItems = {
252+
@PathItem(name = "UserEvent",
253+
description = "Standard definition for receiving events about users",
254+
summary = "User Event reception API",
255+
operations = {
256+
@PathItemOperation(
257+
method = "PUT",
258+
summary = "User added event",
259+
description = "A user was added",
260+
externalDocs = @ExternalDocumentation(url = "http://example.com/docs"),
261+
operationId = "userAddedEvent",
262+
parameters = @Parameter(name = "authenticated",
263+
description = "Whether the user is authenticated",
264+
in = ParameterIn.QUERY,
265+
schema = @Schema(type = SchemaType.BOOLEAN),
266+
required = false),
267+
requestBody = @RequestBody(
268+
description = "The added user",
269+
content = @Content(mediaType = MediaType.APPLICATION_JSON,
270+
schema = @Schema(ref = "User"))),
271+
responses = {
272+
@APIResponse(responseCode = "200",
273+
description = "Event received"),
274+
@APIResponse(responseCode = "429",
275+
description = "Server is too busy to process the event. It will be sent again later")
276+
}),
277+
@PathItemOperation(
278+
method = "DELETE",
279+
summary = "A user was deleted",
280+
parameters = @Parameter(name = "id",
281+
in = ParameterIn.QUERY,
282+
schema = @Schema(type = SchemaType.STRING),
283+
required = true),
284+
responses = {
285+
@APIResponse(responseCode = "200",
286+
description = "Event received")
287+
})
288+
}),
289+
@PathItem(name = "UserEventARef",
290+
ref = "#/components/pathItems/UserEvent",
291+
description = "UserEvent reference",
292+
summary = "Referenced PathItem"),
293+
@PathItem(name = "CallbackPathItem",
294+
operations = @PathItemOperation(
295+
method = "POST",
296+
responses = @APIResponse(responseCode = "200"),
297+
callbacks = @Callback(name = "getBookings",
298+
ref = "#/components/callbacks/GetBookings"))),
299+
// Test remaining properties on PathItemOperation
300+
@PathItem(name = "OperationTest",
301+
operations = @PathItemOperation(
302+
method = "POST",
303+
responses = @APIResponse(responseCode = "200"),
304+
deprecated = true,
305+
security = @SecurityRequirement(name = "testScheme1"),
306+
securitySets = @SecurityRequirementsSet({}),
307+
servers = @Server(url = "http://old.example.com/api"),
308+
extensions = @Extension(name = "x-operation",
309+
value = "test operation"))),
310+
// Test remaining properties on PathItem
311+
@PathItem(name = "PathItemTest",
312+
operations = {
313+
@PathItemOperation(method = "POST",
314+
responses = @APIResponse(responseCode = "200")),
315+
@PathItemOperation(method = "PUT",
316+
responses = @APIResponse(responseCode = "200"))
317+
},
318+
servers = @Server(url = "http://example.com"),
319+
parameters = @Parameter(name = "id",
320+
in = ParameterIn.PATH,
321+
schema = @Schema(type = SchemaType.STRING)),
322+
extensions = @Extension(name = "x-pathItem",
323+
value = "test path item"))
223324
},
224325
extensions = @Extension(name = "x-components", value = "test-components")),
225326
extensions = @Extension(name = "x-openapi-definition", value = "test-openapi-definition"))

tck/src/main/java/org/eclipse/microprofile/openapi/tck/AirlinesAppTest.java

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import static org.hamcrest.Matchers.contains;
2424
import static org.hamcrest.Matchers.containsInAnyOrder;
2525
import static org.hamcrest.Matchers.containsString;
26+
import static org.hamcrest.Matchers.emptyIterable;
2627
import static org.hamcrest.Matchers.equalTo;
2728
import static org.hamcrest.Matchers.greaterThan;
2829
import static org.hamcrest.Matchers.hasEntry;
@@ -472,6 +473,10 @@ public void testCallbackAnnotations(String type) {
472473
endpoint = "paths.'/bookings'.post.callbacks";
473474
vr.body(endpoint, hasKey("bookingCallback"));
474475
vr.body(endpoint + ".'bookingCallback'", hasKey("http://localhost:9080/airlines/bookings"));
476+
477+
endpoint = "components.callbacks.UserEvents";
478+
vr.body(endpoint, hasKey("http://localhost:9080/users/events"));
479+
vr.body(endpoint + ".'http://localhost:9080/users/events'.$ref", equalTo("#/components/pathItems/UserEvent"));
475480
}
476481

477482
@Test(dataProvider = "formatProvider")
@@ -871,6 +876,7 @@ public void testComponents(String type) {
871876
vr.body("components.securitySchemes.httpTestScheme", notNullValue());
872877
vr.body("components.links.UserName", notNullValue());
873878
vr.body("components.callbacks.GetBookings", notNullValue());
879+
vr.body("components.pathItems.UserEvent", notNullValue());
874880

875881
// Test an extension on the components object itself
876882
vr.body("components.x-components", equalTo("test-components"));
@@ -1186,6 +1192,73 @@ public void testRef(String type) {
11861192

11871193
vr.body("components.callbacks.GetBookingsARef.$ref",
11881194
equalTo("#/components/callbacks/GetBookings"));
1195+
1196+
vr.body("components.pathItems.UserEventARef.$ref", equalTo("#/components/pathItems/UserEvent"));
1197+
vr.body("components.pathItems.UserEventARef.description", equalTo("UserEvent reference"));
1198+
vr.body("components.pathItems.UserEventARef.summary", equalTo("Referenced PathItem"));
11891199
}
11901200

1201+
@Test(dataProvider = "formatProvider")
1202+
public void testPathItem(String type) {
1203+
ValidatableResponse vr = callEndpoint(type);
1204+
1205+
String pathItem = "components.pathItems.UserEvent";
1206+
vr.body(pathItem + ".description", equalTo("Standard definition for receiving events about users"));
1207+
vr.body(pathItem + ".summary", equalTo("User Event reception API"));
1208+
vr.body(pathItem + ".put", notNullValue());
1209+
vr.body(pathItem + ".delete", notNullValue());
1210+
1211+
pathItem = "components.pathItems.PathItemTest";
1212+
vr.body(pathItem + ".servers[0].url", equalTo("http://example.com"));
1213+
vr.body(pathItem + ".parameters[0].name", equalTo("id"));
1214+
vr.body(pathItem + ".x-pathItem", equalTo("test path item"));
1215+
}
1216+
1217+
@Test(dataProvider = "formatProvider")
1218+
public void testPathItemOperation(String type) {
1219+
ValidatableResponse vr = callEndpoint(type);
1220+
1221+
String op = "components.pathItems.UserEvent.put";
1222+
vr.body(op, notNullValue());
1223+
vr.body(op + ".summary", equalTo("User added event"));
1224+
vr.body(op + ".description", equalTo("A user was added"));
1225+
vr.body(op + ".externalDocs.url", equalTo("http://example.com/docs"));
1226+
vr.body(op + ".operationId", equalTo("userAddedEvent"));
1227+
vr.body(op + ".parameters[0].name", equalTo("authenticated"));
1228+
vr.body(op + ".requestBody.description", equalTo("The added user"));
1229+
vr.body(op + ".responses.'200'.description", equalTo("Event received"));
1230+
vr.body(op + ".responses.'429'.description", containsString("Server is too busy"));
1231+
1232+
op = "components.pathItems.CallbackPathItem.post";
1233+
vr.body(op, notNullValue());
1234+
vr.body(op + ".callbacks.getBookings.$ref", equalTo("#/components/callbacks/GetBookings"));
1235+
1236+
op = "components.pathItems.OperationTest.post";
1237+
vr.body(op, notNullValue());
1238+
vr.body(op + ".deprecated", equalTo(true));
1239+
vr.body(op + ".security", hasSize(2));
1240+
vr.body(op + ".security", hasItem(anEmptyMap()));
1241+
// JsonPath syntax sucks - this expects security to contain two items, one of which
1242+
// maps "testScheme1" to an empty list and the other of which doesn't have a "testScheme1" entry.
1243+
vr.body(op + ".security.testScheme1", containsInAnyOrder(emptyIterable(), nullValue()));
1244+
vr.body(op + ".servers[0].url", equalTo("http://old.example.com/api"));
1245+
vr.body(op + ".x-operation", equalTo("test operation"));
1246+
}
1247+
1248+
@Test(dataProvider = "formatProvider")
1249+
public void testWebhooks(String type) {
1250+
ValidatableResponse vr = callEndpoint(type);
1251+
1252+
String webhook = "webhooks.bookingEvent";
1253+
vr.body(webhook, notNullValue());
1254+
vr.body(webhook + ".description", equalTo("Notifies about booking creation and deletion"));
1255+
vr.body(webhook + ".summary", equalTo("Booking Events"));
1256+
vr.body(webhook + ".put", notNullValue());
1257+
vr.body(webhook + ".delete", notNullValue());
1258+
vr.body(webhook + ".x-webhook", equalTo("test-webhook"));
1259+
1260+
webhook = "webhooks.userEvent";
1261+
vr.body(webhook, notNullValue());
1262+
vr.body(webhook + ".$ref", equalTo("#/components/pathItems/UserEvent"));
1263+
}
11911264
}

0 commit comments

Comments
 (0)