Implemented Accounts CRUD functionality via REST API. Closes #10
parent
cbe55fbd5a
commit
6015b06a87
|
@ -0,0 +1,87 @@
|
|||
package de.nclazz.service.mailrelay;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import de.nclazz.service.mailrelay.adapter.web.RelayAccountForm;
|
||||
import de.nclazz.service.mailrelay.domain.Relay;
|
||||
import de.nclazz.service.mailrelay.domain.RelayAccount;
|
||||
import org.junit.jupiter.api.Test;
|
||||
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.boot.test.context.TestConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
|
||||
|
||||
import java.time.Clock;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.core.Is.is;
|
||||
import static org.springframework.http.MediaType.APPLICATION_JSON;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||
|
||||
@SpringBootTest
|
||||
@ActiveProfiles("integration")
|
||||
@AutoConfigureMockMvc
|
||||
public class AccountCrudTest {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper mapper;
|
||||
|
||||
@Autowired
|
||||
private Relay relay;
|
||||
|
||||
private static final LocalDateTime FIXED_TIME = LocalDateTime.of(2019, 4, 25, 13, 12);
|
||||
|
||||
@TestConfiguration
|
||||
static class TestConfig {
|
||||
@Bean
|
||||
public Clock clock() {
|
||||
return FakeClock.fixed(FIXED_TIME);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void newAccountCanBeCreatedAndAccessedAfterwards() throws Exception {
|
||||
RelayAccountForm form = new RelayAccountForm("my-company", List.of("vip@my-company.com"));
|
||||
mockMvc.perform(post("/accounts").contentType(APPLICATION_JSON).content(mapper.writeValueAsString(form)))
|
||||
.andExpect(status().isCreated())
|
||||
.andExpect(content().contentType(APPLICATION_JSON))
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(jsonPath("$.name").value("my-company"))
|
||||
.andExpect(jsonPath("$.receivers", is(List.of("vip@my-company.com"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void existingAccountCanBeRetrieved() throws Exception {
|
||||
RelayAccount account = RelayAccount.of("retrievable-account", List.of("info@account.com"));
|
||||
account = relay.saveAccount(account);
|
||||
|
||||
mockMvc.perform(get("/accounts/{guid}", account.getGuid()))
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpect(content().contentType(APPLICATION_JSON))
|
||||
.andExpect(jsonPath("$.name").value("retrievable-account"))
|
||||
.andExpect(jsonPath("$.receivers", is(List.of("info@account.com"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void existingAccountCanBeUpdated() throws Exception {
|
||||
RelayAccount account = RelayAccount.of("updated-account", List.of("info@account.com"));
|
||||
account = relay.saveAccount(account);
|
||||
|
||||
RelayAccountForm form = new RelayAccountForm("updated-account-renamed", List.of("vip@account.com"));
|
||||
|
||||
mockMvc.perform(put("/accounts/{guid}", account.getGuid()).contentType(APPLICATION_JSON).content(mapper.writeValueAsString(form)))
|
||||
.andExpect(status().is2xxSuccessful())
|
||||
.andExpect(content().contentType(APPLICATION_JSON))
|
||||
.andExpect(jsonPath("$.name").value("updated-account-renamed"))
|
||||
.andExpect(jsonPath("$.receivers", is(List.of("vip@account.com"))));
|
||||
}
|
||||
|
||||
}
|
|
@ -47,7 +47,7 @@ public class ForwardMessageFormTest {
|
|||
@PostConstruct
|
||||
public void init() {
|
||||
RelayAccount account = new RelayAccount(UUID.randomUUID(), "company-account", TOKEN, List.of("vip@company.com"));
|
||||
relay.addAccount(account);
|
||||
relay.saveAccount(account);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,4 +35,9 @@ public class JpaRelayAccountRepositoryAdapter implements RelayAccountRepository
|
|||
public RelayAccount save(@NonNull RelayAccount account) {
|
||||
return this.jpaRepository.save(account);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteByGuid(@NonNull UUID guid) {
|
||||
this.jpaRepository.deleteById(guid);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package de.nclazz.service.mailrelay.adapter.web;
|
||||
|
||||
import de.nclazz.service.mailrelay.domain.RelayAccount;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class RelayAccountForm {
|
||||
|
||||
private String name;
|
||||
private List<String> receivers;
|
||||
|
||||
public RelayAccount toAccount() {
|
||||
return RelayAccount.of(this.name, this.receivers);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package de.nclazz.service.mailrelay.adapter.web;
|
||||
|
||||
import de.nclazz.service.mailrelay.domain.Relay;
|
||||
import de.nclazz.service.mailrelay.domain.RelayAccount;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("accounts")
|
||||
@RequiredArgsConstructor
|
||||
public class RelayAccountRestController {
|
||||
|
||||
private final Relay relay;
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<RelayAccount> addAccount(@RequestBody RelayAccountForm form) {
|
||||
RelayAccount account = form.toAccount();
|
||||
account = this.relay.saveAccount(account);
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(account);
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public List<RelayAccount> getAllAccounts() {
|
||||
return this.relay.accounts();
|
||||
}
|
||||
|
||||
@GetMapping("{guid}")
|
||||
public RelayAccount findByGuid(@PathVariable("guid")UUID guid) {
|
||||
return this.relay.findAccount(guid)
|
||||
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
|
||||
}
|
||||
|
||||
@DeleteMapping("{guid}")
|
||||
public RelayAccount deleteByGuid(@PathVariable("guid")UUID guid) {
|
||||
return this.relay.deleteAccount(guid)
|
||||
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
|
||||
}
|
||||
|
||||
@PutMapping("{guid}")
|
||||
public RelayAccount updateByGuid(@PathVariable("guid")UUID guid, @RequestBody RelayAccountForm form) {
|
||||
RelayAccount account = this.relay.findAccount(guid)
|
||||
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
|
||||
account.setName(form.getName());
|
||||
account.setReceivers(form.getReceivers());
|
||||
return this.relay.saveAccount(account);
|
||||
}
|
||||
}
|
|
@ -1,11 +1,14 @@
|
|||
package de.nclazz.service.mailrelay.domain;
|
||||
|
||||
import com.sun.istack.NotNull;
|
||||
import lombok.Data;
|
||||
import lombok.NonNull;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
@Data
|
||||
@Slf4j
|
||||
|
@ -27,7 +30,24 @@ public class Relay {
|
|||
return message;
|
||||
}
|
||||
|
||||
public void addAccount(@NonNull RelayAccount account) {
|
||||
this.accountRepository.save(account);
|
||||
public RelayAccount saveAccount(@NonNull RelayAccount account) {
|
||||
return this.accountRepository.save(account);
|
||||
}
|
||||
|
||||
public List<RelayAccount> accounts() {
|
||||
return this.accountRepository.findAll();
|
||||
}
|
||||
|
||||
public Optional<RelayAccount> findAccount(@NonNull UUID guid) {
|
||||
return this.accountRepository.findByGuid(guid);
|
||||
}
|
||||
|
||||
public Optional<RelayAccount> deleteAccount(@NotNull UUID guid) {
|
||||
Optional<RelayAccount> accountOptional = findAccount(guid);
|
||||
if(accountOptional.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
this.accountRepository.deleteByGuid(guid);
|
||||
return accountOptional;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package de.nclazz.service.mailrelay.domain;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
@ -12,6 +13,7 @@ import javax.persistence.CollectionTable;
|
|||
import javax.persistence.Column;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Index;
|
||||
|
@ -38,10 +40,11 @@ public class RelayAccount {
|
|||
private String name;
|
||||
private String token;
|
||||
|
||||
@ElementCollection
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(name = "accounts_receivers")
|
||||
private List<String> receivers;
|
||||
|
||||
@JsonIgnore
|
||||
@OneToMany
|
||||
private final List<Message> sentMessages = new ArrayList<>();
|
||||
|
||||
|
@ -50,8 +53,11 @@ public class RelayAccount {
|
|||
this.sentMessages.add(message);
|
||||
}
|
||||
|
||||
|
||||
public boolean matchesToken(String token) {
|
||||
return this.token.equals(token);
|
||||
public static RelayAccount of(@NonNull String name, @NonNull List<String> receivers) {
|
||||
RelayAccount account = new RelayAccount();
|
||||
account.setName(name);
|
||||
account.setReceivers(receivers);
|
||||
return account;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,5 +16,5 @@ public interface RelayAccountRepository {
|
|||
|
||||
RelayAccount save(@NonNull RelayAccount account);
|
||||
|
||||
|
||||
void deleteByGuid(@NonNull UUID guid);
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ class MessageFormControllerTest {
|
|||
);
|
||||
|
||||
Relay relay = new Relay(new FakeRelayAccountRepository(), new FakeMessageRepository());
|
||||
relay.addAccount(account);
|
||||
relay.saveAccount(account);
|
||||
|
||||
LocalDateTime now = LocalDateTime.of(2020, 12, 24, 12, 54);
|
||||
Clock fakeClock = FakeClock.fixed(now);
|
||||
|
|
|
@ -27,7 +27,7 @@ class MessageRestControllerTest {
|
|||
);
|
||||
|
||||
Relay relay = new Relay(new FakeRelayAccountRepository(), new FakeMessageRepository());
|
||||
relay.addAccount(account);
|
||||
relay.saveAccount(account);
|
||||
|
||||
LocalDateTime now = LocalDateTime.of(2020, 12, 24, 12, 54);
|
||||
Clock fakeClock = FakeClock.fixed(now);
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
package de.nclazz.service.mailrelay.adapter.web;
|
||||
|
||||
import de.nclazz.service.mailrelay.domain.FakeMessageRepository;
|
||||
import de.nclazz.service.mailrelay.domain.FakeRelayAccountRepository;
|
||||
import de.nclazz.service.mailrelay.domain.Relay;
|
||||
import de.nclazz.service.mailrelay.domain.RelayAccount;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
class RelayAccountRestControllerTest {
|
||||
|
||||
@Test
|
||||
void addAccountCreatesNewAccountAndReturnsIs() {
|
||||
|
||||
Relay relay = new Relay(new FakeRelayAccountRepository(), new FakeMessageRepository());
|
||||
|
||||
RelayAccountRestController controller = new RelayAccountRestController(relay);
|
||||
RelayAccountForm form = new RelayAccountForm(
|
||||
"my-account",
|
||||
List.of("vip@my-company.com", "info@my-company.com")
|
||||
);
|
||||
|
||||
assertThat(controller.addAccount(form))
|
||||
.extracting("name", "receivers")
|
||||
.containsExactly("my-account", List.of("vip@my-company.com", "info@my-company.com"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void addedAccountCanBeAccessedByItsGuid() {
|
||||
Relay relay = new Relay(new FakeRelayAccountRepository(), new FakeMessageRepository());
|
||||
|
||||
RelayAccountRestController controller = new RelayAccountRestController(relay);
|
||||
RelayAccountForm form = new RelayAccountForm(
|
||||
"my-account",
|
||||
List.of("vip@my-company.com", "info@my-company.com")
|
||||
);
|
||||
|
||||
RelayAccount account = controller.addAccount(form).getBody();
|
||||
|
||||
assertThat(controller.findByGuid(account.getGuid()))
|
||||
.isNotNull()
|
||||
.extracting("name", "receivers")
|
||||
.containsExactly("my-account", List.of("vip@my-company.com", "info@my-company.com"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void addedAccountCanBeDeletedAndIsReturned() {
|
||||
Relay relay = new Relay(new FakeRelayAccountRepository(), new FakeMessageRepository());
|
||||
|
||||
RelayAccountRestController controller = new RelayAccountRestController(relay);
|
||||
RelayAccountForm form = new RelayAccountForm(
|
||||
"my-account",
|
||||
List.of("vip@my-company.com", "info@my-company.com")
|
||||
);
|
||||
|
||||
RelayAccount account = controller.addAccount(form).getBody();
|
||||
|
||||
assertThat(controller.deleteByGuid(account.getGuid()))
|
||||
.isNotNull()
|
||||
.extracting("name", "receivers")
|
||||
.containsExactly("my-account", List.of("vip@my-company.com", "info@my-company.com"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void addedAccountCanBeDeletedAndIsNotAccessibleAfterwards() {
|
||||
Relay relay = new Relay(new FakeRelayAccountRepository(), new FakeMessageRepository());
|
||||
|
||||
RelayAccountRestController controller = new RelayAccountRestController(relay);
|
||||
RelayAccountForm form = new RelayAccountForm(
|
||||
"my-account",
|
||||
List.of("vip@my-company.com", "info@my-company.com")
|
||||
);
|
||||
|
||||
RelayAccount account = controller.addAccount(form).getBody();
|
||||
controller.deleteByGuid(account.getGuid());
|
||||
|
||||
assertThatThrownBy(() -> controller.findByGuid(account.getGuid()))
|
||||
.isInstanceOf(ResponseStatusException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void accountCanBeUpdated() {
|
||||
Relay relay = new Relay(new FakeRelayAccountRepository(), new FakeMessageRepository());
|
||||
|
||||
RelayAccountRestController controller = new RelayAccountRestController(relay);
|
||||
|
||||
RelayAccount account = controller.addAccount(
|
||||
new RelayAccountForm(
|
||||
"my-account",
|
||||
List.of("vip@my-company.com")
|
||||
)
|
||||
).getBody();
|
||||
|
||||
RelayAccountForm form = new RelayAccountForm("my-renamed-account", List.of("vip@my-company.com", "other@my-company.com"));
|
||||
|
||||
assertThat(controller.updateByGuid(account.getGuid(), form))
|
||||
.extracting("name", "receivers")
|
||||
.containsExactly("my-renamed-account", List.of("vip@my-company.com", "other@my-company.com"));
|
||||
}
|
||||
}
|
|
@ -8,10 +8,11 @@ import java.util.List;
|
|||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class FakeRelayAccountRepository implements RelayAccountRepository {
|
||||
|
||||
private final Set<RelayAccount> accounts = new HashSet<>();
|
||||
private Set<RelayAccount> accounts = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public List<RelayAccount> findAll() {
|
||||
|
@ -41,4 +42,11 @@ public class FakeRelayAccountRepository implements RelayAccountRepository {
|
|||
|
||||
return account;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteByGuid(@NonNull UUID guid) {
|
||||
this.accounts = this.accounts.stream()
|
||||
.filter(account -> !account.getGuid().equals(guid))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ class ForwardMessageTest {
|
|||
);
|
||||
|
||||
Relay relay = new Relay(new FakeRelayAccountRepository(), new FakeMessageRepository());
|
||||
relay.addAccount(account);
|
||||
relay.saveAccount(account);
|
||||
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
Message message = Message.of(
|
||||
|
@ -48,7 +48,7 @@ class ForwardMessageTest {
|
|||
);
|
||||
|
||||
Relay relay = new Relay(new FakeRelayAccountRepository(), new FakeMessageRepository());
|
||||
relay.addAccount(account);
|
||||
relay.saveAccount(account);
|
||||
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
Message message = Message.of(
|
||||
|
|
|
@ -20,7 +20,7 @@ class RelayTest {
|
|||
|
||||
FakeRelayAccountRepository repository = new FakeRelayAccountRepository();
|
||||
Relay relay = new Relay(repository, new FakeMessageRepository());
|
||||
relay.addAccount(account);
|
||||
relay.saveAccount(account);
|
||||
|
||||
assertThat(repository.findAll())
|
||||
.hasSize(1)
|
||||
|
|
Loading…
Reference in New Issue