finish 3rd practical
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
plugins {
|
||||
id("java")
|
||||
alias(libs.plugins.spring.boot)
|
||||
}
|
||||
|
||||
group = "ua.com.dxrkness"
|
||||
version = "1.0-SNAPSHOT"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// spring
|
||||
implementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES))
|
||||
implementation(libs.spring.boot.starter.web)
|
||||
implementation(libs.spring.boot.starter.web.test)
|
||||
|
||||
// http client
|
||||
implementation(libs.apache.http.client)
|
||||
|
||||
// openapi docs
|
||||
implementation(libs.springdoc.openapi.starter.webmvc.ui)
|
||||
|
||||
// testing
|
||||
testImplementation(platform(libs.junit.bom))
|
||||
testImplementation(libs.junit.jupiter)
|
||||
testRuntimeOnly(libs.junit.platform.launcher)
|
||||
|
||||
implementation(libs.jspecify)
|
||||
|
||||
implementation(project(":models"))
|
||||
implementation(project(":shared"))
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package ua.com.dxrkness;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class RouteServiceApp {
|
||||
static void main(String[] args) {
|
||||
SpringApplication.run(RouteServiceApp.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package ua.com.dxrkness.client;
|
||||
|
||||
import com.networknt.schema.InputFormat;
|
||||
import com.networknt.schema.Schema;
|
||||
import org.springframework.http.HttpStatusCode;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.ErrorResponseException;
|
||||
import org.springframework.web.client.RestClient;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
import tools.jackson.core.type.TypeReference;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
import ua.com.dxrkness.model.Freight;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public class FreightClient {
|
||||
private final RestClient freightRestClient;
|
||||
private final Schema freightSchema;
|
||||
private final JsonMapper mapper = JsonMapper.shared();
|
||||
|
||||
public FreightClient(RestClient freightRestClient, Schema freightSchema) {
|
||||
this.freightRestClient = freightRestClient;
|
||||
this.freightSchema = freightSchema;
|
||||
}
|
||||
|
||||
public Freight getById(long id) {
|
||||
var resp = freightRestClient.get().uri("/{id}", id)
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.retrieve()
|
||||
.onStatus(HttpStatusCode::is4xxClientError, (req, res) -> {
|
||||
throw new ResponseStatusException(res.getStatusCode(), res.getStatusText());
|
||||
})
|
||||
.body(String.class);
|
||||
System.out.println(resp);
|
||||
List<com.networknt.schema.Error> errs = freightSchema.validate(resp, InputFormat.JSON);
|
||||
if (!errs.isEmpty()) {
|
||||
System.out.println("Some errors have occured!");
|
||||
errs.forEach(err -> {
|
||||
System.out.print(err);
|
||||
});
|
||||
}
|
||||
return mapper.readValue(resp, new TypeReference<List<Freight>>() {
|
||||
}).getFirst();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package ua.com.dxrkness.client;
|
||||
|
||||
import com.networknt.schema.Error;
|
||||
import com.networknt.schema.InputFormat;
|
||||
import com.networknt.schema.Schema;
|
||||
import org.springframework.http.HttpStatusCode;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.client.RestClient;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
import tools.jackson.core.type.TypeReference;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
import ua.com.dxrkness.model.Vehicle;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public class VehicleClient {
|
||||
private final RestClient vehicleRestClient;
|
||||
private final Schema vehicleSchema;
|
||||
private final JsonMapper mapper = JsonMapper.shared();
|
||||
|
||||
public VehicleClient(RestClient vehicleRestClient, Schema vehicleSchema) {
|
||||
this.vehicleRestClient = vehicleRestClient;
|
||||
this.vehicleSchema = vehicleSchema;
|
||||
}
|
||||
|
||||
public Vehicle getById(long id) {
|
||||
var resp = vehicleRestClient.get().uri("/{id}", id)
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.retrieve()
|
||||
.onStatus(HttpStatusCode::is4xxClientError, (req, res) -> {
|
||||
throw new ResponseStatusException(res.getStatusCode(), res.getStatusText());
|
||||
})
|
||||
.body(String.class);
|
||||
System.out.println(resp);
|
||||
List<Error> errs = vehicleSchema.validate(resp, InputFormat.JSON);
|
||||
if (!errs.isEmpty()) {
|
||||
System.out.println("Some errors have occured!");
|
||||
errs.forEach(err -> {
|
||||
System.out.print(err);
|
||||
});
|
||||
}
|
||||
return mapper.readValue(resp, new TypeReference<List<Vehicle>>() {
|
||||
}).getFirst();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package ua.com.dxrkness.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.client.RestClient;
|
||||
|
||||
@Configuration
|
||||
public class ClientConfiguration {
|
||||
@Bean
|
||||
public RestClient vehicleRestClient() {
|
||||
return RestClient.create("http://localhost:8081/vehicles");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RestClient freightRestClient() {
|
||||
return RestClient.create("http://localhost:8080/freights");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
package ua.com.dxrkness.controller;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import ua.com.dxrkness.client.FreightClient;
|
||||
import ua.com.dxrkness.client.VehicleClient;
|
||||
import ua.com.dxrkness.model.Freight;
|
||||
import ua.com.dxrkness.model.Route;
|
||||
import ua.com.dxrkness.model.Vehicle;
|
||||
import ua.com.dxrkness.service.RouteService;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(
|
||||
value = "/routes",
|
||||
produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE},
|
||||
consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE}
|
||||
)
|
||||
@Tag(name = "Route", description = "Routes management")
|
||||
@NullMarked
|
||||
public class RouteController {
|
||||
private final RouteService routeService;
|
||||
private final VehicleClient vehicleClient;
|
||||
private final FreightClient freightClient;
|
||||
|
||||
public RouteController(RouteService routeService,
|
||||
VehicleClient vehicleClient,
|
||||
FreightClient freightClient) {
|
||||
this.routeService = routeService;
|
||||
this.vehicleClient = vehicleClient;
|
||||
this.freightClient = freightClient;
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "Get routes",
|
||||
description = "Get all routes or filter by freight ID/vehicle ID/status. May result in empty list!"
|
||||
)
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "Successfully retrieved routes"
|
||||
)
|
||||
@GetMapping(consumes = MediaType.ALL_VALUE)
|
||||
public List<Route> getAll(
|
||||
@Parameter(description = "Filter routes by freight ID")
|
||||
@RequestParam(name = "freightId", required = false) @Nullable Long freightId,
|
||||
@Parameter(description = "Filter routes by vehicle ID")
|
||||
@RequestParam(name = "vehicleId", required = false) @Nullable Long vehicleId,
|
||||
@Parameter(description = "Filter routes by status (PLANNED, IN_PROGRESS, COMPLETED, CANCELLED)")
|
||||
@RequestParam(name = "status", required = false) Route.@Nullable Status status) {
|
||||
if (status != null) {
|
||||
return routeService.getByStatus(status);
|
||||
}
|
||||
if (vehicleId != null) {
|
||||
return routeService.getByVehicleId(vehicleId);
|
||||
}
|
||||
if (freightId != null) {
|
||||
var route = routeService.getByFreightId(freightId);
|
||||
if (route == null) {
|
||||
return List.of();
|
||||
}
|
||||
return List.of(route);
|
||||
}
|
||||
return routeService.getAll();
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "Retrieve a route by ID",
|
||||
description = "Get a single route by its ID"
|
||||
)
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "Route found"
|
||||
)
|
||||
@ApiResponse(
|
||||
responseCode = "404",
|
||||
description = "Route not found"
|
||||
)
|
||||
@GetMapping(value = "/{id}", consumes = MediaType.ALL_VALUE)
|
||||
public Route getById(
|
||||
@Parameter(description = "ID of the route to retrieve", required = true)
|
||||
@PathVariable("id") long id) {
|
||||
return routeService.getById(id);
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "Retrieve a vehicle by route ID"
|
||||
)
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "Route and vehicle found"
|
||||
)
|
||||
@ApiResponse(
|
||||
responseCode = "404",
|
||||
description = "Route or vehicle not found"
|
||||
)
|
||||
@GetMapping(value = "/{id}/vehicle", consumes = MediaType.ALL_VALUE)
|
||||
public Vehicle getVehicleById(
|
||||
@Parameter(description = "ID of the route to retrieve", required = true)
|
||||
@PathVariable("id") long id) {
|
||||
return vehicleClient.getById(routeService.getById(id).vehicleId());
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "Retrieve freights by route ID"
|
||||
)
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "Route and freights found"
|
||||
)
|
||||
@ApiResponse(
|
||||
responseCode = "404",
|
||||
description = "Route or freight not found"
|
||||
)
|
||||
@GetMapping(value = "/{id}/freights", consumes = MediaType.ALL_VALUE)
|
||||
public List<Freight> getFreightsById(
|
||||
@Parameter(description = "ID of the route to retrieve", required = true)
|
||||
@PathVariable("id") long id) {
|
||||
var route = routeService.getById(id);
|
||||
var freights = new ArrayList<Freight>();
|
||||
for (var freightId : route.freightId()) {
|
||||
freights.add(freightClient.getById(freightId));
|
||||
}
|
||||
return freights;
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "Create new route",
|
||||
description = "Add new route"
|
||||
)
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "Route successfully created"
|
||||
)
|
||||
@ApiResponse(
|
||||
responseCode = "400",
|
||||
description = "Invalid route data: vehicle or freight not found"
|
||||
)
|
||||
@ApiResponse(
|
||||
responseCode = "404",
|
||||
description = "Referenced vehicle or freight not found"
|
||||
)
|
||||
@PostMapping
|
||||
public Route add(
|
||||
@io.swagger.v3.oas.annotations.parameters.RequestBody(
|
||||
description = "Route object to be created. Must include valid vehicleId and freightId list.",
|
||||
required = true
|
||||
)
|
||||
@RequestBody Route newRoute) {
|
||||
return routeService.add(newRoute);
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "Update a route (full)",
|
||||
description = "Update all fields of an existing route by ID"
|
||||
)
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "Route successfully updated"
|
||||
)
|
||||
@ApiResponse(
|
||||
responseCode = "400",
|
||||
description = "Invalid route data provided"
|
||||
)
|
||||
@PutMapping("/{id}")
|
||||
public Route update(
|
||||
@Parameter(description = "ID of the route to update", required = true)
|
||||
@PathVariable("id") long id,
|
||||
@io.swagger.v3.oas.annotations.parameters.RequestBody(
|
||||
description = "Updated route object",
|
||||
required = true
|
||||
)
|
||||
@RequestBody Route newRoute) {
|
||||
return routeService.update(id, newRoute);
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "Update a route (partial)",
|
||||
description = "Update specific fields of an existing route by ID"
|
||||
)
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "Route successfully updated"
|
||||
)
|
||||
@ApiResponse(
|
||||
responseCode = "400",
|
||||
description = "Invalid route data provided"
|
||||
)
|
||||
@PatchMapping("/{id}")
|
||||
public Route updatePatch(
|
||||
@Parameter(description = "ID of the route to update", required = true)
|
||||
@PathVariable("id") long id,
|
||||
@io.swagger.v3.oas.annotations.parameters.RequestBody(
|
||||
description = "Route object with fields to update",
|
||||
required = true
|
||||
)
|
||||
@RequestBody Route newRoute) {
|
||||
return routeService.update(id, newRoute);
|
||||
}
|
||||
|
||||
|
||||
@Operation(
|
||||
summary = "Delete a route",
|
||||
description = "Delete a route by ID"
|
||||
)
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "Route successfully deleted"
|
||||
)
|
||||
@ApiResponse(
|
||||
responseCode = "404",
|
||||
description = "Route not found"
|
||||
)
|
||||
@DeleteMapping(value = "/{id}", consumes = MediaType.ALL_VALUE)
|
||||
public Route delete(
|
||||
@Parameter(description = "ID of the route to delete", required = true)
|
||||
@PathVariable("id") long id) {
|
||||
return routeService.delete(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package ua.com.dxrkness.repository;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import ua.com.dxrkness.model.Route;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public final class RouteRepository extends CrudRepository<Route> {
|
||||
public @Nullable Route getByFreightId(long freightId) {
|
||||
Route found = null;
|
||||
out: for (var route : STORAGE) {
|
||||
var freights = route.freightId();
|
||||
for (var freight : freights) {
|
||||
if (freight == freightId) {
|
||||
found = route;
|
||||
break out;
|
||||
}
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
public List<Route> getByVehicleId(long vehicleId) {
|
||||
List<Route> found = new ArrayList<>();
|
||||
for (var route : STORAGE) {
|
||||
if (route.vehicleId() == vehicleId) {
|
||||
found.add(route);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
package ua.com.dxrkness.service;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import ua.com.dxrkness.client.FreightClient;
|
||||
import ua.com.dxrkness.client.VehicleClient;
|
||||
import ua.com.dxrkness.dto.FreightDto;
|
||||
import ua.com.dxrkness.dto.VehicleDto;
|
||||
import ua.com.dxrkness.exception.FreightNotFoundException;
|
||||
import ua.com.dxrkness.exception.RouteNotFoundException;
|
||||
import ua.com.dxrkness.exception.VehicleNotFoundException;
|
||||
import ua.com.dxrkness.model.Route;
|
||||
import ua.com.dxrkness.repository.RouteRepository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public final class RouteService {
|
||||
private final RouteRepository repo;
|
||||
private final VehicleClient vehicleClient;
|
||||
private final FreightClient freightClient;
|
||||
|
||||
public RouteService(RouteRepository repo,
|
||||
VehicleClient vehicleClient,
|
||||
FreightClient freightClient) {
|
||||
this.repo = repo;
|
||||
this.vehicleClient = vehicleClient;
|
||||
this.freightClient = freightClient;
|
||||
}
|
||||
|
||||
public List<Route> getAll() {
|
||||
return repo.getAll();
|
||||
}
|
||||
|
||||
public Route getById(long id) {
|
||||
Route route = repo.getById(id);
|
||||
if (route == null) {
|
||||
throw new RouteNotFoundException("Route with ID " + id + " not found.");
|
||||
}
|
||||
return route;
|
||||
}
|
||||
|
||||
public Route add(Route route) {
|
||||
VehicleDto vehicleDto = validateAndGetVehicle(route.vehicleId());
|
||||
List<FreightDto> freightDtos = validateAndGetFreights(route.freightId());
|
||||
|
||||
var newRoute = new Route(repo.lastId(),
|
||||
route.vehicleId(),
|
||||
route.freightId(),
|
||||
route.startLocation(),
|
||||
route.endLocation(),
|
||||
route.distanceKm(),
|
||||
route.estimatedDurationHours(),
|
||||
route.status());
|
||||
repo.add(route);
|
||||
return newRoute;
|
||||
}
|
||||
|
||||
private VehicleDto validateAndGetVehicle(long vehicleId) {
|
||||
try {
|
||||
var vehicle = vehicleClient.getById(vehicleId);
|
||||
return VehicleDto.fromVehicle(vehicle);
|
||||
} catch (VehicleNotFoundException e) {
|
||||
throw new VehicleNotFoundException(
|
||||
"Cannot create or update route: Referenced vehicle with ID " + vehicleId + " not found.");
|
||||
}
|
||||
}
|
||||
|
||||
private List<FreightDto> validateAndGetFreights(List<Long> freightIds) {
|
||||
List<FreightDto> freightDtos = new java.util.ArrayList<>();
|
||||
for (long freightId : freightIds) {
|
||||
try {
|
||||
var freight = freightClient.getById(freightId);
|
||||
freightDtos.add(FreightDto.fromFreight(freight));
|
||||
} catch (FreightNotFoundException e) {
|
||||
throw new FreightNotFoundException(
|
||||
"Cannot create or update route: Referenced freight with ID " + freightId + " not found.");
|
||||
}
|
||||
}
|
||||
return freightDtos;
|
||||
}
|
||||
|
||||
public @Nullable Route getByFreightId(long freightId) {
|
||||
return repo.getByFreightId(freightId);
|
||||
}
|
||||
|
||||
public List<Route> getByVehicleId(long vehicleId) {
|
||||
return repo.getByVehicleId(vehicleId);
|
||||
}
|
||||
|
||||
public List<Route> getByStatus(Route.Status status) {
|
||||
return repo.getAll().stream()
|
||||
.filter(r -> r.status() == status)
|
||||
.toList();
|
||||
}
|
||||
|
||||
public Route update(long id, Route newRoute) {
|
||||
VehicleDto vehicleDto = validateAndGetVehicle(newRoute.vehicleId());
|
||||
List<FreightDto> freightDtos = validateAndGetFreights(newRoute.freightId());
|
||||
|
||||
newRoute = new Route(id,
|
||||
newRoute.vehicleId(),
|
||||
newRoute.freightId(),
|
||||
newRoute.startLocation(),
|
||||
newRoute.endLocation(),
|
||||
newRoute.distanceKm(),
|
||||
newRoute.estimatedDurationHours(),
|
||||
newRoute.status());
|
||||
return repo.update(id, newRoute);
|
||||
}
|
||||
|
||||
public Route delete(long id) {
|
||||
var deleted = repo.delete(id);
|
||||
if (deleted == null) {
|
||||
throw new RouteNotFoundException("Route with ID " + id + " not found.");
|
||||
}
|
||||
return deleted;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
spring:
|
||||
application:
|
||||
name: route-service
|
||||
server:
|
||||
port: 8082
|
||||
@@ -0,0 +1,300 @@
|
||||
package ua.com.dxrkness.integration;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.servlet.client.RestTestClient;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import ua.com.dxrkness.model.Freight;
|
||||
import ua.com.dxrkness.model.Route;
|
||||
import ua.com.dxrkness.model.Vehicle;
|
||||
import ua.com.dxrkness.service.PopulateService;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.assertj.core.api.BDDAssertions.then;
|
||||
|
||||
@SpringBootTest
|
||||
@NullMarked
|
||||
class RouteIntegrationTest {
|
||||
private static final int AMOUNT = 100;
|
||||
@Autowired
|
||||
private PopulateService populateService;
|
||||
|
||||
private RestTestClient testClient;
|
||||
|
||||
@BeforeEach
|
||||
void setUp(WebApplicationContext context) {
|
||||
populateService.populate(AMOUNT);
|
||||
testClient = RestTestClient.bindToApplicationContext(context).baseUrl("/routes").build();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void teardown() {
|
||||
populateService.clear();
|
||||
}
|
||||
|
||||
private static Stream<MediaType> mediaTypesClientConsumes() {
|
||||
return Stream.of(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML);
|
||||
}
|
||||
|
||||
private static Stream<Arguments> mediaTypesClientConsumesProduces() {
|
||||
return Stream.of(
|
||||
Arguments.of(MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON),
|
||||
Arguments.of(MediaType.APPLICATION_XML, MediaType.APPLICATION_XML),
|
||||
Arguments.of(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML),
|
||||
Arguments.of(MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON)
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("mediaTypesClientConsumes")
|
||||
void getAll(MediaType mediaType) {
|
||||
// given
|
||||
|
||||
// when
|
||||
// then
|
||||
testClient.get()
|
||||
.accept(mediaType)
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
.isOk()
|
||||
.expectBody(new ParameterizedTypeReference<List<Route>>() {
|
||||
})
|
||||
.consumeWith(res -> then(res.getResponseBody()).hasSize(AMOUNT));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("mediaTypesClientConsumes")
|
||||
void getByVehicleIdReturnsEntity(MediaType mediaType) {
|
||||
// given
|
||||
int vehicleId = 1;
|
||||
|
||||
// when
|
||||
// then
|
||||
testClient.get().uri(b -> b.queryParam("vehicleId", vehicleId).build())
|
||||
.accept(mediaType)
|
||||
.exchangeSuccessfully()
|
||||
.expectStatus()
|
||||
.isOk()
|
||||
.expectBody(new ParameterizedTypeReference<List<Route>>() {
|
||||
})
|
||||
.value(val -> then(val).isNotNull()
|
||||
.hasSize(1)
|
||||
.allSatisfy(route -> then(route.vehicleId()).isEqualTo(vehicleId)));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("mediaTypesClientConsumes")
|
||||
void getByVehicleIdReturns404(MediaType mediaType) {
|
||||
// given
|
||||
int vehicleId = AMOUNT + 1;
|
||||
|
||||
// when
|
||||
// then
|
||||
testClient.get().uri(b -> b.queryParam("vehicleId", vehicleId).build())
|
||||
.accept(mediaType)
|
||||
.exchangeSuccessfully()
|
||||
.expectStatus()
|
||||
.isOk()
|
||||
.expectBody(List.class)
|
||||
.isEqualTo(List.of());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("mediaTypesClientConsumes")
|
||||
void getByFreightIdReturnsEntity(MediaType mediaType) {
|
||||
// given
|
||||
int freightId = 1;
|
||||
|
||||
// when
|
||||
// then
|
||||
testClient.get().uri(b -> b.queryParam("freightId", freightId).build())
|
||||
.accept(mediaType)
|
||||
.exchangeSuccessfully()
|
||||
.expectStatus()
|
||||
.isOk()
|
||||
.expectBody(new ParameterizedTypeReference<List<Route>>() {
|
||||
})
|
||||
.value(val -> then(val).isNotNull()
|
||||
.hasSize(1)
|
||||
.allSatisfy(route -> then(route.freightId())
|
||||
.isNotNull()
|
||||
.isNotEmpty()
|
||||
.anySatisfy(fre -> then(fre).isEqualTo(freightId))));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("mediaTypesClientConsumes")
|
||||
void getByFreightIdReturns404(MediaType mediaType) {
|
||||
// given
|
||||
int freightId = AMOUNT + 1;
|
||||
|
||||
// when
|
||||
// then
|
||||
testClient.get().uri(b -> b.queryParam("freightId", freightId).build())
|
||||
.accept(mediaType)
|
||||
.exchangeSuccessfully()
|
||||
.expectStatus()
|
||||
.isOk()
|
||||
.expectBody(List.class)
|
||||
.isEqualTo(List.of());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("mediaTypesClientConsumes")
|
||||
void getByIdReturnsEntity(MediaType mediaType) {
|
||||
// given
|
||||
final var id = 1;
|
||||
|
||||
// when
|
||||
// then
|
||||
testClient.get().uri("/{id}", id)
|
||||
.accept(mediaType)
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
.isOk()
|
||||
.expectBody(Route.class)
|
||||
.value(val -> {
|
||||
then(val).isNotNull();
|
||||
then(val.id()).isEqualTo(id);
|
||||
});
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("mediaTypesClientConsumes")
|
||||
void getByIdReturnsNotFound(MediaType mediaType) {
|
||||
// given
|
||||
final var id = -1;
|
||||
|
||||
// when
|
||||
// then
|
||||
testClient.get().uri("/{id}", id)
|
||||
.accept(mediaType)
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
.isNotFound();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("mediaTypesClientConsumesProduces")
|
||||
void add(MediaType clientConsumes, MediaType clientProduces) {
|
||||
// given
|
||||
final var newEntity = new Route(444, 1, List.of(1L), "123", "321", 1., 2., Route.Status.IN_PROGRESS);
|
||||
|
||||
// when
|
||||
// then
|
||||
testClient.post()
|
||||
.accept(clientConsumes)
|
||||
.contentType(clientProduces)
|
||||
.body(newEntity)
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
.isOk()
|
||||
.expectBody(Route.class)
|
||||
.value(val -> {
|
||||
then(val.id()).isEqualTo(AMOUNT+1);
|
||||
then(val).usingRecursiveComparison()
|
||||
.ignoringFields("id")
|
||||
.isEqualTo(newEntity);
|
||||
});
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("mediaTypesClientConsumesProduces")
|
||||
void update(MediaType clientConsumes, MediaType clientProduces) {
|
||||
// given
|
||||
final var existingEntityId = AMOUNT - 1;
|
||||
final var newEntity = new Route(432, 1, List.of(1L), "123", "321", 22., 44., Route.Status.PLANNED);
|
||||
|
||||
// when
|
||||
// then
|
||||
testClient.put().uri("/{id}", existingEntityId)
|
||||
.accept(clientConsumes)
|
||||
.contentType(clientProduces)
|
||||
.body(newEntity)
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
.isOk()
|
||||
.expectBody(Route.class)
|
||||
.value(val -> {
|
||||
then(val.id()).isEqualTo(existingEntityId);
|
||||
then(val).usingRecursiveComparison()
|
||||
.ignoringFields("id")
|
||||
.isEqualTo(newEntity);
|
||||
});
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("mediaTypesClientConsumesProduces")
|
||||
void updatePatch(MediaType clientConsumes, MediaType clientProduces) {
|
||||
// given
|
||||
final var existingEntityId = AMOUNT - 1;
|
||||
final var newEntity = new Route(432, 1, List.of(1L), "123", "321", 22., 44., Route.Status.CANCELLED);
|
||||
|
||||
// when
|
||||
// then
|
||||
testClient.patch().uri("/{id}", existingEntityId)
|
||||
.accept(clientConsumes)
|
||||
.contentType(clientProduces)
|
||||
.body(newEntity)
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
.isOk()
|
||||
.expectBody(Route.class)
|
||||
.value(val -> {
|
||||
then(val).isNotNull();
|
||||
then(val.id()).isEqualTo(existingEntityId);
|
||||
then(val).usingRecursiveComparison()
|
||||
.ignoringFields("id")
|
||||
.isEqualTo(newEntity);
|
||||
});
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("mediaTypesClientConsumes")
|
||||
void delete(MediaType mediaType) {
|
||||
// given
|
||||
final var existingEntityId = AMOUNT - 1;
|
||||
|
||||
// when
|
||||
// then
|
||||
testClient.delete().uri("/{id}", existingEntityId)
|
||||
.accept(mediaType)
|
||||
.exchange()
|
||||
.expectBody(Route.class)
|
||||
.value(val -> {
|
||||
then(val).isNotNull();
|
||||
then(val.id()).isEqualTo(existingEntityId);
|
||||
});
|
||||
|
||||
testClient.get().uri("/{id}", existingEntityId)
|
||||
.accept(mediaType)
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
.isNotFound();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("mediaTypesClientConsumes")
|
||||
void deleteIfEntityNotFound(MediaType mediaType) {
|
||||
// given
|
||||
final var existingEntityId = AMOUNT + 1;
|
||||
|
||||
// when
|
||||
// then
|
||||
testClient.delete().uri("/{id}", existingEntityId)
|
||||
.accept(mediaType)
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
.isNotFound();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user