/* * Copyright 2016 EuregJUG. * * 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 eu.euregjug.site.posts; import eu.euregjug.site.config.SecurityTestConfig; import com.fasterxml.jackson.databind.ObjectMapper; import eu.euregjug.site.posts.PostEntity.Format; import eu.euregjug.site.posts.PostEntity.Status; import java.util.Arrays; import java.util.Date; import java.util.Locale; import java.util.Optional; import org.joor.Reflect; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.json.JacksonTester; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; import org.springframework.data.web.config.EnableSpringDataWebSupport; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasSize; import static org.mockito.Matchers.any; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import static org.springframework.http.MediaType.APPLICATION_JSON; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest; import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; /** * @author Michael J. Simons, 2016-07-13 */ @RunWith(SpringRunner.class) @ActiveProfiles("test") @WebMvcTest(PostApiController.class) @EnableSpringDataWebSupport // Needed to enable resolving of Pageable and other parameters @Import(SecurityTestConfig.class) // Needed to get rid of default CSRF protection @AutoConfigureRestDocs( outputDir = "target/generated-snippets", uriHost = "euregjug.eu", uriPort = 80 ) public class PostApiControllerTest { @Autowired private MockMvc mvc; @MockBean private PostRepository postRepository; @MockBean private PostIndexService postIndexService; @Autowired private ObjectMapper objectMapper; private JacksonTester<PostEntity> json; @Before public void setup() { JacksonTester.initFields(this, objectMapper); } @Test public void createShouldWork() throws Exception { final PostEntity postEntity1 = new PostEntity(new Date(), "new-site-is-live1", "New site is live", "Welcome to the new EuregJUG website. We have switched off the old static pages and replaced it with a little application based on Hibernate, Spring Data JPA, Spring Boot and Thymeleaf."); postEntity1.setLocale(new Locale("de", "DE")); postEntity1.setStatus(Status.published); when(this.postRepository.save(postEntity1)).then(invocation -> { // Do the stuff JPA would do for us... final PostEntity rv = invocation.getArgumentAt(0, PostEntity.class); return Reflect.on(rv).call("updateUpdatedAt").set("id", 4711).get(); }); final PostEntity postEntity2 = new PostEntity(new Date(), "new-site-is-live2", "New site is live", "Welcome to the new EuregJUG website. We have switched off the old static pages and replaced it with a little application based on Hibernate, Spring Data JPA, Spring Boot and Thymeleaf."); when(this.postRepository.save(postEntity2)).then(invocation -> { // Do the stuff JPA would do for us... final PostEntity rv = invocation.getArgumentAt(0, PostEntity.class); return Reflect.on(rv).call("updateUpdatedAt").set("id", 4712).get(); }); this.mvc .perform( post("/api/posts") .content(this.json.write(postEntity1).getJson()) .contentType(APPLICATION_JSON) .principal(() -> "euregjug") ) .andExpect(status().isCreated()) .andExpect(jsonPath("$.id", equalTo(4711))) .andExpect(jsonPath("$.slug", equalTo("new-site-is-live1"))) .andExpect(jsonPath("$.locale", equalTo("de_DE"))) .andExpect(jsonPath("$.status", equalTo("published"))) .andDo(document("api/posts/create", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()) )); this.mvc .perform( post("/api/posts") .content(this.json.write(postEntity2).getJson()) .contentType(APPLICATION_JSON) .principal(() -> "euregjug") ) .andExpect(status().isCreated()) .andExpect(jsonPath("$.id", equalTo(4712))) .andExpect(jsonPath("$.slug", equalTo("new-site-is-live2"))) .andExpect(jsonPath("$.locale", equalTo("en_US"))) .andExpect(jsonPath("$.status", equalTo("draft"))); verify(this.postRepository).save(postEntity1); verify(this.postRepository).save(postEntity2); verifyNoMoreInteractions(this.postRepository); } @Test public void getShouldWork() throws Exception { final PostEntity p1 = Reflect.on( new PostEntity(new Date(), "new-site-is-live", "New site is live", "Welcome to the new EuregJUG website. We have switched off the old static pages and replaced it with a little application based on Hibernate, Spring Data JPA, Spring Boot and Thymeleaf.") ).call("updateUpdatedAt").set("id", 23).get(); final PostEntity p2 = Reflect.on( new PostEntity(new Date(), "ruckblick-zum-aim42-vortrag-mit-gernot-starke", "Rückblick zum aim42 Vortrag mit Gernot Starke", "Am 7. April lud die Euregio JUG zusammen mit der http://www.inside-online.de/de/[inside Unternehmensgruppe] zu einem Vortrag von Gernot Starke zum Thema _aim42 - software architecture improvement_ ein.") ).call("updateUpdatedAt").set("id", 42).get(); final PageImpl page = new PageImpl(Arrays.asList(p1, p2)); when(this.postRepository.findAll(any(Pageable.class))).thenReturn(page); this.mvc .perform( get("/api/posts") .principal(() -> "euregjug") ) .andExpect(status().isOk()) .andExpect(jsonPath("$.numberOfElements", equalTo(2))) .andExpect(jsonPath("$.totalElements", equalTo(2))) .andExpect(jsonPath("$.totalPages", equalTo(1))) .andExpect(jsonPath("$.content", hasSize(2))) .andExpect(jsonPath("$.content[0].slug", equalTo("new-site-is-live"))) .andExpect(jsonPath("$.content[1].slug", equalTo("ruckblick-zum-aim42-vortrag-mit-gernot-starke"))) .andDo(document("api/posts/get", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()) )); verify(this.postRepository).findAll(any(Pageable.class)); verifyNoMoreInteractions(this.postRepository); } @Test public void searchShouldWork() throws Exception { final PostEntity p1 = Reflect.on( new PostEntity(new Date(), "new-site-is-live", "New site is live", "Welcome to the new EuregJUG website. We have switched off the old static pages and replaced it with a little application based on Hibernate, Spring Data JPA, Spring Boot and Thymeleaf.") ).call("updateUpdatedAt").set("id", 23).get(); when(this.postRepository.searchByKeyword("website")).thenReturn(Arrays.asList(p1)); this.mvc .perform( get("/api/posts/search") .param("q", "website") .principal(() -> "euregjug") ) .andExpect(status().isOk()) .andExpect(jsonPath("$", hasSize(1))) .andExpect(jsonPath("$[0].slug", equalTo("new-site-is-live"))) .andDo(document("api/posts/search", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()) )); verify(this.postRepository).searchByKeyword("website"); verifyNoMoreInteractions(this.postRepository); } @Test public void updateShouldShouldWork() throws Exception { final PostEntity updateEntity = new PostEntity(new Date(), "newslug", "newtitle", "newcontent"); updateEntity.setFormat(Format.markdown); updateEntity.setStatus(null); final PostEntity oldEntity = new PostEntity(new Date(), "oldslug", "oldtitle", "oldcontent"); oldEntity.setLocale(new Locale("de", "DE")); oldEntity.setFormat(Format.asciidoc); oldEntity.setStatus(Status.hidden); when(this.postRepository.findOne(4711)).thenReturn(Optional.empty()); when(this.postRepository.findOne(4712)).thenReturn(Optional.of(oldEntity)); this.mvc .perform( put("/api/posts/{id}", 4711) .content(this.json.write(updateEntity).getJson()) .contentType(APPLICATION_JSON) .principal(() -> "euregjug") ) .andExpect(status().isNotFound()) .andDo(document("api/posts/update/notfound", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()) )); this.mvc .perform( put("/api/posts/{id}", 4712) .content(this.json.write(updateEntity).getJson()) .contentType(APPLICATION_JSON) .principal(() -> "euregjug") ) .andExpect(status().isOk()) .andExpect(jsonPath("$.content", equalTo("newcontent"))) .andExpect(jsonPath("$.format", equalTo("markdown"))) .andExpect(jsonPath("$.title", equalTo("newtitle"))) .andExpect(jsonPath("$.slug", equalTo("oldslug"))) .andExpect(jsonPath("$.locale", equalTo("de_DE"))) .andExpect(jsonPath("$.status", equalTo("hidden"))); updateEntity.setLocale(new Locale("en", "US")); updateEntity.setStatus(Status.published); this.mvc .perform( put("/api/posts/{id}", 4712) .content(this.json.write(updateEntity).getJson()) .contentType(APPLICATION_JSON) .principal(() -> "euregjug") ) .andExpect(status().isOk()) .andExpect(jsonPath("$.locale", equalTo("en_US"))) .andExpect(jsonPath("$.status", equalTo("published"))) .andDo(document("api/posts/update/updated", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()) )); verify(this.postRepository).findOne(4711); verify(this.postRepository, times(2)).findOne(4712); verifyNoMoreInteractions(this.postRepository); } @Test public void rebuildIndexShouldWork() throws Exception { this.mvc .perform( post("/api/posts/rebuildIndex") .principal(() -> "euregjug") ) .andExpect(status().isCreated()) .andDo(document("api/posts/rebuildIndex", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()) )); verify(this.postIndexService).rebuildIndex(); verifyNoMoreInteractions(this.postIndexService); } }