Compare commits
4 Commits
main
...
feature/in
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed95090be8 | ||
|
|
f3dcc948b0 | ||
|
|
946387ae89 | ||
|
|
340d3b2a8a |
6
pom.xml
6
pom.xml
@@ -69,12 +69,6 @@
|
|||||||
<artifactId>mongodb</artifactId>
|
<artifactId>mongodb</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>de.flapdoodle.embed</groupId>
|
|
||||||
<artifactId>de.flapdoodle.embed.mongo</artifactId>
|
|
||||||
<version>3.4.5</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ public class TeamService {
|
|||||||
.flatMap(createTeamDto -> teamRepository.findByName(createTeamDto.name())
|
.flatMap(createTeamDto -> teamRepository.findByName(createTeamDto.name())
|
||||||
.doOnEach(team -> log.error("Team with name " + createTeamDto.name() + " already exists"))
|
.doOnEach(team -> log.error("Team with name " + createTeamDto.name() + " already exists"))
|
||||||
.map(Team::toGetTeamDto)
|
.map(Team::toGetTeamDto)
|
||||||
.switchIfEmpty(Mono.defer(() -> createTeamWithMembers(createTeamDto))));
|
.switchIfEmpty(Mono.defer(() -> createTeamWithMembers(createTeamDto))));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mono<GetTeamDto> createTeamWithMembers(CreateTeamDto createTeamDto) {
|
private Mono<GetTeamDto> createTeamWithMembers(CreateTeamDto createTeamDto) {
|
||||||
|
|||||||
@@ -13,5 +13,7 @@ public interface CrudRepository<T, ID> {
|
|||||||
Mono<T> save(T t);
|
Mono<T> save(T t);
|
||||||
Mono<T> delete(ID id);
|
Mono<T> delete(ID id);
|
||||||
|
|
||||||
|
Mono<Void> deleteAll();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public class Team {
|
|||||||
return TeamEntity.builder()
|
return TeamEntity.builder()
|
||||||
.id(id)
|
.id(id)
|
||||||
.name(name)
|
.name(name)
|
||||||
.members(members.stream().map(User::toEntity).toList())
|
.members(members == null ? null : members.stream().map(User::toEntity).toList())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,5 +8,6 @@ import java.util.function.Function;
|
|||||||
public interface TeamUtils {
|
public interface TeamUtils {
|
||||||
|
|
||||||
Function<Team, String> toId = team -> team.id;
|
Function<Team, String> toId = team -> team.id;
|
||||||
|
Function<Team, String> toName = team -> team.name;
|
||||||
Function<Team, List<User>> toMembers = team -> team.members;
|
Function<Team, List<User>> toMembers = team -> team.members;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package net.szymonsawicki.reactivetimesheetapp.infrastructure.persistence.reposi
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import net.szymonsawicki.reactivetimesheetapp.domain.team.Team;
|
import net.szymonsawicki.reactivetimesheetapp.domain.team.Team;
|
||||||
import net.szymonsawicki.reactivetimesheetapp.domain.team.repository.TeamRepository;
|
import net.szymonsawicki.reactivetimesheetapp.domain.team.repository.TeamRepository;
|
||||||
import net.szymonsawicki.reactivetimesheetapp.domain.user.User;
|
|
||||||
import net.szymonsawicki.reactivetimesheetapp.infrastructure.persistence.dao.TeamDao;
|
import net.szymonsawicki.reactivetimesheetapp.infrastructure.persistence.dao.TeamDao;
|
||||||
import net.szymonsawicki.reactivetimesheetapp.infrastructure.persistence.exception.PersistenceException;
|
import net.szymonsawicki.reactivetimesheetapp.infrastructure.persistence.exception.PersistenceException;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
@@ -51,6 +50,11 @@ public class TeamsRepositoryImpl implements TeamRepository {
|
|||||||
.switchIfEmpty(Mono.error(new PersistenceException("cannot find team to delete")));
|
.switchIfEmpty(Mono.error(new PersistenceException("cannot find team to delete")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<Void> deleteAll() {
|
||||||
|
return teamDao.deleteAll();
|
||||||
|
}
|
||||||
|
|
||||||
public Mono<Team> findByName(String name) {
|
public Mono<Team> findByName(String name) {
|
||||||
return teamDao.findByName(name)
|
return teamDao.findByName(name)
|
||||||
.flatMap(teamEntity -> Mono.just(teamEntity.toTeam()));
|
.flatMap(teamEntity -> Mono.just(teamEntity.toTeam()));
|
||||||
|
|||||||
@@ -52,6 +52,11 @@ public class TimeEntryRepositoryImpl implements TimeEntryRepository {
|
|||||||
.switchIfEmpty(Mono.error(new PersistenceException("cannot find team to delete")));
|
.switchIfEmpty(Mono.error(new PersistenceException("cannot find team to delete")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<Void> deleteAll() {
|
||||||
|
return timeEntryDao.deleteAll();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Flux<TimeEntry> findAllByUser(User user) {
|
public Flux<TimeEntry> findAllByUser(User user) {
|
||||||
return timeEntryDao.findAllByUser(user.toEntity())
|
return timeEntryDao.findAllByUser(user.toEntity())
|
||||||
|
|||||||
@@ -74,4 +74,9 @@ public class UserRepositoryImpl implements UserRepository {
|
|||||||
return userDao
|
return userDao
|
||||||
.deleteAll(users.stream().map(User::toEntity).toList());
|
.deleteAll(users.stream().map(User::toEntity).toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<Void> deleteAll() {
|
||||||
|
return userDao.deleteAll();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,13 +28,14 @@ public class Routing {
|
|||||||
RouterFunctions.route(GET("/{name}").and(accept(MediaType.APPLICATION_JSON)), teamHandlers::findByName)
|
RouterFunctions.route(GET("/{name}").and(accept(MediaType.APPLICATION_JSON)), teamHandlers::findByName)
|
||||||
.andRoute(GET("/id/{id}").and(accept(MediaType.APPLICATION_JSON)), teamHandlers::findById)
|
.andRoute(GET("/id/{id}").and(accept(MediaType.APPLICATION_JSON)), teamHandlers::findById)
|
||||||
.andRoute(POST("/").and(accept(MediaType.APPLICATION_JSON)), teamHandlers::addTeam)
|
.andRoute(POST("/").and(accept(MediaType.APPLICATION_JSON)), teamHandlers::addTeam)
|
||||||
.andRoute(DELETE("/{id}").and(accept(MediaType.APPLICATION_JSON)), teamHandlers::deleteTeam))
|
.andRoute(DELETE("/{id}").and(accept(MediaType.APPLICATION_JSON)), teamHandlers::deleteTeam)
|
||||||
.andNest(path("/users"),
|
.andNest(path("/reset"), RouterFunctions.route(GET("/reset").and(accept(MediaType.APPLICATION_JSON)), teamHandlers::findByName))
|
||||||
RouterFunctions.route(GET("/id/{id}").and(accept(MediaType.APPLICATION_JSON)), userHandlers::findById)
|
.andNest(path("/users"),
|
||||||
.andRoute(GET("/{username}").and(accept(MediaType.APPLICATION_JSON)), userHandlers::findByUsername)
|
RouterFunctions.route(GET("/id/{id}").and(accept(MediaType.APPLICATION_JSON)), userHandlers::findById)
|
||||||
.andRoute(POST("/").and(accept(MediaType.APPLICATION_JSON)), userHandlers::createUser)
|
.andRoute(GET("/{username}").and(accept(MediaType.APPLICATION_JSON)), userHandlers::findByUsername)
|
||||||
.andRoute(DELETE("/{id}").and(accept(MediaType.APPLICATION_JSON)), userHandlers::deleteUser))
|
.andRoute(POST("/").and(accept(MediaType.APPLICATION_JSON)), userHandlers::createUser)
|
||||||
.andNest(path("/time-entries"),
|
.andRoute(DELETE("/{id}").and(accept(MediaType.APPLICATION_JSON)), userHandlers::deleteUser))
|
||||||
RouterFunctions.route(POST("/").and(accept(MediaType.APPLICATION_JSON)), timeEntryHandlers::addTimeEntry));
|
.andNest(path("/time-entries"),
|
||||||
|
RouterFunctions.route(POST("/").and(accept(MediaType.APPLICATION_JSON)), timeEntryHandlers::addTimeEntry)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
8
src/main/resources/application-docker.yml
Normal file
8
src/main/resources/application-docker.yml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
spring:
|
||||||
|
application:
|
||||||
|
name: reactive-timesheet-app
|
||||||
|
data:
|
||||||
|
mongodb:
|
||||||
|
database: db_1
|
||||||
|
host: mongodb
|
||||||
|
port: 27017
|
||||||
8
src/main/resources/application-local.yml
Normal file
8
src/main/resources/application-local.yml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
spring:
|
||||||
|
application:
|
||||||
|
name: reactive-timesheet-app
|
||||||
|
data:
|
||||||
|
mongodb:
|
||||||
|
database: db_1
|
||||||
|
host: localhost
|
||||||
|
port: 27017
|
||||||
3
src/main/resources/application-test.yml
Normal file
3
src/main/resources/application-test.yml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
spring:
|
||||||
|
application:
|
||||||
|
name: reactive-timesheet-app
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
spring:
|
|
||||||
application:
|
|
||||||
name: reactive-timesheet-app
|
|
||||||
# data:
|
|
||||||
# database: db_1
|
|
||||||
# host: localhost
|
|
||||||
# port: 27017
|
|
||||||
|
|
||||||
mongodb:
|
|
||||||
embedded:
|
|
||||||
version: 3.4.5
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
package net.szymonsawicki.reactivetimesheetapp.application.service;
|
|
||||||
|
|
||||||
import net.szymonsawicki.reactivetimesheetapp.domain.team.Team;
|
|
||||||
import net.szymonsawicki.reactivetimesheetapp.domain.team.TeamUtils;
|
|
||||||
import net.szymonsawicki.reactivetimesheetapp.domain.team.repository.TeamRepository;
|
|
||||||
import net.szymonsawicki.reactivetimesheetapp.domain.user.User;
|
|
||||||
import net.szymonsawicki.reactivetimesheetapp.domain.user.type.Role;
|
|
||||||
import org.junit.jupiter.api.AfterAll;
|
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
|
||||||
import org.springframework.test.context.DynamicPropertyRegistry;
|
|
||||||
import org.springframework.test.context.DynamicPropertySource;
|
|
||||||
import org.testcontainers.containers.MongoDBContainer;
|
|
||||||
import org.testcontainers.junit.jupiter.Container;
|
|
||||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
|
||||||
import org.testcontainers.utility.DockerImageName;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Testcontainers
|
|
||||||
@SpringBootTest
|
|
||||||
public class ITTest {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private TeamRepository teamRepository;
|
|
||||||
|
|
||||||
@Container
|
|
||||||
public static MongoDBContainer container = new MongoDBContainer(DockerImageName.parse("mongo:4.4.3"));
|
|
||||||
|
|
||||||
@BeforeAll
|
|
||||||
static void initAll() {
|
|
||||||
container.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterAll
|
|
||||||
static void classAll() {
|
|
||||||
container.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
@DynamicPropertySource
|
|
||||||
static void setProperties(DynamicPropertyRegistry registry) {
|
|
||||||
registry.add("spring.data.mongodb.port", () -> container.getBoundPortNumbers().get(0));
|
|
||||||
registry.add("spring.data.mongodb.host", () -> container.getHost());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void containerStartsAndPublicPortIsAvailable() {
|
|
||||||
|
|
||||||
|
|
||||||
assertThatPortIsAvailable(container);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void saveEmployee() {
|
|
||||||
|
|
||||||
String userId = "21344r23r34";
|
|
||||||
String teamId = "2r872394r578";
|
|
||||||
String teamName = "Some team";
|
|
||||||
String username = "testsusrname";
|
|
||||||
Role role = Role.DEVELOPER;
|
|
||||||
|
|
||||||
var member = User.builder()
|
|
||||||
.username(username)
|
|
||||||
.password("some password")
|
|
||||||
.teamId(teamId)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
var team = Team.builder()
|
|
||||||
.id(teamId)
|
|
||||||
.name(teamName)
|
|
||||||
.members(List.of(member))
|
|
||||||
.build();
|
|
||||||
|
|
||||||
var insertedTeam = teamRepository.save(team);
|
|
||||||
|
|
||||||
var insertedTeamId = TeamUtils.toId.apply(teamRepository.save(team).block());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertThatPortIsAvailable(MongoDBContainer container) {
|
|
||||||
try {
|
|
||||||
new Socket(container.getContainerIpAddress(), container.getFirstMappedPort());
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new AssertionError("The expected port " + container.getFirstMappedPort() + " is not available!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -0,0 +1,192 @@
|
|||||||
|
package net.szymonsawicki.reactivetimesheetapp.application.service;
|
||||||
|
|
||||||
|
import net.szymonsawicki.reactivetimesheetapp.application.service.exception.TeamServiceException;
|
||||||
|
import net.szymonsawicki.reactivetimesheetapp.domain.team.Team;
|
||||||
|
import net.szymonsawicki.reactivetimesheetapp.domain.team.TeamUtils;
|
||||||
|
import net.szymonsawicki.reactivetimesheetapp.domain.team.dto.CreateTeamDto;
|
||||||
|
import net.szymonsawicki.reactivetimesheetapp.domain.team.dto.GetTeamDto;
|
||||||
|
import net.szymonsawicki.reactivetimesheetapp.domain.team.repository.TeamRepository;
|
||||||
|
import net.szymonsawicki.reactivetimesheetapp.domain.user.User;
|
||||||
|
import net.szymonsawicki.reactivetimesheetapp.domain.user.UserUtils;
|
||||||
|
import net.szymonsawicki.reactivetimesheetapp.domain.user.dto.GetUserDto;
|
||||||
|
import net.szymonsawicki.reactivetimesheetapp.domain.user.repository.UserRepository;
|
||||||
|
import net.szymonsawicki.reactivetimesheetapp.domain.user.type.Role;
|
||||||
|
import org.assertj.core.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.AfterAll;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
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.reactive.AutoConfigureWebTestClient;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.test.annotation.DirtiesContext;
|
||||||
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
|
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||||
|
import org.springframework.web.reactive.function.BodyInserters;
|
||||||
|
import org.testcontainers.containers.MongoDBContainer;
|
||||||
|
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||||
|
import reactor.test.StepVerifier;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
@SpringBootTest
|
||||||
|
@Testcontainers
|
||||||
|
@AutoConfigureWebTestClient
|
||||||
|
@ActiveProfiles("test")
|
||||||
|
public class TeamServiceIT {
|
||||||
|
|
||||||
|
/* @ClassRule
|
||||||
|
private static final MongoDBContainer MONGO_DB_CONTAINER = TimesheetAppMongoDbContainer.getInstance();
|
||||||
|
*/
|
||||||
|
|
||||||
|
private static final MongoDBContainer MONGO_DB_CONTAINER =
|
||||||
|
new MongoDBContainer("mongo:4.2.8");
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TeamRepository teamRepository;
|
||||||
|
@Autowired
|
||||||
|
private UserRepository userRepository;
|
||||||
|
@Autowired
|
||||||
|
private WebTestClient webClient;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void clearDb() {
|
||||||
|
userRepository.deleteAll();
|
||||||
|
teamRepository.deleteAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
static void setUpAll() {
|
||||||
|
MONGO_DB_CONTAINER.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterAll
|
||||||
|
static void tearDownAll() {
|
||||||
|
if (!MONGO_DB_CONTAINER.isShouldBeReused()) {
|
||||||
|
MONGO_DB_CONTAINER.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldReturnTeamOnGetById() {
|
||||||
|
|
||||||
|
String teamId = "2r872394r578";
|
||||||
|
String teamName = "Some team";
|
||||||
|
String username = "testsusrname";
|
||||||
|
Role role = Role.DEVELOPER;
|
||||||
|
|
||||||
|
var member = User.builder()
|
||||||
|
.username(username)
|
||||||
|
.password("some password")
|
||||||
|
.teamId(teamId)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
var team = Team.builder()
|
||||||
|
.name(teamName)
|
||||||
|
.members(List.of(member))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
var insertedTeam = teamRepository.save(team);
|
||||||
|
|
||||||
|
var insertedTeamId = TeamUtils.toId.apply(insertedTeam.block());
|
||||||
|
|
||||||
|
webClient.get().uri("/teams/id/{id}", insertedTeamId)
|
||||||
|
.header(HttpHeaders.ACCEPT, "application/json")
|
||||||
|
.exchange()
|
||||||
|
.expectStatus().isOk()
|
||||||
|
.expectBodyList(GetTeamDto.class);
|
||||||
|
|
||||||
|
StepVerifier.create(teamRepository.findById(insertedTeamId))
|
||||||
|
.expectNextMatches(t -> TeamUtils.toMembers.apply(t).size() == 1)
|
||||||
|
.verifyComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldReturnErrorOnGetByIdWhenNotExist() {
|
||||||
|
|
||||||
|
webClient.get().uri("/teams/id/{id}", "test123")
|
||||||
|
.header(HttpHeaders.ACCEPT, "application/json")
|
||||||
|
.exchange()
|
||||||
|
.expectStatus().is5xxServerError()
|
||||||
|
.expectBodyList(TeamServiceException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DirtiesContext
|
||||||
|
void shouldCreateTeamWithTwoMembersOnCreate() {
|
||||||
|
|
||||||
|
String teamName = "Some test team2";
|
||||||
|
String username1 = "testsusrname1";
|
||||||
|
String username2 = "testsusrname2";
|
||||||
|
String password1 = "kongamafonga";
|
||||||
|
String password2 = "kupaladupa.";
|
||||||
|
Role role = Role.DEVELOPER;
|
||||||
|
|
||||||
|
var member1 = new GetUserDto(null, username1, password1, role, null);
|
||||||
|
// var member2 = new GetUserDto(null, username2, password2, role, null);
|
||||||
|
|
||||||
|
var createTeamDto = new CreateTeamDto(teamName, List.of(member1));
|
||||||
|
|
||||||
|
webClient.post().uri("/teams/")
|
||||||
|
.header(HttpHeaders.ACCEPT, "application/json")
|
||||||
|
.body(BodyInserters.fromValue(createTeamDto))
|
||||||
|
.exchange()
|
||||||
|
.expectStatus().isCreated()
|
||||||
|
.expectBodyList(GetTeamDto.class);
|
||||||
|
|
||||||
|
StepVerifier.create(teamRepository.findByName(teamName))
|
||||||
|
.assertNext(t -> {
|
||||||
|
Assertions.assertThat(TeamUtils.toName.apply(t)).isEqualTo(teamName);
|
||||||
|
Assertions.assertThat(TeamUtils.toMembers.apply(t).size()).isEqualTo(2);
|
||||||
|
Assertions.assertThat(TeamUtils.toMembers.apply(t).stream().map(UserUtils.toUsername).toList())
|
||||||
|
.containsAll(List.of(username1, username2));
|
||||||
|
})
|
||||||
|
.verifyComplete();
|
||||||
|
|
||||||
|
var insertedTeamId = TeamUtils.toId.apply(teamRepository.findByName(teamName).block());
|
||||||
|
|
||||||
|
StepVerifier.create(userRepository.findByUsername(username1))
|
||||||
|
.expectNextMatches(user -> UserUtils.toTeamId.apply(user).equals(insertedTeamId))
|
||||||
|
.verifyComplete();
|
||||||
|
|
||||||
|
StepVerifier.create(userRepository.findByUsername(username2))
|
||||||
|
.expectNextMatches(user -> UserUtils.toTeamId.apply(user).equals(insertedTeamId))
|
||||||
|
.verifyComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldReturnExistingTeamOnCreateWhenNameTaken() {
|
||||||
|
|
||||||
|
String teamName = "Some test team2";
|
||||||
|
String username1 = "testsusrname1";
|
||||||
|
String password1 = "sdcvdfvbgdf";
|
||||||
|
Role role = Role.DEVELOPER;
|
||||||
|
|
||||||
|
var team = Team.builder()
|
||||||
|
.name(teamName)
|
||||||
|
.members(null)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
var insertedTeam = teamRepository.save(team);
|
||||||
|
|
||||||
|
var member1 = new GetUserDto(null, username1, password1, role, null);
|
||||||
|
|
||||||
|
var createTeamDto = new CreateTeamDto(teamName, List.of(member1));
|
||||||
|
|
||||||
|
webClient.post().uri("/teams/")
|
||||||
|
.header(HttpHeaders.ACCEPT, "application/json")
|
||||||
|
.body(BodyInserters.fromValue(createTeamDto))
|
||||||
|
.exchange()
|
||||||
|
.expectStatus().is2xxSuccessful()
|
||||||
|
.expectBodyList(TeamServiceException.class);
|
||||||
|
|
||||||
|
StepVerifier.create(teamRepository.findByName(teamName))
|
||||||
|
.assertNext(t -> {
|
||||||
|
Assertions.assertThat(TeamUtils.toName.apply(t)).isEqualTo(teamName);
|
||||||
|
// Assertions.assertThat(TeamUtils.toMembers.apply(t).size()).isZero();
|
||||||
|
})
|
||||||
|
.verifyComplete();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,34 +1,134 @@
|
|||||||
package net.szymonsawicki.reactivetimesheetapp.application.service;
|
package net.szymonsawicki.reactivetimesheetapp.application.service;
|
||||||
|
|
||||||
import net.szymonsawicki.reactivetimesheetapp.application.service.utils.TimesheetAppMongoDbContainer;
|
import net.szymonsawicki.reactivetimesheetapp.application.service.exception.TeamServiceException;
|
||||||
import net.szymonsawicki.reactivetimesheetapp.domain.team.Team;
|
import net.szymonsawicki.reactivetimesheetapp.domain.team.Team;
|
||||||
import net.szymonsawicki.reactivetimesheetapp.domain.team.TeamUtils;
|
import net.szymonsawicki.reactivetimesheetapp.domain.team.TeamUtils;
|
||||||
|
import net.szymonsawicki.reactivetimesheetapp.domain.team.dto.CreateTeamDto;
|
||||||
|
import net.szymonsawicki.reactivetimesheetapp.domain.team.dto.GetTeamDto;
|
||||||
import net.szymonsawicki.reactivetimesheetapp.domain.team.repository.TeamRepository;
|
import net.szymonsawicki.reactivetimesheetapp.domain.team.repository.TeamRepository;
|
||||||
import net.szymonsawicki.reactivetimesheetapp.domain.user.User;
|
import net.szymonsawicki.reactivetimesheetapp.domain.user.User;
|
||||||
|
import net.szymonsawicki.reactivetimesheetapp.domain.user.UserUtils;
|
||||||
|
import net.szymonsawicki.reactivetimesheetapp.domain.user.dto.GetUserDto;
|
||||||
import net.szymonsawicki.reactivetimesheetapp.domain.user.repository.UserRepository;
|
import net.szymonsawicki.reactivetimesheetapp.domain.user.repository.UserRepository;
|
||||||
import net.szymonsawicki.reactivetimesheetapp.domain.user.type.Role;
|
import net.szymonsawicki.reactivetimesheetapp.domain.user.type.Role;
|
||||||
|
import org.assertj.core.api.Assertions;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Captor;
|
||||||
|
import org.mockito.InOrder;
|
||||||
|
import org.mockito.Mockito;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.TestConfiguration;
|
||||||
import org.testcontainers.containers.MongoDBContainer;
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
import org.testcontainers.junit.jupiter.Container;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
|
import reactor.core.publisher.Flux;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
import reactor.test.StepVerifier;
|
import reactor.test.StepVerifier;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ExtendWith(SpringExtension.class)
|
||||||
@SpringBootTest
|
|
||||||
public class TeamServiceTest {
|
public class TeamServiceTest {
|
||||||
@Container
|
|
||||||
private static final MongoDBContainer MONGO_DB_CONTAINER = TimesheetAppMongoDbContainer.getInstance();
|
@TestConfiguration
|
||||||
|
public static class TeamServiceTestConfiguration {
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
public TeamRepository teamRepository;
|
||||||
|
@MockBean
|
||||||
|
public UserRepository userRepository;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public TeamService teamService() {
|
||||||
|
return new TeamService(teamRepository, userRepository);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private TeamRepository teamRepository;
|
public TeamRepository teamRepository;
|
||||||
@Autowired
|
@Autowired
|
||||||
private UserRepository userRepository;
|
public UserRepository userRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public TeamService teamService;
|
||||||
|
|
||||||
|
@Captor
|
||||||
|
public ArgumentCaptor<List<User>> usersCaptor;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldReturnTeamOnGetById() {
|
public void shouldReturnThreeTeamsOnFindAll() {
|
||||||
|
|
||||||
|
String userId1 = "21344r23r34";
|
||||||
|
String userId2 = "21344r23r34";
|
||||||
|
String teamId1 = "2r872394r578";
|
||||||
|
String teamId2 = "2r872394r578";
|
||||||
|
String teamName1 = "Some team";
|
||||||
|
String teamName2 = "Some team";
|
||||||
|
String username1 = "testsusrname";
|
||||||
|
String username2 = "testsusrname2";
|
||||||
|
|
||||||
|
var member1 = new GetUserDto(
|
||||||
|
userId1,
|
||||||
|
username1,
|
||||||
|
"some password",
|
||||||
|
null, teamId1);
|
||||||
|
|
||||||
|
var member2 = new GetUserDto(
|
||||||
|
userId2,
|
||||||
|
username2,
|
||||||
|
"some password",
|
||||||
|
null, teamId2);
|
||||||
|
|
||||||
|
var expectedTeam1 = new GetTeamDto(
|
||||||
|
teamId1,
|
||||||
|
teamName1,
|
||||||
|
List.of(member1));
|
||||||
|
|
||||||
|
var expectedTeam2 = new GetTeamDto(
|
||||||
|
teamId2,
|
||||||
|
teamName2,
|
||||||
|
List.of(member2));
|
||||||
|
|
||||||
|
var memberFromDb1 = User.builder()
|
||||||
|
.id(userId1)
|
||||||
|
.username(username1)
|
||||||
|
.password("some password")
|
||||||
|
.teamId(teamId1)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
var memberFromDb2 = User.builder()
|
||||||
|
.id(userId2)
|
||||||
|
.username(username2)
|
||||||
|
.password("some password")
|
||||||
|
.teamId(teamId2)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
var teamFromDb1 = Team.builder()
|
||||||
|
.id(teamId1)
|
||||||
|
.name(teamName1)
|
||||||
|
.members(List.of(memberFromDb1))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
var teamFromDb2 = Team.builder()
|
||||||
|
.id(teamId2)
|
||||||
|
.name(teamName2)
|
||||||
|
.members(List.of(memberFromDb2))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Mockito.when(teamRepository.findAll())
|
||||||
|
.thenReturn(Flux.just(teamFromDb1, teamFromDb2));
|
||||||
|
|
||||||
|
StepVerifier
|
||||||
|
.create(teamService.findAllTeams())
|
||||||
|
.expectNext(expectedTeam1)
|
||||||
|
.expectNext(expectedTeam2)
|
||||||
|
.verifyComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldReturnTeamWithOneMemberOnGetById() {
|
||||||
|
|
||||||
String userId = "21344r23r34";
|
String userId = "21344r23r34";
|
||||||
String teamId = "2r872394r578";
|
String teamId = "2r872394r578";
|
||||||
@@ -42,17 +142,311 @@ public class TeamServiceTest {
|
|||||||
.teamId(teamId)
|
.teamId(teamId)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
var team = Team.builder()
|
var teamEntityMono = Mono.just(Team.builder()
|
||||||
|
.id(teamId)
|
||||||
.name(teamName)
|
.name(teamName)
|
||||||
.members(List.of(member))
|
.members(List.of(member))
|
||||||
.build();
|
.build());
|
||||||
|
|
||||||
var insertedTeam = teamRepository.save(team);
|
Mockito.when(teamRepository.findById(Mockito.anyString()))
|
||||||
|
.thenReturn(teamEntityMono);
|
||||||
|
|
||||||
var insertedTeamId = TeamUtils.toId.apply(insertedTeam.block());
|
StepVerifier
|
||||||
|
.create(teamService.findById(userId))
|
||||||
StepVerifier.create(teamRepository.findById(insertedTeamId))
|
.assertNext(team -> {
|
||||||
.expectNextMatches(t -> TeamUtils.toMembers.apply(t).size() == 1)
|
Assertions.assertThat(team.name().equals(teamName));
|
||||||
|
Assertions.assertThat(team.members()).hasSize(1);
|
||||||
|
Assertions.assertThat(team.members().get(0).username()).isEqualTo(username);
|
||||||
|
})
|
||||||
.verifyComplete();
|
.verifyComplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldReturnErrorOnGetByIdWhenTeamMissing() {
|
||||||
|
|
||||||
|
Mockito.when(teamRepository.findById(Mockito.anyString()))
|
||||||
|
.thenReturn(Mono.empty());
|
||||||
|
|
||||||
|
StepVerifier
|
||||||
|
.create(teamService.findById("some id"))
|
||||||
|
.expectErrorMatches(error -> error instanceof TeamServiceException && error.getMessage().equals("Team with given id doesn't exist"))
|
||||||
|
.verify();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldFindTeamByName() {
|
||||||
|
|
||||||
|
String userId = "21344r23r34";
|
||||||
|
String teamId = "2r872394r578";
|
||||||
|
String teamName = "Some team";
|
||||||
|
String username = "testsusrname";
|
||||||
|
|
||||||
|
var member = User.builder()
|
||||||
|
.id(userId)
|
||||||
|
.username(username)
|
||||||
|
.password("some password")
|
||||||
|
.teamId(teamId)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
var expectedMemberDto = new GetUserDto(
|
||||||
|
userId,
|
||||||
|
username,
|
||||||
|
"some password",
|
||||||
|
null, teamId);
|
||||||
|
|
||||||
|
|
||||||
|
var teamMono = Mono.just(Team.builder()
|
||||||
|
.id(teamId)
|
||||||
|
.name(teamName)
|
||||||
|
.members(List.of(member))
|
||||||
|
.build());
|
||||||
|
|
||||||
|
Mockito.when(teamRepository.findByName(Mockito.anyString()))
|
||||||
|
.thenReturn(teamMono);
|
||||||
|
|
||||||
|
StepVerifier
|
||||||
|
.create(teamService.findByName(teamName))
|
||||||
|
.expectNextMatches(resultingTeam -> resultingTeam.name().equals(teamName))
|
||||||
|
.verifyComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldReturnErrorOnGetTeamByNameWhenMissing() {
|
||||||
|
|
||||||
|
Mockito.when(teamRepository.findByName(Mockito.anyString()))
|
||||||
|
.thenReturn(Mono.empty());
|
||||||
|
|
||||||
|
StepVerifier
|
||||||
|
.create(teamService.findByName("some name"))
|
||||||
|
.expectErrorMatches(error -> error instanceof TeamServiceException && error.getMessage().equals("Team with given name doesn't exist"))
|
||||||
|
.verify();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldCreateNewTeamWithMembers() {
|
||||||
|
|
||||||
|
String userId1 = "21344r23r34";
|
||||||
|
String userId2 = "21344r23r34";
|
||||||
|
String teamId = "2r872394r578";
|
||||||
|
String teamName = "Some team";
|
||||||
|
String username1 = "testsusrname";
|
||||||
|
String username2 = "testsusrname2";
|
||||||
|
|
||||||
|
ArgumentCaptor<Team> saveTeamCaptor = ArgumentCaptor.forClass(Team.class);
|
||||||
|
|
||||||
|
var member1 = new GetUserDto(
|
||||||
|
userId1,
|
||||||
|
username1,
|
||||||
|
"some password",
|
||||||
|
null, null);
|
||||||
|
|
||||||
|
var member2 = new GetUserDto(
|
||||||
|
userId2,
|
||||||
|
username2,
|
||||||
|
"some password",
|
||||||
|
null, null);
|
||||||
|
|
||||||
|
var savedMember1 = User.builder()
|
||||||
|
.id(userId1)
|
||||||
|
.username(username1)
|
||||||
|
.password("some password")
|
||||||
|
.teamId(teamId)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
var savedMember2 = User.builder()
|
||||||
|
.id(userId2)
|
||||||
|
.username(username2)
|
||||||
|
.password("some password")
|
||||||
|
.teamId(teamId)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
var teamToCreateMono = Mono.just(new CreateTeamDto(
|
||||||
|
teamName
|
||||||
|
, List.of(member1, member2)));
|
||||||
|
|
||||||
|
var createdTeamMono = Mono.just(Team.builder()
|
||||||
|
.id(teamId)
|
||||||
|
.name(teamName)
|
||||||
|
.members(List.of(savedMember1, savedMember2))
|
||||||
|
.build());
|
||||||
|
|
||||||
|
Mockito.when(teamRepository.findByName(Mockito.anyString()))
|
||||||
|
.thenReturn(Mono.empty());
|
||||||
|
|
||||||
|
Mockito.when(teamRepository.save(saveTeamCaptor.capture()))
|
||||||
|
.thenReturn(createdTeamMono);
|
||||||
|
|
||||||
|
Mockito.when(userRepository.saveAll(usersCaptor.capture()))
|
||||||
|
.thenReturn(Flux.just(savedMember1, savedMember2));
|
||||||
|
|
||||||
|
StepVerifier
|
||||||
|
.create(teamService.addTeam(teamToCreateMono))
|
||||||
|
.assertNext(team -> {
|
||||||
|
Assertions.assertThat(team.name()).isEqualTo(teamName);
|
||||||
|
Assertions.assertThat(team.members()).hasSize(2);
|
||||||
|
Assertions.assertThat(team.members().stream().map(GetUserDto::username).toList()).containsAll(List.of(username1, username2));
|
||||||
|
Assertions.assertThat(team.members().stream().filter(member -> !member.teamId().equals(teamId)).toList()).isEmpty();
|
||||||
|
// captor assertions
|
||||||
|
Assertions.assertThat(TeamUtils.toMembers.apply(saveTeamCaptor.getValue())).hasSize(2);
|
||||||
|
Assertions.assertThat(TeamUtils.toId.apply(saveTeamCaptor.getValue())).isEqualTo(teamId);
|
||||||
|
Assertions.assertThat(usersCaptor.getValue()).hasSize(2);
|
||||||
|
})
|
||||||
|
.verifyComplete();
|
||||||
|
|
||||||
|
InOrder inOrder = Mockito.inOrder(teamRepository, userRepository);
|
||||||
|
|
||||||
|
inOrder.verify(teamRepository, Mockito.times(1)).findByName(teamName);
|
||||||
|
inOrder.verify(teamRepository, Mockito.times(1)).save(Mockito.any(Team.class));
|
||||||
|
inOrder.verify(userRepository, Mockito.times(1)).saveAll(Mockito.any());
|
||||||
|
inOrder.verify(teamRepository, Mockito.times(1)).save(Mockito.any(Team.class));
|
||||||
|
|
||||||
|
Mockito.verifyNoMoreInteractions(teamRepository, userRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldReturnExistingTeamWhenNameIsTakenOnAddTeam() {
|
||||||
|
|
||||||
|
String userId1 = "21344r23r34";
|
||||||
|
String userId2 = "tzuh";
|
||||||
|
String teamId = "2r872394r578";
|
||||||
|
String teamName = "Some team";
|
||||||
|
String username1 = "testsusrname";
|
||||||
|
String username2 = "testsusrname2";
|
||||||
|
|
||||||
|
var member1 = new GetUserDto(
|
||||||
|
userId1,
|
||||||
|
username1,
|
||||||
|
"some password",
|
||||||
|
null, null);
|
||||||
|
|
||||||
|
var member2 = new GetUserDto(
|
||||||
|
userId2,
|
||||||
|
username2,
|
||||||
|
"some password",
|
||||||
|
null, null);
|
||||||
|
|
||||||
|
var expectedMember1 = new GetUserDto(
|
||||||
|
userId1,
|
||||||
|
username1,
|
||||||
|
"some password",
|
||||||
|
null, teamId);
|
||||||
|
|
||||||
|
var expectedMember2 = new GetUserDto(
|
||||||
|
userId2,
|
||||||
|
username2,
|
||||||
|
"some password",
|
||||||
|
null, teamId);
|
||||||
|
|
||||||
|
var savedMember1 = User.builder()
|
||||||
|
.id(userId1)
|
||||||
|
.username(username1)
|
||||||
|
.password("some password")
|
||||||
|
.teamId(teamId)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
var savedMember2 = User.builder()
|
||||||
|
.id(userId2)
|
||||||
|
.username(username2)
|
||||||
|
.password("some password")
|
||||||
|
.teamId(teamId)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
var teamToCreateMono = Mono.just(new CreateTeamDto(
|
||||||
|
teamName
|
||||||
|
, List.of(member1, member2)));
|
||||||
|
|
||||||
|
var expectedTeamDto = new GetTeamDto(
|
||||||
|
teamId,
|
||||||
|
teamName
|
||||||
|
, List.of(expectedMember1, expectedMember2));
|
||||||
|
|
||||||
|
var existingTeamMono = Mono.just(Team.builder()
|
||||||
|
.id(teamId)
|
||||||
|
.name(teamName)
|
||||||
|
.members(List.of(savedMember1, savedMember2))
|
||||||
|
.build());
|
||||||
|
|
||||||
|
Mockito.when(teamRepository.findByName(Mockito.anyString()))
|
||||||
|
.thenReturn(existingTeamMono);
|
||||||
|
|
||||||
|
StepVerifier
|
||||||
|
.create(teamService.addTeam(teamToCreateMono))
|
||||||
|
.expectNext(expectedTeamDto)
|
||||||
|
.verifyComplete();
|
||||||
|
|
||||||
|
Mockito.verify(teamRepository, Mockito.never())
|
||||||
|
.save(Mockito.any());
|
||||||
|
Mockito.verify(userRepository, Mockito.never())
|
||||||
|
.saveAll(Mockito.any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void ShouldDeleteTeamOnDelete() {
|
||||||
|
|
||||||
|
String userId1 = "21344r23r34";
|
||||||
|
String userId2 = "21344r23r34";
|
||||||
|
String teamId = "2r872394r578";
|
||||||
|
String teamName = "Some team";
|
||||||
|
String username1 = "testsusrname";
|
||||||
|
String username2 = "testsusrname2";
|
||||||
|
|
||||||
|
var existingMember1 = User.builder()
|
||||||
|
.id(userId1)
|
||||||
|
.username(username1)
|
||||||
|
.password("some password")
|
||||||
|
.teamId(teamId)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
var existingMember2 = User.builder()
|
||||||
|
.id(userId2)
|
||||||
|
.username(username2)
|
||||||
|
.password("some password")
|
||||||
|
.teamId(teamId)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
var existingTeam = Team.builder()
|
||||||
|
.id(teamId)
|
||||||
|
.name(teamName)
|
||||||
|
.members(List.of(existingMember1, existingMember2))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Mockito.when(teamRepository.findById(Mockito.anyString()))
|
||||||
|
.thenReturn(Mono.just(existingTeam));
|
||||||
|
|
||||||
|
Mockito.when(userRepository.saveAll(usersCaptor.capture()))
|
||||||
|
.thenReturn(Flux.just(existingMember1, existingMember2));
|
||||||
|
|
||||||
|
Mockito.when(teamRepository.delete(Mockito.anyString()))
|
||||||
|
.thenReturn(Mono.empty());
|
||||||
|
|
||||||
|
StepVerifier
|
||||||
|
.create(teamService.deleteTeam(teamId))
|
||||||
|
.assertNext(team -> {
|
||||||
|
Assertions.assertThat(team.name()).isEqualTo(teamName);
|
||||||
|
Assertions.assertThat(team.members()).hasSize(2);
|
||||||
|
Assertions.assertThat(team.members().stream().map(GetUserDto::username).toList()).containsAll(List.of(username1, username2));
|
||||||
|
Assertions.assertThat(team.members().stream().filter(member -> !member.teamId().equals(teamId)).toList()).isEmpty();
|
||||||
|
// captor assertions
|
||||||
|
Assertions.assertThat(usersCaptor.getValue()).hasSize(2);
|
||||||
|
Assertions.assertThat(usersCaptor.getValue().stream().filter(user -> UserUtils.toTeamId.apply(user) != null).toList()).isEmpty();
|
||||||
|
})
|
||||||
|
.verifyComplete();
|
||||||
|
|
||||||
|
Mockito.verify(teamRepository, Mockito.times(1))
|
||||||
|
.delete(teamId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldReturnErrorOnDeleteWhenNotExist() {
|
||||||
|
|
||||||
|
Mockito.when(teamRepository.findById(Mockito.anyString()))
|
||||||
|
.thenReturn(Mono.empty());
|
||||||
|
|
||||||
|
StepVerifier
|
||||||
|
.create(teamService.deleteTeam("some id"))
|
||||||
|
.expectErrorMatches(error -> error instanceof TeamServiceException && error.getMessage().equals("cannot find team to delete"))
|
||||||
|
.verify();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,453 +0,0 @@
|
|||||||
package unit_tests.net.szymonsawicki.reactivetimesheetapp.application.service;
|
|
||||||
|
|
||||||
import net.szymonsawicki.reactivetimesheetapp.application.service.TeamService;
|
|
||||||
import net.szymonsawicki.reactivetimesheetapp.application.service.exception.TeamServiceException;
|
|
||||||
import net.szymonsawicki.reactivetimesheetapp.domain.team.Team;
|
|
||||||
import net.szymonsawicki.reactivetimesheetapp.domain.team.TeamUtils;
|
|
||||||
import net.szymonsawicki.reactivetimesheetapp.domain.team.dto.CreateTeamDto;
|
|
||||||
import net.szymonsawicki.reactivetimesheetapp.domain.team.dto.GetTeamDto;
|
|
||||||
import net.szymonsawicki.reactivetimesheetapp.domain.team.repository.TeamRepository;
|
|
||||||
import net.szymonsawicki.reactivetimesheetapp.domain.user.User;
|
|
||||||
import net.szymonsawicki.reactivetimesheetapp.domain.user.UserUtils;
|
|
||||||
import net.szymonsawicki.reactivetimesheetapp.domain.user.dto.GetUserDto;
|
|
||||||
import net.szymonsawicki.reactivetimesheetapp.domain.user.repository.UserRepository;
|
|
||||||
import net.szymonsawicki.reactivetimesheetapp.domain.user.type.Role;
|
|
||||||
import org.assertj.core.api.Assertions;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
|
||||||
import org.mockito.ArgumentCaptor;
|
|
||||||
import org.mockito.Captor;
|
|
||||||
import org.mockito.InOrder;
|
|
||||||
import org.mockito.Mockito;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.boot.test.context.TestConfiguration;
|
|
||||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
|
||||||
import reactor.core.publisher.Flux;
|
|
||||||
import reactor.core.publisher.Mono;
|
|
||||||
import reactor.test.StepVerifier;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@ExtendWith(SpringExtension.class)
|
|
||||||
public class TeamServiceTest {
|
|
||||||
|
|
||||||
@TestConfiguration
|
|
||||||
public static class TeamServiceTestConfiguration {
|
|
||||||
|
|
||||||
@MockBean
|
|
||||||
public TeamRepository teamRepository;
|
|
||||||
@MockBean
|
|
||||||
public UserRepository userRepository;
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public TeamService teamService() {
|
|
||||||
return new TeamService(teamRepository, userRepository);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public TeamRepository teamRepository;
|
|
||||||
@Autowired
|
|
||||||
public UserRepository userRepository;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public TeamService teamService;
|
|
||||||
|
|
||||||
@Captor
|
|
||||||
public ArgumentCaptor<List<User>> usersCaptor;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldReturnThreeTeamsOnFindAll() {
|
|
||||||
|
|
||||||
String userId1 = "21344r23r34";
|
|
||||||
String userId2 = "21344r23r34";
|
|
||||||
String teamId1 = "2r872394r578";
|
|
||||||
String teamId2 = "2r872394r578";
|
|
||||||
String teamName1 = "Some team";
|
|
||||||
String teamName2 = "Some team";
|
|
||||||
String username1 = "testsusrname";
|
|
||||||
String username2 = "testsusrname2";
|
|
||||||
|
|
||||||
var member1 = new GetUserDto(
|
|
||||||
userId1,
|
|
||||||
username1,
|
|
||||||
"some password",
|
|
||||||
null, teamId1);
|
|
||||||
|
|
||||||
var member2 = new GetUserDto(
|
|
||||||
userId2,
|
|
||||||
username2,
|
|
||||||
"some password",
|
|
||||||
null, teamId2);
|
|
||||||
|
|
||||||
var expectedTeam1 = new GetTeamDto(
|
|
||||||
teamId1,
|
|
||||||
teamName1,
|
|
||||||
List.of(member1));
|
|
||||||
|
|
||||||
var expectedTeam2 = new GetTeamDto(
|
|
||||||
teamId2,
|
|
||||||
teamName2,
|
|
||||||
List.of(member2));
|
|
||||||
|
|
||||||
var memberFromDb1 = User.builder()
|
|
||||||
.id(userId1)
|
|
||||||
.username(username1)
|
|
||||||
.password("some password")
|
|
||||||
.teamId(teamId1)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
var memberFromDb2 = User.builder()
|
|
||||||
.id(userId2)
|
|
||||||
.username(username2)
|
|
||||||
.password("some password")
|
|
||||||
.teamId(teamId2)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
var teamFromDb1 = Team.builder()
|
|
||||||
.id(teamId1)
|
|
||||||
.name(teamName1)
|
|
||||||
.members(List.of(memberFromDb1))
|
|
||||||
.build();
|
|
||||||
|
|
||||||
var teamFromDb2 = Team.builder()
|
|
||||||
.id(teamId2)
|
|
||||||
.name(teamName2)
|
|
||||||
.members(List.of(memberFromDb2))
|
|
||||||
.build();
|
|
||||||
|
|
||||||
Mockito.when(teamRepository.findAll())
|
|
||||||
.thenReturn(Flux.just(teamFromDb1, teamFromDb2));
|
|
||||||
|
|
||||||
StepVerifier
|
|
||||||
.create(teamService.findAllTeams())
|
|
||||||
.expectNext(expectedTeam1)
|
|
||||||
.expectNext(expectedTeam2)
|
|
||||||
.verifyComplete();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldReturnTeamWithOneMemberOnGetById() {
|
|
||||||
|
|
||||||
String userId = "21344r23r34";
|
|
||||||
String teamId = "2r872394r578";
|
|
||||||
String teamName = "Some team";
|
|
||||||
String username = "testsusrname";
|
|
||||||
Role role = Role.DEVELOPER;
|
|
||||||
|
|
||||||
var member = User.builder()
|
|
||||||
.username(username)
|
|
||||||
.password("some password")
|
|
||||||
.teamId(teamId)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
var teamEntityMono = Mono.just(Team.builder()
|
|
||||||
.id(teamId)
|
|
||||||
.name(teamName)
|
|
||||||
.members(List.of(member))
|
|
||||||
.build());
|
|
||||||
|
|
||||||
Mockito.when(teamRepository.findById(Mockito.anyString()))
|
|
||||||
.thenReturn(teamEntityMono);
|
|
||||||
|
|
||||||
StepVerifier
|
|
||||||
.create(teamService.findById(userId))
|
|
||||||
.assertNext(team -> {
|
|
||||||
Assertions.assertThat(team.name().equals(teamName));
|
|
||||||
Assertions.assertThat(team.members()).hasSize(1);
|
|
||||||
Assertions.assertThat(team.members().get(0).username()).isEqualTo(username);
|
|
||||||
})
|
|
||||||
.verifyComplete();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldReturnErrorOnGetByIdWhenTeamMissing() {
|
|
||||||
|
|
||||||
Mockito.when(teamRepository.findById(Mockito.anyString()))
|
|
||||||
.thenReturn(Mono.empty());
|
|
||||||
|
|
||||||
StepVerifier
|
|
||||||
.create(teamService.findById("some id"))
|
|
||||||
.expectErrorMatches(error -> error instanceof TeamServiceException && error.getMessage().equals("Team with given id doesn't exist"))
|
|
||||||
.verify();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldFindTeamByName() {
|
|
||||||
|
|
||||||
String userId = "21344r23r34";
|
|
||||||
String teamId = "2r872394r578";
|
|
||||||
String teamName = "Some team";
|
|
||||||
String username = "testsusrname";
|
|
||||||
|
|
||||||
var member = User.builder()
|
|
||||||
.id(userId)
|
|
||||||
.username(username)
|
|
||||||
.password("some password")
|
|
||||||
.teamId(teamId)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
var expectedMemberDto = new GetUserDto(
|
|
||||||
userId,
|
|
||||||
username,
|
|
||||||
"some password",
|
|
||||||
null, teamId);
|
|
||||||
|
|
||||||
|
|
||||||
var teamMono = Mono.just(Team.builder()
|
|
||||||
.id(teamId)
|
|
||||||
.name(teamName)
|
|
||||||
.members(List.of(member))
|
|
||||||
.build());
|
|
||||||
|
|
||||||
Mockito.when(teamRepository.findByName(Mockito.anyString()))
|
|
||||||
.thenReturn(teamMono);
|
|
||||||
|
|
||||||
StepVerifier
|
|
||||||
.create(teamService.findByName(teamName))
|
|
||||||
.expectNextMatches(resultingTeam -> resultingTeam.name().equals(teamName))
|
|
||||||
.verifyComplete();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldReturnErrorOnGetTeamByNameWhenMissing() {
|
|
||||||
|
|
||||||
Mockito.when(teamRepository.findByName(Mockito.anyString()))
|
|
||||||
.thenReturn(Mono.empty());
|
|
||||||
|
|
||||||
StepVerifier
|
|
||||||
.create(teamService.findByName("some name"))
|
|
||||||
.expectErrorMatches(error -> error instanceof TeamServiceException && error.getMessage().equals("Team with given name doesn't exist"))
|
|
||||||
.verify();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldCreateNewTeamWithMembers() {
|
|
||||||
|
|
||||||
String userId1 = "21344r23r34";
|
|
||||||
String userId2 = "21344r23r34";
|
|
||||||
String teamId = "2r872394r578";
|
|
||||||
String teamName = "Some team";
|
|
||||||
String username1 = "testsusrname";
|
|
||||||
String username2 = "testsusrname2";
|
|
||||||
|
|
||||||
ArgumentCaptor<Team> saveTeamCaptor = ArgumentCaptor.forClass(Team.class);
|
|
||||||
|
|
||||||
var member1 = new GetUserDto(
|
|
||||||
userId1,
|
|
||||||
username1,
|
|
||||||
"some password",
|
|
||||||
null, null);
|
|
||||||
|
|
||||||
var member2 = new GetUserDto(
|
|
||||||
userId2,
|
|
||||||
username2,
|
|
||||||
"some password",
|
|
||||||
null, null);
|
|
||||||
|
|
||||||
var savedMember1 = User.builder()
|
|
||||||
.id(userId1)
|
|
||||||
.username(username1)
|
|
||||||
.password("some password")
|
|
||||||
.teamId(teamId)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
var savedMember2 = User.builder()
|
|
||||||
.id(userId2)
|
|
||||||
.username(username2)
|
|
||||||
.password("some password")
|
|
||||||
.teamId(teamId)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
var teamToCreateMono = Mono.just(new CreateTeamDto(
|
|
||||||
teamName
|
|
||||||
, List.of(member1, member2)));
|
|
||||||
|
|
||||||
var createdTeamMono = Mono.just(Team.builder()
|
|
||||||
.id(teamId)
|
|
||||||
.name(teamName)
|
|
||||||
.members(List.of(savedMember1, savedMember2))
|
|
||||||
.build());
|
|
||||||
|
|
||||||
Mockito.when(teamRepository.findByName(Mockito.anyString()))
|
|
||||||
.thenReturn(Mono.empty());
|
|
||||||
|
|
||||||
Mockito.when(teamRepository.save(saveTeamCaptor.capture()))
|
|
||||||
.thenReturn(createdTeamMono);
|
|
||||||
|
|
||||||
Mockito.when(userRepository.saveAll(usersCaptor.capture()))
|
|
||||||
.thenReturn(Flux.just(savedMember1, savedMember2));
|
|
||||||
|
|
||||||
StepVerifier
|
|
||||||
.create(teamService.addTeam(teamToCreateMono))
|
|
||||||
.assertNext(team -> {
|
|
||||||
Assertions.assertThat(team.name()).isEqualTo(teamName);
|
|
||||||
Assertions.assertThat(team.members()).hasSize(2);
|
|
||||||
Assertions.assertThat(team.members().stream().map(GetUserDto::username).toList()).containsAll(List.of(username1, username2));
|
|
||||||
Assertions.assertThat(team.members().stream().filter(member -> !member.teamId().equals(teamId)).toList()).isEmpty();
|
|
||||||
// captor assertions
|
|
||||||
Assertions.assertThat(TeamUtils.toMembers.apply(saveTeamCaptor.getValue())).hasSize(2);
|
|
||||||
Assertions.assertThat(TeamUtils.toId.apply(saveTeamCaptor.getValue())).isEqualTo(teamId);
|
|
||||||
Assertions.assertThat(usersCaptor.getValue()).hasSize(2);
|
|
||||||
})
|
|
||||||
.verifyComplete();
|
|
||||||
|
|
||||||
InOrder inOrder = Mockito.inOrder(teamRepository, userRepository);
|
|
||||||
|
|
||||||
inOrder.verify(teamRepository, Mockito.times(1)).findByName(teamName);
|
|
||||||
inOrder.verify(teamRepository, Mockito.times(1)).save(Mockito.any(Team.class));
|
|
||||||
inOrder.verify(userRepository, Mockito.times(1)).saveAll(Mockito.any());
|
|
||||||
inOrder.verify(teamRepository, Mockito.times(1)).save(Mockito.any(Team.class));
|
|
||||||
|
|
||||||
Mockito.verifyNoMoreInteractions(teamRepository, userRepository);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldReturnExistingTeamWhenNameIsTakenOnAddTeam() {
|
|
||||||
|
|
||||||
String userId1 = "21344r23r34";
|
|
||||||
String userId2 = "tzuh";
|
|
||||||
String teamId = "2r872394r578";
|
|
||||||
String teamName = "Some team";
|
|
||||||
String username1 = "testsusrname";
|
|
||||||
String username2 = "testsusrname2";
|
|
||||||
|
|
||||||
var member1 = new GetUserDto(
|
|
||||||
userId1,
|
|
||||||
username1,
|
|
||||||
"some password",
|
|
||||||
null, null);
|
|
||||||
|
|
||||||
var member2 = new GetUserDto(
|
|
||||||
userId2,
|
|
||||||
username2,
|
|
||||||
"some password",
|
|
||||||
null, null);
|
|
||||||
|
|
||||||
var expectedMember1 = new GetUserDto(
|
|
||||||
userId1,
|
|
||||||
username1,
|
|
||||||
"some password",
|
|
||||||
null, teamId);
|
|
||||||
|
|
||||||
var expectedMember2 = new GetUserDto(
|
|
||||||
userId2,
|
|
||||||
username2,
|
|
||||||
"some password",
|
|
||||||
null, teamId);
|
|
||||||
|
|
||||||
var savedMember1 = User.builder()
|
|
||||||
.id(userId1)
|
|
||||||
.username(username1)
|
|
||||||
.password("some password")
|
|
||||||
.teamId(teamId)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
var savedMember2 = User.builder()
|
|
||||||
.id(userId2)
|
|
||||||
.username(username2)
|
|
||||||
.password("some password")
|
|
||||||
.teamId(teamId)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
var teamToCreateMono = Mono.just(new CreateTeamDto(
|
|
||||||
teamName
|
|
||||||
, List.of(member1, member2)));
|
|
||||||
|
|
||||||
var expectedTeamDto = new GetTeamDto(
|
|
||||||
teamId,
|
|
||||||
teamName
|
|
||||||
, List.of(expectedMember1, expectedMember2));
|
|
||||||
|
|
||||||
var existingTeamMono = Mono.just(Team.builder()
|
|
||||||
.id(teamId)
|
|
||||||
.name(teamName)
|
|
||||||
.members(List.of(savedMember1, savedMember2))
|
|
||||||
.build());
|
|
||||||
|
|
||||||
Mockito.when(teamRepository.findByName(Mockito.anyString()))
|
|
||||||
.thenReturn(existingTeamMono);
|
|
||||||
|
|
||||||
StepVerifier
|
|
||||||
.create(teamService.addTeam(teamToCreateMono))
|
|
||||||
.expectNext(expectedTeamDto)
|
|
||||||
.verifyComplete();
|
|
||||||
|
|
||||||
Mockito.verify(teamRepository, Mockito.never())
|
|
||||||
.save(Mockito.any());
|
|
||||||
Mockito.verify(userRepository, Mockito.never())
|
|
||||||
.saveAll(Mockito.any());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void ShouldDeleteTeamOnDelete() {
|
|
||||||
|
|
||||||
String userId1 = "21344r23r34";
|
|
||||||
String userId2 = "21344r23r34";
|
|
||||||
String teamId = "2r872394r578";
|
|
||||||
String teamName = "Some team";
|
|
||||||
String username1 = "testsusrname";
|
|
||||||
String username2 = "testsusrname2";
|
|
||||||
|
|
||||||
var existingMember1 = User.builder()
|
|
||||||
.id(userId1)
|
|
||||||
.username(username1)
|
|
||||||
.password("some password")
|
|
||||||
.teamId(teamId)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
var existingMember2 = User.builder()
|
|
||||||
.id(userId2)
|
|
||||||
.username(username2)
|
|
||||||
.password("some password")
|
|
||||||
.teamId(teamId)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
var existingTeam = Team.builder()
|
|
||||||
.id(teamId)
|
|
||||||
.name(teamName)
|
|
||||||
.members(List.of(existingMember1, existingMember2))
|
|
||||||
.build();
|
|
||||||
|
|
||||||
Mockito.when(teamRepository.findById(Mockito.anyString()))
|
|
||||||
.thenReturn(Mono.just(existingTeam));
|
|
||||||
|
|
||||||
Mockito.when(userRepository.saveAll(usersCaptor.capture()))
|
|
||||||
.thenReturn(Flux.just(existingMember1, existingMember2));
|
|
||||||
|
|
||||||
Mockito.when(teamRepository.delete(Mockito.anyString()))
|
|
||||||
.thenReturn(Mono.empty());
|
|
||||||
|
|
||||||
StepVerifier
|
|
||||||
.create(teamService.deleteTeam(teamId))
|
|
||||||
.assertNext(team -> {
|
|
||||||
Assertions.assertThat(team.name()).isEqualTo(teamName);
|
|
||||||
Assertions.assertThat(team.members()).hasSize(2);
|
|
||||||
Assertions.assertThat(team.members().stream().map(GetUserDto::username).toList()).containsAll(List.of(username1, username2));
|
|
||||||
Assertions.assertThat(team.members().stream().filter(member -> !member.teamId().equals(teamId)).toList()).isEmpty();
|
|
||||||
// captor assertions
|
|
||||||
Assertions.assertThat(usersCaptor.getValue()).hasSize(2);
|
|
||||||
Assertions.assertThat(usersCaptor.getValue().stream().filter(user -> UserUtils.toTeamId.apply(user) != null).toList()).isEmpty();
|
|
||||||
})
|
|
||||||
.verifyComplete();
|
|
||||||
|
|
||||||
Mockito.verify(teamRepository, Mockito.times(1))
|
|
||||||
.delete(teamId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldReturnErrorOnDeleteWhenNotExist() {
|
|
||||||
|
|
||||||
Mockito.when(teamRepository.findById(Mockito.anyString()))
|
|
||||||
.thenReturn(Mono.empty());
|
|
||||||
|
|
||||||
StepVerifier
|
|
||||||
.create(teamService.deleteTeam("some id"))
|
|
||||||
.expectErrorMatches(error -> error instanceof TeamServiceException && error.getMessage().equals("cannot find team to delete"))
|
|
||||||
.verify();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user