Search in sources :

Example 1 with PaginatedResult

use of com.amplifyframework.api.graphql.PaginatedResult in project amplify-android by aws-amplify.

the class AppSyncMockingTest method mockFailureForSync.

/**
 * When mockFailure() is called on the SyncConfigurator, the AppSync mock
 * will emit the provided failure.
 * @throws DataStoreException On failure to get a SyncConfigurator via sync()
 */
@Test
public void mockFailureForSync() throws DataStoreException {
    DataStoreException failure = new DataStoreException("Foo", "Bar");
    AppSyncMocking.sync(appSync).mockFailure(failure);
    GraphQLRequest<PaginatedResult<ModelWithMetadata<BlogOwner>>> request = appSync.buildSyncRequest(schema, null, 100, QueryPredicates.all());
    Single.create(emitter -> appSync.sync(request, emitter::onSuccess, emitter::onError)).test().awaitDone(TIMEOUT_SECONDS, TimeUnit.SECONDS).assertError(failure);
}
Also used : Arrays(java.util.Arrays) Single(io.reactivex.rxjava3.core.Single) SyncConfigurator(com.amplifyframework.datastore.appsync.AppSyncMocking.SyncConfigurator) AmplifyException(com.amplifyframework.AmplifyException) QueryPredicates(com.amplifyframework.core.model.query.predicate.QueryPredicates) GraphQLRequest(com.amplifyframework.api.graphql.GraphQLRequest) BlogOwner(com.amplifyframework.testmodels.commentsblog.BlogOwner) Test(org.junit.Test) Completable(io.reactivex.rxjava3.core.Completable) HashSet(java.util.HashSet) TimeUnit(java.util.concurrent.TimeUnit) DataStoreException(com.amplifyframework.datastore.DataStoreException) Consumer(com.amplifyframework.core.Consumer) Observable(io.reactivex.rxjava3.core.Observable) ModelSchema(com.amplifyframework.core.model.ModelSchema) GraphQLResponse(com.amplifyframework.api.graphql.GraphQLResponse) Temporal(com.amplifyframework.core.model.temporal.Temporal) PaginatedResult(com.amplifyframework.api.graphql.PaginatedResult) NoOpAction(com.amplifyframework.core.NoOpAction) NoOpConsumer(com.amplifyframework.core.NoOpConsumer) Collections(java.util.Collections) Before(org.junit.Before) Mockito.mock(org.mockito.Mockito.mock) DataStoreException(com.amplifyframework.datastore.DataStoreException) PaginatedResult(com.amplifyframework.api.graphql.PaginatedResult) BlogOwner(com.amplifyframework.testmodels.commentsblog.BlogOwner) Test(org.junit.Test)

Example 2 with PaginatedResult

use of com.amplifyframework.api.graphql.PaginatedResult 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;
}
Also used : AmplifyException(com.amplifyframework.AmplifyException) ApplicationProvider.getApplicationContext(androidx.test.core.app.ApplicationProvider.getApplicationContext) ArgumentMatchers.argThat(org.mockito.ArgumentMatchers.argThat) ModelWithMetadata(com.amplifyframework.datastore.appsync.ModelWithMetadata) ModelProvider(com.amplifyframework.core.model.ModelProvider) GraphQLPathSegment(com.amplifyframework.api.graphql.GraphQLPathSegment) ApiChannelEventName(com.amplifyframework.api.events.ApiChannelEventName) ArgumentMatcher(org.mockito.ArgumentMatcher) JSONException(org.json.JSONException) JSONObject(org.json.JSONObject) GraphQLLocation(com.amplifyframework.api.graphql.GraphQLLocation) Map(java.util.Map) Mockito.doAnswer(org.mockito.Mockito.doAnswer) Mockito.atLeast(org.mockito.Mockito.atLeast) GraphQLResponse(com.amplifyframework.api.graphql.GraphQLResponse) Assert.fail(org.junit.Assert.fail) HubEvent(com.amplifyframework.hub.HubEvent) HubChannel(com.amplifyframework.hub.HubChannel) ApiCategory(com.amplifyframework.api.ApiCategory) InitializationStatus(com.amplifyframework.core.InitializationStatus) RobolectricTestRunner(org.robolectric.RobolectricTestRunner) Person(com.amplifyframework.testmodels.personcar.Person) CountDownLatch(java.util.concurrent.CountDownLatch) List(java.util.List) RandomString(com.amplifyframework.testutils.random.RandomString) Mockito.any(org.mockito.Mockito.any) Mockito.mock(org.mockito.Mockito.mock) Context(android.content.Context) GraphQLRequest(com.amplifyframework.api.graphql.GraphQLRequest) RunWith(org.junit.runner.RunWith) HashMap(java.util.HashMap) Car(com.amplifyframework.testmodels.personcar.Car) Mockito.spy(org.mockito.Mockito.spy) ArrayList(java.util.ArrayList) Consumer(com.amplifyframework.core.Consumer) ApiEndpointStatusChangeEvent(com.amplifyframework.api.events.ApiEndpointStatusChangeEvent) ModelMetadata(com.amplifyframework.datastore.appsync.ModelMetadata) PaginatedResult(com.amplifyframework.api.graphql.PaginatedResult) Before(org.junit.Before) Amplify(com.amplifyframework.core.Amplify) SynchronousDataStore(com.amplifyframework.testutils.sync.SynchronousDataStore) ApiPlugin(com.amplifyframework.api.ApiPlugin) CategoryType(com.amplifyframework.core.category.CategoryType) Assert.assertTrue(org.junit.Assert.assertTrue) Test(org.junit.Test) Completable(io.reactivex.rxjava3.core.Completable) Action(com.amplifyframework.core.Action) Mockito.when(org.mockito.Mockito.when) AmplifyCliGeneratedModelProvider(com.amplifyframework.testmodels.personcar.AmplifyCliGeneratedModelProvider) Mockito.verify(org.mockito.Mockito.verify) TimeUnit(java.util.concurrent.TimeUnit) ApiCategoryConfiguration(com.amplifyframework.api.ApiCategoryConfiguration) Temporal(com.amplifyframework.core.model.temporal.Temporal) GraphQLOperation(com.amplifyframework.api.graphql.GraphQLOperation) Collections(java.util.Collections) Assert.assertEquals(org.junit.Assert.assertEquals) Action(com.amplifyframework.core.Action) GraphQLLocation(com.amplifyframework.api.graphql.GraphQLLocation) ArrayList(java.util.ArrayList) GraphQLPathSegment(com.amplifyframework.api.graphql.GraphQLPathSegment) RandomString(com.amplifyframework.testutils.random.RandomString) GraphQLRequest(com.amplifyframework.api.graphql.GraphQLRequest) Consumer(com.amplifyframework.core.Consumer) List(java.util.List) ArrayList(java.util.ArrayList) ModelWithMetadata(com.amplifyframework.datastore.appsync.ModelWithMetadata) PaginatedResult(com.amplifyframework.api.graphql.PaginatedResult) GraphQLResponse(com.amplifyframework.api.graphql.GraphQLResponse) Car(com.amplifyframework.testmodels.personcar.Car) GraphQLOperation(com.amplifyframework.api.graphql.GraphQLOperation) Person(com.amplifyframework.testmodels.personcar.Person) Map(java.util.Map) HashMap(java.util.HashMap) ModelMetadata(com.amplifyframework.datastore.appsync.ModelMetadata)

Example 3 with PaginatedResult

use of com.amplifyframework.api.graphql.PaginatedResult in project amplify-android by aws-amplify.

the class AppSyncClientTest method validateBaseSyncQueryGen.

/**
 * Validates the construction of a base-sync query.
 * @throws JSONException On bad request JSON found in API category call
 * @throws DataStoreException If no valid response returned from AppSync endpoint during sync
 * @throws AmplifyException On failure to arrange model schema
 */
@Test
public void validateBaseSyncQueryGen() throws JSONException, AmplifyException {
    ModelSchema schema = ModelSchema.fromModelClass(BlogOwner.class);
    Await.result((Consumer<GraphQLResponse<PaginatedResult<ModelWithMetadata<BlogOwner>>>> onResult, Consumer<DataStoreException> onError) -> {
        try {
            GraphQLRequest<PaginatedResult<ModelWithMetadata<BlogOwner>>> request = endpoint.buildSyncRequest(schema, null, null, QueryPredicates.all());
            endpoint.sync(request, onResult, onError);
        } catch (DataStoreException datastoreException) {
            onError.accept(datastoreException);
        }
    });
    // Now, capture the request argument on API, so we can see what was passed.
    // Recall that we pass a raw doc to API.
    ArgumentCaptor<GraphQLRequest<ModelWithMetadata<BlogOwner>>> requestCaptor = ArgumentCaptor.forClass(GraphQLRequest.class);
    verify(api).query(requestCaptor.capture(), any(Consumer.class), any(Consumer.class));
    GraphQLRequest<ModelWithMetadata<BlogOwner>> capturedRequest = requestCaptor.getValue();
    Type type = TypeMaker.getParameterizedType(PaginatedResult.class, ModelWithMetadata.class, BlogOwner.class);
    assertEquals(type, capturedRequest.getResponseType());
    // The request was sent as JSON. It has a null variables field, and a present query field.
    JSONAssert.assertEquals(Resources.readAsString("base-sync-request-document-for-blog-owner.txt"), capturedRequest.getContent(), true);
}
Also used : ModelSchema(com.amplifyframework.core.model.ModelSchema) GraphQLRequest(com.amplifyframework.api.graphql.GraphQLRequest) DataStoreException(com.amplifyframework.datastore.DataStoreException) Type(java.lang.reflect.Type) Consumer(com.amplifyframework.core.Consumer) PaginatedResult(com.amplifyframework.api.graphql.PaginatedResult) BlogOwner(com.amplifyframework.testmodels.commentsblog.BlogOwner) Test(org.junit.Test)

Example 4 with PaginatedResult

use of com.amplifyframework.api.graphql.PaginatedResult in project amplify-android by aws-amplify.

the class SyncProcessor method syncModel.

/**
 * Sync models for a given model class.
 * This involves three steps:
 *  1. Lookup the last time the model class was synced;
 *  2. Make a request to the AppSync endpoint. If the last sync time is within a recent window
 *     of time, then request a *delta* sync. If the last sync time is outside a recent window of time,
 *     perform a *base* sync. A base sync is preformed by passing null.
 *  3. Continue fetching paged results until !hasNextResult() or we have synced the max records.
 *
 * @param schema The schema of the model to sync
 * @param syncTime The time of a last successful sync.
 * @param <T> The type of model to sync.
 * @return a stream of all ModelWithMetadata&lt;T&gt; objects from all pages for the provided model.
 * @throws DataStoreException if dataStoreConfigurationProvider.getConfiguration() fails
 */
private <T extends Model> Flowable<List<ModelWithMetadata<T>>> syncModel(ModelSchema schema, SyncTime syncTime) throws DataStoreException {
    final Long lastSyncTimeAsLong = syncTime.exists() ? syncTime.toLong() : null;
    final Integer syncPageSize = dataStoreConfigurationProvider.getConfiguration().getSyncPageSize();
    final Integer syncMaxRecords = dataStoreConfigurationProvider.getConfiguration().getSyncMaxRecords();
    AtomicReference<Integer> recordsFetched = new AtomicReference<>(0);
    QueryPredicate predicate = queryPredicateProvider.getPredicate(schema.getName());
    // Create a BehaviorProcessor, and set the default value to a GraphQLRequest that fetches the first page.
    BehaviorProcessor<GraphQLRequest<PaginatedResult<ModelWithMetadata<T>>>> processor = BehaviorProcessor.createDefault(appSync.buildSyncRequest(schema, lastSyncTimeAsLong, syncPageSize, predicate));
    return processor.concatMap(request -> {
        if (isSyncRetryEnabled) {
            return syncPageWithRetry(request).toFlowable();
        } else {
            return syncPage(request).toFlowable();
        }
    }).doOnNext(paginatedResult -> {
        if (paginatedResult.hasNextResult()) {
            processor.onNext(paginatedResult.getRequestForNextResult());
        } else {
            processor.onComplete();
        }
    }).map(paginatedResult -> Flowable.fromIterable(paginatedResult).map(modelWithMetadata -> hydrateSchemaIfNeeded(modelWithMetadata, schema)).toList().blockingGet()).takeUntil(items -> recordsFetched.accumulateAndGet(items.size(), Integer::sum) >= syncMaxRecords);
}
Also used : DataStoreConfigurationProvider(com.amplifyframework.datastore.DataStoreConfigurationProvider) Single(io.reactivex.rxjava3.core.Single) DataStoreErrorHandler(com.amplifyframework.datastore.DataStoreErrorHandler) BehaviorProcessor(io.reactivex.rxjava3.processors.BehaviorProcessor) NonNull(androidx.annotation.NonNull) ModelWithMetadata(com.amplifyframework.datastore.appsync.ModelWithMetadata) GraphQLRequest(com.amplifyframework.api.graphql.GraphQLRequest) ModelProvider(com.amplifyframework.core.model.ModelProvider) DataStoreChannelEventName(com.amplifyframework.datastore.DataStoreChannelEventName) AppSync(com.amplifyframework.datastore.appsync.AppSync) SyncQueriesStartedEvent(com.amplifyframework.datastore.events.SyncQueriesStartedEvent) AtomicReference(java.util.concurrent.atomic.AtomicReference) ApiException(com.amplifyframework.api.ApiException) ArrayList(java.util.ArrayList) SchemaRegistry(com.amplifyframework.core.model.SchemaRegistry) Time(com.amplifyframework.util.Time) Schedulers(io.reactivex.rxjava3.schedulers.Schedulers) Consumer(com.amplifyframework.core.Consumer) ModelSchema(com.amplifyframework.core.model.ModelSchema) PaginatedResult(com.amplifyframework.api.graphql.PaginatedResult) QueryPredicate(com.amplifyframework.core.model.query.predicate.QueryPredicate) HubEvent(com.amplifyframework.hub.HubEvent) Amplify(com.amplifyframework.core.Amplify) Flowable(io.reactivex.rxjava3.core.Flowable) HubChannel(com.amplifyframework.hub.HubChannel) SerializedModel(com.amplifyframework.core.model.SerializedModel) Model(com.amplifyframework.core.model.Model) Completable(io.reactivex.rxjava3.core.Completable) Logger(com.amplifyframework.logging.Logger) Objects(java.util.Objects) DataStoreException(com.amplifyframework.datastore.DataStoreException) List(java.util.List) Cancelable(com.amplifyframework.core.async.Cancelable) AmplifyDisposables(com.amplifyframework.datastore.AmplifyDisposables) ForEach(com.amplifyframework.util.ForEach) Collections(java.util.Collections) GraphQLRequest(com.amplifyframework.api.graphql.GraphQLRequest) ModelWithMetadata(com.amplifyframework.datastore.appsync.ModelWithMetadata) QueryPredicate(com.amplifyframework.core.model.query.predicate.QueryPredicate) AtomicReference(java.util.concurrent.atomic.AtomicReference)

Example 5 with PaginatedResult

use of com.amplifyframework.api.graphql.PaginatedResult in project amplify-android by aws-amplify.

the class AWSApiPluginTest method requestUsesIamForAuth.

/**
 * Ensure the auth mode used for the request is AWS_IAM. We verify this by
 * @throws AmplifyException Not expected.
 * @throws InterruptedException Not expected.
 */
@Test
public void requestUsesIamForAuth() throws AmplifyException, InterruptedException {
    webServer.enqueue(new MockResponse().setBody(Resources.readAsString("blog-owners-query-results.json")));
    AppSyncGraphQLRequest<PaginatedResult<BlogOwner>> appSyncGraphQLRequest = createQueryRequestWithAuthMode(BlogOwner.class, AuthorizationType.AWS_IAM);
    GraphQLResponse<PaginatedResult<BlogOwner>> actualResponse = Await.<GraphQLResponse<PaginatedResult<BlogOwner>>, ApiException>result((onResult, onError) -> plugin.query(appSyncGraphQLRequest, onResult, onError));
    RecordedRequest recordedRequest = webServer.takeRequest();
    assertNull(recordedRequest.getHeader("x-api-key"));
    assertNotNull(recordedRequest.getHeader("authorization"));
    assertTrue(recordedRequest.getHeader("authorization").startsWith("AWS4-HMAC-SHA256"));
    assertEquals(Arrays.asList("Curly", "Moe", "Larry"), Observable.fromIterable(actualResponse.getData()).map(BlogOwner::getName).toList().blockingGet());
}
Also used : RecordedRequest(okhttp3.mockwebserver.RecordedRequest) MockResponse(okhttp3.mockwebserver.MockResponse) PaginatedResult(com.amplifyframework.api.graphql.PaginatedResult) GraphQLResponse(com.amplifyframework.api.graphql.GraphQLResponse) BlogOwner(com.amplifyframework.testmodels.commentsblog.BlogOwner) ApiException(com.amplifyframework.api.ApiException) Test(org.junit.Test)

Aggregations

PaginatedResult (com.amplifyframework.api.graphql.PaginatedResult)18 Test (org.junit.Test)13 GraphQLResponse (com.amplifyframework.api.graphql.GraphQLResponse)12 Type (java.lang.reflect.Type)8 GraphQLRequest (com.amplifyframework.api.graphql.GraphQLRequest)7 QueryType (com.amplifyframework.api.graphql.QueryType)7 Consumer (com.amplifyframework.core.Consumer)7 HashMap (java.util.HashMap)6 JSONObject (org.json.JSONObject)6 ModelSchema (com.amplifyframework.core.model.ModelSchema)5 BlogOwner (com.amplifyframework.testmodels.commentsblog.BlogOwner)5 ApiException (com.amplifyframework.api.ApiException)4 GraphQLLocation (com.amplifyframework.api.graphql.GraphQLLocation)4 GraphQLPathSegment (com.amplifyframework.api.graphql.GraphQLPathSegment)4 DataStoreException (com.amplifyframework.datastore.DataStoreException)4 ModelWithMetadata (com.amplifyframework.datastore.appsync.ModelWithMetadata)4 ArrayList (java.util.ArrayList)4 AmplifyException (com.amplifyframework.AmplifyException)3 ApiCategory (com.amplifyframework.api.ApiCategory)3 ApiCategoryConfiguration (com.amplifyframework.api.ApiCategoryConfiguration)3