You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

GitBlitSuite.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. /*
  2. * Copyright 2011 gitblit.com.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.gitblit.tests;
  17. import java.io.File;
  18. import java.io.FileInputStream;
  19. import java.io.FileOutputStream;
  20. import java.io.IOException;
  21. import java.lang.reflect.Field;
  22. import java.util.concurrent.Executors;
  23. import java.util.concurrent.atomic.AtomicBoolean;
  24. import java.util.concurrent.atomic.AtomicInteger;
  25. import java.util.zip.ZipEntry;
  26. import java.util.zip.ZipInputStream;
  27. import org.eclipse.jgit.api.Git;
  28. import org.eclipse.jgit.lib.Repository;
  29. import org.eclipse.jgit.lib.RepositoryCache;
  30. import org.eclipse.jgit.lib.RepositoryCache.FileKey;
  31. import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
  32. import org.eclipse.jgit.util.FS;
  33. import org.eclipse.jgit.util.FileUtils;
  34. import org.junit.AfterClass;
  35. import org.junit.BeforeClass;
  36. import org.junit.runner.RunWith;
  37. import org.junit.runners.Suite;
  38. import org.junit.runners.Suite.SuiteClasses;
  39. import com.gitblit.FileSettings;
  40. import com.gitblit.GitBlitException;
  41. import com.gitblit.GitBlitServer;
  42. import com.gitblit.manager.IRepositoryManager;
  43. import com.gitblit.models.RepositoryModel;
  44. import com.gitblit.servlet.GitblitContext;
  45. import com.gitblit.utils.JGitUtils;
  46. /**
  47. * The GitBlitSuite uses test-gitblit.properties and test-users.conf. The suite
  48. * is fairly comprehensive for all lower-level functionality. Wicket pages are
  49. * currently not unit-tested.
  50. *
  51. * This suite starts a Gitblit server instance within the same JVM instance as
  52. * the unit tests. This allows the unit tests to access the GitBlit static
  53. * singleton while also being able to communicate with the instance via tcp/ip
  54. * for testing rpc requests, federation requests, and git servlet operations.
  55. *
  56. * @author James Moger
  57. *
  58. */
  59. @RunWith(Suite.class)
  60. @SuiteClasses({ ArrayUtilsTest.class, FileUtilsTest.class, TimeUtilsTest.class,
  61. StringUtilsTest.class, Base64Test.class, JsonUtilsTest.class, ByteFormatTest.class,
  62. UserModelTest.class, UserChoiceTest.class,
  63. ObjectCacheTest.class, PermissionsTest.class, UserServiceTest.class, LdapAuthenticationTest.class,
  64. MarkdownUtilsTest.class, JGitUtilsTest.class, SyndicationUtilsTest.class,
  65. DiffUtilsTest.class, MetricUtilsTest.class, X509UtilsTest.class,
  66. GitBlitTest.class, FederationTests.class, RpcTests.class, GitServletTest.class, GitDaemonTest.class,
  67. SshDaemonTest.class, GroovyScriptTest.class, LuceneExecutorTest.class, RepositoryModelTest.class,
  68. FanoutServiceTest.class, Issue0259Test.class, Issue0271Test.class, HtpasswdAuthenticationTest.class,
  69. ModelUtilsTest.class, JnaUtilsTest.class, LdapSyncServiceTest.class, FileTicketServiceTest.class,
  70. BranchTicketServiceTest.class, RedisTicketServiceTest.class, AuthenticationManagerTest.class,
  71. SshKeysDispatcherTest.class, UITicketTest.class, PathUtilsTest.class, SshKerberosAuthenticationTest.class,
  72. GravatarTest.class, FilestoreManagerTest.class, FilestoreServletTest.class, TicketReferenceTest.class })
  73. public class GitBlitSuite {
  74. public static final File BASEFOLDER = new File("data");
  75. public static final File REPOSITORIES = new File("data/git");
  76. public static final File SETTINGS = new File("src/test/config/test-gitblit.properties");
  77. public static final File USERSCONF = new File("src/test/config/test-users.conf");
  78. private static final File AMBITION_REPO_SOURCE = new File("src/test/data/ambition.git");
  79. private static final File TICGIT_REPO_SOURCE = new File("src/test/data/ticgit.git");
  80. private static final File GITECTIVE_REPO_SOURCE = new File("src/test/data/gitective.git");
  81. private static final File HELLOWORLD_REPO_SOURCE = new File("src/test/data/hello-world.git");
  82. private static final File HELLOWORLD_REPO_PROPERTIES = new File("src/test/data/hello-world.properties");
  83. public static final FileSettings helloworldSettings = new FileSettings(HELLOWORLD_REPO_PROPERTIES.getAbsolutePath());
  84. static int port = 8280;
  85. static int gitPort = 8300;
  86. static int shutdownPort = 8281;
  87. static int sshPort = 39418;
  88. public static String url = "http://localhost:" + port;
  89. public static String gitServletUrl = "http://localhost:" + port + "/git";
  90. public static String gitDaemonUrl = "git://localhost:" + gitPort;
  91. public static String sshDaemonUrl = "ssh://admin@localhost:" + sshPort;
  92. public static String account = "admin";
  93. public static String password = "admin";
  94. private static AtomicBoolean started = new AtomicBoolean(false);
  95. public static Repository getHelloworldRepository() {
  96. return getRepository("helloworld.git");
  97. }
  98. public static Repository getTicgitRepository() {
  99. return getRepository("ticgit.git");
  100. }
  101. public static Repository getJGitRepository() {
  102. return getRepository("test/jgit.git");
  103. }
  104. public static Repository getAmbitionRepository() {
  105. return getRepository("test/ambition.git");
  106. }
  107. public static Repository getGitectiveRepository() {
  108. return getRepository("test/gitective.git");
  109. }
  110. public static Repository getTicketsTestRepository() {
  111. JGitUtils.createRepository(REPOSITORIES, "gb-tickets.git").close();
  112. return getRepository("gb-tickets.git");
  113. }
  114. private static Repository getRepository(String name) {
  115. try {
  116. File gitDir = FileKey.resolve(new File(REPOSITORIES, name), FS.DETECTED);
  117. Repository repository = new FileRepositoryBuilder().setGitDir(gitDir).build();
  118. return repository;
  119. } catch (Exception e) {
  120. e.printStackTrace();
  121. }
  122. return null;
  123. }
  124. public static boolean startGitblit() throws Exception {
  125. if (started.get()) {
  126. // already started
  127. return false;
  128. }
  129. GitServletTest.deleteWorkingFolders();
  130. // Start a Gitblit instance
  131. Executors.newSingleThreadExecutor().execute(new Runnable() {
  132. @Override
  133. public void run() {
  134. GitBlitServer.main(
  135. "--httpPort", "" + port,
  136. "--httpsPort", "0",
  137. "--shutdownPort", "" + shutdownPort,
  138. "--gitPort", "" + gitPort,
  139. "--sshPort", "" + sshPort,
  140. "--repositoriesFolder", GitBlitSuite.REPOSITORIES.getAbsolutePath(),
  141. "--userService", GitBlitSuite.USERSCONF.getAbsolutePath(),
  142. "--settings", GitBlitSuite.SETTINGS.getAbsolutePath(),
  143. "--baseFolder", "data");
  144. }
  145. });
  146. // Wait a few seconds for it to be running
  147. Thread.sleep(5000);
  148. started.set(true);
  149. return true;
  150. }
  151. public static void stopGitblit() throws Exception {
  152. // Stop Gitblit
  153. GitBlitServer.main("--stop", "--shutdownPort", "" + shutdownPort);
  154. // Wait a few seconds for it to be running
  155. Thread.sleep(5000);
  156. }
  157. public static void deleteRefChecksFolder() throws IOException {
  158. File refChecks = new File(GitBlitSuite.REPOSITORIES, "refchecks");
  159. if (refChecks.exists()) {
  160. FileUtils.delete(refChecks, FileUtils.RECURSIVE | FileUtils.RETRY);
  161. }
  162. }
  163. @BeforeClass
  164. public static void setUp() throws Exception {
  165. //"refchecks" folder is used in GitServletTest;
  166. //need be deleted before Gitblit server instance is started
  167. deleteRefChecksFolder();
  168. startGitblit();
  169. if (REPOSITORIES.exists() || REPOSITORIES.mkdirs()) {
  170. if (!HELLOWORLD_REPO_SOURCE.exists()) {
  171. unzipRepository(HELLOWORLD_REPO_SOURCE.getPath() + ".zip", HELLOWORLD_REPO_SOURCE.getParentFile());
  172. }
  173. if (!TICGIT_REPO_SOURCE.exists()) {
  174. unzipRepository(TICGIT_REPO_SOURCE.getPath() + ".zip", TICGIT_REPO_SOURCE.getParentFile());
  175. }
  176. if (!AMBITION_REPO_SOURCE.exists()) {
  177. unzipRepository(AMBITION_REPO_SOURCE.getPath() + ".zip", AMBITION_REPO_SOURCE.getParentFile());
  178. }
  179. if (!GITECTIVE_REPO_SOURCE.exists()) {
  180. unzipRepository(GITECTIVE_REPO_SOURCE.getPath() + ".zip", GITECTIVE_REPO_SOURCE.getParentFile());
  181. }
  182. cloneOrFetch("helloworld.git", HELLOWORLD_REPO_SOURCE.getAbsolutePath());
  183. cloneOrFetch("ticgit.git", TICGIT_REPO_SOURCE.getAbsolutePath());
  184. cloneOrFetch("test/jgit.git", "https://github.com/eclipse/jgit.git");
  185. cloneOrFetch("test/helloworld.git", HELLOWORLD_REPO_SOURCE.getAbsolutePath());
  186. cloneOrFetch("test/ambition.git", AMBITION_REPO_SOURCE.getAbsolutePath());
  187. cloneOrFetch("test/gitective.git", GITECTIVE_REPO_SOURCE.getAbsolutePath());
  188. showRemoteBranches("ticgit.git");
  189. automaticallyTagBranchTips("ticgit.git");
  190. showRemoteBranches("test/jgit.git");
  191. automaticallyTagBranchTips("test/jgit.git");
  192. }
  193. }
  194. @AfterClass
  195. public static void tearDown() throws Exception {
  196. stopGitblit();
  197. }
  198. private static void cloneOrFetch(String name, String fromUrl) throws Exception {
  199. System.out.print("Fetching " + name + "... ");
  200. try {
  201. JGitUtils.cloneRepository(REPOSITORIES, name, fromUrl);
  202. } catch (Throwable t) {
  203. System.out.println("Error: " + t.getMessage());
  204. }
  205. System.out.println("done.");
  206. }
  207. private static void showRemoteBranches(String repositoryName) {
  208. try {
  209. IRepositoryManager repositoryManager = GitblitContext.getManager(IRepositoryManager.class);
  210. RepositoryModel model = repositoryManager.getRepositoryModel(repositoryName);
  211. model.showRemoteBranches = true;
  212. repositoryManager.updateRepositoryModel(model.name, model, false);
  213. } catch (GitBlitException g) {
  214. g.printStackTrace();
  215. }
  216. }
  217. private static void automaticallyTagBranchTips(String repositoryName) {
  218. try {
  219. IRepositoryManager repositoryManager = GitblitContext.getManager(IRepositoryManager.class);
  220. RepositoryModel model = repositoryManager.getRepositoryModel(repositoryName);
  221. model.useIncrementalPushTags = true;
  222. repositoryManager.updateRepositoryModel(model.name, model, false);
  223. } catch (GitBlitException g) {
  224. g.printStackTrace();
  225. }
  226. }
  227. public static void close(File repository) {
  228. try {
  229. File gitDir = FileKey.resolve(repository, FS.detect());
  230. if (gitDir != null && gitDir.exists()) {
  231. close(RepositoryCache.open(FileKey.exact(gitDir, FS.detect())));
  232. }
  233. } catch (Exception e) {
  234. e.printStackTrace();
  235. }
  236. }
  237. public static void close(Git git) {
  238. close(git.getRepository());
  239. }
  240. public static void close(Repository r) {
  241. RepositoryCache.close(r);
  242. // assume 2 uses in case reflection fails
  243. int uses = 2;
  244. try {
  245. Field useCnt = Repository.class.getDeclaredField("useCnt");
  246. useCnt.setAccessible(true);
  247. uses = ((AtomicInteger) useCnt.get(r)).get();
  248. } catch (Exception e) {
  249. e.printStackTrace();
  250. }
  251. for (int i = 0; i < uses; i++) {
  252. r.close();
  253. }
  254. }
  255. private static void unzipRepository(String zippedRepo, File destDir) throws IOException {
  256. System.out.print("Unzipping " + zippedRepo + "... ");
  257. if (!destDir.exists()) {
  258. destDir.mkdir();
  259. }
  260. byte[] buffer = new byte[1024];
  261. ZipInputStream zis = new ZipInputStream(new FileInputStream(zippedRepo));
  262. ZipEntry zipEntry = zis.getNextEntry();
  263. while (zipEntry != null) {
  264. File newFile = newFile(destDir, zipEntry);
  265. if (zipEntry.isDirectory()) {
  266. newFile.mkdirs();
  267. }
  268. else {
  269. FileOutputStream fos = new FileOutputStream(newFile);
  270. int len;
  271. while ((len = zis.read(buffer)) > 0) {
  272. fos.write(buffer, 0, len);
  273. }
  274. fos.close();
  275. }
  276. zipEntry = zis.getNextEntry();
  277. }
  278. zis.closeEntry();
  279. zis.close();
  280. System.out.println("done.");
  281. }
  282. private static File newFile(File destinationDir, ZipEntry zipEntry) throws IOException {
  283. File destFile = new File(destinationDir, zipEntry.getName());
  284. String destDirPath = destinationDir.getCanonicalPath();
  285. String destFilePath = destFile.getCanonicalPath();
  286. //guards against writing files to the file system outside of the target folder
  287. //to prevent Zip Slip exploit
  288. if (!destFilePath.startsWith(destDirPath + File.separator)) {
  289. throw new IOException("Entry is outside of the target dir: " + zipEntry.getName());
  290. }
  291. return destFile;
  292. }
  293. }