From de054011fbca455e3ef7081ac900735d34040cdc Mon Sep 17 00:00:00 2001 From: Dave Cramer Date: Tue, 20 Aug 2024 08:57:52 -0400 Subject: [PATCH] add metadata and tests for PostgreSQL JDBC version 42.7.3 (#521) added tests and metadata for version 42.7.3 --- .../postgresql/42.7.3/index.json | 3 + .../postgresql/42.7.3/reflect-config.json | 98 ++++++++ metadata/org.postgresql/postgresql/index.json | 8 + tests/src/index.json | 6 + .../postgresql/42.7.3/.gitignore | 6 + .../postgresql/42.7.3/build.gradle | 17 ++ .../postgresql/42.7.3/gradle.properties | 2 + .../42.7.3/required-docker-images.txt | 1 + .../postgresql/42.7.3/settings.gradle | 13 ++ .../test/java/postgresql/PostgresqlTests.java | 212 ++++++++++++++++++ 10 files changed, 366 insertions(+) create mode 100644 metadata/org.postgresql/postgresql/42.7.3/index.json create mode 100644 metadata/org.postgresql/postgresql/42.7.3/reflect-config.json create mode 100644 tests/src/org.postgresql/postgresql/42.7.3/.gitignore create mode 100644 tests/src/org.postgresql/postgresql/42.7.3/build.gradle create mode 100644 tests/src/org.postgresql/postgresql/42.7.3/gradle.properties create mode 100644 tests/src/org.postgresql/postgresql/42.7.3/required-docker-images.txt create mode 100644 tests/src/org.postgresql/postgresql/42.7.3/settings.gradle create mode 100644 tests/src/org.postgresql/postgresql/42.7.3/src/test/java/postgresql/PostgresqlTests.java diff --git a/metadata/org.postgresql/postgresql/42.7.3/index.json b/metadata/org.postgresql/postgresql/42.7.3/index.json new file mode 100644 index 000000000..768b5502a --- /dev/null +++ b/metadata/org.postgresql/postgresql/42.7.3/index.json @@ -0,0 +1,3 @@ +[ + "reflect-config.json" +] diff --git a/metadata/org.postgresql/postgresql/42.7.3/reflect-config.json b/metadata/org.postgresql/postgresql/42.7.3/reflect-config.json new file mode 100644 index 000000000..e4e6fa568 --- /dev/null +++ b/metadata/org.postgresql/postgresql/42.7.3/reflect-config.json @@ -0,0 +1,98 @@ +[ + { + "condition": { + "typeReachable": "org.postgresql.jdbc.PgConnection" + }, + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ], + "name": "org.postgresql.util.PGInterval" + }, + { + "condition": { + "typeReachable": "org.postgresql.jdbc.PgConnection" + }, + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ], + "name": "org.postgresql.geometric.PGbox" + }, + { + "condition": { + "typeReachable": "org.postgresql.jdbc.PgConnection" + }, + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ], + "name": "org.postgresql.geometric.PGcircle" + }, + { + "condition": { + "typeReachable": "org.postgresql.jdbc.PgConnection" + }, + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ], + "name": "org.postgresql.geometric.PGline" + }, + { + "condition": { + "typeReachable": "org.postgresql.jdbc.PgConnection" + }, + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ], + "name": "org.postgresql.geometric.PGlseg" + }, + { + "condition": { + "typeReachable": "org.postgresql.jdbc.PgConnection" + }, + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ], + "name": "org.postgresql.geometric.PGpath" + }, + { + "condition": { + "typeReachable": "org.postgresql.jdbc.PgConnection" + }, + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ], + "name": "org.postgresql.geometric.PGpoint" + }, + { + "condition": { + "typeReachable": "org.postgresql.jdbc.PgConnection" + }, + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ], + "name": "org.postgresql.geometric.PGpolygon" + } +] diff --git a/metadata/org.postgresql/postgresql/index.json b/metadata/org.postgresql/postgresql/index.json index 67f337e68..aacf301df 100644 --- a/metadata/org.postgresql/postgresql/index.json +++ b/metadata/org.postgresql/postgresql/index.json @@ -1,10 +1,18 @@ [ { "latest": true, + "metadata-version": "42.7.3", + "module": "org.postgresql:postgresql", + "tested-versions": [ + "42.7.3" + ] + }, + { "metadata-version": "42.3.4", "module": "org.postgresql:postgresql", "tested-versions": [ "42.3.4" ] } + ] diff --git a/tests/src/index.json b/tests/src/index.json index f246e4a6b..afbba5126 100644 --- a/tests/src/index.json +++ b/tests/src/index.json @@ -574,6 +574,12 @@ "name" : "org.postgresql:postgresql", "versions" : [ "42.3.4" ] } ] +}, { + "test-project-path" : "org.postgresql/postgresql/42.7.3", + "libraries" : [ { + "name" : "org.postgresql:postgresql", + "versions" : [ "42.7.3" ] + } ] }, { "test-project-path" : "org.quartz-scheduler/quartz/2.3.2", "libraries" : [ { diff --git a/tests/src/org.postgresql/postgresql/42.7.3/.gitignore b/tests/src/org.postgresql/postgresql/42.7.3/.gitignore new file mode 100644 index 000000000..d7dfba5f3 --- /dev/null +++ b/tests/src/org.postgresql/postgresql/42.7.3/.gitignore @@ -0,0 +1,6 @@ +gradlew.bat +gradlew +gradle/ +build/ +postgres-stderr.txt +postgres-stdout.txt diff --git a/tests/src/org.postgresql/postgresql/42.7.3/build.gradle b/tests/src/org.postgresql/postgresql/42.7.3/build.gradle new file mode 100644 index 000000000..f71d7f86b --- /dev/null +++ b/tests/src/org.postgresql/postgresql/42.7.3/build.gradle @@ -0,0 +1,17 @@ +/* + * Copyright and related rights waived via CC0 + * + * You should have received a copy of the CC0 legalcode along with this + * work. If not, see . + */ +plugins { + id "org.graalvm.internal.tck" +} + +String libraryVersion = tck.testedLibraryVersion.get() + +dependencies { + testImplementation "org.postgresql:postgresql:$libraryVersion" + testImplementation 'org.assertj:assertj-core:3.22.0' + testImplementation 'org.awaitility:awaitility:4.2.0' +} diff --git a/tests/src/org.postgresql/postgresql/42.7.3/gradle.properties b/tests/src/org.postgresql/postgresql/42.7.3/gradle.properties new file mode 100644 index 000000000..a9bde2f00 --- /dev/null +++ b/tests/src/org.postgresql/postgresql/42.7.3/gradle.properties @@ -0,0 +1,2 @@ +library.version = 42.7.3 +metadata.dir = org.postgresql/postgresql/42.7.3/ diff --git a/tests/src/org.postgresql/postgresql/42.7.3/required-docker-images.txt b/tests/src/org.postgresql/postgresql/42.7.3/required-docker-images.txt new file mode 100644 index 000000000..d44d138ec --- /dev/null +++ b/tests/src/org.postgresql/postgresql/42.7.3/required-docker-images.txt @@ -0,0 +1 @@ +postgres:16-alpine \ No newline at end of file diff --git a/tests/src/org.postgresql/postgresql/42.7.3/settings.gradle b/tests/src/org.postgresql/postgresql/42.7.3/settings.gradle new file mode 100644 index 000000000..ff19e44fd --- /dev/null +++ b/tests/src/org.postgresql/postgresql/42.7.3/settings.gradle @@ -0,0 +1,13 @@ +pluginManagement { + def tckPath = Objects.requireNonNullElse( + System.getenv("GVM_TCK_TCKDIR"), + "../../../../tck-build-logic" + ) + includeBuild(tckPath) +} + +plugins { + id "org.graalvm.internal.tck-settings" version "1.0.0-SNAPSHOT" +} + +rootProject.name = 'postgresql-tests' diff --git a/tests/src/org.postgresql/postgresql/42.7.3/src/test/java/postgresql/PostgresqlTests.java b/tests/src/org.postgresql/postgresql/42.7.3/src/test/java/postgresql/PostgresqlTests.java new file mode 100644 index 000000000..fad34f5fd --- /dev/null +++ b/tests/src/org.postgresql/postgresql/42.7.3/src/test/java/postgresql/PostgresqlTests.java @@ -0,0 +1,212 @@ +/* + * Copyright and related rights waived via CC0 + * + * You should have received a copy of the CC0 legalcode along with this + * work. If not, see . + */ +package postgresql; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.sql.Connection; +import java.sql.Date; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.time.Duration; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetDateTime; +import java.time.OffsetTime; +import java.time.ZoneOffset; +import java.util.Properties; +import java.util.UUID; + +import org.awaitility.Awaitility; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * This test uses docker to start a postgresql database to test against. + */ +public class PostgresqlTests { + + private static final String USERNAME = "fred"; + + private static final String PASSWORD = "secret"; + + private static final String DATABASE = "test"; + + private static final String JDBC_URL = "jdbc:postgresql://localhost/" + DATABASE; + + private static Process process; + + private static Connection openConnection() throws SQLException { + Properties props = new Properties(); + props.setProperty("user", USERNAME); + props.setProperty("password", PASSWORD); + return DriverManager.getConnection(JDBC_URL, props); + } + + @BeforeAll + static void beforeAll() throws IOException { + System.out.println("Starting PostgreSQL ..."); + process = new ProcessBuilder( + "docker", "run", "--rm", "-p", "5432:5432", "-e", "POSTGRES_DB=" + DATABASE, "-e", "POSTGRES_USER=" + USERNAME, + "-e", "POSTGRES_PASSWORD=" + PASSWORD, "postgres:16-alpine").redirectOutput(new File("postgres-stdout.txt")) + .redirectError(new File("postgres-stderr.txt")).start(); + + // Wait until connection can be established + Awaitility.await().atMost(Duration.ofMinutes(1)).ignoreExceptions().until(() -> { + openConnection().close(); + return true; + }); + System.out.println("PostgreSQL started"); + } + + @AfterAll + static void tearDown() { + if (process != null && process.isAlive()) { + System.out.println("Shutting down PostgreSQL"); + process.destroy(); + } + } + + @Test + void commitAndRollback() throws Exception { + try (Connection conn = openConnection()) { + conn.setAutoCommit(false); + conn.prepareStatement("CREATE TABLE foo (id INT GENERATED ALWAYS AS IDENTITY, name VARCHAR)").execute(); + conn.commit(); + } + + try (Connection conn = openConnection()) { + conn.setAutoCommit(false); + PreparedStatement statement = conn.prepareStatement("INSERT INTO foo (name) VALUES (?)"); + statement.setString(1, "Adam"); + statement.execute(); + statement.setString(1, "Eve"); + statement.execute(); + conn.commit(); + } + + try (Connection conn = openConnection()) { + // Test rollbacks + conn.setAutoCommit(false); + conn.prepareStatement("DELETE FROM foo").execute(); + conn.rollback(); + } + + try (Connection conn = openConnection()) { + conn.setAutoCommit(false); + try (ResultSet resultSet = conn.prepareStatement("SELECT * FROM foo").executeQuery()) { + assertThat(resultSet.next()).isTrue(); + assertThat(resultSet.getInt(1)).isEqualTo(1); + assertThat(resultSet.getString(2)).isEqualTo("Adam"); + assertThat(resultSet.next()).isTrue(); + assertThat(resultSet.getInt(1)).isEqualTo(2); + assertThat(resultSet.getString(2)).isEqualTo("Eve"); + assertThat(resultSet.next()).isFalse(); + } + } + } + + @Test + void otherDatatypes() throws Exception { + try (Connection connection = openConnection()) { + connection.setAutoCommit(false); + connection.prepareStatement("CREATE TABLE other_datatypes(c1 cidr, i1 inet, i2 interval, m1 macaddr, m2 macaddr8, m3 money, n1 numeric(10, 2), t1 tsvector)").execute(); + PreparedStatement statement = connection.prepareStatement("INSERT INTO other_datatypes VALUES (CAST(? as cidr), CAST(? as inet), CAST(? as interval), CAST(? as macaddr), CAST(? as macaddr8), ?, ?, CAST(? as tsvector))"); + statement.setString(1, "192.168.100.128/25"); // cidr + statement.setString(2, "fe80::20c:29ff:fe8a:cd55/64"); // inet + statement.setString(3, "1 year 2 months 3 days 4 hours 5 minutes 6 seconds"); // interval + statement.setString(4, "08:00:2b:01:02:03"); // macaddr + statement.setString(5, "08:00:2b:01:02:03:04:05"); // macaddr8 + statement.setInt(6, 12); // money + statement.setDouble(7, Math.PI); // numeric + statement.setString(8, "this is an example sentence"); // tsvector + + statement.execute(); + + try (ResultSet resultSet = connection.prepareStatement("SELECT * FROM other_datatypes").executeQuery()) { + assertThat(resultSet.next()).isTrue(); + for (int i = 1; i <= 8; i++) { + System.out.printf("column %d: %s%n", i, resultSet.getObject(i)); + } + } + } + } + + @Test + void geometricDatatypes() throws Exception { + try (Connection connection = openConnection()) { + connection.setAutoCommit(false); + connection.prepareStatement("CREATE TABLE geometric_datatypes(b1 box, c1 circle, l1 line, l2 lseg, p1 path, p2 point, p3 polygon)").execute(); + PreparedStatement statement = connection.prepareStatement("INSERT INTO geometric_datatypes VALUES (CAST(? as box), CAST(? as circle), CAST(? as line), CAST(? as lseg), CAST(? as path), CAST(? as point), CAST(? as polygon))"); + statement.setString(1, "(0, 0), (10, 10)"); // box + statement.setString(2, "< (0, 0), 5 >"); // circle + statement.setString(3, "{ 1, 2, 3 }"); // line + statement.setString(4, "[ ( 0, 1 ), ( 2, 3 ) ]"); // lseg + statement.setString(5, "[ ( 1, 2 ), ( 3, 4 ), ( 5, 6 ) ]"); // path + statement.setString(6, "( 1, 2 )"); // point + statement.setString(7, "( ( 1, 2 ), ( 3, 4 ), ( 5, 6 ) )"); // polygon + statement.execute(); + + try (ResultSet resultSet = connection.prepareStatement("SELECT * FROM geometric_datatypes").executeQuery()) { + assertThat(resultSet.next()).isTrue(); + for (int i = 1; i <= 7; i++) { + System.out.printf("column %d: %s%n", i, resultSet.getObject(i)); + } + } + } + } + + @Test + void simpleDatatypes() throws Exception { + try (Connection connection = openConnection()) { + connection.setAutoCommit(false); + connection.prepareStatement("CREATE TABLE simple_datatypes " + + "(b1 bigint, b2 bit(1), b3 boolean, b4 bytea, c1 character(1), c2 character varying, d1 date, d2 double precision, " + + "i1 integer, j1 json, j2 jsonb, r1 real, s1 smallint, t1 text, t2 time, t3 time with time zone, t4 timestamp, " + + "t5 timestamp with time zone, u1 uuid, x1 xml, n1 integer)").execute(); + PreparedStatement statement = connection.prepareStatement("INSERT INTO simple_datatypes VALUES (?, CAST(? AS bit), ?, ?, ?, ?, ?, ?, ?, CAST(? AS json), CAST(? AS jsonb), ?, ?, ?, ?, ?, ?, ?, ?, CAST(? AS xml), ?)"); + statement.setLong(1, Long.MAX_VALUE); // bigint + statement.setString(2, "1"); // bit(1) + statement.setBoolean(3, true); // boolean + statement.setObject(4, "some-bytes".getBytes(StandardCharsets.UTF_8)); // bytea + statement.setString(5, "c"); // character(1) + statement.setString(6, "some-string"); // character varying + statement.setDate(7, Date.valueOf(LocalDate.of(2020, 1, 2))); // date + statement.setDouble(8, Math.PI); // double precision + statement.setInt(9, 42); // integer + statement.setString(10, "{ \"foo\": \"bar\"}"); // json + statement.setString(11, "{ \"foo\": \"bar\"}"); // jsonb + statement.setFloat(12, (float) Math.PI); // real + // s1 smallint, t1 text, t2 time, t3 time with time zone, t4 timestamp, t5 timestamp with time zone, u1 uuid, x1 xml)").execute(); + statement.setInt(13, 5); // smallint + statement.setString(14, "some-text"); // text + statement.setObject(15, LocalTime.of(23, 59)); // time + statement.setObject(16, OffsetTime.of(23, 59, 0, 0, ZoneOffset.ofHours(2))); // time with time zone + statement.setObject(17, LocalDateTime.of(2020, 1, 2, 23, 59, 0)); // timestamp + statement.setObject(18, OffsetDateTime.of(2020, 1, 2, 23, 59, 0, 0, ZoneOffset.ofHours(3))); // timestamp with time zone + statement.setObject(19, UUID.randomUUID()); // uuid + statement.setString(20, ""); + statement.setNull(21, Types.INTEGER); + statement.execute(); + + try (ResultSet resultSet = connection.prepareStatement("SELECT * FROM simple_datatypes").executeQuery()) { + assertThat(resultSet.next()).isTrue(); + for (int i = 1; i <= 21; i++) { + System.out.printf("column %d: %s%n", i, resultSet.getObject(i)); + } + } + } + } +}