def notify_delete(self, item_id): # pragma: no cover '''Adds an deleted notification. Notification is added for every listener that is listening on the updated item id. ''' with self._dbconn.transaction() as t: ro = self._create_resource_ro_storage( self._listener_table, listener_prototype) listener_resources = ro.search(t, [ qvarn.create_search_param(u'exact', u'listen_on', item_id), ], []) wildcard_listener_resources = ro.search(t, [ qvarn.create_search_param(u'exact', u'listen_on_all', True), ], []) listeners = listener_resources[u'resources'] listeners.extend(wildcard_listener_resources[u'resources']) wo = self._create_resource_wo_storage( self._notification_table, notification_prototype) for listener in listeners: notification = { u'type': u'notification', u'listener_id': listener[u'id'], u'resource_id': item_id, u'resource_revision': None, u'resource_change': u'deleted', u'last_modified': int(time.time() * 1000000) } wo.add_item(t, notification)
def dont_test_search_multiple_conditions_from_different_rows(self): with self._dbconn.transaction() as t: added = self.wo.add_item(t, self.item) new_id = added[u'id'] search_result = self.ro.search( t, [ qvarn.create_search_param(u'exact', u'baz', u'bling'), qvarn.create_search_param(u'exact', u'baz', u'blang'), ], []) self.assertIn(new_id, search_result[u'resources'][0][u'id'])
def dont_test_search_multiple_conditions_from_same_table(self): with self._dbconn.transaction() as t: added = self.wo.add_item(t, self.item) new_id = added[u'id'] search_result = self.ro.search( t, [ qvarn.create_search_param(u'exact', u'foo', u'foobar'), qvarn.create_search_param(u'exact', u'type', u'yo'), ], []) self.assertIn(new_id, search_result[u'resources'][0][u'id'])
def notify_create(self, item_id, item_revision): '''Adds a created notification. Notification is added for every listener that has notify_of_new enabled. ''' with self._dbconn.transaction() as t: ro = self._create_resource_ro_storage( self._listener_table, listener_prototype) listener_resources = ro.search(t, [ qvarn.create_search_param(u'exact', u'notify_of_new', True), ], []) wo = self._create_resource_wo_storage( self._notification_table, notification_prototype) for listener in listener_resources[u'resources']: notification = { u'type': u'notification', u'listener_id': listener[u'id'], u'resource_id': item_id, u'resource_revision': item_revision, u'resource_change': u'created', u'last_modified': int(time.time() * 1000000) } wo.add_item(t, notification)
def test_case_search_bad_key(self): with self.assertRaises(qvarn.FieldNotInResource): with self._dbconn.transaction() as t: self.wo.add_item(t, self.item) self.ro.search( t, [qvarn.create_search_param(u'exact', u'KEY', u'BANG')], [u'show_all'])
def dont_test_search_main_list(self): with self._dbconn.transaction() as t: added = self.wo.add_item(t, self.item) new_id = added[u'id'] search_result = self.ro.search( t, [qvarn.create_search_param('exact', u'bars', u'bar1')], {}) self.assertIn(new_id, search_result[u'resources'][0][u'id'])
def dont_test_search_with_boolean(self): with self._dbconn.transaction() as t: self.wo.add_item(t, self.item) search_result = self.ro.search( t, [qvarn.create_search_param(u'exact', u'bool', 'false')], [u'show_all']) match_list = search_result[u'resources'] self.assertEqual(match_list, [])
def dont_test_search_main_item(self): with self._dbconn.transaction() as t: added = self.wo.add_item(t, self.item) new_id = added[u'id'] search_result = self.ro.search(t, [ qvarn.create_search_param(u'exact', u'foo', u'foobar'), ], []) self.assertEqual(search_result, {u'resources': [{u'id': new_id}]})
def dont_test_case_insensitive_search(self): with self._dbconn.transaction() as t: added = self.wo.add_item(t, self.item) new_id = added[u'id'] search_result = self.ro.search( t, [qvarn.create_search_param(u'exact', u'bar', u'BANG')], [u'show_all']) match_list = search_result[u'resources'] self.assertIn(new_id, match_list[0][u'id'])
def dont_test_search_condition_with_multiple_targets(self): with self._dbconn.transaction() as t: added = self.wo.add_item(t, self.item) new_id = added[u'id'] search_result = self.ro.search(t, [ qvarn.create_search_param(u'exact', u'bar', u'barbaz'), ], []) match_list = search_result[u'resources'] self.assertIsNot(0, len(match_list)) self.assertIn(new_id, match_list[0][u'id'])
def get_notifications(self, listener_id): '''Serve GET /foos/listeners/123/notifications. Lists all notifications. ''' ro = self._create_resource_ro_storage( self._notification_table, notification_prototype) with self._dbconn.transaction() as t: result = ro.search(t, [ qvarn.create_search_param(u'exact', u'listener_id', listener_id), ], [], sort_params=[u'last_modified']) return result
def delete_listener(self, listener_id): # pragma: no cover '''Serve DELETE /foos/listeners/123 to delete a listener.''' with self._dbconn.transaction() as t: wo_listener = self._create_resource_wo_storage( self._listener_table, listener_prototype) wo_listener.delete_item(t, listener_id) ro = self._create_resource_ro_storage( self._notification_table, notification_prototype) notification_resources = ro.search(t, [ qvarn.create_search_param(u'exact', u'listener_id', listener_id), ], []) wo_notification = self._create_resource_wo_storage( self._notification_table, notification_prototype) for notification in notification_resources[u'resources']: try: wo_notification.delete_item(t, notification[u'id']) except qvarn.ItemDoesNotExist: # Try to delete all anyway pass
def get_matching_items(self, search_criteria): # pragma: no cover '''Serve GET /foos/search to list items matching search criteria.''' # We need criteria to be encoded so that when we split by slash (/), # we split the criteria correctly and keep the slashes in the # condition values. # We use REQUEST_URI provided by uWSGI instead of bottle's default # that uses decoded PATH_INFO. request_uri = bottle.request.environ['REQUEST_URI'] # Split at the first "/search/" and take the part after it search_criteria = request_uri.split('/search/', 1)[1] criteria = [urllib.unquote(c).decode('utf8') for c in search_criteria.split('/')] search_params = [] show_params = [] sort_params = [] limit = None offset = None search_any = False any_opers = [ u'exact', u'startswith', u'contains', ] opers = [ u'exact', u'gt', u'ge', u'lt', u'le', u'ne', u'startswith', u'contains', ] i = 0 while i < len(criteria): part = criteria[i] if part in opers: if i + 2 >= len(criteria): raise BadSearchCondition() matching_rule = part search_field = criteria[i + 1] search_value = criteria[i + 2] if search_any: try: search_value = json.loads(search_value) except ValueError as e: raise BadAnySearchValue(error=str(e)) if not isinstance(search_value, list): raise BadAnySearchValue( error=u"%r is not a list" % search_value) search_param = qvarn.create_search_param( matching_rule, search_field, search_value, any=search_any, ) search_params.append(search_param) search_any = False i += 3 elif part == u'show_all': show_params.append(part) i += 1 elif part == u'show': if i + 1 >= len(criteria): raise BadSearchCondition() show_params.append((part, criteria[i + 1])) i += 2 elif part == u'sort': sort_field = criteria[i + 1] sort_params.append(sort_field) i += 2 elif part == u'limit': try: limit = int(criteria[i + 1]) except ValueError as e: raise BadLimitValue(error=str(e)) if limit < 0: raise BadLimitValue(error="should be positive integer") i += 2 elif part == u'offset': try: offset = int(criteria[i + 1]) except ValueError as e: raise BadOffsetValue(error=str(e)) if offset < 0: raise BadOffsetValue(error="should be positive integer") i += 2 elif part == u'any': if (i + 1) >= len(criteria): raise MissingAnyOperator() elif criteria[i + 1] not in any_opers: raise InvalidAnyOperator( allowed_operators=', '.join(any_opers), given_operator=criteria[i + 1], ) search_any = True i += 1 else: raise BadSearchCondition() if (limit is not None or offset is not None) and not sort_params: raise LimitWithoutSortError() ro = self._create_ro_storage() with self._dbconn.transaction() as t: return ro.search(t, search_params, show_params, sort_params, limit=limit, offset=offset)