class CollectionLoggingTest(unittest.TestCase): def setUp(self): self.session = mock.MagicMock() self.client = Client(session=self.session) mock_response(self.session) def test_create_collection_logs_info_message(self): with mock.patch('kinto_http.logger') as mocked_logger: self.client.create_collection(id='mozilla', bucket="buck", data={'foo': 'bar'}, permissions={'write': [ 'blah', ]}) mocked_logger.info.assert_called_with( "Create collection 'mozilla' in bucket 'buck'") def test_update_collection_logs_info_message(self): with mock.patch('kinto_http.logger') as mocked_logger: self.client.update_collection( data={'foo': 'bar'}, id='mozilla', bucket='buck', permissions={'write': [ 'blahblah', ]}) mocked_logger.info.assert_called_with( "Update collection 'mozilla' in bucket 'buck'") def test_patch_collection_logs_info_message(self): with mock.patch('kinto_http.logger') as mocked_logger: self.client.patch_collection(data={'foo': 'bar'}, id='mozilla', bucket='buck', permissions={'write': [ 'blahblah', ]}) mocked_logger.info.assert_called_with( "Patch collection 'mozilla' in bucket 'buck'") def test_get_collection_logs_info_message(self): with mock.patch('kinto_http.logger') as mocked_logger: self.client.get_collection(id='mozilla', bucket='buck') mocked_logger.info.assert_called_with( "Get collection 'mozilla' in bucket 'buck'") def test_delete_collection_logs_info_message(self): with mock.patch('kinto_http.logger') as mocked_logger: self.client.delete_collection(id='mozilla', bucket="buck") mocked_logger.info.assert_called_with( "Delete collection 'mozilla' in bucket 'buck'") def test_delete_collections_logs_info_message(self): with mock.patch('kinto_http.logger') as mocked_logger: self.client.delete_collections(bucket="buck") mocked_logger.info.assert_called_with( "Delete collections in bucket 'buck'")
def test_collection_sharing(self): alice_credentials = ("alice", "p4ssw0rd") alice_userid = self.get_user_id(alice_credentials) self.client.create_bucket(id="bob-bucket") self.client.create_collection(id="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(id="shared", bucket="bob-bucket")
def test_file_can_have_yaml_references(self): self.load() client = Client(server_url=self.server, auth=tuple(self.auth.split(':'))) collection = client.get_collection(bucket="main", id="certificates") assert 'url' in collection['data']['schema']['properties'] collection = client.get_collection(bucket="main", id="addons") assert 'url' in collection['data']['schema']['properties'] # the anchor did not get interpreted as a bucket: with self.assertRaises(exceptions.KintoException): client.get_collection(bucket="attachment-schema")
def test_collection_sharing(self): alice_credentials = ('alice', 'p4ssw0rd') alice_userid = self.get_user_id(alice_credentials) self.client.create_bucket(id='bob-bucket') self.client.create_collection( id='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(id='shared', bucket='bob-bucket')
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')
class BasicMigrationsTest(unittest.TestCase): def setUp(self): self.client = Client(server_url='http://localhost:8888/v1/', auth=('test', 'case')) def test_create_bucket(self): model = {'$buckets': {'stuff': {}}} migrate_model(self.client, model) self.client.get_bucket('stuff') def test_create_collection(self): model = {'$buckets': {'stuff': {'$collections': {'good_stuff': {}}}}} migrate_model(self.client, model) self.client.get_collection('good_stuff', bucket='stuff') def test_create_record(self): model = { '$buckets': { 'stuff': { '$collections': { 'good_stuff': { '$records': { 'bitcoin': {} } } } } } } migrate_model(self.client, model) self.client.get_record('bitcoin', bucket='stuff', collection='good_stuff') def test_support_metadata(self): model = {'$buckets': {'stuff': {'foo': 'bar'}}} migrate_model(self.client, model) data = self.client.get_bucket('stuff')['data'] assert data['foo'] == 'bar' def test_support_permissions(self): model = {'$buckets': {'stuff': {'$permissions': {'read': ['bar']}}}} migrate_model(self.client, model) perms = self.client.get_bucket('stuff')['permissions'] assert 'bar' in perms['read']
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!'
class CollectionLoggingTest(unittest.TestCase): def setUp(self): self.session = mock.MagicMock() self.client = Client(session=self.session) mock_response(self.session) def test_create_collection_logs_info_message(self): with mock.patch('kinto_http.logger') as mocked_logger: self.client.create_collection( 'mozilla', bucket="buck", data={'foo': 'bar'}, permissions={'write': ['blah', ]}) mocked_logger.info.assert_called_with( "Create collection 'mozilla' in bucket 'buck'") def test_update_collection_logs_info_message(self): with mock.patch('kinto_http.logger') as mocked_logger: self.client.update_collection( data={'foo': 'bar'}, collection='mozilla', bucket='buck', permissions={'write': ['blahblah', ]}) mocked_logger.info.assert_called_with( "Update collection 'mozilla' in bucket 'buck'") def test_get_collection_logs_info_message(self): with mock.patch('kinto_http.logger') as mocked_logger: self.client.get_collection( 'mozilla', bucket='buck') mocked_logger.info.assert_called_with( "Get collection 'mozilla' in bucket 'buck'") def test_delete_collection_logs_info_message(self): with mock.patch('kinto_http.logger') as mocked_logger: self.client.delete_collection( 'mozilla', bucket="buck") mocked_logger.info.assert_called_with( "Delete collection 'mozilla' in bucket 'buck'") def test_delete_collections_logs_info_message(self): with mock.patch('kinto_http.logger') as mocked_logger: self.client.delete_collections( bucket="buck") mocked_logger.info.assert_called_with( "Delete collections in bucket 'buck'")
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 download_collection_data(server_url, collection): client = Client( server_url=server_url, bucket=collection["bucket"], collection=collection["collection"], ) endpoint = client.get_endpoint("collection") # Collection metadata with cache busting metadata = client.get_collection( _expected=collection["last_modified"])["data"] # Download records with cache busting records = client.get_records(_sort="-last_modified", _expected=collection["last_modified"]) timestamp = client.get_records_timestamp() return (collection, endpoint, metadata, records, timestamp)
def _has_inconsistencies(server_url, auth, r): client = Client(server_url=server_url, auth=auth) source_metadata = client.get_collection( bucket=r["source"]["bucket"], id=r["source"]["collection"])["data"] status = source_metadata["status"] identifier = "{bucket}/{collection}".format(**r["destination"]) # Collection status is reset on any modification, so if status is ``to-review``, # then records in the source should be exactly the same as the records in the preview if status == "to-review": source_records = client.get_records(**r["source"]) preview_records = client.get_records(**r["preview"]) diff = compare_collections(source_records, preview_records) if diff: return identifier, diff # And if status is ``signed``, then records in the source and preview should # all be the same as those in the destination. elif status == "signed" or status is None: source_records = client.get_records(**r["source"]) dest_records = client.get_records(**r["destination"]) if "preview" in r: # If preview is enabled, then compare source/preview and preview/dest preview_records = client.get_records(**r["preview"]) diff_source = compare_collections(source_records, preview_records) diff_preview = compare_collections(preview_records, dest_records) else: # Otherwise, just compare source/dest diff_source = compare_collections(source_records, dest_records) diff_preview = [] # If difference detected, report it! if diff_source or diff_preview: return identifier, diff_source + diff_preview else: # And if status is ``work-in-progress``, we can't really check anything. # Source can differ from preview, and preview can differ from destination # if a review request was previously rejected. print(f"{identifier} SKIP ({status})") return identifier, None print(f"{identifier} OK") return identifier, None
class FunctionalTest(unittest.TestCase): def setUp(self): super().setUp() # 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) self.create_user(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 create_user(self, credentials): account_url = urljoin(self.server_url, "/accounts/{}".format(credentials[0])) r = requests.put(account_url, json={"data": { "password": credentials[1] }}, auth=DEFAULT_AUTH) r.raise_for_status() return r.json() def get_user_id(self, credentials): r = self.create_user(credentials) return "account:{}".format(r["data"]["id"]) def test_bucket_creation(self): bucket = self.client.create_bucket(id="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(id="mozilla") # Should not raise. self.client.create_bucket(id="mozilla", if_not_exists=True) def test_buckets_retrieval(self): self.client.create_bucket(id="mozilla") buckets = self.client.get_buckets() assert len(buckets) == 1 def test_bucket_retrieval(self): self.client.create_bucket(id="mozilla") self.client.get_bucket(id="mozilla") # XXX Add permissions handling during creation and check they are # present during retrieval. def test_bucket_modification(self): bucket = self.client.create_bucket(id="mozilla", data={"version": 1}) assert bucket["data"]["version"] == 1 bucket = self.client.patch_bucket(id="mozilla", data={"author": "you"}) assert bucket["data"]["version"] == 1 assert bucket["data"]["author"] == "you" bucket = self.client.update_bucket(id="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, id="non-existent") def test_bucket_deletion(self): self.client.create_bucket(id="mozilla") self.client.delete_bucket(id="mozilla") self.assertRaises(BucketNotFound, self.client.get_bucket, id="mozilla") def test_bucket_deletion_if_exists(self): self.client.create_bucket(id="mozilla") self.client.delete_bucket(id="mozilla") self.client.delete_bucket(id="mozilla", if_exists=True) def test_buckets_deletion(self): self.client.create_bucket(id="mozilla") buckets = self.client.delete_buckets() assert buckets[0]["id"] == "mozilla" self.assertRaises(BucketNotFound, self.client.get_bucket, id="mozilla") def test_buckets_deletion_when_no_buckets_exist(self): deleted_buckets = self.client.delete_buckets() assert len(deleted_buckets) == 0 def test_bucket_save(self): self.client.create_bucket(id="mozilla", permissions={"write": ["account:alexis"]}) bucket = self.client.get_bucket(id="mozilla") assert "account:alexis" in bucket["permissions"]["write"] def test_group_creation(self): self.client.create_bucket(id="mozilla") self.client.create_group( id="payments", bucket="mozilla", data={"members": ["blah"]}, permissions={"write": ["blah"]}, ) # Test retrieval of a group gets the permissions as well. group = self.client.get_group(id="payments", bucket="mozilla") assert "blah" in group["permissions"]["write"] def test_group_creation_if_not_exists(self): self.client.create_bucket(id="mozilla") self.client.create_group(id="payments", bucket="mozilla", data={"members": ["blah"]}) self.client.create_group( id="payments", bucket="mozilla", data={"members": ["blah"]}, permissions={"write": ["blah"]}, if_not_exists=True, ) def test_group_creation_if_bucket_does_not_exist(self): with pytest.raises(KintoException) as e: self.client.create_group(id="payments", bucket="mozilla", data={"members": ["blah"]}) assert str(e).endswith( "PUT /v1/buckets/mozilla/groups/payments - " "403 Unauthorized. Please check that the " "bucket exists and that you have the permission " "to create or write on this group.") def test_group_update(self): self.client.create_bucket(id="mozilla") group = self.client.create_group(id="payments", bucket="mozilla", data={"members": ["blah"]}, if_not_exists=True) assert group["data"]["members"][0] == "blah" group = self.client.update_group(data={"members": ["blah", "foo"]}, id="payments", bucket="mozilla") self.assertEqual(group["data"]["members"][1], "foo") def test_group_list(self): self.client.create_bucket(id="mozilla") self.client.create_group(id="receipts", bucket="mozilla", data={"members": ["blah"]}) self.client.create_group(id="assets", bucket="mozilla", data={"members": ["blah"]}) # The returned groups should be strings. groups = self.client.get_groups(bucket="mozilla") self.assertEqual(2, len(groups)) self.assertEqual(set([coll["id"] for coll in groups]), set(["receipts", "assets"])) def test_group_deletion(self): self.client.create_bucket(id="mozilla") self.client.create_group(id="payments", bucket="mozilla", data={"members": ["blah"]}) self.client.delete_group(id="payments", bucket="mozilla") assert len(self.client.get_groups(bucket="mozilla")) == 0 def test_group_deletion_if_exists(self): self.client.create_bucket(id="mozilla") self.client.create_group(id="payments", bucket="mozilla", data={"members": ["blah"]}) self.client.delete_group(id="payments", bucket="mozilla") self.client.delete_group(id="payments", bucket="mozilla", if_exists=True) def test_group_deletion_can_still_raise_errors(self): error = KintoException("An error occured") with mock.patch.object(self.client.session, "request", side_effect=error): with pytest.raises(KintoException): self.client.delete_group(id="payments", bucket="mozilla", if_exists=True) def test_groups_deletion(self): self.client.create_bucket(id="mozilla") self.client.create_group(id="amo", bucket="mozilla", data={"members": ["blah"]}) self.client.create_group(id="blocklist", bucket="mozilla", data={"members": ["blah"]}) self.client.delete_groups(bucket="mozilla") assert len(self.client.get_groups(bucket="mozilla")) == 0 def test_groups_deletion_when_no_groups_exist(self): self.client.create_bucket(id="mozilla") deleted_groups = self.client.delete_groups(bucket="mozilla") assert len(deleted_groups) == 0 def test_collection_creation(self): self.client.create_bucket(id="mozilla") self.client.create_collection( id="payments", bucket="mozilla", permissions={"write": ["account:alexis"]}) # Test retrieval of a collection gets the permissions as well. collection = self.client.get_collection(id="payments", bucket="mozilla") assert "account:alexis" in collection["permissions"]["write"] def test_collection_not_found(self): self.client.create_bucket(id="mozilla") with pytest.raises(CollectionNotFound): self.client.get_collection(id="payments", bucket="mozilla") def test_collection_access_forbidden(self): with pytest.raises(KintoException): self.client.get_collection(id="payments", bucket="mozilla") def test_collection_creation_if_not_exists(self): self.client.create_bucket(id="mozilla") self.client.create_collection(id="payments", bucket="mozilla") # Should not raise. self.client.create_collection(id="payments", bucket="mozilla", if_not_exists=True) def test_collection_list(self): self.client.create_bucket(id="mozilla") self.client.create_collection(id="receipts", bucket="mozilla") self.client.create_collection(id="assets", bucket="mozilla") # The returned collections should be strings. collections = self.client.get_collections(bucket="mozilla") self.assertEqual(len(collections), 2) self.assertEqual(set([coll["id"] for coll in collections]), set(["receipts", "assets"])) def test_collection_deletion(self): self.client.create_bucket(id="mozilla") self.client.create_collection(id="payments", bucket="mozilla") self.client.delete_collection(id="payments", bucket="mozilla") assert len(self.client.get_collections(bucket="mozilla")) == 0 def test_collection_deletion_if_exists(self): self.client.create_bucket(id="mozilla") self.client.create_collection(id="payments", bucket="mozilla") self.client.delete_collection(id="payments", bucket="mozilla") self.client.delete_collection(id="payments", bucket="mozilla", if_exists=True) def test_collection_deletion_can_still_raise_errors(self): error = KintoException("An error occured") with mock.patch.object(self.client.session, "request", side_effect=error): with pytest.raises(KintoException): self.client.delete_collection(id="payments", bucket="mozilla", if_exists=True) def test_collections_deletion(self): self.client.create_bucket(id="mozilla") self.client.create_collection(id="amo", bucket="mozilla") self.client.create_collection(id="blocklist", bucket="mozilla") self.client.delete_collections(bucket="mozilla") assert len(self.client.get_collections(bucket="mozilla")) == 0 def test_collections_deletion_when_no_collections_exist(self): self.client.create_bucket(id="mozilla") deleted_collections = self.client.delete_collections(bucket="mozilla") assert len(deleted_collections) == 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": ["account:alexis"]}) record = client.get_record(id=created["data"]["id"]) assert "account: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": ["account:alexis"]}) records = client.get_records() assert len(records) == 1 def test_records_timestamp_retrieval(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(data={"foo": "bar"}, permissions={"read": ["account:alexis"]}) etag = client.get_records_timestamp() assert str(etag) == str(record["data"]["last_modified"]) 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": ["account:alexis"]}) # Kinto is running with kinto.paginate_by = 5 records = client.get_records() assert len(records) == 10 def test_records_generator_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": ["account:alexis"]}) pages = list(client.get_paginated_records()) assert len(pages) == 2 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": ["account: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(id=created["data"]["id"]) assert "account: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": ["account: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": ["account: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(data={"foo": "bar"}) deleted = client.delete_record(id=record["data"]["id"]) assert deleted["deleted"] is True assert len(client.get_records()) == 0 def test_record_deletion_if_exists(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(data={"foo": "bar"}) deleted = client.delete_record(id=record["data"]["id"]) deleted_if_exists = client.delete_record(id=record["data"]["id"], if_exists=True) assert deleted["deleted"] is True assert deleted_if_exists is None 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(data={"foo": "bar"}) client.delete_records() assert len(client.get_records()) == 0 def test_records_deletion_when_no_records_exist(self): client = Client(server_url=self.server_url, auth=self.auth, bucket="mozilla", collection="payments") client.create_bucket() client.create_collection() deleted_records = client.delete_records() assert len(deleted_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(id="shared-bucket", permissions={"read": [alice_userid]}) alice_client = Client(server_url=self.server_url, auth=alice_credentials) alice_client.get_bucket(id="shared-bucket") def test_updating_data_on_a_group(self): client = Client(server_url=self.server_url, auth=self.auth, bucket="mozilla") client.create_bucket() client.create_group(id="payments", data={"members": []}) client.patch_group(id="payments", data={"secret": "psssssst!"}) group = client.get_group(id="payments") assert group["data"]["secret"] == "psssssst!" 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(id="bob-bucket") self.client.create_collection(id="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(id="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(id="bob-bucket") self.client.create_collection(id="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": ["account:alexis"]}) _, _, r1, r2 = batch.results() records = self.client.get_records(bucket="mozilla", collection="fonts") assert len(records) == 2 assert records[0] == r2["data"] assert records[1] == r1["data"] def test_patch_record_jsonpatch(self): self.client.create_bucket(id="b1") self.client.create_collection(id="c1", bucket="b1") self.client.create_record(id="r1", collection="c1", bucket="b1", data={"hello": "world"}) patch = JSONPatch([ { "op": "add", "path": "/data/goodnight", "value": "moon" }, { "op": "add", "path": "/permissions/read/alice" }, ]) self.client.patch_record(id="r1", collection="c1", bucket="b1", changes=patch) record = self.client.get_record(bucket="b1", collection="c1", id="r1") assert record["data"]["hello"] == "world" assert record["data"]["goodnight"] == "moon" assert record["permissions"]["read"] == ["alice"] 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(unittest.TestCase): def setUp(self): super().setUp() # 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) self.create_user(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 create_user(self, credentials): account_url = urljoin(self.server_url, '/accounts/{}'.format(credentials[0])) r = requests.put(account_url, json={"data": {"password": credentials[1]}}, auth=DEFAULT_AUTH) r.raise_for_status() return r.json() def get_user_id(self, credentials): r = self.create_user(credentials) return 'account:{}'.format(r["data"]["id"]) def test_bucket_creation(self): bucket = self.client.create_bucket(id='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(id='mozilla') # Should not raise. self.client.create_bucket(id='mozilla', if_not_exists=True) def test_buckets_retrieval(self): self.client.create_bucket(id='mozilla') buckets = self.client.get_buckets() assert len(buckets) == 1 def test_bucket_retrieval(self): self.client.create_bucket(id='mozilla') self.client.get_bucket(id='mozilla') # XXX Add permissions handling during creation and check they are # present during retrieval. def test_bucket_modification(self): bucket = self.client.create_bucket(id='mozilla', data={'version': 1}) assert bucket['data']['version'] == 1 bucket = self.client.patch_bucket(id='mozilla', data={'author': 'you'}) assert bucket['data']['version'] == 1 assert bucket['data']['author'] == 'you' bucket = self.client.update_bucket(id='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, id='non-existent') def test_bucket_deletion(self): self.client.create_bucket(id='mozilla') self.client.delete_bucket(id='mozilla') self.assertRaises(BucketNotFound, self.client.get_bucket, id='mozilla') def test_bucket_deletion_if_exists(self): self.client.create_bucket(id='mozilla') self.client.delete_bucket(id='mozilla') self.client.delete_bucket(id='mozilla', if_exists=True) def test_buckets_deletion(self): self.client.create_bucket(id='mozilla') buckets = self.client.delete_buckets() assert buckets[0]['id'] == 'mozilla' self.assertRaises(BucketNotFound, self.client.get_bucket, id='mozilla') def test_buckets_deletion_when_no_buckets_exist(self): deleted_buckets = self.client.delete_buckets() assert len(deleted_buckets) == 0 def test_bucket_save(self): self.client.create_bucket(id='mozilla', permissions={'write': ['account:alexis']}) bucket = self.client.get_bucket(id='mozilla') assert 'account:alexis' in bucket['permissions']['write'] def test_group_creation(self): self.client.create_bucket(id='mozilla') self.client.create_group( id='payments', bucket='mozilla', data={'members': ['blah', ]}, permissions={'write': ['blah', ]}) # Test retrieval of a group gets the permissions as well. group = self.client.get_group(id='payments', bucket='mozilla') assert 'blah' in group['permissions']['write'] def test_group_creation_if_not_exists(self): self.client.create_bucket(id='mozilla') self.client.create_group(id='payments', bucket='mozilla', data={'members': ['blah', ]}) self.client.create_group( id='payments', bucket='mozilla', data={'members': ['blah', ]}, permissions={'write': ['blah', ]}, if_not_exists=True) def test_group_creation_if_bucket_does_not_exist(self): with pytest.raises(KintoException) as e: self.client.create_group( id='payments', bucket='mozilla', data={'members': ['blah']}) assert str(e).endswith('PUT /v1/buckets/mozilla/groups/payments - ' '403 Unauthorized. Please check that the ' 'bucket exists and that you have the permission ' 'to create or write on this group.') def test_group_update(self): self.client.create_bucket(id='mozilla') group = self.client.create_group( id='payments', bucket='mozilla', data={'members': ['blah', ]}, if_not_exists=True) assert group['data']['members'][0] == 'blah' group = self.client.update_group( data={'members': ['blah', 'foo']}, id='payments', bucket='mozilla') self.assertEqual(group['data']['members'][1], 'foo') def test_group_list(self): self.client.create_bucket(id='mozilla') self.client.create_group(id='receipts', bucket='mozilla', data={'members': ['blah', ]}) self.client.create_group(id='assets', bucket='mozilla', data={'members': ['blah', ]}) # The returned groups should be strings. groups = self.client.get_groups(bucket='mozilla') self.assertEqual(2, len(groups)) self.assertEqual(set([coll['id'] for coll in groups]), set(['receipts', 'assets'])) def test_group_deletion(self): self.client.create_bucket(id='mozilla') self.client.create_group(id='payments', bucket='mozilla', data={'members': ['blah', ]}) self.client.delete_group(id='payments', bucket='mozilla') assert len(self.client.get_groups(bucket='mozilla')) == 0 def test_group_deletion_if_exists(self): self.client.create_bucket(id='mozilla') self.client.create_group(id='payments', bucket='mozilla', data={'members': ['blah', ]}) self.client.delete_group(id='payments', bucket='mozilla') self.client.delete_group(id='payments', bucket='mozilla', if_exists=True) def test_group_deletion_can_still_raise_errors(self): error = KintoException("An error occured") with mock.patch.object(self.client.session, 'request', side_effect=error): with pytest.raises(KintoException): self.client.delete_group(id='payments', bucket='mozilla', if_exists=True) def test_groups_deletion(self): self.client.create_bucket(id='mozilla') self.client.create_group(id='amo', bucket='mozilla', data={'members': ['blah', ]}) self.client.create_group(id='blocklist', bucket='mozilla', data={'members': ['blah', ]}) self.client.delete_groups(bucket='mozilla') assert len(self.client.get_groups(bucket='mozilla')) == 0 def test_groups_deletion_when_no_groups_exist(self): self.client.create_bucket(id='mozilla') deleted_groups = self.client.delete_groups(bucket='mozilla') assert len(deleted_groups) == 0 def test_collection_creation(self): self.client.create_bucket(id='mozilla') self.client.create_collection( id='payments', bucket='mozilla', permissions={'write': ['account:alexis', ]} ) # Test retrieval of a collection gets the permissions as well. collection = self.client.get_collection(id='payments', bucket='mozilla') assert 'account:alexis' in collection['permissions']['write'] def test_collection_not_found(self): self.client.create_bucket(id='mozilla') with pytest.raises(CollectionNotFound): self.client.get_collection(id='payments', bucket='mozilla') def test_collection_access_forbidden(self): with pytest.raises(KintoException): self.client.get_collection(id='payments', bucket='mozilla') def test_collection_creation_if_not_exists(self): self.client.create_bucket(id='mozilla') self.client.create_collection(id='payments', bucket='mozilla') # Should not raise. self.client.create_collection(id='payments', bucket='mozilla', if_not_exists=True) def test_collection_list(self): self.client.create_bucket(id='mozilla') self.client.create_collection(id='receipts', bucket='mozilla') self.client.create_collection(id='assets', bucket='mozilla') # The returned collections should be strings. collections = self.client.get_collections(bucket='mozilla') self.assertEqual(len(collections), 2) self.assertEqual(set([coll['id'] for coll in collections]), set(['receipts', 'assets'])) def test_collection_deletion(self): self.client.create_bucket(id='mozilla') self.client.create_collection(id='payments', bucket='mozilla') self.client.delete_collection(id='payments', bucket='mozilla') assert len(self.client.get_collections(bucket='mozilla')) == 0 def test_collection_deletion_if_exists(self): self.client.create_bucket(id='mozilla') self.client.create_collection(id='payments', bucket='mozilla') self.client.delete_collection(id='payments', bucket='mozilla') self.client.delete_collection(id='payments', bucket='mozilla', if_exists=True) def test_collection_deletion_can_still_raise_errors(self): error = KintoException("An error occured") with mock.patch.object(self.client.session, 'request', side_effect=error): with pytest.raises(KintoException): self.client.delete_collection(id='payments', bucket='mozilla', if_exists=True) def test_collections_deletion(self): self.client.create_bucket(id='mozilla') self.client.create_collection(id='amo', bucket='mozilla') self.client.create_collection(id='blocklist', bucket='mozilla') self.client.delete_collections(bucket='mozilla') assert len(self.client.get_collections(bucket='mozilla')) == 0 def test_collections_deletion_when_no_collections_exist(self): self.client.create_bucket(id='mozilla') deleted_collections = self.client.delete_collections(bucket='mozilla') assert len(deleted_collections) == 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': ['account:alexis']}) record = client.get_record(id=created['data']['id']) assert 'account: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': ['account:alexis']}) records = client.get_records() assert len(records) == 1 def test_records_timestamp_retrieval(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(data={'foo': 'bar'}, permissions={'read': ['account:alexis']}) etag = client.get_records_timestamp() assert str(etag) == str(record["data"]["last_modified"]) 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': ['account: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': ['account: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(id=created['data']['id']) assert 'account: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': ['account: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': ['account: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(data={'foo': 'bar'}) deleted = client.delete_record(id=record['data']['id']) assert deleted['deleted'] is True assert len(client.get_records()) == 0 def test_record_deletion_if_exists(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(data={'foo': 'bar'}) deleted = client.delete_record(id=record['data']['id']) deleted_if_exists = client.delete_record(id=record['data']['id'], if_exists=True) assert deleted['deleted'] is True assert deleted_if_exists is None 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(data={'foo': 'bar'}) client.delete_records() assert len(client.get_records()) == 0 def test_records_deletion_when_no_records_exist(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() deleted_records = client.delete_records() assert len(deleted_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(id='shared-bucket', permissions={'read': [alice_userid, ]}) alice_client = Client(server_url=self.server_url, auth=alice_credentials) alice_client.get_bucket(id='shared-bucket') def test_updating_data_on_a_group(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla') client.create_bucket() client.create_group(id='payments', data={'members': []}) client.patch_group(id='payments', data={'secret': 'psssssst!'}) group = client.get_group(id='payments') assert group['data']['secret'] == 'psssssst!' 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(id='bob-bucket') self.client.create_collection( id='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(id='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(id='bob-bucket') self.client.create_collection(id='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': ['account:alexis']}) _, _, r1, r2 = batch.results() records = self.client.get_records(bucket='mozilla', collection='fonts') assert len(records) == 2 assert records[0] == r2['data'] assert records[1] == r1['data'] def test_patch_record_jsonpatch(self): self.client.create_bucket(id='b1') self.client.create_collection(id='c1', bucket='b1') self.client.create_record(id='r1', collection='c1', bucket='b1', data={"hello": "world"}) patch = JSONPatch([ {'op': 'add', 'path': '/data/goodnight', 'value': 'moon'}, {'op': 'add', 'path': '/permissions/read/alice'} ]) self.client.patch_record(id='r1', collection='c1', bucket='b1', changes=patch) record = self.client.get_record(bucket='b1', collection='c1', id='r1') assert record['data']['hello'] == 'world' assert record['data']['goodnight'] == 'moon' assert record['permissions']['read'] == ['alice'] 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 CollectionTest(unittest.TestCase): def setUp(self): self.session = mock.MagicMock() mock_response(self.session) self.client = Client(session=self.session, bucket='mybucket') def test_collection_names_are_slugified(self): self.client.get_collection('my collection') url = '/buckets/mybucket/collections/my-collection' self.session.request.assert_called_with('get', url) def test_collection_creation_issues_an_http_put(self): self.client.create_collection( 'mycollection', permissions=mock.sentinel.permissions) url = '/buckets/mybucket/collections/mycollection' self.session.request.assert_called_with( 'put', url, data=None, permissions=mock.sentinel.permissions, headers=DO_NOT_OVERWRITE) def test_data_can_be_sent_on_creation(self): self.client.create_collection( 'mycollection', 'testbucket', data={'foo': 'bar'}) self.session.request.assert_called_with( 'put', '/buckets/testbucket/collections/mycollection', data={'foo': 'bar'}, permissions=None, headers=DO_NOT_OVERWRITE) def test_collection_update_issues_an_http_put(self): self.client.update_collection( {'foo': 'bar'}, collection='mycollection', permissions=mock.sentinel.permissions) url = '/buckets/mybucket/collections/mycollection' self.session.request.assert_called_with( 'put', url, data={'foo': 'bar'}, permissions=mock.sentinel.permissions, headers=None) def test_update_handles_if_match(self): self.client.update_collection( {'foo': 'bar'}, collection='mycollection', if_match=1234) url = '/buckets/mybucket/collections/mycollection' headers = {'If-Match': '"1234"'} self.session.request.assert_called_with( 'put', url, data={'foo': 'bar'}, headers=headers, permissions=None) def test_collection_update_use_an_if_match_header(self): data = {'foo': 'bar', 'last_modified': '1234'} self.client.update_collection( data, collection='mycollection', permissions=mock.sentinel.permissions) url = '/buckets/mybucket/collections/mycollection' self.session.request.assert_called_with( 'put', url, data={'foo': 'bar', 'last_modified': '1234'}, permissions=mock.sentinel.permissions, headers={'If-Match': '"1234"'}) def test_patch_collection_issues_an_http_patch(self): self.client.patch_collection( collection='mycollection', data={'key': 'secret'}) url = '/buckets/mybucket/collections/mycollection' self.session.request.assert_called_with( 'patch', url, data={'key': 'secret'}, headers=None, permissions=None) def test_patch_collection_handles_if_match(self): self.client.patch_collection( collection='mycollection', data={'key': 'secret'}, if_match=1234) url = '/buckets/mybucket/collections/mycollection' headers = {'If-Match': '"1234"'} self.session.request.assert_called_with( 'patch', url, data={'key': 'secret'}, headers=headers, permissions=None) def test_get_collections_returns_the_list_of_collections(self): mock_response( self.session, data=[ {'id': 'foo', 'last_modified': '12345'}, {'id': 'bar', 'last_modified': '59874'}, ]) collections = self.client.get_collections(bucket='default') assert list(collections) == [ {'id': 'foo', 'last_modified': '12345'}, {'id': 'bar', 'last_modified': '59874'}, ] def test_collection_can_delete_all_its_records(self): self.client.delete_records(bucket='abucket', collection='acollection') url = '/buckets/abucket/collections/acollection/records' self.session.request.assert_called_with('delete', url, headers=None) def test_delete_is_issued_on_list_deletion(self): self.client.delete_collections(bucket='mybucket') url = '/buckets/mybucket/collections' self.session.request.assert_called_with('delete', url, headers=None) def test_collection_can_be_deleted(self): data = {} mock_response(self.session, data=data) deleted = self.client.delete_collection('mycollection') assert deleted == data url = '/buckets/mybucket/collections/mycollection' self.session.request.assert_called_with('delete', url, headers=None) def test_collection_delete_if_match(self): data = {} mock_response(self.session, data=data) deleted = self.client.delete_collection( 'mycollection', if_match=1234) assert deleted == data url = '/buckets/mybucket/collections/mycollection' self.session.request.assert_called_with( 'delete', url, headers={'If-Match': '"1234"'}) def test_collection_delete_if_match_not_included_if_not_safe(self): data = {} mock_response(self.session, data=data) deleted = self.client.delete_collection( 'mycollection', if_match=1324, safe=False) assert deleted == data url = '/buckets/mybucket/collections/mycollection' self.session.request.assert_called_with('delete', url, headers=None) 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_collection( bucket="buck", collection="coll", 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_collection( bucket="buck", collection="coll", if_not_exists=True) def test_create_collection_raises_a_special_error_on_403(self): self.session.request.side_effect = get_http_error(status=403) with self.assertRaises(KintoException) as e: self.client.create_collection( bucket="buck", collection="coll") expected_msg = ("Unauthorized. Please check that the bucket exists " "and that you have the permission to create or write " "on this collection.") assert e.exception.message == expected_msg
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 = kinto_core_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_bucket_deletion_if_exists(self): self.client.create_bucket('mozilla') self.client.delete_bucket('mozilla') self.client.delete_bucket('mozilla', if_exists=True) 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_buckets_deletion_when_no_buckets_exist(self): deleted_buckets = self.client.delete_buckets() assert len(deleted_buckets) == 0 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_group_creation(self): self.client.create_bucket('mozilla') self.client.create_group( 'payments', bucket='mozilla', data={'members': ['blah', ]}, permissions={'write': ['blah', ]}) # Test retrieval of a group gets the permissions as well. group = self.client.get_group('payments', bucket='mozilla') assert 'blah' in group['permissions']['write'] def test_group_creation_if_not_exists(self): self.client.create_bucket('mozilla') self.client.create_group('payments', bucket='mozilla', data={'members': ['blah', ]}) self.client.create_group( 'payments', bucket='mozilla', data={'members': ['blah', ]}, permissions={'write': ['blah', ]}, if_not_exists=True) def test_group_creation_if_bucket_does_not_exist(self): with pytest.raises(KintoException): self.client.create_group( 'payments', bucket='mozilla', data={'members': ['blah', ]}) self.client.create_group( 'payments', bucket='mozilla', data={'members': ['blah', ]}, if_not_exists=True) def test_group_update(self): self.client.create_bucket('mozilla') group = self.client.create_group( 'payments', bucket='mozilla', data={'members': ['blah', ]}, if_not_exists=True) assert group['data']['members'][0] == 'blah' group = self.client.update_group( data={'members': ['blah', 'foo']}, group='payments', bucket='mozilla') self.assertEquals(group['data']['members'][1], 'foo') def test_group_list(self): self.client.create_bucket('mozilla') self.client.create_group('receipts', bucket='mozilla', data={'members': ['blah', ]}) self.client.create_group('assets', bucket='mozilla', data={'members': ['blah', ]}) # The returned groups should be strings. groups = self.client.get_groups('mozilla') self.assertEquals(2, len(groups)) self.assertEquals(set([coll['id'] for coll in groups]), set(['receipts', 'assets'])) def test_group_deletion(self): self.client.create_bucket('mozilla') self.client.create_group('payments', bucket='mozilla', data={'members': ['blah', ]}) self.client.delete_group('payments', bucket='mozilla') assert len(self.client.get_groups(bucket='mozilla')) == 0 def test_group_deletion_if_exists(self): self.client.create_bucket('mozilla') self.client.create_group('payments', bucket='mozilla', data={'members': ['blah', ]}) self.client.delete_group('payments', bucket='mozilla') self.client.delete_group('payments', bucket='mozilla', if_exists=True) def test_group_deletion_can_still_raise_errors(self): error = KintoException("An error occured") with mock.patch.object(self.client.session, 'request', side_effect=error): with pytest.raises(KintoException): self.client.delete_group('payments', bucket='mozilla', if_exists=True) def test_groups_deletion(self): self.client.create_bucket('mozilla') self.client.create_group('amo', bucket='mozilla', data={'members': ['blah', ]}) self.client.create_group('blocklist', bucket='mozilla', data={'members': ['blah', ]}) self.client.delete_groups(bucket='mozilla') assert len(self.client.get_groups(bucket='mozilla')) == 0 def test_groups_deletion_when_no_groups_exist(self): self.client.create_bucket('mozilla') deleted_groups = self.client.delete_groups(bucket='mozilla') assert len(deleted_groups) == 0 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_collection_deletion_if_exists(self): self.client.create_bucket('mozilla') self.client.create_collection('payments', bucket='mozilla') self.client.delete_collection('payments', bucket='mozilla') self.client.delete_collection('payments', bucket='mozilla', if_exists=True) def test_collection_deletion_can_still_raise_errors(self): error = KintoException("An error occured") with mock.patch.object(self.client.session, 'request', side_effect=error): with pytest.raises(KintoException): self.client.delete_collection('payments', bucket='mozilla', if_exists=True) 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_collections_deletion_when_no_collections_exist(self): self.client.create_bucket('mozilla') deleted_collections = self.client.delete_collections(bucket='mozilla') assert len(deleted_collections) == 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_record_deletion_if_exists(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']) deleted_if_exists = client.delete_record(record['data']['id'], if_exists=True) assert deleted['deleted'] is True assert deleted_if_exists is None 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_deletion_when_no_records_exist(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() deleted_records = client.delete_records() assert len(deleted_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_group(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla') client.create_bucket() client.create_group('payments', data={'members': []}) client.patch_group('payments', data={'secret': 'psssssst!'}) group = client.get_group('payments') assert group['data']['secret'] == 'psssssst!' 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
import re from config import kinto_url, kinto_admin, kinto_password from utils import accident_is_valid from uuid import uuid5, NAMESPACE_URL from kinto_http import Client client = Client(server_url=kinto_url, auth=(kinto_admin, kinto_password), retry=10) raw_accident_schema = client.get_collection(bucket='accidents', id='accidents_raw') # use only the first type of the schema, we're having some fields with for # example type: ["string", null] in there raw_accident_schema = { key: { **value, **{ 'type': value['type'][0] if value['type'][0] else value['type'] } } for (key, value) in ( raw_accident_schema['data']['schema']['properties'].items()) } for key, value in raw_accident_schema.items(): if value.get('pattern') is not None: value['pattern'] = re.compile(value['pattern'])
def main(): args = _get_args() client = Client(server_url=args.server, auth=tuple(args.auth.split(':')), bucket=args.source_bucket, collection=args.source_col) if args.editor_auth is None: args.editor_auth = args.auth if args.reviewer_auth is None: args.reviewer_auth = args.auth editor_client = Client(server_url=args.server, auth=tuple(args.editor_auth.split(':')), bucket=args.source_bucket, collection=args.source_col) reviewer_client = Client(server_url=args.server, auth=tuple(args.reviewer_auth.split(':')), bucket=args.source_bucket, collection=args.source_col) # 0. initialize source bucket/collection (if necessary) server_info = client.server_info() editor_id = editor_client.server_info()['user']['id'] reviewer_id = reviewer_client.server_info()['user']['id'] print('Server: {0}'.format(args.server)) print('Author: {user[id]}'.format(**server_info)) print('Editor: {0}'.format(editor_id)) print('Reviewer: {0}'.format(reviewer_id)) # 0. check that this collection is well configured. signer_capabilities = server_info['capabilities']['signer'] to_review_enabled = signer_capabilities.get('to_review_enabled', False) group_check_enabled = signer_capabilities.get('group_check_enabled', False) resources = [ r for r in signer_capabilities['resources'] if (args.source_bucket, args.source_col) == (r['source']['bucket'], r['source']['collection']) ] assert len(resources) > 0, 'Specified source not configured to be signed' resource = resources[0] if to_review_enabled and 'preview' in resource: print( 'Signoff: {source[bucket]}/{source[collection]} => {preview[bucket]}/{preview[collection]} => {destination[bucket]}/{destination[collection]}' .format(**resource)) else: print( 'Signoff: {source[bucket]}/{source[collection]} => {destination[bucket]}/{destination[collection]}' .format(**resource)) print('Group check: {0}'.format(group_check_enabled)) print('Review workflow: {0}'.format(to_review_enabled)) print('_' * 80) bucket = client.create_bucket(if_not_exists=True) client.patch_bucket(permissions={ 'write': [editor_id, reviewer_id] + bucket['permissions']['write'] }, if_match=bucket['data']['last_modified'], safe=True) client.create_collection(if_not_exists=True) if args.reset: client.delete_records() existing = 0 else: existing_records = client.get_records() existing = len(existing_records) if group_check_enabled: editors_group = signer_capabilities['editors_group'] client.create_group(editors_group, data={'members': [editor_id]}, if_not_exists=True) reviewers_group = signer_capabilities['reviewers_group'] client.create_group(reviewers_group, data={'members': [reviewer_id]}, if_not_exists=True) dest_client = Client(server_url=args.server, bucket=resource['destination']['bucket'], collection=resource['destination']['collection']) preview_client = None if to_review_enabled and 'preview' in resource: preview_bucket = resource['preview']['bucket'] preview_collection = resource['preview']['collection'] preview_client = Client(server_url=args.server, bucket=preview_bucket, collection=preview_collection) # 1. upload data print('Author uploads 20 random records') records = upload_records(client, 20) # 2. ask for a signature # 2.1 ask for review (noop on old versions) print('Editor asks for review') data = {"status": "to-review"} editor_client.patch_collection(data=data) # 2.2 check the preview collection (if enabled) if preview_client: print('Check preview collection') preview_records = preview_client.get_records() expected = existing + 20 assert len(preview_records) == expected, '%s != %s records' % ( len(preview_records), expected) metadata = preview_client.get_collection()['data'] preview_signature = metadata.get('signature') assert preview_signature, 'Preview collection not signed' preview_timestamp = collection_timestamp(preview_client) # 2.3 approve the review print('Reviewer approves and triggers signature') data = {"status": "to-sign"} reviewer_client.patch_collection(data=data) # 3. upload more data print('Author creates 20 others records') upload_records(client, 20) print('Editor updates 5 random records') for toupdate in random.sample(records, 5): editor_client.patch_record(dict(newkey=_rand(10), **toupdate)) print('Author deletes 5 random records') for todelete in random.sample(records, 5): client.delete_record(todelete['id']) expected = existing + 20 + 20 - 5 # 4. ask again for a signature # 2.1 ask for review (noop on old versions) print('Editor asks for review') data = {"status": "to-review"} editor_client.patch_collection(data=data) # 2.2 check the preview collection (if enabled) if preview_client: print('Check preview collection') preview_records = preview_client.get_records() assert len(preview_records) == expected, '%s != %s records' % ( len(preview_records), expected) # Diff size is 20 + 5 if updated records are also all deleted, # or 30 if deletions and updates apply to different records. diff_since_last = preview_client.get_records(_since=preview_timestamp) assert 25 <= len( diff_since_last ) <= 30, 'Changes since last signature are not consistent' metadata = preview_client.get_collection()['data'] assert preview_signature != metadata[ 'signature'], 'Preview collection not updated' # 2.3 approve the review print('Reviewer approves and triggers signature') data = {"status": "to-sign"} reviewer_client.patch_collection(data=data) # 5. wait for the result # 6. obtain the destination records and serialize canonically. records = list(dest_client.get_records()) assert len(records) == expected, '%s != %s records' % (len(records), expected) timestamp = collection_timestamp(dest_client) serialized = canonical_json(records, timestamp) print('Hash is %r' % compute_hash(serialized)) # 7. get back the signed hash dest_col = dest_client.get_collection() signature = dest_col['data']['signature'] with open('pub', 'w') as f: f.write(signature['public_key']) # 8. verify the signature matches the hash signer = ECDSASigner(public_key='pub') try: signer.verify(serialized, signature) print('Signature OK') except Exception: print('Signature KO') raise
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 = kinto_core_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_bucket_deletion_if_exists(self): self.client.create_bucket('mozilla') self.client.delete_bucket('mozilla') self.client.delete_bucket('mozilla', if_exists=True) 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_buckets_deletion_when_no_buckets_exist(self): deleted_buckets = self.client.delete_buckets() assert len(deleted_buckets) == 0 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_group_creation(self): self.client.create_bucket('mozilla') self.client.create_group('payments', bucket='mozilla', data={'members': [ 'blah', ]}, permissions={'write': [ 'blah', ]}) # Test retrieval of a group gets the permissions as well. group = self.client.get_group('payments', bucket='mozilla') assert 'blah' in group['permissions']['write'] def test_group_creation_if_not_exists(self): self.client.create_bucket('mozilla') self.client.create_group('payments', bucket='mozilla', data={'members': [ 'blah', ]}) self.client.create_group('payments', bucket='mozilla', data={'members': [ 'blah', ]}, permissions={'write': [ 'blah', ]}, if_not_exists=True) def test_group_creation_if_bucket_does_not_exist(self): with pytest.raises(KintoException): self.client.create_group('payments', bucket='mozilla', data={'members': [ 'blah', ]}) self.client.create_group('payments', bucket='mozilla', data={'members': [ 'blah', ]}, if_not_exists=True) def test_group_update(self): self.client.create_bucket('mozilla') group = self.client.create_group('payments', bucket='mozilla', data={'members': [ 'blah', ]}, if_not_exists=True) assert group['data']['members'][0] == 'blah' group = self.client.update_group(data={'members': ['blah', 'foo']}, group='payments', bucket='mozilla') self.assertEquals(group['data']['members'][1], 'foo') def test_group_list(self): self.client.create_bucket('mozilla') self.client.create_group('receipts', bucket='mozilla', data={'members': [ 'blah', ]}) self.client.create_group('assets', bucket='mozilla', data={'members': [ 'blah', ]}) # The returned groups should be strings. groups = self.client.get_groups('mozilla') self.assertEquals(2, len(groups)) self.assertEquals(set([coll['id'] for coll in groups]), set(['receipts', 'assets'])) def test_group_deletion(self): self.client.create_bucket('mozilla') self.client.create_group('payments', bucket='mozilla', data={'members': [ 'blah', ]}) self.client.delete_group('payments', bucket='mozilla') assert len(self.client.get_groups(bucket='mozilla')) == 0 def test_group_deletion_if_exists(self): self.client.create_bucket('mozilla') self.client.create_group('payments', bucket='mozilla', data={'members': [ 'blah', ]}) self.client.delete_group('payments', bucket='mozilla') self.client.delete_group('payments', bucket='mozilla', if_exists=True) def test_group_deletion_can_still_raise_errors(self): error = KintoException("An error occured") with mock.patch.object(self.client.session, 'request', side_effect=error): with pytest.raises(KintoException): self.client.delete_group('payments', bucket='mozilla', if_exists=True) def test_groups_deletion(self): self.client.create_bucket('mozilla') self.client.create_group('amo', bucket='mozilla', data={'members': [ 'blah', ]}) self.client.create_group('blocklist', bucket='mozilla', data={'members': [ 'blah', ]}) self.client.delete_groups(bucket='mozilla') assert len(self.client.get_groups(bucket='mozilla')) == 0 def test_groups_deletion_when_no_groups_exist(self): self.client.create_bucket('mozilla') deleted_groups = self.client.delete_groups(bucket='mozilla') assert len(deleted_groups) == 0 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_collection_deletion_if_exists(self): self.client.create_bucket('mozilla') self.client.create_collection('payments', bucket='mozilla') self.client.delete_collection('payments', bucket='mozilla') self.client.delete_collection('payments', bucket='mozilla', if_exists=True) def test_collection_deletion_can_still_raise_errors(self): error = KintoException("An error occured") with mock.patch.object(self.client.session, 'request', side_effect=error): with pytest.raises(KintoException): self.client.delete_collection('payments', bucket='mozilla', if_exists=True) 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_collections_deletion_when_no_collections_exist(self): self.client.create_bucket('mozilla') deleted_collections = self.client.delete_collections(bucket='mozilla') assert len(deleted_collections) == 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_record_deletion_if_exists(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']) deleted_if_exists = client.delete_record(record['data']['id'], if_exists=True) assert deleted['deleted'] is True assert deleted_if_exists is None 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_deletion_when_no_records_exist(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla', collection='payments') client.create_bucket() client.create_collection() deleted_records = client.delete_records() assert len(deleted_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_group(self): client = Client(server_url=self.server_url, auth=self.auth, bucket='mozilla') client.create_bucket() client.create_group('payments', data={'members': []}) client.patch_group('payments', data={'secret': 'psssssst!'}) group = client.get_group('payments') assert group['data']['secret'] == 'psssssst!' 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 CollectionTest(unittest.TestCase): def setUp(self): self.session = mock.MagicMock() mock_response(self.session) self.client = Client(session=self.session, bucket='mybucket') def test_collection_names_are_slugified(self): self.client.get_collection(id='my collection') url = '/buckets/mybucket/collections/my-collection' self.session.request.assert_called_with('get', url) def test_collection_creation_issues_an_http_put(self): self.client.create_collection(id='mycollection', permissions=mock.sentinel.permissions) url = '/buckets/mybucket/collections/mycollection' self.session.request.assert_called_with( 'put', url, data=None, permissions=mock.sentinel.permissions, headers=DO_NOT_OVERWRITE) def test_data_can_be_sent_on_creation(self): self.client.create_collection(id='mycollection', bucket='testbucket', data={'foo': 'bar'}) self.session.request.assert_called_with( 'put', '/buckets/testbucket/collections/mycollection', data={'foo': 'bar'}, permissions=None, headers=DO_NOT_OVERWRITE) def test_collection_update_issues_an_http_put(self): self.client.update_collection(id='mycollection', data={'foo': 'bar'}, permissions=mock.sentinel.permissions) url = '/buckets/mybucket/collections/mycollection' self.session.request.assert_called_with( 'put', url, data={'foo': 'bar'}, permissions=mock.sentinel.permissions, headers=None) def test_update_handles_if_match(self): self.client.update_collection(id='mycollection', data={'foo': 'bar'}, if_match=1234) url = '/buckets/mybucket/collections/mycollection' headers = {'If-Match': '"1234"'} self.session.request.assert_called_with( 'put', url, data={'foo': 'bar'}, headers=headers, permissions=None) def test_collection_update_use_an_if_match_header(self): data = {'foo': 'bar', 'last_modified': '1234'} self.client.update_collection(id='mycollection', data=data, permissions=mock.sentinel.permissions) url = '/buckets/mybucket/collections/mycollection' self.session.request.assert_called_with( 'put', url, data={'foo': 'bar', 'last_modified': '1234'}, permissions=mock.sentinel.permissions, headers={'If-Match': '"1234"'}) def test_patch_collection_issues_an_http_patch(self): self.client.patch_collection(id='mycollection', data={'key': 'secret'}) url = '/buckets/mybucket/collections/mycollection' self.session.request.assert_called_with( 'patch', url, payload={'data': {'key': 'secret'}}, headers={'Content-Type': 'application/json'}, ) def test_patch_collection_handles_if_match(self): self.client.patch_collection(id='mycollection', data={'key': 'secret'}, if_match=1234) url = '/buckets/mybucket/collections/mycollection' headers = {'If-Match': '"1234"', 'Content-Type': 'application/json'} self.session.request.assert_called_with( 'patch', url, payload={'data': {'key': 'secret'}}, headers=headers, ) def test_patch_requires_patch_to_be_patch_type(self): with pytest.raises(TypeError): self.client.patch_collection(id='testcoll', bucket='testbucket', changes=5) def test_get_collections_returns_the_list_of_collections(self): mock_response( self.session, data=[ {'id': 'foo', 'last_modified': '12345'}, {'id': 'bar', 'last_modified': '59874'}, ]) collections = self.client.get_collections(bucket='default') assert list(collections) == [ {'id': 'foo', 'last_modified': '12345'}, {'id': 'bar', 'last_modified': '59874'}, ] def test_collection_can_delete_all_its_records(self): self.client.delete_records(bucket='abucket', collection='acollection') url = '/buckets/abucket/collections/acollection/records' self.session.request.assert_called_with('delete', url, headers=None) def test_delete_is_issued_on_list_deletion(self): self.client.delete_collections(bucket='mybucket') url = '/buckets/mybucket/collections' self.session.request.assert_called_with('delete', url, headers=None) def test_collection_can_be_deleted(self): data = {} mock_response(self.session, data=data) deleted = self.client.delete_collection(id='mycollection') assert deleted == data url = '/buckets/mybucket/collections/mycollection' self.session.request.assert_called_with('delete', url, headers=None) def test_collection_delete_if_match(self): data = {} mock_response(self.session, data=data) deleted = self.client.delete_collection(id='mycollection', if_match=1234) assert deleted == data url = '/buckets/mybucket/collections/mycollection' self.session.request.assert_called_with( 'delete', url, headers={'If-Match': '"1234"'}) def test_collection_delete_if_match_not_included_if_not_safe(self): data = {} mock_response(self.session, data=data) deleted = self.client.delete_collection(id='mycollection', if_match=1324, safe=False) assert deleted == data url = '/buckets/mybucket/collections/mycollection' self.session.request.assert_called_with('delete', url, headers=None) 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_collection(bucket="buck", id="coll", 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_collection(bucket="buck", id="coll", if_not_exists=True) def test_create_collection_raises_a_special_error_on_403(self): self.session.request.side_effect = get_http_error(status=403) with self.assertRaises(KintoException) as e: self.client.create_collection(bucket="buck", id="coll") expected_msg = ("Unauthorized. Please check that the bucket exists " "and that you have the permission to create or write " "on this collection.") assert e.exception.message == expected_msg def test_create_collection_can_deduce_id_from_data(self): self.client.create_collection(data={'id': 'coll'}, bucket='buck') self.session.request.assert_called_with( 'put', '/buckets/buck/collections/coll', data={'id': 'coll'}, permissions=None, headers=DO_NOT_OVERWRITE) def test_update_collection_can_deduce_id_from_data(self): self.client.update_collection(data={'id': 'coll'}, bucket='buck') self.session.request.assert_called_with( 'put', '/buckets/buck/collections/coll', data={'id': 'coll'}, permissions=None, headers=None)
def main(): args = _get_args() client = Client(server_url=args.server, auth=tuple(args.auth.split(':')), bucket=args.source_bucket, collection=args.source_col) if args.editor_auth is None: args.editor_auth = args.auth if args.reviewer_auth is None: args.reviewer_auth = args.auth editor_client = Client(server_url=args.server, auth=tuple(args.editor_auth.split(':')), bucket=args.source_bucket, collection=args.source_col) reviewer_client = Client(server_url=args.server, auth=tuple(args.reviewer_auth.split(':')), bucket=args.source_bucket, collection=args.source_col) # 0. initialize source bucket/collection (if necessary) server_info = client.server_info() editor_id = editor_client.server_info()['user']['id'] reviewer_id = reviewer_client.server_info()['user']['id'] print('Server: {0}'.format(args.server)) print('Author: {user[id]}'.format(**server_info)) print('Editor: {0}'.format(editor_id)) print('Reviewer: {0}'.format(reviewer_id)) # 0. check that this collection is well configured. signer_capabilities = server_info['capabilities']['signer'] resources = [r for r in signer_capabilities['resources'] if (args.source_bucket, args.source_col) == (r['source']['bucket'], r['source']['collection']) or (args.source_bucket, None) == (r['source']['bucket'], r['source']['collection'])] assert len(resources) > 0, 'Specified source not configured to be signed' resource = resources[0] if 'preview' in resource: print('Signoff: {source[bucket]}/{source[collection]} => {preview[bucket]}/{preview[collection]} => {destination[bucket]}/{destination[collection]}'.format(**resource)) else: print('Signoff: {source[bucket]}/{source[collection]} => {destination[bucket]}/{destination[collection]}'.format(**resource)) print('_' * 80) bucket = client.create_bucket(if_not_exists=True) client.create_collection(permissions={'write': [editor_id, reviewer_id] + bucket['permissions']['write']}, if_not_exists=True) editors_group = resource.get('editors_group') or signer_capabilities['editors_group'] editors_group = editors_group.format(collection_id=args.source_col) client.patch_group(id=editors_group, data={'members': [editor_id]}) reviewers_group = resource.get('reviewers_group') or signer_capabilities['reviewers_group'] reviewers_group = reviewers_group.format(collection_id=args.source_col) client.patch_group(id=reviewers_group, data={'members': [reviewer_id]}) if args.reset: client.delete_records() existing = 0 else: existing_records = client.get_records() existing = len(existing_records) dest_col = resource['destination'].get('collection') or args.source_col dest_client = Client(server_url=args.server, bucket=resource['destination']['bucket'], collection=dest_col) preview_client = None if 'preview' in resource: preview_bucket = resource['preview']['bucket'] preview_collection = resource['preview'].get('collection') or args.source_col preview_client = Client(server_url=args.server, bucket=preview_bucket, collection=preview_collection) # 1. upload data print('Author uploads 20 random records') records = upload_records(client, 20) # 2. ask for a signature # 2.1 ask for review (noop on old versions) print('Editor asks for review') data = {"status": "to-review"} editor_client.patch_collection(data=data) # 2.2 check the preview collection (if enabled) if preview_client: print('Check preview collection') preview_records = preview_client.get_records() expected = existing + 20 assert len(preview_records) == expected, '%s != %s records' % (len(preview_records), expected) metadata = preview_client.get_collection()['data'] preview_signature = metadata.get('signature') assert preview_signature, 'Preview collection not signed' preview_timestamp = preview_client.get_records_timestamp() # 2.3 approve the review print('Reviewer approves and triggers signature') data = {"status": "to-sign"} reviewer_client.patch_collection(data=data) # 3. upload more data print('Author creates 20 others records') upload_records(client, 20) print('Editor updates 5 random records') for toupdate in random.sample(records, 5): editor_client.patch_record(data=dict(newkey=_rand(10), **toupdate)) print('Author deletes 5 random records') for todelete in random.sample(records, 5): client.delete_record(id=todelete['id']) expected = existing + 20 + 20 - 5 # 4. ask again for a signature # 2.1 ask for review (noop on old versions) print('Editor asks for review') data = {"status": "to-review"} editor_client.patch_collection(data=data) # 2.2 check the preview collection (if enabled) if preview_client: print('Check preview collection') preview_records = preview_client.get_records() assert len(preview_records) == expected, '%s != %s records' % (len(preview_records), expected) # Diff size is 20 + 5 if updated records are also all deleted, # or 30 if deletions and updates apply to different records. diff_since_last = preview_client.get_records(_since=preview_timestamp) assert 25 <= len(diff_since_last) <= 30, 'Changes since last signature are not consistent' metadata = preview_client.get_collection()['data'] assert preview_signature != metadata['signature'], 'Preview collection not updated' # 2.3 approve the review print('Reviewer approves and triggers signature') data = {"status": "to-sign"} reviewer_client.patch_collection(data=data) # 5. wait for the result # 6. obtain the destination records and serialize canonically. records = list(dest_client.get_records()) assert len(records) == expected, '%s != %s records' % (len(records), expected) timestamp = dest_client.get_records_timestamp() serialized = canonical_json(records, timestamp) print('Hash is %r' % compute_hash(serialized)) # 7. get back the signed hash signature = dest_client.get_collection()['data']['signature'] with open('pub', 'w') as f: f.write(signature['public_key']) # 8. verify the signature matches the hash signer = ECDSASigner(public_key='pub') try: signer.verify(serialized, signature) print('Signature OK') except Exception: print('Signature KO') raise