/* * Copyright 2013-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.data.rest.tests; import static org.assertj.core.api.Assertions.*; import static org.hamcrest.Matchers.*; import static org.junit.Assume.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; import net.minidev.json.JSONArray; import java.net.URI; import java.util.List; import java.util.Map; import org.junit.Test; import org.springframework.data.rest.webmvc.RestMediaTypes; import org.springframework.hateoas.Link; import org.springframework.hateoas.Links; import org.springframework.hateoas.MediaTypes; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.test.web.servlet.ResultActions; import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; import org.springframework.test.web.servlet.result.MockMvcResultHandlers; import com.jayway.jsonpath.JsonPath; /** * This class contains a common test suite used to verify multiple data stores with the same domain space. When * verifying support of a new data store, it's good to start with extending this suite of tests. However, if the data * store doesn't map well onto this, then a good alternative would be write a new test suite using * {@link org.springframework.data.rest.webmvc.AbstractWebIntegrationTests AbstractWebIntegrationTests} as the test * harness. * * @author Oliver Gierke * @author Greg Turnquist */ public abstract class CommonWebTests extends AbstractWebIntegrationTests { protected abstract Iterable<String> expectedRootLinkRels(); // Root test cases @Test public void exposesRootResource() throws Exception { ResultActions actions = mvc.perform(get("/").accept(TestMvcClient.DEFAULT_MEDIA_TYPE)).andExpect(status().isOk()); for (String rel : expectedRootLinkRels()) { actions.andDo(MockMvcResultHandlers.print()).andExpect(client.hasLinkWithRel(rel)); } } @Test // DATAREST-113, DATAREST-638 public void exposesSchemasForResourcesExposed() throws Exception { MockHttpServletResponse response = client.request("/"); for (String rel : expectedRootLinkRels()) { Link link = client.assertHasLinkWithRel(rel, response); // Resource client.follow(link).andExpect(status().is2xxSuccessful()); Link profileLink = client.discoverUnique(link, "profile"); // Default metadata client.follow(profileLink).andExpect(status().is2xxSuccessful()); // JSON Schema client.follow(profileLink, RestMediaTypes.SCHEMA_JSON).andExpect(status().is2xxSuccessful()); // ALPS client.follow(profileLink, RestMediaTypes.ALPS_JSON).andExpect(status().is2xxSuccessful()); } } @Test // DATAREST-203 public void servesHalWhenRequested() throws Exception { mvc.perform(get("/")). // andExpect(content().contentTypeCompatibleWith(MediaTypes.HAL_JSON)). // andExpect(jsonPath("$._links", notNullValue())); } @Test // DATAREST-203 public void servesHalWhenJsonIsRequested() throws Exception { mvc.perform(get("/").accept(MediaType.APPLICATION_JSON)). // andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)). // andExpect(jsonPath("$._links", notNullValue())); } @Test // DATAREST-203 public void exposesSearchesForRootResources() throws Exception { MockHttpServletResponse response = client.request("/"); for (String rel : expectedRootLinkRels()) { Link link = client.assertHasLinkWithRel(rel, response); String rootResourceRepresentation = client.request(link).getContentAsString(); Link searchLink = client.getDiscoverer(response).findLinkWithRel("search", rootResourceRepresentation); if (searchLink != null) { client.follow(searchLink).// andExpect(client.hasLinkWithRel("self")).// andExpect(jsonPath("$.domainType").doesNotExist()); // DATAREST-549 } } } @Test public void nic() throws Exception { Map<String, String> payloads = getPayloadToPost(); assumeFalse(payloads.isEmpty()); MockHttpServletResponse response = client.request("/"); for (String rel : expectedRootLinkRels()) { String payload = payloads.get(rel); if (payload != null) { Link link = client.assertHasLinkWithRel(rel, response); String target = link.expand().getHref(); MockHttpServletRequestBuilder request = post(target).// content(payload).// contentType(MediaType.APPLICATION_JSON); mvc.perform(request). // andExpect(status().isCreated()); } } } @Test // DATAREST-198 public void accessLinkedResources() throws Exception { MockHttpServletResponse rootResource = client.request("/"); for (Map.Entry<String, List<String>> linked : getRootAndLinkedResources().entrySet()) { Link resourceLink = client.assertHasLinkWithRel(linked.getKey(), rootResource); MockHttpServletResponse resource = client.request(resourceLink); for (String linkedRel : linked.getValue()) { // Find URIs pointing to linked resources String jsonPath = String.format("$._embedded.%s[*]._links.%s.href", linked.getKey(), linkedRel); String representation = resource.getContentAsString(); JSONArray uris = JsonPath.read(representation, jsonPath); for (Object href : uris) { client.follow(href.toString()). // andExpect(status().isOk()); } } } } @Test // DATAREST-230 public void exposesDescriptionAsAlpsDocuments() throws Exception { MediaType ALPS_MEDIA_TYPE = MediaType.valueOf("application/alps+json"); MockHttpServletResponse response = client.request("/"); Link profileLink = client.assertHasLinkWithRel("profile", response); mvc.perform(// get(profileLink.expand().getHref()).// accept(ALPS_MEDIA_TYPE)) .// andExpect(status().isOk()).// andExpect(content().contentTypeCompatibleWith(ALPS_MEDIA_TYPE)); } @Test // DATAREST-448 public void returnsNotFoundForUriNotBackedByARepository() throws Exception { mvc.perform(get("/index.html")).// andExpect(status().isNotFound()); } @Test // DATAREST-658 public void collectionResourcesExposeLinksAsHeadersForHeadRequest() throws Exception { for (String rel : expectedRootLinkRels()) { Link link = client.discoverUnique(rel); MockHttpServletResponse response = mvc.perform(head(link.expand().getHref()))// .andExpect(status().isNoContent())// .andReturn().getResponse(); Links links = Links.valueOf(response.getHeader("Link")); assertThat(links.hasLink(Link.REL_SELF)).isTrue(); assertThat(links.hasLink("profile")).isTrue(); } } @Test // DATAREST-661 public void patchToNonExistingResourceReturnsNotFound() throws Exception { String rel = expectedRootLinkRels().iterator().next(); String uri = client.discoverUnique(rel).expand().getHref().concat("/"); String id = "4711"; Integer status = null; do { // Try to find non existing resource uri = uri.concat(id); status = mvc.perform(get(URI.create(uri))).andReturn().getResponse().getStatus(); } while (status != HttpStatus.NOT_FOUND.value()); // PATCH to non-existing resource mvc.perform(patch(URI.create(uri))).andExpect(status().isNotFound()); } @Test // DATAREST-1003 public void rejectsUnsupportedAcceptTypeForResources() throws Exception { for (String string : expectedRootLinkRels()) { Link link = client.discoverUnique(string); mvc.perform(get(link.expand().getHref())// .accept(MediaType.valueOf("application/schema+json")))// .andExpect(status().isNotAcceptable()); } } }