From e05656e3fb2803dc3cca15e951b063951b8ae392 Mon Sep 17 00:00:00 2001 From: Florian Gessner Date: Thu, 12 Nov 2020 21:23:26 +0100 Subject: [PATCH] #33: add application version to UI --- build.gradle | 7 +++- .../fakesmtp/controller/EmailController.java | 12 ++++++- .../resources/templates/fragments/navbar.html | 5 ++- .../EmailControllerMVCIntegrationTest.java | 15 +++------ .../controller/EmailControllerTest.java | 33 +++++++++++++++---- ...EmailRestControllerMVCIntegrationTest.java | 9 ----- 6 files changed, 52 insertions(+), 29 deletions(-) diff --git a/build.gradle b/build.gradle index d49da862..f8943df3 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { id "com.cinnober.gradle.semver-git" version "3.0.0" - id 'org.springframework.boot' version '2.3.4.RELEASE' + id 'org.springframework.boot' version '2.4.0' id "org.sonarqube" version "3.0" } @@ -39,12 +39,17 @@ dependencies { implementation('org.webjars:material-design-icons:3.0.1') runtimeOnly('com.h2database:h2') + testImplementation('org.junit.vintage:junit-vintage-engine') testImplementation('org.springframework.boot:spring-boot-starter-test') testImplementation('org.ow2.asm:asm:9.0') testImplementation('org.apache.commons:commons-lang3:3.11') testImplementation('org.hamcrest:hamcrest-core:2.2') } +springBoot { + buildInfo() +} + sonarqube { properties { property "sonar.projectName", "Fake SMTP Server" diff --git a/src/main/java/de/gessnerfl/fakesmtp/controller/EmailController.java b/src/main/java/de/gessnerfl/fakesmtp/controller/EmailController.java index 47118acf..f919f904 100644 --- a/src/main/java/de/gessnerfl/fakesmtp/controller/EmailController.java +++ b/src/main/java/de/gessnerfl/fakesmtp/controller/EmailController.java @@ -3,6 +3,7 @@ import de.gessnerfl.fakesmtp.model.Email; import de.gessnerfl.fakesmtp.repository.EmailRepository; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.info.BuildProperties; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Controller; @@ -16,6 +17,7 @@ public class EmailController { private static final Sort DEFAULT_SORT = Sort.by(Sort.Direction.DESC, "receivedOn"); private static final int DEFAULT_PAGE_SIZE = 10; + static final String APP_VERSION_MODEL_NAME = "appVersion"; static final String EMAIL_LIST_VIEW = "email-list"; static final String EMAIL_LIST_MODEL_NAME = "mails"; static final String SINGLE_EMAIL_VIEW = "email"; @@ -23,10 +25,12 @@ public class EmailController { static final String REDIRECT_EMAIL_LIST_VIEW = "redirect:/email"; private final EmailRepository emailRepository; + private final BuildProperties buildProperties; @Autowired - public EmailController(EmailRepository emailRepository) { + public EmailController(EmailRepository emailRepository, BuildProperties buildProperties) { this.emailRepository = emailRepository; + this.buildProperties = buildProperties; } @GetMapping({"/", "/email"}) @@ -43,6 +47,7 @@ private String getAllEmailsPaged(int page, int size, Model model) { return REDIRECT_EMAIL_LIST_VIEW; } model.addAttribute(EMAIL_LIST_MODEL_NAME, result); + addApplicationVersion(model); return EMAIL_LIST_VIEW; } @@ -53,6 +58,7 @@ public String getEmailById(@PathVariable Long id, Model model) { private String appendToModelAndReturnView(Model model, Email email) { model.addAttribute(SINGLE_EMAIL_MODEL_NAME, email); + addApplicationVersion(model); return SINGLE_EMAIL_VIEW; } @@ -63,4 +69,8 @@ public String deleteEmailById(@PathVariable Long id) { return REDIRECT_EMAIL_LIST_VIEW; } + private void addApplicationVersion(Model model){ + model.addAttribute(APP_VERSION_MODEL_NAME, buildProperties.getVersion()); + } + } diff --git a/src/main/resources/templates/fragments/navbar.html b/src/main/resources/templates/fragments/navbar.html index 89bda1b4..553dc4ce 100644 --- a/src/main/resources/templates/fragments/navbar.html +++ b/src/main/resources/templates/fragments/navbar.html @@ -5,9 +5,12 @@ diff --git a/src/test/java/de/gessnerfl/fakesmtp/controller/EmailControllerMVCIntegrationTest.java b/src/test/java/de/gessnerfl/fakesmtp/controller/EmailControllerMVCIntegrationTest.java index 05651481..c0cdbb07 100644 --- a/src/test/java/de/gessnerfl/fakesmtp/controller/EmailControllerMVCIntegrationTest.java +++ b/src/test/java/de/gessnerfl/fakesmtp/controller/EmailControllerMVCIntegrationTest.java @@ -1,28 +1,17 @@ package de.gessnerfl.fakesmtp.controller; -import de.gessnerfl.fakesmtp.model.ContentType; import de.gessnerfl.fakesmtp.model.Email; -import de.gessnerfl.fakesmtp.model.EmailAttachment; -import de.gessnerfl.fakesmtp.model.EmailContent; import de.gessnerfl.fakesmtp.repository.EmailRepository; -import org.apache.commons.lang3.RandomStringUtils; 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.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; -import java.nio.charset.StandardCharsets; -import java.time.LocalDateTime; -import java.time.ZoneOffset; -import java.util.Date; - import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; @@ -50,6 +39,7 @@ public void shouldReturnEmptyListWhenNoEmailsAreAvailable() throws Exception { this.mockMvc.perform(get("/email?page")) .andExpect(status().isOk()) .andExpect(model().attribute("mails", emptyIterableOf(Email.class))) + .andExpect(model().attribute("appVersion", any(String.class))) .andExpect(view().name("email-list")); } @@ -63,12 +53,14 @@ public void shouldReturnListOfEmailsPagedWhenEmailsAreAvailable() throws Excepti .andExpect(status().isOk()) .andExpect(model().attribute("mails", iterableWithSize(2))) .andExpect(model().attribute("mails", contains(equalTo(email3), equalTo(email2)))) + .andExpect(model().attribute("appVersion", any(String.class))) .andExpect(view().name("email-list")); this.mockMvc.perform(get("/email?page=1&size=2")) .andExpect(status().isOk()) .andExpect(model().attribute("mails", iterableWithSize(1))) .andExpect(model().attribute("mails", contains(equalTo(email1)))) + .andExpect(model().attribute("appVersion", any(String.class))) .andExpect(view().name("email-list")); } @@ -89,6 +81,7 @@ public void shouldReturnMailById() throws Exception { this.mockMvc.perform(get("/email/"+email.getId())) .andExpect(status().isOk()) .andExpect(model().attribute("mail", equalTo(email))) + .andExpect(model().attribute("appVersion", any(String.class))) .andExpect(view().name("email")); } diff --git a/src/test/java/de/gessnerfl/fakesmtp/controller/EmailControllerTest.java b/src/test/java/de/gessnerfl/fakesmtp/controller/EmailControllerTest.java index 875f443a..23cf51e6 100644 --- a/src/test/java/de/gessnerfl/fakesmtp/controller/EmailControllerTest.java +++ b/src/test/java/de/gessnerfl/fakesmtp/controller/EmailControllerTest.java @@ -8,6 +8,7 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.boot.info.BuildProperties; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.ui.Model; @@ -23,21 +24,27 @@ public class EmailControllerTest { private Model model; @Mock private EmailRepository emailRepository; + @Mock + private BuildProperties buildProperties; @InjectMocks private EmailController sut; @Test public void shouldReturnEmailsPaged() { + final String appVersion = "appVersion"; final Page page = createFirstPageEmail(); when(emailRepository.findAll(any(Pageable.class))).thenReturn(page); + when(buildProperties.getVersion()).thenReturn(appVersion); var result = sut.getAll(0, 5, model); assertEquals(EmailController.EMAIL_LIST_VIEW, result); verify(emailRepository).findAll(argThat(matchPageable(0, 5))); - verifyNoMoreInteractions(emailRepository); verify(model).addAttribute(EmailController.EMAIL_LIST_MODEL_NAME, page); + verify(buildProperties).getVersion(); + verify(model).addAttribute(EmailController.APP_VERSION_MODEL_NAME, appVersion); + verifyNoMoreInteractions(emailRepository, buildProperties, model); } @Test @@ -52,21 +59,26 @@ public void shouldReturnRedirectToFirstPageWhenRequestedPageIsOutOfRange() { assertEquals(EmailController.REDIRECT_EMAIL_LIST_VIEW, result); verify(emailRepository).findAll(argThat(matchPageable(3, 5))); - verifyNoMoreInteractions(emailRepository); + verifyNoMoreInteractions(emailRepository, buildProperties, model); } @Test public void shouldNotRedirectToFirstPageWhenNoDataIsAvailable() { + final String appVersion = "appVersion"; var page = mock(Page.class); when(page.getNumber()).thenReturn(0); when(emailRepository.findAll(any(Pageable.class))).thenReturn(page); + when(buildProperties.getVersion()).thenReturn(appVersion); var result = sut.getAll(0, 5, model); assertEquals(EmailController.EMAIL_LIST_VIEW, result); verify(emailRepository).findAll(argThat(matchPageable(0, 5))); - verifyNoMoreInteractions(emailRepository); + verify(model).addAttribute(EmailController.EMAIL_LIST_MODEL_NAME, page); + verify(buildProperties).getVersion(); + verify(model).addAttribute(EmailController.APP_VERSION_MODEL_NAME, appVersion); + verifyNoMoreInteractions(emailRepository, emailRepository, model); } @Test @@ -74,7 +86,7 @@ public void shouldRedirectToFirstPageWhenPageNumberIsBelowNull() { var result = sut.getAll(-1, 5, model); assertEquals(EmailController.REDIRECT_EMAIL_LIST_VIEW, result); - verifyNoInteractions(emailRepository); + verifyNoInteractions(emailRepository, buildProperties, model); } @Test @@ -82,7 +94,7 @@ public void shouldRedirectToFirstPageWhenPageSizeIsNull() { String result = sut.getAll(0, 0, model); assertEquals(EmailController.REDIRECT_EMAIL_LIST_VIEW, result); - verifyNoInteractions(emailRepository); + verifyNoInteractions(emailRepository, buildProperties, model); } @Test @@ -90,14 +102,16 @@ public void shouldRedirectToFirstPageWhenPageSizeIsBelowNull() { var result = sut.getAll(0, -1, model); assertEquals(EmailController.REDIRECT_EMAIL_LIST_VIEW, result); - verifyNoInteractions(emailRepository); + verifyNoInteractions(emailRepository, buildProperties, model); } @Test public void shouldReturnSingleEmailWhenIdIsValid() { + final String appVersion = "appVersion"; var id = 12L; var mail = mock(Email.class); when(emailRepository.findById(id)).thenReturn(Optional.of(mail)); + when(buildProperties.getVersion()).thenReturn(appVersion); var result = sut.getEmailById(id, model); @@ -105,6 +119,9 @@ public void shouldReturnSingleEmailWhenIdIsValid() { verify(emailRepository).findById(id); verify(model).addAttribute(EmailController.SINGLE_EMAIL_MODEL_NAME, mail); + verify(buildProperties).getVersion(); + verify(model).addAttribute(EmailController.APP_VERSION_MODEL_NAME, appVersion); + verifyNoMoreInteractions(emailRepository, buildProperties, model); } @Test @@ -117,6 +134,8 @@ public void shouldReturnRedirectToListPageWhenIdIsNotValid() { assertEquals(EmailController.REDIRECT_EMAIL_LIST_VIEW, result); verify(emailRepository).findById(id); + verifyNoMoreInteractions(emailRepository); + verifyNoInteractions(buildProperties, model); } private Page createFirstPageEmail() { @@ -138,5 +157,7 @@ public void shouldDeleteEmailByItsIdAndFlushChangesSoThatDeleteIsApplied(){ verify(emailRepository).deleteById(emailId); verify(emailRepository).flush(); + verifyNoMoreInteractions(emailRepository); + verifyNoInteractions(buildProperties); } } \ No newline at end of file diff --git a/src/test/java/de/gessnerfl/fakesmtp/controller/EmailRestControllerMVCIntegrationTest.java b/src/test/java/de/gessnerfl/fakesmtp/controller/EmailRestControllerMVCIntegrationTest.java index 4873a50d..ce28cb18 100644 --- a/src/test/java/de/gessnerfl/fakesmtp/controller/EmailRestControllerMVCIntegrationTest.java +++ b/src/test/java/de/gessnerfl/fakesmtp/controller/EmailRestControllerMVCIntegrationTest.java @@ -1,13 +1,8 @@ package de.gessnerfl.fakesmtp.controller; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import de.gessnerfl.fakesmtp.model.ContentType; import de.gessnerfl.fakesmtp.model.Email; -import de.gessnerfl.fakesmtp.model.EmailAttachment; -import de.gessnerfl.fakesmtp.model.EmailContent; import de.gessnerfl.fakesmtp.repository.EmailRepository; -import org.apache.commons.lang3.RandomStringUtils; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -22,10 +17,6 @@ import org.springframework.test.web.servlet.MvcResult; import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.time.LocalDateTime; -import java.time.ZoneOffset; -import java.util.Date; import java.util.List; import static org.hamcrest.Matchers.*;