give back application layer

This commit is contained in:
Wojtek Krzywiec
2020-06-07 11:03:28 +02:00
parent d2b7d08072
commit 8a1e7ae20e
13 changed files with 186 additions and 112 deletions

View File

@@ -0,0 +1,26 @@
package io.wkrzywiec.hexagonal.library.domain;
import io.restassured.RestAssured;
import org.junit.jupiter.api.BeforeEach;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.jdbc.core.JdbcTemplate;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public abstract class BaseComponentTest {
@LocalServerPort
private int port;
protected String baseURL;
@Autowired
protected JdbcTemplate jdbcTemplate;
@BeforeEach
public void init() {
this.baseURL = "http://localhost:" + port;
RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();
}
}

View File

@@ -1,40 +1,19 @@
package io.wkrzywiec.hexagonal.library.domain.borrowing;
import io.restassured.RestAssured;
import io.wkrzywiec.hexagonal.library.BookTestData;
import io.wkrzywiec.hexagonal.library.UserTestData;
import io.wkrzywiec.hexagonal.library.domain.borrowing.core.model.BookReservationCommand;
import io.wkrzywiec.hexagonal.library.domain.BaseComponentTest;
import io.wkrzywiec.hexagonal.library.domain.borrowing.core.model.BorrowBookCommand;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.jdbc.Sql;
import static io.restassured.RestAssured.given;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.AFTER_TEST_METHOD;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class BorrowBookComponentTest {
@LocalServerPort
private int port;
private String baseURL;
@Autowired
private JdbcTemplate jdbcTemplate;
@BeforeEach
public void init() {
this.baseURL = "http://localhost:" + port;
RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();
}
public class BorrowBookComponentTest extends BaseComponentTest {
@Test
@Disabled
@@ -73,11 +52,11 @@ public class BorrowBookComponentTest {
.prettyPeek()
.then();
Long reservationId = jdbcTemplate.queryForObject(
Long borrowId = jdbcTemplate.queryForObject(
"SELECT id FROM borrowed WHERE book_id = ?",
Long.class,
homoDeusBookId);
assertTrue(reservationId > 0);
assertTrue(borrowId > 0);
}
}

View File

@@ -0,0 +1,62 @@
package io.wkrzywiec.hexagonal.library.domain.borrowing;
import io.wkrzywiec.hexagonal.library.BookTestData;
import io.wkrzywiec.hexagonal.library.UserTestData;
import io.wkrzywiec.hexagonal.library.domain.BaseComponentTest;
import io.wkrzywiec.hexagonal.library.domain.borrowing.core.model.GiveBackBookCommand;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.test.context.jdbc.Sql;
import static io.restassured.RestAssured.given;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.AFTER_TEST_METHOD;
public class GiveBackBookComponentTest extends BaseComponentTest {
@Test
@Disabled
@DisplayName("Give back borrowed book")
@Sql({"/book-and-user.sql", "/available-book.sql"})
@Sql(scripts = "/clean-database.sql", executionPhase = AFTER_TEST_METHOD)
public void givenBookIsReserved_thenBorrowIt_thenBookIsBorrowed() {
//given
Long homoDeusBookId = jdbcTemplate.queryForObject(
"SELECT id FROM book WHERE title = ?",
Long.class,
BookTestData.homoDeusBookTitle());
Long activeUserId = jdbcTemplate.queryForObject(
"SELECT id FROM user WHERE email = ?",
Long.class,
UserTestData.johnDoeEmail());
jdbcTemplate.update(
"INSERT INTO public.borrowed (book_id, user_id) VALUES (?, ?)",
homoDeusBookId,
activeUserId);
GiveBackBookCommand giveBackBookCommand =
GiveBackBookCommand.builder()
.bookId(homoDeusBookId )
.userId(activeUserId)
.build();
//when
given()
.contentType("application/json")
.body(giveBackBookCommand)
.when()
.post( baseURL + "/giveBack")
.prettyPeek()
.then();
Long bookId = jdbcTemplate.queryForObject(
"SELECT book_id FROM available WHERE book_id = ?",
Long.class,
homoDeusBookId);
assertEquals(homoDeusBookId, bookId);
}
}

View File

@@ -1,43 +1,24 @@
package io.wkrzywiec.hexagonal.library.domain.borrowing;
import io.restassured.RestAssured;
import io.wkrzywiec.hexagonal.library.BookTestData;
import io.wkrzywiec.hexagonal.library.UserTestData;
import io.wkrzywiec.hexagonal.library.domain.BaseComponentTest;
import io.wkrzywiec.hexagonal.library.domain.borrowing.core.model.BookReservationCommand;
import io.wkrzywiec.hexagonal.library.domain.inventory.infrastructure.BookRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.jdbc.Sql;
import static io.restassured.RestAssured.given;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.AFTER_TEST_METHOD;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class MakeReservationComponentTest {
@LocalServerPort
private int port;
public class MakeReservationComponentTest extends BaseComponentTest {
@Autowired
private BookRepository bookRepository;
@Autowired
private JdbcTemplate jdbcTemplate;
private String baseURL;
@BeforeEach
public void init() {
this.baseURL = "http://localhost:" + port;
RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();
}
@Test
@DisplayName("Reserve available book")
@Sql({"/book-and-user.sql", "/available-book.sql"})

View File

@@ -1,17 +1,12 @@
package io.wkrzywiec.hexagonal.library.domain.inventory;
import io.restassured.RestAssured;
import io.restassured.response.ValidatableResponse;
import io.wkrzywiec.hexagonal.library.BookTestData;
import io.wkrzywiec.hexagonal.library.domain.BaseComponentTest;
import io.wkrzywiec.hexagonal.library.domain.inventory.core.model.AddNewBookCommand;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.http.HttpStatus;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.jdbc.Sql;
import static io.restassured.RestAssured.given;
@@ -19,22 +14,7 @@ import static org.hamcrest.Matchers.greaterThan;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.AFTER_TEST_METHOD;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class AddNewBookComponentTest {
@LocalServerPort
private int port;
@Autowired
private JdbcTemplate jdbc;
private String baseURL;
@BeforeEach
public void init(){
this.baseURL = "http://localhost:" + port;
RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();
}
public class AddNewBookComponentTest extends BaseComponentTest {
@Test
@DisplayName("Search for a new book in Google Books")
@@ -73,14 +53,14 @@ public class AddNewBookComponentTest {
.then();
//then
Long savedBookId = jdbc.queryForObject(
Long savedBookId = jdbcTemplate.queryForObject(
"SELECT id FROM book WHERE book_external_id = ?",
Long.class,
BookTestData.homoDeusBookGoogleId());
assertTrue(savedBookId > 0);
Long availableBookId = jdbc.queryForObject(
Long availableBookId = jdbcTemplate.queryForObject(
"SELECT id FROM available WHERE book_id = ?",
Long.class,
savedBookId);

View File

@@ -1,36 +1,16 @@
package io.wkrzywiec.hexagonal.library.domain.user;
import io.restassured.RestAssured;
import io.wkrzywiec.hexagonal.library.domain.BaseComponentTest;
import io.wkrzywiec.hexagonal.library.domain.user.core.model.AddUserCommand;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.jdbc.Sql;
import static io.restassured.RestAssured.given;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.AFTER_TEST_METHOD;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class AddNewUserComponentTest {
@LocalServerPort
private int port;
private String baseURL;
@Autowired
private JdbcTemplate jdbcTemplate;
@BeforeEach
public void init(){
baseURL = "http://localhost:" + port;
RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();
}
public class AddNewUserComponentTest extends BaseComponentTest {
@Test
@DisplayName("Create new user")

View File

@@ -22,6 +22,6 @@ public class BorrowBookController {
@PostMapping("")
public ResponseEntity<String> borrowBook(@RequestBody BorrowBookCommand borrowBookCommand){
borrowBook.handle(borrowBookCommand);
return new ResponseEntity<>("Book with an id " + borrowBookCommand.getBookId() + " was borrowed", HttpStatus.CREATED);
return new ResponseEntity<>("Book with an id " + borrowBookCommand.getBookId() + " was borrowed", HttpStatus.OK);
}
}

View File

@@ -0,0 +1,27 @@
package io.wkrzywiec.hexagonal.library.domain.borrowing.application;
import io.wkrzywiec.hexagonal.library.domain.borrowing.core.model.GiveBackBookCommand;
import io.wkrzywiec.hexagonal.library.domain.borrowing.core.ports.incoming.GiveBackBook;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/giveBack")
@RequiredArgsConstructor
public class GiveBackController {
@Qualifier("GiveBackBook")
private final GiveBackBook giveBackBook;
@PostMapping("")
public ResponseEntity<String> giveBack(@RequestBody GiveBackBookCommand giveBackBookCommand){
giveBackBook.handle(giveBackBookCommand);
return new ResponseEntity<>("Book with an id " + giveBackBookCommand.getBookId() + " was returned", HttpStatus.OK);
}
}

View File

@@ -22,6 +22,6 @@ public class ReservationController {
@PostMapping("")
public ResponseEntity<String> makeReservation(@RequestBody BookReservationCommand reservationCommand){
Long reservationId = reserveBook.handle(reservationCommand);
return new ResponseEntity<>("Reservation has been made with an id " + reservationId, HttpStatus.CREATED);
return new ResponseEntity<>("Reservation has been made with an id " + reservationId, HttpStatus.OK);
}
}

View File

@@ -7,10 +7,10 @@ import java.time.Instant;
@EqualsAndHashCode
public class BorrowedBook implements Book {
private final Long bookId;
private final Long userId;
private Long bookId;
private Long userId;
@EqualsAndHashCode.Exclude
private final Instant borrowedDate;
private Instant borrowedDate;
public BorrowedBook(Long bookId, Long userId) {
this.bookId = bookId;

View File

@@ -133,7 +133,15 @@ public class BorrowingDatabaseAdapter implements BorrowingDatabase {
@Override
public Optional<BorrowedBook> getBorrowedBook(Long bookId) {
return Optional.empty();
try {
return Optional.ofNullable(
jdbcTemplate.queryForObject(
"SELECT book_id, user_id, borrowed_date FROM borrowed WHERE book_id = ?",
new BeanPropertyRowMapper<BorrowedBook>(BorrowedBook.class),
bookId));
} catch (DataAccessException exception) {
return Optional.empty();
}
}
private List<ReservedBook> getReservedBooksByUser(Long userId) {

View File

@@ -3,6 +3,7 @@ package io.wkrzywiec.hexagonal.library.infrastructure;
import io.wkrzywiec.hexagonal.library.domain.borrowing.core.BorrowingFacade;
import io.wkrzywiec.hexagonal.library.domain.borrowing.core.ports.incoming.BorrowBook;
import io.wkrzywiec.hexagonal.library.domain.borrowing.core.ports.incoming.CancelOverdueReservations;
import io.wkrzywiec.hexagonal.library.domain.borrowing.core.ports.incoming.GiveBackBook;
import io.wkrzywiec.hexagonal.library.domain.borrowing.core.ports.incoming.MakeBookAvailable;
import io.wkrzywiec.hexagonal.library.domain.borrowing.core.ports.incoming.ReserveBook;
import io.wkrzywiec.hexagonal.library.domain.borrowing.core.ports.outgoing.BorrowingDatabase;
@@ -12,7 +13,6 @@ import io.wkrzywiec.hexagonal.library.domain.borrowing.infrastructure.SpringBorr
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.core.JdbcTemplate;
public class BorrowingDomainConfig {
@@ -45,6 +45,12 @@ public class BorrowingDomainConfig {
return new BorrowingFacade(database, borrowingEventPublisher);
}
@Bean
@Qualifier("GiveBackBook")
public GiveBackBook giveBackBook(BorrowingDatabase database, BorrowingEventPublisher borrowingEventPublisher){
return new BorrowingFacade(database, borrowingEventPublisher);
}
@Bean
@Qualifier("CancelOverdueReservations")
public CancelOverdueReservations cancelOverdueReservations(BorrowingDatabase database, BorrowingEventPublisher borrowingEventPublisher){

View File

@@ -45,7 +45,7 @@ public class BorrowingDatabaseAdapterITCase {
@Sql(scripts = "/clean-database.sql", executionPhase = AFTER_TEST_METHOD)
public void shouldSaveAvailableBook(){
//given
Long bookId = getHomoDeusBookId();
Long bookId = getHomoDeusBookIdFromDb();
//when
database.save(new AvailableBook(bookId));
@@ -64,7 +64,7 @@ public class BorrowingDatabaseAdapterITCase {
@Sql(scripts = "/clean-database.sql", executionPhase = AFTER_TEST_METHOD)
public void shouldGetAvailableBook(){
//given
Long bookId = getHomoDeusBookId();
Long bookId = getHomoDeusBookIdFromDb();
//when
Optional<AvailableBook> availableBookOptional = database.getAvailableBook(bookId);
@@ -80,7 +80,7 @@ public class BorrowingDatabaseAdapterITCase {
@Sql(scripts = "/clean-database.sql", executionPhase = AFTER_TEST_METHOD)
public void shouldGetActiveUser() {
//given
Long activeUserId = getJohnDoeUserId();
Long activeUserId = getJohnDoeUserIdFromDb();
//when
Optional<ActiveUser> activeUserOptional = database.getActiveUser(activeUserId);
@@ -96,9 +96,9 @@ public class BorrowingDatabaseAdapterITCase {
@Sql(scripts = "/clean-database.sql", executionPhase = AFTER_TEST_METHOD)
public void shouldSaveReservedBook(){
//given
Long bookId = getHomoDeusBookId();
Long bookId = getHomoDeusBookIdFromDb();
Long activeUserId = getJohnDoeUserId();
Long activeUserId = getJohnDoeUserIdFromDb();
ReservedBook reservedBook = new ReservedBook(bookId, activeUserId);
@@ -118,8 +118,8 @@ public class BorrowingDatabaseAdapterITCase {
@Sql(scripts = "/clean-database.sql", executionPhase = AFTER_TEST_METHOD)
public void shouldFindReservedBook(){
//given
Long bookId = getHomoDeusBookId();
Long johnDoeUserId = getJohnDoeUserId();
Long bookId = getHomoDeusBookIdFromDb();
Long johnDoeUserId = getJohnDoeUserIdFromDb();
jdbcTemplate.update(
"INSERT INTO public.reserved (book_id, user_id) VALUES (?, ?)",
bookId,
@@ -139,8 +139,8 @@ public class BorrowingDatabaseAdapterITCase {
@Sql(scripts = "/clean-database.sql", executionPhase = AFTER_TEST_METHOD)
public void shouldSaveBorrowedBook(){
//given
Long bookId = getHomoDeusBookId();
Long activeUserId = getJohnDoeUserId();
Long bookId = getHomoDeusBookIdFromDb();
Long activeUserId = getJohnDoeUserIdFromDb();
BorrowedBook borrowedBook = new BorrowedBook(bookId, activeUserId);
@@ -162,8 +162,8 @@ public class BorrowingDatabaseAdapterITCase {
public void shouldFindOverdueReservations(){
//given
DueDate thirdDayAfterReservation = new DueDate(Instant.now().plus(3, ChronoUnit.DAYS));
Long overdueBookId = getHomoDeusBookId();
Long johnDoeUserId = getJohnDoeUserId();
Long overdueBookId = getHomoDeusBookIdFromDb();
Long johnDoeUserId = getJohnDoeUserIdFromDb();
jdbcTemplate.update(
"INSERT INTO public.reserved (book_id, user_id, reserved_date) VALUES (?, ?, ?)",
overdueBookId,
@@ -177,14 +177,39 @@ public class BorrowingDatabaseAdapterITCase {
assertEquals(overdueBookId, overdueReservation.getBookIdentificationAsLong());
}
private Long getHomoDeusBookId(){
@Test
@Disabled
@DisplayName("Find borrowed book by id")
@Sql({"/book-and-user.sql"})
@Sql(scripts = "/clean-database.sql", executionPhase = AFTER_TEST_METHOD)
public void shouldFindBorrowedBook(){
//given
Long bookId = getHomoDeusBookIdFromDb();
Long johnDoeUserId = getJohnDoeUserIdFromDb();
jdbcTemplate.update(
"INSERT INTO public.borrowed (book_id, user_id, borrowed_date) VALUES (?, ?, ?)",
bookId,
johnDoeUserId,
Instant.now());
Long id = jdbcTemplate.queryForObject("SELECT book_id FROM borrowed WHERE book_id = ?", Long.class, bookId);
//when
Optional<BorrowedBook> borrowedBook = database.getBorrowedBook(bookId);
//then
assertTrue(borrowedBook.isPresent());
assertEquals(bookId, borrowedBook.get().getIdAsLong());
}
private Long getHomoDeusBookIdFromDb(){
return jdbcTemplate.queryForObject(
"SELECT id FROM book WHERE title = ?",
Long.class,
BookTestData.homoDeusBookTitle());
}
private Long getJohnDoeUserId(){
private Long getJohnDoeUserIdFromDb(){
return jdbcTemplate.queryForObject(
"SELECT id FROM user WHERE email = ?",
Long.class,