Repository: camel
Updated Branches:
  refs/heads/master b77de5f41 -> fc447e8ba


CAMEL-8396 Update Salesforce component to support new REST APIs in Salesforce 
API V33.0

This commit adds support for the Organization Limits Salesforce API[1].

New operation `limit` was added and can be used like:

    ...to("salesforce:limit")
        .choice()
          .when(
             simple("${body.dailyApiRequests.remaining} > 0")
          )...
        .endChoice();

Supports all usage limits currently returned with v38.0 Salesforce API.
Adding of new usage limits is performed by adding enum constant to
Limits.Operation and corresponding getter to Limits class.

[1] 
https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_limits.htm


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/af150675
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/af150675
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/af150675

Branch: refs/heads/master
Commit: af150675aa2f436c57c30cc1c5373fbef240e8b1
Parents: b77de5f
Author: Zoran Regvart <zo...@regvart.com>
Authored: Thu Nov 10 17:57:11 2016 +0100
Committer: Claus Ibsen <davscl...@apache.org>
Committed: Tue Nov 22 10:07:49 2016 +0100

----------------------------------------------------------------------
 .../component/salesforce/api/dto/Limits.java    | 276 +++++++++++++++++++
 .../salesforce/internal/OperationName.java      |   5 +-
 .../internal/client/DefaultRestClient.java      |  10 +
 .../salesforce/internal/client/RestClient.java  |   7 +
 .../processor/AbstractRestProcessor.java        |   7 +
 .../internal/processor/JsonRestProcessor.java   |   6 +
 .../salesforce/LimitsIntegrationTest.java       |  97 +++++++
 .../salesforce/api/dto/LimitsTest.java          |  87 ++++++
 .../component/salesforce/api/dto/limits.json    |  94 +++++++
 9 files changed, 588 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/af150675/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/Limits.java
----------------------------------------------------------------------
diff --git 
a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/Limits.java
 
b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/Limits.java
new file mode 100644
index 0000000..20f7c15
--- /dev/null
+++ 
b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/api/dto/Limits.java
@@ -0,0 +1,276 @@
+/**
+ * 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.api.dto;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+
+import org.apache.camel.component.salesforce.api.dto.Limits.LimitsDeserializer;
+
+/**
+ * Data given by the `Limits` resource on Salesforce.
+ *
+ * @see <a href= 
"https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_limits.htm";>
+ *      
https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_limits.htm</a>
+ */
+@JsonDeserialize(using = LimitsDeserializer.class)
+public final class Limits implements Serializable {
+
+    public static final class LimitsDeserializer extends JsonDeserializer {
+
+        private static final TypeReference<Map<Operation, Usage>> USAGES_TYPE 
= new TypeReference<Map<Operation, Usage>>() {
+        };
+
+        @Override
+        public Object deserialize(final JsonParser parser, final 
DeserializationContext context)
+                throws IOException, JsonProcessingException {
+
+            final Map<Operation, Usage> usages = 
parser.readValueAs(USAGES_TYPE);
+
+            return new Limits(usages);
+        }
+
+    }
+
+    public enum Operation {
+        ConcurrentAsyncGetReportInstances,
+        ConcurrentSyncReportRuns,
+        DailyApiRequests,
+        DailyAsyncApexExecutions,
+        DailyBulkApiRequests,
+        DailyDurableGenericStreamingApiEvents,
+        DailyDurableStreamingApiEvents,
+        DailyGenericStreamingApiEvents,
+        DailyStreamingApiEvents,
+        DailyWorkflowEmails,
+        DataStorageMB,
+        DurableStreamingApiConcurrentClients,
+        FileStorageMB,
+        HourlyAsyncReportRuns,
+        HourlyDashboardRefreshes,
+        HourlyDashboardResults,
+        HourlyDashboardStatuses,
+        HourlyODataCallout,
+        HourlySyncReportRuns,
+        HourlyTimeBasedWorkflow,
+        MassEmail,
+        SingleEmail,
+        StreamingApiConcurrentClients
+    }
+
+    /**
+     * Encapsulates usage limits for single operation.
+     */
+    public static final class Usage implements Serializable {
+
+        private static final long serialVersionUID = 1L;
+
+        private static final int UNKNOWN_VAL = Integer.MIN_VALUE;
+
+        public static final Usage UNKNOWN = new Usage(UNKNOWN_VAL, 
UNKNOWN_VAL);
+
+        private final int max;
+
+        private final int remaining;
+
+        @JsonCreator
+        Usage(@JsonProperty("Max") final int max, @JsonProperty("Remaining") 
final int remaining) {
+            this.max = max;
+            this.remaining = remaining;
+        }
+
+        /** Maximum allowed by the limit */
+        public int getMax() {
+            return max;
+        }
+
+        /** Remaining invocations allowed */
+        public int getRemaining() {
+            return remaining;
+        }
+
+        public boolean isUnknown() {
+            return max == UNKNOWN_VAL && remaining == UNKNOWN_VAL;
+        }
+
+        @Override
+        public String toString() {
+            if (max == UNKNOWN_VAL && remaining == UNKNOWN_VAL) {
+                return "Undefined";
+            }
+
+            return "Max: " + max + ", Remaining: " + remaining;
+        }
+    }
+
+    private static final long serialVersionUID = 1L;
+
+    private static final Usage UNDEFINED = new Usage(Usage.UNKNOWN_VAL, 
Usage.UNKNOWN_VAL);
+
+    private final Map<Operation, Usage> usages;
+
+    public Limits(final Map<Operation, Usage> usages) {
+        this.usages = usages;
+    }
+
+    public Usage forOperation(final Operation operation) {
+        return usages.getOrDefault(operation, UNDEFINED);
+    }
+
+    /** Concurrent REST API requests for results of asynchronous report runs */
+    public Usage getConcurrentAsyncGetReportInstances() {
+        return forOperation(Operation.ConcurrentAsyncGetReportInstances);
+    }
+
+    /** Concurrent synchronous report runs via REST API */
+    public Usage getConcurrentSyncReportRuns() {
+        return forOperation(Operation.ConcurrentSyncReportRuns);
+    }
+
+    /** Daily API calls */
+    public Usage getDailyApiRequests() {
+        return forOperation(Operation.DailyApiRequests);
+    }
+
+    /** Daily Batch Apex and future method executions */
+    public Usage getDailyAsyncApexExecutions() {
+        return forOperation(Operation.DailyAsyncApexExecutions);
+    }
+
+    /** Daily Bulk API calls */
+    public Usage getDailyBulkApiRequests() {
+        return forOperation(Operation.DailyBulkApiRequests);
+    }
+
+    /**
+     * Daily durable generic streaming events (if generic streaming is enabled 
for your organization)
+     */
+    public Usage getDailyDurableGenericStreamingApiEvents() {
+        return forOperation(Operation.DailyDurableGenericStreamingApiEvents);
+    }
+
+    /**
+     * Daily durable streaming events (if generic streaming is enabled for 
your organization)
+     */
+    public Usage getDailyDurableStreamingApiEvents() {
+        return forOperation(Operation.DailyDurableStreamingApiEvents);
+    }
+
+    /**
+     * Daily generic streaming events (if generic streaming is enabled for 
your organization)
+     */
+    public Usage getDailyGenericStreamingApiEvents() {
+        return forOperation(Operation.DailyGenericStreamingApiEvents);
+    }
+
+    /** Daily Streaming API events */
+    public Usage getDailyStreamingApiEvents() {
+        return forOperation(Operation.DailyStreamingApiEvents);
+    }
+
+    /** Daily workflow emails */
+    public Usage getDailyWorkflowEmails() {
+        return forOperation(Operation.DailyWorkflowEmails);
+    }
+
+    /** Data storage (MB) */
+    public Usage getDataStorageMB() {
+        return forOperation(Operation.DataStorageMB);
+    }
+
+    /** Streaming API concurrent clients */
+    public Usage getDurableStreamingApiConcurrentClients() {
+        return forOperation(Operation.DurableStreamingApiConcurrentClients);
+    }
+
+    /** File storage (MB) */
+    public Usage getFileStorageMB() {
+        return forOperation(Operation.FileStorageMB);
+    }
+
+    /** Hourly asynchronous report runs via REST API */
+    public Usage getHourlyAsyncReportRuns() {
+        return forOperation(Operation.HourlyAsyncReportRuns);
+    }
+
+    /** Hourly dashboard refreshes via REST API */
+    public Usage getHourlyDashboardRefreshes() {
+        return forOperation(Operation.HourlyDashboardRefreshes);
+    }
+
+    /** Hourly REST API requests for dashboard results */
+    public Usage getHourlyDashboardResults() {
+        return forOperation(Operation.HourlyDashboardResults);
+    }
+
+    /** Hourly dashboard status requests via REST API */
+    public Usage getHourlyDashboardStatuses() {
+        return forOperation(Operation.HourlyDashboardStatuses);
+    }
+
+    /** Hourly OData callouts */
+    public Usage getHourlyODataCallout() {
+        return forOperation(Operation.HourlyODataCallout);
+    }
+
+    /** Hourly synchronous report runs via REST API */
+    public Usage getHourlySyncReportRuns() {
+        return forOperation(Operation.HourlySyncReportRuns);
+    }
+
+    /** Hourly workflow time triggers */
+    public Usage getHourlyTimeBasedWorkflow() {
+        return forOperation(Operation.HourlyTimeBasedWorkflow);
+    }
+
+    /**
+     * Daily number of mass emails that are sent to external email addresses 
by using Apex or Force.com APIs
+     */
+    public Usage getMassEmail() {
+        return forOperation(Operation.MassEmail);
+    }
+
+    /**
+     * Daily number of single emails that are sent to external email addresses 
by using Apex or Force.com APIs
+     */
+    public Usage getSingleEmail() {
+        return forOperation(Operation.SingleEmail);
+    }
+
+    /** Durable streaming API concurrent clients */
+    public Usage getStreamingApiConcurrentClients() {
+        return forOperation(Operation.StreamingApiConcurrentClients);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return "Limits: " + usages.entrySet().stream().map(e -> e.getKey() + 
": " + e.getValue())
+                .collect(Collectors.joining(", "));
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/af150675/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/OperationName.java
----------------------------------------------------------------------
diff --git 
a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/OperationName.java
 
b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/OperationName.java
index 6107750..15fdf0b 100644
--- 
a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/OperationName.java
+++ 
b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/OperationName.java
@@ -58,7 +58,10 @@ public enum OperationName {
     EXECUTE_SYNCREPORT("executeSyncReport"),
     EXECUTE_ASYNCREPORT("executeAsyncReport"),
     GET_REPORT_INSTANCES("getReportInstances"),
-    GET_REPORT_RESULTS("getReportResults");
+    GET_REPORT_RESULTS("getReportResults"),
+
+    // limits API
+    LIMITS("limits");
 
     private final String value;
 

http://git-wip-us.apache.org/repos/asf/camel/blob/af150675/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultRestClient.java
----------------------------------------------------------------------
diff --git 
a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultRestClient.java
 
b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultRestClient.java
index f39673b..076b3fd 100644
--- 
a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultRestClient.java
+++ 
b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/DefaultRestClient.java
@@ -405,6 +405,16 @@ public class DefaultRestClient extends AbstractClientBase 
implements RestClient
         return instanceUrl + SERVICES_APEXREST + apexUrl;
     }
 
+    @Override
+    public void limits(final ResponseCallback responseCallback) {
+        final Request get = getRequest(HttpMethod.GET, versionUrl() + 
"limits/");
+
+        // requires authorization token
+        setAccessToken(get);
+
+        doHttpRequest(get, new DelegatingClientCallback(responseCallback));
+    }
+
     private String servicesDataUrl() {
         return instanceUrl + SERVICES_DATA;
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/af150675/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/RestClient.java
----------------------------------------------------------------------
diff --git 
a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/RestClient.java
 
b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/RestClient.java
index af0a2a7..470aa33 100644
--- 
a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/RestClient.java
+++ 
b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/client/RestClient.java
@@ -193,4 +193,11 @@ public interface RestClient {
      */
     void apexCall(String httpMethod, String apexUrl, Map<String, Object> 
queryParams, InputStream requestDto,
                   ResponseCallback callback);
+
+    /**
+     * Fetches Organization Limits.
+     *
+     * @param responseCallback {@link ResponseCallback} to handle response or 
exception
+     */
+    void limits(ResponseCallback responseCallback);
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/af150675/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/AbstractRestProcessor.java
----------------------------------------------------------------------
diff --git 
a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/AbstractRestProcessor.java
 
b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/AbstractRestProcessor.java
index d487235..35e0aff 100644
--- 
a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/AbstractRestProcessor.java
+++ 
b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/AbstractRestProcessor.java
@@ -152,6 +152,9 @@ public abstract class AbstractRestProcessor extends 
AbstractSalesforceProcessor
             case APEX_CALL:
                 processApexCall(exchange, callback);
                 break;
+            case LIMITS:
+                processLimits(exchange, callback);
+                break;
             default:
                 throw new SalesforceException("Unknown operation name: " + 
operationName.value(), null);
             }
@@ -561,6 +564,10 @@ public abstract class AbstractRestProcessor extends 
AbstractSalesforceProcessor
         return apexUrl;
     }
 
+    private void processLimits(Exchange exchange, AsyncCallback callback) {
+        restClient.limits((response, exception) -> processResponse(exchange, 
response, exception, callback));
+    }
+
     @SuppressWarnings("unchecked")
     private Map<String, Object> getQueryParams(Exchange exchange) {
 

http://git-wip-us.apache.org/repos/asf/camel/blob/af150675/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/JsonRestProcessor.java
----------------------------------------------------------------------
diff --git 
a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/JsonRestProcessor.java
 
b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/JsonRestProcessor.java
index 4f97a83..7d26b8f 100644
--- 
a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/JsonRestProcessor.java
+++ 
b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/processor/JsonRestProcessor.java
@@ -33,6 +33,7 @@ import 
org.apache.camel.component.salesforce.api.SalesforceException;
 import org.apache.camel.component.salesforce.api.dto.AbstractDTOBase;
 import org.apache.camel.component.salesforce.api.dto.CreateSObjectResult;
 import org.apache.camel.component.salesforce.api.dto.GlobalObjects;
+import org.apache.camel.component.salesforce.api.dto.Limits;
 import org.apache.camel.component.salesforce.api.dto.RestResources;
 import org.apache.camel.component.salesforce.api.dto.SObjectBasicInfo;
 import org.apache.camel.component.salesforce.api.dto.SObjectDescription;
@@ -104,6 +105,11 @@ public class JsonRestProcessor extends 
AbstractRestProcessor {
             });
             break;
 
+        case LIMITS:
+            // handle known response type
+            exchange.setProperty(RESPONSE_CLASS, Limits.class);
+            break;
+
         default:
             // ignore, some operations do not require response class or type
         }

http://git-wip-us.apache.org/repos/asf/camel/blob/af150675/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/LimitsIntegrationTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/LimitsIntegrationTest.java
 
b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/LimitsIntegrationTest.java
new file mode 100644
index 0000000..ed99818
--- /dev/null
+++ 
b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/LimitsIntegrationTest.java
@@ -0,0 +1,97 @@
+/**
+ * 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 org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.salesforce.api.dto.Limits;
+import org.apache.camel.component.salesforce.api.dto.Limits.Usage;
+import org.junit.Test;
+
+public class LimitsIntegrationTest extends AbstractSalesforceTestBase {
+
+    private static final Object NOT_USED = null;
+
+    @Test
+    public void shouldFetchLimitsForOrganization() {
+        final Limits limits = template.requestBody("direct:test-limits", 
NOT_USED, Limits.class);
+
+        assertNotNull("Should fetch limits from Salesforce REST API", limits);
+
+        assertLimitIsFetched("ConcurrentAsyncGetReportInstances", 
limits.getConcurrentAsyncGetReportInstances());
+
+        assertLimitIsFetched("ConcurrentSyncReportRuns", 
limits.getConcurrentSyncReportRuns());
+
+        assertLimitIsFetched("DailyApiRequests", limits.getDailyApiRequests());
+
+        assertLimitIsFetched("DailyAsyncApexExecutions", 
limits.getDailyAsyncApexExecutions());
+
+        assertLimitIsFetched("DailyBulkApiRequests", 
limits.getDailyBulkApiRequests());
+
+        assertLimitIsFetched("DailyDurableGenericStreamingApiEvents",
+                limits.getDailyDurableGenericStreamingApiEvents());
+
+        assertLimitIsFetched("DailyDurableStreamingApiEvents", 
limits.getDailyDurableStreamingApiEvents());
+
+        assertLimitIsFetched("DailyGenericStreamingApiEvents", 
limits.getDailyGenericStreamingApiEvents());
+
+        assertLimitIsFetched("DailyStreamingApiEvents", 
limits.getDailyStreamingApiEvents());
+
+        assertLimitIsFetched("DailyWorkflowEmails", 
limits.getDailyWorkflowEmails());
+
+        assertLimitIsFetched("DataStorageMB", limits.getDataStorageMB());
+
+        assertLimitIsFetched("DurableStreamingApiConcurrentClients", 
limits.getDurableStreamingApiConcurrentClients());
+
+        assertLimitIsFetched("FileStorageMB", limits.getFileStorageMB());
+
+        assertLimitIsFetched("HourlyAsyncReportRuns", 
limits.getHourlyAsyncReportRuns());
+
+        assertLimitIsFetched("HourlyDashboardRefreshes", 
limits.getHourlyDashboardRefreshes());
+
+        assertLimitIsFetched("HourlyDashboardResults", 
limits.getHourlyDashboardResults());
+
+        assertLimitIsFetched("HourlyDashboardStatuses", 
limits.getHourlyDashboardStatuses());
+
+        assertLimitIsFetched("HourlyODataCallout", 
limits.getHourlyODataCallout());
+
+        assertLimitIsFetched("HourlySyncReportRuns", 
limits.getHourlySyncReportRuns());
+
+        assertLimitIsFetched("HourlyTimeBasedWorkflow", 
limits.getHourlyTimeBasedWorkflow());
+
+        assertLimitIsFetched("MassEmail", limits.getMassEmail());
+
+        assertLimitIsFetched("SingleEmail", limits.getSingleEmail());
+
+        assertLimitIsFetched("StreamingApiConcurrentClients", 
limits.getStreamingApiConcurrentClients());
+    }
+
+    private static void assertLimitIsFetched(String property, Usage usage) {
+        assertNotNull("Usage for `" + property + "` should be defined", usage);
+        assertNotEquals("Max usage for `" + property + "` should be defined", 
0, usage.getMax());
+        assertNotEquals("Remaining usage for `" + property + "` should be 
defined", 0, usage.getRemaining());
+    }
+
+    @Override
+    protected RouteBuilder doCreateRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:test-limits").to("salesforce:limits");
+            }
+        };
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/af150675/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/dto/LimitsTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/dto/LimitsTest.java
 
b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/dto/LimitsTest.java
new file mode 100644
index 0000000..6b7b0d3
--- /dev/null
+++ 
b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/api/dto/LimitsTest.java
@@ -0,0 +1,87 @@
+/**
+ * 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.api.dto;
+
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import org.apache.camel.component.salesforce.api.dto.Limits.Usage;
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+public class LimitsTest {
+
+    @Test
+    public void shouldBeKnownIfDefined() {
+        assertFalse("Known usage must not declare itself as unknown", new 
Usage(1, 2).isUnknown());
+    }
+
+    @Test
+    public void shouldDeserializeFromSalesforceGeneratedJSON() throws 
JsonProcessingException, IOException {
+        final ObjectMapper mapper = new ObjectMapper();
+
+        final Object read = mapper.readerFor(Limits.class)
+                
.readValue(LimitsTest.class.getResource("/org/apache/camel/component/salesforce/api/dto/limits.json"));
+
+        assertThat("Limits should be parsed from JSON", read, 
instanceOf(Limits.class));
+
+        final Limits limits = (Limits) read;
+
+        assertFalse("Should have some usage present", 
limits.getDailyApiRequests().isUnknown());
+    }
+
+    @Test
+    public void usageShouldBeUnknownIfUnknown() {
+        assertTrue("Unknown usage must declare itself as such", 
Usage.UNKNOWN.isUnknown());
+    }
+
+    @Test
+    public void shouldSupportGettingAllDefinedUsages() throws 
IntrospectionException {
+        BeanInfo beanInfo = Introspector.getBeanInfo(Limits.class);
+
+        PropertyDescriptor[] propertyDescriptors = 
beanInfo.getPropertyDescriptors();
+
+        Set<String> found = new HashSet<>();
+        for (PropertyDescriptor descriptor : propertyDescriptors) {
+            found.add(descriptor.getName());
+        }
+
+        Set<String> defined = 
Arrays.stream(Limits.Operation.values()).map(Limits.Operation::name)
+                .map(Introspector::decapitalize).collect(Collectors.toSet());
+
+        defined.removeAll(found);
+
+        assertThat("All operations declared in Operation enum should have it's 
corresponding getter", defined,
+                is(Collections.emptySet()));
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/af150675/components/camel-salesforce/camel-salesforce-component/src/test/resources/org/apache/camel/component/salesforce/api/dto/limits.json
----------------------------------------------------------------------
diff --git 
a/components/camel-salesforce/camel-salesforce-component/src/test/resources/org/apache/camel/component/salesforce/api/dto/limits.json
 
b/components/camel-salesforce/camel-salesforce-component/src/test/resources/org/apache/camel/component/salesforce/api/dto/limits.json
new file mode 100644
index 0000000..c355c74
--- /dev/null
+++ 
b/components/camel-salesforce/camel-salesforce-component/src/test/resources/org/apache/camel/component/salesforce/api/dto/limits.json
@@ -0,0 +1,94 @@
+{
+  "ConcurrentAsyncGetReportInstances" : {
+    "Max" : 200,
+    "Remaining" : 200
+  },
+  "ConcurrentSyncReportRuns" : {
+    "Max" : 20,
+    "Remaining" : 20
+  },
+  "DailyApiRequests" : {
+    "Max" : 15000,
+    "Remaining" : 14998
+  },
+  "DailyAsyncApexExecutions" : {
+    "Max" : 250000,
+    "Remaining" : 250000
+  },
+  "DailyBulkApiRequests" : {
+    "Max" : 5000,
+    "Remaining" : 5000
+  },
+  "DailyDurableGenericStreamingApiEvents" : {
+    "Max" : 10000,
+    "Remaining" : 10000
+  },
+  "DailyDurableStreamingApiEvents" : {
+    "Max" : 10000,
+    "Remaining" : 10000
+  },
+  "DailyGenericStreamingApiEvents" : {
+    "Max" : 10000,
+    "Remaining" : 10000
+  },
+  "DailyStreamingApiEvents" : {
+    "Max" : 10000,
+    "Remaining" : 10000
+  },
+  "DailyWorkflowEmails" : {
+    "Max" : 390,
+    "Remaining" : 390
+  },
+  "DataStorageMB" : {
+    "Max" : 5,
+    "Remaining" : 5
+  },
+  "DurableStreamingApiConcurrentClients" : {
+    "Max" : 20,
+    "Remaining" : 20
+  },
+  "FileStorageMB" : {
+    "Max" : 20,
+    "Remaining" : 20
+  },
+  "HourlyAsyncReportRuns" : {
+    "Max" : 1200,
+    "Remaining" : 1200
+  },
+  "HourlyDashboardRefreshes" : {
+    "Max" : 200,
+    "Remaining" : 200
+  },
+  "HourlyDashboardResults" : {
+    "Max" : 5000,
+    "Remaining" : 5000
+  },
+  "HourlyDashboardStatuses" : {
+    "Max" : 999999999,
+    "Remaining" : 999999999
+  },
+  "HourlyODataCallout" : {
+    "Remaining" : 9999,
+    "Max" : 10000
+  },
+  "HourlySyncReportRuns" : {
+    "Max" : 500,
+    "Remaining" : 500
+  },
+  "HourlyTimeBasedWorkflow" : {
+    "Max" : 50,
+    "Remaining" : 50
+  },
+  "MassEmail" : {
+    "Max" : 10,
+    "Remaining" : 10
+  },
+  "SingleEmail" : {
+    "Max" : 15,
+    "Remaining" : 15
+  },
+  "StreamingApiConcurrentClients" : {
+    "Max" : 20,
+    "Remaining" : 20
+  }
+}
\ No newline at end of file

Reply via email to