booksAsAuthor;
+
+ public UserResponse(User user) {
+ this.userId = user.getId();
+ username = user.getUsername();
+ about = user.getAbout();
+ information = user.getInformation();
+ booksAsSubAuthor = user.getBooksAsSubAuthor().stream().map(BookResponse::new).collect(Collectors.toSet());
+ booksAsAuthor = user.getBooksAsAuthor().stream().map(BookResponse::new).collect(Collectors.toSet());
+ addSelfLink(userId);
+ }
+
+ private void addSelfLink(Long id) {
+ add(linkTo(methodOn(UserController.class, id).getUserById(id)).withSelfRel());
+ }
+}
diff --git a/src/main/resources/application-db-mysql.yml b/src/main/resources/application-db-mysql.yml
new file mode 100644
index 0000000..c27a72f
--- /dev/null
+++ b/src/main/resources/application-db-mysql.yml
@@ -0,0 +1,17 @@
+spring:
+ datasource:
+ url: jdbc:mysql://localhost:3306/ficwriter
+ username: dl
+ password: p@ssword
+ initialization-mode: always
+
+ jpa:
+ hibernate:
+ ddl-auto: create-drop
+ properties:
+ hibernate:
+ dialect: org.hibernate.dialect.MySQL5InnoDBDialect
+ hbm2ddl:
+ import_files_sql_extractor: org.hibernate.tool.hbm2ddl.MultipleLinesSqlCommandExtractor
+ import_files: data/user.sql, data/actor.sql, data/book.sql, data/article.sql,data/book_article.sql, data/actor_state.sql
+
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
new file mode 100644
index 0000000..596c249
--- /dev/null
+++ b/src/main/resources/application.yml
@@ -0,0 +1,9 @@
+spring:
+ profiles:
+ active: db-mysql
+logging:
+ level:
+ org:
+ springframework: INFO
+server:
+ port: 8080
\ No newline at end of file
diff --git a/src/main/resources/data/actor.sql b/src/main/resources/data/actor.sql
new file mode 100644
index 0000000..bb9597c
--- /dev/null
+++ b/src/main/resources/data/actor.sql
@@ -0,0 +1,10 @@
+INSERT INTO actor(id,description,name)VALUES(1,'description1','name1');
+INSERT INTO actor(id,description,name)VALUES(2,'description2','name2');
+INSERT INTO actor(id,description,name)VALUES(3,'description3','name3');
+INSERT INTO actor(id,description,name)VALUES(987,'description','name');
+INSERT INTO actor(id,description,name)VALUES(333,'description','name');
+INSERT INTO actor(id,description,name)VALUES(334,'description','name');
+
+
+
+
diff --git a/src/main/resources/data/actor_state.sql b/src/main/resources/data/actor_state.sql
new file mode 100644
index 0000000..6e99aca
--- /dev/null
+++ b/src/main/resources/data/actor_state.sql
@@ -0,0 +1,7 @@
+INSERT INTO actor_state(content,title,actor_id,article_id)VALUES('content1','title1',1,1);
+INSERT INTO actor_state(content,title,actor_id,article_id)VALUES('content2','title2',1,2);
+INSERT INTO actor_state(content,title,actor_id,article_id)VALUES('content3','title3',2,1);
+INSERT INTO actor_state(content,title,actor_id,article_id)VALUES('content4','title4',2,2);
+
+INSERT INTO actor_state(content,title,actor_id,article_id)VALUES('content4','title4',333,3);
+INSERT INTO actor_state(content,title,actor_id,article_id)VALUES('content4','title4',334,3);
\ No newline at end of file
diff --git a/src/main/resources/data/article.sql b/src/main/resources/data/article.sql
new file mode 100644
index 0000000..1572fba
--- /dev/null
+++ b/src/main/resources/data/article.sql
@@ -0,0 +1,146 @@
+INSERT INTO article(id,annotation,content,title,book_id)VALUES(1,'Place for annotation','Place for content.
','Summer inspiration',1);
+INSERT INTO article(id,annotation,content,title)VALUES(2,'annotation2','content2','title2');
+INSERT INTO article(id,annotation,content,title)VALUES(3,'annotation','content','title');
+INSERT INTO article(id,annotation,content,title)VALUES(4,'annotation','content','title');
+INSERT INTO article(id,annotation,content,title)VALUES(333,'annotation','content','delete article');
+
+INSERT INTO article(id,book_id,annotation,title,content)VALUES(335,1,'','Зимняя поэма',
+'
Измеряются грустью и чашками чая
+Безымянные, кроткие, зимние дни.
+Проживаешь мгновения, не замечая,
+Как бесследно теряются в прошлом они.
+
+Покрывает надежды обманчивый иней,
+Запотевшая память подобна окну.
+Растворяется контур реальности синей:
+Над экраном холодным и ясным усну.
+
+Утомлен безучастностью, сентиментален,
+Погружаюсь, запутавшись, в тихую тьму.
+А приснятся весенние язвы проталин
+И снега, равнодушны к концу своему.
+
+И покажется, будто неловко ступаю
+По сулящему гибель лукавому льду,
+Приближаюсь безвольно к незримому краю,
+Безучастно забвения смертного жду.
+
+Обреченность души молодой беспричинна,
+И мечты, и стремления сердца смешны.
+Неизбежно и близко маячит кончина,
+Обещая обители вечной весны.
+
+А былого сомнения ныне убоги,
+Поглотила пучина загробной реки;
+Мысли канули в тени последней дороги.
+Берега колдовской глубины далеки.
+
+Не внимая молитвам, судьба непреклонна,
+И слова, и молчание тщетны, пусты,
+Но зовут перезвоны миров Авалона
+Сквозь слепую завесу могильной черты.
+
+Промелькнуло знамение в зыби туманной,
+Воплощение обетованной земли.
+Кровоточит сознание призрачной раной.
+Рассеченную веру, Харон, исцели!
+
+На морозе растрескалась черная лодка,
+Перевозчик не тронет стремнину веслом.
+Изменилась от боли и страха походка:
+Не устанешь терзаться, скорбеть о былом.
+
+Разрывается грудь от печали железной,
+Утянуло уныние душу на дно.
+Беспредельная пропасть зияющей бездной
+Констатирует факт: умереть суждено.
+
+Принимаю жестокую истину эту.
+Под ногами ни твердь, но крошащийся наст.
+Пересечь пожелавший замерзшую Лету
+Неизбежно бесценное стражу отдаст.
+
+Проседает поверхность, ломаясь и тая,
+Увлекаясь течением мертвой воды,
+И тасует агония льды, как живая,
+И надежды безлики и сердцу чужды.
+
+На сминаемой глади нельзя схорониться,
+Настигает невидимый ужас. Фантом
+Беспощаден. Аида владений граница
+Искаверкала личность в тумане густом.
+
+Просыпаюсь, но кровь под висками грохочет,
+Что увидел в зловещем, пророческом сне.
+И дрожу, возвратившийся первопроходчик,
+Почему темнота ухмыляется мне?
+
+Поднимусь, в запыленное зеркало гляну,
+Не поверю, что нет в волосах седины.
+Удивленный открытому в духе изъяну,
+Осознаю, подобные обречены.
+
+Не бывает беспечна дорога поэта,
+И печаль неотступная бдит за спиной.
+Угнетает суровая истина эта.
+Почему безучастность любезна со мной?
+
+Очарован иллюзией, горечью болен,
+За словами под землю бреду в глубину.
+В лабиринтах блуждаю заброшенных штолен
+И ищу драгоценную правду одну.
+
+И в прорубленных поиском чьим-то пещерах
+Затеряюсь: обманка, сомнения, ложь.
+А в рассветных, неискренних сумерках серых
+На умершего в зеркале старом похож.
+
+Бесполезен желанием я. Одноразов
+И порыв, и поэзии выкрик немой.
+Принимаю стекляшки за груды алмазов.
+Одиссей никогда не вернется домой.
+
+Помню Данте и вечный огонь Одиссею,
+И правдивый, бесплотный, печальный язык.
+Опереться на слабую веру не смею,
+К безысходности мрачной за годы привык.
+
+Не боюсь очевидной угрозы обвала,
+Не боюсь нависающей тяжести гор.
+Равнодушная память, чадя, истлевала.
+Неужели конец однозначен и скор?
+
+Умываюсь, покинув недвижность постели,
+Отвечает насмешкой безмолвие глаз.
+А секунды, минуты, недели летели.
+Поклянусь измениться единственный раз.
+
+И слезами обет приношу перед Богом,
+Не терять ни мгновения, миг не терять.
+На пути разрушения скользком, пологом
+Не могу, покатившись, подняться опять.
+
+Поклонюсь утешающим, строгим иконам,
+И молитва развеет гнетущую тьму.
+И прощенный, служивший делам беззаконным,
+Не надеюсь тщеславно спастись самому.
+
+На восходе сугроб переливчат и розов,
+И затейлив узор приукрасил окно.
+Неужели с уходом кристальных морозов
+Полотно белотканное обречено?
+
+Опалив чистоту, молодое светило
+Прожигает сияющий кров белизны,
+А снежинки в бесплодную грязь превратило.
+Обтекают деревья угрюмы, темны.
+
+Почему разрушения ярость воспета?
+Сожаления вязки, сугубы, остры.
+Разлилась половодьем забвения Лета,
+Разделяя потоком зеркальным миры.
+
+А тлетворная оттепель жизни хлопочет,
+Умирает в смирении зимний покой.
+Вырываются листья из лопнувших почек,
+И весна торжествует в капели слепой.
');
\ No newline at end of file
diff --git a/src/main/resources/data/book.sql b/src/main/resources/data/book.sql
new file mode 100644
index 0000000..49fd526
--- /dev/null
+++ b/src/main/resources/data/book.sql
@@ -0,0 +1,11 @@
+INSERT INTO book(id,title,description, size, state,author_id)VALUES(1,'Arabella','Artic monkeys', 1,2,1);
+INSERT INTO user_books_as_author (user_id,books_as_author_id)VALUES(1,1);
+INSERT INTO book_subauthors (user_id,book_id)VALUES(2,1);
+INSERT INTO book(title,description, size, state)VALUES('Old yellow bricks','Artic monkeys', 1,2);
+INSERT INTO book(title,description, size, state)VALUES('End of me','Apocalyptica', 0,1);
+INSERT INTO book(title,description, size, state)VALUES('Отблеск разочарований','Безнадежности печать...', 0,1);
+
+
+
+
+
diff --git a/src/main/resources/data/book_article.sql b/src/main/resources/data/book_article.sql
new file mode 100644
index 0000000..1c61683
--- /dev/null
+++ b/src/main/resources/data/book_article.sql
@@ -0,0 +1,2 @@
+INSERT INTO book_articles(book_id,articles_id)VALUES(1,335);
+INSERT INTO book_articles(book_id,articles_id)VALUES(1,1);
\ No newline at end of file
diff --git a/src/main/resources/data/user.sql b/src/main/resources/data/user.sql
new file mode 100644
index 0000000..deb354d
--- /dev/null
+++ b/src/main/resources/data/user.sql
@@ -0,0 +1,2 @@
+INSERT INTO user(id,about, information, username)VALUES(1,'I am author',' zaraza-takaja@mail.ru','Zaraza takaja');
+INSERT INTO user(id,about, information, username)VALUES(2,'I am author, too',' zaraza-takaja@mail.ru','@uthor');
\ No newline at end of file
diff --git a/src/test/java/fic/writer/domain/service/ActorAndActorStateServicesTest.java b/src/test/java/fic/writer/domain/service/ActorAndActorStateServicesTest.java
new file mode 100644
index 0000000..4c36603
--- /dev/null
+++ b/src/test/java/fic/writer/domain/service/ActorAndActorStateServicesTest.java
@@ -0,0 +1,105 @@
+package fic.writer.domain.service;
+
+import fic.writer.domain.entity.Actor;
+import fic.writer.domain.entity.ActorState;
+import fic.writer.domain.entity.ActorStateId;
+import fic.writer.domain.entity.Article;
+import fic.writer.domain.entity.dto.ActorDto;
+import org.hibernate.Session;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.persistence.EntityManager;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+@Transactional
+public class ActorAndActorStateServicesTest {
+ @Autowired
+ private ActorService actorService;
+ @Autowired
+ private ActorStateService actorStateService;
+ @Autowired
+ private EntityManager entityManager;
+
+ @Test
+ public void updateActorWithActorStates_whenCorrect_shouldUpdateInActorState() {
+ final Long ACTOR_ID = 333L;
+ final Long ARTICLE_ID = 3L;
+ final String NEW_ACTOR_NAME = "new name";
+ Actor actor = actorService.findById(ACTOR_ID).get();
+ ActorStateId actorStateId = ActorStateId.builder()
+ .actorId(ACTOR_ID)
+ .articleId(ARTICLE_ID)
+ .build();
+ actor.setName(NEW_ACTOR_NAME);
+ actorService.update(ACTOR_ID, ActorDto.of(actor));
+
+ ActorState actorState = actorStateService.findById(actorStateId).get();
+
+ assertEquals(NEW_ACTOR_NAME, actorState.getActor().getName());
+ }
+
+ private Session getSession() {
+ return entityManager.unwrap(Session.class);
+ }
+
+ @Test
+ public void deleteActorState_whenCorrect_shouldCleanInActor() {
+ final Long ACTOR_ID = 333L;
+ final Long ARTICLE_ID = 3L;
+ Session session = getSession();
+ ActorStateId actorStateId = ActorStateId.builder()
+ .actorId(ACTOR_ID)
+ .articleId(ARTICLE_ID)
+ .build();
+
+ actorStateService.deleteById(actorStateId);
+ session.flush();
+ Actor actor = actorService.findById(ACTOR_ID).get();
+
+ Boolean isStateInActor = actor.getActorStates().stream().anyMatch(as -> as.getId().equals(actorStateId));
+ assertFalse(isStateInActor);
+ }
+
+
+ @Test
+ public void deleteActor_whenCorrect_shouldCleanActorStates() {
+ final Long ACTOR_ID = 334L;
+
+ Actor actor = actorService.findById(ACTOR_ID).get();
+
+ actorService.deleteById(ACTOR_ID);
+
+ assertFalse(actorStateService.findAll().stream().anyMatch(as -> as.getActor().equals(actor)));
+ }
+
+ @Test
+ public void createActorState_whenCorrect_shouldCascadeAddInActor() {
+ final Long ACTOR_ID = 333L;
+ final Long ARTICLE_ID = 1L;
+ final int EXPECTED_SIZE = 2;
+ Article article = Article.builder().id(ARTICLE_ID).build();
+ Actor actor = actorService.findById(ACTOR_ID).get();
+ ActorState actorState = ActorState.builder()
+ .id(ActorStateId.builder().actorId(ACTOR_ID).articleId(ARTICLE_ID).build())
+ .actor(actor)
+ .article(article)
+ .title("title")
+ .build();
+ Set actorStates = actor.getActorStates();
+ actorStates.add(actorState);
+ actor.setActorStates(actorStates);
+ actorService.update(ACTOR_ID, ActorDto.of(actor));
+ int changedSize = actorService.findById(ACTOR_ID).get().getActorStates().size();
+ assertEquals(EXPECTED_SIZE, changedSize);
+ }
+}
diff --git a/src/test/java/fic/writer/domain/service/ActorServiceTest.java b/src/test/java/fic/writer/domain/service/ActorServiceTest.java
new file mode 100644
index 0000000..85f6754
--- /dev/null
+++ b/src/test/java/fic/writer/domain/service/ActorServiceTest.java
@@ -0,0 +1,59 @@
+package fic.writer.domain.service;
+
+import fic.writer.domain.entity.Actor;
+import fic.writer.domain.entity.dto.ActorDto;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.dao.EmptyResultDataAccessException;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Optional;
+
+import static org.junit.Assert.*;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+@Transactional
+public class ActorServiceTest {
+ @Autowired
+ private ActorService actorService;
+
+ @Test
+ public void createActor_whenCorrect_shouldFindWithId() {
+ Actor actor = Actor.builder().build();
+ actor = actorService.create(ActorDto.of(actor));
+
+ assertTrue(actorService.findById(actor.getId()).isPresent());
+ }
+
+ @Test
+ public void createActor_whenIdExists_shouldFindUpdate() {
+ final Long ACTOR_ID = 1L;
+ final String NEW_NAME = "new name";
+ actorService.update(ACTOR_ID, ActorDto.builder().name(NEW_NAME).build());
+ Optional updatedActor = actorService.findById(ACTOR_ID);
+ assertTrue(updatedActor.isPresent());
+ assertEquals(NEW_NAME, updatedActor.get().getName());
+ }
+
+ @Test
+ public void deleteActor_whenExists_shouldNotFound() {
+ final Long AUTHOR_ID = 987L;
+ assertTrue(actorService.findById(AUTHOR_ID).isPresent());
+ actorService.deleteById(AUTHOR_ID);
+ assertFalse(actorService.findById(AUTHOR_ID).isPresent());
+ }
+
+ @Test(expected = EmptyResultDataAccessException.class)
+ public void deleteActor_whenNotExists_shouldThrowException() {
+ final Long AUTHOR_ID = -1L;
+
+ assertFalse(actorService.findById(AUTHOR_ID).isPresent());
+ actorService.deleteById(AUTHOR_ID);
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/test/java/fic/writer/domain/service/ActorStateServiceTest.java b/src/test/java/fic/writer/domain/service/ActorStateServiceTest.java
new file mode 100644
index 0000000..419ba1a
--- /dev/null
+++ b/src/test/java/fic/writer/domain/service/ActorStateServiceTest.java
@@ -0,0 +1,125 @@
+package fic.writer.domain.service;
+
+import fic.writer.domain.entity.Actor;
+import fic.writer.domain.entity.ActorState;
+import fic.writer.domain.entity.ActorStateId;
+import fic.writer.domain.entity.Article;
+import fic.writer.domain.entity.dto.ActorDto;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.dao.EmptyResultDataAccessException;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Optional;
+
+import static org.junit.Assert.*;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+@Transactional
+public class ActorStateServiceTest {
+ @Autowired
+ private ActorStateService actorStateService;
+ @Autowired
+ private ActorService actorService;
+
+ @Test
+ public void createActorState_whenCorrect_shouldFindWithId() {
+ final Long ARTICLE_ID = 3L;
+ final Long ACTOR_ID = 3L;
+ Actor actor = actorService.findById(ACTOR_ID).get();
+ ActorState actorState = buildActorState(actor, ARTICLE_ID);
+ actor.getActorStates().add(actorState);
+
+ actor = actorService.update(ACTOR_ID, ActorDto.of(actor));
+ assertTrue(actorStateService.findById(actorState.getId()).isPresent());
+ }
+
+ private ActorState buildActorState(Actor actor, Long articleId) {
+ Article article = Article.builder().id(articleId).build();
+ ActorStateId actorStateId = ActorStateId.builder().articleId(articleId).actorId(actor.getId()).build();
+ return ActorState.builder()
+ .id(actorStateId)
+ .actor(actor)
+ .article(article)
+ .build();
+ }
+
+ private ActorState buildActorState(Long actorId, Long articleId) {
+ Article article = Article.builder().id(articleId).build();
+ Actor actor = actorService.findById(actorId).get();
+ ActorStateId actorStateId = ActorStateId.builder().articleId(articleId).actorId(actor.getId()).build();
+ return ActorState.builder()
+ .id(actorStateId)
+ .actor(actor)
+ .article(article)
+ .build();
+ }
+
+ @Test
+ public void findActorStateByArticle_whenCorrect_shouldExist() {
+ assertTrue(actorStateService.findForActorByArticle(1L, 1L).isPresent());
+ }
+
+ @Test
+ public void findActorStateByActor_whenCorrect_shouldExist() {
+ Pageable pageable = new PageRequest(0, 10);
+ assertNotEquals(0, actorStateService.findAllByActor(1L, pageable).getTotalElements());
+ }
+
+ @Test
+ public void findActorStateByActor_whenActorNotExist_shouldReturnEmptyPage() {
+ Pageable pageable = new PageRequest(0, 10);
+ assertEquals(0, actorStateService.findAllByActor(-1L, pageable).getTotalElements());
+ }
+
+ @Test
+ public void findActorStateByArticle_whenArticleNotExists_shouldExist() {
+ assertFalse(actorStateService.findForActorByArticle(1L, -1L).isPresent());
+ }
+
+ @Test
+ public void createActorState_whenAlreadyExist_shouldCreateId() {
+ final Long ARTICLE_ID = 1L;
+ final Long ACTOR_ID = 1L;
+
+ Actor actor = actorService.findById(ACTOR_ID).get();
+ ActorState actorState = buildActorState(ACTOR_ID, ARTICLE_ID);
+ actor.getActorStates().add(actorState);
+ actorService.update(ACTOR_ID, ActorDto.of(actor));
+
+ assertNotNull(actorStateService.findForActorByArticle(ACTOR_ID, ARTICLE_ID));
+ }
+
+ @Test
+ public void deleteActorState_whenCorrect_shouldNotFoundAfterDelete() {
+ final Long ARTICLE_ID = 2L;
+ final Long ACTOR_ID = 2L;
+ ActorStateId actorStateId = ActorStateId.builder().actorId(ACTOR_ID).articleId(ARTICLE_ID).build();
+
+ Optional actorState = actorStateService.findById(actorStateId);
+ assertTrue(actorState.isPresent());
+
+ actorStateService.delete(actorState.get());
+
+ assertFalse(actorStateService.findById(actorStateId).isPresent());
+ }
+
+ @Test(expected = EmptyResultDataAccessException.class)
+ public void deleteActorState_whenIdNotExist_should() {
+ final Long ARTICLE_ID = 2L;
+ final Long ACTOR_ID = -2L;
+
+ ActorStateId actorStateId = ActorStateId.builder()
+ .actorId(ACTOR_ID)
+ .articleId(ARTICLE_ID)
+ .build();
+
+ actorStateService.deleteById(actorStateId);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/fic/writer/domain/service/ArticleServiceTest.java b/src/test/java/fic/writer/domain/service/ArticleServiceTest.java
new file mode 100644
index 0000000..9c52f6f
--- /dev/null
+++ b/src/test/java/fic/writer/domain/service/ArticleServiceTest.java
@@ -0,0 +1,54 @@
+package fic.writer.domain.service;
+
+import fic.writer.domain.entity.Article;
+import fic.writer.domain.entity.dto.ArticleDto;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.util.Date;
+
+import static org.junit.Assert.*;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+@EnableJpaAuditing
+public class ArticleServiceTest {
+ @Autowired
+ private ArticleService articleService;
+
+
+ @Test
+ public void updateArticle_whenUpdateTitle_shouldChangeTitle() {
+ final Long ARTICLE_ID = 3L;
+ final String NEW_TITLE = "new title";
+
+ ArticleDto articleDto = ArticleDto.builder().title(NEW_TITLE).build();
+ articleService.update(ARTICLE_ID, articleDto);
+ Article article = articleService.findById(ARTICLE_ID).get();
+ assertEquals(NEW_TITLE, article.getTitle());
+ }
+
+ @Test
+ public void updateArticle_whenUpdateTitle_shouldChangeUpdateDate() {
+ final Long ARTICLE_ID = 4L;
+ final String NEW_TITLE = "new title";
+ Date prevUpdateDate = articleService.findById(ARTICLE_ID).get().getLastModify();
+
+ ArticleDto articleDto = ArticleDto.builder().title(NEW_TITLE).build();
+ articleService.update(ARTICLE_ID, articleDto);
+ Article article = articleService.findById(ARTICLE_ID).get();
+ assertNotEquals(prevUpdateDate, article.getLastModify());
+ }
+
+ @Test
+ public void deleteArticle_whenExist_shouldNotFoundById() {
+ final Long ARTICLE_ID = 333L;
+ articleService.deleteById(ARTICLE_ID);
+ assertFalse(articleService.findById(ARTICLE_ID).isPresent());
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/fic/writer/domain/service/BookAndArticleServicesTest.java b/src/test/java/fic/writer/domain/service/BookAndArticleServicesTest.java
new file mode 100644
index 0000000..3b2b564
--- /dev/null
+++ b/src/test/java/fic/writer/domain/service/BookAndArticleServicesTest.java
@@ -0,0 +1,56 @@
+package fic.writer.domain.service;
+
+import fic.writer.domain.entity.Article;
+import fic.writer.domain.entity.Book;
+import fic.writer.domain.entity.dto.ArticleDto;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.transaction.annotation.Transactional;
+
+import static org.junit.Assert.*;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+@EnableJpaAuditing
+@Transactional
+public class BookAndArticleServicesTest {
+ @Autowired
+ private ArticleService articleService;
+ @Autowired
+ private BookService bookService;
+
+ @Test
+ public void createArticle_shouldFindByGeneratedId() {
+ final Long BOOK_ID = 1L;
+ Article article = Article.builder().build();
+ bookService.addArticle(BOOK_ID, ArticleDto.of(article));
+
+ Book book = bookService.findById(BOOK_ID).get();
+ book.getArticles().forEach(art -> assertTrue(articleService.findById(art.getId()).isPresent()));
+ }
+
+ @Test
+ public void createArticle_shouldGenerateCreatedDate() {
+ final Long BOOK_ID = 1L;
+ Article article = Article.builder().build();
+ bookService.addArticle(BOOK_ID, ArticleDto.of(article));
+
+ Book book = bookService.findById(BOOK_ID).get();
+ book.getArticles().forEach(art -> assertNotNull(art.getCreated()));
+ }
+
+ @Test
+ public void removeArticle_shouldGenerateCreatedDate() {
+ final Long BOOK_ID = 334L;
+ Book book = bookService.findById(BOOK_ID).get();
+
+ Long articleId = book.getArticles().stream().findFirst().get().getId();
+ book = bookService.removeArticle(BOOK_ID, articleId);
+
+ book.getArticles().forEach(art -> assertNotEquals(articleId, art.getId()));
+ }
+}
diff --git a/src/test/java/fic/writer/domain/service/BookServiceTest.java b/src/test/java/fic/writer/domain/service/BookServiceTest.java
new file mode 100644
index 0000000..279574c
--- /dev/null
+++ b/src/test/java/fic/writer/domain/service/BookServiceTest.java
@@ -0,0 +1,69 @@
+package fic.writer.domain.service;
+
+import fic.writer.domain.entity.Book;
+import fic.writer.domain.entity.dto.BookDto;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.dao.EmptyResultDataAccessException;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import static org.junit.Assert.*;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class BookServiceTest {
+ @Autowired
+ private BookService bookService;
+
+ @Test
+ public void createBook_shouldChangeCount() {
+ final int SIZE_BEFORE = bookService.findAll().size();
+ Book emptyBook = Book.builder().build();
+ bookService.create(BookDto.of(emptyBook));
+
+ assertNotEquals(SIZE_BEFORE, bookService.findAll().size());
+ }
+
+ @Test
+ public void createBook_whenTitleIsCyrillic_shouldFindByGeneratedId() {
+ final String TITLE = "Заголовок";
+ final long CURRENT_COUNT = 1L;
+ Book emptyBook = Book.builder().title(TITLE).build();
+ bookService.create(BookDto.of(emptyBook));
+
+ assertEquals(CURRENT_COUNT, bookService.findAll().stream().filter(book -> book.getTitle().equals(TITLE)).count());
+ }
+
+ @Test
+ public void findBook_whenContainSizeEnum_shouldConvertToNotNullSize() {
+ final Long BOOK_ID = 3L;
+ Book book = bookService.findById(BOOK_ID).get();
+
+ assertNotNull(book.getSize());
+ }
+
+ @Test
+ public void findBook_whenContainStateEnum_shouldConvertToNotNullState() {
+ final Long BOOK_ID = 4L;
+ Book book = bookService.findById(BOOK_ID).get();
+
+ assertNotNull(book.getState());
+ }
+
+ @Test
+ public void deletedBook_whenExist_shouldNotFound() {
+ final Long DELETE_BOOK_ID = 333L;
+ bookService.deleteById(DELETE_BOOK_ID);
+
+ assertNotNull(bookService.findById(DELETE_BOOK_ID));
+ }
+
+ @Test(expected = EmptyResultDataAccessException.class)
+ public void deletedBook_whenNotExist_shouldThorwException() {
+ final Long DELETE_BOOK_ID = -1L;
+ bookService.deleteById(DELETE_BOOK_ID);
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/fic/writer/domain/service/UserServiceTest.java b/src/test/java/fic/writer/domain/service/UserServiceTest.java
new file mode 100644
index 0000000..2dc5473
--- /dev/null
+++ b/src/test/java/fic/writer/domain/service/UserServiceTest.java
@@ -0,0 +1,42 @@
+package fic.writer.domain.service;
+
+import fic.writer.domain.entity.dto.UserDto;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import static org.junit.Assert.*;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class UserServiceTest {
+ @Autowired
+ private UserService userService;
+
+ @Test
+ public void createUser() {
+ final String USERNAME = "createTestUser";
+ UserDto user = UserDto.builder().username(USERNAME).build();
+ userService.create(user);
+ assertTrue(userService.findAll().stream().anyMatch(u -> u.getUsername().equals(USERNAME)));
+ }
+
+ @Test
+ public void deleteUser() {
+ final Long USER_ID = 123L;
+ assertTrue(userService.findById(USER_ID).isPresent());
+ userService.deleteById(USER_ID);
+ assertFalse(userService.findById(USER_ID).isPresent());
+ }
+
+ @Test
+ public void updateUser_whenUpdateAbout_shouldChangeAbout() {
+ final Long USER_ID = 1L;
+ final String NEW_ABOUT = "new about";
+ UserDto userDto = UserDto.builder().about(NEW_ABOUT).build();
+ userService.update(USER_ID, userDto);
+ assertEquals(NEW_ABOUT, userService.findById(USER_ID).get().getAbout());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/fic/writer/web/controller/UserControllerTest.java b/src/test/java/fic/writer/web/controller/UserControllerTest.java
new file mode 100644
index 0000000..3c2eb61
--- /dev/null
+++ b/src/test/java/fic/writer/web/controller/UserControllerTest.java
@@ -0,0 +1,133 @@
+package fic.writer.web.controller;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import fic.writer.domain.entity.User;
+import fic.writer.domain.entity.dto.UserDto;
+import fic.writer.domain.service.UserService;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+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.http.MediaType;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.servlet.MockMvc;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@RunWith(SpringRunner.class)
+@WebMvcTest(value = UserController.class, secure = false)
+public class UserControllerTest {
+ private static final String USERS_PATH = "/users";
+ private static final String USER_ID_PATH_TEMPLATE = USERS_PATH + "/{id}";
+ @Autowired
+ private UserController userController;
+ @Autowired
+ private MockMvc mockMvc;
+ @MockBean
+ private UserService userService;
+
+
+ @Test
+ public void getUsers_whenDtoIsEmpty_shouldReturnOk() throws Exception {
+ List userList = new ArrayList<>();
+ User user = new User();
+ user.setId(1L);
+ user.setUsername("testUsername");
+ userList.add(user);
+ Mockito.when(userService.findAll()).thenReturn(userList);
+
+ mockMvc.perform(get(USERS_PATH))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.[0].username").value(user.getUsername()))
+ .andExpect(jsonPath("$.[0].links.[0].rel").value("self"));
+ }
+
+ @Test
+ public void getUserById_whenUserExists_shouldReturnOk() throws Exception {
+ final long ID = 1L;
+ User user = new User();
+ user.setId(ID);
+ user.setUsername("testUsername");
+
+ Mockito.when(userService.findById(1L)).thenReturn(Optional.of(user));
+
+ mockMvc.perform(get(USER_ID_PATH_TEMPLATE, ID))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.username").value(user.getUsername()))
+ .andExpect(jsonPath("$._links.self").hasJsonPath());
+ }
+
+ @Test
+ public void createUser() throws Exception {
+ final Long USER_ID = 1L;
+ final String username = "testUsername", about = "about", information = "inform";
+ UserDto dto = new UserDto(username, about, information);
+ ObjectMapper mapper = new ObjectMapper();
+
+ User user = User.builder()
+ .id(USER_ID)
+ .username(username)
+ .about(about)
+ .information(information)
+ .booksAsAuthor(new HashSet<>())
+ .booksAsSubAuthor(new HashSet<>())
+ .build();
+
+ mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+ String body = mapper.writeValueAsString(dto);
+ Mockito.when(userService.create(any(UserDto.class))).thenReturn(user);
+
+ mockMvc.perform(post(USERS_PATH)
+ .content(body)
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isCreated())
+ .andExpect(jsonPath("$.username").value(user.getUsername()))
+ .andExpect(jsonPath("$._links.self").hasJsonPath());
+ }
+
+ @Test
+ public void updateUser() throws Exception {
+ final Long USER_ID = 1L;
+ final String NEW_USERNAME = "testUsername";
+ User updatedUser = User.builder()
+ .id(USER_ID)
+ .username(NEW_USERNAME)
+ .booksAsAuthor(new HashSet<>())
+ .booksAsSubAuthor(new HashSet<>())
+ .build();
+ UserDto dto = new UserDto(NEW_USERNAME, null, null);
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+ String body = mapper.writeValueAsString(dto);
+
+ Mockito.when(userService.update(anyLong(), any(UserDto.class))).thenReturn(updatedUser);
+
+ mockMvc.perform(put(USER_ID_PATH_TEMPLATE, USER_ID)
+ .content(body)
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.username").value(updatedUser.getUsername()))
+ .andExpect(jsonPath("$._links.self").hasJsonPath());
+
+ }
+
+ @Test
+ public void deleteUser() throws Exception {
+ final long ID = 1L;
+
+ mockMvc.perform(delete(USER_ID_PATH_TEMPLATE, ID))
+ .andExpect(status().isNoContent());
+ }
+}
\ No newline at end of file
diff --git a/src/test/resources/application-db-h2.yml b/src/test/resources/application-db-h2.yml
new file mode 100644
index 0000000..ced131b
--- /dev/null
+++ b/src/test/resources/application-db-h2.yml
@@ -0,0 +1,13 @@
+spring:
+ datasource:
+ url: jdbc:h2:mem:testdb
+ driverClassName: org.h2.Driver
+ username: sa
+ password:
+ jpa:
+ properties:
+ hibernate:
+ dialect: org.hibernate.dialect.H2Dialect
+ h2:
+ console:
+ enabled: true
\ No newline at end of file
diff --git a/src/test/resources/application-db-mysql.yml b/src/test/resources/application-db-mysql.yml
new file mode 100644
index 0000000..68c4a70
--- /dev/null
+++ b/src/test/resources/application-db-mysql.yml
@@ -0,0 +1,12 @@
+spring:
+ datasource:
+ url: jdbc:mysql://localhost:3306/ficwriter-test
+ username: dl
+ password: p@ssword
+ initialization-mode: always
+ jpa:
+ hibernate:
+ ddl-auto: create-drop
+ properties:
+ hibernate:
+ dialect: org.hibernate.dialect.MySQL5InnoDBDialect
\ No newline at end of file
diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml
new file mode 100644
index 0000000..5828953
--- /dev/null
+++ b/src/test/resources/application.yml
@@ -0,0 +1,15 @@
+spring:
+ profiles:
+ active: db-mysql
+ jpa:
+ hibernate:
+ ddl-auto: create-drop
+ properties:
+ hibernate:
+ hbm2ddl:
+ import_files: data/user.sql, data/actor.sql, data/book.sql, data/article.sql, data/book_article.sql, data/actor_state.sql
+logging:
+ level:
+ org:
+ springframework: INFO
+
diff --git a/src/test/resources/data/actor.sql b/src/test/resources/data/actor.sql
new file mode 100644
index 0000000..bb9597c
--- /dev/null
+++ b/src/test/resources/data/actor.sql
@@ -0,0 +1,10 @@
+INSERT INTO actor(id,description,name)VALUES(1,'description1','name1');
+INSERT INTO actor(id,description,name)VALUES(2,'description2','name2');
+INSERT INTO actor(id,description,name)VALUES(3,'description3','name3');
+INSERT INTO actor(id,description,name)VALUES(987,'description','name');
+INSERT INTO actor(id,description,name)VALUES(333,'description','name');
+INSERT INTO actor(id,description,name)VALUES(334,'description','name');
+
+
+
+
diff --git a/src/test/resources/data/actor_state.sql b/src/test/resources/data/actor_state.sql
new file mode 100644
index 0000000..6e99aca
--- /dev/null
+++ b/src/test/resources/data/actor_state.sql
@@ -0,0 +1,7 @@
+INSERT INTO actor_state(content,title,actor_id,article_id)VALUES('content1','title1',1,1);
+INSERT INTO actor_state(content,title,actor_id,article_id)VALUES('content2','title2',1,2);
+INSERT INTO actor_state(content,title,actor_id,article_id)VALUES('content3','title3',2,1);
+INSERT INTO actor_state(content,title,actor_id,article_id)VALUES('content4','title4',2,2);
+
+INSERT INTO actor_state(content,title,actor_id,article_id)VALUES('content4','title4',333,3);
+INSERT INTO actor_state(content,title,actor_id,article_id)VALUES('content4','title4',334,3);
\ No newline at end of file
diff --git a/src/test/resources/data/article.sql b/src/test/resources/data/article.sql
new file mode 100644
index 0000000..3ca4a6e
--- /dev/null
+++ b/src/test/resources/data/article.sql
@@ -0,0 +1,12 @@
+INSERT INTO article(id,annotation,content,title)VALUES(1,'annotation1','content1','title1');
+INSERT INTO article(id,annotation,content,title)VALUES(2,'annotation2','content2','title2');
+INSERT INTO article(id,annotation,content,title)VALUES(3,'annotation','content','title');
+INSERT INTO article(id,annotation,content,title)VALUES(4,'annotation','content','title');
+INSERT INTO article(id,annotation,content,title)VALUES(333,'annotation','content','delete article');
+INSERT INTO article(id,annotation,content,title)VALUES(334,'annotation','content','delete article');
+
+INSERT INTO article(id,annotation,content,title,book_id)VALUES(5,'Place for annotation','Place for content.
','Summer inspiration',335);
+INSERT INTO article(id,annotation,content,title,book_id)VALUES(6,'Place for annotation','
Place for content.
','Summer inspiration#2',335);
+INSERT INTO article(id,annotation,content,title,book_id)VALUES(7,'Place for annotation','
Place for content.
','Summer #3',335);
+INSERT INTO article(id,annotation,content,title,book_id)VALUES(8,'Place for annotation','
Place for content.
','Winrte',335);
+
diff --git a/src/test/resources/data/book.sql b/src/test/resources/data/book.sql
new file mode 100644
index 0000000..b3adcdc
--- /dev/null
+++ b/src/test/resources/data/book.sql
@@ -0,0 +1,15 @@
+INSERT INTO book(id,title)VALUES(1,'book title');
+INSERT INTO book(id,title,description)VALUES(2,'book title','description');
+INSERT INTO book(id,title,size)VALUES(3,'book title',1);
+INSERT INTO book(id,title,state)VALUES(4,'book title',1);
+INSERT INTO book(id,title)VALUES(5,'book title');
+INSERT INTO book(id,title)VALUES(333,'delete book');
+INSERT INTO book(id,title)VALUES(334,'Книга для удаления');
+
+INSERT INTO book(id,title,description, size, state,author_id)VALUES(335,'Arabella','Artic monkeys', 1,2,3);
+INSERT INTO user_books_as_author (user_id,books_as_author_id)VALUES(3,335);
+INSERT INTO book_subauthors (user_id,book_id)VALUES(4,335);
+
+
+
+
diff --git a/src/test/resources/data/book_article.sql b/src/test/resources/data/book_article.sql
new file mode 100644
index 0000000..7cf2f23
--- /dev/null
+++ b/src/test/resources/data/book_article.sql
@@ -0,0 +1,5 @@
+INSERT INTO book_articles(book_id,articles_id)VALUES(334,334);
+INSERT INTO book_articles(book_id,articles_id)VALUES(335,5);
+INSERT INTO book_articles(book_id,articles_id)VALUES(335,6);
+INSERT INTO book_articles(book_id,articles_id)VALUES(335,7);
+INSERT INTO book_articles(book_id,articles_id)VALUES(335,8);
\ No newline at end of file
diff --git a/src/test/resources/data/user.sql b/src/test/resources/data/user.sql
new file mode 100644
index 0000000..dd5d16b
--- /dev/null
+++ b/src/test/resources/data/user.sql
@@ -0,0 +1,4 @@
+INSERT INTO user(id,username)VALUES(123,'delete user');
+INSERT INTO user(id,username)VALUES(1,'test user');
+INSERT INTO user(id,username)VALUES(3,'Bella');
+INSERT INTO user(id,username)VALUES(4,'Bella junior');
\ No newline at end of file