DATAREST-774 - Separated integration tests from core project to avoid classpath overlap.
Extracted store specific tests into separate test modules to prevent classpath overlap between projects. Those tests are now executed in an "it" build profile to prevent the tests being packaged for distribution on release. Use Map-based repositories and mapping contexts for test in the Core and WebMvc module. Slightly changed the configuration API for lookup types on RepositoryRestConfiguration. Related ticket: DATAREST-776.
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2012-2016 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.mongodb;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
|
||||
import org.springframework.data.mongodb.config.EnableMongoAuditing;
|
||||
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
|
||||
|
||||
import com.mongodb.Mongo;
|
||||
import com.mongodb.MongoClient;
|
||||
|
||||
/**
|
||||
* @author Jon Brisbin
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Configuration
|
||||
@EnableMongoRepositories
|
||||
@EnableMongoAuditing
|
||||
public class MongoDbRepositoryConfig extends AbstractMongoConfiguration {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.config.AbstractMongoConfiguration#getDatabaseName()
|
||||
*/
|
||||
@Override
|
||||
protected String getDatabaseName() {
|
||||
return "spring-data-rest-sample";
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.config.AbstractMongoConfiguration#getMappingBasePackage()
|
||||
*/
|
||||
@Override
|
||||
protected String getMappingBasePackage() {
|
||||
return "";
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.config.AbstractMongoConfiguration#mongo()
|
||||
*/
|
||||
@Override
|
||||
public Mongo mongo() throws Exception {
|
||||
return new MongoClient();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,352 @@
|
||||
/*
|
||||
* Copyright 2013-2016 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.mongodb;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.http.HttpHeaders.*;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.rest.tests.CommonWebTests;
|
||||
import org.springframework.data.rest.tests.mongodb.Address;
|
||||
import org.springframework.data.rest.tests.mongodb.Profile;
|
||||
import org.springframework.data.rest.tests.mongodb.ProfileRepository;
|
||||
import org.springframework.data.rest.tests.mongodb.Receipt;
|
||||
import org.springframework.data.rest.tests.mongodb.User;
|
||||
import org.springframework.data.rest.tests.mongodb.UserRepository;
|
||||
import org.springframework.data.rest.webmvc.RestMediaTypes;
|
||||
import org.springframework.data.rest.webmvc.support.RepositoryEntityLinks;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.jayway.jsonpath.JsonPath;
|
||||
|
||||
/**
|
||||
* Integration tests for MongoDB repositories.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
@ContextConfiguration(classes = MongoDbRepositoryConfig.class)
|
||||
public class MongoWebTests extends CommonWebTests {
|
||||
|
||||
@Autowired ProfileRepository repository;
|
||||
@Autowired UserRepository userRepository;
|
||||
@Autowired RepositoryEntityLinks entityLinks;
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
@Before
|
||||
public void populateProfiles() {
|
||||
|
||||
mapper.setSerializationInclusion(Include.NON_NULL);
|
||||
|
||||
Profile twitter = new Profile();
|
||||
twitter.setPerson(1L);
|
||||
twitter.setType("Twitter");
|
||||
|
||||
Profile linkedIn = new Profile();
|
||||
linkedIn.setPerson(1L);
|
||||
linkedIn.setType("LinkedIn");
|
||||
|
||||
repository.save(Arrays.asList(twitter, linkedIn));
|
||||
|
||||
Address address = new Address();
|
||||
address.street = "ETagDoesntMatchExceptionUnitTests";
|
||||
address.zipCode = "Bar";
|
||||
|
||||
User thomas = new User();
|
||||
thomas.firstname = "Thomas";
|
||||
thomas.lastname = "Darimont";
|
||||
thomas.address = address;
|
||||
|
||||
userRepository.save(thomas);
|
||||
|
||||
User oliver = new User();
|
||||
oliver.firstname = "Oliver";
|
||||
oliver.lastname = "Gierke";
|
||||
oliver.address = address;
|
||||
oliver.colleagues = Arrays.asList(thomas);
|
||||
userRepository.save(oliver);
|
||||
|
||||
thomas.colleagues = Arrays.asList(oliver);
|
||||
userRepository.save(thomas);
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanUp() {
|
||||
repository.deleteAll();
|
||||
userRepository.deleteAll();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.webmvc.AbstractWebIntegrationTests#expectedRootLinkRels()
|
||||
*/
|
||||
@Override
|
||||
protected Iterable<String> expectedRootLinkRels() {
|
||||
return Arrays.asList("profiles", "users");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void foo() throws Exception {
|
||||
|
||||
Link profileLink = client.discoverUnique("profiles");
|
||||
client.follow(profileLink).//
|
||||
andExpect(jsonPath("$._embedded.profiles").value(hasSize(2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rendersEmbeddedDocuments() throws Exception {
|
||||
|
||||
Link usersLink = client.discoverUnique("users");
|
||||
Link userLink = assertHasContentLinkWithRel("self", client.request(usersLink));
|
||||
client.follow(userLink).//
|
||||
andExpect(jsonPath("$.address.zipCode").value(is(notNullValue())));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-247
|
||||
*/
|
||||
@Test
|
||||
public void executeQueryMethodWithPrimitiveReturnType() throws Exception {
|
||||
|
||||
Link profiles = client.discoverUnique("profiles");
|
||||
Link profileSearches = client.discoverUnique(profiles, "search");
|
||||
Link countByTypeLink = client.discoverUnique(profileSearches, "countByType");
|
||||
|
||||
assertThat(countByTypeLink.isTemplated(), is(true));
|
||||
assertThat(countByTypeLink.getVariableNames(), hasItem("type"));
|
||||
|
||||
MockHttpServletResponse response = client.request(countByTypeLink.expand("Twitter"));
|
||||
assertThat(response.getContentAsString(), is("1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testname() throws Exception {
|
||||
|
||||
Link usersLink = client.discoverUnique("users");
|
||||
Link userLink = assertHasContentLinkWithRel("self", client.request(usersLink));
|
||||
|
||||
MockHttpServletResponse response = patchAndGet(userLink,
|
||||
"{\"lastname\" : null, \"address\" : { \"zipCode\" : \"ZIP\"}}", MediaType.APPLICATION_JSON);
|
||||
|
||||
assertThat(JsonPath.read(response.getContentAsString(), "$.lastname"), is(nullValue()));
|
||||
assertThat(JsonPath.read(response.getContentAsString(), "$.address.zipCode"), is((Object) "ZIP"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testname2() throws Exception {
|
||||
|
||||
Link usersLink = client.discoverUnique("users");
|
||||
Link userLink = assertHasContentLinkWithRel("self", client.request(usersLink));
|
||||
|
||||
MockHttpServletResponse response = patchAndGet(userLink,
|
||||
"[{ \"op\": \"replace\", \"path\": \"/address/zipCode\", \"value\": \"ZIP\" },"
|
||||
// + "{ \"op\": \"replace\", \"path\": \"/lastname\", \"value\": null }]", //
|
||||
+ "{ \"op\": \"remove\", \"path\": \"/lastname\" }]", //
|
||||
RestMediaTypes.JSON_PATCH_JSON);
|
||||
|
||||
assertThat(JsonPath.read(response.getContentAsString(), "$.lastname"), is(nullValue()));
|
||||
assertThat(JsonPath.read(response.getContentAsString(), "$.address.zipCode"), is((Object) "ZIP"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-160
|
||||
*/
|
||||
@Test
|
||||
public void returnConflictWhenConcurrentlyEditingVersionedEntity() throws Exception {
|
||||
|
||||
Link receiptLink = client.discoverUnique("receipts");
|
||||
|
||||
Receipt receipt = new Receipt();
|
||||
receipt.amount = new BigDecimal(50);
|
||||
receipt.saleItem = "Springy Tacos";
|
||||
|
||||
String stringReceipt = mapper.writeValueAsString(receipt);
|
||||
|
||||
MockHttpServletResponse createdReceipt = postAndGet(receiptLink, stringReceipt, MediaType.APPLICATION_JSON);
|
||||
Link tacosLink = client.assertHasLinkWithRel("self", createdReceipt);
|
||||
assertJsonPathEquals("$.saleItem", "Springy Tacos", createdReceipt);
|
||||
|
||||
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(tacosLink.getHref());
|
||||
String concurrencyTag = createdReceipt.getHeader("ETag");
|
||||
|
||||
mvc.perform(patch(builder.build().toUriString()).content("{ \"saleItem\" : \"SpringyBurritos\" }")
|
||||
.contentType(MediaType.APPLICATION_JSON).header(IF_MATCH, concurrencyTag))
|
||||
.andExpect(status().is2xxSuccessful());
|
||||
|
||||
mvc.perform(patch(builder.build().toUriString()).content("{ \"saleItem\" : \"SpringyTequila\" }")
|
||||
.contentType(MediaType.APPLICATION_JSON).header(IF_MATCH, concurrencyTag))
|
||||
.andExpect(status().isPreconditionFailed());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-471
|
||||
*/
|
||||
@Test
|
||||
public void auditableResourceHasLastModifiedHeaderSet() throws Exception {
|
||||
|
||||
Profile profile = repository.findAll().iterator().next();
|
||||
|
||||
String header = mvc.perform(get("/profiles/{id}", profile.getId())).//
|
||||
andReturn().getResponse().getHeader("Last-Modified");
|
||||
|
||||
assertThat(header, not(isEmptyOrNullString()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-482
|
||||
*/
|
||||
@Test
|
||||
public void putDoesNotRemoveAssociations() throws Exception {
|
||||
|
||||
Link usersLink = client.discoverUnique("users");
|
||||
Link userLink = assertHasContentLinkWithRel("self", client.request(usersLink));
|
||||
Link colleaguesLink = client.assertHasLinkWithRel("colleagues", client.request(userLink));
|
||||
|
||||
// Expect a user returned as colleague
|
||||
client.follow(colleaguesLink).//
|
||||
andExpect(jsonPath("$._embedded.users").exists());
|
||||
|
||||
User oliver = new User();
|
||||
oliver.firstname = "Oliver";
|
||||
oliver.lastname = "Gierke";
|
||||
|
||||
putAndGet(userLink, mapper.writeValueAsString(oliver), MediaType.APPLICATION_JSON);
|
||||
|
||||
// Expect colleague still present but address has been wiped
|
||||
client.follow(colleaguesLink).//
|
||||
andExpect(jsonPath("$._embedded.users").exists()).//
|
||||
andExpect(jsonPath("$.embedded.users[0].address").doesNotExist());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-482
|
||||
*/
|
||||
@Test
|
||||
public void emptiesAssociationForEmptyUriList() throws Exception {
|
||||
|
||||
Link usersLink = client.discoverUnique("users");
|
||||
Link userLink = assertHasContentLinkWithRel("self", client.request(usersLink));
|
||||
Link colleaguesLink = client.assertHasLinkWithRel("colleagues", client.request(userLink));
|
||||
|
||||
putAndGet(colleaguesLink, "", MediaType.parseMediaType("text/uri-list"));
|
||||
|
||||
client.follow(colleaguesLink).//
|
||||
andExpect(status().isOk()).//
|
||||
andExpect(jsonPath("$").exists());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-491
|
||||
*/
|
||||
@Test
|
||||
public void updatesMapPropertyCorrectly() throws Exception {
|
||||
|
||||
Link profilesLink = client.discoverUnique("profiles");
|
||||
Link profileLink = assertHasContentLinkWithRel("self", client.request(profilesLink));
|
||||
|
||||
Profile profile = new Profile();
|
||||
profile.setMetadata(Collections.singletonMap("Key", "Value"));
|
||||
|
||||
putAndGet(profileLink, mapper.writeValueAsString(profile), MediaType.APPLICATION_JSON);
|
||||
|
||||
client.follow(profileLink).andExpect(jsonPath("$.metadata.Key").value("Value"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-506
|
||||
*/
|
||||
@Test
|
||||
public void supportsConditionalGetsOnItemResource() throws Exception {
|
||||
|
||||
Receipt receipt = new Receipt();
|
||||
receipt.amount = new BigDecimal(50);
|
||||
receipt.saleItem = "Springy Tacos";
|
||||
|
||||
Link receiptsLink = client.discoverUnique("receipts");
|
||||
|
||||
MockHttpServletResponse response = postAndGet(receiptsLink, mapper.writeValueAsString(receipt),
|
||||
MediaType.APPLICATION_JSON);
|
||||
|
||||
Link receiptLink = client.getDiscoverer(response).findLinkWithRel("self", response.getContentAsString());
|
||||
|
||||
mvc.perform(get(receiptLink.getHref()).header(IF_MODIFIED_SINCE, response.getHeader(LAST_MODIFIED))).//
|
||||
andExpect(status().isNotModified()).//
|
||||
andExpect(header().string(ETAG, is(notNullValue())));
|
||||
|
||||
mvc.perform(get(receiptLink.getHref()).header(IF_NONE_MATCH, response.getHeader(ETAG))).//
|
||||
andExpect(status().isNotModified()).//
|
||||
andExpect(header().string(ETAG, is(notNullValue())));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-511
|
||||
*/
|
||||
@Test
|
||||
public void invokesQueryResourceReturningAnOptional() throws Exception {
|
||||
|
||||
Profile profile = repository.findAll().iterator().next();
|
||||
|
||||
Link link = client.discoverUnique("profiles", "search", "findById");
|
||||
|
||||
mvc.perform(get(link.expand(profile.getId()).getHref())).//
|
||||
andExpect(status().isOk());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-517
|
||||
*/
|
||||
@Test
|
||||
public void returnsNotFoundIfQueryExecutionDoesNotReturnResult() throws Exception {
|
||||
|
||||
Link link = client.discoverUnique("profiles", "search", "findById");
|
||||
|
||||
mvc.perform(get(link.expand("").getHref())).//
|
||||
andExpect(status().isNotFound());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-712
|
||||
*/
|
||||
@Test
|
||||
public void invokesQueryMethodTakingAReferenceCorrectly() throws Exception {
|
||||
|
||||
Link link = client.discoverUnique("users", "search", "findByColleaguesContains");
|
||||
|
||||
User thomas = userRepository.findAll(QUser.user.firstname.eq("Thomas")).iterator().next();
|
||||
Link thomasUri = entityLinks.linkToSingleResource(User.class, thomas.id).expand();
|
||||
|
||||
String href = link.expand(thomasUri.getHref()).getHref();
|
||||
|
||||
mvc.perform(get(href)).andExpect(status().isOk());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2014-2016 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.mongodb;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Test helper methods.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class TestUtils {
|
||||
|
||||
private static final Charset UTF8 = Charset.forName("UTF-8");
|
||||
|
||||
/**
|
||||
* Returns the given {@link String} as {@link InputStream}.
|
||||
*
|
||||
* @param source must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static InputStream asStream(String source) {
|
||||
Assert.notNull(source, "Source string must not be null!");
|
||||
return new ByteArrayInputStream(source.getBytes(UTF8));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2015-2016 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.webmvc;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Test;
|
||||
import org.mockito.internal.stubbing.answers.ReturnsArgumentAt;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.rest.core.support.DefaultSelfLinkProvider;
|
||||
import org.springframework.data.rest.core.support.EntityLookup;
|
||||
import org.springframework.data.rest.tests.AbstractControllerIntegrationTests;
|
||||
import org.springframework.data.rest.tests.AbstractControllerIntegrationTests.TestConfiguration;
|
||||
import org.springframework.data.rest.tests.mongodb.MongoDbRepositoryConfig;
|
||||
import org.springframework.data.rest.tests.mongodb.User;
|
||||
import org.springframework.data.rest.webmvc.mapping.Associations;
|
||||
import org.springframework.data.rest.webmvc.support.Projector;
|
||||
import org.springframework.hateoas.EntityLinks;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.Links;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link PersistentEntityResourceAssembler}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@ContextConfiguration(classes = { TestConfiguration.class, MongoDbRepositoryConfig.class })
|
||||
public class PersistentEntityResourceAssemblerIntegrationTests extends AbstractControllerIntegrationTests {
|
||||
|
||||
@Autowired PersistentEntities entities;
|
||||
@Autowired EntityLinks entityLinks;
|
||||
@Autowired @Qualifier("objectMapper") ObjectMapper objectMapper;
|
||||
@Autowired Associations associations;
|
||||
|
||||
/**
|
||||
* @see DATAREST-609
|
||||
*/
|
||||
@Test
|
||||
public void addsSelfAndSingleResourceLinkToResourceByDefault() throws Exception {
|
||||
|
||||
Projector projector = mock(Projector.class);
|
||||
|
||||
when(projector.projectExcerpt(anyObject())).thenAnswer(new ReturnsArgumentAt(0));
|
||||
|
||||
PersistentEntityResourceAssembler assembler = new PersistentEntityResourceAssembler(entities, projector,
|
||||
associations, new DefaultSelfLinkProvider(entities, entityLinks, Collections.<EntityLookup<?>> emptyList()));
|
||||
|
||||
User user = new User();
|
||||
user.id = BigInteger.valueOf(4711);
|
||||
|
||||
PersistentEntityResource resource = assembler.toResource(user);
|
||||
|
||||
Links links = new Links(resource.getLinks());
|
||||
|
||||
assertThat(links, is(Matchers.<Link> iterableWithSize(2)));
|
||||
assertThat(links.getLink("self").getVariables(), is(Matchers.empty()));
|
||||
assertThat(links.getLink("user").getVariableNames(), is(hasItem("projection")));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2015-2016 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.webmvc;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.rest.tests.AbstractControllerIntegrationTests;
|
||||
import org.springframework.data.rest.tests.mongodb.MongoDbRepositoryConfig;
|
||||
import org.springframework.data.rest.webmvc.support.DelegatingHandlerMapping;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.HandlerExecutionChain;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link BasePathAwareHandlerMapping}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @soundtrack Elephants Crossing - Echo (Irrelephant)
|
||||
*/
|
||||
@ContextConfiguration(classes = MongoDbRepositoryConfig.class)
|
||||
public class RepositoryRestHandlerMappingIntegrationTests extends AbstractControllerIntegrationTests {
|
||||
|
||||
@Autowired DelegatingHandlerMapping mapping;
|
||||
|
||||
/**
|
||||
* @see DATAREST-617
|
||||
*/
|
||||
@Test
|
||||
public void usesMethodsWithoutProducesClauseForGeneralJsonRequests() throws Exception {
|
||||
|
||||
MockHttpServletRequest mockRequest = new MockHttpServletRequest("GET", "/users");
|
||||
mockRequest.addHeader("Accept", "application/*+json");
|
||||
|
||||
HandlerExecutionChain chain = mapping.getHandler(mockRequest);
|
||||
|
||||
assertThat(chain, is(notNullValue()));
|
||||
|
||||
Object handler = chain.getHandler();
|
||||
assertThat(handler, is(instanceOf(HandlerMethod.class)));
|
||||
|
||||
HandlerMethod method = (HandlerMethod) handler;
|
||||
assertThat(method.getMethod().getDeclaringClass(), is(typeCompatibleWith(RepositoryEntityController.class)));
|
||||
assertThat(method.getMethod().getName(), is("getCollectionResource"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2013-2016 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.webmvc.config;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
/**
|
||||
* Base class for integration tests that are run against a particular configuration defined by the subclass.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@WebAppConfiguration
|
||||
public abstract class AbstractRepositoryRestMvcConfigurationIntegrationTests {
|
||||
|
||||
@Autowired WebApplicationContext context;
|
||||
protected MockMvc mvc;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
this.mvc = MockMvcBuilders.webAppContextSetup(context).build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 2014-2016 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.webmvc.config;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.springframework.data.rest.tests.mongodb.TestUtils.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMappings;
|
||||
import org.springframework.data.rest.tests.mongodb.Address;
|
||||
import org.springframework.data.rest.tests.mongodb.User;
|
||||
import org.springframework.data.rest.webmvc.RestMediaTypes;
|
||||
import org.springframework.data.rest.webmvc.json.DomainObjectReader;
|
||||
import org.springframework.data.rest.webmvc.mapping.Associations;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link JsonPatchHandler}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class JsonPatchHandlerUnitTests {
|
||||
|
||||
JsonPatchHandler handler;
|
||||
User user;
|
||||
|
||||
@Mock ResourceMappings mappings;
|
||||
public @Rule ExpectedException exception = ExpectedException.none();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
MongoMappingContext context = new MongoMappingContext();
|
||||
context.getPersistentEntity(User.class);
|
||||
|
||||
PersistentEntities entities = new PersistentEntities(Arrays.asList(context));
|
||||
|
||||
Associations associations = new Associations(mappings, mock(RepositoryRestConfiguration.class));
|
||||
|
||||
this.handler = new JsonPatchHandler(new ObjectMapper(), new DomainObjectReader(entities, associations));
|
||||
|
||||
Address address = new Address();
|
||||
address.street = "Foo";
|
||||
address.zipCode = "Bar";
|
||||
|
||||
this.user = new User();
|
||||
this.user.firstname = "Oliver";
|
||||
this.user.lastname = "Gierke";
|
||||
this.user.address = address;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-348
|
||||
*/
|
||||
@Test
|
||||
public void appliesRemoveOperationCorrectly() throws Exception {
|
||||
|
||||
String input = "[{ \"op\": \"replace\", \"path\": \"/address/zipCode\", \"value\": \"ZIP\" },"
|
||||
+ "{ \"op\": \"remove\", \"path\": \"/lastname\" }]";
|
||||
|
||||
User result = handler.applyPatch(asStream(input), user);
|
||||
|
||||
assertThat(result.lastname, is(nullValue()));
|
||||
assertThat(result.address.zipCode, is("ZIP"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-348
|
||||
*/
|
||||
@Test
|
||||
public void appliesMergePatchCorrectly() throws Exception {
|
||||
|
||||
String input = "{ \"address\" : { \"zipCode\" : \"ZIP\"}, \"lastname\" : null }";
|
||||
|
||||
User result = handler.applyMergePatch(asStream(input), user);
|
||||
|
||||
assertThat(result.lastname, is(nullValue()));
|
||||
assertThat(result.address.zipCode, is("ZIP"));
|
||||
}
|
||||
|
||||
/**
|
||||
* DATAREST-537
|
||||
*/
|
||||
@Test
|
||||
public void removesArrayItemCorrectly() throws Exception {
|
||||
|
||||
User thomas = new User();
|
||||
thomas.firstname = "Thomas";
|
||||
|
||||
User christoph = new User();
|
||||
christoph.firstname = "Christoph";
|
||||
|
||||
this.user.colleagues = Arrays.asList(thomas, christoph);
|
||||
|
||||
String input = "[{ \"op\": \"remove\", \"path\": \"/colleagues/0\" }]";
|
||||
|
||||
handler.applyPatch(asStream(input), user);
|
||||
|
||||
assertThat(user.colleagues, hasSize(1));
|
||||
assertThat(user.colleagues.get(0).firstname, is(christoph.firstname));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-609
|
||||
*/
|
||||
@Test
|
||||
public void hintsToMediaTypeIfBodyCantBeRead() throws Exception {
|
||||
|
||||
exception.expect(HttpMessageNotReadableException.class);
|
||||
exception.expectMessage(RestMediaTypes.JSON_PATCH_JSON.toString());
|
||||
|
||||
handler.applyPatch(asStream("{ \"foo\" : \"bar\" }"), new User());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2013-2016 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.webmvc.config;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
|
||||
import org.springframework.data.rest.tests.mongodb.MongoDbRepositoryConfig;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
/**
|
||||
* Integration tests to check the legacy representation is rendered if HAL is not the default media type.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@ContextConfiguration
|
||||
public class LegacyRepresentationConfigIntegrationTests extends AbstractRepositoryRestMvcConfigurationIntegrationTests {
|
||||
|
||||
@Configuration
|
||||
@Import({ MongoDbRepositoryConfig.class, RepositoryRestMvcConfiguration.class })
|
||||
static class Config extends RepositoryRestConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
|
||||
config.setDefaultMediaType(MediaType.APPLICATION_JSON);
|
||||
config.useHalAsDefaultJsonMediaType(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-213, DATAREST-617
|
||||
*/
|
||||
@Test
|
||||
public void returnsJsonIfConfiguredAndRequested() throws Exception {
|
||||
|
||||
for (String resource : Arrays.asList("/", "/users")) {
|
||||
|
||||
mvc.perform(get(resource).accept(MediaType.APPLICATION_JSON)). //
|
||||
andExpect(jsonPath("links", is(notNullValue())));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-213, DATAREST-617
|
||||
*/
|
||||
@Test
|
||||
public void returnsJsonIfConfigured() throws Exception {
|
||||
|
||||
for (String resource : Arrays.asList("/", "/users")) {
|
||||
|
||||
mvc.perform(get(resource).accept(MediaType.ALL)). //
|
||||
andExpect(jsonPath("links", is(notNullValue())));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright 2015-2016 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.webmvc.config;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
|
||||
import org.springframework.data.querydsl.QuerydslRepositoryInvokerAdapter;
|
||||
import org.springframework.data.querydsl.SimpleEntityPathResolver;
|
||||
import org.springframework.data.querydsl.binding.QuerydslBinderCustomizer;
|
||||
import org.springframework.data.querydsl.binding.QuerydslBindings;
|
||||
import org.springframework.data.querydsl.binding.QuerydslBindingsFactory;
|
||||
import org.springframework.data.querydsl.binding.QuerydslPredicate;
|
||||
import org.springframework.data.querydsl.binding.QuerydslPredicateBuilder;
|
||||
import org.springframework.data.repository.support.Repositories;
|
||||
import org.springframework.data.repository.support.RepositoryInvoker;
|
||||
import org.springframework.data.repository.support.RepositoryInvokerFactory;
|
||||
import org.springframework.data.rest.tests.mongodb.QUser;
|
||||
import org.springframework.data.rest.tests.mongodb.Receipt;
|
||||
import org.springframework.data.rest.tests.mongodb.ReceiptRepository;
|
||||
import org.springframework.data.rest.tests.mongodb.User;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link QuerydslAwareRootResourceInformationHandlerMethodArgumentResolver}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class QuerydslAwareRootResourceInformationHandlerMethodArgumentResolverUnitTests {
|
||||
|
||||
static final Map<String, String[]> NO_PARAMETERS = Collections.emptyMap();
|
||||
|
||||
@Mock Repositories repositories;
|
||||
@Mock RepositoryInvokerFactory invokerFactory;
|
||||
@Mock ResourceMetadataHandlerMethodArgumentResolver resourceMetadataResolver;
|
||||
|
||||
@Mock RepositoryInvoker invoker;
|
||||
@Mock MethodParameter parameter;
|
||||
|
||||
QuerydslAwareRootResourceInformationHandlerMethodArgumentResolver resolver;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
QuerydslBindingsFactory factory = new QuerydslBindingsFactory(SimpleEntityPathResolver.INSTANCE);
|
||||
ReflectionTestUtils.setField(factory, "repositories", repositories);
|
||||
QuerydslPredicateBuilder builder = new QuerydslPredicateBuilder(new DefaultConversionService(),
|
||||
factory.getEntityPathResolver());
|
||||
|
||||
this.resolver = new QuerydslAwareRootResourceInformationHandlerMethodArgumentResolver(repositories, invokerFactory,
|
||||
resourceMetadataResolver, builder, factory);
|
||||
|
||||
when(parameter.hasParameterAnnotation(QuerydslPredicate.class)).thenReturn(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-616
|
||||
*/
|
||||
@Test
|
||||
public void returnsInvokerIfRepositoryIsNotQuerydslAware() {
|
||||
|
||||
ReceiptRepository repository = mock(ReceiptRepository.class);
|
||||
when(repositories.getRepositoryFor(Receipt.class)).thenReturn(repository);
|
||||
|
||||
RepositoryInvoker result = resolver.postProcess(parameter, invoker, Receipt.class, NO_PARAMETERS);
|
||||
|
||||
assertThat(result, is(invoker));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-616
|
||||
*/
|
||||
@Test
|
||||
public void wrapsInvokerInQuerydslAdapter() {
|
||||
|
||||
Object repository = mock(QuerydslUserRepository.class);
|
||||
when(repositories.getRepositoryFor(User.class)).thenReturn(repository);
|
||||
|
||||
RepositoryInvoker result = resolver.postProcess(parameter, invoker, User.class, NO_PARAMETERS);
|
||||
|
||||
assertThat(result, is(instanceOf(QuerydslRepositoryInvokerAdapter.class)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-616
|
||||
*/
|
||||
@Test
|
||||
public void invokesCustomizationOnRepositoryIfItImplementsCustomizer() {
|
||||
|
||||
QuerydslCustomizingUserRepository repository = mock(QuerydslCustomizingUserRepository.class);
|
||||
when(repositories.hasRepositoryFor(User.class)).thenReturn(true);
|
||||
when(repositories.getRepositoryFor(User.class)).thenReturn(repository);
|
||||
|
||||
RepositoryInvoker result = resolver.postProcess(parameter, invoker, User.class, NO_PARAMETERS);
|
||||
|
||||
assertThat(result, is(instanceOf(QuerydslRepositoryInvokerAdapter.class)));
|
||||
verify(repository, times(1)).customize(Mockito.any(QuerydslBindings.class), Mockito.any(QUser.class));
|
||||
}
|
||||
|
||||
interface QuerydslUserRepository extends QueryDslPredicateExecutor<User> {}
|
||||
|
||||
interface QuerydslCustomizingUserRepository
|
||||
extends QueryDslPredicateExecutor<User>, QuerydslBinderCustomizer<QUser> {}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright 2012-2016 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.webmvc.json;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.support.MessageSourceAccessor;
|
||||
import org.springframework.context.support.StaticMessageSource;
|
||||
import org.springframework.data.projection.ProjectionFactory;
|
||||
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
|
||||
import org.springframework.data.repository.support.Repositories;
|
||||
import org.springframework.data.rest.tests.RepositoryTestsConfig;
|
||||
import org.springframework.data.rest.tests.mongodb.Address;
|
||||
import org.springframework.data.rest.tests.mongodb.MongoDbRepositoryConfig;
|
||||
import org.springframework.data.rest.tests.mongodb.User;
|
||||
import org.springframework.data.rest.tests.mongodb.User.Gender;
|
||||
import org.springframework.data.rest.webmvc.PersistentEntityResource;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.LinkDiscoverer;
|
||||
import org.springframework.hateoas.PagedResources;
|
||||
import org.springframework.hateoas.PagedResources.PageMetadata;
|
||||
import org.springframework.hateoas.hal.HalLinkDiscoverer;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletWebRequest;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.jayway.jsonpath.JsonPath;
|
||||
|
||||
/**
|
||||
* Integration tests for entity (de)serialization.
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
* @author Greg Turnquist
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = { MongoDbRepositoryConfig.class, RepositoryTestsConfig.class,
|
||||
PersistentEntitySerializationTests.TestConfig.class })
|
||||
@Transactional
|
||||
public class PersistentEntitySerializationTests {
|
||||
|
||||
@Autowired ObjectMapper mapper;
|
||||
@Autowired Repositories repositories;
|
||||
|
||||
@Configuration
|
||||
static class TestConfig extends RepositoryTestsConfig {
|
||||
|
||||
@Bean
|
||||
@Override
|
||||
public ObjectMapper objectMapper() {
|
||||
|
||||
ObjectMapper objectMapper = super.objectMapper();
|
||||
objectMapper.registerModule(
|
||||
new JacksonSerializers(new EnumTranslator(new MessageSourceAccessor(new StaticMessageSource()))));
|
||||
return objectMapper;
|
||||
}
|
||||
}
|
||||
|
||||
LinkDiscoverer linkDiscoverer;
|
||||
ProjectionFactory projectionFactory;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
RequestContextHolder.setRequestAttributes(new ServletWebRequest(new MockHttpServletRequest()));
|
||||
|
||||
this.linkDiscoverer = new HalLinkDiscoverer();
|
||||
this.projectionFactory = new SpelAwareProxyProjectionFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-250
|
||||
*/
|
||||
@Test
|
||||
public void serializesEmbeddedReferencesCorrectly() throws Exception {
|
||||
|
||||
User user = new User();
|
||||
user.address = new Address();
|
||||
user.address.street = "Street";
|
||||
|
||||
PersistentEntityResource userResource = PersistentEntityResource.//
|
||||
build(user, repositories.getPersistentEntity(User.class)).//
|
||||
withLink(new Link("/users/1")).//
|
||||
build();
|
||||
|
||||
PagedResources<PersistentEntityResource> persistentEntityResource = new PagedResources<PersistentEntityResource>(
|
||||
Arrays.asList(userResource), new PageMetadata(1, 0, 10));
|
||||
|
||||
String result = mapper.writeValueAsString(persistentEntityResource);
|
||||
|
||||
assertThat(JsonPath.read(result, "$_embedded.users[*].address"), is(notNullValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-654
|
||||
*/
|
||||
@Test
|
||||
public void deserializesTranslatedEnumProperty() throws Exception {
|
||||
assertThat(mapper.readValue("{ \"gender\" : \"Male\" }", User.class).gender, is(Gender.MALE));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* Copyright 2014-2016 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.webmvc.json;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hamcrest.Matcher;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.support.MessageSourceAccessor;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.rest.core.config.JsonSchemaFormat;
|
||||
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
|
||||
import org.springframework.data.rest.tests.TestMvcClient;
|
||||
import org.springframework.data.rest.tests.mongodb.MongoDbRepositoryConfig;
|
||||
import org.springframework.data.rest.tests.mongodb.Profile;
|
||||
import org.springframework.data.rest.tests.mongodb.User;
|
||||
import org.springframework.data.rest.tests.mongodb.User.EmailAddress;
|
||||
import org.springframework.data.rest.tests.mongodb.User.TypeWithPattern;
|
||||
import org.springframework.data.rest.tests.mongodb.groovy.SimulatedGroovyDomainClass;
|
||||
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter;
|
||||
import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration;
|
||||
import org.springframework.data.rest.webmvc.json.PersistentEntityToJsonSchemaConverter.ValueTypeSchemaPropertyCustomizerFactory;
|
||||
import org.springframework.data.rest.webmvc.json.PersistentEntityToJsonSchemaConverterUnitTests.TestConfiguration;
|
||||
import org.springframework.data.rest.webmvc.mapping.Associations;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.jayway.jsonpath.JsonPath;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = { MongoDbRepositoryConfig.class, TestConfiguration.class })
|
||||
public class PersistentEntityToJsonSchemaConverterUnitTests {
|
||||
|
||||
@Autowired @Qualifier("resourceDescriptionMessageSourceAccessor") MessageSourceAccessor accessor;
|
||||
@Autowired RepositoryRestConfiguration configuration;
|
||||
@Autowired PersistentEntities entities;
|
||||
@Autowired @Qualifier("objectMapper") ObjectMapper objectMapper;
|
||||
@Autowired Associations associations;
|
||||
|
||||
@Configuration
|
||||
@Import(RepositoryRestMvcConfiguration.class)
|
||||
static class TestConfiguration extends RepositoryRestConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
|
||||
|
||||
config.getMetadataConfiguration().registerJsonSchemaFormat(JsonSchemaFormat.EMAIL, EmailAddress.class);
|
||||
config.getMetadataConfiguration().registerFormattingPatternFor("[A-Z]+", TypeWithPattern.class);
|
||||
|
||||
config.exposeIdsFor(Profile.class);
|
||||
}
|
||||
}
|
||||
|
||||
PersistentEntityToJsonSchemaConverter converter;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
TestMvcClient.initWebTest();
|
||||
|
||||
ValueTypeSchemaPropertyCustomizerFactory customizerFactory = mock(ValueTypeSchemaPropertyCustomizerFactory.class);
|
||||
|
||||
converter = new PersistentEntityToJsonSchemaConverter(entities, associations, accessor, objectMapper, configuration,
|
||||
customizerFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-631, DATAREST-632
|
||||
*/
|
||||
@Test
|
||||
public void fulfillsConstraintsForProfile() {
|
||||
|
||||
List<Constraint> constraints = new ArrayList<Constraint>();
|
||||
constraints.add(new Constraint("$.properties.id", is(notNullValue()), "Has descriptor for id property"));
|
||||
constraints.add(new Constraint("$.description", is("Profile description"), "Adds description to schema root"));
|
||||
constraints.add(new Constraint("$.properties.renamed", is(notNullValue()), "Has descriptor for renamed property"));
|
||||
constraints.add(
|
||||
new Constraint("$.properties.aliased", is(nullValue()), "No descriptor for original name of renamed property"));
|
||||
|
||||
assertConstraints(Profile.class, constraints);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-632
|
||||
*/
|
||||
@Test
|
||||
public void fulfillsConstraintsForUser() throws Exception {
|
||||
|
||||
List<Constraint> constraints = new ArrayList<Constraint>();
|
||||
constraints.add(new Constraint("$.properties.id", is(nullValue()), "Does NOT have descriptor for id property"));
|
||||
constraints.add(new Constraint("$.properties.firstname.type", is("string"), "Exposes firstname as String"));
|
||||
constraints
|
||||
.add(new Constraint("$.definitions.address", is(notNullValue()), "Exposes nested objects as definitions."));
|
||||
constraints.add(new Constraint("$.definitions.address.type", is("object"), "Nested entity is of type 'object'"));
|
||||
constraints.add(
|
||||
new Constraint("$.definitions.address.properties.zipCode", is(notNullValue()), "Exposes nested properties"));
|
||||
constraints.add(
|
||||
new Constraint("$.definitions.address.requiredProperties[0]", is("zipCode"), "Lists nested required property"));
|
||||
constraints.add(new Constraint("$.properties.gender.type", is("string"), "Enums are strings."));
|
||||
constraints.add(new Constraint("$.properties.gender.enum", is(notNullValue()), "Exposes enum values."));
|
||||
constraints
|
||||
.add(new Constraint("$.properties.jodaDateTime.format", is("date-time"), "Exposes JodaTime dates in format."));
|
||||
constraints
|
||||
.add(new Constraint("$.properties.java8DateTime.format", is("date-time"), "Exposes Java 8 dates in format."));
|
||||
constraints.add(new Constraint("$.properties.nicknames.type", is("array"), "Exposes collection of simple types."));
|
||||
constraints.add(new Constraint("$.properties.nicknames.items.type", is("string"),
|
||||
"Exposes element type of collection of simple types."));
|
||||
constraints.add(new Constraint("$.properties.email.format", is("email"), "Uses manually configured format."));
|
||||
constraints.add(new Constraint("$.properties.email.type", is("string"), "Treats types with format as String."));
|
||||
|
||||
constraints.add(
|
||||
new Constraint("$.properties.shippingAddresses.type", is("array"), "Exposes collection of complex types."));
|
||||
constraints
|
||||
.add(new Constraint("$.properties.shippingAddresses.uniqueItems", is(true), "Exposes uniqueness for Sets."));
|
||||
constraints.add(new Constraint("$.properties.shippingAddresses.items['$ref']", is("#/definitions/address"),
|
||||
"References definition of complex element type."));
|
||||
|
||||
// DATAREST-531
|
||||
constraints.add(new Constraint("$.properties.email.readOnly", is(true), "Email is read-only property"));
|
||||
|
||||
// DATAREST-644
|
||||
constraints.add(new Constraint("$.properties.shippingAddresses.title", is("Shipping addresses"),
|
||||
"Defaults titles correctly (split at camel case)"));
|
||||
|
||||
// DATAREST-665
|
||||
constraints.add(new Constraint("$.properties.address.title", is("Adresse"), "I18n from simple property"));
|
||||
constraints.add(new Constraint("$.properties.gender.title", is("Geschlecht"), "I18n from property on local type"));
|
||||
constraints.add(
|
||||
new Constraint("$.properties.firstname.title", is("Vorname"), "I18n from property on fully-qualified type"));
|
||||
|
||||
// DATAREST-690
|
||||
constraints.add(new Constraint("$.properties.colleagues.items", is(nullValue()),
|
||||
"Items must not appear for collection associations."));
|
||||
|
||||
assertConstraints(User.class, constraints);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-754
|
||||
*/
|
||||
@Test
|
||||
public void handlesGroovyDomainObjects() {
|
||||
|
||||
List<Constraint> constraints = new ArrayList<Constraint>();
|
||||
constraints.add(new Constraint("$.properties.name", is(notNullValue()), "Has descriptor for name property"));
|
||||
|
||||
assertConstraints(SimulatedGroovyDomainClass.class, constraints);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void assertConstraints(Class<?> type, Iterable<Constraint> constraints) {
|
||||
|
||||
String writeSchemaFor = writeSchemaFor(type);
|
||||
|
||||
for (Constraint constraint : constraints) {
|
||||
|
||||
try {
|
||||
assertThat(constraint.description, JsonPath.read(writeSchemaFor, constraint.selector), constraint.matcher);
|
||||
} catch (RuntimeException e) {
|
||||
assertThat(e, constraint.matcher);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String writeSchemaFor(Class<?> type) {
|
||||
|
||||
try {
|
||||
return objectMapper.writeValueAsString(converter.convert(type));
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static class Constraint {
|
||||
|
||||
String selector;
|
||||
Matcher matcher;
|
||||
String description;
|
||||
|
||||
public Constraint(String selector, Matcher matcher, String description) {
|
||||
this.selector = selector;
|
||||
this.matcher = matcher;
|
||||
this.description = description;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2014-2016 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.webmvc.support;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.mapping.context.PersistentEntities;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
import org.springframework.data.rest.core.mapping.PersistentEntitiesResourceMappings;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMappings;
|
||||
import org.springframework.data.rest.tests.TestMvcClient;
|
||||
import org.springframework.data.rest.tests.mongodb.Profile;
|
||||
import org.springframework.data.rest.webmvc.BaseUri;
|
||||
import org.springframework.hateoas.Link;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link RepositoryLinkBuilder}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class RepositoryLinkBuildUnitTests {
|
||||
|
||||
MongoMappingContext context = new MongoMappingContext();
|
||||
|
||||
/**
|
||||
* @see DATAREST-292
|
||||
*/
|
||||
@Test
|
||||
public void usesCurrentRequestsUriBaseForRelativeBaseUri() {
|
||||
|
||||
TestMvcClient.initWebTest();
|
||||
|
||||
assertRootUriFor("api", "http://localhost/api/profile");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-292, DATAREST-296
|
||||
*/
|
||||
@Test
|
||||
public void usesBaseUriOnlyIfItIsAbsolute() {
|
||||
assertRootUriFor("http://foobar/api", "http://foobar/api/profile");
|
||||
}
|
||||
|
||||
private void assertRootUriFor(String baseUri, String expectedUri) {
|
||||
|
||||
context.getPersistentEntity(Profile.class);
|
||||
ResourceMappings mappings = new PersistentEntitiesResourceMappings(new PersistentEntities(Arrays.asList(context)));
|
||||
|
||||
RepositoryLinkBuilder builder = new RepositoryLinkBuilder(mappings.getMetadataFor(Profile.class),
|
||||
new BaseUri(baseUri));
|
||||
Link link = builder.withSelfRel();
|
||||
|
||||
assertThat(link.getHref(), is(expectedUri));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
rest.description.profile=Profile description
|
||||
|
||||
# User
|
||||
# Local property
|
||||
address._title=Adresse
|
||||
|
||||
# Property on simple type
|
||||
User.gender._title=Geschlecht
|
||||
|
||||
# Property on fully-qualified property
|
||||
org.springframework.data.rest.tests.mongodb.User.firstname._title=Vorname
|
||||
|
||||
# Local property that should be trumped by the more precise definition above
|
||||
firstname._title=emanroV
|
||||
Reference in New Issue
Block a user