use of com.amplifyframework.api.graphql.GraphQLResponse 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.api.graphql.GraphQLResponse in project amplify-android by aws-amplify.
the class MutationProcessorTest method conflictHandlerInvokedForUnhandledConflictError.
/**
* If the AppSync response to the mutation contains a ConflictUnhandled
* error in the GraphQLResponse error list, then the user-provided
* conflict handler should be invoked.
* @throws DataStoreException On failure to obtain configuration from the provider
* @throws AmplifyException On failure to build {@link ModelSchema}
*/
@Test
public void conflictHandlerInvokedForUnhandledConflictError() throws AmplifyException {
// Arrange a user-provided conflict handler.
CountDownLatch handlerInvocationsRemainingCount = new CountDownLatch(1);
when(configurationProvider.getConfiguration()).thenReturn(DataStoreConfiguration.builder().conflictHandler((conflictData, onDecision) -> handlerInvocationsRemainingCount.countDown()).build());
// Save a model, its metadata, and its last sync data.
BlogOwner model = BlogOwner.builder().name("Exceptional Blogger").build();
ModelMetadata metadata = new ModelMetadata(model.getModelName() + "|" + model.getId(), false, 1, Temporal.Timestamp.now());
ModelSchema schema = schemaRegistry.getModelSchemaForModelClass(BlogOwner.class);
LastSyncMetadata lastSyncMetadata = LastSyncMetadata.baseSyncedAt(schema.getName(), 1_000L);
synchronousStorageAdapter.save(model, metadata, lastSyncMetadata);
// Enqueue an update in the mutation outbox
assertTrue(mutationOutbox.enqueue(PendingMutation.update(model, schema)).blockingAwait(TIMEOUT_SECONDS, TimeUnit.SECONDS));
// Fields that represent the "server's" understanding of the model state
Map<String, Object> serverModelData = new HashMap<>();
serverModelData.put("id", model.getId());
serverModelData.put("name", "Server blogger name");
serverModelData.put("_version", 1);
serverModelData.put("_deleted", false);
serverModelData.put("_lastChangedAt", 1_000);
// When AppSync receives that update, have it respond
// with a ConflictUnhandledError.
String message = "Conflict resolver rejects mutation.";
List<GraphQLPathSegment> paths = Collections.singletonList(new GraphQLPathSegment("updateBlogOwner"));
List<GraphQLLocation> locations = Collections.singletonList(new GraphQLLocation(2, 3));
Map<String, Object> extensions = new HashMap<>();
extensions.put("errorType", "ConflictUnhandled");
extensions.put("data", serverModelData);
GraphQLResponse.Error error = new GraphQLResponse.Error(message, locations, paths, extensions);
AppSyncMocking.update(appSync).mockErrorResponse(model, 1, error);
// Start the mutation processor.
mutationProcessor.startDrainingMutationOutbox();
// Wait for the conflict handler to be called.
Latch.await(handlerInvocationsRemainingCount);
}
use of com.amplifyframework.api.graphql.GraphQLResponse in project amplify-android by aws-amplify.
the class CodeGenerationInstrumentationTest method belongsToRelationship.
/**
* For a model having an {@link BelongsTo} relationship to another model, validate
* successful query, mutations, subscription.
* TODO: Add mutate with condition and list with predicate since those are the ones
* that actually use the original model name
* @throws ApiException On failure to obtain valid response from endpoint
*/
@Test
public void belongsToRelationship() throws ApiException {
// Subscribe to creation events for any Projectfields
TestObserver<GraphQLResponse<Projectfields>> observer = api.onCreate(PROJECT_API_NAME, Projectfields.class).test();
// Create a team
Team team = Team.builder().name("AWS Mobile SDK").build();
Team createdTeam = api.create(PROJECT_API_NAME, team);
// Create a Projectfields
Projectfields projectfields = Projectfields.builder().name("API Codegen").team(Team.justId(createdTeam.getId())).build();
Projectfields createdProjectfields = api.create(PROJECT_API_NAME, projectfields);
// Query for the Projectfields that were just created. The referenced team
// should be the same as the one we requested for creation, earlier.
assertEquals(team, api.get(PROJECT_API_NAME, Projectfields.class, createdProjectfields.getId()).getTeam());
// Validate that subscription received the newly created team, too.
Projectfields projectfieldsOnSubscription = observer.awaitCount(1).values().get(0).getData();
assertEquals(projectfields.getName(), projectfieldsOnSubscription.getName());
assertEquals(team, projectfieldsOnSubscription.getTeam());
// Cancel the subscription
observer.dispose();
}
use of com.amplifyframework.api.graphql.GraphQLResponse in project amplify-android by aws-amplify.
the class CodeGenerationInstrumentationTest method subscribeReceivesMutationEvent.
/**
* Tests that a subscription can receive an event when a create mutation takes place.
* @throws ApiException On failure to obtain valid response from endpoint
*/
@Test
public void subscribeReceivesMutationEvent() throws ApiException {
TestObserver<GraphQLResponse<Person>> observer = api.onCreate(PERSON_API_NAME, Person.class).test();
Person johnDoe = Person.builder().firstName("John").lastName("Doe").build();
api.create(PERSON_API_NAME, johnDoe);
// Validate that subscription received the newly created person.
Person firstPersonOnSubscription = observer.awaitCount(1).values().get(0).getData();
assertEquals(johnDoe.getFirstName(), firstPersonOnSubscription.getFirstName());
assertEquals(johnDoe.getLastName(), firstPersonOnSubscription.getLastName());
// Cancel the subscription
observer.dispose();
}
use of com.amplifyframework.api.graphql.GraphQLResponse 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;
}
Aggregations