def test_is_equivalent_fail(): sid = uuid.UUID('1234567890abcdef1234567890abcdef') dl1 = DataLink(uuid.UUID('1234567890abcdef1234567890abcdee'), DataUnitID(UPA('2/6/4'), 'whee'), SampleNodeAddress(SampleAddress(sid, 8), 'bar'), dt(400), UserID('myuserᚥnameisHank'), dt(400), UserID('yay')) with raises(Exception) as got: dl1.is_equivalent(None) assert_exception_correct( got.value, ValueError('link cannot be a value that evaluates to false'))
def test_links_to_dicts(): links = [ DataLink( UUID('f5bd78c3-823e-40b2-9f93-20e78680e41e'), DataUnitID(UPA('1/2/3'), 'foo'), SampleNodeAddress( SampleAddress(UUID('f5bd78c3-823e-40b2-9f93-20e78680e41f'), 6), 'foo'), dt(0.067), UserID('usera'), dt(89), UserID('userb') ), DataLink( UUID('f5bd78c3-823e-40b2-9f93-20e78680e41a'), DataUnitID(UPA('4/9/10')), SampleNodeAddress( SampleAddress(UUID('f5bd78c3-823e-40b2-9f93-20e78680e41b'), 4), 'bar'), dt(1), UserID('userc'), ), ] assert links_to_dicts(links) == [ { 'upa': '1/2/3', 'dataid': 'foo', 'id': 'f5bd78c3-823e-40b2-9f93-20e78680e41f', 'version': 6, 'node': 'foo', 'created': 67, 'createdby': 'usera', 'expired': 89000, 'expiredby': 'userb' }, { 'upa': '4/9/10', 'dataid': None, 'id': 'f5bd78c3-823e-40b2-9f93-20e78680e41b', 'version': 4, 'node': 'bar', 'created': 1000, 'createdby': 'userc', 'expired': None, 'expiredby': None } ]
def create_data_link(self, user: UserID, duid: DataUnitID, sna: SampleNodeAddress, update: bool = False, as_admin: bool = False) -> DataLink: ''' Create a link from a data unit to a sample. The user must have admin access to the sample, since linking data grants permissions: once linked, if a user has access to the data unit, the user also has access to the sample. The user must have write access to the data since adding a sample to the data effectively modifies the data, but doesn't grant any additional access. Each data unit can be linked to only one sample at a time. Expired links may exist to other samples. :param user: the user creating the link. :param duid: the data unit to link the the sample. :param sna: the sample node to link to the data unit. :param update: True to expire any extant link if it does not link to the provided sample. If False and a link from the data unit already exists, link creation will fail. :param as_admin: allow link creation to proceed if user does not have appropriate permissions. :returns: the new link. :raises UnauthorizedError: if the user does not have acceptable permissions. :raises NoSuchSampleError: if the sample does not exist. :raises NoSuchSampleVersionError: if the sample version does not exist. :raises NoSuchSampleNodeError: if the sample node does not exist. :raises NoSuchWorkspaceDataError: if the workspace or UPA doesn't exist. :raises DataLinkExistsError: if a link already exists from the data unit. :raises TooManyDataLinksError: if there are too many links from the sample version or the workspace object version. :raises SampleStorageError: if the sample could not be retrieved. ''' _not_falsy(user, 'user') _not_falsy(duid, 'duid') self._check_perms(_not_falsy(sna, 'sna').sampleid, user, _SampleAccessType.ADMIN, as_admin=as_admin) wsperm = _WorkspaceAccessType.NONE if as_admin else _WorkspaceAccessType.WRITE self._ws.has_permission(user, wsperm, upa=duid.upa) dl = DataLink(self._uuid_gen(), duid, sna, self._now(), user) expired_id = self._storage.create_data_link(dl, update=update) if self._kafka: self._kafka.notify_new_link(dl.id) if expired_id: # maybe make the notifier accept both notifications & send both? self._kafka.notify_expired_link(expired_id) return dl
def test_links_to_dicts_fail_bad_args(): dl = DataLink( UUID('f5bd78c3-823e-40b2-9f93-20e78680e41e'), DataUnitID(UPA('1/2/3'), 'foo'), SampleNodeAddress( SampleAddress(UUID('f5bd78c3-823e-40b2-9f93-20e78680e41f'), 6), 'foo'), dt(0.067), UserID('usera'), dt(89), UserID('userb') ) _links_to_dicts_fail(None, ValueError('links cannot be None')) _links_to_dicts_fail([dl, None], ValueError( 'Index 1 of iterable links cannot be a value that evaluates to false'))
def _is_equivalent(duid1, sna1, duid2, sna2, expected): dl1 = DataLink(uuid.UUID('1234567890abcdef1234567890abcdee'), duid1, sna1, dt(400), UserID('myuserᚥnameisHank'), dt(400), UserID('yay')) dl2 = DataLink(uuid.UUID('1234567890abcdef1234567890abcdef'), duid2, sna2, dt(500), UserID('waaaahrrgg'), dt(8900), UserID('go faster stripes')) assert dl1.is_equivalent(dl2) is expected assert dl2.is_equivalent(dl1) is expected
def test_init_with_expire1(): sid = uuid.UUID('1234567890abcdef1234567890abcdef') dl = DataLink(uuid.UUID('1234567890abcdef1234567890abcdee'), DataUnitID(UPA('2/6/4'), 'whee'), SampleNodeAddress(SampleAddress(sid, 7), 'bar'), dt(400), UserID('u'), dt(800), UserID('gotdam')) assert dl.id == uuid.UUID('1234567890abcdef1234567890abcdee') assert dl.duid == DataUnitID(UPA('2/6/4'), 'whee') assert dl.sample_node_address == SampleNodeAddress(SampleAddress(sid, 7), 'bar') assert dl.created == dt(400) assert dl.created_by == UserID('u') assert dl.expired == dt(800) assert dl.expired_by == UserID('gotdam') assert str(dl) == ( 'id=12345678-90ab-cdef-1234-567890abcdee ' + 'duid=[2/6/4:whee] ' + 'sample_node_address=[12345678-90ab-cdef-1234-567890abcdef:7:bar] ' + 'created=400.0 created_by=u expired=800.0 expired_by=gotdam')
def test_init_no_expire(): sid = uuid.UUID('1234567890abcdef1234567890abcdef') dl = DataLink( uuid.UUID('1234567890abcdef1234567890abcdee'), DataUnitID(UPA('2/3/4')), SampleNodeAddress(SampleAddress(sid, 5), 'foo'), dt(500), UserID('usera'), expired_by=UserID('u') # should be ignored ) assert dl.id == uuid.UUID('1234567890abcdef1234567890abcdee') assert dl.duid == DataUnitID(UPA('2/3/4')) assert dl.sample_node_address == SampleNodeAddress(SampleAddress(sid, 5), 'foo') assert dl.created == dt(500) assert dl.created_by == UserID('usera') assert dl.expired is None assert dl.expired_by is None assert str(dl) == ( 'id=12345678-90ab-cdef-1234-567890abcdee ' + 'duid=[2/3/4] ' + 'sample_node_address=[12345678-90ab-cdef-1234-567890abcdef:5:foo] ' + 'created=500.0 created_by=usera expired=None expired_by=None')
def test_hash(): # hashes will change from instance to instance of the python interpreter, and therefore # tests can't be written that directly test the hash value. See # https://docs.python.org/3/reference/datamodel.html#object.__hash__ lid1 = uuid.UUID('1234567890abcdef1234567890abcdee') lid1a = uuid.UUID('1234567890abcdef1234567890abcdee') lid2 = uuid.UUID('1234567890abcdef1234567890abcdec') lid2a = uuid.UUID('1234567890abcdef1234567890abcdec') d1 = DataUnitID(UPA('1/1/1')) d1a = DataUnitID(UPA('1/1/1')) d2 = DataUnitID(UPA('1/1/2')) d2a = DataUnitID(UPA('1/1/2')) id_ = uuid.UUID('1234567890abcdef1234567890abcdef') s1 = SampleNodeAddress(SampleAddress(id_, 1), 'foo') s1a = SampleNodeAddress(SampleAddress(id_, 1), 'foo') s2 = SampleNodeAddress(SampleAddress(id_, 2), 'foo') s2a = SampleNodeAddress(SampleAddress(id_, 2), 'foo') t1 = dt(500) t1a = dt(500) t2 = dt(600) t2a = dt(600) u1 = UserID('u') u1a = UserID('u') u2 = UserID('y') u2a = UserID('y') assert hash(DataLink(lid1, d1, s1, t1, u1)) == hash(DataLink(lid1a, d1a, s1a, t1a, u1a)) assert hash(DataLink(lid1, d1, s1, t1, u1, None)) == hash( DataLink(lid1a, d1a, s1a, t1a, u1a, None)) assert hash(DataLink(lid2, d2, s2, t1, u2, t2, u1)) == hash( DataLink(lid2a, d2a, s2a, t1a, u2a, t2a, u1a)) assert hash(DataLink(lid1, d1, s1, t1, u1)) != hash( DataLink(lid2, d1a, s1a, t1a, u1a)) assert hash(DataLink(lid1, d1, s1, t1, u1)) != hash( DataLink(lid1a, d2, s1a, t1a, u1a)) assert hash(DataLink(lid1, d1, s1, t1, u1)) != hash( DataLink(lid1a, d1a, s2, t1a, u1a)) assert hash(DataLink(lid1, d1, s1, t1, u1)) != hash( DataLink(lid1a, d1a, s1a, t2, u1a)) assert hash(DataLink(lid1, d1, s1, t1, u1)) != hash( DataLink(lid1a, d1a, s1a, t1a, u2)) assert hash(DataLink(lid1, d1, s1, t1, u1, t2, u2)) != hash( DataLink(lid1a, d1a, s1a, t1a, u1a, t1, u2a)) assert hash(DataLink(lid1, d1, s1, t1, u1, t2, u2)) != hash( DataLink(lid1a, d1a, s1a, t1a, u1a, t2a, u1a)) assert hash(DataLink(lid1, d1, s1, t1, u1, t1, u2)) != hash( DataLink(lid1a, d1a, s1a, t1a, u1a)) assert hash(DataLink(lid1, d1, s1, t1, u1)) != hash( DataLink(lid1a, d1a, s1a, t1a, u1a, t1a, u2a))
def test_equals(): lid1 = uuid.UUID('1234567890abcdef1234567890abcdee') lid1a = uuid.UUID('1234567890abcdef1234567890abcdee') lid2 = uuid.UUID('1234567890abcdef1234567890abcdec') lid2a = uuid.UUID('1234567890abcdef1234567890abcdec') d1 = DataUnitID(UPA('1/1/1')) d1a = DataUnitID(UPA('1/1/1')) d2 = DataUnitID(UPA('1/1/2')) d2a = DataUnitID(UPA('1/1/2')) sid = uuid.UUID('1234567890abcdef1234567890abcdef') s1 = SampleNodeAddress(SampleAddress(sid, 1), 'foo') s1a = SampleNodeAddress(SampleAddress(sid, 1), 'foo') s2 = SampleNodeAddress(SampleAddress(sid, 2), 'foo') s2a = SampleNodeAddress(SampleAddress(sid, 2), 'foo') t1 = dt(500) t1a = dt(500) t2 = dt(600) t2a = dt(600) u1 = UserID('u') u1a = UserID('u') u2 = UserID('y') u2a = UserID('y') assert DataLink(lid1, d1, s1, t1, u1) == DataLink(lid1a, d1a, s1a, t1a, u1a) assert DataLink(lid1, d1, s1, t1, u1, None) == DataLink(lid1a, d1a, s1a, t1a, u1a, None) assert DataLink(lid2, d2, s2, t1, u2, t2, u1) == DataLink(lid2a, d2a, s2a, t1a, u2a, t2a, u1a) assert DataLink(lid1, d1, s1, t1, u1) != (lid1, d1, s1, t1, u1) assert DataLink(lid1, d1, s1, t1, u1, t2, u2) != (lid1, d1, s1, t1, u1, t2, u2) assert DataLink(lid1, d1, s1, t1, u1) != DataLink(lid2, d1a, s1a, t1a, u1a) assert DataLink(lid1, d1, s1, t1, u1) != DataLink(lid1a, d2, s1a, t1a, u1a) assert DataLink(lid1, d1, s1, t1, u1) != DataLink(lid1a, d1a, s2, t1a, u1a) assert DataLink(lid1, d1, s1, t1, u1) != DataLink(lid1a, d1a, s1a, t2, u1a) assert DataLink(lid1, d1, s1, t1, u1) != DataLink(lid1a, d1a, s1a, t1, u2) assert DataLink(lid1, d1, s1, t1, u1, t2, u2) != DataLink( lid1a, d1a, s1a, t1a, u1a, t1, u2a) assert DataLink(lid1, d1, s1, t1, u1, t2, u2) != DataLink( lid1a, d1a, s1a, t1a, u1a, t2a, u1) assert DataLink(lid1, d1, s1, t1, u1, t1, u1) != DataLink( lid1a, d1a, s1a, t1a, u1a) assert DataLink(lid1, d1, s1, t1, u1) != DataLink(lid1a, d1a, s1a, t1a, u1a, t1a, u1a)
def _init_fail(lid, duid, sna, cr, cru, ex, eu, expected): with raises(Exception) as got: DataLink(lid, duid, sna, cr, cru, ex, eu) assert_exception_correct(got.value, expected)
def test_timestamp_seconds_to_milliseconds(samplestorage): ts1=1614958000000 # milliseconds ts2=1614958000 # seconds ts3=1614958 # seconds ts4=9007199254740.991 # seconds id1 = uuid.UUID('1234567890abcdef1234567890abcdef') id2 = uuid.UUID('1234567890abcdef1234567890abcdee') assert samplestorage.save_sample( SavedSample(id1, UserID('user'), [SampleNode('mynode')], dt(ts3), 'foo')) is True assert samplestorage.save_sample_version( SavedSample(id1, UserID('user'), [SampleNode('mynode1')], dt(ts2), 'foo')) == 2 assert samplestorage.save_sample( SavedSample(id2, UserID('user'), [SampleNode('mynode2')], dt(ts3), 'foo')) is True lid1=uuid.UUID('1234567890abcdef1234567890abcde2') lid2=uuid.UUID('1234567890abcdef1234567890abcde3') lid3=uuid.UUID('1234567890abcdef1234567890abcde4') samplestorage.create_data_link(DataLink( lid1, DataUnitID(UPA('42/42/42'), 'dataunit1'), SampleNodeAddress(SampleAddress(id1, 1), 'mynode'), dt(ts2), UserID('user')) ) samplestorage.create_data_link(DataLink( lid2, DataUnitID(UPA('5/89/32'), 'dataunit2'), SampleNodeAddress(SampleAddress(id2, 1), 'mynode2'), dt(ts3), UserID('user')) ) _create_and_expire_data_link( samplestorage, DataLink( lid3, DataUnitID(UPA('5/89/33'), 'dataunit1'), SampleNodeAddress(SampleAddress(id1, 1), 'mynode'), dt(ts3), UserID('user')), dt(ts3+100), UserID('user') ) assert samplestorage.get_sample(id1, 1).savetime == dt(ts3) assert samplestorage.get_sample(id1, 2).savetime == dt(ts2) assert samplestorage.get_sample(id2).savetime == dt(ts3) assert samplestorage.get_data_link(lid1).created == dt(ts2) assert samplestorage.get_data_link(lid2).created == dt(ts3) assert samplestorage.get_data_link(lid3).created == dt(ts3) assert samplestorage.get_data_link(lid3).expired == dt(ts3+100) threshold=1000000000000 # current timestamp in milliseconds is above 1600000000000 query=""" FOR sample1 IN samples_nodes FILTER sample1.saved < @threshold UPDATE sample1 WITH { saved: ROUND(sample1.saved * 1000) } IN samples_nodes FOR sample2 IN samples_version FILTER sample2.saved < @threshold UPDATE sample2 WITH { saved: ROUND(sample2.saved * 1000) } IN samples_version FOR link IN samples_data_link FILTER link.expired < @threshold OR link.created < @threshold UPDATE link WITH { expired: link.expired < @threshold ? ROUND(link.expired * 1000) : link.expired, created: link.created < @threshold ? ROUND(link.created * 1000) : link.created } IN samples_data_link """ samplestorage._db.aql.execute(query, bind_vars={'threshold': threshold}) assert samplestorage.get_sample(id1, 1).savetime == dt(ts2) assert samplestorage.get_sample(id1, 2).savetime == dt(ts2) assert samplestorage.get_sample(id2).savetime == dt(ts2) assert samplestorage.get_data_link(lid1).created == dt(ts2) assert samplestorage.get_data_link(lid2).created == dt(ts2) assert samplestorage.get_data_link(lid3).created == dt(ts2) assert samplestorage.get_data_link(lid3).expired == dt((ts3+100) * 1000) samplestorage._db.aql.execute(query, bind_vars={'threshold': threshold}) assert samplestorage.get_sample(id1, 1).savetime == dt(ts2) assert samplestorage.get_sample(id1, 2).savetime == dt(ts2) assert samplestorage.get_sample(id2).savetime == dt(ts2) assert samplestorage.get_data_link(lid1).created == dt(ts2) assert samplestorage.get_data_link(lid2).created == dt(ts2) assert samplestorage.get_data_link(lid3).created == dt(ts2) assert samplestorage.get_data_link(lid3).expired == dt((ts3+100) * 1000)