use of com.amplifyframework.testutils.HubAccumulator in project amplify-android by aws-amplify.
the class MutationProcessorTest method canDrainMutationOutboxOnPublicationError.
/**
* If error is caused by AppSync response, then the mutation outbox continues to
* drain without getting blocked.
* @throws DataStoreException On failure to save models
*/
@Test
public void canDrainMutationOutboxOnPublicationError() throws DataStoreException {
ModelSchema schema = schemaRegistry.getModelSchemaForModelClass(BlogOwner.class);
// We will attempt to "sync" 10 models.
final int maxAttempts = 10;
for (int attempt = 0; attempt < maxAttempts; attempt++) {
BlogOwner model = BlogOwner.builder().name("Blogger #" + attempt).build();
synchronousStorageAdapter.save(model);
// Every other model triggers an AppSync error response.
if (attempt % 2 == 0) {
AppSyncMocking.create(appSync).mockErrorResponse(model);
} else {
AppSyncMocking.create(appSync).mockSuccessResponse(model);
}
// Enqueue a creation in the mutation outbox
assertTrue(mutationOutbox.enqueue(PendingMutation.creation(model, schema)).blockingAwait(TIMEOUT_SECONDS, TimeUnit.SECONDS));
}
// Start listening for Mutation Outbox Empty event.
HubAccumulator accumulator = HubAccumulator.create(HubChannel.DATASTORE, isOutboxEmpty(true), 1).start();
// Start draining the outbox.
mutationProcessor.startDrainingMutationOutbox();
accumulator.await();
}
use of com.amplifyframework.testutils.HubAccumulator in project amplify-android by aws-amplify.
the class HybridOfflineInstrumentationTest method setupPlugin.
/**
* Configures an AWSDataStorePlugin which only operates offline (not connected to any remote backend),
* and is able to warehouse the commentsblog family of models.
* @throws AmplifyException In a variety of scenarios where setup fails
*/
@Before
public void setupPlugin() throws AmplifyException {
blogOwnerSchema = schemaFrom("schemas/commentsblog/blog-owner.json");
blogSchema = schemaFrom("schemas/commentsblog/blog.json");
SchemaProvider schemaProvider = SchemaProvider.of(blogOwnerSchema, blogSchema);
getApplicationContext().deleteDatabase("AmplifyDatastore.db");
StrictMode.enable();
Amplify.addPlugin(new AndroidLoggingPlugin(LogLevel.VERBOSE));
HubAccumulator initializationObserver = HubAccumulator.create(HubChannel.DATASTORE, InitializationStatus.SUCCEEDED, 1).start();
AWSDataStorePlugin plugin = AWSDataStorePlugin.builder().modelProvider(schemaProvider).build();
DataStoreCategory dataStoreCategory = new DataStoreCategory();
dataStoreCategory.addPlugin(plugin);
dataStoreCategory.configure(new DataStoreCategoryConfiguration(), getApplicationContext());
dataStoreCategory.initialize(getApplicationContext());
initializationObserver.await(TIMEOUT_SECONDS, TimeUnit.SECONDS);
hybridBehaviors = SynchronousHybridBehaviors.delegatingTo(plugin);
normalBehaviors = SynchronousDataStore.delegatingTo(plugin);
}
use of com.amplifyframework.testutils.HubAccumulator in project amplify-android by aws-amplify.
the class HybridTemporalSyncInstrumentationTest method temporalTypesAreSyncedUpToCloud.
/**
* It is possible to dispatch a model that contain temporal types. After publishing
* such a model to the cloud, we can query AppSync and find it there.
* @throws ApiException on failure to communicate with AppSync API in verification phase of test
*/
@Ignore("It passes. Not automating due to operational concerns as noted in class-level @Ignore.")
@Test
public void temporalTypesAreSyncedUpToCloud() throws ApiException {
// Prepare a SerializedModel that we will save to DataStore.
Meeting meeting = createMeeting();
Map<String, Object> sentData = toMap(meeting);
SerializedModel sentModel = SerializedModel.builder().serializedData(sentData).modelSchema(modelSchema).build();
HubAccumulator publicationAccumulator = HubAccumulator.create(HubChannel.DATASTORE, publicationOf(modelSchema.getName(), sentModel.getId()), 1).start();
hybridBehaviors.save(sentModel);
publicationAccumulator.await(TIMEOUT_SECONDS, TimeUnit.SECONDS);
// Retrieve the model from AppSync.
Meeting remoteMeeting = api.get(Meeting.class, sentModel.getId());
// Inspect the fields of the data in AppSync, and prepare it into a map
// that we can compare with what we sent. Are they the same? They should be.
assertEquals(sentData, toMap(remoteMeeting));
}
use of com.amplifyframework.testutils.HubAccumulator in project amplify-android by aws-amplify.
the class AWSDataStorePluginTest method clearStopsSyncAndDeletesDatabase.
/**
* Verify that when the clear method is called, the following happens
* - All remote synchronization processes are stopped
* - The database is deleted.
* - On the next interaction with the DataStore, the synchronization processes are restarted.
* @throws JSONException on failure to arrange plugin config
* @throws AmplifyException on failure to arrange API plugin via Amplify facade
*/
@Test
public void clearStopsSyncAndDeletesDatabase() throws AmplifyException, JSONException {
ApiCategory mockApiCategory = mockApiCategoryWithGraphQlApi();
ApiPlugin<?> mockApiPlugin = mockApiCategory.getPlugin(MOCK_API_PLUGIN_NAME);
JSONObject dataStorePluginJson = new JSONObject().put("syncIntervalInMinutes", 60);
AWSDataStorePlugin awsDataStorePlugin = AWSDataStorePlugin.builder().modelProvider(modelProvider).apiCategory(mockApiCategory).build();
SynchronousDataStore synchronousDataStore = SynchronousDataStore.delegatingTo(awsDataStorePlugin);
awsDataStorePlugin.configure(dataStorePluginJson, context);
awsDataStorePlugin.initialize(context);
// Trick the DataStore since it's not getting initialized as part of the Amplify.initialize call chain
Amplify.Hub.publish(HubChannel.DATASTORE, HubEvent.create(InitializationStatus.SUCCEEDED));
// Setup objects
Person person1 = createPerson("Test", "Dummy I");
Person person2 = createPerson("Test", "Dummy II");
// Mock responses for person 1
doAnswer(invocation -> {
int indexOfResponseConsumer = 1;
Consumer<GraphQLResponse<ModelWithMetadata<Person>>> onResponse = invocation.getArgument(indexOfResponseConsumer);
ModelMetadata modelMetadata = new ModelMetadata(person1.getId(), false, 1, Temporal.Timestamp.now());
ModelWithMetadata<Person> modelWithMetadata = new ModelWithMetadata<>(person1, modelMetadata);
onResponse.accept(new GraphQLResponse<>(modelWithMetadata, Collections.emptyList()));
return mock(GraphQLOperation.class);
}).when(mockApiPlugin).mutate(any(), any(), any());
HubAccumulator apiInteractionObserver = HubAccumulator.create(HubChannel.DATASTORE, DataStoreChannelEventName.OUTBOX_MUTATION_PROCESSED, 1).start();
// Save person 1
synchronousDataStore.save(person1);
Person result1 = synchronousDataStore.get(Person.class, person1.getId());
assertEquals(person1, result1);
apiInteractionObserver.await();
verify(mockApiCategory).mutate(argThat(getMatcherFor(person1)), any(), any());
// Mock responses for person 2
doAnswer(invocation -> {
int indexOfResponseConsumer = 1;
Consumer<GraphQLResponse<ModelWithMetadata<Person>>> onResponse = invocation.getArgument(indexOfResponseConsumer);
ModelMetadata modelMetadata = new ModelMetadata(person2.getId(), false, 1, Temporal.Timestamp.now());
ModelWithMetadata<Person> modelWithMetadata = new ModelWithMetadata<>(person2, modelMetadata);
onResponse.accept(new GraphQLResponse<>(modelWithMetadata, Collections.emptyList()));
return mock(GraphQLOperation.class);
}).when(mockApiPlugin).mutate(any(), any(), any());
// Do the thing!
synchronousDataStore.clear();
assertRemoteSubscriptionsCancelled();
apiInteractionObserver = HubAccumulator.create(HubChannel.DATASTORE, DataStoreChannelEventName.OUTBOX_MUTATION_PROCESSED, 1).start();
HubAccumulator orchestratorInitObserver = HubAccumulator.create(HubChannel.DATASTORE, DataStoreChannelEventName.READY, 1).start();
// Interact with the DataStore after the clear
synchronousDataStore.save(person2);
// Verify person 2 was published to the cloud
apiInteractionObserver.await();
// Verify the orchestrator started back up and subscriptions are active.
orchestratorInitObserver.await();
assertRemoteSubscriptionsStarted();
Person result2 = synchronousDataStore.get(Person.class, person2.getId());
assertEquals(person2, result2);
verify(mockApiCategory, atLeastOnce()).mutate(argThat(getMatcherFor(person2)), any(), any());
}
use of com.amplifyframework.testutils.HubAccumulator in project amplify-android by aws-amplify.
the class AWSDataStorePluginTest method stopStopsSyncUntilNextInteraction.
/**
* Verify that when the stop method is called, the following happens
* - All remote synchronization processes are stopped
* - On the next interaction with the DataStore, the synchronization processes are restarted.
* @throws JSONException on failure to arrange plugin config
* @throws AmplifyException on failure to arrange API plugin via Amplify facade
*/
@Test
public void stopStopsSyncUntilNextInteraction() throws AmplifyException, JSONException {
ApiCategory mockApiCategory = mockApiCategoryWithGraphQlApi();
ApiPlugin<?> mockApiPlugin = mockApiCategory.getPlugin(MOCK_API_PLUGIN_NAME);
JSONObject dataStorePluginJson = new JSONObject().put("syncIntervalInMinutes", 60);
AWSDataStorePlugin awsDataStorePlugin = AWSDataStorePlugin.builder().modelProvider(modelProvider).apiCategory(mockApiCategory).build();
SynchronousDataStore synchronousDataStore = SynchronousDataStore.delegatingTo(awsDataStorePlugin);
awsDataStorePlugin.configure(dataStorePluginJson, context);
awsDataStorePlugin.initialize(context);
// Trick the DataStore since it's not getting initialized as part of the Amplify.initialize call chain
Amplify.Hub.publish(HubChannel.DATASTORE, HubEvent.create(InitializationStatus.SUCCEEDED));
// Setup objects
Person person1 = createPerson("Test", "Dummy I");
Person person2 = createPerson("Test", "Dummy II");
// Mock responses for person 1
doAnswer(invocation -> {
int indexOfResponseConsumer = 1;
Consumer<GraphQLResponse<ModelWithMetadata<Person>>> onResponse = invocation.getArgument(indexOfResponseConsumer);
ModelMetadata modelMetadata = new ModelMetadata(person1.getId(), false, 1, Temporal.Timestamp.now());
ModelWithMetadata<Person> modelWithMetadata = new ModelWithMetadata<>(person1, modelMetadata);
onResponse.accept(new GraphQLResponse<>(modelWithMetadata, Collections.emptyList()));
return mock(GraphQLOperation.class);
}).when(mockApiPlugin).mutate(any(), any(), any());
HubAccumulator apiInteractionObserver = HubAccumulator.create(HubChannel.DATASTORE, DataStoreChannelEventName.OUTBOX_MUTATION_PROCESSED, 1).start();
// Save person 1
synchronousDataStore.save(person1);
Person result1 = synchronousDataStore.get(Person.class, person1.getId());
assertEquals(person1, result1);
apiInteractionObserver.await();
verify(mockApiCategory).mutate(argThat(getMatcherFor(person1)), any(), any());
// Mock responses for person 2
doAnswer(invocation -> {
int indexOfResponseConsumer = 1;
Consumer<GraphQLResponse<ModelWithMetadata<Person>>> onResponse = invocation.getArgument(indexOfResponseConsumer);
ModelMetadata modelMetadata = new ModelMetadata(person2.getId(), false, 1, Temporal.Timestamp.now());
ModelWithMetadata<Person> modelWithMetadata = new ModelWithMetadata<>(person2, modelMetadata);
onResponse.accept(new GraphQLResponse<>(modelWithMetadata, Collections.emptyList()));
return mock(GraphQLOperation.class);
}).when(mockApiPlugin).mutate(any(), any(), any());
// Do the thing!
synchronousDataStore.stop();
assertRemoteSubscriptionsCancelled();
apiInteractionObserver = HubAccumulator.create(HubChannel.DATASTORE, DataStoreChannelEventName.OUTBOX_MUTATION_PROCESSED, 1).start();
HubAccumulator orchestratorInitObserver = HubAccumulator.create(HubChannel.DATASTORE, DataStoreChannelEventName.READY, 1).start();
// Interact with the DataStore after the stop
synchronousDataStore.save(person2);
// Verify person 2 was published to the cloud
apiInteractionObserver.await();
// Verify the orchestrator started back up and subscriptions are active.
orchestratorInitObserver.await();
assertRemoteSubscriptionsStarted();
// Verify person 1 and 2 are in the DataStore
List<Person> results = synchronousDataStore.list(Person.class);
assertEquals(Arrays.asList(person1, person2), results);
verify(mockApiCategory, atLeastOnce()).mutate(argThat(getMatcherFor(person2)), any(), any());
}
Aggregations