Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -242,16 +242,19 @@ private ValidationReport validateHeader(final ApiOperation apiOperation,
final String headerName,
final Header apiHeader,
final Collection<String> propertyValues) {
final ValidationReport.MessageContext context =
ValidationReport.MessageContext.create().withResponseHeaderName(headerName).build();

if (propertyValues.isEmpty() && TRUE.equals(apiHeader.getRequired())) {
return ValidationReport.singleton(
messages.get("validation.response.header.missing", headerName, apiOperation.getApiPath().original())
);
).withAdditionalContext(context);
}

return propertyValues
.stream()
.map(v -> schemaValidator.validate(v, apiHeader.getSchema(), "response.header"))
.map(v -> schemaValidator.validate(v, apiHeader.getSchema(), "response.header")
.withAdditionalContext(context))
.reduce(ValidationReport.empty(), ValidationReport::merge);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class ImmutableMessageContext implements ValidationReport.MessageContext {
private final String apiRequestContentType;

private final Integer responseStatus;
private final String responseHeaderName;
private final ApiResponse apiResponseDefinition;

private final Location location;
Expand All @@ -38,6 +39,7 @@ class ImmutableMessageContext implements ValidationReport.MessageContext {
apiRequestBodyDefinition = builder.apiRequestBodyDefinition;
apiRequestContentType = builder.apiRequestContentType;
responseStatus = builder.responseStatus;
responseHeaderName = builder.responseHeaderName;
apiResponseDefinition = builder.apiResponse;
location = builder.location;
whitelistRule = builder.whitelistRule;
Expand Down Expand Up @@ -81,6 +83,11 @@ public Optional<Integer> getResponseStatus() {
return Optional.ofNullable(responseStatus);
}

@Override
public Optional<String> getHResponseHeaderName() {
return Optional.ofNullable(responseHeaderName);
}

@JsonIgnore
@Override
public Optional<ApiResponse> getApiResponseDefinition() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,8 @@ static Builder from(final MessageContext other) {

Optional<Integer> getResponseStatus();

Optional<String> getHResponseHeaderName();

Optional<ApiResponse> getApiResponseDefinition();

/**
Expand Down Expand Up @@ -225,6 +227,7 @@ class Builder {
RequestBody apiRequestBodyDefinition;

Integer responseStatus;
String responseHeaderName;
ApiResponse apiResponse;

Location location;
Expand All @@ -244,6 +247,7 @@ private Builder(final MessageContext init) {
apiRequestBodyDefinition = init.getApiRequestBodyDefinition().orElse(null);
apiRequestContentType = init.getApiRequestContentType().orElse(null);
responseStatus = init.getResponseStatus().orElse(null);
responseHeaderName = init.getHResponseHeaderName().orElse(null);
apiResponse = init.getApiResponseDefinition().orElse(null);
location = init.getLocation().orElse(null);
whitelistRule = init.getAppliedWhitelistRule().orElse(null);
Expand Down Expand Up @@ -285,6 +289,11 @@ public Builder withResponseStatus(final Integer status) {
return this;
}

public Builder withResponseHeaderName(final String headerName) {
responseHeaderName = headerName;
return this;
}

public Builder withApiResponseDefinition(final ApiResponse apiResponseDefinition) {
apiResponse = apiResponseDefinition;
return this;
Expand Down Expand Up @@ -327,6 +336,9 @@ public Builder withAdditionalDataFrom(final MessageContext other) {
if (responseStatus == null) {
responseStatus = other.getResponseStatus().orElse(null);
}
if (responseHeaderName == null) {
responseHeaderName = other.getHResponseHeaderName().orElse(null);
}
if (apiResponse == null) {
apiResponse = other.getApiResponseDefinition().orElse(null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
import static com.atlassian.oai.validator.util.ValidatorTestUtil.assertPass;
import static com.atlassian.oai.validator.util.ValidatorTestUtil.loadJsonResponse;
import static com.atlassian.oai.validator.util.ValidatorTestUtil.loadXmlResponse;
import static com.atlassian.oai.validator.util.ValidatorTestUtil.getContextsForKey;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.CoreMatchers.is;

public class OpenAPIV3ResponseValidationTest {

Expand Down Expand Up @@ -204,8 +207,15 @@ public void validate_withInvalidResponseHeader_shouldFail() {
.withHeader("X-Failure-Code", "1.0")
.build();

assertFail(classUnderTest.validateResponse("/healthcheck", GET, response),
"validation.response.header.schema.type");
final ValidationReport report = classUnderTest.validateResponse("/healthcheck", GET, response);

assertFail(report, "validation.response.header.schema.type");
getContextsForKey(report, "validation.response.header.schema.type").forEach(ctx -> {
assertThat(ctx.isPresent(), is(true));
assertThat(ctx.get().getHResponseHeaderName().isPresent(), is(true));
assertThat(ctx.get().getHResponseHeaderName().get(), is("X-Failure-Code"));
}
);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;

import static java.lang.String.format;
import static java.util.stream.Collectors.toList;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
Expand Down Expand Up @@ -51,10 +51,10 @@ private static void assertFail(final ValidationReport report, final boolean expe
log.trace(JsonValidationReportFormat.getInstance().apply(report));
assertThat("Expected validation errors but found none. Enable trace logging for more details.", report.getMessages(), is(not(empty())));

final List<String> foundKeys = report.getMessages().stream().map(ValidationReport.Message::getKey).collect(toList());
final List<String> foundKeys = report.getMessages().stream().map(ValidationReport.Message::getKey).toList();

for (final String key : expectedKeys) {
assertThat(format("Expected message key '%s' but not found. Found <%s>.", key, foundKeys.toString()),
assertThat(format("Expected message key '%s' but not found. Found <%s>.", key, foundKeys),
foundKeys.contains(key), is(true));
}

Expand Down Expand Up @@ -83,6 +83,16 @@ public static Consumer<ValidationReport> assertPass() {
return ValidatorTestUtil::assertPass;
}

/**
* Returns existing (Optional.isPresent) contexts for messages in {@code report} for message key = {@code key}.
*/
public static List<Optional<ValidationReport.MessageContext>> getContextsForKey(final ValidationReport report, final String key) {
return report.getMessages().stream()
.filter(v -> key.equals(v.getKey()))
.map(ValidationReport.Message::getContext)
.toList();
}

/**
* Load a response JSON file with the given name.
*
Expand Down