diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 9753dd85688becca88b4b28d3b5984bec1f4c68c..5905846d7594c926b6e2a90fb6c58b69de0da753 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -30,33 +30,6 @@ docker:
         - Dockerfile-base
     - if: $COMPILE_DOCKER
 
-test_ppparis:
-  stage: test
-  image: registry.git.laquadrature.net/bastien/raaspotter/base:latest
-  tags:
-  - unprivileged
-  needs: [install]
-  script:
-  - curl --silent --location --output artifacts.zip "${CI_SERVER_PROTOCOL}://${CI_SERVER_HOST}:${CI_SERVER_PORT}/api/v4/projects/${CI_PROJECT_ID}/jobs/artifacts/${CI_COMMIT_BRANCH}/download?job=${CI_JOB_NAME}&job_token=${CI_JOB_TOKEN}" || true
-  - unzip -q artifacts.zip data/ppparis/* || true
-  - rm artifacts.zip || true
-  - source bin/activate
-  - python ./cli.py --pref ppparis
-  retry: 2
-  cache:
-    key: $CI_COMMIT_REF_SLUG
-    paths:
-    - bin/
-    - lib/
-    - pyvenv.cfg
-  artifacts:
-    paths:
-    - data/ppparis/*.txt
-    - output.log
-    expire_in: 1 hour
-  rules:
-    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $COMPILE_DOCKER == null
-
 install:
   stage: install
   image: registry.git.laquadrature.net/bastien/raaspotter/base:latest
@@ -75,7 +48,7 @@ install:
   rules:
     - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $COMPILE_DOCKER == null
 
-test_pref06:
+.default_pref:
   stage: test
   image: registry.git.laquadrature.net/bastien/raaspotter/base:latest
   tags:
@@ -83,11 +56,11 @@ test_pref06:
   needs: [install]
   script:
   - curl --silent --location --output artifacts.zip "${CI_SERVER_PROTOCOL}://${CI_SERVER_HOST}:${CI_SERVER_PORT}/api/v4/projects/${CI_PROJECT_ID}/jobs/artifacts/${CI_COMMIT_BRANCH}/download?job=${CI_JOB_NAME}&job_token=${CI_JOB_TOKEN}" || true
-  - unzip -q artifacts.zip data/pref06/* || true
+  - unzip -q artifacts.zip data/"${PREF}"/* || true
   - rm artifacts.zip || true
   - source bin/activate
   - /etc/init.d/tor start
-  - python ./cli.py --pref pref06
+  - python ./cli.py --pref "${PREF}"
   retry: 2
   cache:
     key: $CI_COMMIT_REF_SLUG
@@ -97,204 +70,53 @@ test_pref06:
     - pyvenv.cfg
   artifacts:
     paths:
-    - data/pref06/*.txt
+    - data/${PREF}/*.txt
     - output.log
     expire_in: 1 hour
   rules:
     - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $COMPILE_DOCKER == null
 
+test_ppparis:
+  variables:
+    PREF: "ppparis"
+  extends: .default_pref
+
+test_pref06:
+  variables:
+    PREF: "pref06"
+  extends: .default_pref
+
 test_pref13:
-  stage: test
-  image: registry.git.laquadrature.net/bastien/raaspotter/base:latest
-  tags:
-  - unprivileged
-  needs: [install]
-  script:
-  - curl --silent --location --output artifacts.zip "${CI_SERVER_PROTOCOL}://${CI_SERVER_HOST}:${CI_SERVER_PORT}/api/v4/projects/${CI_PROJECT_ID}/jobs/artifacts/${CI_COMMIT_BRANCH}/download?job=${CI_JOB_NAME}&job_token=${CI_JOB_TOKEN}" || true
-  - unzip -q artifacts.zip data/pref13/* || true
-  - rm artifacts.zip || true
-  - source bin/activate
-  - /etc/init.d/tor start
-  - python ./cli.py --pref pref13
-  retry: 2
-  cache:
-    key: $CI_COMMIT_REF_SLUG
-    paths:
-    - bin/
-    - lib/
-    - pyvenv.cfg
-  artifacts:
-    paths:
-    - data/pref13/*.txt
-    - output.log
-    expire_in: 1 hour
-  rules:
-    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $COMPILE_DOCKER == null
+  variables:
+    PREF: "pref13"
+  extends: .default_pref
 
 test_pref34:
-  stage: test
-  image: registry.git.laquadrature.net/bastien/raaspotter/base:latest
-  tags:
-  - unprivileged
-  needs: [install]
-  script:
-  - curl --silent --location --output artifacts.zip "${CI_SERVER_PROTOCOL}://${CI_SERVER_HOST}:${CI_SERVER_PORT}/api/v4/projects/${CI_PROJECT_ID}/jobs/artifacts/${CI_COMMIT_BRANCH}/download?job=${CI_JOB_NAME}&job_token=${CI_JOB_TOKEN}" || true
-  - unzip -q artifacts.zip data/pref34/* || true
-  - rm artifacts.zip || true
-  - source bin/activate
-  - /etc/init.d/tor start
-  - python ./cli.py --pref pref34
-  retry: 2
-  cache:
-    key: $CI_COMMIT_REF_SLUG
-    paths:
-    - bin/
-    - lib/
-    - pyvenv.cfg
-  artifacts:
-    paths:
-    - data/pref34/*.txt
-    - output.log
-    expire_in: 1 hour
-  rules:
-    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $COMPILE_DOCKER == null
+  variables:
+    PREF: "pref34"
+  extends: .default_pref
 
 test_pref35:
-  stage: test
-  image: registry.git.laquadrature.net/bastien/raaspotter/base:latest
-  tags:
-  - unprivileged
-  needs: [install]
-  script:
-  - curl --silent --location --output artifacts.zip "${CI_SERVER_PROTOCOL}://${CI_SERVER_HOST}:${CI_SERVER_PORT}/api/v4/projects/${CI_PROJECT_ID}/jobs/artifacts/${CI_COMMIT_BRANCH}/download?job=${CI_JOB_NAME}&job_token=${CI_JOB_TOKEN}" || true
-  - unzip -q artifacts.zip data/pref35/* || true
-  - rm artifacts.zip || true
-  - source bin/activate
-  - /etc/init.d/tor start
-  - python ./cli.py --pref pref35
-  retry: 2
-  cache:
-    key: $CI_COMMIT_REF_SLUG
-    paths:
-    - bin/
-    - lib/
-    - pyvenv.cfg
-  artifacts:
-    paths:
-    - data/pref35/*.txt
-    - output.log
-    expire_in: 1 hour
-  rules:
-    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $COMPILE_DOCKER == null
+  variables:
+    PREF: "pref35"
+  extends: .default_pref
 
 test_pref38:
-  stage: test
-  image: registry.git.laquadrature.net/bastien/raaspotter/base:latest
-  tags:
-  - unprivileged
-  needs: [install]
-  script:
-  - curl --silent --location --output artifacts.zip "${CI_SERVER_PROTOCOL}://${CI_SERVER_HOST}:${CI_SERVER_PORT}/api/v4/projects/${CI_PROJECT_ID}/jobs/artifacts/${CI_COMMIT_BRANCH}/download?job=${CI_JOB_NAME}&job_token=${CI_JOB_TOKEN}" || true
-  - unzip -q artifacts.zip data/pref38/* || true
-  - rm artifacts.zip || true
-  - source bin/activate
-  - /etc/init.d/tor start
-  - python ./cli.py --pref pref38
-  retry: 2
-  cache:
-    key: $CI_COMMIT_REF_SLUG
-    paths:
-    - bin/
-    - lib/
-    - pyvenv.cfg
-  artifacts:
-    paths:
-    - data/pref38/*.txt
-    - output.log
-    expire_in: 1 hour
-  rules:
-    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $COMPILE_DOCKER == null
+  variables:
+    PREF: "pref38"
+  extends: .default_pref
 
 test_pref59:
-  stage: test
-  image: registry.git.laquadrature.net/bastien/raaspotter/base:latest
-  tags:
-  - unprivileged
-  needs: [install]
-  script:
-  - curl --silent --location --output artifacts.zip "${CI_SERVER_PROTOCOL}://${CI_SERVER_HOST}:${CI_SERVER_PORT}/api/v4/projects/${CI_PROJECT_ID}/jobs/artifacts/${CI_COMMIT_BRANCH}/download?job=${CI_JOB_NAME}&job_token=${CI_JOB_TOKEN}" || true
-  - unzip -q artifacts.zip data/pref59/* || true
-  - rm artifacts.zip || true
-  - source bin/activate
-  - /etc/init.d/tor start
-  - python ./cli.py --pref pref59
-  retry: 2
-  cache:
-    key: $CI_COMMIT_REF_SLUG
-    paths:
-    - bin/
-    - lib/
-    - pyvenv.cfg
-  artifacts:
-    paths:
-    - data/pref59/*.txt
-    - output.log
-    expire_in: 1 hour
-  rules:
-    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $COMPILE_DOCKER == null
+  variables:
+    PREF: "pref59"
+  extends: .default_pref
 
 test_pref62:
-  stage: test
-  image: registry.git.laquadrature.net/bastien/raaspotter/base:latest
-  tags:
-  - unprivileged
-  needs: [install]
-  script:
-  - curl --silent --location --output artifacts.zip "${CI_SERVER_PROTOCOL}://${CI_SERVER_HOST}:${CI_SERVER_PORT}/api/v4/projects/${CI_PROJECT_ID}/jobs/artifacts/${CI_COMMIT_BRANCH}/download?job=${CI_JOB_NAME}&job_token=${CI_JOB_TOKEN}" || true
-  - unzip -q artifacts.zip data/pref62/* || true
-  - rm artifacts.zip || true
-  - source bin/activate
-  - /etc/init.d/tor start
-  - python ./cli.py --pref pref62
-  retry: 2
-  cache:
-    key: $CI_COMMIT_REF_SLUG
-    paths:
-    - bin/
-    - lib/
-    - pyvenv.cfg
-  artifacts:
-    paths:
-    - data/pref62/*.txt
-    - output.log
-    expire_in: 1 hour
-  rules:
-    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $COMPILE_DOCKER == null
+  variables:
+    PREF: "pref62"
+  extends: .default_pref
 
 test_pref69:
-  stage: test
-  image: registry.git.laquadrature.net/bastien/raaspotter/base:latest
-  tags:
-  - unprivileged
-  needs: [install]
-  script:
-  - curl --silent --location --output artifacts.zip "${CI_SERVER_PROTOCOL}://${CI_SERVER_HOST}:${CI_SERVER_PORT}/api/v4/projects/${CI_PROJECT_ID}/jobs/artifacts/${CI_COMMIT_BRANCH}/download?job=${CI_JOB_NAME}&job_token=${CI_JOB_TOKEN}" || true
-  - unzip -q artifacts.zip data/pref69/* || true
-  - rm artifacts.zip || true
-  - source bin/activate
-  - /etc/init.d/tor start
-  - python ./cli.py --pref pref69
-  retry: 2
-  cache:
-    key: $CI_COMMIT_REF_SLUG
-    paths:
-    - bin/
-    - lib/
-    - pyvenv.cfg
-  artifacts:
-    paths:
-    - data/pref69/*.txt
-    - output.log
-    expire_in: 1 hour
-  rules:
-    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $COMPILE_DOCKER == null
+  variables:
+    PREF: "pref69"
+  extends: .default_pref