PageRenderTime 26ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/amps-maven-plugin/src/test/java/com/atlassian/maven/plugins/amps/wadl/RestDocsGeneratorTest.java

https://bitbucket.org/atlassian/amps
Java | 301 lines | 248 code | 44 blank | 9 comment | 0 complexity | 572b079a3dd9a8f7344482e2556b0ea5 MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause
  1. package com.atlassian.maven.plugins.amps.wadl;
  2. import com.atlassian.maven.plugins.amps.MavenContext;
  3. import com.atlassian.maven.plugins.amps.TestMavenGoals;
  4. import com.atlassian.maven.plugins.amps.util.MojoExecutorWrapper;
  5. import com.atlassian.maven.plugins.amps.util.PreserveClassLoaderRule;
  6. import com.google.common.collect.ImmutableList;
  7. import org.apache.maven.model.Build;
  8. import org.apache.maven.model.Plugin;
  9. import org.apache.maven.plugin.MojoExecutionException;
  10. import org.apache.maven.plugin.logging.Log;
  11. import org.apache.maven.project.MavenProject;
  12. import org.codehaus.plexus.util.xml.Xpp3Dom;
  13. import org.hamcrest.Description;
  14. import org.hamcrest.Matcher;
  15. import org.hamcrest.TypeSafeMatcher;
  16. import org.junit.Before;
  17. import org.junit.Rule;
  18. import org.junit.Test;
  19. import org.junit.rules.TemporaryFolder;
  20. import org.junit.rules.TestRule;
  21. import org.mockito.ArgumentCaptor;
  22. import org.mockito.InjectMocks;
  23. import org.mockito.Mock;
  24. import org.mockito.junit.MockitoJUnit;
  25. import org.mockito.junit.MockitoRule;
  26. import org.twdata.maven.mojoexecutor.MojoExecutor.ExecutionEnvironment;
  27. import java.io.File;
  28. import java.net.URI;
  29. import java.net.URISyntaxException;
  30. import java.net.URL;
  31. import java.net.URLClassLoader;
  32. import java.nio.file.Files;
  33. import java.nio.file.Path;
  34. import java.nio.file.Paths;
  35. import java.util.Optional;
  36. import java.util.Set;
  37. import java.util.function.Function;
  38. import java.util.stream.Stream;
  39. import static com.atlassian.maven.plugins.amps.util.Xpp3DomMatchers.childMatching;
  40. import static com.atlassian.maven.plugins.amps.util.Xpp3DomMatchers.childrenMatching;
  41. import static com.atlassian.maven.plugins.amps.util.Xpp3DomMatchers.valueMatching;
  42. import static java.lang.Thread.currentThread;
  43. import static java.nio.charset.StandardCharsets.UTF_8;
  44. import static java.util.Arrays.stream;
  45. import static java.util.stream.Collectors.toSet;
  46. import static org.apache.commons.io.FileUtils.readFileToString;
  47. import static org.apache.commons.io.FileUtils.writeStringToFile;
  48. import static org.hamcrest.MatcherAssert.assertThat;
  49. import static org.hamcrest.Matchers.contains;
  50. import static org.hamcrest.Matchers.is;
  51. import static org.mockito.ArgumentMatchers.any;
  52. import static org.mockito.ArgumentMatchers.eq;
  53. import static org.mockito.ArgumentMatchers.same;
  54. import static org.mockito.Mockito.doAnswer;
  55. import static org.mockito.Mockito.doThrow;
  56. import static org.mockito.Mockito.never;
  57. import static org.mockito.Mockito.verify;
  58. import static org.mockito.Mockito.when;
  59. public class RestDocsGeneratorTest {
  60. @Rule
  61. public final MockitoRule mockitoRule = MockitoJUnit.rule();
  62. @Rule
  63. public final TemporaryFolder temporaryFolder = new TemporaryFolder();
  64. @Rule
  65. public final TestRule preserveClassLoaderRule = new PreserveClassLoaderRule();
  66. @Mock
  67. private Build build;
  68. @Mock
  69. private ExecutionEnvironment executionEnvironment;
  70. @Mock
  71. private Log log;
  72. @Mock
  73. private MavenContext mavenContext;
  74. @Mock
  75. private MavenProject mavenProject;
  76. @Mock
  77. private MojoExecutorWrapper mojoExecutorWrapper;
  78. @Mock
  79. private Plugin javadocPlugin;
  80. @InjectMocks
  81. private RestDocsGenerator restDocsGenerator;
  82. @Before
  83. public void setUpMavenContext() {
  84. when(mavenContext.getProject()).thenReturn(mavenProject);
  85. when(mavenProject.getBuild()).thenReturn(build);
  86. }
  87. private void setUpExecutionEnvironment() {
  88. when(mavenContext.getExecutionEnvironment()).thenReturn(executionEnvironment);
  89. }
  90. private void setUpLog() {
  91. when(mavenContext.getLog()).thenReturn(log);
  92. }
  93. @Test
  94. public void shouldGracefullyHandleRestDocGenerationFailure() throws Exception {
  95. setUpContextClassLoader();
  96. setUpExecutionEnvironment();
  97. setUpLog();
  98. createStructureInTempDirectory();
  99. copyPluginXmlWithRestModules();
  100. final Path buildOutputDirectory = temporaryFolder.getRoot().toPath().resolve("target");
  101. when(build.getOutputDirectory()).thenReturn(buildOutputDirectory.toAbsolutePath().toString());
  102. final Path sourceDirectory = temporaryFolder.getRoot().toPath().resolve("src/main/java");
  103. when(build.getSourceDirectory()).thenReturn(sourceDirectory.toAbsolutePath().toString());
  104. doThrow(new MojoExecutionException("fake problem")).when(mojoExecutorWrapper).executeWithMergedConfig(
  105. any(), eq("javadoc"), any(), eq(executionEnvironment));
  106. restDocsGenerator.generateRestDocs("");
  107. assertGeneratedFileEqualsExpectedFile(buildOutputDirectory, "application-doc.xml",
  108. "expected-application-doc.xml");
  109. assertGeneratedFileEqualsExpectedFile(buildOutputDirectory, "application-grammars.xml",
  110. "expected-application-grammars.xml");
  111. }
  112. @Test
  113. public void shouldNotReplaceRestDocFilesIfTheyWereGenerated() throws Exception {
  114. setUpContextClassLoader();
  115. setUpExecutionEnvironment();
  116. createStructureInTempDirectory();
  117. copyPluginXmlWithRestModules();
  118. final Path buildOutputDirectory = temporaryFolder.getRoot().toPath().resolve("target");
  119. when(build.getOutputDirectory()).thenReturn(buildOutputDirectory.toAbsolutePath().toString());
  120. final Path sourceDirectory = temporaryFolder.getRoot().toPath().resolve("src/main/java");
  121. when(build.getSourceDirectory()).thenReturn(sourceDirectory.toAbsolutePath().toString());
  122. doAnswer(a -> {
  123. writeStringToFile(buildOutputDirectory.resolve("application-doc.xml").toFile(), "appDoc", UTF_8);
  124. writeStringToFile(buildOutputDirectory.resolve("application-grammars.xml").toFile(), "appGrammars", UTF_8);
  125. return null;
  126. }).when(mojoExecutorWrapper).executeWithMergedConfig(any(), eq("javadoc"), any(), eq(executionEnvironment));
  127. restDocsGenerator.generateRestDocs("");
  128. assertGeneratedFileEqualsString(buildOutputDirectory, "application-doc.xml", "appDoc");
  129. assertGeneratedFileEqualsString(buildOutputDirectory, "application-grammars.xml", "appGrammars");
  130. }
  131. @Test
  132. public void shouldCorrectlyBuildPaths() throws Exception {
  133. // Arrange
  134. setUpContextClassLoader();
  135. setUpExecutionEnvironment();
  136. setUpLog();
  137. createStructureInTempDirectory();
  138. copyPluginXmlWithRestModules();
  139. final Path buildOutputDirectory = temporaryFolder.getRoot().toPath().resolve("target");
  140. when(build.getOutputDirectory()).thenReturn(buildOutputDirectory.toAbsolutePath().toString());
  141. final Path sourceDirectory = temporaryFolder.getRoot().toPath().resolve("src/main/java");
  142. when(build.getSourceDirectory()).thenReturn(sourceDirectory.toAbsolutePath().toString());
  143. final String jacksonModules = "java.lang.Object";
  144. final Set<String> expectedClasspathElements = prepareClasspathElements(buildOutputDirectory.toString());
  145. when(mavenContext.getPlugin("org.apache.maven.plugins", "maven-javadoc-plugin"))
  146. .thenReturn(javadocPlugin);
  147. // Act
  148. restDocsGenerator.generateRestDocs(jacksonModules);
  149. // Assert
  150. final ArgumentCaptor<Xpp3Dom> configCaptor = ArgumentCaptor.forClass(Xpp3Dom.class);
  151. verify(mojoExecutorWrapper).executeWithMergedConfig(
  152. same(javadocPlugin), eq("javadoc"), configCaptor.capture(), same(executionEnvironment));
  153. final Xpp3Dom actualConfig = configCaptor.getValue();
  154. assertThat(actualConfig, childMatching(
  155. "sourcepath", valueMatching(sourceDirectory.resolve("com/atlassian/labs").toString())));
  156. assertThat(actualConfig, childMatching(
  157. "docletPath", valueMatching(new ClasspathElementsMatcher(expectedClasspathElements))));
  158. assertThat(actualConfig, childMatching(
  159. "additionalOptions", childrenMatching(
  160. contains(
  161. valueMatching(String.format("-output \"%s\"",
  162. buildOutputDirectory
  163. .resolve("resourcedoc.xml")
  164. .toAbsolutePath())
  165. ),
  166. valueMatching(String.format(" -modules \"%s\"", jacksonModules))))));
  167. }
  168. private void setUpContextClassLoader() {
  169. // The production code expects the context class loader to be a
  170. // URLClassLoader, so we set it to a no-op child of the current one.
  171. final URLClassLoader urlClassLoader = new URLClassLoader(new URL[0], currentThread().getContextClassLoader());
  172. currentThread().setContextClassLoader(urlClassLoader);
  173. }
  174. @Test
  175. public void shouldNotExecuteJavadocPluginIfNoRestModulesDefined() throws Exception {
  176. setUpLog();
  177. createStructureInTempDirectory();
  178. copyPluginXmlWithoutRestModules();
  179. final Path buildOutputDirectory = temporaryFolder.getRoot().toPath().resolve("target");
  180. when(build.getOutputDirectory()).thenReturn(buildOutputDirectory.toAbsolutePath().toString());
  181. restDocsGenerator.generateRestDocs("");
  182. verify(mojoExecutorWrapper, never()).executeWithMergedConfig(any(), eq("javadoc"), any(), any());
  183. }
  184. private Set<String> prepareClasspathElements(String buildOutputDirectory) throws Exception {
  185. final ImmutableList<String> compileClasspathElements = ImmutableList.of("classpath1", "classpath2");
  186. when(mavenProject.getCompileClasspathElements()).thenReturn(compileClasspathElements);
  187. final ImmutableList<String> runtimeClasspathElements = ImmutableList.of("runtime1", "runtime2");
  188. when(mavenProject.getRuntimeClasspathElements()).thenReturn(runtimeClasspathElements);
  189. final ImmutableList<String> systemClasspathElements = ImmutableList.of("system1", "system2");
  190. //noinspection deprecation - used in production code
  191. when(mavenProject.getSystemClasspathElements()).thenReturn(systemClasspathElements);
  192. return Stream.of(
  193. Stream.of(buildOutputDirectory),
  194. compileClasspathElements.stream(),
  195. runtimeClasspathElements.stream(),
  196. systemClasspathElements.stream(),
  197. RestDocsGenerator.getPluginClasspathElements().stream()
  198. )
  199. .flatMap(Function.identity())
  200. .collect(toSet());
  201. }
  202. @SuppressWarnings("ResultOfMethodCallIgnored")
  203. private void createStructureInTempDirectory() {
  204. new File(temporaryFolder.getRoot(), "src/main/java").mkdirs();
  205. new File(temporaryFolder.getRoot(), "target").mkdirs();
  206. }
  207. private void copyPluginXmlWithRestModules() throws Exception {
  208. Files.copy(Paths.get(loadResource("plugin-xml-with-rest-modules.xml")),
  209. temporaryFolder.getRoot().toPath().resolve("target/atlassian-plugin.xml"));
  210. }
  211. private void copyPluginXmlWithoutRestModules() throws Exception {
  212. Files.copy(Paths.get(loadResource("plugin-xml-without-rest-modules.xml")),
  213. temporaryFolder.getRoot().toPath().resolve("target/atlassian-plugin.xml"));
  214. }
  215. private static void assertGeneratedFileEqualsExpectedFile(
  216. final Path buildOutputDirectory, final String fileName, final String expectedContent) throws Exception {
  217. assertGeneratedFileEqualsString(buildOutputDirectory, fileName,
  218. readFileToString(new File(loadResource(expectedContent)), UTF_8));
  219. }
  220. private static URI loadResource(final String resource) {
  221. return Optional.ofNullable(TestMavenGoals.class.getResource(resource))
  222. .map(url -> {
  223. try {
  224. return url.toURI();
  225. } catch (URISyntaxException e) {
  226. throw new IllegalStateException(e);
  227. }
  228. })
  229. .orElseThrow(() -> new IllegalStateException("Could not find " + resource));
  230. }
  231. private static void assertGeneratedFileEqualsString(
  232. final Path buildOutputDirectory, final String fileName, final String expectedContent)
  233. throws Exception {
  234. assertThat(readFileToString(buildOutputDirectory.resolve(fileName).toFile(), UTF_8),
  235. is(expectedContent));
  236. }
  237. /**
  238. * A matcher that checks whether a given classpath is equal to the specified set of classpath entries.
  239. */
  240. private static class ClasspathElementsMatcher extends TypeSafeMatcher<String> {
  241. private final Matcher<Set<String>> matcher;
  242. ClasspathElementsMatcher(final Set<String> classpathElements) {
  243. this.matcher = is(classpathElements);
  244. }
  245. @Override
  246. protected boolean matchesSafely(final String item) {
  247. final Set<String> classpathElements = stream(item.split(File.pathSeparator))
  248. .collect(toSet());
  249. return matcher.matches(classpathElements);
  250. }
  251. @Override
  252. public void describeTo(final Description description) {
  253. description.appendText("Matcher for doclet path with elements: ")
  254. .appendDescriptionOf(matcher);
  255. }
  256. }
  257. }