Exemplo n.º 1
0
def create_encryption_event(encr_result, key_fingerprint):
    """Return a PREMIS:EVENT for the encryption event."""
    # First line of stdout from ``gpg --version`` is expected to be
    # something like 'gpg (GnuPG) 1.4.16'
    gpg_version = subprocess.check_output(['gpg', '--version'
                                           ]).splitlines()[0].split()[-1]
    # detail = escape(
    #     'program=gpg (GnuPG); version={}; python-gnupg; version={}'.format(
    #         gpg_version, gnupg.__version__))
    detail = escape('program=GPG; version={}; key={}'.format(
        gpg_version, key_fingerprint))
    outcome_detail_note = 'Status="{}"; Standard Error="{}"'.format(
        encr_result.status.replace('"', r'\"'),
        encr_result.stderr.replace('"', r'\"').strip())
    agents = utils.get_ss_premis_agents()
    event = [
        'event', premisrw.PREMIS_META,
        (
            'event_identifier',
            ('event_identifier_type', 'UUID'),
            ('event_identifier_value', str(uuid4())),
        ), ('event_type', 'encryption'),
        ('event_date_time', utils.mets_file_now()), ('event_detail', detail),
        ('event_outcome_information', ('event_outcome', 'success'),
         ('event_outcome_detail', ('event_outcome_detail_note',
                                   outcome_detail_note)))
    ]
    event = tuple(utils.add_agents_to_event_as_list(event, agents))
    return premisrw.PREMISEvent(data=event)
Exemplo n.º 2
0
def create_encryption_event(encr_result, key_fingerprint):
    """Return a PREMIS:EVENT for the encryption event."""
    gpg_version = _get_gpg_version()
    detail = escape(
        'program=GPG; version={}; key={}'.format(
            gpg_version, key_fingerprint))
    outcome_detail_note = 'Status="{}"; Standard Error="{}"'.format(
        encr_result.status.replace('"', r'\"'),
        encr_result.stderr.replace('"', r'\"').strip())
    agents = utils.get_ss_premis_agents()
    event = [
        'event',
        premisrw.PREMIS_META,
        (
            'event_identifier',
            ('event_identifier_type', 'UUID'),
            ('event_identifier_value', str(uuid4())),
        ),
        ('event_type', 'encryption'),
        ('event_date_time', utils.mets_file_now()),
        ('event_detail', detail),
        (
            'event_outcome_information',
            ('event_outcome', 'success'),
            (
                'event_outcome_detail',
                ('event_outcome_detail_note', outcome_detail_note)
            )
        )
    ]
    event = tuple(utils.add_agents_to_event_as_list(event, agents))
    return premisrw.PREMISEvent(data=event)
Exemplo n.º 3
0
 def create_test_pointer_file(self):
     # 1. Get the PREMIS events and object as premisrw class instances.
     compression_event = premisrw.PREMISEvent(data=c.EX_COMPR_EVT)
     events = [compression_event]
     _, compression_program_version, archive_tool = (
         compression_event.compression_details)
     premis_object = premisrw.PREMISObject(
         xsi_type=c.EX_PTR_XSI_TYPE,
         identifier_value=c.EX_PTR_IDENTIFIER_VALUE,
         message_digest_algorithm=c.EX_PTR_MESSAGE_DIGEST_ALGORITHM,
         message_digest=c.EX_PTR_MESSAGE_DIGEST,
         size=c.EX_PTR_SIZE,
         format_name=c.EX_PTR_FORMAT_NAME,
         format_registry_key=c.EX_PTR_FORMAT_REGISTRY_KEY,
         creating_application_name=archive_tool,
         creating_application_version=compression_program_version,
         date_created_by_application=c.EX_PTR_DATE_CREATED_BY_APPLICATION)
     transform_files = compression_event.get_decompression_transform_files()
     # 2. Construct the METS pointer file
     mw = metsrw.METSDocument()
     mets_fs_entry = metsrw.FSEntry(path=c.EX_PTR_PATH,
                                    file_uuid=c.EX_PTR_IDENTIFIER_VALUE,
                                    use=c.EX_PTR_PACKAGE_TYPE,
                                    type=c.EX_PTR_PACKAGE_TYPE,
                                    transform_files=transform_files,
                                    mets_div_type=c.EX_PTR_AIP_SUBTYPE)
     mets_fs_entry.add_premis_object(premis_object.serialize())
     for event in events:
         mets_fs_entry.add_premis_event(event.serialize())
     for agent in [c.EX_AGT_1, c.EX_AGT_2]:
         mets_fs_entry.add_premis_agent(premisrw.data_to_premis(agent))
     mw.append_file(mets_fs_entry)
     return mw
Exemplo n.º 4
0
 def test_premis_event_cls_data(self):
     """Tests that you can pass a Python tuple as the ``data`` argument to
     ``PREMISEvent`` to construct an instance.
     """
     premis_obj = premisrw.PREMISEvent(data=c.EX_COMPR_EVT)
     lxml_el = premis_obj.serialize()
     data = premisrw.premis_to_data(lxml_el)
     assert data == c.EX_COMPR_EVT
Exemplo n.º 5
0
    def test_premis_event_cls_kwargs(self):
        """You should be able to pass sanely-named kwargs to ``PREMISEvent`` on
        instantiation.
        """
        premis_obj = premisrw.PREMISEvent(
            identifier_value=c.EX_COMPR_EVT_IDENTIFIER_VALUE,
            type=c.EX_COMPR_EVT_TYPE,
            date_time=c.EX_COMPR_EVT_DATE_TIME,
            detail=c.EX_COMPR_EVT_DETAIL,
            outcome_detail_note=c.EX_COMPR_EVT_OUTCOME_DETAIL_NOTE,
            linking_agent_identifier=c.EX_COMPR_EVT_AGENTS)
        lxml_el = premis_obj.serialize()
        data = premisrw.premis_to_data(lxml_el)

        assert data == c.EX_COMPR_EVT
Exemplo n.º 6
0
    def test_dependency_injection(self):
        """Test the dependency injection (DI) infrastructure for metsrw plugins.

        - client: metsrw.FSEntry
        - services: classes for reading and writing metadata elements, e.g.,
          the PREMISObject class of metsrw.plugins.premisrw or other classes
          exposing the same interface.
        - injector: this test code or the code in metsrw/di.py which calls
          ``provide`` on the ``feature_broker`` singleton.

        The ``FSEntry`` class declares its dependency on the class attributes
        ``premis_object_class``, ``premis_event_class``, and
        ``premis_agent_class`` and further requires that these return classes
        with ``fromtree`` and ``serialize`` methods::

            >>> premis_object_class = Dependency(
            ...     has_methods('serialize'),
            ...     has_class_methods('fromtree'),
            ...     is_class)

        """

        # Clear the feature broker and then register/provide the premisrw
        # plugin classes (services) with the feature broker.
        feature_broker = metsrw.feature_broker
        assert len(feature_broker) == 3
        feature_broker.clear()
        assert not feature_broker
        feature_broker.provide('premis_object_class', premisrw.PREMISObject)
        feature_broker.provide('premis_event_class', premisrw.PREMISEvent)
        feature_broker.provide('premis_agent_class', premisrw.PREMISAgent)
        assert len(feature_broker) == 3

        # Create premisrw instances.
        compression_premis_event = premisrw.PREMISEvent(data=EX_COMPR_EVT)
        premis_events = [compression_premis_event]
        premis_agents = [
            premisrw.PREMISAgent(data=x) for x in [EX_AGT_1, EX_AGT_2]
        ]
        _, compression_program_version, archive_tool = (
            compression_premis_event.compression_details)
        premis_object = premisrw.PREMISObject(
            xsi_type=EX_PTR_XSI_TYPE,
            identifier_value=EX_PTR_IDENTIFIER_VALUE,
            message_digest_algorithm=EX_PTR_MESSAGE_DIGEST_ALGORITHM,
            message_digest=EX_PTR_MESSAGE_DIGEST,
            size=EX_PTR_SIZE,
            format_name=EX_PTR_FORMAT_NAME,
            format_registry_key=EX_PTR_FORMAT_REGISTRY_KEY,
            creating_application_name=archive_tool,
            creating_application_version=compression_program_version,
            date_created_by_application=EX_PTR_DATE_CREATED_BY_APPLICATION)
        transform_files = compression_premis_event.get_decompression_transform_files(
        )

        # Create metsrw ``METSDocument`` and ``FSEntry`` instances.
        mets_doc = metsrw.METSDocument()
        fs_entry = metsrw.FSEntry(path=EX_PTR_PATH,
                                  file_uuid=EX_PTR_IDENTIFIER_VALUE,
                                  use=EX_PTR_PACKAGE_TYPE,
                                  type=EX_PTR_PACKAGE_TYPE,
                                  transform_files=transform_files,
                                  mets_div_type=EX_PTR_AIP_SUBTYPE)
        mets_doc.append_file(fs_entry)

        # Use the ``add_premis_...`` methods to add the PREMIS metadata
        # elements to the ``FSEntry`` instance. This will assert that each
        # PREMIS instance is of the correct type (e.g., that ``premis_object``
        # is an instance of ``FSEntry().premis_object_class``) and will call the
        # instance's ``serialize`` method and incorporate the resulting
        # ``lxml.etree._ElementTree`` instance into the ``FSEntry`` instance
        # appropriately.
        fs_entry.add_premis_object(premis_object)
        for premis_event in premis_events:
            fs_entry.add_premis_event(premis_event)
        for premis_agent in premis_agents:
            fs_entry.add_premis_agent(premis_agent)

        # Assert that the instances returned by the
        # ``FSEntry().get_premis_...`` methods are of the anticipated type.
        new_premis_agents = fs_entry.get_premis_agents()
        for new_premis_agent in new_premis_agents:
            assert isinstance(new_premis_agent, premisrw.PREMISAgent)
            assert new_premis_agent in premis_agents
            assert id(new_premis_agent) not in [id(pa) for pa in premis_agents]
        new_premis_events = fs_entry.get_premis_events()
        for new_premis_event in new_premis_events:
            assert isinstance(new_premis_event, premisrw.PREMISEvent)
            assert new_premis_event in premis_events
            assert id(new_premis_event) not in [id(pa) for pa in premis_events]
        new_premis_objects = fs_entry.get_premis_objects()
        for new_premis_object in new_premis_objects:
            assert isinstance(new_premis_object, premisrw.PREMISObject)
            assert new_premis_object == premis_object
            assert id(new_premis_object) is not premis_object

        # Assert that the resulting mets XML contains a
        # premis:objectIdentifierValue in the anticipated location in the
        # structure with the anticipated value.
        mets_doc_el = mets_doc.serialize()
        xpath = ('mets:amdSec/mets:techMD/mets:mdWrap[@MDTYPE="PREMIS:OBJECT"]'
                 '/mets:xmlData/premis:object/premis:objectIdentifier/'
                 'premis:objectIdentifierValue')
        a = mets_doc_el.find(xpath, namespaces=metsrw.NAMESPACES)
        assert a.text == EX_PTR_IDENTIFIER_VALUE

        # Now change the feature broker so that ``FSEntry``'s dependency on a
        # ``premis_object_class`` class attribute is being fulfilled by a new
        # class: ``BetterPREMISObject``.
        feature_broker.provide('premis_object_class', BetterPREMISObject)

        # Now create a new PREMIS object
        premis_object_tree = premis_object.serialize()
        better_premis_object = BetterPREMISObject.fromtree(premis_object_tree)

        # And re-create the ``METSDocument`` and ``FSEntry`` instances.
        mets_doc = metsrw.METSDocument()
        fs_entry = metsrw.FSEntry(path=EX_PTR_PATH,
                                  file_uuid=EX_PTR_IDENTIFIER_VALUE,
                                  use=EX_PTR_PACKAGE_TYPE,
                                  type=EX_PTR_PACKAGE_TYPE,
                                  transform_files=transform_files,
                                  mets_div_type=EX_PTR_AIP_SUBTYPE)
        mets_doc.append_file(fs_entry)

        # Add the PREMIS metadata again, but this time use the instance of
        # ``BetterPREMISObject``.
        fs_entry.add_premis_object(better_premis_object)
        for premis_event in premis_events:
            fs_entry.add_premis_event(premis_event)
        for premis_agent in premis_agents:
            fs_entry.add_premis_agent(premis_agent)

        # Assert that the instances returned by the
        # ``FSEntry().get_premis_...`` methods are of the anticipated type.
        new_premis_objects = fs_entry.get_premis_objects()
        for new_premis_object in new_premis_objects:
            assert isinstance(new_premis_object, BetterPREMISObject)

        # Make sure we can still find the PREMIS object id value.
        mets_doc_el = mets_doc.serialize()
        assert (mets_doc_el.find(
            xpath,
            namespaces=metsrw.NAMESPACES).text == EX_PTR_IDENTIFIER_VALUE)

        # Reset the feature broker to its default state so subsequent tests
        # don't break.
        metsrw.set_feature_broker_to_default_state(feature_broker)
Exemplo n.º 7
0
    def test_attr_get_set(self):
        compression_event = premisrw.PREMISEvent(data=c.EX_COMPR_EVT)
        _, compression_program_version, archive_tool = (
            compression_event.compression_details)
        INHIBITORS = (('inhibitors', ('inhibitor_type', 'GPG'),
                       ('inhibitor_target', 'All content')),
                      ('inhibitors', ('inhibitor_type', 'Password protection'),
                       ('inhibitor_target', 'Function: Play')))

        old_premis_object = premisrw.PREMISObject(
            xsi_type=c.EX_PTR_XSI_TYPE,
            identifier_value=c.EX_PTR_IDENTIFIER_VALUE,
            message_digest_algorithm=c.EX_PTR_MESSAGE_DIGEST_ALGORITHM,
            message_digest=c.EX_PTR_MESSAGE_DIGEST,
            size=c.EX_PTR_SIZE,
            format_name=c.EX_PTR_FORMAT_NAME,
            format_registry_key=c.EX_PTR_FORMAT_REGISTRY_KEY,
            creating_application_name=archive_tool,
            creating_application_version=compression_program_version,
            date_created_by_application=c.EX_PTR_DATE_CREATED_BY_APPLICATION,
            relationship=c.EX_RELATIONSHIP_1)
        assert old_premis_object.relationship == (c.EX_RELATIONSHIP_1, )
        new_composition_level = str(
            int(old_premis_object.composition_level) + 1)

        new_premis_object = premisrw.PREMISObject(
            xsi_type=old_premis_object.xsi_type,
            identifier_value=old_premis_object.identifier_value,
            message_digest_algorithm=old_premis_object.
            message_digest_algorithm,
            message_digest=old_premis_object.message_digest,
            size=old_premis_object.size,
            format_name=old_premis_object.format_name,
            format_registry_key=old_premis_object.format_registry_key,
            creating_application_name=old_premis_object.
            creating_application_name,
            creating_application_version=old_premis_object.
            creating_application_version,
            date_created_by_application=old_premis_object.
            date_created_by_application,
            # New attributes:
            relationship=[
                old_premis_object.relationship[0].data, c.EX_RELATIONSHIP_2
            ],
            inhibitors=INHIBITORS,
            composition_level=new_composition_level)

        for attr in ('xsi_type', 'identifier_value',
                     'message_digest_algorithm', 'message_digest', 'size',
                     'format_name', 'format_registry_key',
                     'creating_application_name',
                     'creating_application_version',
                     'date_created_by_application'):
            assert getattr(old_premis_object,
                           attr) == getattr(new_premis_object, attr)
        assert not old_premis_object.inhibitors
        assert new_premis_object.inhibitors == INHIBITORS
        assert old_premis_object.composition_level == '1'
        assert new_premis_object.composition_level == new_composition_level
        assert (old_premis_object.relationship[0],
                c.EX_RELATIONSHIP_2) == (new_premis_object.relationship)

        # Here are two ways to create a new PREMIS:OBJECT that's just like an
        # old one.

        # 1. Just pass in its data via the data kw
        new_premis_object = premisrw.PREMISObject(data=old_premis_object.data)
        assert new_premis_object == old_premis_object

        # 2. ...
        new_premis_object = premisrw.PREMISObject(
            xsi_type=old_premis_object.xsi_type,
            object_identifier=old_premis_object.find('object_identifier'),
            object_characteristics=old_premis_object.find(
                'object_characteristics'),
            relationship=old_premis_object.find('relationship'))
        assert new_premis_object == old_premis_object

        new_relationships = [
            r.data for r in old_premis_object.findall('relationship')
        ]
        new_relationships.append(c.EX_RELATIONSHIP_2)
        new_premis_object = premisrw.PREMISObject(
            xsi_type=old_premis_object.xsi_type,
            object_identifier=old_premis_object.find('object_identifier'),
            object_characteristics=old_premis_object.find(
                'object_characteristics'),
            relationship=new_relationships)
        assert new_premis_object.object_identifier == old_premis_object.object_identifier
        assert new_premis_object.object_characteristics == old_premis_object.object_characteristics
        assert new_premis_object.relationship != old_premis_object.relationship
        assert old_premis_object.find(
            'relationship') in new_premis_object.findall('relationship')
Exemplo n.º 8
0
 def test_encryption_event(self):
     encryption_event = premisrw.PREMISEvent(data=c.EX_ENCR_EVT)
     decr_tf = encryption_event.get_decryption_transform_file()
     assert decr_tf['algorithm'] == 'GPG'
     assert decr_tf['order'] == '1'
     assert decr_tf['type'] == 'decryption'
Exemplo n.º 9
0
    def test_dynamic_attrs(self):
        """Tests that dynamic attribute accession works correctly on
        PREMISElement subclasses. This allows us to use the output of the
        ``generate_data`` abstract method to dynamically create accessors for
        PREMIS entities, e.g., ``PREMISObject().identifier_value`` and
        ``PREMISObject().object_identifier_value`` should both return the value
        of the element at 'object_identifier/object_identifier_value' even
        though ``PREMISObject`` does not explicitly define either of those
        attributes.
        """
        compression_event = premisrw.PREMISEvent(data=c.EX_COMPR_EVT)
        _, compression_program_version, archive_tool = (
            compression_event.compression_details)
        inhibitors1 = ('inhibitors', ('inhibitorType', 'GPG'),
                       ('inhibitorTarget', 'All content'))
        premis_object = premisrw.PREMISObject(
            xsi_type=c.EX_PTR_XSI_TYPE,
            identifier_value=c.EX_PTR_IDENTIFIER_VALUE,
            message_digest_algorithm=c.EX_PTR_MESSAGE_DIGEST_ALGORITHM,
            message_digest=c.EX_PTR_MESSAGE_DIGEST,
            size=c.EX_PTR_SIZE,
            format_name=c.EX_PTR_FORMAT_NAME,
            format_registry_key=c.EX_PTR_FORMAT_REGISTRY_KEY,
            creating_application_name=archive_tool,
            creating_application_version=compression_program_version,
            date_created_by_application=c.EX_PTR_DATE_CREATED_BY_APPLICATION,
            inhibitors=[inhibitors1])
        assert premis_object.format_name == c.EX_PTR_FORMAT_NAME
        assert premis_object.identifier_value == c.EX_PTR_IDENTIFIER_VALUE
        assert premis_object.object_identifier_value == c.EX_PTR_IDENTIFIER_VALUE
        assert premis_object.message_digest == c.EX_PTR_MESSAGE_DIGEST
        assert premis_object.object_characteristics__fixity__message_digest == c.EX_PTR_MESSAGE_DIGEST

        # A partial path to a leaf element is not a valid accessor:
        with pytest.raises(AttributeError):
            premis_object.fixity__message_digest

        # XML attribute accessors
        assert premis_object.xsi_type == c.EX_PTR_XSI_TYPE  # namespaced
        assert premis_object.xsi__type == c.EX_PTR_XSI_TYPE  # namespaced
        assert premis_object.type == c.EX_PTR_XSI_TYPE  # not namespaced
        assert premis_object.xsi_schema_location == (
            premisrw.PREMIS_META['xsi:schema_location'])

        assert compression_event.event_type == c.EX_COMPR_EVT_TYPE
        assert compression_event.type == c.EX_COMPR_EVT_TYPE
        assert compression_event.event_detail == c.EX_COMPR_EVT_DETAIL
        assert compression_event.detail == c.EX_COMPR_EVT_DETAIL

        premis_agent_1 = premisrw.PREMISAgent(data=c.EX_AGT_1)
        assert premis_agent_1.name == c.EX_AGT_1_NAME
        assert premis_agent_1.type == c.EX_AGT_1_TYPE
        assert premis_agent_1.identifier_type == c.EX_AGT_1_IDENTIFIER_TYPE
        assert premis_agent_1.identifier_value == c.EX_AGT_1_IDENTIFIER_VALUE
        assert premis_agent_1.agent_name == c.EX_AGT_1_NAME
        assert premis_agent_1.agent_type == c.EX_AGT_1_TYPE
        assert premis_agent_1.agent_identifier_type == c.EX_AGT_1_IDENTIFIER_TYPE
        assert premis_agent_1.agent_identifier_value == c.EX_AGT_1_IDENTIFIER_VALUE
        assert premis_agent_1.agent_identifier__agent_identifier_type == c.EX_AGT_1_IDENTIFIER_TYPE
        with pytest.raises(AttributeError):
            premis_agent_1.agent_identifier__agent_name