use of com.amplifyframework.datastore.appsync.ModelMetadata in project amplify-android by aws-amplify.
the class MutationProcessorTest method hubEventPublishedForPublicationError.
/**
* If the AppSync response to the mutation contains not-empty GraphQLResponse error
* list without any ConflictUnhandled error, then
* {@link DataStoreChannelEventName#OUTBOX_MUTATION_FAILED} event is published via Hub.
* @throws DataStoreException On failure to save model and metadata
*/
@Test
public void hubEventPublishedForPublicationError() throws DataStoreException {
// Save a model, its metadata, and its last sync data.
BlogOwner model = BlogOwner.builder().name("Average Joe").build();
ModelMetadata metadata = new ModelMetadata(model.getModelName() + "|" + model.getId(), false, 1, Temporal.Timestamp.now());
ModelSchema schema = schemaRegistry.getModelSchemaForModelClass(BlogOwner.class);
synchronousStorageAdapter.save(model, metadata);
// Enqueue an update in the mutation outbox
assertTrue(mutationOutbox.enqueue(PendingMutation.update(model, schema)).blockingAwait(TIMEOUT_SECONDS, TimeUnit.SECONDS));
// When AppSync receives that update, have it respond with an error.
AppSyncMocking.update(appSync).mockErrorResponse(model, 1);
// Start listening for publication events.
HubAccumulator errorAccumulator = HubAccumulator.create(HubChannel.DATASTORE, DataStoreChannelEventName.OUTBOX_MUTATION_FAILED, 1).start();
// Start the mutation processor and wait for hub event.
mutationProcessor.startDrainingMutationOutbox();
errorAccumulator.await();
}
use of com.amplifyframework.datastore.appsync.ModelMetadata in project amplify-android by aws-amplify.
the class VersionRepositoryTest method emitsSuccessWithValueWhenVersionInStore.
/**
* When there is metadata for a model in the store, and that metadata includes a version -
* for heaven's sake, man - do please emit the dang thing.
* @throws DataStoreException On failure to arrange data into store
* @throws InterruptedException If interrupted while awaiting terminal result in test observer
*/
@Test
public void emitsSuccessWithValueWhenVersionInStore() throws DataStoreException, InterruptedException {
// Arrange versioning info into the store.
BlogOwner owner = BlogOwner.builder().name("Jameson").build();
final int maxRandomVersion = 1_000;
int expectedVersion = new Random().nextInt(maxRandomVersion);
storageAdapter.save(new ModelMetadata(owner.getModelName() + "|" + owner.getId(), false, expectedVersion, Temporal.Timestamp.now()));
// Act! Try to obtain it via the Versioning Repository.
TestObserver<Integer> observer = versionRepository.findModelVersion(owner).test();
assertTrue(observer.await(REASONABLE_WAIT_TIME, TimeUnit.MILLISECONDS));
// Assert: we got a version.
observer.assertNoErrors().assertComplete().assertValue(expectedVersion);
}
use of com.amplifyframework.datastore.appsync.ModelMetadata in project amplify-android by aws-amplify.
the class ConflictResolverIntegrationTest method setupApiMock.
@SuppressWarnings("unchecked")
private Person setupApiMock(CountDownLatch latch, ApiCategory mockApiCategory) {
Person person1 = createPerson("Test", "Dummy I");
// Mock success on subscription.
doAnswer(invocation -> {
int indexOfStartConsumer = 1;
Consumer<String> onStart = invocation.getArgument(indexOfStartConsumer);
GraphQLOperation<?> mockOperation = mock(GraphQLOperation.class);
doAnswer(opAnswer -> {
return null;
}).when(mockOperation).cancel();
// Trigger the subscription start event.
onStart.accept(RandomString.string());
return mockOperation;
}).when(mockApiCategory).subscribe(any(GraphQLRequest.class), any(Consumer.class), any(Consumer.class), any(Consumer.class), any(Action.class));
// When mutate is called on the appsync for the first time unhandled conflict error is returned.
doAnswer(invocation -> {
int indexOfResponseConsumer = 1;
Consumer<GraphQLResponse<ModelWithMetadata<Person>>> onResponse = invocation.getArgument(indexOfResponseConsumer);
List<GraphQLLocation> locations = new ArrayList<>();
locations.add(new GraphQLLocation(2, 3));
List<GraphQLPathSegment> path = new ArrayList<>();
path.add(new GraphQLPathSegment("updatePost"));
Map<String, Object> serverModelData = new HashMap<>();
serverModelData.put("id", "5c895eae-88ef-4ce8-9d58-e27d0c7cbe99");
serverModelData.put("createdAt", "2022-02-04T19:41:05.973Z");
serverModelData.put("first_name", "test");
serverModelData.put("last_name", "server last");
serverModelData.put("_version", 92);
serverModelData.put("_deleted", false);
serverModelData.put("_lastChangedAt", 1_000);
Map<String, Object> extensions = new HashMap<>();
extensions.put("errorInfo", null);
extensions.put("data", serverModelData);
extensions.put("errorType", "ConflictUnhandled");
ArrayList<GraphQLResponse.Error> errorList = new ArrayList<>();
errorList.add(new GraphQLResponse.Error("Conflict resolver rejects mutation.", locations, path, extensions));
onResponse.accept(new GraphQLResponse<>(null, errorList));
// latch makes sure conflict unhandled response is returned.
latch.countDown();
return mock(GraphQLOperation.class);
}).doAnswer(invocation -> {
// When mutate is called on the appsync for the second time success response is returned
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()));
verify(mockApiCategory, atLeast(2)).mutate(argThat(getMatcherFor(person1)), any(), any());
// latch makes sure success response is returned.
latch.countDown();
return mock(GraphQLOperation.class);
}).when(mockApiCategory).mutate(any(), any(), any());
// Setup to mimic successful sync
doAnswer(invocation -> {
int indexOfResponseConsumer = 1;
ModelMetadata modelMetadata = new ModelMetadata(person1.getId(), false, 1, Temporal.Timestamp.now());
ModelWithMetadata<Person> modelWithMetadata = new ModelWithMetadata<>(person1, modelMetadata);
// Mock the API emitting an ApiEndpointStatusChangeEvent event.
Consumer<GraphQLResponse<PaginatedResult<ModelWithMetadata<Person>>>> onResponse = invocation.getArgument(indexOfResponseConsumer);
PaginatedResult<ModelWithMetadata<Person>> data = new PaginatedResult<>(Collections.singletonList(modelWithMetadata), null);
onResponse.accept(new GraphQLResponse<>(data, Collections.emptyList()));
latch.countDown();
return mock(GraphQLOperation.class);
}).doAnswer(invocation -> {
int indexOfResponseConsumer = 1;
Car car = Car.builder().build();
ModelMetadata modelMetadata = new ModelMetadata(car.getId(), false, 1, Temporal.Timestamp.now());
ModelWithMetadata<Car> modelWithMetadata = new ModelWithMetadata<>(car, modelMetadata);
Consumer<GraphQLResponse<PaginatedResult<ModelWithMetadata<Car>>>> onResponse = invocation.getArgument(indexOfResponseConsumer);
PaginatedResult<ModelWithMetadata<Car>> data = new PaginatedResult<>(Collections.singletonList(modelWithMetadata), null);
onResponse.accept(new GraphQLResponse<>(data, Collections.emptyList()));
latch.countDown();
return mock(GraphQLOperation.class);
}).when(mockApiCategory).query(any(), any(), any());
return person1;
}
use of com.amplifyframework.datastore.appsync.ModelMetadata in project amplify-android by aws-amplify.
the class OutboxMutationEvent method create.
/**
* Constructs an outbox mutation event containing both the model and its
* sync metadata.
* This format will be used for representing a pending mutation that has
* successfully undergone cloud publication.
* @param modelName Name of the model that has been processed (e.g., "Blog".)
* @param modelWithMetadata Processed model with its sync metadata.
* @param <M> Class type of the model.
* @return Outbox mutation event with sync metadata.
*/
@NonNull
public static <M extends Model> OutboxMutationEvent<M> create(@NonNull String modelName, @NonNull ModelWithMetadata<M> modelWithMetadata) {
Objects.requireNonNull(modelName);
Objects.requireNonNull(modelWithMetadata);
M model = modelWithMetadata.getModel();
ModelMetadata metadata = modelWithMetadata.getSyncMetadata();
Integer version = metadata.getVersion();
Long lastChangedAt = metadata.getLastChangedAt() != null ? metadata.getLastChangedAt().getSecondsSinceEpoch() : null;
Boolean deleted = metadata.isDeleted();
OutboxMutationEventElement<M> element = new OutboxMutationEventElement<>(model, version, lastChangedAt, deleted);
return new OutboxMutationEvent<>(modelName, element);
}
use of com.amplifyframework.datastore.appsync.ModelMetadata in project amplify-android by aws-amplify.
the class BasicCloudSyncInstrumentationTest method syncDownFromCloudIsWorking.
/**
* The sync engine should receive mutations for its managed models, through its
* subscriptions. When we create a model remotely, the sync engine should respond
* by processing the subscription event and saving the model locally.
* @throws DataStoreException On failure to query the local data store for
* local presence of arranged data (second step)
* @throws AmplifyException On failure to arrange a {@link DataStoreCategory} via the
* {@link DataStoreCategoryConfigurator}
*/
@Test
public void syncDownFromCloudIsWorking() throws AmplifyException {
// This model will get saved to the cloud.
BlogOwner jameson = BlogOwner.builder().name("Jameson Williams").build();
// Start watching locally, to see if it shows up on the client.
HubAccumulator receiptAccumulator = HubAccumulator.create(HubChannel.DATASTORE, receiptOf(jameson.getId()), 1).start();
// Act: create the model in the cloud
ModelSchema schema = ModelSchema.fromModelClass(BlogOwner.class);
GraphQLResponse<ModelWithMetadata<BlogOwner>> createResponse = appSync.create(jameson, schema);
ModelMetadata metadata = createResponse.getData().getSyncMetadata();
assertEquals(Integer.valueOf(1), metadata.getVersion());
// Wait for the events to show up on Hub.
receiptAccumulator.awaitFirst(TIMEOUT_SECONDS, TimeUnit.SECONDS);
// Jameson should be in the local DataStore.
BlogOwner owner = dataStore.get(BlogOwner.class, jameson.getId());
assertEquals("Jameson Williams", owner.getName());
assertEquals(jameson.getId(), owner.getId());
}
Aggregations