Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
FROM openjdk:17-alpine
RUN addgroup -S spring && adduser -S spring -G spring
USER spring:spring
FROM eclipse-temurin:17-jdk-jammy
ARG JAR_FILE=build/libs/showcase.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ repositories {

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'

implementation 'org.springframework.boot:spring-boot-starter-mail'

testImplementation('org.springframework.boot:spring-boot-starter-test')
}

Expand Down
38 changes: 38 additions & 0 deletions compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
services:
showcase:
build:
context: .
ports:
- "8080:8080"
- "8000:8000"
environment:
- JAVA_TOOL_OPTIONS=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8000

smtp-client:
image: maildev/maildev:2.1.0
command:
- "--web"
- "1080"
- "--smtp"
- "1025"
- "--auto-relay"
- "--verbose"
environment:
- MAILDEV_OUTGOING_HOST=smtp-server
- MAILDEV_OUTGOING_PORT=1025
expose:
- "1025"
- "1080"
ports:
- "10000:1080"
- "10001:1025"

smtp-server:
image: greenmail/standalone:2.0.0
environment:
- GREENMAIL_OPTS=-Dgreenmail.smtp.hostname=0.0.0.0 -Dgreenmail.smtp.port=1025 -Dgreenmail.imap.hostname=0.0.0.0 -Dgreenmail.imap.port=1143 -Dgreenmail.auth.disabled -Dgreenmail.startup.timeout=10000
expose:
- "1025"
- "1143"
# ports:
# - "20000:1143"
Original file line number Diff line number Diff line change
@@ -1,26 +1,37 @@
package com.wilkins.showcase.controller;

import com.wilkins.showcase.service.GreetingService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/greetings")
public class GreetingController {
public record GreetingController(GreetingService greetingService) {

private static final Logger log = LoggerFactory.getLogger(GreetingController.class);

@GetMapping
public JsonGreeting getGreeting(@RequestParam(name = "salutation", required = false, defaultValue = "hello") String salutationParam,
@RequestParam(name = "name", required = false, defaultValue = "world") String nameParam) {
log.info("A greeting was requested");

var greeting = JsonGreeting.of(salutationParam, nameParam);

log.info("Greeting returned: {}", greeting);

return greeting;
}

@PostMapping
public JsonGreeting postGreeting(@RequestParam(name = "salutation", required = false, defaultValue = "hello") String salutationParam,
@RequestParam(name = "name", required = false, defaultValue = "world") String nameParam) {
log.info("A greeting was requested");

var greeting = JsonGreeting.of(salutationParam, nameParam);

greetingService.sendGreeting(salutationParam, nameParam);

log.info("Greeting returned: {}", greeting);

return greeting;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.wilkins.showcase.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.stereotype.Component;

@Component
public record EmailGreetingService(MailSender mailSender) implements GreetingService {
private static final Logger log = LoggerFactory.getLogger(EmailGreetingService.class);

@Override
public void sendGreeting(String salutation, String name) {
log.info("Sending email");
var message = new SimpleMailMessage();
message.setFrom("showcase@cleancoders.net");
message.setTo("test@cleancoders.net");
message.setSubject("test email");
message.setText("%s %s".formatted(salutation, name));
mailSender.send(message);
log.info("Email sent");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.wilkins.showcase.service;

public interface GreetingService {
void sendGreeting(String salutation, String name);
}
4 changes: 4 additions & 0 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
spring:
mail:
host: smtp-client
port: 1025
Original file line number Diff line number Diff line change
@@ -1,21 +1,31 @@
package com.wilkins.showcase.controller;

import com.wilkins.showcase.service.GreetingService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;

import static org.hamcrest.CoreMatchers.is;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
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;

@WebMvcTest
public class GreetingControllerTest {

@Autowired
MockMvc mockMvc;

GreetingService greetingService = mock(GreetingService.class);

@BeforeEach
void beforeEach() {
var controller = new GreetingController(greetingService);
mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
}

@Test
void returnsGreeting() throws Exception {
mockMvc.perform(get("/greetings"))
Expand All @@ -24,4 +34,13 @@ void returnsGreeting() throws Exception {
.andExpect(jsonPath("$.name", is("world")));
}

@Test
void emailsGreeting() throws Exception {
mockMvc.perform(post("/greetings"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.salutation", is("hello")))
.andExpect(jsonPath("$.name", is("world")));
verify(greetingService).sendGreeting("hello", "world");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.wilkins.showcase.service;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

class EmailGreetingServiceTest {

GreetingService underTest;
MailSender mailSender = mock(MailSender.class);

@BeforeEach
void beforeEach() {
underTest = new EmailGreetingService(mailSender);
}

@Test
void canEmailGreeting() {
var expectedMessage = new SimpleMailMessage();
expectedMessage.setFrom("showcase@cleancoders.net");
expectedMessage.setTo("test@cleancoders.net");
expectedMessage.setSubject("test email");
expectedMessage.setText("%s %s".formatted("hello", "world"));

underTest.sendGreeting("hello", "world");

verify(mailSender).send(expectedMessage);
}
}