use of com.amplifyframework.datastore.appsync.ModelMetadata in project amplify-android by aws-amplify.
the class MergerTest method itemWithSameVersionIsNotMerged.
/**
* If the incoming change has the SAME version as the data currently in the DB, we refuse to update it.
* The user may have updated the data locally via the DataStore API. So we would clobber it.
* The version must be strictly HIGHER than the current version, in order for the merge to succeed.
* @throws DataStoreException On failure to interact with storage during arrange/verify
* @throws InterruptedException If interrupted while awaiting terminal result in test observer
*/
@Test
public void itemWithSameVersionIsNotMerged() throws DataStoreException, InterruptedException {
// Arrange a model and metadata into storage.
BlogOwner existingModel = BlogOwner.builder().name("Cornelius Daniels").build();
ModelMetadata existingMetadata = new ModelMetadata(existingModel.getModelName() + "|" + existingModel.getId(), false, 55, Temporal.Timestamp.now());
storageAdapter.save(existingModel, existingMetadata);
// Act: try to merge, but specify a LOWER version.
BlogOwner incomingModel = existingModel.copyOfBuilder().name("Cornelius Daniels, but woke af, now.").build();
ModelMetadata lowerVersionMetadata = new ModelMetadata(incomingModel.getId(), false, 33, Temporal.Timestamp.now());
ModelWithMetadata<BlogOwner> modelWithLowerVersionMetadata = new ModelWithMetadata<>(incomingModel, lowerVersionMetadata);
TestObserver<Void> mergeObserver = merger.merge(modelWithLowerVersionMetadata).test();
mergeObserver.await(REASONABLE_WAIT_TIME, TimeUnit.MILLISECONDS);
mergeObserver.assertNoErrors().assertComplete();
// Assert: Joey is still the same old Joey.
List<BlogOwner> actualBlogOwners = storageAdapter.query(BlogOwner.class);
assertEquals(1, actualBlogOwners.size());
assertEquals(existingModel, actualBlogOwners.get(0));
// And his metadata is the still the same.
assertEquals(Collections.singletonList(existingMetadata), storageAdapter.query(ModelMetadata.class, Where.id(existingModel.getModelName() + "|" + existingModel.getId())));
}
use of com.amplifyframework.datastore.appsync.ModelMetadata in project amplify-android by aws-amplify.
the class MergerTest method mergeSaveForExistingItem.
/**
* Assume there is an item A in the store. We try to merge a save for A.
* This should succeed, and it should be treated as an update. After the merge,
* A should have the updates from the merge.
* @throws DataStoreException On failure to arrange data into store
* @throws InterruptedException If interrupted while awaiting terminal result in test observer
*/
@Test
public void mergeSaveForExistingItem() throws DataStoreException, InterruptedException {
// Arrange: an item is already in the store.
BlogOwner originalModel = BlogOwner.builder().name("Jameson The Original").build();
ModelMetadata originalMetadata = new ModelMetadata(originalModel.getModelName() + "|" + originalModel.getId(), false, 1, Temporal.Timestamp.now());
storageAdapter.save(originalModel, originalMetadata);
// Act: merge a save.
BlogOwner updatedModel = originalModel.copyOfBuilder().name("Jameson The New and Improved").build();
ModelMetadata updatedMetadata = new ModelMetadata(originalMetadata.getId(), false, 2, Temporal.Timestamp.now());
TestObserver<Void> observer = merger.merge(new ModelWithMetadata<>(updatedModel, updatedMetadata)).test();
assertTrue(observer.await(REASONABLE_WAIT_TIME, TimeUnit.MILLISECONDS));
observer.assertComplete().assertNoErrors();
// Assert: the *UPDATED* stuff is in the store, *only*.
assertEquals(Collections.singletonList(updatedModel), storageAdapter.query(BlogOwner.class));
assertEquals(Collections.singletonList(updatedMetadata), storageAdapter.query(ModelMetadata.class));
}
use of com.amplifyframework.datastore.appsync.ModelMetadata in project amplify-android by aws-amplify.
the class MergerTest method mergeSaveForNotExistingItem.
/**
* Assume there is NO item A. Then, we try to merge a save for a
* item A. This should succeed, with A being in the store, at the end.
* @throws DataStoreException On failure to query results for assertions
* @throws InterruptedException If interrupted while awaiting terminal result in test observer
*/
@Test
public void mergeSaveForNotExistingItem() throws DataStoreException, InterruptedException {
// Arrange: nothing in the store, to start.
BlogOwner blogOwner = BlogOwner.builder().name("Jameson").build();
ModelMetadata metadata = new ModelMetadata(blogOwner.getModelName() + "|" + blogOwner.getId(), false, 1, Temporal.Timestamp.now());
// Note that storageAdapter.save(...) is NOT called!
// storageAdapter.save(blogOwner, metadata);
// Act: merge a creation for an item
TestObserver<Void> observer = merger.merge(new ModelWithMetadata<>(blogOwner, metadata)).test();
assertTrue(observer.await(REASONABLE_WAIT_TIME, TimeUnit.MILLISECONDS));
observer.assertNoErrors().assertComplete();
// Assert: the item & its associated metadata are now in the store.
assertEquals(Collections.singletonList(blogOwner), storageAdapter.query(BlogOwner.class));
assertEquals(Collections.singletonList(metadata), storageAdapter.query(ModelMetadata.class));
}
use of com.amplifyframework.datastore.appsync.ModelMetadata in project amplify-android by aws-amplify.
the class MergerTest method itemWithLowerVersionIsNotMerged.
/**
* An incoming mutation whose model has a LOWER version than an already existing model
* shall be rejected from the merger.
* @throws DataStoreException On failure interacting with local store during test arrange/verify.
* @throws InterruptedException If interrupted while awaiting terminal result in test observer
*/
@Test
public void itemWithLowerVersionIsNotMerged() throws DataStoreException, InterruptedException {
// Arrange a model and metadata into storage.
BlogOwner existingModel = BlogOwner.builder().name("Cornelius Daniels").build();
ModelMetadata existingMetadata = new ModelMetadata(existingModel.getId(), false, 55, Temporal.Timestamp.now());
storageAdapter.save(existingModel, existingMetadata);
// Act: try to merge, but specify a LOWER version.
BlogOwner incomingModel = existingModel.copyOfBuilder().name("Cornelius Daniels, but woke af, now.").build();
ModelMetadata lowerVersionMetadata = new ModelMetadata(incomingModel.getId(), false, 33, Temporal.Timestamp.now());
ModelWithMetadata<BlogOwner> modelWithLowerVersionMetadata = new ModelWithMetadata<>(existingModel, lowerVersionMetadata);
TestObserver<Void> mergeObserver = merger.merge(modelWithLowerVersionMetadata).test();
mergeObserver.await(REASONABLE_WAIT_TIME, TimeUnit.MILLISECONDS);
mergeObserver.assertNoErrors().assertComplete();
// Assert: Joey is still the same old Joey.
assertEquals(Collections.singletonList(existingModel), storageAdapter.query(BlogOwner.class));
// And his metadata is the still the same.
assertEquals(Collections.singletonList(existingMetadata), storageAdapter.query(ModelMetadata.class, Where.id(existingModel.getId())));
}
use of com.amplifyframework.datastore.appsync.ModelMetadata in project amplify-android by aws-amplify.
the class MutationProcessorTest method conflictHandlerInvokedForUnhandledConflictError.
/**
* If the AppSync response to the mutation contains a ConflictUnhandled
* error in the GraphQLResponse error list, then the user-provided
* conflict handler should be invoked.
* @throws DataStoreException On failure to obtain configuration from the provider
* @throws AmplifyException On failure to build {@link ModelSchema}
*/
@Test
public void conflictHandlerInvokedForUnhandledConflictError() throws AmplifyException {
// Arrange a user-provided conflict handler.
CountDownLatch handlerInvocationsRemainingCount = new CountDownLatch(1);
when(configurationProvider.getConfiguration()).thenReturn(DataStoreConfiguration.builder().conflictHandler((conflictData, onDecision) -> handlerInvocationsRemainingCount.countDown()).build());
// Save a model, its metadata, and its last sync data.
BlogOwner model = BlogOwner.builder().name("Exceptional Blogger").build();
ModelMetadata metadata = new ModelMetadata(model.getModelName() + "|" + model.getId(), false, 1, Temporal.Timestamp.now());
ModelSchema schema = schemaRegistry.getModelSchemaForModelClass(BlogOwner.class);
LastSyncMetadata lastSyncMetadata = LastSyncMetadata.baseSyncedAt(schema.getName(), 1_000L);
synchronousStorageAdapter.save(model, metadata, lastSyncMetadata);
// Enqueue an update in the mutation outbox
assertTrue(mutationOutbox.enqueue(PendingMutation.update(model, schema)).blockingAwait(TIMEOUT_SECONDS, TimeUnit.SECONDS));
// Fields that represent the "server's" understanding of the model state
Map<String, Object> serverModelData = new HashMap<>();
serverModelData.put("id", model.getId());
serverModelData.put("name", "Server blogger name");
serverModelData.put("_version", 1);
serverModelData.put("_deleted", false);
serverModelData.put("_lastChangedAt", 1_000);
// When AppSync receives that update, have it respond
// with a ConflictUnhandledError.
String message = "Conflict resolver rejects mutation.";
List<GraphQLPathSegment> paths = Collections.singletonList(new GraphQLPathSegment("updateBlogOwner"));
List<GraphQLLocation> locations = Collections.singletonList(new GraphQLLocation(2, 3));
Map<String, Object> extensions = new HashMap<>();
extensions.put("errorType", "ConflictUnhandled");
extensions.put("data", serverModelData);
GraphQLResponse.Error error = new GraphQLResponse.Error(message, locations, paths, extensions);
AppSyncMocking.update(appSync).mockErrorResponse(model, 1, error);
// Start the mutation processor.
mutationProcessor.startDrainingMutationOutbox();
// Wait for the conflict handler to be called.
Latch.await(handlerInvocationsRemainingCount);
}
Aggregations