Search in sources :

Example 1 with ModelMetadata

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);
}
Also used : ModelWithMetadata(com.amplifyframework.datastore.appsync.ModelWithMetadata) GraphQLResponse(com.amplifyframework.api.graphql.GraphQLResponse) BlogOwner(com.amplifyframework.testmodels.commentsblog.BlogOwner) CountDownLatch(java.util.concurrent.CountDownLatch) ModelMetadata(com.amplifyframework.datastore.appsync.ModelMetadata)

Example 2 with ModelMetadata

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));
}
Also used : ModelWithMetadata(com.amplifyframework.datastore.appsync.ModelWithMetadata) Temporal(com.amplifyframework.core.model.temporal.Temporal) Random(java.util.Random) BlogOwner(com.amplifyframework.testmodels.commentsblog.BlogOwner) ModelMetadata(com.amplifyframework.datastore.appsync.ModelMetadata)

Example 3 with ModelMetadata

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);
}
Also used : ModelWithMetadata(com.amplifyframework.datastore.appsync.ModelWithMetadata) Temporal(com.amplifyframework.core.model.temporal.Temporal) BlogOwner(com.amplifyframework.testmodels.commentsblog.BlogOwner) ModelMetadata(com.amplifyframework.datastore.appsync.ModelMetadata) Test(org.junit.Test)

Example 4 with ModelMetadata

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());
}
Also used : ModelWithMetadata(com.amplifyframework.datastore.appsync.ModelWithMetadata) Temporal(com.amplifyframework.core.model.temporal.Temporal) HashMap(java.util.HashMap) SerializedModel(com.amplifyframework.core.model.SerializedModel) ModelMetadata(com.amplifyframework.datastore.appsync.ModelMetadata) Test(org.junit.Test)

Example 5 with ModelMetadata

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());
}
Also used : ModelWithMetadata(com.amplifyframework.datastore.appsync.ModelWithMetadata) BlogOwner(com.amplifyframework.testmodels.commentsblog.BlogOwner) ModelMetadata(com.amplifyframework.datastore.appsync.ModelMetadata) Test(org.junit.Test)

Aggregations

ModelMetadata (com.amplifyframework.datastore.appsync.ModelMetadata)29 ModelWithMetadata (com.amplifyframework.datastore.appsync.ModelWithMetadata)23 Test (org.junit.Test)23 BlogOwner (com.amplifyframework.testmodels.commentsblog.BlogOwner)22 Temporal (com.amplifyframework.core.model.temporal.Temporal)7 GraphQLResponse (com.amplifyframework.api.graphql.GraphQLResponse)6 ModelSchema (com.amplifyframework.core.model.ModelSchema)6 HubAccumulator (com.amplifyframework.testutils.HubAccumulator)4 NonNull (androidx.annotation.NonNull)3 ApiCategory (com.amplifyframework.api.ApiCategory)3 SerializedModel (com.amplifyframework.core.model.SerializedModel)3 Person (com.amplifyframework.testmodels.personcar.Person)3 RandomString (com.amplifyframework.testutils.random.RandomString)3 SynchronousDataStore (com.amplifyframework.testutils.sync.SynchronousDataStore)3 HashMap (java.util.HashMap)3 CountDownLatch (java.util.concurrent.CountDownLatch)3 GraphQLLocation (com.amplifyframework.api.graphql.GraphQLLocation)2 GraphQLPathSegment (com.amplifyframework.api.graphql.GraphQLPathSegment)2 Amplify (com.amplifyframework.core.Amplify)2 Consumer (com.amplifyframework.core.Consumer)2