diff --git a/docker-compose.yml b/docker-compose.yml index 3d08a0ee64f..ef809d4dc16 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -25,3 +25,14 @@ services: - POSTGRES_DB=petclinic profiles: - postgres + oracle: + image: gvenzl/oracle-free:slim-faststart + ports: + - "1521:1521" + environment: + - APP_USER=petclinic + - APP_USER_PASSWORD=petclinic + - ORACLE_RANDOM_PASSWORD=yes + - ORACLE_DATABASE=petclinic + profiles: + - oracle diff --git a/pom.xml b/pom.xml index ce55092cf66..0e3929a4229 100644 --- a/pom.xml +++ b/pom.xml @@ -85,7 +85,11 @@ postgresql runtime - + + com.oracle.database.jdbc + ojdbc11 + runtime + javax.cache @@ -133,7 +137,11 @@ mysql test - + + org.testcontainers + oracle-free + test + jakarta.xml.bind jakarta.xml.bind-api @@ -218,7 +226,7 @@ spring-boot-maven-plugin - build-info @@ -376,7 +384,7 @@ - org.eclipse.m2e @@ -434,4 +442,4 @@ - \ No newline at end of file + diff --git a/src/main/resources/application-oracle.properties b/src/main/resources/application-oracle.properties new file mode 100644 index 00000000000..6dc9ecdcac4 --- /dev/null +++ b/src/main/resources/application-oracle.properties @@ -0,0 +1,6 @@ +database=oracle +spring.datasource.url=${ORACLE_URL:jdbc:oracle:thin:@//localhost:1521/petclinic} +spring.datasource.username=${APP_USER:petclinic} +spring.datasource.password=${APP_USER_PASSWORD:petclinic} +# SQL is written to be idempotent so this is safe +spring.sql.init.mode=always diff --git a/src/main/resources/db/oracle/data.sql b/src/main/resources/db/oracle/data.sql new file mode 100644 index 00000000000..311a3d92529 --- /dev/null +++ b/src/main/resources/db/oracle/data.sql @@ -0,0 +1,53 @@ +INSERT INTO vets VALUES (default, 'James', 'Carter'); +INSERT INTO vets VALUES (default, 'Helen', 'Leary'); +INSERT INTO vets VALUES (default, 'Linda', 'Douglas'); +INSERT INTO vets VALUES (default, 'Rafael', 'Ortega'); +INSERT INTO vets VALUES (default, 'Henry', 'Stevens'); +INSERT INTO vets VALUES (default, 'Sharon', 'Jenkins'); + +INSERT INTO specialties VALUES (default, 'radiology'); +INSERT INTO specialties VALUES (default, 'surgery'); +INSERT INTO specialties VALUES (default, 'dentistry'); + +INSERT INTO vet_specialties VALUES (2, 1); +INSERT INTO vet_specialties VALUES (3, 2); +INSERT INTO vet_specialties VALUES (3, 3); +INSERT INTO vet_specialties VALUES (4, 2); +INSERT INTO vet_specialties VALUES (5, 1); + +INSERT INTO types VALUES (default, 'cat'); +INSERT INTO types VALUES (default, 'dog'); +INSERT INTO types VALUES (default, 'lizard'); +INSERT INTO types VALUES (default, 'snake'); +INSERT INTO types VALUES (default, 'bird'); +INSERT INTO types VALUES (default, 'hamster'); + +INSERT INTO owners VALUES (default, 'George', 'Franklin', '110 W. Liberty St.', 'Madison', '6085551023'); +INSERT INTO owners VALUES (default, 'Betty', 'Davis', '638 Cardinal Ave.', 'Sun Prairie', '6085551749'); +INSERT INTO owners VALUES (default, 'Eduardo', 'Rodriquez', '2693 Commerce St.', 'McFarland', '6085558763'); +INSERT INTO owners VALUES (default, 'Harold', 'Davis', '563 Friendly St.', 'Windsor', '6085553198'); +INSERT INTO owners VALUES (default, 'Peter', 'McTavish', '2387 S. Fair Way', 'Madison', '6085552765'); +INSERT INTO owners VALUES (default, 'Jean', 'Coleman', '105 N. Lake St.', 'Monona', '6085552654'); +INSERT INTO owners VALUES (default, 'Jeff', 'Black', '1450 Oak Blvd.', 'Monona', '6085555387'); +INSERT INTO owners VALUES (default, 'Maria', 'Escobito', '345 Maple St.', 'Madison', '6085557683'); +INSERT INTO owners VALUES (default, 'David', 'Schroeder', '2749 Blackhawk Trail', 'Madison', '6085559435'); +INSERT INTO owners VALUES (default, 'Carlos', 'Estaban', '2335 Independence La.', 'Waunakee', '6085555487'); + +INSERT INTO pets VALUES (default, 'Leo', TO_DATE('2010-09-07', 'YYYY-MM-DD'), 1, 1); +INSERT INTO pets VALUES (default, 'Basil', TO_DATE('2012-08-06', 'YYYY-MM-DD'), 6, 2); +INSERT INTO pets VALUES (default, 'Rosy', TO_DATE('2011-04-17', 'YYYY-MM-DD'), 2, 3); +INSERT INTO pets VALUES (default, 'Jewel', TO_DATE('2010-03-07', 'YYYY-MM-DD'), 2, 3); +INSERT INTO pets VALUES (default, 'Iggy', TO_DATE('2010-11-30', 'YYYY-MM-DD'), 3, 4); +INSERT INTO pets VALUES (default, 'George', TO_DATE('2010-01-20', 'YYYY-MM-DD'), 4, 5); +INSERT INTO pets VALUES (default, 'Samantha', TO_DATE('2012-09-04', 'YYYY-MM-DD'), 1, 6); +INSERT INTO pets VALUES (default, 'Max', TO_DATE('2012-09-04', 'YYYY-MM-DD'), 1, 6); +INSERT INTO pets VALUES (default, 'Lucky', TO_DATE('2011-08-06', 'YYYY-MM-DD'), 5, 7); +INSERT INTO pets VALUES (default, 'Mulligan', TO_DATE('2007-02-24', 'YYYY-MM-DD'), 2, 8); +INSERT INTO pets VALUES (default, 'Freddy', TO_DATE('2010-03-09', 'YYYY-MM-DD'), 5, 9); +INSERT INTO pets VALUES (default, 'Lucky', TO_DATE('2010-06-24', 'YYYY-MM-DD'), 2, 10); +INSERT INTO pets VALUES (default, 'Sly', TO_DATE('2012-06-08', 'YYYY-MM-DD'), 1, 10); + +INSERT INTO visits VALUES (default, 7, TO_DATE('2013-01-01', 'YYYY-MM-DD'), 'rabies shot'); +INSERT INTO visits VALUES (default, 8, TO_DATE('2013-01-02', 'YYYY-MM-DD'), 'rabies shot'); +INSERT INTO visits VALUES (default, 8, TO_DATE('2013-01-03', 'YYYY-MM-DD'), 'neutered'); +INSERT INTO visits VALUES (default, 7, TO_DATE('2013-01-04', 'YYYY-MM-DD'), 'spayed'); diff --git a/src/main/resources/db/oracle/petclinic_db_setup_oracle.txt b/src/main/resources/db/oracle/petclinic_db_setup_oracle.txt new file mode 100644 index 00000000000..e5fa53ff4f8 --- /dev/null +++ b/src/main/resources/db/oracle/petclinic_db_setup_oracle.txt @@ -0,0 +1,19 @@ +=============================================================================== +=== Spring PetClinic sample application - OracleSQL Configuration === +=============================================================================== + +1) Run the "docker-compose.yml" from the root of the project: + + $ docker-compose up oracle + ... + spring-petclinit-oracle-1 | ######################### + spring-petclinit-oracle-1 | DATABASE IS READY TO USE! + spring-petclinit-oracle-1 | ######################### + ... + +2) Run the app with `spring.profiles.active=oracle` (e.g. as a System property via the command + line, but any way that sets that property in a Spring Boot app should work). For example use + + mvn spring-boot:run -Dspring-boot.run.profiles=oracle + + To activate the profile on the command line. diff --git a/src/main/resources/db/oracle/schema.sql b/src/main/resources/db/oracle/schema.sql new file mode 100644 index 00000000000..9a3577b1296 --- /dev/null +++ b/src/main/resources/db/oracle/schema.sql @@ -0,0 +1,56 @@ +CREATE TABLE IF NOT EXISTS vets ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + first_name VARCHAR(30), + last_name VARCHAR(30) +); +CREATE INDEX IF NOT EXISTS vets_last_name ON vets (last_name); + +CREATE TABLE IF NOT EXISTS specialties ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name VARCHAR(80) +); +CREATE INDEX IF NOT EXISTS specialties_name ON specialties (name); + +CREATE TABLE IF NOT EXISTS vet_specialties ( + vet_id INTEGER NOT NULL, + specialty_id INTEGER NOT NULL, + CONSTRAINT fk_vet_specialties_vets FOREIGN KEY (vet_id) REFERENCES vets (id), + CONSTRAINT fk_vet_specialties_specialties FOREIGN KEY (specialty_id) REFERENCES specialties (id) + +); + +CREATE TABLE IF NOT EXISTS types ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name VARCHAR(80) +); +CREATE INDEX IF NOT EXISTS types_name ON types (name); + +CREATE TABLE IF NOT EXISTS owners ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + first_name VARCHAR(30), + last_name VARCHAR(30), + address VARCHAR(255), + city VARCHAR(80), + telephone VARCHAR(20) +); +CREATE INDEX IF NOT EXISTS owners_last_name ON owners (last_name); + +CREATE TABLE IF NOT EXISTS pets ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name VARCHAR(30), + birth_date DATE, + type_id INTEGER NOT NULL, + owner_id INTEGER, + CONSTRAINT fk_pets_owners FOREIGN KEY (owner_id) REFERENCES owners (id), + CONSTRAINT fk_pets_types FOREIGN KEY (type_id) REFERENCES types (id) +); +CREATE INDEX IF NOT EXISTS pets_name ON pets (name); + +CREATE TABLE IF NOT EXISTS visits ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + pet_id INTEGER, + visit_date DATE, + description VARCHAR(255), + CONSTRAINT fk_visits_pets FOREIGN KEY (pet_id) REFERENCES pets (id) +); +CREATE INDEX IF NOT EXISTS visits_pet_id ON visits (pet_id); diff --git a/src/test/java/org/springframework/samples/petclinic/OracleIntegrationTests.java b/src/test/java/org/springframework/samples/petclinic/OracleIntegrationTests.java new file mode 100644 index 00000000000..50dac4f9d09 --- /dev/null +++ b/src/test/java/org/springframework/samples/petclinic/OracleIntegrationTests.java @@ -0,0 +1,54 @@ +package org.springframework.samples.petclinic; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledInNativeImage; +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.boot.web.client.RestTemplateBuilder; +import org.springframework.http.HttpStatus; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; +import org.springframework.samples.petclinic.vet.VetRepository; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.web.client.RestTemplate; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.oracle.OracleContainer; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@ActiveProfiles("oracle") +@Testcontainers(disabledWithoutDocker = true) +@DisabledInNativeImage +class OracleIntegrationTests { + + @ServiceConnection + @Container + static OracleContainer container = new OracleContainer("gvenzl/oracle-free:slim-faststart"); + + @LocalServerPort + int port; + + @Autowired + private VetRepository vets; + + @Autowired + private RestTemplateBuilder builder; + + @Test + void testFindAll() { + vets.findAll(); + vets.findAll(); // served from cache + } + + @Test + void testOwnerDetails() { + RestTemplate template = builder.rootUri("http://localhost:" + port).build(); + ResponseEntity result = template.exchange(RequestEntity.get("/owners/1").build(), String.class); + assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); + } + +} diff --git a/src/test/java/org/springframework/samples/petclinic/OracleTestApplication.java b/src/test/java/org/springframework/samples/petclinic/OracleTestApplication.java new file mode 100644 index 00000000000..d60760d11a1 --- /dev/null +++ b/src/test/java/org/springframework/samples/petclinic/OracleTestApplication.java @@ -0,0 +1,30 @@ +package org.springframework.samples.petclinic; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.testcontainers.service.connection.ServiceConnection; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.testcontainers.oracle.OracleContainer; + +/** + * PetClinic Spring Boot Application + * + * @author Radu Ghiorma + * + */ +@Configuration +public class OracleTestApplication { + + @ServiceConnection + @Profile("oracle") + @Bean + static OracleContainer container() { + return new OracleContainer("gvenzl/oracle-free:slim-faststart"); + } + + public static void main(String[] args) { + SpringApplication.run(PetClinicApplication.class, "--spring.profiles.active=oracle"); + } + +}