diff --git a/connectors/slack/element-templates/slack-connector.json b/connectors/slack/element-templates/slack-connector.json
index dcddf5ad71..a169aa7bf3 100644
--- a/connectors/slack/element-templates/slack-connector.json
+++ b/connectors/slack/element-templates/slack-connector.json
@@ -34,6 +34,10 @@
"id": "channel",
"label": "Channel"
},
+ {
+ "id": "invite",
+ "label": "Invite"
+ },
{
"id": "output",
"label": "Output Mapping"
@@ -65,6 +69,10 @@
{
"name": "Create Channel",
"value": "conversations.create"
+ },
+ {
+ "name": "Invite to Channel",
+ "value": "conversations.invite"
}
],
"binding": {
@@ -169,6 +177,44 @@
"equals": "chat.postMessage"
}
},
+ {
+ "label": "Channel Name",
+ "group": "invite",
+ "type": "String",
+ "feel": "optional",
+ "binding": {
+ "type": "zeebe:input",
+ "name": "data.channelName"
+ },
+ "constraints": {
+ "notEmpty": true,
+ "pattern": {
+ "value": "^(=|[-_a-z0-9]{1,80}$)",
+ "message": "May contain up to 80 lowercase letters, digits, underscores, and dashes"
+ }
+ },
+ "condition": {
+ "property": "method",
+ "equals": "conversations.invite"
+ }
+ },
+ {
+ "label": "Users",
+ "description": "Comma separated list of invitee names",
+ "group": "invite",
+ "type": "String",
+ "binding": {
+ "type": "zeebe:input",
+ "name": "data.users"
+ },
+ "constraints": {
+ "notEmpty": true
+ },
+ "condition": {
+ "property": "method",
+ "equals": "conversations.invite"
+ }
+ },
{
"label": "Result Variable",
"description": "Name of variable to store the response in",
diff --git a/connectors/slack/pom.xml b/connectors/slack/pom.xml
index 742ee8c2e6..d7456cbd28 100644
--- a/connectors/slack/pom.xml
+++ b/connectors/slack/pom.xml
@@ -99,6 +99,11 @@ except in compliance with the proprietary license.
mockito-junit-jupiter
test
+
+ io.camunda
+ spring-zeebe-connector-runtime
+ test
+
diff --git a/connectors/slack/src/main/java/io/camunda/connector/slack/ChatPostMessageData.java b/connectors/slack/src/main/java/io/camunda/connector/slack/ChatPostMessageData.java
index 8872b1a41e..bb642e206e 100644
--- a/connectors/slack/src/main/java/io/camunda/connector/slack/ChatPostMessageData.java
+++ b/connectors/slack/src/main/java/io/camunda/connector/slack/ChatPostMessageData.java
@@ -9,10 +9,8 @@
import com.slack.api.methods.MethodsClient;
import com.slack.api.methods.SlackApiException;
import com.slack.api.methods.request.chat.ChatPostMessageRequest;
-import com.slack.api.methods.request.users.UsersListRequest;
import com.slack.api.methods.request.users.UsersLookupByEmailRequest;
import com.slack.api.methods.response.chat.ChatPostMessageResponse;
-import com.slack.api.methods.response.users.UsersListResponse;
import com.slack.api.methods.response.users.UsersLookupByEmailResponse;
import com.slack.api.model.User;
import io.camunda.connector.api.annotation.Secret;
@@ -24,16 +22,14 @@
public class ChatPostMessageData implements SlackRequestData {
- private static final String EMAIL_REGEX = "^.+[@].+[.].{2,4}$";
-
@NotBlank @Secret private String channel;
@NotBlank @Secret private String text;
@Override
public SlackResponse invoke(MethodsClient methodsClient) throws SlackApiException, IOException {
if (channel.startsWith("@")) {
- channel = getUserId(channel.substring(1), methodsClient);
- } else if (isEmail(channel)) {
+ channel = DataLookupService.getUserIdByName(channel.substring(1), methodsClient);
+ } else if (DataLookupService.isEmail(channel)) {
channel = getUserIdByEmail(methodsClient);
}
ChatPostMessageRequest request =
@@ -52,44 +48,6 @@ public SlackResponse invoke(MethodsClient methodsClient) throws SlackApiExceptio
}
}
- private String getUserId(String userName, MethodsClient methodsClient) {
- String userId = null;
- String nextCursor = null;
-
- do {
- UsersListRequest request = UsersListRequest.builder().limit(100).cursor(nextCursor).build();
-
- try {
- UsersListResponse response = methodsClient.usersList(request);
- if (response.isOk()) {
- userId =
- response.getMembers().stream()
- .filter(user -> userName.equals(user.getRealName()))
- .map(User::getId)
- .findFirst()
- .orElse(null);
- nextCursor = response.getResponseMetadata().getNextCursor();
- } else {
- throw new RuntimeException(
- "Unable to find user with name: " + userName + "; message: " + response.getError());
- }
- } catch (Exception e) {
- throw new RuntimeException("Unable to find user with name: " + userName, e);
- }
-
- } while (userId == null && nextCursor != null && !nextCursor.isBlank());
-
- if (userId == null) {
- throw new RuntimeException("Unable to find user with name: " + userName);
- }
-
- return userId;
- }
-
- private boolean isEmail(final String str) {
- return str.matches(EMAIL_REGEX);
- }
-
private String getUserIdByEmail(final MethodsClient methodsClient)
throws IOException, SlackApiException {
UsersLookupByEmailRequest lookupByEmailRequest =
diff --git a/connectors/slack/src/main/java/io/camunda/connector/slack/Conversation.java b/connectors/slack/src/main/java/io/camunda/connector/slack/Conversation.java
new file mode 100644
index 0000000000..c1844b8797
--- /dev/null
+++ b/connectors/slack/src/main/java/io/camunda/connector/slack/Conversation.java
@@ -0,0 +1,44 @@
+package io.camunda.connector.slack;
+
+import java.util.Objects;
+
+public class Conversation {
+
+ private final String id;
+ private final String name;
+
+ public Conversation(com.slack.api.model.Conversation conversation) {
+ this.id = conversation.getId();
+ this.name = conversation.getName();
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Conversation that = (Conversation) o;
+ return Objects.equals(id, that.id) && Objects.equals(name, that.name);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, name);
+ }
+
+ @Override
+ public String toString() {
+ return "Conversation{" + "id='" + id + '\'' + ", name='" + name + '\'' + '}';
+ }
+}
diff --git a/connectors/slack/src/main/java/io/camunda/connector/slack/ConversationsCreateSlackResponse.java b/connectors/slack/src/main/java/io/camunda/connector/slack/ConversationsCreateSlackResponse.java
index 152511b656..93bed4ae86 100644
--- a/connectors/slack/src/main/java/io/camunda/connector/slack/ConversationsCreateSlackResponse.java
+++ b/connectors/slack/src/main/java/io/camunda/connector/slack/ConversationsCreateSlackResponse.java
@@ -42,45 +42,4 @@ public int hashCode() {
public String toString() {
return "ConversationsCreateSlackResponse{" + "channel=" + channel + '}';
}
-
- protected static class Conversation {
-
- private final String id;
- private final String name;
-
- public Conversation(com.slack.api.model.Conversation conversation) {
- this.id = conversation.getId();
- this.name = conversation.getName();
- }
-
- public String getId() {
- return id;
- }
-
- public String getName() {
- return name;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- Conversation that = (Conversation) o;
- return Objects.equals(id, that.id) && Objects.equals(name, that.name);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(id, name);
- }
-
- @Override
- public String toString() {
- return "Conversation{" + "id='" + id + '\'' + ", name='" + name + '\'' + '}';
- }
- }
}
diff --git a/connectors/slack/src/main/java/io/camunda/connector/slack/ConversationsInviteData.java b/connectors/slack/src/main/java/io/camunda/connector/slack/ConversationsInviteData.java
new file mode 100644
index 0000000000..6392b19057
--- /dev/null
+++ b/connectors/slack/src/main/java/io/camunda/connector/slack/ConversationsInviteData.java
@@ -0,0 +1,78 @@
+package io.camunda.connector.slack;
+
+import com.slack.api.methods.MethodsClient;
+import com.slack.api.methods.SlackApiException;
+import com.slack.api.methods.request.conversations.ConversationsInviteRequest;
+import com.slack.api.methods.response.conversations.ConversationsInviteResponse;
+import io.camunda.connector.api.annotation.Secret;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.io.IOException;
+import java.util.List;
+import java.util.Objects;
+
+public class ConversationsInviteData implements SlackRequestData {
+
+ @NotBlank
+ @Secret
+ private String channelName;
+ @NotBlank
+ @Secret
+ private String users;
+
+ @Override
+ public SlackResponse invoke(MethodsClient methodsClient) throws SlackApiException, IOException {
+ List userList = DataLookupService.getUserIdsFromNameOrEmail(DataLookupService.convertStringToList(users), methodsClient);
+ ConversationsInviteRequest request =
+ ConversationsInviteRequest.builder()
+ .channel(DataLookupService.getChannelIdByName(channelName, methodsClient))
+ .users(userList)
+ .build();
+
+ ConversationsInviteResponse response = methodsClient.conversationsInvite(request);
+
+ if (response.isOk()) {
+ return new ConversationsInviteSlackResponse(response);
+ } else {
+ throw new RuntimeException(response.getError());
+ }
+ }
+
+ public String getChannelName() {
+ return channelName;
+ }
+
+ public void setChannelName(String channelName) {
+ this.channelName = channelName;
+ }
+
+ public String getUsers() {
+ return users;
+ }
+
+ public void setUsers(String users) {
+ this.users = users;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ConversationsInviteData that = (ConversationsInviteData) o;
+ return channelName.equals(that.channelName) && Objects.equals(users, that.users);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(channelName, users);
+ }
+
+ @Override
+ public String toString() {
+ return "ConversationsInviteData{" +
+ "channelName='" + channelName + '\'' +
+ ", users=" + users +
+ '}';
+ }
+}
diff --git a/connectors/slack/src/main/java/io/camunda/connector/slack/ConversationsInviteSlackResponse.java b/connectors/slack/src/main/java/io/camunda/connector/slack/ConversationsInviteSlackResponse.java
new file mode 100644
index 0000000000..cf9ef57ac0
--- /dev/null
+++ b/connectors/slack/src/main/java/io/camunda/connector/slack/ConversationsInviteSlackResponse.java
@@ -0,0 +1,42 @@
+package io.camunda.connector.slack;
+
+import com.slack.api.methods.response.conversations.ConversationsInviteResponse;
+import java.util.Objects;
+
+public class ConversationsInviteSlackResponse implements SlackResponse {
+
+ private final Conversation channel;
+ private final String needed;
+ private final String provided;
+
+ public ConversationsInviteSlackResponse(ConversationsInviteResponse conversationsInviteResponse) {
+ this.channel = new Conversation(conversationsInviteResponse.getChannel());
+ this.needed = conversationsInviteResponse.getNeeded();
+ this.provided = conversationsInviteResponse.getProvided();
+ }
+
+ public Conversation getChannel() {
+ return channel;
+ }
+
+ public String getNeeded() {
+ return needed;
+ }
+
+ public String getProvided() {
+ return provided;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ConversationsInviteSlackResponse that = (ConversationsInviteSlackResponse) o;
+ return Objects.equals(channel, that.channel) && Objects.equals(needed, that.needed) && Objects.equals(provided, that.provided);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(channel, needed, provided);
+ }
+}
diff --git a/connectors/slack/src/main/java/io/camunda/connector/slack/DataLookupService.java b/connectors/slack/src/main/java/io/camunda/connector/slack/DataLookupService.java
new file mode 100644
index 0000000000..065eb64c68
--- /dev/null
+++ b/connectors/slack/src/main/java/io/camunda/connector/slack/DataLookupService.java
@@ -0,0 +1,166 @@
+package io.camunda.connector.slack;
+
+import com.slack.api.methods.MethodsClient;
+import com.slack.api.methods.SlackApiException;
+import com.slack.api.methods.request.conversations.ConversationsListRequest;
+import com.slack.api.methods.request.users.UsersListRequest;
+import com.slack.api.methods.request.users.UsersLookupByEmailRequest;
+import com.slack.api.methods.response.conversations.ConversationsListResponse;
+import com.slack.api.methods.response.users.UsersListResponse;
+import com.slack.api.methods.response.users.UsersLookupByEmailResponse;
+import com.slack.api.model.Conversation;
+import com.slack.api.model.User;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class DataLookupService {
+
+ private static final String EMAIL_REGEX = "^.+[@].+[.].{2,4}$";
+
+ public static List convertStringToList(String string) {
+ if(StringUtils.isBlank(string)) {
+ return new ArrayList<>();
+ }
+ return Arrays.stream(string.split(",")).map(s -> s.trim()).collect(Collectors.toList());
+ }
+
+ public static boolean isEmail(final String str) {
+ return str.matches(EMAIL_REGEX);
+ }
+
+ public static List getUserIdsFromNameOrEmail(List userList, MethodsClient methodsClient) {
+ if(Objects.isNull(userList) || userList.isEmpty()) {
+ return new ArrayList<>();
+ }
+
+ List emails = new ArrayList<>();
+ List usernames = new ArrayList<>();
+ userList.stream().forEach(user -> (isEmail(user) ? emails : usernames).add(user));
+
+ List idListByEmail = emails.stream()
+ .map(email -> {
+ try {
+ return getUserIdByEmail(email, methodsClient);
+ } catch (Exception e) {
+ throw new RuntimeException("Unable to find user with name or email : " + email, e);
+ }
+ })
+ .collect(Collectors.toList());
+
+ List idListByUserName = getIdListByUserNameList(usernames, methodsClient);
+
+ return Stream.concat(idListByEmail.stream(), idListByUserName.stream()).collect(Collectors.toList());
+ }
+
+ public static String getUserIdByEmail(String email, MethodsClient methodsClient) throws SlackApiException, IOException {
+ UsersLookupByEmailRequest lookupByEmailRequest = UsersLookupByEmailRequest.builder().email(email).build();
+ return Optional.ofNullable(methodsClient.usersLookupByEmail(lookupByEmailRequest))
+ .filter(UsersLookupByEmailResponse::isOk)
+ .map(UsersLookupByEmailResponse::getUser)
+ .map(User::getId)
+ .orElseThrow(() -> new RuntimeException("Unable to find user with email: " + email));
+ }
+
+ public static List getIdListByUserNameList(List userNameList, MethodsClient methodsClient) {
+ if(userNameList == null || userNameList.isEmpty()) {
+ return new ArrayList<>();
+ }
+ String nextCursor = null;
+ List idList = new ArrayList<>();
+ do {
+ UsersListRequest request = UsersListRequest.builder().limit(100).cursor(nextCursor).build();
+
+ try {
+ UsersListResponse response = methodsClient.usersList(request);
+ if (response.isOk()) {
+ idList.addAll(response.getMembers().stream()
+ .filter(user -> userNameList.contains(user.getRealName()))
+ .map(User::getId)
+ .collect(Collectors.toList()));
+ nextCursor = response.getResponseMetadata().getNextCursor();
+ } else {
+ throw new RuntimeException(
+ "Unable to get users; message: " + response.getError());
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("Unable to find users by name", e);
+ }
+
+ } while (idList.size() < userNameList.size() && nextCursor != null && !nextCursor.isBlank());
+ return idList;
+ }
+
+ public static String getChannelIdByName(String channelName, MethodsClient methodsClient) {
+ String channelId = null;
+ String nextCursor = null;
+
+ do {
+ ConversationsListRequest request = ConversationsListRequest.builder().limit(100).cursor(nextCursor).build();
+
+ try {
+ ConversationsListResponse response = methodsClient.conversationsList(request);
+ if (response.isOk()) {
+ channelId =
+ response.getChannels().stream()
+ .filter(channel -> channelName.equals(channel.getName()))
+ .map(Conversation::getId)
+ .findFirst()
+ .orElse(null);
+ nextCursor = response.getResponseMetadata().getNextCursor();
+ } else {
+ throw new RuntimeException(
+ "Unable to find conversation with channel name: " + channelName + "; message: " + response.getError());
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("Unable to find conversation with name: " + channelName, e);
+ }
+
+ } while (channelId == null && nextCursor != null && !nextCursor.isBlank());
+
+ if (channelId == null) {
+ throw new RuntimeException("Unable to find conversation with name: " + channelName);
+ }
+
+ return channelId;
+ }
+
+ public static String getUserIdByName(String userName, MethodsClient methodsClient) {
+ String userId = null;
+ String nextCursor = null;
+
+ do {
+ UsersListRequest request = UsersListRequest.builder().limit(100).cursor(nextCursor).build();
+
+ try {
+ UsersListResponse response = methodsClient.usersList(request);
+ if (response.isOk()) {
+ userId =
+ response.getMembers().stream()
+ .filter(user -> userName.equals(user.getRealName()))
+ .map(User::getId)
+ .findFirst()
+ .orElse(null);
+ nextCursor = response.getResponseMetadata().getNextCursor();
+ } else {
+ throw new RuntimeException(
+ "Unable to find user with name: " + userName + "; message: " + response.getError());
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("Unable to find user with name: " + userName, e);
+ }
+
+ } while (userId == null && nextCursor != null && !nextCursor.isBlank());
+
+ if (userId == null) {
+ throw new RuntimeException("Unable to find user with name: " + userName);
+ }
+
+ return userId;
+ }
+
+
+}
diff --git a/connectors/slack/src/main/java/io/camunda/connector/slack/GsonSupplier.java b/connectors/slack/src/main/java/io/camunda/connector/slack/GsonSupplier.java
index ac77809758..f9f155f1d1 100644
--- a/connectors/slack/src/main/java/io/camunda/connector/slack/GsonSupplier.java
+++ b/connectors/slack/src/main/java/io/camunda/connector/slack/GsonSupplier.java
@@ -13,8 +13,9 @@ public final class GsonSupplier {
private static final SlackRequestDeserializer DESERIALIZER =
new SlackRequestDeserializer("method")
- .registerType("chat.postMessage", ChatPostMessageData.class)
- .registerType("conversations.create", ConversationsCreateData.class);
+ .registerType("chat.postMessage", ChatPostMessageData.class)
+ .registerType("conversations.create", ConversationsCreateData.class)
+ .registerType("conversations.invite", ConversationsInviteData.class);
private static final Gson GSON =
new GsonBuilder().registerTypeAdapter(SlackRequest.class, DESERIALIZER).create();
diff --git a/connectors/slack/src/test/java/io/camunda/connector/slack/ConversationsInviteDataTest.java b/connectors/slack/src/test/java/io/camunda/connector/slack/ConversationsInviteDataTest.java
new file mode 100644
index 0000000000..e0b082d904
--- /dev/null
+++ b/connectors/slack/src/test/java/io/camunda/connector/slack/ConversationsInviteDataTest.java
@@ -0,0 +1,111 @@
+package io.camunda.connector.slack;
+
+import com.slack.api.methods.MethodsClient;
+import com.slack.api.methods.SlackApiException;
+import com.slack.api.methods.request.conversations.ConversationsInviteRequest;
+import com.slack.api.methods.request.conversations.ConversationsListRequest;
+import com.slack.api.methods.request.users.UsersLookupByEmailRequest;
+import com.slack.api.methods.response.conversations.ConversationsInviteResponse;
+import com.slack.api.methods.response.conversations.ConversationsListResponse;
+import com.slack.api.methods.response.users.UsersLookupByEmailResponse;
+import com.slack.api.model.*;
+import com.slack.api.model.Conversation;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+public class ConversationsInviteDataTest {
+ @Mock
+ private MethodsClient methodsClient;
+ @Mock private UsersLookupByEmailResponse lookupByEmailResponse;
+ @Mock private ConversationsListResponse conversationsListResponse;
+ @Mock private User user;
+ @Mock private ConversationsInviteResponse conversationsInviteResponse;
+
+ @Captor
+ private ArgumentCaptor conversationsInviteRequest;
+
+ private static final String USERID = "testUserId";
+
+ private static final String CHANNEL_NAME = "channel";
+
+ @Test
+ void invoke_shouldThrowExceptionWhenUserNotFoundByEmail() throws SlackApiException, IOException {
+ // Given
+ ConversationsInviteData conversationsInviteData = new ConversationsInviteData();
+ conversationsInviteData.setChannelName(CHANNEL_NAME);
+ conversationsInviteData.setUsers("test1@test.com, test2@test.com");
+ when(methodsClient.usersLookupByEmail(any(UsersLookupByEmailRequest.class))).thenReturn(null);
+ // When and then
+ RuntimeException thrown =
+ assertThrows(
+ RuntimeException.class,
+ () -> conversationsInviteData.invoke(methodsClient),
+ "RuntimeException was expected");
+ assertThat(thrown.getMessage())
+ .contains(
+ "Unable to find user with name or email : test1@test.com");
+ }
+
+ @ParameterizedTest
+ @ValueSource(
+ strings = {
+ "test1@test.com, test2@test.com",
+ "firstName.LastName1@mail.org,firstName.LastName2@mail.org",
+ "n.a.m.e@mail.ua",
+ "a@m.uat",
+ "_23@ma.au"
+ })
+ void invoke_shouldFindUserIdByEmail(final String emailList) throws SlackApiException, IOException {
+ // Given
+ ConversationsInviteData conversationsInviteData = new ConversationsInviteData();
+ conversationsInviteData.setUsers(emailList);
+ conversationsInviteData.setChannelName(CHANNEL_NAME);
+
+ when(methodsClient.usersLookupByEmail(any(UsersLookupByEmailRequest.class)))
+ .thenReturn(lookupByEmailResponse);
+ when(lookupByEmailResponse.isOk()).thenReturn(true);
+ when(lookupByEmailResponse.getUser()).thenReturn(user);
+ when(user.getId()).thenReturn(USERID);
+
+ when(methodsClient.conversationsList(any(ConversationsListRequest.class)))
+ .thenReturn(conversationsListResponse);
+ when(conversationsListResponse.isOk()).thenReturn(true);
+ when(conversationsListResponse.getChannels())
+ .thenReturn(Arrays.asList(Conversation.builder().id("wrong_id").name("wrong_name").build(),
+ Conversation.builder().id("good_id").name(CHANNEL_NAME).build()));
+ when(conversationsListResponse.getResponseMetadata())
+ .thenReturn(new ResponseMetadata());
+
+ when(methodsClient.conversationsInvite(conversationsInviteRequest.capture()))
+ .thenReturn(conversationsInviteResponse);
+ when(conversationsInviteResponse.isOk()).thenReturn(true);
+ when(conversationsInviteResponse.getChannel()).thenReturn(new Conversation());
+ when(conversationsInviteResponse.getNeeded()).thenReturn("needed");
+ when(conversationsInviteResponse.getProvided()).thenReturn("provided");
+ // When
+ conversationsInviteData.invoke(methodsClient);
+ // Then
+ ConversationsInviteRequest value = conversationsInviteRequest.getValue();
+ List expectedResolvedUserIds = Arrays.stream(emailList.split(",")).map(s -> USERID).collect(Collectors.toList());
+
+ assertEquals("good_id", value.getChannel());
+ assertTrue(value.getUsers().containsAll(expectedResolvedUserIds) && expectedResolvedUserIds.containsAll(value.getUsers()));
+ }
+}
diff --git a/connectors/slack/src/test/java/io/camunda/connector/slack/ConversationsInviteSlackResponseTest.java b/connectors/slack/src/test/java/io/camunda/connector/slack/ConversationsInviteSlackResponseTest.java
new file mode 100644
index 0000000000..df4b58ab33
--- /dev/null
+++ b/connectors/slack/src/test/java/io/camunda/connector/slack/ConversationsInviteSlackResponseTest.java
@@ -0,0 +1,31 @@
+package io.camunda.connector.slack;
+
+import com.slack.api.methods.response.conversations.ConversationsInviteResponse;
+import com.slack.api.model.Conversation;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+public class ConversationsInviteSlackResponseTest {
+ private static final String CHANNEL_NAME = "channel";
+ @Mock private ConversationsInviteResponse conversationsInviteResponse;
+ @Mock private Conversation conversation;
+
+ @Test
+ public void shouldReturnCorrectResponse() {
+ // Given
+ when(conversationsInviteResponse.getChannel()).thenReturn(conversation);
+ when(conversation.getName()).thenReturn(CHANNEL_NAME);
+ // When
+ ConversationsInviteSlackResponse response =
+ new ConversationsInviteSlackResponse(conversationsInviteResponse);
+ // Then
+ assertThat(response.getChannel().getName()).isEqualTo(CHANNEL_NAME);
+ }
+
+}
diff --git a/connectors/slack/src/test/java/io/camunda/connector/slack/LocalConnectorRuntime.java b/connectors/slack/src/test/java/io/camunda/connector/slack/LocalConnectorRuntime.java
new file mode 100644
index 0000000000..df166179da
--- /dev/null
+++ b/connectors/slack/src/test/java/io/camunda/connector/slack/LocalConnectorRuntime.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
+ * under one or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information regarding copyright
+ * ownership. Camunda licenses this file to you under the Apache License,
+ * Version 2.0; 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 io.camunda.connector.slack;
+
+import io.camunda.connector.runtime.ConnectorRuntimeApplication;
+import org.springframework.boot.SpringApplication;
+
+public class LocalConnectorRuntime {
+
+ public static void main(String[] args) {
+ SpringApplication.run(ConnectorRuntimeApplication.class, args);
+ }
+}
diff --git a/connectors/slack/src/test/resources/application.properties b/connectors/slack/src/test/resources/application.properties
new file mode 100644
index 0000000000..a1e4eff8e7
--- /dev/null
+++ b/connectors/slack/src/test/resources/application.properties
@@ -0,0 +1,4 @@
+# Configuration for running connectors locally in bundle with connector-runtime
+server.port=9898
+zeebe.broker.gateway-address=localhost:26500
+zeebe.client.security.plaintext=true