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 <[email protected]> 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
