/*
* 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.mongodb;
import static org.assertj.core.api.Assertions.*;
import static org.hamcrest.Matchers.*;
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.assertj.core.api.Condition;
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.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.saveAll(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())));
}
@Test // DATAREST-247
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()).isTrue();
assertThat(countByTypeLink.getVariableNames()).contains("type");
MockHttpServletResponse response = client.request(countByTypeLink.expand("Twitter"));
assertThat(response.getContentAsString()).isEqualTo("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\"}}",
org.springframework.http.MediaType.APPLICATION_JSON);
assertThat(JsonPath.<String> read(response.getContentAsString(), "$.lastname")).isNull();
assertThat(JsonPath.<String> read(response.getContentAsString(), "$.address.zipCode")).isEqualTo("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.<String> read(response.getContentAsString(), "$.lastname")).isNull();
assertThat(JsonPath.<String> read(response.getContentAsString(), "$.address.zipCode")).isEqualTo("ZIP");
}
@Test // DATAREST-160
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());
}
@Test // DATAREST-471
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).isNot(new Condition<String>(it -> it == null || it.isEmpty(), "Foo"));
}
@Test // DATAREST-482
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());
}
@Test // DATAREST-482
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());
}
@Test // DATAREST-491
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"));
}
@Test // DATAREST-506
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())));
}
@Test // DATAREST-511
public void invokesQueryResourceReturningAnOptional() throws Exception {
Profile profile = repository.findAll().iterator().next();
Link link = client.discoverUnique("profiles", "search", "findProfileById");
mvc.perform(get(link.expand(profile.getId()).getHref())).//
andExpect(status().isOk());
}
@Test // DATAREST-517
public void returnsNotFoundIfQueryExecutionDoesNotReturnResult() throws Exception {
Link link = client.discoverUnique("profiles", "search", "findProfileById");
mvc.perform(get(link.expand("").getHref())).//
andExpect(status().isNotFound());
}
@Test // DATAREST-712
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());
}
@Test // DATAREST-835
public void exposesETagHeaderForSearchResourceYieldingItemResource() throws Exception {
Link link = client.discoverUnique("profiles", "search", "findProfileById");
Profile profile = repository.findAll().iterator().next();
mvc.perform(get(link.expand(profile.getId()).getHref()))//
.andExpect(header().string("ETag", is("\"0\"")))//
.andExpect(header().string("Last-Modified", is(notNullValue())));
}
@Test // DATAREST-835
public void doesNotAddETagHeaderForCollectionQueryResource() throws Exception {
Link link = client.discoverUnique("profiles", "search", "findByType");
Profile profile = repository.findAll().iterator().next();
mvc.perform(get(link.expand(profile.getType()).getHref()))//
.andExpect(header().string("ETag", is(nullValue())))//
.andExpect(header().string("Last-Modified", is(nullValue())));
}
}