Skip to content

Commit 4ad86d7

Browse files
authored
test(jdbc): add Hibernate integration smoke tests (#264)
## Summary Promotes the Hibernate smoke prototype into `libsql-jdbc` as a Failsafe integration test. - `HibernateIT` drives the in-tree driver through Hibernate ORM 7.4: identity-generated keys, scalar mapping, `@ManyToOne` associations, HQL joins and pagination, repeated inserts, schema validation, and optimistic locking. - `HibernateSqldSupport` starts the pinned sqld Testcontainer and creates the schema through JDBC. Hibernate 7.4's SQLite dialect emits an untyped identity column for `book`, so its own DDL is not used; the validator test still reads the schema back through the driver's `DatabaseMetaData`. - Optimistic locking coverage: - version increment on a successful update; - explicit `OPTIMISTIC_FORCE_INCREMENT`; - stale detached merge; - stale delete; - versioned update through a foreign-key association; - timestamp-valued `@Version` round-trip and stale merge. - Stale-write tests assert Hibernate receives an update count of `0`, throws an optimistic-lock exception, and leaves the stored row unchanged. - Test-only dependencies: Hibernate 7.4.13, Testcontainers, and Failsafe `*IT` wiring. `./mvnw test` stays unit-only. - The module copies the shared Docker config into `target/docker-config` and sets `DOCKER_CONFIG` for Failsafe, so sandboxed runs work without a shell override. ## Driver findings No driver-level defects surfaced in the covered Hibernate paths. Generated keys, versioned update/delete counts, timestamp comparisons, and schema validation all behaved correctly. ## Auto-commit identity `#83` already tracks the relevant limitation: in auto-commit, a direct `SELECT last_insert_rowid()` reads a fresh Hrana stream. Hibernate's `GenerationType.IDENTITY` uses that same query, so this suite keeps auto-commit disabled (Hibernate's default) and documents the dependency. No duplicate issue was created. Refs #83 ## Test plan - [x] `./mvnw -pl libsql-jdbc -am -Dit.test=HibernateIT -Dtest=NoSuchTest -Dsurefire.failIfNoSpecifiedTests=false verify` — 11 tests pass - [x] `./mvnw spotless:check` - [x] `./prototype/hibernate-smoke/run.sh` — 11 prototype tests pass against a throwaway sqld container
1 parent 08a3531 commit 4ad86d7

7 files changed

Lines changed: 649 additions & 0 deletions

File tree

‎libsql-jdbc/pom.xml‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,18 @@
3838
<version>${flyway.version}</version>
3939
<scope>test</scope>
4040
</dependency>
41+
<dependency>
42+
<groupId>org.hibernate.orm</groupId>
43+
<artifactId>hibernate-core</artifactId>
44+
<version>${hibernate.version}</version>
45+
<scope>test</scope>
46+
</dependency>
47+
<dependency>
48+
<groupId>org.hibernate.orm</groupId>
49+
<artifactId>hibernate-community-dialects</artifactId>
50+
<version>${hibernate.version}</version>
51+
<scope>test</scope>
52+
</dependency>
4153
<dependency>
4254
<groupId>org.liquibase</groupId>
4355
<artifactId>liquibase-core</artifactId>
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package io.github.magnusp.libsql.jdbc.hibernate;
2+
3+
import jakarta.persistence.Column;
4+
import jakarta.persistence.Entity;
5+
import jakarta.persistence.GeneratedValue;
6+
import jakarta.persistence.GenerationType;
7+
import jakarta.persistence.Id;
8+
import jakarta.persistence.Table;
9+
import jakarta.persistence.Version;
10+
11+
@Entity
12+
@Table(name = "author")
13+
public class Author {
14+
15+
@Id
16+
@GeneratedValue(strategy = GenerationType.IDENTITY)
17+
private Integer id;
18+
19+
@Column(nullable = false)
20+
private String name;
21+
22+
private String country;
23+
24+
@Version
25+
private long version;
26+
27+
protected Author() {}
28+
29+
public Author(String name, String country) {
30+
this.name = name;
31+
this.country = country;
32+
}
33+
34+
public Integer getId() {
35+
return id;
36+
}
37+
38+
public String getName() {
39+
return name;
40+
}
41+
42+
public void setName(String name) {
43+
this.name = name;
44+
}
45+
46+
public String getCountry() {
47+
return country;
48+
}
49+
50+
public void setCountry(String country) {
51+
this.country = country;
52+
}
53+
54+
public long getVersion() {
55+
return version;
56+
}
57+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package io.github.magnusp.libsql.jdbc.hibernate;
2+
3+
import jakarta.persistence.Column;
4+
import jakarta.persistence.Entity;
5+
import jakarta.persistence.FetchType;
6+
import jakarta.persistence.GeneratedValue;
7+
import jakarta.persistence.GenerationType;
8+
import jakarta.persistence.Id;
9+
import jakarta.persistence.JoinColumn;
10+
import jakarta.persistence.ManyToOne;
11+
import jakarta.persistence.Table;
12+
import jakarta.persistence.Version;
13+
14+
import java.math.BigDecimal;
15+
16+
@Entity
17+
@Table(name = "book")
18+
public class Book {
19+
20+
@Id
21+
@GeneratedValue(strategy = GenerationType.IDENTITY)
22+
private Integer id;
23+
24+
@ManyToOne(fetch = FetchType.LAZY, optional = false)
25+
@JoinColumn(name = "author_id", nullable = false)
26+
private Author author;
27+
28+
@Column(nullable = false)
29+
private String title;
30+
31+
private BigDecimal price;
32+
33+
@Column(name = "in_print", nullable = false)
34+
private boolean inPrint;
35+
36+
@Version
37+
private long version;
38+
39+
protected Book() {}
40+
41+
public Book(Author author, String title, BigDecimal price, boolean inPrint) {
42+
this.author = author;
43+
this.title = title;
44+
this.price = price;
45+
this.inPrint = inPrint;
46+
}
47+
48+
public Integer getId() {
49+
return id;
50+
}
51+
52+
public Author getAuthor() {
53+
return author;
54+
}
55+
56+
public String getTitle() {
57+
return title;
58+
}
59+
60+
public void setTitle(String title) {
61+
this.title = title;
62+
}
63+
64+
public BigDecimal getPrice() {
65+
return price;
66+
}
67+
68+
public void setPrice(BigDecimal price) {
69+
this.price = price;
70+
}
71+
72+
public boolean isInPrint() {
73+
return inPrint;
74+
}
75+
76+
public void setInPrint(boolean inPrint) {
77+
this.inPrint = inPrint;
78+
}
79+
80+
public long getVersion() {
81+
return version;
82+
}
83+
}

0 commit comments

Comments
 (0)