You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ja...@apache.org on 2020/10/29 08:44:50 UTC

[camel-quarkus] 02/02: Twilio native support

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

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

commit 0f7b5e22154c01fb6499f58cb67862a2f45f6799
Author: James Netherton <ja...@gmail.com>
AuthorDate: Wed Oct 28 09:04:57 2020 +0000

    Twilio native support
    
    Fixes #1633
---
 .../ROOT/pages/reference/extensions/twilio.adoc    |  14 ++-
 .../ROOT/partials/reference/components/twilio.adoc |   6 +-
 extensions-jvm/pom.xml                             |   1 -
 .../twilio/deployment/TwilioProcessor.java         |  46 --------
 .../component/twilio/it/TwilioResource.java        |  51 --------
 .../src/main/resources/application.properties      |  20 ----
 extensions/pom.xml                                 |   1 +
 .../twilio/deployment/pom.xml                      |   8 ++
 .../twilio/deployment/TwilioProcessor.java         |  95 +++++++++++++++
 {extensions-jvm => extensions}/twilio/pom.xml      |   1 -
 .../twilio/runtime/pom.xml                         |   9 ++
 .../main/resources/META-INF/quarkus-extension.yaml |   3 +-
 integration-tests/pom.xml                          |   1 +
 integration-tests/twilio/README.adoc               |  22 ++++
 .../twilio}/pom.xml                                |  79 ++++++++++---
 .../component/twilio/it/TwilioResource.java        | 129 +++++++++++++++++++++
 .../quarkus/component/twilio/it/TwilioIT.java      |  16 +--
 .../quarkus/component/twilio/it/TwilioTest.java    |  75 ++++++++++++
 .../component/twilio/it/TwilioTestResource.java    |  51 ++++++++
 .../test/resources/mappings/twilioPhoneCall.json   |  31 +++++
 .../resources/mappings/twilioPurchaseNumber.json   |  31 +++++
 .../test/resources/mappings/twilioSendMessage.json |  31 +++++
 tooling/scripts/test-categories.yaml               |   1 +
 23 files changed, 567 insertions(+), 155 deletions(-)

diff --git a/docs/modules/ROOT/pages/reference/extensions/twilio.adoc b/docs/modules/ROOT/pages/reference/extensions/twilio.adoc
index b6d990d..d0bfdd3 100644
--- a/docs/modules/ROOT/pages/reference/extensions/twilio.adoc
+++ b/docs/modules/ROOT/pages/reference/extensions/twilio.adoc
@@ -2,15 +2,15 @@
 // This file was generated by camel-quarkus-maven-plugin:update-extension-doc-page
 = Twilio
 :cq-artifact-id: camel-quarkus-twilio
-:cq-native-supported: false
-:cq-status: Preview
+:cq-native-supported: true
+:cq-status: Stable
 :cq-description: Interact with Twilio REST APIs using Twilio Java SDK.
 :cq-deprecated: false
 :cq-jvm-since: 1.1.0
-:cq-native-since: n/a
+:cq-native-since: 1.4.0
 
 [.badges]
-[.badge-key]##JVM since##[.badge-supported]##1.1.0## [.badge-key]##Native##[.badge-unsupported]##unsupported##
+[.badge-key]##JVM since##[.badge-supported]##1.1.0## [.badge-key]##Native since##[.badge-supported]##1.4.0##
 
 Interact with Twilio REST APIs using Twilio Java SDK.
 
@@ -31,3 +31,9 @@ Please refer to the above link for usage and configuration details.
 ----
 
 Check the xref:user-guide/index.adoc[User guide] for more information about writing Camel Quarkus applications.
+
+== SSL in native mode
+
+This extension auto-enables SSL support in native mode. Hence you do not need to add
+`quarkus.ssl.native=true` to your `application.properties` yourself. See also
+https://quarkus.io/guides/native-and-ssl[Quarkus SSL guide].
diff --git a/docs/modules/ROOT/partials/reference/components/twilio.adoc b/docs/modules/ROOT/partials/reference/components/twilio.adoc
index 6dc1b67..d666b93 100644
--- a/docs/modules/ROOT/partials/reference/components/twilio.adoc
+++ b/docs/modules/ROOT/partials/reference/components/twilio.adoc
@@ -2,11 +2,11 @@
 // This file was generated by camel-quarkus-maven-plugin:update-extension-doc-page
 :cq-artifact-id: camel-quarkus-twilio
 :cq-artifact-id-base: twilio
-:cq-native-supported: false
-:cq-status: Preview
+:cq-native-supported: true
+:cq-status: Stable
 :cq-deprecated: false
 :cq-jvm-since: 1.1.0
-:cq-native-since: n/a
+:cq-native-since: 1.4.0
 :cq-camel-part-name: twilio
 :cq-camel-part-title: Twilio
 :cq-camel-part-description: Interact with Twilio REST APIs using Twilio Java SDK.
diff --git a/extensions-jvm/pom.xml b/extensions-jvm/pom.xml
index 0d19d38..782c646 100644
--- a/extensions-jvm/pom.xml
+++ b/extensions-jvm/pom.xml
@@ -135,7 +135,6 @@
         <module>stub</module>
         <module>syslog</module>
         <module>thrift</module>
-        <module>twilio</module>
         <module>web3j</module>
         <module>weka</module>
         <module>wordpress</module>
diff --git a/extensions-jvm/twilio/deployment/src/main/java/org/apache/camel/quarkus/component/twilio/deployment/TwilioProcessor.java b/extensions-jvm/twilio/deployment/src/main/java/org/apache/camel/quarkus/component/twilio/deployment/TwilioProcessor.java
deleted file mode 100644
index a843176..0000000
--- a/extensions-jvm/twilio/deployment/src/main/java/org/apache/camel/quarkus/component/twilio/deployment/TwilioProcessor.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.quarkus.component.twilio.deployment;
-
-import io.quarkus.deployment.annotations.BuildStep;
-import io.quarkus.deployment.annotations.ExecutionTime;
-import io.quarkus.deployment.annotations.Record;
-import io.quarkus.deployment.builditem.FeatureBuildItem;
-import io.quarkus.deployment.pkg.steps.NativeBuild;
-import org.apache.camel.quarkus.core.JvmOnlyRecorder;
-import org.jboss.logging.Logger;
-
-class TwilioProcessor {
-
-    private static final Logger LOG = Logger.getLogger(TwilioProcessor.class);
-    private static final String FEATURE = "camel-twilio";
-
-    @BuildStep
-    FeatureBuildItem feature() {
-        return new FeatureBuildItem(FEATURE);
-    }
-
-    /**
-     * Remove this once this extension starts supporting the native mode.
-     */
-    @BuildStep(onlyIf = NativeBuild.class)
-    @Record(value = ExecutionTime.RUNTIME_INIT)
-    void warnJvmInNative(JvmOnlyRecorder recorder) {
-        JvmOnlyRecorder.warnJvmInNative(LOG, FEATURE); // warn at build time
-        recorder.warnJvmInNative(FEATURE); // warn at runtime
-    }
-}
diff --git a/extensions-jvm/twilio/integration-test/src/main/java/org/apache/camel/quarkus/component/twilio/it/TwilioResource.java b/extensions-jvm/twilio/integration-test/src/main/java/org/apache/camel/quarkus/component/twilio/it/TwilioResource.java
deleted file mode 100644
index 444e452..0000000
--- a/extensions-jvm/twilio/integration-test/src/main/java/org/apache/camel/quarkus/component/twilio/it/TwilioResource.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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.quarkus.component.twilio.it;
-
-import javax.enterprise.context.ApplicationScoped;
-import javax.inject.Inject;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-
-import org.apache.camel.CamelContext;
-import org.jboss.logging.Logger;
-
-@Path("/twilio")
-@ApplicationScoped
-public class TwilioResource {
-
-    private static final Logger LOG = Logger.getLogger(TwilioResource.class);
-
-    private static final String COMPONENT_TWILIO = "twilio";
-    @Inject
-    CamelContext context;
-
-    @Path("/load/component/twilio")
-    @GET
-    @Produces(MediaType.TEXT_PLAIN)
-    public Response loadComponentTwilio() throws Exception {
-        /* This is an autogenerated test */
-        if (context.getComponent(COMPONENT_TWILIO) != null) {
-            return Response.ok().build();
-        }
-        LOG.warnf("Could not load [%s] from the Camel context", COMPONENT_TWILIO);
-        return Response.status(500, COMPONENT_TWILIO + " could not be loaded from the Camel context").build();
-    }
-}
diff --git a/extensions-jvm/twilio/integration-test/src/main/resources/application.properties b/extensions-jvm/twilio/integration-test/src/main/resources/application.properties
deleted file mode 100644
index 16e6c31..0000000
--- a/extensions-jvm/twilio/integration-test/src/main/resources/application.properties
+++ /dev/null
@@ -1,20 +0,0 @@
-## ---------------------------------------------------------------------------
-## 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.
-## ---------------------------------------------------------------------------
-
-# Bogus credentials are here to allow the component to get initialized. We won't connect to Twilio using these
-camel.component.twilio.username = bogus
-camel.component.twilio.password = bogus
diff --git a/extensions/pom.xml b/extensions/pom.xml
index 20ebe54..49e7935 100644
--- a/extensions/pom.xml
+++ b/extensions/pom.xml
@@ -194,6 +194,7 @@
         <module>telegram</module>
         <module>tika</module>
         <module>timer</module>
+        <module>twilio</module>
         <module>twitter</module>
         <module>univocity-parsers</module>
         <module>validator</module>
diff --git a/extensions-jvm/twilio/deployment/pom.xml b/extensions/twilio/deployment/pom.xml
similarity index 88%
rename from extensions-jvm/twilio/deployment/pom.xml
rename to extensions/twilio/deployment/pom.xml
index caf7a61..207c8ba 100644
--- a/extensions-jvm/twilio/deployment/pom.xml
+++ b/extensions/twilio/deployment/pom.xml
@@ -31,6 +31,14 @@
 
     <dependencies>
         <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-jackson-deployment</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-support-httpclient-deployment</artifactId>
+        </dependency>
+        <dependency>
             <groupId>org.apache.camel.quarkus</groupId>
             <artifactId>camel-quarkus-core-deployment</artifactId>
         </dependency>
diff --git a/extensions/twilio/deployment/src/main/java/org/apache/camel/quarkus/component/twilio/deployment/TwilioProcessor.java b/extensions/twilio/deployment/src/main/java/org/apache/camel/quarkus/component/twilio/deployment/TwilioProcessor.java
new file mode 100644
index 0000000..51a5c2d
--- /dev/null
+++ b/extensions/twilio/deployment/src/main/java/org/apache/camel/quarkus/component/twilio/deployment/TwilioProcessor.java
@@ -0,0 +1,95 @@
+/*
+ * 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.quarkus.component.twilio.deployment;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+
+import com.twilio.base.Creator;
+import com.twilio.base.Deleter;
+import com.twilio.base.Fetcher;
+import com.twilio.base.Reader;
+import com.twilio.base.Updater;
+import com.twilio.type.Endpoint;
+import io.quarkus.deployment.annotations.BuildProducer;
+import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.builditem.AdditionalApplicationArchiveMarkerBuildItem;
+import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
+import io.quarkus.deployment.builditem.ExtensionSslNativeSupportBuildItem;
+import io.quarkus.deployment.builditem.FeatureBuildItem;
+import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem;
+import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
+import org.jboss.jandex.DotName;
+import org.jboss.jandex.IndexView;
+import org.joda.time.DateTimeZone;
+
+class TwilioProcessor {
+
+    private static final String FEATURE = "camel-twilio";
+
+    @BuildStep
+    FeatureBuildItem feature() {
+        return new FeatureBuildItem(FEATURE);
+    }
+
+    @BuildStep
+    ExtensionSslNativeSupportBuildItem activateSslNativeSupport() {
+        return new ExtensionSslNativeSupportBuildItem(FEATURE);
+    }
+
+    @BuildStep
+    AdditionalApplicationArchiveMarkerBuildItem boxArchiveMarker() {
+        return new AdditionalApplicationArchiveMarkerBuildItem("com/twilio");
+    }
+
+    @BuildStep
+    void registerForReflection(BuildProducer<ReflectiveClassBuildItem> reflectiveClass, CombinedIndexBuildItem combinedIndex) {
+        IndexView index = combinedIndex.getIndex();
+
+        // Register Twilio API CRUD generator classes for reflection
+        String[] reflectiveClasses = Stream.of(Creator.class, Deleter.class, Fetcher.class, Reader.class, Updater.class)
+                .map(aClass -> aClass.getName())
+                .map(DotName::createSimple)
+                .flatMap(dotName -> index.getAllKnownSubclasses(dotName).stream())
+                .map(classInfo -> classInfo.name().toString())
+                .filter(className -> className.startsWith("com.twilio.rest.api.v2010"))
+                .toArray(String[]::new);
+        reflectiveClass.produce(new ReflectiveClassBuildItem(true, false, reflectiveClasses));
+
+        // Register Twilio Endpoint implementors for reflection
+        String[] endpointImplementors = index.getAllKnownImplementors(DotName.createSimple(Endpoint.class.getName()))
+                .stream()
+                .map(classInfo -> classInfo.name().toString())
+                .toArray(String[]::new);
+
+        reflectiveClass.produce(new ReflectiveClassBuildItem(false, false, endpointImplementors));
+    }
+
+    @BuildStep
+    NativeImageResourceBuildItem nativeImageResources() {
+        // Add Joda timezone resources into the native image as it is required by com.twilio.converter.DateConverter
+        List<String> timezones = new ArrayList<>();
+        for (String timezone : DateTimeZone.getAvailableIDs()) {
+            String[] zoneParts = timezone.split("/");
+            if (zoneParts.length == 2) {
+                timezones.add(String.format("org/joda/time/tz/data/%s/%s", zoneParts[0], zoneParts[1]));
+            }
+        }
+        return new NativeImageResourceBuildItem(timezones);
+    }
+}
diff --git a/extensions-jvm/twilio/pom.xml b/extensions/twilio/pom.xml
similarity index 97%
rename from extensions-jvm/twilio/pom.xml
rename to extensions/twilio/pom.xml
index 93d06e3..40d7480 100644
--- a/extensions-jvm/twilio/pom.xml
+++ b/extensions/twilio/pom.xml
@@ -33,6 +33,5 @@
     <modules>
         <module>deployment</module>
         <module>runtime</module>
-        <module>integration-test</module>
     </modules>
 </project>
diff --git a/extensions-jvm/twilio/runtime/pom.xml b/extensions/twilio/runtime/pom.xml
similarity index 91%
rename from extensions-jvm/twilio/runtime/pom.xml
rename to extensions/twilio/runtime/pom.xml
index e86d5d6..30aa967 100644
--- a/extensions-jvm/twilio/runtime/pom.xml
+++ b/extensions/twilio/runtime/pom.xml
@@ -32,6 +32,7 @@
 
     <properties>
         <camel.quarkus.jvmSince>1.1.0</camel.quarkus.jvmSince>
+        <camel.quarkus.nativeSince>1.4.0</camel.quarkus.nativeSince>
     </properties>
 
     <dependencyManagement>
@@ -48,6 +49,14 @@
 
     <dependencies>
         <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-jackson</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-support-httpclient</artifactId>
+        </dependency>
+        <dependency>
             <groupId>org.apache.camel.quarkus</groupId>
             <artifactId>camel-quarkus-core</artifactId>
         </dependency>
diff --git a/extensions-jvm/twilio/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/twilio/runtime/src/main/resources/META-INF/quarkus-extension.yaml
similarity index 97%
rename from extensions-jvm/twilio/runtime/src/main/resources/META-INF/quarkus-extension.yaml
rename to extensions/twilio/runtime/src/main/resources/META-INF/quarkus-extension.yaml
index bfeb129..ae48d6f 100644
--- a/extensions-jvm/twilio/runtime/src/main/resources/META-INF/quarkus-extension.yaml
+++ b/extensions/twilio/runtime/src/main/resources/META-INF/quarkus-extension.yaml
@@ -24,9 +24,8 @@
 name: "Camel Twilio"
 description: "Interact with Twilio REST APIs using Twilio Java SDK"
 metadata:
-  unlisted: true
   guide: "https://camel.apache.org/camel-quarkus/latest/reference/extensions/twilio.html"
   categories:
   - "integration"
   status:
-  - "preview"
+  - "stable"
diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml
index 7ee0b1c..9a90095 100644
--- a/integration-tests/pom.xml
+++ b/integration-tests/pom.xml
@@ -161,6 +161,7 @@
         <module>tarfile</module>
         <module>telegram</module>
         <module>tika</module>
+        <module>twilio</module>
         <module>twitter</module>
         <module>univocity-parsers</module>
         <module>validator</module>
diff --git a/integration-tests/twilio/README.adoc b/integration-tests/twilio/README.adoc
new file mode 100644
index 0000000..b3b3c5f
--- /dev/null
+++ b/integration-tests/twilio/README.adoc
@@ -0,0 +1,22 @@
+== Camel Quarkus Twilio Integration Tests
+
+By default the Twilio integration tests use WireMock to stub the API interactions.
+
+To run the `camel-quarkus-twilio` integration tests against the real API, you must first create a Twilio account https://www.twilio.com/try-twilio.
+
+Then find your API https://www.twilio.com/docs/iam/test-credentials[test credentials] and set the following environment variables:
+
+[source,shell]
+----
+export TWILIO_USERNAME=your-user-name
+export TWILIO_PASSWORD=your-password
+export TWILIO_ACCOUNT_SID=your-account-sid
+----
+
+If the WireMock stub recordings need updating, then remove the existing files from `src/test/resources/mappings` and run tests with either:
+
+System property `-Dwiremock.record=true`
+
+Or
+
+Set environment variable `WIREMOCK_RECORD=true`
diff --git a/extensions-jvm/twilio/integration-test/pom.xml b/integration-tests/twilio/pom.xml
similarity index 50%
rename from extensions-jvm/twilio/integration-test/pom.xml
rename to integration-tests/twilio/pom.xml
index 450bef4..6d0819a 100644
--- a/extensions-jvm/twilio/integration-test/pom.xml
+++ b/integration-tests/twilio/pom.xml
@@ -21,25 +21,14 @@
     <modelVersion>4.0.0</modelVersion>
     <parent>
         <groupId>org.apache.camel.quarkus</groupId>
-        <artifactId>camel-quarkus-build-parent-it</artifactId>
+        <artifactId>camel-quarkus-integration-tests</artifactId>
         <version>1.4.0-SNAPSHOT</version>
-        <relativePath>../../../poms/build-parent-it/pom.xml</relativePath>
     </parent>
 
-    <artifactId>camel-quarkus-twilio-integration-test</artifactId>
-    <name>Camel Quarkus :: Twilio :: Integration Test</name>
+    <artifactId>camel-quarkus-integration-test-twilio</artifactId>
+    <name>Camel Quarkus :: Integration Tests :: Twilio</name>
     <description>Integration tests for Camel Quarkus Twilio extension</description>
 
-    <properties>
-        <!-- mvnd, a.k.a. Maven Daemon: https://github.com/mvndaemon/mvnd -->
-        <!-- The following rule tells mvnd to build the listed deployment modules before this module. -->
-        <!-- This is important because mvnd builds modules in parallel by default. The deployment modules are not -->
-        <!-- explicit dependencies of this module in the Maven sense, although they are required by the Quarkus Maven plugin. -->
-        <!-- Please update the rule whenever you change the dependencies of this module by running -->
-        <!--     mvn process-resources -Pformat    from the root directory -->
-        <mvnd.builder.rule>camel-quarkus-support-policy-deployment,camel-quarkus-twilio-deployment</mvnd.builder.rule>
-    </properties>
-
     <dependencyManagement>
         <dependencies>
             <dependency>
@@ -77,6 +66,68 @@
             <artifactId>rest-assured</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-integration-wiremock-support</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- The following dependencies guarantee that this module is built after them. You can update them by running `mvn process-resources -Pformat -N` from the source tree root directory -->
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-main-deployment</artifactId>
+            <version>${project.version}</version>
+            <type>pom</type>
+            <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>*</groupId>
+                    <artifactId>*</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-twilio-deployment</artifactId>
+            <version>${project.version}</version>
+            <type>pom</type>
+            <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>*</groupId>
+                    <artifactId>*</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
     </dependencies>
 
+    <profiles>
+        <profile>
+            <id>native</id>
+            <activation>
+                <property>
+                    <name>native</name>
+                </property>
+            </activation>
+            <properties>
+                <quarkus.package.type>native</quarkus.package.type>
+            </properties>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-failsafe-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <goals>
+                                    <goal>integration-test</goal>
+                                    <goal>verify</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
 </project>
diff --git a/integration-tests/twilio/src/main/java/org/apache/camel/quarkus/component/twilio/it/TwilioResource.java b/integration-tests/twilio/src/main/java/org/apache/camel/quarkus/component/twilio/it/TwilioResource.java
new file mode 100644
index 0000000..e53e28d
--- /dev/null
+++ b/integration-tests/twilio/src/main/java/org/apache/camel/quarkus/component/twilio/it/TwilioResource.java
@@ -0,0 +1,129 @@
+/*
+ * 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.quarkus.component.twilio.it;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import com.twilio.http.HttpClient;
+import com.twilio.http.NetworkHttpClient;
+import com.twilio.http.Request;
+import com.twilio.http.TwilioRestClient;
+import com.twilio.rest.api.v2010.account.Call;
+import com.twilio.rest.api.v2010.account.IncomingPhoneNumber;
+import com.twilio.rest.api.v2010.account.Message;
+import io.quarkus.arc.Unremovable;
+import org.apache.camel.ProducerTemplate;
+
+@Path("/twilio")
+public class TwilioResource {
+
+    @Inject
+    ProducerTemplate producerTemplate;
+
+    @Path("/message")
+    @POST
+    @Produces(MediaType.TEXT_PLAIN)
+    @Consumes(MediaType.TEXT_PLAIN)
+    public Response createMessage(String body) throws Exception {
+        Message message = producerTemplate.requestBody(
+                "twilio://message/create?from=RAW(+15005550006)&to=RAW(+14108675310)&body=" + body, null, Message.class);
+        return Response.ok(message.getSid()).build();
+    }
+
+    @Path("/purchase")
+    @POST
+    @Produces(MediaType.TEXT_PLAIN)
+    public Response purchasePhoneNumber() throws Exception {
+        IncomingPhoneNumber phoneNumber = producerTemplate.requestBody(
+                "twilio://incoming-phone-number/create?phonenumber=RAW(+15005550006)", null, IncomingPhoneNumber.class);
+        return Response.ok(phoneNumber.getPhoneNumber()).build();
+    }
+
+    @Path("/call")
+    @POST
+    @Produces(MediaType.TEXT_PLAIN)
+    public Response phoneCall() throws Exception {
+        Call call = producerTemplate.requestBody(
+                "twilio://call/create?from=RAW(+15005550006)&to=RAW(+14108675310)&url=http://demo.twilio.com/docs/voice.xml",
+                null, Call.class);
+        return Response.ok(call.getSid()).build();
+    }
+
+    @Unremovable
+    @Singleton
+    @Produces
+    @Named("restClient")
+    public TwilioRestClient restClient() {
+        // If mocking is enabled, we need to ensure Twilio API calls are directed to the mock server
+        String wireMockUrl = System.getProperty("wiremock.url");
+        if (wireMockUrl != null) {
+            HttpClient client = new NetworkHttpClient() {
+                @Override
+                public com.twilio.http.Response makeRequest(Request originalRequest) {
+                    String url = originalRequest.getUrl();
+
+                    Request modified = new Request(originalRequest.getMethod(),
+                            url.replace("https://api.twilio.com", wireMockUrl));
+
+                    Map<String, List<String>> headerParams = originalRequest.getHeaderParams();
+                    for (String key : headerParams.keySet()) {
+                        for (String value : headerParams.get(key)) {
+                            modified.addHeaderParam(key, value);
+                        }
+                    }
+
+                    Map<String, List<String>> postParams = originalRequest.getPostParams();
+                    for (String key : postParams.keySet()) {
+                        for (String value : postParams.get(key)) {
+                            modified.addPostParam(key, value);
+                        }
+                    }
+
+                    Map<String, List<String>> queryParams = originalRequest.getQueryParams();
+                    for (String key : queryParams.keySet()) {
+                        for (String value : queryParams.get(key)) {
+                            modified.addQueryParam(key, value);
+                        }
+                    }
+
+                    modified.setAuth(originalRequest.getUsername(), originalRequest.getPassword());
+
+                    return super.makeRequest(modified);
+                }
+            };
+
+            return new TwilioRestClient.Builder(
+                    System.getProperty("camel.component.twilio.username"),
+                    System.getProperty("camel.component.twilio.password"))
+                            .accountSid(System.getProperty("camel.component.twilio.account-sid"))
+                            .httpClient(client)
+                            .build();
+        }
+        return null;
+    }
+}
diff --git a/extensions-jvm/twilio/integration-test/src/test/java/org/apache/camel/quarkus/component/twilio/it/TwilioTest.java b/integration-tests/twilio/src/test/java/org/apache/camel/quarkus/component/twilio/it/TwilioIT.java
similarity index 70%
rename from extensions-jvm/twilio/integration-test/src/test/java/org/apache/camel/quarkus/component/twilio/it/TwilioTest.java
rename to integration-tests/twilio/src/test/java/org/apache/camel/quarkus/component/twilio/it/TwilioIT.java
index 55b53b5..bc15dbf 100644
--- a/extensions-jvm/twilio/integration-test/src/test/java/org/apache/camel/quarkus/component/twilio/it/TwilioTest.java
+++ b/integration-tests/twilio/src/test/java/org/apache/camel/quarkus/component/twilio/it/TwilioIT.java
@@ -16,19 +16,9 @@
  */
 package org.apache.camel.quarkus.component.twilio.it;
 
-import io.quarkus.test.junit.QuarkusTest;
-import io.restassured.RestAssured;
-import org.junit.jupiter.api.Test;
+import io.quarkus.test.junit.NativeImageTest;
 
-@QuarkusTest
-class TwilioTest {
-
-    @Test
-    public void loadComponentTwilio() {
-        /* A simple autogenerated test */
-        RestAssured.get("/twilio/load/component/twilio")
-                .then()
-                .statusCode(200);
-    }
+@NativeImageTest
+class TwilioIT extends TwilioTest {
 
 }
diff --git a/integration-tests/twilio/src/test/java/org/apache/camel/quarkus/component/twilio/it/TwilioTest.java b/integration-tests/twilio/src/test/java/org/apache/camel/quarkus/component/twilio/it/TwilioTest.java
new file mode 100644
index 0000000..e1b2a8a
--- /dev/null
+++ b/integration-tests/twilio/src/test/java/org/apache/camel/quarkus/component/twilio/it/TwilioTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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.quarkus.component.twilio.it;
+
+import io.quarkus.test.common.QuarkusTestResource;
+import io.quarkus.test.junit.QuarkusTest;
+import io.restassured.RestAssured;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+/**
+ * Note: The scenarios tested here are the only ones supported with Twilio test credentials
+ *
+ * https://www.twilio.com/docs/iam/test-credentials
+ */
+@QuarkusTestResource(TwilioTestResource.class)
+@QuarkusTest
+class TwilioTest {
+
+    @Test
+    public void sendMessage() {
+        String messageId = RestAssured.given()
+                .body("Hello Camel Quarkus Twilio")
+                .post("/twilio/message")
+                .then()
+                .statusCode(200)
+                .extract()
+                .body()
+                .asString();
+
+        assertFalse(messageId.isEmpty());
+    }
+
+    @Test
+    public void purchasePhoneNumber() {
+        String phoneNumber = RestAssured.given()
+                .post("/twilio/purchase")
+                .then()
+                .statusCode(200)
+                .extract()
+                .body()
+                .asString();
+
+        assertEquals("+15005550006", phoneNumber);
+    }
+
+    @Test
+    public void phoneCall() {
+        String phoneNumber = RestAssured.given()
+                .post("/twilio/call")
+                .then()
+                .statusCode(200)
+                .extract()
+                .body()
+                .asString();
+
+        assertFalse(phoneNumber.isEmpty());
+    }
+}
diff --git a/integration-tests/twilio/src/test/java/org/apache/camel/quarkus/component/twilio/it/TwilioTestResource.java b/integration-tests/twilio/src/test/java/org/apache/camel/quarkus/component/twilio/it/TwilioTestResource.java
new file mode 100644
index 0000000..1fca0cd
--- /dev/null
+++ b/integration-tests/twilio/src/test/java/org/apache/camel/quarkus/component/twilio/it/TwilioTestResource.java
@@ -0,0 +1,51 @@
+/*
+ * 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.quarkus.component.twilio.it;
+
+import java.util.Map;
+
+import org.apache.camel.quarkus.test.wiremock.WireMockTestResourceLifecycleManager;
+import org.apache.camel.util.CollectionHelper;
+
+public class TwilioTestResource extends WireMockTestResourceLifecycleManager {
+
+    private static final String TWILIO_API_BASE_URL = "https://api.twilio.com";
+    private static final String TWILIO_ENV_USERNAME = "TWILIO_USERNAME";
+    private static final String TWILIO_ENV_PASSWORD = "TWILIO_PASSWORD";
+    private static final String TWILIO_ENV_ACCOUNT_SID = "TWILIO_ACCOUNT_SID";
+
+    @Override
+    public Map<String, String> start() {
+        return CollectionHelper.mergeMaps(super.start(), CollectionHelper.mapOf(
+                "camel.component.twilio.username", envOrDefault(TWILIO_ENV_USERNAME, "test"),
+                "camel.component.twilio.password", envOrDefault(TWILIO_ENV_PASSWORD, "2se3r3t"),
+                "camel.component.twilio.account-sid", envOrDefault(TWILIO_ENV_ACCOUNT_SID, "test")));
+    }
+
+    @Override
+    public String getRecordTargetBaseUrl() {
+        return TWILIO_API_BASE_URL;
+    }
+
+    @Override
+    public boolean isMockingEnabled() {
+        return !envVarsPresent(
+                TWILIO_ENV_USERNAME,
+                TWILIO_ENV_PASSWORD,
+                TWILIO_ENV_ACCOUNT_SID);
+    }
+}
diff --git a/integration-tests/twilio/src/test/resources/mappings/twilioPhoneCall.json b/integration-tests/twilio/src/test/resources/mappings/twilioPhoneCall.json
new file mode 100644
index 0000000..301e366
--- /dev/null
+++ b/integration-tests/twilio/src/test/resources/mappings/twilioPhoneCall.json
@@ -0,0 +1,31 @@
+{
+  "id" : "5857027d-5598-4769-b79e-78951d1a8b8d",
+  "name" : "2010-04-01_accounts_test_callsjson",
+  "request" : {
+    "url" : "/2010-04-01/Accounts/test/Calls.json",
+    "method" : "POST",
+    "bodyPatterns" : [ {
+      "equalTo" : "To=%2B14108675310&From=%2B15005550006&Url=http%3A%2F%2Fdemo.twilio.com%2Fdocs%2Fvoice.xml",
+      "caseInsensitive" : false
+    } ]
+  },
+  "response" : {
+    "status" : 201,
+    "body" : "{\"date_updated\": \"Tue, 27 Oct 2020 14:14:02 +0000\", \"price_unit\": \"USD\", \"parent_call_sid\": null, \"caller_name\": null, \"duration\": null, \"from\": \"+15005550006\", \"to\": \"+14108675310\", \"annotation\": null, \"answered_by\": null, \"sid\": \"CA66b4ff97854621f04fea0e49f92f66ea\", \"queue_time\": \"0\", \"price\": null, \"api_version\": \"2010-04-01\", \"status\": \"queued\", \"direction\": null, \"start_time\": null, \"date_created\": \"Tue, 27 Oct 2020 14 [...]
+    "headers" : {
+      "Date" : "Tue, 27 Oct 2020 14:14:02 GMT",
+      "Content-Type" : "application/json",
+      "Twilio-Concurrent-Requests" : "1",
+      "Twilio-Request-Id" : "RQ3e5e14c2989a443ab231b79611748321",
+      "Twilio-Request-Duration" : "0.018",
+      "X-Powered-By" : "AT-5000",
+      "X-Shenanigans" : "none",
+      "X-Home-Region" : "us1",
+      "X-API-Domain" : "api.twilio.com",
+      "Strict-Transport-Security" : "max-age=31536000"
+    }
+  },
+  "uuid" : "5857027d-5598-4769-b79e-78951d1a8b8d",
+  "persistent" : true,
+  "insertionIndex" : 1
+}
\ No newline at end of file
diff --git a/integration-tests/twilio/src/test/resources/mappings/twilioPurchaseNumber.json b/integration-tests/twilio/src/test/resources/mappings/twilioPurchaseNumber.json
new file mode 100644
index 0000000..65d5698
--- /dev/null
+++ b/integration-tests/twilio/src/test/resources/mappings/twilioPurchaseNumber.json
@@ -0,0 +1,31 @@
+{
+  "id" : "49f6b8ea-9fc0-4804-bda4-46c0f5304bb0",
+  "name" : "2010-04-01_accounts_test_incomingphonenumbersjson",
+  "request" : {
+    "url" : "/2010-04-01/Accounts/test/IncomingPhoneNumbers.json",
+    "method" : "POST",
+    "bodyPatterns" : [ {
+      "equalTo" : "PhoneNumber=%2B15005550006",
+      "caseInsensitive" : false
+    } ]
+  },
+  "response" : {
+    "status" : 201,
+    "body" : "{\"sid\": \"PNd0a95f9f5b0dabf14b472bfd4b4b72d1\", \"account_sid\": \"test\", \"friendly_name\": \"(500) 555-0006\", \"phone_number\": \"+15005550006\", \"voice_url\": null, \"voice_method\": \"POST\", \"voice_fallback_url\": null, \"voice_fallback_method\": \"POST\", \"voice_caller_id_lookup\": false, \"date_created\": \"Tue, 27 Oct 2020 14:14:03 +0000\", \"date_updated\": \"Tue, 27 Oct 2020 14:14:03 +0000\", \"sms_url\": \"\", \"sms_method\": \"POST\", \"sms_fallback_url\" [...]
+    "headers" : {
+      "Date" : "Tue, 27 Oct 2020 14:14:03 GMT",
+      "Content-Type" : "application/json",
+      "Twilio-Concurrent-Requests" : "1",
+      "Twilio-Request-Id" : "RQ3b188151ab1440a89a2b754c23500c44",
+      "Twilio-Request-Duration" : "0.226",
+      "X-Powered-By" : "AT-5000",
+      "X-Shenanigans" : "none",
+      "X-Home-Region" : "us1",
+      "X-API-Domain" : "api.twilio.com",
+      "Strict-Transport-Security" : "max-age=31536000"
+    }
+  },
+  "uuid" : "49f6b8ea-9fc0-4804-bda4-46c0f5304bb0",
+  "persistent" : true,
+  "insertionIndex" : 3
+}
\ No newline at end of file
diff --git a/integration-tests/twilio/src/test/resources/mappings/twilioSendMessage.json b/integration-tests/twilio/src/test/resources/mappings/twilioSendMessage.json
new file mode 100644
index 0000000..88cedb8
--- /dev/null
+++ b/integration-tests/twilio/src/test/resources/mappings/twilioSendMessage.json
@@ -0,0 +1,31 @@
+{
+  "id" : "86fb6910-1118-4067-b2e1-9520828b76a9",
+  "name" : "2010-04-01_accounts_test_messagesjson",
+  "request" : {
+    "url" : "/2010-04-01/Accounts/test/Messages.json",
+    "method" : "POST",
+    "bodyPatterns" : [ {
+      "equalTo" : "To=%2B14108675310&From=%2B15005550006&Body=Hello+Camel+Quarkus+Twilio",
+      "caseInsensitive" : false
+    } ]
+  },
+  "response" : {
+    "status" : 201,
+    "body" : "{\"sid\": \"SM2691e2c49c654cf1bbc96300f3d68b2b\", \"date_created\": \"Tue, 27 Oct 2020 14:14:03 +0000\", \"date_updated\": \"Tue, 27 Oct 2020 14:14:03 +0000\", \"date_sent\": null, \"account_sid\": \"test\", \"to\": \"+14108675310\", \"from\": \"+15005550006\", \"messaging_service_sid\": null, \"body\": \"Hello Camel Quarkus Twilio\", \"status\": \"queued\", \"num_segments\": \"1\", \"num_media\": \"0\", \"direction\": \"outbound-api\", \"api_version\": \"2010-04-01\", \"pr [...]
+    "headers" : {
+      "Date" : "Tue, 27 Oct 2020 14:14:03 GMT",
+      "Content-Type" : "application/json",
+      "Twilio-Concurrent-Requests" : "1",
+      "Twilio-Request-Id" : "RQd1b0d893e7c148d1b3a1ded5c2f0fa76",
+      "Twilio-Request-Duration" : "0.042",
+      "X-Powered-By" : "AT-5000",
+      "X-Shenanigans" : "none",
+      "X-Home-Region" : "us1",
+      "X-API-Domain" : "api.twilio.com",
+      "Strict-Transport-Security" : "max-age=31536000"
+    }
+  },
+  "uuid" : "86fb6910-1118-4067-b2e1-9520828b76a9",
+  "persistent" : true,
+  "insertionIndex" : 2
+}
\ No newline at end of file
diff --git a/tooling/scripts/test-categories.yaml b/tooling/scripts/test-categories.yaml
index 70b6133..7d9695a 100644
--- a/tooling/scripts/test-categories.yaml
+++ b/tooling/scripts/test-categories.yaml
@@ -148,3 +148,4 @@ saas:
   - sap-netweaver
   - servicenow
   - slack
+  - twilio