Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,22 @@ quarkus.datasource.password=password
quarkus.datasource.jdbc.min-size=1
quarkus.datasource.jdbc.max-size=1
quarkus.devservices.enabled=false
quarkus.hibernate-orm.dialect=org.hibernate.dialect.PostgreSQLDialect
quarkus.hibernate-orm.unsupported-properties."hibernate.boot.allow_jdbc_metadata_access"=false
```

### Spring Boot - NOT TESTED
### Spring Boot

```properties
# application-test.properties
spring.datasource.url=jdbc:pglite:memory://
spring.datasource.driver-class-name=io.roastedroot.pglite4j.jdbc.PgLiteDriver
spring.datasource.username=postgres
spring.datasource.password=password
spring.datasource.hikari.maximum-pool-size=1
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.properties.hibernate.boot.allow_jdbc_metadata_access=false
```

### HikariCP - NOT TESTED
Expand Down
1 change: 1 addition & 0 deletions it/src/it/spring-boot-pet-clinic/invoker.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
invoker.goals=test
57 changes: 57 additions & 0 deletions it/src/it/spring-boot-pet-clinic/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.4.4</version>
<relativePath/>
</parent>

<groupId>org.acme</groupId>
<artifactId>spring-boot-pet-clinic-it</artifactId>
<version>0.0-SNAPSHOT</version>
<packaging>jar</packaging>

<properties>
<java.version>17</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>io.roastedroot</groupId>
<artifactId>pglite4j-jdbc</artifactId>
<version>@project.version@</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.acme;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
50 changes: 50 additions & 0 deletions it/src/it/spring-boot-pet-clinic/src/main/java/org/acme/Pet.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package org.acme;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity
public class Pet {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String name;
private String species;
private int age;

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getSpecies() {
return species;
}

public void setSpecies(String species) {
this.species = species;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package org.acme;

import java.util.List;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ResponseStatusException;

@RestController
@RequestMapping("/pets")
public class PetController {

private final PetRepository repository;

public PetController(PetRepository repository) {
this.repository = repository;
}

@GetMapping
public List<Pet> list() {
return repository.findAllByOrderByIdAsc();
}

@GetMapping("/{id}")
public Pet get(@PathVariable Long id) {
return repository
.findById(id)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
}

@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public Pet create(@RequestBody Pet pet) {
return repository.save(pet);
}

@PutMapping("/{id}")
public Pet update(@PathVariable Long id, @RequestBody Pet pet) {
Pet existing =
repository
.findById(id)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
existing.setName(pet.getName());
existing.setSpecies(pet.getSpecies());
existing.setAge(pet.getAge());
return repository.save(existing);
}

@DeleteMapping("/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void delete(@PathVariable Long id) {
if (!repository.existsById(id)) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND);
}
repository.deleteById(id);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.acme;

import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;

public interface PetRepository extends JpaRepository<Pet, Long> {

List<Pet> findAllByOrderByIdAsc();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
spring.datasource.url=jdbc:pglite:memory://
spring.datasource.driver-class-name=io.roastedroot.pglite4j.jdbc.PgLiteDriver
spring.datasource.username=postgres
spring.datasource.password=password
spring.datasource.hikari.maximum-pool-size=1
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.properties.hibernate.boot.allow_jdbc_metadata_access=false
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package org.acme;

import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;

import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestMethodOrder;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class PetControllerTest {

@LocalServerPort private int port;

private int buddyId;
private int whiskersId;
private int goldieId;

@BeforeEach
void setUp() {
RestAssured.port = port;
}

@Test
@Order(1)
void createBuddy() {
buddyId =
given().contentType(ContentType.JSON)
.body("{\"name\":\"Buddy\",\"species\":\"Dog\",\"age\":3}")
.when()
.post("/pets")
.then()
.statusCode(201)
.body("name", is("Buddy"))
.body("species", is("Dog"))
.body("age", is(3))
.extract()
.path("id");
}

@Test
@Order(2)
void createWhiskers() {
whiskersId =
given().contentType(ContentType.JSON)
.body("{\"name\":\"Whiskers\",\"species\":\"Cat\",\"age\":5}")
.when()
.post("/pets")
.then()
.statusCode(201)
.body("name", is("Whiskers"))
.extract()
.path("id");
}

@Test
@Order(3)
void createGoldie() {
goldieId =
given().contentType(ContentType.JSON)
.body("{\"name\":\"Goldie\",\"species\":\"Fish\",\"age\":1}")
.when()
.post("/pets")
.then()
.statusCode(201)
.body("name", is("Goldie"))
.extract()
.path("id");
}

@Test
@Order(4)
void listAll() {
given().when()
.get("/pets")
.then()
.statusCode(200)
.body("size()", is(3))
.body("[0].name", is("Buddy"))
.body("[1].name", is("Whiskers"))
.body("[2].name", is("Goldie"));
}

@Test
@Order(5)
void getById() {
given().when()
.get("/pets/" + buddyId)
.then()
.statusCode(200)
.body("name", is("Buddy"))
.body("species", is("Dog"))
.body("age", is(3));
}

@Test
@Order(6)
void updateBuddy() {
given().contentType(ContentType.JSON)
.body("{\"name\":\"Buddy\",\"species\":\"Dog\",\"age\":4}")
.when()
.put("/pets/" + buddyId)
.then()
.statusCode(200)
.body("name", is("Buddy"))
.body("age", is(4));
}

@Test
@Order(7)
void verifyUpdate() {
given().when().get("/pets/" + buddyId).then().statusCode(200).body("age", is(4));
}

@Test
@Order(8)
void deleteGoldie() {
given().when().delete("/pets/" + goldieId).then().statusCode(204);
}

@Test
@Order(9)
void listAfterDelete() {
given().when()
.get("/pets")
.then()
.statusCode(200)
.body("size()", is(2))
.body("[0].name", is("Buddy"))
.body("[1].name", is("Whiskers"));
}

@Test
@Order(10)
void getDeletedReturns404() {
given().when().get("/pets/" + goldieId).then().statusCode(404);
}
}
Loading