package example.jbot.slack; import me.ramswaroop.jbot.core.slack.Bot; import me.ramswaroop.jbot.core.slack.Controller; import me.ramswaroop.jbot.core.slack.EventType; import me.ramswaroop.jbot.core.slack.SlackService; import me.ramswaroop.jbot.core.slack.models.Event; import me.ramswaroop.jbot.core.slack.models.User; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.rule.OutputCapture; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; import java.util.Arrays; import java.util.regex.Matcher; import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.assertThat; import static org.mockito.Mockito.when; /** * @author ramswaroop * @version 20/06/2016 */ @RunWith(MockitoJUnitRunner.class) @SpringBootTest public class SlackBotTest { @Mock private WebSocketSession session; @Mock private SlackService slackService; @InjectMocks private TestBot bot; @Rule public OutputCapture capture = new OutputCapture(); @Before public void init() { // set user User user = new User(); user.setName("SlackBot"); user.setId("UEADGH12S"); // set rtm when(slackService.getDmChannels()).thenReturn(Arrays.asList("D1E79BACV", "C0NDSV5B8")); when(slackService.getCurrentUser()).thenReturn(user); when(slackService.getWebSocketUrl()).thenReturn(""); } @Test public void when_DirectMention_Should_InvokeOnDirectMention() throws Exception { TextMessage textMessage = new TextMessage("{\"type\": \"message\"," + "\"ts\": \"1358878749.000002\"," + "\"user\": \"U023BECGF\"," + "\"text\": \"<@UEADGH12S>: Hello\"}"); bot.handleTextMessage(session, textMessage); assertThat(capture.toString(), containsString("Hi, I am")); } @Test public void when_DirectMessage_Should_InvokeOnDirectMessage() throws Exception { TextMessage textMessage = new TextMessage("{\"type\": \"message\"," + "\"ts\": \"1358878749.000002\"," + "\"channel\": \"D1E79BACV\"," + "\"user\": \"U023BECGF\"," + "\"text\": \"Hello\"}"); bot.handleTextMessage(session, textMessage); assertThat(capture.toString(), containsString("this is a direct message")); } @Test public void when_MessageWithPattern_Should_InvokeOnReceiveMessageWithPattern() throws Exception { TextMessage textMessage = new TextMessage("{\"type\": \"message\"," + "\"ts\": \"1358878749.000002\"," + "\"channel\": \"A1E78BACV\"," + "\"user\": \"U023BECGF\"," + "\"text\": \"as12sd\"}"); bot.handleTextMessage(session, textMessage); assertThat(capture.toString(), containsString("First group: as12sd")); assertThat(capture.toString(), containsString("Second group: as")); assertThat(capture.toString(), containsString("Third group: 12")); assertThat(capture.toString(), containsString("Fourth group: sd")); } @Test public void when_DirectMessageWithPattern_Should_InvokeOnDirectMessage() throws Exception { TextMessage textMessage = new TextMessage("{\"type\": \"message\"," + "\"ts\": \"1358878749.000002\"," + "\"channel\": \"D1E79BACV\"," + "\"user\": \"U023BECGF\"," + "\"text\": \"as12sd\"}"); // this matches the pattern but it's a direct message instead of message bot.handleTextMessage(session, textMessage); assertThat(capture.toString(), containsString("this is a direct message")); } @Test public void when_DirectMessage_Should_InvokeOnPinAdded() throws Exception { TextMessage textMessage = new TextMessage("{\"type\":\"pin_added\"," + "\"user\":\"U0MCAEX8A\",\"channel_id\":\"C0NDSV5B8\"," + "\"item\":{\"type\":\"message\",\"channel\":\"C0NDSV5B8\"," + "\"message\":{\"type\":\"message\",\"user\":\"U1G0EBU2G\"," + "\"text\":\"Hi, I am nexagebot\",\"ts\":\"1471213096.000004\"," + "\"permalink\":\"https://aol.slack.com/archives/house-hunting/p1471213096000004\"," + "\"pinned_to\":[\"C0NDSV5B8\"]}," + "\"created\":1471213126}," + "\"item_user\":\"U1G0EBU2G\"," + "\"event_ts\":\"1471213126.954738\"}"); bot.handleTextMessage(session, textMessage); assertThat(capture.toString(), containsString("Thanks for the pin")); } @Test public void when_DirectMessage_Should_InvokeOnFileShared() throws Exception { TextMessage textMessage = new TextMessage("{\"type\":\"file_shared\"," + "\"file_id\":\"F219AF6VD\"," + "\"user_id\":\"U0MCAEX8A\"," + "\"file\":{\"id\":\"F219AF6VD\"}," + "\"event_ts\":\"1471213812.962298\"}"); bot.handleTextMessage(session, textMessage); assertThat(capture.toString(), containsString("File shared")); } @Test public void when_ConversationPattern_Should_StartConversation() throws Exception { TextMessage textMessage = new TextMessage("{\"type\": \"message\"," + "\"ts\": \"1158878749.000002\"," + "\"channel\": \"A1E78BACV\"," + "\"user\": \"U023BECGF\"," + "\"text\": \"setup meeting\"}"); bot.handleTextMessage(session, textMessage); assertThat(capture.toString(), containsString("At what time (ex. 15:30) do you want me to set up the meeting?")); textMessage = new TextMessage("{\"type\": \"message\"," + "\"ts\": \"1258878749.000002\"," + "\"channel\": \"A1E78BACV\"," + "\"user\": \"U023BECGF\"," + "\"text\": \"12:50\"}"); bot.handleTextMessage(session, textMessage); assertThat(capture.toString(), containsString("Would you like to repeat it tomorrow?")); textMessage = new TextMessage("{\"type\": \"message\"," + "\"ts\": \"1358878749.000002\"," + "\"channel\": \"A1E78BACV\"," + "\"user\": \"U023BECGF\"," + "\"text\": \"yes\"}"); bot.handleTextMessage(session, textMessage); assertThat(capture.toString(), containsString("Would you like me to set a reminder for you")); textMessage = new TextMessage("{\"type\": \"message\"," + "\"ts\": \"1458878749.000002\"," + "\"channel\": \"A1E78BACV\"," + "\"user\": \"U023BECGF\"," + "\"text\": \"yes\"}"); bot.handleTextMessage(session, textMessage); assertThat(capture.toString(), containsString("I will remind you tomorrow before the meeting")); } @Test public void given_InConversation_when_AnswerNo_Should_StopConversation() throws Exception { TextMessage textMessage = new TextMessage("{\"type\": \"message\"," + "\"ts\": \"1368878749.000602\"," + "\"channel\": \"A1E78BACV\"," + "\"user\": \"U023BECGF\"," + "\"text\": \"setup meeting\"}"); bot.handleTextMessage(session, textMessage); assertThat(capture.toString(), containsString("At what time (ex. 15:30) do you want me to set up the meeting?")); textMessage = new TextMessage("{\"type\": \"message\"," + "\"ts\": \"1348878749.000302\"," + "\"channel\": \"A1E78BACV\"," + "\"user\": \"U023BECGF\"," + "\"text\": \"12:40\"}"); bot.handleTextMessage(session, textMessage); assertThat(capture.toString(), containsString("Would you like to repeat it tomorrow?")); textMessage = new TextMessage("{\"type\": \"message\"," + "\"ts\": \"1358878749.000002\"," + "\"channel\": \"A1E78BACV\"," + "\"user\": \"U023BECGF\"," + "\"text\": \"no\"}"); bot.handleTextMessage(session, textMessage); assertThat(capture.toString(), containsString("You can always schedule one with 'setup meeting' command")); } /** * Slack Bot for unit tests. */ public static class TestBot extends Bot { @Override public String getSlackToken() { return "slackToken"; } @Override public Bot getSlackBot() { return this; } @Controller(events = EventType.DIRECT_MENTION) public void onDirectMention(WebSocketSession session, Event event) { System.out.println("Hi, I am SlackBot"); } @Controller(events = EventType.DIRECT_MESSAGE) public void onDirectMessage(WebSocketSession session, Event event) { System.out.println("Hi, this is a direct message."); } @Controller(events = EventType.MESSAGE, pattern = "^([a-z ]{2})(\\d+)([a-z ]{2})$") public void onReceiveMessageWithPattern(WebSocketSession session, Event event, Matcher matcher) { System.out.println("First group: " + matcher.group(0) + "\n" + "Second group: " + matcher.group(1) + "\n" + "Third group: " + matcher.group(2) + "\n" + "Fourth group: " + matcher.group(3)); } @Controller(events = EventType.PIN_ADDED) public void onPinAdded(WebSocketSession session, Event event) { System.out.println("Thanks for the pin! You can find all pinned items under channel details."); } @Controller(events = EventType.FILE_SHARED) public void onFileShared(WebSocketSession session, Event event) { System.out.println("File shared."); } /** * Conversation feature of JBot. */ @Controller(pattern = "(setup meeting)", next = "confirmTiming") public void setupMeeting(WebSocketSession session, Event event) { startConversation(event, "confirmTiming"); // start conversation System.out.println("Cool! At what time (ex. 15:30) do you want me to set up the meeting?"); } @Controller(next = "askTimeForMeeting") public void confirmTiming(WebSocketSession session, Event event) { System.out.println("Your meeting is set at " + event.getText() + ". Would you like to repeat it tomorrow?"); nextConversation(event); // jump to next question in conversation } @Controller(next = "askWhetherToRepeat") public void askTimeForMeeting(WebSocketSession session, Event event) { if (event.getText().contains("yes")) { System.out.println("Okay. Would you like me to set a reminder for you?"); nextConversation(event); // jump to next question in conversation } else { System.out.println("No problem. You can always schedule one with 'setup meeting' command."); stopConversation(event); // stop conversation only if user says no } } @Controller public void askWhetherToRepeat(WebSocketSession session, Event event) { if (event.getText().contains("yes")) { System.out.println("Great! I will remind you tomorrow before the meeting."); } else { System.out.println("Oh! my boss is smart enough to remind himself :)"); } stopConversation(event); // stop conversation } } }