diff --git a/src/main/java/net/szymonsawicki/reactivetimesheetapp/application/service/TeamService.java b/src/main/java/net/szymonsawicki/reactivetimesheetapp/application/service/TeamService.java index 1ac4e69..0f7e40c 100644 --- a/src/main/java/net/szymonsawicki/reactivetimesheetapp/application/service/TeamService.java +++ b/src/main/java/net/szymonsawicki/reactivetimesheetapp/application/service/TeamService.java @@ -44,7 +44,7 @@ public class TeamService { .flatMap(createTeamDto -> teamRepository.findByName(createTeamDto.name()) .doOnEach(team -> log.error("Team with name " + createTeamDto.name() + " already exists")) .map(Team::toGetTeamDto) - .switchIfEmpty(Mono.defer(() -> createTeamWithMembers(createTeamDto)))); + .switchIfEmpty(Mono.defer(() -> createTeamWithMembers(createTeamDto)))); } private Mono createTeamWithMembers(CreateTeamDto createTeamDto) { diff --git a/src/main/java/net/szymonsawicki/reactivetimesheetapp/domain/configs/CrudRepository.java b/src/main/java/net/szymonsawicki/reactivetimesheetapp/domain/configs/CrudRepository.java index bc57ff7..cc143ca 100644 --- a/src/main/java/net/szymonsawicki/reactivetimesheetapp/domain/configs/CrudRepository.java +++ b/src/main/java/net/szymonsawicki/reactivetimesheetapp/domain/configs/CrudRepository.java @@ -13,5 +13,7 @@ public interface CrudRepository { Mono save(T t); Mono delete(ID id); + Mono deleteAll(); + } diff --git a/src/main/java/net/szymonsawicki/reactivetimesheetapp/domain/team/Team.java b/src/main/java/net/szymonsawicki/reactivetimesheetapp/domain/team/Team.java index f0353fe..d141f38 100644 --- a/src/main/java/net/szymonsawicki/reactivetimesheetapp/domain/team/Team.java +++ b/src/main/java/net/szymonsawicki/reactivetimesheetapp/domain/team/Team.java @@ -32,7 +32,7 @@ public class Team { return TeamEntity.builder() .id(id) .name(name) - .members(members.stream().map(User::toEntity).toList()) + .members(members == null ? null : members.stream().map(User::toEntity).toList()) .build(); } diff --git a/src/main/java/net/szymonsawicki/reactivetimesheetapp/infrastructure/persistence/repository/TeamsRepositoryImpl.java b/src/main/java/net/szymonsawicki/reactivetimesheetapp/infrastructure/persistence/repository/TeamsRepositoryImpl.java index 2920e4c..c41fe26 100644 --- a/src/main/java/net/szymonsawicki/reactivetimesheetapp/infrastructure/persistence/repository/TeamsRepositoryImpl.java +++ b/src/main/java/net/szymonsawicki/reactivetimesheetapp/infrastructure/persistence/repository/TeamsRepositoryImpl.java @@ -3,7 +3,6 @@ package net.szymonsawicki.reactivetimesheetapp.infrastructure.persistence.reposi import lombok.RequiredArgsConstructor; import net.szymonsawicki.reactivetimesheetapp.domain.team.Team; 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.exception.PersistenceException; import org.springframework.stereotype.Repository; @@ -51,6 +50,11 @@ public class TeamsRepositoryImpl implements TeamRepository { .switchIfEmpty(Mono.error(new PersistenceException("cannot find team to delete"))); } + @Override + public Mono deleteAll() { + return teamDao.deleteAll(); + } + public Mono findByName(String name) { return teamDao.findByName(name) .flatMap(teamEntity -> Mono.just(teamEntity.toTeam())); diff --git a/src/main/java/net/szymonsawicki/reactivetimesheetapp/infrastructure/persistence/repository/TimeEntryRepositoryImpl.java b/src/main/java/net/szymonsawicki/reactivetimesheetapp/infrastructure/persistence/repository/TimeEntryRepositoryImpl.java index 1458e5e..fd9d087 100644 --- a/src/main/java/net/szymonsawicki/reactivetimesheetapp/infrastructure/persistence/repository/TimeEntryRepositoryImpl.java +++ b/src/main/java/net/szymonsawicki/reactivetimesheetapp/infrastructure/persistence/repository/TimeEntryRepositoryImpl.java @@ -52,6 +52,11 @@ public class TimeEntryRepositoryImpl implements TimeEntryRepository { .switchIfEmpty(Mono.error(new PersistenceException("cannot find team to delete"))); } + @Override + public Mono deleteAll() { + return timeEntryDao.deleteAll(); + } + @Override public Flux findAllByUser(User user) { return timeEntryDao.findAllByUser(user.toEntity()) diff --git a/src/main/java/net/szymonsawicki/reactivetimesheetapp/infrastructure/persistence/repository/UserRepositoryImpl.java b/src/main/java/net/szymonsawicki/reactivetimesheetapp/infrastructure/persistence/repository/UserRepositoryImpl.java index 02c053e..b0ffa10 100644 --- a/src/main/java/net/szymonsawicki/reactivetimesheetapp/infrastructure/persistence/repository/UserRepositoryImpl.java +++ b/src/main/java/net/szymonsawicki/reactivetimesheetapp/infrastructure/persistence/repository/UserRepositoryImpl.java @@ -74,4 +74,9 @@ public class UserRepositoryImpl implements UserRepository { return userDao .deleteAll(users.stream().map(User::toEntity).toList()); } + + @Override + public Mono deleteAll() { + return userDao.deleteAll(); + } } diff --git a/src/main/java/net/szymonsawicki/reactivetimesheetapp/web/Routing.java b/src/main/java/net/szymonsawicki/reactivetimesheetapp/web/Routing.java index 59a087e..116b5da 100644 --- a/src/main/java/net/szymonsawicki/reactivetimesheetapp/web/Routing.java +++ b/src/main/java/net/szymonsawicki/reactivetimesheetapp/web/Routing.java @@ -28,13 +28,14 @@ public class Routing { RouterFunctions.route(GET("/{name}").and(accept(MediaType.APPLICATION_JSON)), teamHandlers::findByName) .andRoute(GET("/id/{id}").and(accept(MediaType.APPLICATION_JSON)), teamHandlers::findById) .andRoute(POST("/").and(accept(MediaType.APPLICATION_JSON)), teamHandlers::addTeam) - .andRoute(DELETE("/{id}").and(accept(MediaType.APPLICATION_JSON)), teamHandlers::deleteTeam)) - .andNest(path("/users"), - RouterFunctions.route(GET("/id/{id}").and(accept(MediaType.APPLICATION_JSON)), userHandlers::findById) - .andRoute(GET("/{username}").and(accept(MediaType.APPLICATION_JSON)), userHandlers::findByUsername) - .andRoute(POST("/").and(accept(MediaType.APPLICATION_JSON)), userHandlers::createUser) - .andRoute(DELETE("/{id}").and(accept(MediaType.APPLICATION_JSON)), userHandlers::deleteUser)) - .andNest(path("/time-entries"), - RouterFunctions.route(POST("/").and(accept(MediaType.APPLICATION_JSON)), timeEntryHandlers::addTimeEntry)); + .andRoute(DELETE("/{id}").and(accept(MediaType.APPLICATION_JSON)), teamHandlers::deleteTeam) + .andNest(path("/reset"), RouterFunctions.route(GET("/reset").and(accept(MediaType.APPLICATION_JSON)), teamHandlers::findByName)) + .andNest(path("/users"), + RouterFunctions.route(GET("/id/{id}").and(accept(MediaType.APPLICATION_JSON)), userHandlers::findById) + .andRoute(GET("/{username}").and(accept(MediaType.APPLICATION_JSON)), userHandlers::findByUsername) + .andRoute(POST("/").and(accept(MediaType.APPLICATION_JSON)), userHandlers::createUser) + .andRoute(DELETE("/{id}").and(accept(MediaType.APPLICATION_JSON)), userHandlers::deleteUser)) + .andNest(path("/time-entries"), + RouterFunctions.route(POST("/").and(accept(MediaType.APPLICATION_JSON)), timeEntryHandlers::addTimeEntry))); } } diff --git a/src/test/java/net/szymonsawicki/reactivetimesheetapp/application/service/TeamServiceIT.java b/src/test/java/net/szymonsawicki/reactivetimesheetapp/application/service/TeamServiceIT.java index d6d195b..6abb0ef 100644 --- a/src/test/java/net/szymonsawicki/reactivetimesheetapp/application/service/TeamServiceIT.java +++ b/src/test/java/net/szymonsawicki/reactivetimesheetapp/application/service/TeamServiceIT.java @@ -1,7 +1,6 @@ package net.szymonsawicki.reactivetimesheetapp.application.service; import net.szymonsawicki.reactivetimesheetapp.application.service.exception.TeamServiceException; -import net.szymonsawicki.reactivetimesheetapp.application.service.utils.TimesheetAppMongoDbContainer; import net.szymonsawicki.reactivetimesheetapp.domain.team.Team; import net.szymonsawicki.reactivetimesheetapp.domain.team.TeamUtils; import net.szymonsawicki.reactivetimesheetapp.domain.team.dto.CreateTeamDto; @@ -13,16 +12,19 @@ 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.Container; import org.testcontainers.junit.jupiter.Testcontainers; import reactor.test.StepVerifier; @@ -34,8 +36,13 @@ import java.util.List; @AutoConfigureWebTestClient @ActiveProfiles("test") public class TeamServiceIT { - @Container + + /* @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; @@ -44,7 +51,23 @@ public class TeamServiceIT { @Autowired private WebTestClient webClient; - // TODO clear db after each method (deleteAll method must be implemented + @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() { @@ -90,21 +113,21 @@ public class TeamServiceIT { .expectBodyList(TeamServiceException.class); } - @Test + @DirtiesContext void shouldCreateTeamWithTwoMembersOnCreate() { - String teamName = "Some test team"; + String teamName = "Some test team2"; String username1 = "testsusrname1"; String username2 = "testsusrname2"; - String password1 = "sdcvdfvbgdf"; - String password2 = "xlöifxdl."; + String password1 = "kongamafonga"; + String password2 = "kupaladupa."; Role role = Role.DEVELOPER; - var member1 = new GetUserDto(username1, password1, password1, role, teamName); - var member2 = new GetUserDto(username2, password2, password2, role, teamName); + 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, member2)); + var createTeamDto = new CreateTeamDto(teamName, List.of(member1)); webClient.post().uri("/teams/") .header(HttpHeaders.ACCEPT, "application/json") @@ -121,5 +144,49 @@ public class TeamServiceIT { .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(); } }