def test_records_list_retrieval(self): client = Client(server_url=self.server_url, auth=self.auth, bucket="mozilla", collection="payments") client.create_bucket() client.create_collection() client.create_record(data={"foo": "bar"}, permissions={"read": ["alexis"]}) records = client.get_records() assert len(records) == 1
def test_multiple_record_deletion(self): client = Client(server_url=self.server_url, auth=self.auth, bucket="mozilla", collection="payments") client.create_bucket() client.create_collection() client.create_record({"foo": "bar"}) client.delete_records() assert len(client.get_records()) == 0
def test_single_record_can_overwrite(self): client = Client(server_url=self.server_url, auth=self.auth, bucket="mozilla", collection="payments") client.create_bucket() client.create_collection() created = client.create_record(data={"foo": "bar"}, permissions={"read": ["alexis"]}) client.create_record(data={"id": created["data"]["id"], "bar": "baz"}, safe=False)
def test_records_list_retrieval(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() client.create_record(data={'foo': 'bar'}, permissions={'read': ['alexis']}) records = client.get_records() assert len(records) == 1
def test_single_record_creation_if_not_exists(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() created = client.create_record(data={'foo': 'bar'}) client.create_record(data={'id': created['data']['id'], 'bar': 'baz'}, if_not_exists=True)
def test_single_record_doesnt_overwrite(self): client = Client(server_url=self.server_url, auth=self.auth, bucket="mozilla", collection="payments") client.create_bucket() client.create_collection() created = client.create_record(data={"foo": "bar"}, permissions={"read": ["alexis"]}) with self.assertRaises(KintoException): # Create a second record with the ID of the first one. client.create_record(data={"id": created["data"]["id"], "bar": "baz"})
def test_records_paginated_list_retrieval(self): client = Client(server_url=self.server_url, auth=self.auth, bucket="mozilla", collection="payments") client.create_bucket() client.create_collection() for i in range(10): client.create_record(data={"foo": "bar"}, permissions={"read": ["alexis"]}) # Kinto is running with kinto.paginate_by = 5 records = client.get_records() assert len(records) == 10
def test_single_record_can_overwrite(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() created = client.create_record(data={'foo': 'bar'}, permissions={'read': ['alexis']}) client.create_record(data={'id': created['data']['id'], 'bar': 'baz'}, safe=False)
def test_multiple_record_deletion(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() client.create_record({'foo': 'bar'}) client.delete_records() assert len(client.get_records()) == 0
def test_records_paginated_list_retrieval(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() for i in range(10): client.create_record(data={'foo': 'bar'}, permissions={'read': ['alexis']}) # Kinto is running with kinto.paginate_by = 5 records = client.get_records() assert len(records) == 10
def test_single_record_doesnt_overwrite(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() created = client.create_record(data={'foo': 'bar'}, permissions={'read': ['alexis']}) with self.assertRaises(KintoException): # Create a second record with the ID of the first one. client.create_record(data={'id': created['data']['id'], 'bar': 'baz'})
def test_single_record_creation_if_not_exists(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() created = client.create_record(data={'foo': 'bar'}) client.create_record(data={ 'id': created['data']['id'], 'bar': 'baz' }, if_not_exists=True)
def test_single_record_can_overwrite(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() created = client.create_record(data={'foo': 'bar'}, permissions={'read': ['alexis']}) client.create_record(data={ 'id': created['data']['id'], 'bar': 'baz' }, safe=False)
def test_single_record_doesnt_overwrite(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() created = client.create_record(data={'foo': 'bar'}, permissions={'read': ['alexis']}) with self.assertRaises(KintoException): # Create a second record with the ID of the first one. client.create_record(data={ 'id': created['data']['id'], 'bar': 'baz' })
def test_record_creation_and_retrieval(self): client = Client(server_url=self.server_url, auth=self.auth, bucket="mozilla", collection="payments") client.create_bucket() client.create_collection() created = client.create_record(data={"foo": "bar"}, permissions={"read": ["alexis"]}) record = client.get_record(created["data"]["id"]) assert "alexis" in record["permissions"]["read"]
class KintoRecords(Records): def _load(self): self.client = Client(server_url=self.options['server'], auth=self.options['auth'], bucket=self.options['bucket_name'], collection=self.options['collection_name']) # Create bucket try: self.client.create_bucket() except KintoException as e: if e.response.status_code != 412: raise e try: self.client.create_collection( permissions=self.options['permissions']) except KintoException as e: if e.response.status_code != 412: raise e return [self._kinto2rec(rec) for rec in self.client.get_records()] def _kinto2rec(self, record): return record def delete(self, data): self.client.delete_record(data['id']) def create(self, data): if 'id' not in data: data['id'] = create_id(data) rec = self.client.create_record(data) return rec
class KintoRecords(Records): def _load(self): self.client = Client(server_url=self.options['server'], auth=self.options['auth'], bucket=self.options['bucket_name'], collection=self.options['collection_name']) # Create bucket self.client.create_bucket() self.client.create_collection(self.options['collection_name'], permissions=self.options['permissions']) # XXX to be removed later # remove the 'onecrl' bucket if it exists try: self.client.delete_bucket('onecrl') except KintoException: pass return [self._kinto2rec(rec) for rec in self.client.get_records()] def _kinto2rec(self, record): return record def delete(self, data): self.client.delete_record(data['id']) def create(self, data): if 'id' not in data: data['id'] = create_id(data) rec = self.client.create_record(data) return rec
def test_one_record_deletion(self): client = Client(server_url=self.server_url, auth=self.auth, bucket="mozilla", collection="payments") client.create_bucket() client.create_collection() record = client.create_record({"foo": "bar"}) deleted = client.delete_record(record["data"]["id"]) assert deleted["deleted"] is True assert len(client.get_records()) == 0
def test_one_record_deletion(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() record = client.create_record({'foo': 'bar'}) deleted = client.delete_record(record['data']['id']) assert deleted['deleted'] is True assert len(client.get_records()) == 0
def test_record_creation_and_retrieval(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() created = client.create_record(data={'foo': 'bar'}, permissions={'read': ['alexis']}) record = client.get_record(created['data']['id']) assert 'alexis' in record['permissions']['read']
class FunctionalTest(unittest.TestCase): def __init__(self, *args, **kwargs): super(FunctionalTest, self).__init__(*args, **kwargs) self.emailer_config = configparser.RawConfigParser() self.emailer_config.read(os.path.join(__HERE__, 'config/kinto.ini')) # Setup the kinto clients for the source and destination. self._auth = DEFAULT_AUTH self._server_url = SERVER_URL self._bucket = "emailer" self._collection = "collection1" self.client = Client( server_url=self._server_url, auth=self._auth, bucket=self._bucket, collection=self._collection) def tearDown(self): # Delete all the created objects. self._flush_server(self._server_url) shutil.rmtree('mail/', ignore_errors=True) def _flush_server(self, server_url): flush_url = urljoin(server_url, '/__flush__') resp = requests.post(flush_url) resp.raise_for_status() def test_new_record_send_email(self): self.client.create_bucket() self.client.create_collection(data={ "kinto-emailer": { 'hooks': [{ "resource_name": "record", "action": "create", "subject": "Action on {root_url}", "template": ("{client_address} edited:\n " "{bucket_id}/{collection_id}/{record_id}."), "recipients": ['*****@*****.**'], }] } }) record = self.client.create_record({'foo': 'bar'})['data'] filename = glob('mail/*.eml')[0] with open(filename, 'r') as f: body = f.read() assert '*****@*****.**' in body assert "Action on http://localhost:8888/v1/" in body assert "127.0.0.1=20edited" in body assert "emailer/collection1/{}".format(record['id']) in body
def test_single_record_save(self): client = Client(server_url=self.server_url, auth=self.auth, bucket="mozilla", collection="payments") client.create_bucket() client.create_collection() created = client.create_record(data={"foo": "bar"}, permissions={"read": ["alexis"]}) created["data"]["bar"] = "baz" # XXX enhance this in order to have to pass only one argument, created. client.update_record(id=created["data"]["id"], data=created["data"]) retrieved = client.get_record(created["data"]["id"]) assert "alexis" in retrieved["permissions"]["read"] assert retrieved["data"]["foo"] == u"bar" assert retrieved["data"]["bar"] == u"baz" assert created["data"]["id"] == retrieved["data"]["id"]
def test_single_record_save(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() created = client.create_record(data={'foo': 'bar'}, permissions={'read': ['alexis']}) created['data']['bar'] = 'baz' # XXX enhance this in order to have to pass only one argument, created. client.update_record(id=created['data']['id'], data=created['data']) retrieved = client.get_record(created['data']['id']) assert 'alexis' in retrieved['permissions']['read'] assert retrieved['data']['foo'] == u'bar' assert retrieved['data']['bar'] == u'baz' assert created['data']['id'] == retrieved['data']['id']
class RecordTest(unittest.TestCase): def setUp(self): self.session = mock.MagicMock() self.client = Client(session=self.session, bucket='mybucket', collection='mycollection') def test_record_id_is_given_after_creation(self): mock_response(self.session, data={'id': 5678}) record = self.client.create_record({'foo': 'bar'}) assert 'id' in record['data'].keys() def test_generated_record_id_is_an_uuid(self): mock_response(self.session) self.client.create_record({'foo': 'bar'}) id = self.session.request.mock_calls[0][1][1].split('/')[-1] uuid_regexp = r'[\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12}' self.assertRegexpMatches(id, uuid_regexp) def test_records_handles_permissions(self): mock_response(self.session) self.client.create_record({ 'id': '1234', 'foo': 'bar' }, permissions=mock.sentinel.permissions) self.session.request.assert_called_with( 'put', '/buckets/mybucket/collections/mycollection/records/1234', data={ 'foo': 'bar', 'id': '1234' }, permissions=mock.sentinel.permissions, headers=DO_NOT_OVERWRITE) def test_collection_argument_takes_precedence(self): mock_response(self.session) # Specify a different collection name for the client and the operation. client = Client(session=self.session, bucket='mybucket', collection='wrong_collection') client.update_record(data={'id': '1234'}, collection='good_collection', permissions=mock.sentinel.permissions) self.session.request.assert_called_with( 'put', '/buckets/mybucket/collections/good_collection/records/1234', data={'id': '1234'}, headers=None, permissions=mock.sentinel.permissions) def test_record_id_is_derived_from_data_if_present(self): mock_response(self.session) self.client.create_record(data={ 'id': '1234', 'foo': 'bar' }, permissions=mock.sentinel.permissions) self.session.request.assert_called_with( 'put', '/buckets/mybucket/collections/mycollection/records/1234', data={ 'id': '1234', 'foo': 'bar' }, permissions=mock.sentinel.permissions, headers=DO_NOT_OVERWRITE) def test_data_and_permissions_are_added_on_create(self): mock_response(self.session) data = {'foo': 'bar'} permissions = {'read': ['mle']} self.client.create_record(id='1234', data=data, permissions=permissions) url = '/buckets/mybucket/collections/mycollection/records/1234' self.session.request.assert_called_with('put', url, data=data, permissions=permissions, headers=DO_NOT_OVERWRITE) def test_creation_sends_if_none_match_by_default(self): mock_response(self.session) data = {'foo': 'bar'} self.client.create_record(id='1234', data=data) url = '/buckets/mybucket/collections/mycollection/records/1234' self.session.request.assert_called_with('put', url, data=data, permissions=None, headers=DO_NOT_OVERWRITE) def test_creation_doesnt_add_if_none_match_when_overwrite(self): mock_response(self.session) data = {'foo': 'bar'} self.client.create_record(id='1234', data=data, safe=False) url = '/buckets/mybucket/collections/mycollection/records/1234' self.session.request.assert_called_with('put', url, data=data, permissions=None, headers=None) def test_records_issues_a_request_on_delete(self): mock_response(self.session) self.client.delete_record('1234') url = '/buckets/mybucket/collections/mycollection/records/1234' self.session.request.assert_called_with('delete', url, headers=None) def test_record_issues_a_request_on_retrieval(self): mock_response(self.session, data={'foo': 'bar'}) record = self.client.get_record('1234') self.assertEquals(record['data'], {'foo': 'bar'}) url = '/buckets/mybucket/collections/mycollection/records/1234' self.session.request.assert_called_with('get', url) def test_collection_can_retrieve_all_records(self): mock_response(self.session, data=[{'id': 'foo'}, {'id': 'bar'}]) records = self.client.get_records() assert list(records) == [{'id': 'foo'}, {'id': 'bar'}] def test_pagination_is_followed(self): # Mock the calls to request. link = ('http://example.org/buckets/buck/collections/coll/records/' '?token=1234') self.session.request.side_effect = [ # First one returns a list of items with a pagination token. build_response([ { 'id': '1', 'value': 'item1' }, { 'id': '2', 'value': 'item2' }, ], {'Next-Page': link}), # Second one returns a list of items without a pagination token. build_response([ { 'id': '3', 'value': 'item3' }, { 'id': '4', 'value': 'item4' }, ], ), ] records = self.client.get_records('bucket', 'collection') assert list(records) == [ { 'id': '1', 'value': 'item1' }, { 'id': '2', 'value': 'item2' }, { 'id': '3', 'value': 'item3' }, { 'id': '4', 'value': 'item4' }, ] def test_pagination_supports_if_none_match(self): link = ('http://example.org/buckets/buck/collections/coll/records/' '?token=1234') self.session.request.side_effect = [ # First one returns a list of items with a pagination token. build_response([ { 'id': '1', 'value': 'item1' }, { 'id': '2', 'value': 'item2' }, ], {'Next-Page': link}), # Second one returns a list of items without a pagination token. build_response([ { 'id': '3', 'value': 'item3' }, { 'id': '4', 'value': 'item4' }, ], ), ] self.client.get_records('bucket', 'collection', if_none_match="1234") # Check that the If-None-Match header is present in the requests. self.session.request.assert_any_call( 'get', '/buckets/collection/collections/bucket/records', headers={'If-None-Match': '"1234"'}, params={}) self.session.request.assert_any_call( 'get', link, headers={'If-None-Match': '"1234"'}, params={}) def test_collection_can_delete_a_record(self): mock_response(self.session, data={'id': 1234}) resp = self.client.delete_record(id=1234) assert resp == {'id': 1234} url = '/buckets/mybucket/collections/mycollection/records/1234' self.session.request.assert_called_with('delete', url, headers=None) def test_record_delete_if_match(self): data = {} mock_response(self.session, data=data) deleted = self.client.delete_record(collection='mycollection', bucket='mybucket', id='1', last_modified=1234) assert deleted == data url = '/buckets/mybucket/collections/mycollection/records/1' self.session.request.assert_called_with('delete', url, headers={'If-Match': '"1234"'}) def test_record_delete_if_match_not_included_if_not_safe(self): data = {} mock_response(self.session, data=data) deleted = self.client.delete_record(collection='mycollection', bucket='mybucket', id='1', last_modified=1234, safe=False) assert deleted == data url = '/buckets/mybucket/collections/mycollection/records/1' self.session.request.assert_called_with('delete', url, headers=None) def test_update_record_gets_the_id_from_data_if_exists(self): mock_response(self.session) self.client.update_record(bucket='mybucket', collection='mycollection', data={ 'id': 1, 'foo': 'bar' }) self.session.request.assert_called_with( 'put', '/buckets/mybucket/collections/mycollection/records/1', data={ 'id': 1, 'foo': 'bar' }, headers=None, permissions=None) def test_update_record_handles_last_modified(self): mock_response(self.session) self.client.update_record(bucket='mybucket', collection='mycollection', data={ 'id': 1, 'foo': 'bar' }, last_modified=1234) headers = {'If-Match': '"1234"'} self.session.request.assert_called_with( 'put', '/buckets/mybucket/collections/mycollection/records/1', data={ 'id': 1, 'foo': 'bar' }, headers=headers, permissions=None) def test_patch_record_uses_the_patch_method(self): mock_response(self.session) self.client.patch_record(bucket='mybucket', collection='mycollection', data={ 'id': 1, 'foo': 'bar' }) self.session.request.assert_called_with( 'patch', '/buckets/mybucket/collections/mycollection/records/1', data={ 'id': 1, 'foo': 'bar' }, headers=None, permissions=None) def test_update_record_raises_if_no_id_is_given(self): with self.assertRaises(KeyError) as cm: self.client.update_record( data={'foo': 'bar'}, # Omit the id on purpose here. bucket='mybucket', collection='mycollection') assert text_type( cm.exception) == ("'Unable to update a record, need an id.'") def test_get_or_create_doesnt_raise_in_case_of_conflict(self): data = { 'permissions': mock.sentinel.permissions, 'data': { 'foo': 'bar' } } self.session.request.side_effect = [ get_http_error(status=412), (data, None) ] returned_data = self.client.create_record( bucket="buck", collection="coll", data={ 'id': 1234, 'foo': 'bar' }, if_not_exists=True) # Should not raise. assert returned_data == data def test_get_or_create_raise_in_other_cases(self): self.session.request.side_effect = get_http_error(status=500) with self.assertRaises(KintoException): self.client.create_record(bucket="buck", collection="coll", data={'foo': 'bar'}, if_not_exists=True)
class FunctionalTest(unittest2.TestCase): def __init__(self, *args, **kwargs): super(FunctionalTest, self).__init__(*args, **kwargs) # XXX Read the configuration from env variables. self.server_url = SERVER_URL self.auth = DEFAULT_AUTH # Read the configuration. self.config = configparser.RawConfigParser() self.config.read(os.path.join(__HERE__, 'config/kinto.ini')) self.client = Client(server_url=self.server_url, auth=self.auth) def tearDown(self): # Delete all the created objects flush_url = urljoin(self.server_url, '/__flush__') resp = requests.post(flush_url) resp.raise_for_status() def get_user_id(self, credentials): hmac_secret = self.config.get('app:main', 'cliquet.userid_hmac_secret') credentials = '%s:%s' % credentials digest = cliquet_utils.hmac_digest(hmac_secret, credentials) return 'basicauth:%s' % digest def test_bucket_creation(self): bucket = self.client.create_bucket('mozilla') user_id = self.get_user_id(self.auth) assert user_id in bucket['permissions']['write'] def test_bucket_creation_if_not_exists(self): self.client.create_bucket('mozilla') # Should not raise. self.client.create_bucket('mozilla', if_not_exists=True) def test_bucket_retrieval(self): self.client.create_bucket('mozilla') self.client.get_bucket('mozilla') # XXX Add permissions handling during creation and check they are # present during retrieval. def test_bucket_retrieval_fails_when_not_created(self): self.assertRaises(BucketNotFound, self.client.get_bucket, 'non-existent') def test_bucket_deletion(self): self.client.create_bucket('mozilla') self.client.delete_bucket('mozilla') self.assertRaises(BucketNotFound, self.client.get_bucket, 'mozilla') def test_bucket_save(self): self.client.create_bucket('mozilla', permissions={'write': ['alexis']}) bucket = self.client.get_bucket('mozilla') assert 'alexis' in bucket['permissions']['write'] def test_collection_creation(self): self.client.create_bucket('mozilla') self.client.create_collection( 'payments', bucket='mozilla', permissions={'write': ['alexis', ]} ) # Test retrieval of a collection gets the permissions as well. collection = self.client.get_collection('payments', bucket='mozilla') assert 'alexis' in collection['permissions']['write'] def test_collection_creation_if_not_exists(self): self.client.create_bucket('mozilla') self.client.create_collection('payments', bucket='mozilla') # Should not raise. self.client.create_collection('payments', bucket='mozilla', if_not_exists=True) def test_collection_list(self): self.client.create_bucket('mozilla') self.client.create_collection('receipts', bucket='mozilla') self.client.create_collection('assets', bucket='mozilla') # The returned collections should be strings. collections = self.client.get_collections('mozilla') self.assertEquals(2, len(collections)) self.assertEquals(set([coll['id'] for coll in collections]), set(['receipts', 'assets'])) def test_collection_deletion(self): self.client.create_bucket('mozilla') self.client.create_collection('payments', bucket='mozilla') self.client.delete_collection('payments', bucket='mozilla') assert len(self.client.get_collections(bucket='mozilla')) == 0 def test_record_creation_and_retrieval(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() created = client.create_record(data={'foo': 'bar'}, permissions={'read': ['alexis']}) record = client.get_record(created['data']['id']) assert 'alexis' in record['permissions']['read'] def test_records_list_retrieval(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() client.create_record(data={'foo': 'bar'}, permissions={'read': ['alexis']}) records = client.get_records() assert len(records) == 1 def test_records_paginated_list_retrieval(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() for i in range(10): client.create_record(data={'foo': 'bar'}, permissions={'read': ['alexis']}) # Kinto is running with kinto.paginate_by = 5 records = client.get_records() assert len(records) == 10 def test_single_record_save(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() created = client.create_record(data={'foo': 'bar'}, permissions={'read': ['alexis']}) created['data']['bar'] = 'baz' # XXX enhance this in order to have to pass only one argument, created. client.update_record(id=created['data']['id'], data=created['data']) retrieved = client.get_record(created['data']['id']) assert 'alexis' in retrieved['permissions']['read'] assert retrieved['data']['foo'] == u'bar' assert retrieved['data']['bar'] == u'baz' assert created['data']['id'] == retrieved['data']['id'] def test_single_record_doesnt_overwrite(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() created = client.create_record(data={'foo': 'bar'}, permissions={'read': ['alexis']}) with self.assertRaises(KintoException): # Create a second record with the ID of the first one. client.create_record(data={'id': created['data']['id'], 'bar': 'baz'}) def test_single_record_creation_if_not_exists(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() created = client.create_record(data={'foo': 'bar'}) client.create_record(data={'id': created['data']['id'], 'bar': 'baz'}, if_not_exists=True) def test_single_record_can_overwrite(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() created = client.create_record(data={'foo': 'bar'}, permissions={'read': ['alexis']}) client.create_record(data={'id': created['data']['id'], 'bar': 'baz'}, safe=False) def test_one_record_deletion(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() record = client.create_record({'foo': 'bar'}) deleted = client.delete_record(record['data']['id']) assert deleted['deleted'] is True assert len(client.get_records()) == 0 def test_bucket_sharing(self): alice_credentials = ('alice', 'p4ssw0rd') alice_userid = self.get_user_id(alice_credentials) # Create a bucket and share it with alice. self.client.create_bucket('shared-bucket', permissions={'read': [alice_userid, ]}) alice_client = Client(server_url=self.server_url, auth=alice_credentials) alice_client.get_bucket('shared-bucket') def test_updating_data_on_a_collection(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() client.patch_collection(data={'secret': 'psssssst!'}) collection = client.get_collection() assert collection['data']['secret'] == 'psssssst!' def test_collection_sharing(self): alice_credentials = ('alice', 'p4ssw0rd') alice_userid = self.get_user_id(alice_credentials) self.client.create_bucket('bob-bucket') self.client.create_collection( 'shared', bucket='bob-bucket', permissions={'read': [alice_userid, ]}) # Try to read the collection as Alice. alice_client = Client(server_url=self.server_url, auth=alice_credentials) alice_client.get_collection('shared', bucket='bob-bucket') def test_record_sharing(self): alice_credentials = ('alice', 'p4ssw0rd') alice_userid = self.get_user_id(alice_credentials) # Create a record, and share it with Alice. self.client.create_bucket('bob-bucket') self.client.create_collection('bob-personal-collection', bucket='bob-bucket') record = self.client.create_record( data={'foo': 'bar'}, permissions={'read': [alice_userid, ]}, bucket='bob-bucket', collection='bob-personal-collection') # Try to read the record as Alice alice_client = Client(server_url=self.server_url, auth=alice_credentials) record = alice_client.get_record( id=record['data']['id'], bucket='bob-bucket', collection='bob-personal-collection') assert record['data']['foo'] == 'bar' def test_request_batching(self): with self.client.batch(bucket='mozilla', collection='fonts') as batch: batch.create_bucket() batch.create_collection() batch.create_record(data={'foo': 'bar'}, permissions={'read': ['natim']}) batch.create_record(data={'bar': 'baz'}, permissions={'read': ['alexis']}) records = self.client.get_records(bucket='mozilla', collection='fonts') assert len(records) == 2 def test_replication(self): # First, create a few records on the first kinto collection. with self.client.batch(bucket='origin', collection='coll') as batch: batch.create_bucket() batch.create_collection() for n in range(10): batch.create_record(data={'foo': 'bar', 'n': n}) origin = Client( server_url=self.server_url, auth=self.auth, bucket='origin', collection='coll' ) destination = Client( server_url=self.server_url, auth=self.auth, bucket='destination', collection='coll') replication.replicate(origin, destination) records = self.client.get_records(bucket='destination', collection='coll') assert len(records) == 10
class FunctionalTest(unittest2.TestCase): def __init__(self, *args, **kwargs): super(FunctionalTest, self).__init__(*args, **kwargs) # XXX Read the configuration from env variables. self.server_url = SERVER_URL self.auth = DEFAULT_AUTH # Read the configuration. self.config = configparser.RawConfigParser() self.config.read(os.path.join(__HERE__, "config/kinto.ini")) self.client = Client(server_url=self.server_url, auth=self.auth) def tearDown(self): # Delete all the created objects flush_url = urljoin(self.server_url, "/__flush__") resp = requests.post(flush_url) resp.raise_for_status() def get_user_id(self, credentials): hmac_secret = self.config.get("app:main", "kinto.userid_hmac_secret") credentials = "%s:%s" % credentials digest = cliquet_utils.hmac_digest(hmac_secret, credentials) return "basicauth:%s" % digest def test_bucket_creation(self): bucket = self.client.create_bucket("mozilla") user_id = self.get_user_id(self.auth) assert user_id in bucket["permissions"]["write"] def test_bucket_creation_if_not_exists(self): self.client.create_bucket("mozilla") # Should not raise. self.client.create_bucket("mozilla", if_not_exists=True) def test_buckets_retrieval(self): self.client.create_bucket("mozilla") buckets = self.client.get_buckets() assert len(buckets) == 1 def test_bucket_retrieval(self): self.client.create_bucket("mozilla") self.client.get_bucket("mozilla") # XXX Add permissions handling during creation and check they are # present during retrieval. def test_bucket_modification(self): bucket = self.client.create_bucket("mozilla", data={"version": 1}) assert bucket["data"]["version"] == 1 bucket = self.client.patch_bucket("mozilla", data={"author": "you"}) assert bucket["data"]["version"] == 1 assert bucket["data"]["author"] == "you" bucket = self.client.update_bucket("mozilla", data={"date": "today"}) assert bucket["data"]["date"] == "today" assert "version" not in bucket["data"] def test_bucket_retrieval_fails_when_not_created(self): self.assertRaises(BucketNotFound, self.client.get_bucket, "non-existent") def test_bucket_deletion(self): self.client.create_bucket("mozilla") self.client.delete_bucket("mozilla") self.assertRaises(BucketNotFound, self.client.get_bucket, "mozilla") def test_buckets_deletion(self): self.client.create_bucket("mozilla") buckets = self.client.delete_buckets() assert buckets[0]["id"] == "mozilla" self.assertRaises(BucketNotFound, self.client.get_bucket, "mozilla") def test_bucket_save(self): self.client.create_bucket("mozilla", permissions={"write": ["alexis"]}) bucket = self.client.get_bucket("mozilla") assert "alexis" in bucket["permissions"]["write"] def test_collection_creation(self): self.client.create_bucket("mozilla") self.client.create_collection("payments", bucket="mozilla", permissions={"write": ["alexis"]}) # Test retrieval of a collection gets the permissions as well. collection = self.client.get_collection("payments", bucket="mozilla") assert "alexis" in collection["permissions"]["write"] def test_collection_creation_if_not_exists(self): self.client.create_bucket("mozilla") self.client.create_collection("payments", bucket="mozilla") # Should not raise. self.client.create_collection("payments", bucket="mozilla", if_not_exists=True) def test_collection_list(self): self.client.create_bucket("mozilla") self.client.create_collection("receipts", bucket="mozilla") self.client.create_collection("assets", bucket="mozilla") # The returned collections should be strings. collections = self.client.get_collections("mozilla") self.assertEquals(2, len(collections)) self.assertEquals(set([coll["id"] for coll in collections]), set(["receipts", "assets"])) def test_collection_deletion(self): self.client.create_bucket("mozilla") self.client.create_collection("payments", bucket="mozilla") self.client.delete_collection("payments", bucket="mozilla") assert len(self.client.get_collections(bucket="mozilla")) == 0 def test_collections_deletion(self): self.client.create_bucket("mozilla") self.client.create_collection("amo", bucket="mozilla") self.client.create_collection("blocklist", bucket="mozilla") self.client.delete_collections(bucket="mozilla") assert len(self.client.get_collections(bucket="mozilla")) == 0 def test_record_creation_and_retrieval(self): client = Client(server_url=self.server_url, auth=self.auth, bucket="mozilla", collection="payments") client.create_bucket() client.create_collection() created = client.create_record(data={"foo": "bar"}, permissions={"read": ["alexis"]}) record = client.get_record(created["data"]["id"]) assert "alexis" in record["permissions"]["read"] def test_records_list_retrieval(self): client = Client(server_url=self.server_url, auth=self.auth, bucket="mozilla", collection="payments") client.create_bucket() client.create_collection() client.create_record(data={"foo": "bar"}, permissions={"read": ["alexis"]}) records = client.get_records() assert len(records) == 1 def test_records_paginated_list_retrieval(self): client = Client(server_url=self.server_url, auth=self.auth, bucket="mozilla", collection="payments") client.create_bucket() client.create_collection() for i in range(10): client.create_record(data={"foo": "bar"}, permissions={"read": ["alexis"]}) # Kinto is running with kinto.paginate_by = 5 records = client.get_records() assert len(records) == 10 def test_single_record_save(self): client = Client(server_url=self.server_url, auth=self.auth, bucket="mozilla", collection="payments") client.create_bucket() client.create_collection() created = client.create_record(data={"foo": "bar"}, permissions={"read": ["alexis"]}) created["data"]["bar"] = "baz" # XXX enhance this in order to have to pass only one argument, created. client.update_record(id=created["data"]["id"], data=created["data"]) retrieved = client.get_record(created["data"]["id"]) assert "alexis" in retrieved["permissions"]["read"] assert retrieved["data"]["foo"] == u"bar" assert retrieved["data"]["bar"] == u"baz" assert created["data"]["id"] == retrieved["data"]["id"] def test_single_record_doesnt_overwrite(self): client = Client(server_url=self.server_url, auth=self.auth, bucket="mozilla", collection="payments") client.create_bucket() client.create_collection() created = client.create_record(data={"foo": "bar"}, permissions={"read": ["alexis"]}) with self.assertRaises(KintoException): # Create a second record with the ID of the first one. client.create_record(data={"id": created["data"]["id"], "bar": "baz"}) def test_single_record_creation_if_not_exists(self): client = Client(server_url=self.server_url, auth=self.auth, bucket="mozilla", collection="payments") client.create_bucket() client.create_collection() created = client.create_record(data={"foo": "bar"}) client.create_record(data={"id": created["data"]["id"], "bar": "baz"}, if_not_exists=True) def test_single_record_can_overwrite(self): client = Client(server_url=self.server_url, auth=self.auth, bucket="mozilla", collection="payments") client.create_bucket() client.create_collection() created = client.create_record(data={"foo": "bar"}, permissions={"read": ["alexis"]}) client.create_record(data={"id": created["data"]["id"], "bar": "baz"}, safe=False) def test_one_record_deletion(self): client = Client(server_url=self.server_url, auth=self.auth, bucket="mozilla", collection="payments") client.create_bucket() client.create_collection() record = client.create_record({"foo": "bar"}) deleted = client.delete_record(record["data"]["id"]) assert deleted["deleted"] is True assert len(client.get_records()) == 0 def test_multiple_record_deletion(self): client = Client(server_url=self.server_url, auth=self.auth, bucket="mozilla", collection="payments") client.create_bucket() client.create_collection() client.create_record({"foo": "bar"}) client.delete_records() assert len(client.get_records()) == 0 def test_bucket_sharing(self): alice_credentials = ("alice", "p4ssw0rd") alice_userid = self.get_user_id(alice_credentials) # Create a bucket and share it with alice. self.client.create_bucket("shared-bucket", permissions={"read": [alice_userid]}) alice_client = Client(server_url=self.server_url, auth=alice_credentials) alice_client.get_bucket("shared-bucket") def test_updating_data_on_a_collection(self): client = Client(server_url=self.server_url, auth=self.auth, bucket="mozilla", collection="payments") client.create_bucket() client.create_collection() client.patch_collection(data={"secret": "psssssst!"}) collection = client.get_collection() assert collection["data"]["secret"] == "psssssst!" def test_collection_sharing(self): alice_credentials = ("alice", "p4ssw0rd") alice_userid = self.get_user_id(alice_credentials) self.client.create_bucket("bob-bucket") self.client.create_collection("shared", bucket="bob-bucket", permissions={"read": [alice_userid]}) # Try to read the collection as Alice. alice_client = Client(server_url=self.server_url, auth=alice_credentials) alice_client.get_collection("shared", bucket="bob-bucket") def test_record_sharing(self): alice_credentials = ("alice", "p4ssw0rd") alice_userid = self.get_user_id(alice_credentials) # Create a record, and share it with Alice. self.client.create_bucket("bob-bucket") self.client.create_collection("bob-personal-collection", bucket="bob-bucket") record = self.client.create_record( data={"foo": "bar"}, permissions={"read": [alice_userid]}, bucket="bob-bucket", collection="bob-personal-collection", ) # Try to read the record as Alice alice_client = Client(server_url=self.server_url, auth=alice_credentials) record = alice_client.get_record( id=record["data"]["id"], bucket="bob-bucket", collection="bob-personal-collection" ) assert record["data"]["foo"] == "bar" def test_request_batching(self): with self.client.batch(bucket="mozilla", collection="fonts") as batch: batch.create_bucket() batch.create_collection() batch.create_record(data={"foo": "bar"}, permissions={"read": ["natim"]}) batch.create_record(data={"bar": "baz"}, permissions={"read": ["alexis"]}) records = self.client.get_records(bucket="mozilla", collection="fonts") assert len(records) == 2 def test_replication(self): # First, create a few records on the first kinto collection. with self.client.batch(bucket="origin", collection="coll") as batch: batch.create_bucket() batch.create_collection() for n in range(10): batch.create_record(data={"foo": "bar", "n": n}) origin = Client(server_url=self.server_url, auth=self.auth, bucket="origin", collection="coll") destination = Client(server_url=self.server_url, auth=self.auth, bucket="destination", collection="coll") replication.replicate(origin, destination) records = self.client.get_records(bucket="destination", collection="coll") assert len(records) == 10
def test_single_record_creation_if_not_exists(self): client = Client(server_url=self.server_url, auth=self.auth, bucket="mozilla", collection="payments") client.create_bucket() client.create_collection() created = client.create_record(data={"foo": "bar"}) client.create_record(data={"id": created["data"]["id"], "bar": "baz"}, if_not_exists=True)
class RecordTest(unittest.TestCase): def setUp(self): self.session = mock.MagicMock() self.client = Client(session=self.session, bucket="mybucket", collection="mycollection") def test_record_id_is_given_after_creation(self): mock_response(self.session, data={"id": 5678}) record = self.client.create_record({"foo": "bar"}) assert "id" in record["data"].keys() def test_generated_record_id_is_an_uuid(self): mock_response(self.session) self.client.create_record({"foo": "bar"}) id = self.session.request.mock_calls[0][1][1].split("/")[-1] uuid_regexp = r"[\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12}" self.assertRegexpMatches(id, uuid_regexp) def test_records_handles_permissions(self): mock_response(self.session) self.client.create_record({"id": "1234", "foo": "bar"}, permissions=mock.sentinel.permissions) self.session.request.assert_called_with( "put", "/buckets/mybucket/collections/mycollection/records/1234", data={"foo": "bar", "id": "1234"}, permissions=mock.sentinel.permissions, headers=DO_NOT_OVERWRITE, ) def test_collection_argument_takes_precedence(self): mock_response(self.session) # Specify a different collection name for the client and the operation. client = Client(session=self.session, bucket="mybucket", collection="wrong_collection") client.update_record(data={"id": "1234"}, collection="good_collection", permissions=mock.sentinel.permissions) self.session.request.assert_called_with( "put", "/buckets/mybucket/collections/good_collection/records/1234", data={"id": "1234"}, headers=None, permissions=mock.sentinel.permissions, ) def test_record_id_is_derived_from_data_if_present(self): mock_response(self.session) self.client.create_record(data={"id": "1234", "foo": "bar"}, permissions=mock.sentinel.permissions) self.session.request.assert_called_with( "put", "/buckets/mybucket/collections/mycollection/records/1234", data={"id": "1234", "foo": "bar"}, permissions=mock.sentinel.permissions, headers=DO_NOT_OVERWRITE, ) def test_data_and_permissions_are_added_on_create(self): mock_response(self.session) data = {"foo": "bar"} permissions = {"read": ["mle"]} self.client.create_record(id="1234", data=data, permissions=permissions) url = "/buckets/mybucket/collections/mycollection/records/1234" self.session.request.assert_called_with( "put", url, data=data, permissions=permissions, headers=DO_NOT_OVERWRITE ) def test_creation_sends_if_none_match_by_default(self): mock_response(self.session) data = {"foo": "bar"} self.client.create_record(id="1234", data=data) url = "/buckets/mybucket/collections/mycollection/records/1234" self.session.request.assert_called_with("put", url, data=data, permissions=None, headers=DO_NOT_OVERWRITE) def test_creation_doesnt_add_if_none_match_when_overwrite(self): mock_response(self.session) data = {"foo": "bar"} self.client.create_record(id="1234", data=data, safe=False) url = "/buckets/mybucket/collections/mycollection/records/1234" self.session.request.assert_called_with("put", url, data=data, permissions=None, headers=None) def test_records_issues_a_request_on_delete(self): mock_response(self.session) self.client.delete_record("1234") url = "/buckets/mybucket/collections/mycollection/records/1234" self.session.request.assert_called_with("delete", url, headers=None) def test_record_issues_a_request_on_retrieval(self): mock_response(self.session, data={"foo": "bar"}) record = self.client.get_record("1234") self.assertEquals(record["data"], {"foo": "bar"}) url = "/buckets/mybucket/collections/mycollection/records/1234" self.session.request.assert_called_with("get", url) def test_collection_can_retrieve_all_records(self): mock_response(self.session, data=[{"id": "foo"}, {"id": "bar"}]) records = self.client.get_records() assert list(records) == [{"id": "foo"}, {"id": "bar"}] def test_pagination_is_followed(self): # Mock the calls to request. link = "http://example.org/buckets/buck/collections/coll/records/" "?token=1234" self.session.request.side_effect = [ # First one returns a list of items with a pagination token. build_response([{"id": "1", "value": "item1"}, {"id": "2", "value": "item2"}], {"Next-Page": link}), # Second one returns a list of items without a pagination token. build_response([{"id": "3", "value": "item3"}, {"id": "4", "value": "item4"}]), ] records = self.client.get_records("bucket", "collection") assert list(records) == [ {"id": "1", "value": "item1"}, {"id": "2", "value": "item2"}, {"id": "3", "value": "item3"}, {"id": "4", "value": "item4"}, ] def test_pagination_supports_if_none_match(self): link = "http://example.org/buckets/buck/collections/coll/records/" "?token=1234" self.session.request.side_effect = [ # First one returns a list of items with a pagination token. build_response([{"id": "1", "value": "item1"}, {"id": "2", "value": "item2"}], {"Next-Page": link}), # Second one returns a list of items without a pagination token. build_response([{"id": "3", "value": "item3"}, {"id": "4", "value": "item4"}]), ] self.client.get_records("bucket", "collection", if_none_match="1234") # Check that the If-None-Match header is present in the requests. self.session.request.assert_any_call( "get", "/buckets/collection/collections/bucket/records", headers={"If-None-Match": '"1234"'}, params={} ) self.session.request.assert_any_call("get", link, headers={"If-None-Match": '"1234"'}, params={}) def test_collection_can_delete_a_record(self): mock_response(self.session, data={"id": 1234}) resp = self.client.delete_record(id=1234) assert resp == {"id": 1234} url = "/buckets/mybucket/collections/mycollection/records/1234" self.session.request.assert_called_with("delete", url, headers=None) def test_collection_can_delete_a_list_of_records(self): self.client.delete_records(["1234", "5678"]) # url = '/buckets/mybucket/collections/mycollection/records/9' # XXX check that the delete is done in a BATCH. def test_record_delete_if_match(self): data = {} mock_response(self.session, data=data) deleted = self.client.delete_record(collection="mycollection", bucket="mybucket", id="1", last_modified=1234) assert deleted == data url = "/buckets/mybucket/collections/mycollection/records/1" self.session.request.assert_called_with("delete", url, headers={"If-Match": '"1234"'}) def test_record_delete_if_match_not_included_if_not_safe(self): data = {} mock_response(self.session, data=data) deleted = self.client.delete_record( collection="mycollection", bucket="mybucket", id="1", last_modified=1234, safe=False ) assert deleted == data url = "/buckets/mybucket/collections/mycollection/records/1" self.session.request.assert_called_with("delete", url, headers=None) def test_update_record_gets_the_id_from_data_if_exists(self): mock_response(self.session) self.client.update_record(bucket="mybucket", collection="mycollection", data={"id": 1, "foo": "bar"}) self.session.request.assert_called_with( "put", "/buckets/mybucket/collections/mycollection/records/1", data={"id": 1, "foo": "bar"}, headers=None, permissions=None, ) def test_update_record_handles_last_modified(self): mock_response(self.session) self.client.update_record( bucket="mybucket", collection="mycollection", data={"id": 1, "foo": "bar"}, last_modified=1234 ) headers = {"If-Match": '"1234"'} self.session.request.assert_called_with( "put", "/buckets/mybucket/collections/mycollection/records/1", data={"id": 1, "foo": "bar"}, headers=headers, permissions=None, ) def test_patch_record_uses_the_patch_method(self): mock_response(self.session) self.client.patch_record(bucket="mybucket", collection="mycollection", data={"id": 1, "foo": "bar"}) self.session.request.assert_called_with( "patch", "/buckets/mybucket/collections/mycollection/records/1", data={"id": 1, "foo": "bar"}, headers=None, permissions=None, ) def test_update_record_raises_if_no_id_is_given(self): with self.assertRaises(KeyError) as cm: self.client.update_record( data={"foo": "bar"}, bucket="mybucket", collection="mycollection" # Omit the id on purpose here. ) assert text_type(cm.exception) == ("'Unable to update a record, need an id.'") def test_get_or_create_doesnt_raise_in_case_of_conflict(self): data = {"permissions": mock.sentinel.permissions, "data": {"foo": "bar"}} self.session.request.side_effect = [get_http_error(status=412), (data, None)] returned_data = self.client.create_record( bucket="buck", collection="coll", data={"id": 1234, "foo": "bar"}, if_not_exists=True ) # Should not raise. assert returned_data == data def test_get_or_create_raise_in_other_cases(self): self.session.request.side_effect = get_http_error(status=500) with self.assertRaises(KintoException): self.client.create_record(bucket="buck", collection="coll", data={"foo": "bar"}, if_not_exists=True)
class DeploymentTest(unittest.TestCase): """ Tests to verify deployments have been successful """ def setUp(self): self.credentials = ('testuser', 'abc123') self.client = Client(server_url=DEFAULT_SERVER, auth=self.credentials) self.collection = uuid.uuid1() self.bucket = 'deploytest' self.client.create_bucket(self.bucket, if_not_exists=True) self.client.create_collection(self.collection, bucket=self.bucket) def test_file_operations(self): # Create a record so we have an ID n = time.time() d = datetime.datetime.fromtimestamp(n) timestamp = int(time.mktime(d.timetuple())) data = {'timestamp': timestamp, 'title': 'Deploy Record'} self.client.create_record(data=data, bucket=self.bucket, collection=self.collection) # Work some magic to get our records and grab the first one records = self.client.get_records(collection=self.collection, bucket=self.bucket) record = records.pop(0) filename = os.path.basename(FILEPATH) mimetype, _ = mimetypes.guess_type(FILEPATH) filecontent = open(FILEPATH, "r").read() m = hashlib.sha256() m.update(filecontent) sha256 = m.hexdigest() attributes = { 'original': { 'filename': filename, 'hash': sha256, 'mimetype': mimetype, 'size': len(filecontent) } } record_uri = self.client._get_endpoint('record', id=record['id'], collection=self.collection, bucket=self.bucket) attachment_uri = '%s/attachment' % record_uri multipart = [("attachment", (filename, filecontent, mimetype))] body, _ = self.client.session.request(method='post', endpoint=attachment_uri, data=json.dumps(attributes), files=multipart) self.assertEquals(body['filename'], FILEPATH) # retrieve the file and verify the contents match new_record = self.client.get_record(id=record['id'], collection=self.collection, bucket=self.bucket) stored_file = new_record['data']['attachment']['location'] response = requests.get(stored_file, stream=True) self.assertEquals(response.text, filecontent) def testChangeOfHash(self): # Make sure old version is still accessible # Make sure new version is not the same URL as the old one # Make sure new version hash matches self.assertTrue(False) def testCleanUp(self): # HTTP DELETE # Make sure record no longer appears in collection # Make sure S3 bucket no longer contains latest version self.assertTrue(False) def testSanityChecks(self): # HTTP POST to public endpoint should fail (HTTP 405) # S3 bucket is protected (HTTP 403) # __heartbeat__ endpoint returns something reasonable self.assertTrue(False)
class Kinto_Sync(unittest.TestCase): """ Tests that given two Kinto servers you can successfully sync data from one to the other """ def setUp(self): # Figure out what the IP address where the containers are running f = os.popen('which docker-machine') docker_machine = str(f.read()).strip() if string.find(docker_machine, "/docker-machine") == -1: print("Could not find docker-machine in our path") exit() f = os.popen('%s ip default' % docker_machine) ip = str(f.read()).strip() # Set our master and read-only end points and create our test bucket self.master_url = "http://%s:8888/v1/" % ip self.read_only_url = "http://%s:8889/v1/" % ip self.credentials = ('testuser', 'abc123') self.master = Client(server_url=self.master_url, auth=self.credentials) self.read_only = Client(server_url=self.read_only_url, auth=self.credentials) self.bucket = self.get_timestamp() self.master.create_bucket(self.bucket) self.read_only.create_bucket(self.bucket) def test_sync(self): # Generate some random records collection = self.get_timestamp() self.master.create_collection(collection, bucket=self.bucket) self.read_only.create_collection(collection, bucket=self.bucket) for x in range(10): self.read_only.create_record(data=self.generate_record(), bucket=self.bucket, collection=collection) # Pause and generate some more random records on the master end-point time.sleep(3) for x in range(5): self.master.create_record(data=self.generate_record(), bucket=self.bucket, collection=collection) # Get the timestamp of our last record by doing an HTTP query of the # read-only collection and grabbing the Etag value from the header response = self.read_only.get_records(bucket=self.bucket, collection=collection) last_record = response[-1] since = last_record['last_modified'] # Query the master using that value for all the records since that one new_records = self.master.get_records(bucket=self.bucket, collection=collection, _since=since) # Add those records to our read-only end-point for data in new_records: new_data = { 'internal_id': data['internal_id'], 'title': data['title'] } self.read_only.create_record(data=new_data, bucket=self.bucket, collection=collection) master_records = self.master.get_records(bucket=self.bucket, collection=collection) read_only_records = self.read_only.get_records(bucket=self.bucket, collection=collection) # We should have 5 records in master and 15 in read-only self.assertEquals(5, len(master_records)) self.assertEquals(15, len(read_only_records)) # Clean up our collections self.master.delete_collection(collection, bucket=self.bucket) self.read_only.delete_collection(collection, bucket=self.bucket) def test_update(self): # Create ten records collection = self.get_timestamp() self.master.create_collection(collection, bucket=self.bucket) self.read_only.create_collection(collection, bucket=self.bucket) # Insert them into master for x in range(10): record = self.master.create_record(data=self.generate_record(), collection=collection, bucket=self.bucket) # Replicate them over to the read-only instance origin = dict(server_url=self.master_url, auth=self.credentials, bucket=self.bucket, collection=collection) destination = dict(server_url=self.read_only_url, auth=self.credentials, bucket=self.bucket, collection=collection) replication.replicate(origin, destination) records = self.read_only.get_records(bucket=self.bucket, collection=collection) self.assertEquals(10, len(records)) # Change one record and update master records = self.master.get_records(bucket=self.bucket, collection=collection) record = records[1] record['title'] = 'Updated record' updated_id = record['id'] self.master.update_record(record, bucket=self.bucket, collection=collection) replication.replicate(origin, destination) # Verify that the matched record was changed record = self.read_only.get_record(updated_id, bucket=self.bucket, collection=collection) self.assertEquals(updated_id, record['data']['id']) # Verify that we have ten records in each system self.assertEquals( len( self.master.get_records(bucket=self.bucket, collection=collection)), len( self.read_only.get_records(bucket=self.bucket, collection=collection))) self.master.delete_collection(collection, bucket=self.bucket) self.read_only.delete_collection(collection, bucket=self.bucket) def get_timestamp(self): n = time.time() d = datetime.datetime.fromtimestamp(n) return int(time.mktime(d.timetuple())) def generate_record(self): data = {'internal_id': self.get_timestamp(), 'title': 'Test Record'} return data
class RecordTest(unittest.TestCase): def setUp(self): self.session = mock.MagicMock() self.client = Client( session=self.session, bucket='mybucket', collection='mycollection') def test_record_id_is_given_after_creation(self): mock_response(self.session, data={'id': 5678}) record = self.client.create_record({'foo': 'bar'}) assert 'id' in record['data'].keys() def test_generated_record_id_is_an_uuid(self): mock_response(self.session) self.client.create_record({'foo': 'bar'}) id = self.session.request.mock_calls[0][1][1].split('/')[-1] uuid_regexp = r'[\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12}' self.assertRegexpMatches(id, uuid_regexp) def test_records_handles_permissions(self): mock_response(self.session) self.client.create_record( {'id': '1234', 'foo': 'bar'}, permissions=mock.sentinel.permissions) self.session.request.assert_called_with( 'put', '/buckets/mybucket/collections/mycollection/records/1234', data={'foo': 'bar', 'id': '1234'}, permissions=mock.sentinel.permissions, headers=DO_NOT_OVERWRITE) def test_collection_argument_takes_precedence(self): mock_response(self.session) # Specify a different collection name for the client and the operation. client = Client(session=self.session, bucket='mybucket', collection='wrong_collection') client.update_record(data={'id': '1234'}, collection='good_collection', permissions=mock.sentinel.permissions) self.session.request.assert_called_with( 'put', '/buckets/mybucket/collections/good_collection/records/1234', data={'id': '1234'}, headers=None, permissions=mock.sentinel.permissions) def test_record_id_is_derived_from_data_if_present(self): mock_response(self.session) self.client.create_record(data={'id': '1234', 'foo': 'bar'}, permissions=mock.sentinel.permissions) self.session.request.assert_called_with( 'put', '/buckets/mybucket/collections/mycollection/records/1234', data={'id': '1234', 'foo': 'bar'}, permissions=mock.sentinel.permissions, headers=DO_NOT_OVERWRITE) def test_data_and_permissions_are_added_on_create(self): mock_response(self.session) data = {'foo': 'bar'} permissions = {'read': ['mle']} self.client.create_record( id='1234', data=data, permissions=permissions) url = '/buckets/mybucket/collections/mycollection/records/1234' self.session.request.assert_called_with( 'put', url, data=data, permissions=permissions, headers=DO_NOT_OVERWRITE) def test_creation_sends_if_none_match_by_default(self): mock_response(self.session) data = {'foo': 'bar'} self.client.create_record( id='1234', data=data) url = '/buckets/mybucket/collections/mycollection/records/1234' self.session.request.assert_called_with( 'put', url, data=data, permissions=None, headers=DO_NOT_OVERWRITE) def test_creation_doesnt_add_if_none_match_when_overwrite(self): mock_response(self.session) data = {'foo': 'bar'} self.client.create_record(id='1234', data=data, safe=False) url = '/buckets/mybucket/collections/mycollection/records/1234' self.session.request.assert_called_with( 'put', url, data=data, permissions=None, headers=None) def test_records_issues_a_request_on_delete(self): mock_response(self.session) self.client.delete_record('1234') url = '/buckets/mybucket/collections/mycollection/records/1234' self.session.request.assert_called_with('delete', url, headers=None) def test_record_issues_a_request_on_retrieval(self): mock_response(self.session, data={'foo': 'bar'}) record = self.client.get_record('1234') self.assertEquals(record['data'], {'foo': 'bar'}) url = '/buckets/mybucket/collections/mycollection/records/1234' self.session.request.assert_called_with('get', url) def test_collection_can_retrieve_all_records(self): mock_response(self.session, data=[{'id': 'foo'}, {'id': 'bar'}]) records = self.client.get_records() assert list(records) == [{'id': 'foo'}, {'id': 'bar'}] def test_pagination_is_followed(self): # Mock the calls to request. link = ('http://example.org/buckets/buck/collections/coll/records/' '?token=1234') self.session.request.side_effect = [ # First one returns a list of items with a pagination token. build_response( [{'id': '1', 'value': 'item1'}, {'id': '2', 'value': 'item2'}, ], {'Next-Page': link}), # Second one returns a list of items without a pagination token. build_response( [{'id': '3', 'value': 'item3'}, {'id': '4', 'value': 'item4'}, ], ), ] records = self.client.get_records('bucket', 'collection') assert list(records) == [ {'id': '1', 'value': 'item1'}, {'id': '2', 'value': 'item2'}, {'id': '3', 'value': 'item3'}, {'id': '4', 'value': 'item4'}, ] def test_pagination_supports_if_none_match(self): link = ('http://example.org/buckets/buck/collections/coll/records/' '?token=1234') self.session.request.side_effect = [ # First one returns a list of items with a pagination token. build_response( [{'id': '1', 'value': 'item1'}, {'id': '2', 'value': 'item2'}, ], {'Next-Page': link}), # Second one returns a list of items without a pagination token. build_response( [{'id': '3', 'value': 'item3'}, {'id': '4', 'value': 'item4'}, ], ), ] self.client.get_records('bucket', 'collection', if_none_match="1234") # Check that the If-None-Match header is present in the requests. self.session.request.assert_any_call( 'get', '/buckets/collection/collections/bucket/records', headers={'If-None-Match': '"1234"'}, params={}) self.session.request.assert_any_call( 'get', link, headers={'If-None-Match': '"1234"'}, params={}) def test_collection_can_delete_a_record(self): mock_response(self.session, data={'id': 1234}) resp = self.client.delete_record(id=1234) assert resp == {'id': 1234} url = '/buckets/mybucket/collections/mycollection/records/1234' self.session.request.assert_called_with('delete', url, headers=None) def test_record_delete_if_match(self): data = {} mock_response(self.session, data=data) deleted = self.client.delete_record( collection='mycollection', bucket='mybucket', id='1', last_modified=1234) assert deleted == data url = '/buckets/mybucket/collections/mycollection/records/1' self.session.request.assert_called_with( 'delete', url, headers={'If-Match': '"1234"'}) def test_record_delete_if_match_not_included_if_not_safe(self): data = {} mock_response(self.session, data=data) deleted = self.client.delete_record( collection='mycollection', bucket='mybucket', id='1', last_modified=1234, safe=False) assert deleted == data url = '/buckets/mybucket/collections/mycollection/records/1' self.session.request.assert_called_with( 'delete', url, headers=None) def test_update_record_gets_the_id_from_data_if_exists(self): mock_response(self.session) self.client.update_record( bucket='mybucket', collection='mycollection', data={'id': 1, 'foo': 'bar'}) self.session.request.assert_called_with( 'put', '/buckets/mybucket/collections/mycollection/records/1', data={'id': 1, 'foo': 'bar'}, headers=None, permissions=None) def test_update_record_handles_last_modified(self): mock_response(self.session) self.client.update_record( bucket='mybucket', collection='mycollection', data={'id': 1, 'foo': 'bar'}, last_modified=1234) headers = {'If-Match': '"1234"'} self.session.request.assert_called_with( 'put', '/buckets/mybucket/collections/mycollection/records/1', data={'id': 1, 'foo': 'bar'}, headers=headers, permissions=None) def test_patch_record_uses_the_patch_method(self): mock_response(self.session) self.client.patch_record( bucket='mybucket', collection='mycollection', data={'id': 1, 'foo': 'bar'}) self.session.request.assert_called_with( 'patch', '/buckets/mybucket/collections/mycollection/records/1', data={'id': 1, 'foo': 'bar'}, headers=None, permissions=None) def test_update_record_raises_if_no_id_is_given(self): with self.assertRaises(KeyError) as cm: self.client.update_record( data={'foo': 'bar'}, # Omit the id on purpose here. bucket='mybucket', collection='mycollection' ) assert text_type(cm.exception) == ( "'Unable to update a record, need an id.'") def test_get_or_create_doesnt_raise_in_case_of_conflict(self): data = { 'permissions': mock.sentinel.permissions, 'data': {'foo': 'bar'} } self.session.request.side_effect = [ get_http_error(status=412), (data, None) ] returned_data = self.client.create_record( bucket="buck", collection="coll", data={'id': 1234, 'foo': 'bar'}, if_not_exists=True) # Should not raise. assert returned_data == data def test_get_or_create_raise_in_other_cases(self): self.session.request.side_effect = get_http_error(status=500) with self.assertRaises(KintoException): self.client.create_record( bucket="buck", collection="coll", data={'foo': 'bar'}, if_not_exists=True)
class FunctionalTest(unittest2.TestCase): def __init__(self, *args, **kwargs): super(FunctionalTest, self).__init__(*args, **kwargs) # XXX Read the configuration from env variables. self.server_url = SERVER_URL self.auth = DEFAULT_AUTH # Read the configuration. self.config = configparser.RawConfigParser() self.config.read(os.path.join(__HERE__, 'config/kinto.ini')) self.client = Client(server_url=self.server_url, auth=self.auth) def tearDown(self): # Delete all the created objects flush_url = urljoin(self.server_url, '/__flush__') resp = requests.post(flush_url) resp.raise_for_status() def get_user_id(self, credentials): hmac_secret = self.config.get('app:main', 'kinto.userid_hmac_secret') credentials = '%s:%s' % credentials digest = cliquet_utils.hmac_digest(hmac_secret, credentials) return 'basicauth:%s' % digest def test_bucket_creation(self): bucket = self.client.create_bucket('mozilla') user_id = self.get_user_id(self.auth) assert user_id in bucket['permissions']['write'] def test_bucket_creation_if_not_exists(self): self.client.create_bucket('mozilla') # Should not raise. self.client.create_bucket('mozilla', if_not_exists=True) def test_buckets_retrieval(self): self.client.create_bucket('mozilla') buckets = self.client.get_buckets() assert len(buckets) == 1 def test_bucket_retrieval(self): self.client.create_bucket('mozilla') self.client.get_bucket('mozilla') # XXX Add permissions handling during creation and check they are # present during retrieval. def test_bucket_modification(self): bucket = self.client.create_bucket('mozilla', data={'version': 1}) assert bucket['data']['version'] == 1 bucket = self.client.patch_bucket('mozilla', data={'author': 'you'}) assert bucket['data']['version'] == 1 assert bucket['data']['author'] == 'you' bucket = self.client.update_bucket('mozilla', data={'date': 'today'}) assert bucket['data']['date'] == 'today' assert 'version' not in bucket['data'] def test_bucket_retrieval_fails_when_not_created(self): self.assertRaises(BucketNotFound, self.client.get_bucket, 'non-existent') def test_bucket_deletion(self): self.client.create_bucket('mozilla') self.client.delete_bucket('mozilla') self.assertRaises(BucketNotFound, self.client.get_bucket, 'mozilla') def test_buckets_deletion(self): self.client.create_bucket('mozilla') buckets = self.client.delete_buckets() assert buckets[0]['id'] == 'mozilla' self.assertRaises(BucketNotFound, self.client.get_bucket, 'mozilla') def test_bucket_save(self): self.client.create_bucket('mozilla', permissions={'write': ['alexis']}) bucket = self.client.get_bucket('mozilla') assert 'alexis' in bucket['permissions']['write'] def test_collection_creation(self): self.client.create_bucket('mozilla') self.client.create_collection('payments', bucket='mozilla', permissions={'write': [ 'alexis', ]}) # Test retrieval of a collection gets the permissions as well. collection = self.client.get_collection('payments', bucket='mozilla') assert 'alexis' in collection['permissions']['write'] def test_collection_creation_if_not_exists(self): self.client.create_bucket('mozilla') self.client.create_collection('payments', bucket='mozilla') # Should not raise. self.client.create_collection('payments', bucket='mozilla', if_not_exists=True) def test_collection_list(self): self.client.create_bucket('mozilla') self.client.create_collection('receipts', bucket='mozilla') self.client.create_collection('assets', bucket='mozilla') # The returned collections should be strings. collections = self.client.get_collections('mozilla') self.assertEquals(2, len(collections)) self.assertEquals(set([coll['id'] for coll in collections]), set(['receipts', 'assets'])) def test_collection_deletion(self): self.client.create_bucket('mozilla') self.client.create_collection('payments', bucket='mozilla') self.client.delete_collection('payments', bucket='mozilla') assert len(self.client.get_collections(bucket='mozilla')) == 0 def test_collections_deletion(self): self.client.create_bucket('mozilla') self.client.create_collection('amo', bucket='mozilla') self.client.create_collection('blocklist', bucket='mozilla') self.client.delete_collections(bucket='mozilla') assert len(self.client.get_collections(bucket='mozilla')) == 0 def test_record_creation_and_retrieval(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() created = client.create_record(data={'foo': 'bar'}, permissions={'read': ['alexis']}) record = client.get_record(created['data']['id']) assert 'alexis' in record['permissions']['read'] def test_records_list_retrieval(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() client.create_record(data={'foo': 'bar'}, permissions={'read': ['alexis']}) records = client.get_records() assert len(records) == 1 def test_records_paginated_list_retrieval(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() for i in range(10): client.create_record(data={'foo': 'bar'}, permissions={'read': ['alexis']}) # Kinto is running with kinto.paginate_by = 5 records = client.get_records() assert len(records) == 10 def test_single_record_save(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() created = client.create_record(data={'foo': 'bar'}, permissions={'read': ['alexis']}) created['data']['bar'] = 'baz' # XXX enhance this in order to have to pass only one argument, created. client.update_record(id=created['data']['id'], data=created['data']) retrieved = client.get_record(created['data']['id']) assert 'alexis' in retrieved['permissions']['read'] assert retrieved['data']['foo'] == u'bar' assert retrieved['data']['bar'] == u'baz' assert created['data']['id'] == retrieved['data']['id'] def test_single_record_doesnt_overwrite(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() created = client.create_record(data={'foo': 'bar'}, permissions={'read': ['alexis']}) with self.assertRaises(KintoException): # Create a second record with the ID of the first one. client.create_record(data={ 'id': created['data']['id'], 'bar': 'baz' }) def test_single_record_creation_if_not_exists(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() created = client.create_record(data={'foo': 'bar'}) client.create_record(data={ 'id': created['data']['id'], 'bar': 'baz' }, if_not_exists=True) def test_single_record_can_overwrite(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() created = client.create_record(data={'foo': 'bar'}, permissions={'read': ['alexis']}) client.create_record(data={ 'id': created['data']['id'], 'bar': 'baz' }, safe=False) def test_one_record_deletion(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() record = client.create_record({'foo': 'bar'}) deleted = client.delete_record(record['data']['id']) assert deleted['deleted'] is True assert len(client.get_records()) == 0 def test_multiple_record_deletion(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() client.create_record({'foo': 'bar'}) client.delete_records() assert len(client.get_records()) == 0 def test_bucket_sharing(self): alice_credentials = ('alice', 'p4ssw0rd') alice_userid = self.get_user_id(alice_credentials) # Create a bucket and share it with alice. self.client.create_bucket('shared-bucket', permissions={'read': [ alice_userid, ]}) alice_client = Client(server_url=self.server_url, auth=alice_credentials) alice_client.get_bucket('shared-bucket') def test_updating_data_on_a_collection(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() client.patch_collection(data={'secret': 'psssssst!'}) collection = client.get_collection() assert collection['data']['secret'] == 'psssssst!' def test_collection_sharing(self): alice_credentials = ('alice', 'p4ssw0rd') alice_userid = self.get_user_id(alice_credentials) self.client.create_bucket('bob-bucket') self.client.create_collection('shared', bucket='bob-bucket', permissions={'read': [ alice_userid, ]}) # Try to read the collection as Alice. alice_client = Client(server_url=self.server_url, auth=alice_credentials) alice_client.get_collection('shared', bucket='bob-bucket') def test_record_sharing(self): alice_credentials = ('alice', 'p4ssw0rd') alice_userid = self.get_user_id(alice_credentials) # Create a record, and share it with Alice. self.client.create_bucket('bob-bucket') self.client.create_collection('bob-personal-collection', bucket='bob-bucket') record = self.client.create_record( data={'foo': 'bar'}, permissions={'read': [ alice_userid, ]}, bucket='bob-bucket', collection='bob-personal-collection') # Try to read the record as Alice alice_client = Client(server_url=self.server_url, auth=alice_credentials) record = alice_client.get_record(id=record['data']['id'], bucket='bob-bucket', collection='bob-personal-collection') assert record['data']['foo'] == 'bar' def test_request_batching(self): with self.client.batch(bucket='mozilla', collection='fonts') as batch: batch.create_bucket() batch.create_collection() batch.create_record(data={'foo': 'bar'}, permissions={'read': ['natim']}) batch.create_record(data={'bar': 'baz'}, permissions={'read': ['alexis']}) records = self.client.get_records(bucket='mozilla', collection='fonts') assert len(records) == 2 def test_replication(self): # First, create a few records on the first kinto collection. with self.client.batch(bucket='origin', collection='coll') as batch: batch.create_bucket() batch.create_collection() for n in range(10): batch.create_record(data={'foo': 'bar', 'n': n}) origin = Client(server_url=self.server_url, auth=self.auth, bucket='origin', collection='coll') destination = Client(server_url=self.server_url, auth=self.auth, bucket='destination', collection='coll') replication.replicate(origin, destination) records = self.client.get_records(bucket='destination', collection='coll') assert len(records) == 10