From daa7f582db9f4c75c2e1a31f0279e2d0b98ea528 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 25 Sep 2019 11:37:33 +0200 Subject: [PATCH] DATACASS-687 - Polishing. Adapt unit tests. --- ...assandraPersistentEntitySchemaCreator.java | 77 +++++++++++++------ ...ersistentEntitySchemaCreatorUnitTests.java | 30 ++++++-- 2 files changed, 78 insertions(+), 29 deletions(-) diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraPersistentEntitySchemaCreator.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraPersistentEntitySchemaCreator.java index a4146e067..a9daeab18 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraPersistentEntitySchemaCreator.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/core/CassandraPersistentEntitySchemaCreator.java @@ -16,8 +16,6 @@ package org.springframework.data.cassandra.core; import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -148,7 +146,7 @@ public class CassandraPersistentEntitySchemaCreator { */ protected List createUserTypeSpecifications(boolean ifNotExists) { - Collection> entities = new ArrayList<>( + List> entities = new ArrayList<>( this.mappingContext.getUserDefinedTypeEntities()); Map> byTableName = entities.stream() @@ -158,11 +156,12 @@ public class CassandraPersistentEntitySchemaCreator { UserDefinedTypeSet udts = new UserDefinedTypeSet(); entities.forEach(entity -> { - udts.add(entity.getTableName()); visitUserTypes(entity, udts); }); + System.out.println(udts.stream().collect(Collectors.toList())); + specifications .addAll(udts .stream().map(identifier -> this.mappingContext @@ -185,9 +184,8 @@ public class CassandraPersistentEntitySchemaCreator { if (propertyType.isUserDefinedType()) { if (udts.add(propertyType.getTableName())) { visitUserTypes(propertyType, udts); - } else { - udts.updateDependency(entity.getTableName(), propertyType.getTableName()); } + udts.addDependency(entity.getTableName(), propertyType.getTableName()); } } } @@ -198,12 +196,12 @@ public class CassandraPersistentEntitySchemaCreator { static class UserDefinedTypeSet implements Streamable { private final Set seen = new HashSet<>(); - private final List creationOrder = new ArrayList<>(); + private final List creationOrder = new ArrayList<>(); public boolean add(CqlIdentifier cqlIdentifier) { if (seen.add(cqlIdentifier)) { - creationOrder.add(cqlIdentifier); + creationOrder.add(new DependencyNode(cqlIdentifier)); return true; } @@ -214,30 +212,63 @@ public class CassandraPersistentEntitySchemaCreator { @Override public Iterator iterator() { - List reverseCreationOrder = new ArrayList<>(creationOrder); - Collections.reverse(reverseCreationOrder); + // Return items in creation order considering dependencies + return creationOrder.stream() // + .sorted((left, right) -> { - return reverseCreationOrder.iterator(); + if (left.dependsOn(right.getIdentifier())) { + return 1; + } + + if (right.dependsOn(left.getIdentifier())) { + return -1; + } + + return 0; + }) // + .map(DependencyNode::getIdentifier) // + .iterator(); } /** - * Checks the dependency order. {@code referent} depends on {@code reference} and we need to make sure that - * {@code referent} gets created after {@code reference}. - *

- * This method therefore updates the dependency order. + * Updates the dependency order. * - * @param referent the client of {@code reference}. - * @param reference the dependency required by {@code referent}. + * @param typeToCreate the client of {@code dependsOn}. + * @param dependsOn the dependency required by {@code typeToCreate}. */ - void updateDependency(CqlIdentifier referent, CqlIdentifier reference) { + void addDependency(CqlIdentifier typeToCreate, CqlIdentifier dependsOn) { - int referentIndex = creationOrder.indexOf(referent); - int referenceIndex = creationOrder.indexOf(reference); + for (DependencyNode toCreate : creationOrder) { + if (toCreate.matches(typeToCreate)) { + toCreate.addDependency(dependsOn); + } + } + } - if (referentIndex > referenceIndex) { + static class DependencyNode { - creationOrder.remove(referent); - creationOrder.add(referenceIndex, referent); + private final CqlIdentifier identifier; + private final List dependsOn = new ArrayList<>(); + + DependencyNode(CqlIdentifier identifier) { + this.identifier = identifier; + } + + public CqlIdentifier getIdentifier() { + return identifier; + } + + boolean matches(CqlIdentifier typeToCreate) { + return identifier.equals(typeToCreate); + } + + void addDependency(CqlIdentifier dependsOn) { + this.dependsOn.add(dependsOn); + + } + + boolean dependsOn(CqlIdentifier identifier) { + return this.dependsOn.contains(identifier); } } } diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/CassandraPersistentEntitySchemaCreatorUnitTests.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/CassandraPersistentEntitySchemaCreatorUnitTests.java index b07441b83..275c56ba6 100644 --- a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/CassandraPersistentEntitySchemaCreatorUnitTests.java +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/core/CassandraPersistentEntitySchemaCreatorUnitTests.java @@ -22,15 +22,15 @@ import static org.mockito.Mockito.*; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.stream.Collectors; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.InOrder; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; -import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; import org.springframework.data.cassandra.core.cql.CqlIdentifier; @@ -113,7 +113,20 @@ public class CassandraPersistentEntitySchemaCreatorUnitTests extends CassandraPe @Test // DATACASS-406 public void createsCorrectTypeForSets() { - context.getPersistentEntity(PlanetType.class); + List> ordered = new ArrayList<>(Arrays.asList(UniverseType.class, PlanetType.class, MoonType.class)); + + Collections.shuffle(ordered); // catch ordering issues + context = new CassandraMappingContext() { + @Override + public Collection> getUserDefinedTypeEntities() { + return ordered.stream().map(this::getRequiredPersistentEntity).collect(Collectors.toList()); + } + }; + context.setUserTypeResolver(typeName -> { + // make sure that calls to this method pop up. Calling UserTypeResolver while resolving + // to be created user types isn't a good idea because they do not exist at resolution time. + throw new IllegalArgumentException(String.format("Type %s not found", typeName)); + }); CassandraPersistentEntitySchemaCreator schemaCreator = new CassandraPersistentEntitySchemaCreator(context, adminOperations); @@ -168,10 +181,15 @@ public class CassandraPersistentEntitySchemaCreatorUnitTests extends CassandraPe private void verifyTypesGetCreatedInOrderFor(String... typenames) { - InOrder inOrder = Mockito.inOrder(operations); + ArgumentCaptor cql = ArgumentCaptor.forClass(String.class); - for (String typename : typenames) { - inOrder.verify(operations).execute(Mockito.contains("CREATE TYPE " + typename)); + verify(operations, atLeast(typenames.length)).execute(cql.capture()); + + List allValues = cql.getAllValues(); + + for (int i = 0; i < typenames.length; i++) { + assertThat(allValues.get(i)).describedAs("Actual: " + allValues + ", expected: " + Arrays.toString(typenames)) + .contains("CREATE TYPE " + typenames[i]); } }