mirror of
https://github.com/suitenumerique/docs.git
synced 2026-09-09 11:17:55 +02:00
✨(backend) allow too migrate a specific document
The management command migrating document to yhub didn't allow to target a specific document. This can be usefull for debugging purpose but also to replay the migration of a specific document.
This commit is contained in:
@@ -10,13 +10,17 @@ It is meant to be run again: every document it finishes is recorded, and the
|
||||
collaboration server answers "already" for anything it has already migrated, so
|
||||
a run that is interrupted, rate limited or killed simply picks up where it
|
||||
stopped. Nothing is destroyed, on either side.
|
||||
|
||||
One document can also be handed over on its own with `--document-id`, which is
|
||||
how a document a run left behind is dealt with once its cause is understood.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import time
|
||||
import uuid
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.utils import timezone
|
||||
|
||||
from core import models
|
||||
@@ -46,6 +50,16 @@ class Command(BaseCommand):
|
||||
|
||||
def add_arguments(self, parser):
|
||||
"""Define the arguments of the command."""
|
||||
parser.add_argument(
|
||||
"--document-id",
|
||||
type=uuid.UUID,
|
||||
default=None,
|
||||
help=(
|
||||
"Migrate this document alone, whatever a previous run recorded "
|
||||
"for it. The filters selecting a corpus (--created-before, "
|
||||
"--limit, --retry-failed) do not apply to it."
|
||||
),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--concurrency",
|
||||
type=int,
|
||||
@@ -136,7 +150,20 @@ class Command(BaseCommand):
|
||||
A document is opened before it is missed: the ones edited recently are
|
||||
the ones users are about to read, and until a document is migrated the
|
||||
collaboration server only seeds its latest state, without its history.
|
||||
|
||||
Naming one document is an instruction rather than a filter: it is handed
|
||||
over even when a previous run recorded it as done, which costs a call
|
||||
the collaboration server answers with "already". Nothing else would be
|
||||
useful — a command asked for one document and reporting that it had
|
||||
nothing to do says neither what happened nor why.
|
||||
"""
|
||||
if options["document_id"]:
|
||||
queryset = models.Document.objects.filter(pk=options["document_id"])
|
||||
if not queryset.exists():
|
||||
raise CommandError(f"No document with id {options['document_id']}")
|
||||
|
||||
return queryset
|
||||
|
||||
queryset = models.Document.objects.all()
|
||||
|
||||
if options["created_before"]:
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
"""Unit tests for the `migrate_documents` command."""
|
||||
|
||||
import uuid
|
||||
from io import StringIO
|
||||
from unittest import mock
|
||||
|
||||
from django.core.management import call_command
|
||||
from django.core.management.base import CommandError
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -167,3 +169,47 @@ def test_commands_migrate_documents_dry_run(collaboration_server):
|
||||
assert "2 documents to migrate" in output
|
||||
collaboration_server.assert_not_called()
|
||||
assert not models.DocumentMigration.objects.exists()
|
||||
|
||||
|
||||
def test_commands_migrate_documents_document_id(collaboration_server):
|
||||
"""Naming a document should hand over that one and leave the corpus alone."""
|
||||
factories.DocumentFactory.create_batch(3)
|
||||
document = factories.DocumentFactory()
|
||||
|
||||
output = run_command(document_id=document.pk)
|
||||
|
||||
assert collaboration_server.call_count == 1
|
||||
assert collaboration_server.call_args[0][0].pk == document.pk
|
||||
assert models.DocumentMigration.objects.get().document_id == document.pk
|
||||
assert "ok=1" in output
|
||||
|
||||
|
||||
def test_commands_migrate_documents_document_id_already_migrated(
|
||||
collaboration_server,
|
||||
):
|
||||
"""
|
||||
A document already recorded as done should be handed over again when named.
|
||||
|
||||
Asking for a document by its id is an instruction, not a filter over what is
|
||||
left to do: the collaboration server answers "already" when it has nothing
|
||||
to replay, which is the answer the run records.
|
||||
"""
|
||||
document = factories.DocumentFactory()
|
||||
run_command()
|
||||
collaboration_server.return_value = migrated(status="already")
|
||||
|
||||
run_command(document_id=document.pk)
|
||||
|
||||
assert collaboration_server.call_count == 2
|
||||
assert (
|
||||
models.DocumentMigration.objects.get(document=document).status
|
||||
== models.DocumentMigrationStatus.ALREADY
|
||||
)
|
||||
|
||||
|
||||
def test_commands_migrate_documents_document_id_unknown(collaboration_server):
|
||||
"""An id that is no document should stop the command, not migrate nothing."""
|
||||
with pytest.raises(CommandError, match="No document with id"):
|
||||
run_command(document_id=uuid.uuid4())
|
||||
|
||||
collaboration_server.assert_not_called()
|
||||
|
||||
Reference in New Issue
Block a user