use of com.amplifyframework.datastore.appsync.ModelMetadata in project amplify-android by aws-amplify.
the class SubscriptionProcessorTest method isDataMergedWhenBufferDrainedForBlogOwnerNamed.
/**
* Return whether a response with a BlogOwner with the given name gets merged with the merger.
* @param name name of the BlogOwner returned in the subscription
* @return whether the data was merged
* @throws DataStoreException On failure to arrange mocking
* @throws InterruptedException On failure to await latch
*/
private boolean isDataMergedWhenBufferDrainedForBlogOwnerNamed(String name) throws DataStoreException, InterruptedException {
// By default, start the subscriptions up.
arrangeStartedSubscriptions(appSync, modelSchemas, SubscriptionType.values());
// Arrange some subscription data
BlogOwner model = BlogOwner.builder().name(name).build();
ModelMetadata modelMetadata = new ModelMetadata(model.getId(), false, 1, Temporal.Timestamp.now());
ModelWithMetadata<BlogOwner> modelWithMetadata = new ModelWithMetadata<>(model, modelMetadata);
GraphQLResponse<ModelWithMetadata<BlogOwner>> response = new GraphQLResponse<>(modelWithMetadata, null);
arrangeDataEmittingSubscription(appSync, schemaRegistry.getModelSchemaForModelInstance(model), SubscriptionType.ON_CREATE, response);
// Merge will be invoked for the subcription data, when we start draining...
CountDownLatch latch = new CountDownLatch(1);
doAnswer(invocation -> {
latch.countDown();
return Completable.complete();
}).when(merger).merge(eq(response.getData()));
// Start draining....
subscriptionProcessor.startSubscriptions();
subscriptionProcessor.startDrainingMutationBuffer();
// Was the data merged?
return latch.await(OPERATION_TIMEOUT_MS, TimeUnit.MILLISECONDS);
}
use of com.amplifyframework.datastore.appsync.ModelMetadata in project amplify-android by aws-amplify.
the class SyncProcessorTest method randomBlogOwnerWithMetadata.
private static ModelWithMetadata<BlogOwner> randomBlogOwnerWithMetadata() {
BlogOwner blogOwner = BlogOwner.builder().name(RandomString.string()).id(RandomString.string()).build();
Temporal.Timestamp randomTimestamp = new Temporal.Timestamp(new Random().nextLong(), TimeUnit.SECONDS);
return new ModelWithMetadata<>(blogOwner, new ModelMetadata(blogOwner.getId(), null, new Random().nextInt(), randomTimestamp));
}
use of com.amplifyframework.datastore.appsync.ModelMetadata in project amplify-android by aws-amplify.
the class ConflictResolverTest method conflictIsResolvedByApplyingRemoteData.
/**
* When the user elects to apply the remote data, the following is expected:
* 1. No additional calls are made to app sync.
* @throws DataStoreException On failure to obtain configuration from provider,
* or on failure to arrange metadata into storage
*/
@Test
public void conflictIsResolvedByApplyingRemoteData() throws DataStoreException {
// The user provides a conflict handler which will always apply the remote
// copy of the data.
when(configurationProvider.getConfiguration()).thenReturn(DataStoreConfiguration.builder().conflictHandler(DataStoreConflictHandler.alwaysApplyRemote()).build());
// Arrange some local pending mutation
BlogOwner localSusan = BlogOwner.builder().name("Local Susan").build();
PendingMutation<BlogOwner> mutation = PendingMutation.update(localSusan, schema);
// Arrange some server data, that is in conflict
BlogOwner serverSusan = localSusan.copyOfBuilder().name("Remote Susan").build();
Temporal.Timestamp now = Temporal.Timestamp.now();
ModelMetadata modelMetadata = new ModelMetadata(serverSusan.getId(), false, 2, now);
ModelWithMetadata<BlogOwner> serverData = new ModelWithMetadata<>(serverSusan, modelMetadata);
// Arrange a conflict error that we could hypothetically get from AppSync
AppSyncConflictUnhandledError<BlogOwner> unhandledConflictError = AppSyncConflictUnhandledErrorFactory.createUnhandledConflictError(serverData);
// When we try to resolve the conflict, the final resolved conflict
// is identically the server's version.
resolver.resolve(mutation, unhandledConflictError).test().awaitDone(TIMEOUT_SECONDS, TimeUnit.SECONDS).assertValue(serverData);
// AppSync wasn't called, since the server was already "correct."
verifyNoInteractions(appSync);
}
use of com.amplifyframework.datastore.appsync.ModelMetadata in project amplify-android by aws-amplify.
the class ConflictResolverTest method conflictIsResolvedByRetryingLocalDataWithFlutterSerializedModel.
/**
* When the user elects to retry the mutation using the local copy of the data,
* the following is expected:
* 1. The AppSync API is invoked, with the local mutation data
* 2. We assume that the AppSync API will respond differently
* upon retry.
* @throws AmplifyException On failure to arrange metadata into storage
*/
@Test
public void conflictIsResolvedByRetryingLocalDataWithFlutterSerializedModel() throws AmplifyException {
// Arrange for the user-provided conflict handler to always request local retry.
when(configurationProvider.getConfiguration()).thenReturn(DataStoreConfiguration.builder().conflictHandler(DataStoreConflictHandler.alwaysRetryLocal()).build());
// Arrange a pending mutation that includes the local data
Map<String, Object> blogOwnerData = new HashMap<>();
blogOwnerData.put("name", "A seasoned writer");
blogOwnerData.put("id", "e50ffa8f-783b-4780-89b4-27043ffc35be");
SerializedModel serializedOwner = SerializedModel.builder().serializedData(blogOwnerData).modelSchema(schemaFrom()).build();
PendingMutation<SerializedModel> mutation = PendingMutation.update(serializedOwner, schema);
// Arrange server state for the model, in conflict to local data
Map<String, Object> serverBlogOwnerData = new HashMap<>();
serverBlogOwnerData.put("name", "A seasoned writer");
serverBlogOwnerData.put("id", "e50ffa8f-783b-4780-89b4-27043ffc35be");
SerializedModel serverModel = SerializedModel.builder().serializedData(serverBlogOwnerData).modelSchema(null).build();
Temporal.Timestamp now = Temporal.Timestamp.now();
ModelMetadata metadata = new ModelMetadata(serverModel.getId(), false, 4, now);
ModelWithMetadata<SerializedModel> serverData = new ModelWithMetadata<>(serializedOwner, metadata);
// Arrange a hypothetical conflict error from AppSync
AppSyncConflictUnhandledError<SerializedModel> unhandledConflictError = AppSyncConflictUnhandledErrorFactory.createUnhandledConflictError(serverData);
// Assume that the AppSync call succeeds this time.
ModelWithMetadata<SerializedModel> versionFromAppSyncResponse = new ModelWithMetadata<>(serializedOwner, metadata);
AppSyncMocking.update(appSync).mockSuccessResponse(serializedOwner, metadata.getVersion(), versionFromAppSyncResponse);
// Act: when the resolver is invoked, we expect the resolved version
// to include the server's metadata, but with the local data.
resolver.resolve(mutation, unhandledConflictError).test();
// The handler should have called up to AppSync to update the model
verify(appSync).update(eq(serializedOwner), any(), eq(metadata.getVersion()), any(), any());
}
use of com.amplifyframework.datastore.appsync.ModelMetadata in project amplify-android by aws-amplify.
the class MergerTest method mergeDeletionForExistingItem.
/**
* Assume there is a item A in the store. Then, we try to merge
* a mutation to delete item A. This should succeed. After the
* merge, A should NOT be in the store anymore.
* @throws DataStoreException On failure to arrange test data into store,
* or on failure to query results for test assertions
* @throws InterruptedException If interrupted while awaiting terminal result in test observer
*/
@Test
public void mergeDeletionForExistingItem() throws DataStoreException, InterruptedException {
// Arrange: A blog owner, and some metadata about it, are in the store.
BlogOwner blogOwner = BlogOwner.builder().name("Jameson").build();
ModelMetadata originalMetadata = new ModelMetadata(blogOwner.getId(), false, 1, Temporal.Timestamp.now());
storageAdapter.save(blogOwner, originalMetadata);
// Just to be sure, our arrangement worked, and that thing is in there, right? Good.
assertEquals(Collections.singletonList(blogOwner), storageAdapter.query(BlogOwner.class));
// Act: merge a model deletion.
ModelMetadata deletionMetadata = new ModelMetadata(blogOwner.getId(), true, 2, Temporal.Timestamp.now());
TestObserver<Void> observer = merger.merge(new ModelWithMetadata<>(blogOwner, deletionMetadata)).test();
assertTrue(observer.await(REASONABLE_WAIT_TIME, TimeUnit.MILLISECONDS));
observer.assertNoErrors().assertComplete();
// Assert: the blog owner is no longer in the store.
assertEquals(0, storageAdapter.query(BlogOwner.class).size());
}
Aggregations