Пример #1
0
def test_sync_execute_register_desktop_tag_not_linked():
    """Syncs a new d.Desktop with HID and a non-linked tag.

    It is OK if the tag was not linked, it will be linked in this process.
    """
    tag = Tag(id='foo')
    db.session.add(tag)
    db.session.commit()

    # Create a new transient non-db object
    pc = d.Desktop(**yaml2json('pc-components.db')['device'],
                   tags=OrderedSet([Tag(id='foo')]))
    returned_pc = Sync().execute_register(pc)
    assert returned_pc == pc
    assert tag.device == pc, 'Tag has to be linked'
    assert d.Desktop.query.one() == pc, 'd.Desktop had to be set to db'
Пример #2
0
def test_sync_execute_register_tag_linked_same_device():
    """
    If the tag is linked to the device, regardless if it has HID,
    the system should match the device through the tag.
    (If it has HID it validates both HID and tag point at the same
    device, this his checked in ).
    """
    orig_pc = Computer(**file('pc-components.db')['device'])
    db.session.add(Tag(id='foo', device=orig_pc))
    db.session.commit()

    pc = Computer(**file('pc-components.db')['device'])  # Create a new transient non-db object
    pc.tags.add(Tag(id='foo'))
    db_pc = Sync().execute_register(pc)
    assert db_pc.id == orig_pc.id
    assert len(db_pc.tags) == 1
    assert next(iter(db_pc.tags)).id == 'foo'
Пример #3
0
def test_sync_execute_register_tag_linked_other_device_mismatch_between_tags():
    """
    Checks that sync raises an error if finds that at least two passed-in
    tags are not linked to the same device.
    """
    pc1 = Computer(**file('pc-components.db')['device'])
    db.session.add(Tag(id='foo-1', device=pc1))
    pc2 = Computer(**file('pc-components.db')['device'])
    pc2.serial_number = 'pc2-serial'
    pc2.hid = Naming.hid(pc2.manufacturer, pc2.serial_number, pc2.model)
    db.session.add(Tag(id='foo-2', device=pc2))
    db.session.commit()

    pc1 = Computer(**file('pc-components.db')['device'])  # Create a new transient non-db object
    pc1.tags.add(Tag(id='foo-1'))
    pc1.tags.add(Tag(id='foo-2'))
    with raises(MismatchBetweenTags):
        Sync().execute_register(pc1)
Пример #4
0
 def create_tag(self,
                id: str,
                org: str = None,
                sec: str = None,
                provider: str = None):
     """Create a tag with the given ID."""
     db.session.add(Tag(**self.schema.load(
         dict(id=id, org=org, secondary=sec, provider=provider)
     )))
     db.session.commit()
Пример #5
0
def test_sync_execute_register_mismatch_between_tags_and_hid():
    """
    Checks that sync raises an error if it finds that the HID does
    not point at the same device as the tag does.

    In this case we set HID -> pc1 but tag -> pc2
    """
    pc1 = Computer(**file('pc-components.db')['device'])
    db.session.add(Tag(id='foo-1', device=pc1))
    pc2 = Computer(**file('pc-components.db')['device'])
    pc2.serial_number = 'pc2-serial'
    pc2.hid = Naming.hid(pc2.manufacturer, pc2.serial_number, pc2.model)
    db.session.add(Tag(id='foo-2', device=pc2))
    db.session.commit()

    pc1 = Computer(**file('pc-components.db')['device'])  # Create a new transient non-db object
    pc1.tags.add(Tag(id='foo-2'))
    with raises(MismatchBetweenTagsAndHid):
        Sync().execute_register(pc1)
Пример #6
0
def test_sync_execute_register_tag_does_not_exist():
    """
    Ensures not being able to register if the tag does not exist,
    even if the device has HID or it existed before.

    Tags have to be created before trying to link them through a Snapshot.
    """
    pc = Computer(**file('pc-components.db')['device'], tags=OrderedSet([Tag()]))
    with raises(ResourceNotFound):
        Sync().execute_register(pc)
Пример #7
0
def test_sync_execute_register_tag_does_not_exist():
    """Ensures not being able to register if the tag does not exist,
    even if the device has HID or it existed before.

    Tags have to be created before trying to link them through a Snapshot.
    """
    user = User.query.filter().first()
    pc = d.Desktop(**yaml2json('pc-components.db')['device'],
                   tags=OrderedSet([Tag('foo')]))
    pc.owner_id = user.id
    with raises(ResourceNotFound):
        Sync().execute_register(pc)
Пример #8
0
    def create_tags_csv(self, path: pathlib.Path, org: str, provider: str):
        """Creates tags by reading CSV from ereuse-tag.

        CSV must have the following columns:

        1. ID tag
        2. Secondary id tag (or empty)
        """
        with path.open() as f:
            for id, sec in csv.reader(f):
                db.session.add(Tag(**self.schema.load(
                    dict(id=id, org=org, secondary=sec, provider=provider)
                )))
        db.session.commit()
Пример #9
0
    def create_tags(self,
                    ids: Tuple[str],
                    org: str = None,
                    provider: str = None):
        """Create TAGS and associates them to a specific PROVIDER."""
        tag_schema = TagS(only=('id', 'provider', 'org'))

        db.session.add_all(
            Tag(**tag_schema.load({
                'id': tag_id,
                'provider': provider,
                'org': org
            })) for tag_id in ids)
        db.session.commit()
Пример #10
0
def test_sync_execute_register_no_hid_tag_not_linked(tag_id: str):
    """
    Validates registering a computer without HID and a non-linked tag.

    In this case it is ok still, as the non-linked tag proves that
    the computer was not existing before (otherwise the tag would
    be linked), and thus it creates a new computer.
    """
    tag = Tag(id=tag_id)
    pc = Computer(**file('pc-components.db')['device'], tags=OrderedSet([tag]))
    returned_pc = Sync().execute_register(pc)
    db.session.commit()
    assert returned_pc == pc
    db_tag = next(iter(returned_pc.tags))
    # they are not the same tags though
    # tag is a transient obj and db_tag the one from the db
    # they have the same pk though
    assert tag != db_tag, 'They are not the same tags though'
    assert db_tag.id == tag.id
    assert Computer.query.one() == pc, 'Computer had to be set to db'
Пример #11
0
def test_sync_execute_register_no_hid_tag_not_linked(tag_id: str):
    """Validates registering a d.Desktop without HID and a non-linked tag.

    In this case it is ok still, as the non-linked tag proves that
    the d.Desktop was not existing before (otherwise the tag would
    be linked), and thus it creates a new d.Desktop.
    """
    tag = Tag(id=tag_id)
    pc = d.Desktop(**yaml2json('pc-components.db')['device'],
                   tags=OrderedSet([tag]))
    db.session.add(g.user)
    returned_pc = Sync().execute_register(pc)
    db.session.commit()
    assert returned_pc == pc
    db_tag = next(iter(returned_pc.tags))
    # they are not the same tags though
    # tag is a transient obj and db_tag the one from the db
    # they have the same pk though
    assert d.Desktop.query.one() == pc, 'd.Desktop had to be set to db'
    assert tag != db_tag, 'They are not the same tags though'
    for tag in pc.tags:
        assert tag.id in ['foo', pc.devicehub_id]
Пример #12
0
    def execute_register(self, device: Device) -> Device:
        """
        Synchronizes one device to the DB.

        This method tries to get an existing device using the HID
        or one of the tags, and...

        - if it already exists it returns a "local synced version"
          –the same ``device`` you passed-in but with updated values
          from the database. In this case we do not
          "touch" any of its values on the DB.
        - If it did not exist, a new device is created in the db.

        This method validates that all passed-in tags (``device.tags``),
        if linked, are linked to the same device, ditto for the hid.
        Finally it links the tags with the device.

        If you pass-in a component that is inside a parent, use
        :meth:`.execute_register_component` as it has more specialized
        methods to handle them.

        :param device: The device to synchronize to the DB.
        :raise NeedsId: The device has not any identifier we can use.
                        To still create the device use
                        ``force_creation``.
        :raise DatabaseError: Any other error from the DB.
        :return: The synced device from the db with the tags linked.
        """
        assert inspect(
            device).transient, 'Device cannot be already synced from DB'
        assert all(inspect(tag).transient
                   for tag in device.tags), 'Tags cannot be synced from DB'
        if not device.tags and not device.hid:
            # We cannot identify this device
            raise NeedsId()
        db_device = None
        if device.hid:
            with suppress(ResourceNotFound):
                db_device = Device.query.filter_by(hid=device.hid).one()
        try:
            tags = {Tag.from_an_id(tag.id).one()
                    for tag in device.tags}  # type: Set[Tag]
        except ResourceNotFound:
            raise ResourceNotFound(
                'tag you are linking to device {}'.format(device))
        linked_tags = {tag for tag in tags if tag.device_id}  # type: Set[Tag]
        if linked_tags:
            sample_tag = next(iter(linked_tags))
            for tag in linked_tags:
                if tag.device_id != sample_tag.device_id:
                    raise MismatchBetweenTags(
                        tag, sample_tag)  # Tags linked to different devices
            if db_device:  # Device from hid
                if sample_tag.device_id != db_device.id:  # Device from hid != device from tags
                    raise MismatchBetweenTagsAndHid(db_device.id,
                                                    db_device.hid)
            else:  # There was no device from hid
                if sample_tag.device.physical_properties != device.physical_properties:
                    # Incoming physical props of device != props from tag's device
                    # which means that the devices are not the same
                    raise MismatchBetweenProperties(
                        sample_tag.device.physical_properties,
                        device.physical_properties)
                db_device = sample_tag.device
        if db_device:  # Device from hid or tags
            self.merge(device, db_device)
        else:  # Device is new and tags are not linked to a device
            device.tags.clear(
            )  # We don't want to add the transient dummy tags
            db.session.add(device)
            db_device = device
        db_device.tags |= tags  # Union of tags the device had plus the (potentially) new ones
        try:
            db.session.flush()
        except IntegrityError as e:
            # Manage 'one tag per organization' unique constraint
            if 'One tag per organization' in e.args[0]:
                # todo test for this
                id = int(e.args[0][135:e.args[0].index(',', 135)])
                raise ValidationError('The device is already linked to tag {} '
                                      'from the same organization.'.format(id),
                                      field_names=['device.tags'])
            else:
                raise
        assert db_device is not None
        return db_device