Allow links to be optional

Previously, if a link was documented then it had to be present in the
response payload for the test to pass. This was unnecessarily
restrictive and caused problems when a link was omitted due to the
application's current state.

This commit allows a link to be declared as optional. If a link is
optional then the test will pass irrespective of the link's presence
in the response.

See gh-74
This commit is contained in:
Kellen Dye
2015-06-10 15:48:57 +02:00
committed by Andy Wilkinson
parent 0e5151e91b
commit 0699cdd068
3 changed files with 43 additions and 6 deletions

View File

@@ -29,6 +29,8 @@ public class LinkDescriptor {
private String description;
private boolean optional;
LinkDescriptor(String rel) {
this.rel = rel;
}
@@ -44,6 +46,16 @@ public class LinkDescriptor {
return this;
}
/**
* Marks the link as optional
*
* @return {@code this}
*/
public LinkDescriptor optional() {
this.optional = true;
return this;
}
String getRel() {
return this.rel;
}
@@ -51,4 +63,8 @@ public class LinkDescriptor {
String getDescription() {
return this.description;
}
boolean isOptional() {
return this.optional;
}
}

View File

@@ -42,6 +42,8 @@ public class LinkSnippetResultHandler extends SnippetWritingResultHandler {
private final Map<String, LinkDescriptor> descriptorsByRel = new LinkedHashMap<>();
private final Set<String> requiredRels = new HashSet<String>();
private final LinkExtractor extractor;
LinkSnippetResultHandler(String outputDir, LinkExtractor linkExtractor,
@@ -52,6 +54,9 @@ public class LinkSnippetResultHandler extends SnippetWritingResultHandler {
Assert.hasText(descriptor.getRel());
Assert.hasText(descriptor.getDescription());
this.descriptorsByRel.put(descriptor.getRel(), descriptor);
if (!descriptor.isOptional()) {
this.requiredRels.add(descriptor.getRel());
}
}
}
@@ -78,12 +83,11 @@ public class LinkSnippetResultHandler extends SnippetWritingResultHandler {
}
Set<String> actualRels = links.keySet();
Set<String> expectedRels = this.descriptorsByRel.keySet();
Set<String> undocumentedRels = new HashSet<String>(actualRels);
undocumentedRels.removeAll(expectedRels);
undocumentedRels.removeAll(this.descriptorsByRel.keySet());
Set<String> missingRels = new HashSet<String>(expectedRels);
Set<String> missingRels = new HashSet<String>(this.requiredRels);
missingRels.removeAll(actualRels);
if (!undocumentedRels.isEmpty() || !missingRels.isEmpty()) {
@@ -102,8 +106,6 @@ public class LinkSnippetResultHandler extends SnippetWritingResultHandler {
throw new SnippetGenerationException(message);
}
Assert.isTrue(actualRels.equals(expectedRels));
writer.table(new TableAction() {
@Override

View File

@@ -60,10 +60,29 @@ public class HypermediaDocumentationTests {
this.thrown.expect(SnippetGenerationException.class);
this.thrown.expectMessage(equalTo("Links with the following relations were not"
+ " found in the response: [foo]"));
documentLinks("undocumented-link", new StubLinkExtractor(),
documentLinks("missing-link", new StubLinkExtractor(),
new LinkDescriptor("foo").description("bar")).handle(result());
}
@Test
public void documentedOptionalLink() throws IOException {
this.snippet.expectLinks("documented-optional-link").withContents( //
tableWithHeader("Relation", "Description") //
.row("foo", "bar"));
documentLinks("documented-optional-link",
new StubLinkExtractor().withLinks(new Link("foo", "blah")),
new LinkDescriptor("foo").description("bar").optional()).handle(result());
}
@Test
public void missingOptionalLink() throws IOException {
this.snippet.expectLinks("missing-optional-link").withContents( //
tableWithHeader("Relation", "Description") //
.row("foo", "bar"));
documentLinks("missing-optional-link", new StubLinkExtractor(),
new LinkDescriptor("foo").description("bar").optional()).handle(result());
}
@Test
public void undocumentedLinkAndMissingLink() throws IOException {
this.thrown.expect(SnippetGenerationException.class);