diff --git a/README.md b/README.md index d33b7e90bfe0b5e9f9598ca6a34f15daf22180ca..7ce09fd8e36c95451ae901560e91ab9cba71aba8 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,11 @@ Common classes used across the application. Management of cars. Runs on port 8082. +Extended functionality for car module: For a given car and its component, both given by their respective IDs, +a list of sparse components can be fetched from carComponent module. A sparse component is any component +with the same name as the given component of the car that is not used by the car. +WARNING: when putting components or drivers, services component and driver need to run. ### component @@ -70,7 +74,15 @@ Runs on port 8083. `mvn -pl race spring-boot:run` -Management of races. +Management of races. Extended functionality for this module +is endpoint findMostSuitableDriverForLocation. This endpoint finds drivers with max +points from all races at given location. + +WARNING: when posting race with driver or car assigned, +you have to run also car and driver services in order to check that these objects exist. +You can create race without driverOne and driverTwo. +Corresponding services need to run when also assigning drivers or cars in other endpoints. + Runs on port 8081. diff --git a/car/src/main/java/cz/muni/pa165/car/data/repository/CarRepository.java b/car/src/main/java/cz/muni/pa165/car/data/repository/CarRepository.java index 0a6e95ea9cbe91c0884dc99959848b3245218a74..17273a5a8b86e7113ea6bb1415686a2f92fef31a 100644 --- a/car/src/main/java/cz/muni/pa165/car/data/repository/CarRepository.java +++ b/car/src/main/java/cz/muni/pa165/car/data/repository/CarRepository.java @@ -1,12 +1,23 @@ package cz.muni.pa165.car.data.repository; - import cz.muni.pa165.car.data.model.Car; +import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; /** * Car Repository for Driver Manager. */ @Repository -public interface CarRepository extends JpaRepository<Car, Long> {} +public interface CarRepository extends JpaRepository<Car, Long> { + + @Query("SELECT c FROM Car c WHERE c.id = :id") + Optional<Car> findById(@Param("id") Long id); + + @Query("SELECT c FROM Car c") + List<Car> findAll(); + +} diff --git a/common_library/src/main/java/cz/muni/pa165/common_library/dtos/RaceDto.java b/common_library/src/main/java/cz/muni/pa165/common_library/dtos/RaceDto.java index 6bfc8104aa033ec44cd4d3a2452a0bc35d97e3d4..aa6f565db887675a8536cc744bcf8de60008107d 100644 --- a/common_library/src/main/java/cz/muni/pa165/common_library/dtos/RaceDto.java +++ b/common_library/src/main/java/cz/muni/pa165/common_library/dtos/RaceDto.java @@ -23,10 +23,10 @@ public class RaceDto { @Schema(description = "race information") private RaceDto.RaceInfo raceInfo; - @Schema(description = "driver one", example = "{1, 1, Charles Leclerc}") + @Schema(description = "driver one") private RaceDriverCarDto driverOne; - @Schema(description = "driver two", example = "{2, 2, Carlos Sainz}") + @Schema(description = "driver two") private RaceDriverCarDto driverTwo; /** @@ -39,7 +39,7 @@ public class RaceDto { public static class RaceInfo { @NotNull - @Schema(description = "race location", example = "Monaco") + @Schema(description = "race location", example = "MONACO") private Location location; @NotNull diff --git a/common_library/src/main/java/cz/muni/pa165/common_library/dtos/SeasonDto.java b/common_library/src/main/java/cz/muni/pa165/common_library/dtos/SeasonDto.java index f5ea5df1445b44fcf57d58797ed53e38933889d5..bb6664b573a7640258f5f0e9bdd54b7c142eac74 100644 --- a/common_library/src/main/java/cz/muni/pa165/common_library/dtos/SeasonDto.java +++ b/common_library/src/main/java/cz/muni/pa165/common_library/dtos/SeasonDto.java @@ -30,7 +30,6 @@ public class SeasonDto { private int year; @NotNull - @Schema(description = "season races", example = "[{1, STC Saudi Arabian GP Jeddah}," - + " {2, Rolex Australian GP Melbourne}]") + @Schema(description = "season races") List<RaceNameDto> races; } diff --git a/common_library/src/main/java/cz/muni/pa165/common_library/exception/RestExceptionHandler.java b/common_library/src/main/java/cz/muni/pa165/common_library/exception/RestExceptionHandler.java index 2fa79a3098fc9805deaad690d50971d912746804..c7f84bf902685be55ac99595a5724944b6ab2516 100644 --- a/common_library/src/main/java/cz/muni/pa165/common_library/exception/RestExceptionHandler.java +++ b/common_library/src/main/java/cz/muni/pa165/common_library/exception/RestExceptionHandler.java @@ -1,6 +1,7 @@ package cz.muni.pa165.common_library.exception; import jakarta.persistence.EntityNotFoundException; +import org.apache.hc.client5.http.HttpHostConnectException; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -11,6 +12,7 @@ import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.client.HttpServerErrorException; import org.springframework.web.servlet.NoHandlerFoundException; /** @@ -88,7 +90,7 @@ public class RestExceptionHandler { for (ObjectError error : validationErrors) { var errorField = (FieldError) error; var errorMessage = errorField.getDefaultMessage(); - var fieldName = errorField.getField(); + var fieldName = errorField.getField(); validtionMessage.append(" field ").append(fieldName).append(": ") .append(errorMessage).append(","); @@ -102,4 +104,47 @@ public class RestExceptionHandler { return new ResponseEntity<>( new ExError(message), new HttpHeaders(), HttpStatus.BAD_REQUEST); } + + /** + * Handler for server error exception. + * + * @param ex thrown exception. + * @return Message with datetime. + */ + @ExceptionHandler(HttpServerErrorException.class) + public ResponseEntity<ExError> handleServerException(HttpServerErrorException ex) { + return new ResponseEntity<>( + new ExError(ex.getMessage()), new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR); + } + + /** + * Handler for server error exception. + * + * @param ex thrown exception. + * @return Message with datetime. + */ + @ExceptionHandler(HttpServerErrorException.InternalServerError.class) + public ResponseEntity<ExError> handleServerException( + HttpServerErrorException.InternalServerError ex) { + return new ResponseEntity<>( + new ExError(ex.getMessage()), new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR); + } + + /** + * Handler for server error exception. + * + * @param ex thrown exception. + * @return Message with datetime. + */ + @ExceptionHandler(HttpHostConnectException.class) + public ResponseEntity<ExError> handleServerException(HttpHostConnectException ex) { + var message = ""; + if (ex.getMessage().contains("8083")) { + message = "Failed to connect to the driver service"; + } else if (ex.getMessage().contains("8082")) { + message = "Failed to connect to the car service"; + } + return new ResponseEntity<>( + new ExError(message), new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR); + } } diff --git a/component/pom.xml b/component/pom.xml index 9b25686fc78bd88a2147b3846ac79b44e0d96839..4e6c25d3423eaa8f57edf40187a810e7b843464f 100644 --- a/component/pom.xml +++ b/component/pom.xml @@ -48,6 +48,12 @@ <artifactId>spring-data-jpa</artifactId> <version>3.0.2</version> </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.12</version> + <scope>test</scope> + </dependency> </dependencies> <properties> <maven.compiler.source>17</maven.compiler.source> diff --git a/component/src/main/java/cz/muni/pa165/component/App.java b/component/src/main/java/cz/muni/pa165/component/App.java index 6509fc53585d232a161f6f2aea8c9aa1291c5299..4e6c468adf2fe106355cf5266674cef8113ab522 100644 --- a/component/src/main/java/cz/muni/pa165/component/App.java +++ b/component/src/main/java/cz/muni/pa165/component/App.java @@ -1,22 +1,27 @@ package cz.muni.pa165.component; -import cz.muni.pa165.common_library.exception.RestExceptionHandler; +import jakarta.persistence.EntityManagerFactory; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.domain.EntityScan; -import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.Bean; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.web.client.RestTemplate; /** * Main app. */ -@SpringBootApplication -@EnableJpaRepositories(basePackages = {"cz.muni.pa165.component.data.repository"}) +@SpringBootApplication() @EntityScan("cz.muni.pa165.component.data.model") -@Import(RestExceptionHandler.class) public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); } + + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } + } diff --git a/component/src/main/java/cz/muni/pa165/component/data/repository/ComponentRepositoryInterface.java b/component/src/main/java/cz/muni/pa165/component/data/repository/ComponentRepositoryInterface.java index 42fa5b48e9bb43c5d42d09bc1a94d07a3ec3d2d0..708ad1670964f288993f326e6d850d9b8eb9b1a1 100644 --- a/component/src/main/java/cz/muni/pa165/component/data/repository/ComponentRepositoryInterface.java +++ b/component/src/main/java/cz/muni/pa165/component/data/repository/ComponentRepositoryInterface.java @@ -1,7 +1,11 @@ package cz.muni.pa165.component.data.repository; import cz.muni.pa165.component.data.model.CarComponent; +import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; /** @@ -9,4 +13,11 @@ import org.springframework.stereotype.Repository; */ @Repository public interface ComponentRepositoryInterface extends JpaRepository<CarComponent, Long> { + + @Query("SELECT c FROM CarComponent c WHERE c.id = :id") + Optional<CarComponent> findById(@Param("id") Long id); + + @Query("SELECT c FROM CarComponent c") + List<CarComponent> findAll(); + } diff --git a/component/src/test/java/cz/muni/pa165/component/config/TestConfig.java b/component/src/test/java/cz/muni/pa165/component/config/TestConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..ec59a47401a9218a4e71b7e282d136b5a4f6cf8a --- /dev/null +++ b/component/src/test/java/cz/muni/pa165/component/config/TestConfig.java @@ -0,0 +1,56 @@ +package cz.muni.pa165.component.config; + +import javax.sql.DataSource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; + +/** + * Configuration for tests. + */ +@Configuration +public class TestConfig { + + private DataSource dataSource; + + @Autowired + public void setDataSource() { + this.dataSource = dataSource(); + } + + /** + * Data source for factory. + * + * @return data source + */ + public DataSource dataSource() { + DriverManagerDataSource dataSource = new DriverManagerDataSource(); + dataSource.setDriverClassName("org.h2.Driver"); + dataSource.setUrl("jdbc:h2:mem:component;DB_CLOSE_DELAY=-1"); + dataSource.setUsername("admin"); + dataSource.setPassword("admin"); + return dataSource; + } + + /** + * Custom entity manager factory. + * + * @return factory bean + */ + @Bean + public LocalContainerEntityManagerFactoryBean entityManagerFactory() { + HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); + vendorAdapter.setGenerateDdl(true); + + LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean(); + factory.setJpaVendorAdapter(vendorAdapter); + factory.setPackagesToScan("cz.muni.pa165.component"); + factory.setDataSource(dataSource); + + return factory; + } +} + diff --git a/component/src/test/java/cz/muni/pa165/component/repository/ComponentRepositoryUnitTest.java b/component/src/test/java/cz/muni/pa165/component/repository/ComponentRepositoryUnitTest.java new file mode 100644 index 0000000000000000000000000000000000000000..5aba00f05c988ba00752f6f9f641616df1a63c26 --- /dev/null +++ b/component/src/test/java/cz/muni/pa165/component/repository/ComponentRepositoryUnitTest.java @@ -0,0 +1,101 @@ +package cz.muni.pa165.component.repository; + +import static cz.muni.pa165.component.util.ComponentTestUtil.getComponent; + +import cz.muni.pa165.component.data.model.CarComponent; +import cz.muni.pa165.component.data.repository.ComponentRepositoryInterface; +import java.math.BigDecimal; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * Unit tests for component repository. + */ +@RunWith(SpringRunner.class) +@DataJpaTest +public class ComponentRepositoryUnitTest { + + @Autowired + private TestEntityManager entityManager; + + @Autowired + private ComponentRepositoryInterface componentRepository; + + @Test + public void saveTest() { + Long id = 1L; + String name = "Engine"; + BigDecimal one = BigDecimal.ONE; + String manufacturer = "Ferrari"; + var carComponent = getComponent(id, name, one, manufacturer); + + var savedComponent = componentRepository.save(carComponent); + + Assertions.assertEquals(savedComponent, carComponent); + Assertions.assertEquals(entityManager.find(CarComponent.class, 1L).getId(), 1); + } + + @Test + public void findByIdTest() { + + Long id = 2L; + String name = "Engine"; + BigDecimal one = BigDecimal.ONE; + String manufacturer = "Ferrari"; + var carComponent = getComponent(id, name, one, manufacturer); + + var savedComponent = componentRepository.save(carComponent); + var component = componentRepository.findById(savedComponent.getId()).orElseThrow(); + + Assertions.assertAll( + () -> Assertions.assertEquals(component.getId(), savedComponent.getId()), + () -> Assertions.assertEquals(component.getName(), savedComponent.getName()), + () -> Assertions.assertEquals(component.getPrice(), savedComponent.getPrice()), + () -> Assertions.assertEquals(component.getWeight(), savedComponent.getWeight()), + () -> Assertions.assertEquals(component.getManufacturer(), savedComponent.getManufacturer()) + ); + } + + @Test + public void findByNonExistingIdTest() { + Assertions.assertThrows(Exception.class, () -> componentRepository.findById(-1L).orElseThrow()); + } + + @Test + public void deleteByIdTest() { + Long id = 3L; + String name = "Engine"; + BigDecimal one = BigDecimal.ONE; + String manufacturer = "Ferrari"; + var carComponent = getComponent(id, name, one, manufacturer); + + var savedComponent = componentRepository.save(carComponent); + componentRepository.delete(savedComponent); + + Assertions.assertThrows(Exception.class, () -> componentRepository + .findById(savedComponent.getId()).orElseThrow()); + } + + @Test + public void testFindAll() { + Long id1 = 4L; + Long id2 = 5L; + String name = "Engine"; + BigDecimal one = BigDecimal.ONE; + String manufacturer = "Ferrari"; + var carComponent1 = getComponent(id1, name, one, manufacturer); + var carComponent2 = getComponent(id2, name, one, manufacturer); + + componentRepository.save(carComponent1); + componentRepository.save(carComponent2); + + var components = componentRepository.findAll(); + Assertions.assertEquals(2, components.size()); + } + +} diff --git a/component/src/test/java/cz/muni/pa165/component/rest/ComponentControllerIntegrationTest.java b/component/src/test/java/cz/muni/pa165/component/rest/ComponentControllerIntegrationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..3ec3bf26d694b868f40711ef9344e7151554ade4 --- /dev/null +++ b/component/src/test/java/cz/muni/pa165/component/rest/ComponentControllerIntegrationTest.java @@ -0,0 +1,145 @@ +package cz.muni.pa165.component.rest; + +import static cz.muni.pa165.component.util.ComponentTestUtil.getComponent; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +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.MockMvcResultMatchers.status; + +import com.fasterxml.jackson.databind.ObjectMapper; +import cz.muni.pa165.component.data.model.CarComponent; +import cz.muni.pa165.component.data.repository.ComponentRepositoryInterface; +import java.math.BigDecimal; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; + +@SpringBootTest +@AutoConfigureMockMvc +class ComponentControllerIntegrationTest { + + @Autowired + private MockMvc mockMvc; + + @MockBean + private ComponentRepositoryInterface componentRepositoryMock; + + @Autowired + private ObjectMapper objectMapper; + + @Test + void postIntegrationTest() throws Exception { + + Long id = 1L; + String name = "Engine"; + BigDecimal one = BigDecimal.ONE; + String manufacturer = "Ferrari"; + var carComponent = getComponent(id, name, one, manufacturer); + + given(componentRepositoryMock.save(any(CarComponent.class))).willReturn(carComponent); + + String response = mockMvc.perform(post("/component/") + .content(objectMapper.writeValueAsString(carComponent)) + .contentType(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(); + + CarComponent componentResponse = objectMapper.readValue(response, CarComponent.class); + assertAll( + () -> assertEquals(carComponent.getId(), componentResponse.getId()), + () -> assertEquals(carComponent.getName(), componentResponse.getName()), + () -> assertEquals(carComponent.getWeight(), componentResponse.getWeight()), + () -> assertEquals(carComponent.getPrice(), componentResponse.getPrice()), + () -> assertEquals(carComponent.getManufacturer(), componentResponse.getManufacturer()) + ); + } + + @Test + void deleteIntegrationTest() throws Exception { + + Long id = 1L; + String name = "Engine"; + BigDecimal one = BigDecimal.ONE; + String manufacturer = "Ferrari"; + var carComponent = getComponent(id, name, one, manufacturer); + + given(componentRepositoryMock.findById(anyLong())).willReturn( + Optional.of(carComponent)); + + String expectedResponse = "Car component with id: 1was successfully deleted"; + String actualResponse = mockMvc.perform(delete("/component/") + .param("componentId", String.valueOf(id)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(); + + Assertions.assertEquals(expectedResponse, actualResponse); + } + + @Test + void getComponentByIdTest() throws Exception { + + Long id = 1L; + String name = "Engine"; + BigDecimal one = BigDecimal.ONE; + String manufacturer = "Ferrari"; + var carComponent = getComponent(id, name, one, manufacturer); + + given(componentRepositoryMock.findById(id)).willReturn(Optional.of(carComponent)); + + String response = mockMvc.perform(get("/component/id") + .param("componentId", String.valueOf(id)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(); + var componentResponse = objectMapper.readValue(response, CarComponent.class); + + Assertions.assertAll( + () -> Assertions.assertEquals(id, componentResponse.getId()), + () -> Assertions.assertEquals(name, componentResponse.getName()), + () -> Assertions.assertEquals(one, componentResponse.getWeight()), + () -> Assertions.assertEquals(one, componentResponse.getPrice()), + () -> Assertions.assertEquals(manufacturer, componentResponse.getManufacturer()) + ); + } + + @Test + void getAllComponentsTest() throws Exception { + + Long id = 1L; + String name = "Engine"; + BigDecimal one = BigDecimal.ONE; + String manufacturer = "Ferrari"; + var carComponent = getComponent(id, name, one, manufacturer); + + given(componentRepositoryMock.findAll()).willReturn(List.of(carComponent)); + + String response = mockMvc.perform(get("/component/") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(); + + var componentResponse = objectMapper.readValue(response, CarComponent[].class); + Assertions.assertAll( + () -> Assertions.assertEquals(id, componentResponse[0].getId()), + () -> Assertions.assertEquals(name, componentResponse[0].getName()), + () -> Assertions.assertEquals(one, componentResponse[0].getWeight()), + () -> Assertions.assertEquals(one, componentResponse[0].getPrice()), + () -> Assertions.assertEquals(manufacturer, componentResponse[0].getManufacturer()) + ); + } + +} + diff --git a/component/src/test/java/cz/muni/pa165/component/rest/ComponentControllerUnitTest.java b/component/src/test/java/cz/muni/pa165/component/rest/ComponentControllerUnitTest.java new file mode 100644 index 0000000000000000000000000000000000000000..3b2a20d148ba283c633fdf52570e9f16fd0736b6 --- /dev/null +++ b/component/src/test/java/cz/muni/pa165/component/rest/ComponentControllerUnitTest.java @@ -0,0 +1,126 @@ +package cz.muni.pa165.component.rest; + +import static cz.muni.pa165.component.util.ComponentTestUtil.getComponent; +import static cz.muni.pa165.component.util.ComponentTestUtil.getComponentResponseDto; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +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.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.fasterxml.jackson.databind.ObjectMapper; +import cz.muni.pa165.common_library.dtos.CarComponentRequestDto; +import cz.muni.pa165.common_library.dtos.CarComponentResponseDto; +import cz.muni.pa165.component.data.model.CarComponent; +import cz.muni.pa165.component.service.ComponentService; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +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.web.servlet.MockMvc; + +@WebMvcTest(ComponentController.class) +class ComponentControllerUnitTest { + + @Autowired + private MockMvc mockMvc; + + @MockBean + private ComponentService componentService; + + @Autowired + private ObjectMapper objectMapper; + + @Test + void createCarComponentTest() throws Exception { + + Long id = 1L; + String name = "Engine"; + BigDecimal one = BigDecimal.ONE; + String manufacturer = "Ferrari"; + var carComponent = getComponent(id, name, one, manufacturer); + var carComponentResponseDto = getComponentResponseDto(id, name, one, manufacturer); + + given(componentService.postCarComponent(CarComponentRequestDto.builder().build())) + .willReturn(carComponentResponseDto); + mockMvc.perform(post("/component/") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(carComponent))) + .andExpect(status().isOk()); + } + + @Test + void nonExistingPathTest() throws Exception { + mockMvc.perform(post("/invalidPath")) + .andExpect(status().isNotFound()); + } + + @Test + void createComponentWithNullValuesTest() throws Exception { + + CarComponent carComponent = new CarComponent(); + CarComponentRequestDto carComponentRequestDto = new CarComponentRequestDto(); + CarComponentResponseDto carComponentResponseDto = new CarComponentResponseDto(); + + given(componentService.postCarComponent(carComponentRequestDto)) + .willReturn(carComponentResponseDto); + mockMvc.perform(post("/component/").contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(carComponent))) + .andExpect(status().isBadRequest()); + } + + @Test + void deleteCarComponentTest() throws Exception { + + Long id = 1L; + + String expectedResponse = "Car component with id: 1was successfully deleted"; + given(componentService.deleteById(id)).willReturn(expectedResponse); + String actualResponse = mockMvc.perform(delete("/component/") + .param("componentId", String.valueOf(id)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn().getResponse().getContentAsString(); + Assertions.assertEquals(expectedResponse, actualResponse); + } + + @Test + void getCarComponentTest() throws Exception { + + Long id = 1L; + String name = "Engine"; + BigDecimal one = BigDecimal.ONE; + String manufacturer = "Ferrari"; + var carComponentResponseDto = getComponentResponseDto(id, name, one, manufacturer); + + given(componentService.getCarComponentById(id)).willReturn(carComponentResponseDto); + mockMvc.perform(get("/component/id") + .param("componentId", String.valueOf(id)) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id").value(id)) + .andExpect(jsonPath("$.name").value(name)) + .andExpect(jsonPath("$.price").value(one)) + .andExpect(jsonPath("$.weight").value(one)) + .andExpect(jsonPath("$.manufacturer").value(manufacturer)); + } + + @Test + void getAllCarComponentsTest() throws Exception { + + List<CarComponentResponseDto> components = new ArrayList<>(); + + given(componentService.getAllCarComponents()).willReturn(components); + mockMvc.perform(get("/component/") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + } + +} + diff --git a/component/src/test/java/cz/muni/pa165/component/rest/ComponentInitControllerItTest.java b/component/src/test/java/cz/muni/pa165/component/rest/ComponentInitControllerItTest.java deleted file mode 100644 index 3c9619a4f578deb24a97e86d847c650c0938ea3a..0000000000000000000000000000000000000000 --- a/component/src/test/java/cz/muni/pa165/component/rest/ComponentInitControllerItTest.java +++ /dev/null @@ -1,25 +0,0 @@ -package cz.muni.pa165.component.rest; - -import com.fasterxml.jackson.databind.ObjectMapper; -import cz.muni.pa165.component.service.ComponentService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.web.servlet.MockMvc; - - -@SpringBootTest -@AutoConfigureMockMvc -class ComponentInitControllerItTest { - - @Autowired - private MockMvc mockMvc; - - @Autowired - private ObjectMapper objectMapper; - - @Autowired - ComponentService componentInitService; - - -} diff --git a/component/src/test/java/cz/muni/pa165/component/rest/ComponentInitControllerUnitTest.java b/component/src/test/java/cz/muni/pa165/component/rest/ComponentInitControllerUnitTest.java deleted file mode 100644 index 4586f73d2bd56cdd90c541c576fb05ec4de034e0..0000000000000000000000000000000000000000 --- a/component/src/test/java/cz/muni/pa165/component/rest/ComponentInitControllerUnitTest.java +++ /dev/null @@ -1,21 +0,0 @@ -package cz.muni.pa165.component.rest; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.test.web.servlet.MockMvc; - -@WebMvcTest(ComponentController.class) -class ComponentInitControllerUnitTest { - - @Autowired - private MockMvc mockMvc; - - //@MockBean - //private ComponentInitFacade mockComponentInitFacade; - - @Autowired - private ObjectMapper objectMapper; - - -} diff --git a/component/src/test/java/cz/muni/pa165/component/util/ComponentTestUtil.java b/component/src/test/java/cz/muni/pa165/component/util/ComponentTestUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..d2927bde8100be7b7731bdac7463dc679de9090c --- /dev/null +++ b/component/src/test/java/cz/muni/pa165/component/util/ComponentTestUtil.java @@ -0,0 +1,76 @@ +package cz.muni.pa165.component.util; + +import cz.muni.pa165.common_library.dtos.CarComponentRequestDto; +import cz.muni.pa165.common_library.dtos.CarComponentResponseDto; +import cz.muni.pa165.component.data.model.CarComponent; +import java.math.BigDecimal; + +/** + * Helper class for creating Component objects. + */ +public class ComponentTestUtil { + + /** + * Returns a CarComponent instance initialized with the given parameters. + * + * @param id the ID of the car component + * @param name the name of the car component + * @param decimal the weight and price of the car component + * @param manufacturer the manufacturer of the car component + * @return a CarComponent instance initialized with the given parameters + */ + public static CarComponent getComponent(Long id, + String name, + BigDecimal decimal, + String manufacturer) { + return CarComponent.builder() + .id(id) + .name(name) + .weight(decimal) + .price(decimal) + .manufacturer(manufacturer) + .build(); + } + + /** + * Returns a CarComponentResponseDto instance initialized with the given parameters. + * + * @param id the ID of the car component + * @param name the name of the car component + * @param decimal the weight and price of the car component + * @param manufacturer the manufacturer of the car component + * @return a CarComponentResponseDto instance initialized with the given parameters + */ + public static CarComponentResponseDto getComponentResponseDto(Long id, + String name, + BigDecimal decimal, + String manufacturer) { + return CarComponentResponseDto.builder() + .id(id) + .name(name) + .weight(decimal) + .price(decimal) + .manufacturer(manufacturer) + .build(); + } + + /** + * Returns a CarComponentResponseDto instance initialized with the given parameters. + * + * @param name the name of the car component + * @param decimal the weight and price of the car component + * @param manufacturer the manufacturer of the car component + * @return a CarComponentResponseDto instance initialized with the given parameters + */ + public static CarComponentRequestDto getComponentRequestDto(String name, + BigDecimal decimal, + String manufacturer) { + return CarComponentRequestDto.builder() + .name(name) + .weight(decimal) + .price(decimal) + .manufacturer(manufacturer) + .build(); + } + +} diff --git a/driver/src/main/java/cz/muni/pa165/driver/data/repository/DriverRepository.java b/driver/src/main/java/cz/muni/pa165/driver/data/repository/DriverRepository.java index 6a5eb0cd0eef31040355dec815d53a3840791106..ed33361037a8a8a409581ec0ca2c4f90cbb3d480 100644 --- a/driver/src/main/java/cz/muni/pa165/driver/data/repository/DriverRepository.java +++ b/driver/src/main/java/cz/muni/pa165/driver/data/repository/DriverRepository.java @@ -1,7 +1,11 @@ package cz.muni.pa165.driver.data.repository; import cz.muni.pa165.driver.data.model.Driver; +import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; /** @@ -10,4 +14,10 @@ import org.springframework.stereotype.Repository; @Repository public interface DriverRepository extends JpaRepository<Driver, Long> { + @Query("SELECT d FROM Driver d WHERE d.id = :id") + Optional<Driver> findById(@Param("id") Long id); + + @Query("SELECT d FROM Driver d") + List<Driver> findAll(); + } diff --git a/race/src/main/java/cz/muni/pa165/race/data/repository/RaceRepository.java b/race/src/main/java/cz/muni/pa165/race/data/repository/RaceRepository.java index b1bdd7be9675172e847cfbbfd19ab69e1fb066e5..3bd94a36e827c4fdb12130e00f45e6190365e382 100644 --- a/race/src/main/java/cz/muni/pa165/race/data/repository/RaceRepository.java +++ b/race/src/main/java/cz/muni/pa165/race/data/repository/RaceRepository.java @@ -26,4 +26,5 @@ public interface RaceRepository extends JpaRepository<Race, Long> { + " JOIN r.raceInfo ri " + "WHERE ri.location = :location") List<Race> findRacesByLocation(@Param("location") Location raceLocation); + } diff --git a/race/src/main/java/cz/muni/pa165/race/data/repository/SeasonRepository.java b/race/src/main/java/cz/muni/pa165/race/data/repository/SeasonRepository.java index 65b0c2dda424cedcb3fe5f97f9551998b12f2cae..ecea648538411110f6aadcc15ea1895520d95b73 100644 --- a/race/src/main/java/cz/muni/pa165/race/data/repository/SeasonRepository.java +++ b/race/src/main/java/cz/muni/pa165/race/data/repository/SeasonRepository.java @@ -1,7 +1,11 @@ package cz.muni.pa165.race.data.repository; import cz.muni.pa165.race.data.model.Season; +import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; /** @@ -9,4 +13,11 @@ import org.springframework.stereotype.Repository; */ @Repository public interface SeasonRepository extends JpaRepository<Season, Long> { + + @Query("SELECT s FROM Season s WHERE s.id = :id") + Optional<Season> findById(@Param("id") Long id); + + @Query("SELECT s FROM Season s") + List<Season> findAll(); + } diff --git a/race/src/main/java/cz/muni/pa165/race/service/DbGetter.java b/race/src/main/java/cz/muni/pa165/race/service/DbGetter.java new file mode 100644 index 0000000000000000000000000000000000000000..e8f0b5bc40e854f00e2c2e60d1b91312d6cb9913 --- /dev/null +++ b/race/src/main/java/cz/muni/pa165/race/service/DbGetter.java @@ -0,0 +1,41 @@ +package cz.muni.pa165.race.service; + +import cz.muni.pa165.common_library.dtos.CarResponseDto; +import cz.muni.pa165.common_library.dtos.DriverDto; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +/** + * Getter for driver and car from appropriate modules. + */ +@Component +public class DbGetter { + + @Autowired + RestTemplate client; + + /** + * Calls driver module for a driver given by id. + * + * @param driverId id of a driver. + * @return driverDto. + */ + public DriverDto getDriver(Long driverId) { + var response = + client.getForEntity("http://localhost:8083/driver/get/id=" + driverId, DriverDto.class); + return response.getBody(); + } + + /** + * Calls car module for a car given by id. + * + * @param carId id of a car. + * @return carDto. + */ + public CarResponseDto getCar(Long carId) { + var response = + client.getForEntity("http://localhost:8082/car/?carId=" + carId, CarResponseDto.class); + return response.getBody(); + } +} diff --git a/race/src/main/java/cz/muni/pa165/race/service/RaceService.java b/race/src/main/java/cz/muni/pa165/race/service/RaceService.java index ad0ff086584e5b069e37b0b1a937903042b8bc0f..5d6dc7afd3ef7aa06161add29f21ef7580a26761 100644 --- a/race/src/main/java/cz/muni/pa165/race/service/RaceService.java +++ b/race/src/main/java/cz/muni/pa165/race/service/RaceService.java @@ -1,7 +1,5 @@ package cz.muni.pa165.race.service; -import cz.muni.pa165.common_library.dtos.CarResponseDto; -import cz.muni.pa165.common_library.dtos.DriverDto; import cz.muni.pa165.common_library.dtos.Location; import cz.muni.pa165.common_library.dtos.RaceDriverCarDto; import cz.muni.pa165.common_library.dtos.RaceDto; @@ -19,7 +17,6 @@ import java.util.Set; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.client.RestTemplate; /** * Service for managing races. @@ -33,7 +30,7 @@ public class RaceService implements RaceServiceI { RaceRepository raceRepository; @Autowired - RestTemplate client; + DbGetter dbGetter; RaceService(RaceRepository raceRepository) { this.raceRepository = raceRepository; @@ -48,6 +45,45 @@ public class RaceService implements RaceServiceI { @Transactional public RaceDto postRace(RaceDto raceDto) { raceDto.setId(null); + + if ((raceDto.getDriverOne() != null) + && (raceDto.getDriverTwo() != null)) { + + if (raceDto.getDriverOne().getDriverId() != null + && raceDto.getDriverTwo().getDriverId() != null) { + if (Objects.equals(raceDto.getDriverOne().getCarId(), + raceDto.getDriverTwo().getCarId())) { + throw new DatabaseException("Cant assign same car to both drivers"); + } + + if (Objects.equals(raceDto.getDriverOne().getDriverId(), + raceDto.getDriverTwo().getDriverId())) { + throw new DatabaseException("Cant assign same driver to both drivers"); + } + } + } + + if (raceDto.getDriverOne() != null) { + if (raceDto.getDriverOne().getDriverId() != null) { + dbGetter.getDriver(raceDto.getDriverOne().getDriverId()); + } + if (raceDto.getDriverOne().getCarId() != null) { + dbGetter.getCar(raceDto.getDriverOne().getCarId()); + } + } + + if (raceDto.getDriverTwo() != null) { + if (raceDto.getDriverTwo().getDriverId() != null) { + dbGetter.getDriver(raceDto.getDriverTwo().getDriverId()); + } + if (raceDto.getDriverTwo().getCarId() != null) { + dbGetter.getCar(raceDto.getDriverTwo().getCarId()); + } + } + if (raceDto.getDriverTwo() != null && raceDto.getDriverTwo().getDriverId() != null) { + dbGetter.getDriver(raceDto.getDriverTwo().getDriverId()); + } + return convertRace(raceRepository.save(convertRaceDto(raceDto))); } @@ -70,12 +106,12 @@ public class RaceService implements RaceServiceI { var race = raceRepository.findById(raceId) .orElseThrow(() -> new DatabaseException("Race not found")); - var driver = getDriver(driverId); + var driver = dbGetter.getDriver(driverId); if (race.getDriver2() != null && Objects.equals(race.getDriver2().getDriverId(), driverId)) { throw new BadRequestException("Driver already assigned to the race as driver two"); } - var car = getCar(carId); + var car = dbGetter.getCar(carId); if (race.getDriver2() != null && Objects.equals(race.getDriver2().getCarId(), carId)) { throw new BadRequestException("Car is already assigned to the race for driver two"); } @@ -92,11 +128,11 @@ public class RaceService implements RaceServiceI { var race = raceRepository.findById(raceId) .orElseThrow(() -> new DatabaseException("Race not found")); - var driver = getDriver(driverId); + var driver = dbGetter.getDriver(driverId); if (race.getDriver1() != null && Objects.equals(race.getDriver1().getDriverId(), driverId)) { throw new BadRequestException("Driver already assigned to the race as driver one"); } - var car = getCar(carId); + var car = dbGetter.getCar(carId); if (race.getDriver1() != null && Objects.equals(race.getDriver1().getCarId(), carId)) { throw new BadRequestException("Car is already assigned to the race for driver two"); } @@ -133,7 +169,7 @@ public class RaceService implements RaceServiceI { /** * Assigns positions for driver number two. * - * @param raceId race id. + * @param raceId race id. * @param position position of driver two. * @return updated race. */ @@ -148,7 +184,7 @@ public class RaceService implements RaceServiceI { /** * Assigns positions for driver number one. * - * @param raceId race id. + * @param raceId race id. * @param position position of driver one. * @return updated race. */ @@ -263,15 +299,5 @@ public class RaceService implements RaceServiceI { return raceDto; } - private DriverDto getDriver(Long driverId) { - var response = - client.getForEntity("http://localhost:8083/driver/get/id=" + driverId, DriverDto.class); - return response.getBody(); - } - private CarResponseDto getCar(Long carId) { - var response = - client.getForEntity("http://localhost:8082/car/?carId=" + carId, CarResponseDto.class); - return response.getBody(); - } } diff --git a/race/src/test/java/cz/muni/pa165/race/rest/RaceControllerTest.java b/race/src/test/java/cz/muni/pa165/race/rest/RaceControllerTest.java index 05249babd0536b490d9bc8b49cc493bd369fad7c..39665d916965a9603379237cae4c234eae5b1b50 100644 --- a/race/src/test/java/cz/muni/pa165/race/rest/RaceControllerTest.java +++ b/race/src/test/java/cz/muni/pa165/race/rest/RaceControllerTest.java @@ -1,18 +1,5 @@ package cz.muni.pa165.race.rest; -import cz.muni.pa165.race.data.model.Race; -import cz.muni.pa165.race.data.repository.RaceRepository; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.http.MediaType; -import org.springframework.test.web.servlet.MockMvc; -import java.util.List; -import java.util.Optional; - import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.BDDMockito.given; @@ -21,9 +8,24 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; 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.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import cz.muni.pa165.common_library.dtos.CarResponseDto; +import cz.muni.pa165.common_library.dtos.DriverDto; +import cz.muni.pa165.race.data.model.Race; +import cz.muni.pa165.race.data.repository.RaceRepository; +import cz.muni.pa165.race.service.DbGetter; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; @SpringBootTest @AutoConfigureMockMvc @@ -39,8 +41,22 @@ class RaceControllerTest { } } """; - private String expectedMessagePost = "{\"id\":1,\"raceInfo\":{\"location\":\"MONACO\",\"name\":\"Monaco Grand Prix 2023\",\"prizePool\":30000000},\"driverOne\":{\"driverId\":1,\"carId\":1,\"position\":null},\"driverTwo\":{\"driverId\":2,\"carId\":2,\"position\":null}}"; - + private String expectedMessagePost = "{\"id\":1,\"raceInfo\":{\"location\":\"MONACO\"," + + "\"name\":\"Monaco Grand Prix 2023\",\"prizePool\":30000000},\"driverOne\"" + + ":{\"driverId\":1,\"carId\":1,\"position\":null},\"driverTwo\":{\"driverId\"" + + ":2,\"carId\":2,\"position\":null}}"; + private String expectedMessageAssignTwo = "{\"id\":1,\"raceInfo\":{\"location\":" + + "\"MONACO\",\"name\":\"Monaco Grand Prix 2023\",\"prizePool\":30000000}," + + "\"driverOne\":{\"driverId\":1,\"carId\":1,\"position\":null},\"driverTwo\"" + + ":{\"driverId\":1,\"carId\":1,\"position\":null}}"; + private String expectedMessageGet = "{\"id\":1,\"raceInfo\":{\"location\":\"MONACO\"" + + ",\"name\":\"Monaco Grand Prix 2023\",\"prizePool\":30000000},\"driverOne\"" + + ":{\"driverId\":1,\"carId\":1,\"position\":null},\"driverTwo\":{\"driverId\"" + + ":2,\"carId\":2,\"position\":null}}"; + private String expectedMessageGetAll = "[{\"id\":1,\"raceInfo\":{\"location\"" + + ":\"MONACO\",\"name\":\"Monaco Grand Prix 2023\",\"prizePool\":30000000},\"" + + "driverOne\":{\"driverId\":1,\"carId\":1,\"position\":null},\"driverTwo\":{\"" + + "driverId\":2,\"carId\":2,\"position\":null}}]"; @Autowired private MockMvc mockMvc; @@ -48,6 +64,9 @@ class RaceControllerTest { @MockBean private RaceRepository raceRepository; + @MockBean + private DbGetter dbGetter; + @BeforeEach void setup() { Race raceDao = RaceTestUtil.getDaoRace(); @@ -56,6 +75,10 @@ class RaceControllerTest { given(raceRepository.findById(anyLong())).willReturn( Optional.of(raceDao)); given(raceRepository.findAll()).willReturn(List.of(raceDao)); + CarResponseDto carDao = RaceTestUtil.getCarDao(); + given(dbGetter.getCar(anyLong())).willReturn(carDao); + DriverDto driverDto = RaceTestUtil.getDriverDao(); + given(dbGetter.getDriver(anyLong())).willReturn(driverDto); } @@ -64,7 +87,6 @@ class RaceControllerTest { var request = post("/race/") .content(bodyContent) .contentType(MediaType.APPLICATION_JSON_VALUE); - this.mockMvc.perform(request) .andDo(print()) .andExpect(status().isOk()) @@ -74,7 +96,6 @@ class RaceControllerTest { @Test void deleteRace() throws Exception { String expectedMessage = "Race with id: 1was succesfully deleted"; - var requestDelete = delete("/race/") .param("raceId", "1") .contentType(MediaType.APPLICATION_JSON_VALUE); @@ -86,26 +107,22 @@ class RaceControllerTest { @Test void getExistingRace() throws Exception { - String expectedMessage = "{\"id\":1,\"raceInfo\":{\"location\":\"MONACO\",\"name\":\"Monaco Grand Prix 2023\",\"prizePool\":30000000},\"driverOne\":{\"driverId\":1,\"carId\":1,\"position\":null},\"driverTwo\":{\"driverId\":2,\"carId\":2,\"position\":null}}"; - var requestGet = get("/race/id") .param("raceId", "1") .contentType(MediaType.APPLICATION_JSON_VALUE); this.mockMvc.perform(requestGet) .andDo(print()) .andExpect(status().isOk()) - .andExpect(content().string(expectedMessage)); + .andExpect(content().string(expectedMessageGet)); } @Test void getAllRaces() throws Exception { var requestGet = get("/race/"); - String expectedMessage = "[{\"id\":1,\"raceInfo\":{\"location\":\"MONACO\",\"name\":\"Monaco Grand Prix 2023\",\"prizePool\":30000000},\"driverOne\":{\"driverId\":1,\"carId\":1,\"position\":null},\"driverTwo\":{\"driverId\":2,\"carId\":2,\"position\":null}}]"; - this.mockMvc.perform(requestGet) .andDo(print()) .andExpect(status().isOk()) - .andExpect(content().string(expectedMessage)); + .andExpect(content().string(expectedMessageGetAll)); } @Test @@ -113,13 +130,25 @@ class RaceControllerTest { var requestAssign = patch("/race/assignDriverOne") .param("driverOneId", "1") .param("raceId", "1") - .param("carId", "2") + .param("carId", "1") .contentType(MediaType.APPLICATION_JSON_VALUE); - this.mockMvc.perform(requestAssign) .andDo(print()) .andExpect(status().isOk()) .andExpect(content().string(expectedMessagePost)); } + @Test + void assignDriverTwo() throws Exception { + var requestAssign = patch("/race/assignDriverTwo") + .param("driverTwoId", "2") + .param("raceId", "2") + .param("carId", "2") + .contentType(MediaType.APPLICATION_JSON_VALUE); + this.mockMvc.perform(requestAssign) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(content().string(expectedMessageAssignTwo)); + } + } diff --git a/race/src/test/java/cz/muni/pa165/race/rest/RaceTestUtil.java b/race/src/test/java/cz/muni/pa165/race/rest/RaceTestUtil.java index 7606cb9b4b26666ccf9602499725af47818942e1..164179e3da60e8707866bd623ab3b462a4f1e49d 100644 --- a/race/src/test/java/cz/muni/pa165/race/rest/RaceTestUtil.java +++ b/race/src/test/java/cz/muni/pa165/race/rest/RaceTestUtil.java @@ -1,13 +1,19 @@ package cz.muni.pa165.race.rest; +import cz.muni.pa165.common_library.dtos.CarResponseDto; +import cz.muni.pa165.common_library.dtos.DriverDto; import cz.muni.pa165.common_library.dtos.Location; -import cz.muni.pa165.common_library.dtos.RaceDto; import cz.muni.pa165.race.data.model.Race; /** - * @author Oto Stanko + * Util functions for race tests. */ public class RaceTestUtil { + /** + * Returns a created race. + * + * @return a race. + */ public static Race getDaoRace() { return Race.builder() .id(1L) @@ -31,4 +37,11 @@ public class RaceTestUtil { .build(); } + public static CarResponseDto getCarDao() { + return new CarResponseDto(1L, null, null, 1L); + } + + public static DriverDto getDriverDao() { + return new DriverDto(1L, "Name", "Surname"); + } } diff --git a/race/src/test/java/cz/muni/pa165/race/rest/SeasonControllerTest.java b/race/src/test/java/cz/muni/pa165/race/rest/SeasonControllerTest.java index 6164708954390fad410090539a09da6e5640bd09..bc1ce050604d6f00faae2409ba25fae8be4d9b0b 100644 --- a/race/src/test/java/cz/muni/pa165/race/rest/SeasonControllerTest.java +++ b/race/src/test/java/cz/muni/pa165/race/rest/SeasonControllerTest.java @@ -1,19 +1,5 @@ package cz.muni.pa165.race.rest; -import cz.muni.pa165.race.data.model.Season; -import cz.muni.pa165.race.data.repository.SeasonRepository; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.http.MediaType; -import org.springframework.test.web.servlet.MockMvc; - -import java.util.List; -import java.util.Optional; - import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.BDDMockito.given; @@ -25,6 +11,24 @@ import static org.springframework.test.web.servlet.result.MockMvcResultHandlers. import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import cz.muni.pa165.race.data.model.Race; +import cz.muni.pa165.race.data.model.Season; +import cz.muni.pa165.race.data.repository.RaceRepository; +import cz.muni.pa165.race.data.repository.SeasonRepository; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; + +/** + * Tests for season controller. + */ @SpringBootTest @AutoConfigureMockMvc public class SeasonControllerTest { @@ -36,7 +40,11 @@ public class SeasonControllerTest { } """; private String expectedMessagePost = "{\"id\":1,\"year\":2023,\"races\":[]}"; - + private String expectedMessageDelete = "Season with id: 1was succesfully deleted"; + private String expectedMessageGet = "{\"id\":1,\"year\":2023,\"races\":[]}"; + private String expectedMessageGetAll = "[{\"id\":1,\"year\":2023,\"races\":[]}]"; + private String expectedMessageAddRace = "{\"id\":1,\"year\":2023,\"races\":[{\"" + + "id\":1,\"name\":\"Monaco Grand Prix 2023\"}]}"; @Autowired private MockMvc mockMvc; @@ -44,14 +52,20 @@ public class SeasonControllerTest { @MockBean private SeasonRepository seasonRepository; + @MockBean + private RaceRepository raceRepository; + @BeforeEach void setup() { Season seasonDao = SeasonTestUtil.getDaoSeason(); + Race raceDao = RaceTestUtil.getDaoRace(); given(seasonRepository.save(any(Season.class))).willReturn( seasonDao); given(seasonRepository.findById(anyLong())).willReturn( Optional.of(seasonDao)); given(seasonRepository.findAll()).willReturn(List.of(seasonDao)); + given(raceRepository.findById(anyLong())).willReturn( + Optional.of(raceDao)); } @@ -60,7 +74,6 @@ public class SeasonControllerTest { var request = post("/season/") .content(bodyContent) .contentType(MediaType.APPLICATION_JSON_VALUE); - this.mockMvc.perform(request) .andDo(print()) .andExpect(status().isOk()) @@ -69,39 +82,33 @@ public class SeasonControllerTest { @Test void deleteRace() throws Exception { - String expectedMessage = "Season with id: 1was succesfully deleted"; - var requestDelete = delete("/season/") .param("seasonId", "1") .contentType(MediaType.APPLICATION_JSON_VALUE); this.mockMvc.perform(requestDelete) .andDo(print()) .andExpect(status().isOk()) - .andExpect(content().string(expectedMessage)); + .andExpect(content().string(expectedMessageDelete)); } @Test void getExistingRace() throws Exception { - String expectedMessage = "{\"id\":1,\"year\":2023,\"races\":[]}"; - var requestGet = get("/season/id") .param("seasonId", "1") .contentType(MediaType.APPLICATION_JSON_VALUE); this.mockMvc.perform(requestGet) .andDo(print()) .andExpect(status().isOk()) - .andExpect(content().string(expectedMessage)); + .andExpect(content().string(expectedMessageGet)); } @Test void getAllRaces() throws Exception { var requestGet = get("/season/"); - String expectedMessage = "[{\"id\":1,\"year\":2023,\"races\":[]}]"; - this.mockMvc.perform(requestGet) .andDo(print()) .andExpect(status().isOk()) - .andExpect(content().string(expectedMessage)); + .andExpect(content().string(expectedMessageGetAll)); } @Test @@ -109,11 +116,9 @@ public class SeasonControllerTest { var requestPatch = patch("/season/addRace") .param("seasonId", "1") .param("raceId", "1"); - String expectedMessage = "[{\"id\":1,\"year\":2023,\"races\":[]}]"; - this.mockMvc.perform(requestPatch) .andDo(print()) .andExpect(status().isOk()) - .andExpect(content().string(expectedMessage)); + .andExpect(content().string(expectedMessageAddRace)); } } diff --git a/race/src/test/java/cz/muni/pa165/race/rest/SeasonTestUtil.java b/race/src/test/java/cz/muni/pa165/race/rest/SeasonTestUtil.java index 4655a413d3a3233d94f251c4f1fbebebff724fa5..7c73931528a779d6004cb7db18fed7b641150cee 100644 --- a/race/src/test/java/cz/muni/pa165/race/rest/SeasonTestUtil.java +++ b/race/src/test/java/cz/muni/pa165/race/rest/SeasonTestUtil.java @@ -4,9 +4,14 @@ import cz.muni.pa165.race.data.model.Season; import java.util.ArrayList; /** - * @author Oto Stanko + * Utils for season tests. */ public class SeasonTestUtil { + /** + * Returns a created Season. + * + * @return a season. + */ public static Season getDaoSeason() { return Season.builder() .id(1L)