blob: f7466b5a04c85e858e7878d852fc20a8215ab851 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.salesforce;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import com.googlecode.junittoolbox.ParallelParameterized;
import com.thoughtworks.xstream.annotations.XStreamImplicit;
import org.apache.camel.CamelExecutionException;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.salesforce.api.dto.AbstractQueryRecordsBase;
import org.apache.camel.component.salesforce.api.dto.CreateSObjectResult;
import org.apache.camel.component.salesforce.api.dto.composite.SObjectComposite;
import org.apache.camel.component.salesforce.api.dto.composite.SObjectComposite.Method;
import org.apache.camel.component.salesforce.api.dto.composite.SObjectCompositeResponse;
import org.apache.camel.component.salesforce.api.dto.composite.SObjectCompositeResult;
import org.apache.camel.component.salesforce.api.utils.Version;
import org.apache.camel.component.salesforce.dto.generated.Account;
import org.assertj.core.api.Assertions;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized.Parameters;
@RunWith(ParallelParameterized.class)
public class CompositeApiIntegrationTest extends AbstractSalesforceTestBase {
public static class Accounts extends AbstractQueryRecordsBase {
@XStreamImplicit
private List<Account> records;
public List<Account> getRecords() {
return records;
}
public void setRecords(final List<Account> records) {
this.records = records;
}
}
private static final Set<String> VERSIONS = new HashSet<>(Arrays.asList("38.0", "41.0"));
private String accountId;
private final String compositeUri;
private final String version;
public CompositeApiIntegrationTest(final String format, final String version) {
this.version = version;
compositeUri = "salesforce:composite?format=" + format;
}
@After
public void removeRecords() {
try {
template.sendBody("salesforce:deleteSObject?sObjectName=Account&sObjectId=" + accountId, null);
} catch (final CamelExecutionException ignored) {
// other tests run in parallel could have deleted the Account
}
template.request("direct:deleteBatchAccounts", null);
}
@Before
public void setupRecords() {
final Account account = new Account();
account.setName("Composite API Batch");
final CreateSObjectResult result = template.requestBody("salesforce:createSObject", account, CreateSObjectResult.class);
accountId = result.getId();
}
@Test
public void shouldSubmitBatchUsingCompositeApi() {
final SObjectComposite composite = new SObjectComposite(version, true);
final Account updates = new Account();
updates.setName("NewName");
composite.addUpdate("Account", accountId, updates, "UpdateExistingAccountReferenceId");
final Account newAccount = new Account();
newAccount.setName("Account created from Composite batch API");
composite.addCreate(newAccount, "CreateAccountReferenceId");
composite.addGet("Account", accountId, "GetAccountReferenceId", "Name", "BillingPostalCode");
composite.addDelete("Account", accountId, "DeleteAccountReferenceId");
testComposite(composite);
}
@Test
public void shouldSupportGenericCompositeRequests() {
final SObjectComposite composite = new SObjectComposite(version, true);
composite.addGeneric(Method.GET, "/sobjects/Account/" + accountId, "GetExistingAccountReferenceId");
testComposite(composite);
}
@Test
public void shouldSupportObjectCreation() {
final SObjectComposite compoiste = new SObjectComposite(version, true);
final Account newAccount = new Account();
newAccount.setName("Account created from Composite batch API");
compoiste.addCreate(newAccount, "CreateAccountReferenceId");
final SObjectCompositeResponse response = testComposite(compoiste);
assertResponseContains(response, "id");
}
@Test
public void shouldSupportObjectDeletion() {
final SObjectComposite composite = new SObjectComposite(version, true);
composite.addDelete("Account", accountId, "DeleteAccountReferenceId");
testComposite(composite);
}
@Test
public void shouldSupportObjectRetrieval() {
final SObjectComposite composite = new SObjectComposite(version, true);
composite.addGet("Account", accountId, "GetExistingAccountReferenceId", "Name");
final SObjectCompositeResponse response = testComposite(composite);
assertResponseContains(response, "Name");
}
@Test
public void shouldSupportObjectUpdates() {
final SObjectComposite composite = new SObjectComposite(version, true);
final Account updates = new Account();
updates.setName("NewName");
updates.setAccountNumber("AC12345");
composite.addUpdate("Account", accountId, updates, "UpdateAccountReferenceId");
testComposite(composite);
}
@Test
public void shouldSupportQuery() {
final SObjectComposite composite = new SObjectComposite(version, true);
composite.addQuery("SELECT Id, Name FROM Account", "SelectQueryReferenceId");
final SObjectCompositeResponse response = testComposite(composite);
assertResponseContains(response, "totalSize");
}
@Test
public void shouldSupportQueryAll() {
final SObjectComposite composite = new SObjectComposite(version, true);
composite.addQueryAll("SELECT Id, Name FROM Account", "SelectQueryReferenceId");
final SObjectCompositeResponse response = testComposite(composite);
assertResponseContains(response, "totalSize");
}
@Test
public void shouldSupportRelatedObjectRetrieval() {
if (Version.create(version).compareTo(Version.create("36.0")) < 0) {
return;
}
final SObjectComposite composite = new SObjectComposite("36.0", true);
composite.addGetRelated("Account", accountId, "CreatedBy", "GetRelatedAccountReferenceId");
final SObjectCompositeResponse response = testComposite(composite);
assertResponseContains(response, "Username");
}
SObjectCompositeResponse testComposite(final SObjectComposite batch) {
final SObjectCompositeResponse response = template.requestBody(compositeUri, batch, SObjectCompositeResponse.class);
Assertions.assertThat(response).as("Response should be provided").isNotNull();
Assertions.assertThat(response.getCompositeResponse()).as("Received errors in: " + response)
.allMatch(val -> val.getHttpStatusCode() >= 200 && val.getHttpStatusCode() <= 299);
return response;
}
@Override
protected RouteBuilder doCreateRouteBuilder() throws Exception {
return new RouteBuilder() {
@Override
public void configure() throws Exception {
from("direct:deleteBatchAccounts")
.to("salesforce:query?sObjectClass=" + Accounts.class.getName()
+ "&sObjectQuery=SELECT Id FROM Account WHERE Name = 'Account created from Composite batch API'")
.split(simple("${body.records}")).setHeader("sObjectId", simple("${body.id}")).to("salesforce:deleteSObject?sObjectName=Account").end();
}
};
}
@Override
protected String salesforceApiVersionToUse() {
return version;
}
@Parameters(name = "format = {0}, version = {1}")
public static Iterable<Object[]> formats() {
return VERSIONS.stream().map(v -> new Object[] {"JSON", v}).collect(Collectors.toList());
}
static void assertResponseContains(final SObjectCompositeResponse response, final String key) {
Assertions.assertThat(response).isNotNull();
final List<SObjectCompositeResult> compositeResponse = response.getCompositeResponse();
Assertions.assertThat(compositeResponse).hasSize(1);
final SObjectCompositeResult firstCompositeResponse = compositeResponse.get(0);
Assertions.assertThat(firstCompositeResponse).isNotNull();
final Object firstCompositeResponseBody = firstCompositeResponse.getBody();
Assertions.assertThat(firstCompositeResponseBody).isInstanceOf(Map.class);
@SuppressWarnings("unchecked")
final Map<String, ?> body = (Map<String, ?>)firstCompositeResponseBody;
Assertions.assertThat(body).containsKey(key);
Assertions.assertThat(body.get(key)).isNotNull();
}
}