Skip to content

Commit

Permalink
Merge pull request #131 from SpineEventEngine/testutil-gcloud
Browse files Browse the repository at this point in the history
Extract test utilities to `testutil-gcloud`
  • Loading branch information
dmitrykuzmin authored Oct 2, 2019
2 parents 6814482 + b5ec10a commit e0bc530
Show file tree
Hide file tree
Showing 56 changed files with 1,746 additions and 320 deletions.
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@ dependencies {
implementation (
// Datastore Storage support library.
"io.spine.gcloud:spine-datastore:1.1.2",
"io.spine.gcloud:spine-datastore:1.1.3-SNAPSHOT+1",
// Stackdriver Trace support library.
"io.spine.gcloud:spine-stackdriver-trace:1.1.2"
"io.spine.gcloud:spine-stackdriver-trace:1.1.3-SNAPSHOT+1",
// Datastore-related test utilities (if needed).
"io.spine.gcloud:testutil-gcloud:1.1.3-SNAPSHOT+1"
)
}
```
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ ext {
credentialsPropertyFile = 'credentials.properties'
spineProtobufPluginId = 'io.spine.tools.spine-model-compiler'

projectsToPublish = ['datastore', 'stackdriver-trace']
projectsToPublish = ['datastore', 'stackdriver-trace', 'testutil-gcloud']
}

allprojects {
Expand Down
2 changes: 1 addition & 1 deletion config
1 change: 1 addition & 0 deletions datastore/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ dependencies {
exclude group: 'com.google.guava'
}

testImplementation project(path: ":testutil-gcloud")
testImplementation "io.spine:spine-server:"
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public class DatastoreStorageFactory implements StorageFactory {

private final NsConverterFactory converterFactory;

DatastoreStorageFactory(Builder builder) {
protected DatastoreStorageFactory(Builder builder) {
this.typeRegistry = builder.typeRegistry;
this.datastore = builder.datastore;
this.converterFactory = builder.converterFactory;
Expand Down Expand Up @@ -217,7 +217,7 @@ protected Iterable<DatastoreWrapper> wrappers() {
}

/**
* Returs the instance of wrapped {@link Datastore}.
* Returns the instance of wrapped {@link Datastore}.
*/
@VisibleForTesting
protected Datastore datastore() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
Expand Down Expand Up @@ -76,7 +77,7 @@ public class DatastoreWrapper implements Logging {
private static final int MAX_KEYS_PER_READ_REQUEST = 1000;
static final int MAX_ENTITIES_PER_WRITE_REQUEST = 500;

private static final Map<Kind, KeyFactory> keyFactories = new HashMap<>();
private static final Map<DatastoreKind, KeyFactory> keyFactories = new HashMap<>();

private static final Key[] EMPTY_KEY_ARRAY = new Key[0];

Expand Down Expand Up @@ -198,7 +199,7 @@ public void createOrUpdate(Collection<Entity> entities) {
* @return the {@link Entity} or {@code null} in case of no results for the key given
* @see DatastoreReader#get(Key)
*/
public Entity read(Key key) {
public @Nullable Entity read(Key key) {
return actor.get(key);
}

Expand Down Expand Up @@ -301,7 +302,7 @@ public <R> DsQueryIterator<R> read(StructuredQuery<R> query) {
* @throws IllegalArgumentException
* if the provided {@linkplain StructuredQuery#getLimit() query includes a limit}
*/
<R> Iterator<R> readAll(StructuredQuery<R> query, int pageSize) {
public <R> Iterator<R> readAll(StructuredQuery<R> query, int pageSize) {
return readAllPageByPage(query, pageSize);
}

Expand All @@ -322,7 +323,7 @@ <R> Iterator<R> readAll(StructuredQuery<R> query, int pageSize) {
* @throws IllegalArgumentException
* if the provided {@linkplain StructuredQuery#getLimit() query includes a limit}
*/
<R> Iterator<R> readAll(StructuredQuery<R> query) {
public <R> Iterator<R> readAll(StructuredQuery<R> query) {
return readAllPageByPage(query, null);
}

Expand Down Expand Up @@ -386,7 +387,8 @@ public void delete(Key... keys) {
* @param table
* kind (a.k.a. type, table, etc.) of the records to delete
*/
void dropTable(String table) {
@VisibleForTesting
protected void dropTable(String table) {
Namespace namespace = currentNamespace();
StructuredQuery<Entity> query =
Query.newEntityQueryBuilder()
Expand Down Expand Up @@ -504,7 +506,8 @@ public boolean isTransactionActive() {
* @return an instance of {@link KeyFactory} for given kind
*/
public KeyFactory keyFactory(Kind kind) {
KeyFactory keyFactory = keyFactories.get(kind);
DatastoreKind datastoreKind = new DatastoreKind(projectId(), kind);
KeyFactory keyFactory = keyFactories.get(datastoreKind);
if (keyFactory == null) {
keyFactory = initKeyFactory(kind);
}
Expand All @@ -522,17 +525,26 @@ public DatastoreOptions datastoreOptions() {
return options;
}

Datastore datastore() {
@VisibleForTesting
public Datastore datastore() {
return datastore;
}

private KeyFactory initKeyFactory(Kind kind) {
KeyFactory keyFactory = datastore.newKeyFactory()
.setKind(kind.getValue());
keyFactories.put(kind, keyFactory);
.setKind(kind.value());
DatastoreKind datastoreKind = new DatastoreKind(projectId(), kind);
keyFactories.put(datastoreKind, keyFactory);
return keyFactory;
}

private ProjectId projectId() {
String projectId = datastore.getOptions()
.getProjectId();
ProjectId result = ProjectId.of(projectId);
return result;
}

/**
* Reads big number of records.
*
Expand Down Expand Up @@ -587,4 +599,37 @@ private Namespace currentNamespace() {
private void writeSmallBulk(Entity[] entities) {
actor.put(entities);
}

/**
* A Datastore {@link Kind} by project ID.
*/
private static class DatastoreKind {

private final ProjectId projectId;
private final Kind kind;

private DatastoreKind(ProjectId projectId, Kind kind) {
this.projectId = projectId;
this.kind = kind;
}

@SuppressWarnings("EqualsGetClass") // The class is effectively final.
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
DatastoreKind kind1 = (DatastoreKind) o;
return Objects.equals(projectId, kind1.projectId) &&
Objects.equals(kind, kind1.kind);
}

@Override
public int hashCode() {
return Objects.hash(projectId, kind);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ public void writeAll(Iterable<M> messages) {
*/
Iterator<M> readAll(EntityQuery.Builder queryBuilder, int readBatchSize) {
StructuredQuery<Entity> query =
queryBuilder.setKind(kind.getValue())
queryBuilder.setKind(kind.value())
.build();
Iterator<Entity> iterator = datastore.readAll(query, readBatchSize);
Iterator<M> transformed =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ static <I> Iterator<I> indexIterator(DatastoreWrapper datastore, Kind kind, Clas
checkNotNull(idType);

StructuredQuery<Key> query = Query.newKeyQueryBuilder()
.setKind(kind.getValue())
.setKind(kind.value())
.build();
Iterator<Key> allEntities = datastore.read(query);
Iterator<I> idIterator = Streams.stream(allEntities)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@

package io.spine.server.storage.datastore;

import com.google.common.base.Objects;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Message;
import io.spine.annotation.Internal;
import io.spine.type.TypeName;
import io.spine.type.TypeUrl;
import io.spine.value.StringTypeValue;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
Expand All @@ -34,7 +34,9 @@
* A data transfer object representing a Datastore
* <a href="https://cloud.google.com/datastore/docs/concepts/entities#kinds_and_identifiers">kind</a>.
*/
public final class Kind {
public final class Kind extends StringTypeValue {

private static final long serialVersionUID = 0L;

private static final String INVALID_KIND_ERROR_MESSAGE =
"Datastore kind cannot start with \"__\". See " +
Expand All @@ -44,10 +46,8 @@ public final class Kind {

private static final String NAMESPACE_KIND = "__namespace__";

private final String value;

private Kind(String value) {
this.value = checkValidKind(value);
super(checkValidKind(value));
}

/**
Expand All @@ -59,8 +59,8 @@ private Kind(String value) {
* the flag showing that the {@code Kind} is ancillary; must be set to {@code true}
*/
private Kind(String value, boolean ancillary) {
super(value);
checkArgument(ancillary);
this.value = value;
}

public static Kind of(String value) {
Expand Down Expand Up @@ -92,30 +92,9 @@ public static Kind ofNamespace() {
return new Kind(NAMESPACE_KIND, true);
}

public String getValue() {
return value;
}

private static String checkValidKind(String kind) {
checkNotNull(kind);
checkArgument(!kind.startsWith(FORBIDDEN_PREFIX), INVALID_KIND_ERROR_MESSAGE);
return kind;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Kind kind = (Kind) o;
return Objects.equal(getValue(), kind.getValue());
}

@Override
public int hashCode() {
return Objects.hashCode(getValue());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ final class QueryWithFilter implements Function<StructuredQuery.Filter, Structur
checkNotNull(kind);

this.builder = Query.newEntityQueryBuilder()
.setKind(kind.getValue());
.setKind(kind.value());
if (format.hasOrderBy()) {
this.builder.setOrderBy(translateOrderBy(format.getOrderBy()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ private DefaultNamespaceQuery(Datastore datastore) {
@Override
public Iterator<Key> run() {
Query<Key> query = Query.newKeyQueryBuilder()
.setKind(NAMESPACE_KIND.getValue())
.setKind(NAMESPACE_KIND.value())
.build();
Iterator<Key> result = datastore.run(query);
return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
* @param <I>
* the type of the ID in the tested {@linkplain RecordStorage}
*/
public class BigDataTester<I> implements Logging {
public final class BigDataTester<I> implements Logging {

private static final int DEFAULT_BULK_SIZE = 500;

Expand All @@ -80,13 +80,14 @@ public static <I> Builder<I> newBuilder() {
*
* <p>The execution flow is as follows:
* <ol>
* <li>1. Produce the records with the given {@link EntryFactory}
* <li>2. Measure the time of the {@linkplain RecordStorage#write(Map) bulk write}
* <li>3. Fail if the time is over the specified limit
* <li>4. Wait 1 second to ensure the Datastore has established the data consistency
* <li>5. Measure the time of the {@linkplain RecordStorage#readAll() bulk read}
* <li>6. Fail if the time is over the specified limit
* <li>7. Check the count of the records written and read is equal
* <li>Produce the records with the given {@link EntryFactory}.
* <li>Measure the time of the {@linkplain RecordStorage#write(Map) bulk write}.
* <li>Fail if the time is over the specified limit.
* <li>Wait 1 second to ensure the Datastore has established the data consistency.
* <li>Measure the time of the
* {@linkplain RecordStorage#readAll(ResponseFormat) bulk read}.
* <li>Fail if the time is over the specified limit.
* <li>Check the count of the records written and read is equal.
* </ol>
*
* <p>This method performs {@code debug} logging of the measure results. To see the log, run
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,20 @@
import io.spine.server.entity.storage.ColumnType;
import io.spine.server.entity.storage.ColumnTypeRegistry;
import io.spine.server.storage.datastore.given.Columns.ByteColumnType;
import io.spine.server.storage.datastore.given.TestDatastores;
import io.spine.server.storage.datastore.type.DatastoreTypeRegistryFactory;
import io.spine.testing.server.storage.datastore.TestDatastores;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import static io.spine.server.ContextSpec.singleTenant;
import static io.spine.server.storage.datastore.given.Columns.byteColumn;
import static io.spine.server.storage.datastore.given.TestDatastores.projectId;
import static io.spine.server.storage.datastore.type.DatastoreTypeRegistryFactory.predefinedValuesAnd;
import static io.spine.testing.DisplayNames.HAVE_PARAMETERLESS_CTOR;
import static io.spine.testing.DisplayNames.NOT_ACCEPT_NULLS;
import static io.spine.testing.Tests.assertHasPrivateParameterlessCtor;
import static io.spine.testing.server.storage.datastore.TestDatastores.defaultLocalProjectId;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
Expand Down Expand Up @@ -102,7 +102,7 @@ class Namespaces {
void setUp() {
builder = DatastoreOptions
.newBuilder()
.setProjectId(projectId().getValue());
.setProjectId(defaultLocalProjectId().getValue());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@

import static com.google.common.truth.Truth.assertThat;
import static io.spine.server.ContextSpec.multitenant;
import static io.spine.server.storage.datastore.given.TestDatastores.local;
import static io.spine.server.storage.datastore.given.TestDatastores.projectId;
import static io.spine.server.tenant.TenantAwareRunner.with;
import static io.spine.testing.DisplayNames.NOT_ACCEPT_NULLS;
import static io.spine.testing.server.storage.datastore.TestDatastores.local;
import static io.spine.testing.server.storage.datastore.TestDatastores.defaultLocalProjectId;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertSame;
Expand Down Expand Up @@ -81,7 +81,8 @@ void testCreateMultitenant() {
StorageFactory factory = DatastoreStorageFactory.newBuilder()
.setDatastore(datastore)
.build();
RecordStorage storage = factory.createRecordStorage(TestEnvironment.multiTenantSpec(), TestEntity.class);
RecordStorage storage =
factory.createRecordStorage(TestEnvironment.multiTenantSpec(), TestEntity.class);
assertTrue(storage.isMultitenant());
storage.close();
}
Expand Down Expand Up @@ -176,7 +177,7 @@ private static Key.Builder whiteForTenant(DsPropertyStorage storage, TenantId te
with(tenant).run(
() -> storage.write(recordId, message)
);
return Key.newBuilder(projectId().getValue(),
return Key.newBuilder(defaultLocalProjectId().getValue(),
TypeName.of(message)
.value(),
recordId.getValue());
Expand Down
Loading

0 comments on commit e0bc530

Please sign in to comment.