Search in sources :

Example 1 with ModelWithMetadata

use of com.amplifyframework.datastore.appsync.ModelWithMetadata 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 ModelWithMetadata

use of com.amplifyframework.datastore.appsync.ModelWithMetadata in project amplify-android by aws-amplify.

the class SyncProcessorTest method dataStoreHubEventsTriggered.

/**
 * During a base sync, there are a series of events that should be emitted.
 * This test verifies that these events are published via Amplify Hub depending
 * on actions takes for each available model.
 * @throws DataStoreException Not expected.
 * @throws InterruptedException Not expected.
 */
@Test
public void dataStoreHubEventsTriggered() throws DataStoreException, InterruptedException {
    // Arrange - BEGIN
    int expectedModelCount = Arrays.asList(Post.class, BlogOwner.class).size();
    // Collects one syncQueriesStarted event.
    HubAccumulator syncStartAccumulator = createAccumulator(syncQueryStartedForModels(modelCount), 1);
    // Collects one syncQueriesReady event.
    HubAccumulator syncQueryReadyAccumulator = createAccumulator(forEvent(DataStoreChannelEventName.SYNC_QUERIES_READY), 1);
    // Collects one modelSynced event for each model.
    HubAccumulator modelSyncedAccumulator = createAccumulator(forEvent(DataStoreChannelEventName.MODEL_SYNCED), expectedModelCount);
    // Add a couple of seed records so they can be deleted/updated.
    storageAdapter.save(DRUM_POST.getModel());
    storageAdapter.save(BLOGGER_ISLA.getModel());
    // Mock sync query results for a couple of models.
    AppSyncMocking.sync(appSync).mockSuccessResponse(Post.class, DELETED_DRUM_POST).mockSuccessResponse(BlogOwner.class, BLOGGER_ISLA, BLOGGER_JAMESON);
    // Start the accumulators.
    syncQueryReadyAccumulator.start();
    syncStartAccumulator.start();
    modelSyncedAccumulator.start();
    TestObserver<ModelWithMetadata<? extends Model>> hydrationObserver = TestObserver.create();
    // Arrange - END
    // Act: kickoff sync.
    syncProcessor.hydrate().subscribe(hydrationObserver);
    // Check - BEGIN
    // Verify that sync completes.
    assertTrue(hydrationObserver.await(OP_TIMEOUT_MS, TimeUnit.MILLISECONDS));
    hydrationObserver.assertNoErrors();
    hydrationObserver.assertComplete();
    // Verify that syncQueriesStarted was emitted once.
    assertEquals(1, syncStartAccumulator.await((int) OP_TIMEOUT_MS, TimeUnit.MILLISECONDS).size());
    // Verify that syncQueriesReady was emitted once.
    assertEquals(1, syncQueryReadyAccumulator.await((int) OP_TIMEOUT_MS, TimeUnit.MILLISECONDS).size());
    // Get the list of modelSynced events captured.
    List<HubEvent<?>> hubEvents = modelSyncedAccumulator.await((int) OP_TIMEOUT_MS, TimeUnit.MILLISECONDS);
    // Verify that [number of events] = [number of models]
    assertEquals(expectedModelCount, hubEvents.size());
    ModelSyncedEvent expectedBlogOwnerCounts = new ModelSyncedEvent("BlogOwner", true, 1, 1, 0);
    ModelSyncedEvent expectedPostCounts = new ModelSyncedEvent("Post", true, 0, 0, 1);
    // For each event (excluding system models), verify the desired count.
    for (HubEvent<?> event : hubEvents) {
        ModelSyncedEvent eventData = (ModelSyncedEvent) event.getData();
        assertTrue(eventData.isFullSync());
        assertFalse(eventData.isDeltaSync());
        String eventModel = eventData.getModel();
        switch(eventModel) {
            case "BlogOwner":
                // One BlogOwner added and one updated.
                assertEquals(expectedBlogOwnerCounts, eventData);
                break;
            case "Post":
                // One post deleted.
                assertEquals(expectedPostCounts, eventData);
                break;
            default:
                // Exclude system models
                if (!SYSTEM_MODEL_NAMES.contains(eventModel)) {
                    ModelSyncedEvent otherCounts = new ModelSyncedEvent(eventModel, true, 0, 0, 0);
                    assertEquals(otherCounts, eventData);
                }
        }
    }
// Check - END
}
Also used : ModelWithMetadata(com.amplifyframework.datastore.appsync.ModelWithMetadata) Post(com.amplifyframework.testmodels.commentsblog.Post) Model(com.amplifyframework.core.model.Model) HubEvent(com.amplifyframework.hub.HubEvent) ModelSyncedEvent(com.amplifyframework.datastore.events.ModelSyncedEvent) BlogOwner(com.amplifyframework.testmodels.commentsblog.BlogOwner) HubAccumulator(com.amplifyframework.testutils.HubAccumulator) RandomString(com.amplifyframework.testutils.random.RandomString) Test(org.junit.Test)

Example 3 with ModelWithMetadata

use of com.amplifyframework.datastore.appsync.ModelWithMetadata 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 4 with ModelWithMetadata

use of com.amplifyframework.datastore.appsync.ModelWithMetadata 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 5 with ModelWithMetadata

use of com.amplifyframework.datastore.appsync.ModelWithMetadata 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)

Aggregations

ModelWithMetadata (com.amplifyframework.datastore.appsync.ModelWithMetadata)35 ModelMetadata (com.amplifyframework.datastore.appsync.ModelMetadata)25 Test (org.junit.Test)22 BlogOwner (com.amplifyframework.testmodels.commentsblog.BlogOwner)21 GraphQLResponse (com.amplifyframework.api.graphql.GraphQLResponse)13 ModelSchema (com.amplifyframework.core.model.ModelSchema)10 Temporal (com.amplifyframework.core.model.temporal.Temporal)10 Consumer (com.amplifyframework.core.Consumer)9 Model (com.amplifyframework.core.model.Model)9 SerializedModel (com.amplifyframework.core.model.SerializedModel)9 SchemaRegistry (com.amplifyframework.core.model.SchemaRegistry)8 HubEvent (com.amplifyframework.hub.HubEvent)8 Completable (io.reactivex.rxjava3.core.Completable)8 DataStoreException (com.amplifyframework.datastore.DataStoreException)7 AppSync (com.amplifyframework.datastore.appsync.AppSync)7 HubChannel (com.amplifyframework.hub.HubChannel)7 List (java.util.List)7 NonNull (androidx.annotation.NonNull)6 Amplify (com.amplifyframework.core.Amplify)6 ModelProvider (com.amplifyframework.core.model.ModelProvider)6