This is an automated email from the ASF dual-hosted git repository.
zbendhiba pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new e1215d172f5c CAMEL-23251- Google mail Add DataTypeTransformer for
Gmail ModifyMess… (#22285)
e1215d172f5c is described below
commit e1215d172f5c69a3756cc70f763950ff260150ae
Author: Zineb BENDHIBA <[email protected]>
AuthorDate: Thu Mar 26 16:21:00 2026 +0100
CAMEL-23251- Google mail Add DataTypeTransformer for Gmail ModifyMess…
(#22285)
* CAMEL-23251- Google mail Add DataTypeTransformer for Gmail
ModifyMessageRequest to update labels
Fixes #CAMEL-23251
Co-authored-by: Guillaume Nodet <[email protected]>
---
.../apache/camel/catalog/transformers.properties | 1 +
.../google-mail-update-message-labels.json | 14 ++
.../org/apache/camel/transformer.properties | 2 +-
.../transformer/google-mail-update-message-labels | 2 +
.../google-mail-update-message-labels.json | 14 ++
.../src/main/docs/google-mail-component.adoc | 78 ++++++
...MailUpdateMessageLabelsDataTypeTransformer.java | 133 ++++++++++
.../google/mail/MockGoogleMailClientFactory.java | 83 +++++++
...UpdateMessageLabelsDataTypeTransformerTest.java | 273 +++++++++++++++++++++
9 files changed, 599 insertions(+), 1 deletion(-)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/transformers.properties
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/transformers.properties
index d9a9a5e978be..c261164480cc 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/transformers.properties
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/transformers.properties
@@ -22,6 +22,7 @@ azure-storage-datalake-application-cloudevents
azure-storage-queue-application-cloudevents
google-calendar-stream-application-cloudevents
google-mail-stream-application-cloudevents
+google-mail-update-message-labels
google-pubsub-application-cloudevents
google-sheets-application-x-struct
google-sheets-stream-application-cloudevents
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/transformers/google-mail-update-message-labels.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/transformers/google-mail-update-message-labels.json
new file mode 100644
index 000000000000..6f56dd20d990
--- /dev/null
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/transformers/google-mail-update-message-labels.json
@@ -0,0 +1,14 @@
+{
+ "transformer": {
+ "kind": "transformer",
+ "name": "google-mail:update-message-labels",
+ "title": "Google Mail (Update Message Labels)",
+ "description": "Updates Gmail message labels by resolving label names from
addLabels\/removeLabels exchange variables",
+ "deprecated": false,
+ "javaType":
"org.apache.camel.component.google.mail.transform.GoogleMailUpdateMessageLabelsDataTypeTransformer",
+ "groupId": "org.apache.camel",
+ "artifactId": "camel-google-mail",
+ "version": "4.19.0-SNAPSHOT"
+ }
+}
+
diff --git
a/components/camel-google/camel-google-mail/src/generated/resources/META-INF/services/org/apache/camel/transformer.properties
b/components/camel-google/camel-google-mail/src/generated/resources/META-INF/services/org/apache/camel/transformer.properties
index ff3378f9a0fe..20bd343808d0 100644
---
a/components/camel-google/camel-google-mail/src/generated/resources/META-INF/services/org/apache/camel/transformer.properties
+++
b/components/camel-google/camel-google-mail/src/generated/resources/META-INF/services/org/apache/camel/transformer.properties
@@ -1,5 +1,5 @@
# Generated by camel build tools - do NOT edit this file!
-transformers=google-mail-stream:application-cloudevents
+transformers=google-mail-stream:application-cloudevents
google-mail:update-message-labels
groupId=org.apache.camel
artifactId=camel-google-mail
version=4.19.0-SNAPSHOT
diff --git
a/components/camel-google/camel-google-mail/src/generated/resources/META-INF/services/org/apache/camel/transformer/google-mail-update-message-labels
b/components/camel-google/camel-google-mail/src/generated/resources/META-INF/services/org/apache/camel/transformer/google-mail-update-message-labels
new file mode 100644
index 000000000000..e439c96ed1ff
--- /dev/null
+++
b/components/camel-google/camel-google-mail/src/generated/resources/META-INF/services/org/apache/camel/transformer/google-mail-update-message-labels
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.component.google.mail.transform.GoogleMailUpdateMessageLabelsDataTypeTransformer
diff --git
a/components/camel-google/camel-google-mail/src/generated/resources/META-INF/services/org/apache/camel/transformer/google-mail-update-message-labels.json
b/components/camel-google/camel-google-mail/src/generated/resources/META-INF/services/org/apache/camel/transformer/google-mail-update-message-labels.json
new file mode 100644
index 000000000000..6f56dd20d990
--- /dev/null
+++
b/components/camel-google/camel-google-mail/src/generated/resources/META-INF/services/org/apache/camel/transformer/google-mail-update-message-labels.json
@@ -0,0 +1,14 @@
+{
+ "transformer": {
+ "kind": "transformer",
+ "name": "google-mail:update-message-labels",
+ "title": "Google Mail (Update Message Labels)",
+ "description": "Updates Gmail message labels by resolving label names from
addLabels\/removeLabels exchange variables",
+ "deprecated": false,
+ "javaType":
"org.apache.camel.component.google.mail.transform.GoogleMailUpdateMessageLabelsDataTypeTransformer",
+ "groupId": "org.apache.camel",
+ "artifactId": "camel-google-mail",
+ "version": "4.19.0-SNAPSHOT"
+ }
+}
+
diff --git
a/components/camel-google/camel-google-mail/src/main/docs/google-mail-component.adoc
b/components/camel-google/camel-google-mail/src/main/docs/google-mail-component.adoc
index bf1eb6788ae3..69381e4843e7 100644
---
a/components/camel-google/camel-google-mail/src/main/docs/google-mail-component.adoc
+++
b/components/camel-google/camel-google-mail/src/main/docs/google-mail-component.adoc
@@ -63,6 +63,84 @@ include::partial$component-endpoint-options.adoc[]
include::partial$component-endpoint-headers.adoc[]
// component options: END
+== Data Type Transformer: update-message-labels
+
+The `google-mail:update-message-labels` data type transformer builds a
`ModifyMessageRequest` from exchange variables, resolving label names to Gmail
label IDs automatically.
+
+This is useful for modifying Gmail message labels (categorizing, archiving,
starring, moving, etc.) without manually calling the labels/list API.
+
+=== Exchange Variables
+
+[cols="1,1,3"]
+|===
+| Variable | Type | Description
+
+| `addLabels`
+| `String` (comma-separated) or `List<String>`
+| Label names to add to the message.
+
+| `removeLabels`
+| `String` (comma-separated) or `List<String>`
+| Label names to remove from the message.
+|===
+
+At least one of the two variables must be set.
+
+Both system labels (INBOX, UNREAD, STARRED, SPAM, TRASH, IMPORTANT, etc.) and
custom user-defined labels are resolved via the Gmail labels/list API.
+
+=== Examples
+
+[tabs]
+====
+Java::
++
+[source,java]
+----
+from("google-mail-stream:0")
+ .setVariable("addLabels", constant("Work"))
+ .setVariable("removeLabels", constant("INBOX,UNREAD"))
+ .transformDataType(new DataType("google-mail:update-message-labels"))
+ .to("google-mail:messages/modify");
+----
+
+YAML::
++
+[source,yaml]
+----
+- route:
+ from:
+ uri: "google-mail-stream:0"
+ steps:
+ - setVariable:
+ name: addLabels
+ constant: "Work"
+ - setVariable:
+ name: removeLabels
+ constant: "INBOX,UNREAD"
+ - transformDataType:
+ toType: "google-mail:update-message-labels"
+ - to:
+ uri: "google-mail:messages/modify"
+----
+
+XML::
++
+[source,xml]
+----
+<route>
+ <from uri="google-mail-stream:0"/>
+ <setVariable name="addLabels">
+ <constant>Work</constant>
+ </setVariable>
+ <setVariable name="removeLabels">
+ <constant>INBOX,UNREAD</constant>
+ </setVariable>
+ <transformDataType toType="google-mail:update-message-labels"/>
+ <to uri="google-mail:messages/modify"/>
+</route>
+----
+====
+
== More Information
For more information on the endpoints and options see API documentation
diff --git
a/components/camel-google/camel-google-mail/src/main/java/org/apache/camel/component/google/mail/transform/GoogleMailUpdateMessageLabelsDataTypeTransformer.java
b/components/camel-google/camel-google-mail/src/main/java/org/apache/camel/component/google/mail/transform/GoogleMailUpdateMessageLabelsDataTypeTransformer.java
new file mode 100644
index 000000000000..6dcf63b8cd70
--- /dev/null
+++
b/components/camel-google/camel-google-mail/src/main/java/org/apache/camel/component/google/mail/transform/GoogleMailUpdateMessageLabelsDataTypeTransformer.java
@@ -0,0 +1,133 @@
+/*
+ * 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.mail.transform;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.google.api.services.gmail.Gmail;
+import com.google.api.services.gmail.model.Label;
+import com.google.api.services.gmail.model.ListLabelsResponse;
+import com.google.api.services.gmail.model.ModifyMessageRequest;
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.component.google.mail.GoogleMailComponent;
+import org.apache.camel.component.google.mail.internal.GoogleMailConstants;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.DataTypeTransformer;
+import org.apache.camel.spi.Transformer;
+
+/**
+ * Data type transformer that builds a {@link ModifyMessageRequest} that
updates labels of a message from exchange
+ * variables {@code addLabels} and {@code removeLabels} .
+ *
+ */
+@DataTypeTransformer(name = "google-mail:update-message-labels",
+ description = "Updates Gmail message labels by resolving
label names from addLabels/removeLabels exchange variables")
+public class GoogleMailUpdateMessageLabelsDataTypeTransformer extends
Transformer {
+
+ public static final String VARIABLE_ADD_LABELS = "addLabels";
+ public static final String VARIABLE_REMOVE_LABELS = "removeLabels";
+
+ private static final String DEFAULT_USER_ID = "me";
+ private static final String HEADER_USER_ID =
GoogleMailConstants.PROPERTY_PREFIX + "userId";
+
+ @Override
+ public void transform(Message message, DataType fromType, DataType toType)
throws Exception {
+ Exchange exchange = message.getExchange();
+
+ List<String> addLabelNames = getLabelsVariable(exchange,
VARIABLE_ADD_LABELS);
+ List<String> removeLabelNames = getLabelsVariable(exchange,
VARIABLE_REMOVE_LABELS);
+
+ if (addLabelNames.isEmpty() && removeLabelNames.isEmpty()) {
+ throw new CamelExecutionException(
+ "At least one of 'addLabels' or 'removeLabels' exchange
variables must be set", exchange);
+ }
+
+ String userId = message.getHeader(HEADER_USER_ID, DEFAULT_USER_ID,
String.class);
+ Map<String, String> labelMap = fetchLabelMap(userId);
+
+ List<String> addLabelIds = resolveLabelIds(addLabelNames, labelMap,
exchange);
+ List<String> removeLabelIds = resolveLabelIds(removeLabelNames,
labelMap, exchange);
+
+ ModifyMessageRequest request = new ModifyMessageRequest();
+ if (!addLabelIds.isEmpty()) {
+ request.setAddLabelIds(addLabelIds);
+ }
+ if (!removeLabelIds.isEmpty()) {
+ request.setRemoveLabelIds(removeLabelIds);
+ }
+
+ message.setBody(request);
+ }
+
+ @SuppressWarnings("unchecked")
+ private List<String> getLabelsVariable(Exchange exchange, String
variableName) {
+ Object value = exchange.getVariable(variableName);
+ if (value == null) {
+ return Collections.emptyList();
+ }
+ if (value instanceof List) {
+ return (List<String>) value;
+ }
+ if (value instanceof String stringValue) {
+ if (stringValue.isBlank()) {
+ return Collections.emptyList();
+ }
+ return
Arrays.stream(stringValue.split(",")).map(String::trim).toList();
+ }
+ throw new CamelExecutionException(
+ "Exchange variable '" + variableName + "' must be a
List<String> or a comma-separated String, but was: "
+ + value.getClass().getName(),
+ exchange);
+ }
+
+ private List<String> resolveLabelIds(List<String> labelNames, Map<String,
String> labelMap, Exchange exchange) {
+ List<String> ids = new ArrayList<>(labelNames.size());
+ for (String name : labelNames) {
+ String id = labelMap.get(name);
+ if (id == null) {
+ throw new CamelExecutionException(
+ "Label '" + name + "' not found. Available labels: " +
labelMap.keySet(), exchange);
+ }
+ ids.add(id);
+ }
+ return ids;
+ }
+
+ private Map<String, String> fetchLabelMap(String userId) throws Exception {
+ Gmail client = getGmailClient();
+ ListLabelsResponse response =
client.users().labels().list(userId).execute();
+ Map<String, String> map = new HashMap<>();
+ if (response.getLabels() != null) {
+ for (Label label : response.getLabels()) {
+ map.put(label.getName(), label.getId());
+ }
+ }
+ return map;
+ }
+
+ private Gmail getGmailClient() {
+ GoogleMailComponent component =
getCamelContext().getComponent("google-mail", GoogleMailComponent.class);
+ return component.getClient(component.getConfiguration());
+ }
+}
diff --git
a/components/camel-google/camel-google-mail/src/test/java/org/apache/camel/component/google/mail/MockGoogleMailClientFactory.java
b/components/camel-google/camel-google-mail/src/test/java/org/apache/camel/component/google/mail/MockGoogleMailClientFactory.java
new file mode 100644
index 000000000000..123b868be9a4
--- /dev/null
+++
b/components/camel-google/camel-google-mail/src/test/java/org/apache/camel/component/google/mail/MockGoogleMailClientFactory.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.google.mail;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import com.google.api.client.auth.oauth2.Credential;
+import
com.google.api.client.googleapis.testing.auth.oauth2.MockGoogleCredential;
+import com.google.api.client.http.HttpTransport;
+import com.google.api.client.http.LowLevelHttpRequest;
+import com.google.api.client.http.LowLevelHttpResponse;
+import com.google.api.client.json.JsonFactory;
+import com.google.api.client.json.gson.GsonFactory;
+import com.google.api.client.testing.http.MockHttpTransport;
+import com.google.api.client.testing.http.MockLowLevelHttpRequest;
+import com.google.api.client.testing.http.MockLowLevelHttpResponse;
+import com.google.api.services.gmail.Gmail;
+import org.apache.camel.CamelContext;
+
+public class MockGoogleMailClientFactory implements GoogleMailClientFactory {
+
+ public static final JsonFactory JSON_FACTORY =
GsonFactory.getDefaultInstance();
+
+ private final HttpTransport transport;
+ private final List<String> requestUrls = new ArrayList<>();
+
+ public MockGoogleMailClientFactory(String jsonContent) {
+ transport = new MockHttpTransport() {
+ @Override
+ public LowLevelHttpRequest buildRequest(String method, String url)
{
+ requestUrls.add(url);
+ return new MockLowLevelHttpRequest() {
+ @Override
+ public LowLevelHttpResponse execute() {
+ MockLowLevelHttpResponse response = new
MockLowLevelHttpResponse();
+ response.setContentType("application/json");
+ response.setContent(jsonContent);
+ return response;
+ }
+ };
+ }
+ };
+ }
+
+ public List<String> getRequestUrls() {
+ return requestUrls;
+ }
+
+ @Override
+ public Gmail makeClient(
+ String clientId, String clientSecret, Collection<String> scopes,
String applicationName,
+ String refreshToken, String accessToken) {
+ return makeClient();
+ }
+
+ @Override
+ public Gmail makeClient(
+ CamelContext camelContext, String serviceAccountKey,
Collection<String> scopes,
+ String applicationName, String delegate) {
+ return makeClient();
+ }
+
+ private Gmail makeClient() {
+ Credential credential = new MockGoogleCredential.Builder().build();
+ return new Gmail.Builder(transport, JSON_FACTORY,
credential).setApplicationName("mock").build();
+ }
+}
diff --git
a/components/camel-google/camel-google-mail/src/test/java/org/apache/camel/component/google/mail/transform/GoogleMailUpdateMessageLabelsDataTypeTransformerTest.java
b/components/camel-google/camel-google-mail/src/test/java/org/apache/camel/component/google/mail/transform/GoogleMailUpdateMessageLabelsDataTypeTransformerTest.java
new file mode 100644
index 000000000000..30f4a8463f69
--- /dev/null
+++
b/components/camel-google/camel-google-mail/src/test/java/org/apache/camel/component/google/mail/transform/GoogleMailUpdateMessageLabelsDataTypeTransformerTest.java
@@ -0,0 +1,273 @@
+/*
+ * 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.mail.transform;
+
+import java.util.List;
+
+import com.google.api.services.gmail.model.ModifyMessageRequest;
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.google.mail.GoogleMailComponent;
+import org.apache.camel.component.google.mail.GoogleMailConfiguration;
+import org.apache.camel.component.google.mail.MockGoogleMailClientFactory;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.support.DefaultExchange;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@TestInstance(TestInstance.Lifecycle.PER_CLASS)
+class GoogleMailUpdateMessageLabelsDataTypeTransformerTest extends
CamelTestSupport {
+
+ private static final String LABELS_RESPONSE = """
+ {
+ "labels": [
+ {"id": "INBOX", "name": "INBOX"},
+ {"id": "UNREAD", "name": "UNREAD"},
+ {"id": "Label_789", "name": "Work"},
+ {"id": "Label_456", "name": "Another Label"}
+ ]
+ }
+ """;
+
+ private GoogleMailUpdateMessageLabelsDataTypeTransformer transformer;
+ private MockGoogleMailClientFactory mockClientFactory;
+
+ @Override
+ protected CamelContext createCamelContext() throws Exception {
+ final CamelContext context = new DefaultCamelContext();
+
+ GoogleMailConfiguration configuration = new GoogleMailConfiguration();
+ configuration.setClientId("mock-client-id");
+ configuration.setClientSecret("mock-client-secret");
+ configuration.setApplicationName("mock");
+
+ mockClientFactory = new MockGoogleMailClientFactory(LABELS_RESPONSE);
+
+ final GoogleMailComponent component = new GoogleMailComponent(context);
+ component.setConfiguration(configuration);
+ component.setClientFactory(mockClientFactory);
+
+ context.addComponent("google-mail", component);
+
+ return context;
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("direct:input")
+ .transformDataType("google-mail:update-message-labels")
+ .to("mock:result");
+ }
+ };
+ }
+
+ @Override
+ protected void doPostSetup() {
+ transformer = new GoogleMailUpdateMessageLabelsDataTypeTransformer();
+ transformer.setCamelContext(context);
+ }
+
+ @Test
+ void testAddAndRemoveLabels() throws Exception {
+ Exchange exchange = new DefaultExchange(context);
+ exchange.setVariable("addLabels", List.of("Work"));
+ exchange.setVariable("removeLabels", List.of("INBOX"));
+
+ transformer.transform(exchange.getMessage(), DataType.ANY,
DataType.ANY);
+
+ ModifyMessageRequest request =
exchange.getMessage().getBody(ModifyMessageRequest.class);
+ assertNotNull(request);
+ assertEquals(List.of("Label_789"), request.getAddLabelIds());
+ assertEquals(List.of("INBOX"), request.getRemoveLabelIds());
+ }
+
+ @Test
+ void testCommaSeparatedString() throws Exception {
+ Exchange exchange = new DefaultExchange(context);
+ exchange.setVariable("addLabels", "Work,Another Label");
+ exchange.setVariable("removeLabels", "INBOX");
+
+ transformer.transform(exchange.getMessage(), DataType.ANY,
DataType.ANY);
+
+ ModifyMessageRequest request =
exchange.getMessage().getBody(ModifyMessageRequest.class);
+ assertNotNull(request);
+ assertEquals(List.of("Label_789", "Label_456"),
request.getAddLabelIds());
+ assertEquals(List.of("INBOX"), request.getRemoveLabelIds());
+ }
+
+ @Test
+ void testOnlyAddLabels() throws Exception {
+ Exchange exchange = new DefaultExchange(context);
+ exchange.setVariable("addLabels", List.of("Work"));
+
+ transformer.transform(exchange.getMessage(), DataType.ANY,
DataType.ANY);
+
+ ModifyMessageRequest request =
exchange.getMessage().getBody(ModifyMessageRequest.class);
+ assertNotNull(request);
+ assertEquals(List.of("Label_789"), request.getAddLabelIds());
+ assertNull(request.getRemoveLabelIds());
+ }
+
+ @Test
+ void testOnlyRemoveLabels() throws Exception {
+ Exchange exchange = new DefaultExchange(context);
+ exchange.setVariable("removeLabels", List.of("INBOX"));
+
+ transformer.transform(exchange.getMessage(), DataType.ANY,
DataType.ANY);
+
+ ModifyMessageRequest request =
exchange.getMessage().getBody(ModifyMessageRequest.class);
+ assertNotNull(request);
+ assertNull(request.getAddLabelIds());
+ assertEquals(List.of("INBOX"), request.getRemoveLabelIds());
+ }
+
+ @Test
+ void testNoLabelsThrowsException() {
+ Exchange exchange = new DefaultExchange(context);
+
+ assertThrows(CamelExecutionException.class,
+ () -> transformer.transform(exchange.getMessage(),
DataType.ANY, DataType.ANY));
+ }
+
+ @Test
+ void testUnknownLabelThrowsException() {
+ Exchange exchange = new DefaultExchange(context);
+ exchange.setVariable("addLabels", List.of("NonExistentLabel"));
+
+ assertThrows(CamelExecutionException.class,
+ () -> transformer.transform(exchange.getMessage(),
DataType.ANY, DataType.ANY));
+ }
+
+ @Test
+ void testExplicitUserId() throws Exception {
+ int urlCountBefore = mockClientFactory.getRequestUrls().size();
+
+ Exchange exchange = new DefaultExchange(context);
+ exchange.getMessage().setHeader("CamelGoogleMail.userId",
"[email protected]");
+ exchange.setVariable("addLabels", List.of("Work"));
+
+ transformer.transform(exchange.getMessage(), DataType.ANY,
DataType.ANY);
+
+ ModifyMessageRequest request =
exchange.getMessage().getBody(ModifyMessageRequest.class);
+ assertNotNull(request);
+ assertEquals(List.of("Label_789"), request.getAddLabelIds());
+
+ // Verify the userId was forwarded to the Gmail API
+ List<String> newUrls =
mockClientFactory.getRequestUrls().subList(urlCountBefore,
+ mockClientFactory.getRequestUrls().size());
+ assertTrue(newUrls.stream().anyMatch(url ->
url.contains("/users/[email protected]/")),
+ "Expected Gmail API call with userId '[email protected]', but
URLs were: " + newUrls);
+ }
+
+ @Test
+ void testTransformerName() {
+ assertEquals("google-mail:update-message-labels",
transformer.getName());
+ }
+
+ // E2E tests via Camel route)
+
+ @Test
+ void testAddAndRemoveLabelsViaRoute() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:result");
+ mock.reset();
+ mock.expectedMessageCount(1);
+
+ template.send("direct:input", exchange -> {
+ exchange.setVariable("addLabels", List.of("Work"));
+ exchange.setVariable("removeLabels", List.of("INBOX"));
+ });
+
+ mock.assertIsSatisfied();
+
+ Exchange received = mock.getExchanges().get(0);
+ ModifyMessageRequest request =
received.getMessage().getBody(ModifyMessageRequest.class);
+ assertNotNull(request);
+ assertEquals(List.of("Label_789"), request.getAddLabelIds());
+ assertEquals(List.of("INBOX"), request.getRemoveLabelIds());
+ }
+
+ @Test
+ void testCommaSeparatedLabelsViaRoute() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:result");
+ mock.reset();
+ mock.expectedMessageCount(1);
+
+ template.send("direct:input", exchange -> {
+ exchange.setVariable("addLabels", "Work,Another Label");
+ exchange.setVariable("removeLabels", "INBOX");
+ });
+
+ mock.assertIsSatisfied();
+
+ Exchange received = mock.getExchanges().get(0);
+ ModifyMessageRequest request =
received.getMessage().getBody(ModifyMessageRequest.class);
+ assertNotNull(request);
+ assertEquals(List.of("Label_789", "Label_456"),
request.getAddLabelIds());
+ assertEquals(List.of("INBOX"), request.getRemoveLabelIds());
+ }
+
+ @Test
+ void testOnlyAddLabelsViaRoute() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:result");
+ mock.reset();
+ mock.expectedMessageCount(1);
+
+ template.send("direct:input", exchange -> {
+ exchange.setVariable("addLabels", List.of("Work"));
+ });
+
+ mock.assertIsSatisfied();
+
+ Exchange received = mock.getExchanges().get(0);
+ ModifyMessageRequest request =
received.getMessage().getBody(ModifyMessageRequest.class);
+ assertNotNull(request);
+ assertEquals(List.of("Label_789"), request.getAddLabelIds());
+ }
+
+ @Test
+ void testOnlyRemoveLabelsViaRoute() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:result");
+ mock.reset();
+ mock.expectedMessageCount(1);
+
+ template.send("direct:input", exchange -> {
+ exchange.setVariable("removeLabels", List.of("INBOX"));
+ });
+
+ mock.assertIsSatisfied();
+
+ Exchange received = mock.getExchanges().get(0);
+ ModifyMessageRequest request =
received.getMessage().getBody(ModifyMessageRequest.class);
+ assertNotNull(request);
+ assertNull(request.getAddLabelIds());
+ assertEquals(List.of("INBOX"), request.getRemoveLabelIds());
+ }
+}