HHH-18377 Test cases to check monofonicity of generated version 6 & version 7 UUID's
This commit is contained in:
parent
b57e84e736
commit
90e4f06d37
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
|
*/
|
||||||
|
package org.hibernate.orm.test.id.uuid.rfc9562;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.UuidGenerator;
|
||||||
|
import org.hibernate.id.uuid.UuidVersion7Strategy;
|
||||||
|
|
||||||
|
import jakarta.persistence.Basic;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
|
||||||
|
@Entity(name = "EntitySeven")
|
||||||
|
@Table(name = "entity_seven")
|
||||||
|
public class EntitySeven {
|
||||||
|
@Id
|
||||||
|
@UuidGenerator(algorithm = UuidVersion7Strategy.class)
|
||||||
|
public UUID id;
|
||||||
|
@Basic
|
||||||
|
public String name;
|
||||||
|
|
||||||
|
private EntitySeven() {
|
||||||
|
// for Hibernate use
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntitySeven(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
|
*/
|
||||||
|
package org.hibernate.orm.test.id.uuid.rfc9562;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.UuidGenerator;
|
||||||
|
import org.hibernate.id.uuid.UuidVersion6Strategy;
|
||||||
|
|
||||||
|
import jakarta.persistence.Basic;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@Table(name = "entity_six")
|
||||||
|
@Entity
|
||||||
|
public class EntitySix {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
@UuidGenerator(algorithm = UuidVersion6Strategy.class)
|
||||||
|
private UUID id;
|
||||||
|
@Basic
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
protected EntitySix() {
|
||||||
|
// for Hibernate use
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntitySix(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
|
*/
|
||||||
|
package org.hibernate.orm.test.id.uuid.rfc9562;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.UuidGenerator;
|
||||||
|
import org.hibernate.id.uuid.UuidVersion7Strategy;
|
||||||
|
|
||||||
|
import jakarta.persistence.Basic;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
|
||||||
|
@Entity(name = "OtherEntitySeven")
|
||||||
|
@Table(name = "other_entity_seven")
|
||||||
|
public class OtherEntitySeven {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
public Long pk;
|
||||||
|
|
||||||
|
@UuidGenerator(algorithm = UuidVersion7Strategy.class)
|
||||||
|
public UUID id;
|
||||||
|
|
||||||
|
@Basic
|
||||||
|
public String name;
|
||||||
|
|
||||||
|
private OtherEntitySeven() {
|
||||||
|
// for Hibernate use
|
||||||
|
}
|
||||||
|
|
||||||
|
public OtherEntitySeven(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
|
*/
|
||||||
|
package org.hibernate.orm.test.id.uuid.rfc9562;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
|
import org.hibernate.id.uuid.UuidValueGenerator;
|
||||||
|
import org.hibernate.id.uuid.UuidVersion6Strategy;
|
||||||
|
import org.hibernate.id.uuid.UuidVersion7Strategy;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
|
public class UUidV6V7GenetartorTest {
|
||||||
|
|
||||||
|
private static final UUID NIL_UUID = new UUID( 0L, 0L );
|
||||||
|
private static final int ITERATIONS = 1_000_000;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testMonotonicityUuid6() {
|
||||||
|
testMonotonicity( UuidVersion6Strategy.INSTANCE );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testMonotonicityUuid7() {
|
||||||
|
testMonotonicity( UuidVersion7Strategy.INSTANCE );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testMonotonicity(UuidValueGenerator generator) {
|
||||||
|
final SharedSessionContractImplementor session = mock( SharedSessionContractImplementor.class );
|
||||||
|
final UUID[] uuids = new UUID[ITERATIONS + 1];
|
||||||
|
uuids[0] = NIL_UUID;
|
||||||
|
for ( int n = 1; n <= ITERATIONS; ++n ) {
|
||||||
|
uuids[n] = generator.generateUuid( session );
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( var n = 0; n < ITERATIONS; ++n ) {
|
||||||
|
assertThat( uuids[n + 1].toString() ).isGreaterThan( uuids[n].toString() );
|
||||||
|
assertThat( uuids[n + 1] ).isGreaterThan( uuids[n] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,143 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
* Copyright Red Hat Inc. and Hibernate Authors
|
||||||
|
*/
|
||||||
|
package org.hibernate.orm.test.id.uuid.rfc9562;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.hibernate.dialect.SybaseDialect;
|
||||||
|
import org.hibernate.generator.Generator;
|
||||||
|
import org.hibernate.id.uuid.UuidGenerator;
|
||||||
|
import org.hibernate.id.uuid.UuidVersion6Strategy;
|
||||||
|
import org.hibernate.id.uuid.UuidVersion7Strategy;
|
||||||
|
import org.hibernate.mapping.BasicValue;
|
||||||
|
import org.hibernate.mapping.Property;
|
||||||
|
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModelScope;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.hibernate.testing.orm.junit.SkipForDialect;
|
||||||
|
import org.hibernate.testing.util.uuid.IdGeneratorCreationContext;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
@SuppressWarnings("JUnitMalformedDeclaration")
|
||||||
|
@DomainModel(annotatedClasses = {
|
||||||
|
EntitySeven.class, OtherEntitySeven.class, EntitySix.class
|
||||||
|
})
|
||||||
|
@SessionFactory
|
||||||
|
@SkipForDialect(dialectClass = SybaseDialect.class, matchSubTypes = true,
|
||||||
|
reason = "Skipped for Sybase to avoid problems with UUIDs potentially ending with a trailing 0 byte")
|
||||||
|
public class UuidGeneratorAnnotationTests {
|
||||||
|
@Test
|
||||||
|
public void verifyUuidV7IdGeneratorModel(final DomainModelScope scope) {
|
||||||
|
scope.withHierarchy( EntitySeven.class, descriptor -> {
|
||||||
|
final Property idProperty = descriptor.getIdentifierProperty();
|
||||||
|
final BasicValue value = (BasicValue) idProperty.getValue();
|
||||||
|
|
||||||
|
assertThat( value.getCustomIdGeneratorCreator() ).isNotNull();
|
||||||
|
final Generator generator = value.getCustomIdGeneratorCreator()
|
||||||
|
.createGenerator( new IdGeneratorCreationContext(
|
||||||
|
scope.getDomainModel(),
|
||||||
|
descriptor
|
||||||
|
) );
|
||||||
|
|
||||||
|
assertThat( generator ).isInstanceOf( UuidGenerator.class );
|
||||||
|
final UuidGenerator uuidGenerator = (UuidGenerator) generator;
|
||||||
|
assertThat( uuidGenerator.getValueGenerator() ).isInstanceOf( UuidVersion7Strategy.class );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void verifyUuidV6IdGeneratorModel(final DomainModelScope scope) {
|
||||||
|
scope.withHierarchy( EntitySix.class, descriptor -> {
|
||||||
|
final Property idProperty = descriptor.getIdentifierProperty();
|
||||||
|
final BasicValue value = (BasicValue) idProperty.getValue();
|
||||||
|
|
||||||
|
assertThat( value.getCustomIdGeneratorCreator() ).isNotNull();
|
||||||
|
final Generator generator = value.getCustomIdGeneratorCreator()
|
||||||
|
.createGenerator( new IdGeneratorCreationContext(
|
||||||
|
scope.getDomainModel(),
|
||||||
|
descriptor
|
||||||
|
) );
|
||||||
|
|
||||||
|
assertThat( generator ).isInstanceOf( UuidGenerator.class );
|
||||||
|
final UuidGenerator uuidGenerator = (UuidGenerator) generator;
|
||||||
|
assertThat( uuidGenerator.getValueGenerator() ).isInstanceOf( UuidVersion6Strategy.class );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void basicUseTest(final SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( session -> {
|
||||||
|
final EntitySeven seven = new EntitySeven( "John Doe" );
|
||||||
|
session.persist( seven );
|
||||||
|
session.flush();
|
||||||
|
assertThat( seven.id ).isNotNull();
|
||||||
|
assertThat( seven.id.version() ).isEqualTo( 7 );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void nonPkUseTest(final SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( session -> {
|
||||||
|
final Instant startTime = Instant.now();
|
||||||
|
|
||||||
|
final OtherEntitySeven seven = new OtherEntitySeven( "Dave Default" );
|
||||||
|
session.persist( seven );
|
||||||
|
session.flush();
|
||||||
|
|
||||||
|
final Instant endTime = Instant.now();
|
||||||
|
assertThat( seven.id ).isNotNull();
|
||||||
|
assertThat( seven.id.version() ).isEqualTo( 7 );
|
||||||
|
|
||||||
|
assertThat( Instant.ofEpochMilli( seven.id.getMostSignificantBits() >> 16 & 0xFFFF_FFFF_FFFFL ) )
|
||||||
|
.isBetween( startTime.truncatedTo( ChronoUnit.MILLIS ), endTime.truncatedTo( ChronoUnit.MILLIS ) );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testUuidV6IdGenerator(final SessionFactoryScope sessionFactoryScope) {
|
||||||
|
sessionFactoryScope.inTransaction( session -> {
|
||||||
|
final Instant startTime = Instant.now();
|
||||||
|
|
||||||
|
final EntitySix six = new EntitySix( "Jane Doe" );
|
||||||
|
session.persist( six );
|
||||||
|
assertThat( six.getId() ).isNotNull();
|
||||||
|
assertThat( six.getId().version() ).isEqualTo( 6 );
|
||||||
|
|
||||||
|
session.flush();
|
||||||
|
final Instant endTime = Instant.now();
|
||||||
|
assertThat( six.getId() ).isNotNull();
|
||||||
|
assertThat( six.getId().version() ).isEqualTo( 6 );
|
||||||
|
assertThat( uuid6Instant( six.getId() ) ).isBetween( startTime, endTime );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
void dropTestData(final SessionFactoryScope sessionFactoryScope) {
|
||||||
|
sessionFactoryScope.inTransaction( session -> {
|
||||||
|
session.createMutationQuery( "delete EntitySeven" ).executeUpdate();
|
||||||
|
session.createMutationQuery( "delete OtherEntitySeven" ).executeUpdate();
|
||||||
|
session.createMutationQuery( "delete EntitySix" ).executeUpdate();
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Instant uuid6Instant(final UUID uuid) {
|
||||||
|
assert uuid.version() == 6;
|
||||||
|
|
||||||
|
final var msb = uuid.getMostSignificantBits();
|
||||||
|
final var ts = msb >> 4 & 0x0FFF_FFFF_FFFF_F000L | msb & 0x0FFFL;
|
||||||
|
return LocalDate.of( 1582, 10, 15 ).atStartOfDay( ZoneId.of( "UTC" ) ).toInstant()
|
||||||
|
.plusSeconds( ts / 10_000_000 ).plusNanos( ts % 10_000_000 * 100 );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -69,7 +69,6 @@ import static org.hamcrest.Matchers.isOneOf;
|
||||||
import static org.hibernate.testing.orm.domain.gambit.EntityOfBasics.Gender.FEMALE;
|
import static org.hibernate.testing.orm.domain.gambit.EntityOfBasics.Gender.FEMALE;
|
||||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue