Skip to content

Commit

Permalink
#33: add application version to UI
Browse files Browse the repository at this point in the history
  • Loading branch information
gessnerfl committed Nov 12, 2020
1 parent 688f728 commit e05656e
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 29 deletions.
7 changes: 6 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
@@ -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"
}

Expand Down Expand Up @@ -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"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -16,17 +17,20 @@
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";
static final String SINGLE_EMAIL_MODEL_NAME = "mail";
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"})
Expand All @@ -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;
}

Expand All @@ -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;
}

Expand All @@ -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());
}

}
5 changes: 4 additions & 1 deletion src/main/resources/templates/fragments/navbar.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@

<body>
<div class="navbar-fixed" th:fragment="navbar" >
<nav class="light-blue darken-4" style="padding-left:10px">
<nav class="light-blue darken-4" style="padding-left:10px; padding-right:10px;">
<div class="nav-wrapper">
<a class="brand-logo" href="/"><i class="material-icons" style="font-size: 2rem">email</i>Fake SMTP Server</a>
<ul class="right">
<li th:text="${'Version: ' + appVersion}"></li>
</ul>
</div>
</nav>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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"));
}

Expand All @@ -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"));
}

Expand All @@ -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"));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<Email> 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
Expand All @@ -52,59 +59,69 @@ 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
public void shouldRedirectToFirstPageWhenPageNumberIsBelowNull() {
var result = sut.getAll(-1, 5, model);

assertEquals(EmailController.REDIRECT_EMAIL_LIST_VIEW, result);
verifyNoInteractions(emailRepository);
verifyNoInteractions(emailRepository, buildProperties, model);
}

@Test
public void shouldRedirectToFirstPageWhenPageSizeIsNull() {
String result = sut.getAll(0, 0, model);

assertEquals(EmailController.REDIRECT_EMAIL_LIST_VIEW, result);
verifyNoInteractions(emailRepository);
verifyNoInteractions(emailRepository, buildProperties, model);
}

@Test
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);

assertEquals(EmailController.SINGLE_EMAIL_VIEW, result);

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
Expand All @@ -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<Email> createFirstPageEmail() {
Expand All @@ -138,5 +157,7 @@ public void shouldDeleteEmailByItsIdAndFlushChangesSoThatDeleteIsApplied(){

verify(emailRepository).deleteById(emailId);
verify(emailRepository).flush();
verifyNoMoreInteractions(emailRepository);
verifyNoInteractions(buildProperties);
}
}
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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.*;
Expand Down

0 comments on commit e05656e

Please sign in to comment.