You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ac...@apache.org on 2016/11/14 08:14:28 UTC

[2/4] camel git commit: CAMEL-10178: Google PubSub Component

http://git-wip-us.apache.org/repos/asf/camel/blob/07f57c33/components/camel-google-pubsub/src/main/java/org/apache/camel/component/google/pubsub/consumer/ExchangeAckTransaction.java
----------------------------------------------------------------------
diff --git a/components/camel-google-pubsub/src/main/java/org/apache/camel/component/google/pubsub/consumer/ExchangeAckTransaction.java b/components/camel-google-pubsub/src/main/java/org/apache/camel/component/google/pubsub/consumer/ExchangeAckTransaction.java
new file mode 100644
index 0000000..b1e7c41
--- /dev/null
+++ b/components/camel-google-pubsub/src/main/java/org/apache/camel/component/google/pubsub/consumer/ExchangeAckTransaction.java
@@ -0,0 +1,61 @@
+/**
+ * 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.google.pubsub.consumer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.component.google.pubsub.GooglePubsubConstants;
+import org.apache.camel.component.google.pubsub.GooglePubsubEndpoint;
+import org.apache.camel.spi.Synchronization;
+
+public class ExchangeAckTransaction extends PubsubAcknowledgement implements Synchronization {
+
+    public ExchangeAckTransaction(GooglePubsubEndpoint endpoint) {
+        super(endpoint);
+    }
+
+    @Override
+    public void onComplete(Exchange exchange) {
+        acknowledge(getAckIdList(exchange));
+    }
+
+    @Override
+    public void onFailure(Exchange exchange) {
+        resetAckDeadline(getAckIdList(exchange));
+    }
+
+    private List<String> getAckIdList(Exchange exchange) {
+        List<String> ackList = new ArrayList<>();
+
+        if (null != exchange.getProperty(Exchange.GROUPED_EXCHANGE)) {
+            for (Exchange ex : (List<Exchange>) exchange.getProperty(Exchange.GROUPED_EXCHANGE)) {
+                String ackId = (String) ex.getIn().getHeader(GooglePubsubConstants.ACK_ID);
+                if (null != ackId) {
+                    ackList.add(ackId);
+                }
+            }
+        } else {
+            ackList.add((String) exchange.getIn().getHeader(GooglePubsubConstants.ACK_ID));
+        }
+
+        return ackList;
+    }
+}
+
+

http://git-wip-us.apache.org/repos/asf/camel/blob/07f57c33/components/camel-google-pubsub/src/main/java/org/apache/camel/component/google/pubsub/consumer/PubsubAcknowledgement.java
----------------------------------------------------------------------
diff --git a/components/camel-google-pubsub/src/main/java/org/apache/camel/component/google/pubsub/consumer/PubsubAcknowledgement.java b/components/camel-google-pubsub/src/main/java/org/apache/camel/component/google/pubsub/consumer/PubsubAcknowledgement.java
new file mode 100644
index 0000000..742c469
--- /dev/null
+++ b/components/camel-google-pubsub/src/main/java/org/apache/camel/component/google/pubsub/consumer/PubsubAcknowledgement.java
@@ -0,0 +1,83 @@
+/**
+ * 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.google.pubsub.consumer;
+
+import java.util.List;
+
+import com.google.api.client.repackaged.com.google.common.base.Strings;
+import com.google.api.services.pubsub.model.AcknowledgeRequest;
+import com.google.api.services.pubsub.model.ModifyAckDeadlineRequest;
+import org.apache.camel.component.google.pubsub.GooglePubsubEndpoint;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public abstract class PubsubAcknowledgement {
+
+    private Logger logger;
+    private final String subscriptionFullName;
+
+    private final GooglePubsubEndpoint endpoint;
+
+    public PubsubAcknowledgement(GooglePubsubEndpoint endpoint) {
+        super();
+        this.endpoint = endpoint;
+        this.subscriptionFullName = String.format("projects/%s/subscriptions/%s", endpoint.getProjectId(), endpoint.getDestinationName());
+
+        String loggerId = endpoint.getLoggerId();
+
+        if (Strings.isNullOrEmpty(loggerId)) {
+            loggerId = this.getClass().getName();
+        }
+
+        logger = LoggerFactory.getLogger(loggerId);
+    }
+
+    void acknowledge(List<String> ackIdList) {
+        AcknowledgeRequest ackRequest = new AcknowledgeRequest()
+                .setAckIds(ackIdList);
+        try {
+            endpoint.getPubsub()
+                    .projects()
+                    .subscriptions()
+                    .acknowledge(subscriptionFullName, ackRequest)
+                    .execute();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    void resetAckDeadline(List<String> ackIdList) {
+
+        ModifyAckDeadlineRequest nackRequest = new ModifyAckDeadlineRequest()
+                .setAckIds(ackIdList)
+                .setAckDeadlineSeconds(0);
+
+        try {
+            endpoint.getPubsub()
+                    .projects()
+                    .subscriptions()
+                    .modifyAckDeadline(subscriptionFullName, nackRequest)
+                    .execute();
+        } catch (Exception e) {
+            // It will timeout automatically on the channel
+            logger.warn("Unable to reset ack deadline " + ackIdList, e);
+        }
+    }
+}
+
+

http://git-wip-us.apache.org/repos/asf/camel/blob/07f57c33/components/camel-google-pubsub/src/main/resources/META-INF/LICENSE.txt
----------------------------------------------------------------------
diff --git a/components/camel-google-pubsub/src/main/resources/META-INF/LICENSE.txt b/components/camel-google-pubsub/src/main/resources/META-INF/LICENSE.txt
new file mode 100644
index 0000000..6b0b127
--- /dev/null
+++ b/components/camel-google-pubsub/src/main/resources/META-INF/LICENSE.txt
@@ -0,0 +1,203 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.
+

http://git-wip-us.apache.org/repos/asf/camel/blob/07f57c33/components/camel-google-pubsub/src/main/resources/META-INF/NOTICE.txt
----------------------------------------------------------------------
diff --git a/components/camel-google-pubsub/src/main/resources/META-INF/NOTICE.txt b/components/camel-google-pubsub/src/main/resources/META-INF/NOTICE.txt
new file mode 100644
index 0000000..2e215bf
--- /dev/null
+++ b/components/camel-google-pubsub/src/main/resources/META-INF/NOTICE.txt
@@ -0,0 +1,11 @@
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Apache Camel distribution.                    ==
+   =========================================================================
+
+   This product includes software developed by
+   The Apache Software Foundation (http://www.apache.org/).
+
+   Please read the different LICENSE files present in the licenses directory of
+   this distribution.

http://git-wip-us.apache.org/repos/asf/camel/blob/07f57c33/components/camel-google-pubsub/src/main/resources/META-INF/services/org/apache/camel/component/google-pubsub
----------------------------------------------------------------------
diff --git a/components/camel-google-pubsub/src/main/resources/META-INF/services/org/apache/camel/component/google-pubsub b/components/camel-google-pubsub/src/main/resources/META-INF/services/org/apache/camel/component/google-pubsub
new file mode 100644
index 0000000..ae01293
--- /dev/null
+++ b/components/camel-google-pubsub/src/main/resources/META-INF/services/org/apache/camel/component/google-pubsub
@@ -0,0 +1,18 @@
+## ------------------------------------------------------------------------
+## 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.
+## ------------------------------------------------------------------------
+
+class=org.apache.camel.component.google.pubsub.GooglePubsubComponent

http://git-wip-us.apache.org/repos/asf/camel/blob/07f57c33/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/PubsubTestSupport.java
----------------------------------------------------------------------
diff --git a/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/PubsubTestSupport.java b/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/PubsubTestSupport.java
new file mode 100644
index 0000000..47ed6cc
--- /dev/null
+++ b/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/PubsubTestSupport.java
@@ -0,0 +1,140 @@
+/**
+ * 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.google.pubsub;
+
+import java.io.InputStream;
+import java.util.Properties;
+
+import com.google.api.client.googleapis.json.GoogleJsonResponseException;
+import com.google.api.services.pubsub.Pubsub;
+import com.google.api.services.pubsub.model.Subscription;
+import com.google.api.services.pubsub.model.Topic;
+import org.apache.camel.CamelContext;
+import org.apache.camel.component.properties.PropertiesComponent;
+import org.apache.camel.impl.JndiRegistry;
+import org.apache.camel.test.junit4.CamelTestSupport;
+
+public class PubsubTestSupport extends CamelTestSupport {
+
+    public static final String SERVICE_KEY;
+    public static final String SERVICE_ACCOUNT;
+    public static final String PROJECT_ID;
+    public static final String SERVICE_URL;
+
+    static {
+        Properties testProperties = loadProperties();
+        SERVICE_KEY = testProperties.getProperty("service.key");
+        SERVICE_ACCOUNT = testProperties.getProperty("service.account");
+        PROJECT_ID = testProperties.getProperty("project.id");
+        SERVICE_URL = testProperties.getProperty("test.serviceURL");
+    }
+
+    private static Properties loadProperties() {
+        Properties testProperties = new Properties();
+        InputStream fileIn = testProperties.getClass().getResourceAsStream("/simple.properties");
+        try {
+            testProperties.load(fileIn);
+
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+
+        return testProperties;
+    }
+
+    protected void addPubsubComponent(CamelContext context) {
+
+        GooglePubsubConnectionFactory cf = new GooglePubsubConnectionFactory()
+            .setServiceAccount(SERVICE_ACCOUNT)
+            .setServiceAccountKey(SERVICE_KEY)
+            .setServiceURL(SERVICE_URL);
+
+        GooglePubsubComponent component = new GooglePubsubComponent();
+        component.setConnectionFactory(cf);
+
+        context.addComponent("google-pubsub", component);
+        context.addComponent("properties", new PropertiesComponent("ref:prop"));
+    }
+
+    @Override
+    protected JndiRegistry createRegistry() throws Exception {
+        JndiRegistry jndi = super.createRegistry();
+        jndi.bind("prop", loadProperties());
+        return jndi;
+    }
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        CamelContext context = super.createCamelContext();
+        addPubsubComponent(context);
+        return context;
+    }
+
+    public static void createTopicSubscriptionPair(String topicName, String subscriptionName) throws Exception {
+        createTopicSubscriptionPair(topicName, subscriptionName, 10);
+    }
+
+    public static void createTopicSubscriptionPair(String topicName, String subscriptionName, int ackDealineSeconds) throws Exception {
+
+        Pubsub pubsub = new GooglePubsubConnectionFactory()
+            .setServiceAccount(SERVICE_ACCOUNT)
+            .setServiceAccountKey(SERVICE_KEY)
+            .setServiceURL(SERVICE_URL)
+            .getClient();
+
+        String topicFullName = String.format("projects/%s/topics/%s",
+                                         PubsubTestSupport.PROJECT_ID,
+                                         topicName);
+
+        String subscriptionFullName = String.format("projects/%s/subscriptions/%s",
+                                                PubsubTestSupport.PROJECT_ID,
+                                                subscriptionName);
+
+        try {
+            pubsub.projects()
+                  .topics()
+                  .create(topicFullName, new Topic())
+                  .execute();
+        } catch (Exception e) {
+            handleAlreadyExistsException(e);
+        }
+
+        try {
+            Subscription subscription = new Subscription()
+                    .setTopic(topicFullName)
+                    .setAckDeadlineSeconds(ackDealineSeconds);
+
+            pubsub.projects()
+                  .subscriptions()
+                  .create(subscriptionFullName, subscription)
+                  .execute();
+        } catch (Exception e) {
+            handleAlreadyExistsException(e);
+        }
+    }
+
+    private static void handleAlreadyExistsException(Exception e) throws Exception {
+        if (e instanceof GoogleJsonResponseException) {
+            GoogleJsonResponseException exc = (GoogleJsonResponseException) e;
+            // 409 indicates that the resource is available already
+            if (409 == exc.getStatusCode()) {
+                return;
+            }
+        }
+        throw e;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/07f57c33/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/integration/AckModeNoneTest.java
----------------------------------------------------------------------
diff --git a/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/integration/AckModeNoneTest.java b/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/integration/AckModeNoneTest.java
new file mode 100644
index 0000000..e2cc821f
--- /dev/null
+++ b/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/integration/AckModeNoneTest.java
@@ -0,0 +1,94 @@
+/**
+ * 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.google.pubsub.integration;
+
+import org.apache.camel.Endpoint;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Exchange;
+import org.apache.camel.Produce;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.google.pubsub.PubsubTestSupport;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.impl.DefaultExchange;
+import org.junit.BeforeClass;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class AckModeNoneTest extends PubsubTestSupport {
+
+    private static final String TOPIC_NAME = "ackNoneTopic";
+    private static final String SUBSCRIPTION_NAME = "ackNoneSub";
+
+    @EndpointInject(uri = "direct:in")
+    private Endpoint directIn;
+
+    @EndpointInject(uri = "google-pubsub:{{project.id}}:" + TOPIC_NAME)
+    private Endpoint pubsubTopic;
+
+    @EndpointInject(uri = "google-pubsub:{{project.id}}:"
+            + SUBSCRIPTION_NAME
+            + "?ackMode=NONE")
+    private Endpoint pubsubSub;
+
+    @EndpointInject(uri = "mock:receiveResult")
+    private MockEndpoint receiveResult;
+
+    @Produce(uri = "direct:in")
+    private ProducerTemplate producer;
+
+    @BeforeClass
+    public static void createPubSub() throws Exception {
+        createTopicSubscriptionPair(TOPIC_NAME, SUBSCRIPTION_NAME, 1);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() {
+                from(directIn)
+                    .routeId("AckNONE_SEND")
+                    .to(pubsubTopic);
+
+                from(pubsubSub)
+                    .routeId("AckNONE_RECV")
+                    .autoStartup(true)
+                    .to(receiveResult);
+            }
+        };
+    }
+    /**
+     * Expecting two messages received for the one sent.
+     * With Ack mode set to NONE the same message will be delivered again and again,
+     * after the deadline expiration.
+     * Setting deadline to 1 second and waiting for more than 2 to ensure the message has been resent.
+     * @throws Exception
+     */
+    @Test
+    public void singleMessage() throws Exception {
+
+        Exchange exchange = new DefaultExchange(context);
+
+        exchange.getIn().setBody("ACK NONE  : " + exchange.getExchangeId());
+
+        receiveResult.expectedMessageCount(2);
+        producer.send(exchange);
+        receiveResult.assertIsSatisfied(4000);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/07f57c33/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/integration/AcknowledgementTest.java
----------------------------------------------------------------------
diff --git a/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/integration/AcknowledgementTest.java b/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/integration/AcknowledgementTest.java
new file mode 100644
index 0000000..0eee503
--- /dev/null
+++ b/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/integration/AcknowledgementTest.java
@@ -0,0 +1,136 @@
+/**
+ * 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.google.pubsub.integration;
+
+import org.apache.camel.Endpoint;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.Produce;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.google.pubsub.PubsubTestSupport;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.impl.DefaultExchange;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class AcknowledgementTest extends PubsubTestSupport {
+
+    private static final String TOPIC_NAME = "failureSingle";
+    private static final String SUBSCRIPTION_NAME = "failureSub";
+    private static Boolean fail = false;
+
+    @EndpointInject(uri = "direct:in")
+    private Endpoint directIn;
+
+    @EndpointInject(uri = "google-pubsub:{{project.id}}:" + TOPIC_NAME)
+    private Endpoint pubsubTopic;
+
+    @EndpointInject(uri = "google-pubsub:{{project.id}}:" + SUBSCRIPTION_NAME)
+    private Endpoint pubsubSubscription;
+
+    @EndpointInject(uri = "mock:receiveResult")
+    private MockEndpoint receiveResult;
+
+    @Produce(uri = "direct:in")
+    private ProducerTemplate producer;
+
+    @BeforeClass
+    public static void createTopicSubscription() throws Exception {
+        createTopicSubscriptionPair(TOPIC_NAME, SUBSCRIPTION_NAME);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() {
+                from(directIn)
+                        .routeId("Send_to_Fail")
+                        .to(pubsubTopic);
+
+                from(pubsubSubscription)
+                        .routeId("Fail_Receive")
+                        .autoStartup(true)
+                        .process(
+                                new Processor() {
+                                    @Override
+                                    public void process(Exchange exchange) throws Exception {
+                                        if (AcknowledgementTest.fail) {
+                                            Thread.sleep(750);
+                                            throw new Exception("fail");
+                                        }
+                                    }
+                                }
+                        )
+                        .to(receiveResult);
+            }
+        };
+    }
+
+    /**
+     * Testing acknowledgements.
+     * Three checks to be performed.
+     *
+     * Check 1 : Successful round trip.
+     * Message received and acknowledged.
+     * If the ACK fails for the first message, it will be delivered again for the second check and the body comparison will fail.
+     *
+     * Check 2 : Failure. As the route throws and exception and the message is NACK'ed.
+     * The message should remain in the PubSub Subscription for the third check.
+     *
+     * Check 3 : Success for the second message.
+     * The message received should match the second message sent.
+     *
+     * @throws Exception
+     */
+
+    @Test
+    public void singleMessage() throws Exception {
+
+        Exchange firstExchange = new DefaultExchange(context);
+        Exchange secondExchange = new DefaultExchange(context);
+
+        firstExchange.getIn().setBody("SUCCESS  : " + firstExchange.getExchangeId());
+        secondExchange.getIn().setBody("fail  : " + secondExchange.getExchangeId());
+
+        // Check 1 : Successful roundtrip.
+        System.out.println("Acknowledgement Test : Stage 1");
+        receiveResult.reset();
+        fail = false;
+        receiveResult.expectedMessageCount(1);
+        receiveResult.expectedBodiesReceivedInAnyOrder(firstExchange.getIn().getBody());
+        producer.send(firstExchange);
+        receiveResult.assertIsSatisfied(3000);
+
+        // Check 2 : Failure for the second message.
+        System.out.println("Acknowledgement Test : Stage 2");
+        receiveResult.reset();
+        fail = true;
+        receiveResult.expectedMessageCount(0);
+        producer.send(secondExchange);
+        receiveResult.assertIsSatisfied(3000);
+
+        // Check 3 : Success for the second message.
+        System.out.println("Acknowledgement Test : Stage 3");
+        receiveResult.reset();
+        fail = false;
+        receiveResult.expectedMessageCount(1);
+        receiveResult.expectedBodiesReceivedInAnyOrder(secondExchange.getIn().getBody());
+        receiveResult.assertIsSatisfied(3000);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/07f57c33/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/integration/BodyTypesTest.java
----------------------------------------------------------------------
diff --git a/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/integration/BodyTypesTest.java b/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/integration/BodyTypesTest.java
new file mode 100644
index 0000000..a0f8094
--- /dev/null
+++ b/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/integration/BodyTypesTest.java
@@ -0,0 +1,171 @@
+/**
+ * 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.google.pubsub.integration;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.camel.Endpoint;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Exchange;
+import org.apache.camel.Produce;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.google.pubsub.PubsubTestSupport;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.impl.DefaultExchange;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class BodyTypesTest extends PubsubTestSupport {
+
+    private static final String TOPIC_NAME = "typesSend";
+    private static final String SUBSCRIPTION_NAME = "TypesReceive";
+
+    @EndpointInject(uri = "direct:from")
+    private Endpoint directIn;
+
+    @EndpointInject(uri = "google-pubsub:{{project.id}}:" + TOPIC_NAME)
+    private Endpoint pubsubTopic;
+
+    @EndpointInject(uri = "mock:sendResult")
+    private MockEndpoint sendResult;
+
+    @EndpointInject(uri = "google-pubsub:{{project.id}}:" + SUBSCRIPTION_NAME)
+    private Endpoint pubsubSubscription;
+
+    @EndpointInject(uri = "mock:receiveResult")
+    private MockEndpoint receiveResult;
+
+    @Produce(uri = "direct:from")
+    private ProducerTemplate producer;
+
+    @BeforeClass
+    public static void createTopicSubscription() throws Exception {
+        createTopicSubscriptionPair(TOPIC_NAME, SUBSCRIPTION_NAME);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() {
+                from(directIn)
+                        .routeId("Single_Send")
+                        .to(pubsubTopic)
+                        .to(sendResult);
+
+                from(pubsubSubscription)
+                        .routeId("Single_Receive")
+                        .to("direct:one");
+
+                from("direct:one")
+                        .to(receiveResult);
+            }
+        };
+    }
+
+    @Test
+    public void byteArray() throws Exception {
+
+        Exchange exchange = new DefaultExchange(context);
+
+        byte[] body = {1, 2, 3};
+
+        exchange.getIn().setBody(body);
+
+        receiveResult.expectedMessageCount(1);
+
+        producer.send(exchange);
+
+        List<Exchange> sentExchanges = sendResult.getExchanges();
+        assertEquals("Sent exchanges", 1, sentExchanges.size());
+
+        Exchange sentExchange = sentExchanges.get(0);
+
+        assertTrue("Sent body type is byte[]",
+                   sentExchange.getIn().getBody() instanceof byte[]);
+
+        assertTrue("Sent body type is the one sent",
+                   sentExchange.getIn().getBody() == body);
+
+        receiveResult.assertIsSatisfied(5000);
+
+        List<Exchange> receivedExchanges = receiveResult.getExchanges();
+
+        assertNotNull("Received exchanges", receivedExchanges);
+
+        Exchange receivedExchange = receivedExchanges.get(0);
+
+        assertTrue("Received body is of byte[] type",
+                   receivedExchange.getIn().getBody() instanceof byte[]);
+
+        assertTrue("Received body equals sent",
+                   Arrays.equals(body, (byte[]) receivedExchange.getIn().getBody()));
+
+    }
+
+    @Test
+    public void objectSerialised() throws Exception {
+
+        Exchange exchange = new DefaultExchange(context);
+
+        Map<String, String> body = new HashMap<>();
+        body.put("KEY", "VALUE1212");
+
+        exchange.getIn().setBody(body);
+
+        receiveResult.expectedMessageCount(1);
+
+        producer.send(exchange);
+
+        List<Exchange> sentExchanges = sendResult.getExchanges();
+        assertEquals("Sent exchanges", 1, sentExchanges.size());
+
+        Exchange sentExchange = sentExchanges.get(0);
+
+        assertTrue("Sent body type is byte[]",
+                   sentExchange.getIn().getBody() instanceof Map);
+
+        receiveResult.assertIsSatisfied(5000);
+
+        List<Exchange> receivedExchanges = receiveResult.getExchanges();
+
+        assertNotNull("Received exchanges", receivedExchanges);
+
+        Exchange receivedExchange = receivedExchanges.get(0);
+
+        assertTrue("Received body is of byte[] type",
+                   receivedExchange.getIn().getBody() instanceof byte[]);
+
+        Object bodyReceived = deserialize((byte[]) receivedExchange.getIn().getBody());
+
+        assertTrue("Received body is a Map ",
+                   ((Map) bodyReceived).get("KEY").equals("VALUE1212"));
+
+    }
+
+    public static Object deserialize(byte[] data) throws IOException, ClassNotFoundException {
+        ByteArrayInputStream in = new ByteArrayInputStream(data);
+        ObjectInputStream is = new ObjectInputStream(in);
+        return is.readObject();
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/07f57c33/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/integration/GroupedExchangeRoundtripTest.java
----------------------------------------------------------------------
diff --git a/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/integration/GroupedExchangeRoundtripTest.java b/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/integration/GroupedExchangeRoundtripTest.java
new file mode 100644
index 0000000..2a06465
--- /dev/null
+++ b/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/integration/GroupedExchangeRoundtripTest.java
@@ -0,0 +1,119 @@
+/**
+ * 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.google.pubsub.integration;
+
+import java.util.List;
+
+import org.apache.camel.Endpoint;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Exchange;
+import org.apache.camel.Produce;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.google.pubsub.PubsubTestSupport;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.impl.DefaultExchange;
+import org.apache.camel.processor.aggregate.GroupedExchangeAggregationStrategy;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class GroupedExchangeRoundtripTest extends PubsubTestSupport {
+
+    private static final String TOPIC_NAME = "groupTopic";
+    private static final String SUBSCRIPTION_NAME = "groupSubscription";
+
+    @EndpointInject(uri = "direct:aggregator")
+    private Endpoint aggregator;
+
+    @EndpointInject(uri = "google-pubsub:{{project.id}}:" + TOPIC_NAME)
+    private Endpoint topic;
+
+    @EndpointInject(uri = "mock:sendResult")
+    private MockEndpoint sendResult;
+
+    @EndpointInject(uri = "google-pubsub:{{project.id}}:" + SUBSCRIPTION_NAME)
+    private Endpoint pubsubSubscription;
+
+    @EndpointInject(uri = "mock:receiveResult")
+    private MockEndpoint receiveResult;
+
+    @Produce(uri = "direct:aggregator")
+    private ProducerTemplate producer;
+
+    @BeforeClass
+    public static void createTopicSubscription() throws Exception {
+        createTopicSubscriptionPair(TOPIC_NAME, SUBSCRIPTION_NAME);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() {
+
+                from(aggregator)
+                        .routeId("Group_Send")
+                        .aggregate(new GroupedExchangeAggregationStrategy())
+                        .constant(true)
+                        .completionSize(2)
+                        .completionTimeout(5000L)
+                        .to(topic)
+                        .to(sendResult);
+
+                from(pubsubSubscription)
+                        .routeId("Group_Receive")
+                        .to(receiveResult);
+
+            }
+        };
+    }
+
+    /**
+     * Tests that a grouped exhcange is successfully received
+     *
+     * @throws Exception
+     */
+
+    @Test
+    public void sendGrouped() throws Exception {
+
+        Exchange exchange1 = new DefaultExchange(context);
+        Exchange exchange2 = new DefaultExchange(context);
+
+        String body1 = "Group 1.1 : " + exchange1.getExchangeId();
+        String body2 = "Group 1.2 : " + exchange2.getExchangeId();
+
+        receiveResult.expectedMessageCount(2);
+        receiveResult.expectedBodiesReceivedInAnyOrder(body1, body2);
+
+        exchange1.getIn().setBody(body1);
+        exchange2.getIn().setBody(body2);
+
+        producer.send(exchange1);
+        producer.send(exchange2);
+
+        receiveResult.assertIsSatisfied(3000);
+
+        // Send result section
+        List<Exchange> results = sendResult.getExchanges();
+        assertEquals("Received exchanges", 1, results.size());
+
+        List exchangeGrouped = (List) results
+                .get(0)
+                .getProperty(Exchange.GROUPED_EXCHANGE);
+        assertEquals("Received messages within the exchange", 2, exchangeGrouped.size());
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/07f57c33/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/integration/PubsubConnectionFactoryTest.java
----------------------------------------------------------------------
diff --git a/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/integration/PubsubConnectionFactoryTest.java b/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/integration/PubsubConnectionFactoryTest.java
new file mode 100644
index 0000000..60dbacd
--- /dev/null
+++ b/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/integration/PubsubConnectionFactoryTest.java
@@ -0,0 +1,65 @@
+/**
+ * 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.google.pubsub.integration;
+
+import java.io.File;
+
+import com.google.api.services.pubsub.Pubsub;
+import org.apache.camel.component.google.pubsub.GooglePubsubConnectionFactory;
+import org.apache.camel.component.google.pubsub.PubsubTestSupport;
+import org.junit.Test;
+
+public class PubsubConnectionFactoryTest extends PubsubTestSupport {
+
+    /**
+     * Testing Credentials File only,
+     * the explicitly set Service Account and Key are tested everywhere else.
+     *
+     * A section of the test is disabled by default as it relies on
+     *
+     *  - a valid credentials file
+     *  - a valid project
+     *
+     * and therefore can not be tested with the PubSub Emulator
+     *
+     * Defaults Option is not tested.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testCredentialsFile() throws Exception {
+
+        ClassLoader classLoader = getClass().getClassLoader();
+        File file = new File(classLoader.getResource("camel-pubsub-component.json").getFile());
+
+        GooglePubsubConnectionFactory cf = new GooglePubsubConnectionFactory()
+                .setCredentialsFileLocation(file.getAbsolutePath())
+                .setServiceURL(SERVICE_URL);
+
+        Pubsub pubsub = cf.getClient();
+
+        String query = String.format("projects/%s", PROJECT_ID);
+        // [ DEPENDS on actual project being available]
+        /*
+        pubsub.projects()
+              .topics()
+              .list(query)
+              .execute();
+
+        */
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/07f57c33/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/integration/SingleExchangeRoundtripTest.java
----------------------------------------------------------------------
diff --git a/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/integration/SingleExchangeRoundtripTest.java b/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/integration/SingleExchangeRoundtripTest.java
new file mode 100644
index 0000000..a0bb7ee
--- /dev/null
+++ b/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/integration/SingleExchangeRoundtripTest.java
@@ -0,0 +1,132 @@
+/**
+ * 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.google.pubsub.integration;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.camel.Endpoint;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Exchange;
+import org.apache.camel.Produce;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.google.pubsub.GooglePubsubConstants;
+import org.apache.camel.component.google.pubsub.PubsubTestSupport;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.impl.DefaultExchange;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class SingleExchangeRoundtripTest extends PubsubTestSupport {
+
+    private static final String TOPIC_NAME = "singleSend";
+    private static final String SUBSCRIPTION_NAME = "singleReceive";
+
+    @EndpointInject(uri = "direct:from")
+    private Endpoint directIn;
+
+    @EndpointInject(uri = "google-pubsub:{{project.id}}:" + TOPIC_NAME)
+    private Endpoint pubsubTopic;
+
+    @EndpointInject(uri = "mock:sendResult")
+    private MockEndpoint sendResult;
+
+    @EndpointInject(uri = "google-pubsub:{{project.id}}:" + SUBSCRIPTION_NAME)
+    private Endpoint pubsubSubscription;
+
+    @EndpointInject(uri = "mock:receiveResult")
+    private MockEndpoint receiveResult;
+
+    @Produce(uri = "direct:from")
+    private ProducerTemplate producer;
+
+    @BeforeClass
+    public static void createTopicSubscription() throws Exception {
+        createTopicSubscriptionPair(TOPIC_NAME, SUBSCRIPTION_NAME);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() {
+                from(directIn)
+                        .routeId("Single_Send")
+                        .to(pubsubTopic)
+                        .to(sendResult);
+
+                from(pubsubSubscription)
+                        .routeId("Single_Receive")
+                        .to("direct:one");
+
+                from("direct:one")
+                        .to(receiveResult);
+            }
+        };
+    }
+
+    @Test
+    public void testSingleMessageSend() throws Exception {
+
+        Exchange exchange = new DefaultExchange(context);
+
+        String attributeKey = "ATTRIBUTE-TEST-KEY";
+        String attributeValue = "ATTRIBUTE-TEST-VALUE";
+
+        Map<String, String> attributes = new HashMap<>();
+        attributes.put(attributeKey, attributeValue);
+
+        exchange.getIn().setBody("Single  : " + exchange.getExchangeId());
+        exchange.getIn().setHeader(GooglePubsubConstants.ATTRIBUTES, attributes);
+
+        receiveResult.expectedMessageCount(1);
+        receiveResult.expectedBodiesReceivedInAnyOrder(exchange.getIn().getBody());
+
+        producer.send(exchange);
+
+        List<Exchange> sentExchanges = sendResult.getExchanges();
+        assertEquals("Sent exchanges", 1, sentExchanges.size());
+
+        Exchange sentExchange = sentExchanges.get(0);
+
+        assertEquals("Sent ID",
+                     exchange.getIn().getHeader(GooglePubsubConstants.MESSAGE_ID),
+                     sentExchange.getIn().getHeader(GooglePubsubConstants.MESSAGE_ID));
+
+        receiveResult.assertIsSatisfied(5000);
+
+        List<Exchange> receivedExchanges = receiveResult.getExchanges();
+
+        assertNotNull("Received exchanges", receivedExchanges);
+
+        Exchange receivedExchange = receivedExchanges.get(0);
+
+        assertNotNull("PUBSUB Message ID Property",
+                      receivedExchange.getIn().getHeader(GooglePubsubConstants.MESSAGE_ID));
+        assertNotNull("PUBSUB Ack ID Property",
+                      receivedExchange.getIn().getHeader(GooglePubsubConstants.ACK_ID));
+        assertNotNull("PUBSUB Published Time",
+                      receivedExchange.getIn().getHeader(GooglePubsubConstants.PUBLISH_TIME));
+
+        assertEquals("PUBSUB Header Attribute", attributeValue,
+                     ((Map) receivedExchange.getIn().getHeader(GooglePubsubConstants.ATTRIBUTES)).get(attributeKey));
+
+        assertEquals(sentExchange.getIn().getHeader(GooglePubsubConstants.MESSAGE_ID),
+                     receivedExchange.getIn().getHeader(GooglePubsubConstants.MESSAGE_ID));
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/07f57c33/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/unit/PubsubComponentTest.java
----------------------------------------------------------------------
diff --git a/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/unit/PubsubComponentTest.java b/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/unit/PubsubComponentTest.java
new file mode 100644
index 0000000..3d9a840
--- /dev/null
+++ b/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/unit/PubsubComponentTest.java
@@ -0,0 +1,43 @@
+/**
+ * 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.google.pubsub.unit;
+
+import org.apache.camel.Component;
+import org.apache.camel.component.google.pubsub.GooglePubsubComponent;
+import org.apache.camel.component.google.pubsub.PubsubTestSupport;
+import org.junit.Test;
+
+public class PubsubComponentTest extends PubsubTestSupport {
+
+    @Test
+    public void testComponentConfiguration() throws Exception {
+
+        Component contextComponent = context.hasComponent("google-pubsub");
+
+        assertNotNull(contextComponent);
+        assertTrue(contextComponent instanceof GooglePubsubComponent);
+
+        GooglePubsubComponent pubsubComponent = (GooglePubsubComponent) contextComponent;
+
+        assertEquals(SERVICE_ACCOUNT,
+                     pubsubComponent.getConnectionFactory().getServiceAccount());
+
+        assertEquals(SERVICE_KEY,
+                     pubsubComponent.getConnectionFactory().getServiceAccountKey());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/07f57c33/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/unit/PubsubEndpointTest.java
----------------------------------------------------------------------
diff --git a/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/unit/PubsubEndpointTest.java b/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/unit/PubsubEndpointTest.java
new file mode 100644
index 0000000..50a2875
--- /dev/null
+++ b/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/unit/PubsubEndpointTest.java
@@ -0,0 +1,76 @@
+/**
+ * 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.google.pubsub.unit;
+
+import org.apache.camel.Endpoint;
+import org.apache.camel.EndpointConfiguration;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.ExchangePattern;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.google.pubsub.GooglePubsubConstants;
+import org.apache.camel.component.google.pubsub.GooglePubsubEndpoint;
+import org.apache.camel.component.google.pubsub.PubsubTestSupport;
+import org.junit.Test;
+
+public class PubsubEndpointTest extends PubsubTestSupport {
+
+    private static final String TEST_SUBSCRIPTION_NAME = "test-sub-name";
+
+    // For testing purposes the URI params need to be aligned in alphabetical order
+    private static final String SUBSCRIPTION_URI = TEST_SUBSCRIPTION_NAME
+            + "?ackMode=NONE"
+            + "&concurrentConsumers=5"
+            + "&maxMessagesPerPoll=2";
+
+    @EndpointInject(uri = "google-pubsub://{{project.id}}:" + SUBSCRIPTION_URI)
+    private Endpoint from;
+
+    @EndpointInject(uri = "direct:to")
+    private Endpoint to;
+
+    @Test
+    public void testEndpointConfiguration() throws Exception {
+
+        // :1 identifies the first registered endpoint fo a type in the context
+        Endpoint endpoint = context.hasEndpoint(String.format("google-pubsub:%s:%s:1", PROJECT_ID, SUBSCRIPTION_URI));
+        assertNotNull(String.format("Endpoint 'google-pubsub:%s:%s' is not found in Camel Context",
+                                    PROJECT_ID, SUBSCRIPTION_URI), endpoint);
+
+        assertTrue(endpoint instanceof GooglePubsubEndpoint);
+        GooglePubsubEndpoint pubsubEndpoint = (GooglePubsubEndpoint) endpoint;
+
+        assertEquals(ExchangePattern.InOnly, pubsubEndpoint.createExchange().getPattern());
+        assertEquals("google-pubsub", pubsubEndpoint.getEndpointConfiguration().getParameter(EndpointConfiguration.URI_SCHEME));
+        assertEquals("google-pubsub://" + PROJECT_ID + ":" + SUBSCRIPTION_URI, pubsubEndpoint.getEndpointUri());
+
+        assertEquals(PROJECT_ID, pubsubEndpoint.getProjectId());
+        assertEquals(TEST_SUBSCRIPTION_NAME, pubsubEndpoint.getDestinationName());
+        assertEquals(new Integer(5), pubsubEndpoint.getConcurrentConsumers());
+        assertEquals(new Integer(2), pubsubEndpoint.getMaxMessagesPerPoll());
+        assertEquals(GooglePubsubConstants.AckMode.NONE, pubsubEndpoint.getAckMode());
+
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() {
+                from(from).to(to);
+            }
+        };
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/07f57c33/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/unit/PubsubProducerTest.java
----------------------------------------------------------------------
diff --git a/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/unit/PubsubProducerTest.java b/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/unit/PubsubProducerTest.java
new file mode 100644
index 0000000..311b4fa
--- /dev/null
+++ b/components/camel-google-pubsub/src/test/java/org/apache/camel/component/google/pubsub/unit/PubsubProducerTest.java
@@ -0,0 +1,58 @@
+/**
+ * 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.google.pubsub.unit;
+
+import org.apache.camel.Endpoint;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Producer;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.google.pubsub.GooglePubsubProducer;
+import org.apache.camel.component.google.pubsub.PubsubTestSupport;
+import org.junit.Test;
+
+public class PubsubProducerTest extends PubsubTestSupport {
+
+    private static final String TEST_TOPIC_NAME = "test-topic-name";
+
+    @EndpointInject(uri = "google-pubsub:{{project.id}}:" + TEST_TOPIC_NAME)
+    private Endpoint to;
+
+    @EndpointInject(uri = "direct:from")
+    private Endpoint from;
+
+    @Test
+    public void testProducerConfiguration() throws Exception {
+        // :1 indicates first of a component type in Camel context
+        Endpoint endpoint = context.hasEndpoint(String.format("google-pubsub:%s:%s:1", PROJECT_ID, TEST_TOPIC_NAME));
+        assertNotNull(String.format("Endpoint 'google-pubsub:%s:$s' is not found in Camel Context",
+                                    PROJECT_ID,
+                                    TEST_TOPIC_NAME), endpoint);
+
+        Producer producer = endpoint.createProducer();
+        assertTrue(producer instanceof GooglePubsubProducer);
+    }
+
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() {
+                from(from).to(to);
+            }
+        };
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/07f57c33/components/camel-google-pubsub/src/test/resources/camel-pubsub-component.json
----------------------------------------------------------------------
diff --git a/components/camel-google-pubsub/src/test/resources/camel-pubsub-component.json b/components/camel-google-pubsub/src/test/resources/camel-pubsub-component.json
new file mode 100644
index 0000000..7c4eef8
--- /dev/null
+++ b/components/camel-google-pubsub/src/test/resources/camel-pubsub-component.json
@@ -0,0 +1,12 @@
+{
+  "type": "service_account",
+  "project_id": "test-project",
+  "private_key_id": "1f36ef368ef8f210cc739b93a769804f501bd75b",
+  "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCmPGGWiCb2Z7+c\n26Tk/J+gYCpP0VLrsnlkORrIRYbaJrGn/C0cSoVXqBh3yZbKWIWrD6/cesuJCPHc\n9xddJhlpDKgOjYvlpFQofPpacEi+JhQjpmsYYqPC+TZL6YlbWSuFR4cqtVFFgbT/\nbBQBhkQF7Bhk0nEUus0B2DrE+L7lOz2Ml+7gwdFILc8i94GnW//CPW9VNv9xRo4g\npPkdHjTCsJGj3CrTCHfCQiCEHtk4d5nztgkENpvObRhXb2pr9+xNVu3Ll4M86deH\nzdP/0O+MK7+W07KgvCM1y9SDT4AFQm9ATCiaP7BXJcgEl98HAdQ5i0EEyyc9+YiB\nuCHI04J/AgMBAAECggEATVAn0urftBnsc/dzaUxUsTIIe7bO6e/HpWUpn5s2bJ8y\nYP5XvKCsA2iaeJu5FcK16CkTkWdK4iDW2/3PT/M4PjM0tg/+0H7s5Se7B/TQ4B61\nnx73EBBQOY3OQuAKkgGWzBXIN4S8l6cLlv+dDlhzqo1zivCUxx9Z2VHHg3Rs1A9I\n7C+nIBDRNKqbxZ+5eHPmPvpu32W74cpbhIyPE+6FYjTa6lO9OHdL5YVW+q8u5InX\n0XT0lzmMVjMK7HFm5j5vaUU/p1i1/pGsWvdhfPV7qx2utJWV5sVla0uUBOndg2bO\nAwUl84LBaPiLgCBNbPI1hB7w+2hG2wYViFLWk6MMgQKBgQDczAD7aBeOQDaueKup\nZe8ykJlWNytwknWijSAN/vXH98NvRgnLcig5sZFVc4BiHnnAp6gpMnpIOBZnGBI0\nKR46jtkyOIdBpLN23E4z+MyPLQDlmrq8LLwvXFF5cwOLQlBwC0jlzwm+9k9j9dHh\n/WNHP68T4ahMJ56pCFGyFJNBcw
 KBgQDAvW1Ds1Lm7ryIaDex4z6Vq2LwuEdDjXY7\n8lNvWMTnNazJ8v+YqFRygFpHo1BO48MFAteqxR6H3UxV3wrOlmRUjUSLfm6//O93\nRkbPkAeHeOPy9gOkYCaNcZdjZCtqPEHPA++zMyZyjnGzRV5D4XEbxa6T2n3QcX4T\noNan0mgHxQKBgErOY1bKQZDUeLJL9/0AqDX9f7YSIwmU1X4pSj7zrtn9O52roQ3o\ns3A4lQDajRixMpbvNq4eiAeH2S88nI5HkBJO6490T38SCiuvIF/DX6rymGcyMSoo\nDeoN4RzAtuarpQ0RBbW2m5qzYNqBIobqjoRJM0wNHDQRCFREmUk4Z1u5AoGBALsc\naqHJyhak9+SZAFCyosRcMN4umAhtobXKp9M141nuksMvI5GJAQpzrrFTS5h6po4L\n12FSojQV05CdynkKKXan+j5NzKiXncY2NHI2igirhOgOizSdn2+7MdPsn/UvcFfP\no3ldk9qsjJcUJdJSXyMuAzBIcdHVDCd0Ak/EBPhdAoGAVIQyUIJdkn7u/9dKOpzR\novChkG6fe7bz7aTbfmexZQupQSgjKSd8eR/+Y+Q2Ar4yDsXyoGbCdt2O3y4hM5sv\nofbk2n7qmKT0ErI8EjxDNG4q7zvxaFWym9/1O/uCSgIK/qlGuF/JnFo0c/hh2rla\nq/i0Qx/jd4U1P455NxBkAAU=\n-----END PRIVATE KEY-----\n",
+  "client_email": "camel-pubsub-component-1@appspot.gserviceaccount.com",
+  "client_id": "117882068603044062985",
+  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
+  "token_uri": "https://accounts.google.com/o/oauth2/token",
+  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
+  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/camel-pubsub-component-1%40appspot.gserviceaccount.com"
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/07f57c33/components/camel-google-pubsub/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/components/camel-google-pubsub/src/test/resources/log4j.properties b/components/camel-google-pubsub/src/test/resources/log4j.properties
new file mode 100644
index 0000000..c47ad73
--- /dev/null
+++ b/components/camel-google-pubsub/src/test/resources/log4j.properties
@@ -0,0 +1,37 @@
+## ------------------------------------------------------------------------
+## 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.
+## ------------------------------------------------------------------------
+
+#
+# The logging properties used during tests..
+#
+log4j.rootLogger=INFO, out
+
+#log4j.logger.org.apache.camel.component.google.pubsub=TRACE
+#log4j.logger.org.apache.camel=DEBUG
+#log4j.logger.org.apache.camel.impl=WARN
+
+# CONSOLE appender not used by default
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
+
+# File appender
+log4j.appender.out=org.apache.log4j.FileAppender
+log4j.appender.out.layout=org.apache.log4j.PatternLayout
+log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
+log4j.appender.out.file=target/camel-google-pubsub-test.log
+log4j.appender.out.append=true

http://git-wip-us.apache.org/repos/asf/camel/blob/07f57c33/components/camel-google-pubsub/src/test/resources/logging.properties
----------------------------------------------------------------------
diff --git a/components/camel-google-pubsub/src/test/resources/logging.properties b/components/camel-google-pubsub/src/test/resources/logging.properties
new file mode 100644
index 0000000..0f88cc7
--- /dev/null
+++ b/components/camel-google-pubsub/src/test/resources/logging.properties
@@ -0,0 +1,4 @@
+.level=SEVERE
+handlers= java.util.logging.ConsoleHandler
+java.util.logging.ConsoleHandler.level = SEVERE
+java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter

http://git-wip-us.apache.org/repos/asf/camel/blob/07f57c33/components/camel-google-pubsub/src/test/resources/simple.properties
----------------------------------------------------------------------
diff --git a/components/camel-google-pubsub/src/test/resources/simple.properties b/components/camel-google-pubsub/src/test/resources/simple.properties
new file mode 100644
index 0000000..9e4feaf
--- /dev/null
+++ b/components/camel-google-pubsub/src/test/resources/simple.properties
@@ -0,0 +1,9 @@
+project.id=test-project
+topic.name=test-topic
+subscription.name=test-topic-subscription
+# Set to empty to test against GCP PubSub
+test.serviceURL=http://localhost:8383
+# Service Account Name and Key do not belong to any project
+# Have been generated for PubSub Emulator
+service.account=test-account@camel-pubsub-component.iam.gserviceaccount.com
+service.key=-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCfCiEwLed3hJ+h\n3zkpsGZj+MEB8MbpbqdUsiAp+Ok05zchGHM8iEG5s4gh013CI0rnta4zYDTrB98p\nBD+BX0TFP4S1QecSK0RoaJ8OmLYgYN56olobbedPRRdZIwopvQ7wSIqrEwWtez6Y\nRXcQzykYzETDEc2s0JyJU9BI2ZAENPbMheZICUkLHJdX0FqVf5WTtRDXnyL79CiW\nRirqN+eJdhq46Dz/TlEymuMePZVWAdcx0v8xv102H9bqFWtJvin8pD6fIT6f2iL1\ne/lQjNUVvX7Sx2EuLWZlPo+mWNvRCTXZymTcluj0jleAYhjuMc2xVEDx2RaCt2sx\nCo2Nb0edAgMBAAECggEAIFEJn2WkhCfB3D2kuvDqTWQtq/xGHwbqH462dHDsymA1\nVpdGS0WQvXBauCzf/2P2g5DqXewttJh74zTGxr4aFk6q474JeyqpkuG3eFrVn0yv\nyJGW5730Y6oxbV5uYT7We0LyUoLiA3dop75tzE+cFTrkuhKzDWuyc0FBsJvs5L2e\nl/xJh7M8I6+9h+NlP9p90NujxSTIIYD/Ft7+KucG5q8ZlQksHnS6RavLPJ/lShmZ\nFmoGwJnNTwBSZnlz8txnWVjSDtTiqdrKrQVTeT8Vu8X0tw9lu49t9OsdrLkAVhHe\nyEF8WJmYlOhxIN8vgz6XYIUGzC1k00JB4fHTFaXygQKBgQD5HtUZL1ZtDDa+N/wx\npxQitmcI/ZkHHTIbRvy65XOAXBr4Ipa/eOHdrCZw7GAlj2zHIZJwIOg+6vfF2959\nirWBiwmLSvldMlGL6QaCWgqfhHJH8UIjeeYnmU1q6YBsFr1m8jDgzp/QLNpTKMjW\nvfN6cqJedRJiym1tTvtXjhip4QKBgQCj
 bnd3dLAYIOMsARKOj7rAjzDWVgFRIhOR\nUgPY+zCsgLp/ffKUqH2fhS9R6RAXosVeMBChn6kePVxxbVXjw18fGKdXgSjBXjQh\neyXjkKHe7gPT9MyuAk22tNpkAWcht5nR+mA8wLT23C0CYBblch7dDm+dc6QtLlHt\np4xuvHptPQKBgGBqAmdg3r4NgBJWcJB27WAR4Aamv1b1gbL04lMjAnSnMPjfyiAI\nlMHKIoaJtRxUSfE3mQk0cy4GmiZFVfKYgG7GdMcoGSJsmwrfANnqJzpddC1LviEk\nyGKC/mdmP4GVu2/gQ/J9hXR4J3cPzcrucRDu1NBh1t/NIFSxwKy+HeWBAoGATOoB\nKWPuN/zKTPxYOmWkM1lwV370cbWC1gJuMyDMYHLY0oV4s8O0E23/viHcY/NDxbcD\nLL1SPxwLtIoLQPzCeIUGxGTRxGdMS3GEfFumAp+rh4YPCdmlr1Xf7e7HFZQtvSeD\nQTRENmWafSKxw9v4cHqJxuUUn/rLrfgLXFYxm9UCgYEAwlPP5J4pr19rokKIoS00\nRLrIKipEmiQoo1ENP4efjuAFMMxLQnXnx1NusiVEHb5RUiHAEY5sm5OxyP1XN+RF\nch2BhWnx+4+quIsspNkc9qfQKS9Xvb/GulhRTS/NKQSBNjs+Qe80LxBcuHdFhf1y\nrskSCZARtDqGrfblLQo26Mg=\n-----END PRIVATE KEY-----

http://git-wip-us.apache.org/repos/asf/camel/blob/07f57c33/components/pom.xml
----------------------------------------------------------------------
diff --git a/components/pom.xml b/components/pom.xml
index abbeb0b..8f7d0e5 100644
--- a/components/pom.xml
+++ b/components/pom.xml
@@ -121,6 +121,7 @@
     <module>camel-google-calendar</module>
     <module>camel-google-drive</module>
     <module>camel-google-mail</module>
+    <module>camel-google-pubsub</module>
     <module>camel-gora</module>
     <module>camel-grape</module>
     <module>camel-gson</module>

http://git-wip-us.apache.org/repos/asf/camel/blob/07f57c33/components/readme.adoc
----------------------------------------------------------------------
diff --git a/components/readme.adoc b/components/readme.adoc
index 598d317..383efdf 100644
--- a/components/readme.adoc
+++ b/components/readme.adoc
@@ -204,6 +204,9 @@ Components
 | link:camel-google-mail/src/main/docs/google-mail-component.adoc[Google Mail] (camel-google-mail) +
 `google-mail:apiName/methodName` | The google-mail component provides access to Google Mail.
 
+| link:camel-google-pubsub/src/main/docs/google-pubsub-component.adoc[Google Pubsub] (camel-google-pubsub) +
+`google-pubsub:projectId:destinationName?[options]` | PubSub Endpoint Definition
+
 | link:camel-gora/src/main/docs/gora-component.adoc[Gora] (camel-gora) +
 `gora:name` | The gora component allows you to work with NoSQL databases using the Apache Gora framework.
 

http://git-wip-us.apache.org/repos/asf/camel/blob/07f57c33/docs/user-manual/en/SUMMARY.md
----------------------------------------------------------------------
diff --git a/docs/user-manual/en/SUMMARY.md b/docs/user-manual/en/SUMMARY.md
index e38a901..8efc73c 100644
--- a/docs/user-manual/en/SUMMARY.md
+++ b/docs/user-manual/en/SUMMARY.md
@@ -210,6 +210,7 @@
 	* [Google Calendar](google-calendar-component.adoc)
 	* [Google Drive](google-drive-component.adoc)
 	* [Google Mail](google-mail-component.adoc)
+	* [Google Pubsub](google-pubsub-component.adoc)
 	* [Gora](gora-component.adoc)
 	* [Grape](grape-component.adoc)
 	* [Guava EventBus](guava-eventbus-component.adoc)

http://git-wip-us.apache.org/repos/asf/camel/blob/07f57c33/parent/pom.xml
----------------------------------------------------------------------
diff --git a/parent/pom.xml b/parent/pom.xml
index f2cfc05..c88a66c 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -227,6 +227,7 @@
     <google-api-services-drive-version>v2-rev240-1.22.0</google-api-services-drive-version>
     <google-api-services-calendar-version>v3-rev214-1.22.0</google-api-services-calendar-version>
     <google-api-services-mail-version>v1-rev48-1.22.0</google-api-services-mail-version>
+    <google-api-services-pubsub-version>v1-rev12-1.22.0</google-api-services-pubsub-version>
     <google-truth-version>0.27</google-truth-version>
     <grizzly-websockets-version>2.3.25</grizzly-websockets-version>
     <groovy-version>2.4.7</groovy-version>
@@ -1071,6 +1072,11 @@
       </dependency>
       <dependency>
         <groupId>org.apache.camel</groupId>
+        <artifactId>camel-google-pubsub</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
         <artifactId>camel-gora</artifactId>
         <version>${project.version}</version>
       </dependency>
@@ -2303,6 +2309,11 @@
       </dependency>
       <dependency>
         <groupId>org.apache.camel</groupId>
+        <artifactId>camel-google-pubsub-starter</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
         <artifactId>camel-gora-starter</artifactId>
         <version>${project.version}</version>
       </dependency>

http://git-wip-us.apache.org/repos/asf/camel/blob/07f57c33/platforms/karaf/features/src/main/resources/features.xml
----------------------------------------------------------------------
diff --git a/platforms/karaf/features/src/main/resources/features.xml b/platforms/karaf/features/src/main/resources/features.xml
index 335fec5..0ded6b1 100644
--- a/platforms/karaf/features/src/main/resources/features.xml
+++ b/platforms/karaf/features/src/main/resources/features.xml
@@ -92,7 +92,7 @@
     <bundle dependency='true'>mvn:io.netty/netty-transport/${netty40-version}</bundle>
     <bundle dependency='true'>mvn:io.netty/netty-handler/${netty40-version}</bundle>
     <bundle dependency='true'>mvn:io.netty/netty-transport-native-epoll/${netty40-version}</bundle>
-    <bundle dependency='true'>mvn:io.netty/netty-codec/${netty40-version}</bundle>    
+    <bundle dependency='true'>mvn:io.netty/netty-codec/${netty40-version}</bundle>
     <bundle dependency='true'>mvn:io.netty/netty-codec-http/${netty40-version}</bundle>
     <bundle dependency='true'>mvn:javax.servlet/javax.servlet-api/${javax.servlet-api-version}</bundle>
     <bundle>mvn:org.apache.camel/camel-http-common/${project.version}</bundle>
@@ -458,10 +458,10 @@
     <feature version="${project.version}">camel-core</feature>
     <bundle dependency='true'>mvn:commons-io/commons-io/${commons-io-version}</bundle>
     <bundle dependency='true'>mvn:com.fasterxml.jackson.core/jackson-core/${jackson2-version}</bundle>
-    <bundle dependency='true'>mvn:javax.servlet/javax.servlet-api/${javax.servlet-api-version}</bundle>    
+    <bundle dependency='true'>mvn:javax.servlet/javax.servlet-api/${javax.servlet-api-version}</bundle>
     <bundle dependency='true'>wrap:mvn:com.dropbox.core/dropbox-core-sdk/${dropbox-version}</bundle>
     <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.okhttp/${squareup-okhttp-bundle-version}</bundle>
-    <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.okio/${squareup-okio-bundle-version}</bundle>    
+    <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.okio/${squareup-okio-bundle-version}</bundle>
     <bundle>mvn:org.apache.camel/camel-dropbox/${project.version}</bundle>
   </feature>
   <feature name='camel-ehcache' version='${project.version}' resolver='(obr)' start-level='50'>
@@ -655,6 +655,21 @@
     <bundle dependency='true'>wrap:mvn:com.google.oauth-client/google-oauth-client-jetty/${google-api-client-version}</bundle>
     <bundle>mvn:org.apache.camel/camel-google-mail/${project.version}</bundle>
   </feature>
+  <feature name='camel-google-pubsub' version='${project.version}' resolver='(obr)' start-level='50'>
+    <feature version='${project.version}'>camel-core</feature>
+    <bundle dependency='true'>wrap:mvn:com.google.apis/google-api-services-pubsub/${google-api-services-pubsub-version}</bundle>
+    <bundle dependency='true'>wrap:mvn:com.google.api-client/google-api-client/${google-api-client-version}</bundle>
+    <bundle dependency='true'>mvn:commons-codec/commons-codec/${commons-codec-version}</bundle>
+    <bundle dependency='true'>wrap:mvn:com.google.http-client/google-http-client/${google-api-client-version}</bundle>
+    <bundle dependency='true'>wrap:mvn:com.google.http-client/google-http-client-jackson2/${google-api-client-version}</bundle>
+    <bundle dependency='true'>wrap:mvn:com.google.oauth-client/google-oauth-client/${google-api-client-version}</bundle>
+    <bundle dependency='true'>wrap:mvn:com.google.oauth-client/google-oauth-client-java6/${google-api-client-version}</bundle>
+    <bundle dependency='true'>wrap:mvn:com.google.oauth-client/google-oauth-client-jetty/${google-api-client-version}</bundle>
+    <bundle dependency='true'>mvn:com.fasterxml.jackson.core/jackson-core/${jackson2-version}</bundle>
+    <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.commons-httpclient/${commons-httpclient-bundle-version}</bundle>
+    <bundle dependency='true'>mvn:com.google.guava/guava/${google-guava-version}</bundle>
+    <bundle>mvn:org.apache.camel/camel-google-pubsub/${project.version}</bundle>
+  </feature>
   <feature name='camel-grape' version='${project.version}' resolver='(obr)' start-level='50'>
     <feature version='${project.version}'>camel-core</feature>
     <bundle dependency='true'>mvn:org.codehaus.groovy/groovy-all/${groovy-version}</bundle>
@@ -664,7 +679,7 @@
   </feature>
   <feature name='camel-groovy' version='${project.version}' resolver='(obr)' start-level='50'>
     <feature version='${project.version}'>camel-core</feature>
-    <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.ant/${ant-bundle-version}</bundle>    
+    <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.ant/${ant-bundle-version}</bundle>
     <bundle dependency='true'>mvn:org.codehaus.groovy/groovy-all/${groovy-version}</bundle>
     <bundle>mvn:org.apache.camel/camel-groovy/${project.version}</bundle>
   </feature>
@@ -811,8 +826,8 @@
   <feature name='camel-hystrix' version='${project.version}' resolver='(obr)' start-level='50'>
     <feature version='${project.version}'>camel-core</feature>
     <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.hystrix/${hystrix-bundle-version}</bundle>
-    <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.hystrix-event-stream/${hystrix-bundle-version}</bundle>    
-    <bundle dependency='true'>mvn:javax.servlet/javax.servlet-api/${javax.servlet-api-version}</bundle>    
+    <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.hystrix-event-stream/${hystrix-bundle-version}</bundle>
+    <bundle dependency='true'>mvn:javax.servlet/javax.servlet-api/${javax.servlet-api-version}</bundle>
     <bundle dependency='true'>mvn:commons-configuration/commons-configuration/${commons-configuration-version}</bundle>
     <bundle dependency='true'>mvn:commons-lang/commons-lang/${commons-lang-version}</bundle>
     <bundle dependency='true'>mvn:io.reactivex/rxjava/${rxjava-version}</bundle>
@@ -836,7 +851,7 @@
         You need to add this package to the list of packages exported by the system bundle in the etc/jre.properties file.
 
         Additionally, you must provision the Ignite Karaf features repository in your container: mvn:org.apache.ignite/ignite-osgi-karaf/${ignite-version}.
-        
+
         Please refer to the component page (https://camel.apache.org/ignite.html) and to the Ignite docs (https://apacheignite.readme.io/docs/osgi-installation-in-karaf#preparatory-steps) for more information.]]>
     </details>
     <feature version='${project.version}'>camel-core</feature>
@@ -1547,7 +1562,7 @@
     <feature version='${project.version}'>camel-core</feature>
     <feature version='${cxf-version-range}'>cxf-core</feature>
     <feature version='${cxf-version-range}'>cxf-jaxrs</feature>
-    <feature version='${cxf-version-range}'>cxf-rs-security-oauth2</feature>    
+    <feature version='${cxf-version-range}'>cxf-rs-security-oauth2</feature>
     <bundle dependency='true'>mvn:com.fasterxml.jackson.core/jackson-core/${jackson2-version}</bundle>
     <bundle dependency='true'>mvn:com.fasterxml.jackson.core/jackson-databind/${jackson2-version}</bundle>
     <bundle dependency='true'>mvn:com.fasterxml.jackson.core/jackson-annotations/${jackson2-version}</bundle>

http://git-wip-us.apache.org/repos/asf/camel/blob/07f57c33/platforms/spring-boot/spring-boot-dm/camel-spring-boot-dependencies/pom.xml
----------------------------------------------------------------------
diff --git a/platforms/spring-boot/spring-boot-dm/camel-spring-boot-dependencies/pom.xml b/platforms/spring-boot/spring-boot-dm/camel-spring-boot-dependencies/pom.xml
index b537886..faf7df4 100644
--- a/platforms/spring-boot/spring-boot-dm/camel-spring-boot-dependencies/pom.xml
+++ b/platforms/spring-boot/spring-boot-dm/camel-spring-boot-dependencies/pom.xml
@@ -914,6 +914,16 @@
       </dependency>
       <dependency>
         <groupId>org.apache.camel</groupId>
+        <artifactId>camel-google-pubsub</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>camel-google-pubsub-starter</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
         <artifactId>camel-gora</artifactId>
         <version>${project.version}</version>
       </dependency>