summaryrefslogtreecommitdiffstats
path: root/src/test
diff options
context:
space:
mode:
authorPaul Martin <paul@paulsputer.com>2015-10-10 12:46:51 +0100
committerPaul Martin <paul@paulsputer.com>2015-10-10 12:50:00 +0100
commitbd0e83e350fc703bcae72a28c41b09d9a9cec594 (patch)
treef9c3d5112600f89f64ded2d56472664db185750a /src/test
parentf2a9b239d2605b36401dd723ac22c195b938f8e0 (diff)
downloadgitblit-bd0e83e350fc703bcae72a28c41b09d9a9cec594.tar.gz
gitblit-bd0e83e350fc703bcae72a28c41b09d9a9cec594.zip
Git-LFS support
+ Metadata maintained in append-only JSON file providing complete audit history. + Filestore menu item + Lists filestore items + Current size and availability + Link to GitBlit Filestore help page (top right) + Hooks into existing repository permissions + Uses default repository path for out-of-box operation with Git-LFS client + accessRestrictionFilter now has access to http method and auth header + Testing for servlet and manager
Diffstat (limited to 'src/test')
-rw-r--r--src/test/java/com/gitblit/tests/FilestoreManagerTest.java547
-rw-r--r--src/test/java/com/gitblit/tests/FilestoreServletTest.java355
-rw-r--r--src/test/java/com/gitblit/tests/GitBlitSuite.java2
-rw-r--r--src/test/java/com/gitblit/tests/GitblitUnitTest.java5
4 files changed, 908 insertions, 1 deletions
diff --git a/src/test/java/com/gitblit/tests/FilestoreManagerTest.java b/src/test/java/com/gitblit/tests/FilestoreManagerTest.java
new file mode 100644
index 00000000..c76e9dd6
--- /dev/null
+++ b/src/test/java/com/gitblit/tests/FilestoreManagerTest.java
@@ -0,0 +1,547 @@
+package com.gitblit.tests;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.Date;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.commons.codec.digest.DigestUtils;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.gitblit.Constants.AccessPermission;
+import com.gitblit.Constants.AccessRestrictionType;
+import com.gitblit.Constants.AuthorizationControl;
+import com.gitblit.Keys;
+import com.gitblit.models.FilestoreModel.Status;
+import com.gitblit.models.RepositoryModel;
+import com.gitblit.models.UserModel;
+import com.gitblit.utils.FileUtils;
+
+
+/**
+ * Test of the filestore manager and confirming filesystem updated
+ *
+ * @author Paul Martin
+ *
+ */
+public class FilestoreManagerTest extends GitblitUnitTest {
+
+ private static final AtomicBoolean started = new AtomicBoolean(false);
+
+ private static final BlobInfo blob_zero = new BlobInfo(0);
+ private static final BlobInfo blob_512KB = new BlobInfo(512*FileUtils.KB);
+ private static final BlobInfo blob_6MB = new BlobInfo(6*FileUtils.MB);
+
+ private static int download_limit_default = -1;
+ private static int download_limit_test = 5*FileUtils.MB;
+
+ private static final String invalid_hash_empty = "";
+ private static final String invalid_hash_major = "INVALID_HASH";
+ private static final String invalid_hash_regex_attack = blob_512KB.hash.replace('a', '*');
+ private static final String invalid_hash_one_long = blob_512KB.hash.concat("a");
+ private static final String invalid_hash_one_short = blob_512KB.hash.substring(1);
+
+
+
+ @BeforeClass
+ public static void startGitblit() throws Exception {
+ started.set(GitBlitSuite.startGitblit());
+ }
+
+ @AfterClass
+ public static void stopGitblit() throws Exception {
+ if (started.get()) {
+ GitBlitSuite.stopGitblit();
+ }
+ }
+
+
+
+ @Test
+ public void testAdminAccess() throws Exception {
+
+ FileUtils.delete(filestore().getStorageFolder());
+ filestore().clearFilestoreCache();
+
+ RepositoryModel r = new RepositoryModel("myrepo.git", null, null, new Date());
+ ByteArrayOutputStream streamOut = new ByteArrayOutputStream();
+
+ UserModel u = new UserModel("admin");
+ u.canAdmin = true;
+
+ //No upload limit
+ settings().overrideSetting(Keys.filestore.maxUploadSize, download_limit_default);
+
+ //Invalid hash tests
+ assertEquals(Status.Error_Invalid_Oid, filestore().downloadBlob(invalid_hash_major, u, r, streamOut));
+ assertEquals(Status.Error_Invalid_Oid, filestore().downloadBlob(invalid_hash_regex_attack, u, r, streamOut));
+ assertEquals(Status.Error_Invalid_Oid, filestore().downloadBlob(invalid_hash_one_long, u, r, streamOut));
+ assertEquals(Status.Error_Invalid_Oid, filestore().downloadBlob(invalid_hash_one_short, u, r, streamOut));
+
+ // Download prior to upload
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+
+ //Bad input is rejected with no upload taking place
+ assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_empty, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_major, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_regex_attack, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_one_long, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_one_short, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+
+ assertEquals(Status.Error_Invalid_Size, filestore().uploadBlob(blob_512KB.hash, -1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+
+ assertEquals(Status.Error_Size_Mismatch, filestore().uploadBlob(blob_512KB.hash, 0, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ assertEquals(Status.Error_Size_Mismatch, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length-1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ assertEquals(Status.Error_Size_Mismatch, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length+1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+
+ assertEquals(Status.Error_Hash_Mismatch, filestore().uploadBlob(blob_zero.hash, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+
+ //Confirm no upload with bad input
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+
+ //Good input will accept the upload
+ assertEquals(Status.Available, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ streamOut.reset();
+ assertEquals(Status.Available, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+ assertArrayEquals(blob_512KB.blob, streamOut.toByteArray());
+
+ //Subsequent failed uploads do not affect file
+ assertEquals(Status.Error_Size_Mismatch, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length-1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ assertEquals(Status.Error_Size_Mismatch, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length+1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+
+ streamOut.reset();
+ assertEquals(Status.Available, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+ assertArrayEquals(blob_512KB.blob, streamOut.toByteArray());
+
+ //Zero length upload is valid
+ assertEquals(Status.Available, filestore().uploadBlob(blob_zero.hash, blob_zero.length, u, r, new ByteArrayInputStream(blob_zero.blob)));
+
+ streamOut.reset();
+ assertEquals(Status.Available, filestore().downloadBlob(blob_zero.hash, u, r, streamOut));
+ assertArrayEquals(blob_zero.blob, streamOut.toByteArray());
+
+
+ //Pre-informed upload identifies identical errors as immediate upload
+ assertEquals(Status.Upload_Pending, filestore().addObject(blob_6MB.hash, blob_6MB.length, u, r));
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_6MB.hash, u, r, streamOut));
+
+ assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_empty, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+ assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_major, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+ assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_regex_attack, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+ assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_one_long, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+ assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_one_short, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+
+ assertEquals(Status.Error_Size_Mismatch, filestore().uploadBlob(blob_6MB.hash, 0, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+ assertEquals(Status.Error_Size_Mismatch, filestore().uploadBlob(blob_6MB.hash, blob_6MB.length-1, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+ assertEquals(Status.Error_Size_Mismatch, filestore().uploadBlob(blob_6MB.hash, blob_6MB.length+1, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_6MB.hash, u, r, streamOut));
+
+ //Good input will accept the upload
+ assertEquals(Status.Available, filestore().uploadBlob(blob_6MB.hash, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+ streamOut.reset();
+ assertEquals(Status.Available, filestore().downloadBlob(blob_6MB.hash, u, r, streamOut));
+ assertArrayEquals(blob_6MB.blob, streamOut.toByteArray());
+
+ //Confirm the relevant files exist
+ assertTrue("Admin did not save zero length file!", filestore().getStoragePath(blob_zero.hash).exists());
+ assertTrue("Admin did not save 512KB file!", filestore().getStoragePath(blob_512KB.hash).exists());
+ assertTrue("Admin did not save 6MB file!", filestore().getStoragePath(blob_6MB.hash).exists());
+
+ //Clear the files and cache to test upload limit property
+ FileUtils.delete(filestore().getStorageFolder());
+ filestore().clearFilestoreCache();
+
+ settings().overrideSetting(Keys.filestore.maxUploadSize, download_limit_test);
+
+ assertEquals(Status.Available, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ streamOut.reset();
+ assertEquals(Status.Available, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+ assertArrayEquals(blob_512KB.blob, streamOut.toByteArray());
+
+ assertEquals(Status.Error_Exceeds_Size_Limit, filestore().uploadBlob(blob_6MB.hash, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_6MB.hash, u, r, streamOut));
+
+ assertTrue("Admin did not save 512KB file!", filestore().getStoragePath(blob_512KB.hash).exists());
+ assertFalse("Admin saved 6MB file despite (over filesize limit)!", filestore().getStoragePath(blob_6MB.hash).exists());
+
+ }
+
+ @Test
+ public void testAuthenticatedAccess() throws Exception {
+
+ FileUtils.delete(filestore().getStorageFolder());
+ filestore().clearFilestoreCache();
+
+ RepositoryModel r = new RepositoryModel("myrepo.git", null, null, new Date());
+ r.authorizationControl = AuthorizationControl.AUTHENTICATED;
+ r.accessRestriction = AccessRestrictionType.VIEW;
+
+ ByteArrayOutputStream streamOut = new ByteArrayOutputStream();
+
+ UserModel u = new UserModel("test");
+
+ //No upload limit
+ settings().overrideSetting(Keys.filestore.maxUploadSize, download_limit_default);
+
+ //Invalid hash tests
+ assertEquals(Status.Error_Invalid_Oid, filestore().downloadBlob(invalid_hash_major, u, r, streamOut));
+ assertEquals(Status.Error_Invalid_Oid, filestore().downloadBlob(invalid_hash_regex_attack, u, r, streamOut));
+ assertEquals(Status.Error_Invalid_Oid, filestore().downloadBlob(invalid_hash_one_long, u, r, streamOut));
+ assertEquals(Status.Error_Invalid_Oid, filestore().downloadBlob(invalid_hash_one_short, u, r, streamOut));
+
+ // Download prior to upload
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+
+ //Bad input is rejected with no upload taking place
+ assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_empty, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_major, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_regex_attack, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_one_long, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_one_short, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+
+ assertEquals(Status.Error_Invalid_Size, filestore().uploadBlob(blob_512KB.hash, -1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+
+ assertEquals(Status.Error_Size_Mismatch, filestore().uploadBlob(blob_512KB.hash, 0, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ assertEquals(Status.Error_Size_Mismatch, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length-1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ assertEquals(Status.Error_Size_Mismatch, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length+1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+
+ assertEquals(Status.Error_Hash_Mismatch, filestore().uploadBlob(blob_zero.hash, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+
+ //Confirm no upload with bad input
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+
+ //Good input will accept the upload
+ assertEquals(Status.Available, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ streamOut.reset();
+ assertEquals(Status.Available, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+ assertArrayEquals(blob_512KB.blob, streamOut.toByteArray());
+
+ //Subsequent failed uploads do not affect file
+ assertEquals(Status.Error_Size_Mismatch, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length-1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ assertEquals(Status.Error_Size_Mismatch, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length+1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+
+ streamOut.reset();
+ assertEquals(Status.Available, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+ assertArrayEquals(blob_512KB.blob, streamOut.toByteArray());
+
+ //Zero length upload is valid
+ assertEquals(Status.Available, filestore().uploadBlob(blob_zero.hash, blob_zero.length, u, r, new ByteArrayInputStream(blob_zero.blob)));
+
+ streamOut.reset();
+ assertEquals(Status.Available, filestore().downloadBlob(blob_zero.hash, u, r, streamOut));
+ assertArrayEquals(blob_zero.blob, streamOut.toByteArray());
+
+
+ //Pre-informed upload identifies identical errors as immediate upload
+ assertEquals(Status.Upload_Pending, filestore().addObject(blob_6MB.hash, blob_6MB.length, u, r));
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_6MB.hash, u, r, streamOut));
+
+ assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_empty, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+ assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_major, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+ assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_regex_attack, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+ assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_one_long, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+ assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_one_short, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+
+ assertEquals(Status.Error_Size_Mismatch, filestore().uploadBlob(blob_6MB.hash, 0, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+ assertEquals(Status.Error_Size_Mismatch, filestore().uploadBlob(blob_6MB.hash, blob_6MB.length-1, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+ assertEquals(Status.Error_Size_Mismatch, filestore().uploadBlob(blob_6MB.hash, blob_6MB.length+1, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_6MB.hash, u, r, streamOut));
+
+ //Good input will accept the upload
+ assertEquals(Status.Available, filestore().uploadBlob(blob_6MB.hash, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+ streamOut.reset();
+ assertEquals(Status.Available, filestore().downloadBlob(blob_6MB.hash, u, r, streamOut));
+ assertArrayEquals(blob_6MB.blob, streamOut.toByteArray());
+
+ //Confirm the relevant files exist
+ assertTrue("Authenticated user did not save zero length file!", filestore().getStoragePath(blob_zero.hash).exists());
+ assertTrue("Authenticated user did not save 512KB file!", filestore().getStoragePath(blob_512KB.hash).exists());
+ assertTrue("Authenticated user did not save 6MB file!", filestore().getStoragePath(blob_6MB.hash).exists());
+
+ //Clear the files and cache to test upload limit property
+ FileUtils.delete(filestore().getStorageFolder());
+ filestore().clearFilestoreCache();
+
+ settings().overrideSetting(Keys.filestore.maxUploadSize, download_limit_test);
+
+ assertEquals(Status.Available, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ streamOut.reset();
+ assertEquals(Status.Available, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+ assertArrayEquals(blob_512KB.blob, streamOut.toByteArray());
+
+ assertEquals(Status.Error_Exceeds_Size_Limit, filestore().uploadBlob(blob_6MB.hash, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_6MB.hash, u, r, streamOut));
+
+ assertTrue("Authenticated user did not save 512KB file!", filestore().getStoragePath(blob_512KB.hash).exists());
+ assertFalse("Authenticated user saved 6MB file (over filesize limit)!", filestore().getStoragePath(blob_6MB.hash).exists());
+
+ }
+
+ @Test
+ public void testAnonymousAccess() throws Exception {
+
+ FileUtils.delete(filestore().getStorageFolder());
+ filestore().clearFilestoreCache();
+
+ RepositoryModel r = new RepositoryModel("myrepo.git", null, null, new Date());
+ r.authorizationControl = AuthorizationControl.NAMED;
+ r.accessRestriction = AccessRestrictionType.CLONE;
+
+ ByteArrayOutputStream streamOut = new ByteArrayOutputStream();
+
+ UserModel u = UserModel.ANONYMOUS;
+
+ //No upload limit
+ settings().overrideSetting(Keys.filestore.maxUploadSize, download_limit_default);
+
+ //Invalid hash tests
+ assertEquals(Status.Error_Invalid_Oid, filestore().downloadBlob(invalid_hash_major, u, r, streamOut));
+ assertEquals(Status.Error_Invalid_Oid, filestore().downloadBlob(invalid_hash_regex_attack, u, r, streamOut));
+ assertEquals(Status.Error_Invalid_Oid, filestore().downloadBlob(invalid_hash_one_long, u, r, streamOut));
+ assertEquals(Status.Error_Invalid_Oid, filestore().downloadBlob(invalid_hash_one_short, u, r, streamOut));
+
+ // Download prior to upload
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+
+ //Bad input is rejected with no upload taking place
+ assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(invalid_hash_empty, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(invalid_hash_major, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(invalid_hash_regex_attack, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(invalid_hash_one_long, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(invalid_hash_one_short, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+
+ assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(blob_512KB.hash, -1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+
+ assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(blob_512KB.hash, 0, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length-1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length+1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+
+ assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(blob_zero.hash, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+
+ //Confirm no upload with bad input
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+
+ //Good input will accept the upload
+ assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+
+ //Subsequent failed uploads do not affect file
+ assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length-1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length+1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+
+ //Zero length upload is valid
+ assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(blob_zero.hash, blob_zero.length, u, r, new ByteArrayInputStream(blob_zero.blob)));
+
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_zero.hash, u, r, streamOut));
+
+
+ //Pre-informed upload identifies identical errors as immediate upload
+ assertEquals(Status.AuthenticationRequired, filestore().addObject(blob_6MB.hash, blob_6MB.length, u, r));
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_6MB.hash, u, r, streamOut));
+
+ assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(invalid_hash_empty, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+ assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(invalid_hash_major, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+ assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(invalid_hash_regex_attack, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+ assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(invalid_hash_one_long, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+ assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(invalid_hash_one_short, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+
+ assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(blob_6MB.hash, -1, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+
+ assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(blob_6MB.hash, 0, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+ assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(blob_6MB.hash, blob_6MB.length-1, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+ assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(blob_6MB.hash, blob_6MB.length+1, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_6MB.hash, u, r, streamOut));
+
+ //Good input will accept the upload
+ assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(blob_6MB.hash, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_6MB.hash, u, r, streamOut));
+
+ //Confirm the relevant files do not exist
+ assertFalse("Anonymous user saved zero length file!", filestore().getStoragePath(blob_zero.hash).exists());
+ assertFalse("Anonymous user 512KB file!", filestore().getStoragePath(blob_512KB.hash).exists());
+ assertFalse("Anonymous user 6MB file!", filestore().getStoragePath(blob_6MB.hash).exists());
+
+ //Clear the files and cache to test upload limit property
+ FileUtils.delete(filestore().getStorageFolder());
+ filestore().clearFilestoreCache();
+
+ settings().overrideSetting(Keys.filestore.maxUploadSize, download_limit_test);
+
+ assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+
+ assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(blob_6MB.hash, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_6MB.hash, u, r, streamOut));
+
+ assertFalse("Anonymous user saved 512KB file!", filestore().getStoragePath(blob_512KB.hash).exists());
+ assertFalse("Anonymous user saved 6MB file (over filesize limit)!", filestore().getStoragePath(blob_6MB.hash).exists());
+
+ }
+
+ @Test
+ public void testUnauthorizedAccess() throws Exception {
+
+ FileUtils.delete(filestore().getStorageFolder());
+ filestore().clearFilestoreCache();
+
+ RepositoryModel r = new RepositoryModel("myrepo.git", null, null, new Date());
+ r.authorizationControl = AuthorizationControl.NAMED;
+ r.accessRestriction = AccessRestrictionType.VIEW;
+
+ ByteArrayOutputStream streamOut = new ByteArrayOutputStream();
+
+ UserModel u = new UserModel("test");
+ u.setRepositoryPermission(r.name, AccessPermission.CLONE);
+
+ //No upload limit
+ settings().overrideSetting(Keys.filestore.maxUploadSize, download_limit_default);
+
+ //Invalid hash tests
+ assertEquals(Status.Error_Invalid_Oid, filestore().downloadBlob(invalid_hash_major, u, r, streamOut));
+ assertEquals(Status.Error_Invalid_Oid, filestore().downloadBlob(invalid_hash_regex_attack, u, r, streamOut));
+ assertEquals(Status.Error_Invalid_Oid, filestore().downloadBlob(invalid_hash_one_long, u, r, streamOut));
+ assertEquals(Status.Error_Invalid_Oid, filestore().downloadBlob(invalid_hash_one_short, u, r, streamOut));
+
+ // Download prior to upload
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+
+ //Bad input is rejected with no upload taking place
+ assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(invalid_hash_major, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(invalid_hash_regex_attack, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(invalid_hash_one_long, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(invalid_hash_empty, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(invalid_hash_one_short, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+
+ assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(blob_512KB.hash, -1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+
+ assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(blob_512KB.hash, 0, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length-1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length+1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+
+ assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(blob_zero.hash, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+
+ //Confirm no upload with bad input
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+
+ //Good input will accept the upload
+ assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+
+ //Subsequent failed uploads do not affect file
+ assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length-1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length+1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+
+ //Zero length upload is valid
+ assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(blob_zero.hash, blob_zero.length, u, r, new ByteArrayInputStream(blob_zero.blob)));
+
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_zero.hash, u, r, streamOut));
+
+
+ //Pre-informed upload identifies identical errors as immediate upload
+ assertEquals(Status.Error_Unauthorized, filestore().addObject(blob_6MB.hash, blob_6MB.length, u, r));
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_6MB.hash, u, r, streamOut));
+
+ assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(invalid_hash_empty, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+ assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(invalid_hash_major, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+ assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(invalid_hash_regex_attack, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+ assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(invalid_hash_one_long, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+ assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(invalid_hash_one_short, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+
+ assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(blob_6MB.hash, -1, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+
+ assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(blob_6MB.hash, 0, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+ assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(blob_6MB.hash, blob_6MB.length-1, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+ assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(blob_6MB.hash, blob_6MB.length+1, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_6MB.hash, u, r, streamOut));
+
+ //Good input will accept the upload
+ assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(blob_6MB.hash, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_6MB.hash, u, r, streamOut));
+
+ //Confirm the relevant files exist
+ assertFalse("Unauthorized user saved zero length file!", filestore().getStoragePath(blob_zero.hash).exists());
+ assertFalse("Unauthorized user saved 512KB file!", filestore().getStoragePath(blob_512KB.hash).exists());
+ assertFalse("Unauthorized user saved 6MB file!", filestore().getStoragePath(blob_6MB.hash).exists());
+
+ //Clear the files and cache to test upload limit property
+ FileUtils.delete(filestore().getStorageFolder());
+ filestore().clearFilestoreCache();
+
+ settings().overrideSetting(Keys.filestore.maxUploadSize, download_limit_test);
+
+ assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+
+ assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(blob_6MB.hash, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+ streamOut.reset();
+ assertEquals(Status.Unavailable, filestore().downloadBlob(blob_6MB.hash, u, r, streamOut));
+
+ assertFalse("Unauthorized user saved 512KB file!", filestore().getStoragePath(blob_512KB.hash).exists());
+ assertFalse("Unauthorized user saved 6MB file (over filesize limit)!", filestore().getStoragePath(blob_6MB.hash).exists());
+
+ }
+
+}
+
+/*
+ * Test helper structure to create blobs of a given size
+ */
+final class BlobInfo {
+ public byte[] blob;
+ public String hash;
+ public int length;
+
+ public BlobInfo(int nBytes) {
+ blob = new byte[nBytes];
+ new java.util.Random().nextBytes(blob);
+ hash = DigestUtils.sha256Hex(blob);
+ length = nBytes;
+ }
+} \ No newline at end of file
diff --git a/src/test/java/com/gitblit/tests/FilestoreServletTest.java b/src/test/java/com/gitblit/tests/FilestoreServletTest.java
new file mode 100644
index 00000000..4e4b056a
--- /dev/null
+++ b/src/test/java/com/gitblit/tests/FilestoreServletTest.java
@@ -0,0 +1,355 @@
+package com.gitblit.tests;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpHeaders;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.entity.ByteArrayEntity;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.gitblit.Keys;
+import com.gitblit.manager.FilestoreManager;
+import com.gitblit.models.RepositoryModel;
+import com.gitblit.models.UserModel;
+import com.gitblit.models.FilestoreModel.Status;
+import com.gitblit.servlet.FilestoreServlet;
+import com.gitblit.utils.FileUtils;
+
+public class FilestoreServletTest extends GitblitUnitTest {
+
+ private static final AtomicBoolean started = new AtomicBoolean(false);
+
+ private static final String SHA256_EG = "9a712c5d4037503a2d5ee1d07ad191eb99d051e84cbb020c171a5ae19bbe3cbd";
+
+ private static final String repoName = "helloworld.git";
+
+ private static final String repoLfs = "/r/" + repoName + "/info/lfs/objects/";
+
+ @BeforeClass
+ public static void startGitblit() throws Exception {
+ started.set(GitBlitSuite.startGitblit());
+ }
+
+ @AfterClass
+ public static void stopGitblit() throws Exception {
+ if (started.get()) {
+ GitBlitSuite.stopGitblit();
+ }
+ }
+
+
+ @Test
+ public void testRegexGroups() throws Exception {
+
+ Pattern p = Pattern.compile(FilestoreServlet.REGEX_PATH);
+
+ String basicUrl = "https://localhost:8080/r/test.git/info/lfs/objects/";
+ String batchUrl = basicUrl + "batch";
+ String oidUrl = basicUrl + SHA256_EG;
+
+ Matcher m = p.matcher(batchUrl);
+ assertTrue(m.find());
+ assertEquals("https://localhost:8080", m.group(FilestoreServlet.REGEX_GROUP_BASE_URI));
+ assertEquals("r", m.group(FilestoreServlet.REGEX_GROUP_PREFIX));
+ assertEquals("test.git", m.group(FilestoreServlet.REGEX_GROUP_REPOSITORY));
+ assertEquals("batch", m.group(FilestoreServlet.REGEX_GROUP_ENDPOINT));
+
+ m = p.matcher(oidUrl);
+ assertTrue(m.find());
+ assertEquals("https://localhost:8080", m.group(FilestoreServlet.REGEX_GROUP_BASE_URI));
+ assertEquals("r", m.group(FilestoreServlet.REGEX_GROUP_PREFIX));
+ assertEquals("test.git", m.group(FilestoreServlet.REGEX_GROUP_REPOSITORY));
+ assertEquals(SHA256_EG, m.group(FilestoreServlet.REGEX_GROUP_ENDPOINT));
+ }
+
+ @Test
+ public void testRegexGroupsNestedRepo() throws Exception {
+
+ Pattern p = Pattern.compile(FilestoreServlet.REGEX_PATH);
+
+ String basicUrl = "https://localhost:8080/r/nested/test.git/info/lfs/objects/";
+ String batchUrl = basicUrl + "batch";
+ String oidUrl = basicUrl + SHA256_EG;
+
+ Matcher m = p.matcher(batchUrl);
+ assertTrue(m.find());
+ assertEquals("https://localhost:8080", m.group(FilestoreServlet.REGEX_GROUP_BASE_URI));
+ assertEquals("r", m.group(FilestoreServlet.REGEX_GROUP_PREFIX));
+ assertEquals("nested/test.git", m.group(FilestoreServlet.REGEX_GROUP_REPOSITORY));
+ assertEquals("batch", m.group(FilestoreServlet.REGEX_GROUP_ENDPOINT));
+
+ m = p.matcher(oidUrl);
+ assertTrue(m.find());
+ assertEquals("https://localhost:8080", m.group(FilestoreServlet.REGEX_GROUP_BASE_URI));
+ assertEquals("r", m.group(FilestoreServlet.REGEX_GROUP_PREFIX));
+ assertEquals("nested/test.git", m.group(FilestoreServlet.REGEX_GROUP_REPOSITORY));
+ assertEquals(SHA256_EG, m.group(FilestoreServlet.REGEX_GROUP_ENDPOINT));
+ }
+
+ @Test
+ public void testDownload() throws Exception {
+
+ FileUtils.delete(filestore().getStorageFolder());
+ filestore().clearFilestoreCache();
+
+ RepositoryModel r = gitblit().getRepositoryModel(repoName);
+
+ UserModel u = new UserModel("admin");
+ u.canAdmin = true;
+
+ //No upload limit
+ settings().overrideSetting(Keys.filestore.maxUploadSize, FilestoreManager.UNDEFINED_SIZE);
+
+ final BlobInfo blob = new BlobInfo(512*FileUtils.KB);
+
+ //Emulate a pre-existing Git-LFS repository by using using internal pre-tested methods
+ assertEquals(Status.Available, filestore().uploadBlob(blob.hash, blob.length, u, r, new ByteArrayInputStream(blob.blob)));
+
+ final String downloadURL = GitBlitSuite.url + repoLfs + blob.hash;
+
+ HttpClient client = HttpClientBuilder.create().build();
+ HttpGet request = new HttpGet(downloadURL);
+
+ // add request header
+ request.addHeader(HttpHeaders.ACCEPT, FilestoreServlet.GIT_LFS_META_MIME);
+ HttpResponse response = client.execute(request);
+
+ assertEquals(200, response.getStatusLine().getStatusCode());
+
+ String content = IOUtils.toString(response.getEntity().getContent(), "UTF-8");
+
+ String expectedContent = String.format("{%s:%s,%s:%d,%s:{%s:{%s:%s}}}",
+ "\"oid\"", "\"" + blob.hash + "\"",
+ "\"size\"", blob.length,
+ "\"actions\"",
+ "\"download\"",
+ "\"href\"", "\"" + downloadURL + "\"");
+
+ assertEquals(expectedContent, content);
+
+
+ //Now try the binary download
+ request.removeHeaders(HttpHeaders.ACCEPT);
+ response = client.execute(request);
+
+ assertEquals(200, response.getStatusLine().getStatusCode());
+
+ byte[] dlData = IOUtils.toByteArray(response.getEntity().getContent());
+
+ assertArrayEquals(blob.blob, dlData);
+
+ }
+
+ @Test
+ public void testDownloadMultiple() throws Exception {
+
+ FileUtils.delete(filestore().getStorageFolder());
+ filestore().clearFilestoreCache();
+
+ RepositoryModel r = gitblit().getRepositoryModel(repoName);
+
+ UserModel u = new UserModel("admin");
+ u.canAdmin = true;
+
+ //No upload limit
+ settings().overrideSetting(Keys.filestore.maxUploadSize, FilestoreManager.UNDEFINED_SIZE);
+
+ final BlobInfo blob = new BlobInfo(512*FileUtils.KB);
+
+ //Emulate a pre-existing Git-LFS repository by using using internal pre-tested methods
+ assertEquals(Status.Available, filestore().uploadBlob(blob.hash, blob.length, u, r, new ByteArrayInputStream(blob.blob)));
+
+ final String batchURL = GitBlitSuite.url + repoLfs + "batch";
+ final String downloadURL = GitBlitSuite.url + repoLfs + blob.hash;
+
+ HttpClient client = HttpClientBuilder.create().build();
+ HttpPost request = new HttpPost(batchURL);
+
+ // add request header
+ request.addHeader(HttpHeaders.ACCEPT, FilestoreServlet.GIT_LFS_META_MIME);
+ request.addHeader(HttpHeaders.CONTENT_ENCODING, FilestoreServlet.GIT_LFS_META_MIME);
+
+ String content = String.format("{%s:%s,%s:[{%s:%s,%s:%d},{%s:%s,%s:%d}]}",
+ "\"operation\"", "\"download\"",
+ "\"objects\"",
+ "\"oid\"", "\"" + blob.hash + "\"",
+ "\"size\"", blob.length,
+ "\"oid\"", "\"" + SHA256_EG + "\"",
+ "\"size\"", 0);
+
+ HttpEntity entity = new ByteArrayEntity(content.getBytes("UTF-8"));
+ request.setEntity(entity);
+
+ HttpResponse response = client.execute(request);
+
+ String responseMessage = IOUtils.toString(response.getEntity().getContent(), "UTF-8");
+ assertEquals(200, response.getStatusLine().getStatusCode());
+
+ String expectedContent = String.format("{%s:[{%s:%s,%s:%d,%s:{%s:{%s:%s}}},{%s:%s,%s:%d,%s:{%s:%s,%s:%d}}]}",
+ "\"objects\"",
+ "\"oid\"", "\"" + blob.hash + "\"",
+ "\"size\"", blob.length,
+ "\"actions\"",
+ "\"download\"",
+ "\"href\"", "\"" + downloadURL + "\"",
+ "\"oid\"", "\"" + SHA256_EG + "\"",
+ "\"size\"", 0,
+ "\"error\"",
+ "\"message\"", "\"Object not available\"",
+ "\"code\"", 404
+ );
+
+ assertEquals(expectedContent, responseMessage);
+ }
+
+ @Test
+ public void testDownloadUnavailable() throws Exception {
+
+ FileUtils.delete(filestore().getStorageFolder());
+ filestore().clearFilestoreCache();
+
+ //No upload limit
+ settings().overrideSetting(Keys.filestore.maxUploadSize, FilestoreManager.UNDEFINED_SIZE);
+
+ final BlobInfo blob = new BlobInfo(512*FileUtils.KB);
+
+ final String downloadURL = GitBlitSuite.url + repoLfs + blob.hash;
+
+ HttpClient client = HttpClientBuilder.create().build();
+ HttpGet request = new HttpGet(downloadURL);
+
+ // add request header
+ request.addHeader(HttpHeaders.ACCEPT, FilestoreServlet.GIT_LFS_META_MIME);
+ HttpResponse response = client.execute(request);
+
+ assertEquals(404, response.getStatusLine().getStatusCode());
+
+ String content = IOUtils.toString(response.getEntity().getContent(), "UTF-8");
+
+ String expectedError = String.format("{%s:%s,%s:%d}",
+ "\"message\"", "\"Object not available\"",
+ "\"code\"", 404);
+
+ assertEquals(expectedError, content);
+ }
+
+ @Test
+ public void testUpload() throws Exception {
+
+ FileUtils.delete(filestore().getStorageFolder());
+ filestore().clearFilestoreCache();
+
+ RepositoryModel r = gitblit().getRepositoryModel(repoName);
+
+ UserModel u = new UserModel("admin");
+ u.canAdmin = true;
+
+ //No upload limit
+ settings().overrideSetting(Keys.filestore.maxUploadSize, FilestoreManager.UNDEFINED_SIZE);
+
+ final BlobInfo blob = new BlobInfo(512*FileUtils.KB);
+
+ final String expectedUploadURL = GitBlitSuite.url + repoLfs + blob.hash;
+ final String initialUploadURL = GitBlitSuite.url + repoLfs + "batch";
+
+ HttpClient client = HttpClientBuilder.create().build();
+ HttpPost request = new HttpPost(initialUploadURL);
+
+ // add request header
+ request.addHeader(HttpHeaders.ACCEPT, FilestoreServlet.GIT_LFS_META_MIME);
+ request.addHeader(HttpHeaders.CONTENT_ENCODING, FilestoreServlet.GIT_LFS_META_MIME);
+
+ String content = String.format("{%s:%s,%s:[{%s:%s,%s:%d}]}",
+ "\"operation\"", "\"upload\"",
+ "\"objects\"",
+ "\"oid\"", "\"" + blob.hash + "\"",
+ "\"size\"", blob.length);
+
+ HttpEntity entity = new ByteArrayEntity(content.getBytes("UTF-8"));
+ request.setEntity(entity);
+
+ HttpResponse response = client.execute(request);
+ String responseMessage = IOUtils.toString(response.getEntity().getContent(), "UTF-8");
+ assertEquals(200, response.getStatusLine().getStatusCode());
+
+ String expectedContent = String.format("{%s:[{%s:%s,%s:%d,%s:{%s:{%s:%s}}}]}",
+ "\"objects\"",
+ "\"oid\"", "\"" + blob.hash + "\"",
+ "\"size\"", blob.length,
+ "\"actions\"",
+ "\"upload\"",
+ "\"href\"", "\"" + expectedUploadURL + "\"");
+
+ assertEquals(expectedContent, responseMessage);
+
+
+ //Now try to upload the binary download
+ HttpPut putRequest = new HttpPut(expectedUploadURL);
+ putRequest.setEntity(new ByteArrayEntity(blob.blob));
+ response = client.execute(putRequest);
+
+ responseMessage = IOUtils.toString(response.getEntity().getContent(), "UTF-8");
+
+ assertEquals(200, response.getStatusLine().getStatusCode());
+
+ //Confirm behind the scenes that it is available
+ ByteArrayOutputStream savedBlob = new ByteArrayOutputStream();
+ assertEquals(Status.Available, filestore().downloadBlob(blob.hash, u, r, savedBlob));
+ assertArrayEquals(blob.blob, savedBlob.toByteArray());
+ }
+
+ @Test
+ public void testMalformedUpload() throws Exception {
+
+ FileUtils.delete(filestore().getStorageFolder());
+ filestore().clearFilestoreCache();
+
+ //No upload limit
+ settings().overrideSetting(Keys.filestore.maxUploadSize, FilestoreManager.UNDEFINED_SIZE);
+
+ final BlobInfo blob = new BlobInfo(512*FileUtils.KB);
+
+ final String initialUploadURL = GitBlitSuite.url + repoLfs + "batch";
+
+ HttpClient client = HttpClientBuilder.create().build();
+ HttpPost request = new HttpPost(initialUploadURL);
+
+ // add request header
+ request.addHeader(HttpHeaders.ACCEPT, FilestoreServlet.GIT_LFS_META_MIME);
+ request.addHeader(HttpHeaders.CONTENT_ENCODING, FilestoreServlet.GIT_LFS_META_MIME);
+
+ //Malformed JSON, comma instead of colon and unquoted strings
+ String content = String.format("{%s:%s,%s:[{%s:%s,%s,%d}]}",
+ "operation", "upload",
+ "objects",
+ "oid", blob.hash,
+ "size", blob.length);
+
+ HttpEntity entity = new ByteArrayEntity(content.getBytes("UTF-8"));
+ request.setEntity(entity);
+
+ HttpResponse response = client.execute(request);
+ String responseMessage = IOUtils.toString(response.getEntity().getContent(), "UTF-8");
+ assertEquals(400, response.getStatusLine().getStatusCode());
+
+ String expectedError = String.format("{%s:%s,%s:%d}",
+ "\"message\"", "\"Malformed Git-LFS request\"",
+ "\"code\"", 400);
+
+ assertEquals(expectedError, responseMessage);
+ }
+
+}
diff --git a/src/test/java/com/gitblit/tests/GitBlitSuite.java b/src/test/java/com/gitblit/tests/GitBlitSuite.java
index af20a487..b01c82c4 100644
--- a/src/test/java/com/gitblit/tests/GitBlitSuite.java
+++ b/src/test/java/com/gitblit/tests/GitBlitSuite.java
@@ -66,7 +66,7 @@ import com.gitblit.utils.JGitUtils;
ModelUtilsTest.class, JnaUtilsTest.class, LdapSyncServiceTest.class, FileTicketServiceTest.class,
BranchTicketServiceTest.class, RedisTicketServiceTest.class, AuthenticationManagerTest.class,
SshKeysDispatcherTest.class, UITicketTest.class, PathUtilsTest.class, SshKerberosAuthenticationTest.class,
- GravatarTest.class })
+ GravatarTest.class, FilestoreManagerTest.class, FilestoreServletTest.class })
public class GitBlitSuite {
public static final File BASEFOLDER = new File("data");
diff --git a/src/test/java/com/gitblit/tests/GitblitUnitTest.java b/src/test/java/com/gitblit/tests/GitblitUnitTest.java
index 9dceaaf4..58bc60e4 100644
--- a/src/test/java/com/gitblit/tests/GitblitUnitTest.java
+++ b/src/test/java/com/gitblit/tests/GitblitUnitTest.java
@@ -18,6 +18,7 @@ package com.gitblit.tests;
import com.gitblit.IStoredSettings;
import com.gitblit.manager.IAuthenticationManager;
import com.gitblit.manager.IFederationManager;
+import com.gitblit.manager.IFilestoreManager;
import com.gitblit.manager.IGitblit;
import com.gitblit.manager.INotificationManager;
import com.gitblit.manager.IProjectManager;
@@ -64,4 +65,8 @@ public class GitblitUnitTest extends org.junit.Assert {
public static IGitblit gitblit() {
return GitblitContext.getManager(IGitblit.class);
}
+
+ public static IFilestoreManager filestore() {
+ return GitblitContext.getManager(IFilestoreManager.class);
+ }
}