Skip to content

Commit 49bb128

Browse files
blafondDavideD
authored andcommitted
[#1442] Add test for TimeZoneStorage
- Disabled for SQLServer which does not support java.time.OffsetTime
1 parent 2a1b40b commit 49bb128

File tree

1 file changed

+301
-0
lines changed

1 file changed

+301
-0
lines changed
Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
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.Duration;
9+
import java.time.LocalDateTime;
10+
import java.time.LocalTime;
11+
import java.time.OffsetDateTime;
12+
import java.time.OffsetTime;
13+
import java.time.ZoneOffset;
14+
import java.time.ZonedDateTime;
15+
import java.time.format.DateTimeFormatter;
16+
import java.util.Collection;
17+
import java.util.List;
18+
19+
import org.hibernate.annotations.TimeZoneColumn;
20+
import org.hibernate.annotations.TimeZoneStorage;
21+
import org.hibernate.annotations.TimeZoneStorageType;
22+
import org.hibernate.cfg.Configuration;
23+
import org.hibernate.reactive.BaseReactiveTest;
24+
import org.hibernate.reactive.testing.DBSelectionExtension;
25+
26+
import org.junit.jupiter.api.BeforeEach;
27+
import org.junit.jupiter.api.Test;
28+
import org.junit.jupiter.api.extension.RegisterExtension;
29+
30+
import io.vertx.junit5.Timeout;
31+
import io.vertx.junit5.VertxTestContext;
32+
import jakarta.persistence.Column;
33+
import jakarta.persistence.Entity;
34+
import jakarta.persistence.Id;
35+
import jakarta.persistence.Table;
36+
import jakarta.persistence.Tuple;
37+
38+
import static java.util.concurrent.TimeUnit.MINUTES;
39+
import static org.assertj.core.api.Assertions.assertThat;
40+
import static org.hibernate.cfg.AvailableSettings.TIMEZONE_DEFAULT_STORAGE;
41+
import static org.hibernate.reactive.containers.DatabaseConfiguration.DBType.SQLSERVER;
42+
43+
/**
44+
* Adapted from org.hibernate.orm.test.mapping.basic.TimeZoneStorageMappingTests
45+
*
46+
* <p>
47+
* Note that the tests below do not use ORM's annotations below to calculate
48+
* if a Dialect supports Format or Timezone types:
49+
* @RequiresDialectFeature(feature = DialectFeatureChecks.SupportsFormat.class)
50+
* @RequiresDialectFeature(feature = DialectFeatureChecks.SupportsTimezoneTypes.class....)
51+
* </p>
52+
* <p>
53+
* It appears that DB2, SQLServer and Oracle do not yet support FORMAT and none of reactive's supported Dialects
54+
* support Timezone Types via Offset, so the ORM's testNormalizeOffset(...) method is not included in these tests.
55+
* </p>
56+
*/
57+
@Timeout(value = 10, timeUnit = MINUTES)
58+
public class TimeZoneStorageMappingTest extends BaseReactiveTest {
59+
60+
// SQLSERVER currently does not support java.time.OffsetTime
61+
@RegisterExtension
62+
public DBSelectionExtension selectionRule = DBSelectionExtension.skipTestsFor( SQLSERVER );
63+
64+
private static final ZoneOffset JVM_TIMEZONE_OFFSET = OffsetDateTime.now().getOffset();
65+
private static final OffsetTime OFFSET_TIME = OffsetTime.of(
66+
LocalTime.of(
67+
12,
68+
0,
69+
0
70+
),
71+
ZoneOffset.ofHoursMinutes( 5, 45 )
72+
);
73+
private static final OffsetDateTime OFFSET_DATE_TIME = OffsetDateTime.of(
74+
LocalDateTime.of(
75+
2022,
76+
3,
77+
1,
78+
12,
79+
0,
80+
0
81+
),
82+
ZoneOffset.ofHoursMinutes( 5, 45 )
83+
);
84+
private static final ZonedDateTime ZONED_DATE_TIME = ZonedDateTime.of(
85+
LocalDateTime.of(
86+
2022,
87+
3,
88+
1,
89+
12,
90+
0,
91+
0
92+
),
93+
ZoneOffset.ofHoursMinutes( 5, 45 )
94+
);
95+
private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern( "HH:mm:ssxxx" );
96+
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern( "dd/MM/yyyy 'at' HH:mm:ssxxx" );
97+
98+
@Override
99+
protected Collection<Class<?>> annotatedEntities() {
100+
return List.of( TimeZoneStorageEntity.class );
101+
}
102+
103+
@Override
104+
protected void setProperties(Configuration configuration) {
105+
super.setProperties( configuration );
106+
configuration.setProperty( TIMEZONE_DEFAULT_STORAGE, "AUTO" );
107+
}
108+
109+
@BeforeEach
110+
public void populateDb(VertxTestContext context) {
111+
TimeZoneStorageEntity entity = new TimeZoneStorageEntity( 1, OFFSET_TIME, OFFSET_DATE_TIME, ZONED_DATE_TIME );
112+
113+
test( context, getMutinySessionFactory().withTransaction( (s, t) -> s.persist( entity ) ) );
114+
}
115+
116+
@Test
117+
public void testOffsetRetainedAuto(VertxTestContext context) {
118+
testOffsetRetained( context, "Auto" );
119+
}
120+
121+
@Test
122+
public void testOffsetRetainedColumn(VertxTestContext context) {
123+
testOffsetRetained( context, "Column" );
124+
}
125+
126+
@Test
127+
public void testOffsetRetainedFormatAuto(VertxTestContext context) {
128+
testOffsetRetainedFormat( context, "Auto" );
129+
}
130+
131+
@Test
132+
public void testOffsetRetainedFormatColumn(VertxTestContext context) {
133+
testOffsetRetainedFormat( context, "Column" );
134+
}
135+
136+
public void testOffsetRetained(VertxTestContext context, String suffix) {
137+
test( context, openSession()
138+
.thenCompose( session -> session.createQuery(
139+
"select " +
140+
"e.offsetTime" + suffix + ", " +
141+
"e.offsetDateTime" + suffix + ", " +
142+
"e.zonedDateTime" + suffix + ", " +
143+
"extract(offset from e.offsetTime" + suffix + "), " +
144+
"extract(offset from e.offsetDateTime" + suffix + "), " +
145+
"extract(offset from e.zonedDateTime" + suffix + "), " +
146+
"e.offsetTime" + suffix + " + 1 hour, " +
147+
"e.offsetDateTime" + suffix + " + 1 hour, " +
148+
"e.zonedDateTime" + suffix + " + 1 hour, " +
149+
"e.offsetTime" + suffix + " + 1 hour - e.offsetTime" + suffix + ", " +
150+
"e.offsetDateTime" + suffix + " + 1 hour - e.offsetDateTime" + suffix + ", " +
151+
"e.zonedDateTime" + suffix + " + 1 hour - e.zonedDateTime" + suffix + ", " +
152+
"1 from TimeZoneStorageEntity e " +
153+
"where e.offsetDateTime" + suffix + " = e.offsetDateTime" + suffix,
154+
Tuple.class
155+
).getSingleResult()
156+
.thenAccept( result -> {
157+
assertThat( result.get( 0, OffsetTime.class ) ).isEqualTo( OFFSET_TIME );
158+
assertThat( result.get( 1, OffsetDateTime.class ) ).isEqualTo( OFFSET_DATE_TIME );
159+
assertThat( result.get( 2, ZonedDateTime.class ) ).isEqualTo( ZONED_DATE_TIME );
160+
assertThat( result.get( 3, ZoneOffset.class ) ).isEqualTo( OFFSET_TIME.getOffset() );
161+
assertThat( result.get( 4, ZoneOffset.class ) ).isEqualTo( OFFSET_DATE_TIME.getOffset() );
162+
assertThat( result.get( 5, ZoneOffset.class ) ).isEqualTo( ZONED_DATE_TIME.getOffset() );
163+
assertThat( result.get( 6, OffsetTime.class ) ).isEqualTo( OFFSET_TIME.plusHours( 1L ) );
164+
assertThat( result.get( 7, OffsetDateTime.class ) ).isEqualTo( OFFSET_DATE_TIME.plusHours( 1L ) );
165+
assertThat( result.get( 8, ZonedDateTime.class ) ).isEqualTo( ZONED_DATE_TIME.plusHours( 1L ) );
166+
assertThat( result.get( 9, Duration.class ) ).isEqualTo( Duration.ofHours( 1L ) );
167+
assertThat( result.get( 10, Duration.class ) ).isEqualTo( Duration.ofHours( 1L ) );
168+
assertThat( result.get( 11, Duration.class ) ).isEqualTo( Duration.ofHours( 1L ) );
169+
} )
170+
)
171+
);
172+
}
173+
174+
public void testOffsetRetainedFormat(VertxTestContext context, String suffix) {
175+
test( context, openSession()
176+
.thenCompose( session -> session.createQuery(
177+
"select " +
178+
"format(e.offsetTime" + suffix + " as 'HH:mm:ssxxx'), " +
179+
"format(e.offsetDateTime" + suffix + " as 'dd/MM/yyyy ''at'' HH:mm:ssxxx'), " +
180+
"format(e.zonedDateTime" + suffix + " as 'dd/MM/yyyy ''at'' HH:mm:ssxxx'), " +
181+
"1 from TimeZoneStorageEntity e " +
182+
"where e.offsetDateTime" + suffix + " = e.offsetDateTime" + suffix,
183+
Tuple.class
184+
).getSingleResult()
185+
.thenAccept( result -> {
186+
assertThat( result.get( 0, String.class ) ).isEqualTo( TIME_FORMATTER.format( OFFSET_TIME ) );
187+
assertThat( result.get( 1, String.class ) ).isEqualTo( FORMATTER.format( OFFSET_DATE_TIME ) );
188+
assertThat( result.get( 2, String.class ) ).isEqualTo( FORMATTER.format( ZONED_DATE_TIME ) );
189+
} )
190+
)
191+
);
192+
}
193+
194+
@Test
195+
public void testNormalize(VertxTestContext context) {
196+
test( context, openSession()
197+
.thenCompose( session -> session.createQuery(
198+
"select " +
199+
"e.offsetTimeNormalized, " +
200+
"e.offsetDateTimeNormalized, " +
201+
"e.zonedDateTimeNormalized, " +
202+
"e.offsetTimeNormalizedUtc, " +
203+
"e.offsetDateTimeNormalizedUtc, " +
204+
"e.zonedDateTimeNormalizedUtc " +
205+
"from TimeZoneStorageEntity e",
206+
Tuple.class
207+
).getSingleResult()
208+
.thenAccept( result -> {
209+
assertThat( result.get( 0, OffsetTime.class ).toLocalTime()).isEqualTo( OFFSET_TIME.withOffsetSameInstant( JVM_TIMEZONE_OFFSET ).toLocalTime() );
210+
assertThat( result.get( 0, OffsetTime.class ).getOffset()).isEqualTo( JVM_TIMEZONE_OFFSET );
211+
assertThat( result.get( 1, OffsetDateTime.class ).toInstant()).isEqualTo( OFFSET_DATE_TIME.toInstant() );
212+
assertThat( result.get( 2, ZonedDateTime.class ).toInstant()).isEqualTo( ZONED_DATE_TIME.toInstant() );
213+
assertThat( result.get( 3, OffsetTime.class ).toLocalTime()).isEqualTo( OFFSET_TIME.withOffsetSameInstant( ZoneOffset.UTC ).toLocalTime() );
214+
assertThat( result.get( 3, OffsetTime.class ).getOffset()).isEqualTo( ZoneOffset.UTC );
215+
assertThat( result.get( 4, OffsetDateTime.class ).toInstant()).isEqualTo( OFFSET_DATE_TIME.toInstant() );
216+
assertThat( result.get( 5, ZonedDateTime.class ).toInstant()).isEqualTo( ZONED_DATE_TIME.toInstant() );
217+
}
218+
)
219+
)
220+
);
221+
}
222+
223+
@Entity(name = "TimeZoneStorageEntity")
224+
@Table(name = "TimeZoneStorageEntity")
225+
public static class TimeZoneStorageEntity {
226+
@Id
227+
public Integer id;
228+
229+
//tag::time-zone-column-examples-mapping-example[]
230+
@TimeZoneStorage(TimeZoneStorageType.COLUMN)
231+
@TimeZoneColumn(name = "birthtime_offset_offset")
232+
@Column(name = "birthtime_offset")
233+
public OffsetTime offsetTimeColumn;
234+
235+
@TimeZoneStorage(TimeZoneStorageType.COLUMN)
236+
@TimeZoneColumn(name = "birthday_offset_offset")
237+
@Column(name = "birthday_offset")
238+
public OffsetDateTime offsetDateTimeColumn;
239+
240+
@TimeZoneStorage(TimeZoneStorageType.COLUMN)
241+
@TimeZoneColumn(name = "birthday_zoned_offset")
242+
@Column(name = "birthday_zoned")
243+
public ZonedDateTime zonedDateTimeColumn;
244+
//end::time-zone-column-examples-mapping-example[]
245+
246+
@TimeZoneStorage
247+
@Column(name = "birthtime_offset_auto")
248+
public OffsetTime offsetTimeAuto;
249+
250+
@TimeZoneStorage
251+
@Column(name = "birthday_offset_auto")
252+
public OffsetDateTime offsetDateTimeAuto;
253+
254+
@TimeZoneStorage
255+
@Column(name = "birthday_zoned_auto")
256+
public ZonedDateTime zonedDateTimeAuto;
257+
258+
@TimeZoneStorage(TimeZoneStorageType.NORMALIZE)
259+
@Column(name = "birthtime_offset_normalized")
260+
public OffsetTime offsetTimeNormalized;
261+
262+
@TimeZoneStorage(TimeZoneStorageType.NORMALIZE)
263+
@Column(name = "birthday_offset_normalized")
264+
public OffsetDateTime offsetDateTimeNormalized;
265+
266+
@TimeZoneStorage(TimeZoneStorageType.NORMALIZE)
267+
@Column(name = "birthday_zoned_normalized")
268+
public ZonedDateTime zonedDateTimeNormalized;
269+
270+
@TimeZoneStorage(TimeZoneStorageType.NORMALIZE_UTC)
271+
@Column(name = "birthtime_offset_utc")
272+
public OffsetTime offsetTimeNormalizedUtc;
273+
274+
@TimeZoneStorage(TimeZoneStorageType.NORMALIZE_UTC)
275+
@Column(name = "birthday_offset_utc")
276+
public OffsetDateTime offsetDateTimeNormalizedUtc;
277+
278+
@TimeZoneStorage(TimeZoneStorageType.NORMALIZE_UTC)
279+
@Column(name = "birthday_zoned_utc")
280+
private ZonedDateTime zonedDateTimeNormalizedUtc;
281+
282+
public TimeZoneStorageEntity() {
283+
}
284+
285+
public TimeZoneStorageEntity(Integer id, OffsetTime offsetTime, OffsetDateTime offsetDateTime, ZonedDateTime zonedDateTime) {
286+
this.id = id;
287+
this.offsetTimeColumn = offsetTime;
288+
this.offsetDateTimeColumn = offsetDateTime;
289+
this.zonedDateTimeColumn = zonedDateTime;
290+
this.offsetTimeAuto = offsetTime;
291+
this.offsetDateTimeAuto = offsetDateTime;
292+
this.zonedDateTimeAuto = zonedDateTime;
293+
this.offsetTimeNormalized = offsetTime;
294+
this.offsetDateTimeNormalized = offsetDateTime;
295+
this.zonedDateTimeNormalized = zonedDateTime;
296+
this.offsetTimeNormalizedUtc = offsetTime;
297+
this.offsetDateTimeNormalizedUtc = offsetDateTime;
298+
this.zonedDateTimeNormalizedUtc = zonedDateTime;
299+
}
300+
}
301+
}

0 commit comments

Comments
 (0)