Java tutorial
package com.atlassian.jira.functest.framework; import com.atlassian.jira.functest.framework.admin.AdminTabs; import com.atlassian.jira.functest.framework.admin.AdminTabsImpl; import com.atlassian.jira.functest.framework.admin.AdvancedApplicationProperties; import com.atlassian.jira.functest.framework.admin.AdvancedApplicationPropertiesImpl; import com.atlassian.jira.functest.framework.admin.Attachments; import com.atlassian.jira.functest.framework.admin.AttachmentsImpl; import com.atlassian.jira.functest.framework.admin.CustomFields; import com.atlassian.jira.functest.framework.admin.CustomFieldsImpl; import com.atlassian.jira.functest.framework.admin.DefaultMailServerAdministration; import com.atlassian.jira.functest.framework.admin.FieldConfigurationSchemes; import com.atlassian.jira.functest.framework.admin.FieldConfigurationSchemesImpl; import com.atlassian.jira.functest.framework.admin.FieldConfigurations; import com.atlassian.jira.functest.framework.admin.FieldConfigurationsImpl; import com.atlassian.jira.functest.framework.admin.GeneralConfiguration; import com.atlassian.jira.functest.framework.admin.GeneralConfigurationImpl; import com.atlassian.jira.functest.framework.admin.IssueLinking; import com.atlassian.jira.functest.framework.admin.IssueLinkingImpl; import com.atlassian.jira.functest.framework.admin.IssueSecuritySchemes; import com.atlassian.jira.functest.framework.admin.IssueSecuritySchemesImpl; import com.atlassian.jira.functest.framework.admin.MailServerAdministration; import com.atlassian.jira.functest.framework.admin.NotificationSchemes; import com.atlassian.jira.functest.framework.admin.NotificationSchemesImpl; import com.atlassian.jira.functest.framework.admin.PermissionSchemes; import com.atlassian.jira.functest.framework.admin.PermissionSchemesImpl; import com.atlassian.jira.functest.framework.admin.Project; import com.atlassian.jira.functest.framework.admin.ProjectImpl; import com.atlassian.jira.functest.framework.admin.ProjectImport; import com.atlassian.jira.functest.framework.admin.ProjectImportImpl; import com.atlassian.jira.functest.framework.admin.Resolutions; import com.atlassian.jira.functest.framework.admin.ResolutionsImpl; import com.atlassian.jira.functest.framework.admin.Roles; import com.atlassian.jira.functest.framework.admin.RolesImpl; import com.atlassian.jira.functest.framework.admin.SendBulkMail; import com.atlassian.jira.functest.framework.admin.Subtasks; import com.atlassian.jira.functest.framework.admin.SubtasksImpl; import com.atlassian.jira.functest.framework.admin.TimeTracking; import com.atlassian.jira.functest.framework.admin.TimeTrackingImpl; import com.atlassian.jira.functest.framework.admin.UsersAndGroups; import com.atlassian.jira.functest.framework.admin.UsersAndGroupsImpl; import com.atlassian.jira.functest.framework.admin.ViewFieldScreens; import com.atlassian.jira.functest.framework.admin.ViewFieldScreensImpl; import com.atlassian.jira.functest.framework.admin.ViewServices; import com.atlassian.jira.functest.framework.admin.ViewWorkflows; import com.atlassian.jira.functest.framework.admin.ViewWorkflowsImpl; import com.atlassian.jira.functest.framework.admin.plugins.Plugins; import com.atlassian.jira.functest.framework.admin.plugins.PluginsImpl; import com.atlassian.jira.functest.framework.admin.user.shared.DefaultSharedDashboardsAdministration; import com.atlassian.jira.functest.framework.admin.user.shared.DefaultSharedFiltersAdministration; import com.atlassian.jira.functest.framework.admin.user.shared.SharedDashboardsAdministration; import com.atlassian.jira.functest.framework.admin.user.shared.SharedFiltersAdministration; import com.atlassian.jira.functest.framework.assertions.Assertions; import com.atlassian.jira.functest.framework.assertions.TextAssertions; import com.atlassian.jira.functest.framework.backdoor.Backdoor; import com.atlassian.jira.functest.framework.dump.TestInformationKit; import com.atlassian.jira.functest.framework.locator.IdLocator; import com.atlassian.jira.functest.framework.locator.XPathLocator; import com.atlassian.jira.functest.framework.util.AsynchronousTasks; import com.atlassian.jira.permission.GlobalPermissionKey; import com.atlassian.jira.testkit.client.dump.FuncTestTimer; import com.atlassian.jira.testkit.client.log.FuncTestLogger; import com.atlassian.jira.testkit.client.xmlbackup.XmlBackupCopier; import com.atlassian.jira.webtests.LicenseKeys; import com.atlassian.jira.webtests.util.JIRAEnvironmentData; import com.google.common.base.Preconditions; import com.meterware.httpunit.WebForm; import com.meterware.httpunit.WebRequestSource; import com.meterware.httpunit.WebTable; import com.sun.jersey.api.client.UniformInterfaceException; import junit.framework.Assert; import net.sourceforge.jwebunit.WebTester; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.xml.sax.SAXException; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import static com.atlassian.jira.functest.matcher.BuildNumberMatcher.hasBuildNumber; import static com.atlassian.jira.webtests.LicenseKeys.V2_COMMERCIAL; import static java.lang.String.valueOf; import static junit.framework.Assert.fail; import static org.junit.Assert.assertThat; /** * Implementation of {@link com.atlassian.jira.functest.framework.Administration} * * @since v3.13 */ public class AdministrationImpl extends AbstractFuncTestUtil implements Administration, FuncTestLogger { /** * The name of the import directory. */ private static final String IMPORT_DIR = "import"; private static final Pattern PATTERN_BUILD_NUMBER = Pattern.compile("#(\\d+)"); private final XmlBackupCopier xmlBackupCopier; private final Navigation navigation; private AsynchronousTasks asynchronousTasks; private final TextAssertions text; private final GeneralConfiguration generalConfiguration; private final Project project; private final UsersAndGroups usersAndGroups; private final Roles roles; private final CustomFields customFields; private final PermissionSchemes permissionSchemes; private final IssueSecuritySchemes issueSecuritySchemes; private final FieldConfigurations fieldConfigurations; private final FieldConfigurationSchemes fieldConfigurationSchemes; private final ResolutionsImpl resolutions; private final ViewServices viewServices; private final ProjectImport projectImport; private final Attachments attachments; private final Plugins plugins; private final ViewFieldScreensImpl viewFieldScreens; private final ViewWorkflows workflows; private final MailServerAdministration mailServerAdministration; private final SharedFiltersAdministration sharedFiltersAdministration; private final SharedDashboardsAdministration sharedDashboardsAdministration; private final NotificationSchemes notificationSchemes; private final SendBulkMail sendBulkMail; private final AdminTabs adminTabs; private final AdvancedApplicationProperties advancedApplicationProperties; private final Backdoor backdoor; private static Set<String> copiedFiles = Collections.synchronizedSet(new HashSet<String>()); /** * Evil but necessary static field used for caching the JIRA_HOME during func test runs. */ private static final ThreadLocal<String> JIRA_HOME_DIR = new ThreadLocal<String>(); private static boolean backdoorIsPresent = true; private boolean safeMode = false; /** * Note: if you need to construct this for an old-style {@link com.atlassian.jira.webtests.JIRAWebTest}, you may * want to consider using {@link com.atlassian.jira.functest.framework.FuncTestHelperFactory} instead. * * @param tester the tester * @param environmentData the environment data * @param navigation the navigation * @param assertions the assertions * @see FuncTestHelperFactory#getAdministration() */ public AdministrationImpl(final WebTester tester, final JIRAEnvironmentData environmentData, final Navigation navigation, final Assertions assertions) { super(tester, environmentData, 2); this.backdoor = new Backdoor(environmentData); this.xmlBackupCopier = new XmlBackupCopier(environmentData.getBaseUrl()); this.navigation = navigation; this.asynchronousTasks = new AsynchronousTasks(tester, environmentData, childLogIndentLevel()); this.text = assertions.getTextAssertions(); this.generalConfiguration = new GeneralConfigurationImpl(tester, environmentData); this.project = new ProjectImpl(backdoor, tester, environmentData, navigation, assertions, asynchronousTasks); this.usersAndGroups = new UsersAndGroupsImpl(tester, navigation, assertions.getTextAssertions(), locators); this.roles = new RolesImpl(tester, environmentData, 3); this.customFields = new CustomFieldsImpl(tester, environmentData, navigation, getFuncTestHelperFactory().getForm()); this.permissionSchemes = new PermissionSchemesImpl(tester, environmentData); this.issueSecuritySchemes = new IssueSecuritySchemesImpl(tester, environmentData); this.fieldConfigurations = new FieldConfigurationsImpl(tester, environmentData); this.fieldConfigurationSchemes = new FieldConfigurationSchemesImpl(tester, environmentData); this.resolutions = new ResolutionsImpl(tester, environmentData); this.viewServices = new ViewServices(tester, navigation); this.projectImport = new ProjectImportImpl(tester, environmentData, navigation, this); this.attachments = new AttachmentsImpl(tester, environmentData, navigation); this.viewFieldScreens = new ViewFieldScreensImpl(tester, environmentData, navigation); this.workflows = new ViewWorkflowsImpl(tester, environmentData, childLogIndentLevel(), navigation); this.plugins = new PluginsImpl(tester, environmentData, logIndentLevel, navigation, this, locators); this.mailServerAdministration = new DefaultMailServerAdministration(tester, navigation, locators); this.sharedFiltersAdministration = new DefaultSharedFiltersAdministration(tester, navigation, locators); this.sharedDashboardsAdministration = new DefaultSharedDashboardsAdministration(tester, navigation, locators); this.sendBulkMail = new DefaultSendBulkMail(navigation); this.notificationSchemes = new NotificationSchemesImpl(tester, environmentData, childLogIndentLevel()); this.adminTabs = new AdminTabsImpl(tester, environmentData); this.advancedApplicationProperties = new AdvancedApplicationPropertiesImpl(tester, environmentData); } public void reIndex() { tester.gotoPage("secure/admin/jira/IndexAdmin.jspa"); tester.submit("reindex"); waitForIndexCompletion(1000, 100); } public void setProfiling(final boolean on) { } /** * Restores the jira instance to one with no issues. Some projects have been created */ public void restoreBlankInstance() { restoreBlankInstanceWithLicense(V2_COMMERCIAL); } public void restoreBlankInstanceWithLicense(LicenseKeys.License license) { restoreDataWithLicense("blankprojects.xml", license.getLicenseString()); } public void restoreNotSetupInstance() { final File file = new File(environmentData.getXMLDataLocation(), "TestEmpty.xml"); copyFileToJiraImportDirectory(file); tester.gotoPage(getRestoreUrl()); tester.setWorkingForm("restore-xml-data-backup"); tester.setFormElement("license", V2_COMMERCIAL.getLicenseString()); tester.setFormElement("filename", file.getName()); tester.checkCheckbox("quickImport", "true"); tester.submit(); waitForRestore(); //should go straight to the Setup screen after the import! tester.assertTextPresent("JIRA Setup"); } private void copyFileToJiraImportDirectory(File file) { String filename = file.getName(); if (!copiedFiles.contains(filename)) { File jiraImportDirectory = new File(getJiraHomeDirectory(), IMPORT_DIR); try { FileUtils.copyFileToDirectory(file, jiraImportDirectory); copiedFiles.add(filename); } catch (IOException e) { throw new RuntimeException("Could not copy file " + file.getAbsolutePath() + " to the import directory in jira home " + jiraImportDirectory, e); } } } public File replaceTokensInFile(final String originalXmlFileName, final Map<String, String> replacements) throws IOException { final String resource = environmentData.getXMLDataLocation().getAbsolutePath() + "/" + originalXmlFileName; String xml = IOUtils.toString(new FileReader(resource)); xml = replaceTokens(xml, replacements); // write new data to temp file File newData = File.createTempFile(originalXmlFileName, ".xml"); final FileWriter of = new FileWriter(newData); of.write(xml); of.close(); return newData; } /** * Turn on safe mode - ignores dangermode. */ @Override public void setSafeMode(final boolean safeModeIsOn) { this.safeMode = safeModeIsOn; } public void restoreDataWithReplacedTokens(final String originalXmlFileName, final Map<String, String> replacements) throws IOException { restoreDataWithReplacedTokens(originalXmlFileName, replacements, false); } @Override public void restoreDataWithReplacedTokens(String originalXmlFileName, Map<String, String> replacements, boolean useDefaultPaths) throws IOException { final String resource = environmentData.getXMLDataLocation().getAbsolutePath() + "/" + originalXmlFileName; String xml = IOUtils.toString(new FileReader(resource)); xml = replaceTokens(xml, replacements); File newData = null; try { newData = replaceTokensInFile(originalXmlFileName, replacements); restoreData(newData.getParent(), newData.getName(), useDefaultPaths); } finally { if (newData.exists()) { assert newData.delete(); } } } public void restoreData(final String fileName) { if (backdoorIsPresent) { try { backdoor.restoreData(fileName); // Retain parity with restoreData behaviour navigation.login(FunctTestConstants.ADMIN_USERNAME, FunctTestConstants.ADMIN_PASSWORD); } catch (UniformInterfaceException uie) { log("Backdoor was not present"); log(uie); backdoorIsPresent = false; restoreData(fileName, false); } } else { restoreData(fileName, false); } } @Override public void restoreData(String fileName, boolean useDefaultPaths) { restoreData(environmentData.getXMLDataLocation().getAbsolutePath(), fileName, useDefaultPaths); } @Override public void restoreData(final String fileName, final OutgoingMailSettings outgoingMailSetting) { restoreData(environmentData.getXMLDataLocation().getAbsolutePath(), fileName, true, FunctTestConstants.ADMIN_USERNAME, FunctTestConstants.ADMIN_PASSWORD, false, V2_COMMERCIAL.getLicenseString(), outgoingMailSetting); } @Override public Link link() { return new DefaultLink(tester); } @Override public void restoreDataAndLogin(final String fileName, final String username) { restoreDataAndLogin(fileName, username, false); } @Override public void restoreDataAndLogin(final String fileName, final String username, boolean useDefaultPaths) { restoreData(environmentData.getXMLDataLocation().getAbsolutePath(), fileName, true, username, username, useDefaultPaths); } @Override public void restoreDataSlowOldWayAndLogin(String fileName, String username) { restoreDataSlowOldWayAndLogin(fileName, username, false); } @Override public void restoreDataSlowOldWayAndLogin(String fileName, String username, boolean useDefaultPath) { restoreData(environmentData.getXMLDataLocation().getAbsolutePath(), fileName, false, FunctTestConstants.ADMIN_USERNAME, FunctTestConstants.ADMIN_PASSWORD, useDefaultPath); } public void restoreDataSlowOldWay(final String fileName) { restoreDataSlowOldWay(fileName, false); } @Override public void restoreDataSlowOldWay(String fileName, boolean useDefaultPaths) { restoreDataSlowOldWay(environmentData.getXMLDataLocation().getAbsolutePath(), fileName, useDefaultPaths); } @Override public void restoreDataWithPluginsReload(String fileName) { restoreDataWithPluginsReload(fileName, false); } @Override public void restoreDataWithPluginsReload(String fileName, boolean useDefaultPaths) { restoreDataSlowOldWay(environmentData.getXMLDataLocation().getAbsolutePath(), fileName, useDefaultPaths); } public void restoreData(final String path, final String fileName) { restoreData(path, fileName, false); } public void restoreData(final String path, final String fileName, boolean useDefaultPath) { restoreData(path, fileName, true, FunctTestConstants.ADMIN_USERNAME, FunctTestConstants.ADMIN_PASSWORD, useDefaultPath); } public void restoreDataSlowOldWay(final String path, final String fileName) { restoreDataSlowOldWay(path, fileName, false); } public void restoreDataSlowOldWay(final String path, final String fileName, boolean useDefaultPath) { restoreData(path, fileName, false, FunctTestConstants.ADMIN_USERNAME, FunctTestConstants.ADMIN_PASSWORD, useDefaultPath); } private void restoreData(final String path, final String fileName, final boolean clearCache, final String username, final String password, final boolean useDefaultPaths) { restoreData(path, fileName, clearCache, username, password, useDefaultPaths, V2_COMMERCIAL.getLicenseString()); } @Override public void restoreDataWithLicense(String fileName, String licenseKey, boolean useDefaultPaths) { restoreData(environmentData.getXMLDataLocation().getAbsolutePath(), fileName, true, FunctTestConstants.ADMIN_USERNAME, FunctTestConstants.ADMIN_PASSWORD, useDefaultPaths, licenseKey); } public void restoreDataWithLicense(final String fileName, final String licenseKey) { restoreDataWithLicense(fileName, licenseKey, false); } private void restoreData(final String path, final String fileName, final boolean clearCache, final String username, final String password, final boolean useDefaultPaths, final String licenseString) { navigation.gotoAdminSection("system_info"); final FuncTestTimer timer = TestInformationKit.pullTimer("XML Restore"); final String sourcePath = path + FS + fileName; final String jiraImportDir = getJiraHomeDirectory() + FS + IMPORT_DIR + FS + new File(fileName).getName(); boolean baseUrlReplaced = xmlBackupCopier.copyXmlBackupTo(sourcePath, jiraImportDir); log("Restoring data '" + jiraImportDir + "'"); tester.gotoPage(getRestoreUrl()); tester.setWorkingForm("restore-xml-data-backup"); tester.setFormElement("filename", fileName); tester.setFormElement("license", licenseString); if (useDefaultPaths) { reflectivelySetDefaultPaths(tester.getDialog().getForm()); } if (clearCache) { tester.checkCheckbox("quickImport", "true"); } tester.submit(); waitForRestore(); if (!isRestoreSuccessful()) { //The following are assertions of possible error messages to display the cause of failure to import //instead of having to check HTML dump manually. Please add/modify new error messages not included already. assertCauseOfError( "The xml data you are trying to import seems to be from a newer version of JIRA. This will not work.", jiraImportDir); assertCauseOfError("You must enter the location of an XML file.", jiraImportDir); assertCauseOfError("Could not find file at this location.", jiraImportDir); assertCauseOfError("Invalid license key specified.", jiraImportDir); assertCauseOfError("The current license is too old to install this version of JIRA", jiraImportDir); assertCauseOfError("Invalid license type for this version of JIRA. License should be of type Standard.", jiraImportDir); assertCauseOfError( "Invalid license type for this version of JIRA. License should be of type Professional.", jiraImportDir); assertCauseOfError( "Invalid license type for this version of JIRA. License should be of type Enterprise.", jiraImportDir); assertCauseOfError("You must specify an index for the restore process.", jiraImportDir); assertCauseOfError("Error parsing export file. Your export file is invalid.", jiraImportDir); assertCauseOfError("specified in the backup file is not valid", jiraImportDir); throw new AssertionError( "Failed to restore JIRA data from [" + jiraImportDir + "]. See logs for details."); } navigation.disableWebSudo(); navigation.login(username, password); final long howLong = timer.end(); log("Restored '" + fileName + "' in " + (howLong) + "ms"); if (!baseUrlReplaced) { generalConfiguration.setBaseUrl(getEnvironmentData().getBaseUrl().toString()); } tester.beginAt("/"); } private String getRestoreUrl() { final String safeModeParam = safeMode ? "?safemode=true" : ""; return "secure/admin/XmlRestore!default.jspa" + safeModeParam; } private void restoreData(final String path, final String fileName, final boolean clearCache, final String username, final String password, final boolean useDefaultPaths, final String licenseString, final OutgoingMailSettings outgoingMailSetting) { navigation.gotoAdminSection("system_info"); final FuncTestTimer timer = TestInformationKit.pullTimer("XML Restore"); final String sourcePath = path + FS + fileName; final String jiraImportDir = getJiraHomeDirectory() + FS + IMPORT_DIR + FS + new File(fileName).getName(); boolean baseUrlReplaced = xmlBackupCopier.copyXmlBackupTo(sourcePath, jiraImportDir); log("Restoring data '" + jiraImportDir + "'"); tester.gotoPage(getRestoreUrl()); tester.setWorkingForm("restore-xml-data-backup"); tester.setFormElement("filename", fileName); tester.setFormElement("license", licenseString); tester.setFormElement("outgoingEmail", outgoingMailSetting.asString()); if (useDefaultPaths) { reflectivelySetDefaultPaths(tester.getDialog().getForm()); } if (clearCache) { tester.checkCheckbox("quickImport", "true"); } tester.submit(); waitForRestore(); if (!isRestoreSuccessful()) { //The following are assertions of possible error messages to display the cause of failure to import //instead of having to check HTML dump manually. Please add/modify new error messages not included already. assertCauseOfError( "The xml data you are trying to import seems to be from a newer version of JIRA. This will not work.", jiraImportDir); assertCauseOfError("You must enter the location of an XML file.", jiraImportDir); assertCauseOfError("Could not find file at this location.", jiraImportDir); assertCauseOfError("Invalid license key specified.", jiraImportDir); assertCauseOfError("The current license is too old to install this version of JIRA", jiraImportDir); assertCauseOfError("Invalid license type for this version of JIRA. License should be of type Standard.", jiraImportDir); assertCauseOfError( "Invalid license type for this version of JIRA. License should be of type Professional.", jiraImportDir); assertCauseOfError( "Invalid license type for this version of JIRA. License should be of type Enterprise.", jiraImportDir); assertCauseOfError("You must specify an index for the restore process.", jiraImportDir); assertCauseOfError("Error parsing export file. Your export file is invalid.", jiraImportDir); assertCauseOfError("specified in the backup file is not valid", jiraImportDir); throw new AssertionError( "Failed to restore JIRA data from [" + jiraImportDir + "]. See logs for details."); } navigation.disableWebSudo(); navigation.login(username, password); final long howLong = timer.end(); log("Restored '" + fileName + "' in " + (howLong) + "ms"); if (!baseUrlReplaced) { generalConfiguration.setBaseUrl(getEnvironmentData().getBaseUrl().toString()); } tester.beginAt("/"); } public void restoreI18nData(final String fileName) { final FuncTestTimer timer = TestInformationKit.pullTimer("XML Restore"); final String filePath = environmentData.getXMLDataLocation().getAbsolutePath() + "/" + fileName; File file = new File(filePath); copyFileToJiraImportDirectory(file); log("Restoring data '" + filePath + "'"); tester.gotoPage(getRestoreUrl()); tester.setWorkingForm("restore-xml-data-backup"); tester.setFormElement("filename", file.getName()); tester.setFormElement("license", V2_COMMERCIAL.getLicenseString()); tester.checkCheckbox("quickImport", "true"); tester.submit(); waitForRestore(); if (!isRestoreSuccessful()) { Assert.fail("Your project failed to import successfully. See logs for details"); } final long howLong = timer.end(); navigation.disableWebSudo(); navigation.login(FunctTestConstants.ADMIN_USERNAME, FunctTestConstants.ADMIN_PASSWORD); log("Restored '" + fileName + "' in " + (howLong) + "ms"); } @Override public void restoreDataWithBuildNumber(String fileName, int expectedBuilderNumber) { // make sure the backup file has not been upgraded File backupFile = new File(getEnvironmentData().getXMLDataLocation(), fileName); FileInputStream backup = null; try { backup = new FileInputStream(backupFile); assertThat(backup, hasBuildNumber(expectedBuilderNumber)); } catch (FileNotFoundException missingXmlBackup) { fail(String.format("The xml backup file: %s could not be found.", fileName)); } finally { if (backup != null) { IOUtils.closeQuietly(backup); } } restoreData(fileName); } private void reflectivelySetDefaultPaths(final WebForm jiraForm) { final Class<WebForm> webFormClass = WebForm.class; final Class<WebRequestSource> webRequestSourceClass = WebRequestSource.class; reflectivlySetField(jiraForm, webFormClass, "_formParameters", null); reflectivlySetField(jiraForm, webFormClass, "_presetParameters", null); final String postUrl = (String) reflectivelyGetField(jiraForm, webRequestSourceClass, "_destination"); //the _destination field exists on the superclass of webForms //TODO: check the action url for other params before appending to it! reflectivlySetField(jiraForm, webRequestSourceClass, "_destination", postUrl + "?useDefaultPaths=true"); final Class[] paramType = { String.class, String.class }; final String[] params = { "useDefaultPaths", "true" }; reflectivelyInvoke(jiraForm, webFormClass, "addPresetParameter", paramType, params); tester.setFormElement("useDefaultPaths", "true"); } private void reflectivelyInvoke(final Object self, final Class<?> clazz, final String methodName, final Class[] paramType, final Object[] params) { Preconditions.checkNotNull(self, "cannot invoke %s on null object", methodName); Method method = null; try { method = clazz.getDeclaredMethod(methodName, paramType); method.setAccessible(true); method.invoke(self, params); } catch (NoSuchMethodException e) { throw new RuntimeException(String.format( "Error getting method '%s(%s)' for %s : possibly a library update has changed this method", methodName, Arrays.toString(paramType), clazz.getName()), e); } catch (InvocationTargetException e) { throw new RuntimeException(String.format( "Error invoking method '%s(%s)' for %s : exception raised during method invocation : %s", e.getCause().getMessage(), methodName, Arrays.toString(paramType), clazz.getName()), e.getCause()); } catch (IllegalAccessException e) { throw new RuntimeException(String.format( "Error invoking method '%s(%s)' for %s : possibly a security manager has prevented access to this method", methodName, Arrays.toString(paramType), clazz.getName()), e); } finally { if (method != null) { method.setAccessible(false); } } } private void reflectivlySetField(final Object self, Class<?> clazz, final String fieldName, final Object fieldValue) { Preconditions.checkNotNull(self, "cannot set field %s to %s on null object", fieldName, fieldValue); Field field = null; try { field = clazz.getDeclaredField(fieldName); field.setAccessible(true); field.set(self, fieldValue); } catch (IllegalAccessException e) { throw new RuntimeException(String.format( "Error setting field '%s' to '%s' for %s : possibly a security manager has prevented access to this field", fieldName, fieldValue, clazz.getName()), e); } catch (NoSuchFieldException e) { throw new RuntimeException(String.format( "Error setting field '%s' to '%s' for %s : possibly a library update has changed this field", fieldName, fieldValue, clazz.getName()), e); } finally { if (field != null) { field.setAccessible(false); } } } private Object reflectivelyGetField(final Object self, final Class<?> clazz, final String fieldName) { Preconditions.checkNotNull(self, "cannot get field %s on null object", fieldName); Field field = null; try { field = clazz.getDeclaredField(fieldName); field.setAccessible(true); return field.get(self); } catch (IllegalAccessException e) { throw new RuntimeException(String.format( "Error getting field '%s' for %s : possibly a security manager has prevented access to this field", fieldName, clazz.getName()), e); } catch (NoSuchFieldException e) { throw new RuntimeException(String.format( "Error getting field '%s' for %s : possibly a library update has changed this field", fieldName, clazz.getName()), e); } finally { if (field != null) { field.setAccessible(false); } } } public File exportDataToFile(final String fileName) { final FuncTestTimer timer = TestInformationKit.pullTimer("XML Export"); final String realFileName = FilenameUtils.getName(fileName); log("Backing up data to '" + realFileName + "'"); tester.gotoPage("secure/admin/XmlBackup!default.jspa"); tester.setWorkingForm("jiraform"); tester.setFormElement("filename", realFileName); tester.submit(); if (new IdLocator(tester, "replace_submit").exists()) { tester.setWorkingForm("jiraform"); tester.submit(); } final String text = StringUtils.stripToNull(new IdLocator(tester, "backup-file").getText()); if (text == null) { Assert.fail("The restore did not redirect to the result page."); } timer.end(); final File file = new File(text); Assert.assertTrue("Backup returned '" + text + "' which is not an absolute file.", file.isAbsolute()); return file; } public String getCurrentAttachmentPath() { navigation.gotoAdmin(); tester.clickLink("attachments"); // Get the table 'attachmentSettings'. final WebTable attachmentSettings = tester.getDialog().getWebTableBySummaryOrId("table-AttachmentSettings"); // Check that 'Attachment Path' is in the third row where we expect it: if (attachmentSettings.getCellAsText(1, 0).contains("Attachment Path")) { String attachmentPath = attachmentSettings.getCellAsText(1, 1).trim(); // Check if this is the "default" directory. Looks like "Default Directory [/home/mlassau/jira/jira_trunk/data/attachments]" if (attachmentPath.startsWith("Default Directory [")) { // Strip "Default Directory [" from the front, and the "]" from the end attachmentPath = attachmentPath.substring("Default Directory [".length(), attachmentPath.length() - 1); } return attachmentPath; } else { throw new RuntimeException( "Error occured when trying to screen-scrape the attachment path. 'Attachment Path' not found where expected in the table."); } } public void activateSubTasks() { log("activating sub tasks"); tester.gotoPage("/secure/admin/subtasks/ManageSubTasks.jspa"); if (tester.getDialog().isLinkPresentWithText("Enable")) { tester.clickLinkWithText("Enable"); } else { log("Subtasks already enabled"); } } public void addSubTaskType(final String name) { activateSubTasks(); tester.setFormElement("name", name); tester.submit("Add"); } public GeneralConfiguration generalConfiguration() { return generalConfiguration; } @Override public Backdoor backdoor() { return backdoor; } public Project project() { return project; } public UsersAndGroups usersAndGroups() { return usersAndGroups; } public Roles roles() { return roles; } public CustomFields customFields() { return customFields; } public PermissionSchemes permissionSchemes() { return permissionSchemes; } public IssueSecuritySchemes issueSecuritySchemes() { return issueSecuritySchemes; } public FieldConfigurations fieldConfigurations() { return fieldConfigurations; } public FieldConfigurationSchemes fieldConfigurationSchemes() { return fieldConfigurationSchemes; } public ProjectImport projectImport() { return projectImport; } public Plugins plugins() { return plugins; } public void removeGlobalPermission(final GlobalPermissionKey permissionKey, final String group) { final String deleteLink = "del_" + permissionKey.getKey() + "_" + group; navigation.gotoAdminSection("global_permissions"); if ((tester.getDialog().isLinkPresent(deleteLink))) { tester.clickLink(deleteLink); tester.submit("Delete"); } } public void removeGlobalPermission(final int permission, final String group) { final GlobalPermissionKey permissionKey = GlobalPermissionKey.GLOBAL_PERMISSION_ID_TRANSLATION .get(permission); removeGlobalPermission(permissionKey, group); } public void addGlobalPermission(final GlobalPermissionKey permission, final String group) { final HtmlPage page = new HtmlPage(tester); final String addUrl = page.addXsrfToken("secure/admin/jira/GlobalPermissions.jspa?groupName=" + group + "&globalPermType=" + permission.getKey() + "&action=add"); tester.gotoPage(addUrl); } public void addGlobalPermission(final int permission, final String group) { final GlobalPermissionKey permissionKey = GlobalPermissionKey.GLOBAL_PERMISSION_ID_TRANSLATION .get(permission); addGlobalPermission(permissionKey, group); } public void switchToLicense(final LicenseKeys.License license) { switchToLicense(license.getLicenseString(), license.getDescription()); } public void switchToLicense(final String license, final String description) { navigation.gotoAdminSection("license_details"); tester.setFormElement("license", license); tester.submit("Add"); text.assertTextPresent(new XPathLocator(tester, "//table[@id='license_table']"), description); } public void switchToPersonalLicense() { switchToLicense(LicenseKeys.V2_PERSONAL.getLicenseString(), "JIRA " + getEdition() + ": Personal"); } public void switchToStarterLicense() { switchToLicense(LicenseKeys.V2_STARTER.getLicenseString(), "JIRA " + getEdition() + ": Starter"); } public String getJiraHomeDirectory() { String jiraHome = JIRA_HOME_DIR.get(); if (jiraHome == null) { String jiraHomePath = null; try { navigation.gotoAdminSection("system_info"); WebTable filePathTable = tester.getDialog().getResponse().getTableWithID("file_paths"); if (filePathTable != null && filePathTable.getTableCellWithID("file_paths_jirahome") != null) { jiraHomePath = filePathTable.getTableCellWithID("file_paths_jirahome").asText().trim(); } if (jiraHomePath == null) { throw new RuntimeException("Can't find JIRA.HOME. Do you have websudo enabled?"); } else { // try to get the canonical path JIRA_HOME_DIR.set(jiraHome = new File(jiraHomePath).getCanonicalPath()); } } catch (Exception e) { throw new RuntimeException(e); } } return jiraHome; } @Override public String getSystemTenantHomeDirectory() { navigation.gotoAdminSection("system_info"); final WebTable filePathTable; try { filePathTable = tester.getDialog().getResponse().getTableWithID("file_paths"); } catch (SAXException e) { throw new RuntimeException(e); } if (filePathTable != null && filePathTable.getTableCellWithID("file_paths_jirahome") != null) { return filePathTable.getTableCellWithID("file_paths_jirahome").asText().trim(); } return null; } @Override public MailServerAdministration mailServers() { return mailServerAdministration; } @Override public SharedFiltersAdministration sharedFilters() { return sharedFiltersAdministration; } @Override public SharedDashboardsAdministration sharedDashboards() { return sharedDashboardsAdministration; } @Override public SendBulkMail sendBulkMail() { return sendBulkMail; } @Override public AdminTabs tabs() { return adminTabs; } @Override public AdvancedApplicationProperties advancedApplicationProperties() { return advancedApplicationProperties; } private void assertCauseOfError(final String errorMessage, final String filePath) { if (tester.getDialog().isTextInResponse(errorMessage)) { throw new AssertionError( "Failed to restore JIRA data. Cause: " + errorMessage + " File path: [" + filePath + "]"); } } public Subtasks subtasks() { return new SubtasksImpl(tester, getEnvironmentData()); } public IssueLinking issueLinking() { return new IssueLinkingImpl(tester, navigation, logger); } public TimeTracking timeTracking() { return new TimeTrackingImpl(tester, getEnvironmentData()); } public Resolutions resolutions() { return resolutions; } public ViewServices services() { return viewServices; } public String getEdition() { return ENTERPRISE; } public long getBuildNumber() { final IdLocator idLocator = new IdLocator(tester, "footer-build-information"); final String buildInfo = idLocator.getText(); if (StringUtils.isBlank(buildInfo)) { throw new RuntimeException("Unable to find build information in the footer."); } final Matcher matcher = PATTERN_BUILD_NUMBER.matcher(buildInfo); if (!matcher.find()) { throw new RuntimeException("Unable to find build number from the footer."); } try { return Long.parseLong(matcher.group(1)); } catch (NumberFormatException e) { throw new RuntimeException("Unable to find builder number from the footer.", e); } } private String replaceTokens(String source, final Map<String, String> replacements) { for (final String token : replacements.keySet()) { final int index = source.indexOf(token); if (index < 0) { Assert.fail("Replacement token '" + token + "' not found"); } source = source.replaceAll(token, Matcher.quoteReplacement(replacements.get(token))); } return source; } public void runJellyScript(final String script) { log("Running jelly script '" + script + "'."); navigation.gotoAdminSection("jelly_runner"); tester.setFormElement("script", script); tester.submit("Run now"); } public void enableAccessLogging() { log("enabling access logging"); navigation.gotoAdminSection("logging_profiling"); tester.clickLink("enable_http_access"); } @Override public Attachments attachments() { return attachments; } @Override public ViewFieldScreens viewFieldScreens() { return viewFieldScreens; } @Override public Utilities utilities() { return new Util(); } @Override public ViewWorkflows workflows() { return workflows; } @Override public NotificationSchemes notificationSchemes() { return notificationSchemes; } public static class DefaultLink implements Link { private final WebTester tester; private DefaultLink(final WebTester tester) { this.tester = tester; } @Override public boolean isPresent() { return tester.getDialog().isLinkPresent("admin_link") || tester.getDialog().isLinkPresent("admin_project_menu"); } } private class Util implements Utilities { public void runServiceNow(final long serviceId) { navigation.gotoPage("ServiceExecutor.jspa"); tester.setFormElement("serviceId", valueOf(serviceId)); tester.submit(); tester.assertTextNotPresent("No service with this id exists"); } } private void waitForIndexCompletion(long sleepTime, int retryCount) { asynchronousTasks.waitForSuccessfulCompletion(sleepTime, retryCount, "Indexing"); } private boolean isRestoreSuccessful() { return isOnRestore() && new XPathLocator(tester, "//a[@id=\"login\"]").exists(); } private boolean isOnRestore() { return tester.getDialog().getResponse().getURL().toExternalForm().contains("ImportResult.jspa"); } public void waitForRestore() { //wait for result page to come up String url = tester.getDialog().getResponse().getURL().toExternalForm(); while (url.contains("importprogress")) { try { Thread.sleep(200); } catch (InterruptedException e) { } final String subUrl = url.substring(getEnvironmentData().getBaseUrl().toString().length()); tester.gotoPage(subUrl); url = tester.getDialog().getResponse().getURL().toExternalForm(); } } }