/* * Copyright 2012 Nodeable Inc * * Licensed 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 com.streamreduce.util; import com.google.common.collect.ImmutableSet; import com.streamreduce.connections.AuthType; import com.streamreduce.connections.ConnectionProvidersForTests; import com.streamreduce.core.model.Account; import com.streamreduce.core.model.Connection; import com.streamreduce.core.model.ConnectionCredentials; import com.streamreduce.core.model.InventoryItem; import com.streamreduce.core.model.User; import junit.framework.Assert; import net.sf.json.JSONArray; import net.sf.json.JSONObject; import org.bson.types.ObjectId; import org.junit.Before; import org.junit.Test; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.ResourceBundle; import java.util.Set; /** * Tests for {@link GitHubClient}. */ public class GitHubClientIT { private ResourceBundle gitHubProperties = ResourceBundle.getBundle("github"); private String githubPassword = gitHubProperties.getString("nodeable.github.password"); private String githubUsername = gitHubProperties.getString("nodeable.github.username"); private Set<String> monitoredProjects = new HashSet<>(); private Connection connection; private InventoryItem inventoryItem; private GitHubClient gitHubClient; @Before public void setUp() throws Exception { Account testAccount = new Account.Builder() .url("http://nodeable.com") .description("Nodeable Test Account") .name("Nodeable Testing") .build(); User testUser = new User.Builder() .account(testAccount) .accountLocked(false) .accountOriginator(true) .fullname("Nodeable Test User") .username("test_user_" + new Date().getTime() + "@nodeable.com") .build(); connection = new Connection.Builder() .credentials(new ConnectionCredentials(githubUsername, githubPassword)) .provider(ConnectionProvidersForTests.GITHUB_PROVIDER) .alias("Test GitHub Connection") .authType(AuthType.USERNAME_PASSWORD) .user(testUser) .build(); //Properties normally set by persistence/polling connection.setId(new ObjectId()); connection.setLastActivityPollDate(new Date(System.currentTimeMillis() - (1000 * 60 * 60 * 24))); // Create a date a day in the past inventoryItem = new InventoryItem.Builder() .account(testAccount) .user(testUser) .connection(connection) .hashtags(ImmutableSet.of("#github")) .build(); gitHubClient = new GitHubClient(connection,ConnectionProvidersForTests.GITHUB_PROVIDER.getOAuthService()); List<JSONObject> allRepositories = gitHubClient.getRepositories(); for (JSONObject repo : allRepositories) { monitoredProjects.add(repo.getJSONObject("owner").getString("login") + "/" + repo.getString("name")); } } /** * This tests that the parsing of GitHub activities generates the expected title and content strings * for the project hosting inventory item activity messages. * * @throws Exception if something goes wrong */ @Test public void testGetGitHubActivityParts() throws Exception { String validCharsClassRegex = "[a-zA-Z0-9_.-]"; int maxResults = 100; List<JSONObject> activities = gitHubClient.getActivity(monitoredProjects, maxResults); Assert.assertTrue("activities size was " + activities.size(), activities.size() > 0 && activities.size() <= maxResults); for (JSONObject activity : activities) { String projectKey = activity.getJSONObject("repo").getString("name"); // Prepare the inventory item inventoryItem.getExternalId(); String activityType = activity.getString("type"); // Only run supported tests and tests that haven't already been ran if (GitHubClient.SUPPORTED_EVENT_TYPES.contains(activityType)) { Map<String, Object> activityParts = gitHubClient.getPartsForActivity(inventoryItem, activity); String title = (String)activityParts.get("title"); String content = (String)activityParts.get("content"); Set<String> hashtags = (Set<String>)activityParts.get("hashtags"); String titleRegex = "^" + validCharsClassRegex + "+ "; String contentRegex = null; Set<String> expectedActivityHashtags = null; Assert.assertTrue(hashtags.contains("#" + projectKey.toLowerCase())); Assert.assertTrue(hashtags.contains("#github")); if (activityType.equals("CommitCommentEvent")) { titleRegex += ("commented on " + validCharsClassRegex + "+/" + validCharsClassRegex + "+$"); contentRegex = "^Comment in [a-zA-Z0-9]{10}: [\\s\\S]+$"; expectedActivityHashtags = ImmutableSet.of("#comment", "#source", "#changeset"); } else if (activityType.equals("CreateEvent")) { // We need to test three different create events String refType = activity.getJSONObject("payload").getString("ref_type"); titleRegex += ("created " + refType + (refType.equals("repository") ? " " + validCharsClassRegex + "+$" : " " + validCharsClassRegex + "+ at " + validCharsClassRegex + "+/" + validCharsClassRegex + "+$")); contentRegex = (refType.equals("repository") ? "^.*$" : "New " + refType + " is at /" + validCharsClassRegex + "+/" + validCharsClassRegex + "+/tree/" + validCharsClassRegex + "+$"); expectedActivityHashtags = ImmutableSet.of("#source", "#create", "#" + refType); } else if (activityType.equals("DeleteEvent")) { // We need to test two different create events String refType = activity.getJSONObject("payload").getString("ref_type"); titleRegex += ("deleted " + refType + " " + validCharsClassRegex + "+ at " + validCharsClassRegex + "+/" + validCharsClassRegex + "+$"); contentRegex = "^Deleted " + refType + " was at /" + validCharsClassRegex + "+/" + validCharsClassRegex + "+/tree/" + validCharsClassRegex + "+$"; expectedActivityHashtags = ImmutableSet.of("#source", "#delete", "#" + refType); } else if (activityType.equals("DownloadEvent")) { titleRegex += ("uploaded a file to " + validCharsClassRegex + "+/" + validCharsClassRegex + "+$"); contentRegex = "^\".+\" is at /" + validCharsClassRegex + "+/" + validCharsClassRegex + "+/downloads\n.+$"; expectedActivityHashtags = ImmutableSet.of("#download"); } else if (activityType.equals("ForkEvent")) { titleRegex += "forked " + validCharsClassRegex + "+/" + validCharsClassRegex + "+$"; contentRegex = "Forked repository is at " + validCharsClassRegex + "+/" + validCharsClassRegex + "+$"; expectedActivityHashtags = ImmutableSet.of("#repository", "#fork", "#create"); } else if (activityType.equals("ForkApplyEvent")) { titleRegex += "applied fork commits to " + validCharsClassRegex + "+/" + validCharsClassRegex + "+$"; contentRegex = "([a-zA-Z0-9]{7} .+[\\n]*)+"; expectedActivityHashtags = ImmutableSet.of("#fork", "#apply", "#source", "#changeset"); } else if (activityType.equals("GollumEvent")) { JSONArray pages = activity.getJSONObject("payload").getJSONArray("pages"); String action = null; if (pages.size() <= 1) { action = pages.getJSONObject(0).getString("action"); titleRegex += (action + " the " + validCharsClassRegex + "+/" + validCharsClassRegex + "+ wiki$"); } else { titleRegex += ("made multiple changes to the " + validCharsClassRegex + "+/" + validCharsClassRegex + "+ wiki$"); } contentRegex = "((Created|Edited) .+[\\n]*)+"; expectedActivityHashtags = ImmutableSet.of("#wiki"); } else if (activityType.equals("IssueCommentEvent")) { titleRegex += ("commented on (issue|pull request) \\d+ on " + validCharsClassRegex + "+/" + validCharsClassRegex + "+$"); contentRegex = "^[\\s\\S]+$"; expectedActivityHashtags = ImmutableSet.of("#issue", "#comment", "#" + activity.getJSONObject("payload").getJSONObject("issue").getString("state")); } else if (activityType.equals("IssuesEvent")) { titleRegex += ("(opened|closed|reopened) issue \\d+ on " + validCharsClassRegex + "+/" + validCharsClassRegex + "+$"); contentRegex = "^[\\s\\S]+$"; expectedActivityHashtags = ImmutableSet.of("#issue", "#" + activity.getJSONObject("payload").getJSONObject("issue").getString("state")); } else if (activityType.equals("MemberEvent")) { titleRegex += (" added " + validCharsClassRegex + "+ to " + validCharsClassRegex + "+/" + validCharsClassRegex + "+$"); contentRegex = ("^" + validCharsClassRegex + "+ is at " + validCharsClassRegex + "+/" + validCharsClassRegex + "+$"); expectedActivityHashtags = ImmutableSet.of("#repository", "#membership"); } else if (activityType.equals("PublicEvent")) { titleRegex += ("open sourced " + validCharsClassRegex + "+/" + validCharsClassRegex + "+$"); contentRegex = "^[\\s\\S]+$"; expectedActivityHashtags = ImmutableSet.of("#repository", "#opensourced"); } else if (activityType.equals("PullRequestEvent")) { titleRegex += ("(opened|closed|synchronized|reopened|merged) pull request \\d+ on " + validCharsClassRegex + "+/" + validCharsClassRegex + "+$"); contentRegex = "^.+\\n\\d+ commits with \\d+ additions and \\d+ deletions$"; String action = activity.getJSONObject("payload").getString("action").equals("closed") ? "merged" : activity.getJSONObject("payload").getString("action"); //handle case where we tranform "closed" to "merged" expectedActivityHashtags = ImmutableSet.of("#pullrequest", "#source", "#" + action); } else if (activityType.equals("PushEvent")) { titleRegex += ("pushed to " + validCharsClassRegex + "+ at " + validCharsClassRegex + "+/" + validCharsClassRegex + "+$"); contentRegex = "([a-zA-Z0-9]{7}[\\s\\S]+[\\n]*)*"; expectedActivityHashtags = ImmutableSet.of("#source", "#changeset"); } else if (activityType.equals("WatchEvent")) { titleRegex += ("started watching " + validCharsClassRegex + "+/" + validCharsClassRegex + "+$"); contentRegex = "^" + validCharsClassRegex + "+ description: \\n.+$"; expectedActivityHashtags = ImmutableSet.of("#repository", "#watch"); } Assert.assertTrue(activityType + " title (" + title + ") does not match regex (" + titleRegex + ").", title.matches(titleRegex)); Assert.assertTrue(activityType + " content (" + content + ") does not match regex (" + contentRegex + ").", content.matches(contentRegex)); for (String hashtag : expectedActivityHashtags) { Assert.assertTrue(activityType + " hashtag (" + hashtag + ") is not present as expected", hashtags.contains(hashtag)); } } } } }