Skip to content

Commit 81b96e2

Browse files
gavinkingDavideD
authored andcommitted
[#1584] Add tests for timezone + Instant handling
1 parent c82f372 commit 81b96e2

File tree

9 files changed

+591
-2
lines changed

9 files changed

+591
-2
lines changed

hibernate-reactive-core/src/test/java/org/hibernate/reactive/BaseReactiveTest.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
import org.hibernate.boot.registry.StandardServiceRegistry;
1717
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
1818
import org.hibernate.cfg.Configuration;
19+
import org.hibernate.dialect.Dialect;
1920
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
21+
import org.hibernate.engine.spi.SessionFactoryImplementor;
2022
import org.hibernate.reactive.containers.DatabaseConfiguration;
2123
import org.hibernate.reactive.containers.DatabaseConfiguration.DBType;
2224
import org.hibernate.reactive.mutiny.Mutiny;
@@ -352,6 +354,13 @@ protected static Stage.SessionFactory getSessionFactory() {
352354
return factoryManager.getHibernateSessionFactory().unwrap( Stage.SessionFactory.class );
353355
}
354356

357+
protected static Dialect getDialect() {
358+
return factoryManager.getHibernateSessionFactory()
359+
.unwrap( SessionFactoryImplementor.class )
360+
.getJdbcServices()
361+
.getDialect();
362+
}
363+
355364
/**
356365
* Close the existing open session and create a new {@link Stage.Session}
357366
*

hibernate-reactive-core/src/test/java/org/hibernate/reactive/testing/ReactiveAssertions.java

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,18 @@
55
*/
66
package org.hibernate.reactive.testing;
77

8-
import static org.assertj.core.api.Assertions.assertThat;
9-
8+
import java.time.Instant;
9+
import java.time.temporal.ChronoUnit;
1010
import java.util.concurrent.CompletionException;
1111
import java.util.concurrent.CompletionStage;
1212

1313
import io.smallrye.mutiny.Uni;
14+
import org.assertj.core.api.AbstractInstantAssert;
15+
16+
import static java.time.temporal.ChronoUnit.MILLIS;
17+
import static java.util.Comparator.comparing;
18+
import static org.assertj.core.api.Assertions.assertThat;
19+
1420

1521
/**
1622
* Utility to handle verifying the information about an expected {@link Throwable}
@@ -32,6 +38,19 @@ public static <T extends Throwable> CompletionStage<T> assertThrown(Class<T> exp
3238
} );
3339
}
3440

41+
public static AbstractInstantAssert<?> assertWithTruncationThat(Instant instant) {
42+
return javaVersion() < 15
43+
? assertThat( instant )
44+
// Since java 15, the precision of the equals has changed.
45+
// It won't work unless we truncate the value to the millis
46+
: assertThat( instant ).usingComparator( comparing( o -> o.truncatedTo( MILLIS ) ) );
47+
}
48+
49+
private static Integer javaVersion() {
50+
String version = System.getProperty( "java.version" );
51+
return Integer.valueOf( version.substring( 0, 2 ) );
52+
}
53+
3554
/**
3655
* Depending on the use case, the real exception could be wrapped in a {@link CompletionException}.
3756
* In that case the method returns the cause.
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/* Hibernate, Relational Persistence for Idiomatic Java
2+
*
3+
* SPDX-License-Identifier: Apache-2.0
4+
* Copyright: Red Hat Inc. and Hibernate Authors
5+
*/
6+
package org.hibernate.reactive.timezones;
7+
8+
import io.vertx.ext.unit.TestContext;
9+
import jakarta.persistence.Entity;
10+
import jakarta.persistence.GeneratedValue;
11+
import jakarta.persistence.Id;
12+
13+
import org.hibernate.cfg.Configuration;
14+
import org.hibernate.reactive.BaseReactiveTest;
15+
16+
import org.junit.Test;
17+
18+
import java.time.OffsetDateTime;
19+
import java.time.ZoneId;
20+
import java.time.ZoneOffset;
21+
import java.time.ZonedDateTime;
22+
import java.util.Collection;
23+
import java.util.List;
24+
25+
import static org.assertj.core.api.Assertions.assertThat;
26+
import static org.hibernate.cfg.AvailableSettings.TIMEZONE_DEFAULT_STORAGE;
27+
import static org.hibernate.reactive.testing.ReactiveAssertions.assertWithTruncationThat;
28+
import static org.hibernate.type.descriptor.DateTimeUtils.roundToDefaultPrecision;
29+
30+
public class AutoZonedTest extends BaseReactiveTest {
31+
32+
@Override
33+
protected Collection<Class<?>> annotatedEntities() {
34+
return List.of( Zoned.class );
35+
}
36+
37+
@Override
38+
protected void setProperties(Configuration configuration) {
39+
super.setProperties( configuration );
40+
configuration.setProperty( TIMEZONE_DEFAULT_STORAGE, "AUTO" );
41+
}
42+
43+
@Test
44+
public void test(TestContext context) {
45+
ZonedDateTime nowZoned = ZonedDateTime.now().withZoneSameInstant( ZoneId.of( "CET" ) );
46+
OffsetDateTime nowOffset = OffsetDateTime.now().withOffsetSameInstant( ZoneOffset.ofHours( 3 ) );
47+
test( context, getSessionFactory()
48+
.withTransaction( s -> {
49+
Zoned z = new Zoned();
50+
z.zonedDateTime = nowZoned;
51+
z.offsetDateTime = nowOffset;
52+
return s.persist( z ).thenApply( v -> z.id );
53+
} )
54+
.thenCompose( zid -> openSession()
55+
.thenCompose( s -> s.find( Zoned.class, zid )
56+
.thenAccept( z -> {
57+
assertWithTruncationThat( roundToDefaultPrecision( z.zonedDateTime.toInstant(), getDialect() ) )
58+
.isEqualTo( roundToDefaultPrecision( nowZoned.toInstant(), getDialect() ) );
59+
assertWithTruncationThat( roundToDefaultPrecision( z.offsetDateTime.toInstant(), getDialect() ) )
60+
.isEqualTo( roundToDefaultPrecision( nowOffset.toInstant(), getDialect() ) );
61+
assertThat( z.zonedDateTime.toOffsetDateTime().getOffset() )
62+
.isEqualTo( nowZoned.toOffsetDateTime().getOffset() );
63+
assertThat( z.offsetDateTime.getOffset() )
64+
.isEqualTo( nowOffset.getOffset() );
65+
} )
66+
)
67+
)
68+
);
69+
}
70+
71+
@Entity(name = "Zoned")
72+
public static class Zoned {
73+
@Id
74+
@GeneratedValue
75+
Long id;
76+
ZonedDateTime zonedDateTime;
77+
OffsetDateTime offsetDateTime;
78+
}
79+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/* Hibernate, Relational Persistence for Idiomatic Java
2+
*
3+
* SPDX-License-Identifier: Apache-2.0
4+
* Copyright: Red Hat Inc. and Hibernate Authors
5+
*/
6+
package org.hibernate.reactive.timezones;
7+
8+
import io.vertx.ext.unit.TestContext;
9+
import jakarta.persistence.Entity;
10+
import jakarta.persistence.GeneratedValue;
11+
import jakarta.persistence.Id;
12+
13+
import org.hibernate.cfg.Configuration;
14+
import org.hibernate.reactive.BaseReactiveTest;
15+
16+
import org.junit.Test;
17+
18+
import java.time.OffsetDateTime;
19+
import java.time.ZoneId;
20+
import java.time.ZoneOffset;
21+
import java.time.ZonedDateTime;
22+
import java.util.Collection;
23+
import java.util.List;
24+
25+
import static org.assertj.core.api.Assertions.assertThat;
26+
import static org.hibernate.cfg.AvailableSettings.TIMEZONE_DEFAULT_STORAGE;
27+
import static org.hibernate.reactive.testing.ReactiveAssertions.assertWithTruncationThat;
28+
import static org.hibernate.type.descriptor.DateTimeUtils.roundToDefaultPrecision;
29+
30+
31+
public class ColumnZonedTest extends BaseReactiveTest {
32+
33+
@Override
34+
protected Collection<Class<?>> annotatedEntities() {
35+
return List.of( Zoned.class );
36+
}
37+
38+
@Override
39+
protected void setProperties(Configuration configuration) {
40+
super.setProperties( configuration );
41+
configuration.setProperty( TIMEZONE_DEFAULT_STORAGE, "COLUMN" );
42+
}
43+
44+
@Test
45+
public void test(TestContext context) {
46+
ZonedDateTime nowZoned = ZonedDateTime.now().withZoneSameInstant( ZoneId.of( "CET" ) );
47+
OffsetDateTime nowOffset = OffsetDateTime.now().withOffsetSameInstant( ZoneOffset.ofHours( 3 ) );
48+
test( context, getSessionFactory()
49+
.withTransaction( s -> {
50+
Zoned z = new Zoned();
51+
z.zonedDateTime = nowZoned;
52+
z.offsetDateTime = nowOffset;
53+
return s.persist( z ).thenApply( v -> z.id );
54+
} )
55+
.thenCompose( zid -> openSession()
56+
.thenCompose( s -> s.find( Zoned.class, zid )
57+
.thenAccept( z -> {
58+
assertWithTruncationThat( roundToDefaultPrecision( z.zonedDateTime.toInstant(), getDialect() ) )
59+
.isEqualTo( roundToDefaultPrecision( nowZoned.toInstant(), getDialect() ) );
60+
assertWithTruncationThat( roundToDefaultPrecision( z.offsetDateTime.toInstant(), getDialect() ) )
61+
.isEqualTo( roundToDefaultPrecision( nowOffset.toInstant(), getDialect() ) );
62+
assertThat( z.zonedDateTime.toOffsetDateTime().getOffset() )
63+
.isEqualTo( nowZoned.toOffsetDateTime().getOffset() );
64+
assertThat( z.offsetDateTime.getOffset() )
65+
.isEqualTo( nowOffset.getOffset() );
66+
} )
67+
)
68+
)
69+
);
70+
}
71+
72+
@Entity(name = "Zoned")
73+
public static class Zoned {
74+
@Id
75+
@GeneratedValue
76+
Long id;
77+
ZonedDateTime zonedDateTime;
78+
OffsetDateTime offsetDateTime;
79+
}
80+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/* Hibernate, Relational Persistence for Idiomatic Java
2+
*
3+
* SPDX-License-Identifier: Apache-2.0
4+
* Copyright: Red Hat Inc. and Hibernate Authors
5+
*/
6+
package org.hibernate.reactive.timezones;
7+
8+
import io.vertx.ext.unit.TestContext;
9+
import jakarta.persistence.Entity;
10+
import jakarta.persistence.GeneratedValue;
11+
import jakarta.persistence.Id;
12+
13+
import org.hibernate.dialect.TimeZoneSupport;
14+
import org.hibernate.reactive.BaseReactiveTest;
15+
16+
import org.junit.Test;
17+
18+
import java.time.OffsetDateTime;
19+
import java.time.ZoneId;
20+
import java.time.ZoneOffset;
21+
import java.time.ZonedDateTime;
22+
import java.util.Collection;
23+
import java.util.List;
24+
25+
import static org.assertj.core.api.Assertions.assertThat;
26+
import static org.hibernate.reactive.testing.ReactiveAssertions.assertWithTruncationThat;
27+
import static org.hibernate.type.descriptor.DateTimeUtils.roundToDefaultPrecision;
28+
29+
public class DefaultZonedTest extends BaseReactiveTest {
30+
31+
@Override
32+
protected Collection<Class<?>> annotatedEntities() {
33+
return List.of( Zoned.class );
34+
}
35+
36+
@Test
37+
public void test(TestContext context) {
38+
ZonedDateTime nowZoned = ZonedDateTime.now().withZoneSameInstant( ZoneId.of( "CET" ) );
39+
OffsetDateTime nowOffset = OffsetDateTime.now().withOffsetSameInstant( ZoneOffset.ofHours( 3 ) );
40+
test( context, getSessionFactory()
41+
.withTransaction( s -> {
42+
Zoned z = new Zoned();
43+
z.zonedDateTime = nowZoned;
44+
z.offsetDateTime = nowOffset;
45+
return s.persist( z ).thenApply( v -> z.id );
46+
} )
47+
.thenCompose( zid -> openSession()
48+
.thenCompose( s -> s.find( Zoned.class, zid )
49+
.thenAccept( z -> {
50+
assertWithTruncationThat( roundToDefaultPrecision( z.zonedDateTime.toInstant(), getDialect() ) )
51+
.isEqualTo( roundToDefaultPrecision( nowZoned.toInstant(), getDialect() ) );
52+
assertWithTruncationThat( roundToDefaultPrecision( z.offsetDateTime.toInstant(), getDialect() ) )
53+
.isEqualTo( roundToDefaultPrecision( nowOffset.toInstant(), getDialect() ) );
54+
55+
if ( getDialect().getTimeZoneSupport() == TimeZoneSupport.NATIVE ) {
56+
assertThat( z.zonedDateTime.toOffsetDateTime().getOffset() )
57+
.isEqualTo( nowZoned.toOffsetDateTime().getOffset() );
58+
assertThat( z.offsetDateTime.getOffset() ).isEqualTo( nowOffset.getOffset() );
59+
}
60+
else {
61+
assertThat( z.zonedDateTime.getZone() )
62+
.isEqualTo( ZoneId.of( "Z" ) );
63+
assertThat( z.offsetDateTime.getOffset() )
64+
.isEqualTo( ZoneOffset.ofHours( 0 ) );
65+
}
66+
} )
67+
)
68+
)
69+
);
70+
}
71+
72+
@Entity(name = "Zoned")
73+
public static class Zoned {
74+
@Id
75+
@GeneratedValue
76+
Long id;
77+
ZonedDateTime zonedDateTime;
78+
OffsetDateTime offsetDateTime;
79+
}
80+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/* Hibernate, Relational Persistence for Idiomatic Java
2+
*
3+
* SPDX-License-Identifier: Apache-2.0
4+
* Copyright: Red Hat Inc. and Hibernate Authors
5+
*/
6+
package org.hibernate.reactive.timezones;
7+
8+
import java.time.Instant;
9+
import java.time.OffsetDateTime;
10+
import java.time.ZoneId;
11+
import java.time.ZoneOffset;
12+
import java.time.ZonedDateTime;
13+
import java.util.Collection;
14+
import java.util.List;
15+
16+
import org.hibernate.cfg.Configuration;
17+
import org.hibernate.reactive.BaseReactiveTest;
18+
19+
import org.junit.Test;
20+
21+
import io.vertx.ext.unit.TestContext;
22+
import jakarta.persistence.Entity;
23+
import jakarta.persistence.GeneratedValue;
24+
import jakarta.persistence.Id;
25+
26+
import static org.assertj.core.api.Assertions.assertThat;
27+
import static org.hibernate.cfg.AvailableSettings.JDBC_TIME_ZONE;
28+
import static org.hibernate.cfg.AvailableSettings.TIMEZONE_DEFAULT_STORAGE;
29+
import static org.hibernate.reactive.testing.ReactiveAssertions.assertWithTruncationThat;
30+
import static org.hibernate.type.descriptor.DateTimeUtils.roundToDefaultPrecision;
31+
32+
public class JDBCTimeZoneZonedTest extends BaseReactiveTest {
33+
@Override
34+
protected Collection<Class<?>> annotatedEntities() {
35+
return List.of( Zoned.class );
36+
}
37+
38+
@Override
39+
protected void setProperties(Configuration configuration) {
40+
super.setProperties( configuration );
41+
configuration.setProperty( TIMEZONE_DEFAULT_STORAGE, "NORMALIZE" );
42+
configuration.setProperty( JDBC_TIME_ZONE, "GMT+5" );
43+
}
44+
45+
@Test
46+
public void test(TestContext context) {
47+
ZonedDateTime nowZoned = ZonedDateTime.now().withZoneSameInstant( ZoneId.of( "CET" ) );
48+
OffsetDateTime nowOffset = OffsetDateTime.now().withOffsetSameInstant( ZoneOffset.ofHours( 3 ) );
49+
test( context, getSessionFactory()
50+
.withTransaction( s -> {
51+
Zoned z = new Zoned();
52+
z.zonedDateTime = nowZoned;
53+
z.offsetDateTime = nowOffset;
54+
return s.persist( z ).thenApply( v -> z.id );
55+
} )
56+
.thenCompose( zid -> openSession()
57+
.thenCompose( s -> s.find( Zoned.class, zid )
58+
.thenAccept( z -> {
59+
assertWithTruncationThat( roundToDefaultPrecision( z.zonedDateTime.toInstant(), getDialect() ) )
60+
.isEqualTo( roundToDefaultPrecision( nowZoned.toInstant(), getDialect() ) );
61+
62+
assertWithTruncationThat( roundToDefaultPrecision( z.offsetDateTime.toInstant(), getDialect() ) )
63+
.isEqualTo( roundToDefaultPrecision( nowOffset.toInstant(), getDialect() ) );
64+
65+
ZoneId systemZone = ZoneId.systemDefault();
66+
ZoneOffset systemOffset = systemZone.getRules().getOffset( Instant.now() );
67+
assertThat( z.zonedDateTime.getZone() ).isEqualTo( systemZone );
68+
assertThat( z.offsetDateTime.getOffset() ).isEqualTo( systemOffset );
69+
} )
70+
)
71+
)
72+
);
73+
}
74+
75+
@Entity(name = "Zoned")
76+
public static class Zoned {
77+
@Id
78+
@GeneratedValue
79+
Long id;
80+
ZonedDateTime zonedDateTime;
81+
OffsetDateTime offsetDateTime;
82+
}
83+
}

0 commit comments

Comments
 (0)