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 2021/03/19 06:39:38 UTC

[camel] 03/22: CAMEL-15963 Create a Google Cloud Functions component

This is an automated email from the ASF dual-hosted git repository.

acosentino pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 308e6f03a9175de3f0084ff8c5eb0af4ea10c97e
Author: Raffaele Marcello <ma...@gmail.com>
AuthorDate: Sat Feb 27 20:38:39 2021 +0100

    CAMEL-15963 Create a Google Cloud Functions component
---
 .../catalog/docs/google-functions-component.adoc   |   7 +-
 components/camel-google-functions/ReadMe.txt       |  46 +++-
 components/camel-google-functions/pom.xml          |  26 +-
 .../GoogleCloudFunctionsEndpointConfigurer.java    |  23 ++
 .../GoogleCloudFunctionsEndpointUriFactory.java    |   7 +-
 .../google/functions/google-functions.json         |   7 +-
 .../src/main/docs/google-functions-component.adoc  |   7 +-
 .../functions/GoogleCloudFunctionsComponent.java   |   9 +
 .../GoogleCloudFunctionsConfiguration.java         | 123 ++++++----
 .../functions/GoogleCloudFunctionsConstants.java   |  53 ++++
 .../functions/GoogleCloudFunctionsEndpoint.java    |  44 +++-
 ...er.java => GoogleCloudFunctionsOperations.java} |  42 ++--
 .../functions/GoogleCloudFunctionsProducer.java    |  81 ++++++-
 .../functions/mock/MockCloudFunctionsService.java  | 268 +++++++++++++++++++++
 .../unit/GoogleCloudFunctionsBaseTest.java         |  56 +++++
 .../unit/GoogleCloudFunctionsComponentTest.java    |  61 ++++-
 .../GoogleCloudFunctionsConfigurationTest.java     |   5 +
 .../src/test/resources/log4j.properties            |  41 +++-
 ...GoogleCloudFunctionsEndpointBuilderFactory.java | 148 +++++++++++-
 .../ROOT/pages/google-functions-component.adoc     |   7 +-
 20 files changed, 947 insertions(+), 114 deletions(-)

diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/google-functions-component.adoc b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/google-functions-component.adoc
index 495172d..1ed9b9e 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/google-functions-component.adoc
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/google-functions-component.adoc
@@ -109,7 +109,7 @@ with the following path and query parameters:
 |===
 
 
-=== Query Parameters (2 parameters):
+=== Query Parameters (7 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -117,6 +117,11 @@ with the following path and query parameters:
 | Name | Description | Default | Type
 | *serviceAccountKey* (common) | Service account key to authenticate an application as a service account |  | String
 | *lazyStartProducer* (producer) | Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and [...]
+| *location* (producer) | location |  | String
+| *operation* (producer) | The operation to perform on the producer. There are 3 enums and the value can be one of: listFunctions, getFunction, callFunction |  | GoogleCloudFunctionsOperations
+| *pojoRequest* (producer) | Configure the input type. If true the message will be POJO type. | false | boolean
+| *project* (producer) | Project |  | String
+| *client* (advanced) | *Autowired* The client to use during service invocation. |  | CloudFunctionsServiceClient
 |===
 // endpoint options: END
 
diff --git a/components/camel-google-functions/ReadMe.txt b/components/camel-google-functions/ReadMe.txt
index f327e1e..c9ad8d9 100644
--- a/components/camel-google-functions/ReadMe.txt
+++ b/components/camel-google-functions/ReadMe.txt
@@ -1,13 +1,43 @@
-Camel Component Project
-=======================
+# Camel Google Functions Component
+This component is based on the [google java functions library](https://github.com/googleapis/java-storage) that works as a client for the Google Cloud Storage.
 
-This project is a template of a Camel component.
 
-To build this project use
+## Camel Google Storage Component testing
 
-    mvn install
+The unit tests provided are somewhat limited.
+Due to the nature of the component, it needs to be tested against a google Storage instance because although there are some emulators
+they doesn't cover all the functionalities.
+
+The tests are organized into two packages:
+* **Unit** : Standalone tests that can be conducted on their own
+* **Integration** : Tests against a Google Storage instance
+
+For the Unit tests has been extended the emulator [google-cloud-nio](https://github.com/googleapis/java-storage-nio/tree/master/google-cloud-nio/src/main/java/com/google/cloud/storage/contrib/nio/testing)
+adding some functionalities (bucket creation and deletion). However there are still some unsupported operations.
+
+
+### Execution of integration tests
+
+To run the Google Storage client library, you must first set up authentication by creating a service account key.
+You can find more info at: [cloud.google.com/storage/docs/reference/libraries#setting_up_authentication](https://cloud.google.com/storage/docs/reference/libraries#setting_up_authentication).
+
+When you have the **service account key** you can provide authentication credentials to your application code by setting the environment variable:
+
+`export GOOGLE_APPLICATION_CREDENTIALS="/home/user/Downloads/my-key.json"`
+
+or for windows:
+
+`$Env:GOOGLE_APPLICATION_CREDENTIALS = "/home/user/Downloads/my-key.json"`
+
+or directly through the component endpoint
+
+`from("google-functions://myCamelFunction?serviceAccountKey=/home/user/Downloads/my-key.json")`
+
+
+Running tests against Google Functions instance:
+
+```
+mvn -Pgoogle-functions-test verify
+```
 
-For more help see the Apache Camel documentation:
 
-    http://camel.apache.org/writing-components.html
-    
diff --git a/components/camel-google-functions/pom.xml b/components/camel-google-functions/pom.xml
index 311fd6e..f42cb00 100644
--- a/components/camel-google-functions/pom.xml
+++ b/components/camel-google-functions/pom.xml
@@ -34,24 +34,24 @@
 
   <properties>
     <firstVersion>3.9.0</firstVersion>
+    <google-cloud-functions-version>1.0.8</google-cloud-functions-version>
   </properties>
 
   <dependencyManagement>
     <dependencies>
       <!-- Override the android JDK 7 guava in libraries-bom -->
-    <!--  <dependency>
+      <dependency>
         <groupId>com.google.guava</groupId>
         <artifactId>guava</artifactId>
         <version>${google-cloud-guava-version}</version>
       </dependency>
       <dependency>
         <groupId>com.google.cloud</groupId>
-        <artifactId>libraries-bom</artifactId>
-        <version>${google-cloud-bom-version}</version>
+        <artifactId>google-cloud-functions-bom</artifactId>
+        <version>${google-cloud-functions-version}</version>
         <type>pom</type>
         <scope>import</scope>
       </dependency>
-      -->
     </dependencies>
   
   </dependencyManagement>
@@ -61,16 +61,28 @@
       <groupId>org.apache.camel</groupId>
       <artifactId>camel-support</artifactId>
     </dependency>
-    <!--
+    
     <dependency>
       <groupId>com.google.guava</groupId>
       <artifactId>guava</artifactId>
     </dependency>
     <dependency>
       <groupId>com.google.cloud</groupId>
-      <artifactId>google-cloud-storage</artifactId>
+      <artifactId>google-cloud-functions</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.google.api.grpc</groupId>
+      <artifactId>grpc-google-cloud-functions-v1</artifactId>
+      <scope>test</scope>
     </dependency>
-  -->
+    <dependency>
+      <groupId>com.google.api</groupId>
+      <artifactId>gax-grpc</artifactId>
+      <classifier>testlib</classifier>
+      <version>1.62.0</version>
+      <scope>test</scope>
+    </dependency>
+
     <dependency>
       <groupId>org.apache.camel</groupId>
       <artifactId>camel-test-junit5</artifactId>
diff --git a/components/camel-google-functions/src/generated/java/org/apache/camel/component/google/functions/GoogleCloudFunctionsEndpointConfigurer.java b/components/camel-google-functions/src/generated/java/org/apache/camel/component/google/functions/GoogleCloudFunctionsEndpointConfigurer.java
index f18c71e..6ca6e8d 100644
--- a/components/camel-google-functions/src/generated/java/org/apache/camel/component/google/functions/GoogleCloudFunctionsEndpointConfigurer.java
+++ b/components/camel-google-functions/src/generated/java/org/apache/camel/component/google/functions/GoogleCloudFunctionsEndpointConfigurer.java
@@ -21,8 +21,14 @@ public class GoogleCloudFunctionsEndpointConfigurer extends PropertyConfigurerSu
     public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) {
         GoogleCloudFunctionsEndpoint target = (GoogleCloudFunctionsEndpoint) obj;
         switch (ignoreCase ? name.toLowerCase() : name) {
+        case "client": target.getConfiguration().setClient(property(camelContext, com.google.cloud.functions.v1.CloudFunctionsServiceClient.class, value)); return true;
         case "lazystartproducer":
         case "lazyStartProducer": target.setLazyStartProducer(property(camelContext, boolean.class, value)); return true;
+        case "location": target.getConfiguration().setLocation(property(camelContext, java.lang.String.class, value)); return true;
+        case "operation": target.getConfiguration().setOperation(property(camelContext, org.apache.camel.component.google.functions.GoogleCloudFunctionsOperations.class, value)); return true;
+        case "pojorequest":
+        case "pojoRequest": target.getConfiguration().setPojoRequest(property(camelContext, boolean.class, value)); return true;
+        case "project": target.getConfiguration().setProject(property(camelContext, java.lang.String.class, value)); return true;
         case "serviceaccountkey":
         case "serviceAccountKey": target.getConfiguration().setServiceAccountKey(property(camelContext, java.lang.String.class, value)); return true;
         default: return false;
@@ -30,10 +36,21 @@ public class GoogleCloudFunctionsEndpointConfigurer extends PropertyConfigurerSu
     }
 
     @Override
+    public String[] getAutowiredNames() {
+        return new String[]{"client"};
+    }
+
+    @Override
     public Class<?> getOptionType(String name, boolean ignoreCase) {
         switch (ignoreCase ? name.toLowerCase() : name) {
+        case "client": return com.google.cloud.functions.v1.CloudFunctionsServiceClient.class;
         case "lazystartproducer":
         case "lazyStartProducer": return boolean.class;
+        case "location": return java.lang.String.class;
+        case "operation": return org.apache.camel.component.google.functions.GoogleCloudFunctionsOperations.class;
+        case "pojorequest":
+        case "pojoRequest": return boolean.class;
+        case "project": return java.lang.String.class;
         case "serviceaccountkey":
         case "serviceAccountKey": return java.lang.String.class;
         default: return null;
@@ -44,8 +61,14 @@ public class GoogleCloudFunctionsEndpointConfigurer extends PropertyConfigurerSu
     public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
         GoogleCloudFunctionsEndpoint target = (GoogleCloudFunctionsEndpoint) obj;
         switch (ignoreCase ? name.toLowerCase() : name) {
+        case "client": return target.getConfiguration().getClient();
         case "lazystartproducer":
         case "lazyStartProducer": return target.isLazyStartProducer();
+        case "location": return target.getConfiguration().getLocation();
+        case "operation": return target.getConfiguration().getOperation();
+        case "pojorequest":
+        case "pojoRequest": return target.getConfiguration().isPojoRequest();
+        case "project": return target.getConfiguration().getProject();
         case "serviceaccountkey":
         case "serviceAccountKey": return target.getConfiguration().getServiceAccountKey();
         default: return null;
diff --git a/components/camel-google-functions/src/generated/java/org/apache/camel/component/google/functions/GoogleCloudFunctionsEndpointUriFactory.java b/components/camel-google-functions/src/generated/java/org/apache/camel/component/google/functions/GoogleCloudFunctionsEndpointUriFactory.java
index 1ec7800..f372af5 100644
--- a/components/camel-google-functions/src/generated/java/org/apache/camel/component/google/functions/GoogleCloudFunctionsEndpointUriFactory.java
+++ b/components/camel-google-functions/src/generated/java/org/apache/camel/component/google/functions/GoogleCloudFunctionsEndpointUriFactory.java
@@ -20,10 +20,15 @@ public class GoogleCloudFunctionsEndpointUriFactory extends org.apache.camel.sup
     private static final Set<String> PROPERTY_NAMES;
     private static final Set<String> SECRET_PROPERTY_NAMES;
     static {
-        Set<String> props = new HashSet<>(3);
+        Set<String> props = new HashSet<>(8);
         props.add("serviceAccountKey");
         props.add("lazyStartProducer");
         props.add("functionName");
+        props.add("project");
+        props.add("client");
+        props.add("location");
+        props.add("operation");
+        props.add("pojoRequest");
         PROPERTY_NAMES = Collections.unmodifiableSet(props);
         SECRET_PROPERTY_NAMES = Collections.emptySet();
     }
diff --git a/components/camel-google-functions/src/generated/resources/org/apache/camel/component/google/functions/google-functions.json b/components/camel-google-functions/src/generated/resources/org/apache/camel/component/google/functions/google-functions.json
index 01fcc4d..812d563 100644
--- a/components/camel-google-functions/src/generated/resources/org/apache/camel/component/google/functions/google-functions.json
+++ b/components/camel-google-functions/src/generated/resources/org/apache/camel/component/google/functions/google-functions.json
@@ -28,6 +28,11 @@
   "properties": {
     "functionName": { "kind": "path", "displayName": "Function Name", "group": "common", "label": "common", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.google.functions.GoogleCloudFunctionsConfiguration", "configurationField": "configuration", "description": "Function name" },
     "serviceAccountKey": { "kind": "parameter", "displayName": "Service Account Key", "group": "common", "label": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.google.functions.GoogleCloudFunctionsConfiguration", "configurationField": "configuration", "description": "Service account key to authenticate an application as a service account" },
-    "lazyStartProducer": { "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during sta [...]
+    "lazyStartProducer": { "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during sta [...]
+    "location": { "kind": "parameter", "displayName": "Location", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.google.functions.GoogleCloudFunctionsConfiguration", "configurationField": "configuration", "description": "location" },
+    "operation": { "kind": "parameter", "displayName": "Operation", "group": "producer", "label": "producer", "required": false, "type": "object", "javaType": "org.apache.camel.component.google.functions.GoogleCloudFunctionsOperations", "enum": [ "listFunctions", "getFunction", "callFunction" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.google.functions.GoogleCloudFunctionsConfiguration", "configurationField": "configurati [...]
+    "pojoRequest": { "kind": "parameter", "displayName": "Pojo Request", "group": "producer", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.google.functions.GoogleCloudFunctionsConfiguration", "configurationField": "configuration", "description": "Configure the input type. If true the message will be POJO type." },
+    "project": { "kind": "parameter", "displayName": "Project", "group": "producer", "label": "producer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.google.functions.GoogleCloudFunctionsConfiguration", "configurationField": "configuration", "description": "Project" },
+    "client": { "kind": "parameter", "displayName": "Client", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "com.google.cloud.functions.v1.CloudFunctionsServiceClient", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.google.functions.GoogleCloudFunctionsConfiguration", "configurationField": "configuration", "description": "The client to use during service invocation." }
   }
 }
diff --git a/components/camel-google-functions/src/main/docs/google-functions-component.adoc b/components/camel-google-functions/src/main/docs/google-functions-component.adoc
index 495172d..1ed9b9e 100644
--- a/components/camel-google-functions/src/main/docs/google-functions-component.adoc
+++ b/components/camel-google-functions/src/main/docs/google-functions-component.adoc
@@ -109,7 +109,7 @@ with the following path and query parameters:
 |===
 
 
-=== Query Parameters (2 parameters):
+=== Query Parameters (7 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -117,6 +117,11 @@ with the following path and query parameters:
 | Name | Description | Default | Type
 | *serviceAccountKey* (common) | Service account key to authenticate an application as a service account |  | String
 | *lazyStartProducer* (producer) | Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and [...]
+| *location* (producer) | location |  | String
+| *operation* (producer) | The operation to perform on the producer. There are 3 enums and the value can be one of: listFunctions, getFunction, callFunction |  | GoogleCloudFunctionsOperations
+| *pojoRequest* (producer) | Configure the input type. If true the message will be POJO type. | false | boolean
+| *project* (producer) | Project |  | String
+| *client* (advanced) | *Autowired* The client to use during service invocation. |  | CloudFunctionsServiceClient
 |===
 // endpoint options: END
 
diff --git a/components/camel-google-functions/src/main/java/org/apache/camel/component/google/functions/GoogleCloudFunctionsComponent.java b/components/camel-google-functions/src/main/java/org/apache/camel/component/google/functions/GoogleCloudFunctionsComponent.java
index fc536f9..4319fc4 100644
--- a/components/camel-google-functions/src/main/java/org/apache/camel/component/google/functions/GoogleCloudFunctionsComponent.java
+++ b/components/camel-google-functions/src/main/java/org/apache/camel/component/google/functions/GoogleCloudFunctionsComponent.java
@@ -23,10 +23,14 @@ import org.apache.camel.Endpoint;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.annotations.Component;
 import org.apache.camel.support.DefaultComponent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 @Component("google-functions")
 public class GoogleCloudFunctionsComponent extends DefaultComponent {
 
+    private static final Logger LOG = LoggerFactory.getLogger(GoogleCloudFunctionsComponent.class);
+
     @Metadata
     private GoogleCloudFunctionsConfiguration configuration = new GoogleCloudFunctionsConfiguration();
 
@@ -48,6 +52,11 @@ public class GoogleCloudFunctionsComponent extends DefaultComponent {
 
         Endpoint endpoint = new GoogleCloudFunctionsEndpoint(uri, this, configuration);
         setProperties(endpoint, parameters);
+        LOG.info("configuration={}", configuration);
         return endpoint;
     }
+
+    public GoogleCloudFunctionsConfiguration getConfiguration() {
+        return configuration;
+    }
 }
diff --git a/components/camel-google-functions/src/main/java/org/apache/camel/component/google/functions/GoogleCloudFunctionsConfiguration.java b/components/camel-google-functions/src/main/java/org/apache/camel/component/google/functions/GoogleCloudFunctionsConfiguration.java
index b4dca133..3b65664 100644
--- a/components/camel-google-functions/src/main/java/org/apache/camel/component/google/functions/GoogleCloudFunctionsConfiguration.java
+++ b/components/camel-google-functions/src/main/java/org/apache/camel/component/google/functions/GoogleCloudFunctionsConfiguration.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.component.google.functions;
 
+import com.google.cloud.functions.v1.CloudFunctionsServiceClient;
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.UriParam;
@@ -32,48 +33,21 @@ public class GoogleCloudFunctionsConfiguration implements Cloneable {
     @UriParam(label = "common", description = "Service account key to authenticate an application as a service account")
     private String serviceAccountKey;
 
-    /*
-    @UriParam(label = "producer",
-              enums = "copyObject,listObjects,deleteObject,deleteBucket,listBuckets,getObject,createDownloadLink")
-    private GoogleCloudStorageOperations operation;
-    
-    @UriParam(label = "producer", description = "The Object name inside the bucket")
-    private String objectName;
-    
-    @UriParam(label = "common", defaultValue = "US-EAST1",
-              description = "The Cloud Storage location to use when creating the new buckets")
-    private String storageLocation = "US-EAST1";
-    
-    @UriParam(label = "common", defaultValue = "STANDARD",
-              description = "The Cloud Storage class to use when creating the new buckets")
-    private StorageClass storageClass = StorageClass.STANDARD;
-    
-    @UriParam(label = "common", defaultValue = "true")
-    private boolean autoCreateBucket = true;
-    
-    @UriParam(label = "consumer")
-    private boolean moveAfterRead;
-    
-    @UriParam(label = "consumer")
-    private String destinationBucket;
-    
-    @UriParam(label = "consumer", defaultValue = "true")
-    private boolean deleteAfterRead = true;
-    
-    @UriParam(label = "consumer", defaultValue = "true")
-    private boolean includeBody = true;
-    
-    @UriParam(label = "consumer", defaultValue = "true")
-    private boolean includeFolders = true;
-    
-    @UriParam
+    @UriParam(label = "producer", description = "Project")
+    private String project;
+
+    @UriParam(label = "producer", description = "location")
+    private String location;
+
+    @UriParam(label = "producer", enums = "listFunctions,getFunction,callFunction")
+    private GoogleCloudFunctionsOperations operation;
+
+    @UriParam(defaultValue = "false")
+    private boolean pojoRequest;
+
+    @UriParam(label = "advanced")
     @Metadata(autowired = true)
-    private Storage storageClient;
-    
-    public String getBucketName() {
-        return this.bucketName;
-    }
-    */
+    private CloudFunctionsServiceClient client;
 
     public String getFunctionName() {
         return functionName;
@@ -101,6 +75,67 @@ public class GoogleCloudFunctionsConfiguration implements Cloneable {
         this.serviceAccountKey = serviceAccountKey;
     }
 
+    public String getProject() {
+        return project;
+    }
+
+    /**
+     * The project to work with.
+     * 
+     * @param project
+     */
+    public void setProject(String project) {
+        this.project = project;
+    }
+
+    public String getLocation() {
+        return location;
+    }
+
+    /**
+     * The target location.
+     * 
+     * @param location
+     */
+    public void setLocation(String location) {
+        this.location = location;
+    }
+
+    public GoogleCloudFunctionsOperations getOperation() {
+        return operation;
+    }
+
+    /**
+     * The operation to perform on the producer.
+     */
+    public void setOperation(GoogleCloudFunctionsOperations operation) {
+        this.operation = operation;
+    }
+
+    public CloudFunctionsServiceClient getClient() {
+        return client;
+    }
+
+    /**
+     * The client to use during service invocation.
+     */
+    public void setClient(CloudFunctionsServiceClient client) {
+        this.client = client;
+    }
+
+    public boolean isPojoRequest() {
+        return pojoRequest;
+    }
+
+    /**
+     * Configure the input type. If true the message will be POJO type.
+     * 
+     * @param pojoRequest
+     */
+    public void setPojoRequest(boolean pojoRequest) {
+        this.pojoRequest = pojoRequest;
+    }
+
     public GoogleCloudFunctionsConfiguration copy() {
         try {
             return (GoogleCloudFunctionsConfiguration) super.clone();
@@ -109,10 +144,4 @@ public class GoogleCloudFunctionsConfiguration implements Cloneable {
         }
     }
 
-    @Override
-    public String toString() {
-        return "GoogleCloudFunctionsConfiguration [functionName=" + functionName + ", serviceAccountKey="
-               + serviceAccountKey + "]";
-    }
-
 }
diff --git a/components/camel-google-functions/src/main/java/org/apache/camel/component/google/functions/GoogleCloudFunctionsConstants.java b/components/camel-google-functions/src/main/java/org/apache/camel/component/google/functions/GoogleCloudFunctionsConstants.java
new file mode 100644
index 0000000..b90f6d1
--- /dev/null
+++ b/components/camel-google-functions/src/main/java/org/apache/camel/component/google/functions/GoogleCloudFunctionsConstants.java
@@ -0,0 +1,53 @@
+/*
+ * 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.functions;
+
+public interface GoogleCloudFunctionsConstants {
+
+    String OPERATION = "GoogleCloudFunctionsOperation";
+
+    // String S3_BUCKET = "CamelAwsLambdaS3Bucket";
+    // String S3_KEY = "CamelAwsLambdaS3Key";
+    // String S3_OBJECT_VERSION = "CamelAwsLambdaS3ObjectVersion";
+    // String ZIP_FILE = "CamelAwsLambdaZipFile";
+    // String DESCRIPTION = "CamelAwsLambdaDescription";
+    // String ROLE = "CamelAwsLambdaRole";
+    // String RUNTIME = "CamelAwsLambdaRuntime";
+    // String HANDLER = "CamelAwsLambdaHandler";
+    // String TARGET_ARN = "CamelAwsLambdaTargetArn";
+    // String MEMORY_SIZE = "CamelAwsLambdaMemorySize";
+    // String KMS_KEY_ARN = "CamelAwsLambdaKMSKeyArn";
+    // String ENVIRONMENT_VARIABLES = "CamelAwsLambdaEnvironmentVariables";
+    // String PUBLISH = "CamelAwsLambdaPublish";
+    // String TIMEOUT = "CamelAwsLambdaTimeout";
+    // String TAGS = "CamelAwsLambdaTags";
+    // String TRACING_CONFIG = "CamelAwsLambdaTracingConfig";
+    // String SECURITY_GROUP_IDS = "CamelAwsLambdaSecurityGroupIds";
+    // String SUBNET_IDS = "CamelAwsLambdaSubnetIds";
+    // String EVENT_SOURCE_ARN = "CamelAwsLambdaEventSourceArn";
+    // String EVENT_SOURCE_BATCH_SIZE = "CamelAwsLambdaEventSourceBatchSize";
+    // String EVENT_SOURCE_UUID = "CamelAwsLambdaEventSourceUuid";
+    // String RESOURCE_ARN = "CamelAwsLambdaResourceArn";
+    // String RESOURCE_TAGS = "CamelAwsLambdaResourceTags";
+    // String RESOURCE_TAG_KEYS = "CamelAwsLambdaResourceTagKeys";
+    // String VERSION_DESCRIPTION = "CamelAwsLambdaVersionDescription";
+    // String VERSION_REVISION_ID = "CamelAwsLambdaVersionRevisionId";
+    // String FUNCTION_VERSION = "CamelAwsLambdaFunctionVersion";
+    // String FUNCTION_ALIAS_NAME = "CamelAwsLambdaAliasFunctionName";
+    // String FUNCTION_ALIAS_DESCRIPTION = "CamelAwsLambdaAliasFunctionDescription";
+
+}
diff --git a/components/camel-google-functions/src/main/java/org/apache/camel/component/google/functions/GoogleCloudFunctionsEndpoint.java b/components/camel-google-functions/src/main/java/org/apache/camel/component/google/functions/GoogleCloudFunctionsEndpoint.java
index b9a7f43..e74c9d7 100644
--- a/components/camel-google-functions/src/main/java/org/apache/camel/component/google/functions/GoogleCloudFunctionsEndpoint.java
+++ b/components/camel-google-functions/src/main/java/org/apache/camel/component/google/functions/GoogleCloudFunctionsEndpoint.java
@@ -16,6 +16,14 @@
  */
 package org.apache.camel.component.google.functions;
 
+import java.io.FileInputStream;
+
+import com.google.api.client.util.Strings;
+import com.google.api.gax.core.FixedCredentialsProvider;
+import com.google.auth.Credentials;
+import com.google.auth.oauth2.ServiceAccountCredentials;
+import com.google.cloud.functions.v1.CloudFunctionsServiceClient;
+import com.google.cloud.functions.v1.CloudFunctionsServiceSettings;
 import org.apache.camel.Category;
 import org.apache.camel.Consumer;
 import org.apache.camel.Processor;
@@ -33,8 +41,9 @@ import org.slf4j.LoggerFactory;
  * behavior of Producer.
  */
 @UriEndpoint(firstVersion = "3.9.0", scheme = "google-functions", title = "GoogleCloudFunctions",
-             syntax = "google-functions:name",
-             category = { Category.CLOUD }, producerOnly = true)
+             syntax = "google-functions:name", category = {
+                     Category.CLOUD },
+             producerOnly = true)
 public class GoogleCloudFunctionsEndpoint extends DefaultEndpoint {
 
     private static final Logger LOG = LoggerFactory.getLogger(GoogleCloudFunctionsEndpoint.class);
@@ -42,6 +51,8 @@ public class GoogleCloudFunctionsEndpoint extends DefaultEndpoint {
     @UriParam
     private GoogleCloudFunctionsConfiguration configuration;
 
+    private CloudFunctionsServiceClient cloudFunctionsClient;
+
     public GoogleCloudFunctionsEndpoint(String uri, GoogleCloudFunctionsComponent component,
                                         GoogleCloudFunctionsConfiguration configuration) {
         super(uri, component);
@@ -54,7 +65,8 @@ public class GoogleCloudFunctionsEndpoint extends DefaultEndpoint {
     }
 
     public Consumer createConsumer(Processor processor) throws Exception {
-        throw new UnsupportedOperationException("Cannot consume from the google-functions endpoint: " + getEndpointUri());
+        throw new UnsupportedOperationException(
+                "Cannot consume from the google-functions endpoint: " + getEndpointUri());
     }
 
     public GoogleCloudFunctionsConfiguration getConfiguration() {
@@ -71,15 +83,37 @@ public class GoogleCloudFunctionsEndpoint extends DefaultEndpoint {
     @Override
     protected void doStart() throws Exception {
         super.doStart();
+        if (configuration.getClient() != null) {
+            cloudFunctionsClient = configuration.getClient();
+        } else {
+
+            if (!Strings.isNullOrEmpty(configuration.getServiceAccountKey())) {
+                Credentials myCredentials = ServiceAccountCredentials
+                        .fromStream(new FileInputStream(configuration.getServiceAccountKey()));
+                CloudFunctionsServiceSettings settings = CloudFunctionsServiceSettings.newBuilder()
+                        .setCredentialsProvider(FixedCredentialsProvider.create(myCredentials)).build();
+                cloudFunctionsClient = CloudFunctionsServiceClient.create(settings);
 
-        System.out.println("start");
+            } else {
+                // TODO remember to implement this
+                throw new RuntimeException("Not yet implmented");
+            }
+
+        }
     }
 
     @Override
     protected void doStop() throws Exception {
         super.doStop();
+        if (configuration.getClient() == null) {
+            if (cloudFunctionsClient != null) {
+                cloudFunctionsClient.close();
+            }
+        }
+    }
 
-        System.out.println("stop");
+    public CloudFunctionsServiceClient getClient() {
+        return cloudFunctionsClient;
     }
 
 }
diff --git a/components/camel-google-functions/src/main/java/org/apache/camel/component/google/functions/GoogleCloudFunctionsProducer.java b/components/camel-google-functions/src/main/java/org/apache/camel/component/google/functions/GoogleCloudFunctionsOperations.java
similarity index 56%
copy from components/camel-google-functions/src/main/java/org/apache/camel/component/google/functions/GoogleCloudFunctionsProducer.java
copy to components/camel-google-functions/src/main/java/org/apache/camel/component/google/functions/GoogleCloudFunctionsOperations.java
index 1c590d4..fa48fd9 100644
--- a/components/camel-google-functions/src/main/java/org/apache/camel/component/google/functions/GoogleCloudFunctionsProducer.java
+++ b/components/camel-google-functions/src/main/java/org/apache/camel/component/google/functions/GoogleCloudFunctionsOperations.java
@@ -16,25 +16,29 @@
  */
 package org.apache.camel.component.google.functions;
 
-import org.apache.camel.Exchange;
-import org.apache.camel.support.DefaultProducer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+public enum GoogleCloudFunctionsOperations {
 
-/**
- * The GoogleCloudFunctions producer.
- */
-public class GoogleCloudFunctionsProducer extends DefaultProducer {
-    private static final Logger LOG = LoggerFactory.getLogger(GoogleCloudFunctionsProducer.class);
-    private GoogleCloudFunctionsEndpoint endpoint;
-
-    public GoogleCloudFunctionsProducer(GoogleCloudFunctionsEndpoint endpoint) {
-        super(endpoint);
-        this.endpoint = endpoint;
-    }
-
-    public void process(Exchange exchange) throws Exception {
-        System.out.println(exchange.getIn().getBody());
-    }
+    listFunctions,
+    getFunction,
+    callFunction;
 
+    //TODO Clean up
+    // listFunctions,
+    // getFunction,
+    // createAlias,
+    // deleteAlias,
+    // getAlias,
+    // listAliases,
+    // createFunction,
+    // deleteFunction,
+    // invokeFunction,
+    // updateFunction,
+    // createEventSourceMapping,
+    // deleteEventSourceMapping,
+    // listEventSourceMapping,
+    // listTags,
+    // tagResource,
+    // untagResource,
+    // publishVersion,
+    // listVersions
 }
diff --git a/components/camel-google-functions/src/main/java/org/apache/camel/component/google/functions/GoogleCloudFunctionsProducer.java b/components/camel-google-functions/src/main/java/org/apache/camel/component/google/functions/GoogleCloudFunctionsProducer.java
index 1c590d4..8abd299 100644
--- a/components/camel-google-functions/src/main/java/org/apache/camel/component/google/functions/GoogleCloudFunctionsProducer.java
+++ b/components/camel-google-functions/src/main/java/org/apache/camel/component/google/functions/GoogleCloudFunctionsProducer.java
@@ -16,7 +16,18 @@
  */
 package org.apache.camel.component.google.functions;
 
+import java.util.List;
+
+import com.google.api.client.util.Lists;
+import com.google.api.gax.rpc.ApiException;
+import com.google.cloud.functions.v1.CloudFunction;
+import com.google.cloud.functions.v1.CloudFunctionsServiceClient;
+import com.google.cloud.functions.v1.CloudFunctionsServiceClient.ListFunctionsPagedResponse;
+import com.google.cloud.functions.v1.ListFunctionsRequest;
+import com.google.cloud.functions.v1.LocationName;
 import org.apache.camel.Exchange;
+import org.apache.camel.InvalidPayloadException;
+import org.apache.camel.Message;
 import org.apache.camel.support.DefaultProducer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -26,6 +37,7 @@ import org.slf4j.LoggerFactory;
  */
 public class GoogleCloudFunctionsProducer extends DefaultProducer {
     private static final Logger LOG = LoggerFactory.getLogger(GoogleCloudFunctionsProducer.class);
+
     private GoogleCloudFunctionsEndpoint endpoint;
 
     public GoogleCloudFunctionsProducer(GoogleCloudFunctionsEndpoint endpoint) {
@@ -33,8 +45,73 @@ public class GoogleCloudFunctionsProducer extends DefaultProducer {
         this.endpoint = endpoint;
     }
 
-    public void process(Exchange exchange) throws Exception {
-        System.out.println(exchange.getIn().getBody());
+    @Override
+    public void process(final Exchange exchange) throws Exception {
+        switch (determineOperation(exchange)) {
+            case listFunctions:
+                listFunctions(endpoint.getClient(), exchange);
+                break;
+            case getFunction:
+                getFunction(endpoint.getClient(), exchange);
+                break;
+            case callFunction:
+                callFunction(endpoint.getClient(), exchange);
+                break;
+
+            default:
+                throw new IllegalArgumentException("Unsupported operation");
+        }
+    }
+
+    private void listFunctions(CloudFunctionsServiceClient client, Exchange exchange) throws InvalidPayloadException {
+        if (getConfiguration().isPojoRequest()) {
+            Object payload = exchange.getIn().getMandatoryBody();
+            if (payload instanceof ListFunctionsRequest) {
+                ListFunctionsPagedResponse result;
+                try {
+                    result = client.listFunctions((ListFunctionsRequest) payload);
+                } catch (ApiException ae) {
+                    LOG.trace("listFunctions command returned the error code {}", ae.getStatusCode());
+                    throw ae;
+                }
+                Message message = getMessageForResponse(exchange);
+                message.setBody(result);
+            }
+        } else {
+            ListFunctionsRequest request = ListFunctionsRequest.newBuilder()
+                    .setParent(LocationName.of(getConfiguration().getProject(), getConfiguration().getLocation()).toString())
+                    .setPageSize(883849137) //TODO check it
+                    .setPageToken("pageToken873572522").build();
+            ListFunctionsPagedResponse pagedListResponse = client.listFunctions(request);
+            List<CloudFunction> result = Lists.newArrayList(pagedListResponse.iterateAll());
+            Message message = getMessageForResponse(exchange);
+            message.setBody(result);
+        }
+    }
+
+    private void getFunction(CloudFunctionsServiceClient client, Exchange exchange) {
+    }
+
+    private void callFunction(CloudFunctionsServiceClient client, Exchange exchange) {
+    }
+
+    private GoogleCloudFunctionsOperations determineOperation(Exchange exchange) {
+        GoogleCloudFunctionsOperations operation = exchange.getIn().getHeader(GoogleCloudFunctionsConstants.OPERATION,
+                GoogleCloudFunctionsOperations.class);
+        if (operation == null) {
+            operation = getConfiguration().getOperation() == null
+                    ? GoogleCloudFunctionsOperations.callFunction
+                    : getConfiguration().getOperation();
+        }
+        return operation;
+    }
+
+    public static Message getMessageForResponse(final Exchange exchange) {
+        return exchange.getMessage();
+    }
+
+    private GoogleCloudFunctionsConfiguration getConfiguration() {
+        return this.endpoint.getConfiguration();
     }
 
 }
diff --git a/components/camel-google-functions/src/test/java/org/apache/camel/component/google/functions/mock/MockCloudFunctionsService.java b/components/camel-google-functions/src/test/java/org/apache/camel/component/google/functions/mock/MockCloudFunctionsService.java
new file mode 100644
index 0000000..757ae18
--- /dev/null
+++ b/components/camel-google-functions/src/test/java/org/apache/camel/component/google/functions/mock/MockCloudFunctionsService.java
@@ -0,0 +1,268 @@
+/*
+ * 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.functions.mock;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+
+import com.google.api.gax.grpc.testing.MockGrpcService;
+import com.google.cloud.functions.v1.CallFunctionRequest;
+import com.google.cloud.functions.v1.CallFunctionResponse;
+import com.google.cloud.functions.v1.CloudFunction;
+import com.google.cloud.functions.v1.CloudFunctionsServiceGrpc.CloudFunctionsServiceImplBase;
+import com.google.cloud.functions.v1.CreateFunctionRequest;
+import com.google.cloud.functions.v1.DeleteFunctionRequest;
+import com.google.cloud.functions.v1.GenerateDownloadUrlRequest;
+import com.google.cloud.functions.v1.GenerateDownloadUrlResponse;
+import com.google.cloud.functions.v1.GenerateUploadUrlRequest;
+import com.google.cloud.functions.v1.GenerateUploadUrlResponse;
+import com.google.cloud.functions.v1.GetFunctionRequest;
+import com.google.cloud.functions.v1.ListFunctionsRequest;
+import com.google.cloud.functions.v1.ListFunctionsResponse;
+import com.google.cloud.functions.v1.UpdateFunctionRequest;
+import com.google.iam.v1.GetIamPolicyRequest;
+import com.google.iam.v1.Policy;
+import com.google.iam.v1.SetIamPolicyRequest;
+import com.google.iam.v1.TestIamPermissionsRequest;
+import com.google.iam.v1.TestIamPermissionsResponse;
+import com.google.longrunning.Operation;
+import com.google.protobuf.AbstractMessage;
+import io.grpc.ServerServiceDefinition;
+import io.grpc.stub.StreamObserver;
+
+public class MockCloudFunctionsService extends CloudFunctionsServiceImplBase implements MockGrpcService {
+    private List<AbstractMessage> requests;
+    private Queue<Object> responses;
+
+    public MockCloudFunctionsService() {
+        requests = new ArrayList<>();
+        responses = new LinkedList<>();
+    }
+
+    public List<AbstractMessage> getRequests() {
+        return requests;
+    }
+
+    public void addResponse(AbstractMessage response) {
+        responses.add(response);
+    }
+
+    public void setResponses(List<AbstractMessage> responses) {
+        this.responses = new LinkedList<Object>(responses);
+    }
+
+    public void addException(Exception exception) {
+        responses.add(exception);
+    }
+
+    public void reset() {
+        requests = new ArrayList<>();
+        responses = new LinkedList<>();
+    }
+
+    @Override
+    public void listFunctions(ListFunctionsRequest request, StreamObserver<ListFunctionsResponse> responseObserver) {
+        Object response = responses.remove();
+        if (response instanceof ListFunctionsResponse) {
+            requests.add(request);
+            responseObserver.onNext(((ListFunctionsResponse) response));
+            responseObserver.onCompleted();
+        } else if (response instanceof Exception) {
+            responseObserver.onError(((Exception) response));
+        } else {
+            responseObserver.onError(new IllegalArgumentException(
+                    String.format("Unrecognized response type %s for method ListFunctions, expected %s or %s",
+                            response.getClass().getName(), ListFunctionsResponse.class.getName(), Exception.class.getName())));
+        }
+    }
+
+    @Override
+    public void getFunction(GetFunctionRequest request, StreamObserver<CloudFunction> responseObserver) {
+        Object response = responses.remove();
+        if (response instanceof CloudFunction) {
+            requests.add(request);
+            responseObserver.onNext(((CloudFunction) response));
+            responseObserver.onCompleted();
+        } else if (response instanceof Exception) {
+            responseObserver.onError(((Exception) response));
+        } else {
+            responseObserver.onError(new IllegalArgumentException(
+                    String.format("Unrecognized response type %s for method GetFunction, expected %s or %s",
+                            response.getClass().getName(), CloudFunction.class.getName(), Exception.class.getName())));
+        }
+    }
+
+    @Override
+    public void createFunction(CreateFunctionRequest request, StreamObserver<Operation> responseObserver) {
+        Object response = responses.remove();
+        if (response instanceof Operation) {
+            requests.add(request);
+            responseObserver.onNext(((Operation) response));
+            responseObserver.onCompleted();
+        } else if (response instanceof Exception) {
+            responseObserver.onError(((Exception) response));
+        } else {
+            responseObserver.onError(new IllegalArgumentException(
+                    String.format("Unrecognized response type %s for method CreateFunction, expected %s or %s",
+                            response.getClass().getName(), Operation.class.getName(), Exception.class.getName())));
+        }
+    }
+
+    @Override
+    public void updateFunction(UpdateFunctionRequest request, StreamObserver<Operation> responseObserver) {
+        Object response = responses.remove();
+        if (response instanceof Operation) {
+            requests.add(request);
+            responseObserver.onNext(((Operation) response));
+            responseObserver.onCompleted();
+        } else if (response instanceof Exception) {
+            responseObserver.onError(((Exception) response));
+        } else {
+            responseObserver.onError(new IllegalArgumentException(
+                    String.format("Unrecognized response type %s for method UpdateFunction, expected %s or %s",
+                            response.getClass().getName(), Operation.class.getName(), Exception.class.getName())));
+        }
+    }
+
+    @Override
+    public void deleteFunction(DeleteFunctionRequest request, StreamObserver<Operation> responseObserver) {
+        Object response = responses.remove();
+        if (response instanceof Operation) {
+            requests.add(request);
+            responseObserver.onNext(((Operation) response));
+            responseObserver.onCompleted();
+        } else if (response instanceof Exception) {
+            responseObserver.onError(((Exception) response));
+        } else {
+            responseObserver.onError(new IllegalArgumentException(
+                    String.format("Unrecognized response type %s for method DeleteFunction, expected %s or %s",
+                            response.getClass().getName(), Operation.class.getName(), Exception.class.getName())));
+        }
+    }
+
+    @Override
+    public void callFunction(CallFunctionRequest request, StreamObserver<CallFunctionResponse> responseObserver) {
+        Object response = responses.remove();
+        if (response instanceof CallFunctionResponse) {
+            requests.add(request);
+            responseObserver.onNext(((CallFunctionResponse) response));
+            responseObserver.onCompleted();
+        } else if (response instanceof Exception) {
+            responseObserver.onError(((Exception) response));
+        } else {
+            responseObserver.onError(new IllegalArgumentException(
+                    String.format("Unrecognized response type %s for method CallFunction, expected %s or %s",
+                            response.getClass().getName(), CallFunctionResponse.class.getName(), Exception.class.getName())));
+        }
+    }
+
+    @Override
+    public void generateUploadUrl(
+            GenerateUploadUrlRequest request,
+            StreamObserver<GenerateUploadUrlResponse> responseObserver) {
+        Object response = responses.remove();
+        if (response instanceof GenerateUploadUrlResponse) {
+            requests.add(request);
+            responseObserver.onNext(((GenerateUploadUrlResponse) response));
+            responseObserver.onCompleted();
+        } else if (response instanceof Exception) {
+            responseObserver.onError(((Exception) response));
+        } else {
+            responseObserver.onError(new IllegalArgumentException(
+                    String.format("Unrecognized response type %s for method GenerateUploadUrl, expected %s or %s",
+                            response.getClass().getName(), GenerateUploadUrlResponse.class.getName(),
+                            Exception.class.getName())));
+        }
+    }
+
+    @Override
+    public void generateDownloadUrl(
+            GenerateDownloadUrlRequest request,
+            StreamObserver<GenerateDownloadUrlResponse> responseObserver) {
+        Object response = responses.remove();
+        if (response instanceof GenerateDownloadUrlResponse) {
+            requests.add(request);
+            responseObserver.onNext(((GenerateDownloadUrlResponse) response));
+            responseObserver.onCompleted();
+        } else if (response instanceof Exception) {
+            responseObserver.onError(((Exception) response));
+        } else {
+            responseObserver.onError(new IllegalArgumentException(
+                    String.format("Unrecognized response type %s for method GenerateDownloadUrl, expected %s or %s",
+                            response.getClass().getName(), GenerateDownloadUrlResponse.class.getName(),
+                            Exception.class.getName())));
+        }
+    }
+
+    @Override
+    public void setIamPolicy(SetIamPolicyRequest request, StreamObserver<Policy> responseObserver) {
+        Object response = responses.remove();
+        if (response instanceof Policy) {
+            requests.add(request);
+            responseObserver.onNext(((Policy) response));
+            responseObserver.onCompleted();
+        } else if (response instanceof Exception) {
+            responseObserver.onError(((Exception) response));
+        } else {
+            responseObserver.onError(new IllegalArgumentException(
+                    String.format("Unrecognized response type %s for method SetIamPolicy, expected %s or %s",
+                            response.getClass().getName(), Policy.class.getName(), Exception.class.getName())));
+        }
+    }
+
+    @Override
+    public void getIamPolicy(GetIamPolicyRequest request, StreamObserver<Policy> responseObserver) {
+        Object response = responses.remove();
+        if (response instanceof Policy) {
+            requests.add(request);
+            responseObserver.onNext(((Policy) response));
+            responseObserver.onCompleted();
+        } else if (response instanceof Exception) {
+            responseObserver.onError(((Exception) response));
+        } else {
+            responseObserver.onError(new IllegalArgumentException(
+                    String.format("Unrecognized response type %s for method GetIamPolicy, expected %s or %s",
+                            response.getClass().getName(), Policy.class.getName(), Exception.class.getName())));
+        }
+    }
+
+    @Override
+    public void testIamPermissions(
+            TestIamPermissionsRequest request,
+            StreamObserver<TestIamPermissionsResponse> responseObserver) {
+        Object response = responses.remove();
+        if (response instanceof TestIamPermissionsResponse) {
+            requests.add(request);
+            responseObserver.onNext(((TestIamPermissionsResponse) response));
+            responseObserver.onCompleted();
+        } else if (response instanceof Exception) {
+            responseObserver.onError(((Exception) response));
+        } else {
+            responseObserver.onError(new IllegalArgumentException(
+                    String.format("Unrecognized response type %s for method TestIamPermissions, expected %s or %s",
+                            response.getClass().getName(), TestIamPermissionsResponse.class.getName(),
+                            Exception.class.getName())));
+        }
+    }
+
+    @Override
+    public ServerServiceDefinition getServiceDefinition() {
+        return bindService();
+    }
+}
diff --git a/components/camel-google-functions/src/test/java/org/apache/camel/component/google/functions/unit/GoogleCloudFunctionsBaseTest.java b/components/camel-google-functions/src/test/java/org/apache/camel/component/google/functions/unit/GoogleCloudFunctionsBaseTest.java
new file mode 100644
index 0000000..47ceac0
--- /dev/null
+++ b/components/camel-google-functions/src/test/java/org/apache/camel/component/google/functions/unit/GoogleCloudFunctionsBaseTest.java
@@ -0,0 +1,56 @@
+package org.apache.camel.component.google.functions.unit;
+
+import java.util.Arrays;
+import java.util.UUID;
+
+import com.google.api.gax.core.NoCredentialsProvider;
+import com.google.api.gax.grpc.testing.LocalChannelProvider;
+import com.google.api.gax.grpc.testing.MockGrpcService;
+import com.google.api.gax.grpc.testing.MockServiceHelper;
+import com.google.cloud.functions.v1.CloudFunctionsServiceClient;
+import com.google.cloud.functions.v1.CloudFunctionsServiceSettings;
+import org.apache.camel.CamelContext;
+import org.apache.camel.component.google.functions.GoogleCloudFunctionsComponent;
+import org.apache.camel.component.google.functions.mock.MockCloudFunctionsService;
+import org.apache.camel.test.junit5.CamelTestSupport;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeEach;
+
+public class GoogleCloudFunctionsBaseTest extends CamelTestSupport {
+
+    protected static MockServiceHelper mockServiceHelper;
+    protected static MockCloudFunctionsService mockCloudFunctionsService;
+    protected LocalChannelProvider channelProvider;
+    protected CloudFunctionsServiceClient clientMock;
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        CamelContext context = super.createCamelContext();
+        GoogleCloudFunctionsComponent component = context.getComponent("google-functions", GoogleCloudFunctionsComponent.class);
+
+        //init mock
+        mockCloudFunctionsService = new MockCloudFunctionsService();
+        mockServiceHelper = new MockServiceHelper(
+                UUID.randomUUID().toString(),
+                Arrays.<MockGrpcService> asList(mockCloudFunctionsService));
+        mockServiceHelper.start();
+        channelProvider = mockServiceHelper.createChannelProvider();
+        CloudFunctionsServiceSettings settings = CloudFunctionsServiceSettings.newBuilder()
+                .setTransportChannelProvider(channelProvider).setCredentialsProvider(NoCredentialsProvider.create())
+                .build();
+        clientMock = CloudFunctionsServiceClient.create(settings);
+
+        component.getConfiguration().setClient(clientMock);
+        return context;
+    }
+
+    @BeforeEach
+    public void restMock() {
+        mockServiceHelper.reset();
+    }
+
+    @AfterAll
+    public static void releaseResources() {
+        mockServiceHelper.stop();
+    }
+}
diff --git a/components/camel-google-functions/src/test/java/org/apache/camel/component/google/functions/unit/GoogleCloudFunctionsComponentTest.java b/components/camel-google-functions/src/test/java/org/apache/camel/component/google/functions/unit/GoogleCloudFunctionsComponentTest.java
index 02db0ce..d7be5d1 100644
--- a/components/camel-google-functions/src/test/java/org/apache/camel/component/google/functions/unit/GoogleCloudFunctionsComponentTest.java
+++ b/components/camel-google-functions/src/test/java/org/apache/camel/component/google/functions/unit/GoogleCloudFunctionsComponentTest.java
@@ -1,26 +1,71 @@
+/*
+ * 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.functions.unit;
 
+import java.util.Arrays;
+
+import com.google.cloud.functions.v1.CloudFunction;
+import com.google.cloud.functions.v1.CloudFunctionsServiceClient.ListFunctionsPagedResponse;
+import com.google.cloud.functions.v1.ListFunctionsResponse;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Exchange;
+import org.apache.camel.ExchangePattern;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.mock.MockEndpoint;
-import org.apache.camel.test.junit5.CamelTestSupport;
 import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.camel.component.google.functions.unit.GoogleCloudFunctionsBaseTest.mockCloudFunctionsService;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+public class GoogleCloudFunctionsComponentTest extends GoogleCloudFunctionsBaseTest {
 
-public class GoogleCloudFunctionsComponentTest extends CamelTestSupport {
+    private static final Logger log = LoggerFactory.getLogger(GoogleCloudFunctionsComponentTest.class);
+
+    @EndpointInject("mock:result")
+    private MockEndpoint mock;
 
     @Test
-    public void testGoogleCloudFunctions() throws Exception {
-        MockEndpoint mock = getMockEndpoint("mock:result");
-        //mock.expectedMinimumMessageCount(1);
+    public void listFunctionsTest() throws Exception {
+
+        CloudFunction responsesElement = CloudFunction.newBuilder().build();
+        ListFunctionsResponse expectedResponse = ListFunctionsResponse.newBuilder().setNextPageToken("")
+                .addAllFunctions(Arrays.asList(responsesElement)).build();
+        mockCloudFunctionsService.addResponse(expectedResponse);
 
-        //assertMockEndpointsSatisfied();
+        Exchange exchange = template.send("direct:listFunctions", ExchangePattern.InOut, exc -> {
+        });
+        log.info("body: " + exchange.getMessage().getBody());
+        ListFunctionsPagedResponse result = exchange.getMessage().getBody(ListFunctionsPagedResponse.class);
+        assertNotNull(result);
+        // assertEquals(1, result.getPage().);
+        // assertEquals("GetHelloWithName", result.functions().get(0).functionName());
     }
 
     @Override
     protected RouteBuilder createRouteBuilder() throws Exception {
+        log.info("createRouteBuilder");
         return new RouteBuilder() {
             public void configure() {
-                from("direct:test")
-                        .to("google-functions://function1")
+
+                from("direct:listFunctions")
+                        // .to("google-functions://myCamelFunction?client=#client&operation=listFunctions")
+                        .to("google-functions://myCamelFunction?project=proj1&location=loc1&operation=listFunctions")
                         .to("mock:result");
             }
         };
diff --git a/components/camel-google-functions/src/test/java/org/apache/camel/component/google/functions/unit/GoogleCloudFunctionsConfigurationTest.java b/components/camel-google-functions/src/test/java/org/apache/camel/component/google/functions/unit/GoogleCloudFunctionsConfigurationTest.java
index 872f9b3..9a66af6 100644
--- a/components/camel-google-functions/src/test/java/org/apache/camel/component/google/functions/unit/GoogleCloudFunctionsConfigurationTest.java
+++ b/components/camel-google-functions/src/test/java/org/apache/camel/component/google/functions/unit/GoogleCloudFunctionsConfigurationTest.java
@@ -20,11 +20,15 @@ import org.apache.camel.component.google.functions.GoogleCloudFunctionsComponent
 import org.apache.camel.component.google.functions.GoogleCloudFunctionsEndpoint;
 import org.apache.camel.test.junit5.CamelTestSupport;
 import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
 public class GoogleCloudFunctionsConfigurationTest extends CamelTestSupport {
 
+    private static final Logger LOGGER = LoggerFactory.getLogger(GoogleCloudFunctionsConfigurationTest.class);
+
     @Test
     public void createEndpointWithMinimalConfiguration() throws Exception {
         final String functionName = "function1";
@@ -36,6 +40,7 @@ public class GoogleCloudFunctionsConfigurationTest extends CamelTestSupport {
 
         assertEquals(endpoint.getConfiguration().getFunctionName(), functionName);
         assertEquals(endpoint.getConfiguration().getServiceAccountKey(), serviceAccountKeyFile);
+        LOGGER.info("OK");
     }
 
 }
diff --git a/components/camel-google-functions/src/test/resources/log4j.properties b/components/camel-google-functions/src/test/resources/log4j.properties
index 3b1bd38..1541092 100644
--- a/components/camel-google-functions/src/test/resources/log4j.properties
+++ b/components/camel-google-functions/src/test/resources/log4j.properties
@@ -1,14 +1,31 @@
+## ---------------------------------------------------------------------------
+## 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
+# The logging properties used during tests..
 #
-log4j.rootLogger=INFO, out
-
-# uncomment the following line to turn on Camel debugging
-#log4j.logger.org.apache.camel=DEBUG
-
-# CONSOLE appender not used by default
-log4j.appender.out=org.apache.log4j.ConsoleAppender
-log4j.appender.out.layout=org.apache.log4j.PatternLayout
-log4j.appender.out.layout.ConversionPattern=[%30.30t] %-30.30c{1} %-5p %m%n
-#log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
-
+appender.file.type = File
+appender.file.name = file
+appender.file.fileName = target/camel-google-storage-test.log
+appender.file.layout.type = PatternLayout
+appender.file.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+appender.out.type = Console
+appender.out.name = out
+appender.out.layout.type = PatternLayout
+appender.out.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+rootLogger.level = INFO
+rootLogger.appenderRef.file.ref = file
diff --git a/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/GoogleCloudFunctionsEndpointBuilderFactory.java b/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/GoogleCloudFunctionsEndpointBuilderFactory.java
index b84a257..230ef09 100644
--- a/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/GoogleCloudFunctionsEndpointBuilderFactory.java
+++ b/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/GoogleCloudFunctionsEndpointBuilderFactory.java
@@ -37,6 +37,9 @@ public interface GoogleCloudFunctionsEndpointBuilderFactory {
     public interface GoogleCloudFunctionsEndpointBuilder
             extends
                 EndpointProducerBuilder {
+        default AdvancedGoogleCloudFunctionsEndpointBuilder advanced() {
+            return (AdvancedGoogleCloudFunctionsEndpointBuilder) this;
+        }
         /**
          * Service account key to authenticate an application as a service
          * account.
@@ -102,6 +105,149 @@ public interface GoogleCloudFunctionsEndpointBuilderFactory {
             doSetProperty("lazyStartProducer", lazyStartProducer);
             return this;
         }
+        /**
+         * location.
+         * 
+         * The option is a: &lt;code&gt;java.lang.String&lt;/code&gt; type.
+         * 
+         * Group: producer
+         * 
+         * @param location the value to set
+         * @return the dsl builder
+         */
+        default GoogleCloudFunctionsEndpointBuilder location(String location) {
+            doSetProperty("location", location);
+            return this;
+        }
+        /**
+         * The operation to perform on the producer.
+         * 
+         * The option is a:
+         * &lt;code&gt;org.apache.camel.component.google.functions.GoogleCloudFunctionsOperations&lt;/code&gt; type.
+         * 
+         * Group: producer
+         * 
+         * @param operation the value to set
+         * @return the dsl builder
+         */
+        default GoogleCloudFunctionsEndpointBuilder operation(
+                GoogleCloudFunctionsOperations operation) {
+            doSetProperty("operation", operation);
+            return this;
+        }
+        /**
+         * The operation to perform on the producer.
+         * 
+         * The option will be converted to a
+         * &lt;code&gt;org.apache.camel.component.google.functions.GoogleCloudFunctionsOperations&lt;/code&gt; type.
+         * 
+         * Group: producer
+         * 
+         * @param operation the value to set
+         * @return the dsl builder
+         */
+        default GoogleCloudFunctionsEndpointBuilder operation(String operation) {
+            doSetProperty("operation", operation);
+            return this;
+        }
+        /**
+         * Configure the input type. If true the message will be POJO type.
+         * 
+         * The option is a: &lt;code&gt;boolean&lt;/code&gt; type.
+         * 
+         * Default: false
+         * Group: producer
+         * 
+         * @param pojoRequest the value to set
+         * @return the dsl builder
+         */
+        default GoogleCloudFunctionsEndpointBuilder pojoRequest(
+                boolean pojoRequest) {
+            doSetProperty("pojoRequest", pojoRequest);
+            return this;
+        }
+        /**
+         * Configure the input type. If true the message will be POJO type.
+         * 
+         * The option will be converted to a &lt;code&gt;boolean&lt;/code&gt;
+         * type.
+         * 
+         * Default: false
+         * Group: producer
+         * 
+         * @param pojoRequest the value to set
+         * @return the dsl builder
+         */
+        default GoogleCloudFunctionsEndpointBuilder pojoRequest(
+                String pojoRequest) {
+            doSetProperty("pojoRequest", pojoRequest);
+            return this;
+        }
+        /**
+         * Project.
+         * 
+         * The option is a: &lt;code&gt;java.lang.String&lt;/code&gt; type.
+         * 
+         * Group: producer
+         * 
+         * @param project the value to set
+         * @return the dsl builder
+         */
+        default GoogleCloudFunctionsEndpointBuilder project(String project) {
+            doSetProperty("project", project);
+            return this;
+        }
+    }
+
+    /**
+     * Advanced builder for endpoint for the GoogleCloudFunctions component.
+     */
+    public interface AdvancedGoogleCloudFunctionsEndpointBuilder
+            extends
+                EndpointProducerBuilder {
+        default GoogleCloudFunctionsEndpointBuilder basic() {
+            return (GoogleCloudFunctionsEndpointBuilder) this;
+        }
+        /**
+         * The client to use during service invocation.
+         * 
+         * The option is a:
+         * &lt;code&gt;com.google.cloud.functions.v1.CloudFunctionsServiceClient&lt;/code&gt; type.
+         * 
+         * Group: advanced
+         * 
+         * @param client the value to set
+         * @return the dsl builder
+         */
+        default AdvancedGoogleCloudFunctionsEndpointBuilder client(Object client) {
+            doSetProperty("client", client);
+            return this;
+        }
+        /**
+         * The client to use during service invocation.
+         * 
+         * The option will be converted to a
+         * &lt;code&gt;com.google.cloud.functions.v1.CloudFunctionsServiceClient&lt;/code&gt; type.
+         * 
+         * Group: advanced
+         * 
+         * @param client the value to set
+         * @return the dsl builder
+         */
+        default AdvancedGoogleCloudFunctionsEndpointBuilder client(String client) {
+            doSetProperty("client", client);
+            return this;
+        }
+    }
+
+    /**
+     * Proxy enum for
+     * <code>org.apache.camel.component.google.functions.GoogleCloudFunctionsOperations</code> enum.
+     */
+    enum GoogleCloudFunctionsOperations {
+        listFunctions,
+        getFunction,
+        callFunction;
     }
 
     public interface GoogleCloudFunctionsBuilders {
@@ -153,7 +299,7 @@ public interface GoogleCloudFunctionsEndpointBuilderFactory {
     static GoogleCloudFunctionsEndpointBuilder endpointBuilder(
             String componentName,
             String path) {
-        class GoogleCloudFunctionsEndpointBuilderImpl extends AbstractEndpointBuilder implements GoogleCloudFunctionsEndpointBuilder {
+        class GoogleCloudFunctionsEndpointBuilderImpl extends AbstractEndpointBuilder implements GoogleCloudFunctionsEndpointBuilder, AdvancedGoogleCloudFunctionsEndpointBuilder {
             public GoogleCloudFunctionsEndpointBuilderImpl(String path) {
                 super(componentName, path);
             }
diff --git a/docs/components/modules/ROOT/pages/google-functions-component.adoc b/docs/components/modules/ROOT/pages/google-functions-component.adoc
index 3d0390c..1cb25d9 100644
--- a/docs/components/modules/ROOT/pages/google-functions-component.adoc
+++ b/docs/components/modules/ROOT/pages/google-functions-component.adoc
@@ -111,7 +111,7 @@ with the following path and query parameters:
 |===
 
 
-=== Query Parameters (2 parameters):
+=== Query Parameters (7 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -119,6 +119,11 @@ with the following path and query parameters:
 | Name | Description | Default | Type
 | *serviceAccountKey* (common) | Service account key to authenticate an application as a service account |  | String
 | *lazyStartProducer* (producer) | Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first message is processed then creating and [...]
+| *location* (producer) | location |  | String
+| *operation* (producer) | The operation to perform on the producer. There are 3 enums and the value can be one of: listFunctions, getFunction, callFunction |  | GoogleCloudFunctionsOperations
+| *pojoRequest* (producer) | Configure the input type. If true the message will be POJO type. | false | boolean
+| *project* (producer) | Project |  | String
+| *client* (advanced) | *Autowired* The client to use during service invocation. |  | CloudFunctionsServiceClient
 |===
 // endpoint options: END