PageRenderTime 66ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 1ms

/amps-maven-plugin/src/test/java/com/atlassian/maven/plugins/amps/product/TestJiraProductHandler.java

https://bitbucket.org/atlassian/amps
Java | 488 lines | 377 code | 85 blank | 26 comment | 10 complexity | 5ba739af739c67e5401651f09e1aeb68 MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause
  1. package com.atlassian.maven.plugins.amps.product;
  2. import com.atlassian.maven.plugins.amps.MavenContext;
  3. import com.atlassian.maven.plugins.amps.MavenGoals;
  4. import com.atlassian.maven.plugins.amps.Node;
  5. import com.atlassian.maven.plugins.amps.Product;
  6. import com.atlassian.maven.plugins.amps.XmlOverride;
  7. import com.atlassian.maven.plugins.amps.database.DatabaseType;
  8. import com.atlassian.maven.plugins.amps.database.MssqlJtds;
  9. import com.atlassian.maven.plugins.amps.database.MssqlMicrosoft;
  10. import com.atlassian.maven.plugins.amps.database.MySQL;
  11. import com.atlassian.maven.plugins.amps.database.Oracle10g;
  12. import com.atlassian.maven.plugins.amps.database.Oracle12c;
  13. import com.atlassian.maven.plugins.amps.database.Postgres;
  14. import com.atlassian.maven.plugins.amps.product.manager.WebAppManager;
  15. import com.atlassian.maven.plugins.amps.util.ConfigFileUtils.Replacement;
  16. import org.apache.commons.io.FileUtils;
  17. import org.apache.maven.artifact.resolver.ArtifactResolver;
  18. import org.apache.maven.model.Build;
  19. import org.apache.maven.plugin.logging.Log;
  20. import org.apache.maven.project.MavenProject;
  21. import org.apache.maven.repository.RepositorySystem;
  22. import org.dom4j.io.SAXReader;
  23. import org.junit.After;
  24. import org.junit.Before;
  25. import org.junit.Rule;
  26. import org.junit.Test;
  27. import org.junit.rules.MethodRule;
  28. import org.junit.rules.TemporaryFolder;
  29. import org.mockito.ArgumentCaptor;
  30. import org.mockito.Captor;
  31. import org.mockito.Mock;
  32. import org.mockito.junit.MockitoJUnit;
  33. import org.w3c.dom.Document;
  34. import javax.xml.parsers.DocumentBuilderFactory;
  35. import javax.xml.xpath.XPathExpression;
  36. import javax.xml.xpath.XPathFactory;
  37. import java.io.File;
  38. import java.io.IOException;
  39. import java.nio.charset.StandardCharsets;
  40. import java.util.Collection;
  41. import java.util.Iterator;
  42. import java.util.List;
  43. import java.util.Map;
  44. import java.util.Optional;
  45. import static com.atlassian.maven.plugins.amps.product.JiraProductHandler.BUNDLED_PLUGINS_FROM_4_1;
  46. import static com.atlassian.maven.plugins.amps.product.JiraProductHandler.BUNDLED_PLUGINS_UNZIPPED;
  47. import static com.atlassian.maven.plugins.amps.product.JiraProductHandler.BUNDLED_PLUGINS_UPTO_4_0;
  48. import static com.atlassian.maven.plugins.amps.product.JiraProductHandler.FILENAME_DBCONFIG;
  49. import static com.atlassian.maven.plugins.amps.product.JiraProductHandler.INSTALLED_PLUGINS_DIR;
  50. import static com.atlassian.maven.plugins.amps.product.JiraProductHandler.PLUGINS_DIR;
  51. import static com.google.common.collect.Lists.newArrayList;
  52. import static java.lang.String.format;
  53. import static java.util.Collections.singletonList;
  54. import static org.apache.commons.lang3.JavaVersion.JAVA_9;
  55. import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast;
  56. import static org.hamcrest.CoreMatchers.containsString;
  57. import static org.hamcrest.CoreMatchers.is;
  58. import static org.hamcrest.MatcherAssert.assertThat;
  59. import static org.hamcrest.Matchers.contains;
  60. import static org.hamcrest.Matchers.hasEntry;
  61. import static org.hamcrest.Matchers.hasKey;
  62. import static org.hamcrest.Matchers.not;
  63. import static org.junit.Assert.assertEquals;
  64. import static org.junit.Assert.assertNotNull;
  65. import static org.junit.Assert.assertTrue;
  66. import static org.mockito.ArgumentMatchers.any;
  67. import static org.mockito.Mockito.mock;
  68. import static org.mockito.Mockito.spy;
  69. import static org.mockito.Mockito.times;
  70. import static org.mockito.Mockito.verify;
  71. import static org.mockito.Mockito.when;
  72. public class TestJiraProductHandler {
  73. private static File TEMP_HOME;
  74. @Rule
  75. public final MethodRule mockitoRule = MockitoJUnit.rule();
  76. @Rule
  77. public final TemporaryFolder temporaryFolder = new TemporaryFolder();
  78. @Mock
  79. private RepositorySystem repositorySystem;
  80. @Mock
  81. private ArtifactResolver artifactResolver;
  82. @Mock
  83. private Build build;
  84. @Mock
  85. private Log log;
  86. @Mock
  87. private MavenContext mavenContext;
  88. @Mock
  89. private MavenGoals mavenGoals;
  90. @Mock
  91. private MavenProject mavenProject;
  92. @Mock
  93. private WebAppManager webAppManager;
  94. @Captor
  95. private ArgumentCaptor<Collection<XmlOverride>> expectedOverridesCaptor;
  96. // Can't use @InjectMocks because of method calls on constructor args
  97. private JiraProductHandler productHandler;
  98. private static File createTempDir(final String subPath) {
  99. return new File(System.getProperty("java.io.tmpdir"), subPath);
  100. }
  101. @Before
  102. public void setUp() throws Exception {
  103. when(build.getDirectory()).thenReturn(temporaryFolder.newFolder("jira").getAbsolutePath());
  104. when(mavenProject.getBuild()).thenReturn(build);
  105. when(mavenContext.getLog()).thenReturn(log);
  106. when(mavenContext.getProject()).thenReturn(mavenProject);
  107. productHandler = new JiraProductHandler(mavenContext, mavenGoals, repositorySystem, artifactResolver, webAppManager);
  108. createTemporaryHomeDirectory();
  109. }
  110. public void createTemporaryHomeDirectory() throws IOException {
  111. final File f = File.createTempFile("temp-jira-", "-home");
  112. if (!f.delete()) {
  113. throw new IOException();
  114. }
  115. if (!f.mkdir()) {
  116. throw new IOException();
  117. }
  118. TEMP_HOME = f;
  119. }
  120. @After
  121. public void deleteTemporaryHomeDirectoryAndContents() throws Exception {
  122. if (TEMP_HOME != null) {
  123. FileUtils.deleteDirectory(TEMP_HOME);
  124. TEMP_HOME = null;
  125. }
  126. }
  127. @Test
  128. public void itShouldSetNewJvmArgsForJira8_0_0AndHigher() {
  129. newArrayList(
  130. newProduct("8.0.0-ALPHA"), newProduct("8.0.0-SNAPSHOT"), newProduct("8.0-EAP01"),
  131. newProduct("8.0.0"), newProduct("8.0.1-SNAPSHOT"), newProduct("8.0.2"),
  132. newProduct("8.0.0-m0030"), newProduct("8.1-rc1"), newProduct("8.1"))
  133. .forEach(product -> {
  134. productHandler.fixJvmArgs(product);
  135. assertThat(format("Jira version %s does not have the correct Xmx", product.getVersion()), product.getJvmArgs(), containsString("-Xmx2g"));
  136. assertThat(format("Jira version %s does not have the correct Xms", product.getVersion()), product.getJvmArgs(), containsString("-Xms1g"));
  137. if (isJavaVersionAtLeast(JAVA_9)) {
  138. assertThat(product.getJvmArgs(), containsString("--add-opens"));
  139. }
  140. });
  141. }
  142. @Test
  143. public void itShouldSetNewJvmArgsForJira7_7_0AndHigher() {
  144. newArrayList(
  145. newProduct("7.7.0-ALPHA"), newProduct("7.7.0-SNAPSHOT"), newProduct("7.7-EAP01"), newProduct("7.7.0"),
  146. newProduct("7.7.1-SNAPSHOT"), newProduct("7.7.2"), newProduct("7.8-rc1"), newProduct("7.8"))
  147. .forEach(product -> {
  148. productHandler.fixJvmArgs(product);
  149. assertThat(format("Jira version %s does not have the correct Xmx", product.getVersion()), product.getJvmArgs(), containsString("-Xmx768m"));
  150. assertThat(format("Jira version %s does not have the correct Xms", product.getVersion()), product.getJvmArgs(), containsString("-Xms384m"));
  151. });
  152. }
  153. @Test
  154. public void itShouldUseDefaultJvmArgsForLowerThanJira7_7_0() {
  155. newArrayList(
  156. newProduct("7.6.0"), newProduct("7.6.19-SNAPSHOT"), newProduct("7.1"))
  157. .forEach(product -> {
  158. productHandler.fixJvmArgs(product);
  159. assertThat(format("Jira version %s does not have the correct Xmx", product.getVersion()), product.getJvmArgs(), containsString("-Xmx512m"));
  160. assertThat(format("Jira version %s has Xms set and should not", product.getVersion()), product.getJvmArgs(), not(containsString("-Xms384m")));
  161. });
  162. }
  163. @Test
  164. public void dbconfigXmlCreatedWithCorrectPath() throws Exception {
  165. JiraProductHandler.createDbConfigXmlIfNone(TEMP_HOME);
  166. File f = new File(TEMP_HOME, FILENAME_DBCONFIG);
  167. assertTrue("The config file is created: " + FILENAME_DBCONFIG, f.exists());
  168. assertTrue("And it's a regular file", f.isFile());
  169. File dbFile = new File(TEMP_HOME, "database");
  170. Document d = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(f);
  171. XPathExpression xpe = XPathFactory.newInstance().newXPath().compile("/jira-database-config/jdbc-datasource/url");
  172. String x = xpe.evaluate(d);
  173. assertEquals("The JDBC URI for the embedded database is as expected",
  174. "jdbc:hsqldb:file:" + dbFile.toURI().getPath(), x);
  175. }
  176. @Test
  177. public void updateDBConfigXmlForOracle10g() throws Exception {
  178. testUpdateDbConfigXml(new Oracle10g(log));
  179. }
  180. @Test
  181. public void updateDBConfigXmlForOracle12c() throws Exception {
  182. testUpdateDbConfigXml(new Oracle12c(log));
  183. }
  184. @Test
  185. public void updateDBConfigXmlForMysql() throws Exception {
  186. testUpdateDbConfigXml(new MySQL(log));
  187. }
  188. @Test
  189. public void updateDBConfigXmlForPostgres() throws Exception {
  190. testUpdateDbConfigXml(new Postgres(log));
  191. }
  192. @Test
  193. public void updateDBConfigXmlForMicrosoftMssql() throws Exception {
  194. testUpdateDbConfigXml(new MssqlMicrosoft(log));
  195. }
  196. @Test
  197. public void updateDBConfigXmlForJtdsMssql() throws Exception {
  198. testUpdateDbConfigXml(new MssqlJtds(log));
  199. }
  200. @Test
  201. public void shouldByDefaultForceJiraSynchronousStartup() {
  202. final Product product = newProduct();
  203. final Map<String, String> systemProperties = productHandler.getSystemProperties(product, 0);
  204. // then
  205. assertThat(
  206. systemProperties, hasEntry(
  207. "com.atlassian.jira.startup.LauncherContextListener.SYNCHRONOUS", "true"
  208. ));
  209. }
  210. @Test
  211. public void shouldPassAwaitInitializationFlagFromProduct() {
  212. final Product product = newProduct();
  213. final Map<String, String> systemPropertiesWithAwait = productHandler.getSystemProperties(product, 0);
  214. product.setAwaitFullInitialization(false);
  215. final Map<String, String> systemPropertiesNoWait = productHandler.getSystemProperties(product, 0);
  216. // then
  217. assertThat(
  218. systemPropertiesWithAwait, hasEntry(
  219. "com.atlassian.jira.startup.LauncherContextListener.SYNCHRONOUS", "true"
  220. ));
  221. assertThat(
  222. systemPropertiesNoWait, not(hasKey(
  223. "com.atlassian.jira.startup.LauncherContextListener.SYNCHRONOUS"
  224. )));
  225. }
  226. private void testUpdateDbConfigXml(final DatabaseType databaseType) throws Exception {
  227. // Create default dbconfig.xml
  228. JiraProductHandler.createDbConfigXmlIfNone(TEMP_HOME);
  229. // Setup
  230. final File f = new File(TEMP_HOME, FILENAME_DBCONFIG);
  231. final String schema = "test-schema";
  232. final SAXReader reader = new SAXReader();
  233. org.dom4j.Document dbConfigXml = reader.read(f);
  234. // Check default db type
  235. assertEquals("hsql", getDbType(dbConfigXml));
  236. assertEquals("PUBLIC", getDbSchema(dbConfigXml));
  237. // Invoke: update dbconfig.xml
  238. JiraProductHandler.updateDbConfigXml(TEMP_HOME, databaseType, schema);
  239. dbConfigXml = reader.read(f);
  240. // Check
  241. assertEquals(databaseType.getOfBizName(), getDbType(dbConfigXml));
  242. if (databaseType.hasSchema()) {
  243. assertThat("Schema has to update", schema.equals(getDbSchema(dbConfigXml)), is(true));
  244. } else {
  245. assertThat("Schema has not to update", schema.equals(getDbSchema(dbConfigXml)), is(false));
  246. }
  247. }
  248. private String getDbType(org.dom4j.Document dbConfigXml) {
  249. final org.dom4j.Node dbTypeNode = dbConfigXml.selectSingleNode("//jira-database-config/database-type");
  250. return dbTypeNode == null ? "" : dbTypeNode.getStringValue();
  251. }
  252. private String getDbSchema(org.dom4j.Document dbConfigXml) {
  253. final org.dom4j.Node schemaNode = dbConfigXml.selectSingleNode("//jira-database-config/schema-name");
  254. return schemaNode == null ? "" : schemaNode.getStringValue();
  255. }
  256. @Test
  257. public void dbconfigXmlNotCreatedWhenAlreadyExists() throws Exception {
  258. final File f = new File(TEMP_HOME, FILENAME_DBCONFIG);
  259. FileUtils.writeStringToFile(f, "Original contents", StandardCharsets.UTF_8);
  260. JiraProductHandler.createDbConfigXmlIfNone(TEMP_HOME);
  261. final String after = FileUtils.readFileToString(f, StandardCharsets.UTF_8);
  262. assertEquals("Original contents", after);
  263. }
  264. @Test
  265. public void pluginsShouldGoIntoLocalHomeIfNoSharedHomeIsSpecified() {
  266. final File localHome = createTempDir("jira-local");
  267. assertUserInstalledPluginsDirectory(localHome, null, localHome);
  268. }
  269. @Test
  270. public void pluginsShouldGoIntoSharedHomeIfOneIsSpecified() {
  271. final File sharedHome = createTempDir("jira-shared");
  272. assertUserInstalledPluginsDirectory(null, sharedHome.getPath(), sharedHome);
  273. }
  274. private void assertUserInstalledPluginsDirectory(
  275. final File localHome, final String sharedHomePath, final File expectedParentDir) {
  276. // Set up
  277. final Product mockProduct = mock(Product.class);
  278. when(mockProduct.getSharedHome()).thenReturn(sharedHomePath);
  279. // Invoke
  280. final Optional<File> userInstalledPluginsDirectory =
  281. productHandler.getUserInstalledPluginsDirectory(mockProduct, null, localHome);
  282. // Check
  283. assertNotNull(userInstalledPluginsDirectory);
  284. assertThat(userInstalledPluginsDirectory,
  285. is(Optional.of(new File(new File(expectedParentDir, PLUGINS_DIR), INSTALLED_PLUGINS_DIR))));
  286. }
  287. @Test
  288. public void bundledPluginsShouldBeUnzippedIfPresent() {
  289. final File bundledPluginsDir = new File(TEMP_HOME, BUNDLED_PLUGINS_UNZIPPED);
  290. //noinspection ResultOfMethodCallIgnored
  291. bundledPluginsDir.mkdirs();
  292. assertTrue(bundledPluginsDir.exists());
  293. assertBundledPluginPath("6.3", TEMP_HOME, bundledPluginsDir);
  294. }
  295. @Test
  296. public void bundledPluginsLocationCorrectFor41() {
  297. final File bundledPluginsZip = new File(TEMP_HOME, BUNDLED_PLUGINS_FROM_4_1);
  298. assertBundledPluginPath("4.1", TEMP_HOME, bundledPluginsZip);
  299. }
  300. @Test
  301. public void bundledPluginsLocationCorrectFor40() {
  302. final File bundledPluginsZip = new File(TEMP_HOME, BUNDLED_PLUGINS_UPTO_4_0);
  303. assertBundledPluginPath("4.0", TEMP_HOME, bundledPluginsZip);
  304. }
  305. @Test
  306. public void bundledPluginsLocationCorrectForFallback() {
  307. final File bundledPluginsZip = new File(TEMP_HOME, BUNDLED_PLUGINS_FROM_4_1);
  308. assertBundledPluginPath("not.a.version", TEMP_HOME, bundledPluginsZip);
  309. }
  310. @Test
  311. public void testCustomiseInstanceForServerXmlOverridesForNewJiras() {
  312. final Product ctx = mock(Product.class);
  313. when(ctx.getVersion()).thenReturn("7.12.0");
  314. final JiraProductHandler spied = spy(productHandler);
  315. // Execute
  316. spied.customiseInstance(ctx, new File("./"), new File("./"));
  317. // Validate
  318. verify(ctx, times(1)).setCargoXmlOverrides(expectedOverridesCaptor.capture());
  319. assertThat(expectedOverridesCaptor.getValue().size(), is(2));
  320. final Iterator<XmlOverride> valueIterator = expectedOverridesCaptor.getValue().iterator();
  321. final XmlOverride first = valueIterator.next();
  322. assertThat(first.getAttributeName(), is("relaxedPathChars"));
  323. assertThat(first.getValue(), is("[]|"));
  324. final XmlOverride second = valueIterator.next();
  325. assertThat(second.getAttributeName(), is("relaxedQueryChars"));
  326. assertThat(second.getValue(), is("[]|{}^\\`\"<>"));
  327. }
  328. @Test
  329. public void testCustomiseInstanceForServerXmlOverridesForOlderJiras() {
  330. final Product ctx = mock(Product.class);
  331. when(ctx.getVersion()).thenReturn("7.11.0");
  332. final JiraProductHandler spied = spy(productHandler);
  333. // Execute
  334. spied.customiseInstance(ctx, new File("./"), new File("./"));
  335. // Validate we did not overide configuration
  336. // reason - older Jiras run older tomcat version that are less resticted
  337. verify(ctx, times(0)).setCargoXmlOverrides(any());
  338. }
  339. private Product newProduct(String version) {
  340. final Product product = newProduct();
  341. product.setVersion(version);
  342. return product;
  343. }
  344. private Product newProduct() {
  345. final Product product = new Product();
  346. product.setInstanceId("jira");
  347. product.setDataSources(newArrayList());
  348. product.setAwaitFullInitialization(null);
  349. product.initialiseNodes();
  350. return product;
  351. }
  352. private void assertBundledPluginPath(final String version, final File appDir, final File expectedPath) {
  353. // Set up
  354. final Log mockLog = mock(Log.class);
  355. when(mavenContext.getLog()).thenReturn(mockLog);
  356. final Product mockProduct = mock(Product.class);
  357. when(mockProduct.getVersion()).thenReturn(version);
  358. // Invoke
  359. final File bundledPluginPath = productHandler.getBundledPluginPath(mockProduct, appDir);
  360. // Check
  361. assertNotNull(bundledPluginPath);
  362. assertEquals(expectedPath, bundledPluginPath);
  363. }
  364. @Test
  365. public void getExtraJarsToSkipWhenScanningForTldsAndWebFragments_whenCalled_shouldSkipJotmAndXapool() {
  366. // Set up
  367. // Invoke
  368. final Collection<String> extraJarsToSkip = productHandler.getExtraJarsToSkipWhenScanningForTldsAndWebFragments();
  369. // Check
  370. assertThat(extraJarsToSkip, contains("jotm*.jar", "xapool*.jar"));
  371. }
  372. @Test
  373. public void getReplacements_whenBaseUrlReplaced_shouldUseCorrectPortNumber() {
  374. assertReplacedWithBaseUrl("@base-url@");
  375. }
  376. @Test
  377. public void getReplacements_whenLocalhost8080Replaced_shouldUseCorrectPortNumber() {
  378. assertReplacedWithBaseUrl("http://localhost:8080");
  379. }
  380. private void assertReplacedWithBaseUrl(final String original) {
  381. // Set up
  382. final Product product = mock(Product.class);
  383. when(product.getContextPath()).thenReturn("theContextPath");
  384. when(product.getDataHome()).thenReturn("theParent/theDataHome");
  385. when(product.getInstanceId()).thenReturn("theInstanceId");
  386. when(product.getProtocol()).thenReturn("theProtocol");
  387. when(product.getServer()).thenReturn("theServer");
  388. when(product.getWebPortForNode(0)).thenReturn(42);
  389. final Node node = mock(Node.class);
  390. when(product.getNodes()).thenReturn(singletonList(node));
  391. // Invoke
  392. final List<Replacement> replacements = productHandler.getReplacements(product, 0);
  393. // Check
  394. final String result = apply(replacements, original);
  395. assertThat(result, is("theProtocol://theServer:42/theContextPath"));
  396. }
  397. private static String apply(final List<Replacement> replacements, String result) {
  398. for (final Replacement replacement : replacements) {
  399. result = replacement.replace(result);
  400. }
  401. return result;
  402. }
  403. }