From 5b93369852ebdcac45d7f4e462311de7f4178184 Mon Sep 17 00:00:00 2001 From: Florian THIERRY Date: Tue, 9 Mar 2021 00:13:13 +0100 Subject: [PATCH] Add base --- pom.xml | 6 + .../controller/GameController.java | 24 ++++ .../demo/intellijshortcuts/model/Dlc.java | 28 +++++ .../demo/intellijshortcuts/model/Editor.java | 25 ++++ .../demo/intellijshortcuts/model/Game.java | 33 +++++ .../repository/DlcRepository.java | 12 ++ .../repository/EditorRepository.java | 11 ++ .../repository/GameRepository.java | 15 +++ .../service/GameService.java | 20 +++ ...application.properties => application.yml} | 0 .../RepositoryConfiguration.java | 37 ++++++ .../configuration/TestUtilsConfiguration.java | 16 +++ .../controller/GameControllerTest.java | 49 ++++++++ .../DatabaseInitializationExtension.java | 24 ++++ .../util/DatabaseInitializer.java | 119 ++++++++++++++++++ src/test/resources/application-test.yml | 0 src/test/resources/sql/01_init-db.sql | 30 +++++ 17 files changed, 449 insertions(+) create mode 100644 src/main/java/org/takiguchi/demo/intellijshortcuts/controller/GameController.java create mode 100644 src/main/java/org/takiguchi/demo/intellijshortcuts/model/Dlc.java create mode 100644 src/main/java/org/takiguchi/demo/intellijshortcuts/model/Editor.java create mode 100644 src/main/java/org/takiguchi/demo/intellijshortcuts/model/Game.java create mode 100644 src/main/java/org/takiguchi/demo/intellijshortcuts/repository/DlcRepository.java create mode 100644 src/main/java/org/takiguchi/demo/intellijshortcuts/repository/EditorRepository.java create mode 100644 src/main/java/org/takiguchi/demo/intellijshortcuts/repository/GameRepository.java create mode 100644 src/main/java/org/takiguchi/demo/intellijshortcuts/service/GameService.java rename src/main/resources/{application.properties => application.yml} (100%) create mode 100644 src/test/java/org/takiguchi/demo/intellijshortcuts/configuration/RepositoryConfiguration.java create mode 100644 src/test/java/org/takiguchi/demo/intellijshortcuts/configuration/TestUtilsConfiguration.java create mode 100644 src/test/java/org/takiguchi/demo/intellijshortcuts/controller/GameControllerTest.java create mode 100644 src/test/java/org/takiguchi/demo/intellijshortcuts/extension/DatabaseInitializationExtension.java create mode 100644 src/test/java/org/takiguchi/demo/intellijshortcuts/util/DatabaseInitializer.java create mode 100644 src/test/resources/application-test.yml create mode 100644 src/test/resources/sql/01_init-db.sql diff --git a/pom.xml b/pom.xml index 05c00f8..84da830 100644 --- a/pom.xml +++ b/pom.xml @@ -46,6 +46,12 @@ org.springframework.boot spring-boot-starter-test test + + + org.junit.vintage + junit-vintage-engine + + diff --git a/src/main/java/org/takiguchi/demo/intellijshortcuts/controller/GameController.java b/src/main/java/org/takiguchi/demo/intellijshortcuts/controller/GameController.java new file mode 100644 index 0000000..6ef9d14 --- /dev/null +++ b/src/main/java/org/takiguchi/demo/intellijshortcuts/controller/GameController.java @@ -0,0 +1,24 @@ +package org.takiguchi.demo.intellijshortcuts.controller; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.takiguchi.demo.intellijshortcuts.model.Game; +import org.takiguchi.demo.intellijshortcuts.service.GameService; + +import java.util.List; + +@RestController +@RequestMapping("/api/games") +public class GameController { + private final GameService gameService; + + public GameController(GameService gameService) { + this.gameService = gameService; + } + + @GetMapping + public List getAll() { + return gameService.findAll(); + } +} diff --git a/src/main/java/org/takiguchi/demo/intellijshortcuts/model/Dlc.java b/src/main/java/org/takiguchi/demo/intellijshortcuts/model/Dlc.java new file mode 100644 index 0000000..d15fd09 --- /dev/null +++ b/src/main/java/org/takiguchi/demo/intellijshortcuts/model/Dlc.java @@ -0,0 +1,28 @@ +package org.takiguchi.demo.intellijshortcuts.model; + +import lombok.*; + +import javax.persistence.*; +import java.time.LocalDate; +import java.util.UUID; + +import static javax.persistence.FetchType.LAZY; + +@Entity +@Table(name = "dlc") +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class Dlc { + @Id + @GeneratedValue(generator = "system-uuid") + private UUID id; + private String title; + private LocalDate publicationDate; + private Double price; + @ManyToOne(fetch = LAZY) + @JoinColumn(name = "game_id") + private Game game; +} diff --git a/src/main/java/org/takiguchi/demo/intellijshortcuts/model/Editor.java b/src/main/java/org/takiguchi/demo/intellijshortcuts/model/Editor.java new file mode 100644 index 0000000..4ff7b71 --- /dev/null +++ b/src/main/java/org/takiguchi/demo/intellijshortcuts/model/Editor.java @@ -0,0 +1,25 @@ +package org.takiguchi.demo.intellijshortcuts.model; + +import lombok.*; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Table; +import java.time.LocalDate; +import java.util.UUID; + +@Entity +@Table(name = "editor") +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class Editor { + @Id + @GeneratedValue(generator = "system-uuid") + private UUID id; + private String name; + private LocalDate creationDate; +} diff --git a/src/main/java/org/takiguchi/demo/intellijshortcuts/model/Game.java b/src/main/java/org/takiguchi/demo/intellijshortcuts/model/Game.java new file mode 100644 index 0000000..cf45a62 --- /dev/null +++ b/src/main/java/org/takiguchi/demo/intellijshortcuts/model/Game.java @@ -0,0 +1,33 @@ +package org.takiguchi.demo.intellijshortcuts.model; + +import lombok.*; + +import javax.persistence.*; +import java.time.LocalDate; +import java.util.List; +import java.util.UUID; + +import static javax.persistence.CascadeType.*; +import static javax.persistence.FetchType.LAZY; + +@Entity +@Table(name = "game") +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class Game { + @Id + @GeneratedValue(generator = "system-uuid") + private UUID id; + private String title; + private String description; + private LocalDate publicationDate; + private Double price; + @ManyToOne(fetch = LAZY) + @JoinColumn(name = "editor_id") + private Editor editor; + @OneToMany(mappedBy = "game", cascade = ALL) + private List dlcList; +} diff --git a/src/main/java/org/takiguchi/demo/intellijshortcuts/repository/DlcRepository.java b/src/main/java/org/takiguchi/demo/intellijshortcuts/repository/DlcRepository.java new file mode 100644 index 0000000..96b137d --- /dev/null +++ b/src/main/java/org/takiguchi/demo/intellijshortcuts/repository/DlcRepository.java @@ -0,0 +1,12 @@ +package org.takiguchi.demo.intellijshortcuts.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import org.takiguchi.demo.intellijshortcuts.model.Dlc; + +import java.util.UUID; + +@Repository +public interface DlcRepository extends JpaRepository { + +} diff --git a/src/main/java/org/takiguchi/demo/intellijshortcuts/repository/EditorRepository.java b/src/main/java/org/takiguchi/demo/intellijshortcuts/repository/EditorRepository.java new file mode 100644 index 0000000..afd90fb --- /dev/null +++ b/src/main/java/org/takiguchi/demo/intellijshortcuts/repository/EditorRepository.java @@ -0,0 +1,11 @@ +package org.takiguchi.demo.intellijshortcuts.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import org.takiguchi.demo.intellijshortcuts.model.Editor; + +import java.util.UUID; + +@Repository +public interface EditorRepository extends JpaRepository { +} diff --git a/src/main/java/org/takiguchi/demo/intellijshortcuts/repository/GameRepository.java b/src/main/java/org/takiguchi/demo/intellijshortcuts/repository/GameRepository.java new file mode 100644 index 0000000..927e275 --- /dev/null +++ b/src/main/java/org/takiguchi/demo/intellijshortcuts/repository/GameRepository.java @@ -0,0 +1,15 @@ +package org.takiguchi.demo.intellijshortcuts.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; +import org.takiguchi.demo.intellijshortcuts.model.Game; + +import java.util.List; +import java.util.UUID; + +@Repository +public interface GameRepository extends JpaRepository { + @Query("SELECT DISTINCT g FROM Game g LEFT JOIN FETCH g.dlcList") + List findAllWithDlcs(); +} diff --git a/src/main/java/org/takiguchi/demo/intellijshortcuts/service/GameService.java b/src/main/java/org/takiguchi/demo/intellijshortcuts/service/GameService.java new file mode 100644 index 0000000..47e7f00 --- /dev/null +++ b/src/main/java/org/takiguchi/demo/intellijshortcuts/service/GameService.java @@ -0,0 +1,20 @@ +package org.takiguchi.demo.intellijshortcuts.service; + +import org.springframework.stereotype.Service; +import org.takiguchi.demo.intellijshortcuts.model.Game; +import org.takiguchi.demo.intellijshortcuts.repository.GameRepository; + +import java.util.List; + +@Service +public class GameService { + private final GameRepository gameRepository; + + public GameService(GameRepository gameRepository) { + this.gameRepository = gameRepository; + } + + public List findAll() { + return gameRepository.findAllWithDlcs(); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.yml similarity index 100% rename from src/main/resources/application.properties rename to src/main/resources/application.yml diff --git a/src/test/java/org/takiguchi/demo/intellijshortcuts/configuration/RepositoryConfiguration.java b/src/test/java/org/takiguchi/demo/intellijshortcuts/configuration/RepositoryConfiguration.java new file mode 100644 index 0000000..a333455 --- /dev/null +++ b/src/test/java/org/takiguchi/demo/intellijshortcuts/configuration/RepositoryConfiguration.java @@ -0,0 +1,37 @@ +package org.takiguchi.demo.intellijshortcuts.configuration; + +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase; +import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; +import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; +import org.takiguchi.demo.intellijshortcuts.repository.EditorRepository; +import org.takiguchi.demo.intellijshortcuts.repository.GameRepository; +import org.takiguchi.demo.intellijshortcuts.util.DatabaseInitializer; + +import javax.sql.DataSource; + +@TestConfiguration +@ComponentScan(basePackages = "org.takiguchi.demo.intellijshortcuts.repository") +public class RepositoryConfiguration { + @Bean + public EmbeddedDatabase dataSource() { + return new EmbeddedDatabaseBuilder() + .setType(EmbeddedDatabaseType.H2) + .addScript("sql/01_init-db.sql") + .build(); + } + + @Bean + public JdbcTemplate jdbcTemplate(DataSource dataSource) { + return new JdbcTemplate(dataSource); + } + + @Bean + public DatabaseInitializer dataConfiguration(EditorRepository editorRepository, + GameRepository gameRepository) { + return new DatabaseInitializer(editorRepository, gameRepository); + } +} diff --git a/src/test/java/org/takiguchi/demo/intellijshortcuts/configuration/TestUtilsConfiguration.java b/src/test/java/org/takiguchi/demo/intellijshortcuts/configuration/TestUtilsConfiguration.java new file mode 100644 index 0000000..f6cbd32 --- /dev/null +++ b/src/test/java/org/takiguchi/demo/intellijshortcuts/configuration/TestUtilsConfiguration.java @@ -0,0 +1,16 @@ +package org.takiguchi.demo.intellijshortcuts.configuration; + +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.DefaultUriBuilderFactory; + +@TestConfiguration +public class TestUtilsConfiguration { + @Bean + public RestTemplate restTemplate() { + RestTemplate restTemplate = new RestTemplate(); + restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory("http://localhost:8080")); + return restTemplate; + } +} diff --git a/src/test/java/org/takiguchi/demo/intellijshortcuts/controller/GameControllerTest.java b/src/test/java/org/takiguchi/demo/intellijshortcuts/controller/GameControllerTest.java new file mode 100644 index 0000000..120c5d1 --- /dev/null +++ b/src/test/java/org/takiguchi/demo/intellijshortcuts/controller/GameControllerTest.java @@ -0,0 +1,49 @@ +package org.takiguchi.demo.intellijshortcuts.controller; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.takiguchi.demo.intellijshortcuts.configuration.RepositoryConfiguration; +import org.takiguchi.demo.intellijshortcuts.configuration.TestUtilsConfiguration; +import org.takiguchi.demo.intellijshortcuts.extension.DatabaseInitializationExtension; +import org.takiguchi.demo.intellijshortcuts.model.Dlc; +import org.takiguchi.demo.intellijshortcuts.model.Game; + +import java.util.Collection; +import java.util.List; + +import static java.util.stream.Collectors.toList; +import static org.assertj.core.api.Assertions.assertThat; + +@ExtendWith({ + SpringExtension.class, + DatabaseInitializationExtension.class +}) +@SpringBootTest(classes = { + RepositoryConfiguration.class, + TestUtilsConfiguration.class +}) +public class GameControllerTest { + @Autowired + private GameController gameController; + + @Test + void getAll_should_fetch_dlc_list() { + // when + List games = gameController.getAll(); + + // then + assertThat(games).hasSize(5); + List dlcTitles = games.stream() + .filter(game -> "World of Warcraft".equals(game.getTitle())) + .findFirst() + .map(Game::getDlcList) + .stream() + .flatMap(Collection::stream) + .map(Dlc::getTitle) + .collect(toList()); + assertThat(dlcTitles).containsExactlyInAnyOrder("The Burning Crusade", "Wrath of the Lich King"); + } +} diff --git a/src/test/java/org/takiguchi/demo/intellijshortcuts/extension/DatabaseInitializationExtension.java b/src/test/java/org/takiguchi/demo/intellijshortcuts/extension/DatabaseInitializationExtension.java new file mode 100644 index 0000000..cac28cb --- /dev/null +++ b/src/test/java/org/takiguchi/demo/intellijshortcuts/extension/DatabaseInitializationExtension.java @@ -0,0 +1,24 @@ +package org.takiguchi.demo.intellijshortcuts.extension; + +import org.junit.jupiter.api.extension.AfterAllCallback; +import org.junit.jupiter.api.extension.BeforeAllCallback; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.springframework.context.ApplicationContext; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.takiguchi.demo.intellijshortcuts.util.DatabaseInitializer; + +public class DatabaseInitializationExtension implements BeforeAllCallback, AfterAllCallback { + @Override + public void beforeAll(ExtensionContext extensionContext) { + ApplicationContext applicationContext = SpringExtension.getApplicationContext(extensionContext); + DatabaseInitializer databaseInitializer = applicationContext.getBean(DatabaseInitializer.class); + databaseInitializer.initData(); + } + + @Override + public void afterAll(ExtensionContext extensionContext) { + ApplicationContext applicationContext = SpringExtension.getApplicationContext(extensionContext); + DatabaseInitializer databaseInitializer = applicationContext.getBean(DatabaseInitializer.class); + databaseInitializer.clearData(); + } +} diff --git a/src/test/java/org/takiguchi/demo/intellijshortcuts/util/DatabaseInitializer.java b/src/test/java/org/takiguchi/demo/intellijshortcuts/util/DatabaseInitializer.java new file mode 100644 index 0000000..de0dc72 --- /dev/null +++ b/src/test/java/org/takiguchi/demo/intellijshortcuts/util/DatabaseInitializer.java @@ -0,0 +1,119 @@ +package org.takiguchi.demo.intellijshortcuts.util; + +import org.takiguchi.demo.intellijshortcuts.model.Dlc; +import org.takiguchi.demo.intellijshortcuts.model.Editor; +import org.takiguchi.demo.intellijshortcuts.model.Game; +import org.takiguchi.demo.intellijshortcuts.repository.EditorRepository; +import org.takiguchi.demo.intellijshortcuts.repository.GameRepository; + +import java.time.LocalDate; +import java.util.List; + +public class DatabaseInitializer { + private final EditorRepository editorRepository; + private final GameRepository gameRepository; + + public DatabaseInitializer(EditorRepository editorRepository, + GameRepository gameRepository) { + this.editorRepository = editorRepository; + this.gameRepository = gameRepository; + } + + public void initData() { + Editor psyconix = Editor.builder() + .name("Psyconix") + .creationDate(LocalDate.of(2000, 4, 30)) + .build(); + + Editor codeMasters = Editor.builder() + .name("Codemasters") + .creationDate(LocalDate.of(1986, 1, 2)) + .build(); + + Editor blizzard = Editor.builder() + .name("Blizzard") + .creationDate(LocalDate.of(1991, 2, 8)) + .build(); + + editorRepository.saveAll(List.of( + psyconix, + codeMasters, + blizzard + )); + + Game rocketLeague = Game.builder() + .title("Rocket league") + .description("Rocket League est un mélange de jeu de voiture et de jeu de football.") + .publicationDate(LocalDate.of(2015, 7, 7)) + .price(0D) + .editor(psyconix) + .build(); + + Game f1_2019 = Game.builder() + .title("F1 2019") + .description("Jeu de simulation de courses de F1 pour la saison 2019.") + .publicationDate(LocalDate.of(2019, 6, 28)) + .price(6.99) + .editor(codeMasters) + .build(); + + Game f1_2020 = Game.builder() + .title("F1 2020") + .description("Jeu de simulation de courses de F1 pour la saison 2020.") + .publicationDate(LocalDate.of(2019, 7, 10)) + .price(6.99) + .editor(codeMasters) + .build(); + + List warcraft3DlcList = List.of(Dlc.builder() + .title("Warcraft III: The Frozen Throne.") + .publicationDate(LocalDate.of(2003, 7, 1)) + .price(14.99) + .build()); + Game warcraft3 = Game.builder() + .title("Warcraft III") + .description("Jeu de stratégie en temps réel dans l'univers de Warcraft.") + .publicationDate(LocalDate.of(2002, 7, 3)) + .price(49.99) + .editor(blizzard) + .dlcList(warcraft3DlcList) + .build(); + warcraft3DlcList.forEach(dlc -> dlc.setGame(warcraft3)); + + List wowDlcList = List.of( + Dlc.builder() + .title("The Burning Crusade") + .publicationDate(LocalDate.of(2007, 1, 16)) + .price(14.99) + .build(), + Dlc.builder() + .title("Wrath of the Lich King") + .publicationDate(LocalDate.of(2008, 11, 13)) + .price(14.99) + .build() + ); + Game worldOfWarcraft = Game.builder() + .title("World of Warcraft") + .description("MMORPG basé sur l'univers de Warcraft") + .publicationDate(LocalDate.of(2004, 11, 23)) + .price(59.99) + .editor(blizzard) + .dlcList(wowDlcList) + .build(); + wowDlcList.forEach(dlc -> dlc.setGame(worldOfWarcraft)); + + gameRepository.saveAll(List.of( + rocketLeague, + f1_2019, + f1_2020, + warcraft3, + worldOfWarcraft + )); + } + + public void clearData() { +// dlcRepository.deleteAll(); + gameRepository.deleteAll(); + editorRepository.deleteAll(); + } +} diff --git a/src/test/resources/application-test.yml b/src/test/resources/application-test.yml new file mode 100644 index 0000000..e69de29 diff --git a/src/test/resources/sql/01_init-db.sql b/src/test/resources/sql/01_init-db.sql new file mode 100644 index 0000000..a4bd691 --- /dev/null +++ b/src/test/resources/sql/01_init-db.sql @@ -0,0 +1,30 @@ +CREATE TABLE editor ( + id UUID DEFAULT random_uuid() NOT NULL, + name VARCHAR NOT NULL, + creation_date DATE NOT NULL, + CONSTRAINT pk_editor PRIMARY KEY (id) +); + +CREATE TABLE game ( + id UUID DEFAULT random_uuid() NOT NULL, + title VARCHAR NOT NULL, + description VARCHAR NOT NULL, + publication_date DATE NOT NULL, + price NUMBER NOT NULL DEFAULT 0, + editor_id UUID NOT NULL, + CONSTRAINT pk_game PRIMARY KEY (id), + CONSTRAINT fk_game_editor_id FOREIGN KEY (editor_id) REFERENCES editor (id) +); + +CREATE TABLE dlc ( + id UUID DEFAULT random_uuid() NOT NULL, + title VARCHAR NOT NULL, + publication_date DATE NOT NULL, + price NUMBER NOT NULL DEFAULT 0, + game_id UUID NOT NULL, + CONSTRAINT pk_dlc PRIMARY KEY (id), + CONSTRAINT fk_dlc_game_id FOREIGN KEY (game_id) REFERENCES game (id) +); + +INSERT INTO editor (name, creation_date) VALUES +('Psyonix', parsedatetime('2000-04-30', 'dd-MM-YYYY')); \ No newline at end of file