Skip to content

Commit

Permalink
Add TCKs for PathItem annotations
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
Azquelt committed Jun 7, 2024
1 parent 042f241 commit 65919a6
Show file tree
Hide file tree
Showing 2 changed files with 175 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import org.eclipse.microprofile.openapi.annotations.Components;
import org.eclipse.microprofile.openapi.annotations.ExternalDocumentation;
import org.eclipse.microprofile.openapi.annotations.OpenAPIDefinition;
import org.eclipse.microprofile.openapi.annotations.PathItem;
import org.eclipse.microprofile.openapi.annotations.PathItemOperation;
import org.eclipse.microprofile.openapi.annotations.callbacks.Callback;
import org.eclipse.microprofile.openapi.annotations.callbacks.CallbackOperation;
import org.eclipse.microprofile.openapi.annotations.enums.ParameterIn;
Expand Down Expand Up @@ -60,6 +62,7 @@
import jakarta.ws.rs.core.Application;
import jakarta.ws.rs.core.MediaType;

@SuppressWarnings("checkstyle:linelength") // indentation of annotations leads to long lines
@ApplicationPath("/")
@OpenAPIDefinition(
tags = {@Tag(name = "user", description = "Operations about user"),
Expand Down Expand Up @@ -107,6 +110,27 @@
extensions = @Extension(name = "x-server", value = "test-server")),
@Server(url = "https://test-server.com:80/basePath", description = "The test API server")
},
webhooks = {
@PathItem(name = "bookingEvent",
description = "Notifies about booking creation and deletion",
summary = "Booking Events",
operations = {
@PathItemOperation(method = "put",
summary = "Notifies that a booking has been created",
requestBody = @RequestBody(content = @Content(mediaType = "application/json",
schema = @Schema(ref = "#/components/schemas/Booking"))),
responses = @APIResponse(responseCode = "204",
description = "Indicates that the creation event was processed successfully")),
@PathItemOperation(method = "delete",
summary = "Notifies that a booking has been deleted",
requestBody = @RequestBody(content = @Content(mediaType = "application/json",
schema = @Schema(ref = "#/components/schemas/Booking"))),
responses = @APIResponse(responseCode = "204",
description = "Indicates that the deletion event was processed successfully"))
},
extensions = @Extension(name = "x-webhook", value = "test-webhook")),
@PathItem(name = "userEvent", ref = "UserEvent")
},
components = @Components(
schemas = {
@Schema(name = "Bookings", title = "Bookings",
Expand Down Expand Up @@ -219,7 +243,84 @@
@APIResponse(ref = "FoundBookings")
})),
@Callback(name = "GetBookingsARef",
ref = "#/components/callbacks/GetBookings")
ref = "#/components/callbacks/GetBookings"),
@Callback(name = "UserEvents",
callbackUrlExpression = "http://localhost:9080/users/events",
pathItemRef = "UserEvent")
},
pathItems = {
@PathItem(name = "UserEvent",
description = "Standard definition for receiving events about users",
summary = "User Event reception API",
operations = {
@PathItemOperation(
method = "PUT",
summary = "User added event",
description = "A user was added",
externalDocs = @ExternalDocumentation(url = "http://example.com/docs"),
operationId = "userAddedEvent",
parameters = @Parameter(name = "authenticated",
description = "Whether the user is authenticated",
in = ParameterIn.QUERY,
schema = @Schema(type = SchemaType.BOOLEAN),
required = false),
requestBody = @RequestBody(
description = "The added user",
content = @Content(mediaType = MediaType.APPLICATION_JSON,
schema = @Schema(ref = "User"))),
responses = {
@APIResponse(responseCode = "200",
description = "Event received"),
@APIResponse(responseCode = "429",
description = "Server is too busy to process the event. It will be sent again later")
}),
@PathItemOperation(
method = "DELETE",
summary = "A user was deleted",
parameters = @Parameter(name = "id",
in = ParameterIn.QUERY,
schema = @Schema(type = SchemaType.STRING),
required = true),
responses = {
@APIResponse(responseCode = "200",
description = "Event received")
})
}),
@PathItem(name = "UserEventARef",
ref = "#/components/pathItems/UserEvent",
description = "UserEvent reference",
summary = "Referenced PathItem"),
@PathItem(name = "CallbackPathItem",
operations = @PathItemOperation(
method = "POST",
responses = @APIResponse(responseCode = "200"),
callbacks = @Callback(name = "getBookings",
ref = "#/components/callbacks/GetBookings"))),
// Test remaining properties on PathItemOperation
@PathItem(name = "OperationTest",
operations = @PathItemOperation(
method = "POST",
responses = @APIResponse(responseCode = "200"),
deprecated = true,
security = @SecurityRequirement(name = "testScheme1"),
securitySets = @SecurityRequirementsSet({}),
servers = @Server(url = "http://old.example.com/api"),
extensions = @Extension(name = "x-operation",
value = "test operation"))),
// Test remaining properties on PathItem
@PathItem(name = "PathItemTest",
operations = {
@PathItemOperation(method = "POST",
responses = @APIResponse(responseCode = "200")),
@PathItemOperation(method = "PUT",
responses = @APIResponse(responseCode = "200"))
},
servers = @Server(url = "http://example.com"),
parameters = @Parameter(name = "id",
in = ParameterIn.PATH,
schema = @Schema(type = SchemaType.STRING)),
extensions = @Extension(name = "x-pathItem",
value = "test path item"))
},
extensions = @Extension(name = "x-components", value = "test-components")),
extensions = @Extension(name = "x-openapi-definition", value = "test-openapi-definition"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.emptyIterable;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.hasEntry;
Expand Down Expand Up @@ -472,6 +473,10 @@ public void testCallbackAnnotations(String type) {
endpoint = "paths.'/bookings'.post.callbacks";
vr.body(endpoint, hasKey("bookingCallback"));
vr.body(endpoint + ".'bookingCallback'", hasKey("http://localhost:9080/airlines/bookings"));

endpoint = "components.callbacks.UserEvents";
vr.body(endpoint, hasKey("http://localhost:9080/users/events"));
vr.body(endpoint + ".'http://localhost:9080/users/events'.$ref", equalTo("#/components/pathItems/UserEvent"));
}

@Test(dataProvider = "formatProvider")
Expand Down Expand Up @@ -871,6 +876,7 @@ public void testComponents(String type) {
vr.body("components.securitySchemes.httpTestScheme", notNullValue());
vr.body("components.links.UserName", notNullValue());
vr.body("components.callbacks.GetBookings", notNullValue());
vr.body("components.pathItems.UserEvent", notNullValue());

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

vr.body("components.callbacks.GetBookingsARef.$ref",
equalTo("#/components/callbacks/GetBookings"));

vr.body("components.pathItems.UserEventARef.$ref", equalTo("#/components/pathItems/UserEvent"));
vr.body("components.pathItems.UserEventARef.description", equalTo("UserEvent reference"));
vr.body("components.pathItems.UserEventARef.summary", equalTo("Referenced PathItem"));
}

@Test(dataProvider = "formatProvider")
public void testPathItem(String type) {
ValidatableResponse vr = callEndpoint(type);

String pathItem = "components.pathItems.UserEvent";
vr.body(pathItem + ".description", equalTo("Standard definition for receiving events about users"));
vr.body(pathItem + ".summary", equalTo("User Event reception API"));
vr.body(pathItem + ".put", notNullValue());
vr.body(pathItem + ".delete", notNullValue());

pathItem = "components.pathItems.PathItemTest";
vr.body(pathItem + ".servers[0].url", equalTo("http://example.com"));
vr.body(pathItem + ".parameters[0].name", equalTo("id"));
vr.body(pathItem + ".x-pathItem", equalTo("test path item"));
}

@Test(dataProvider = "formatProvider")
public void testPathItemOperation(String type) {
ValidatableResponse vr = callEndpoint(type);

String op = "components.pathItems.UserEvent.put";
vr.body(op, notNullValue());
vr.body(op + ".summary", equalTo("User added event"));
vr.body(op + ".description", equalTo("A user was added"));
vr.body(op + ".externalDocs.url", equalTo("http://example.com/docs"));
vr.body(op + ".operationId", equalTo("userAddedEvent"));
vr.body(op + ".parameters[0].name", equalTo("authenticated"));
vr.body(op + ".requestBody.description", equalTo("The added user"));
vr.body(op + ".responses.'200'.description", equalTo("Event received"));
vr.body(op + ".responses.'429'.description", containsString("Server is too busy"));

op = "components.pathItems.CallbackPathItem.post";
vr.body(op, notNullValue());
vr.body(op + ".callbacks.getBookings.$ref", equalTo("#/components/callbacks/GetBookings"));

op = "components.pathItems.OperationTest.post";
vr.body(op, notNullValue());
vr.body(op + ".deprecated", equalTo(true));
vr.body(op + ".security", hasSize(2));
vr.body(op + ".security", hasItem(anEmptyMap()));
// JsonPath syntax sucks - this expects security to contain two items, one of which
// maps "testScheme1" to an empty list and the other of which doesn't have a "testScheme1" entry.
vr.body(op + ".security.testScheme1", containsInAnyOrder(emptyIterable(), nullValue()));
vr.body(op + ".servers[0].url", equalTo("http://old.example.com/api"));
vr.body(op + ".x-operation", equalTo("test operation"));
}

@Test(dataProvider = "formatProvider")
public void testWebhooks(String type) {
ValidatableResponse vr = callEndpoint(type);

String webhook = "webhooks.bookingEvent";
vr.body(webhook, notNullValue());
vr.body(webhook + ".description", equalTo("Notifies about booking creation and deletion"));
vr.body(webhook + ".summary", equalTo("Booking Events"));
vr.body(webhook + ".put", notNullValue());
vr.body(webhook + ".delete", notNullValue());
vr.body(webhook + ".x-webhook", equalTo("test-webhook"));

webhook = "webhooks.userEvent";
vr.body(webhook, notNullValue());
vr.body(webhook + ".$ref", equalTo("#/components/pathItems/UserEvent"));
}
}

0 comments on commit 65919a6

Please sign in to comment.