def test_try_register_documents_call_article_factory_once(self):
        article_factory_mock = MagicMock()
        self.mk_hooks.KERNEL_HOOK_BASE.run.side_effect = [
            MagicMock(url="http://kernel_url/")
        ]

        try_register_documents(
            documents=self.documents,
            get_relation_data=lambda _: (
                "issue-1",
                {
                    "id": "67TH7T7CyPPmgtVrGXhWXVs",
                    "order": "01"
                },
            ),
            fetch_document_front=lambda _: self.document_front,
            article_factory=article_factory_mock,
        )

        article_factory_mock.assert_called_once_with(
            "67TH7T7CyPPmgtVrGXhWXVs",
            self.document_front,
            "issue-1",
            "01",
            "http://kernel_url/documents/67TH7T7CyPPmgtVrGXhWXVs",
        )
    def test_try_register_documents_call_fetch_document_front_once(self):
        fetch_document_front_mock = MagicMock()
        article_factory_mock = MagicMock()

        try_register_documents(
            documents=self.documents,
            get_relation_data=lambda _: ("", {}),
            fetch_document_front=fetch_document_front_mock,
            article_factory=article_factory_mock,
        )

        fetch_document_front_mock.assert_called_once_with(
            "67TH7T7CyPPmgtVrGXhWXVs")
    def test_try_register_documents_call_save_methods_from_article_instance(
            self):
        article_factory_mock = MagicMock()
        article_instance_mock = MagicMock()
        article_factory_mock.return_value = article_instance_mock

        try_register_documents(
            documents=self.documents,
            get_relation_data=lambda document_id: (
                "issue-1",
                {
                    "id": "67TH7T7CyPPmgtVrGXhWXVs",
                    "order": "01"
                },
            ),
            fetch_document_front=lambda document_id: self.document_front,
            article_factory=article_factory_mock,
        )

        article_instance_mock.save.assert_called_once()
    def test_try_register_document_should_be_orphan_when_issue_was_not_found(
            self):
        article_factory_mock = MagicMock()

        orphans = try_register_documents(
            documents=self.documents,
            get_relation_data=lambda document_id: (),
            fetch_document_front=lambda document_id: self.document_front,
            article_factory=article_factory_mock,
        )

        self.assertEqual(1, len(orphans))
        self.assertEqual(["67TH7T7CyPPmgtVrGXhWXVs"], orphans)
Exemplo n.º 5
0
def register_documents(**kwargs):
    """Registra documentos na base de dados do OPAC a partir de
    informações vindas da API do `Kernel`. Armazena como órfãos nas variáveis
    do Airflow os documentos que não puderam ser salvos."""

    mongo_connect()

    tasks = kwargs["ti"].xcom_pull(key="tasks", task_ids="read_changes_task")

    def _get_relation_data(document_id: str) -> Tuple[str, Dict]:
        """Recupera informações sobre o relacionamento entre o 
        DocumentsBundle e o Document.

        Retorna uma tupla contendo o identificador da issue onde o
        documento está relacionado e o item do relacionamento.

        >> _get_relation_data("67TH7T7CyPPmgtVrGXhWXVs")
        ('0034-8910-2019-v53', {'id': '67TH7T7CyPPmgtVrGXhWXVs', 'order': '01'})

        :param document_id: Identificador único de um documento
        """

        for issue_id, items in known_documents.items():
            for item in items:
                if document_id == item["id"]:
                    return (issue_id, item)

        return ()

    def _get_known_documents(**kwargs) -> Dict[str, List[str]]:
        """Recupera a lista de todos os documentos que estão relacionados com
        um `DocumentsBundle`.

        Levando em consideração que a DAG que detecta mudanças na API do Kernel
        roda de forma assíncrona em relação a DAG de espelhamento/sincronização.

        É possível que algumas situações especiais ocorram onde em uma rodada
        **anterior** o **evento de registro** de um `Document` foi capturado mas a 
        atualização de seu `DocumentsBundle` não ocorreu (elas ocorrem em transações
        distintas e possuem timestamps também distintos). O documento será
        registrado como **órfão** e sua `task` não será processada na próxima
        execução.

        Na próxima execução a task `register_issue_task` entenderá que o
        `bundle` é órfão e não conhecerá os seus documentos (known_documents)
        e consequentemente o documento continuará órfão.

        Uma solução para este problema é atualizar a lista de documentos
        conhecidos a partir da lista de eventos de `get` de `bundles`.
        """

        known_documents = kwargs["ti"].xcom_pull(
            key="i_documents", task_ids="register_issues_task"
        )

        issues_recently_updated = [
            get_id(task["id"]) for task in filter_changes(tasks, "bundles", "get")
            if known_documents.get(get_id(task["id"])) is None
        ]

        for issue_id in issues_recently_updated:
            known_documents.setdefault(issue_id, [])
            known_documents[issue_id] = list(
                itertools.chain(
                    known_documents[issue_id], fetch_bundles(issue_id).get("items", [])
                )
            )
        return known_documents

    known_documents = _get_known_documents(**kwargs)

    # TODO: Em caso de um update no document é preciso atualizar o registro
    # Precisamos de uma nova task?

    documents_to_get = itertools.chain(
        Variable.get("orphan_documents", default_var=[], deserialize_json=True),
        (get_id(task["id"]) for task in filter_changes(tasks, "documents", "get")),
    )

    orphans = try_register_documents(
        documents_to_get, _get_relation_data, fetch_documents_front, ArticleFactory
    )

    Variable.set("orphan_documents", orphans, serialize_json=True)