mirror of
https://github.com/spring-projects/spring-petclinic.git
synced 2025-07-20 14:55:50 +00:00
my changes
This commit is contained in:
parent
772502e98a
commit
7124afe527
17 changed files with 266 additions and 89 deletions
16
build.gradle
16
build.gradle
|
@ -26,6 +26,11 @@ dependencies {
|
|||
implementation 'org.springframework.boot:spring-boot-starter-validation'
|
||||
implementation 'javax.cache:cache-api'
|
||||
implementation 'jakarta.xml.bind:jakarta.xml.bind-api'
|
||||
implementation('io.opentelemetry.instrumentation:opentelemetry-instrumentation-annotations:1.28.0')
|
||||
implementation('io.opentelemetry:opentelemetry-api')
|
||||
implementation 'com.squareup.okhttp3:okhttp'
|
||||
implementation 'org.json:json:20171018'
|
||||
|
||||
runtimeOnly 'org.springframework.boot:spring-boot-starter-actuator'
|
||||
runtimeOnly "org.webjars.npm:bootstrap:${webjarsBootstrapVersion}"
|
||||
runtimeOnly "org.webjars.npm:font-awesome:${webjarsFontawesomeVersion}"
|
||||
|
@ -37,6 +42,17 @@ dependencies {
|
|||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||
}
|
||||
|
||||
tasks.named("bootRun") {
|
||||
if (project.hasProperty('digma')) {
|
||||
def tempDir = System.getProperty("java.io.tmpdir")
|
||||
environment["JAVA_TOOL_OPTIONS"] = "-javaagent:${tempDir}/temp-digma-otel-jars/opentelemetry-javaagent.jar"
|
||||
systemProperty 'otel.exporter.otlp.traces.endpoint', 'http://localhost:5050'
|
||||
systemProperty 'otel.traces.exporter', 'otlp'
|
||||
systemProperty 'otel.metrics.exporter', 'none'
|
||||
systemProperty 'otel.service.name', "${project.name}"
|
||||
systemProperty 'otel.javaagent.extensions', "${tempDir}/temp-digma-otel-jars/digma-otel-agent-extension.jar"
|
||||
}
|
||||
}
|
||||
tasks.named('test') {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
|
1
digma-profile.gradle
Normal file
1
digma-profile.gradle
Normal file
|
@ -0,0 +1 @@
|
|||
|
BIN
opentelemetry-agent.jar
Normal file
BIN
opentelemetry-agent.jar
Normal file
Binary file not shown.
BIN
otel/digma-otel-agent-extension.jar
Normal file
BIN
otel/digma-otel-agent-extension.jar
Normal file
Binary file not shown.
BIN
otel/opentelemetry-javaagent.jar
Normal file
BIN
otel/opentelemetry-javaagent.jar
Normal file
Binary file not shown.
86
pom.xml
86
pom.xml
|
@ -5,6 +5,8 @@
|
|||
<artifactId>spring-petclinic</artifactId>
|
||||
<version>3.1.0-SNAPSHOT</version>
|
||||
|
||||
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
|
@ -67,6 +69,27 @@
|
|||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-testcontainers</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.rest-assured</groupId>
|
||||
<artifactId>rest-assured</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Databases - Uses H2 by default -->
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
|
@ -120,7 +143,12 @@
|
|||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.javafaker</groupId>
|
||||
<artifactId>javafaker</artifactId>
|
||||
<version>1.0.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.xml.bind</groupId>
|
||||
<artifactId>jakarta.xml.bind-api</artifactId>
|
||||
|
@ -135,9 +163,20 @@
|
|||
<artifactId>android-json</artifactId>
|
||||
<version>0.0.20131108.vaadin1</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>testcontainers-bom</artifactId>
|
||||
<version>${testcontainers.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
|
@ -183,28 +222,8 @@
|
|||
<artifactId>checkstyle</artifactId>
|
||||
<version>${checkstyle.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.spring.nohttp</groupId>
|
||||
<artifactId>nohttp-checkstyle</artifactId>
|
||||
<version>${nohttp-checkstyle.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>nohttp-checkstyle-validation</id>
|
||||
<phase>validate</phase>
|
||||
<configuration>
|
||||
<configLocation>src/checkstyle/nohttp-checkstyle.xml</configLocation>
|
||||
<suppressionsLocation>src/checkstyle/nohttp-checkstyle-suppressions.xml</suppressionsLocation>
|
||||
<sourceDirectories>${basedir}</sourceDirectories>
|
||||
<includes>**/*</includes>
|
||||
<excludes>**/.git/**/*,**/.idea/**/*,**/target/**/,**/.flattened-pom.xml,**/*.class</excludes>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.graalvm.buildtools</groupId>
|
||||
|
@ -311,6 +330,27 @@
|
|||
</pluginRepositories>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>digma</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<jvmArguments>-javaagent:${env.TMPDIR}/temp-digma-otel-jars/opentelemetry-javaagent.jar</jvmArguments>
|
||||
<systemPropertyVariables>
|
||||
<otel.exporter.otlp.traces.endpoint>http://localhost:5050</otel.exporter.otlp.traces.endpoint>
|
||||
<otel.traces.exporter>otlp</otel.traces.exporter>
|
||||
<otel.metrics.exporter>none</otel.metrics.exporter>
|
||||
<otel.service.name>${pom.artifactId}</otel.service.name>
|
||||
<otel.javaagent.extensions>${env.TMPDIR}/temp-digma-otel-jars/digma-otel-agent-extension.jar</otel.javaagent.extensions>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>css</id>
|
||||
<build>
|
||||
|
|
|
@ -16,8 +16,13 @@
|
|||
|
||||
package org.springframework.samples.petclinic;
|
||||
|
||||
import jakarta.servlet.ServletContext;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.RuntimeHintsRegistrar;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
public class PetClinicRuntimeHints implements RuntimeHintsRegistrar {
|
||||
|
||||
|
|
|
@ -6,9 +6,11 @@ import org.json.JSONException;
|
|||
import java.io.IOException;
|
||||
|
||||
public interface PetVaccinationService {
|
||||
|
||||
@WithSpan
|
||||
VaccinnationRecord[] AllVaccines() throws JSONException, IOException;
|
||||
|
||||
@WithSpan
|
||||
VaccinnationRecord VaccineRecord(int vaccinationRecordId) throws JSONException, IOException;
|
||||
|
||||
}
|
||||
|
|
|
@ -34,8 +34,7 @@ public class PetVaccinationServiceFacade implements PetVaccinationService {
|
|||
|
||||
var vaccineListString = MakeHttpCall(VACCINES_RECORDS_URL);
|
||||
JSONArray jArr = new JSONArray(vaccineListString);
|
||||
var vaccinnationRecords =
|
||||
new ArrayList<VaccinnationRecord>();
|
||||
var vaccinnationRecords = new ArrayList<VaccinnationRecord>();
|
||||
|
||||
for (int i = 0; i < jArr.length(); i++) {
|
||||
|
||||
|
@ -69,6 +68,4 @@ public class PetVaccinationServiceFacade implements PetVaccinationService {
|
|||
return new VaccinnationRecord(id, petId, vaccineDate);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ public class OwnerValidation {
|
|||
|
||||
}
|
||||
|
||||
@WithSpan
|
||||
|
||||
// This function and classes were generated by ChatGPT
|
||||
public boolean ValidateUserAccess(String usr, String pswd, String sysCode) {
|
||||
|
||||
|
@ -62,7 +62,6 @@ public class OwnerValidation {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
boolean vldPswd = pwdUtils.vldtPswd(usr, pswd);
|
||||
if (!vldPswd) {
|
||||
return false;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.springframework.samples.petclinic.domain;
|
||||
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
import io.opentelemetry.instrumentation.annotations.WithSpan;
|
||||
import org.json.JSONException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.samples.petclinic.adapters.PetVaccinationService;
|
||||
|
@ -20,6 +21,7 @@ public class PetVaccinationStatusService {
|
|||
@Autowired
|
||||
private PetVaccinationService adapter;
|
||||
|
||||
@WithSpan
|
||||
public void UpdateVaccinationStatus(Pet[] pets) {
|
||||
|
||||
for (Pet pet : pets) {
|
||||
|
@ -36,13 +38,14 @@ public class PetVaccinationStatusService {
|
|||
}
|
||||
}
|
||||
|
||||
} catch (JSONException |IOException e) {
|
||||
}
|
||||
catch (JSONException | IOException e) {
|
||||
// Fail silently
|
||||
Span.current().recordException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -129,11 +129,6 @@ class OwnerController {
|
|||
return addPaginationModel(page, model, ownersResults);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private String addPaginationModel(int page, Model model, Page<Owner> paginated) {
|
||||
model.addAttribute("listOwners", paginated);
|
||||
List<Owner> listOwners = paginated.getContent();
|
||||
|
@ -151,11 +146,6 @@ class OwnerController {
|
|||
return owners.findByLastName(lastname, pageable);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@GetMapping("/owners/{ownerId}/edit")
|
||||
public String initUpdateOwnerForm(@PathVariable("ownerId") int ownerId, Model model) {
|
||||
Owner owner = this.owners.findById(ownerId);
|
||||
|
@ -163,24 +153,6 @@ class OwnerController {
|
|||
return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@PostMapping("/owners/{ownerId}/edit")
|
||||
public String processUpdateOwnerForm(@Valid Owner owner, BindingResult result,
|
||||
@PathVariable("ownerId") int ownerId) {
|
||||
|
@ -199,10 +171,8 @@ class OwnerController {
|
|||
* @return a ModelMap with the model attributes for the view
|
||||
*/
|
||||
@GetMapping("/owners/{ownerId}")
|
||||
public ModelAndView showOwner(@PathVariable("ownerId")
|
||||
int ownerId) {
|
||||
ModelAndView mav =
|
||||
new ModelAndView("owners/ownerDetails");
|
||||
public ModelAndView showOwner(@PathVariable("ownerId") int ownerId) {
|
||||
ModelAndView mav = new ModelAndView("owners/ownerDetails");
|
||||
Owner owner = this.owners.findById(ownerId);
|
||||
mav.addObject(owner);
|
||||
return mav;
|
||||
|
|
|
@ -79,4 +79,8 @@ public interface OwnerRepository extends Repository<Owner, Integer> {
|
|||
@Transactional(readOnly = true)
|
||||
Page<Owner> findAll(Pageable pageable);
|
||||
|
||||
// @Query("DROP Table Owner")
|
||||
// @Transactional(readOnly = true)
|
||||
// void deleteAll();
|
||||
|
||||
}
|
||||
|
|
|
@ -87,17 +87,6 @@ class PetController {
|
|||
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@PostMapping("/pets/new")
|
||||
public String processCreationForm(Owner owner, @Valid Pet pet, BindingResult result, ModelMap model) {
|
||||
if (StringUtils.hasLength(pet.getName()) && pet.isNew() && owner.getPet(pet.getName(), true) != null) {
|
||||
|
@ -110,19 +99,13 @@ class PetController {
|
|||
return VIEWS_PETS_CREATE_OR_UPDATE_FORM;
|
||||
}
|
||||
|
||||
|
||||
this.owners.save(owner);
|
||||
petVaccinationStatus.UpdateVaccinationStatus(owner.getPets().toArray(Pet[]::new));
|
||||
|
||||
return "redirect:/owners/{ownerId}";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@GetMapping("/pets/{petId}/edit")
|
||||
public String initUpdateForm(Owner owner, @PathVariable("petId") int petId, ModelMap model) {
|
||||
Pet pet = owner.getPet(petId);
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.springframework.samples.petclinic.system;
|
||||
|
||||
import io.opentelemetry.instrumentation.annotations.WithSpan;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
|
@ -27,4 +28,6 @@ class WelcomeController {
|
|||
return "welcome";
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -54,5 +54,5 @@ CREATE INDEX ON visits (pet_id);
|
|||
CREATE TABLE IF NOT EXISTS pet_vaccines (
|
||||
id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
pet_id INT REFERENCES pets (id),
|
||||
vaccine_date DATE,
|
||||
vaccine_date DATE
|
||||
);
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
package org.springframework.samples.petclinic.integration;
|
||||
|
||||
import com.github.javafaker.Faker;
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.instrumentation.annotations.WithSpan;
|
||||
import io.restassured.RestAssured;
|
||||
import io.restassured.http.ContentType;
|
||||
import jakarta.persistence.EntityManagerFactory;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.server.LocalServerPort;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
import org.springframework.samples.petclinic.owner.*;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.testcontainers.containers.PostgreSQLContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import java.time.ZoneId;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import static io.restassured.RestAssured.given;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@Testcontainers
|
||||
@ActiveProfiles(value = "postgres")
|
||||
public class OwnerControllerTests {
|
||||
|
||||
@LocalServerPort
|
||||
private Integer port;
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() {
|
||||
postgres.start();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void afterAll() {
|
||||
postgres.stop();
|
||||
}
|
||||
|
||||
@Container
|
||||
@ServiceConnection
|
||||
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15-alpine");
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
// ownerRepository.deleteAll();
|
||||
|
||||
RestAssured.baseURI = "http://localhost:" + port;
|
||||
}
|
||||
|
||||
Faker faker = new Faker();
|
||||
|
||||
@Autowired
|
||||
EntityManagerFactory emf;
|
||||
|
||||
@Autowired
|
||||
OwnerRepository ownerRepository;
|
||||
|
||||
@Test
|
||||
@WithSpan(kind = SpanKind.SERVER)
|
||||
void shouldSaveNewOwnerPet() {
|
||||
|
||||
Owner owner = CreateOwner();
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
|
||||
String newPetName = faker.dog().name();
|
||||
given().contentType("multipart/form-data")
|
||||
.multiPart("id", "")
|
||||
.multiPart("birthDate", "0222-02-02")
|
||||
.multiPart("name", newPetName)
|
||||
.multiPart("type", "dog")
|
||||
.when()
|
||||
.post(String.format("/owners/%s/pets/new", owner.getId()))
|
||||
.then()
|
||||
.statusCode(Matchers.not(Matchers.greaterThan(499)));
|
||||
try {
|
||||
Thread.sleep(800);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// var updatedOwner = ownerRepository.findById(owner.getId());
|
||||
// assertThat(updatedOwner.getPets())
|
||||
// .hasSize(2)
|
||||
// .extracting(Pet::getName)
|
||||
// .contains(newPetName);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldGetAllOwners() {
|
||||
|
||||
Owner owner = CreateOwner();
|
||||
|
||||
var ownerLinkMatcher =
|
||||
String.format("**.findAll { node -> node.@href=='/owners/%s'}",
|
||||
owner.getId());
|
||||
|
||||
given()
|
||||
.contentType(ContentType.JSON)
|
||||
.when()
|
||||
.get("/owners")
|
||||
.then()
|
||||
.contentType(ContentType.HTML)
|
||||
.statusCode(200)
|
||||
.body(ownerLinkMatcher,Matchers.notNullValue());
|
||||
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Owner CreateOwner() {
|
||||
var owner = new Owner();
|
||||
owner.setFirstName(faker.name().firstName());
|
||||
owner.setLastName(faker.name().lastName());
|
||||
owner.setAddress(faker.address().streetAddress());
|
||||
owner.setTelephone("5555555");
|
||||
owner.setCity(faker.address().city());
|
||||
|
||||
Pet pet = new Pet();
|
||||
pet.setName(faker.dog().name());
|
||||
pet.setBirthDate(faker.date().birthday().toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
|
||||
PetType dog = new PetType();
|
||||
dog.setName(faker.dog().name());
|
||||
dog.setId(2);
|
||||
pet.setType(dog);
|
||||
PetVaccine vaccine = new PetVaccine();
|
||||
vaccine.setDate(faker.date()
|
||||
.past(30, TimeUnit.DAYS, new java.util.Date())
|
||||
.toInstant()
|
||||
.atZone(ZoneId.systemDefault())
|
||||
.toLocalDate());
|
||||
pet.addVaccine(vaccine);
|
||||
|
||||
owner.addPet(pet);
|
||||
ownerRepository.save(owner);
|
||||
return owner;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue