HHH-18395 Fix intermittent failures of clock based tests by using custom clock
This commit is contained in:
parent
a17b241f40
commit
5b2a87c5e8
|
@ -9,9 +9,10 @@ package org.hibernate.engine.internal;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.hibernate.MappingException;
|
import org.hibernate.MappingException;
|
||||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
import org.hibernate.SharedSessionContract;
|
||||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||||
import org.hibernate.engine.spi.IdentifierValue;
|
import org.hibernate.engine.spi.IdentifierValue;
|
||||||
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.engine.spi.SharedSessionDelegatorBaseImpl;
|
import org.hibernate.engine.spi.SharedSessionDelegatorBaseImpl;
|
||||||
import org.hibernate.engine.spi.VersionValue;
|
import org.hibernate.engine.spi.VersionValue;
|
||||||
import org.hibernate.mapping.KeyValue;
|
import org.hibernate.mapping.KeyValue;
|
||||||
|
@ -85,7 +86,8 @@ public class UnsavedValueFactory {
|
||||||
Integer precision,
|
Integer precision,
|
||||||
Integer scale,
|
Integer scale,
|
||||||
Getter getter,
|
Getter getter,
|
||||||
Supplier<?> templateInstanceAccess) {
|
Supplier<?> templateInstanceAccess,
|
||||||
|
SessionFactoryImplementor sessionFactory) {
|
||||||
final String unsavedValue = bootVersionMapping.getNullValue();
|
final String unsavedValue = bootVersionMapping.getNullValue();
|
||||||
if ( unsavedValue == null ) {
|
if ( unsavedValue == null ) {
|
||||||
if ( getter != null && templateInstanceAccess != null ) {
|
if ( getter != null && templateInstanceAccess != null ) {
|
||||||
|
@ -95,8 +97,7 @@ public class UnsavedValueFactory {
|
||||||
|
|
||||||
// if the version of a newly instantiated object is not the same
|
// if the version of a newly instantiated object is not the same
|
||||||
// as the version seed value, use that as the unsaved-value
|
// as the version seed value, use that as the unsaved-value
|
||||||
final T seedValue = jtd.seed( length, precision, scale,
|
final T seedValue = jtd.seed( length, precision, scale, mockSession( sessionFactory ) );
|
||||||
mockSession( bootVersionMapping.getBuildingContext() ) );
|
|
||||||
return jtd.areEqual( seedValue, defaultValue )
|
return jtd.areEqual( seedValue, defaultValue )
|
||||||
? VersionValue.UNDEFINED
|
? VersionValue.UNDEFINED
|
||||||
: new VersionValue( defaultValue );
|
: new VersionValue( defaultValue );
|
||||||
|
@ -121,12 +122,27 @@ public class UnsavedValueFactory {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SharedSessionDelegatorBaseImpl mockSession(MetadataBuildingContext context) {
|
private static SharedSessionDelegatorBaseImpl mockSession(SessionFactoryImplementor sessionFactory) {
|
||||||
return new SharedSessionDelegatorBaseImpl(null) {
|
return new SharedSessionDelegatorBaseImpl(null) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SharedSessionContract delegate() {
|
||||||
|
throw new UnsupportedOperationException( "Operation not supported" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SessionFactoryImplementor getFactory() {
|
||||||
|
return sessionFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SessionFactoryImplementor getSessionFactory() {
|
||||||
|
return sessionFactory;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JdbcServices getJdbcServices() {
|
public JdbcServices getJdbcServices() {
|
||||||
return context.getBootstrapContext().getServiceRegistry()
|
return sessionFactory.getJdbcServices();
|
||||||
.requireService( JdbcServices.class );
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,11 +7,13 @@
|
||||||
package org.hibernate.generator.internal;
|
package org.hibernate.generator.internal;
|
||||||
|
|
||||||
import org.hibernate.AssertionFailure;
|
import org.hibernate.AssertionFailure;
|
||||||
|
import org.hibernate.SessionFactory;
|
||||||
import org.hibernate.annotations.CreationTimestamp;
|
import org.hibernate.annotations.CreationTimestamp;
|
||||||
import org.hibernate.annotations.CurrentTimestamp;
|
import org.hibernate.annotations.CurrentTimestamp;
|
||||||
import org.hibernate.annotations.SourceType;
|
import org.hibernate.annotations.SourceType;
|
||||||
import org.hibernate.annotations.UpdateTimestamp;
|
import org.hibernate.annotations.UpdateTimestamp;
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
|
import org.hibernate.engine.config.spi.ConfigurationService;
|
||||||
import org.hibernate.engine.jdbc.Size;
|
import org.hibernate.engine.jdbc.Size;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.generator.EventType;
|
import org.hibernate.generator.EventType;
|
||||||
|
@ -36,7 +38,6 @@ import java.time.OffsetDateTime;
|
||||||
import java.time.OffsetTime;
|
import java.time.OffsetTime;
|
||||||
import java.time.Year;
|
import java.time.Year;
|
||||||
import java.time.YearMonth;
|
import java.time.YearMonth;
|
||||||
import java.time.ZoneId;
|
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
@ -44,7 +45,9 @@ import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.function.IntFunction;
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
import static org.hibernate.generator.EventTypeSets.INSERT_AND_UPDATE;
|
import static org.hibernate.generator.EventTypeSets.INSERT_AND_UPDATE;
|
||||||
import static org.hibernate.generator.EventTypeSets.INSERT_ONLY;
|
import static org.hibernate.generator.EventTypeSets.INSERT_ONLY;
|
||||||
|
@ -68,24 +71,34 @@ import static org.hibernate.generator.EventTypeSets.fromArray;
|
||||||
* @author Gavin King
|
* @author Gavin King
|
||||||
*/
|
*/
|
||||||
public class CurrentTimestampGeneration implements BeforeExecutionGenerator, OnExecutionGenerator {
|
public class CurrentTimestampGeneration implements BeforeExecutionGenerator, OnExecutionGenerator {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration property name to set a custom {@link Clock} for Hibernate ORM to use when generating VM based
|
||||||
|
* timestamp values for e.g. {@link CurrentTimestamp}, {@link CreationTimestamp}, {@link UpdateTimestamp}
|
||||||
|
* and {@link org.hibernate.type.descriptor.java.VersionJavaType} methods.
|
||||||
|
*
|
||||||
|
* @since 6.6
|
||||||
|
*/
|
||||||
|
public static final String CLOCK_SETTING_NAME = "hibernate.testing.clock";
|
||||||
|
|
||||||
private final EnumSet<EventType> eventTypes;
|
private final EnumSet<EventType> eventTypes;
|
||||||
|
|
||||||
private final CurrentTimestampGeneratorDelegate delegate;
|
private final CurrentTimestampGeneratorDelegate delegate;
|
||||||
private static final Map<Class<?>, IntFunction<CurrentTimestampGeneratorDelegate>> GENERATOR_PRODUCERS = new HashMap<>();
|
private static final Map<Class<?>, BiFunction<@Nullable Clock, Integer, CurrentTimestampGeneratorDelegate>> GENERATOR_PRODUCERS = new HashMap<>();
|
||||||
private static final Map<Key, CurrentTimestampGeneratorDelegate> GENERATOR_DELEGATES = new ConcurrentHashMap<>();
|
private static final Map<Key, CurrentTimestampGeneratorDelegate> GENERATOR_DELEGATES = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
GENERATOR_PRODUCERS.put(
|
GENERATOR_PRODUCERS.put(
|
||||||
Date.class,
|
Date.class,
|
||||||
precision -> {
|
(baseClock, precision) -> {
|
||||||
final Clock clock = ClockHelper.forPrecision( precision, 3 );
|
final Clock clock = ClockHelper.forPrecision( baseClock, precision, 3 );
|
||||||
return () -> new Date( clock.millis() );
|
return () -> new Date( clock.millis() );
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
GENERATOR_PRODUCERS.put(
|
GENERATOR_PRODUCERS.put(
|
||||||
Calendar.class,
|
Calendar.class,
|
||||||
precision -> {
|
(baseClock, precision) -> {
|
||||||
final Clock clock = ClockHelper.forPrecision( precision, 3 );
|
final Clock clock = ClockHelper.forPrecision( baseClock, precision, 3 );
|
||||||
return () -> {
|
return () -> {
|
||||||
Calendar calendar = Calendar.getInstance();
|
Calendar calendar = Calendar.getInstance();
|
||||||
calendar.setTimeInMillis( clock.millis() );
|
calendar.setTimeInMillis( clock.millis() );
|
||||||
|
@ -95,78 +108,78 @@ public class CurrentTimestampGeneration implements BeforeExecutionGenerator, OnE
|
||||||
);
|
);
|
||||||
GENERATOR_PRODUCERS.put(
|
GENERATOR_PRODUCERS.put(
|
||||||
java.sql.Date.class,
|
java.sql.Date.class,
|
||||||
precision -> () -> new java.sql.Date( System.currentTimeMillis() )
|
(baseClock, precision) -> () -> new java.sql.Date( baseClock == null ? System.currentTimeMillis() : baseClock.millis() )
|
||||||
);
|
);
|
||||||
|
|
||||||
GENERATOR_PRODUCERS.put(
|
GENERATOR_PRODUCERS.put(
|
||||||
Time.class,
|
Time.class,
|
||||||
precision -> {
|
(baseClock, precision) -> {
|
||||||
final Clock clock = ClockHelper.forPrecision( precision, 3 );
|
final Clock clock = ClockHelper.forPrecision( baseClock, precision, 3 );
|
||||||
return () -> new Time( clock.millis() );
|
return () -> new Time( clock.millis() );
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
GENERATOR_PRODUCERS.put(
|
GENERATOR_PRODUCERS.put(
|
||||||
Timestamp.class,
|
Timestamp.class,
|
||||||
precision -> {
|
(baseClock, precision) -> {
|
||||||
final Clock clock = ClockHelper.forPrecision( precision, 9 );
|
final Clock clock = ClockHelper.forPrecision( baseClock, precision, 9 );
|
||||||
return () -> Timestamp.from( clock.instant() );
|
return () -> Timestamp.from( clock.instant() );
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
GENERATOR_PRODUCERS.put(
|
GENERATOR_PRODUCERS.put(
|
||||||
Instant.class,
|
Instant.class,
|
||||||
precision -> {
|
(baseClock, precision) -> {
|
||||||
final Clock clock = ClockHelper.forPrecision( precision, 9 );
|
final Clock clock = ClockHelper.forPrecision( baseClock, precision, 9 );
|
||||||
return clock::instant;
|
return clock::instant;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
GENERATOR_PRODUCERS.put(
|
GENERATOR_PRODUCERS.put(
|
||||||
LocalDate.class,
|
LocalDate.class,
|
||||||
precision -> LocalDate::now
|
(baseClock, precision) -> () -> LocalDate.now( baseClock == null ? Clock.systemDefaultZone() : baseClock )
|
||||||
);
|
);
|
||||||
GENERATOR_PRODUCERS.put(
|
GENERATOR_PRODUCERS.put(
|
||||||
LocalDateTime.class,
|
LocalDateTime.class,
|
||||||
precision -> {
|
(baseClock, precision) -> {
|
||||||
final Clock clock = ClockHelper.forPrecision( precision, 9 );
|
final Clock clock = ClockHelper.forPrecision( baseClock, precision, 9 );
|
||||||
return () -> LocalDateTime.now( clock );
|
return () -> LocalDateTime.now( clock );
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
GENERATOR_PRODUCERS.put(
|
GENERATOR_PRODUCERS.put(
|
||||||
LocalTime.class,
|
LocalTime.class,
|
||||||
precision -> {
|
(baseClock, precision) -> {
|
||||||
final Clock clock = ClockHelper.forPrecision( precision, 9 );
|
final Clock clock = ClockHelper.forPrecision( baseClock, precision, 9 );
|
||||||
return () -> LocalTime.now( clock );
|
return () -> LocalTime.now( clock );
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
GENERATOR_PRODUCERS.put(
|
GENERATOR_PRODUCERS.put(
|
||||||
MonthDay.class,
|
MonthDay.class,
|
||||||
precision -> MonthDay::now
|
(baseClock, precision) -> () -> MonthDay.now( baseClock == null ? Clock.systemDefaultZone() : baseClock )
|
||||||
);
|
);
|
||||||
GENERATOR_PRODUCERS.put(
|
GENERATOR_PRODUCERS.put(
|
||||||
OffsetDateTime.class,
|
OffsetDateTime.class,
|
||||||
precision -> {
|
(baseClock, precision) -> {
|
||||||
final Clock clock = ClockHelper.forPrecision( precision, 9 );
|
final Clock clock = ClockHelper.forPrecision( baseClock, precision, 9 );
|
||||||
return () -> OffsetDateTime.now( clock );
|
return () -> OffsetDateTime.now( clock );
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
GENERATOR_PRODUCERS.put(
|
GENERATOR_PRODUCERS.put(
|
||||||
OffsetTime.class,
|
OffsetTime.class,
|
||||||
precision -> {
|
(baseClock, precision) -> {
|
||||||
final Clock clock = ClockHelper.forPrecision( precision, 9 );
|
final Clock clock = ClockHelper.forPrecision( baseClock, precision, 9 );
|
||||||
return () -> OffsetTime.now( clock );
|
return () -> OffsetTime.now( clock );
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
GENERATOR_PRODUCERS.put(
|
GENERATOR_PRODUCERS.put(
|
||||||
Year.class,
|
Year.class,
|
||||||
precision -> Year::now
|
(baseClock, precision) -> () -> Year.now( baseClock == null ? Clock.systemDefaultZone() : baseClock )
|
||||||
);
|
);
|
||||||
GENERATOR_PRODUCERS.put(
|
GENERATOR_PRODUCERS.put(
|
||||||
YearMonth.class,
|
YearMonth.class,
|
||||||
precision -> YearMonth::now
|
(baseClock, precision) -> () -> YearMonth.now( baseClock == null ? Clock.systemDefaultZone() : baseClock )
|
||||||
);
|
);
|
||||||
GENERATOR_PRODUCERS.put(
|
GENERATOR_PRODUCERS.put(
|
||||||
ZonedDateTime.class,
|
ZonedDateTime.class,
|
||||||
precision -> {
|
(baseClock, precision) -> {
|
||||||
final Clock clock = ClockHelper.forPrecision( precision, 9 );
|
final Clock clock = ClockHelper.forPrecision( baseClock, precision, 9 );
|
||||||
return () -> ZonedDateTime.now( clock );
|
return () -> ZonedDateTime.now( clock );
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -208,16 +221,19 @@ public class CurrentTimestampGeneration implements BeforeExecutionGenerator, OnE
|
||||||
context.getDatabase().getDialect(),
|
context.getDatabase().getDialect(),
|
||||||
basicValue.getMetadata()
|
basicValue.getMetadata()
|
||||||
);
|
);
|
||||||
final Key key = new Key( propertyType, size.getPrecision() == null ? 0 : size.getPrecision() );
|
final Clock baseClock = context.getServiceRegistry()
|
||||||
|
.requireService( ConfigurationService.class )
|
||||||
|
.getSetting( CLOCK_SETTING_NAME, value -> (Clock) value );
|
||||||
|
final Key key = new Key( propertyType, baseClock, size.getPrecision() == null ? 0 : size.getPrecision() );
|
||||||
final CurrentTimestampGeneratorDelegate delegate = GENERATOR_DELEGATES.get( key );
|
final CurrentTimestampGeneratorDelegate delegate = GENERATOR_DELEGATES.get( key );
|
||||||
if ( delegate != null ) {
|
if ( delegate != null ) {
|
||||||
return delegate;
|
return delegate;
|
||||||
}
|
}
|
||||||
final IntFunction<CurrentTimestampGeneratorDelegate> producer = GENERATOR_PRODUCERS.get( key.clazz );
|
final BiFunction<@Nullable Clock, Integer, CurrentTimestampGeneratorDelegate> producer = GENERATOR_PRODUCERS.get( key.clazz );
|
||||||
if ( producer == null ) {
|
if ( producer == null ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final CurrentTimestampGeneratorDelegate generatorDelegate = producer.apply( key.precision );
|
final CurrentTimestampGeneratorDelegate generatorDelegate = producer.apply( key.clock, key.precision );
|
||||||
final CurrentTimestampGeneratorDelegate old = GENERATOR_DELEGATES.putIfAbsent(
|
final CurrentTimestampGeneratorDelegate old = GENERATOR_DELEGATES.putIfAbsent(
|
||||||
key,
|
key,
|
||||||
generatorDelegate
|
generatorDelegate
|
||||||
|
@ -230,6 +246,10 @@ public class CurrentTimestampGeneration implements BeforeExecutionGenerator, OnE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T extends Clock> T getClock(SessionFactory sessionFactory) {
|
||||||
|
return (T) sessionFactory.getProperties().get( CLOCK_SETTING_NAME );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean generatedOnExecution() {
|
public boolean generatedOnExecution() {
|
||||||
return delegate == null;
|
return delegate == null;
|
||||||
|
@ -267,10 +287,12 @@ public class CurrentTimestampGeneration implements BeforeExecutionGenerator, OnE
|
||||||
|
|
||||||
private static class Key {
|
private static class Key {
|
||||||
private final Class<?> clazz;
|
private final Class<?> clazz;
|
||||||
|
private final @Nullable Clock clock;
|
||||||
private final int precision;
|
private final int precision;
|
||||||
|
|
||||||
public Key(Class<?> clazz, int precision) {
|
public Key(Class<?> clazz, @Nullable Clock clock, int precision) {
|
||||||
this.clazz = clazz;
|
this.clazz = clazz;
|
||||||
|
this.clock = clock;
|
||||||
this.precision = precision;
|
this.precision = precision;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,12 +310,13 @@ public class CurrentTimestampGeneration implements BeforeExecutionGenerator, OnE
|
||||||
if ( precision != key.precision ) {
|
if ( precision != key.precision ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return clazz.equals( key.clazz );
|
return clock == key.clock && clazz.equals( key.clazz );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int result = clazz.hashCode();
|
int result = clazz.hashCode();
|
||||||
|
result = 31 * result + ( clock == null ? 0 : clock.hashCode() );
|
||||||
result = 31 * result + precision;
|
result = 31 * result + precision;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,7 +97,8 @@ public class EntityVersionMappingImpl implements EntityVersionMapping, FetchOpti
|
||||||
.getRepresentationStrategy()
|
.getRepresentationStrategy()
|
||||||
.resolvePropertyAccess( bootEntityDescriptor.getVersion() )
|
.resolvePropertyAccess( bootEntityDescriptor.getVersion() )
|
||||||
.getGetter(),
|
.getGetter(),
|
||||||
templateInstanceAccess
|
templateInstanceAccess,
|
||||||
|
creationProcess.getCreationContext().getSessionFactory()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,9 @@ import java.time.Clock;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
|
import org.hibernate.generator.internal.CurrentTimestampGeneration;
|
||||||
|
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper for determining the correct clock for precision
|
* Helper for determining the correct clock for precision
|
||||||
|
@ -17,15 +20,15 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
public class ClockHelper {
|
public class ClockHelper {
|
||||||
|
|
||||||
private static final Clock TICK_9 = Clock.systemDefaultZone();
|
private static final Clock TICK_9 = Clock.systemDefaultZone();
|
||||||
private static final Clock TICK_8 = Clock.tick( TICK_9, Duration.ofNanos( 10L ) );
|
private static final Clock TICK_8 = forPrecision( TICK_9, 8, 9 );
|
||||||
private static final Clock TICK_7 = Clock.tick( TICK_9, Duration.ofNanos( 100L ) );
|
private static final Clock TICK_7 = forPrecision( TICK_9, 7, 9 );
|
||||||
private static final Clock TICK_6 = Clock.tick( TICK_9, Duration.ofNanos( 1000L ) );
|
private static final Clock TICK_6 = forPrecision( TICK_9, 6, 9 );
|
||||||
private static final Clock TICK_5 = Clock.tick( TICK_9, Duration.ofNanos( 10000L ) );
|
private static final Clock TICK_5 = forPrecision( TICK_9, 5, 9 );
|
||||||
private static final Clock TICK_4 = Clock.tick( TICK_9, Duration.ofNanos( 100000L ) );
|
private static final Clock TICK_4 = forPrecision( TICK_9, 4, 9 );
|
||||||
private static final Clock TICK_3 = Clock.tick( TICK_9, Duration.ofNanos( 1000000L ) );
|
private static final Clock TICK_3 = forPrecision( TICK_9, 3, 9 );
|
||||||
private static final Clock TICK_2 = Clock.tick( TICK_9, Duration.ofNanos( 10000000L ) );
|
private static final Clock TICK_2 = forPrecision( TICK_9, 2, 9 );
|
||||||
private static final Clock TICK_1 = Clock.tick( TICK_9, Duration.ofNanos( 100000000L ) );
|
private static final Clock TICK_1 = forPrecision( TICK_9, 1, 9 );
|
||||||
private static final Clock TICK_0 = Clock.tick( TICK_9, Duration.ofNanos( 1000000000L ) );
|
private static final Clock TICK_0 = forPrecision( TICK_9, 0, 9 );
|
||||||
|
|
||||||
public static Clock forPrecision(Integer precision, SharedSessionContractImplementor session) {
|
public static Clock forPrecision(Integer precision, SharedSessionContractImplementor session) {
|
||||||
return forPrecision( precision, session, 9 );
|
return forPrecision( precision, session, 9 );
|
||||||
|
@ -39,31 +42,38 @@ public class ClockHelper {
|
||||||
else {
|
else {
|
||||||
resolvedPrecision = precision;
|
resolvedPrecision = precision;
|
||||||
}
|
}
|
||||||
return forPrecision( resolvedPrecision, maxPrecision );
|
final Clock baseClock = (Clock) session.getFactory()
|
||||||
|
.getProperties()
|
||||||
|
.get( CurrentTimestampGeneration.CLOCK_SETTING_NAME );
|
||||||
|
return forPrecision( baseClock, resolvedPrecision, maxPrecision );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Clock forPrecision(int resolvedPrecision, int maxPrecision) {
|
public static Clock forPrecision(int resolvedPrecision, int maxPrecision) {
|
||||||
|
return forPrecision( null, resolvedPrecision, maxPrecision );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Clock forPrecision(@Nullable Clock baseClock, int resolvedPrecision, int maxPrecision) {
|
||||||
switch ( Math.min( resolvedPrecision, maxPrecision ) ) {
|
switch ( Math.min( resolvedPrecision, maxPrecision ) ) {
|
||||||
case 0:
|
case 0:
|
||||||
return TICK_0;
|
return baseClock == null ? TICK_0 : Clock.tick( baseClock, Duration.ofNanos( 1000000000L ) );
|
||||||
case 1:
|
case 1:
|
||||||
return TICK_1;
|
return baseClock == null ? TICK_1 : Clock.tick( baseClock, Duration.ofNanos( 100000000L ) );
|
||||||
case 2:
|
case 2:
|
||||||
return TICK_2;
|
return baseClock == null ? TICK_2 : Clock.tick( baseClock, Duration.ofNanos( 10000000L ) );
|
||||||
case 3:
|
case 3:
|
||||||
return TICK_3;
|
return baseClock == null ? TICK_3 : Clock.tick( baseClock, Duration.ofNanos( 1000000L ) );
|
||||||
case 4:
|
case 4:
|
||||||
return TICK_4;
|
return baseClock == null ? TICK_4 : Clock.tick( baseClock, Duration.ofNanos( 100000L ) );
|
||||||
case 5:
|
case 5:
|
||||||
return TICK_5;
|
return baseClock == null ? TICK_5 : Clock.tick( baseClock, Duration.ofNanos( 10000L ) );
|
||||||
case 6:
|
case 6:
|
||||||
return TICK_6;
|
return baseClock == null ? TICK_6 : Clock.tick( baseClock, Duration.ofNanos( 1000L ) );
|
||||||
case 7:
|
case 7:
|
||||||
return TICK_7;
|
return baseClock == null ? TICK_7 : Clock.tick( baseClock, Duration.ofNanos( 100L ) );
|
||||||
case 8:
|
case 8:
|
||||||
return TICK_8;
|
return baseClock == null ? TICK_8 : Clock.tick( baseClock, Duration.ofNanos( 10L ) );
|
||||||
case 9:
|
case 9:
|
||||||
return TICK_9;
|
return baseClock == null ? TICK_9 : baseClock;
|
||||||
}
|
}
|
||||||
throw new IllegalArgumentException( "Illegal precision: " + resolvedPrecision );
|
throw new IllegalArgumentException( "Illegal precision: " + resolvedPrecision );
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,15 +7,17 @@
|
||||||
package org.hibernate.orm.test.annotations;
|
package org.hibernate.orm.test.annotations;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
|
|
||||||
import org.hibernate.annotations.UpdateTimestamp;
|
import org.hibernate.annotations.UpdateTimestamp;
|
||||||
|
import org.hibernate.generator.internal.CurrentTimestampGeneration;
|
||||||
import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase;
|
import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase;
|
||||||
|
|
||||||
import org.hibernate.testing.TestForIssue;
|
import org.hibernate.testing.orm.junit.JiraKey;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
@ -25,9 +27,11 @@ import static org.junit.Assert.assertTrue;
|
||||||
/**
|
/**
|
||||||
* @author Vlad Mihalcea
|
* @author Vlad Mihalcea
|
||||||
*/
|
*/
|
||||||
@TestForIssue(jiraKey = "HHH-13256")
|
@JiraKey("HHH-13256")
|
||||||
public class InMemoryUpdateTimestampTest extends BaseEntityManagerFunctionalTestCase {
|
public class InMemoryUpdateTimestampTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
|
|
||||||
|
private static final MutableClock clock = new MutableClock();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Class<?>[] getAnnotatedClasses() {
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
return new Class<?>[] {
|
return new Class<?>[] {
|
||||||
|
@ -35,6 +39,12 @@ public class InMemoryUpdateTimestampTest extends BaseEntityManagerFunctionalTest
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addConfigOptions(Map options) {
|
||||||
|
super.addConfigOptions( options );
|
||||||
|
options.put( CurrentTimestampGeneration.CLOCK_SETTING_NAME, clock );
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test() {
|
public void test() {
|
||||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
@ -47,6 +57,7 @@ public class InMemoryUpdateTimestampTest extends BaseEntityManagerFunctionalTest
|
||||||
entityManager.flush();
|
entityManager.flush();
|
||||||
Assert.assertNotNull( person.getUpdatedOn() );
|
Assert.assertNotNull( person.getUpdatedOn() );
|
||||||
} );
|
} );
|
||||||
|
clock.tick();
|
||||||
|
|
||||||
AtomicReference<Date> beforeTimestamp = new AtomicReference<>();
|
AtomicReference<Date> beforeTimestamp = new AtomicReference<>();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.orm.test.annotations;
|
||||||
|
|
||||||
|
import java.time.Clock;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
|
|
||||||
|
public final class MutableClock extends Clock {
|
||||||
|
|
||||||
|
private static final Instant START_INSTANT = LocalDateTime.of( 2000, 1, 1, 12, 30, 50, 123456789 )
|
||||||
|
.toInstant( ZoneOffset.UTC );
|
||||||
|
|
||||||
|
private final ZoneId zoneId;
|
||||||
|
private Instant instant;
|
||||||
|
|
||||||
|
public MutableClock() {
|
||||||
|
this( ZoneId.systemDefault(), START_INSTANT );
|
||||||
|
}
|
||||||
|
|
||||||
|
public MutableClock(ZoneId zoneId) {
|
||||||
|
this( zoneId, START_INSTANT );
|
||||||
|
}
|
||||||
|
|
||||||
|
public MutableClock(Instant instant) {
|
||||||
|
this( ZoneId.systemDefault(), instant );
|
||||||
|
}
|
||||||
|
|
||||||
|
public MutableClock(ZoneId zoneId, Instant instant) {
|
||||||
|
this.zoneId = zoneId;
|
||||||
|
this.instant = instant;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ZoneId getZone() {
|
||||||
|
return zoneId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Clock withZone(ZoneId zone) {
|
||||||
|
return new MutableClock( zone, instant );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Instant instant() {
|
||||||
|
return instant;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInstant(Instant instant) {
|
||||||
|
this.instant = instant;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
instant = START_INSTANT;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tick() {
|
||||||
|
instant = instant.plusSeconds( 1 );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.orm.test.annotations;
|
||||||
|
|
||||||
|
import java.time.Clock;
|
||||||
|
|
||||||
|
import org.hibernate.testing.orm.junit.SettingProvider;
|
||||||
|
|
||||||
|
public final class MutableClockSettingProvider implements SettingProvider.Provider<Clock> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Clock getSetting() {
|
||||||
|
return new MutableClock();
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ package org.hibernate.orm.test.annotations;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import jakarta.persistence.CascadeType;
|
import jakarta.persistence.CascadeType;
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
|
@ -25,9 +26,10 @@ import jakarta.persistence.TemporalType;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.hibernate.annotations.CreationTimestamp;
|
import org.hibernate.annotations.CreationTimestamp;
|
||||||
import org.hibernate.annotations.UpdateTimestamp;
|
import org.hibernate.annotations.UpdateTimestamp;
|
||||||
|
import org.hibernate.generator.internal.CurrentTimestampGeneration;
|
||||||
import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase;
|
import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase;
|
||||||
|
|
||||||
import org.hibernate.testing.TestForIssue;
|
import org.hibernate.testing.orm.junit.JiraKey;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
@ -41,26 +43,32 @@ import static org.junit.Assert.assertTrue;
|
||||||
/**
|
/**
|
||||||
* @author Andrea Boriero
|
* @author Andrea Boriero
|
||||||
*/
|
*/
|
||||||
@TestForIssue(jiraKey = "HHH-11867")
|
@JiraKey("HHH-11867")
|
||||||
public class UpdateTimeStampInheritanceTest extends BaseEntityManagerFunctionalTestCase {
|
public class UpdateTimeStampInheritanceTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
private static final long SLEEP_MILLIS = 25;
|
|
||||||
|
|
||||||
private static final String customerId = "1";
|
private static final String customerId = "1";
|
||||||
|
private static final MutableClock clock = new MutableClock();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Class<?>[] getAnnotatedClasses() {
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
return new Class[] { Customer.class, AbstractPerson.class, Address.class };
|
return new Class[] { Customer.class, AbstractPerson.class, Address.class };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addConfigOptions(Map options) {
|
||||||
|
super.addConfigOptions( options );
|
||||||
|
options.put( CurrentTimestampGeneration.CLOCK_SETTING_NAME, clock );
|
||||||
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
|
clock.reset();
|
||||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
Customer customer = new Customer();
|
Customer customer = new Customer();
|
||||||
customer.setId( customerId );
|
customer.setId( customerId );
|
||||||
customer.addAddress( "address" );
|
customer.addAddress( "address" );
|
||||||
entityManager.persist( customer );
|
entityManager.persist( customer );
|
||||||
} );
|
} );
|
||||||
sleep( SLEEP_MILLIS );
|
clock.tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -72,6 +80,7 @@ public class UpdateTimeStampInheritanceTest extends BaseEntityManagerFunctionalT
|
||||||
assertModifiedAtWasNotUpdated( customer );
|
assertModifiedAtWasNotUpdated( customer );
|
||||||
customer.setName( "xyz" );
|
customer.setName( "xyz" );
|
||||||
} );
|
} );
|
||||||
|
clock.tick();
|
||||||
|
|
||||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
Customer customer = entityManager.find( Customer.class, customerId );
|
Customer customer = entityManager.find( Customer.class, customerId );
|
||||||
|
@ -90,6 +99,7 @@ public class UpdateTimeStampInheritanceTest extends BaseEntityManagerFunctionalT
|
||||||
assertModifiedAtWasNotUpdated( customer );
|
assertModifiedAtWasNotUpdated( customer );
|
||||||
customer.setEmail( "xyz@" );
|
customer.setEmail( "xyz@" );
|
||||||
} );
|
} );
|
||||||
|
clock.tick();
|
||||||
|
|
||||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
Customer customer = entityManager.find( Customer.class, customerId );
|
Customer customer = entityManager.find( Customer.class, customerId );
|
||||||
|
@ -110,6 +120,7 @@ public class UpdateTimeStampInheritanceTest extends BaseEntityManagerFunctionalT
|
||||||
a.setStreet( "Lollard street" );
|
a.setStreet( "Lollard street" );
|
||||||
customer.setWorkAddress( a );
|
customer.setWorkAddress( a );
|
||||||
} );
|
} );
|
||||||
|
clock.tick();
|
||||||
|
|
||||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
Customer customer = entityManager.find( Customer.class, customerId );
|
Customer customer = entityManager.find( Customer.class, customerId );
|
||||||
|
@ -130,6 +141,7 @@ public class UpdateTimeStampInheritanceTest extends BaseEntityManagerFunctionalT
|
||||||
a.setStreet( "Lollard Street" );
|
a.setStreet( "Lollard Street" );
|
||||||
customer.setHomeAddress( a );
|
customer.setHomeAddress( a );
|
||||||
} );
|
} );
|
||||||
|
clock.tick();
|
||||||
|
|
||||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
Customer customer = entityManager.find( Customer.class, customerId );
|
Customer customer = entityManager.find( Customer.class, customerId );
|
||||||
|
@ -150,6 +162,7 @@ public class UpdateTimeStampInheritanceTest extends BaseEntityManagerFunctionalT
|
||||||
adresses.add( "another address" );
|
adresses.add( "another address" );
|
||||||
customer.setAdresses( adresses );
|
customer.setAdresses( adresses );
|
||||||
} );
|
} );
|
||||||
|
clock.tick();
|
||||||
|
|
||||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
Customer customer = entityManager.find( Customer.class, customerId );
|
Customer customer = entityManager.find( Customer.class, customerId );
|
||||||
|
@ -169,6 +182,7 @@ public class UpdateTimeStampInheritanceTest extends BaseEntityManagerFunctionalT
|
||||||
Set<String> books = new HashSet<>();
|
Set<String> books = new HashSet<>();
|
||||||
customer.setBooks( books );
|
customer.setBooks( books );
|
||||||
} );
|
} );
|
||||||
|
clock.tick();
|
||||||
|
|
||||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
Customer customer = entityManager.find( Customer.class, customerId );
|
Customer customer = entityManager.find( Customer.class, customerId );
|
||||||
|
|
|
@ -25,7 +25,6 @@ import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
|
|
||||||
import org.hibernate.HibernateError;
|
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.hibernate.annotations.ColumnDefault;
|
import org.hibernate.annotations.ColumnDefault;
|
||||||
import org.hibernate.annotations.CreationTimestamp;
|
import org.hibernate.annotations.CreationTimestamp;
|
||||||
|
@ -36,16 +35,23 @@ import org.hibernate.annotations.UpdateTimestamp;
|
||||||
import org.hibernate.dialect.MySQLDialect;
|
import org.hibernate.dialect.MySQLDialect;
|
||||||
import org.hibernate.dialect.SybaseDialect;
|
import org.hibernate.dialect.SybaseDialect;
|
||||||
import org.hibernate.dialect.TiDBDialect;
|
import org.hibernate.dialect.TiDBDialect;
|
||||||
|
import org.hibernate.generator.internal.CurrentTimestampGeneration;
|
||||||
|
import org.hibernate.orm.test.annotations.MutableClock;
|
||||||
|
import org.hibernate.orm.test.annotations.MutableClockSettingProvider;
|
||||||
import org.hibernate.tuple.ValueGenerator;
|
import org.hibernate.tuple.ValueGenerator;
|
||||||
|
|
||||||
|
|
||||||
import org.hibernate.testing.TestForIssue;
|
import org.hibernate.testing.TestForIssue;
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.JiraKey;
|
||||||
|
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.hibernate.testing.orm.junit.SettingProvider;
|
||||||
import org.hibernate.testing.orm.junit.SkipForDialect;
|
import org.hibernate.testing.orm.junit.SkipForDialect;
|
||||||
|
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
@ -65,9 +71,19 @@ import static org.junit.Assert.assertTrue;
|
||||||
@SkipForDialect( dialectClass = TiDBDialect.class, reason = "See HHH-10196" )
|
@SkipForDialect( dialectClass = TiDBDialect.class, reason = "See HHH-10196" )
|
||||||
@DomainModel( annotatedClasses = DefaultGeneratedValueTest.TheEntity.class )
|
@DomainModel( annotatedClasses = DefaultGeneratedValueTest.TheEntity.class )
|
||||||
@SessionFactory
|
@SessionFactory
|
||||||
|
@ServiceRegistry(settingProviders = @SettingProvider(settingName = CurrentTimestampGeneration.CLOCK_SETTING_NAME, provider = MutableClockSettingProvider.class))
|
||||||
public class DefaultGeneratedValueTest {
|
public class DefaultGeneratedValueTest {
|
||||||
|
|
||||||
|
private MutableClock clock;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setup(SessionFactoryScope scope) {
|
||||||
|
clock = CurrentTimestampGeneration.getClock( scope.getSessionFactory() );
|
||||||
|
clock.reset();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestForIssue( jiraKey = "HHH-2907" )
|
@JiraKey( "HHH-2907" )
|
||||||
public void testGeneration(SessionFactoryScope scope) {
|
public void testGeneration(SessionFactoryScope scope) {
|
||||||
final TheEntity created = scope.fromTransaction( (s) -> {
|
final TheEntity created = scope.fromTransaction( (s) -> {
|
||||||
final TheEntity theEntity = new TheEntity( 1 );
|
final TheEntity theEntity = new TheEntity( 1 );
|
||||||
|
@ -153,8 +169,7 @@ public class DefaultGeneratedValueTest {
|
||||||
assertNotNull( created.vmCreatedSqlTimestamp );
|
assertNotNull( created.vmCreatedSqlTimestamp );
|
||||||
assertNotNull( created.updated );
|
assertNotNull( created.updated );
|
||||||
|
|
||||||
//We need to wait a little to make sure the timestamps produced are different
|
clock.tick();
|
||||||
waitALittle();
|
|
||||||
|
|
||||||
scope.inTransaction( (s) -> {
|
scope.inTransaction( (s) -> {
|
||||||
final TheEntity theEntity = s.get( TheEntity.class, 1 );
|
final TheEntity theEntity = s.get( TheEntity.class, 1 );
|
||||||
|
@ -260,12 +275,4 @@ public class DefaultGeneratedValueTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void waitALittle() {
|
|
||||||
try {
|
|
||||||
Thread.sleep( 10 );
|
|
||||||
}
|
|
||||||
catch (InterruptedException e) {
|
|
||||||
throw new HibernateError( "Unexpected wakeup from test sleep" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
package org.hibernate.orm.test.mapping.generated;
|
package org.hibernate.orm.test.mapping.generated;
|
||||||
|
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
|
|
||||||
import jakarta.persistence.Basic;
|
import jakarta.persistence.Basic;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
|
@ -14,11 +15,17 @@ import jakarta.persistence.Table;
|
||||||
|
|
||||||
import org.hibernate.annotations.CreationTimestamp;
|
import org.hibernate.annotations.CreationTimestamp;
|
||||||
import org.hibernate.annotations.UpdateTimestamp;
|
import org.hibernate.annotations.UpdateTimestamp;
|
||||||
|
import org.hibernate.generator.internal.CurrentTimestampGeneration;
|
||||||
|
import org.hibernate.orm.test.annotations.MutableClock;
|
||||||
|
import org.hibernate.orm.test.annotations.MutableClockSettingProvider;
|
||||||
|
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.hibernate.testing.orm.junit.SettingProvider;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
@ -31,14 +38,24 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
*/
|
*/
|
||||||
@DomainModel( annotatedClasses = InVmGenerationsWithAnnotationsTests.AuditedEntity.class )
|
@DomainModel( annotatedClasses = InVmGenerationsWithAnnotationsTests.AuditedEntity.class )
|
||||||
@SessionFactory
|
@SessionFactory
|
||||||
|
@ServiceRegistry(settingProviders = @SettingProvider(settingName = CurrentTimestampGeneration.CLOCK_SETTING_NAME, provider = MutableClockSettingProvider.class))
|
||||||
public class InVmGenerationsWithAnnotationsTests {
|
public class InVmGenerationsWithAnnotationsTests {
|
||||||
|
|
||||||
|
private MutableClock clock;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setup(SessionFactoryScope scope) {
|
||||||
|
clock = CurrentTimestampGeneration.getClock( scope.getSessionFactory() );
|
||||||
|
clock.reset();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGenerations(SessionFactoryScope scope) {
|
public void testGenerations(SessionFactoryScope scope) {
|
||||||
scope.inSession( (session) -> {
|
scope.inSession( (session) -> {
|
||||||
// first creation
|
// first creation
|
||||||
final AuditedEntity saved = scope.fromTransaction( session, (s) -> {
|
final AuditedEntity saved = scope.fromTransaction( session, s -> {
|
||||||
final AuditedEntity entity = new AuditedEntity( 1, "it" );
|
final AuditedEntity entity = new AuditedEntity( 1, "it" );
|
||||||
session.persist( entity );
|
s.persist( entity );
|
||||||
return entity;
|
return entity;
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
@ -47,18 +64,10 @@ public class InVmGenerationsWithAnnotationsTests {
|
||||||
assertThat( saved.lastUpdatedOn ).isNotNull();
|
assertThat( saved.lastUpdatedOn ).isNotNull();
|
||||||
|
|
||||||
saved.name = "changed";
|
saved.name = "changed";
|
||||||
// Let's sleep a millisecond to make sure we actually generate a different timestamp
|
clock.tick();
|
||||||
try {
|
|
||||||
Thread.sleep( 1L );
|
|
||||||
}
|
|
||||||
catch (InterruptedException e) {
|
|
||||||
// Ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
// then changing
|
// then changing
|
||||||
final AuditedEntity merged = scope.fromTransaction( session, (s) -> {
|
final AuditedEntity merged = scope.fromTransaction( session, s -> s.merge( saved ) );
|
||||||
return (AuditedEntity) session.merge( saved );
|
|
||||||
} );
|
|
||||||
|
|
||||||
assertThat( merged ).isNotNull();
|
assertThat( merged ).isNotNull();
|
||||||
assertThat( merged.createdOn ).isNotNull();
|
assertThat( merged.createdOn ).isNotNull();
|
||||||
|
@ -66,9 +75,7 @@ public class InVmGenerationsWithAnnotationsTests {
|
||||||
assertThat( merged.lastUpdatedOn ).isNotEqualTo( merged.createdOn );
|
assertThat( merged.lastUpdatedOn ).isNotEqualTo( merged.createdOn );
|
||||||
|
|
||||||
// lastly, make sure we can load it..
|
// lastly, make sure we can load it..
|
||||||
final AuditedEntity loaded = scope.fromTransaction( session, (s) -> {
|
final AuditedEntity loaded = scope.fromTransaction( session, s -> s.get( AuditedEntity.class, 1 ) );
|
||||||
return session.get( AuditedEntity.class, 1 );
|
|
||||||
} );
|
|
||||||
|
|
||||||
assertThat( loaded ).isNotNull();
|
assertThat( loaded ).isNotNull();
|
||||||
assertThat( loaded.createdOn ).isEqualTo( merged.createdOn );
|
assertThat( loaded.createdOn ).isEqualTo( merged.createdOn );
|
||||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.orm.test.mapping.generated;
|
||||||
|
|
||||||
import java.sql.Date;
|
import java.sql.Date;
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
|
|
||||||
import jakarta.persistence.Basic;
|
import jakarta.persistence.Basic;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
|
@ -15,11 +16,17 @@ import jakarta.persistence.Table;
|
||||||
|
|
||||||
import org.hibernate.annotations.CreationTimestamp;
|
import org.hibernate.annotations.CreationTimestamp;
|
||||||
import org.hibernate.annotations.UpdateTimestamp;
|
import org.hibernate.annotations.UpdateTimestamp;
|
||||||
|
import org.hibernate.generator.internal.CurrentTimestampGeneration;
|
||||||
|
import org.hibernate.orm.test.annotations.MutableClock;
|
||||||
|
import org.hibernate.orm.test.annotations.MutableClockSettingProvider;
|
||||||
|
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.hibernate.testing.orm.junit.SettingProvider;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
@ -32,14 +39,24 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
*/
|
*/
|
||||||
@DomainModel( annotatedClasses = InVmGenerationsWithAnnotationsWithMixedSqlTypesTests.AuditedEntity.class )
|
@DomainModel( annotatedClasses = InVmGenerationsWithAnnotationsWithMixedSqlTypesTests.AuditedEntity.class )
|
||||||
@SessionFactory
|
@SessionFactory
|
||||||
|
@ServiceRegistry(settingProviders = @SettingProvider(settingName = CurrentTimestampGeneration.CLOCK_SETTING_NAME, provider = MutableClockSettingProvider.class))
|
||||||
public class InVmGenerationsWithAnnotationsWithMixedSqlTypesTests {
|
public class InVmGenerationsWithAnnotationsWithMixedSqlTypesTests {
|
||||||
|
|
||||||
|
private MutableClock clock;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setup(SessionFactoryScope scope) {
|
||||||
|
clock = CurrentTimestampGeneration.getClock( scope.getSessionFactory() );
|
||||||
|
clock.reset();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGenerations(SessionFactoryScope scope) {
|
public void testGenerations(SessionFactoryScope scope) {
|
||||||
scope.inSession( (session) -> {
|
scope.inSession( (session) -> {
|
||||||
// first creation
|
// first creation
|
||||||
final AuditedEntity saved = scope.fromTransaction( session, (s) -> {
|
final AuditedEntity saved = scope.fromTransaction( session, s -> {
|
||||||
final AuditedEntity entity = new AuditedEntity( 1, "it" );
|
final AuditedEntity entity = new AuditedEntity( 1, "it" );
|
||||||
session.persist( entity );
|
s.persist( entity );
|
||||||
return entity;
|
return entity;
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
@ -48,18 +65,10 @@ public class InVmGenerationsWithAnnotationsWithMixedSqlTypesTests {
|
||||||
assertThat( saved.lastUpdatedOn ).isNotNull();
|
assertThat( saved.lastUpdatedOn ).isNotNull();
|
||||||
|
|
||||||
saved.name = "changed";
|
saved.name = "changed";
|
||||||
// Let's sleep a millisecond to make sure we actually generate a different timestamp
|
clock.tick();
|
||||||
try {
|
|
||||||
Thread.sleep( 1L );
|
|
||||||
}
|
|
||||||
catch (InterruptedException e) {
|
|
||||||
// Ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
// then changing
|
// then changing
|
||||||
final AuditedEntity merged = scope.fromTransaction( session, (s) -> {
|
final AuditedEntity merged = scope.fromTransaction( session, s -> s.merge( saved ) );
|
||||||
return (AuditedEntity) session.merge( saved );
|
|
||||||
} );
|
|
||||||
|
|
||||||
assertThat( merged ).isNotNull();
|
assertThat( merged ).isNotNull();
|
||||||
assertThat( merged.createdOn ).isNotNull();
|
assertThat( merged.createdOn ).isNotNull();
|
||||||
|
@ -67,9 +76,7 @@ public class InVmGenerationsWithAnnotationsWithMixedSqlTypesTests {
|
||||||
assertThat( merged.lastUpdatedOn ).isNotEqualTo( merged.createdOn );
|
assertThat( merged.lastUpdatedOn ).isNotEqualTo( merged.createdOn );
|
||||||
|
|
||||||
// lastly, make sure we can load it..
|
// lastly, make sure we can load it..
|
||||||
final AuditedEntity loaded = scope.fromTransaction( session, (s) -> {
|
final AuditedEntity loaded = scope.fromTransaction( session, s -> s.get( AuditedEntity.class, 1 ) );
|
||||||
return session.get( AuditedEntity.class, 1 );
|
|
||||||
} );
|
|
||||||
|
|
||||||
assertThat( loaded ).isNotNull();
|
assertThat( loaded ).isNotNull();
|
||||||
assertThat( loaded.createdOn ).isEqualTo( merged.createdOn );
|
assertThat( loaded.createdOn ).isEqualTo( merged.createdOn );
|
||||||
|
|
|
@ -7,19 +7,25 @@
|
||||||
package org.hibernate.orm.test.mapping.generated;
|
package org.hibernate.orm.test.mapping.generated;
|
||||||
|
|
||||||
import java.sql.Date;
|
import java.sql.Date;
|
||||||
|
|
||||||
import jakarta.persistence.Basic;
|
import jakarta.persistence.Basic;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
|
|
||||||
import org.hibernate.HibernateError;
|
|
||||||
import org.hibernate.annotations.CreationTimestamp;
|
import org.hibernate.annotations.CreationTimestamp;
|
||||||
import org.hibernate.annotations.UpdateTimestamp;
|
import org.hibernate.annotations.UpdateTimestamp;
|
||||||
|
import org.hibernate.generator.internal.CurrentTimestampGeneration;
|
||||||
|
import org.hibernate.orm.test.annotations.MutableClock;
|
||||||
|
import org.hibernate.orm.test.annotations.MutableClockSettingProvider;
|
||||||
|
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.hibernate.testing.orm.junit.SettingProvider;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
@ -32,14 +38,24 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
*/
|
*/
|
||||||
@DomainModel( annotatedClasses = InVmGenerationsWithAnnotationsWithSqlDateTests.AuditedEntity.class )
|
@DomainModel( annotatedClasses = InVmGenerationsWithAnnotationsWithSqlDateTests.AuditedEntity.class )
|
||||||
@SessionFactory
|
@SessionFactory
|
||||||
|
@ServiceRegistry(settingProviders = @SettingProvider(settingName = CurrentTimestampGeneration.CLOCK_SETTING_NAME, provider = MutableClockSettingProvider.class))
|
||||||
public class InVmGenerationsWithAnnotationsWithSqlDateTests {
|
public class InVmGenerationsWithAnnotationsWithSqlDateTests {
|
||||||
|
|
||||||
|
private MutableClock clock;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setup(SessionFactoryScope scope) {
|
||||||
|
clock = CurrentTimestampGeneration.getClock( scope.getSessionFactory() );
|
||||||
|
clock.reset();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGenerations(SessionFactoryScope scope) {
|
public void testGenerations(SessionFactoryScope scope) {
|
||||||
scope.inSession( (session) -> {
|
scope.inSession( (session) -> {
|
||||||
// first creation
|
// first creation
|
||||||
final AuditedEntity saved = scope.fromTransaction( session, (s) -> {
|
final AuditedEntity saved = scope.fromTransaction( session, s -> {
|
||||||
final AuditedEntity entity = new AuditedEntity( 1, "it" );
|
final AuditedEntity entity = new AuditedEntity( 1, "it" );
|
||||||
session.persist( entity );
|
s.persist( entity );
|
||||||
return entity;
|
return entity;
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
@ -48,14 +64,10 @@ public class InVmGenerationsWithAnnotationsWithSqlDateTests {
|
||||||
assertThat( saved.lastUpdatedOn ).isNotNull();
|
assertThat( saved.lastUpdatedOn ).isNotNull();
|
||||||
|
|
||||||
saved.name = "changed";
|
saved.name = "changed";
|
||||||
|
clock.tick();
|
||||||
//We need to wait a little to make sure the timestamps produced are different
|
|
||||||
waitALittle();
|
|
||||||
|
|
||||||
// then changing
|
// then changing
|
||||||
final AuditedEntity merged = scope.fromTransaction( session, (s) -> {
|
final AuditedEntity merged = scope.fromTransaction( session, s -> s.merge( saved ) );
|
||||||
return (AuditedEntity) session.merge( saved );
|
|
||||||
} );
|
|
||||||
|
|
||||||
assertThat( merged ).isNotNull();
|
assertThat( merged ).isNotNull();
|
||||||
assertThat( merged.createdOn ).isNotNull();
|
assertThat( merged.createdOn ).isNotNull();
|
||||||
|
@ -63,9 +75,7 @@ public class InVmGenerationsWithAnnotationsWithSqlDateTests {
|
||||||
assertThat( merged.lastUpdatedOn ).isNotEqualTo( merged.createdOn );
|
assertThat( merged.lastUpdatedOn ).isNotEqualTo( merged.createdOn );
|
||||||
|
|
||||||
// lastly, make sure we can load it..
|
// lastly, make sure we can load it..
|
||||||
final AuditedEntity loaded = scope.fromTransaction( session, (s) -> {
|
final AuditedEntity loaded = scope.fromTransaction( session, s -> s.get( AuditedEntity.class, 1 ) );
|
||||||
return session.get( AuditedEntity.class, 1 );
|
|
||||||
} );
|
|
||||||
|
|
||||||
assertThat( loaded ).isNotNull();
|
assertThat( loaded ).isNotNull();
|
||||||
assertThat( loaded.createdOn ).isEqualTo( merged.createdOn );
|
assertThat( loaded.createdOn ).isEqualTo( merged.createdOn );
|
||||||
|
@ -98,13 +108,4 @@ public class InVmGenerationsWithAnnotationsWithSqlDateTests {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void waitALittle() {
|
|
||||||
try {
|
|
||||||
Thread.sleep( 10 );
|
|
||||||
}
|
|
||||||
catch (InterruptedException e) {
|
|
||||||
throw new HibernateError( "Unexpected wakeup from test sleep" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,14 +14,19 @@ import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
|
|
||||||
import org.hibernate.HibernateError;
|
|
||||||
import org.hibernate.annotations.CreationTimestamp;
|
import org.hibernate.annotations.CreationTimestamp;
|
||||||
import org.hibernate.annotations.UpdateTimestamp;
|
import org.hibernate.annotations.UpdateTimestamp;
|
||||||
|
import org.hibernate.generator.internal.CurrentTimestampGeneration;
|
||||||
|
import org.hibernate.orm.test.annotations.MutableClock;
|
||||||
|
import org.hibernate.orm.test.annotations.MutableClockSettingProvider;
|
||||||
|
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.hibernate.testing.orm.junit.SettingProvider;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
@ -34,14 +39,24 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
*/
|
*/
|
||||||
@DomainModel( annotatedClasses = InVmGenerationsWithMultipleAnnotationsTests.AuditedEntity.class )
|
@DomainModel( annotatedClasses = InVmGenerationsWithMultipleAnnotationsTests.AuditedEntity.class )
|
||||||
@SessionFactory
|
@SessionFactory
|
||||||
|
@ServiceRegistry(settingProviders = @SettingProvider(settingName = CurrentTimestampGeneration.CLOCK_SETTING_NAME, provider = MutableClockSettingProvider.class))
|
||||||
public class InVmGenerationsWithMultipleAnnotationsTests {
|
public class InVmGenerationsWithMultipleAnnotationsTests {
|
||||||
|
|
||||||
|
private MutableClock clock;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setup(SessionFactoryScope scope) {
|
||||||
|
clock = CurrentTimestampGeneration.getClock( scope.getSessionFactory() );
|
||||||
|
clock.reset();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGenerations(SessionFactoryScope scope) {
|
public void testGenerations(SessionFactoryScope scope) {
|
||||||
scope.inSession( (session) -> {
|
scope.inSession( (session) -> {
|
||||||
// first creation
|
// first creation
|
||||||
final AuditedEntity saved = scope.fromTransaction( session, (s) -> {
|
final AuditedEntity saved = scope.fromTransaction( session, s -> {
|
||||||
final AuditedEntity entity = new AuditedEntity( 1, "it" );
|
final AuditedEntity entity = new AuditedEntity( 1, "it" );
|
||||||
session.persist( entity );
|
s.persist( entity );
|
||||||
return entity;
|
return entity;
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
@ -50,14 +65,10 @@ public class InVmGenerationsWithMultipleAnnotationsTests {
|
||||||
assertThat( saved.lastUpdatedOn ).isNotNull();
|
assertThat( saved.lastUpdatedOn ).isNotNull();
|
||||||
|
|
||||||
saved.name = "changed";
|
saved.name = "changed";
|
||||||
|
clock.tick();
|
||||||
//We need to wait a little to make sure the timestamps produced are different
|
|
||||||
waitALittle();
|
|
||||||
|
|
||||||
// then changing
|
// then changing
|
||||||
final AuditedEntity merged = scope.fromTransaction( session, (s) -> {
|
final AuditedEntity merged = scope.fromTransaction( session, s -> s.merge( saved ) );
|
||||||
return (AuditedEntity) session.merge( saved );
|
|
||||||
} );
|
|
||||||
|
|
||||||
assertThat( merged ).isNotNull();
|
assertThat( merged ).isNotNull();
|
||||||
assertThat( merged.createdOn ).isNotNull();
|
assertThat( merged.createdOn ).isNotNull();
|
||||||
|
@ -65,9 +76,7 @@ public class InVmGenerationsWithMultipleAnnotationsTests {
|
||||||
assertThat( merged.lastUpdatedOn ).isNotEqualTo( merged.createdOn );
|
assertThat( merged.lastUpdatedOn ).isNotEqualTo( merged.createdOn );
|
||||||
|
|
||||||
// lastly, make sure we can load it..
|
// lastly, make sure we can load it..
|
||||||
final AuditedEntity loaded = scope.fromTransaction( session, (s) -> {
|
final AuditedEntity loaded = scope.fromTransaction( session, s -> s.get( AuditedEntity.class, 1 ) );
|
||||||
return session.get( AuditedEntity.class, 1 );
|
|
||||||
} );
|
|
||||||
|
|
||||||
assertThat( loaded ).isNotNull();
|
assertThat( loaded ).isNotNull();
|
||||||
assertThat( loaded.createdOn ).isEqualTo( merged.createdOn );
|
assertThat( loaded.createdOn ).isEqualTo( merged.createdOn );
|
||||||
|
@ -110,13 +119,4 @@ public class InVmGenerationsWithMultipleAnnotationsTests {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void waitALittle() {
|
|
||||||
try {
|
|
||||||
Thread.sleep( 10 );
|
|
||||||
}
|
|
||||||
catch (InterruptedException e) {
|
|
||||||
throw new HibernateError( "Unexpected wakeup from test sleep" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.orm.test.tenantid;
|
package org.hibernate.orm.test.tenantid;
|
||||||
|
|
||||||
import org.hibernate.HibernateError;
|
|
||||||
import org.hibernate.PropertyValueException;
|
import org.hibernate.PropertyValueException;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.hibernate.StatelessSession;
|
import org.hibernate.StatelessSession;
|
||||||
|
@ -24,13 +23,18 @@ import org.hibernate.testing.orm.junit.SessionFactoryProducer;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
import org.hibernate.testing.orm.junit.Setting;
|
import org.hibernate.testing.orm.junit.Setting;
|
||||||
import org.hibernate.binder.internal.TenantIdBinder;
|
import org.hibernate.binder.internal.TenantIdBinder;
|
||||||
|
import org.hibernate.generator.internal.CurrentTimestampGeneration;
|
||||||
|
import org.hibernate.orm.test.annotations.MutableClock;
|
||||||
|
import org.hibernate.orm.test.annotations.MutableClockSettingProvider;
|
||||||
import org.hibernate.query.Query;
|
import org.hibernate.query.Query;
|
||||||
import org.hibernate.query.criteria.HibernateCriteriaBuilder;
|
import org.hibernate.query.criteria.HibernateCriteriaBuilder;
|
||||||
import org.hibernate.query.criteria.JpaCriteriaQuery;
|
import org.hibernate.query.criteria.JpaCriteriaQuery;
|
||||||
import org.hibernate.query.criteria.JpaRoot;
|
import org.hibernate.query.criteria.JpaRoot;
|
||||||
|
|
||||||
|
import org.hibernate.testing.orm.junit.SettingProvider;
|
||||||
import org.hibernate.testing.orm.junit.SkipForDialect;
|
import org.hibernate.testing.orm.junit.SkipForDialect;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import jakarta.persistence.EntityManager;
|
import jakarta.persistence.EntityManager;
|
||||||
|
@ -54,11 +58,19 @@ import java.util.List;
|
||||||
@ServiceRegistry(
|
@ServiceRegistry(
|
||||||
settings = {
|
settings = {
|
||||||
@Setting(name = JAKARTA_HBM2DDL_DATABASE_ACTION, value = "create-drop")
|
@Setting(name = JAKARTA_HBM2DDL_DATABASE_ACTION, value = "create-drop")
|
||||||
}
|
},
|
||||||
|
settingProviders = @SettingProvider(settingName = CurrentTimestampGeneration.CLOCK_SETTING_NAME, provider = MutableClockSettingProvider.class)
|
||||||
)
|
)
|
||||||
public class TenantIdTest implements SessionFactoryProducer {
|
public class TenantIdTest implements SessionFactoryProducer {
|
||||||
|
|
||||||
String currentTenant;
|
String currentTenant;
|
||||||
|
MutableClock clock;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setup(SessionFactoryScope scope) {
|
||||||
|
clock = CurrentTimestampGeneration.getClock( scope.getSessionFactory() );
|
||||||
|
clock.reset();
|
||||||
|
}
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
public void cleanup(SessionFactoryScope scope) {
|
public void cleanup(SessionFactoryScope scope) {
|
||||||
|
@ -211,8 +223,7 @@ public class TenantIdTest implements SessionFactoryProducer {
|
||||||
assertEquals( "mine", record.state.tenantId );
|
assertEquals( "mine", record.state.tenantId );
|
||||||
assertNotNull( record.state.updated );
|
assertNotNull( record.state.updated );
|
||||||
|
|
||||||
//We need to wait a little to make sure the timestamps produced are different
|
clock.tick();
|
||||||
waitALittle();
|
|
||||||
|
|
||||||
scope.inTransaction( s -> {
|
scope.inTransaction( s -> {
|
||||||
Record r = s.find( Record.class, record.id );
|
Record r = s.find( Record.class, record.id );
|
||||||
|
@ -342,13 +353,4 @@ public class TenantIdTest implements SessionFactoryProducer {
|
||||||
JpaRoot<Record> from = criteriaQuery.from( Record.class );
|
JpaRoot<Record> from = criteriaQuery.from( Record.class );
|
||||||
return session.createQuery( criteriaQuery ).getResultList();
|
return session.createQuery( criteriaQuery ).getResultList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void waitALittle() {
|
|
||||||
try {
|
|
||||||
Thread.sleep( 10 );
|
|
||||||
}
|
|
||||||
catch (InterruptedException e) {
|
|
||||||
throw new HibernateError( "Unexpected wakeup from test sleep" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue