PageRenderTime 49ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/src/test/java/com/aragost/javahg/test/AbstractTestCase.java

https://bitbucket.org/aragost/javahg/
Java | 440 lines | 257 code | 57 blank | 126 comment | 16 complexity | 2ab9b8d298dd0b11c680c97c34475788 MD5 | raw file
  1. /*
  2. * #%L
  3. * JavaHg
  4. * %%
  5. * Copyright (C) 2011 aragost Trifork ag
  6. * %%
  7. * Permission is hereby granted, free of charge, to any person obtaining a copy
  8. * of this software and associated documentation files (the "Software"), to deal
  9. * in the Software without restriction, including without limitation the rights
  10. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. * copies of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included in
  15. * all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. * THE SOFTWARE.
  24. * #L%
  25. */
  26. package com.aragost.javahg.test;
  27. import java.io.BufferedReader;
  28. import java.io.File;
  29. import java.io.FileInputStream;
  30. import java.io.IOException;
  31. import java.io.InputStreamReader;
  32. import java.nio.charset.Charset;
  33. import java.util.Collection;
  34. import java.util.logging.Level;
  35. import java.util.logging.Logger;
  36. import org.junit.After;
  37. import org.junit.Assert;
  38. import org.junit.Assume;
  39. import org.junit.runner.RunWith;
  40. import com.aragost.javahg.BaseRepository;
  41. import com.aragost.javahg.Changeset;
  42. import com.aragost.javahg.HgVersion;
  43. import com.aragost.javahg.Repository;
  44. import com.aragost.javahg.RepositoryConfiguration;
  45. import com.aragost.javahg.RepositoryConfiguration.CachePolicy;
  46. import com.aragost.javahg.commands.AddCommand;
  47. import com.aragost.javahg.commands.CommitCommand;
  48. import com.aragost.javahg.commands.UpdateCommand;
  49. import com.aragost.javahg.commands.VersionCommand;
  50. import com.aragost.javahg.internals.AbstractCommand;
  51. import com.aragost.javahg.internals.GenericCommand;
  52. import com.aragost.javahg.internals.HgInputStream;
  53. import com.aragost.javahg.internals.RuntimeIOException;
  54. import com.aragost.javahg.internals.Server;
  55. import com.aragost.javahg.internals.Utils;
  56. import com.google.common.collect.ObjectArrays;
  57. import com.google.common.io.Files;
  58. /**
  59. * Base class for test cases.
  60. */
  61. @RunWith(org.junit.runners.BlockJUnit4ClassRunner.class)
  62. public abstract class AbstractTestCase {
  63. // The jul root logger is changed in the initialization of this
  64. // class. A strong reference must be maintained to the logger. See
  65. // LG_LOST_LOGGER_DUE_TO_WEAK_REFERENCE on
  66. // http://findbugs.sourceforge.net/bugDescriptions.html
  67. private static final Logger JUL_ROOT_LOGGER = Logger.getLogger("");
  68. private static int count = 0;
  69. private BaseRepository testRepository;
  70. private BaseRepository testRepository2;
  71. protected static final RepositoryConfiguration REPO_CONF;
  72. static {
  73. REPO_CONF = makeRepoConf();
  74. JUL_ROOT_LOGGER.setLevel(Level.WARNING);
  75. File dir = Files.createTempDir();
  76. BaseRepository repo = Repository.create(REPO_CONF, dir);
  77. HgVersion version = VersionCommand.on(repo).execute();
  78. repo.close();
  79. try {
  80. deleteTempDir(dir);
  81. } catch (IOException e) {
  82. System.err.println("JavaHg: Failed to remove temp dir: " + dir.getAbsolutePath());
  83. }
  84. System.err.println("JavaHg test using Mercurial version: " + version + ", binary: " + REPO_CONF.getHgBin());
  85. }
  86. public File createMercurialRepository() {
  87. File dir = Files.createTempDir();
  88. Server server = new Server(RepositoryConfiguration.DEFAULT.getHgBin(),
  89. RepositoryConfiguration.DEFAULT.getEncoding());
  90. server.initMecurialRepository(dir);
  91. return dir;
  92. }
  93. protected static RepositoryConfiguration makeRepoConf() {
  94. RepositoryConfiguration conf = new RepositoryConfiguration();
  95. conf.setCachePolicy(CachePolicy.WEAK);
  96. conf.addExtension(JavaHgTestExtension.class);
  97. return conf;
  98. }
  99. public Charset utf8() {
  100. return Charset.forName("UTF-8");
  101. }
  102. public BaseRepository getTestRepository() {
  103. if (this.testRepository == null) {
  104. File dir = Files.createTempDir();
  105. this.testRepository = Repository.create(REPO_CONF, dir);
  106. }
  107. return this.testRepository;
  108. }
  109. public BaseRepository getTestRepository2() {
  110. if (this.testRepository2 == null) {
  111. File dir = Files.createTempDir();
  112. this.testRepository2 = Repository.create(REPO_CONF, dir);
  113. }
  114. return this.testRepository2;
  115. }
  116. /**
  117. * Write to a file in the test repository
  118. *
  119. * @param name
  120. * @param content
  121. * @throws IOException
  122. */
  123. public void writeFile(String name, String content) throws IOException {
  124. writeFile(getTestRepository(), name, content);
  125. }
  126. public void writeFile(BaseRepository repo, String name, String content) throws IOException {
  127. File file = new File(repo.getDirectory(), name);
  128. Files.write(content, file, utf8());
  129. }
  130. /**
  131. * Write something to the file in the test repository.
  132. * <p>
  133. * Each call to this method will write different content
  134. *
  135. * @param name
  136. * @throws IOException
  137. */
  138. public void writeFile(String name) throws IOException {
  139. writeFile(name, String.valueOf(count++) + "\n");
  140. }
  141. public void appendFile(String name) throws IOException {
  142. File file = new File(getTestRepository().getDirectory(), name);
  143. Files.append(String.valueOf(count++) + "\n", file, utf8());
  144. }
  145. /**
  146. * Read first line of the file
  147. *
  148. * @param name
  149. * @return
  150. * @throws IOException
  151. */
  152. public String readFile(String name) throws IOException {
  153. File file = new File(getTestRepository().getDirectory(), name);
  154. return Files.readFirstLine(file, utf8());
  155. }
  156. /**
  157. * Delete the specified file from the working copy of the test
  158. * repository.
  159. *
  160. * @param name
  161. */
  162. public void deleteFile(String name) {
  163. File file = new File(getTestRepository().getDirectory(), name);
  164. boolean deleted = file.delete();
  165. if (!deleted) {
  166. throw new RuntimeException("Could not delete: " + file);
  167. }
  168. }
  169. /**
  170. * Commit the changes in the test repository
  171. *
  172. * @throws IOException
  173. */
  174. public Changeset commit() throws IOException {
  175. Repository repo = getTestRepository();
  176. AddCommand.on(repo).execute();
  177. CommitCommand cmd = CommitCommand.on(repo).user("testcase").message("testcase: " + getClass().getName());
  178. return cmd.execute();
  179. }
  180. /**
  181. * Create a new changeset in the test repository.
  182. *
  183. * @return the changeset Created
  184. * @throws IOException
  185. */
  186. public Changeset createChangeset() throws IOException {
  187. writeFile("dummyFileForCreatingChangesets", String.valueOf(count++));
  188. return commit();
  189. }
  190. /**
  191. * Update the test repository to the specified changeset
  192. *
  193. * @param cs
  194. * @throws IOException
  195. */
  196. public void update(Changeset cs) throws IOException {
  197. UpdateCommand.on(getTestRepository()).clean().rev(cs.getNode()).execute();
  198. }
  199. @After
  200. public void closeTestRepository() throws IOException {
  201. if (this.testRepository != null) {
  202. this.testRepository.close();
  203. deleteTempDir(this.testRepository.getDirectory());
  204. this.testRepository = null;
  205. }
  206. if (this.testRepository2 != null) {
  207. this.testRepository2.close();
  208. deleteTempDir(this.testRepository2.getDirectory());
  209. this.testRepository2 = null;
  210. }
  211. }
  212. /**
  213. * Return an absolute File object referencing a file in the
  214. * specified repository.
  215. *
  216. * @param repo
  217. * @param parts
  218. * @return
  219. */
  220. public static File repoFile(Repository repo, String... parts) {
  221. File result = repo.getDirectory();
  222. for (String part : parts) {
  223. result = new File(result, part);
  224. }
  225. return result;
  226. }
  227. /**
  228. * The error text for missing files is different on Windows
  229. * compared to Linux/Mac
  230. *
  231. * @return
  232. */
  233. public static String getMissingFileErrorText() {
  234. String error = "No such file or directory";
  235. String osName = System.getProperty("os.name");
  236. if (osName.startsWith("Windows")) {
  237. error = "The system cannot find the file specified";
  238. }
  239. return error;
  240. }
  241. /**
  242. * Create a temp directory, and return the canonical file object
  243. * (i.e. no symlinks).
  244. *
  245. * @return
  246. * @throws IOException
  247. */
  248. protected static File createTempDir() throws IOException {
  249. return Files.createTempDir().getCanonicalFile();
  250. }
  251. /**
  252. * Delete a directory in the system temporary directory
  253. * (java.io.tmpdir).
  254. *
  255. * @throws IOException
  256. */
  257. public static void deleteTempDir(File file) throws IOException {
  258. Utils.deleteTempDir(file);
  259. }
  260. protected void assertSingleton(Object obj, Collection<?> coll) {
  261. Assert.assertEquals(obj, Utils.single(coll));
  262. }
  263. protected void assertFailedExecution(AbstractCommand cmd) {
  264. assertFailedExecution(cmd, "");
  265. }
  266. protected void assertFailedExecution(AbstractCommand cmd, String msg) {
  267. if (msg.length() > 0) {
  268. msg = " Message: " + msg;
  269. }
  270. Assert.fail("Exception expected! Return code: " + cmd.getReturnCode() + "." + msg);
  271. }
  272. /**
  273. * Execute a Mercurial command direcotry for a repository, with
  274. * out using the server
  275. *
  276. * @param repo
  277. * @param hgrcPath
  278. * @param args
  279. */
  280. protected void execHgCommand(BaseRepository repo, String... args) {
  281. try {
  282. String[] arr = Utils.arrayConcat(new String[] { REPO_CONF.getHgBin(), "--repo",
  283. repo.getDirectory().getAbsolutePath() }, args);
  284. Process process = Runtime.getRuntime().exec(arr);
  285. String stderr = Utils.readStream(process.getErrorStream(), repo.newDecoder());
  286. Utils.consumeAll(process.getInputStream());
  287. if (process.waitFor() != 0) {
  288. throw new RuntimeException(stderr);
  289. }
  290. } catch (IOException e) {
  291. throw new RuntimeIOException(e);
  292. } catch (InterruptedException e) {
  293. throw Utils.asRuntime(e);
  294. }
  295. }
  296. /**
  297. * Warning: invoking commands on this server may put it in an invalid state.
  298. * Use AbstractCommand.launchStream(String...) instead.
  299. *
  300. * @param repo The repo
  301. * @return A Server from the repo
  302. */
  303. protected Server getFirstServer(Repository repo) {
  304. return repo.getServerPool().getServers().get(0);
  305. }
  306. protected static ServeState startServing(Repository repo,
  307. String... additionalConfig) {
  308. // On windows hg serve --port 0 doesn't print the port it's listening on
  309. Assume.assumeTrue(!Utils.isWindows());
  310. final File pidFile;
  311. try {
  312. pidFile = File.createTempFile("javahg", ".pid");
  313. final Process process = Runtime.getRuntime().exec(
  314. ObjectArrays.concat(
  315. new String[] {
  316. RepositoryConfiguration.DEFAULT.getHgBin(),
  317. "serve", "--port", "0", "-d", "--pid-file",
  318. pidFile.toString(), "-R",
  319. repo.getDirectory().toString() },
  320. additionalConfig, String.class));
  321. HgInputStream in = new HgInputStream(process.getInputStream(),
  322. repo.newDecoder());
  323. Assert.assertTrue(in.find("(bound to *:".getBytes()));
  324. final int port = in.readDecimal().intValue();
  325. in.close();
  326. return new ServeState() {
  327. public int getPort() {
  328. return port;
  329. }
  330. public void stop() {
  331. BufferedReader in = null;;
  332. try {
  333. // probably already dead:
  334. process.destroy();
  335. in = new BufferedReader(new InputStreamReader(new FileInputStream(pidFile)));
  336. killProcess(Integer.parseInt(in.readLine()));
  337. } catch (Exception e) {
  338. throw Utils.asRuntime(e);
  339. } finally {
  340. try {
  341. in.close();
  342. } catch (IOException e) {
  343. throw Utils.asRuntime(e);
  344. }
  345. }
  346. }};
  347. } catch (IOException e) {
  348. throw Utils.asRuntime(e);
  349. }
  350. }
  351. /**
  352. * Kill a process
  353. *
  354. * @param pid The process id
  355. */
  356. protected static void killProcess(int pid) {
  357. try {
  358. Runtime rt = Runtime.getRuntime();
  359. if (System.getProperty("os.name").toLowerCase().indexOf("windows") > -1) {
  360. rt.exec("taskkill " + pid).waitFor();
  361. } else {
  362. rt.exec(new String[] { "kill", "-9", "" + pid }).waitFor();
  363. }
  364. } catch (IOException e) {
  365. throw Utils.asRuntime(e);
  366. } catch (InterruptedException e) {
  367. throw Utils.asRuntime(e);
  368. }
  369. }
  370. protected static class TestableCommand extends GenericCommand {
  371. public TestableCommand(Repository repository, String commandName) {
  372. super(repository, commandName);
  373. }
  374. public HgInputStream executeToStream(String... args) {
  375. return launchStream(args);
  376. }
  377. }
  378. protected interface ServeState
  379. {
  380. public int getPort();
  381. public void stop();
  382. }
  383. }