diff --git a/archive_test.go b/archive_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..d0d13a39c4f3cdd20541cbde231b566c74b58cfd
--- /dev/null
+++ b/archive_test.go
@@ -0,0 +1,181 @@
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path"
+	"strings"
+	"testing"
+)
+
+func TestAllowedDownloadZip(t *testing.T) {
+	prepareDownloadDir(t)
+
+	// Prepare test server and backend
+	archiveName := "foobar.zip"
+	ts := archiveOKServer(t, archiveName)
+	defer ts.Close()
+	ws := startWorkhorseServer(ts.URL)
+	defer ws.Close()
+
+	downloadCmd := exec.Command("curl", "-J", "-O", fmt.Sprintf("%s/%s/repository/archive.zip", ws.URL, testProject))
+	downloadCmd.Dir = scratchDir
+	runOrFail(t, downloadCmd)
+
+	extractCmd := exec.Command("unzip", archiveName)
+	extractCmd.Dir = scratchDir
+	runOrFail(t, extractCmd)
+}
+
+func TestAllowedDownloadTar(t *testing.T) {
+	prepareDownloadDir(t)
+
+	// Prepare test server and backend
+	archiveName := "foobar.tar"
+	ts := archiveOKServer(t, archiveName)
+	defer ts.Close()
+	ws := startWorkhorseServer(ts.URL)
+	defer ws.Close()
+
+	downloadCmd := exec.Command("curl", "-J", "-O", fmt.Sprintf("%s/%s/repository/archive.tar", ws.URL, testProject))
+	downloadCmd.Dir = scratchDir
+	runOrFail(t, downloadCmd)
+
+	extractCmd := exec.Command("tar", "xf", archiveName)
+	extractCmd.Dir = scratchDir
+	runOrFail(t, extractCmd)
+}
+
+func TestAllowedDownloadTarGz(t *testing.T) {
+	prepareDownloadDir(t)
+
+	// Prepare test server and backend
+	archiveName := "foobar.tar.gz"
+	ts := archiveOKServer(t, archiveName)
+	defer ts.Close()
+	ws := startWorkhorseServer(ts.URL)
+	defer ws.Close()
+
+	downloadCmd := exec.Command("curl", "-J", "-O", fmt.Sprintf("%s/%s/repository/archive.tar.gz", ws.URL, testProject))
+	downloadCmd.Dir = scratchDir
+	runOrFail(t, downloadCmd)
+
+	extractCmd := exec.Command("tar", "zxf", archiveName)
+	extractCmd.Dir = scratchDir
+	runOrFail(t, extractCmd)
+}
+
+func TestAllowedDownloadTarBz2(t *testing.T) {
+	prepareDownloadDir(t)
+
+	// Prepare test server and backend
+	archiveName := "foobar.tar.bz2"
+	ts := archiveOKServer(t, archiveName)
+	defer ts.Close()
+	ws := startWorkhorseServer(ts.URL)
+	defer ws.Close()
+
+	downloadCmd := exec.Command("curl", "-J", "-O", fmt.Sprintf("%s/%s/repository/archive.tar.bz2", ws.URL, testProject))
+	downloadCmd.Dir = scratchDir
+	runOrFail(t, downloadCmd)
+
+	extractCmd := exec.Command("tar", "jxf", archiveName)
+	extractCmd.Dir = scratchDir
+	runOrFail(t, extractCmd)
+}
+
+func TestAllowedApiDownloadZip(t *testing.T) {
+	prepareDownloadDir(t)
+
+	// Prepare test server and backend
+	archiveName := "foobar.zip"
+	ts := archiveOKServer(t, archiveName)
+	defer ts.Close()
+	ws := startWorkhorseServer(ts.URL)
+	defer ws.Close()
+
+	downloadCmd := exec.Command("curl", "-J", "-O", fmt.Sprintf("%s/api/v3/projects/123/repository/archive.zip", ws.URL))
+	downloadCmd.Dir = scratchDir
+	runOrFail(t, downloadCmd)
+
+	extractCmd := exec.Command("unzip", archiveName)
+	extractCmd.Dir = scratchDir
+	runOrFail(t, extractCmd)
+}
+
+func TestAllowedApiDownloadZipWithSlash(t *testing.T) {
+	prepareDownloadDir(t)
+
+	// Prepare test server and backend
+	archiveName := "foobar.zip"
+	ts := archiveOKServer(t, archiveName)
+	defer ts.Close()
+	ws := startWorkhorseServer(ts.URL)
+	defer ws.Close()
+
+	// Use foo%2Fbar instead of a numeric ID
+	downloadCmd := exec.Command("curl", "-J", "-O", fmt.Sprintf("%s/api/v3/projects/foo%%2Fbar/repository/archive.zip", ws.URL))
+	if !strings.Contains(downloadCmd.Args[3], `projects/foo%2Fbar/repository`) {
+		t.Fatalf("Cannot find percent-2F: %v", downloadCmd.Args)
+	}
+	downloadCmd.Dir = scratchDir
+	runOrFail(t, downloadCmd)
+
+	extractCmd := exec.Command("unzip", archiveName)
+	extractCmd.Dir = scratchDir
+	runOrFail(t, extractCmd)
+}
+
+func TestDownloadCacheHit(t *testing.T) {
+	prepareDownloadDir(t)
+
+	// Prepare test server and backend
+	archiveName := "foobar.zip"
+	ts := archiveOKServer(t, archiveName)
+	defer ts.Close()
+	ws := startWorkhorseServer(ts.URL)
+	defer ws.Close()
+
+	if err := os.MkdirAll(cacheDir, 0755); err != nil {
+		t.Fatal(err)
+	}
+	cachedContent := []byte("cached")
+	if err := ioutil.WriteFile(path.Join(cacheDir, archiveName), cachedContent, 0644); err != nil {
+		t.Fatal(err)
+	}
+
+	downloadCmd := exec.Command("curl", "-J", "-O", fmt.Sprintf("%s/api/v3/projects/123/repository/archive.zip", ws.URL))
+	downloadCmd.Dir = scratchDir
+	runOrFail(t, downloadCmd)
+
+	actual, err := ioutil.ReadFile(path.Join(scratchDir, archiveName))
+	if err != nil {
+		t.Fatal(err)
+	}
+	if bytes.Compare(actual, cachedContent) != 0 {
+		t.Fatal("Unexpected file contents in download")
+	}
+}
+
+func TestDownloadCacheCreate(t *testing.T) {
+	prepareDownloadDir(t)
+
+	// Prepare test server and backend
+	archiveName := "foobar.zip"
+	ts := archiveOKServer(t, archiveName)
+	defer ts.Close()
+	ws := startWorkhorseServer(ts.URL)
+	defer ws.Close()
+
+	downloadCmd := exec.Command("curl", "-J", "-O", fmt.Sprintf("%s/api/v3/projects/123/repository/archive.zip", ws.URL))
+	downloadCmd.Dir = scratchDir
+	runOrFail(t, downloadCmd)
+
+	compareCmd := exec.Command("cmp", path.Join(cacheDir, archiveName), path.Join(scratchDir, archiveName))
+	if err := compareCmd.Run(); err != nil {
+		t.Fatalf("Comparison between downloaded file and cache item failed: %s", err)
+	}
+}
diff --git a/main_test.go b/main_test.go
index 4d567a4c9efcbd7a2388ac38c08ddc80794ad364..7047ce9c92770ea150d79812b0679e96a52661ed 100644
--- a/main_test.go
+++ b/main_test.go
@@ -159,175 +159,6 @@ func TestDeniedPush(t *testing.T) {
 	}
 }
 
-func TestAllowedDownloadZip(t *testing.T) {
-	prepareDownloadDir(t)
-
-	// Prepare test server and backend
-	archiveName := "foobar.zip"
-	ts := archiveOKServer(t, archiveName)
-	defer ts.Close()
-	ws := startWorkhorseServer(ts.URL)
-	defer ws.Close()
-
-	downloadCmd := exec.Command("curl", "-J", "-O", fmt.Sprintf("%s/%s/repository/archive.zip", ws.URL, testProject))
-	downloadCmd.Dir = scratchDir
-	runOrFail(t, downloadCmd)
-
-	extractCmd := exec.Command("unzip", archiveName)
-	extractCmd.Dir = scratchDir
-	runOrFail(t, extractCmd)
-}
-
-func TestAllowedDownloadTar(t *testing.T) {
-	prepareDownloadDir(t)
-
-	// Prepare test server and backend
-	archiveName := "foobar.tar"
-	ts := archiveOKServer(t, archiveName)
-	defer ts.Close()
-	ws := startWorkhorseServer(ts.URL)
-	defer ws.Close()
-
-	downloadCmd := exec.Command("curl", "-J", "-O", fmt.Sprintf("%s/%s/repository/archive.tar", ws.URL, testProject))
-	downloadCmd.Dir = scratchDir
-	runOrFail(t, downloadCmd)
-
-	extractCmd := exec.Command("tar", "xf", archiveName)
-	extractCmd.Dir = scratchDir
-	runOrFail(t, extractCmd)
-}
-
-func TestAllowedDownloadTarGz(t *testing.T) {
-	prepareDownloadDir(t)
-
-	// Prepare test server and backend
-	archiveName := "foobar.tar.gz"
-	ts := archiveOKServer(t, archiveName)
-	defer ts.Close()
-	ws := startWorkhorseServer(ts.URL)
-	defer ws.Close()
-
-	downloadCmd := exec.Command("curl", "-J", "-O", fmt.Sprintf("%s/%s/repository/archive.tar.gz", ws.URL, testProject))
-	downloadCmd.Dir = scratchDir
-	runOrFail(t, downloadCmd)
-
-	extractCmd := exec.Command("tar", "zxf", archiveName)
-	extractCmd.Dir = scratchDir
-	runOrFail(t, extractCmd)
-}
-
-func TestAllowedDownloadTarBz2(t *testing.T) {
-	prepareDownloadDir(t)
-
-	// Prepare test server and backend
-	archiveName := "foobar.tar.bz2"
-	ts := archiveOKServer(t, archiveName)
-	defer ts.Close()
-	ws := startWorkhorseServer(ts.URL)
-	defer ws.Close()
-
-	downloadCmd := exec.Command("curl", "-J", "-O", fmt.Sprintf("%s/%s/repository/archive.tar.bz2", ws.URL, testProject))
-	downloadCmd.Dir = scratchDir
-	runOrFail(t, downloadCmd)
-
-	extractCmd := exec.Command("tar", "jxf", archiveName)
-	extractCmd.Dir = scratchDir
-	runOrFail(t, extractCmd)
-}
-
-func TestAllowedApiDownloadZip(t *testing.T) {
-	prepareDownloadDir(t)
-
-	// Prepare test server and backend
-	archiveName := "foobar.zip"
-	ts := archiveOKServer(t, archiveName)
-	defer ts.Close()
-	ws := startWorkhorseServer(ts.URL)
-	defer ws.Close()
-
-	downloadCmd := exec.Command("curl", "-J", "-O", fmt.Sprintf("%s/api/v3/projects/123/repository/archive.zip", ws.URL))
-	downloadCmd.Dir = scratchDir
-	runOrFail(t, downloadCmd)
-
-	extractCmd := exec.Command("unzip", archiveName)
-	extractCmd.Dir = scratchDir
-	runOrFail(t, extractCmd)
-}
-
-func TestAllowedApiDownloadZipWithSlash(t *testing.T) {
-	prepareDownloadDir(t)
-
-	// Prepare test server and backend
-	archiveName := "foobar.zip"
-	ts := archiveOKServer(t, archiveName)
-	defer ts.Close()
-	ws := startWorkhorseServer(ts.URL)
-	defer ws.Close()
-
-	// Use foo%2Fbar instead of a numeric ID
-	downloadCmd := exec.Command("curl", "-J", "-O", fmt.Sprintf("%s/api/v3/projects/foo%%2Fbar/repository/archive.zip", ws.URL))
-	if !strings.Contains(downloadCmd.Args[3], `projects/foo%2Fbar/repository`) {
-		t.Fatalf("Cannot find percent-2F: %v", downloadCmd.Args)
-	}
-	downloadCmd.Dir = scratchDir
-	runOrFail(t, downloadCmd)
-
-	extractCmd := exec.Command("unzip", archiveName)
-	extractCmd.Dir = scratchDir
-	runOrFail(t, extractCmd)
-}
-
-func TestDownloadCacheHit(t *testing.T) {
-	prepareDownloadDir(t)
-
-	// Prepare test server and backend
-	archiveName := "foobar.zip"
-	ts := archiveOKServer(t, archiveName)
-	defer ts.Close()
-	ws := startWorkhorseServer(ts.URL)
-	defer ws.Close()
-
-	if err := os.MkdirAll(cacheDir, 0755); err != nil {
-		t.Fatal(err)
-	}
-	cachedContent := []byte("cached")
-	if err := ioutil.WriteFile(path.Join(cacheDir, archiveName), cachedContent, 0644); err != nil {
-		t.Fatal(err)
-	}
-
-	downloadCmd := exec.Command("curl", "-J", "-O", fmt.Sprintf("%s/api/v3/projects/123/repository/archive.zip", ws.URL))
-	downloadCmd.Dir = scratchDir
-	runOrFail(t, downloadCmd)
-
-	actual, err := ioutil.ReadFile(path.Join(scratchDir, archiveName))
-	if err != nil {
-		t.Fatal(err)
-	}
-	if bytes.Compare(actual, cachedContent) != 0 {
-		t.Fatal("Unexpected file contents in download")
-	}
-}
-
-func TestDownloadCacheCreate(t *testing.T) {
-	prepareDownloadDir(t)
-
-	// Prepare test server and backend
-	archiveName := "foobar.zip"
-	ts := archiveOKServer(t, archiveName)
-	defer ts.Close()
-	ws := startWorkhorseServer(ts.URL)
-	defer ws.Close()
-
-	downloadCmd := exec.Command("curl", "-J", "-O", fmt.Sprintf("%s/api/v3/projects/123/repository/archive.zip", ws.URL))
-	downloadCmd.Dir = scratchDir
-	runOrFail(t, downloadCmd)
-
-	compareCmd := exec.Command("cmp", path.Join(cacheDir, archiveName), path.Join(scratchDir, archiveName))
-	if err := compareCmd.Run(); err != nil {
-		t.Fatalf("Comparison between downloaded file and cache item failed: %s", err)
-	}
-}
-
 func TestRegularProjectsAPI(t *testing.T) {
 	apiResponse := "API RESPONSE"