DATAREST-1356 - Fix updating single associations.

Correct a regression regarding association links. Introduce several test cases to prove this situation is fixed regarding PUTs for association links.

Source of the bug: 554d6cb27b (diff-1d7c16fe1992fef13a47fa8ab8599718L317) flips the criteria from "not single" to "single" without checking for related impacts.
This commit is contained in:
Ľubomír Varga
2019-10-03 05:20:31 +02:00
committed by Greg Turnquist
parent 1e588b5c5a
commit 87f9904e3a
3 changed files with 78 additions and 2 deletions

View File

@@ -28,7 +28,6 @@ import java.util.Optional;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration;
import org.springframework.hateoas.Link;
@@ -61,6 +60,7 @@ import com.jayway.jsonpath.JsonPath;
* @author Oliver Gierke
* @author Greg Turnquist
* @author Christoph Strobl
* @author Ľubomír Varga
*/
@RunWith(SpringRunner.class)
@WebAppConfiguration
@@ -115,6 +115,17 @@ public abstract class AbstractWebIntegrationTests {
return StringUtils.hasText(response.getContentAsString()) ? response : client.request(link);
}
protected MockHttpServletResponse putOnlyExpect5XXStatus(Link link, Object payload, MediaType mediaType)
throws Exception {
String href = link.isTemplated() ? link.expand().getHref() : link.getHref();
MockHttpServletResponse response = mvc.perform(put(href).content(payload.toString()).contentType(mediaType))//
.andExpect(status().is5xxServerError()).andReturn().getResponse();
return StringUtils.hasText(response.getContentAsString()) ? response : client.request(link);
}
protected MockHttpServletResponse patchAndGet(Link link, Object payload, MediaType mediaType) throws Exception {
String href = link.isTemplated() ? link.expand().getHref() : link.getHref();

View File

@@ -61,6 +61,7 @@ import com.jayway.jsonpath.JsonPath;
* @author Oliver Gierke
* @author Greg Turnquist
* @author Mark Paluch
* @author Ľubomír Varga
*/
@Transactional
@ContextConfiguration(classes = JpaRepositoryConfig.class)
@@ -321,6 +322,40 @@ public class JpaWebTests extends CommonWebTests {
assertSiblingNames(frodoSiblingLink, "Merry", "Pippin");
}
/**
* Test does simulate changing creator association from Order to Person. First it sets Frodo Baggins as creator and
* checks for its first name. Than it sets Pippin Baggins as creator of the Order. Check for first name is done again.
*/
@Test // DATAREST-1356
public void associateCreatorToOrderWithSinglePut() throws Exception {
Link firstCreatorLink = preparePersonResource(new Person("Frodo", "Baggins"));
Link secondCreatorLink = preparePersonResource(new Person("Pippin", "Baggins"));
Link orderLinkToItsCreator = prepareOrderResource(new Order());
putAndGet(orderLinkToItsCreator, toUriList(firstCreatorLink), TEXT_URI_LIST);
assertCreatorName(orderLinkToItsCreator, "Frodo");
putAndGet(orderLinkToItsCreator, toUriList(secondCreatorLink), TEXT_URI_LIST);
assertCreatorName(orderLinkToItsCreator, "Pippin");
}
/**
* Negative test scenario, which does try to put two persons at once as the creator of Order. We expect that result
* will contain "send only 1 link" substring.
*/
@Test // DATAREST-1356
public void associateTwoCreatorsToOrderWithSinglePut() throws Exception {
Link firstCreatorLink = preparePersonResource(new Person("Frodo", "Baggins"));
Link secondCreatorLink = preparePersonResource(new Person("Pippin", "Baggins"));
Link orderLinkToItsCreator = prepareOrderResource(new Order());
MockHttpServletResponse response = putOnlyExpect5XXStatus(orderLinkToItsCreator,
toUriList(firstCreatorLink, secondCreatorLink), TEXT_URI_LIST);
assertThat(response.getContentAsString()).contains("send only 1 link");
}
@Test // DATAREST-219
public void manipulatePropertyCollectionRestfullyWithDelete() throws Exception {
@@ -673,6 +708,28 @@ public class JpaWebTests extends CommonWebTests {
return links;
}
/**
* @return link to creator of order (associative link for given order instance)
*/
private Link prepareOrderResource(Order order) throws Exception {
Link orderLink = client.discoverUnique(LinkRelation.of("orders"));
MockHttpServletResponse primaryResponse = postAndGet(orderLink, mapper.writeValueAsString(order),
MediaType.APPLICATION_JSON);
return client.assertHasLinkWithRel("creator", primaryResponse);
}
/**
* @return link to given person (canonical, self, link)
*/
private Link preparePersonResource(Person person) throws Exception {
Link orderLink = client.discoverUnique(LinkRelation.of("people"));
MockHttpServletResponse primaryResponse = postAndGet(orderLink, mapper.writeValueAsString(person),
MediaType.APPLICATION_JSON);
return client.assertHasLinkWithRel("self", primaryResponse);
}
/**
* Asserts the {@link Person} resource the given link points to contains siblings with the given names.
*
@@ -689,6 +746,13 @@ public class JpaWebTests extends CommonWebTests {
assertThat(persons).contains(siblingNames);
}
private void assertCreatorName(Link orderLinkToItsCreator, String creatorName) throws Exception {
String responseBody = client.request(orderLinkToItsCreator).getContentAsString();
String personFirstName = JsonPath.read(responseBody, "$.firstName");
assertThat(personFirstName).isEqualTo(creatorName);
}
private void assertPersonWithNameAndSiblingLink(String name) throws Exception {
MockHttpServletResponse response = client.request(client.discoverUnique(LinkRelation.of("people")));

View File

@@ -77,6 +77,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
* @author Jon Brisbin
* @author Oliver Gierke
* @author Greg Turnquist
* @author Ľubomír Varga
*/
@RepositoryRestController
@SuppressWarnings({ "unchecked" })
@@ -318,7 +319,7 @@ class RepositoryPropertyReferenceController extends AbstractRepositoryRestContro
"Cannot PATCH a reference to this singular property since the property type is not a List or a Map.");
}
if (source.getLinks().hasSingleLink()) {
if (!source.getLinks().hasSingleLink()) {
throw new IllegalArgumentException(
"Must send only 1 link to update a property reference that isn't a List or a Map.");
}