From 8849c5636b69be98f6660cd59473986b8c8a953b Mon Sep 17 00:00:00 2001
From: Valentin Rigal <rigal@teklia.com>
Date: Tue, 13 Oct 2020 14:57:38 +0000
Subject: [PATCH] Add a workers related workflow to the fixture

---
 Makefile                                      |   2 +-
 arkindex/dataimport/serializers/workers.py    |   2 +
 .../dataimport/tests/test_gitlab_provider.py  |   2 +-
 arkindex/dataimport/tests/test_imports.py     |   7 +-
 arkindex/dataimport/tests/test_providers.py   |   2 +-
 arkindex/dataimport/tests/test_repos.py       | 243 ++---
 arkindex/dataimport/tests/test_signals.py     |   4 +-
 arkindex/dataimport/tests/test_workerruns.py  |  33 +-
 arkindex/dataimport/tests/test_workers.py     |  99 ++-
 .../dataimport/tests/test_workflows_api.py    |  50 +-
 arkindex/documents/fixtures/data.json         | 840 ++++++++++--------
 .../management/commands/build_fixtures.py     |  49 +-
 .../tests/test_bulk_classification.py         |  14 +-
 .../tests/test_bulk_element_transcriptions.py |  36 +-
 .../documents/tests/test_bulk_elements.py     |  14 +-
 .../documents/tests/test_children_elements.py |  19 +-
 .../documents/tests/test_create_elements.py   |  34 +-
 .../tests/test_create_transcriptions.py       |  54 +-
 arkindex/documents/tests/test_entities_api.py |  66 +-
 .../documents/tests/test_list_elements.py     |  23 +-
 arkindex/documents/tests/test_moderation.py   |  54 +-
 .../documents/tests/test_parents_elements.py  |  21 +-
 .../documents/tests/test_transcriptions.py    |  14 +-
 arkindex/users/tests/test_gitlab_oauth.py     |   8 +-
 24 files changed, 773 insertions(+), 917 deletions(-)

diff --git a/Makefile b/Makefile
index 7793a20c1a..2845cddef8 100644
--- a/Makefile
+++ b/Makefile
@@ -32,7 +32,7 @@ test-fixtures:
 test-fixtures-run:
 	arkindex/manage.py migrate
 	arkindex/manage.py build_fixtures
-	arkindex/manage.py dumpdata --indent 4 dataimport documents images users auth > arkindex/documents/fixtures/data.json
+	arkindex/manage.py dumpdata --indent 4 dataimport documents images users auth ponos > arkindex/documents/fixtures/data.json
 
 test-fixtures-restore:
 	# This first renaming ensures that arkindex_tmp_fixtures exists; we don't want to drop arkindex_dev without a backup
diff --git a/arkindex/dataimport/serializers/workers.py b/arkindex/dataimport/serializers/workers.py
index 8cb59b5665..9598539dca 100644
--- a/arkindex/dataimport/serializers/workers.py
+++ b/arkindex/dataimport/serializers/workers.py
@@ -80,6 +80,8 @@ class RepositorySerializer(serializers.ModelSerializer):
     type = EnumField(RepositoryType)
 
     def get_git_clone_url(self, repository):
+        # This check avoid to set git_clone_url when this serializer is used to list multiple
+        # repositories because self.instance value would be a list, even if the request user is internal
         if self.context['request'].user.is_internal and isinstance(self.instance, Repository) and self.instance.enabled:
             url = urllib.parse.urlparse(self.instance.url)
             return f"https://oauth2:{repository.credentials.token}@{url.netloc}{url.path}"
diff --git a/arkindex/dataimport/tests/test_gitlab_provider.py b/arkindex/dataimport/tests/test_gitlab_provider.py
index c6f1456cc7..0ce7da9fb8 100644
--- a/arkindex/dataimport/tests/test_gitlab_provider.py
+++ b/arkindex/dataimport/tests/test_gitlab_provider.py
@@ -20,7 +20,7 @@ class TestGitLabProvider(FixtureTestCase):
     def setUpTestData(cls):
         super().setUpTestData()
         cls.creds = cls.user.credentials.get()
-        cls.repo = cls.creds.repos.get()
+        cls.repo = cls.creds.repos.get(type=RepositoryType.IIIF)
         cls.rev = cls.repo.revisions.get()
         cls.gl_patch = patch('arkindex.dataimport.providers.Gitlab')
 
diff --git a/arkindex/dataimport/tests/test_imports.py b/arkindex/dataimport/tests/test_imports.py
index 5e6520b352..a4327feeea 100644
--- a/arkindex/dataimport/tests/test_imports.py
+++ b/arkindex/dataimport/tests/test_imports.py
@@ -1,7 +1,7 @@
 from django.urls import reverse
 from rest_framework import status
 from arkindex_common.enums import DataImportMode
-from arkindex.dataimport.models import DataImport, DataFile
+from arkindex.dataimport.models import DataImport, DataFile, RepositoryType
 from arkindex.documents.models import Corpus, ElementType
 from arkindex.project.tests import FixtureAPITestCase
 from arkindex.users.models import User
@@ -30,7 +30,7 @@ class TestImports(FixtureAPITestCase):
     def setUpTestData(cls):
         super().setUpTestData()
         cls.creds = cls.user.credentials.get()
-        cls.repo = cls.creds.repos.get()
+        cls.repo = cls.creds.repos.get(type=RepositoryType.IIIF)
         cls.rev = cls.repo.revisions.get()
         cls.img_df = cls.corpus.files.create(
             name='test.jpg',
@@ -59,8 +59,7 @@ class TestImports(FixtureAPITestCase):
         """
         workflow, created = Workflow.objects.get_or_create(id=workflow_id, defaults={'recipe': RECIPE})
         if created:
-            # Remove tasks created from the recipe
-            workflow.tasks.all().delete()
+            # Creates the associated dataimport
             DataImport.objects.create(workflow=workflow, mode=DataImportMode.Workers, creator=self.user)
         return Task.objects.create(run=run, depth=depth, workflow=workflow, state=state, slug=str(uuid.uuid4()))
 
diff --git a/arkindex/dataimport/tests/test_providers.py b/arkindex/dataimport/tests/test_providers.py
index a77162ebe0..e67d56fbff 100644
--- a/arkindex/dataimport/tests/test_providers.py
+++ b/arkindex/dataimport/tests/test_providers.py
@@ -12,7 +12,7 @@ class TestProviders(FixtureAPITestCase):
     def setUpTestData(cls):
         super().setUpTestData()
         cls.creds = cls.user.credentials.get()
-        cls.repo = cls.creds.repos.get()
+        cls.repo = cls.creds.repos.get(type=RepositoryType.IIIF)
         cls.rev = cls.repo.revisions.get()
 
     def test_init(self):
diff --git a/arkindex/dataimport/tests/test_repos.py b/arkindex/dataimport/tests/test_repos.py
index 914feb0659..282d4c5511 100644
--- a/arkindex/dataimport/tests/test_repos.py
+++ b/arkindex/dataimport/tests/test_repos.py
@@ -5,8 +5,7 @@ from rest_framework.serializers import DateTimeField
 from ponos.models import Workflow, State
 from arkindex_common.enums import DataImportMode
 from arkindex.project.tests import FixtureTestCase
-from arkindex_common.ml_tool import MLToolType
-from arkindex.dataimport.models import Repository, RepositoryType, DataImport, Worker, WorkerVersion, WorkerVersionState
+from arkindex.dataimport.models import Repository, RepositoryType, DataImport, WorkerVersion, WorkerVersionState
 from arkindex.users.models import User
 from mock import patch, MagicMock
 
@@ -14,10 +13,6 @@ RECIPE = '''
 tasks:
   first:
     image: alpine
-  second:
-    parents:
-      - first
-    image: hello-world
 '''
 
 
@@ -26,11 +21,12 @@ class TestRepositories(FixtureTestCase):
     def setUp(self):
         super().setUp()
         self.creds = self.user.credentials.get()
-        self.repo = self.creds.repos.get()
-        self.rev = self.repo.revisions.get()
+        self.iiif_repo = self.creds.repos.get(type=RepositoryType.IIIF)
+        self.worker_repo = self.creds.repos.get(type=RepositoryType.Worker)
+        self.rev = self.iiif_repo.revisions.get()
         self.serialized_revision = {
             'id': str(self.rev.id),
-            'repo_id': str(self.repo.id),
+            'repo_id': str(self.iiif_repo.id),
             'author': self.rev.author,
             'commit_url': self.rev.commit_url,
             'date': DateTimeField().to_representation(value=self.rev.created),
@@ -38,22 +34,50 @@ class TestRepositories(FixtureTestCase):
             'message': self.rev.message
         }
 
+    def build_repository_response(self):
+        return [
+            {
+                'id': str(self.iiif_repo.id),
+                'type': RepositoryType.IIIF.value,
+                'corpora': [str(c.id) for c in self.iiif_repo.corpora.all()],
+                'enabled': True,
+                'git_clone_url': None,
+                'url': self.iiif_repo.url,
+                'workers': [],
+            }, {
+                'id': str(self.worker_repo.id),
+                'type': RepositoryType.Worker.value,
+                'corpora': [str(c.id) for c in self.worker_repo.corpora.all()],
+                'enabled': True,
+                'git_clone_url': None,
+                'url': self.worker_repo.url,
+                'workers': [
+                    {
+                        'id': str(w.id),
+                        'name': w.name,
+                        'type': w.type.value,
+                        'slug': w.slug
+                    } for w in self.worker_repo.workers.all()
+                ]
+            }
+        ]
+
     def test_delete_credentials_null(self):
         """
         Check deleting OAuthCredentials do not delete repositories and revisions
         """
         self.creds.delete()
         self.assertTrue(Repository.objects.filter(url='http://gitlab/repo').exists())
-        self.repo.refresh_from_db()
-        self.assertTrue(self.repo.revisions.exists())
+        self.iiif_repo.refresh_from_db()
+        self.assertTrue(self.iiif_repo.revisions.exists())
 
     def test_no_credentials_no_import(self):
         """
         Check Repository imports do not start without credentials
         """
-        self.repo.credentials = None
-        self.repo.save()
-        self.assertEqual(Workflow.objects.count(), 0)
+        self.iiif_repo.credentials = None
+        self.iiif_repo.save()
+        workflows_count = Workflow.objects.count()
 
         di = DataImport.objects.create(
             mode=DataImportMode.Repository,
@@ -68,99 +92,51 @@ class TestRepositories(FixtureTestCase):
         with self.assertRaises(ValidationError):
             di.retry()
 
-        self.assertEqual(Workflow.objects.count(), 0)
+        self.assertEqual(Workflow.objects.count(), workflows_count)
 
     def test_list_repository_requires_login(self):
         with self.assertNumQueries(0):
             response = self.client.get(reverse('api:repository-list'))
         self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
 
-    def test_list_repository_with_workers(self):
-        worker = Worker.objects.create(
-            name="my worker",
-            slug="my_worker",
-            type=MLToolType.Classifier,
-            repository=self.repo
-        )
-        self.client.force_login(self.user)
-        with self.assertNumQueries(6):
-            response = self.client.get(reverse('api:repository-list'))
-        self.assertEqual(response.status_code, status.HTTP_200_OK)
-        data = response.json()
-        self.assertEqual(len(data['results']), 1)
-        self.assertDictEqual(data['results'][0], {
-            'id': str(self.repo.id),
-            'type': RepositoryType.IIIF.value,
-            'corpora': [str(c.id) for c in self.repo.corpora.all()],
-            'enabled': True,
-            'git_clone_url': None,
-            'url': self.repo.url,
-            'workers': [{
-                'id': str(worker.id),
-                'name': worker.name,
-                'slug': worker.slug,
-                'type': worker.type.value,
-            }],
-        })
-
     def test_list_repository_external_user(self):
         self.client.force_login(self.user)
         with self.assertNumQueries(6):
             response = self.client.get(reverse('api:repository-list'))
         self.assertEqual(response.status_code, status.HTTP_200_OK)
         data = response.json()
-        self.assertEqual(len(data['results']), 1)
-        self.assertDictEqual(data['results'][0], {
-            'id': str(self.repo.id),
-            'type': RepositoryType.IIIF.value,
-            'corpora': [str(c.id) for c in self.repo.corpora.all()],
-            'enabled': True,
-            'git_clone_url': None,
-            'url': self.repo.url,
-            'workers': [],
-        })
+        self.assertEqual(len(data['results']), 2)
+        self.assertCountEqual(data['results'], self.build_repository_response())
 
     def test_list_repository_internal_user(self):
+        """
+        Multiple repository serialization should not include the git_clone_url field
+        """
         self.client.force_login(self.internal_user)
         with self.assertNumQueries(6):
             response = self.client.get(reverse('api:repository-list'))
         self.assertEqual(response.status_code, status.HTTP_200_OK)
         data = response.json()
-        self.assertEqual(len(data['results']), 1)
-        self.assertDictEqual(data['results'][0], {
-            'id': str(self.repo.id),
-            'type': RepositoryType.IIIF.value,
-            'corpora': [str(c.id) for c in self.repo.corpora.all()],
-            'enabled': True,
-            'git_clone_url': None,
-            'url': self.repo.url,
-            'workers': [],
-        })
+        self.assertEqual(len(data['results']), 2)
+        self.maxDiff = None
+        self.assertCountEqual(data['results'], self.build_repository_response())
 
     def test_list_repository_multiple_refs(self):
         """
         Listed repositories should not be duplicated
         """
-        self.repo.corpora.create()
+        self.iiif_repo.corpora.create()
         self.client.force_login(self.internal_user)
         with self.assertNumQueries(6):
             response = self.client.get(reverse('api:repository-list'))
         self.assertEqual(response.status_code, status.HTTP_200_OK)
         data = response.json()
-        self.assertEqual(len(data['results']), 1)
-        self.assertDictEqual(data['results'][0], {
-            'id': str(self.repo.id),
-            'type': RepositoryType.IIIF.value,
-            'corpora': [str(c.id) for c in self.repo.corpora.all()],
-            'enabled': True,
-            'git_clone_url': None,
-            'url': self.repo.url,
-            'workers': [],
-        })
+        self.assertEqual(len(data['results']), 2)
+        self.assertCountEqual(data['results'], self.build_repository_response())
 
     def test_repository_retrieve_requires_login(self):
         response = self.client.get(
-            reverse('api:repository-retrieve', kwargs={'pk': str(self.repo.id)})
+            reverse('api:repository-retrieve', kwargs={'pk': str(self.iiif_repo.id)})
         )
         self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
 
@@ -176,56 +152,56 @@ class TestRepositories(FixtureTestCase):
         self.client.force_login(self.user)
         self.assertFalse(self.user.is_internal)
         response = self.client.get(
-            reverse('api:repository-retrieve', kwargs={'pk': str(self.repo.id)})
+            reverse('api:repository-retrieve', kwargs={'pk': str(self.iiif_repo.id)})
         )
         self.assertEqual(response.status_code, status.HTTP_200_OK)
         data = response.json()
         self.assertDictEqual(data, {
-            'id': str(self.repo.id),
+            'id': str(self.iiif_repo.id),
             'type': RepositoryType.IIIF.value,
-            'corpora': [str(c.id) for c in self.repo.corpora.all()],
+            'corpora': [str(c.id) for c in self.iiif_repo.corpora.all()],
             'enabled': True,
             'git_clone_url': None,
-            'url': self.repo.url,
+            'url': self.iiif_repo.url,
             'workers': [],
         })
 
     def test_repository_retrieve_internal_user(self):
         self.client.force_login(self.internal_user)
         response = self.client.get(
-            reverse('api:repository-retrieve', kwargs={'pk': str(self.repo.id)})
+            reverse('api:repository-retrieve', kwargs={'pk': str(self.iiif_repo.id)})
         )
         self.assertEqual(response.status_code, status.HTTP_200_OK)
         data = response.json()
         self.assertDictEqual(data, {
-            'id': str(self.repo.id),
+            'id': str(self.iiif_repo.id),
             'type': RepositoryType.IIIF.value,
-            'corpora': [str(c.id) for c in self.repo.corpora.all()],
+            'corpora': [str(c.id) for c in self.iiif_repo.corpora.all()],
             'enabled': True,
             'git_clone_url': 'https://oauth2:oauth-token@gitlab/repo',
-            'url': self.repo.url,
+            'url': self.iiif_repo.url,
             'workers': [],
         })
 
     def test_repository_retrieve_disabled_repo(self):
-        self.repo.credentials = None
-        self.repo.save()
+        self.iiif_repo.credentials = None
+        self.iiif_repo.save()
         internal_user = User.objects.create_user('internal@test.com', internal=True)
         internal_user.verified_email = True
         internal_user.save()
         self.client.force_login(internal_user)
         self.assertFalse(self.user.is_internal)
         with self.assertNumQueries(5):
-            response = self.client.get(reverse('api:repository-retrieve', kwargs={'pk': str(self.repo.id)}))
+            response = self.client.get(reverse('api:repository-retrieve', kwargs={'pk': str(self.iiif_repo.id)}))
         self.assertEqual(response.status_code, status.HTTP_200_OK)
         data = response.json()
         self.assertDictEqual(data, {
-            'id': str(self.repo.id),
+            'id': str(self.iiif_repo.id),
             'type': RepositoryType.IIIF.value,
-            'corpora': [str(c.id) for c in self.repo.corpora.all()],
+            'corpora': [str(c.id) for c in self.iiif_repo.corpora.all()],
             'enabled': False,
             'git_clone_url': None,
-            'url': self.repo.url,
+            'url': self.iiif_repo.url,
             'workers': [],
         })
 
@@ -247,11 +223,11 @@ class TestRepositories(FixtureTestCase):
         self.client.force_login(self.user)
         right = self.corpus.corpus_right.get(user=self.user)
         self.assertTrue(right.can_write)
-        self.assertTrue(self.repo.credentials.user, self.user)
+        self.assertTrue(self.iiif_repo.credentials.user, self.user)
         for i in range(3):
             # Add corpora depending on the same repository
-            self.repo.corpora.create()
-        response = self.client.delete(reverse('api:repository-retrieve', kwargs={'pk': str(self.repo.id)}))
+            self.iiif_repo.corpora.create()
+        response = self.client.delete(reverse('api:repository-retrieve', kwargs={'pk': str(self.iiif_repo.id)}))
         self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
 
     def test_repository_delete_creator_write_access(self):
@@ -261,17 +237,17 @@ class TestRepositories(FixtureTestCase):
         self.client.force_login(self.user)
         right = self.corpus.corpus_right.get(user=self.user)
         self.assertTrue(right.can_write)
-        self.assertTrue(self.repo.credentials.user, self.user)
+        self.assertTrue(self.iiif_repo.credentials.user, self.user)
         corpora = [self.corpus]
         for i in range(3):
             # Add corpora depending on the same repository with write acces for this user
-            corpus = self.repo.corpora.create(name=str(i))
+            corpus = self.iiif_repo.corpora.create(name=str(i))
             corpus.corpus_right.create(user=self.user, can_write=True)
             corpora.append(corpus)
-        response = self.client.delete(reverse('api:repository-retrieve', kwargs={'pk': str(self.repo.id)}))
+        response = self.client.delete(reverse('api:repository-retrieve', kwargs={'pk': str(self.iiif_repo.id)}))
         self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
         with self.assertRaises(Repository.DoesNotExist):
-            self.repo.refresh_from_db()
+            self.iiif_repo.refresh_from_db()
         for corpus in corpora:
             corpus.refresh_from_db()
             self.assertIsNone(corpus.repository)
@@ -300,70 +276,39 @@ class TestRepositories(FixtureTestCase):
         self.assertDictEqual(data, self.serialized_revision)
 
     def test_revision_state(self):
-        # No version on the revision --> Revision : Created
-        self.assertEqual(self.rev.state, WorkerVersionState.Created)
+        revision = self.worker_repo.revisions.create()
 
-        worker_1 = Worker.objects.create(
-            repository=self.repo,
-            name='Worker 1',
-            slug='worker_1',
-            type=MLToolType.Classifier
-        )
-        worker_2 = Worker.objects.create(
-            repository=self.repo,
-            name='Worker 2',
-            slug='worker_2',
-            type=MLToolType.Classifier
-        )
-        version_1 = WorkerVersion.objects.create(
-            worker=worker_1,
-            revision=self.rev,
-            configuration={"test": "test1"}
-        )
-        version_2 = WorkerVersion.objects.create(
-            worker=worker_2,
-            revision=self.rev,
-            configuration={"test": "test1"}
-        )
+        # No version on the revision --> Revision : Created
+        self.assertEqual(revision.state, WorkerVersionState.Created)
 
-        workflow = Workflow.objects.create(recipe=RECIPE)
-        workflow.start()
-        task_1, task_2 = workflow.tasks.order_by('slug')
-        artifact_1 = task_1.artifacts.create(
-            path='path/to/file.tar.zst',
-            size=100,
-            content_type='application/x-tar+zstd',
+        WorkerVersion.objects.filter(worker__repository=self.worker_repo).update(
+            revision=revision,
+            state=WorkerVersionState.Created
         )
-        artifact_2 = task_2.artifacts.create(
-            path='path/to/file.tar.zst',
-            size=100,
-            content_type='application/x-tar+zstd',
-        )
-
+        versions = list(revision.versions.all())
         # Version 1 : Created | Version 2 : Created --> Revision : Created
-        self.assertEqual(self.rev.state, WorkerVersionState.Created)
+        self.assertEqual(WorkerVersion.objects.filter(worker__repository=self.worker_repo).first().state, WorkerVersionState.Created)
+        self.assertEqual(revision.state, WorkerVersionState.Created)
 
-        version_1.state = WorkerVersionState.Error
-        version_1.save()
+        versions[0].state = WorkerVersionState.Error
+        versions[0].save()
         # Version 1 : Error | Version 2 : Created --> Revision : Error
-        self.assertEqual(self.rev.state, WorkerVersionState.Error)
+        self.assertEqual(revision.state, WorkerVersionState.Error)
 
-        version_1.state = WorkerVersionState.Processing
-        version_1.save()
+        versions[0].state = WorkerVersionState.Processing
+        versions[0].save()
         # Version 1 : Processing | Version 2 : Created --> Revision : Processing
-        self.assertEqual(self.rev.state, WorkerVersionState.Processing)
+        self.assertEqual(revision.state, WorkerVersionState.Processing)
 
-        version_1.state = WorkerVersionState.Available
-        version_1.docker_image = artifact_1
-        version_1.save()
+        versions[0].state = WorkerVersionState.Available
+        versions[0].save()
         # Version 1 : Available | Version 2 : Created --> Revision : Created
-        self.assertEqual(self.rev.state, WorkerVersionState.Created)
+        self.assertEqual(revision.state, WorkerVersionState.Created)
 
-        version_2.state = WorkerVersionState.Available
-        version_2.docker_image = artifact_2
-        version_2.save()
+        versions[1].state = WorkerVersionState.Available
+        versions[1].save()
         # Version 1 : Available | Version 2 : Available --> Revision : Available
-        self.assertEqual(self.rev.state, WorkerVersionState.Available)
+        self.assertEqual(revision.state, WorkerVersionState.Available)
 
     @patch('arkindex.users.models.OAuthCredentials.git_provider_class')
     def test_list_repositories(self, git_provider_mock):
@@ -442,7 +387,7 @@ class TestRepositories(FixtureTestCase):
         """
         self.client.force_login(self.user)
         git_provider_mock().get_or_create_revision.return_value = self.rev, None
-        git_provider_mock().create_repo.return_value = self.repo
+        git_provider_mock().create_repo.return_value = self.iiif_repo
         with self.assertNumQueries(11):
             response = self.client.post(reverse('api:available-repositories', kwargs={'pk': self.creds.id}), {'id': 1111})
         self.assertEqual(response.status_code, status.HTTP_201_CREATED)
diff --git a/arkindex/dataimport/tests/test_signals.py b/arkindex/dataimport/tests/test_signals.py
index 231300c1d8..783bc27d88 100644
--- a/arkindex/dataimport/tests/test_signals.py
+++ b/arkindex/dataimport/tests/test_signals.py
@@ -1,6 +1,6 @@
 from arkindex_common.ml_tool import MLToolType
 from arkindex_common.enums import DataImportMode
-from arkindex.dataimport.models import Worker, WorkerVersion, WorkerRun
+from arkindex.dataimport.models import Worker, WorkerVersion, WorkerRun, RepositoryType
 from arkindex.dataimport.signals import _list_ancestors
 from arkindex.project.tests import FixtureAPITestCase
 from rest_framework.exceptions import ValidationError
@@ -15,7 +15,7 @@ class TestSignals(FixtureAPITestCase):
     def setUpTestData(cls):
         super().setUpTestData()
         cls.creds = cls.user.credentials.get()
-        cls.repo = cls.creds.repos.get()
+        cls.repo = cls.creds.repos.get(type=RepositoryType.IIIF)
         cls.rev_1 = cls.repo.revisions.get()
         cls.rev_2 = cls.repo.revisions.create(
             hash='2',
diff --git a/arkindex/dataimport/tests/test_workerruns.py b/arkindex/dataimport/tests/test_workerruns.py
index 85cfa2a519..347e0eb84c 100644
--- a/arkindex/dataimport/tests/test_workerruns.py
+++ b/arkindex/dataimport/tests/test_workerruns.py
@@ -1,9 +1,8 @@
 from unittest.mock import patch
 from django.urls import reverse
 from rest_framework import status
-from arkindex_common.ml_tool import MLToolType
 from arkindex_common.enums import DataImportMode
-from arkindex.dataimport.models import Worker, WorkerVersion, WorkerRun
+from arkindex.dataimport.models import WorkerVersion, WorkerRun
 from ponos.models import Workflow
 from arkindex.project.tests import FixtureAPITestCase
 import uuid
@@ -27,27 +26,11 @@ class TestWorkerRuns(FixtureAPITestCase):
     @classmethod
     def setUpTestData(cls):
         super().setUpTestData()
-        cls.creds = cls.user.credentials.get()
-        cls.repo = cls.creds.repos.get()
-        cls.rev = cls.repo.revisions.get()
-
-        cls.worker_1 = Worker.objects.create(
-            repository=cls.repo,
-            name='Worker 1',
-            slug='worker_1',
-            type=MLToolType.Classifier
-        )
-        cls.version_1 = WorkerVersion.objects.create(
-            worker=cls.worker_1,
-            revision=cls.rev,
-            configuration={"test": "test1"}
-        )
-
         cls.dataimport_1 = cls.corpus.imports.create(creator=cls.user, mode=DataImportMode.Workers)
-        cls.run_1 = cls.dataimport_1.worker_runs.create(
-            version=cls.version_1,
-            parents=[],
-        )
+        cls.version_1 = WorkerVersion.objects.get(worker__slug='reco')
+        cls.worker_1 = cls.version_1.worker
+        cls.repo = cls.worker_1.repository
+        cls.run_1 = cls.dataimport_1.worker_runs.create(version=cls.version_1, parents=[])
         cls.dataimport_2 = cls.corpus.imports.create(creator=cls.user, mode=DataImportMode.Workers)
 
     def test_runs_list_requires_login(self):
@@ -394,7 +377,7 @@ class TestWorkerRuns(FixtureAPITestCase):
     @patch('arkindex.dataimport.models.WorkerVersion.docker_image', ArtifactMock(artifact_id))
     def test_build_task_recipe_no_parent(self):
         self.assertDictEqual(self.run_1.build_task_recipe('import', '/data/import/elements.json'), {
-            'image': f'gitlab/repo/worker_1:{str(self.version_1.id)}',
+            'image': f'my_repo.fake/workers/worker/reco:{str(self.version_1.id)}',
             'command': None,
             'artifact': str(self.artifact_id),
             'parents': ['import'],
@@ -419,9 +402,9 @@ class TestWorkerRuns(FixtureAPITestCase):
         )
 
         self.assertDictEqual(run_2.build_task_recipe('import', '/data/import/elements.json'), {
-            'image': f'gitlab/repo/worker_1:{str(version_2.id)}',
+            'image': f'my_repo.fake/workers/worker/reco:{str(version_2.id)}',
             'command': None,
             'artifact': str(self.artifact_id),
-            'parents': [f'worker_1_{str(self.version_1.id)[0:6]}'],
+            'parents': [f'reco_{str(self.version_1.id)[0:6]}'],
             'env': {'TASK_ELEMENTS': '/data/import/elements.json', 'WORKER_VERSION_ID': str(version_2.id)},
         })
diff --git a/arkindex/dataimport/tests/test_workers.py b/arkindex/dataimport/tests/test_workers.py
index 9ec307e250..f0101cc058 100644
--- a/arkindex/dataimport/tests/test_workers.py
+++ b/arkindex/dataimport/tests/test_workers.py
@@ -25,15 +25,11 @@ class TestWorkersWorkerVersions(FixtureAPITestCase):
     def setUpTestData(cls):
         super().setUpTestData()
         cls.creds = cls.user.credentials.get()
-        cls.repo = cls.creds.repos.get()
+        cls.repo = cls.creds.repos.get(type=RepositoryType.Worker)
         cls.rev = cls.repo.revisions.get()
 
-        cls.worker_1 = Worker.objects.create(
-            repository=cls.repo,
-            name='Worker 1',
-            slug='worker_1',
-            type=MLToolType.Classifier
-        )
+        cls.worker_1 = Worker.objects.get(slug='reco')
+        cls.worker_2 = Worker.objects.get(slug='dla')
         cls.rev2 = Revision.objects.create(
             hash='1234',
             message='commit message',
@@ -42,11 +38,7 @@ class TestWorkersWorkerVersions(FixtureAPITestCase):
         )
 
     def setUp(self):
-        self.version_1 = WorkerVersion.objects.create(
-            worker=self.worker_1,
-            revision=self.rev,
-            configuration={"test": "test1"}
-        )
+        self.version_1 = WorkerVersion.objects.get(worker=self.worker_1)
 
     # Tests on get_query_set for WorkerList
     def test_workers_list_requires_login(self):
@@ -58,12 +50,20 @@ class TestWorkersWorkerVersions(FixtureAPITestCase):
         response = self.client.get(reverse('api:repository-workers', kwargs={'pk': str(self.repo.id)}))
         self.assertEqual(response.status_code, status.HTTP_200_OK)
         data = response.json()
-        self.assertEqual(len(data), 1)
-        worker = data[0]
-        self.assertEqual(worker['id'], str(self.worker_1.id))
-        self.assertEqual(worker['name'], 'Worker 1')
-        self.assertEqual(worker['slug'], 'worker_1')
-        self.assertEqual(worker['type'], MLToolType.Classifier.value)
+        self.assertEqual(len(data), 2)
+        self.assertCountEqual(data, [
+            {
+                'id': str(self.worker_1.id),
+                'name': 'Recognizer',
+                'slug': 'reco',
+                'type': 'recognizer'
+            }, {
+                'id': str(self.worker_2.id),
+                'name': 'Document layout analyser',
+                'slug': 'dla',
+                'type': 'dla'
+            }
+        ])
 
     def test_workers_list_filter_repository(self):
         self.client.force_login(self.user)
@@ -139,14 +139,14 @@ class TestWorkersWorkerVersions(FixtureAPITestCase):
         # A worker named Worker 1 already exists with the same slug on this repo
         response = self.client.post(
             reverse('api:repository-workers', kwargs={'pk': str(self.repo.id)}),
-            data={'name': 'Worker Test', 'slug': 'worker_1', 'type': 'classifier'}
+            data={'name': 'Worker Test', 'slug': 'reco', 'type': 'classifier'}
         )
         self.assertEqual(response.status_code, status.HTTP_200_OK)
         data = response.json()
         self.assertEqual(data['id'], str(self.worker_1.id))
-        self.assertEqual(data['name'], 'Worker 1')
-        self.assertEqual(data['slug'], 'worker_1')
-        self.assertEqual(data['type'], MLToolType.Classifier.value)
+        self.assertEqual(data['name'], 'Recognizer')
+        self.assertEqual(data['slug'], 'reco')
+        self.assertEqual(data['type'], MLToolType.Recognizer.value)
 
     def test_workers_post_empty(self):
         self.client.force_login(self.user)
@@ -173,7 +173,7 @@ class TestWorkersWorkerVersions(FixtureAPITestCase):
         self.assertEqual(len(data), 1)
         version = data[0]
         self.assertEqual(version['id'], str(self.version_1.id))
-        self.assertEqual(version['configuration'], {"test": "test1"})
+        self.assertEqual(version['configuration'], {"test": 42})
         self.assertEqual(version['revision']['id'], str(self.rev.id))
 
     def test_versions_list_filter_worker(self):
@@ -255,9 +255,9 @@ class TestWorkersWorkerVersions(FixtureAPITestCase):
         self.assertEqual(response.status_code, status.HTTP_200_OK)
         data = response.json()
         self.assertEqual(data['id'], str(self.version_1.id))
-        self.assertEqual(data['configuration'], {"test": "test1"})
+        self.assertEqual(data['configuration'], {"test": 42})
         self.assertEqual(data['revision']['id'], str(self.rev.id))
-        self.assertEqual(data['state'], 'created')
+        self.assertEqual(data['state'], 'available')
 
     def test_versions_post_empty(self):
         self.client.force_login(self.user)
@@ -290,13 +290,14 @@ class TestWorkersWorkerVersions(FixtureAPITestCase):
         self.assertEqual(revision['id'], str(self.rev.id))
         worker = data.pop('worker')
         self.assertEqual(worker['id'], str(self.worker_1.id))
+        self.maxDiff = None
         self.assertDictEqual(data, {
             'id': str(self.version_1.id),
-            'configuration': {"test": "test1"},
-            'docker_image': None,
+            'configuration': {"test": 42},
+            'docker_image': str(self.version_1.docker_image.id),
             'docker_image_iid': None,
-            'docker_image_name': f'gitlab/repo/worker_1:{self.version_1.id}',
-            'state': 'created',
+            'docker_image_name': f'my_repo.fake/workers/worker/reco:{self.version_1.id}',
+            'state': 'available',
         })
 
     def test_update_version_requires_login(self):
@@ -322,37 +323,37 @@ class TestWorkersWorkerVersions(FixtureAPITestCase):
         )
         self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
 
-    def test_update_version(self):
-        self.assertEqual(self.version_1.docker_image, None)
-
-        workflow = Workflow.objects.create(recipe=RECIPE)
-        workflow.start()
-        task = workflow.tasks.get(slug='first')
-        artifact = task.artifacts.create(
-            path='path/to/file.json',
-            size=100,
-            content_type='application/json',
-        )
+    def test_update_worker_version(self):
+        """
+        Update worker version artifact, configuration and state
+        """
+        docker_image = self.version_1.docker_image
+        self.version_1.state = WorkerVersionState.Created
+        self.version_1.docker_image = None
+        self.version_1.save()
 
         self.client.force_login(self.user)
         response = self.client.patch(
             reverse('api:version-retrieve', kwargs={'pk': str(self.version_1.id)}),
             data={
                 'configuration': {"test": "test2"},
-                'docker_image': str(artifact.id),
+                'docker_image': str(docker_image.id),
                 'state': 'error'
             }, format='json'
         )
         self.assertEqual(response.status_code, status.HTTP_200_OK)
         data = response.json()
         self.assertEqual(data['id'], str(self.version_1.id))
+        self.version_1.refresh_from_db()
         self.assertEqual(data['configuration'], {"test": "test2"})
-        self.assertEqual(data['docker_image'], str(artifact.id))
+        self.assertEqual(data['docker_image'], str(docker_image.id))
         self.assertIsNone(data['docker_image_iid'])
         self.assertEqual(data['state'], 'error')
 
     def test_update_version_valid(self):
-        self.assertEqual(self.version_1.docker_image, None)
+        self.version_1.state = WorkerVersionState.Created
+        self.version_1.docker_image = None
+        self.version_1.save()
 
         workflow = Workflow.objects.create(recipe=RECIPE)
         workflow.start()
@@ -382,7 +383,9 @@ class TestWorkersWorkerVersions(FixtureAPITestCase):
         self.assertEqual(data['state'], 'available')
 
     def test_update_version_available_requires_docker_image(self):
-        self.assertEqual(self.version_1.docker_image, None)
+        self.version_1.state = WorkerVersionState.Created
+        self.version_1.docker_image = None
+        self.version_1.save()
 
         self.client.force_login(self.user)
         response = self.client.patch(
@@ -449,7 +452,7 @@ class TestWorkersWorkerVersions(FixtureAPITestCase):
         })
 
     def test_property_docker_image_name(self):
-        self.assertEqual(self.version_1.docker_image_name, f'gitlab/repo/worker_1:{self.version_1.id}')
+        self.assertEqual(self.version_1.docker_image_name, f'my_repo.fake/workers/worker/reco:{self.version_1.id}')
 
     def test_property_docker_image_name_explicit(self):
         version_2 = WorkerVersion.objects.create(
@@ -460,11 +463,11 @@ class TestWorkersWorkerVersions(FixtureAPITestCase):
         )
         self.assertEqual(
             version_2.docker_image_name,
-            'gitlab/repo/worker_1:12341234-1234-1234-1234-123412341234'
+            'my_repo.fake/workers/worker/reco:12341234-1234-1234-1234-123412341234'
         )
 
     def test_property_slug(self):
-        self.assertEqual(self.version_1.slug, f'worker_1_{str(self.version_1.id)[0:6]}')
+        self.assertEqual(self.version_1.slug, f'reco_{str(self.version_1.id)[0:6]}')
 
     def test_property_slug_explicit(self):
         version_2 = WorkerVersion.objects.create(
@@ -473,7 +476,7 @@ class TestWorkersWorkerVersions(FixtureAPITestCase):
             revision=self.rev2,
             configuration={"test": "test1"}
         )
-        self.assertEqual(version_2.slug, 'worker_1_012345')
+        self.assertEqual(version_2.slug, 'reco_012345')
 
     def test_property_docker_command_empty(self):
         self.assertEqual(self.version_1.docker_command, None)
diff --git a/arkindex/dataimport/tests/test_workflows_api.py b/arkindex/dataimport/tests/test_workflows_api.py
index 5266901032..21c864446c 100644
--- a/arkindex/dataimport/tests/test_workflows_api.py
+++ b/arkindex/dataimport/tests/test_workflows_api.py
@@ -1,10 +1,9 @@
 from django.test import override_settings
 from rest_framework.reverse import reverse
 from rest_framework import status
-from arkindex_common.ml_tool import MLToolType
 from arkindex_common.enums import DataImportMode
 from ponos.models import State, Workflow
-from arkindex.dataimport.models import DataImport, Worker, WorkerVersion
+from arkindex.dataimport.models import DataImport, WorkerVersion, RepositoryType
 from arkindex.documents.models import Element, Corpus
 from arkindex.project.tests import FixtureAPITestCase
 import yaml
@@ -34,29 +33,17 @@ class TestWorkflows(FixtureAPITestCase):
 
         # Workers DataImportMode
         cls.creds = cls.user.credentials.get()
-        cls.repo = cls.creds.repos.get()
+        cls.repo = cls.creds.repos.get(type=RepositoryType.Worker)
         cls.rev_1 = cls.repo.revisions.get()
         cls.rev_2 = cls.repo.revisions.create(
             hash='2',
             message='commit message',
             author='bob',
         )
-        cls.worker_1 = Worker.objects.create(
-            repository=cls.repo,
-            name='Worker 1',
-            slug='worker_1',
-            type=MLToolType.Classifier
-        )
-        cls.version_1 = WorkerVersion.objects.create(
-            worker=cls.worker_1,
-            revision=cls.rev_1,
-            configuration={"test": "test1"}
-        )
-        cls.version_2 = WorkerVersion.objects.create(
-            worker=cls.worker_1,
-            revision=cls.rev_2,
-            configuration={"test": "test2"}
-        )
+        cls.version_1 = WorkerVersion.objects.get(worker__slug='reco')
+        cls.worker_1 = cls.version_1.worker
+        cls.version_2 = WorkerVersion.objects.get(worker__slug='dla')
+        cls.worker_2 = cls.version_2.worker
 
     @override_settings(
         ARKINDEX_TASKS_IMAGE='tasks:latest',
@@ -448,16 +435,6 @@ class TestWorkflows(FixtureAPITestCase):
 
         workflow_tmp = Workflow.objects.create(recipe=RECIPE)
         workflow_tmp.start()
-        task_tmp = workflow_tmp.tasks.get(slug='first')
-        artifact = task_tmp.artifacts.create(
-            path='path/to/file.json',
-            size=100,
-            content_type='application/json',
-        )
-        self.version_1.docker_image = artifact
-        self.version_1.save()
-        self.version_2.docker_image = artifact
-        self.version_2.save()
 
         self.assertIsNone(dataimport_2.workflow)
 
@@ -470,6 +447,7 @@ class TestWorkflows(FixtureAPITestCase):
         dataimport_2.refresh_from_db()
         self.assertEqual(dataimport_2.state, State.Unscheduled)
         self.assertIsNotNone(dataimport_2.workflow)
+        self.maxDiff = None
         self.assertDictEqual(yaml.safe_load(dataimport_2.workflow.recipe)['tasks'], {
             'import':
                 {
@@ -477,20 +455,20 @@ class TestWorkflows(FixtureAPITestCase):
                                f'{dataimport_2.id} --chunks-number 1',
                     'image': 'registry.gitlab.com/arkindex/tasks'
                 },
-            f'worker_1_{str(self.version_1.id)[0:6]}':
+            f'reco_{str(self.version_1.id)[0:6]}':
                 {
                     'command': None,
-                    'image': f'gitlab/repo/worker_1:{self.version_1.id}',
-                    'artifact': str(artifact.id),
+                    'image': f'my_repo.fake/workers/worker/reco:{self.version_1.id}',
+                    'artifact': str(self.version_1.docker_image.id),
                     'parents': ['import'],
                     'env': {'TASK_ELEMENTS': '/data/import/elements.json', 'WORKER_VERSION_ID': str(self.version_1.id)}
                 },
-            f'worker_1_{str(self.version_2.id)[0:6]}':
+            f'dla_{str(self.version_2.id)[0:6]}':
                 {
                     'command': None,
-                    'image': f'gitlab/repo/worker_1:{self.version_2.id}',
-                    'artifact': str(artifact.id),
-                    'parents': [f'worker_1_{str(self.version_1.id)[0:6]}'],
+                    'image': f'my_repo.fake/workers/worker/dla:{self.version_2.id}',
+                    'artifact': str(self.version_1.docker_image.id),
+                    'parents': [f'reco_{str(self.version_1.id)[0:6]}'],
                     'env': {'TASK_ELEMENTS': '/data/import/elements.json', 'WORKER_VERSION_ID': str(self.version_2.id)}
                 }
         })
diff --git a/arkindex/documents/fixtures/data.json b/arkindex/documents/fixtures/data.json
index 60ce2a6e0f..0cdc384ccf 100644
--- a/arkindex/documents/fixtures/data.json
+++ b/arkindex/documents/fixtures/data.json
@@ -1,44 +1,115 @@
 [
 {
     "model": "dataimport.repository",
-    "pk": "71ea33be-c05f-4813-9222-0d66e4342e71",
+    "pk": "d0cd8a85-8f30-43e1-ba19-7bd0dacb2041",
     "fields": {
         "url": "http://gitlab/repo",
         "type": "iiif",
         "hook_token": "hook-token",
-        "credentials": "fdd4c059-6d10-4aaa-8308-a0aa4bf20284",
+        "credentials": "d21e40e2-32d2-4903-ac4a-6672dc6c14ba",
+        "provider_name": "GitLabProvider"
+    }
+},
+{
+    "model": "dataimport.repository",
+    "pk": "f020dbad-f6ba-4d95-9bba-35dc80272943",
+    "fields": {
+        "url": "http://my_repo.fake/workers/worker",
+        "type": "worker",
+        "hook_token": "worker-hook-token",
+        "credentials": "d21e40e2-32d2-4903-ac4a-6672dc6c14ba",
         "provider_name": "GitLabProvider"
     }
 },
 {
     "model": "dataimport.revision",
-    "pk": "0ab63e11-590a-49b9-8e62-4c867ab68e02",
+    "pk": "3ddfb063-eff0-4a9a-8b0f-000c0eca0f7a",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "repo": "71ea33be-c05f-4813-9222-0d66e4342e71",
+        "repo": "d0cd8a85-8f30-43e1-ba19-7bd0dacb2041",
         "hash": "42",
         "message": "a",
         "author": "me"
     }
 },
+{
+    "model": "dataimport.revision",
+    "pk": "796847cd-9463-4496-a102-c1a5f825e50d",
+    "fields": {
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "repo": "f020dbad-f6ba-4d95-9bba-35dc80272943",
+        "hash": "1337",
+        "message": "My w0rk3r",
+        "author": "Test user"
+    }
+},
+{
+    "model": "dataimport.worker",
+    "pk": "29a773f3-d140-48e3-b1e4-29325f9dbc6f",
+    "fields": {
+        "name": "Recognizer",
+        "slug": "reco",
+        "type": "recognizer",
+        "repository": "f020dbad-f6ba-4d95-9bba-35dc80272943"
+    }
+},
+{
+    "model": "dataimport.worker",
+    "pk": "cf4243ca-5f42-4dbd-a2fe-14a8e75a33d8",
+    "fields": {
+        "name": "Document layout analyser",
+        "slug": "dla",
+        "type": "dla",
+        "repository": "f020dbad-f6ba-4d95-9bba-35dc80272943"
+    }
+},
+{
+    "model": "dataimport.workerversion",
+    "pk": "8d2ca1e7-f4f9-4403-8569-20e9712a897a",
+    "fields": {
+        "worker": "29a773f3-d140-48e3-b1e4-29325f9dbc6f",
+        "revision": "796847cd-9463-4496-a102-c1a5f825e50d",
+        "configuration": {
+            "test": 42
+        },
+        "state": "available",
+        "docker_image": "71a4b60b-a2f2-4503-8f5d-9d3c38f66626",
+        "docker_image_iid": null
+    }
+},
+{
+    "model": "dataimport.workerversion",
+    "pk": "afa4a177-b8d2-4bcf-aaa7-b00196807e1d",
+    "fields": {
+        "worker": "cf4243ca-5f42-4dbd-a2fe-14a8e75a33d8",
+        "revision": "796847cd-9463-4496-a102-c1a5f825e50d",
+        "configuration": {
+            "test": 42
+        },
+        "state": "available",
+        "docker_image": "71a4b60b-a2f2-4503-8f5d-9d3c38f66626",
+        "docker_image_iid": null
+    }
+},
 {
     "model": "documents.corpus",
-    "pk": "2aeff5c5-69c0-4017-9104-636572f95b6f",
+    "pk": "1f7e82ec-4094-4397-b729-ec424ea7a37f",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
         "name": "Unit Tests",
         "description": "",
-        "repository": "71ea33be-c05f-4813-9222-0d66e4342e71",
+        "repository": "d0cd8a85-8f30-43e1-ba19-7bd0dacb2041",
         "public": true
     }
 },
 {
     "model": "documents.elementtype",
-    "pk": "04497bf1-b027-4ff4-b986-02cb530fd7b2",
+    "pk": "33d93a96-58a9-4a7c-be54-12d4691f4e81",
     "fields": {
-        "corpus": "2aeff5c5-69c0-4017-9104-636572f95b6f",
+        "corpus": "1f7e82ec-4094-4397-b729-ec424ea7a37f",
         "slug": "text_line",
         "display_name": "Line",
         "folder": false,
@@ -47,359 +118,359 @@
 },
 {
     "model": "documents.elementtype",
-    "pk": "390071fb-febb-4982-807f-cabe1e803015",
+    "pk": "3bd6b808-4ced-41f5-8ae0-bf00804fcbaa",
     "fields": {
-        "corpus": "2aeff5c5-69c0-4017-9104-636572f95b6f",
-        "slug": "page",
-        "display_name": "Page",
-        "folder": false,
+        "corpus": "1f7e82ec-4094-4397-b729-ec424ea7a37f",
+        "slug": "volume",
+        "display_name": "Volume",
+        "folder": true,
         "allowed_transcription": null
     }
 },
 {
     "model": "documents.elementtype",
-    "pk": "5379fa38-d26e-4545-bbde-860b0ad5ad1b",
+    "pk": "a8c815f0-258f-4025-8f9b-f3bd6a87904c",
     "fields": {
-        "corpus": "2aeff5c5-69c0-4017-9104-636572f95b6f",
-        "slug": "act",
-        "display_name": "Act",
+        "corpus": "1f7e82ec-4094-4397-b729-ec424ea7a37f",
+        "slug": "surface",
+        "display_name": "Surface",
         "folder": false,
         "allowed_transcription": null
     }
 },
 {
     "model": "documents.elementtype",
-    "pk": "8ddf6773-dd69-42b2-8566-5d6cdd9b2358",
+    "pk": "aad1941d-d7dd-485f-8cf3-90487ac522c8",
     "fields": {
-        "corpus": "2aeff5c5-69c0-4017-9104-636572f95b6f",
-        "slug": "volume",
-        "display_name": "Volume",
-        "folder": true,
+        "corpus": "1f7e82ec-4094-4397-b729-ec424ea7a37f",
+        "slug": "page",
+        "display_name": "Page",
+        "folder": false,
         "allowed_transcription": null
     }
 },
 {
     "model": "documents.elementtype",
-    "pk": "c5d42d12-22d1-4f73-92a1-aa080ebee4cc",
+    "pk": "bff45072-bc1b-408d-bd1f-b3ffd22d8796",
     "fields": {
-        "corpus": "2aeff5c5-69c0-4017-9104-636572f95b6f",
-        "slug": "surface",
-        "display_name": "Surface",
+        "corpus": "1f7e82ec-4094-4397-b729-ec424ea7a37f",
+        "slug": "act",
+        "display_name": "Act",
         "folder": false,
         "allowed_transcription": null
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "184acdab-53dc-4b26-8aca-431e69031132",
+    "pk": "0355c4b6-bb16-474e-9b7b-bb86077339f3",
     "fields": {
-        "element": "a239c221-e169-4c28-a201-eadbb954121e",
-        "path": "[\"65069fcc-75df-443f-8dc2-4c8334f488b0\"]",
+        "element": "f3981e96-ed95-43a0-b1ea-fd288c55f5b3",
+        "path": "[\"3c4bce04-3ae8-4f17-86b0-46bc25408b8f\", \"ccc2cfdb-2de5-4e42-8a1a-fc5e1041b21d\"]",
         "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "24ea5001-5357-482e-883f-65b159ade0b6",
+    "pk": "0406c678-c1b1-41b2-a4bd-d85e83ccd230",
     "fields": {
-        "element": "80519bbf-cd39-4142-887c-8066bbb764af",
-        "path": "[\"0e2d02fa-b565-4336-8131-0f8a7e5f29aa\", \"c7cdbe39-71f4-4278-98a2-f39afb1c5595\"]",
-        "ordering": 0
+        "element": "ccc2cfdb-2de5-4e42-8a1a-fc5e1041b21d",
+        "path": "[\"3c4bce04-3ae8-4f17-86b0-46bc25408b8f\"]",
+        "ordering": 2
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "29a651d1-ab51-4391-983a-091df8d314b9",
+    "pk": "0f73c6dc-07b3-494a-b2fd-692c9a19ce5a",
     "fields": {
-        "element": "4c511df6-2791-4b9e-bcf9-eabbcdba3e39",
-        "path": "[\"65069fcc-75df-443f-8dc2-4c8334f488b0\"]",
-        "ordering": 1
+        "element": "9621c876-e7da-4d43-a5a7-82470dead663",
+        "path": "[\"3c4bce04-3ae8-4f17-86b0-46bc25408b8f\"]",
+        "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "2f6644f4-e441-4103-b923-d8b0ae40b600",
+    "pk": "208dd6c4-5510-4ceb-b8b4-fef27680df72",
     "fields": {
-        "element": "239b6dfe-dcff-42a0-b90f-60bcab6dbd20",
-        "path": "[\"0e2d02fa-b565-4336-8131-0f8a7e5f29aa\", \"f61f9197-1012-412e-8649-7fb1caac7f4d\"]",
-        "ordering": 0
+        "element": "cb69d995-2ce2-4404-a567-5598cf9dd231",
+        "path": "[\"3c4bce04-3ae8-4f17-86b0-46bc25408b8f\"]",
+        "ordering": 1
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "43bf2565-714b-4868-82c6-3752e2edb61c",
+    "pk": "269ebcc7-7b11-43c9-a6cd-94d1ee99b03a",
     "fields": {
-        "element": "bc88e446-5145-4d77-a1f4-4c4936df28f2",
-        "path": "[\"0e2d02fa-b565-4336-8131-0f8a7e5f29aa\", \"c7cdbe39-71f4-4278-98a2-f39afb1c5595\"]",
-        "ordering": 1
+        "element": "dbfa2c38-8664-447a-bb09-215cc86c6ab4",
+        "path": "[\"209e1e3b-5808-43bf-99b7-801959d6c807\"]",
+        "ordering": 2
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "469b4efa-3b20-4b7e-950f-035ef208b9ca",
+    "pk": "287575b8-9b19-49bd-adab-a241385191f4",
     "fields": {
-        "element": "c7cdbe39-71f4-4278-98a2-f39afb1c5595",
-        "path": "[\"0e2d02fa-b565-4336-8131-0f8a7e5f29aa\"]",
-        "ordering": 1
+        "element": "f5535f84-2ca7-4853-9ab6-44606a8dc462",
+        "path": "[\"3c4bce04-3ae8-4f17-86b0-46bc25408b8f\", \"9621c876-e7da-4d43-a5a7-82470dead663\"]",
+        "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "4c292f04-abed-4141-989e-2a262907ae9d",
+    "pk": "36cc34f3-8d0b-43cb-9040-7169471a03d4",
     "fields": {
-        "element": "d06ada28-259e-4994-9ca2-75b4af5a2882",
-        "path": "[\"0e2d02fa-b565-4336-8131-0f8a7e5f29aa\"]",
-        "ordering": 3
+        "element": "564aa56f-b257-445c-9930-4b6110628c09",
+        "path": "[\"3c4bce04-3ae8-4f17-86b0-46bc25408b8f\"]",
+        "ordering": 2
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "5b0423e0-1a67-4b1f-9073-cea0c6810d95",
+    "pk": "38df3e8b-d824-4862-b7b5-580065b2011b",
     "fields": {
-        "element": "925d8acd-88a1-434e-91d2-fbb59a830b50",
-        "path": "[\"0e2d02fa-b565-4336-8131-0f8a7e5f29aa\"]",
-        "ordering": 0
+        "element": "c0ec4456-f6a2-4253-a876-6eba4f96f863",
+        "path": "[\"3c4bce04-3ae8-4f17-86b0-46bc25408b8f\"]",
+        "ordering": 1
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "5d0a6638-c04f-40c2-96cb-d39cc1dd0421",
+    "pk": "3a6d0696-1ca2-4f83-a6dc-25a859482ebc",
     "fields": {
-        "element": "ed5a9ff4-46c2-4caa-8f85-a5bcdca18874",
-        "path": "[\"0e2d02fa-b565-4336-8131-0f8a7e5f29aa\", \"4396166b-2c68-4938-81bb-1d4e86b4b6e7\"]",
+        "element": "8f92f79c-471a-4280-9530-66ec406ab8b2",
+        "path": "[\"3c4bce04-3ae8-4f17-86b0-46bc25408b8f\"]",
         "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "650d9dc0-7e0c-4f61-a248-b73e32b07102",
+    "pk": "582355b4-4352-4277-b6dd-62c6a8dfbf88",
     "fields": {
-        "element": "094936fd-546d-426b-86e6-b11fae5cc5ee",
-        "path": "[\"0e2d02fa-b565-4336-8131-0f8a7e5f29aa\", \"3a784a2e-c07e-42c0-a79c-53e338e68345\"]",
+        "element": "d7b6b144-88cb-4c47-a380-a84339773dda",
+        "path": "[\"3c4bce04-3ae8-4f17-86b0-46bc25408b8f\", \"cb69d995-2ce2-4404-a567-5598cf9dd231\"]",
         "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "7520e39c-e5ce-437f-b341-d4a63212d73b",
+    "pk": "7abb9de4-a62f-49e4-979f-8975fe2e1111",
     "fields": {
-        "element": "3a784a2e-c07e-42c0-a79c-53e338e68345",
-        "path": "[\"0e2d02fa-b565-4336-8131-0f8a7e5f29aa\"]",
-        "ordering": 4
+        "element": "02d0fa30-2a2d-4972-a069-626c629357a4",
+        "path": "[\"3c4bce04-3ae8-4f17-86b0-46bc25408b8f\", \"d19ded5f-c50c-4cc6-a0cf-4463e2f2df68\"]",
+        "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "76e22b0c-4a75-4ea8-9915-185e78b8ffe1",
+    "pk": "a30e4bb0-b337-4718-a46b-53fc390393d0",
     "fields": {
-        "element": "f61f9197-1012-412e-8649-7fb1caac7f4d",
-        "path": "[\"0e2d02fa-b565-4336-8131-0f8a7e5f29aa\"]",
-        "ordering": 2
+        "element": "7c022411-eb2c-4f06-9387-5d8418a0bf33",
+        "path": "[\"3c4bce04-3ae8-4f17-86b0-46bc25408b8f\"]",
+        "ordering": 3
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "8f3ced3f-d30a-40d0-9096-068d3a33dd28",
+    "pk": "a47f8cec-6c57-4d9d-a7f8-0ab9ab56ab44",
     "fields": {
-        "element": "0124d2f5-047f-4537-b0ea-cf641cffffb1",
-        "path": "[\"0e2d02fa-b565-4336-8131-0f8a7e5f29aa\", \"d06ada28-259e-4994-9ca2-75b4af5a2882\"]",
+        "element": "b09ebead-3440-4040-8b82-5dc2bae4d2d9",
+        "path": "[\"3c4bce04-3ae8-4f17-86b0-46bc25408b8f\", \"8f92f79c-471a-4280-9530-66ec406ab8b2\"]",
         "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "963e241b-be33-45d0-b19a-901a67df00fb",
+    "pk": "b1b9f9f3-f543-4c57-aa49-a0aa716f1b71",
     "fields": {
-        "element": "5131c496-2487-4640-a972-f1071dfd4328",
-        "path": "[\"0e2d02fa-b565-4336-8131-0f8a7e5f29aa\", \"925d8acd-88a1-434e-91d2-fbb59a830b50\"]",
+        "element": "7e4d2f71-f52a-44a6-8cb5-f209a0b82408",
+        "path": "[\"209e1e3b-5808-43bf-99b7-801959d6c807\"]",
         "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "c710c283-f76e-4a5c-82a9-9c9c91d20dc9",
+    "pk": "bc93dbca-6436-4601-9ecd-0ab08972b309",
     "fields": {
-        "element": "079ac524-4c94-45dc-92fe-74e77723914b",
-        "path": "[\"0e2d02fa-b565-4336-8131-0f8a7e5f29aa\"]",
-        "ordering": 2
+        "element": "51585cf0-35b6-4b13-a445-37bed0aae13b",
+        "path": "[\"3c4bce04-3ae8-4f17-86b0-46bc25408b8f\", \"7c022411-eb2c-4f06-9387-5d8418a0bf33\"]",
+        "ordering": 0
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "ca1d8541-59b9-445f-a0bc-c84db6fdc4af",
+    "pk": "d47680ce-4ab8-4eb4-8cbe-cf06373ed654",
     "fields": {
-        "element": "337803ea-3774-4f50-947b-a8e52c52309d",
-        "path": "[\"65069fcc-75df-443f-8dc2-4c8334f488b0\"]",
-        "ordering": 2
+        "element": "d19ded5f-c50c-4cc6-a0cf-4463e2f2df68",
+        "path": "[\"3c4bce04-3ae8-4f17-86b0-46bc25408b8f\"]",
+        "ordering": 4
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "cf970778-0ca2-417c-b4e5-05bcf696b96a",
+    "pk": "f593ed74-c825-44fa-a7da-a0d9776f2e0b",
     "fields": {
-        "element": "913eca56-5a1f-4006-af8b-100a44a5e1a9",
-        "path": "[\"0e2d02fa-b565-4336-8131-0f8a7e5f29aa\"]",
+        "element": "56a2302d-e027-4724-85be-c4113ff2a243",
+        "path": "[\"3c4bce04-3ae8-4f17-86b0-46bc25408b8f\", \"cb69d995-2ce2-4404-a567-5598cf9dd231\"]",
         "ordering": 1
     }
 },
 {
     "model": "documents.elementpath",
-    "pk": "f19395e9-5c44-4b74-b580-4f354f15da9d",
+    "pk": "fc3dfb9d-1763-4892-95a9-1c8adeb8f41c",
     "fields": {
-        "element": "4396166b-2c68-4938-81bb-1d4e86b4b6e7",
-        "path": "[\"0e2d02fa-b565-4336-8131-0f8a7e5f29aa\"]",
-        "ordering": 0
+        "element": "4e9de67b-6e4f-46b7-936e-34ed9692900b",
+        "path": "[\"209e1e3b-5808-43bf-99b7-801959d6c807\"]",
+        "ordering": 1
     }
 },
 {
     "model": "documents.element",
-    "pk": "0124d2f5-047f-4537-b0ea-cf641cffffb1",
+    "pk": "02d0fa30-2a2d-4972-a069-626c629357a4",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "2aeff5c5-69c0-4017-9104-636572f95b6f",
-        "type": "c5d42d12-22d1-4f73-92a1-aa080ebee4cc",
-        "name": "Surface E",
-        "zone": "ab1ba0c5-0238-4587-9154-3344b1e30a85",
+        "corpus": "1f7e82ec-4094-4397-b729-ec424ea7a37f",
+        "type": "a8c815f0-258f-4025-8f9b-f3bd6a87904c",
+        "name": "Surface F",
+        "zone": "d2e7ee12-14fa-46c8-a360-f5b31939052a",
         "source": null,
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "079ac524-4c94-45dc-92fe-74e77723914b",
+    "pk": "209e1e3b-5808-43bf-99b7-801959d6c807",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "2aeff5c5-69c0-4017-9104-636572f95b6f",
-        "type": "390071fb-febb-4982-807f-cabe1e803015",
-        "name": "Volume 1, page 2r",
-        "zone": "49adab61-dd91-493b-98d0-8e66761e6b44",
+        "corpus": "1f7e82ec-4094-4397-b729-ec424ea7a37f",
+        "type": "3bd6b808-4ced-41f5-8ae0-bf00804fcbaa",
+        "name": "Volume 2",
+        "zone": null,
         "source": null,
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "094936fd-546d-426b-86e6-b11fae5cc5ee",
+    "pk": "3c4bce04-3ae8-4f17-86b0-46bc25408b8f",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "2aeff5c5-69c0-4017-9104-636572f95b6f",
-        "type": "c5d42d12-22d1-4f73-92a1-aa080ebee4cc",
-        "name": "Surface F",
-        "zone": "ecdd78a6-c197-41fe-8a1d-857e57f31526",
+        "corpus": "1f7e82ec-4094-4397-b729-ec424ea7a37f",
+        "type": "3bd6b808-4ced-41f5-8ae0-bf00804fcbaa",
+        "name": "Volume 1",
+        "zone": null,
         "source": null,
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "0e2d02fa-b565-4336-8131-0f8a7e5f29aa",
+    "pk": "4e9de67b-6e4f-46b7-936e-34ed9692900b",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "2aeff5c5-69c0-4017-9104-636572f95b6f",
-        "type": "8ddf6773-dd69-42b2-8566-5d6cdd9b2358",
-        "name": "Volume 1",
-        "zone": null,
+        "corpus": "1f7e82ec-4094-4397-b729-ec424ea7a37f",
+        "type": "aad1941d-d7dd-485f-8cf3-90487ac522c8",
+        "name": "Volume 2, page 1v",
+        "zone": "e67eba1f-4993-492e-9ca0-67451ceb094c",
         "source": null,
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "239b6dfe-dcff-42a0-b90f-60bcab6dbd20",
+    "pk": "51585cf0-35b6-4b13-a445-37bed0aae13b",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "2aeff5c5-69c0-4017-9104-636572f95b6f",
-        "type": "c5d42d12-22d1-4f73-92a1-aa080ebee4cc",
-        "name": "Surface D",
-        "zone": "da3f96a9-ad6d-476a-9c0c-7a08457e9ca5",
+        "corpus": "1f7e82ec-4094-4397-b729-ec424ea7a37f",
+        "type": "a8c815f0-258f-4025-8f9b-f3bd6a87904c",
+        "name": "Surface E",
+        "zone": "f3b62073-8fe4-46c9-b7bf-012c3014359b",
         "source": null,
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "337803ea-3774-4f50-947b-a8e52c52309d",
+    "pk": "564aa56f-b257-445c-9930-4b6110628c09",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "2aeff5c5-69c0-4017-9104-636572f95b6f",
-        "type": "390071fb-febb-4982-807f-cabe1e803015",
-        "name": "Volume 2, page 2r",
-        "zone": "06f88cf0-c12e-4f33-a7ba-e3adb15b6211",
+        "corpus": "1f7e82ec-4094-4397-b729-ec424ea7a37f",
+        "type": "aad1941d-d7dd-485f-8cf3-90487ac522c8",
+        "name": "Volume 1, page 2r",
+        "zone": "20f0abb7-3aac-460b-b1af-b75ed7dab550",
         "source": null,
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "3a784a2e-c07e-42c0-a79c-53e338e68345",
+    "pk": "56a2302d-e027-4724-85be-c4113ff2a243",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "2aeff5c5-69c0-4017-9104-636572f95b6f",
-        "type": "5379fa38-d26e-4545-bbde-860b0ad5ad1b",
-        "name": "Act 5",
-        "zone": null,
+        "corpus": "1f7e82ec-4094-4397-b729-ec424ea7a37f",
+        "type": "a8c815f0-258f-4025-8f9b-f3bd6a87904c",
+        "name": "Surface C",
+        "zone": "dda78215-f30b-497f-aedb-fac49055b667",
         "source": null,
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "4396166b-2c68-4938-81bb-1d4e86b4b6e7",
+    "pk": "7c022411-eb2c-4f06-9387-5d8418a0bf33",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "2aeff5c5-69c0-4017-9104-636572f95b6f",
-        "type": "390071fb-febb-4982-807f-cabe1e803015",
-        "name": "Volume 1, page 1r",
-        "zone": "b833caac-0665-4a51-8022-17bcf74ca629",
+        "corpus": "1f7e82ec-4094-4397-b729-ec424ea7a37f",
+        "type": "bff45072-bc1b-408d-bd1f-b3ffd22d8796",
+        "name": "Act 4",
+        "zone": null,
         "source": null,
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "4c511df6-2791-4b9e-bcf9-eabbcdba3e39",
+    "pk": "7e4d2f71-f52a-44a6-8cb5-f209a0b82408",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "2aeff5c5-69c0-4017-9104-636572f95b6f",
-        "type": "390071fb-febb-4982-807f-cabe1e803015",
-        "name": "Volume 2, page 1v",
-        "zone": "f975ebab-d0e4-44f4-87fd-6c36702de2c8",
+        "corpus": "1f7e82ec-4094-4397-b729-ec424ea7a37f",
+        "type": "aad1941d-d7dd-485f-8cf3-90487ac522c8",
+        "name": "Volume 2, page 1r",
+        "zone": "541c027b-3e0b-42f6-acf6-abcc49ff5f1e",
         "source": null,
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "5131c496-2487-4640-a972-f1071dfd4328",
+    "pk": "8f92f79c-471a-4280-9530-66ec406ab8b2",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "2aeff5c5-69c0-4017-9104-636572f95b6f",
-        "type": "c5d42d12-22d1-4f73-92a1-aa080ebee4cc",
-        "name": "Surface A",
-        "zone": "0132634c-7dec-4a02-96f0-3d3f8205ee34",
+        "corpus": "1f7e82ec-4094-4397-b729-ec424ea7a37f",
+        "type": "aad1941d-d7dd-485f-8cf3-90487ac522c8",
+        "name": "Volume 1, page 1r",
+        "zone": "5bd58b5d-8ed2-4e56-a466-b863101dfdc6",
         "source": null,
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "65069fcc-75df-443f-8dc2-4c8334f488b0",
+    "pk": "9621c876-e7da-4d43-a5a7-82470dead663",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "2aeff5c5-69c0-4017-9104-636572f95b6f",
-        "type": "8ddf6773-dd69-42b2-8566-5d6cdd9b2358",
-        "name": "Volume 2",
+        "corpus": "1f7e82ec-4094-4397-b729-ec424ea7a37f",
+        "type": "bff45072-bc1b-408d-bd1f-b3ffd22d8796",
+        "name": "Act 1",
         "zone": null,
         "source": null,
         "worker_version": null
@@ -407,41 +478,41 @@
 },
 {
     "model": "documents.element",
-    "pk": "80519bbf-cd39-4142-887c-8066bbb764af",
+    "pk": "b09ebead-3440-4040-8b82-5dc2bae4d2d9",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "2aeff5c5-69c0-4017-9104-636572f95b6f",
-        "type": "c5d42d12-22d1-4f73-92a1-aa080ebee4cc",
-        "name": "Surface B",
-        "zone": "1caadaf8-131c-4c10-b41d-8d6098137bf1",
+        "corpus": "1f7e82ec-4094-4397-b729-ec424ea7a37f",
+        "type": "33d93a96-58a9-4a7c-be54-12d4691f4e81",
+        "name": "Text line",
+        "zone": "59c89a4e-b961-4158-8107-f24463b40fca",
         "source": null,
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "913eca56-5a1f-4006-af8b-100a44a5e1a9",
+    "pk": "c0ec4456-f6a2-4253-a876-6eba4f96f863",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "2aeff5c5-69c0-4017-9104-636572f95b6f",
-        "type": "390071fb-febb-4982-807f-cabe1e803015",
+        "corpus": "1f7e82ec-4094-4397-b729-ec424ea7a37f",
+        "type": "aad1941d-d7dd-485f-8cf3-90487ac522c8",
         "name": "Volume 1, page 1v",
-        "zone": "d1dab6ef-17d0-4117-83e5-ce81ba83ca78",
+        "zone": "dda78215-f30b-497f-aedb-fac49055b667",
         "source": null,
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "925d8acd-88a1-434e-91d2-fbb59a830b50",
+    "pk": "cb69d995-2ce2-4404-a567-5598cf9dd231",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "2aeff5c5-69c0-4017-9104-636572f95b6f",
-        "type": "5379fa38-d26e-4545-bbde-860b0ad5ad1b",
-        "name": "Act 1",
+        "corpus": "1f7e82ec-4094-4397-b729-ec424ea7a37f",
+        "type": "bff45072-bc1b-408d-bd1f-b3ffd22d8796",
+        "name": "Act 2",
         "zone": null,
         "source": null,
         "worker_version": null
@@ -449,91 +520,91 @@
 },
 {
     "model": "documents.element",
-    "pk": "a239c221-e169-4c28-a201-eadbb954121e",
+    "pk": "ccc2cfdb-2de5-4e42-8a1a-fc5e1041b21d",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "2aeff5c5-69c0-4017-9104-636572f95b6f",
-        "type": "390071fb-febb-4982-807f-cabe1e803015",
-        "name": "Volume 2, page 1r",
-        "zone": "7cb72016-6e5b-4822-92b3-907ed0afaf4d",
+        "corpus": "1f7e82ec-4094-4397-b729-ec424ea7a37f",
+        "type": "bff45072-bc1b-408d-bd1f-b3ffd22d8796",
+        "name": "Act 3",
+        "zone": null,
         "source": null,
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "bc88e446-5145-4d77-a1f4-4c4936df28f2",
+    "pk": "d19ded5f-c50c-4cc6-a0cf-4463e2f2df68",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "2aeff5c5-69c0-4017-9104-636572f95b6f",
-        "type": "c5d42d12-22d1-4f73-92a1-aa080ebee4cc",
-        "name": "Surface C",
-        "zone": "d1dab6ef-17d0-4117-83e5-ce81ba83ca78",
+        "corpus": "1f7e82ec-4094-4397-b729-ec424ea7a37f",
+        "type": "bff45072-bc1b-408d-bd1f-b3ffd22d8796",
+        "name": "Act 5",
+        "zone": null,
         "source": null,
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "c7cdbe39-71f4-4278-98a2-f39afb1c5595",
+    "pk": "d7b6b144-88cb-4c47-a380-a84339773dda",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "2aeff5c5-69c0-4017-9104-636572f95b6f",
-        "type": "5379fa38-d26e-4545-bbde-860b0ad5ad1b",
-        "name": "Act 2",
-        "zone": null,
+        "corpus": "1f7e82ec-4094-4397-b729-ec424ea7a37f",
+        "type": "a8c815f0-258f-4025-8f9b-f3bd6a87904c",
+        "name": "Surface B",
+        "zone": "b9cb9d9d-8de0-4fcf-8063-a5eb30634b8e",
         "source": null,
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "d06ada28-259e-4994-9ca2-75b4af5a2882",
+    "pk": "dbfa2c38-8664-447a-bb09-215cc86c6ab4",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "2aeff5c5-69c0-4017-9104-636572f95b6f",
-        "type": "5379fa38-d26e-4545-bbde-860b0ad5ad1b",
-        "name": "Act 4",
-        "zone": null,
+        "corpus": "1f7e82ec-4094-4397-b729-ec424ea7a37f",
+        "type": "aad1941d-d7dd-485f-8cf3-90487ac522c8",
+        "name": "Volume 2, page 2r",
+        "zone": "543950e5-031d-41d1-83fd-7365c193c916",
         "source": null,
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "ed5a9ff4-46c2-4caa-8f85-a5bcdca18874",
+    "pk": "f3981e96-ed95-43a0-b1ea-fd288c55f5b3",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "2aeff5c5-69c0-4017-9104-636572f95b6f",
-        "type": "04497bf1-b027-4ff4-b986-02cb530fd7b2",
-        "name": "Text line",
-        "zone": "3df20773-faa5-4d45-ad62-bc3affb526b7",
+        "corpus": "1f7e82ec-4094-4397-b729-ec424ea7a37f",
+        "type": "a8c815f0-258f-4025-8f9b-f3bd6a87904c",
+        "name": "Surface D",
+        "zone": "3e6c6344-4dec-4609-b12d-14fd65c32664",
         "source": null,
         "worker_version": null
     }
 },
 {
     "model": "documents.element",
-    "pk": "f61f9197-1012-412e-8649-7fb1caac7f4d",
+    "pk": "f5535f84-2ca7-4853-9ab6-44606a8dc462",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "corpus": "2aeff5c5-69c0-4017-9104-636572f95b6f",
-        "type": "5379fa38-d26e-4545-bbde-860b0ad5ad1b",
-        "name": "Act 3",
-        "zone": null,
+        "corpus": "1f7e82ec-4094-4397-b729-ec424ea7a37f",
+        "type": "a8c815f0-258f-4025-8f9b-f3bd6a87904c",
+        "name": "Surface A",
+        "zone": "53ad7c0c-efcd-4001-be5b-298d1e8498b6",
         "source": null,
         "worker_version": null
     }
 },
 {
     "model": "documents.datasource",
-    "pk": "b080fedb-cb71-4415-a5f8-b7fbd7ea51a2",
+    "pk": "9ad06f06-000c-4d01-8038-1afc2e73c8e1",
     "fields": {
         "type": "recognizer",
         "slug": "test",
@@ -544,7 +615,7 @@
 },
 {
     "model": "documents.datasource",
-    "pk": "fbc73e49-39d4-4eb5-a06a-8c3f36543abd",
+    "pk": "c357f678-9e18-4179-a9ee-4f35fdf26cd8",
     "fields": {
         "type": "classifier",
         "slug": "test",
@@ -555,12 +626,12 @@
 },
 {
     "model": "documents.transcription",
-    "pk": "0baf8b02-0818-44a6-9e5f-98e72ea8360e",
+    "pk": "2578a1cf-3e57-4a15-b4cb-a0008c13a563",
     "fields": {
-        "element": "4396166b-2c68-4938-81bb-1d4e86b4b6e7",
+        "element": "8f92f79c-471a-4280-9530-66ec406ab8b2",
         "type": "word",
-        "zone": "3df20773-faa5-4d45-ad62-bc3affb526b7",
-        "source": "b080fedb-cb71-4415-a5f8-b7fbd7ea51a2",
+        "zone": "59c89a4e-b961-4158-8107-f24463b40fca",
+        "source": "9ad06f06-000c-4d01-8038-1afc2e73c8e1",
         "worker_version": null,
         "text": "ROY",
         "score": 1.0
@@ -568,25 +639,25 @@
 },
 {
     "model": "documents.transcription",
-    "pk": "325f7a71-6c2b-4fed-8b80-b10de5b085d4",
+    "pk": "4fc2945e-e4be-44d6-a839-c3149cbc66e0",
     "fields": {
-        "element": "079ac524-4c94-45dc-92fe-74e77723914b",
+        "element": "564aa56f-b257-445c-9930-4b6110628c09",
         "type": "word",
-        "zone": "45abfacd-dfd0-46f8-a981-84e384997000",
-        "source": "b080fedb-cb71-4415-a5f8-b7fbd7ea51a2",
+        "zone": "a2723514-109f-4b13-8336-e0128c49aee4",
+        "source": "9ad06f06-000c-4d01-8038-1afc2e73c8e1",
         "worker_version": null,
-        "text": "PARIS",
+        "text": "ROY",
         "score": 1.0
     }
 },
 {
     "model": "documents.transcription",
-    "pk": "352445b1-bb27-45fe-9425-c885156cddf1",
+    "pk": "51785975-0bf3-4bd1-8002-ae8c21dacbd4",
     "fields": {
-        "element": "913eca56-5a1f-4006-af8b-100a44a5e1a9",
+        "element": "c0ec4456-f6a2-4253-a876-6eba4f96f863",
         "type": "word",
-        "zone": "93b10936-a485-43ed-b9fb-82cec3a45586",
-        "source": "b080fedb-cb71-4415-a5f8-b7fbd7ea51a2",
+        "zone": "2e3f07cc-d8cb-4735-bed0-63d4d109d893",
+        "source": "9ad06f06-000c-4d01-8038-1afc2e73c8e1",
         "worker_version": null,
         "text": "PARIS",
         "score": 1.0
@@ -594,90 +665,90 @@
 },
 {
     "model": "documents.transcription",
-    "pk": "562cb1c9-5d84-493e-9d86-20a970331856",
+    "pk": "72409ca8-98ff-4055-98e8-5b5e8620e1fe",
     "fields": {
-        "element": "079ac524-4c94-45dc-92fe-74e77723914b",
+        "element": "c0ec4456-f6a2-4253-a876-6eba4f96f863",
         "type": "word",
-        "zone": "c8c78eb2-f8d8-40e3-9f46-31b39a6a5cea",
-        "source": "b080fedb-cb71-4415-a5f8-b7fbd7ea51a2",
+        "zone": "de6f5a26-52fd-4361-b30e-08b98b9d480a",
+        "source": "9ad06f06-000c-4d01-8038-1afc2e73c8e1",
         "worker_version": null,
-        "text": "ROY",
+        "text": "DATUM",
         "score": 1.0
     }
 },
 {
     "model": "documents.transcription",
-    "pk": "63cb6a02-089f-4f9a-aef1-2b9c23cc5100",
+    "pk": "81e2a90b-d518-4280-b71b-7cdc24587472",
     "fields": {
-        "element": "4396166b-2c68-4938-81bb-1d4e86b4b6e7",
+        "element": "564aa56f-b257-445c-9930-4b6110628c09",
         "type": "word",
-        "zone": "20eb0629-ed33-4174-92d9-e83f73541283",
-        "source": "b080fedb-cb71-4415-a5f8-b7fbd7ea51a2",
+        "zone": "658a1c75-a4de-4842-8a09-2a51c22c8269",
+        "source": "9ad06f06-000c-4d01-8038-1afc2e73c8e1",
         "worker_version": null,
-        "text": "DATUM",
+        "text": "PARIS",
         "score": 1.0
     }
 },
 {
     "model": "documents.transcription",
-    "pk": "aed93356-579f-4114-9f34-20252af6e591",
+    "pk": "d4e38d93-48dc-4c46-881f-fe85ddfd01da",
     "fields": {
-        "element": "079ac524-4c94-45dc-92fe-74e77723914b",
+        "element": "8f92f79c-471a-4280-9530-66ec406ab8b2",
         "type": "word",
-        "zone": "4a4d6030-b40e-4bcd-bea8-ba6e0cc938b8",
-        "source": "b080fedb-cb71-4415-a5f8-b7fbd7ea51a2",
+        "zone": "2d6cbfa0-917e-4f3e-91db-3e050f236922",
+        "source": "9ad06f06-000c-4d01-8038-1afc2e73c8e1",
         "worker_version": null,
-        "text": "DATUM",
+        "text": "PARIS",
         "score": 1.0
     }
 },
 {
     "model": "documents.transcription",
-    "pk": "bfcadc4e-df0a-4bc1-856c-4a1e62d17bd9",
+    "pk": "d5297c59-e7b8-4c03-8b53-d84347ec726c",
     "fields": {
-        "element": "4396166b-2c68-4938-81bb-1d4e86b4b6e7",
+        "element": "8f92f79c-471a-4280-9530-66ec406ab8b2",
         "type": "word",
-        "zone": "1a8a7098-1452-423a-8480-4e352721017f",
-        "source": "b080fedb-cb71-4415-a5f8-b7fbd7ea51a2",
+        "zone": "1323086e-7117-4454-b6d2-d2e9b9b30251",
+        "source": "9ad06f06-000c-4d01-8038-1afc2e73c8e1",
         "worker_version": null,
-        "text": "PARIS",
+        "text": "DATUM",
         "score": 1.0
     }
 },
 {
     "model": "documents.transcription",
-    "pk": "c00d9cfa-e46d-49cc-b077-5d9e569ad87a",
+    "pk": "daef6593-28c3-4b81-a693-e1ec81f52718",
     "fields": {
-        "element": "913eca56-5a1f-4006-af8b-100a44a5e1a9",
+        "element": "c0ec4456-f6a2-4253-a876-6eba4f96f863",
         "type": "word",
-        "zone": "77b9c118-eeb5-4e5f-8cac-4c3a7cf5357e",
-        "source": "b080fedb-cb71-4415-a5f8-b7fbd7ea51a2",
+        "zone": "4ae281d2-de97-42dc-ac66-d3edc93bf92e",
+        "source": "9ad06f06-000c-4d01-8038-1afc2e73c8e1",
         "worker_version": null,
-        "text": "DATUM",
+        "text": "ROY",
         "score": 1.0
     }
 },
 {
     "model": "documents.transcription",
-    "pk": "dbf30003-6ab7-4718-a5ef-dd0e9aeb5a49",
+    "pk": "e275ebac-db1d-48df-90d5-0513464f4ab0",
     "fields": {
-        "element": "913eca56-5a1f-4006-af8b-100a44a5e1a9",
+        "element": "564aa56f-b257-445c-9930-4b6110628c09",
         "type": "word",
-        "zone": "87d0075b-a84c-4b72-9fba-dcdb875830ac",
-        "source": "b080fedb-cb71-4415-a5f8-b7fbd7ea51a2",
+        "zone": "021f8b5e-4963-4638-a24f-fa99114ffd17",
+        "source": "9ad06f06-000c-4d01-8038-1afc2e73c8e1",
         "worker_version": null,
-        "text": "ROY",
+        "text": "DATUM",
         "score": 1.0
     }
 },
 {
     "model": "documents.transcription",
-    "pk": "dc2b4427-07e3-4748-a7a2-ec2ec05d5b7a",
+    "pk": "ea21f8c6-1ecf-4be8-848b-af333c8b83a1",
     "fields": {
-        "element": "4396166b-2c68-4938-81bb-1d4e86b4b6e7",
+        "element": "8f92f79c-471a-4280-9530-66ec406ab8b2",
         "type": "page",
         "zone": null,
-        "source": "b080fedb-cb71-4415-a5f8-b7fbd7ea51a2",
+        "source": "9ad06f06-000c-4d01-8038-1afc2e73c8e1",
         "worker_version": null,
         "text": "Lorem ipsum dolor sit amet",
         "score": 1.0
@@ -685,39 +756,39 @@
 },
 {
     "model": "documents.allowedmetadata",
-    "pk": "20b940e9-606c-42d5-bb3d-b7ca659348c5",
+    "pk": "0f90ca4d-c698-4a14-89fc-32c153e6a5fd",
     "fields": {
-        "corpus": "2aeff5c5-69c0-4017-9104-636572f95b6f",
+        "corpus": "1f7e82ec-4094-4397-b729-ec424ea7a37f",
         "type": "text",
         "name": "folio"
     }
 },
 {
     "model": "documents.allowedmetadata",
-    "pk": "9c34ab1c-8ef0-4d0e-963c-7b10704e4a65",
+    "pk": "1ab75f14-57ca-4c05-a9fb-f10c082f4206",
     "fields": {
-        "corpus": "2aeff5c5-69c0-4017-9104-636572f95b6f",
-        "type": "date",
-        "name": "date"
+        "corpus": "1f7e82ec-4094-4397-b729-ec424ea7a37f",
+        "type": "location",
+        "name": "location"
     }
 },
 {
     "model": "documents.allowedmetadata",
-    "pk": "c468f194-a05a-49ce-9053-b230f27bebc2",
+    "pk": "90cf5544-2b0a-465a-aae4-c7de6ade0592",
     "fields": {
-        "corpus": "2aeff5c5-69c0-4017-9104-636572f95b6f",
-        "type": "location",
-        "name": "location"
+        "corpus": "1f7e82ec-4094-4397-b729-ec424ea7a37f",
+        "type": "date",
+        "name": "date"
     }
 },
 {
     "model": "documents.metadata",
-    "pk": "0c49e0ad-f122-4da0-95a1-6944baf5eed4",
+    "pk": "0be7aa65-fa4d-4cea-bba2-86748478b595",
     "fields": {
-        "element": "f61f9197-1012-412e-8649-7fb1caac7f4d",
-        "name": "number",
+        "element": "564aa56f-b257-445c-9930-4b6110628c09",
+        "name": "folio",
         "type": "text",
-        "value": "3",
+        "value": "2r",
         "revision": null,
         "index": 0,
         "entity": null
@@ -725,12 +796,12 @@
 },
 {
     "model": "documents.metadata",
-    "pk": "23fee0c5-6536-4ea1-9f5d-453f1630765f",
+    "pk": "12069432-7670-4378-a918-23daf27ea172",
     "fields": {
-        "element": "337803ea-3774-4f50-947b-a8e52c52309d",
-        "name": "folio",
+        "element": "7c022411-eb2c-4f06-9387-5d8418a0bf33",
+        "name": "number",
         "type": "text",
-        "value": "2r",
+        "value": "4",
         "revision": null,
         "index": 0,
         "entity": null
@@ -738,12 +809,12 @@
 },
 {
     "model": "documents.metadata",
-    "pk": "34096e03-1738-4ee8-b098-be723c89c773",
+    "pk": "14e7fd76-4c9b-4e45-b01c-f6ac04b4d17c",
     "fields": {
-        "element": "4c511df6-2791-4b9e-bcf9-eabbcdba3e39",
-        "name": "folio",
+        "element": "cb69d995-2ce2-4404-a567-5598cf9dd231",
+        "name": "number",
         "type": "text",
-        "value": "1v",
+        "value": "2",
         "revision": null,
         "index": 0,
         "entity": null
@@ -751,12 +822,12 @@
 },
 {
     "model": "documents.metadata",
-    "pk": "42014bf3-6f29-4ed2-b042-ca7f192faf6e",
+    "pk": "2f82730b-fc55-485c-869d-7aa2214aafef",
     "fields": {
-        "element": "925d8acd-88a1-434e-91d2-fbb59a830b50",
-        "name": "number",
+        "element": "c0ec4456-f6a2-4253-a876-6eba4f96f863",
+        "name": "folio",
         "type": "text",
-        "value": "1",
+        "value": "1v",
         "revision": null,
         "index": 0,
         "entity": null
@@ -764,12 +835,12 @@
 },
 {
     "model": "documents.metadata",
-    "pk": "4be6d63e-2f0c-47e4-b891-2b137f1c58be",
+    "pk": "63ff193e-fd67-4c2d-b52d-3c99a49f1131",
     "fields": {
-        "element": "4396166b-2c68-4938-81bb-1d4e86b4b6e7",
+        "element": "dbfa2c38-8664-447a-bb09-215cc86c6ab4",
         "name": "folio",
         "type": "text",
-        "value": "1r",
+        "value": "2r",
         "revision": null,
         "index": 0,
         "entity": null
@@ -777,12 +848,12 @@
 },
 {
     "model": "documents.metadata",
-    "pk": "792f385f-7056-4308-b520-f97fb98fa3d4",
+    "pk": "759c2edc-6e7b-4f96-9cd9-0daa38d9757a",
     "fields": {
-        "element": "079ac524-4c94-45dc-92fe-74e77723914b",
+        "element": "4e9de67b-6e4f-46b7-936e-34ed9692900b",
         "name": "folio",
         "type": "text",
-        "value": "2r",
+        "value": "1v",
         "revision": null,
         "index": 0,
         "entity": null
@@ -790,12 +861,12 @@
 },
 {
     "model": "documents.metadata",
-    "pk": "a596d55f-c8c1-425a-a125-6d6269cbc21f",
+    "pk": "79c508f3-4288-4a1b-8f1f-19af1a057e3e",
     "fields": {
-        "element": "c7cdbe39-71f4-4278-98a2-f39afb1c5595",
+        "element": "d19ded5f-c50c-4cc6-a0cf-4463e2f2df68",
         "name": "number",
         "type": "text",
-        "value": "2",
+        "value": "5",
         "revision": null,
         "index": 0,
         "entity": null
@@ -803,12 +874,12 @@
 },
 {
     "model": "documents.metadata",
-    "pk": "a8269161-8417-4498-b099-298ef709b675",
+    "pk": "7f3688fb-3a16-4cba-b218-47a372eb5480",
     "fields": {
-        "element": "a239c221-e169-4c28-a201-eadbb954121e",
-        "name": "folio",
+        "element": "9621c876-e7da-4d43-a5a7-82470dead663",
+        "name": "number",
         "type": "text",
-        "value": "1r",
+        "value": "1",
         "revision": null,
         "index": 0,
         "entity": null
@@ -816,12 +887,12 @@
 },
 {
     "model": "documents.metadata",
-    "pk": "aa3c6987-42d6-49e4-881a-a2c668b0cae9",
+    "pk": "d86e7d8d-2dc8-4ac7-ac5e-d8aff8df4548",
     "fields": {
-        "element": "d06ada28-259e-4994-9ca2-75b4af5a2882",
-        "name": "number",
+        "element": "7e4d2f71-f52a-44a6-8cb5-f209a0b82408",
+        "name": "folio",
         "type": "text",
-        "value": "4",
+        "value": "1r",
         "revision": null,
         "index": 0,
         "entity": null
@@ -829,12 +900,12 @@
 },
 {
     "model": "documents.metadata",
-    "pk": "d68375ea-8cbe-437f-a59c-b799ef6e659e",
+    "pk": "d9c74f49-670d-4b37-a21e-60ca50059cda",
     "fields": {
-        "element": "913eca56-5a1f-4006-af8b-100a44a5e1a9",
-        "name": "folio",
+        "element": "ccc2cfdb-2de5-4e42-8a1a-fc5e1041b21d",
+        "name": "number",
         "type": "text",
-        "value": "1v",
+        "value": "3",
         "revision": null,
         "index": 0,
         "entity": null
@@ -842,12 +913,12 @@
 },
 {
     "model": "documents.metadata",
-    "pk": "ea0cd0a0-6ce9-41d8-94c6-3304c7d9a7f9",
+    "pk": "f4103a83-94eb-4634-8cd3-32db7e94ac1e",
     "fields": {
-        "element": "3a784a2e-c07e-42c0-a79c-53e338e68345",
-        "name": "number",
+        "element": "8f92f79c-471a-4280-9530-66ec406ab8b2",
+        "name": "folio",
         "type": "text",
-        "value": "5",
+        "value": "1r",
         "revision": null,
         "index": 0,
         "entity": null
@@ -871,12 +942,12 @@
 },
 {
     "model": "images.image",
-    "pk": "18d5f671-6abe-4e16-9bb2-cfee82a17220",
+    "pk": "0a18ca58-69a7-44f8-b2ac-739a7a978cf2",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
         "server": 1,
-        "path": "img1",
+        "path": "img3",
         "width": 1000,
         "height": 1000,
         "hash": null,
@@ -885,12 +956,12 @@
 },
 {
     "model": "images.image",
-    "pk": "34603613-b450-4f52-8db8-fa0410d53355",
+    "pk": "7ce02a7c-877a-46bc-8557-cd87b6945d81",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
         "server": 1,
-        "path": "img5",
+        "path": "img4",
         "width": 1000,
         "height": 1000,
         "hash": null,
@@ -899,12 +970,12 @@
 },
 {
     "model": "images.image",
-    "pk": "67c8b3de-d245-46cb-b31e-4653493fab27",
+    "pk": "a415642f-af03-422d-acf2-a9fce1cf6ef1",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
         "server": 1,
-        "path": "img4",
+        "path": "img2",
         "width": 1000,
         "height": 1000,
         "hash": null,
@@ -913,12 +984,12 @@
 },
 {
     "model": "images.image",
-    "pk": "70ed4289-845b-4998-8a74-20925816c94b",
+    "pk": "c1f75796-3a1c-4e85-b8fa-43472a719312",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
         "server": 1,
-        "path": "img2",
+        "path": "img5",
         "width": 1000,
         "height": 1000,
         "hash": null,
@@ -927,12 +998,12 @@
 },
 {
     "model": "images.image",
-    "pk": "977247ec-49ee-4f6a-949d-03e267adef23",
+    "pk": "ddbb369c-a6ed-488c-9108-e996ade67b29",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
         "server": 1,
-        "path": "img6",
+        "path": "img1",
         "width": 1000,
         "height": 1000,
         "hash": null,
@@ -941,12 +1012,12 @@
 },
 {
     "model": "images.image",
-    "pk": "c3a900c3-7fe4-44b3-816d-ca69f8227570",
+    "pk": "e6df804d-82f7-420e-a562-fb3d265a2bec",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
         "server": 1,
-        "path": "img3",
+        "path": "img6",
         "width": 1000,
         "height": 1000,
         "hash": null,
@@ -955,209 +1026,209 @@
 },
 {
     "model": "images.zone",
-    "pk": "0132634c-7dec-4a02-96f0-3d3f8205ee34",
+    "pk": "021f8b5e-4963-4638-a24f-fa99114ffd17",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "18d5f671-6abe-4e16-9bb2-cfee82a17220",
-        "polygon": "LINEARRING (0 0, 0 600, 600 600, 600 0, 0 0)"
+        "image": "0a18ca58-69a7-44f8-b2ac-739a7a978cf2",
+        "polygon": "LINEARRING (700 700, 700 800, 800 800, 800 700, 700 700)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "06f88cf0-c12e-4f33-a7ba-e3adb15b6211",
+    "pk": "1323086e-7117-4454-b6d2-d2e9b9b30251",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "977247ec-49ee-4f6a-949d-03e267adef23",
-        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)"
+        "image": "ddbb369c-a6ed-488c-9108-e996ade67b29",
+        "polygon": "LINEARRING (700 700, 700 800, 800 800, 800 700, 700 700)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "1a8a7098-1452-423a-8480-4e352721017f",
+    "pk": "20f0abb7-3aac-460b-b1af-b75ed7dab550",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "18d5f671-6abe-4e16-9bb2-cfee82a17220",
-        "polygon": "LINEARRING (100 100, 100 200, 200 200, 200 100, 100 100)"
+        "image": "0a18ca58-69a7-44f8-b2ac-739a7a978cf2",
+        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "1caadaf8-131c-4c10-b41d-8d6098137bf1",
+    "pk": "2d6cbfa0-917e-4f3e-91db-3e050f236922",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "18d5f671-6abe-4e16-9bb2-cfee82a17220",
-        "polygon": "LINEARRING (600 600, 600 1000, 1000 1000, 1000 600, 600 600)"
+        "image": "ddbb369c-a6ed-488c-9108-e996ade67b29",
+        "polygon": "LINEARRING (100 100, 100 200, 200 200, 200 100, 100 100)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "20eb0629-ed33-4174-92d9-e83f73541283",
+    "pk": "2e3f07cc-d8cb-4735-bed0-63d4d109d893",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "18d5f671-6abe-4e16-9bb2-cfee82a17220",
-        "polygon": "LINEARRING (700 700, 700 800, 800 800, 800 700, 700 700)"
+        "image": "a415642f-af03-422d-acf2-a9fce1cf6ef1",
+        "polygon": "LINEARRING (100 100, 100 200, 200 200, 200 100, 100 100)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "3df20773-faa5-4d45-ad62-bc3affb526b7",
+    "pk": "3e6c6344-4dec-4609-b12d-14fd65c32664",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "18d5f671-6abe-4e16-9bb2-cfee82a17220",
-        "polygon": "LINEARRING (400 400, 400 500, 500 500, 500 400, 400 400)"
+        "image": "0a18ca58-69a7-44f8-b2ac-739a7a978cf2",
+        "polygon": "LINEARRING (0 0, 0 300, 300 300, 300 0, 0 0)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "45abfacd-dfd0-46f8-a981-84e384997000",
+    "pk": "4ae281d2-de97-42dc-ac66-d3edc93bf92e",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "c3a900c3-7fe4-44b3-816d-ca69f8227570",
-        "polygon": "LINEARRING (100 100, 100 200, 200 200, 200 100, 100 100)"
+        "image": "a415642f-af03-422d-acf2-a9fce1cf6ef1",
+        "polygon": "LINEARRING (400 400, 400 500, 500 500, 500 400, 400 400)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "49adab61-dd91-493b-98d0-8e66761e6b44",
+    "pk": "53ad7c0c-efcd-4001-be5b-298d1e8498b6",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "c3a900c3-7fe4-44b3-816d-ca69f8227570",
-        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)"
+        "image": "ddbb369c-a6ed-488c-9108-e996ade67b29",
+        "polygon": "LINEARRING (0 0, 0 600, 600 600, 600 0, 0 0)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "4a4d6030-b40e-4bcd-bea8-ba6e0cc938b8",
+    "pk": "541c027b-3e0b-42f6-acf6-abcc49ff5f1e",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "c3a900c3-7fe4-44b3-816d-ca69f8227570",
-        "polygon": "LINEARRING (700 700, 700 800, 800 800, 800 700, 700 700)"
+        "image": "7ce02a7c-877a-46bc-8557-cd87b6945d81",
+        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "77b9c118-eeb5-4e5f-8cac-4c3a7cf5357e",
+    "pk": "543950e5-031d-41d1-83fd-7365c193c916",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "70ed4289-845b-4998-8a74-20925816c94b",
-        "polygon": "LINEARRING (700 700, 700 800, 800 800, 800 700, 700 700)"
+        "image": "e6df804d-82f7-420e-a562-fb3d265a2bec",
+        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "7cb72016-6e5b-4822-92b3-907ed0afaf4d",
+    "pk": "59c89a4e-b961-4158-8107-f24463b40fca",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "67c8b3de-d245-46cb-b31e-4653493fab27",
-        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)"
+        "image": "ddbb369c-a6ed-488c-9108-e996ade67b29",
+        "polygon": "LINEARRING (400 400, 400 500, 500 500, 500 400, 400 400)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "87d0075b-a84c-4b72-9fba-dcdb875830ac",
+    "pk": "5bd58b5d-8ed2-4e56-a466-b863101dfdc6",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "70ed4289-845b-4998-8a74-20925816c94b",
-        "polygon": "LINEARRING (400 400, 400 500, 500 500, 500 400, 400 400)"
+        "image": "ddbb369c-a6ed-488c-9108-e996ade67b29",
+        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "93b10936-a485-43ed-b9fb-82cec3a45586",
+    "pk": "658a1c75-a4de-4842-8a09-2a51c22c8269",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "70ed4289-845b-4998-8a74-20925816c94b",
+        "image": "0a18ca58-69a7-44f8-b2ac-739a7a978cf2",
         "polygon": "LINEARRING (100 100, 100 200, 200 200, 200 100, 100 100)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "ab1ba0c5-0238-4587-9154-3344b1e30a85",
+    "pk": "a2723514-109f-4b13-8336-e0128c49aee4",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "c3a900c3-7fe4-44b3-816d-ca69f8227570",
-        "polygon": "LINEARRING (300 300, 300 600, 600 600, 600 300, 300 300)"
+        "image": "0a18ca58-69a7-44f8-b2ac-739a7a978cf2",
+        "polygon": "LINEARRING (400 400, 400 500, 500 500, 500 400, 400 400)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "b833caac-0665-4a51-8022-17bcf74ca629",
+    "pk": "b9cb9d9d-8de0-4fcf-8063-a5eb30634b8e",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "18d5f671-6abe-4e16-9bb2-cfee82a17220",
-        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)"
+        "image": "ddbb369c-a6ed-488c-9108-e996ade67b29",
+        "polygon": "LINEARRING (600 600, 600 1000, 1000 1000, 1000 600, 600 600)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "c8c78eb2-f8d8-40e3-9f46-31b39a6a5cea",
+    "pk": "d2e7ee12-14fa-46c8-a360-f5b31939052a",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "c3a900c3-7fe4-44b3-816d-ca69f8227570",
-        "polygon": "LINEARRING (400 400, 400 500, 500 500, 500 400, 400 400)"
+        "image": "0a18ca58-69a7-44f8-b2ac-739a7a978cf2",
+        "polygon": "LINEARRING (600 600, 600 1000, 1000 1000, 1000 600, 600 600)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "d1dab6ef-17d0-4117-83e5-ce81ba83ca78",
+    "pk": "dda78215-f30b-497f-aedb-fac49055b667",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "70ed4289-845b-4998-8a74-20925816c94b",
+        "image": "a415642f-af03-422d-acf2-a9fce1cf6ef1",
         "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "da3f96a9-ad6d-476a-9c0c-7a08457e9ca5",
+    "pk": "de6f5a26-52fd-4361-b30e-08b98b9d480a",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "c3a900c3-7fe4-44b3-816d-ca69f8227570",
-        "polygon": "LINEARRING (0 0, 0 300, 300 300, 300 0, 0 0)"
+        "image": "a415642f-af03-422d-acf2-a9fce1cf6ef1",
+        "polygon": "LINEARRING (700 700, 700 800, 800 800, 800 700, 700 700)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "ecdd78a6-c197-41fe-8a1d-857e57f31526",
+    "pk": "e67eba1f-4993-492e-9ca0-67451ceb094c",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "c3a900c3-7fe4-44b3-816d-ca69f8227570",
-        "polygon": "LINEARRING (600 600, 600 1000, 1000 1000, 1000 600, 600 600)"
+        "image": "c1f75796-3a1c-4e85-b8fa-43472a719312",
+        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)"
     }
 },
 {
     "model": "images.zone",
-    "pk": "f975ebab-d0e4-44f4-87fd-6c36702de2c8",
+    "pk": "f3b62073-8fe4-46c9-b7bf-012c3014359b",
     "fields": {
         "created": "2020-02-02T01:23:45.678Z",
         "updated": "2020-02-02T01:23:45.678Z",
-        "image": "34603613-b450-4f52-8db8-fa0410d53355",
-        "polygon": "LINEARRING (0 0, 0 1000, 1000 1000, 1000 0, 0 0)"
+        "image": "0a18ca58-69a7-44f8-b2ac-739a7a978cf2",
+        "polygon": "LINEARRING (300 300, 300 600, 600 600, 600 300, 300 300)"
     }
 },
 {
     "model": "users.user",
     "pk": 1,
     "fields": {
-        "password": "pbkdf2_sha256$216000$qCN2CTufR3sL$0rQgDgt+QJHL2UaeY1zNT4gIljXW9NtgzdoXIkgBIVA=",
+        "password": "pbkdf2_sha256$216000$l8Q874FbHSd8$nuAro6QYXwWYcYcFP1hVKgZUjTYnmbAKLqvFBRpLizU=",
         "last_login": null,
         "email": "root@root.fr",
         "transkribus_email": null,
@@ -1172,7 +1243,7 @@
     "model": "users.user",
     "pk": 2,
     "fields": {
-        "password": "pbkdf2_sha256$216000$XCkvJTux5hQS$NbaHo9czCWEx63S979W38OyEMWn709+txXKVVl7EGp4=",
+        "password": "pbkdf2_sha256$216000$JbMVfYKIdmbH$HacY6ieeQBFMnMT32valEOgJnifIPuxNWx5LsaZSEN4=",
         "last_login": null,
         "email": "internal@internal.fr",
         "transkribus_email": null,
@@ -1187,7 +1258,7 @@
     "model": "users.user",
     "pk": 3,
     "fields": {
-        "password": "pbkdf2_sha256$216000$T6639eulurna$BjLzenXNk2tjztAJR7hfLuoHv09LwAMVTsVwJkIwPOw=",
+        "password": "pbkdf2_sha256$216000$RurQ9pYDub7S$bhJUTPQbo1jcqBoDS69RNbdzM6cr0ydKcE9Dk7mQyyU=",
         "last_login": null,
         "email": "user@user.fr",
         "transkribus_email": null,
@@ -1200,7 +1271,7 @@
 },
 {
     "model": "users.oauthcredentials",
-    "pk": "fdd4c059-6d10-4aaa-8308-a0aa4bf20284",
+    "pk": "d21e40e2-32d2-4903-ac4a-6672dc6c14ba",
     "fields": {
         "user": 3,
         "provider_name": "gitlab",
@@ -1217,7 +1288,7 @@
     "pk": 1,
     "fields": {
         "user": 3,
-        "corpus": "2aeff5c5-69c0-4017-9104-636572f95b6f",
+        "corpus": "1f7e82ec-4094-4397-b729-ec424ea7a37f",
         "can_write": true,
         "can_admin": true
     }
@@ -2805,5 +2876,48 @@
         "content_type": 44,
         "codename": "view_dataimportelement"
     }
+},
+{
+    "model": "ponos.workflow",
+    "pk": "b391055a-84f5-431e-84ff-fec1836c4a5e",
+    "fields": {
+        "recipe": "tasks:\n docker_build:\n  image: reco",
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z"
+    }
+},
+{
+    "model": "ponos.task",
+    "pk": "71dd7910-8bef-4940-ab6a-50df883a2cb3",
+    "fields": {
+        "run": 0,
+        "depth": 0,
+        "slug": "docker_build",
+        "state": "completed",
+        "tags": "[]",
+        "image": "",
+        "command": null,
+        "env": null,
+        "has_docker_socket": false,
+        "image_artifact": null,
+        "agent": null,
+        "workflow": "b391055a-84f5-431e-84ff-fec1836c4a5e",
+        "container": null,
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z",
+        "parents": []
+    }
+},
+{
+    "model": "ponos.artifact",
+    "pk": "71a4b60b-a2f2-4503-8f5d-9d3c38f66626",
+    "fields": {
+        "task": "71dd7910-8bef-4940-ab6a-50df883a2cb3",
+        "path": "/path/to/docker_build",
+        "size": 42000,
+        "content_type": "application/octet-stream",
+        "created": "2020-02-02T01:23:45.678Z",
+        "updated": "2020-02-02T01:23:45.678Z"
+    }
 }
 ]
diff --git a/arkindex/documents/management/commands/build_fixtures.py b/arkindex/documents/management/commands/build_fixtures.py
index 08f7c16018..55d5ea4161 100644
--- a/arkindex/documents/management/commands/build_fixtures.py
+++ b/arkindex/documents/management/commands/build_fixtures.py
@@ -3,9 +3,10 @@ from django.core.management.base import BaseCommand
 from arkindex_common.ml_tool import MLToolType
 from arkindex_common.enums import TranscriptionType, MetaType
 from arkindex.documents.models import Corpus, Element, Transcription, DataSource, MetaData
-from arkindex.dataimport.models import RepositoryType
+from arkindex.dataimport.models import RepositoryType, WorkerVersion, WorkerVersionState, Workflow
 from arkindex.images.models import ImageServer, Image, Zone
 from arkindex.users.models import User, CorpusRight
+from ponos.models import State
 from django.contrib.gis.geos import LinearRing
 from django.utils import timezone as DjangoTimeZone
 from unittest.mock import patch
@@ -95,7 +96,7 @@ class Command(BaseCommand):
             token='oauth-token',
         )
 
-        # Create a repository
+        # Create a IIIF repository
         repo = creds.repos.create(
             url='http://gitlab/repo',
             type=RepositoryType.IIIF,
@@ -305,3 +306,47 @@ class Command(BaseCommand):
         sd.add_parent(act3)
         se.add_parent(act4)
         sf.add_parent(act5)
+
+        # Create a worker repository
+        worker_repo = creds.repos.create(
+            type=RepositoryType.Worker,
+            url="http://my_repo.fake/workers/worker",
+            hook_token='worker-hook-token',
+            provider_name='GitLabProvider'
+        )
+
+        # Create a revision on this repository
+        revision = worker_repo.revisions.create(
+            hash="1337",
+            message="My w0rk3r",
+            author="Test user"
+        )
+
+        # Create a fake docker build with a docker image task
+        workflow = Workflow.objects.create(recipe='tasks:\n docker_build:\n  image: reco')
+        build_task = workflow.tasks.create(run=0, depth=0, slug='docker_build', state=State.Completed)
+        docker_image = build_task.artifacts.create(size=42_000, path='/path/to/docker_build')
+
+        # Create two workers for the repository with their available version
+        WorkerVersion.objects.create(
+            worker=worker_repo.workers.create(
+                name='Recognizer',
+                slug='reco',
+                type=MLToolType.Recognizer
+            ),
+            revision=revision,
+            configuration={'test': 42},
+            state=WorkerVersionState.Available,
+            docker_image=docker_image
+        )
+        WorkerVersion.objects.create(
+            worker=worker_repo.workers.create(
+                name='Document layout analyser',
+                slug='dla',
+                type=MLToolType.DLAnalyser
+            ),
+            revision=revision,
+            configuration={'test': 42},
+            state=WorkerVersionState.Available,
+            docker_image=docker_image
+        )
diff --git a/arkindex/documents/tests/test_bulk_classification.py b/arkindex/documents/tests/test_bulk_classification.py
index f1203fdd5b..a017985674 100644
--- a/arkindex/documents/tests/test_bulk_classification.py
+++ b/arkindex/documents/tests/test_bulk_classification.py
@@ -3,7 +3,7 @@ from arkindex_common.ml_tool import MLToolType
 from rest_framework import status
 from arkindex.project.tests import FixtureAPITestCase
 from arkindex.documents.models import Corpus, DataSource, MLClass
-from arkindex.dataimport.models import WorkerVersion, Worker
+from arkindex.dataimport.models import WorkerVersion
 
 
 class TestBulkClassification(FixtureAPITestCase):
@@ -14,17 +14,7 @@ class TestBulkClassification(FixtureAPITestCase):
         cls.page = cls.corpus.elements.get(name='Volume 1, page 2r')
         cls.src = DataSource.objects.get(slug='test', type=MLToolType.Classifier)
         cls.private_corpus = Corpus.objects.create(name='private', public=False)
-        cls.repo = cls.user.credentials.get().repos.get()
-        cls.worker_version = WorkerVersion.objects.create(
-            worker=Worker.objects.create(
-                repository=cls.repo,
-                name='Test Worker',
-                slug='test_worker',
-                type=MLToolType.Classifier
-            ),
-            revision=cls.repo.revisions.get(),
-            configuration={"test": "test1"}
-        )
+        cls.worker_version = WorkerVersion.objects.get(worker__slug='reco')
 
     @classmethod
     def setUpClass(cls):
diff --git a/arkindex/documents/tests/test_bulk_element_transcriptions.py b/arkindex/documents/tests/test_bulk_element_transcriptions.py
index cac263203b..15077ebe10 100644
--- a/arkindex/documents/tests/test_bulk_element_transcriptions.py
+++ b/arkindex/documents/tests/test_bulk_element_transcriptions.py
@@ -6,7 +6,7 @@ from mock import AsyncMock
 from rest_framework import status
 from arkindex.project.tests import FixtureAPITestCase
 from arkindex_common.enums import TranscriptionType
-from arkindex.dataimport.models import Worker, WorkerVersion
+from arkindex.dataimport.models import WorkerVersion
 from arkindex.documents.models import Element, Corpus, DataSource
 from arkindex_common.ml_tool import MLToolType
 
@@ -25,9 +25,7 @@ class TestBulkElementTranscriptions(FixtureAPITestCase):
         cls.line = cls.corpus.elements.filter(type__slug='text_line').first()
         cls.private_corpus = Corpus.objects.create(name='Private')
         cls.private_page = cls.private_corpus.elements.create(type=cls.page.type)
-        cls.creds = cls.user.credentials.get()
-        cls.repo = cls.creds.repos.get()
-        cls.rev = cls.repo.revisions.get()
+        cls.worker_version = WorkerVersion.objects.get(worker__slug='reco')
 
     def setUp(self):
         self.manual_source = DataSource.objects.create(type=MLToolType.Recognizer, slug='manual', internal=False)
@@ -118,17 +116,6 @@ class TestBulkElementTranscriptions(FixtureAPITestCase):
         self.src.internal = True
         self.src.save()
 
-        worker = Worker.objects.create(
-            repository=self.repo,
-            name='Worker 1',
-            slug='worker_1',
-            type=MLToolType.Classifier
-        )
-        version = WorkerVersion.objects.create(
-            worker=worker,
-            revision=self.rev,
-            configuration={"test": "test1"}
-        )
         transcriptions = [
             ([[13, 37], [133, 37], [133, 137], [13, 137], [13, 37]], 'Hello world !', 0.1337),
             ([[24, 42], [64, 42], [64, 142], [24, 142], [24, 42]], 'I <3 JavaScript', 0.42),
@@ -136,7 +123,7 @@ class TestBulkElementTranscriptions(FixtureAPITestCase):
         data = {
             'element_type': 'text_line',
             'transcription_type': 'line',
-            'worker_version': str(version.id),
+            'worker_version': str(self.worker_version.id),
             'transcriptions': [{
                 'polygon': poly,
                 'text': text,
@@ -167,8 +154,8 @@ class TestBulkElementTranscriptions(FixtureAPITestCase):
         self.assertCountEqual(
             created_elts.values_list('transcriptions__type', 'transcriptions__text', 'transcriptions__zone', 'transcriptions__source', 'transcriptions__worker_version'),
             [
-                (TranscriptionType.Line, ('Hello world !'), None, None, version.id),
-                (TranscriptionType.Line, ('I <3 JavaScript'), None, None, version.id)
+                (TranscriptionType.Line, ('Hello world !'), None, None, self.worker_version.id),
+                (TranscriptionType.Line, ('I <3 JavaScript'), None, None, self.worker_version.id)
             ]
         )
         get_layer_mock().send.assert_called_once_with('reindex', {
@@ -318,17 +305,6 @@ class TestBulkElementTranscriptions(FixtureAPITestCase):
         """
         Transcriptions must be created with a source or a worker_version not both
         """
-        worker = Worker.objects.create(
-            repository=self.repo,
-            name='Worker 1',
-            slug='worker_1',
-            type=MLToolType.Classifier
-        )
-        version = WorkerVersion.objects.create(
-            worker=worker,
-            revision=self.rev,
-            configuration={"test": "test1"}
-        )
         self.client.force_login(self.user)
         response = self.client.post(
             reverse('api:element-transcriptions-bulk', kwargs={'pk': self.page.id}),
@@ -337,7 +313,7 @@ class TestBulkElementTranscriptions(FixtureAPITestCase):
                 'element_type': 'text_line',
                 'transcription_type': 'line',
                 'source': self.src.slug,
-                'worker_version': str(version.id),
+                'worker_version': str(self.worker_version.id),
                 'transcriptions': [{
                     'polygon': [[13, 37], [133, 37], [133, 137], [13, 137]],
                     'text': 'Can I write womething here ?',
diff --git a/arkindex/documents/tests/test_bulk_elements.py b/arkindex/documents/tests/test_bulk_elements.py
index fe5d1f52d3..ba333cfb4b 100644
--- a/arkindex/documents/tests/test_bulk_elements.py
+++ b/arkindex/documents/tests/test_bulk_elements.py
@@ -1,8 +1,8 @@
 from django.urls import reverse
 from rest_framework import status
-from arkindex_common.ml_tool import MLToolType
 from arkindex.project.tests import FixtureAPITestCase
 from arkindex.documents.models import Element
+from arkindex.dataimport.models import WorkerVersion
 
 
 class TestBulkElements(FixtureAPITestCase):
@@ -10,17 +10,7 @@ class TestBulkElements(FixtureAPITestCase):
     @classmethod
     def setUpTestData(cls):
         super().setUpTestData()
-        repo = cls.user.credentials.get().repos.get()
-        worker = repo.workers.create(
-            name='A worker',
-            slug='coworker',
-            type=MLToolType.Recognizer,
-        )
-        cls.worker_version = worker.workerversion_set.create(
-            revision=repo.revisions.get(),
-            configuration={},
-        )
-
+        cls.worker_version = WorkerVersion.objects.get(worker__slug='reco')
         cls.payload = {
             'worker_version': str(cls.worker_version.id),
             'elements': [
diff --git a/arkindex/documents/tests/test_children_elements.py b/arkindex/documents/tests/test_children_elements.py
index b371f143b5..2423ae9822 100644
--- a/arkindex/documents/tests/test_children_elements.py
+++ b/arkindex/documents/tests/test_children_elements.py
@@ -1,8 +1,7 @@
 from django.urls import reverse
 from rest_framework import status
-from arkindex_common.ml_tool import MLToolType
 from arkindex.documents.models import Element
-from arkindex.dataimport.models import Worker, WorkerVersion
+from arkindex.dataimport.models import WorkerVersion
 from arkindex.project.tests import FixtureAPITestCase
 import uuid
 
@@ -14,6 +13,7 @@ class TestChildrenElements(FixtureAPITestCase):
         super().setUpTestData()
         cls.vol = cls.corpus.elements.get(name='Volume 1')
         cls.element = Element.objects.get(name='Volume 1, page 2r')
+        cls.worker_version = WorkerVersion.objects.get(worker__slug='dla')
 
     def test_element_children(self):
         response = self.client.get(reverse('api:elements-children', kwargs={'pk': str(self.element.id)}))
@@ -100,23 +100,12 @@ class TestChildrenElements(FixtureAPITestCase):
         ])
 
     def test_element_children_worker_version(self):
-        worker = Worker.objects.create(
-            repository=self.user.credentials.get().repos.get(),
-            name='Worker 1',
-            slug='worker_1',
-            type=MLToolType.Classifier
-        )
-        version = WorkerVersion.objects.create(
-            worker=worker,
-            revision=worker.repository.revisions.get(),
-            configuration={"test": "test1"}
-        )
-        self.corpus.elements.filter(name__contains='page 1r').update(worker_version=version)
+        self.corpus.elements.filter(name__contains='page 1r').update(worker_version=self.worker_version)
 
         with self.assertNumQueries(8):
             response = self.client.get(
                 reverse('api:elements-children', kwargs={'pk': str(self.vol.id)}),
-                data={'worker_version': str(version.id)}
+                data={'worker_version': str(self.worker_version.id)}
             )
 
         self.assertListEqual(
diff --git a/arkindex/documents/tests/test_create_elements.py b/arkindex/documents/tests/test_create_elements.py
index ff5ae4b51f..49eb0b0eb8 100644
--- a/arkindex/documents/tests/test_create_elements.py
+++ b/arkindex/documents/tests/test_create_elements.py
@@ -1,7 +1,7 @@
 from django.urls import reverse
 from rest_framework import status
 from arkindex_common.ml_tool import MLToolType
-from arkindex.dataimport.models import Worker, WorkerVersion
+from arkindex.dataimport.models import WorkerVersion
 from arkindex.documents.models import \
     Element, DataSource, Corpus
 from arkindex.images.models import ImageServer
@@ -25,9 +25,7 @@ class TestCreateElements(FixtureAPITestCase):
             width=42,
             height=42,
         )
-        cls.creds = cls.user.credentials.get()
-        cls.repo = cls.creds.repos.get()
-        cls.rev = cls.repo.revisions.get()
+        cls.worker_version = WorkerVersion.objects.get(worker__slug='dla')
 
     def make_create_request(self, name='default', corpus=None, elt_type='volume', **options):
         request = {
@@ -161,21 +159,10 @@ class TestCreateElements(FixtureAPITestCase):
     def test_create_element_worker_version(self):
         # Create an element with a worker version
         self.client.force_login(self.user)
-        worker = Worker.objects.create(
-            repository=self.repo,
-            name='Worker 1',
-            slug='worker_1',
-            type=MLToolType.Classifier
-        )
-        version = WorkerVersion.objects.create(
-            worker=worker,
-            revision=self.rev,
-            configuration={"test": "test1"}
-        )
         request = self.make_create_request(
             name='Castle story',
             elt_type='act',
-            worker_version=str(version.id),
+            worker_version=str(self.worker_version.id),
         )
         with self.assertNumQueries(8):
             response = self.client.post(**request)
@@ -184,7 +171,7 @@ class TestCreateElements(FixtureAPITestCase):
         self.assertEqual(act.name, 'Castle story')
         self.assertEqual(act.type, self.act_type)
         self.assertEqual(act.source, None)
-        self.assertEqual(act.worker_version, version)
+        self.assertEqual(act.worker_version, self.worker_version)
 
     def test_create_element_source_and_worker_version_returns_error(self):
         # Create an element with a source and a worker version (not allowed)
@@ -194,22 +181,11 @@ class TestCreateElements(FixtureAPITestCase):
             slug='fairy_tale_detector',
             internal=False,
         )
-        worker = Worker.objects.create(
-            repository=self.repo,
-            name='Worker 1',
-            slug='worker_1',
-            type=MLToolType.Classifier
-        )
-        version = WorkerVersion.objects.create(
-            worker=worker,
-            revision=self.rev,
-            configuration={"test": "test1"}
-        )
         request = self.make_create_request(
             name='Castle story',
             elt_type='act',
             source='fairy_tale_detector',
-            worker_version=str(version.id),
+            worker_version=str(self.worker_version.id),
         )
         with self.assertNumQueries(6):
             response = self.client.post(**request)
diff --git a/arkindex/documents/tests/test_create_transcriptions.py b/arkindex/documents/tests/test_create_transcriptions.py
index 71c68982ac..0be51e5152 100644
--- a/arkindex/documents/tests/test_create_transcriptions.py
+++ b/arkindex/documents/tests/test_create_transcriptions.py
@@ -6,7 +6,7 @@ from rest_framework import status
 from arkindex.project.tests import FixtureAPITestCase
 from arkindex_common.enums import TranscriptionType
 from arkindex_common.ml_tool import MLToolType
-from arkindex.dataimport.models import Worker, WorkerVersion
+from arkindex.dataimport.models import WorkerVersion
 from arkindex.documents.models import Corpus, Transcription, DataSource
 from arkindex.users.models import User
 from uuid import uuid4
@@ -30,9 +30,7 @@ class TestTranscriptionCreate(FixtureAPITestCase):
         cls.private_read_user.verified_email = True
         cls.private_read_user.save()
         cls.private_corpus.corpus_right.create(user=cls.private_read_user)
-        cls.creds = cls.user.credentials.get()
-        cls.repo = cls.creds.repos.get()
-        cls.rev = cls.repo.revisions.get()
+        cls.worker_version = WorkerVersion.objects.get(worker__slug='reco')
 
     def setUp(self):
         self.manual_source = DataSource.objects.create(type=MLToolType.Recognizer, slug='manual', internal=False)
@@ -251,17 +249,6 @@ class TestTranscriptionCreate(FixtureAPITestCase):
 
     def test_create_transcription_source_and_worker_version_returns_error(self):
         self.client.force_login(self.user)
-        worker = Worker.objects.create(
-            repository=self.repo,
-            name='Worker 1',
-            slug='worker_1',
-            type=MLToolType.Classifier
-        )
-        version = WorkerVersion.objects.create(
-            worker=worker,
-            revision=self.rev,
-            configuration={"test": "test1"}
-        )
         response = self.client.post(
             reverse('api:transcription-create', kwargs={'pk': self.line.id}),
             format='json',
@@ -269,7 +256,7 @@ class TestTranscriptionCreate(FixtureAPITestCase):
                 'type': 'word',
                 'text': 'NEKUDOTAYIM',
                 'source': 'manual',
-                'worker_version': str(version.id),
+                'worker_version': str(self.worker_version.id),
             }
         )
         self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
@@ -280,30 +267,22 @@ class TestTranscriptionCreate(FixtureAPITestCase):
 
     def test_create_transcription_worker_version_non_internal(self):
         self.client.force_login(self.user)
-        worker = Worker.objects.create(
-            repository=self.repo,
-            name='Worker 1',
-            slug='worker_1',
-            type=MLToolType.Classifier
-        )
-        version = WorkerVersion.objects.create(
-            worker=worker,
-            revision=self.rev,
-            configuration={"test": "test1"}
-        )
         response = self.client.post(
             reverse('api:transcription-create', kwargs={'pk': self.line.id}),
             format='json',
             data={
                 'type': 'word',
                 'text': 'NEKUDOTAYIM',
-                'worker_version': str(version.id),
+                'worker_version': str(self.worker_version.id),
                 'score': .42
             }
         )
         self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
         self.assertDictEqual(response.json(), {
-            'worker_version': [f'An internal user is required to create a transcription with the worker_version "{version.id}"']
+            'worker_version': [(
+                'An internal user is required to create a transcription '
+                f'with the worker_version "{self.worker_version.id}"'
+            )]
         })
 
     @patch('arkindex.project.triggers.get_channel_layer')
@@ -311,37 +290,26 @@ class TestTranscriptionCreate(FixtureAPITestCase):
         get_layer_mock.return_value.send = AsyncMock()
 
         self.client.force_login(self.internal_user)
-        worker = Worker.objects.create(
-            repository=self.repo,
-            name='Worker 1',
-            slug='worker_1',
-            type=MLToolType.Classifier
-        )
-        version = WorkerVersion.objects.create(
-            worker=worker,
-            revision=self.rev,
-            configuration={"test": "test1"}
-        )
         response = self.client.post(
             reverse('api:transcription-create', kwargs={'pk': self.line.id}),
             format='json',
             data={
                 'type': 'word',
                 'text': 'NEKUDOTAYIM',
-                'worker_version': str(version.id),
+                'worker_version': str(self.worker_version.id),
                 'score': .42
             }
         )
         self.assertEqual(response.status_code, status.HTTP_201_CREATED)
         tr = Transcription.objects.get(text='NEKUDOTAYIM')
-        self.assertEqual(tr.worker_version, version)
+        self.assertEqual(tr.worker_version, self.worker_version)
         self.assertDictEqual(response.json(), {
             'id': str(tr.id),
             'score': .42,
             'source': None,
             'text': 'NEKUDOTAYIM',
             'type': 'word',
-            'worker_version_id': str(version.id),
+            'worker_version_id': str(self.worker_version.id),
             'zone': None
         })
 
diff --git a/arkindex/documents/tests/test_entities_api.py b/arkindex/documents/tests/test_entities_api.py
index c1211ea728..5b1645f530 100644
--- a/arkindex/documents/tests/test_entities_api.py
+++ b/arkindex/documents/tests/test_entities_api.py
@@ -4,7 +4,7 @@ from unittest.mock import Mock, patch, call
 from rest_framework import status
 from arkindex_common.enums import MetaType
 from arkindex.project.tests import FixtureAPITestCase
-from arkindex.dataimport.models import Worker, WorkerVersion
+from arkindex.dataimport.models import WorkerVersion
 from django.contrib.gis.geos import LinearRing
 from arkindex.documents.models import (
     Corpus, Element, TranscriptionType, DataSource, MLToolType,
@@ -29,9 +29,7 @@ class TestEntitiesAPI(FixtureAPITestCase):
         )
         cls.source = DataSource.objects.get(slug='test', type=MLToolType.Recognizer)
         cls.private_corpus = Corpus.objects.create(name='private')
-        cls.creds = cls.user.credentials.get()
-        cls.repo = cls.creds.repos.get()
-        cls.rev = cls.repo.revisions.get()
+        cls.worker_version = WorkerVersion.objects.get(worker__slug='reco')
 
     def setUp(self):
         super().setUp()
@@ -325,17 +323,6 @@ class TestEntitiesAPI(FixtureAPITestCase):
         })
 
     def test_create_entity_with_source_and_worker_version_returns_error(self):
-        worker = Worker.objects.create(
-            repository=self.repo,
-            name='Worker 1',
-            slug='worker_1',
-            type=MLToolType.Classifier
-        )
-        version = WorkerVersion.objects.create(
-            worker=worker,
-            revision=self.rev,
-            configuration={"test": "test1"}
-        )
         data = {
             'name': '1789',
             'type': EntityType.Date.value,
@@ -345,7 +332,7 @@ class TestEntitiesAPI(FixtureAPITestCase):
                 'other key': 'other value'
             },
             'ner': self.entity_source.slug,
-            'worker_version': str(version.id)
+            'worker_version': str(self.worker_version.id)
         }
         self.client.force_login(self.user)
         response = self.client.post(reverse('api:entity-create'), data=data, format='json')
@@ -356,17 +343,6 @@ class TestEntitiesAPI(FixtureAPITestCase):
         })
 
     def test_create_entity_with_worker_version(self):
-        worker = Worker.objects.create(
-            repository=self.repo,
-            name='Worker 1',
-            slug='worker_1',
-            type=MLToolType.Classifier
-        )
-        version = WorkerVersion.objects.create(
-            worker=worker,
-            revision=self.rev,
-            configuration={"test": "test1"}
-        )
         data = {
             'name': '1789',
             'type': EntityType.Date.value,
@@ -375,7 +351,7 @@ class TestEntitiesAPI(FixtureAPITestCase):
                 'key': 'value',
                 'other key': 'other value'
             },
-            'worker_version': str(version.id)
+            'worker_version': str(self.worker_version.id)
         }
         self.client.force_login(self.user)
         response = self.client.post(reverse('api:entity-create'), data=data, format='json')
@@ -383,7 +359,7 @@ class TestEntitiesAPI(FixtureAPITestCase):
         entity = Entity.objects.get(id=response.json()['id'])
         self.assertEqual(entity.name, '1789')
         self.assertEqual(entity.source, None)
-        self.assertEqual(entity.worker_version, version)
+        self.assertEqual(entity.worker_version, self.worker_version)
 
     def test_create_link(self):
         child = Entity.objects.create(
@@ -579,19 +555,8 @@ class TestEntitiesAPI(FixtureAPITestCase):
         )
 
     def test_list_transcription_entities_worker_version(self):
-        worker = Worker.objects.create(
-            repository=self.repo,
-            name='Worker 1',
-            slug='worker_1',
-            type=MLToolType.Classifier
-        )
-        version = WorkerVersion.objects.create(
-            worker=worker,
-            revision=self.rev,
-            configuration={"test": "test1"}
-        )
         self.entity_bis.source = None
-        self.entity_bis.worker_version = version
+        self.entity_bis.worker_version = self.worker_version
         self.entity_bis.save()
 
         response = self.client.get(reverse('api:transcription-entities', kwargs={'pk': str(self.transcription.id)}))
@@ -607,7 +572,7 @@ class TestEntitiesAPI(FixtureAPITestCase):
                     'validated': False,
                     'dates': [],
                     'source': None,
-                    'worker_version_id': str(version.id),
+                    'worker_version_id': str(self.worker_version.id),
                 },
                 'length': 8,
                 'offset': 2
@@ -715,25 +680,14 @@ class TestEntitiesAPI(FixtureAPITestCase):
         self.assertEqual(response.json(), {'worker_version': ['This worker version does not exist.']})
 
     def test_list_element_entities_worker_version(self):
-        worker = Worker.objects.create(
-            repository=self.repo,
-            name='Worker 1',
-            slug='worker_1',
-            type=MLToolType.Classifier
-        )
-        version = WorkerVersion.objects.create(
-            worker=worker,
-            revision=self.rev,
-            configuration={"test": "test1"}
-        )
         self.entity.source = None
-        self.entity.worker_version = version
+        self.entity.worker_version = self.worker_version
         self.entity.save()
 
         with self.assertNumQueries(6):
             response = self.client.get(
                 reverse('api:element-entities', kwargs={'pk': str(self.page.id)}),
-                data={'worker_version': str(version.id)}
+                data={'worker_version': str(self.worker_version.id)}
             )
             self.assertEqual(response.status_code, status.HTTP_200_OK)
 
@@ -760,7 +714,7 @@ class TestEntitiesAPI(FixtureAPITestCase):
                             'dates': [],
                             'metas': None,
                             'source': None,
-                            'worker_version_id': str(version.id),
+                            'worker_version_id': str(self.worker_version.id),
                         },
                     }
                 ],
diff --git a/arkindex/documents/tests/test_list_elements.py b/arkindex/documents/tests/test_list_elements.py
index 84eedef388..25e6b53f19 100644
--- a/arkindex/documents/tests/test_list_elements.py
+++ b/arkindex/documents/tests/test_list_elements.py
@@ -1,15 +1,19 @@
 from django.urls import reverse
 from django.db.models.sql.constants import LOUTER
 from rest_framework import status
-from arkindex_common.ml_tool import MLToolType
 from arkindex.documents.models import Corpus
-from arkindex.dataimport.models import Worker, WorkerVersion
+from arkindex.dataimport.models import WorkerVersion
 from arkindex.project.tests import FixtureAPITestCase
 import uuid
 
 
 class TestListElements(FixtureAPITestCase):
 
+    @classmethod
+    def setUpTestData(cls):
+        super().setUpTestData()
+        cls.worker_version = WorkerVersion.objects.get(worker__slug='reco')
+
     def test_list_elements_filter_name(self):
         nameSelected = 'ol'
         with self.assertNumQueries(7):
@@ -114,23 +118,12 @@ class TestListElements(FixtureAPITestCase):
         )
 
     def test_list_elements_filter_worker_version(self):
-        worker = Worker.objects.create(
-            repository=self.user.credentials.get().repos.get(),
-            name='Worker 1',
-            slug='worker_1',
-            type=MLToolType.Classifier
-        )
-        version = WorkerVersion.objects.create(
-            worker=worker,
-            revision=worker.repository.revisions.get(),
-            configuration={"test": "test1"}
-        )
-        self.corpus.elements.filter(name__contains='Volume 2').update(worker_version=version)
+        self.corpus.elements.filter(name__contains='Volume 2').update(worker_version=self.worker_version)
 
         with self.assertNumQueries(9):
             response = self.client.get(
                 reverse('api:elements'),
-                data={'corpus': self.corpus.id, 'worker_version': str(version.id)},
+                data={'corpus': self.corpus.id, 'worker_version': str(self.worker_version.id)},
             )
         self.assertEqual(response.status_code, status.HTTP_200_OK)
         self.assertListEqual(
diff --git a/arkindex/documents/tests/test_moderation.py b/arkindex/documents/tests/test_moderation.py
index f38b9831d7..58aa646b76 100644
--- a/arkindex/documents/tests/test_moderation.py
+++ b/arkindex/documents/tests/test_moderation.py
@@ -2,7 +2,7 @@ from django.test import override_settings
 from django.urls import reverse
 from rest_framework import status
 
-from arkindex.dataimport.models import Worker, WorkerVersion
+from arkindex.dataimport.models import WorkerVersion
 from arkindex.documents.models import \
     ClassificationState, DataSource, MLClass, Element, Corpus, Classification, MLToolType
 from arkindex.project.tests import FixtureAPITestCase
@@ -26,9 +26,7 @@ class TestClasses(FixtureAPITestCase):
             revision='1.3.3.7',
             internal=False,
         )
-        cls.creds = cls.user.credentials.get()
-        cls.repo = cls.creds.repos.get()
-        cls.rev = cls.repo.revisions.get()
+        cls.worker_version = WorkerVersion.objects.get(worker__slug='dla')
         cls.internal_user = User.objects.get_by_natural_key('internal@internal.fr')
 
     def _create_classification(self):
@@ -148,23 +146,12 @@ class TestClasses(FixtureAPITestCase):
         })
 
     def test_classification_creation_source_and_worker_version_returns_error(self):
-        worker = Worker.objects.create(
-            repository=self.repo,
-            name='Worker 1',
-            slug='worker_1',
-            type=MLToolType.Classifier
-        )
-        version = WorkerVersion.objects.create(
-            worker=worker,
-            revision=self.rev,
-            configuration={"test": "test1"}
-        )
         self.client.force_login(self.user)
         response = self.client.post(reverse('api:classification-create'), {
             'element': str(self.element.id),
             'ml_class': str(self.text.id),
             'source': 'manual',
-            'worker_version': str(version.id),
+            'worker_version': str(self.worker_version.id),
             'confidence': 0.42,
             'high_confidence': False,
         })
@@ -215,56 +202,35 @@ class TestClasses(FixtureAPITestCase):
         """
         Test creating a classification on a worker_version requires an internal user
         """
-        worker = Worker.objects.create(
-            repository=self.repo,
-            name='Worker 1',
-            slug='worker_1',
-            type=MLToolType.Classifier
-        )
-        version = WorkerVersion.objects.create(
-            worker=worker,
-            revision=self.rev,
-            configuration={"test": "test1"}
-        )
         self.client.force_login(self.user)
         response = self.client.post(reverse('api:classification-create'), {
             'element': str(self.element.id),
             'ml_class': str(self.text.id),
-            'worker_version': str(version.id),
+            'worker_version': str(self.worker_version.id),
         })
         self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
         self.assertDictEqual(response.json(), {
-            'worker_version': [
-                f'An internal user is required to create a classification with the worker_version "{version.id}"'
-            ],
+            'worker_version': [(
+                'An internal user is required to create a classification '
+                f'with the worker_version "{self.worker_version.id}"'
+            )],
             'confidence': ['This field is required for non manual sources.'],
             'high_confidence': ['This field is required for non manual sources.'],
         })
 
     def test_classification_creation_worker_version(self):
-        worker = Worker.objects.create(
-            repository=self.repo,
-            name='Worker 1',
-            slug='worker_1',
-            type=MLToolType.Classifier
-        )
-        version = WorkerVersion.objects.create(
-            worker=worker,
-            revision=self.rev,
-            configuration={"test": "test1"}
-        )
         self.client.force_login(self.internal_user)
         response = self.client.post(reverse('api:classification-create'), {
             'element': str(self.element.id),
             'ml_class': str(self.text.id),
-            'worker_version': str(version.id),
+            'worker_version': str(self.worker_version.id),
             'confidence': 0.42,
             'high_confidence': False,
         })
         self.assertEqual(response.status_code, status.HTTP_201_CREATED)
         classification = self.element.classifications.get()
         self.assertEqual(classification.source, None)
-        self.assertEqual(classification.worker_version, version)
+        self.assertEqual(classification.worker_version, self.worker_version)
         self.assertEqual(classification.ml_class, self.text)
         self.assertEqual(classification.state, ClassificationState.Pending)
         self.assertEqual(classification.confidence, 0.42)
diff --git a/arkindex/documents/tests/test_parents_elements.py b/arkindex/documents/tests/test_parents_elements.py
index dcace96a97..b3f3a5e5b5 100644
--- a/arkindex/documents/tests/test_parents_elements.py
+++ b/arkindex/documents/tests/test_parents_elements.py
@@ -2,7 +2,7 @@ from django.urls import reverse
 from rest_framework import status
 from arkindex_common.ml_tool import MLToolType
 from arkindex.documents.models import Element, DataSource, Corpus
-from arkindex.dataimport.models import Worker, WorkerVersion
+from arkindex.dataimport.models import WorkerVersion
 from arkindex.project.tests import FixtureAPITestCase
 import uuid
 
@@ -16,6 +16,7 @@ class TestParentsElements(FixtureAPITestCase):
         cls.private_corpus = Corpus.objects.create(name='private', public=False)
         cls.private_elt = cls.private_corpus.elements.create(type=cls.private_corpus.types.create(slug='type'))
         cls.manual_source = DataSource.objects.create(type=MLToolType.Recognizer, slug='manual', internal=True)
+        cls.worker_version = WorkerVersion.objects.get(worker__slug='reco')
 
     def setUp(self):
         self.page = self.corpus.elements.get(name='Volume 1, page 1r')
@@ -68,23 +69,15 @@ class TestParentsElements(FixtureAPITestCase):
         self.assertEqual(response.json()['results'][0]['name'], 'Act 1')
 
     def test_parents_worker_version(self):
-        worker = Worker.objects.create(
-            repository=self.user.credentials.get().repos.get(),
-            name='Worker 1',
-            slug='worker_1',
-            type=MLToolType.Classifier
-        )
-        version = WorkerVersion.objects.create(
-            worker=worker,
-            revision=worker.repository.revisions.get(),
-            configuration={"test": "test1"}
-        )
-        self.corpus.elements.filter(name__contains='Volume 1').update(worker_version=version)
+        """
+        List parents filtered by worker_version
+        """
+        self.corpus.elements.filter(name__contains='Volume 1').update(worker_version=self.worker_version)
 
         with self.assertNumQueries(6):
             response = self.client.get(
                 reverse('api:elements-parents', kwargs={'pk': str(self.page.id)}),
-                data={'worker_version': str(version.id)},
+                data={'worker_version': str(self.worker_version.id)},
             )
             self.assertEqual(response.status_code, status.HTTP_200_OK)
 
diff --git a/arkindex/documents/tests/test_transcriptions.py b/arkindex/documents/tests/test_transcriptions.py
index a32205df96..2024377959 100644
--- a/arkindex/documents/tests/test_transcriptions.py
+++ b/arkindex/documents/tests/test_transcriptions.py
@@ -5,7 +5,7 @@ from django.contrib.gis.geos import LinearRing
 from arkindex_common.enums import TranscriptionType
 from arkindex_common.ml_tool import MLToolType
 from arkindex.documents.models import Corpus, DataSource
-from arkindex.dataimport.models import Worker, WorkerVersion
+from arkindex.dataimport.models import WorkerVersion
 from arkindex.users.models import User
 
 
@@ -27,17 +27,7 @@ class TestTranscriptions(FixtureAPITestCase):
         cls.private_read_user = User.objects.create_user('a@bc.de', 'a')
         cls.private_read_user.verified_email = True
         cls.private_read_user.save()
-        cls.repo = cls.user.credentials.get().repos.get()
-        cls.worker_version = WorkerVersion.objects.create(
-            worker=Worker.objects.create(
-                repository=cls.repo,
-                name='Test Worker',
-                slug='test_worker',
-                type=MLToolType.Classifier
-            ),
-            revision=cls.repo.revisions.get(),
-            configuration={"test": "test1"}
-        )
+        cls.worker_version = WorkerVersion.objects.get(worker__slug='reco')
 
     def test_list_transcriptions_read_right(self):
         # A read right on the element corpus is required to access transcriptions
diff --git a/arkindex/users/tests/test_gitlab_oauth.py b/arkindex/users/tests/test_gitlab_oauth.py
index 896a12c24e..04805eb8be 100644
--- a/arkindex/users/tests/test_gitlab_oauth.py
+++ b/arkindex/users/tests/test_gitlab_oauth.py
@@ -143,6 +143,8 @@ class TestGitLabOAuthProvider(FixtureTestCase):
 
         GitLabOAuthProvider(request=request_mock, credentials=self.creds).disconnect()
 
-        self.assertEqual(self.gl_mock().projects.get.call_count, 1)
-        self.assertEqual(self.gl_mock().projects.get.return_value.hooks.list.call_count, 1)
-        self.assertEqual(hook_mock.delete.call_count, 1)
+        # Number of repositories associated to those credentials
+        repos_count = self.creds.repos.count()
+        self.assertEqual(self.gl_mock().projects.get.call_count, repos_count)
+        self.assertEqual(self.gl_mock().projects.get.return_value.hooks.list.call_count, repos_count)
+        self.assertEqual(hook_mock.delete.call_count, repos_count)
-- 
GitLab