diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 8fc55fa04454369a8e7c566db10d5fca5c4f6c14..f17d711abb211620beaae2a52d26e24c584eda5b 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -12,18 +12,40 @@ services:
   - redis:6
 
 variables:
+  CI_DEBUG_TRACE: "true"
   POSTGRES_DB: 'hyrax_test'
   POSTGRES_DB_TEST: 'hyrax_test'
   POSTGRES_USER: 'postgres'
   POSTGRES_PASSWORD: 'password'
   POSTGRES_HOST_AUTH_METHOD: trust
   RAILS_ENV: test
-
+  BUILD_APK_CACHE_DIR: $CI_PROJECT_DIR/.cache_build/apk
+  BUILD_RUBY_CACHE_DIR: $CI_PROJECT_DIR/.cache_build/ruby
+  TEST_APK_CACHE_DIR: $CI_PROJECT_DIR/.cache_test/apk
+  TEST_RUBY_CACHE_DIR: $CI_PROJECT_DIR/.cache_test/ruby
+  FITS_DIR: $CI_PROJECT_DIR/hyrax//fits/fits-1.5.5
+  TEST_SOLR_DOWNLOAD_DIR: $CI_PROJECT_DIR/hyrax/tmp/solr-test/download
+  TEST_SOLR_VALKYRIE_DOWNLOAD_DIR: CI_PROJECT_DIR/hyrax/tmp/solr-valkyrie-test/download
+  TEST_FCREPO_DOWNLOAD_DIR: CI_PROJECT_DIR/hyrax/tmp/fcrepo4-test-data/download
+ 
 build-job:
   stage: build
+  variables:
+    APK_PACKAGES: nodejs curl libarchive-tools build-base git jq libpq-dev sqlite-dev libxml2-dev tzdata 
+  cache:
+    key: "$CI_JOB_STAGE-$CI_COMMIT_REF_SLUG"
+    paths: 
+    - $BUILD_APK_CACHE_DIR
+    - $BUILD_RUBY_CACHE_DIR
   before_script:
-    - apk update && apk upgrade && apk add nodejs curl libarchive-tools build-base libpq-dev sqlite-dev libxml2-dev tzdata
-    - cd hyrax && bundle install --jobs 4 --retry 3
+    - mkdir -p $BUILD_APK_CACHE_DIR
+    - mkdir -p $BUILD_RUBY_CACHE_DIR
+    - apk update --cache-dir $BUILD_APK_CACHE_DIR && apk upgrade --cache-dir $BUILD_APK_CACHE_DIR && apk add --cache-dir $BUILD_APK_CACHE_DIR $APK_PACKAGES
+    - sh hyrax/deploy_info.sh  && cat ./hyrax/deploy_info.json
+    - export DOCKER_IMAGE_TAG="$(git describe --all --always --long --tags | sed -e 's|^heads/||' -e 's|/|_|g')_$(jq -r '.last_deployed' < hyrax/deploy_info.json | sed -E 's|\+00:00$|UTC|g;s|:|-|g')"
+    - echo $DOCKER_IMAGE_TAG
+    - cd hyrax && bundle config set --local path $BUILD_RUBY_CACHE_DIR && bundle install --jobs 4 --retry 3
+  
   script:
     - mkdir -p /fits/fits-1.5.5
     - curl --fail --location "https://github.com/harvard-lts/fits/releases/download/1.5.5/fits-1.5.5.zip" | bsdtar --extract --directory /fits/fits-1.5.5
@@ -32,15 +54,41 @@ build-job:
 
 test-job:
   stage: test
-  coverage: '/coverage: \d+.\d+% of statements/'
+  variables:
+    APK_PACKAGES: bash build-base curl curl-dev gcompat git imagemagick imagemagick-libs imagemagick-dev libarchive-tools libpq-dev libxml2-dev libxslt-dev nodejs openjdk11-jre-headless sqlite-dev tzdata yarn
+    coverage: '/coverage: \d+.\d+% of statements/'
+  cache:
+    key: "$CI_JOB_STAGE-$CI_COMMIT_REF_SLUG"
+    untracked: true
+    when: always
+    paths: 
+      - $TEST_APK_CACHE_DIR
+      - $TEST_RUBY_CACHE_DIR
+      - $TEST_SOLR_DOWNLOAD_DIR
+      - $TEST_SOLR_VALKYRIE_DOWNLOAD_DIR
+      - $TEST_FCREPO_DOWNLOAD_DIR
+      - $CI_PROJECT_DIR/hyrax/tmp/lexvo_2013-02-09.rdf
   before_script:
-    - apk update && apk upgrade && apk add bash build-base curl curl-dev gcompat imagemagick imagemagick-libs imagemagick-dev libarchive-tools libpq-dev libxml2-dev libxslt-dev nodejs openjdk11-jre-headless sqlite-dev tzdata yarn
-    - cd hyrax && bundle install --jobs 4 --retry 3
+    - mkdir -p $TEST_SOLR_DOWNLOAD_DIR
+    - mkdir -p $TEST_SOLR_VALKYRIE_DOWNLOAD_DIR
+    - mkdir -p $TEST_FCREPO_DOWNLOAD_DIR
+    - mkdir -p $TEST_APK_CACHE_DIR
+    - mkdir -p $TEST_RUBY_CACHE_DIR
+    - touch $CI_PROJECT_DIR/hyrax/rspec.xml
+    - apk update --cache-dir $TEST_APK_CACHE_DIR && apk upgrade --cache-dir $TEST_APK_CACHE_DIR && apk add --cache-dir $TEST_APK_CACHE_DIR $APK_PACKAGES
+    - cd hyrax && bundle config set --local path $TEST_RUBY_CACHE_DIR && bundle install --jobs 4 --retry 3 && gem install rspec_junit_formatter
     - bundle exec rake db:setup
   script:
     - export FITS_PATH=/fits/fits-1.5.5/fits.sh
-    - if test -f "lib/tasks/test_servers.rake"; then echo 'Running full tests' && bundle exec rake test:servers:start && bundle exec rake rdms:setup_hyrax && bundle exec rspec && bundle exec rake test:servers:stop; else echo "Running limited tests"; bundle exec rspec --exclude-pattern "**/features/*_spec.rb"; fi
+    - if test -f "lib/tasks/test_servers.rake"; then echo 'Running full tests' && bundle exec rake test:servers:start && bundle exec rake rdms:setup_hyrax && bundle exec rspec --format progress --format RspecJunitFormatter --out rspec.xml && bundle exec rake test:servers:stop; else echo "Running limited tests"; bundle exec rspec --exclude-pattern "**/features/*_spec.rb"; fi
 
+  artifacts:
+    when: always
+    paths:
+      - hyrax/rspec.xml
+    reports:
+      junit: hyrax/rspec.xml
+      
 deploy-job:
   stage: deploy
   script:
diff --git a/hyrax/config/fcrepo_wrapper_test.yml b/hyrax/config/fcrepo_wrapper_test.yml
index 77f79a6e8215a7ad37e1c6c8b752a1ac232a487b..e8fb7278273633fc05251cf8e31c66ce77498147 100644
--- a/hyrax/config/fcrepo_wrapper_test.yml
+++ b/hyrax/config/fcrepo_wrapper_test.yml
@@ -2,3 +2,4 @@
 port: 8986
 enable_jms: false
 fcrepo_home_dir: tmp/fcrepo4-test-data
+download_dir: tmp/fcrepo4-test-data/download
diff --git a/hyrax/config/solr_wrapper_test.yml b/hyrax/config/solr_wrapper_test.yml
index 341336efd5dd95e44e0dd82b382dd8b4e3632863..03c1bf589606f305ecaf035945f4fa94ffaa5a33 100644
--- a/hyrax/config/solr_wrapper_test.yml
+++ b/hyrax/config/solr_wrapper_test.yml
@@ -2,6 +2,7 @@
 version: 8.11.2
 port: 8985
 instance_dir: tmp/solr-test
+download_dir: tmp/solr-test/download
 solr_options: {
   force: true
 }
diff --git a/hyrax/config/solr_wrapper_valkyrie_test.yml b/hyrax/config/solr_wrapper_valkyrie_test.yml
index 226a6748d2f63bfa1e5bbe53cdb984483d54ae49..8eda57f9228d9b51da1c4ad868662b3d84afc101 100644
--- a/hyrax/config/solr_wrapper_valkyrie_test.yml
+++ b/hyrax/config/solr_wrapper_valkyrie_test.yml
@@ -1,6 +1,7 @@
 # config/solr_wrapper_valkyrie_test.yml
 port: 8987
 instance_dir: tmp/solr-valkyrie-test
+download_dir: tmp/solr-valkyrie-test/download
 collection:
     persist: false
     dir: solr/conf