WLGitBridgeIntegrationTest.java 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  1. package uk.ac.ic.wlgitbridge;
  2. import org.eclipse.jgit.api.errors.GitAPIException;
  3. import org.junit.Rule;
  4. import org.junit.Test;
  5. import org.junit.rules.TemporaryFolder;
  6. import uk.ac.ic.wlgitbridge.application.GitBridgeApp;
  7. import uk.ac.ic.wlgitbridge.snapshot.servermock.server.MockSnapshotServer;
  8. import uk.ac.ic.wlgitbridge.snapshot.servermock.state.SnapshotAPIState;
  9. import uk.ac.ic.wlgitbridge.snapshot.servermock.state.SnapshotAPIStateBuilder;
  10. import uk.ac.ic.wlgitbridge.snapshot.servermock.util.FileUtil;
  11. import uk.ac.ic.wlgitbridge.util.Util;
  12. import java.io.*;
  13. import java.nio.file.Path;
  14. import java.nio.file.Paths;
  15. import java.util.Arrays;
  16. import java.util.HashMap;
  17. import java.util.List;
  18. import java.util.Map;
  19. import static org.junit.Assert.assertEquals;
  20. import static org.junit.Assert.assertTrue;
  21. /**
  22. * Created by Winston on 11/01/15.
  23. */
  24. public class WLGitBridgeIntegrationTest {
  25. private Runtime runtime = Runtime.getRuntime();
  26. private Map<String, Map<String, SnapshotAPIState>> states =
  27. new HashMap<String, Map<String, SnapshotAPIState>>() {{
  28. put("canCloneARepository", new HashMap<String, SnapshotAPIState>() {{
  29. put("state", new SnapshotAPIStateBuilder(getResourceAsStream("/canCloneARepository/state/state.json")).build());
  30. }});
  31. put("canCloneMultipleRepositories", new HashMap<String, SnapshotAPIState>() {{
  32. put("state", new SnapshotAPIStateBuilder(getResourceAsStream("/canCloneMultipleRepositories/state/state.json")).build());
  33. }});
  34. put("cannotCloneAProtectedProject", new HashMap<String, SnapshotAPIState>() {{
  35. put("state", new SnapshotAPIStateBuilder(getResourceAsStream("/cannotCloneAProtectedProject/state/state.json")).build());
  36. }});
  37. put("canPullAModifiedTexFile", new HashMap<String, SnapshotAPIState>() {{
  38. put("base", new SnapshotAPIStateBuilder(getResourceAsStream("/canPullAModifiedTexFile/base/state.json")).build());
  39. put("withModifiedTexFile", new SnapshotAPIStateBuilder(getResourceAsStream("/canPullAModifiedTexFile/withModifiedTexFile/state.json")).build());
  40. }});
  41. put("canPullADeletedTexFile", new HashMap<String, SnapshotAPIState>() {{
  42. put("base", new SnapshotAPIStateBuilder(getResourceAsStream("/canPullADeletedTexFile/base/state.json")).build());
  43. put("withDeletedTexFile", new SnapshotAPIStateBuilder(getResourceAsStream("/canPullADeletedTexFile/withDeletedTexFile/state.json")).build());
  44. }});
  45. put("canPullAModifiedBinaryFile", new HashMap<String, SnapshotAPIState>() {{
  46. put("base", new SnapshotAPIStateBuilder(getResourceAsStream("/canPullAModifiedBinaryFile/base/state.json")).build());
  47. put("withModifiedBinaryFile", new SnapshotAPIStateBuilder(getResourceAsStream("/canPullAModifiedBinaryFile/withModifiedBinaryFile/state.json")).build());
  48. }});
  49. put("canPullADeletedBinaryFile", new HashMap<String, SnapshotAPIState>() {{
  50. put("base", new SnapshotAPIStateBuilder(getResourceAsStream("/canPullADeletedBinaryFile/base/state.json")).build());
  51. put("withDeletedBinaryFile", new SnapshotAPIStateBuilder(getResourceAsStream("/canPullADeletedBinaryFile/withDeletedBinaryFile/state.json")).build());
  52. }});
  53. put("canPullAModifiedNestedFile", new HashMap<String, SnapshotAPIState>() {{
  54. put("base", new SnapshotAPIStateBuilder(getResourceAsStream("/canPullADeletedBinaryFile/base/state.json")).build());
  55. put("withModifiedNestedFile", new SnapshotAPIStateBuilder(getResourceAsStream("/canPullAModifiedNestedFile/withModifiedNestedFile/state.json")).build());
  56. }});
  57. put("canPullDeletedNestedFiles", new HashMap<String, SnapshotAPIState>() {{
  58. put("base", new SnapshotAPIStateBuilder(getResourceAsStream("/canPullDeletedNestedFiles/base/state.json")).build());
  59. put("withDeletedNestedFiles", new SnapshotAPIStateBuilder(getResourceAsStream("/canPullDeletedNestedFiles/withDeletedNestedFiles/state.json")).build());
  60. }});
  61. put("canPushFilesSuccessfully", new HashMap<String, SnapshotAPIState>() {{
  62. put("state", new SnapshotAPIStateBuilder(getResourceAsStream("/canPushFilesSuccessfully/state/state.json")).build());
  63. }});
  64. put("pushFailsOnFirstStageOutOfDate", new HashMap<String, SnapshotAPIState>() {{
  65. put("state", new SnapshotAPIStateBuilder(getResourceAsStream("/pushFailsOnFirstStageOutOfDate/state/state.json")).build());
  66. }});
  67. put("pushFailsOnSecondStageOutOfDate", new HashMap<String, SnapshotAPIState>() {{
  68. put("state", new SnapshotAPIStateBuilder(getResourceAsStream("/pushFailsOnSecondStageOutOfDate/state/state.json")).build());
  69. }});
  70. put("pushFailsOnInvalidFiles", new HashMap<String, SnapshotAPIState>() {{
  71. put("state", new SnapshotAPIStateBuilder(getResourceAsStream("/pushFailsOnInvalidFiles/state/state.json")).build());
  72. }});
  73. put("pushFailsOnInvalidProject", new HashMap<String, SnapshotAPIState>() {{
  74. put("state", new SnapshotAPIStateBuilder(getResourceAsStream("/pushFailsOnInvalidProject/state/state.json")).build());
  75. }});
  76. put("pushFailsOnUnexpectedError", new HashMap<String, SnapshotAPIState>() {{
  77. put("state", new SnapshotAPIStateBuilder(getResourceAsStream("/pushFailsOnUnexpectedError/state/state.json")).build());
  78. }});
  79. put("pushSucceedsAfterRemovingInvalidFiles", new HashMap<String, SnapshotAPIState>() {{
  80. put("invalidState", new SnapshotAPIStateBuilder(getResourceAsStream("/pushSucceedsAfterRemovingInvalidFiles/invalidState/state.json")).build());
  81. put("validState", new SnapshotAPIStateBuilder(getResourceAsStream("/pushSucceedsAfterRemovingInvalidFiles/validState/state.json")).build());
  82. }});
  83. }};
  84. @Rule
  85. public TemporaryFolder folder = new TemporaryFolder();
  86. @Test
  87. public void canCloneARepository() throws IOException, GitAPIException, InterruptedException {
  88. MockSnapshotServer server = new MockSnapshotServer(3857, getResource("/canCloneARepository").toFile());
  89. server.start();
  90. server.setState(states.get("canCloneARepository").get("state"));
  91. GitBridgeApp wlgb = new GitBridgeApp(new String[] {
  92. makeConfigFile(33857, 3857)
  93. });
  94. wlgb.run();
  95. File dir = folder.newFolder();
  96. Process git = runtime.exec("git clone http://127.0.0.1:33857/testproj.git", null, dir);
  97. int exitCode = git.waitFor();
  98. wlgb.stop();
  99. File testprojDir = new File(dir, "testproj");
  100. assertEquals(0, exitCode);
  101. assertTrue(FileUtil.gitDirectoriesAreEqual(getResource("/canCloneARepository/state/testproj"), testprojDir.toPath()));
  102. }
  103. @Test
  104. public void canCloneMultipleRepositories() throws IOException, GitAPIException, InterruptedException {
  105. MockSnapshotServer server = new MockSnapshotServer(3858, getResource("/canCloneMultipleRepositories").toFile());
  106. server.start();
  107. server.setState(states.get("canCloneMultipleRepositories").get("state"));
  108. GitBridgeApp wlgb = new GitBridgeApp(new String[] {
  109. makeConfigFile(33858, 3858)
  110. });
  111. wlgb.run();
  112. File dir = folder.newFolder();
  113. Process git1 = runtime.exec("git clone http://127.0.0.1:33858/testproj1.git", null, dir);
  114. int exitCode1 = git1.waitFor();
  115. Process git2 = runtime.exec("git clone http://127.0.0.1:33858/testproj2.git", null, dir);
  116. int exitCode2 = git2.waitFor();
  117. wlgb.stop();
  118. File testproj1Dir = new File(dir, "testproj1");
  119. File testproj2Dir = new File(dir, "testproj2");
  120. assertEquals(0, exitCode1);
  121. assertTrue(FileUtil.gitDirectoriesAreEqual(getResource("/canCloneMultipleRepositories/state/testproj1"), testproj1Dir.toPath()));
  122. assertEquals(0, exitCode2);
  123. assertTrue(FileUtil.gitDirectoriesAreEqual(getResource("/canCloneMultipleRepositories/state/testproj2"), testproj2Dir.toPath()));
  124. }
  125. private static final String EXPECTED_OUT_PROTECTED =
  126. "Cloning into 'protected'...\n" +
  127. "fatal: remote error: Your project is protected, and can't be cloned (yet).\n";
  128. @Test
  129. public void cannotCloneAProtectedProject() throws IOException, GitAPIException, InterruptedException {
  130. MockSnapshotServer server = new MockSnapshotServer(3861, getResource("/cannotCloneAProtectedProject").toFile());
  131. server.start();
  132. server.setState(states.get("cannotCloneAProtectedProject").get("state"));
  133. GitBridgeApp wlgb = new GitBridgeApp(new String[] {
  134. makeConfigFile(33861, 3861)
  135. });
  136. wlgb.run();
  137. File dir = folder.newFolder();
  138. Process git = runtime.exec("git clone http://127.0.0.1:33861/protected.git", null, dir);
  139. String output = Util.fromStream(git.getErrorStream());
  140. int exitCode = git.waitFor();
  141. assertEquals(128, exitCode);
  142. assertEquals(EXPECTED_OUT_PROTECTED, output);
  143. wlgb.stop();
  144. }
  145. @Test
  146. public void canPullAModifiedTexFile() throws IOException, GitAPIException, InterruptedException {
  147. MockSnapshotServer server = new MockSnapshotServer(3859, getResource("/canPullAModifiedTexFile").toFile());
  148. server.start();
  149. server.setState(states.get("canPullAModifiedTexFile").get("base"));
  150. GitBridgeApp wlgb = new GitBridgeApp(new String[] {
  151. makeConfigFile(33859, 3859)
  152. });
  153. wlgb.run();
  154. File dir = folder.newFolder();
  155. Process gitBase = runtime.exec("git clone http://127.0.0.1:33859/testproj.git", null, dir);
  156. int exitCodeBase = gitBase.waitFor();
  157. File testprojDir = new File(dir, "testproj");
  158. assertEquals(0, exitCodeBase);
  159. assertTrue(FileUtil.gitDirectoriesAreEqual(getResource("/canPullAModifiedTexFile/base/testproj"), testprojDir.toPath()));
  160. server.setState(states.get("canPullAModifiedTexFile").get("withModifiedTexFile"));
  161. Process gitWithModifiedTexFile = runtime.exec("git pull", null, testprojDir);
  162. int exitCodeWithModifiedTexFile = gitWithModifiedTexFile.waitFor();
  163. wlgb.stop();
  164. assertEquals(0, exitCodeWithModifiedTexFile);
  165. assertTrue(FileUtil.gitDirectoriesAreEqual(getResource("/canPullAModifiedTexFile/withModifiedTexFile/testproj"), testprojDir.toPath()));
  166. }
  167. @Test
  168. public void canPullADeletedTexFile() throws IOException, GitAPIException, InterruptedException {
  169. MockSnapshotServer server = new MockSnapshotServer(3860, getResource("/canPullADeletedTexFile").toFile());
  170. server.start();
  171. server.setState(states.get("canPullADeletedTexFile").get("base"));
  172. GitBridgeApp wlgb = new GitBridgeApp(new String[] {
  173. makeConfigFile(33860, 3860)
  174. });
  175. wlgb.run();
  176. File dir = folder.newFolder();
  177. Process gitBase = runtime.exec("git clone http://127.0.0.1:33860/testproj.git", null, dir);
  178. int exitCodeBase = gitBase.waitFor();
  179. File testprojDir = new File(dir, "testproj");
  180. assertEquals(0, exitCodeBase);
  181. assertTrue(FileUtil.gitDirectoriesAreEqual(getResource("/canPullADeletedTexFile/base/testproj"), testprojDir.toPath()));
  182. server.setState(states.get("canPullADeletedTexFile").get("withDeletedTexFile"));
  183. Process gitWithDeletedTexFile = runtime.exec("git pull", null, testprojDir);
  184. int exitCodeWithDeletedTexFile = gitWithDeletedTexFile.waitFor();
  185. wlgb.stop();
  186. assertEquals(0, exitCodeWithDeletedTexFile);
  187. assertTrue(FileUtil.gitDirectoriesAreEqual(getResource("/canPullADeletedTexFile/withDeletedTexFile/testproj"), testprojDir.toPath()));
  188. }
  189. @Test
  190. public void canPullAModifiedBinaryFile() throws IOException, GitAPIException, InterruptedException {
  191. MockSnapshotServer server = new MockSnapshotServer(3862, getResource("/canPullAModifiedBinaryFile").toFile());
  192. server.start();
  193. server.setState(states.get("canPullAModifiedBinaryFile").get("base"));
  194. GitBridgeApp wlgb = new GitBridgeApp(new String[] {
  195. makeConfigFile(33862, 3862)
  196. });
  197. wlgb.run();
  198. File dir = folder.newFolder();
  199. Process gitBase = runtime.exec("git clone http://127.0.0.1:33862/testproj.git", null, dir);
  200. int exitCodeBase = gitBase.waitFor();
  201. File testprojDir = new File(dir, "testproj");
  202. assertEquals(0, exitCodeBase);
  203. assertTrue(FileUtil.gitDirectoriesAreEqual(getResource("/canPullAModifiedBinaryFile/base/testproj"), testprojDir.toPath()));
  204. server.setState(states.get("canPullAModifiedBinaryFile").get("withModifiedBinaryFile"));
  205. Process gitWithModifiedBinaryFile = runtime.exec("git pull", null, testprojDir);
  206. int exitCodeWithModifiedBinaryFile = gitWithModifiedBinaryFile.waitFor();
  207. wlgb.stop();
  208. assertEquals(0, exitCodeWithModifiedBinaryFile);
  209. assertTrue(FileUtil.gitDirectoriesAreEqual(getResource("/canPullAModifiedBinaryFile/withModifiedBinaryFile/testproj"), testprojDir.toPath()));
  210. }
  211. @Test
  212. public void canPullADeletedBinaryFile() throws IOException, GitAPIException, InterruptedException {
  213. MockSnapshotServer server = new MockSnapshotServer(3863, getResource("/canPullADeletedBinaryFile").toFile());
  214. server.start();
  215. server.setState(states.get("canPullADeletedBinaryFile").get("base"));
  216. GitBridgeApp wlgb = new GitBridgeApp(new String[] {
  217. makeConfigFile(33863, 3863)
  218. });
  219. wlgb.run();
  220. File dir = folder.newFolder();
  221. Process gitBase = runtime.exec("git clone http://127.0.0.1:33863/testproj.git", null, dir);
  222. int exitCodeBase = gitBase.waitFor();
  223. File testprojDir = new File(dir, "testproj");
  224. assertEquals(0, exitCodeBase);
  225. assertTrue(FileUtil.gitDirectoriesAreEqual(getResource("/canPullADeletedBinaryFile/base/testproj"), testprojDir.toPath()));
  226. server.setState(states.get("canPullADeletedBinaryFile").get("withDeletedBinaryFile"));
  227. Process gitWithDeletedBinaryFile = runtime.exec("git pull", null, testprojDir);
  228. int exitCodeWithDeletedBinaryFile = gitWithDeletedBinaryFile.waitFor();
  229. wlgb.stop();
  230. assertEquals(0, exitCodeWithDeletedBinaryFile);
  231. assertTrue(FileUtil.gitDirectoriesAreEqual(getResource("/canPullADeletedBinaryFile/withDeletedBinaryFile/testproj"), testprojDir.toPath()));
  232. }
  233. @Test
  234. public void canPullAModifiedNestedFile() throws IOException, GitAPIException, InterruptedException {
  235. MockSnapshotServer server = new MockSnapshotServer(3864, getResource("/canPullAModifiedNestedFile").toFile());
  236. server.start();
  237. server.setState(states.get("canPullAModifiedNestedFile").get("base"));
  238. GitBridgeApp wlgb = new GitBridgeApp(new String[] {
  239. makeConfigFile(33864, 3864)
  240. });
  241. wlgb.run();
  242. File dir = folder.newFolder();
  243. Process gitBase = runtime.exec("git clone http://127.0.0.1:33864/testproj.git", null, dir);
  244. int exitCodeBase = gitBase.waitFor();
  245. File testprojDir = new File(dir, "testproj");
  246. assertEquals(0, exitCodeBase);
  247. assertTrue(FileUtil.gitDirectoriesAreEqual(getResource("/canPullAModifiedNestedFile/base/testproj"), testprojDir.toPath()));
  248. server.setState(states.get("canPullAModifiedNestedFile").get("withModifiedNestedFile"));
  249. Process gitWithModifiedNestedFile = runtime.exec("git pull", null, testprojDir);
  250. int exitCodeWithModifiedNestedFile = gitWithModifiedNestedFile.waitFor();
  251. wlgb.stop();
  252. assertEquals(0, exitCodeWithModifiedNestedFile);
  253. assertTrue(FileUtil.gitDirectoriesAreEqual(getResource("/canPullAModifiedNestedFile/withModifiedNestedFile/testproj"), testprojDir.toPath()));
  254. }
  255. @Test
  256. public void canPullDeletedNestedFiles() throws IOException, GitAPIException, InterruptedException {
  257. MockSnapshotServer server = new MockSnapshotServer(3865, getResource("/canPullDeletedNestedFiles").toFile());
  258. server.start();
  259. server.setState(states.get("canPullDeletedNestedFiles").get("base"));
  260. GitBridgeApp wlgb = new GitBridgeApp(new String[] {
  261. makeConfigFile(33865, 3865)
  262. });
  263. wlgb.run();
  264. File dir = folder.newFolder();
  265. Process gitBase = runtime.exec("git clone http://127.0.0.1:33865/testproj.git", null, dir);
  266. int exitCodeBase = gitBase.waitFor();
  267. File testprojDir = new File(dir, "testproj");
  268. assertEquals(0, exitCodeBase);
  269. assertTrue(FileUtil.gitDirectoriesAreEqual(getResource("/canPullDeletedNestedFiles/base/testproj"), testprojDir.toPath()));
  270. server.setState(states.get("canPullDeletedNestedFiles").get("withDeletedNestedFiles"));
  271. Process gitWithDeletedBinaryFile = runtime.exec("git pull", null, testprojDir);
  272. int exitCodeWithDeletedBinaryFile = gitWithDeletedBinaryFile.waitFor();
  273. wlgb.stop();
  274. assertEquals(0, exitCodeWithDeletedBinaryFile);
  275. assertTrue(FileUtil.gitDirectoriesAreEqual(getResource("/canPullDeletedNestedFiles/withDeletedNestedFiles/testproj"), testprojDir.toPath()));
  276. }
  277. @Test
  278. public void canPushFilesSuccessfully() throws IOException, GitAPIException, InterruptedException {
  279. MockSnapshotServer server = new MockSnapshotServer(3866, getResource("/canPushFilesSuccessfully").toFile());
  280. server.start();
  281. server.setState(states.get("canPushFilesSuccessfully").get("state"));
  282. GitBridgeApp wlgb = new GitBridgeApp(new String[] {
  283. makeConfigFile(33866, 3866)
  284. });
  285. wlgb.run();
  286. File dir = folder.newFolder();
  287. Process git = runtime.exec("git clone http://127.0.0.1:33866/testproj.git", null, dir);
  288. int exitCode = git.waitFor();
  289. File testprojDir = new File(dir, "testproj");
  290. assertEquals(0, exitCode);
  291. assertTrue(FileUtil.gitDirectoriesAreEqual(getResource("/canPushFilesSuccessfully/state/testproj"), testprojDir.toPath()));
  292. runtime.exec("touch push.tex", null, testprojDir).waitFor();
  293. runtime.exec("git add -A", null, testprojDir).waitFor();
  294. runtime.exec("git commit -m \"push\"", null, testprojDir).waitFor();
  295. Process gitPush = runtime.exec("git push", null, testprojDir);
  296. int pushExitCode = gitPush.waitFor();
  297. wlgb.stop();
  298. assertEquals(0, pushExitCode);
  299. }
  300. private static final String EXPECTED_OUT_PUSH_OUT_OF_DATE_FIRST =
  301. "To http://127.0.0.1:33867/testproj.git\n" +
  302. " ! [rejected] master -> master (non-fast-forward)\n" +
  303. "error: failed to push some refs to 'http://127.0.0.1:33867/testproj.git'\n" +
  304. "hint: Updates were rejected because the tip of your current branch is behind\n" +
  305. "hint: its remote counterpart. Integrate the remote changes (e.g.\n" +
  306. "hint: 'git pull ...') before pushing again.\n" +
  307. "hint: See the 'Note about fast-forwards' in 'git push --help' for details.\n";
  308. @Test
  309. public void pushFailsOnFirstStageOutOfDate() throws IOException, GitAPIException, InterruptedException {
  310. MockSnapshotServer server = new MockSnapshotServer(3867, getResource("/pushFailsOnFirstStageOutOfDate").toFile());
  311. server.start();
  312. server.setState(states.get("pushFailsOnFirstStageOutOfDate").get("state"));
  313. GitBridgeApp wlgb = new GitBridgeApp(new String[] {
  314. makeConfigFile(33867, 3867)
  315. });
  316. wlgb.run();
  317. File dir = folder.newFolder();
  318. Process git = runtime.exec("git clone http://127.0.0.1:33867/testproj.git", null, dir);
  319. int exitCode = git.waitFor();
  320. File testprojDir = new File(dir, "testproj");
  321. assertEquals(0, exitCode);
  322. assertTrue(FileUtil.gitDirectoriesAreEqual(getResource("/pushFailsOnFirstStageOutOfDate/state/testproj"), testprojDir.toPath()));
  323. runtime.exec("touch push.tex", null, testprojDir).waitFor();
  324. runtime.exec("git add -A", null, testprojDir).waitFor();
  325. runtime.exec("git commit -m \"push\"", null, testprojDir).waitFor();
  326. Process gitPush = runtime.exec("git push", null, testprojDir);
  327. int pushExitCode = gitPush.waitFor();
  328. wlgb.stop();
  329. assertEquals(1, pushExitCode);
  330. assertEquals(EXPECTED_OUT_PUSH_OUT_OF_DATE_FIRST, Util.fromStream(gitPush.getErrorStream(), 2));
  331. }
  332. private static final String EXPECTED_OUT_PUSH_OUT_OF_DATE_SECOND =
  333. "To http://127.0.0.1:33868/testproj.git\n" +
  334. " ! [rejected] master -> master (non-fast-forward)\n" +
  335. "error: failed to push some refs to 'http://127.0.0.1:33868/testproj.git'\n" +
  336. "hint: Updates were rejected because the tip of your current branch is behind\n" +
  337. "hint: its remote counterpart. Integrate the remote changes (e.g.\n" +
  338. "hint: 'git pull ...') before pushing again.\n" +
  339. "hint: See the 'Note about fast-forwards' in 'git push --help' for details.\n";
  340. @Test
  341. public void pushFailsOnSecondStageOutOfDate() throws IOException, GitAPIException, InterruptedException {
  342. MockSnapshotServer server = new MockSnapshotServer(3868, getResource("/pushFailsOnSecondStageOutOfDate").toFile());
  343. server.start();
  344. server.setState(states.get("pushFailsOnSecondStageOutOfDate").get("state"));
  345. GitBridgeApp wlgb = new GitBridgeApp(new String[] {
  346. makeConfigFile(33868, 3868)
  347. });
  348. wlgb.run();
  349. File dir = folder.newFolder();
  350. Process git = runtime.exec("git clone http://127.0.0.1:33868/testproj.git", null, dir);
  351. int exitCode = git.waitFor();
  352. File testprojDir = new File(dir, "testproj");
  353. assertEquals(0, exitCode);
  354. assertTrue(FileUtil.gitDirectoriesAreEqual(getResource("/pushFailsOnSecondStageOutOfDate/state/testproj"), testprojDir.toPath()));
  355. runtime.exec("touch push.tex", null, testprojDir).waitFor();
  356. runtime.exec("git add -A", null, testprojDir).waitFor();
  357. runtime.exec("git commit -m \"push\"", null, testprojDir).waitFor();
  358. Process gitPush = runtime.exec("git push", null, testprojDir);
  359. int pushExitCode = gitPush.waitFor();
  360. wlgb.stop();
  361. assertEquals(1, pushExitCode);
  362. assertEquals(EXPECTED_OUT_PUSH_OUT_OF_DATE_SECOND, Util.fromStream(gitPush.getErrorStream(), 2));
  363. }
  364. private static final List<String> EXPECTED_OUT_PUSH_INVALID_FILES =
  365. Arrays.asList(
  366. "remote: error: invalid files",
  367. "remote: hint: You have 4 invalid files in your Overleaf project:",
  368. "remote: hint: file1.invalid (error)",
  369. "remote: hint: file2.exe (invalid file extension)",
  370. "remote: hint: hello world.png (rename to: hello_world.png)",
  371. "remote: hint: an image.jpg (rename to: an_image.jpg)",
  372. "To http://127.0.0.1:33869/testproj.git",
  373. "! [remote rejected] master -> master (invalid files)",
  374. "error: failed to push some refs to 'http://127.0.0.1:33869/testproj.git'"
  375. );
  376. @Test
  377. public void pushFailsOnInvalidFiles() throws IOException, GitAPIException, InterruptedException {
  378. MockSnapshotServer server = new MockSnapshotServer(3869, getResource("/pushFailsOnInvalidFiles").toFile());
  379. server.start();
  380. server.setState(states.get("pushFailsOnInvalidFiles").get("state"));
  381. GitBridgeApp wlgb = new GitBridgeApp(new String[] {
  382. makeConfigFile(33869, 3869)
  383. });
  384. wlgb.run();
  385. File dir = folder.newFolder();
  386. Process git = runtime.exec("git clone http://127.0.0.1:33869/testproj.git", null, dir);
  387. int exitCode = git.waitFor();
  388. File testprojDir = new File(dir, "testproj");
  389. assertEquals(0, exitCode);
  390. assertTrue(FileUtil.gitDirectoriesAreEqual(getResource("/pushFailsOnInvalidFiles/state/testproj"), testprojDir.toPath()));
  391. runtime.exec("touch push.tex", null, testprojDir).waitFor();
  392. runtime.exec("git add -A", null, testprojDir).waitFor();
  393. runtime.exec("git commit -m \"push\"", null, testprojDir).waitFor();
  394. Process gitPush = runtime.exec("git push", null, testprojDir);
  395. int pushExitCode = gitPush.waitFor();
  396. wlgb.stop();
  397. assertEquals(1, pushExitCode);
  398. List<String> actual = Util.linesFromStream(gitPush.getErrorStream(), 2, "[K");
  399. assertEquals(EXPECTED_OUT_PUSH_INVALID_FILES, actual);
  400. }
  401. private static final List<String> EXPECTED_OUT_PUSH_INVALID_PROJECT =
  402. Arrays.asList(
  403. "remote: error: invalid project",
  404. "remote: hint: project: no main file",
  405. "remote: hint: The project would have no (editable) main .tex file.",
  406. "To http://127.0.0.1:33870/testproj.git",
  407. "! [remote rejected] master -> master (invalid project)",
  408. "error: failed to push some refs to 'http://127.0.0.1:33870/testproj.git'"
  409. );
  410. @Test
  411. public void pushFailsOnInvalidProject() throws IOException, GitAPIException, InterruptedException {
  412. MockSnapshotServer server = new MockSnapshotServer(3870, getResource("/pushFailsOnInvalidProject").toFile());
  413. server.start();
  414. server.setState(states.get("pushFailsOnInvalidProject").get("state"));
  415. GitBridgeApp wlgb = new GitBridgeApp(new String[] {
  416. makeConfigFile(33870, 3870)
  417. });
  418. wlgb.run();
  419. File dir = folder.newFolder();
  420. Process git = runtime.exec("git clone http://127.0.0.1:33870/testproj.git", null, dir);
  421. int exitCode = git.waitFor();
  422. File testprojDir = new File(dir, "testproj");
  423. assertEquals(0, exitCode);
  424. assertTrue(FileUtil.gitDirectoriesAreEqual(getResource("/pushFailsOnInvalidProject/state/testproj"), testprojDir.toPath()));
  425. runtime.exec("touch push.tex", null, testprojDir).waitFor();
  426. runtime.exec("git add -A", null, testprojDir).waitFor();
  427. runtime.exec("git commit -m \"push\"", null, testprojDir).waitFor();
  428. Process gitPush = runtime.exec("git push", null, testprojDir);
  429. int pushExitCode = gitPush.waitFor();
  430. wlgb.stop();
  431. assertEquals(1, pushExitCode);
  432. List<String> actual = Util.linesFromStream(gitPush.getErrorStream(), 2, "[K");
  433. assertEquals(EXPECTED_OUT_PUSH_INVALID_PROJECT, actual);
  434. }
  435. private static final List<String> EXPECTED_OUT_PUSH_UNEXPECTED_ERROR =
  436. Arrays.asList(
  437. "remote: error: Overleaf error",
  438. "remote: hint: There was an internal error with the Overleaf server.",
  439. "remote: hint: Please contact Overleaf.",
  440. "To http://127.0.0.1:33871/testproj.git",
  441. "! [remote rejected] master -> master (Overleaf error)",
  442. "error: failed to push some refs to 'http://127.0.0.1:33871/testproj.git'"
  443. );
  444. /* this one prints a stack trace */
  445. @Test
  446. public void pushFailsOnUnexpectedError() throws IOException, GitAPIException, InterruptedException {
  447. MockSnapshotServer server = new MockSnapshotServer(3871, getResource("/pushFailsOnUnexpectedError").toFile());
  448. server.start();
  449. server.setState(states.get("pushFailsOnUnexpectedError").get("state"));
  450. GitBridgeApp wlgb = new GitBridgeApp(new String[] {
  451. makeConfigFile(33871, 3871)
  452. });
  453. wlgb.run();
  454. File dir = folder.newFolder();
  455. Process git = runtime.exec("git clone http://127.0.0.1:33871/testproj.git", null, dir);
  456. int exitCode = git.waitFor();
  457. File testprojDir = new File(dir, "testproj");
  458. assertEquals(0, exitCode);
  459. assertTrue(FileUtil.gitDirectoriesAreEqual(getResource("/pushFailsOnUnexpectedError/state/testproj"), testprojDir.toPath()));
  460. runtime.exec("touch push.tex", null, testprojDir).waitFor();
  461. runtime.exec("git add -A", null, testprojDir).waitFor();
  462. runtime.exec("git commit -m \"push\"", null, testprojDir).waitFor();
  463. Process gitPush = runtime.exec("git push", null, testprojDir);
  464. int pushExitCode = gitPush.waitFor();
  465. wlgb.stop();
  466. assertEquals(1, pushExitCode);
  467. List<String> actual = Util.linesFromStream(gitPush.getErrorStream(), 2, "[K");
  468. assertEquals(EXPECTED_OUT_PUSH_UNEXPECTED_ERROR, actual);
  469. }
  470. private static final List<String> EXPECTED_OUT_PUSH_INVALID_EXE_FILE =
  471. Arrays.asList(
  472. "remote: error: invalid files",
  473. "remote: hint: You have 1 invalid files in your Overleaf project:",
  474. "remote: hint: file1.exe (invalid file extension)",
  475. "To http://127.0.0.1:33872/testproj.git",
  476. "! [remote rejected] master -> master (invalid files)",
  477. "error: failed to push some refs to 'http://127.0.0.1:33872/testproj.git'"
  478. );
  479. @Test
  480. public void pushSucceedsAfterRemovingInvalidFiles() throws IOException, GitAPIException, InterruptedException {
  481. MockSnapshotServer server = new MockSnapshotServer(3872, getResource("/pushSucceedsAfterRemovingInvalidFiles").toFile());
  482. server.start();
  483. server.setState(states.get("pushSucceedsAfterRemovingInvalidFiles").get("invalidState"));
  484. GitBridgeApp wlgb = new GitBridgeApp(new String[] {
  485. makeConfigFile(33872, 3872)
  486. });
  487. wlgb.run();
  488. File dir = folder.newFolder();
  489. Process git = runtime.exec("git clone http://127.0.0.1:33872/testproj.git", null, dir);
  490. int exitCode = git.waitFor();
  491. File testprojDir = new File(dir, "testproj");
  492. assertEquals(0, exitCode);
  493. // try to push invalid file; it should fail
  494. assertTrue(FileUtil.gitDirectoriesAreEqual(getResource("/pushSucceedsAfterRemovingInvalidFiles/invalidState/testproj"), testprojDir.toPath()));
  495. assertEquals(0, runtime.exec("touch file1.exe", null, testprojDir).waitFor());
  496. assertEquals(0, runtime.exec("git add -A", null, testprojDir).waitFor());
  497. assertEquals(0, runtime.exec("git commit -m \"push\"", null, testprojDir).waitFor());
  498. Process gitPush = runtime.exec("git push", null, testprojDir);
  499. int pushExitCode = gitPush.waitFor();
  500. assertEquals(1, pushExitCode);
  501. List<String> actual = Util.linesFromStream(gitPush.getErrorStream(), 0, "[K");
  502. assertEquals(EXPECTED_OUT_PUSH_INVALID_EXE_FILE, actual);
  503. // remove invalid file and push again; it should succeed this time
  504. assertEquals(0, runtime.exec("git rm file1.exe", null, testprojDir).waitFor());
  505. assertEquals(0, runtime.exec("git commit -m remove_invalid_file", null, testprojDir).waitFor());
  506. server.setState(states.get("pushSucceedsAfterRemovingInvalidFiles").get("validState"));
  507. gitPush = runtime.exec("git push", null, testprojDir);
  508. pushExitCode = gitPush.waitFor();
  509. wlgb.stop();
  510. assertEquals(0, pushExitCode);
  511. assertTrue(FileUtil.gitDirectoriesAreEqual(getResource("/pushSucceedsAfterRemovingInvalidFiles/validState/testproj"), testprojDir.toPath()));
  512. }
  513. private String makeConfigFile(int port, int apiPort) throws IOException {
  514. File wlgb = folder.newFolder();
  515. File config = folder.newFile();
  516. PrintWriter writer = new PrintWriter(config);
  517. writer.println("{\n" +
  518. "\t\"port\": " + port + ",\n" +
  519. "\t\"rootGitDirectory\": \"" + wlgb.getAbsolutePath() + "\",\n" +
  520. "\t\"apiBaseUrl\": \"http://127.0.0.1:" + apiPort + "/api/v0\",\n" +
  521. "\t\"username\": \"\",\n" +
  522. "\t\"password\": \"\",\n" +
  523. "\t\"postbackBaseUrl\": \"http://127.0.0.1:" + port + "\",\n" +
  524. "\t\"serviceName\": \"Overleaf\"\n" +
  525. "}\n");
  526. writer.close();
  527. return config.getAbsolutePath();
  528. }
  529. private Path getResource(String path) {
  530. return Paths.get("src/test/resources/uk/ac/ic/wlgitbridge/WLGitBridgeIntegrationTest" + path);
  531. }
  532. private InputStream getResourceAsStream(String path) {
  533. try {
  534. return new FileInputStream(getResource(path).toFile());
  535. } catch (FileNotFoundException e) {
  536. throw new RuntimeException(e);
  537. }
  538. }
  539. private static String withoutWhitespace(String s) {
  540. return s.replaceAll("\\s","");
  541. }
  542. }