package it.com.atlassian.labs.speakeasy; import com.atlassian.pageobjects.TestedProduct; import com.atlassian.pageobjects.page.LoginPage; import com.atlassian.plugin.test.PluginJarBuilder; import com.atlassian.plugin.util.zip.FileUnzipper; import com.atlassian.webdriver.pageobjects.WebDriverTester; import com.dumbster.smtp.SimpleSmtpServer; import com.google.common.collect.Sets; import it.com.atlassian.labs.speakeasy.util.TempHelp; import org.apache.commons.io.FileUtils; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.mail.MessagingException; import java.io.File; import java.io.IOException; import java.util.*; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Sets.newHashSet; import static it.com.atlassian.labs.speakeasy.ExtensionBuilder.buildSimplePluginFile; import static it.com.atlassian.labs.speakeasy.ExtensionBuilder.startSimpleBuilder; import static it.com.atlassian.labs.speakeasy.MailUtils.assertEmailExists; import static java.util.Arrays.asList; import static org.junit.Assert.*; import static org.junit.Assert.assertEquals; public class TestUserProfile { private static TestedProduct<?> product = OwnerOfTestedProduct.INSTANCE; private SimpleSmtpServer mailServer; private static Logger log = LoggerFactory.getLogger(TestUserProfile.class); @Before public void login() { product.visit(LoginPage.class).loginAsSysAdmin(SpeakeasyUserPage.class); } @After public void logout() { ((WebDriverTester)product.getTester()).getDriver().manage().deleteAllCookies(); } @Before public void startMailServer() { // starting it this way as we don't want to wait for a open socket mailServer = new SimpleSmtpServer(2525); Thread t = new Thread(mailServer); t.start(); } @After public void stopMailServer() { mailServer.stop(); } @Test public void testPluginList() { List<String> pluginKeys = product.getPageBinder().bind(SpeakeasyUserPage.class) .getPluginKeys(); assertTrue(pluginKeys.size() > 0); assertTrue(pluginKeys.contains("plugin-tests")); } @Test public void testEditPlugin() throws IOException { SpeakeasyUserPage page = product.getPageBinder().bind(SpeakeasyUserPage.class) .openInstallDialog() .uploadPlugin(startSimpleBuilder("edit", "Edit").addFormattedResource("foo-min.js", "var bar;").build()); IdeDialog ide = page.openEditDialog("edit"); assertEquals(asList("bar/baz.js", "modules/test.js", "atlassian-plugin.xml", "foo.js"), ide.getFileNames()); ide = ide.editAndSaveFile("foo.js", "var foo;") .done() .openEditDialog("edit"); String contents = ide.getFileContents("foo.js"); assertEquals("var foo;", contents); page = ide.done(); assertFalse(getZipEntries(page.openDownloadDialog("edit").downloadAsExtension()).contains("foo-min.js")); page.uninstallPlugin("edit"); } @Test public void testViewSourceOnPlugin() throws IOException { IdeDialog ide = product.getPageBinder().bind(SpeakeasyUserPage.class) .openInstallDialog() .uploadPlugin( startSimpleBuilder("viewsource", "View Source") .addFormattedResource("foo.js", "var bar;") .build()) .openViewSourceDialog("viewsource"); assertEquals(asList("bar/baz.js", "modules/test.js", "atlassian-plugin.xml", "foo.js"), ide.getFileNames()); assertEquals("var bar;", ide.getFileContents("foo.js").trim()); ide.done().uninstallPlugin("viewsource"); } @Test public void testEditAndBreakThenFixPlugin() throws IOException { product.getPageBinder().bind(SpeakeasyUserPage.class) .openInstallDialog() .uploadPlugin(buildSimplePluginFile()); // break with non-existent module IdeDialog ide = product.visit(SpeakeasyUserPage.class) .openInstallDialog() .uploadPlugin(buildSimplePluginFile()) .openEditDialog("test2") .editAndSaveFile("modules/test.js", "require('nonexistent/module');", "nonexistent/module"); assertTrue(ide.getStatus().contains("nonexistent/module")); SpeakeasyUserPage page = ide.done(); assertTrue(page.getPlugins().get("test2").getDescription().contains("nonexistent/module")); // break by changing the plugin key ide = page.openEditDialog("test2"); final String oldXml = ide.getFileContents("atlassian-plugin.xml"); page = ide .editAndSaveFile("modules/test.js", "require('speakeasy/jquery');") .editAndSaveFile("atlassian-plugin.xml", oldXml.replaceAll("test2", "test-3"), "Unable to install") .editAndSaveFile("atlassian-plugin.xml", oldXml) .done(); assertEquals("Desc", page.getPlugins().get("test2").getDescription()); page.uninstallPlugin("test2"); } @Test public void testDownloadPluginJarAsAmpsProject() throws IOException { final SpeakeasyUserPage page = product.getPageBinder().bind(SpeakeasyUserPage.class) .openInstallDialog() .uploadPlugin( buildSimplePluginFile("download.jar-project", "Download Jar")); File file = page .openDownloadDialog("download.jar-project") .downloadAsAmpsProject(); assertNotNull(file); File unzippedPluginDir = TempHelp.getTempDir("download.jar-project-amps-unzip"); FileUnzipper unzipper = new FileUnzipper(file, unzippedPluginDir); Set<String> entries = new HashSet<String>(); for (ZipEntry entry : unzipper.entries()) { entries.add(entry.getName()); } unzipper.unzip(); assertEquals(Sets.newHashSet( "pom.xml", "src/", "src/main/", "src/main/resources/", "src/main/resources/atlassian-plugin.xml", "src/main/resources/foo.js", "src/main/resources/bar/", "src/main/resources/bar/baz.js", "src/main/resources/modules/", "src/main/resources/modules/test.js" ), entries); File fooFile = new File(unzippedPluginDir, "src/main/resources/foo.js"); assertEquals("alert(\"hi\");", FileUtils.readFileToString(fooFile).trim()); String pomContents = FileUtils.readFileToString(new File(unzippedPluginDir, "pom.xml")); assertFalse(pomContents.contains("${")); assertTrue(pomContents.contains("plugin.key>download.jar-project</plugin.key")); page.uninstallPlugin("download.jar-project"); } @Test public void testDownloadPluginJarAsExtension() throws IOException { final SpeakeasyUserPage page = product. getPageBinder().bind(SpeakeasyUserPage.class). openInstallDialog(). uploadPlugin(buildSimplePluginFile("download.jar-file", "Jar File")); File file = page .openDownloadDialog("download.jar-file") .downloadAsExtension(); assertNotNull(file); assertTrue(file.getName().endsWith(".jar")); File unzippedPluginDir = TempHelp.getTempDir("download.jar-file-extension-unzip"); FileUnzipper unzipper = new FileUnzipper(file, unzippedPluginDir); Set<String> entries = new HashSet<String>(); for (ZipEntry entry : unzipper.entries()) { entries.add(entry.getName()); } unzipper.unzip(); assertEquals(Sets.newHashSet( "atlassian-plugin.xml", "foo.js", "bar/", "bar/baz.js", "modules/", "modules/test.js" ), entries); File fooFile = new File(unzippedPluginDir, "foo.js"); assertEquals("alert(\"hi\");", FileUtils.readFileToString(fooFile).trim()); page.uninstallPlugin("download.jar-file"); } @Test public void testEnableTestPlugin() throws IOException { SpeakeasyUserPage page = product.getPageBinder().bind(SpeakeasyUserPage.class); assertEquals(0, page.getPlugins().get("plugin-tests").getUsers()); PluginTestActivated activated = product.getPageBinder().bind(PluginTestActivated.class); assertFalse(activated.isBannerVisible()); assertTrue(activated.isChangesLinkVisible()); assertFalse(activated.isGoogleLinkVisible()); page.enablePlugin("plugin-tests"); assertEquals(1, page.getPlugins().get("plugin-tests").getUsers()); page = product.visit(SpeakeasyUserPage.class); assertEquals(1, page.getPlugins().get("plugin-tests").getUsers()); activated.waitForBanner(); assertTrue(activated.isBannerVisible()); assertFalse(activated.isChangesLinkVisible()); assertTrue(activated.isGoogleLinkVisible()); page.disablePlugin("plugin-tests"); assertEquals(0, page.getPlugins().get("plugin-tests").getUsers()); product.visit(SpeakeasyUserPage.class); assertEquals(0, page.getPlugins().get("plugin-tests").getUsers()); activated = product.getPageBinder().bind(PluginTestActivated.class); assertFalse(activated.isBannerVisible()); assertTrue(activated.isChangesLinkVisible()); assertFalse(activated.isGoogleLinkVisible()); } @Test public void testEmailAuthorOnEnable() throws IOException, MessagingException { File jar = buildSimplePluginFile(); product.getPageBinder().bind(SpeakeasyUserPage.class) .openInstallDialog() .uploadPlugin(jar); logout(); SpeakeasyUserPage page = product.visit(LoginPage.class) .login("barney", "barney", SpeakeasyUserPage.class) .enablePlugin("test2"); assertEmailExists(mailServer, "admin@example.com", "Barney User has enabled ", asList("you may want to try", "Test Plugin")); page.disablePlugin("test2"); logout(); product.visit(LoginPage.class) .loginAsSysAdmin(SpeakeasyUserPage.class) .enablePlugin("test2"); logout(); page = product.visit(LoginPage.class) .login("barney", "barney", SpeakeasyUserPage.class) .enablePlugin("test2"); assertEmailExists(mailServer, "admin@example.com", "Barney User has enabled your Speakeasy extension!", asList("extensions in common", "Test Plugin")); page.disablePlugin("test2"); logout(); product.visit(LoginPage.class) .loginAsSysAdmin(SpeakeasyUserPage.class) .uninstallPlugin("test2"); } @Test public void testFavoritePlugin() throws IOException, MessagingException { File jar = buildSimplePluginFile("test", "First Plugin"); SpeakeasyUserPage page = product.getPageBinder().bind(SpeakeasyUserPage.class) .openInstallDialog() .uploadPlugin(jar) .openInstallDialog() .uploadPlugin(buildSimplePluginFile("not-fav", "Not favourited")); assertFalse(page.isFavorite("test")); assertEquals(0, page.getPlugins().get("test").getFavorites()); logout(); page = product.visit(LoginPage.class) .login("barney", "barney", SpeakeasyUserPage.class) .favorite("plugin-tests") .favorite("test"); List<String> messages = page.getSuccessMessages(); assertEquals(1, messages.size()); assertTrue(messages.get(0).contains("was marked as")); assertEquals(1, page.getPlugins().get("test").getFavorites()); String body = assertEmailExists(mailServer, "admin@example.com", "Barney User has marked", asList("you may want to try", "plugin-tests")); assertTrue(!body.contains("Not favourited")); page.unfavorite("plugin-tests"); logout(); product.visit(LoginPage.class) .loginAsSysAdmin(SpeakeasyUserPage.class) .uninstallPlugin("test") .uninstallPlugin("not-fav"); } @Test public void testForkPlugin() throws IOException, MessagingException { File jar = buildSimplePluginFile("test", "First Plugin"); File jar2 = buildSimplePluginFile("test2", "Second Plugin"); product.getPageBinder().bind(SpeakeasyUserPage.class) .openInstallDialog() .uploadPlugin(jar) .openInstallDialog() .uploadPlugin(jar2); logout(); SpeakeasyUserPage page = product.visit(LoginPage.class) .login("barney", "barney", SpeakeasyUserPage.class) .openForkDialog("test") .setDescription("Fork Description") .fork() .enablePlugin("test2") .openForkDialog("test2") .setDescription("Fork\' \"Description\"") .fork(); List<String> messages = page.getSuccessMessages(); assertEquals(1, messages.size()); assertTrue(messages.get(0).contains("was forked successfully")); assertTrue(page.getPluginKeys().contains("test2-fork-barney")); assertEmailExists(mailServer, "admin@example.com", "Barney User has forked your Speakeasy extension!", asList( "'Second Plugin'", "First Plugin by A. D. Ministrator (Sysadmin)")); assertFalse(page.canExecute("test", ExtensionOperations.FORK)); assertFalse(page.canExecute("test2", ExtensionOperations.FORK)); SpeakeasyUserPage.PluginRow row = page.getPlugins().get("test2-fork-barney"); assertEquals("test2-fork-barney", row.getKey()); assertEquals("Fork\' \"Description\"", row.getDescription()); assertFalse(page.isPluginEnabled("test2")); assertTrue(page.isPluginEnabled("test2-fork-barney")); assertTrue(page.canExecute("test2-fork-barney", ExtensionOperations.UNINSTALL)); assertTrue(!page.canExecute("test2-fork-barney", ExtensionOperations.FORK)); assertTrue(page.canExecute("test2-fork-barney", ExtensionOperations.DOWNLOAD)); assertTrue(page.canExecute("test2-fork-barney", ExtensionOperations.EDIT)); assertTrue(!page.canExecute("test2", ExtensionOperations.UNINSTALL)); page.enablePlugin("test2"); assertFalse(page.isPluginEnabled("test2-fork-barney")); page.enablePlugin("test2-fork-barney"); assertFalse(page.isPluginEnabled("test2")); // verify on reload page = product.visit(SpeakeasyUserPage.class); assertTrue(page.getPluginKeys().contains("test2-fork-barney")); row = page.getPlugins().get("test2-fork-barney"); assertEquals("test2-fork-barney", row.getKey()); assertEquals("Fork\' \"Description\"", row.getDescription()); page.uninstallPlugin("test2-fork-barney"); assertTrue(page.isPluginEnabled("test2")); assertTrue(product.visit(SpeakeasyUserPage.class).isPluginEnabled("test2")); page.uninstallPlugin("test-fork-barney"); logout(); product.visit(LoginPage.class) .loginAsSysAdmin(SpeakeasyUserPage.class) .uninstallPlugin("test2") .uninstallPlugin("test"); } @Test public void testForkZipPlugin() throws IOException, MessagingException { product.getPageBinder().bind(SpeakeasyUserPage.class) .openInstallDialog() .openCreateExtensionDialog() .key("tofork-zip") .description("Description") .name("Fork Zip") .create(); logout(); SpeakeasyUserPage page = product.visit(LoginPage.class) .login("barney", "barney", SpeakeasyUserPage.class) .openForkDialog("tofork-zip") .setDescription("Fork Description") .fork(); List<String> messages = page.getSuccessMessages(); assertEquals(1, messages.size()); assertTrue(messages.get(0).contains("was forked successfully")); assertTrue(page.getPluginKeys().contains("tofork-zip-fork-barney")); page.uninstallPlugin("tofork-zip-fork-barney"); logout(); product.visit(LoginPage.class) .loginAsSysAdmin(SpeakeasyUserPage.class) .uninstallPlugin("tofork-zip"); } @Test public void testCustomInstallLink() throws IOException { product.getPageBinder().bind(SpeakeasyUserPage.class) .enablePlugin("plugin-tests"); SpeakeasyUserPage page = product.visit(SpeakeasyUserPage.class) .openInstallDialog() .clickCustomLink(); assertTrue(!page.getSuccessMessages().isEmpty()); page.disablePlugin("plugin-tests"); } @Test public void testUnsubscribeFromAllPlugins() throws IOException { File jar = buildSimplePluginFile(); SpeakeasyUserPage page = product.getPageBinder().bind(SpeakeasyUserPage.class) .openInstallDialog() .uploadPlugin(jar) .enablePlugin("test2") .enablePlugin("plugin-tests"); assertTrue(page.isPluginEnabled("test2")); assertTrue(page.isPluginEnabled("plugin-tests")); page = page.unsubscribeFromAllPlugins(); assertFalse(page.isPluginEnabled("test2")); assertFalse(page.isPluginEnabled("plugin-tests")); page = page.restoreEnabledPlugins(); assertTrue(page.isPluginEnabled("test2")); assertTrue(page.isPluginEnabled("plugin-tests")); page.uninstallPlugin("test2") .disablePlugin("plugin-tests"); } @Test public void testCannotInstallOtherUsersPlugin() throws IOException { File jar = new PluginJarBuilder() .addFormattedResource("atlassian-plugin.xml", "<atlassian-plugin key='plugin-tests' pluginsVersion='2' name='Plugin Tests'>", " <plugin-info>", " <version>2</version>", " </plugin-info>", " <scoped-web-item key='item' section='foo' />", "</atlassian-plugin>") .build(); SpeakeasyUserPage page = product.getPageBinder().bind(SpeakeasyUserPage.class) .openInstallDialog() .uploadPluginExpectingFailure(jar); List<String> messages = page.getErrorMessages(); assertEquals(1, messages.size()); assertTrue(messages.get(0).contains("'plugin-tests'")); SpeakeasyUserPage.PluginRow row = page.getPlugins().get("plugin-tests"); assertEquals("1", row.getVersion()); assertEquals("Some Guy", row.getAuthor()); } @Test public void testInstallPluginMissingModules() throws IOException { File jar = new PluginJarBuilder("Missing-Module") .addFormattedResource("atlassian-plugin.xml", "<atlassian-plugin key='unresolved-test' pluginsVersion='2' name='Missing Module Test'>", " <plugin-info>", " <version>2</version>", " </plugin-info>", " <scoped-modules key='item' />", " <scoped-web-resource key='another-item' />", "</atlassian-plugin>") .addFormattedResource("modules/foo.js", "require('speakeasy/user/user');") .build(); SpeakeasyUserPage page = product.getPageBinder().bind(SpeakeasyUserPage.class) .openInstallDialog() .uploadPluginExpectingFailure(jar); List<String> messages = page.getErrorMessages(); assertEquals(1, messages.size()); assertTrue(messages.get(0).contains("speakeasy/user/user")); SpeakeasyUserPage.PluginRow row = page.getPlugins().get("unresolved-test"); assertTrue(row.getDescription().contains("speakeasy/user/user")); page.uninstallPlugin("unresolved-test"); } @Test public void testUninstallPlugin() throws IOException { File jar = buildSimplePluginFile(); product.getPageBinder().bind(SpeakeasyUserPage.class) .openInstallDialog() .uploadPlugin(jar); SpeakeasyUserPage page = product.visit(SpeakeasyUserPage.class); assertTrue(page.getPluginKeys().contains("test2")); assertTrue(page.canExecute("test2", ExtensionOperations.UNINSTALL)); page.uninstallPlugin("test2"); List<String> messages = page.getSuccessMessages(); assertEquals(1, messages.size()); assertTrue(messages.get(0).contains("uninstalled")); assertFalse(page.getPluginKeys().contains("test2")); // verify on reload page = product.visit(SpeakeasyUserPage.class); assertFalse(page.getPluginKeys().contains("test2")); } @Test public void testActionsIfNotAuthorAndNotPureSpeakeasy() throws IOException { SpeakeasyUserPage page = product.getPageBinder().bind(SpeakeasyUserPage.class); assertTrue(page.getPluginKeys().contains("plugin-tests")); assertFalse(page.canExecute("plugin-tests", ExtensionOperations.UNINSTALL)); assertFalse(page.canExecute("plugin-tests", ExtensionOperations.DOWNLOAD)); assertFalse(page.canExecute("plugin-tests", ExtensionOperations.FORK)); } private Set<String> getZipEntries(File artifact) throws IOException { Set<String> entries = newHashSet(); ZipFile file = new ZipFile(artifact); for (Enumeration<? extends ZipEntry> e = file.entries(); e.hasMoreElements(); ) { entries.add(e.nextElement().getName()); } file.close(); return entries; } }