Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • xgulcik/pa165-formula-one-team
1 result
Show changes
Showing
with 770 additions and 76 deletions
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);
}
}
......@@ -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>
......
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();
}
}
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();
}
......@@ -8,6 +8,7 @@ import cz.muni.pa165.component.data.repository.ComponentRepositoryInterface;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
......@@ -34,6 +35,7 @@ public class ComponentService implements ComponentServiceInterface {
* @param carComponentId id of the component.
* @return found car component.
*/
@Transactional(readOnly = true)
public CarComponentResponseDto getCarComponentById(Long carComponentId) {
return carComponentConverter(componentRepository.findById(carComponentId).orElseThrow(
() -> new DatabaseException("Something went wrong when finding car component with id: "
......@@ -45,6 +47,7 @@ public class ComponentService implements ComponentServiceInterface {
*
* @return list of stored car components.
*/
@Transactional(readOnly = true)
public List<CarComponentResponseDto> getAllCarComponents() {
return componentRepository.findAll()
.stream()
......@@ -57,6 +60,7 @@ public class ComponentService implements ComponentServiceInterface {
*
* @param carComponentId of the car component for removal.
*/
@Transactional
public String deleteById(Long carComponentId) {
componentRepository.deleteById(carComponentId);
return "Car component with id: " + carComponentId + "was successfully deleted";
......
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;
}
}
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());
}
}
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())
);
}
}
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());
}
}
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;
}
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();
}
}
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();
}
......@@ -12,6 +12,7 @@ import java.util.List;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* Implementation of driver service.
......@@ -34,6 +35,7 @@ public class DriverServiceImpl implements DriverService {
* @param driverAddDto driver dto object
* @return dto of added driver
*/
@Transactional
public DriverResponseDto addDriver(DriverAddDto driverAddDto) {
var driver = driverMapper.convertToDriver(driverAddDto);
return driverMapper.convertToResponseDto(driverRepository.save(driver));
......@@ -46,6 +48,7 @@ public class DriverServiceImpl implements DriverService {
* @param driverUpdateDto data to be updated
* @return dto of updated driver
*/
@Transactional
public DriverResponseDto updateDriverById(Long id, DriverUpdateDto driverUpdateDto) {
var driver = driverRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Driver with given id not found."));
......@@ -59,6 +62,7 @@ public class DriverServiceImpl implements DriverService {
* @param driver existing driver
* @param driverUpdateDto driver update dto
*/
@Transactional
private static void updateDriverAttributes(Driver driver, DriverUpdateDto driverUpdateDto) {
if (driverUpdateDto.name() != null) {
driver.setName(driverUpdateDto.name());
......@@ -80,6 +84,7 @@ public class DriverServiceImpl implements DriverService {
* @param id driver id
* @return dto of removed driver
*/
@Transactional
public DriverResponseDto removeDriverById(Long id) {
var found = driverRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException(
......@@ -93,6 +98,7 @@ public class DriverServiceImpl implements DriverService {
*
* @return all stored drivers dto list
*/
@Transactional(readOnly = true)
public List<DriverInsightDto> getAllDrivers() {
System.out.println();
return driverRepository.findAll()
......@@ -107,6 +113,7 @@ public class DriverServiceImpl implements DriverService {
* @param id driver id
* @return found driver dto if successful
*/
@Transactional(readOnly = true)
public DriverInsightDto getDriverById(Long id) {
return driverMapper.convertToInsightDto(driverRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException(
......
......@@ -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);
}
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();
}
......@@ -88,7 +88,7 @@ public class RaceController {
return ResponseEntity.ok(raceService.assignPositionForDriverTwo(raceId, position));
}
@Operation(summary = "Assign position for driver two")
@Operation(summary = "Assign position for driver one")
@PatchMapping(path = "/assignPointsDriverOne",
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<RaceDto> assignPositionDriverOne(@RequestParam Long raceId,
......
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();
}
}
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;
......@@ -18,7 +16,7 @@ import java.util.Objects;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.transaction.annotation.Transactional;
/**
* Service for managing races.
......@@ -32,7 +30,7 @@ public class RaceService implements RaceServiceI {
RaceRepository raceRepository;
@Autowired
RestTemplate client;
DbGetter dbGetter;
RaceService(RaceRepository raceRepository) {
this.raceRepository = raceRepository;
......@@ -44,8 +42,48 @@ public class RaceService implements RaceServiceI {
* @param raceDto race to insert.
* @return inserted race.
*/
@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)));
}
......@@ -54,6 +92,7 @@ public class RaceService implements RaceServiceI {
*
* @param raceId race id
*/
@Transactional
public String deleteRace(Long raceId) {
raceRepository.deleteById(raceId);
return "Race with id: " + raceId + "was succesfully deleted";
......@@ -62,16 +101,17 @@ public class RaceService implements RaceServiceI {
/**
* Assigns driver one.
*/
@Transactional
public RaceDto assignDriverOne(Long driverId, Long raceId, Long carId) {
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");
}
......@@ -83,15 +123,16 @@ public class RaceService implements RaceServiceI {
/**
* Assigns driver two.
*/
@Transactional
public RaceDto assignDriverTwo(Long driverId, Long raceId, Long carId) {
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");
}
......@@ -108,6 +149,7 @@ public class RaceService implements RaceServiceI {
* @param raceId id of race.
* @return found race.
*/
@Transactional(readOnly = true)
public RaceDto findRaceById(Long raceId) {
return convertRace(raceRepository.findById(raceId).orElseThrow(
() -> new DatabaseException("Something went wrong when"
......@@ -119,6 +161,7 @@ public class RaceService implements RaceServiceI {
*
* @return found races.
*/
@Transactional(readOnly = true)
public List<RaceDto> findRaces() {
return raceRepository.findAll().stream().map(this::convertRace).toList();
}
......@@ -126,10 +169,11 @@ 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.
*/
@Transactional
public RaceDto assignPositionForDriverTwo(Long raceId, Integer position) {
var race =
raceRepository.findById(raceId).orElseThrow(() -> new DatabaseException("Race not found"));
......@@ -140,14 +184,15 @@ 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.
*/
@Transactional
public RaceDto assignPositionForDriverOne(Long raceId, Integer position) {
var race =
raceRepository.findById(raceId).orElseThrow(() -> new DatabaseException("Race not found"));
race.getDriver2().setFinalPosition(position);
race.getDriver1().setFinalPosition(position);
return convertRace(raceRepository.save(race));
}
......@@ -157,6 +202,7 @@ public class RaceService implements RaceServiceI {
* @param location location of the race.
* @return set if ids of most suitable drivers for given location.
*/
@Transactional(readOnly = true)
public Set<Long> findMostSuitableDriver(Location location) {
var races = raceRepository.findRacesByLocation(location);
Map<Long, Integer> driverWithPoints = new HashMap<>();
......@@ -253,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();
}
}
......@@ -10,6 +10,7 @@ import cz.muni.pa165.race.data.repository.SeasonRepository;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* Season service.
......@@ -33,6 +34,7 @@ public class SeasonService implements SeasonServiceI {
* @param seasonDto season to insert.
* @return inserted season.
*/
@Transactional
public SeasonDto postSeason(SeasonDto seasonDto) {
seasonDto.setId(null);
return seasonConverter(seasonRepository.save(seasonDtoConverter(seasonDto)));
......@@ -44,6 +46,7 @@ public class SeasonService implements SeasonServiceI {
* @param seasonId season id.
* @return found season.
*/
@Transactional(readOnly = true)
public SeasonDto getSeasonById(Long seasonId) {
return seasonConverter(seasonRepository.findById(seasonId).orElseThrow(
() -> new DatabaseException("Something went wrong when"
......@@ -55,6 +58,7 @@ public class SeasonService implements SeasonServiceI {
*
* @return found seasons.
*/
@Transactional(readOnly = true)
public List<SeasonDto> getAllSeasons() {
return seasonRepository.findAll()
.stream()
......@@ -68,6 +72,7 @@ public class SeasonService implements SeasonServiceI {
* @param seasonId season id.
* @return found season.
*/
@Transactional
public String deleteById(Long seasonId) {
seasonRepository.deleteById(seasonId);
return "Season with id: " + seasonId + "was succesfully deleted";
......@@ -80,6 +85,7 @@ public class SeasonService implements SeasonServiceI {
* @param seasonId season id.
* @return modified race.
*/
@Transactional(readOnly = true)
public SeasonDto addRace(Long raceId, Long seasonId) {
var season = seasonRepository.findById(seasonId)
.orElseThrow(() -> new DatabaseException("Season not found"));
......
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;
......@@ -22,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
......@@ -40,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;
......@@ -49,6 +64,9 @@ class RaceControllerTest {
@MockBean
private RaceRepository raceRepository;
@MockBean
private DbGetter dbGetter;
@BeforeEach
void setup() {
Race raceDao = RaceTestUtil.getDaoRace();
......@@ -57,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);
}
......@@ -65,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())
......@@ -75,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);
......@@ -87,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
......@@ -114,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));
}
}