diff --git a/api/src/main/java/ru/kirillius/XCP/Persistence/PersistenceEntity.java b/api/src/main/java/ru/kirillius/XCP/Persistence/PersistenceEntity.java index fbedbd2..59a94a0 100644 --- a/api/src/main/java/ru/kirillius/XCP/Persistence/PersistenceEntity.java +++ b/api/src/main/java/ru/kirillius/XCP/Persistence/PersistenceEntity.java @@ -5,7 +5,7 @@ import java.util.UUID; public interface PersistenceEntity { long getId(); - UUID getUUID(); + UUID getUuid(); Class getBaseType(); } diff --git a/database/src/main/java/ru/kirillius/XCP/Persistence/AbstractRepository.java b/database/src/main/java/ru/kirillius/XCP/Persistence/AbstractRepository.java index 60d7af5..edf2435 100644 --- a/database/src/main/java/ru/kirillius/XCP/Persistence/AbstractRepository.java +++ b/database/src/main/java/ru/kirillius/XCP/Persistence/AbstractRepository.java @@ -1,6 +1,5 @@ package ru.kirillius.XCP.Persistence; -import jakarta.persistence.Table; import lombok.Getter; import org.hibernate.Session; import org.hibernate.Transaction; @@ -45,14 +44,7 @@ public abstract class AbstractRepository implements } //noinspection unchecked entityImplementationClass = (Class) thisClass.getAnnotation(EntityImplementation.class).value(); - - if (entityImplementationClass.isAnnotationPresent(Table.class)) { - tableName = entityImplementationClass.getAnnotation(Table.class).name(); - } - if (tableName == null || tableName.isEmpty()) { - tableName = entityImplementationClass.getName(); - } - + tableName = entityImplementationClass.getName(); } @Override diff --git a/database/src/main/java/ru/kirillius/XCP/Persistence/EntityReferenceSerializer.java b/database/src/main/java/ru/kirillius/XCP/Persistence/EntityReferenceSerializer.java index cbd6356..3437a7e 100644 --- a/database/src/main/java/ru/kirillius/XCP/Persistence/EntityReferenceSerializer.java +++ b/database/src/main/java/ru/kirillius/XCP/Persistence/EntityReferenceSerializer.java @@ -20,7 +20,7 @@ public class EntityReferenceSerializer extends StdSerializer gen.writeStartObject(); gen.writeStringProperty("type", value.getBaseType().getName()); gen.writeNumberProperty("id", value.getId()); - gen.writeStringProperty("uuid", value.getUUID().toString()); + gen.writeStringProperty("uuid", value.getUuid().toString()); gen.writeEndObject(); } } diff --git a/database/src/main/java/ru/kirillius/XCP/Persistence/Repositories/UserRepositoryImpl.java b/database/src/main/java/ru/kirillius/XCP/Persistence/Repositories/UserRepositoryImpl.java index dbce144..120c642 100644 --- a/database/src/main/java/ru/kirillius/XCP/Persistence/Repositories/UserRepositoryImpl.java +++ b/database/src/main/java/ru/kirillius/XCP/Persistence/Repositories/UserRepositoryImpl.java @@ -12,6 +12,7 @@ import ru.kirillius.XCP.Serialization.SerializationUtils; import tools.jackson.databind.node.ObjectNode; import java.io.IOException; +import java.util.Objects; import java.util.UUID; @EntityImplementation(UserRepositoryImpl.UserEntity.class) @@ -36,7 +37,7 @@ public class UserRepositoryImpl extends AbstractRepository implements User } @Entity - @Table(name = "Users") + @Table(name = "UserEntities") @Builder @AllArgsConstructor @NoArgsConstructor @@ -51,11 +52,11 @@ public class UserRepositoryImpl extends AbstractRepository implements User @JsonProperty @Column(unique = true, nullable = false) @UuidGenerator - private UUID UUID; + private UUID uuid; @Column(nullable = false) @JsonProperty - private String login; + private String login = ""; @Column(nullable = false) @JsonProperty @@ -63,12 +64,12 @@ public class UserRepositoryImpl extends AbstractRepository implements User @Column(nullable = false) @JsonProperty - private String passwordHash; + private String passwordHash = ""; @Column(nullable = false) @JsonProperty @Enumerated(EnumType.STRING) - private UserRole role; + private UserRole role=UserRole.User; @Column(name = "custom_values", nullable = false) @Getter @@ -90,5 +91,16 @@ public class UserRepositoryImpl extends AbstractRepository implements User public boolean verifyPassword(String password) { return Argon2HashUtility.getInstance().validate(password, passwordHash); } + + @Override + public boolean equals(Object o) { + if (!(o instanceof UserEntity that)) return false; + return Objects.equals(uuid, that.uuid); + } + + @Override + public int hashCode() { + return Objects.hashCode(uuid); + } } } diff --git a/database/src/main/java/ru/kirillius/XCP/Persistence/RepositoryServiceImpl.java b/database/src/main/java/ru/kirillius/XCP/Persistence/RepositoryServiceImpl.java index fc174b6..dad8398 100644 --- a/database/src/main/java/ru/kirillius/XCP/Persistence/RepositoryServiceImpl.java +++ b/database/src/main/java/ru/kirillius/XCP/Persistence/RepositoryServiceImpl.java @@ -28,7 +28,7 @@ public final class RepositoryServiceImpl implements RepositoryService { managedRepositoryClasses = repositoryImplClasses; configuration = new Configuration(); configuration.configure(); - registerClasses(repositoryImplClasses); + registerClasses(); loadDatabaseConfig(databaseConfiguration); } @@ -41,10 +41,10 @@ public final class RepositoryServiceImpl implements RepositoryService { managedRepositoryClasses = repositoryImplClasses; configuration = new Configuration(); configuration.configure(); - registerClasses(repositoryImplClasses); + registerClasses(); } - private void registerClasses(Collection>> repositoryImplClasses) { + private void registerClasses() { managedRepositoryClasses.forEach(aClass -> { var implementation = aClass.getAnnotation(EntityImplementation.class); if (implementation == null) { diff --git a/database/src/test/java/TestContext.java b/database/src/test/java/TestContext.java deleted file mode 100644 index df6f6e1..0000000 --- a/database/src/test/java/TestContext.java +++ /dev/null @@ -1,26 +0,0 @@ -import ru.kirillius.XCP.Commons.Config; -import ru.kirillius.XCP.Commons.ConfigManager; -import ru.kirillius.XCP.Commons.Context; -import ru.kirillius.XCP.Commons.Service; - -public class TestContext implements Context { - @Override - public Config getConfig() { - return null; - } - - @Override - public ConfigManager getConfigManager() { - return null; - } - - @Override - public S getService(Class serviceClass) { - return null; - } - - @Override - public void shutdown() { - - } -} diff --git a/database/src/test/java/ru/kirillius/XCP/Persistence/Repositories/GenericRepositoryTest.java b/database/src/test/java/ru/kirillius/XCP/Persistence/Repositories/GenericRepositoryTest.java new file mode 100644 index 0000000..5b7a558 --- /dev/null +++ b/database/src/test/java/ru/kirillius/XCP/Persistence/Repositories/GenericRepositoryTest.java @@ -0,0 +1,100 @@ +package ru.kirillius.XCP.Persistence.Repositories; + +import org.junit.jupiter.api.Test; +import ru.kirillius.XCP.Persistence.AbstractRepository; +import ru.kirillius.XCP.Persistence.PersistenceEntity; +import ru.kirillius.XCP.Persistence.RepositoryService; + +import java.io.IOException; +import java.lang.reflect.ParameterizedType; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static ru.kirillius.XCP.Persistence.TestEnvironment.instantiateTestService; + +abstract class GenericRepositoryTest> { + + protected Class entityClass; + protected Class repositoryClass; + + @SuppressWarnings("unchecked") + public GenericRepositoryTest() { + try { + var parameterizedType = (ParameterizedType) getClass().getGenericSuperclass(); + var typeArguments = parameterizedType.getActualTypeArguments(); + + if (typeArguments.length != 2) { + throw new IllegalStateException("Generic parameters count is unsupported"); + } + entityClass = (Class) typeArguments[0]; + repositoryClass = (Class) typeArguments[1]; + + } catch (Exception e) { + throw new RuntimeException("Failed to determine service generic parameters for Service: " + this.getClass().getName(), e); + } + } + + protected RepositoryService spawnRepositoryService() { + return instantiateTestService(List.of(repositoryClass)); + } + + @Test + void testCreate() throws IOException { + try (var service = spawnRepositoryService()) { + var repository = service.getRepositoryForEntity(entityClass); + var entity = repository.create(); + assertThat(entity).isNotNull(); + } + } + + @Test + void testStore() throws IOException { + try (var service = spawnRepositoryService()) { + var repository = service.getRepositoryForEntity(entityClass); + var entity = repository.create(); + repository.store(entity); + assertThat(entity.getId()).isNotZero(); + } + } + + @Test + void testLoad() throws IOException { + try (var service = spawnRepositoryService()) { + var repository = service.getRepositoryForEntity(entityClass); + var entity = repository.create(); + repository.store(entity); + var loaded = repository.load(entity.getId()); + assertThat(loaded).isNotNull().isEqualTo(entity); + + var loadedByUUID = repository.load(entity.getUuid()); + assertThat(loadedByUUID).isNotNull().isEqualTo(entity); + } + } + + @Test + void testModify() throws IOException { + try (var service = spawnRepositoryService()) { + var repository = service.getRepositoryForEntity(entityClass); + var entity = repository.create(); + repository.store(entity); + modify(entity); + repository.store(entity); + var loaded = repository.load(entity.getId()); + assertThat(loaded).isNotNull().isEqualTo(entity); + } + } + + @Test + void testRemove() throws IOException { + try (var service = spawnRepositoryService()) { + var repository = service.getRepositoryForEntity(entityClass); + var entity = repository.create(); + repository.store(entity); + assertThat(repository.getCount()).isEqualTo(1); + repository.remove(entity); + assertThat(repository.getCount()).isZero(); + } + } + + protected abstract void modify(E entity); +} \ No newline at end of file diff --git a/database/src/test/java/ru/kirillius/XCP/Persistence/Repositories/UserRepositoryImplTest.java b/database/src/test/java/ru/kirillius/XCP/Persistence/Repositories/UserRepositoryImplTest.java new file mode 100644 index 0000000..1f1d80e --- /dev/null +++ b/database/src/test/java/ru/kirillius/XCP/Persistence/Repositories/UserRepositoryImplTest.java @@ -0,0 +1,54 @@ +package ru.kirillius.XCP.Persistence.Repositories; + +import org.junit.jupiter.api.Test; +import ru.kirillius.XCP.Persistence.Entities.User; + +import java.io.IOException; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; + +class UserRepositoryImplTest extends GenericRepositoryTest { + + @Test + void getByLogin() throws IOException { + var correct = "correctlogin"; + try (var service = spawnRepositoryService()) { + var repository = service.getRepository(UserRepository.class); + for (var i = 0; i < 10; i++) { + var user = repository.create(); + user.setLogin("incorrect" + UUID.randomUUID()); + repository.store(user); + } + var correctUser = repository.create(); + correctUser.setLogin(correct); + repository.store(correctUser); + for (var i = 0; i < 10; i++) { + var user = repository.create(); + user.setLogin("incorrect" + UUID.randomUUID()); + repository.store(user); + } + + var loaded = repository.getByLogin(correct); + assertThat(loaded).isNotNull().isEqualTo(correctUser); + } + } + + @Test + void testPasswords() throws IOException { + try (var service = spawnRepositoryService()) { + var repository = service.getRepository(UserRepository.class); + var user = repository.create(); + var randPass = UUID.randomUUID().toString(); + user.setPassword(randPass); + + assertThat(user.verifyPassword(randPass)).isTrue(); + assertThat(((UserRepositoryImpl.UserEntity) user).getPasswordHash()).doesNotContain(randPass); + } + } + + @Override + protected void modify(User entity) { + entity.setName("test" + UUID.randomUUID()); + } +} \ No newline at end of file diff --git a/database/src/test/java/ru/kirillius/XCP/Persistence/RepositoryServiceImplTest.java b/database/src/test/java/ru/kirillius/XCP/Persistence/RepositoryServiceImplTest.java index 37c308e..9696b3b 100644 --- a/database/src/test/java/ru/kirillius/XCP/Persistence/RepositoryServiceImplTest.java +++ b/database/src/test/java/ru/kirillius/XCP/Persistence/RepositoryServiceImplTest.java @@ -6,20 +6,17 @@ import lombok.Getter; import lombok.Setter; import org.hibernate.annotations.UuidGenerator; import org.junit.jupiter.api.Test; -import ru.kirillius.XCP.Commons.Context; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.UUID; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; +import static ru.kirillius.XCP.Persistence.TestEnvironment.instantiateTestService; class RepositoryServiceImplTest { - private RepositoryServiceImpl instantiateTestService(Collection>> classes) { - var service = new RepositoryServiceImpl(new H2InMemoryConfiguration(), classes); - service.initialize(mock(Context.class)); - return service; - } public interface TestEntity extends PersistenceEntity { String getTestField(); @@ -62,7 +59,7 @@ class RepositoryServiceImplTest { @UuidGenerator @Getter @Setter - private UUID UUID; + private UUID uuid; @Override public Class getBaseType() { @@ -72,12 +69,12 @@ class RepositoryServiceImplTest { @Override public boolean equals(Object o) { if (!(o instanceof EntityImpl entity)) return false; - return id == entity.id && Objects.equals(testField, entity.testField) && Objects.equals(UUID, entity.UUID); + return id == entity.id && Objects.equals(testField, entity.testField) && Objects.equals(uuid, entity.uuid); } @Override public int hashCode() { - return Objects.hash(testField, id, UUID); + return Objects.hash(testField, id, uuid); } } } diff --git a/database/src/test/java/ru/kirillius/XCP/Persistence/TestEnvironment.java b/database/src/test/java/ru/kirillius/XCP/Persistence/TestEnvironment.java new file mode 100644 index 0000000..62b554d --- /dev/null +++ b/database/src/test/java/ru/kirillius/XCP/Persistence/TestEnvironment.java @@ -0,0 +1,15 @@ +package ru.kirillius.XCP.Persistence; + +import ru.kirillius.XCP.Commons.Context; + +import java.util.Collection; + +import static org.mockito.Mockito.mock; + +public class TestEnvironment { + public static RepositoryServiceImpl instantiateTestService(Collection>> classes) { + var service = new RepositoryServiceImpl(new H2InMemoryConfiguration(), classes); + service.initialize(mock(Context.class)); + return service; + } +}