WLGitBridgeIntegrationTest.java 33 KB

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