diff --git a/README.md b/README.md index e2cfdc7..af503c6 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,7 @@ # OtusSpringHW-Library -Домашние задания по Spring для Otus с базами данных. + +Домашнее задание #9: +- CRUD приложение с Web UI и хранением данных в БД. +- Создайте приложение с хранением сущностей в БД (можно взять DAOs из прошлых занятий). +- Использовать классический View, предусмотреть страницу отображения всех сущностей и создания/редактирования. +- View на Thymeleaf, classic Controllers. \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..a884528 --- /dev/null +++ b/pom.xml @@ -0,0 +1,229 @@ + + + 4.0.0 + + home-work + + ru.otus.mkulikov + home-work + 1.0-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-parent + 2.1.3.RELEASE + + + + + UTF-8 + + + + + net.sf.opencsv + opencsv + 2.3 + + + + javax.annotation + javax.annotation-api + 1.3.2 + + + + org.projectlombok + lombok + 1.18.4 + provided + + + + + junit + junit + 4.12 + test + + + + org.assertj + assertj-core + 3.12.2 + test + + + + org.junit.jupiter + junit-jupiter-api + 5.3.2 + test + + + + org.junit.jupiter + junit-jupiter-engine + 5.3.2 + test + + + + org.junit.platform + junit-platform-launcher + 1.4.1 + test + + + + + org.mockito + mockito-core + 2.21.0 + test + + + + org.mockito + mockito-junit-jupiter + 2.23.0 + test + + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + org.springframework.shell + spring-shell-starter + 2.0.0.RELEASE + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + + + org.springframework.boot + spring-boot-starter-data-mongodb + + + + de.flapdoodle.embed + de.flapdoodle.embed.mongo + + + + org.springframework.data + spring-data-keyvalue + + + + com.github.cloudyrock.mongock + mongock-spring + 2.0.0 + + + + + org.springframework.data + spring-data-jpa + 2.0.8.RELEASE + + + + + + org.webjars + jquery + 3.4.1 + + + + + org.webjars + popper.js + 1.15.0 + + + + org.webjars + bootstrap + 4.3.1 + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 11 + 11 + + + + + org.apache.maven.plugins + maven-resources-plugin + + ${encoding} + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.0 + + + false + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + src/main/resources + + **/*.yml + **/*.txt + **/*.yaml + **/*.html + **/*.css + + false + + + + \ No newline at end of file diff --git a/src/main/java/ru/otus/mkulikov/Application.java b/src/main/java/ru/otus/mkulikov/Application.java new file mode 100644 index 0000000..005151d --- /dev/null +++ b/src/main/java/ru/otus/mkulikov/Application.java @@ -0,0 +1,22 @@ +package ru.otus.mkulikov; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.EnableConfigurationProperties; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 2019-03-14 + * Time: 15:27 + */ + +@SpringBootApplication +@EnableConfigurationProperties +public class Application { + + public static void main(String[] args) throws Exception { + SpringApplication.run(Application.class); + //Console.main(args); + } +} diff --git a/src/main/java/ru/otus/mkulikov/app/dao/AuthorDao.java b/src/main/java/ru/otus/mkulikov/app/dao/AuthorDao.java new file mode 100644 index 0000000..ee744cc --- /dev/null +++ b/src/main/java/ru/otus/mkulikov/app/dao/AuthorDao.java @@ -0,0 +1,15 @@ +package ru.otus.mkulikov.app.dao; + +import org.springframework.data.mongodb.repository.MongoRepository; +import ru.otus.mkulikov.app.model.Author; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 23.05.2019 + * Time: 17:06 + */ + +public interface AuthorDao extends MongoRepository { + +} diff --git a/src/main/java/ru/otus/mkulikov/app/dao/BookDao.java b/src/main/java/ru/otus/mkulikov/app/dao/BookDao.java new file mode 100644 index 0000000..c44a9bf --- /dev/null +++ b/src/main/java/ru/otus/mkulikov/app/dao/BookDao.java @@ -0,0 +1,20 @@ +package ru.otus.mkulikov.app.dao; + +import org.springframework.data.mongodb.repository.MongoRepository; +import ru.otus.mkulikov.app.model.Book; + +import java.util.List; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 23.05.2019 + * Time: 13:28 + */ + +public interface BookDao extends MongoRepository { + + List findByAuthor_Id(String id); + + List findByGenre_Id(String id); +} diff --git a/src/main/java/ru/otus/mkulikov/app/dao/CommentDao.java b/src/main/java/ru/otus/mkulikov/app/dao/CommentDao.java new file mode 100644 index 0000000..aeb0f7d --- /dev/null +++ b/src/main/java/ru/otus/mkulikov/app/dao/CommentDao.java @@ -0,0 +1,19 @@ +package ru.otus.mkulikov.app.dao; + +import org.springframework.data.mongodb.repository.MongoRepository; +import ru.otus.mkulikov.app.model.Book; +import ru.otus.mkulikov.app.model.Comment; + +import java.util.List; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 20.06.2019 + * Time: 23:48 + */ + +public interface CommentDao extends MongoRepository { + + List findByBook(Book book); +} diff --git a/src/main/java/ru/otus/mkulikov/app/dao/GenreDao.java b/src/main/java/ru/otus/mkulikov/app/dao/GenreDao.java new file mode 100644 index 0000000..5c40169 --- /dev/null +++ b/src/main/java/ru/otus/mkulikov/app/dao/GenreDao.java @@ -0,0 +1,15 @@ +package ru.otus.mkulikov.app.dao; + +import org.springframework.data.mongodb.repository.MongoRepository; +import ru.otus.mkulikov.app.model.Genre; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 23.05.2019 + * Time: 17:07 + */ + +public interface GenreDao extends MongoRepository { + +} diff --git a/src/main/java/ru/otus/mkulikov/app/exception/ObjectNotFound.java b/src/main/java/ru/otus/mkulikov/app/exception/ObjectNotFound.java new file mode 100644 index 0000000..43f598d --- /dev/null +++ b/src/main/java/ru/otus/mkulikov/app/exception/ObjectNotFound.java @@ -0,0 +1,15 @@ +package ru.otus.mkulikov.app.exception; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 03.09.2019 + * Time: 1:58 + */ + +public class ObjectNotFound extends RuntimeException { + + public ObjectNotFound(String obj, String id) { + super("Not found object - " + obj + ", id - " + id); + } +} diff --git a/src/main/java/ru/otus/mkulikov/app/model/Author.java b/src/main/java/ru/otus/mkulikov/app/model/Author.java new file mode 100644 index 0000000..5866262 --- /dev/null +++ b/src/main/java/ru/otus/mkulikov/app/model/Author.java @@ -0,0 +1,53 @@ +package ru.otus.mkulikov.app.model; + +import lombok.Data; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.Field; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 23.05.2019 + * Time: 17:02 + */ + +@Data +@Document +public class Author { + + @Id + private String id; + @Field(value = "surname") + private String surname; + @Field(value = "firstName") + private String firstName; + @Field(value = "secondName") + private String secondName; + + public Author() { + } + + public Author(String id, String surname, String firstName, String secondName) { + this.id = id; + this.surname = surname; + this.firstName = firstName; + this.secondName = secondName; + } + + public Author(String surname, String firstName, String secondName) { + this.surname = surname; + this.firstName = firstName; + this.secondName = secondName; + } + + @Override + public String toString() { + return "Author{" + + "id=" + id + + ", surname='" + surname + '\'' + + ", firstName='" + firstName + '\'' + + ", secondName='" + secondName + '\'' + + "}\n"; + } +} diff --git a/src/main/java/ru/otus/mkulikov/app/model/Book.java b/src/main/java/ru/otus/mkulikov/app/model/Book.java new file mode 100644 index 0000000..86ae6e3 --- /dev/null +++ b/src/main/java/ru/otus/mkulikov/app/model/Book.java @@ -0,0 +1,67 @@ +package ru.otus.mkulikov.app.model; + +import lombok.Data; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.DBRef; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.Field; + +import java.util.Date; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 23.05.2019 + * Time: 13:28 + */ + +@Data +@Document +public class Book { + + @Id + private String id; + @Field(value = "addRecordDate") + private Date addRecordDate; + @Field(value = "caption") + private String caption; + @Field(value = "description") + private String description; + + @DBRef + private Author author; + @DBRef + private Genre genre; + + public Book() { + } + + public Book(String id, Date addRecordDate, String caption, Author author, Genre genre, String description) { + this.id = id; + this.addRecordDate = addRecordDate; + this.author = author; + this.genre = genre; + this.caption = caption; + this.description = description; + } + + public Book(Date addRecordDate, String caption, Author author, Genre genre, String description) { + this.addRecordDate = addRecordDate; + this.caption = caption; + this.author = author; + this.genre = genre; + this.description = description; + } + + @Override + public String toString() { + return "Book{" + + "id=" + id + + ", addRecordDate=" + addRecordDate + + ", caption='" + caption + '\'' + + ", description=" + description + + ", author=" + author + + ", genre=" + genre + + "}\n"; + } +} diff --git a/src/main/java/ru/otus/mkulikov/app/model/Comment.java b/src/main/java/ru/otus/mkulikov/app/model/Comment.java new file mode 100644 index 0000000..6cfeaaf --- /dev/null +++ b/src/main/java/ru/otus/mkulikov/app/model/Comment.java @@ -0,0 +1,62 @@ +package ru.otus.mkulikov.app.model; + +import lombok.Data; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.DBRef; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.Field; + +import java.util.Date; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 20.06.2019 + * Time: 23:38 + */ + +@Data +@Document +public class Comment { + + @Id + private String id; + @Field(value = "addRecordDate") + private Date addRecordDate; + @Field(value = "userName") + private String userName; + @Field(value = "text") + private String text; + + @DBRef + private Book book; + + public Comment() { + } + + public Comment(String id, Book book, Date addRecordDate, String userName, String text) { + this.id = id; + this.book = book; + this.addRecordDate = addRecordDate; + this.userName = userName; + this.text = text; + } + + public Comment(Book book, Date addRecordDate, String userName, String text) { + this.book = book; + this.addRecordDate = addRecordDate; + this.userName = userName; + this.text = text; + } + + @Override + public String toString() { + return "Comment{" + + "id=" + id + + ", addRecordDate=" + addRecordDate + + ", userName=" + userName + + ", text='" + text + '\'' + + ", book='" + book + '\'' + + "}\n"; + } +} diff --git a/src/main/java/ru/otus/mkulikov/app/model/Genre.java b/src/main/java/ru/otus/mkulikov/app/model/Genre.java new file mode 100644 index 0000000..14ca394 --- /dev/null +++ b/src/main/java/ru/otus/mkulikov/app/model/Genre.java @@ -0,0 +1,43 @@ +package ru.otus.mkulikov.app.model; + +import lombok.Data; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.Field; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 23.05.2019 + * Time: 17:04 + */ + +@Data +@Document +public class Genre { + + @Id + private String id; + @Field(value = "name") + private String name; + + public Genre() { + } + + public Genre(String id, String name) { + this.id = id; + this.name = name; + } + + public Genre(String name) { + this.name = name; + } + + @Override + public String toString() { + return "Genre{" + + "id=" + id + + ", name='" + name + '\'' + + "}\n"; + } +} \ No newline at end of file diff --git a/src/main/java/ru/otus/mkulikov/app/service/AuthorManageService.java b/src/main/java/ru/otus/mkulikov/app/service/AuthorManageService.java new file mode 100644 index 0000000..84dd68f --- /dev/null +++ b/src/main/java/ru/otus/mkulikov/app/service/AuthorManageService.java @@ -0,0 +1,27 @@ +package ru.otus.mkulikov.app.service; + +import ru.otus.mkulikov.app.model.Author; + +import java.util.List; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 30.05.2019 + * Time: 14:59 + */ + +public interface AuthorManageService { + + T getAuthorById(String id); + + List getAuthors(); + + T addAuthor(String surname, String firstName, String secondName); + + T updateAuthor(String id, String surname, String firstName, String secondName); + + T updateAuthor(T t); + + int deleteAuthor(String id); +} diff --git a/src/main/java/ru/otus/mkulikov/app/service/AuthorManageServiceImpl.java b/src/main/java/ru/otus/mkulikov/app/service/AuthorManageServiceImpl.java new file mode 100644 index 0000000..bca5644 --- /dev/null +++ b/src/main/java/ru/otus/mkulikov/app/service/AuthorManageServiceImpl.java @@ -0,0 +1,64 @@ +package ru.otus.mkulikov.app.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import ru.otus.mkulikov.app.dao.AuthorDao; +import ru.otus.mkulikov.app.exception.ObjectNotFound; +import ru.otus.mkulikov.app.model.Author; + +import java.util.List; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 30.05.2019 + * Time: 15:53 + */ + +@Service +@RequiredArgsConstructor +public class AuthorManageServiceImpl implements AuthorManageService { + + private final AuthorDao authorDao; + + @Override + public Author getAuthorById(String id) { + return authorDao.findById(id).orElseThrow(() -> new ObjectNotFound("Author", id)); + } + + @Override + public List getAuthors() { + return authorDao.findAll(); + } + + @Override + public Author addAuthor(String surname, String firstName, String secondName) { + return authorDao.save(new Author(surname, firstName, secondName)); + } + + @Override + public Author updateAuthor(String id, String surname, String firstName, String secondName) { + Author author = authorDao.findById(id).orElseThrow(() -> new ObjectNotFound("Author", id)); + author.setSurname(surname); + author.setFirstName(firstName); + author.setSecondName(secondName); + + return authorDao.save(author); + } + + @Override + public Author updateAuthor(Author author) { + Author orig = authorDao.findById(author.getId()).orElseThrow(() -> new ObjectNotFound("Author", author.getId())); + orig.setSurname(author.getSurname()); + orig.setFirstName(author.getFirstName()); + orig.setSecondName(author.getSecondName()); + + return authorDao.save(orig); + } + + @Override + public int deleteAuthor(String id) { + authorDao.deleteById(id); + return 1; + } +} diff --git a/src/main/java/ru/otus/mkulikov/app/service/BookManageService.java b/src/main/java/ru/otus/mkulikov/app/service/BookManageService.java new file mode 100644 index 0000000..48991bd --- /dev/null +++ b/src/main/java/ru/otus/mkulikov/app/service/BookManageService.java @@ -0,0 +1,31 @@ +package ru.otus.mkulikov.app.service; + +import ru.otus.mkulikov.app.model.Book; + +import java.util.List; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 27.05.2019 + * Time: 13:42 + */ + +public interface BookManageService { + + T getBookById(String id); + + List getBookByAuthorId(String id); + + List getBookByGenreId(String id); + + List getBooks(); + + T addBook(String caption, String authorId, String genreId, String description); + + T updateBook(String id, String caption, String authorId, String genreId, String description); + + T updateBook(T t); + + int deleteBook(String id); +} diff --git a/src/main/java/ru/otus/mkulikov/app/service/BookManageServiceImpl.java b/src/main/java/ru/otus/mkulikov/app/service/BookManageServiceImpl.java new file mode 100644 index 0000000..87e1e97 --- /dev/null +++ b/src/main/java/ru/otus/mkulikov/app/service/BookManageServiceImpl.java @@ -0,0 +1,84 @@ +package ru.otus.mkulikov.app.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import ru.otus.mkulikov.app.dao.AuthorDao; +import ru.otus.mkulikov.app.dao.BookDao; +import ru.otus.mkulikov.app.dao.GenreDao; +import ru.otus.mkulikov.app.exception.ObjectNotFound; +import ru.otus.mkulikov.app.model.Author; +import ru.otus.mkulikov.app.model.Book; +import ru.otus.mkulikov.app.model.Genre; + +import java.util.Date; +import java.util.List; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 27.05.2019 + * Time: 13:42 + */ + +@Service +@RequiredArgsConstructor +public class BookManageServiceImpl implements BookManageService { + + private final BookDao bookDao; + private final AuthorDao authorDao; + private final GenreDao genreDao; + + @Override + public Book getBookById(String id) { + return bookDao.findById(id).orElseThrow(() -> new ObjectNotFound("Book", id)); + } + + @Override + public List getBookByAuthorId(String id) { + return bookDao.findByAuthor_Id(id); + } + + @Override + public List getBookByGenreId(String id) { + return bookDao.findByGenre_Id(id); + } + + @Override + public List getBooks() { + return bookDao.findAll(); + } + + @Override + public Book addBook(String caption, String authorId, String genreId, String description) { + Author author = authorDao.findById(authorId).orElseThrow(() -> new ObjectNotFound("Author", authorId)); + Genre genre = genreDao.findById(genreId).orElseThrow(() -> new ObjectNotFound("Genre", genreId)); + + return bookDao.save(new Book(new Date(), caption, author, genre, description)); + } + + @Override + public Book updateBook(String id, String caption, String authorId, String genreId, String description) { + Author author = authorDao.findById(authorId).orElseThrow(() -> new ObjectNotFound("Author", authorId)); + Genre genre = genreDao.findById(genreId).orElseThrow(() -> new ObjectNotFound("Genre", genreId)); + + Book book = bookDao.findById(id).orElseThrow(() -> new ObjectNotFound("Book", id)); + book.setCaption(caption); + book.setAuthor(author); + book.setGenre(genre); + book.setDescription(description); + + return bookDao.save(book); + } + + @Override + public Book updateBook(Book book) { + book.setAddRecordDate(new Date()); + return bookDao.save(book); + } + + @Override + public int deleteBook(String id) { + bookDao.deleteById(id); + return 1; + } +} diff --git a/src/main/java/ru/otus/mkulikov/app/service/CommentManageService.java b/src/main/java/ru/otus/mkulikov/app/service/CommentManageService.java new file mode 100644 index 0000000..1618f08 --- /dev/null +++ b/src/main/java/ru/otus/mkulikov/app/service/CommentManageService.java @@ -0,0 +1,30 @@ +package ru.otus.mkulikov.app.service; + +import ru.otus.mkulikov.app.model.Comment; + +import java.util.List; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 30.05.2019 + * Time: 15:50 + */ +public interface CommentManageService { + + T getCommentById(String id); + + List getComments(); + + List getCommentsByBookId(String bookId); + + T addComment(String bookId, String userName, String text); + + T updateComment(String id, String userName, String text); + + T updateComment(T t); + + int deleteComment(String id); + + int deleteComments(List list); +} diff --git a/src/main/java/ru/otus/mkulikov/app/service/CommentManageServiceImpl.java b/src/main/java/ru/otus/mkulikov/app/service/CommentManageServiceImpl.java new file mode 100644 index 0000000..ee0ffce --- /dev/null +++ b/src/main/java/ru/otus/mkulikov/app/service/CommentManageServiceImpl.java @@ -0,0 +1,77 @@ +package ru.otus.mkulikov.app.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import ru.otus.mkulikov.app.dao.BookDao; +import ru.otus.mkulikov.app.dao.CommentDao; +import ru.otus.mkulikov.app.exception.ObjectNotFound; +import ru.otus.mkulikov.app.model.Book; +import ru.otus.mkulikov.app.model.Comment; + +import java.util.Date; +import java.util.List; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 30.05.2019 + * Time: 15:52 + */ + +@Service +@RequiredArgsConstructor +public class CommentManageServiceImpl implements CommentManageService { + + private final CommentDao commentDao; + private final BookDao bookDao; + + @Override + public Comment getCommentById(String id) { + return commentDao.findById(id).orElseThrow(() -> new ObjectNotFound("Comment", id)); + } + + @Override + public List getComments() { + return commentDao.findAll(); + } + + @Override + public List getCommentsByBookId(String bookId) { + Book book = bookDao.findById(bookId).orElseThrow(() -> new ObjectNotFound("Book", bookId)); + return commentDao.findByBook(book); + } + + @Override + public Comment addComment(String bookId, String userName, String text) { + Book book = bookDao.findById(bookId).orElseThrow(() -> new ObjectNotFound("Book", bookId)); + return commentDao.save(new Comment(book, new Date(), userName, text)); + } + + @Override + public Comment updateComment(String id, String userName, String text) { + Comment comment = commentDao.findById(id).orElseThrow(() -> new ObjectNotFound("Comment", id)); + comment.setAddRecordDate(new Date()); + comment.setUserName(userName); + comment.setText(text); + + return commentDao.save(comment); + } + + @Override + public Comment updateComment(Comment comment) { + comment.setAddRecordDate(new Date()); + return commentDao.save(comment); + } + + @Override + public int deleteComment(String id) { + commentDao.deleteById(id); + return 1; + } + + @Override + public int deleteComments(List list) { + commentDao.deleteAll(list); + return 1; + } +} diff --git a/src/main/java/ru/otus/mkulikov/app/service/GenreManageService.java b/src/main/java/ru/otus/mkulikov/app/service/GenreManageService.java new file mode 100644 index 0000000..d6bfbce --- /dev/null +++ b/src/main/java/ru/otus/mkulikov/app/service/GenreManageService.java @@ -0,0 +1,26 @@ +package ru.otus.mkulikov.app.service; + +import ru.otus.mkulikov.app.model.Genre; + +import java.util.List; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 30.05.2019 + * Time: 15:50 + */ +public interface GenreManageService { + + T getGenreById(String id); + + List getGenres(); + + T addGenre(String name); + + T updateGenre(String id, String name); + + T updateGenre(T t); + + int deleteGenre(String id); +} diff --git a/src/main/java/ru/otus/mkulikov/app/service/GenreManageServiceImpl.java b/src/main/java/ru/otus/mkulikov/app/service/GenreManageServiceImpl.java new file mode 100644 index 0000000..53bb46b --- /dev/null +++ b/src/main/java/ru/otus/mkulikov/app/service/GenreManageServiceImpl.java @@ -0,0 +1,57 @@ +package ru.otus.mkulikov.app.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import ru.otus.mkulikov.app.dao.GenreDao; +import ru.otus.mkulikov.app.exception.ObjectNotFound; +import ru.otus.mkulikov.app.model.Genre; + +import java.util.List; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 30.05.2019 + * Time: 15:52 + */ + +@Service +@RequiredArgsConstructor +public class GenreManageServiceImpl implements GenreManageService { + + private final GenreDao genreDao; + + @Override + public Genre getGenreById(String id) { + return genreDao.findById(id).orElseThrow(() -> new ObjectNotFound("Genre", id)); + } + + @Override + public List getGenres() { + return genreDao.findAll(); + } + + @Override + public Genre addGenre(String name) { + return genreDao.save(new Genre(name)); + } + + @Override + public Genre updateGenre(String id, String name) { + Genre genre = genreDao.findById(id).orElseThrow(() -> new ObjectNotFound("Genre", id)); + genre.setName(name); + + return genreDao.save(genre); + } + + @Override + public Genre updateGenre(Genre genre) { + return genreDao.save(genre); + } + + @Override + public int deleteGenre(String id) { + genreDao.deleteById(id); + return 1; + } +} diff --git a/src/main/java/ru/otus/mkulikov/app/utils/DateUtil.java b/src/main/java/ru/otus/mkulikov/app/utils/DateUtil.java new file mode 100644 index 0000000..2401e4f --- /dev/null +++ b/src/main/java/ru/otus/mkulikov/app/utils/DateUtil.java @@ -0,0 +1,44 @@ +package ru.otus.mkulikov.app.utils; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.Date; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 05.06.2019 + * Time: 11:33 + */ + +public class DateUtil { + + private final static String DATE_FORMAT = "yyyy-MM-dd"; + + private final static String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; + + public static String dateToString(Date date) { + DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT); + return date != null ? dateFormat.format(date) : null; + } + + public static String dateTimeToString(Date date) { + DateFormat dateFormat = new SimpleDateFormat(DATE_TIME_FORMAT); + return date != null ? dateFormat.format(date) : null; + } + + public static java.util.Date stringToDateTime(String stringDate) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_TIME_FORMAT); + LocalDateTime dateTime = LocalDateTime.parse(stringDate, formatter); + return dateTime != null ? convertToDateViaInstant(dateTime) : null; + } + + public static Date convertToDateViaInstant(LocalDateTime dateToConvert) { + return java.util.Date + .from(dateToConvert.atZone(ZoneId.systemDefault()) + .toInstant()); + } +} diff --git a/src/main/java/ru/otus/mkulikov/changelog/DbChangeLog.java b/src/main/java/ru/otus/mkulikov/changelog/DbChangeLog.java new file mode 100644 index 0000000..f84fb0f --- /dev/null +++ b/src/main/java/ru/otus/mkulikov/changelog/DbChangeLog.java @@ -0,0 +1,73 @@ +package ru.otus.mkulikov.changelog; + +import com.github.cloudyrock.mongock.ChangeLog; +import com.github.cloudyrock.mongock.ChangeSet; +import com.mongodb.client.MongoDatabase; +import org.springframework.data.mongodb.core.MongoTemplate; +import ru.otus.mkulikov.app.model.Author; +import ru.otus.mkulikov.app.model.Book; +import ru.otus.mkulikov.app.model.Comment; +import ru.otus.mkulikov.app.model.Genre; +import ru.otus.mkulikov.app.utils.DateUtil; + +import java.util.Date; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 19.08.2019 + * Time: 23:33 + */ + +@ChangeLog(order = "001") +public class DbChangeLog { + + private final String DATE_TIME = "2019-01-01 10:01:01"; + private Date date = DateUtil.stringToDateTime(DATE_TIME); + + private Genre genre1; + private Genre genre2; + private Genre genre3; + + private Author author1; + private Author author2; + private Author author3; + + private Book book1; + private Book book2; + private Book book3; + + @ChangeSet(order = "000", id = "dropDB", author = "kulikov-mv", runAlways = true) + public void dropDB(MongoDatabase database) { + database.drop(); + } + + @ChangeSet(order = "001", id = "initGenres", author = "kulikov-mv", runAlways = true) + public void initGenres(MongoTemplate template) { + genre1 = template.save(new Genre("GenreName1")); + genre2 = template.save(new Genre("GenreName2")); + genre3 = template.save(new Genre("GenreName3")); + } + + @ChangeSet(order = "002", id = "initAuthors", author = "kulikov-mv", runAlways = true) + public void initAuthors(MongoTemplate template) { + author1 = template.save(new Author("Surname1", "FirstName1", "SecondName1")); + author2 = template.save(new Author("Surname2", "FirstName2", "SecondName2")); + author3 = template.save(new Author("Surname3", "FirstName3", "SecondName3")); + } + + @ChangeSet(order = "003", id = "initBooks", author = "kulikov-mv", runAlways = true) + public void initBooks(MongoTemplate template) { + book1 = template.save(new Book(date, "BookName1", author1, genre1, "Description1")); + book2 = template.save(new Book(date, "BookName2", author2, genre2, "Description2")); + book3 = template.save(new Book(date, "BookName3", author3, genre3, "Description3")); + } + + @ChangeSet(order = "004", id = "initComments", author = "kulikov-mv", runAlways = true) + public void initComments(MongoTemplate template) { + template.save(new Comment(book1, date, "user1", "text1")); + template.save(new Comment(book1, date, "user2", "text2")); + template.save(new Comment(book2, date, "user3", "text3")); + template.save(new Comment(book2, date, "user4", "text4")); + } +} diff --git a/src/main/java/ru/otus/mkulikov/config/ApplicationConfig.java b/src/main/java/ru/otus/mkulikov/config/ApplicationConfig.java new file mode 100644 index 0000000..ab6f856 --- /dev/null +++ b/src/main/java/ru/otus/mkulikov/config/ApplicationConfig.java @@ -0,0 +1,24 @@ +package ru.otus.mkulikov.config; + +import com.github.cloudyrock.mongock.Mongock; +import com.github.cloudyrock.mongock.SpringMongockBuilder; +import com.mongodb.MongoClient; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 19.08.2019 + * Time: 23:56 + */ + +@Configuration +public class ApplicationConfig { + + @Bean + public Mongock mongock(MongoProps mongoProps, MongoClient mongoClient) { + return new SpringMongockBuilder(mongoClient, mongoProps.getDatabase(), mongoProps.getPack()) + .build(); + } +} \ No newline at end of file diff --git a/src/main/java/ru/otus/mkulikov/config/MongoProps.java b/src/main/java/ru/otus/mkulikov/config/MongoProps.java new file mode 100644 index 0000000..d195ebe --- /dev/null +++ b/src/main/java/ru/otus/mkulikov/config/MongoProps.java @@ -0,0 +1,22 @@ +package ru.otus.mkulikov.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 19.08.2019 + * Time: 23:55 + */ + +@Data +@Component +@ConfigurationProperties("spring.data.mongodb") +public class MongoProps { + private int port; + private String database; + private String uri; + private String pack; +} diff --git a/src/main/java/ru/otus/mkulikov/config/WebMvcConfig.java b/src/main/java/ru/otus/mkulikov/config/WebMvcConfig.java new file mode 100644 index 0000000..a6eb5ac --- /dev/null +++ b/src/main/java/ru/otus/mkulikov/config/WebMvcConfig.java @@ -0,0 +1,26 @@ +package ru.otus.mkulikov.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +@EnableWebMvc +public class WebMvcConfig implements WebMvcConfigurer { + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + registry.addResourceHandler( + "/webjars/**", + "/img/**", + "/css/**", + "/js/**") + .addResourceLocations( + "classpath:/META-INF/resources/webjars/", + "classpath:/static/img/", + "classpath:/static/css/", + "classpath:/static/js/"); + } + +} \ No newline at end of file diff --git a/src/main/java/ru/otus/mkulikov/rest/AuthorController.java b/src/main/java/ru/otus/mkulikov/rest/AuthorController.java new file mode 100644 index 0000000..83f5038 --- /dev/null +++ b/src/main/java/ru/otus/mkulikov/rest/AuthorController.java @@ -0,0 +1,58 @@ +package ru.otus.mkulikov.rest; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import ru.otus.mkulikov.app.model.Author; +import ru.otus.mkulikov.app.model.Book; +import ru.otus.mkulikov.app.service.AuthorManageService; +import ru.otus.mkulikov.app.service.BookManageService; + +import java.util.List; + +@Controller +@RequiredArgsConstructor +public class AuthorController { + + private final AuthorManageService authorManageService; + private final BookManageService bookManageService; + + @GetMapping("/author/list") + public String getAll(Model model) { + List authors = authorManageService.getAuthors(); + model.addAttribute("authors", authors); + return "authors"; + } + + @GetMapping("/author") + public String getById(@RequestParam("id") String id, Model model) { + Author author = authorManageService.getAuthorById(id); + model.addAttribute("author", author); + return "author"; + } + + @GetMapping("/author/new") + public String getNew() { + Author author = authorManageService.addAuthor("", "", ""); + return "redirect:/author?id=" + author.getId(); + } + + @PostMapping(value = "/author/edit") + public String edit(@ModelAttribute Author author) { + authorManageService.updateAuthor(author); + return "redirect:/author/list"; + } + + @PostMapping(value = "/author/delete") + public String delete(@RequestParam("id") String id) { + List books = bookManageService.getBookByAuthorId(id); + if (books == null || (books != null && books.isEmpty())) { + authorManageService.deleteAuthor(id); + } + return "redirect:/author/list"; + } +} diff --git a/src/main/java/ru/otus/mkulikov/rest/BookController.java b/src/main/java/ru/otus/mkulikov/rest/BookController.java new file mode 100644 index 0000000..c7c8dbf --- /dev/null +++ b/src/main/java/ru/otus/mkulikov/rest/BookController.java @@ -0,0 +1,91 @@ +package ru.otus.mkulikov.rest; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import ru.otus.mkulikov.app.model.Author; +import ru.otus.mkulikov.app.model.Book; +import ru.otus.mkulikov.app.model.Comment; +import ru.otus.mkulikov.app.model.Genre; +import ru.otus.mkulikov.app.service.AuthorManageService; +import ru.otus.mkulikov.app.service.BookManageService; +import ru.otus.mkulikov.app.service.CommentManageService; +import ru.otus.mkulikov.app.service.GenreManageService; + +import java.util.List; + +@Controller +@RequiredArgsConstructor +public class BookController { + + private final BookManageService bookManageSevice; + private final AuthorManageService authorManageService; + private final GenreManageService genreManageService; + private final CommentManageService commentManageService; + + @GetMapping("/book/list") + public String getAll(Model model) { + List books = bookManageSevice.getBooks(); + model.addAttribute("books", books); + return "books"; + } + + @GetMapping("/book") + public String getById(@RequestParam("id") String id, Model model) { + List authors = authorManageService.getAuthors(); + List genres = genreManageService.getGenres(); + Book book = bookManageSevice.getBookById(id); + + model.addAttribute("book", book); + model.addAttribute("authors", authors); + model.addAttribute("genres", genres); + + return "book"; + } + + @PostMapping(value = "/book/edit") + public String edit(@ModelAttribute Book book, Model model) { + List authors = authorManageService.getAuthors(); + List genres = genreManageService.getGenres(); + Book updated = bookManageSevice.updateBook(book); + + model.addAttribute("book", updated); + model.addAttribute("authors", authors); + model.addAttribute("genres", genres); + + return "redirect:/book/list"; + } + + @GetMapping("/book/new") + public String getNew(Model model) { + List authors = authorManageService.getAuthors(); + List genres = genreManageService.getGenres(); + + String authorId = (authors != null && !authors.isEmpty()) + ? authors.get(0).getId() + : ""; + String genreId = (genres != null && !genres.isEmpty()) + ? genres.get(0).getId() + : ""; + + Book book = bookManageSevice.addBook("", authorId, genreId, ""); + + model.addAttribute("book", book); + model.addAttribute("authors", authors); + model.addAttribute("genres", genres); + + return "book"; + } + + @PostMapping(value = "/book/delete") + public String delete(@RequestParam("id") String id) { + List comments = commentManageService.getCommentsByBookId(id); + commentManageService.deleteComments(comments); + bookManageSevice.deleteBook(id); + return "redirect:/book/list"; + } +} diff --git a/src/main/java/ru/otus/mkulikov/rest/CommentController.java b/src/main/java/ru/otus/mkulikov/rest/CommentController.java new file mode 100644 index 0000000..4e98ccd --- /dev/null +++ b/src/main/java/ru/otus/mkulikov/rest/CommentController.java @@ -0,0 +1,73 @@ +package ru.otus.mkulikov.rest; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import ru.otus.mkulikov.app.model.Book; +import ru.otus.mkulikov.app.model.Comment; +import ru.otus.mkulikov.app.service.BookManageService; +import ru.otus.mkulikov.app.service.CommentManageService; + +import java.util.List; + +@Controller +@RequiredArgsConstructor +public class CommentController { + + private final BookManageService bookManageSevice; + private final CommentManageService commentManageService; + + @GetMapping("/comment/list") + public String getAll(Model model) { + List comments = commentManageService.getComments(); + model.addAttribute("comments", comments); + return "comments"; + } + + @GetMapping("/comment") + public String getById(@RequestParam("id") String id, Model model) { + List books = bookManageSevice.getBooks(); + Comment comment = commentManageService.getCommentById(id); + + model.addAttribute("books", books); + model.addAttribute("comment", comment); + + return "comment"; + } + + @PostMapping(value = "/comment/edit") + public String edit(@ModelAttribute Comment comment, Model model) { + List books = bookManageSevice.getBooks(); + Comment updated = commentManageService.updateComment(comment); + + model.addAttribute("books", books); + model.addAttribute("comment", updated); + + return "redirect:/comment/list"; + } + + @GetMapping("/comment/new") + public String getNew(Model model) { + List books = bookManageSevice.getBooks(); + + String bookId = (books != null && !books.isEmpty()) + ? books.get(0).getId() + : ""; + Comment comment = commentManageService.addComment(bookId, "", ""); + + model.addAttribute("books", books); + model.addAttribute("comment", comment); + + return "comment"; + } + + @PostMapping(value = "/comment/delete") + public String delete(@RequestParam("id") String id) { + commentManageService.deleteComment(id); + return "redirect:/comment/list"; + } +} diff --git a/src/main/java/ru/otus/mkulikov/rest/GenreController.java b/src/main/java/ru/otus/mkulikov/rest/GenreController.java new file mode 100644 index 0000000..7683485 --- /dev/null +++ b/src/main/java/ru/otus/mkulikov/rest/GenreController.java @@ -0,0 +1,59 @@ +package ru.otus.mkulikov.rest; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import ru.otus.mkulikov.app.model.Book; +import ru.otus.mkulikov.app.model.Genre; +import ru.otus.mkulikov.app.service.BookManageService; +import ru.otus.mkulikov.app.service.GenreManageService; + +import java.util.List; + +@Controller +@RequiredArgsConstructor +public class GenreController { + + private final BookManageService bookManageService; + private final GenreManageService genreManageService; + + @GetMapping("/genre/list") + public String getAll(Model model) { + List genres = genreManageService.getGenres(); + model.addAttribute("genres", genres); + return "genres"; + } + + @GetMapping("/genre") + public String getById(@RequestParam("id") String id, Model model) { + Genre genre = genreManageService.getGenreById(id); + model.addAttribute("genre", genre); + return "genre"; + } + + @GetMapping("/genre/new") + public String getNew() { + Genre genre = genreManageService.addGenre(""); + return "redirect:/genre?id=" + genre.getId(); + } + + @PostMapping(value = "/genre/edit") + public String edit(@ModelAttribute Genre genre, Model model) { + Genre updated = genreManageService.updateGenre(genre); + model.addAttribute("genre", updated); + return "redirect:/genre/list"; + } + + @PostMapping(value = "/genre/delete") + public String delete(@RequestParam("id") String id) { + List books = bookManageService.getBookByGenreId(id); + if (books == null || (books != null && books.isEmpty())) { + genreManageService.deleteGenre(id); + } + return "redirect:/genre/list"; + } +} diff --git a/src/main/java/ru/otus/mkulikov/rest/MainController.java b/src/main/java/ru/otus/mkulikov/rest/MainController.java new file mode 100644 index 0000000..cff40c8 --- /dev/null +++ b/src/main/java/ru/otus/mkulikov/rest/MainController.java @@ -0,0 +1,15 @@ +package ru.otus.mkulikov.rest; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +public class MainController { + + @RequestMapping("/") + public String helloWorld(Model model) { + return "index"; + } + +} diff --git a/src/main/java/ru/otus/mkulikov/shell/AuthorCommands.java b/src/main/java/ru/otus/mkulikov/shell/AuthorCommands.java new file mode 100644 index 0000000..241ce94 --- /dev/null +++ b/src/main/java/ru/otus/mkulikov/shell/AuthorCommands.java @@ -0,0 +1,54 @@ +package ru.otus.mkulikov.shell; + +import lombok.RequiredArgsConstructor; +import org.springframework.shell.standard.ShellComponent; +import org.springframework.shell.standard.ShellMethod; +import org.springframework.shell.standard.ShellOption; +import ru.otus.mkulikov.app.model.Author; +import ru.otus.mkulikov.app.service.AuthorManageService; + +import java.util.List; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 30.05.2019 + * Time: 14:46 + */ + +@ShellComponent +@RequiredArgsConstructor +public class AuthorCommands { + + private final AuthorManageService authorManageService; + + @ShellMethod(key = {"getAuthorById"}, value = "Select author by id.") + public String getAuthorById(@ShellOption String id) { + Author author = authorManageService.getAuthorById(id); + return author.toString(); + } + + @ShellMethod(key = {"getAuthors"}, value = "Select all authors.") + public String getAuthors() { + List allObjects = authorManageService.getAuthors(); + return allObjects.toString(); + } + + @ShellMethod(key = {"addAuthor"}, value = "Add new author.") + public String addAuthor(@ShellOption String surname, @ShellOption String firstName, @ShellOption String secondName) { + Author author = authorManageService.addAuthor(surname, firstName, secondName); + return "Add " + (author != null ? 1 : 0) + " row(s)\nID: " + author.getId(); + } + + @ShellMethod(key = {"updateAuthor"}, value = "Update author by id.") + public String updateAuthor(@ShellOption String id, @ShellOption String surname, @ShellOption String firstName, @ShellOption String secondName) { + Author author = authorManageService.updateAuthor(id, surname, firstName, secondName); + return "Updated " + (author != null ? 1 : 0) + " row(s)\nID: " + author.getId(); + } + + @ShellMethod(key = {"deleteAuthor"}, value = "Delete author by id.") + public String deleteAuthor(@ShellOption String id) { + int count = authorManageService.deleteAuthor(id); + return "Deleted " + count + " row(s)"; + } +} diff --git a/src/main/java/ru/otus/mkulikov/shell/BookCommands.java b/src/main/java/ru/otus/mkulikov/shell/BookCommands.java new file mode 100644 index 0000000..21036c8 --- /dev/null +++ b/src/main/java/ru/otus/mkulikov/shell/BookCommands.java @@ -0,0 +1,54 @@ +package ru.otus.mkulikov.shell; + +import lombok.RequiredArgsConstructor; +import org.springframework.shell.standard.ShellComponent; +import org.springframework.shell.standard.ShellMethod; +import org.springframework.shell.standard.ShellOption; +import ru.otus.mkulikov.app.model.Book; +import ru.otus.mkulikov.app.service.BookManageService; + +import java.util.List; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 23.05.2019 + * Time: 17:33 + */ + +@ShellComponent +@RequiredArgsConstructor +public class BookCommands { + + private final BookManageService bookManageSevice; + + @ShellMethod(key = {"getBookById"}, value = "Select book by id.") + public String getBookById(@ShellOption String id) { + Book book = bookManageSevice.getBookById(id); + return book.toString(); + } + + @ShellMethod(key = {"getBooks"}, value = "Select all books.") + public String getBooks() { + List allObjects = bookManageSevice.getBooks(); + return allObjects.toString(); + } + + @ShellMethod(key = {"addBook"}, value = "Add new book.") + public String addBook(@ShellOption String caption, @ShellOption String authorId, @ShellOption String genreId, @ShellOption String description) { + Book book = bookManageSevice.addBook(caption, authorId, genreId, description); + return "Add " + (book != null ? 1 : 0) + " row(s)\nID: " + book.getId(); + } + + @ShellMethod(key = {"updateBook"}, value = "Update book by id.") + public String updateBook(@ShellOption String id, @ShellOption String caption, @ShellOption String authorId, @ShellOption String genreId, @ShellOption String description) { + Book book = bookManageSevice.updateBook(id, caption, authorId, genreId, description); + return "Updated " + (book != null ? 1 : 0) + " row(s)\nID: " + book.getId(); + } + + @ShellMethod(key = {"deleteBook"}, value = "Delete book by id.") + public String deleteBook(@ShellOption String id) { + int count = bookManageSevice.deleteBook(id); + return "Deleted " + count + " row(s)"; + } +} diff --git a/src/main/java/ru/otus/mkulikov/shell/CommentCommands.java b/src/main/java/ru/otus/mkulikov/shell/CommentCommands.java new file mode 100644 index 0000000..abd452d --- /dev/null +++ b/src/main/java/ru/otus/mkulikov/shell/CommentCommands.java @@ -0,0 +1,60 @@ +package ru.otus.mkulikov.shell; + +import lombok.RequiredArgsConstructor; +import org.springframework.shell.standard.ShellComponent; +import org.springframework.shell.standard.ShellMethod; +import org.springframework.shell.standard.ShellOption; +import ru.otus.mkulikov.app.model.Comment; +import ru.otus.mkulikov.app.service.CommentManageService; + +import java.util.List; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 30.05.2019 + * Time: 14:47 + */ + +@ShellComponent +@RequiredArgsConstructor +public class CommentCommands { + + private final CommentManageService commentManageService; + + @ShellMethod(key = {"getCommentById"}, value = "Select comment by id.") + public String getCommentById(@ShellOption String id) { + Comment comment = commentManageService.getCommentById(id); + return comment.toString(); + } + + @ShellMethod(key = {"getComments"}, value = "Select all comments.") + public String getComments() { + List allObjects = commentManageService.getComments(); + return allObjects.toString(); + } + + @ShellMethod(key = {"getCommentsByBookId"}, value = "Select all comments.") + public String getCommentsByBookId(@ShellOption String bookId) { + List allObjects = commentManageService.getCommentsByBookId(bookId); + return allObjects.toString(); + } + + @ShellMethod(key = {"addComment"}, value = "Add new comment.") + public String addComment(@ShellOption String bookId, @ShellOption String userName, @ShellOption String text) { + Comment comment = commentManageService.addComment(bookId, userName, text); + return "Add " + (comment != null ? 1 : 0) + " row(s)\nID: " + comment.getId(); + } + + @ShellMethod(key = {"updateComment"}, value = "Update comment by id.") + public String updateComment(@ShellOption String id, @ShellOption String userName, @ShellOption String text) { + Comment comment = commentManageService.updateComment(id, userName, text); + return "Updated " + (comment != null ? 1 : 0) + " row(s)\nID: " + comment.getId(); + } + + @ShellMethod(key = {"deleteComment"}, value = "Delete comment by id.") + public String deleteComment(@ShellOption String id) { + int count = commentManageService.deleteComment(id); + return "Deleted " + count + " row(s)"; + } +} diff --git a/src/main/java/ru/otus/mkulikov/shell/GenreCommands.java b/src/main/java/ru/otus/mkulikov/shell/GenreCommands.java new file mode 100644 index 0000000..aa4b95a --- /dev/null +++ b/src/main/java/ru/otus/mkulikov/shell/GenreCommands.java @@ -0,0 +1,54 @@ +package ru.otus.mkulikov.shell; + +import lombok.RequiredArgsConstructor; +import org.springframework.shell.standard.ShellComponent; +import org.springframework.shell.standard.ShellMethod; +import org.springframework.shell.standard.ShellOption; +import ru.otus.mkulikov.app.model.Genre; +import ru.otus.mkulikov.app.service.GenreManageService; + +import java.util.List; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 30.05.2019 + * Time: 14:47 + */ + +@ShellComponent +@RequiredArgsConstructor +public class GenreCommands { + + private final GenreManageService genreManageService; + + @ShellMethod(key = {"getGenreById"}, value = "Select genre by id.") + public String getGenreById(@ShellOption String id) { + Genre genre = genreManageService.getGenreById(id); + return genre.toString(); + } + + @ShellMethod(key = {"getGenres"}, value = "Select all genres.") + public String getGenres() { + List allObjects = genreManageService.getGenres(); + return allObjects.toString(); + } + + @ShellMethod(key = {"addGenre"}, value = "Add new genre.") + public String addGenre(@ShellOption String name) { + Genre genre = genreManageService.addGenre(name); + return "Add " + (genre != null ? 1 : 0) + " row(s)\nID: " + genre.getId(); + } + + @ShellMethod(key = {"updateGenre"}, value = "Update genre by id.") + public String updateGenre(@ShellOption String id, @ShellOption String name) { + Genre genre = genreManageService.updateGenre(id, name); + return "Updated " + (genre != null ? 1 : 0) + " row(s)\nID: " + genre.getId(); + } + + @ShellMethod(key = {"deleteGenre"}, value = "Delete genre by id.") + public String deleteGenre(@ShellOption String id) { + int count = genreManageService.deleteGenre(id); + return "Deleted " + count + " row(s)"; + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..43cd088 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,11 @@ +spring: + banner: + location: "classpath:banner.txt" + + data: + mongodb: + uri: mongodb://localhost + port: 27017 + database: library + pack: "ru.otus.mkulikov.changelog" + diff --git a/src/main/resources/banner.txt b/src/main/resources/banner.txt new file mode 100644 index 0000000..1687640 --- /dev/null +++ b/src/main/resources/banner.txt @@ -0,0 +1,11 @@ + ___ ___ ___ ___ ___ + /\__\ /\ \ /\__\ /\ \ /\ \ + /:/ / /::\ \ /:/ / /::\ \ /::\ \ + /:/ / /:/\:\ \ /:/ / /:/\:\ \ /:/\ \ \ + /:/ / ___ /:/ \:\ \ /:/ / /::\~\:\ \ _\:\~\ \ \ + /:/__/ /\__\ /:/__/ \:\__\ /:/__/ /:/\:\ \:\__\ /\ \:\ \ \__\ + \:\ \ /:/ / \:\ \ /:/ / \:\ \ \:\~\:\ \/__/ \:\ \:\ \/__/ + \:\ /:/ / \:\ /:/ / \:\ \ \:\ \:\__\ \:\ \:\__\ + \:\/:/ / \:\/:/ / \:\ \ \:\ \/__/ \:\/:/ / + \::/ / \::/ / \:\__\ \:\__\ \::/ / + \/__/ \/__/ \/__/ \/__/ \/__/ \ No newline at end of file diff --git a/src/main/resources/static/css/header.css b/src/main/resources/static/css/header.css new file mode 100644 index 0000000..f1541bf --- /dev/null +++ b/src/main/resources/static/css/header.css @@ -0,0 +1,80 @@ +body { + padding: 50px; +} + +.btns td { + border: 1px solid white; + padding: 5px; +} + +.objects td { + border: 1px solid lightgray; + padding: 5px; +} + +/*https://cssgradientbutton.com/#*/ +.button-new { + border:1px solid #96f0ff; -webkit-border-radius: 3px; -moz-border-radius: 3px;border-radius: 3px;font-size:12px;font-family:arial, helvetica, sans-serif; padding: 10px 10px 10px 10px; text-decoration:none; display:inline-block;font-weight:bold; color: #000000; + background-color: #cef8ff; background-image: -webkit-gradient(linear, left top, left bottom, from(#cef8ff), to(#7fe0f8)); + background-image: -webkit-linear-gradient(top, #cef8ff, #7fe0f8); + background-image: -moz-linear-gradient(top, #cef8ff, #7fe0f8); + background-image: -ms-linear-gradient(top, #cef8ff, #7fe0f8); + background-image: -o-linear-gradient(top, #cef8ff, #7fe0f8); + background-image: linear-gradient(to bottom, #cef8ff, #7fe0f8); + filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr=#cef8ff, endColorstr=#7fe0f8); +} + +.button-new:hover { + border:1px solid #68e9ff; + background-color: #9bf1ff; background-image: -webkit-gradient(linear, left top, left bottom, from(#9bf1ff), to(#4fd4f5)); + background-image: -webkit-linear-gradient(top, #9bf1ff, #4fd4f5); + background-image: -moz-linear-gradient(top, #9bf1ff, #4fd4f5); + background-image: -ms-linear-gradient(top, #9bf1ff, #4fd4f5); + background-image: -o-linear-gradient(top, #9bf1ff, #4fd4f5); + background-image: linear-gradient(to bottom, #9bf1ff, #4fd4f5); + filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr=#9bf1ff, endColorstr=#4fd4f5); +} + +.button { + border:1px solid #d1dcdf; -webkit-border-radius: 3px; -moz-border-radius: 3px;border-radius: 3px;font-size:12px;font-family:arial, helvetica, sans-serif; padding: 10px 10px 10px 10px; text-decoration:none; display:inline-block;font-weight:bold; color: #000000; + background-color: #f2f5f6; background-image: -webkit-gradient(linear, left top, left bottom, from(#f2f5f6), to(#c8d7dc)); + background-image: -webkit-linear-gradient(top, #f2f5f6, #c8d7dc); + background-image: -moz-linear-gradient(top, #f2f5f6, #c8d7dc); + background-image: -ms-linear-gradient(top, #f2f5f6, #c8d7dc); + background-image: -o-linear-gradient(top, #f2f5f6, #c8d7dc); + background-image: linear-gradient(to bottom, #f2f5f6, #c8d7dc); + filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr=#f2f5f6, endColorstr=#c8d7dc); +} + +.button:hover { + border:1px solid #b6c7cc; + background-color: #d4dee1; background-image: -webkit-gradient(linear, left top, left bottom, from(#d4dee1), to(#a9c0c8)); + background-image: -webkit-linear-gradient(top, #d4dee1, #a9c0c8); + background-image: -moz-linear-gradient(top, #d4dee1, #a9c0c8); + background-image: -ms-linear-gradient(top, #d4dee1, #a9c0c8); + background-image: -o-linear-gradient(top, #d4dee1, #a9c0c8); + background-image: linear-gradient(to bottom, #d4dee1, #a9c0c8); + filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr=#d4dee1, endColorstr=#a9c0c8); +} + +.button-table { + border:1px solid #d1dcdf; -webkit-border-radius: 3px; -moz-border-radius: 3px;border-radius: 3px;font-size:12px;font-family:arial, helvetica, sans-serif; padding: 3px 3px 3px 3px; text-decoration:none; display:inline-block;font-weight:bold; color: #000000; + background-color: #f2f5f6; background-image: -webkit-gradient(linear, left top, left bottom, from(#f2f5f6), to(#c8d7dc)); + background-image: -webkit-linear-gradient(top, #f2f5f6, #c8d7dc); + background-image: -moz-linear-gradient(top, #f2f5f6, #c8d7dc); + background-image: -ms-linear-gradient(top, #f2f5f6, #c8d7dc); + background-image: -o-linear-gradient(top, #f2f5f6, #c8d7dc); + background-image: linear-gradient(to bottom, #f2f5f6, #c8d7dc); + filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr=#f2f5f6, endColorstr=#c8d7dc); +} + +.button-table:hover { + border:1px solid #b6c7cc; + background-color: #d4dee1; background-image: -webkit-gradient(linear, left top, left bottom, from(#d4dee1), to(#a9c0c8)); + background-image: -webkit-linear-gradient(top, #d4dee1, #a9c0c8); + background-image: -moz-linear-gradient(top, #d4dee1, #a9c0c8); + background-image: -ms-linear-gradient(top, #d4dee1, #a9c0c8); + background-image: -o-linear-gradient(top, #d4dee1, #a9c0c8); + background-image: linear-gradient(to bottom, #d4dee1, #a9c0c8); + filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr=#d4dee1, endColorstr=#a9c0c8); +} \ No newline at end of file diff --git a/src/main/resources/templates/author.html b/src/main/resources/templates/author.html new file mode 100644 index 0000000..481b222 --- /dev/null +++ b/src/main/resources/templates/author.html @@ -0,0 +1,33 @@ + + + + + + + + Author detail + + + + + +
+

+ +

+
+ +

Author detail:

+ +
+

Id:

+

Surname:

+

FirstName:

+

SecondName:

+

+ +

+
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/authors.html b/src/main/resources/templates/authors.html new file mode 100644 index 0000000..94ff040 --- /dev/null +++ b/src/main/resources/templates/authors.html @@ -0,0 +1,89 @@ + + + + + + + + List of all authors + + + + +

Authors:

+ + + + + + + + + + + + +
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + +
IDSurnameFirstNameSecondName
1John DoeJohn DoeJohn Doe +
+

+ + +

+
+
+
+

+ +

+
+
+ +
+Сущности, у которых есть связи с другими объектами, удаляться не будут +
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/book.html b/src/main/resources/templates/book.html new file mode 100644 index 0000000..602d475 --- /dev/null +++ b/src/main/resources/templates/book.html @@ -0,0 +1,47 @@ + + + + + + + + Book detail + + + + + +
+

+ +

+
+ +

Book detail:

+ +
+

Id:

+ +

Author:

+ +

Genre:

+ +

Caption:

+

Description:

+

+ +

+
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/books.html b/src/main/resources/templates/books.html new file mode 100644 index 0000000..6d792b3 --- /dev/null +++ b/src/main/resources/templates/books.html @@ -0,0 +1,93 @@ + + + + + + + + List of all books + + + + +

Books:

+ + + + + + + + + + + + +
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
IDDateCaptionDescriptionAuthorGenre
1John DoeJohn DoeJohn Doe + + + + +
+

+ + +

+
+
+
+

+ +

+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/comment.html b/src/main/resources/templates/comment.html new file mode 100644 index 0000000..9d6f12e --- /dev/null +++ b/src/main/resources/templates/comment.html @@ -0,0 +1,40 @@ + + + + + + + + Comment detail + + + + + +
+

+ +

+
+ +

Comment detail:

+ +
+

Id:

+ +

Book:

+ +

UserName:

+

Text:

+

+ +

+
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/comments.html b/src/main/resources/templates/comments.html new file mode 100644 index 0000000..90a696a --- /dev/null +++ b/src/main/resources/templates/comments.html @@ -0,0 +1,89 @@ + + + + + + + + List of all comments + + + + +

Comments:

+ + + + + + + + + + + + +
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
IDAddRecordDateBookUserNameText
1John Doe + + John DoeJohn Doe +
+

+ + +

+
+
+
+

+ +

+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/genre.html b/src/main/resources/templates/genre.html new file mode 100644 index 0000000..84a31df --- /dev/null +++ b/src/main/resources/templates/genre.html @@ -0,0 +1,31 @@ + + + + + + + + Genre detail + + + + + +
+

+ +

+
+ +

Genre detail:

+ +
+

Id:

+

Name:

+

+ +

+
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/genres.html b/src/main/resources/templates/genres.html new file mode 100644 index 0000000..1dda84c --- /dev/null +++ b/src/main/resources/templates/genres.html @@ -0,0 +1,85 @@ + + + + + + + + List of all genres + + + + +

Genres:

+ + + + + + + + + + + + +
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
IDName
1John Doe +
+

+ + +

+
+
+
+

+ +

+
+
+ +
+Сущности, у которых есть связи с другими объектами, удаляться не будут +
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html new file mode 100644 index 0000000..121da5e --- /dev/null +++ b/src/main/resources/templates/index.html @@ -0,0 +1,72 @@ + + + + + Twitter Bootstrap Example + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#ИмяФамилияUsername
1MarkOtto@mdo
2JacobThornton@fat
3Larrythe Bird@twitter
+ + + \ No newline at end of file diff --git a/src/test/java/ru/otus/mkulikov/app/dao/AuthorDaoTest.java b/src/test/java/ru/otus/mkulikov/app/dao/AuthorDaoTest.java new file mode 100644 index 0000000..6c3c185 --- /dev/null +++ b/src/test/java/ru/otus/mkulikov/app/dao/AuthorDaoTest.java @@ -0,0 +1,103 @@ +package ru.otus.mkulikov.app.dao; + +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.autoconfigure.data.mongo.DataMongoTest; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; +import ru.otus.mkulikov.app.model.Author; + +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static ru.otus.mkulikov.generators.GenerateAuthor.getAuthor; +import static ru.otus.mkulikov.generators.GenerateAuthor.getAuthorList; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 29.05.2019 + * Time: 10:12 + */ + +@DataMongoTest +@DisplayName("Класс AuthorDao") +class AuthorDaoTest { + + private final String ID_1 = "1"; + private final String ID_2 = "2"; + private final String ID_3 = "3"; + private final String ID_4 = "4"; + + private final int OBJECT_COUNT_3 = 3; + private final int OBJECT_COUNT_2 = 2; + + private final String TEST_SURNAME = "TestSurname"; + private final String TEST_FIRST_NAME = "TestFirstName"; + private final String TEST_SECOND_NAME = "TestSecondName"; + + @Autowired + private MongoTemplate mongoTemplate; + + @Autowired + private AuthorDao authorDao; + + @BeforeEach + void init() { + mongoTemplate.save(getAuthor(ID_1)); + mongoTemplate.save(getAuthor(ID_2)); + mongoTemplate.save(getAuthor(ID_3)); + } + + @Test + @DisplayName("Получение автора по id") + void getById() { + Optional author = authorDao.findById(ID_1); + + assertThat(author).isNotEmpty(); + assertThat(author).contains(getAuthor(ID_1)); + } + + @Test + @DisplayName("Получение всех авторов") + void getAllObjects() { + List authors = authorDao.findAll(); + + assertThat(authors).size().isEqualTo(OBJECT_COUNT_3); + assertThat(authors).containsAll(getAuthorList()); + } + + @Test + @DisplayName("Добавление автора") + void addObject() { + Author author = authorDao.save(getAuthor(ID_4)); + Optional author_selected = authorDao.findById(author.getId()); + + assertThat(author_selected).isNotEmpty(); + assertThat(author_selected).contains(getAuthor(ID_4)); + } + + @Test + @DisplayName("Удаление автора") + @Transactional(propagation = Propagation.NOT_SUPPORTED) + void deleteObject() { + assertThat(authorDao.count()).isEqualTo(OBJECT_COUNT_3); + authorDao.deleteById(ID_1); + assertThat(authorDao.count()).isEqualTo(OBJECT_COUNT_2); + } + + @Test + @DisplayName("Обновление автора") + void updateObject() { + Author author = new Author(ID_1, TEST_SURNAME, TEST_FIRST_NAME, TEST_SECOND_NAME); + authorDao.save(author); + Optional author_selected = authorDao.findById(ID_1); + + assertThat(author_selected).isNotEmpty(); + assertThat(author_selected).contains(author); + } +} \ No newline at end of file diff --git a/src/test/java/ru/otus/mkulikov/app/dao/BookDaoTest.java b/src/test/java/ru/otus/mkulikov/app/dao/BookDaoTest.java new file mode 100644 index 0000000..6695308 --- /dev/null +++ b/src/test/java/ru/otus/mkulikov/app/dao/BookDaoTest.java @@ -0,0 +1,156 @@ +package ru.otus.mkulikov.app.dao; + +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.autoconfigure.data.mongo.DataMongoTest; +import org.springframework.data.mongodb.core.MongoTemplate; +import ru.otus.mkulikov.app.model.Author; +import ru.otus.mkulikov.app.model.Book; +import ru.otus.mkulikov.app.model.Genre; +import ru.otus.mkulikov.app.utils.DateUtil; + +import java.util.Date; +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static ru.otus.mkulikov.generators.GenerateAuthor.getAuthor; +import static ru.otus.mkulikov.generators.GenerateBook.getBook; +import static ru.otus.mkulikov.generators.GenerateBook.getBooksList; +import static ru.otus.mkulikov.generators.GenerateGenre.getGenre; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 28.05.2019 + * Time: 13:16 + */ + +@DataMongoTest +@DisplayName("Класс BookDao") +class BookDaoTest { + + private final String ID_1 = "1"; + private final String ID_2 = "2"; + private final String ID_3 = "3"; + private final String ID_4 = "4"; + + private final int OBJECT_COUNT_1 = 1; + private final int OBJECT_COUNT_2 = 2; + private final int OBJECT_COUNT_3 = 3; + + private final String DATE_TIME = "2019-01-01 10:01:01"; + + private final String UPDATED_BOOK_NAME = "UpdatedBookName"; + private final String UPDATED_DESCRIPTION = "UpdatedDescription"; + + @Autowired + private MongoTemplate mongoTemplate; + + @Autowired + private BookDao bookDaoJpa; + + @Autowired + private AuthorDao authorDao; + + @Autowired + private GenreDao genreDao; + + @BeforeEach + void init() { + mongoTemplate.save(getAuthor(ID_1)); + mongoTemplate.save(getAuthor(ID_2)); + mongoTemplate.save(getAuthor(ID_3)); + + mongoTemplate.save(getGenre(ID_1)); + mongoTemplate.save(getGenre(ID_2)); + mongoTemplate.save(getGenre(ID_3)); + + mongoTemplate.save(getBook(ID_1)); + mongoTemplate.save(getBook(ID_2)); + mongoTemplate.save(getBook(ID_3)); + } + + @Test + @DisplayName("Получение книги по id") + void getById() { + Optional book = bookDaoJpa.findById(ID_1); + + assertThat(book).isNotEmpty(); + assertThat(book).contains(getBook(ID_1)); + } + + @Test + @DisplayName("Получение книг по id автора") + void getByAuthorId() { + List books = bookDaoJpa.findByAuthor_Id(ID_1); + + assertThat(books).isNotEmpty(); + assertThat(books).size().isEqualTo(OBJECT_COUNT_1); + } + + @Test + @DisplayName("Получение книг по id жанра") + void getByGenreId() { + List books = bookDaoJpa.findByGenre_Id(ID_1); + + assertThat(books).isNotEmpty(); + assertThat(books).size().isEqualTo(OBJECT_COUNT_2); + } + + @Test + @DisplayName("Получение всех книг") + void getAllObjects() { + List books = bookDaoJpa.findAll(); + + assertThat(books).size().isEqualTo(OBJECT_COUNT_3); + assertThat(books).containsAll(getBooksList()); + } + + @Test + @DisplayName("Добавление книги") + void addObject() { + Book book = getNewBook(ID_4); + + bookDaoJpa.save(book); + Optional book_selected = bookDaoJpa.findById(ID_4); + + assertThat(book_selected).isNotEmpty(); + assertThat(book_selected).contains(book); + } + + @Test + @DisplayName("Удаление книги по id") + void deleteObject() { + bookDaoJpa.deleteById(ID_1); + Optional book = bookDaoJpa.findById(ID_1); + assertThat(book).isEmpty(); + } + + @Test + @DisplayName("Обновление книги") + void updateObject() { + Book book = getUpdatedBook(); + + bookDaoJpa.save(book); + Optional book_selected = bookDaoJpa.findById(ID_1); + + assertThat(book_selected).isNotEmpty(); + assertThat(book_selected).contains(book); + } + + private Book getUpdatedBook() { + Author author = authorDao.findById(ID_1).orElse(null); + Genre genre = genreDao.findById(ID_1).orElse(null); + return new Book(ID_1, new Date(), UPDATED_BOOK_NAME, author, genre, UPDATED_DESCRIPTION); + } + + private Book getNewBook(String id) { + Author author = authorDao.findById(ID_1).orElse(null); + Genre genre = genreDao.findById(ID_1).orElse(null); + Date date = DateUtil.stringToDateTime(DATE_TIME); + return new Book(id, date, UPDATED_BOOK_NAME, author, genre, UPDATED_DESCRIPTION); + } +} \ No newline at end of file diff --git a/src/test/java/ru/otus/mkulikov/app/dao/CommentDaoTest.java b/src/test/java/ru/otus/mkulikov/app/dao/CommentDaoTest.java new file mode 100644 index 0000000..cfa7b0c --- /dev/null +++ b/src/test/java/ru/otus/mkulikov/app/dao/CommentDaoTest.java @@ -0,0 +1,149 @@ +package ru.otus.mkulikov.app.dao; + +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.autoconfigure.data.mongo.DataMongoTest; +import org.springframework.data.mongodb.core.MongoTemplate; +import ru.otus.mkulikov.app.model.Book; +import ru.otus.mkulikov.app.model.Comment; +import ru.otus.mkulikov.app.utils.DateUtil; + +import java.util.Date; +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static ru.otus.mkulikov.generators.GenerateAuthor.getAuthor; +import static ru.otus.mkulikov.generators.GenerateBook.getBook; +import static ru.otus.mkulikov.generators.GenerateComment.getComment; +import static ru.otus.mkulikov.generators.GenerateComment.getCommentList; +import static ru.otus.mkulikov.generators.GenerateGenre.getGenre; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 28.05.2019 + * Time: 9:45 + */ + +@DataMongoTest +@DisplayName("Класс CommentDao") +class CommentDaoTest { + + private final String ID_1 = "1"; + private final String ID_2 = "2"; + private final String ID_3 = "3"; + private final String ID_4 = "4"; + private final String ID_5 = "5"; + + private final int OBJECT_COUNT_4 = 4; + private final int OBJECT_COUNT_2 = 2; + + private final String DATE_TIME = "2019-01-01 10:01:01"; + + private final String COMMENT_USER_NAME = "user"; + private final String COMMENT_UPDATED_USER_NAME = "TestUser"; + private final String COMMENT_TEXT = "text"; + private final String COMMENT_UPDATED_TEXT = "TestText"; + + @Autowired + private MongoTemplate mongoTemplate; + + @Autowired + private BookDao bookDao; + + @Autowired + private CommentDao commentDao; + + @BeforeEach + void init() { + mongoTemplate.save(getAuthor(ID_1)); + mongoTemplate.save(getAuthor(ID_2)); + mongoTemplate.save(getAuthor(ID_3)); + + mongoTemplate.save(getGenre(ID_1)); + mongoTemplate.save(getGenre(ID_2)); + mongoTemplate.save(getGenre(ID_3)); + + mongoTemplate.save(getBook(ID_1)); + mongoTemplate.save(getBook(ID_2)); + + mongoTemplate.save(getComment(ID_1, ID_1)); + mongoTemplate.save(getComment(ID_2, ID_1)); + mongoTemplate.save(getComment(ID_3, ID_2)); + mongoTemplate.save(getComment(ID_4, ID_2)); + } + + @Test + @DisplayName("Получение комментария по id") + void getById() { + Optional comment = commentDao.findById(ID_1); + + assertThat(comment).isNotEmpty(); + assertThat(comment).contains(getComment(ID_1, ID_1)); + } + + @Test + @DisplayName("Получение всех комментариев") + void getAllObjects() { + List comments = commentDao.findAll(); + + assertThat(comments).isNotEmpty(); + assertThat(comments).size().isEqualTo(OBJECT_COUNT_4); + assertThat(comments).containsAll(getCommentList()); + } + + @Test + @DisplayName("Получение всех комментариев для книги") + void getObjectsByBook() { + Optional book = bookDao.findById(ID_1); + List comments = commentDao.findByBook(book.orElse(null)); + + assertThat(comments).isNotEmpty(); + assertThat(comments).size().isEqualTo(OBJECT_COUNT_2); + assertThat(comments).contains(getComment(ID_1, ID_1), getComment(ID_2, ID_1)); + } + + @Test + @DisplayName("Добавление комментария") + void addObject() { + Date date = DateUtil.stringToDateTime(DATE_TIME); + Book book = bookDao.findById(ID_1).orElse(null); + Comment comment = new Comment(ID_5, book, date, COMMENT_USER_NAME + ID_5, COMMENT_TEXT + ID_5); + commentDao.save(comment); + + Optional comment_selected = commentDao.findById(ID_5); + + assertThat(comment_selected).isNotEmpty(); + assertThat(comment_selected).contains(comment); + } + + @Test + @DisplayName("Удаление комментария") + void deleteObject() { + commentDao.deleteById(ID_1); + Optional comment = commentDao.findById(ID_1); + assertThat(comment).isEmpty(); + } + + @Test + @DisplayName("Обновление комментария") + void updateObject() { + Comment comment = getUpdatedComment(); + commentDao.save(comment); + Optional comment_selected = commentDao.findById(ID_1); + + assertThat(comment_selected).isNotEmpty(); + assertThat(comment_selected).contains(comment); + } + + private Comment getUpdatedComment() { + Comment comment = commentDao.findById(ID_1).orElse(null); + comment.setAddRecordDate(new Date()); + comment.setUserName(COMMENT_UPDATED_USER_NAME); + comment.setText(COMMENT_UPDATED_TEXT); + return comment; + } +} \ No newline at end of file diff --git a/src/test/java/ru/otus/mkulikov/app/dao/GenreDaoTest.java b/src/test/java/ru/otus/mkulikov/app/dao/GenreDaoTest.java new file mode 100644 index 0000000..f5aa9dc --- /dev/null +++ b/src/test/java/ru/otus/mkulikov/app/dao/GenreDaoTest.java @@ -0,0 +1,103 @@ +package ru.otus.mkulikov.app.dao; + +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.autoconfigure.data.mongo.DataMongoTest; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; +import ru.otus.mkulikov.app.model.Genre; + +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static ru.otus.mkulikov.generators.GenerateGenre.getGenre; +import static ru.otus.mkulikov.generators.GenerateGenre.getGenreList; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 28.05.2019 + * Time: 9:45 + */ + +@DataMongoTest +@DisplayName("Класс GenreDao") +class GenreDaoTest { + + private final String ID_1 = "1"; + private final String ID_2 = "2"; + private final String ID_3 = "3"; + private final String ID_4 = "4"; + + private final int OBJECT_COUNT_3 = 3; + private final int OBJECT_COUNT_2 = 2; + + private final String UPDATED_NAME = "UpdatedName"; + + @Autowired + private MongoTemplate mongoTemplate; + + @Autowired + private GenreDao genreDao; + + @BeforeEach + void init() { + mongoTemplate.save(getGenre(ID_1)); + mongoTemplate.save(getGenre(ID_2)); + mongoTemplate.save(getGenre(ID_3)); + } + + @Test + @DisplayName("Получение жанра по id") + void getById() { + Optional genre = genreDao.findById(ID_1); + + assertThat(genre).isNotEmpty(); + assertThat(genre).contains(getGenre(ID_1)); + } + + @Test + @DisplayName("Получение всех жанров") + void getAllObjects() { + List genres = genreDao.findAll(); + + assertThat(genres).isNotEmpty(); + assertThat(genres).size().isEqualTo(OBJECT_COUNT_3); + assertThat(genres).containsAll(getGenreList()); + } + + @Test + @DisplayName("Добавление жанра") + void addObject() { + Genre genre = genreDao.save(getGenre(ID_4)); + Optional genre_selected = genreDao.findById(genre.getId()); + + assertThat(genre_selected).isNotEmpty(); + assertThat(genre_selected).contains(genre); + } + + @Test + @DisplayName("Удаление жанра") + @Transactional(propagation = Propagation.NOT_SUPPORTED) + void deleteObject() { + assertThat(genreDao.count()).isEqualTo(OBJECT_COUNT_3); + genreDao.deleteById(ID_1); + assertThat(genreDao.count()).isEqualTo(OBJECT_COUNT_2); + } + + @Test + @DisplayName("Обновление жанра") + void updateObject() { + Genre genre = new Genre(ID_1, UPDATED_NAME); + + genreDao.save(genre); + Optional genre_updated = genreDao.findById(ID_1); + + assertThat(genre_updated).isNotEmpty(); + assertThat(genre_updated).contains(genre); + } +} \ No newline at end of file diff --git a/src/test/java/ru/otus/mkulikov/app/model/DateUtilTest.java b/src/test/java/ru/otus/mkulikov/app/model/DateUtilTest.java new file mode 100644 index 0000000..62f8d72 --- /dev/null +++ b/src/test/java/ru/otus/mkulikov/app/model/DateUtilTest.java @@ -0,0 +1,53 @@ +package ru.otus.mkulikov.app.model; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import ru.otus.mkulikov.app.utils.DateUtil; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 29.05.2019 + * Time: 11:39 + */ + +@DisplayName("Класс DateUtil") +class DateUtilTest { + + private final String DATE_PATTERN = "yyyy-MM-dd"; + private final String DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss"; + private final String DATE_TIME = "2019-01-01 10:01:01"; + + @Test + @DisplayName("Перевод даты в строку, формат даты '" + DATE_PATTERN + "'") + void dateToString() { + Date date = new Date(); + + DateFormat dateFormat = new SimpleDateFormat(DATE_PATTERN); + assertEquals(dateFormat.format(date), DateUtil.dateToString(date)); + } + + @Test + @DisplayName("Перевод даты в строку, формат даты '" + DATETIME_PATTERN + "'") + void dateTimeToString() { + Date date = new Date(); + + DateFormat dateFormat = new SimpleDateFormat(DATETIME_PATTERN); + assertEquals(dateFormat.format(date), DateUtil.dateTimeToString(date)); + } + + @Test + @DisplayName("Перевод строки в дату, формат даты '" + DATETIME_PATTERN + "'") + void stringToDateTime() { + Date date = DateUtil.stringToDateTime(DATE_TIME); + DateFormat dateFormat = new SimpleDateFormat(DATETIME_PATTERN); + + assertEquals(DATE_TIME, dateFormat.format(date)); + } +} \ No newline at end of file diff --git a/src/test/java/ru/otus/mkulikov/app/service/AuthorManageSeviceImplTest.java b/src/test/java/ru/otus/mkulikov/app/service/AuthorManageSeviceImplTest.java new file mode 100644 index 0000000..818a794 --- /dev/null +++ b/src/test/java/ru/otus/mkulikov/app/service/AuthorManageSeviceImplTest.java @@ -0,0 +1,145 @@ +package ru.otus.mkulikov.app.service; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.stubbing.Answer; +import org.springframework.dao.DataIntegrityViolationException; +import ru.otus.mkulikov.app.dao.AuthorDao; +import ru.otus.mkulikov.app.model.Author; + +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.when; +import static ru.otus.mkulikov.generators.GenerateAuthor.getAuthor; +import static ru.otus.mkulikov.generators.GenerateAuthor.getAuthorList; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 30.05.2019 + * Time: 15:59 + */ + +@DisplayName("Класс AuthorManageSevice") +@ExtendWith(MockitoExtension.class) +class AuthorManageSeviceImplTest { + + private final String ID_1 = "1"; + private final String ID_2 = "2"; + + private final int OBJECT_COUNT_3 = 3; + + private final String SURNAME = "Surname1"; + private final String FIRST_NAME = "FirstName1"; + private final String SECOND_NAME = "SecondName1"; + + @Mock + private AuthorDao authorDao; + + @InjectMocks + private AuthorManageServiceImpl authorManageService; + + @Test + @DisplayName("Получение автора по id") + void getAuthorById() { + when(authorDao.findById(anyString())).thenReturn(Optional.of(getAuthor(ID_1))); + Author author = authorManageService.getAuthorById(ID_1); + + assertThat(author).isNotNull(); + assertThat(author).isEqualTo(getAuthor(ID_1)); + } + + @Test + @DisplayName("Получение всех авторов") + void getAuthors() { + when(authorDao.findAll()).thenReturn(getAuthorList()); + List authors = authorManageService.getAuthors(); + + assertThat(authors).isNotNull(); + assertThat(authors).hasSize(OBJECT_COUNT_3); + assertThat(authors).containsAll(getAuthorList()); + } + + @Test + @DisplayName("Добавление автора") + void addAuthor() { + when(authorDao.save(any(Author.class))).then(new Answer() { + @Override + public Author answer(InvocationOnMock invocationOnMock) throws Throwable { + Author author = (Author) invocationOnMock.getArgument(0); + author.setId("2"); + return author; + } + }); + when(authorDao.findById(anyString())).thenReturn(Optional.of(getAuthor(ID_2))); + + Author author1 = authorManageService.addAuthor(SURNAME, FIRST_NAME, SECOND_NAME); + Author author2 = authorManageService.getAuthorById(author1.getId()); + + assertThat(author1.getId()).isEqualTo(ID_2); + assertThat(author2).isNotNull(); + assertThat(author2).isEqualTo(getAuthor(ID_2)); + } + + @Test + @DisplayName("Обновление автора") + void updateAuthor() { + when(authorDao.save(any(Author.class))).then(new Answer() { + + @Override + public Author answer(InvocationOnMock invocationOnMock) throws Throwable { + Author author = (Author) invocationOnMock.getArgument(0); + author.setId(ID_1); + return author; + } + }); + when(authorDao.findById(anyString())).thenReturn(Optional.of(getAuthor(ID_1))); + + Author author1 = authorManageService.updateAuthor(ID_1, SURNAME, FIRST_NAME, SECOND_NAME); + Author author2 = authorManageService.getAuthorById(ID_1); + + assertThat(author1).isNotNull(); + assertThat(author2).isEqualTo(getAuthor(ID_1)); + } + + @Test + @DisplayName("Обновление автора объектом") + void updateAuthorByObject() { + when(authorDao.save(any(Author.class))).then(new Answer() { + + @Override + public Author answer(InvocationOnMock invocationOnMock) throws Throwable { + Author author = (Author) invocationOnMock.getArgument(0); + author.setId(ID_1); + return author; + } + }); + when(authorDao.findById(anyString())).thenReturn(Optional.of(getAuthor(ID_1))); + + Author author1 = authorManageService.updateAuthor(getAuthor(ID_1)); + Author author2 = authorManageService.getAuthorById(ID_1); + + assertThat(author1).isNotNull(); + assertThat(author2).isEqualTo(getAuthor(ID_1)); + } + + @Test + @DisplayName("Удаление автора, который используется в таблице книг") + void deleteAuthor() { + doThrow(DataIntegrityViolationException.class).when(authorDao).deleteById(ID_1); + assertThrows(DataIntegrityViolationException.class, () -> { + authorManageService.deleteAuthor(ID_1); + }); + } +} diff --git a/src/test/java/ru/otus/mkulikov/app/service/BookManageSeviceImplTest.java b/src/test/java/ru/otus/mkulikov/app/service/BookManageSeviceImplTest.java new file mode 100644 index 0000000..b5e416a --- /dev/null +++ b/src/test/java/ru/otus/mkulikov/app/service/BookManageSeviceImplTest.java @@ -0,0 +1,187 @@ +package ru.otus.mkulikov.app.service; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.stubbing.Answer; +import org.springframework.dao.DataIntegrityViolationException; +import ru.otus.mkulikov.app.dao.AuthorDao; +import ru.otus.mkulikov.app.dao.BookDao; +import ru.otus.mkulikov.app.dao.GenreDao; +import ru.otus.mkulikov.app.model.Book; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.when; +import static ru.otus.mkulikov.generators.GenerateAuthor.getAuthor; +import static ru.otus.mkulikov.generators.GenerateBook.getBook; +import static ru.otus.mkulikov.generators.GenerateBook.getBooksList; +import static ru.otus.mkulikov.generators.GenerateGenre.getGenre; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 29.05.2019 + * Time: 13:40 + */ + +@DisplayName("Класс BookManageSevice") +@ExtendWith(MockitoExtension.class) +class BookManageSeviceImplTest { + + private final String ID_1 = "1"; + private final String ID_2 = "2"; + + private final int OBJECT_COUNT_1 = 1; + private final int OBJECT_COUNT_3 = 3; + + private final String BOOK_NAME = "BookName"; + private final String BOOK_DESCRIPTION = "Description"; + + @Mock + private BookDao bookDao; + + @Mock + private AuthorDao authorDao; + + @Mock + private GenreDao genreDao; + + @InjectMocks + private BookManageServiceImpl booksManageSevice; + + @Test + @DisplayName("Получение книги по id") + void getBookById() { + Book book = getBook(ID_1); + when(bookDao.findById(anyString())).thenReturn(Optional.of(book)); + Book bookById = booksManageSevice.getBookById(ID_1); + + assertThat(bookById).isNotNull(); + assertThat(bookById).isEqualTo(book); + } + + @Test + @DisplayName("Получение всех книг") + void getBooks() { + List list = getBooksList(); + when(bookDao.findAll()).thenReturn(list); + List books = booksManageSevice.getBooks(); + + assertThat(books).isNotNull(); + assertThat(books).hasSize(OBJECT_COUNT_3); + assertThat(books).containsAll(list); + } + + @Test + @DisplayName("Получение книг по id автора") + void getBooksByAuthorId() { + Book book = getBook(ID_1); + + List list = new ArrayList<>(); + list.add(book); + + when(bookDao.findByAuthor_Id(anyString())).thenReturn(list); + List books = booksManageSevice.getBookByAuthorId(ID_1); + + assertThat(books).isNotNull(); + assertThat(books).hasSize(OBJECT_COUNT_1); + assertThat(books).contains(book); + } + + @Test + @DisplayName("Получение книг по id жанра") + void getBooksByGenreId() { + Book book = getBook(ID_1); + + List list = new ArrayList<>(); + list.add(book); + + when(bookDao.findByGenre_Id(anyString())).thenReturn(list); + List books = booksManageSevice.getBookByGenreId(ID_1); + + assertThat(books).isNotNull(); + assertThat(books).hasSize(OBJECT_COUNT_1); + assertThat(books).contains(book); + } + + @Test + @DisplayName("Добавление книги") + void addBook() { + when(bookDao.save(any(Book.class))).then(new Answer() { + @Override + public Book answer(InvocationOnMock invocationOnMock) throws Throwable { + Book book = (Book) invocationOnMock.getArgument(0); + book.setId("2"); + return book; + } + }); + when(authorDao.findById(anyString())).thenReturn(Optional.of(getAuthor(ID_1))); + when(genreDao.findById(anyString())).thenReturn(Optional.of(getGenre(ID_1))); + + Book book = booksManageSevice.addBook(BOOK_NAME, ID_1, ID_1, BOOK_DESCRIPTION); + + assertThat(book).isNotNull(); + assertThat(book.getId()).isEqualTo(ID_2); + } + + @Test + @DisplayName("Обновление книги") + void updateBook() { + when(bookDao.save(any(Book.class))).then(new Answer() { + + @Override + public Book answer(InvocationOnMock invocationOnMock) throws Throwable { + Book book = (Book) invocationOnMock.getArgument(0); + book.setId(ID_1); + return book; + } + }); + when(authorDao.findById(anyString())).thenReturn(Optional.of(getAuthor(ID_1))); + when(genreDao.findById(anyString())).thenReturn(Optional.of(getGenre(ID_1))); + when(bookDao.findById(anyString())).thenReturn(Optional.of(getBook(ID_1))); + + Book book = booksManageSevice.updateBook(ID_1, BOOK_NAME, ID_1, ID_1, BOOK_DESCRIPTION); + + assertThat(book).isNotNull(); + assertThat(book.getId()).isEqualTo(ID_1); + } + + @Test + @DisplayName("Обновление книги объектом") + void updateBookByObject() { + when(bookDao.save(any(Book.class))).then(new Answer() { + + @Override + public Book answer(InvocationOnMock invocationOnMock) throws Throwable { + Book book = (Book) invocationOnMock.getArgument(0); + book.setId(ID_1); + return book; + } + }); + Book book = booksManageSevice.updateBook(getBook(ID_1)); + + assertThat(book).isNotNull(); + assertThat(book.getId()).isEqualTo(ID_1); + } + + @Test + @DisplayName("Удаление книги по id") + void deleteBook() { + doThrow(DataIntegrityViolationException.class).when(bookDao).deleteById(ID_1); + assertThrows(DataIntegrityViolationException.class, () -> { + booksManageSevice.deleteBook(ID_1); + }); + } +} \ No newline at end of file diff --git a/src/test/java/ru/otus/mkulikov/app/service/CommentManageSeviceImplTest.java b/src/test/java/ru/otus/mkulikov/app/service/CommentManageSeviceImplTest.java new file mode 100644 index 0000000..e1d6775 --- /dev/null +++ b/src/test/java/ru/otus/mkulikov/app/service/CommentManageSeviceImplTest.java @@ -0,0 +1,165 @@ +package ru.otus.mkulikov.app.service; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.stubbing.Answer; +import org.springframework.dao.DataIntegrityViolationException; +import ru.otus.mkulikov.app.dao.BookDao; +import ru.otus.mkulikov.app.dao.CommentDao; +import ru.otus.mkulikov.app.model.Book; +import ru.otus.mkulikov.app.model.Comment; + +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.when; +import static ru.otus.mkulikov.generators.GenerateBook.getBook; +import static ru.otus.mkulikov.generators.GenerateComment.getComment; +import static ru.otus.mkulikov.generators.GenerateComment.getCommentList; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 30.05.2019 + * Time: 15:56 + */ + +@DisplayName("Класс CommentManageSevice") +@ExtendWith(MockitoExtension.class) +class CommentManageSeviceImplTest { + + private final String ID_1 = "1"; + private final String ID_2 = "2"; + + private final int OBJECT_COUNT_4 = 4; + + private final String COMMENT_USER_NAME = "user"; + private final String COMMENT_UPDATED_USER_NAME = "TestUser"; + private final String COMMENT_TEXT = "text"; + private final String COMMENT_UPDATED_TEXT = "TestText"; + + @Mock + private CommentDao commentDao; + + @Mock + private BookDao bookDao; + + @InjectMocks + private CommentManageServiceImpl commentManageService; + + @Test + @DisplayName("Получение комментария по id") + void getCommentById() { + Comment comment = getComment(ID_1, ID_1); + when(commentDao.findById(anyString())).thenReturn(Optional.of(comment)); + Comment commentById = commentManageService.getCommentById(ID_1); + + assertThat(commentById).isNotNull(); + assertThat(commentById).isEqualTo(comment); + } + + @Test + @DisplayName("Получение всех комментариев") + void getComments() { + List commentsList = getCommentList(); + when(commentDao.findAll()).thenReturn(commentsList); + List comments = commentManageService.getComments(); + + assertThat(comments).isNotNull(); + assertThat(comments).hasSize(OBJECT_COUNT_4); + assertThat(comments).containsAll(commentsList); + } + + @Test + @DisplayName("Добавление комментария") + void addComment() { + Book book = getBook(ID_1); + + when(commentDao.save(any(Comment.class))).then(new Answer() { + @Override + public Comment answer(InvocationOnMock invocationOnMock) throws Throwable { + Comment comment = (Comment) invocationOnMock.getArgument(0); + comment.setId("2"); + return comment; + } + }); + when(bookDao.findById(anyString())).thenReturn(Optional.of(book)); + + Comment comment = commentManageService.addComment(ID_1, COMMENT_USER_NAME, COMMENT_TEXT); + + assertThat(comment).isNotNull(); + assertThat(comment.getId()).isEqualTo(ID_2); + } + + @Test + @DisplayName("Получение комментариев по Id книги") + void getCommentsByBookId() { + List commentList = getCommentList(); + Optional book = Optional.of(getBook(ID_1)); + + when(bookDao.findById(anyString())).thenReturn(book); + when(commentDao.findByBook(book.orElse(null))).thenReturn(commentList); + + List comments = commentManageService.getCommentsByBookId(ID_1); + + assertThat(comments).isNotNull(); + assertThat(comments).isEqualTo(commentList); + } + + @Test + @DisplayName("Обновление комментария") + void updateComment() { + when(commentDao.save(any(Comment.class))).then(new Answer() { + + @Override + public Comment answer(InvocationOnMock invocationOnMock) throws Throwable { + Comment comment = (Comment) invocationOnMock.getArgument(0); + comment.setId(ID_1); + return comment; + } + }); + when(commentDao.findById(anyString())).thenReturn(Optional.of(getComment(ID_1, ID_1))); + + Comment comment = commentManageService.updateComment(ID_1, COMMENT_UPDATED_USER_NAME, COMMENT_UPDATED_TEXT); + + assertThat(comment).isNotNull(); + assertThat(comment.getId()).isEqualTo(ID_1); + } + + @Test + @DisplayName("Обновление комментария объектом") + void updateCommentByObject() { + when(commentDao.save(any(Comment.class))).then(new Answer() { + + @Override + public Comment answer(InvocationOnMock invocationOnMock) throws Throwable { + Comment comment = (Comment) invocationOnMock.getArgument(0); + comment.setId(ID_1); + return comment; + } + }); + Comment comment = commentManageService.updateComment(getComment(ID_1, ID_1)); + + assertThat(comment).isNotNull(); + assertThat(comment.getId()).isEqualTo(ID_1); + } + + @Test + @DisplayName("Удаление комментария") + void deleteComment() { + doThrow(DataIntegrityViolationException.class).when(commentDao).deleteById(ID_1); + assertThrows(DataIntegrityViolationException.class, () -> { + commentManageService.deleteComment(ID_1); + }); + } +} diff --git a/src/test/java/ru/otus/mkulikov/app/service/GenreManageSeviceImplTest.java b/src/test/java/ru/otus/mkulikov/app/service/GenreManageSeviceImplTest.java new file mode 100644 index 0000000..9a4572a --- /dev/null +++ b/src/test/java/ru/otus/mkulikov/app/service/GenreManageSeviceImplTest.java @@ -0,0 +1,138 @@ +package ru.otus.mkulikov.app.service; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.stubbing.Answer; +import org.springframework.dao.DataIntegrityViolationException; +import ru.otus.mkulikov.app.dao.GenreDao; +import ru.otus.mkulikov.app.model.Genre; + +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.when; +import static ru.otus.mkulikov.generators.GenerateGenre.getGenre; +import static ru.otus.mkulikov.generators.GenerateGenre.getGenreList; + +/** + * Created by IntelliJ IDEA. + * Developer: Maksim Kulikov + * Date: 30.05.2019 + * Time: 15:56 + */ + +@DisplayName("Класс GenreManageSevice") +@ExtendWith(MockitoExtension.class) +class GenreManageSeviceImplTest { + + private final String ID_1 = "1"; + private final String ID_2 = "2"; + + private final int OBJECT_COUNT_3 = 3; + + private final String GENRE_UPDATED_NAME = "UpdatedName"; + private final String GENRE_NAME = "GenreName"; + + @Mock + private GenreDao genreDao; + + @InjectMocks + private GenreManageServiceImpl genreManageService; + + @Test + @DisplayName("Получение жанра по id") + void getGenreById() { + when(genreDao.findById(anyString())).thenReturn(Optional.of(getGenre(ID_1))); + Genre genre = genreManageService.getGenreById(ID_1); + + assertThat(genre).isNotNull(); + assertThat(genre).isEqualTo(getGenre(ID_1)); + } + + @Test + @DisplayName("Получение всех жанров") + void getGenres() { + when(genreDao.findAll()).thenReturn(getGenreList()); + List authors = genreManageService.getGenres(); + + assertThat(authors).isNotNull(); + assertThat(authors).hasSize(OBJECT_COUNT_3); + assertThat(authors).containsAll(getGenreList()); + } + + @Test + @DisplayName("Добавление жанра") + void addGenre() { + when(genreDao.save(any(Genre.class))).then(new Answer() { + @Override + public Genre answer(InvocationOnMock invocationOnMock) throws Throwable { + Genre genre = (Genre) invocationOnMock.getArgument(0); + genre.setId(ID_2); + return genre; + } + }); + + Genre genre = genreManageService.addGenre(GENRE_NAME); + + assertThat(genre).isNotNull(); + assertThat(genre.getId()).isEqualTo(ID_2); + } + + @Test + @DisplayName("Обновление жанра") + void updateGenre() { + when(genreDao.save(any(Genre.class))).then(new Answer() { + + @Override + public Genre answer(InvocationOnMock invocationOnMock) throws Throwable { + Genre genre = (Genre) invocationOnMock.getArgument(0); + genre.setId(ID_1); + return genre; + } + }); + when(genreDao.findById(anyString())).thenReturn(Optional.of(getGenre(ID_1))); + + Genre genre = genreManageService.updateGenre(ID_1, GENRE_UPDATED_NAME); + + assertThat(genre).isNotNull(); + assertThat(genre.getId()).isEqualTo(ID_1); + } + + @Test + @DisplayName("Обновление жанра объектом") + void updateGenreByObject() { + when(genreDao.save(any(Genre.class))).then(new Answer() { + + @Override + public Genre answer(InvocationOnMock invocationOnMock) throws Throwable { + Genre genre = (Genre) invocationOnMock.getArgument(0); + genre.setId(ID_1); + return genre; + } + }); + Genre genre = genreManageService.updateGenre(getGenre(ID_1)); + + assertThat(genre).isNotNull(); + assertThat(genre.getId()).isEqualTo(ID_1); + } + + @Test + @DisplayName("Удаление жанра, который используется в таблице книг") + void deleteGenre() { + doThrow(DataIntegrityViolationException.class).when(genreDao).deleteById(ID_1); + assertThrows(DataIntegrityViolationException.class, () -> { + genreManageService.deleteGenre(ID_1); + }); + } + +} diff --git a/src/test/java/ru/otus/mkulikov/generators/GenerateAuthor.java b/src/test/java/ru/otus/mkulikov/generators/GenerateAuthor.java new file mode 100644 index 0000000..53adc55 --- /dev/null +++ b/src/test/java/ru/otus/mkulikov/generators/GenerateAuthor.java @@ -0,0 +1,29 @@ +package ru.otus.mkulikov.generators; + +import ru.otus.mkulikov.app.model.Author; + +import java.util.ArrayList; +import java.util.List; + +public class GenerateAuthor { + + private static final String ID_1 = "1"; + private static final String ID_2 = "2"; + private static final String ID_3 = "3"; + + private static final String SURNAME = "Surname"; + private static final String FIRST_NAME = "FirstName"; + private static final String SECOND_NAME = "SecondName"; + + public static List getAuthorList() { + List authors = new ArrayList(); + authors.add(getAuthor(ID_1)); + authors.add(getAuthor(ID_2)); + authors.add(getAuthor(ID_3)); + return authors; + } + + public static Author getAuthor(String id) { + return new Author(id, SURNAME + id, FIRST_NAME + id, SECOND_NAME + id); + } +} diff --git a/src/test/java/ru/otus/mkulikov/generators/GenerateBook.java b/src/test/java/ru/otus/mkulikov/generators/GenerateBook.java new file mode 100644 index 0000000..6e56762 --- /dev/null +++ b/src/test/java/ru/otus/mkulikov/generators/GenerateBook.java @@ -0,0 +1,40 @@ +package ru.otus.mkulikov.generators; + +import ru.otus.mkulikov.app.model.Author; +import ru.otus.mkulikov.app.model.Book; +import ru.otus.mkulikov.app.model.Genre; +import ru.otus.mkulikov.app.utils.DateUtil; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import static ru.otus.mkulikov.generators.GenerateAuthor.getAuthor; +import static ru.otus.mkulikov.generators.GenerateGenre.getGenre; + +public class GenerateBook { + + private static final String ID_1 = "1"; + private static final String ID_2 = "2"; + private static final String ID_3 = "3"; + + private static final String DATE_TIME = "2019-01-01 10:01:01"; + + private static final String BOOK_NAME = "BookName"; + private static final String BOOK_DESCRIPTION = "Description"; + + public static Book getBook(String id) { + Author author = getAuthor(id); + Genre genre = getGenre(id); + Date date = DateUtil.stringToDateTime(DATE_TIME); + return new Book(id, date, BOOK_NAME, author, genre, BOOK_DESCRIPTION); + } + + public static List getBooksList() { + List list = new ArrayList<>(); + list.add(getBook(ID_1)); + list.add(getBook(ID_2)); + list.add(getBook(ID_3)); + return list; + } +} diff --git a/src/test/java/ru/otus/mkulikov/generators/GenerateComment.java b/src/test/java/ru/otus/mkulikov/generators/GenerateComment.java new file mode 100644 index 0000000..960b0d0 --- /dev/null +++ b/src/test/java/ru/otus/mkulikov/generators/GenerateComment.java @@ -0,0 +1,46 @@ +package ru.otus.mkulikov.generators; + +import ru.otus.mkulikov.app.model.Book; +import ru.otus.mkulikov.app.model.Comment; +import ru.otus.mkulikov.app.utils.DateUtil; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import static ru.otus.mkulikov.generators.GenerateBook.getBook; + +public class GenerateComment { + + private static final String ID_1 = "1"; + private static final String ID_2 = "2"; + private static final String ID_3 = "3"; + private static final String ID_4 = "4"; + + private static final String DATE_TIME = "2019-01-01 10:01:01"; + + private static final String COMMENT_USER_NAME = "user"; + private static final String COMMENT_TEXT = "text"; + + public static Comment getComment(String id, String bookId) { + Date date = DateUtil.stringToDateTime(DATE_TIME); + Book book = getBook(bookId); + return new Comment(id, book, date, COMMENT_USER_NAME + id, COMMENT_TEXT + id); + } + + public static List getCommentList() { + List comments = new ArrayList(); + comments.add(getComment(ID_1, ID_1)); + comments.add(getComment(ID_2, ID_1)); + comments.add(getComment(ID_3, ID_2)); + comments.add(getComment(ID_4, ID_2)); + return comments; + } + + public static List getCommentList(String bookId) { + List comments = new ArrayList(); + comments.add(getComment(ID_1, bookId)); + comments.add(getComment(ID_2, bookId)); + return comments; + } +} diff --git a/src/test/java/ru/otus/mkulikov/generators/GenerateGenre.java b/src/test/java/ru/otus/mkulikov/generators/GenerateGenre.java new file mode 100644 index 0000000..fb929cc --- /dev/null +++ b/src/test/java/ru/otus/mkulikov/generators/GenerateGenre.java @@ -0,0 +1,27 @@ +package ru.otus.mkulikov.generators; + +import ru.otus.mkulikov.app.model.Genre; + +import java.util.ArrayList; +import java.util.List; + +public class GenerateGenre { + + private static final String ID_1 = "1"; + private static final String ID_2 = "2"; + private static final String ID_3 = "3"; + + private static final String GENRE_NAME = "GenreName"; + + public static List getGenreList() { + List genres = new ArrayList(); + genres.add(getGenre(ID_1)); + genres.add(getGenre(ID_2)); + genres.add(getGenre(ID_3)); + return genres; + } + + public static Genre getGenre(String id) { + return new Genre(id, GENRE_NAME + id); + } +} diff --git a/src/test/java/ru/otus/mkulikov/rest/AuthorControllerTest.java b/src/test/java/ru/otus/mkulikov/rest/AuthorControllerTest.java new file mode 100644 index 0000000..d81fa6c --- /dev/null +++ b/src/test/java/ru/otus/mkulikov/rest/AuthorControllerTest.java @@ -0,0 +1,92 @@ +package ru.otus.mkulikov.rest; + +import org.junit.Test; +import org.junit.jupiter.api.DisplayName; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import ru.otus.mkulikov.app.model.Author; +import ru.otus.mkulikov.app.service.AuthorManageService; +import ru.otus.mkulikov.app.service.BookManageService; + +import static org.hamcrest.Matchers.containsString; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import static ru.otus.mkulikov.generators.GenerateAuthor.getAuthor; +import static ru.otus.mkulikov.generators.GenerateAuthor.getAuthorList; +import static ru.otus.mkulikov.generators.GenerateBook.getBooksList; + +@RunWith(SpringRunner.class) +@DisplayName("Класс rest-контроллеров для автора") +@WebMvcTest(AuthorController.class) +public class AuthorControllerTest { + + @MockBean + private AuthorManageService authorManageService; + @MockBean + private BookManageService bookManageService; + + @Autowired + private MockMvc mockMvc; + + @Test + @DisplayName("Получение всех авторов") + public void getAll() throws Exception { + when(authorManageService.getAuthors()).thenReturn(getAuthorList()); + + this.mockMvc.perform(get("/author/list")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(content().string(containsString("Authors:"))); + } + + @Test + @DisplayName("Получение автора по id") + public void getAuthorById() throws Exception { + when(authorManageService.getAuthorById(anyString())).thenReturn(getAuthor("1")); + + this.mockMvc.perform(get("/author").param("id", "1")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(content().string(containsString("Author detail:"))); + } + + @Test + @DisplayName("Добавление автора") + public void addAuthor() throws Exception { + when(authorManageService.addAuthor(anyString(), anyString(), anyString())).thenReturn(getAuthor("1")); + + this.mockMvc.perform(get("/author/new")) + .andDo(print()) + .andExpect(redirectedUrl("/author?id=1")); + } + + @Test + @DisplayName("Изменение автора") + public void edit() throws Exception { + when(authorManageService.updateAuthor(any(Author.class))).thenReturn(getAuthor("1")); + + this.mockMvc.perform(post("/author/edit").requestAttr("Author", getAuthor("1"))) + .andDo(print()) + .andExpect(redirectedUrl("/author/list")); + } + + @Test + @DisplayName("Удаление автора") + public void delete() throws Exception { + when(bookManageService.getBookByAuthorId(anyString())).thenReturn(getBooksList()); + when(authorManageService.deleteAuthor(anyString())).thenReturn(1); + + this.mockMvc.perform(post("/author/delete").param("id", "1")) + .andDo(print()) + .andExpect(redirectedUrl("/author/list")); + } +} diff --git a/src/test/java/ru/otus/mkulikov/rest/BookControllerTest.java b/src/test/java/ru/otus/mkulikov/rest/BookControllerTest.java new file mode 100644 index 0000000..598bd55 --- /dev/null +++ b/src/test/java/ru/otus/mkulikov/rest/BookControllerTest.java @@ -0,0 +1,103 @@ +package ru.otus.mkulikov.rest; + +import org.junit.Test; +import org.junit.jupiter.api.DisplayName; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import ru.otus.mkulikov.app.model.Book; +import ru.otus.mkulikov.app.service.AuthorManageService; +import ru.otus.mkulikov.app.service.BookManageService; +import ru.otus.mkulikov.app.service.CommentManageService; +import ru.otus.mkulikov.app.service.GenreManageService; + +import static org.hamcrest.Matchers.containsString; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import static ru.otus.mkulikov.generators.GenerateAuthor.getAuthorList; +import static ru.otus.mkulikov.generators.GenerateBook.getBook; +import static ru.otus.mkulikov.generators.GenerateComment.getCommentList; +import static ru.otus.mkulikov.generators.GenerateGenre.getGenreList; + +@RunWith(SpringRunner.class) +@DisplayName("Класс rest-контроллеров для книг") +@WebMvcTest(BookController.class) +public class BookControllerTest { + + @MockBean + private BookManageService bookManageService; + @MockBean + private AuthorManageService authorManageService; + @MockBean + private GenreManageService genreManageService; + @MockBean + private CommentManageService commentManageService; + + @Autowired + private MockMvc mockMvc; + + @Test + @DisplayName("Получение всех книг") + public void getAll() throws Exception { + this.mockMvc.perform(get("/book/list")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(content().string(containsString("Books:"))); + } + + @Test + @DisplayName("Получение книги по id") + public void getById() throws Exception { + when(bookManageService.getBookById(anyString())).thenReturn(getBook("1")); + when(authorManageService.getAuthors()).thenReturn(getAuthorList()); + when(genreManageService.getGenres()).thenReturn(getGenreList()); + + this.mockMvc.perform(get("/book").param("id", "1")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(content().string(containsString("Book detail:"))); + } + + @Test + @DisplayName("Добавление книги") + public void addBook() throws Exception { + when(bookManageService.addBook(anyString(), anyString(), anyString(), anyString())).thenReturn(getBook("1")); + when(authorManageService.getAuthors()).thenReturn(getAuthorList()); + when(genreManageService.getGenres()).thenReturn(getGenreList()); + + this.mockMvc.perform(get("/book/new")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(content().string(containsString("Book detail:"))); + } + + @Test + @DisplayName("Изменение книги") + public void edit() throws Exception { + when(bookManageService.updateBook(any(Book.class))).thenReturn(getBook("1")); + + this.mockMvc.perform(post("/book/edit").requestAttr("Book", getBook("1"))) + .andDo(print()) + .andExpect(redirectedUrl("/book/list")); + } + + @Test + @DisplayName("Удаление книги") + public void delete() throws Exception { + when(commentManageService.getCommentsByBookId(anyString())).thenReturn(getCommentList("1")); + when(commentManageService.deleteComments(getCommentList())).thenReturn(1); + when(bookManageService.deleteBook(anyString())).thenReturn(1); + + this.mockMvc.perform(post("/book/delete").param("id", "1")) + .andDo(print()) + .andExpect(redirectedUrl("/book/list")); + } +} diff --git a/src/test/java/ru/otus/mkulikov/rest/CommentControllerTest.java b/src/test/java/ru/otus/mkulikov/rest/CommentControllerTest.java new file mode 100644 index 0000000..6e0c084 --- /dev/null +++ b/src/test/java/ru/otus/mkulikov/rest/CommentControllerTest.java @@ -0,0 +1,91 @@ +package ru.otus.mkulikov.rest; + +import org.junit.Test; +import org.junit.jupiter.api.DisplayName; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import ru.otus.mkulikov.app.model.Comment; +import ru.otus.mkulikov.app.service.BookManageService; +import ru.otus.mkulikov.app.service.CommentManageService; + +import static org.hamcrest.Matchers.containsString; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import static ru.otus.mkulikov.generators.GenerateBook.getBooksList; +import static ru.otus.mkulikov.generators.GenerateComment.getComment; + +@RunWith(SpringRunner.class) +@DisplayName("Класс rest-контроллеров для комментариев") +@WebMvcTest(CommentController.class) +public class CommentControllerTest { + + @MockBean + private BookManageService bookManageService; + @MockBean + private CommentManageService commentManageService; + + @Autowired + private MockMvc mockMvc; + + @Test + @DisplayName("Получение всех комментариев") + public void getAll() throws Exception { + this.mockMvc.perform(get("/comment/list")).andDo(print()) + .andExpect(status().isOk()) + .andExpect(content().string(containsString("Comments:"))); + } + + @Test + @DisplayName("Получение комментария по id") + public void getById() throws Exception { + when(commentManageService.getCommentById(anyString())).thenReturn(getComment("1", "1")); + when(bookManageService.getBooks()).thenReturn(getBooksList()); + + this.mockMvc.perform(get("/comment").param("id", "1")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(content().string(containsString("Comment detail:"))); + } + + @Test + @DisplayName("Изменение комментария") + public void edit() throws Exception { + when(bookManageService.getBooks()).thenReturn(getBooksList()); + when(commentManageService.updateComment(any(Comment.class))).thenReturn(getComment("1", "1")); + + this.mockMvc.perform(post("/comment/edit").requestAttr("Comment", getComment("1", "1"))) + .andDo(print()) + .andExpect(redirectedUrl("/comment/list")); + } + + @Test + @DisplayName("Добавление комментария") + public void addComment() throws Exception { + when(bookManageService.getBooks()).thenReturn(getBooksList()); + when(commentManageService.addComment(anyString(), anyString(), anyString())).thenReturn(getComment("1", "1")); + + this.mockMvc.perform(get("/comment/new")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(content().string(containsString("Comment detail:"))); + } + + @Test + @DisplayName("Удаление комментария") + public void delete() throws Exception { + when(commentManageService.deleteComment(anyString())).thenReturn(1); + + this.mockMvc.perform(post("/comment/delete").param("id", "1")) + .andDo(print()) + .andExpect(redirectedUrl("/comment/list")); + } +} diff --git a/src/test/java/ru/otus/mkulikov/rest/GenreControllerTest.java b/src/test/java/ru/otus/mkulikov/rest/GenreControllerTest.java new file mode 100644 index 0000000..31e3f84 --- /dev/null +++ b/src/test/java/ru/otus/mkulikov/rest/GenreControllerTest.java @@ -0,0 +1,86 @@ +package ru.otus.mkulikov.rest; + +import org.junit.Test; +import org.junit.jupiter.api.DisplayName; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import ru.otus.mkulikov.app.model.Genre; +import ru.otus.mkulikov.app.service.BookManageService; +import ru.otus.mkulikov.app.service.GenreManageService; + +import static org.hamcrest.Matchers.containsString; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import static ru.otus.mkulikov.generators.GenerateGenre.getGenre; + +@RunWith(SpringRunner.class) +@DisplayName("Класс rest-контроллеров для жанров") +@WebMvcTest(GenreController.class) +public class GenreControllerTest { + + @MockBean + private BookManageService bookManageService; + @MockBean + private GenreManageService genreManageService; + + @Autowired + private MockMvc mockMvc; + + @Test + @DisplayName("Получение всех жанров") + public void getAll() throws Exception { + this.mockMvc.perform(get("/genre/list")).andDo(print()) + .andExpect(status().isOk()) + .andExpect(content().string(containsString("Genres:"))); + } + + @Test + @DisplayName("Получение жанра по id") + public void getById() throws Exception { + when(genreManageService.getGenreById(anyString())).thenReturn(getGenre("1")); + + this.mockMvc.perform(get("/genre").param("id", "1")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(content().string(containsString("Genre detail:"))); + } + + @Test + @DisplayName("Добавление жанра") + public void addGenre() throws Exception { + when(genreManageService.addGenre(anyString())).thenReturn(getGenre("1")); + + this.mockMvc.perform(get("/genre/new")) + .andDo(print()) + .andExpect(redirectedUrl("/genre?id=1")); + } + + @Test + @DisplayName("Изменение жанра") + public void edit() throws Exception { + when(genreManageService.updateGenre(any(Genre.class))).thenReturn(getGenre("1")); + + this.mockMvc.perform(post("/genre/edit").requestAttr("Genre", getGenre("1"))) + .andDo(print()) + .andExpect(redirectedUrl("/genre/list")); + } + + @Test + @DisplayName("Удаление жанра") + public void delete() throws Exception { + when(genreManageService.deleteGenre(anyString())).thenReturn(1); + + this.mockMvc.perform(post("/genre/delete").param("id", "1")) + .andDo(print()) + .andExpect(redirectedUrl("/genre/list")); + } +} diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml new file mode 100644 index 0000000..a47425c --- /dev/null +++ b/src/test/resources/application.yml @@ -0,0 +1,4 @@ +spring: + banner: + location: "classpath:banner.txt" + diff --git a/src/test/resources/banner-test.txt b/src/test/resources/banner-test.txt new file mode 100644 index 0000000..50a692c --- /dev/null +++ b/src/test/resources/banner-test.txt @@ -0,0 +1,11 @@ + ___ ___ ___ ___ ___ ___ ___ + /\__\ /\ \ /\__\ /\ \ /\ \ ___ / /\ / /\ ___ + /:/ / /::\ \ /:/ / /::\ \ /::\ \ /__/\ / /::\ / /::\ /__/\ + /:/ / /:/\:\ \ /:/ / /:/\:\ \ /:/\ \ \ \ \:\ / /:/\:\ /__/:/\:\ \ \:\ + /:/ / ___ /:/ \:\ \ /:/ / /::\~\:\ \ _\:\~\ \ \ \__\:\ / /::\ \:\ _\_ \:\ \:\ \__\:\ + /:/__/ /\__\ /:/__/ \:\__\ /:/__/ /:/\:\ \:\__\ /\ \:\ \ \__\ *** / /::\ /__/:/\:\ \:\ /__/\ \:\ \:\ / /::\ + \:\ \ /:/ / \:\ \ /:/ / \:\ \ \:\~\:\ \/__/ \:\ \:\ \/__/ / /:/\:\ \ \:\ \:\_\/ \ \:\ \:\_\/ / /:/\:\ + \:\ /:/ / \:\ /:/ / \:\ \ \:\ \:\__\ \:\ \:\__\ / /:/__\/ \ \:\ \:\ \ \:\_\:\ / /:/__\/ + \:\/:/ / \:\/:/ / \:\ \ \:\ \/__/ \:\/:/ / /__/:/ \ \:\_\/ \ \:\/:/ /__/:/ + \::/ / \::/ / \:\__\ \:\__\ \::/ / \__\/ \ \:\ \ \::/ \__\/ + \/__/ \/__/ \/__/ \/__/ \/__/ \__\/ \__\/