def test_batch_does_not_raise_exception_if_batch_4xx_errors_are_ignored(self): error = { "errno": 121, "message": "Forbidden", "code": 403, "error": "This user cannot access this resource." } self.session.request.side_effect = [ ({"settings": {"batch_max_requests": 25}}, []), ({"responses": [ {"status": 200, "path": "/url1", "body": {}, "headers": {}}, {"status": 403, "path": "/url2", "body": error, "headers": {}} ]}, [])] client = Client(session=self.session, ignore_batch_4xx=True) with client.batch(bucket='moz', collection='test') as batch: # Do not raise batch.create_record(id=1234, data={'foo': 'bar'}) batch.create_record(id=5678, data={'tutu': 'toto'})
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 ClientTest(unittest.TestCase): def setUp(self): self.session = mock.MagicMock() self.client = Client(session=self.session) mock_response(self.session) def test_server_info(self): self.client.server_info() self.session.request.assert_called_with('get', '/') def test_context_manager_works_as_expected(self): settings = {"batch_max_requests": 25} self.session.request.side_effect = [({"settings": settings}, []), ({"responses": []}, [])] with self.client.batch(bucket='mozilla', collection='test') as batch: batch.create_record(id=1234, data={'foo': 'bar'}) batch.create_record(id=5678, data={'bar': 'baz'}) self.session.request.assert_called_with( method='POST', endpoint='/batch', payload={'requests': [ {'body': {'data': {'foo': 'bar'}}, 'path': '/buckets/mozilla/collections/test/records/1234', 'method': 'PUT', 'headers': {'If-None-Match': '*'}}, {'body': {'data': {'bar': 'baz'}}, 'path': '/buckets/mozilla/collections/test/records/5678', 'method': 'PUT', 'headers': {'If-None-Match': '*'}}]}) def test_batch_raises_exception(self): # Make the next call to sess.request raise a 403. exception = KintoException() exception.response = mock.MagicMock() exception.response.status_code = 403 exception.request = mock.sentinel.request self.session.request.side_effect = exception with self.assertRaises(KintoException): with self.client.batch(bucket='moz', collection='test') as batch: batch.create_record(id=1234, data={'foo': 'bar'}) def test_batch_raises_exception_if_subrequest_failed(self): error = { "errno": 121, "message": "This user cannot access this resource.", "code": 403, "error": "Forbidden" } self.session.request.side_effect = [ ({"settings": {"batch_max_requests": 25}}, []), ({"responses": [ {"status": 200, "path": "/url1", "body": {}, "headers": {}}, {"status": 404, "path": "/url2", "body": error, "headers": {}} ]}, [])] with self.assertRaises(KintoException): with self.client.batch(bucket='moz', collection='test') as batch: batch.create_record(id=1234, data={'foo': 'bar'}) batch.create_record(id=5678, data={'tutu': 'toto'}) def test_batch_options_are_transmitted(self): settings = {"batch_max_requests": 25} self.session.request.side_effect = [({"settings": settings}, [])] with mock.patch('kinto_http.create_session') as create_session: with self.client.batch(bucket='moz', collection='test', retry=12, retry_after=20): _, last_call_kwargs = create_session.call_args_list[-1] self.assertEqual(last_call_kwargs['retry'], 12) self.assertEqual(last_call_kwargs['retry_after'], 20) def test_client_is_represented_properly(self): client = Client( server_url="https://kinto.notmyidea.org/v1", bucket="homebrewing", collection="recipes" ) expected_repr = ("<KintoClient https://kinto.notmyidea.org/v1/" "buckets/homebrewing/collections/recipes>") assert str(client) == expected_repr def test_client_uses_default_bucket_if_not_specified(self): mock_response(self.session) client = Client(session=self.session) client.get_bucket() self.session.request.assert_called_with('get', '/buckets/default') def test_client_uses_passed_bucket_if_specified(self): client = Client( server_url="https://kinto.notmyidea.org/v1", bucket="buck") assert client._bucket_name == "buck" def test_client_clone_with_auth(self): client_clone = self.client.clone(auth=("reviewer", "")) assert client_clone.session.auth == ("reviewer", "") assert self.client.session != client_clone.session assert self.client.session.server_url == client_clone.session.server_url assert self.client.session.auth != client_clone.session.auth assert self.client.session.nb_retry == client_clone.session.nb_retry assert self.client.session.retry_after == client_clone.session.retry_after assert self.client._bucket_name == client_clone._bucket_name assert self.client._collection_name == client_clone._collection_name def test_client_clone_with_server_url(self): client_clone = self.client.clone(server_url="https://kinto.notmyidea.org/v1") assert client_clone.session.server_url == "https://kinto.notmyidea.org/v1" assert self.client.session != client_clone.session assert self.client.session.server_url != client_clone.session.server_url assert self.client.session.auth == client_clone.session.auth assert self.client.session.nb_retry == client_clone.session.nb_retry assert self.client.session.retry_after == client_clone.session.retry_after assert self.client._bucket_name == client_clone._bucket_name assert self.client._collection_name == client_clone._collection_name def test_client_clone_with_new_session(self): session = create_session(auth=("reviewer", ""), server_url="https://kinto.notmyidea.org/v1") client_clone = self.client.clone(session=session) assert client_clone.session == session assert self.client.session != client_clone.session assert self.client.session.server_url != client_clone.session.server_url assert self.client.session.auth != client_clone.session.auth assert self.client._bucket_name == client_clone._bucket_name assert self.client._collection_name == client_clone._collection_name def test_client_clone_with_auth_and_server_url(self): client_clone = self.client.clone(auth=("reviewer", ""), server_url="https://kinto.notmyidea.org/v1") assert client_clone.session.auth == ("reviewer", "") assert client_clone.session.server_url == "https://kinto.notmyidea.org/v1" assert self.client.session != client_clone.session assert self.client.session.server_url != client_clone.session.server_url assert self.client.session.auth != client_clone.session.auth assert self.client.session.nb_retry == client_clone.session.nb_retry assert self.client.session.retry_after == client_clone.session.retry_after assert self.client._bucket_name == client_clone._bucket_name assert self.client._collection_name == client_clone._collection_name def test_client_clone_with_existing_session(self): client_clone = self.client.clone(session=self.client.session) assert self.client.session == client_clone.session assert self.client.session.server_url == client_clone.session.server_url assert self.client.session.auth == client_clone.session.auth assert self.client._bucket_name == client_clone._bucket_name assert self.client._collection_name == client_clone._collection_name def test_client_clone_with_new_bucket_and_collection(self): client_clone = self.client.clone(bucket="bucket_blah", collection="coll_blah") assert self.client.session == client_clone.session assert self.client.session.server_url == client_clone.session.server_url assert self.client.session.auth == client_clone.session.auth assert self.client.session.nb_retry == client_clone.session.nb_retry assert self.client.session.retry_after == client_clone.session.retry_after assert self.client._bucket_name != client_clone._bucket_name assert self.client._collection_name != client_clone._collection_name assert client_clone._bucket_name == "bucket_blah" assert client_clone._collection_name == "coll_blah" def test_client_clone_with_auth_and_server_url_bucket_and_collection(self): client_clone = self.client.clone(auth=("reviewer", ""), server_url="https://kinto.notmyidea.org/v1", bucket="bucket_blah", collection="coll_blah") assert self.client.session != client_clone.session assert self.client.session.server_url != client_clone.session.server_url assert self.client.session.auth != client_clone.session.auth assert self.client._bucket_name != client_clone._bucket_name assert self.client._collection_name != client_clone._collection_name assert client_clone.session.auth == ("reviewer", "") assert client_clone.session.server_url == "https://kinto.notmyidea.org/v1" assert client_clone._bucket_name == "bucket_blah" assert client_clone._collection_name == "coll_blah"
class ClientTest(unittest.TestCase): def setUp(self): self.session = mock.MagicMock() self.client = Client(session=self.session) mock_response(self.session) def test_server_info(self): self.client.server_info() self.session.request.assert_called_with('get', '/') def test_context_manager_works_as_expected(self): settings = {"batch_max_requests": 25} self.session.request.side_effect = [({"settings": settings}, []), ({"responses": []}, [])] with self.client.batch(bucket='mozilla', collection='test') as batch: batch.create_record(id=1234, data={'foo': 'bar'}) batch.create_record(id=5678, data={'bar': 'baz'}) batch.patch_record(id=5678, data={'bar': 'biz'}) changes = JSONPatch([{'op': 'add', 'location': 'foo', 'value': 'bar'}]) batch.patch_record(id=5678, changes=changes) self.session.request.assert_called_with( method='POST', endpoint='/batch', payload={'requests': [ {'body': {'data': {'foo': 'bar'}}, 'path': '/buckets/mozilla/collections/test/records/1234', 'method': 'PUT', 'headers': {'If-None-Match': '*'}}, {'body': {'data': {'bar': 'baz'}}, 'path': '/buckets/mozilla/collections/test/records/5678', 'method': 'PUT', 'headers': {'If-None-Match': '*'}}, {'body': {'data': {'bar': 'biz'}}, 'path': '/buckets/mozilla/collections/test/records/5678', 'method': 'PATCH', 'headers': {'Content-Type': 'application/json'}}, {'body': [{'op': 'add', 'location': 'foo', 'value': 'bar'}], 'path': '/buckets/mozilla/collections/test/records/5678', 'method': 'PATCH', 'headers': {'Content-Type': 'application/json-patch+json'}}]}) def test_batch_raises_exception(self): # Make the next call to sess.request raise a 403. exception = KintoException() exception.response = mock.MagicMock() exception.response.status_code = 403 exception.request = mock.sentinel.request self.session.request.side_effect = exception with self.assertRaises(KintoException): with self.client.batch(bucket='moz', collection='test') as batch: batch.create_record(id=1234, data={'foo': 'bar'}) def test_batch_raises_exception_if_subrequest_failed_with_code_5xx(self): error = { "errno": 121, "message": "This user cannot access this resource.", "code": 500, "error": "Server Internal Error" } self.session.request.side_effect = [ ({"settings": {"batch_max_requests": 25}}, []), ({"responses": [ {"status": 200, "path": "/url1", "body": {}, "headers": {}}, {"status": 500, "path": "/url2", "body": error, "headers": {}} ]}, [])] with self.assertRaises(KintoException): with self.client.batch(bucket='moz', collection='test') as batch: batch.create_record(id=1234, data={'foo': 'bar'}) batch.create_record(id=5678, data={'tutu': 'toto'}) def test_batch_raises_exception_if_subrequest_failed_with_code_4xx(self): error_403 = { "errno": 121, "message": "Forbidden", "code": 403, "error": "This user cannot access this resource." } error_400 = { "code": 400, "errno": 104, "error": "Invalid parameters", "message": "Bad Request", } self.session.request.side_effect = [ ({"settings": {"batch_max_requests": 25}}, []), ({"responses": [ {"status": 200, "path": "/url1", "body": {}, "headers": {}}, {"status": 403, "path": "/url2", "body": error_403, "headers": {}}, {"status": 200, "path": "/url1", "body": {}, "headers": {}}, {"status": 400, "path": "/url2", "body": error_400, "headers": {}}, ]}, [])] with self.assertRaises(KintoBatchException) as cm: with self.client.batch(bucket='moz', collection='test') as batch: batch.create_record(id=1234, data={'foo': 'bar'}) batch.create_record(id=1987, data={'maz': 'miz'}) batch.create_record(id=1982, data={'plop': 'plip'}) batch.create_record(id=5678, data={'tutu': 'toto'}) raised = cm.exception assert "403" in str(raised) assert "400" in str(raised) assert isinstance(raised.exceptions[0], KintoException) assert raised.exceptions[0].response.status_code == 403 assert raised.exceptions[1].response.status_code == 400 resp, headers = raised.results[0] assert len(resp["responses"]) == 4 assert resp["responses"][0]["status"] == 200 def test_batch_does_not_raise_exception_if_batch_4xx_errors_are_ignored(self): error = { "errno": 121, "message": "Forbidden", "code": 403, "error": "This user cannot access this resource." } self.session.request.side_effect = [ ({"settings": {"batch_max_requests": 25}}, []), ({"responses": [ {"status": 200, "path": "/url1", "body": {}, "headers": {}}, {"status": 403, "path": "/url2", "body": error, "headers": {}} ]}, [])] client = Client(session=self.session, ignore_batch_4xx=True) with client.batch(bucket='moz', collection='test') as batch: # Do not raise batch.create_record(id=1234, data={'foo': 'bar'}) batch.create_record(id=5678, data={'tutu': 'toto'}) def test_batch_options_are_transmitted(self): settings = {"batch_max_requests": 25} self.session.request.side_effect = [({"settings": settings}, [])] with mock.patch('kinto_http.create_session') as create_session: with self.client.batch(bucket='moz', collection='test', retry=12, retry_after=20): _, last_call_kwargs = create_session.call_args_list[-1] self.assertEqual(last_call_kwargs['retry'], 12) self.assertEqual(last_call_kwargs['retry_after'], 20) def test_client_is_represented_properly_with_bucket_and_collection(self): client = Client( server_url="https://kinto.notmyidea.org/v1", bucket="homebrewing", collection="recipes" ) expected_repr = ("<KintoClient https://kinto.notmyidea.org/v1/" "buckets/homebrewing/collections/recipes>") assert str(client) == expected_repr def test_client_is_represented_properly_with_bucket(self): client = Client( server_url="https://kinto.notmyidea.org/v1", bucket="homebrewing", ) expected_repr = ("<KintoClient https://kinto.notmyidea.org/v1/" "buckets/homebrewing>") assert str(client) == expected_repr def test_client_is_represented_properly_without_bucket(self): client = Client( server_url="https://kinto.notmyidea.org/v1", bucket=None ) expected_repr = ("<KintoClient https://kinto.notmyidea.org/v1/>") assert str(client) == expected_repr def test_client_uses_default_bucket_if_not_specified(self): mock_response(self.session) client = Client(session=self.session) client.get_bucket() self.session.request.assert_called_with('get', '/buckets/default') def test_client_uses_passed_bucket_if_specified(self): client = Client( server_url="https://kinto.notmyidea.org/v1", bucket="buck") assert client._bucket_name == "buck" def test_client_clone_with_auth(self): client_clone = self.client.clone(auth=("reviewer", "")) assert client_clone.session.auth == ("reviewer", "") assert self.client.session != client_clone.session assert self.client.session.server_url == client_clone.session.server_url assert self.client.session.auth != client_clone.session.auth assert self.client.session.nb_retry == client_clone.session.nb_retry assert self.client.session.retry_after == client_clone.session.retry_after assert self.client._bucket_name == client_clone._bucket_name assert self.client._collection_name == client_clone._collection_name def test_client_clone_with_server_url(self): client_clone = self.client.clone(server_url="https://kinto.notmyidea.org/v1") assert client_clone.session.server_url == "https://kinto.notmyidea.org/v1" assert self.client.session != client_clone.session assert self.client.session.server_url != client_clone.session.server_url assert self.client.session.auth == client_clone.session.auth assert self.client.session.nb_retry == client_clone.session.nb_retry assert self.client.session.retry_after == client_clone.session.retry_after assert self.client._bucket_name == client_clone._bucket_name assert self.client._collection_name == client_clone._collection_name def test_client_clone_with_new_session(self): session = create_session(auth=("reviewer", ""), server_url="https://kinto.notmyidea.org/v1") client_clone = self.client.clone(session=session) assert client_clone.session == session assert self.client.session != client_clone.session assert self.client.session.server_url != client_clone.session.server_url assert self.client.session.auth != client_clone.session.auth assert self.client._bucket_name == client_clone._bucket_name assert self.client._collection_name == client_clone._collection_name def test_client_clone_with_auth_and_server_url(self): client_clone = self.client.clone(auth=("reviewer", ""), server_url="https://kinto.notmyidea.org/v1") assert client_clone.session.auth == ("reviewer", "") assert client_clone.session.server_url == "https://kinto.notmyidea.org/v1" assert self.client.session != client_clone.session assert self.client.session.server_url != client_clone.session.server_url assert self.client.session.auth != client_clone.session.auth assert self.client.session.nb_retry == client_clone.session.nb_retry assert self.client.session.retry_after == client_clone.session.retry_after assert self.client._bucket_name == client_clone._bucket_name assert self.client._collection_name == client_clone._collection_name def test_client_clone_with_existing_session(self): client_clone = self.client.clone(session=self.client.session) assert self.client.session == client_clone.session assert self.client.session.server_url == client_clone.session.server_url assert self.client.session.auth == client_clone.session.auth assert self.client._bucket_name == client_clone._bucket_name assert self.client._collection_name == client_clone._collection_name def test_client_clone_with_new_bucket_and_collection(self): client_clone = self.client.clone(bucket="bucket_blah", collection="coll_blah") assert self.client.session == client_clone.session assert self.client.session.server_url == client_clone.session.server_url assert self.client.session.auth == client_clone.session.auth assert self.client.session.nb_retry == client_clone.session.nb_retry assert self.client.session.retry_after == client_clone.session.retry_after assert self.client._bucket_name != client_clone._bucket_name assert self.client._collection_name != client_clone._collection_name assert client_clone._bucket_name == "bucket_blah" assert client_clone._collection_name == "coll_blah" def test_client_clone_with_auth_and_server_url_bucket_and_collection(self): client_clone = self.client.clone(auth=("reviewer", ""), server_url="https://kinto.notmyidea.org/v1", bucket="bucket_blah", collection="coll_blah") assert self.client.session != client_clone.session assert self.client.session.server_url != client_clone.session.server_url assert self.client.session.auth != client_clone.session.auth assert self.client._bucket_name != client_clone._bucket_name assert self.client._collection_name != client_clone._collection_name assert client_clone.session.auth == ("reviewer", "") assert client_clone.session.server_url == "https://kinto.notmyidea.org/v1" assert client_clone._bucket_name == "bucket_blah" assert client_clone._collection_name == "coll_blah"
def backport_records(event, context, **kwargs): """Backport records creations, updates and deletions from one collection to another. """ server_url = event["server"] source_auth = ( event.get("backport_records_source_auth") or os.environ["BACKPORT_RECORDS_SOURCE_AUTH"] ) source_bucket = ( event.get("backport_records_source_bucket") or os.environ["BACKPORT_RECORDS_SOURCE_BUCKET"] ) source_collection = ( event.get("backport_records_source_collection") or os.environ["BACKPORT_RECORDS_SOURCE_COLLECTION"] ) dest_auth = event.get( "backport_records_dest_auth", os.getenv("BACKPORT_RECORDS_DEST_AUTH", source_auth), ) dest_bucket = event.get( "backport_records_dest_bucket", os.getenv("BACKPORT_RECORDS_DEST_BUCKET", source_bucket), ) dest_collection = event.get( "backport_records_dest_collection", os.getenv("BACKPORT_RECORDS_DEST_COLLECTION", source_collection), ) if source_bucket == dest_bucket and source_collection == dest_collection: raise ValueError("Cannot copy records: destination is identical to source") source_client = Client( server_url=server_url, bucket=source_bucket, collection=source_collection, auth=tuple(source_auth.split(":", 1)) if ":" in source_auth else BearerTokenAuth(source_auth), ) dest_client = Client( server_url=server_url, bucket=dest_bucket, collection=dest_collection, auth=tuple(dest_auth.split(":", 1)) if ":" in dest_auth else BearerTokenAuth(dest_auth), ) source_timestamp = source_client.get_records_timestamp() dest_timestamp = dest_client.get_records_timestamp() if source_timestamp <= dest_timestamp: print("Records are in sync. Nothing to do.") return source_records = source_client.get_records() dest_records_by_id = {r["id"]: r for r in dest_client.get_records()} with dest_client.batch() as dest_batch: # Create or update the destination records. for r in source_records: dest_record = dest_records_by_id.pop(r["id"], None) if dest_record is None: dest_batch.create_record(data=r) elif r["last_modified"] > dest_record["last_modified"]: dest_batch.update_record(data=r) # Delete the records missing from source. for r in dest_records_by_id.values(): dest_batch.delete_record(id=r["id"]) ops_count = len(dest_batch.results()) # If destination has signing, request review or auto-approve changes. server_info = dest_client.server_info() signer_config = server_info["capabilities"].get("signer", {}) signer_resources = signer_config.get("resources", []) # Check destination collection config (sign-off required etc.) signed_dest = [ r for r in signer_resources if r["source"]["bucket"] == dest_bucket and r["source"]["collection"] == dest_collection ] if len(signed_dest) == 0: # Not explicitly configured. Check if configured at bucket level? signed_dest = [ r for r in signer_resources if r["source"]["bucket"] == dest_bucket and r["source"]["collection"] is None ] # Destination has no signature enabled. Nothing to do. if len(signed_dest) == 0: print(f"Done. {ops_count} changes applied.") return has_autoapproval = not signed_dest[0].get( "to_review_enabled", signer_config["to_review_enabled"] ) and not signed_dest[0].get( "group_check_enabled", signer_config["group_check_enabled"] ) if has_autoapproval: # Approve the changes. dest_client.patch_collection(data={"status": "to-sign"}) print(f"Done. {ops_count} changes applied and signed.") else: # Request review. dest_client.patch_collection(data={"status": "to-review"}) print(f"Done. Requested review for {ops_count} changes.")
class ClientTest(unittest.TestCase): def setUp(self): self.session = mock.MagicMock() self.client = Client(session=self.session) mock_response(self.session) def test_server_info(self): self.client.server_info() self.session.request.assert_called_with('get', '/') def test_context_manager_works_as_expected(self): settings = {"batch_max_requests": 25} self.session.request.side_effect = [({ "settings": settings }, []), ({ "responses": [] }, [])] with self.client.batch(bucket='mozilla', collection='test') as batch: batch.create_record(id=1234, data={'foo': 'bar'}) batch.create_record(id=5678, data={'bar': 'baz'}) self.session.request.assert_called_with( method='POST', endpoint='/batch', payload={ 'requests': [{ 'body': { 'data': { 'foo': 'bar' } }, 'path': '/buckets/mozilla/collections/test/records/1234', 'method': 'PUT', 'headers': { 'If-None-Match': '*', 'User-Agent': USER_AGENT } }, { 'body': { 'data': { 'bar': 'baz' } }, 'path': '/buckets/mozilla/collections/test/records/5678', 'method': 'PUT', 'headers': { 'If-None-Match': '*', 'User-Agent': USER_AGENT } }] }) def test_batch_raises_exception(self): # Make the next call to sess.request raise a 403. exception = KintoException() exception.response = mock.MagicMock() exception.response.status_code = 403 exception.request = mock.sentinel.request self.session.request.side_effect = exception with self.assertRaises(KintoException): with self.client.batch(bucket='moz', collection='test') as batch: batch.create_record(id=1234, data={'foo': 'bar'}) def test_batch_raises_exception_if_subrequest_failed_with_code_5xx(self): error = { "errno": 121, "message": "This user cannot access this resource.", "code": 500, "error": "Server Internal Error" } self.session.request.side_effect = [({ "settings": { "batch_max_requests": 25 } }, []), ({ "responses": [{ "status": 200, "path": "/url1", "body": {}, "headers": {} }, { "status": 500, "path": "/url2", "body": error, "headers": {} }] }, [])] with self.assertRaises(KintoException): with self.client.batch(bucket='moz', collection='test') as batch: batch.create_record(id=1234, data={'foo': 'bar'}) batch.create_record(id=5678, data={'tutu': 'toto'}) def test_batch_dont_raise_exception_if_subrequest_failed_with_code_4xx( self): error = { "errno": 121, "message": "Forbidden", "code": 403, "error": "This user cannot access this resource." } self.session.request.side_effect = [({ "settings": { "batch_max_requests": 25 } }, []), ({ "responses": [{ "status": 200, "path": "/url1", "body": {}, "headers": {} }, { "status": 403, "path": "/url2", "body": error, "headers": {} }] }, [])] with self.client.batch(bucket='moz', collection='test') as batch: # Do not raise batch.create_record(id=1234, data={'foo': 'bar'}) batch.create_record(id=5678, data={'tutu': 'toto'}) def test_batch_options_are_transmitted(self): settings = {"batch_max_requests": 25} self.session.request.side_effect = [({"settings": settings}, [])] with mock.patch('kinto_http.create_session') as create_session: with self.client.batch(bucket='moz', collection='test', retry=12, retry_after=20): _, last_call_kwargs = create_session.call_args_list[-1] self.assertEqual(last_call_kwargs['retry'], 12) self.assertEqual(last_call_kwargs['retry_after'], 20) def test_client_is_represented_properly_with_bucket_and_collection(self): client = Client(server_url="https://kinto.notmyidea.org/v1", bucket="homebrewing", collection="recipes") expected_repr = ("<KintoClient https://kinto.notmyidea.org/v1/" "buckets/homebrewing/collections/recipes>") assert str(client) == expected_repr def test_client_is_represented_properly_with_bucket(self): client = Client( server_url="https://kinto.notmyidea.org/v1", bucket="homebrewing", ) expected_repr = ("<KintoClient https://kinto.notmyidea.org/v1/" "buckets/homebrewing>") assert str(client) == expected_repr def test_client_is_represented_properly_without_bucket(self): client = Client(server_url="https://kinto.notmyidea.org/v1", bucket=None) expected_repr = ("<KintoClient https://kinto.notmyidea.org/v1/>") assert str(client) == expected_repr def test_client_uses_default_bucket_if_not_specified(self): mock_response(self.session) client = Client(session=self.session) client.get_bucket() self.session.request.assert_called_with('get', '/buckets/default') def test_client_uses_passed_bucket_if_specified(self): client = Client(server_url="https://kinto.notmyidea.org/v1", bucket="buck") assert client._bucket_name == "buck" def test_client_clone_with_auth(self): client_clone = self.client.clone(auth=("reviewer", "")) assert client_clone.session.auth == ("reviewer", "") assert self.client.session != client_clone.session assert self.client.session.server_url == client_clone.session.server_url assert self.client.session.auth != client_clone.session.auth assert self.client.session.nb_retry == client_clone.session.nb_retry assert self.client.session.retry_after == client_clone.session.retry_after assert self.client._bucket_name == client_clone._bucket_name assert self.client._collection_name == client_clone._collection_name def test_client_clone_with_server_url(self): client_clone = self.client.clone( server_url="https://kinto.notmyidea.org/v1") assert client_clone.session.server_url == "https://kinto.notmyidea.org/v1" assert self.client.session != client_clone.session assert self.client.session.server_url != client_clone.session.server_url assert self.client.session.auth == client_clone.session.auth assert self.client.session.nb_retry == client_clone.session.nb_retry assert self.client.session.retry_after == client_clone.session.retry_after assert self.client._bucket_name == client_clone._bucket_name assert self.client._collection_name == client_clone._collection_name def test_client_clone_with_new_session(self): session = create_session(auth=("reviewer", ""), server_url="https://kinto.notmyidea.org/v1") client_clone = self.client.clone(session=session) assert client_clone.session == session assert self.client.session != client_clone.session assert self.client.session.server_url != client_clone.session.server_url assert self.client.session.auth != client_clone.session.auth assert self.client._bucket_name == client_clone._bucket_name assert self.client._collection_name == client_clone._collection_name def test_client_clone_with_auth_and_server_url(self): client_clone = self.client.clone( auth=("reviewer", ""), server_url="https://kinto.notmyidea.org/v1") assert client_clone.session.auth == ("reviewer", "") assert client_clone.session.server_url == "https://kinto.notmyidea.org/v1" assert self.client.session != client_clone.session assert self.client.session.server_url != client_clone.session.server_url assert self.client.session.auth != client_clone.session.auth assert self.client.session.nb_retry == client_clone.session.nb_retry assert self.client.session.retry_after == client_clone.session.retry_after assert self.client._bucket_name == client_clone._bucket_name assert self.client._collection_name == client_clone._collection_name def test_client_clone_with_existing_session(self): client_clone = self.client.clone(session=self.client.session) assert self.client.session == client_clone.session assert self.client.session.server_url == client_clone.session.server_url assert self.client.session.auth == client_clone.session.auth assert self.client._bucket_name == client_clone._bucket_name assert self.client._collection_name == client_clone._collection_name def test_client_clone_with_new_bucket_and_collection(self): client_clone = self.client.clone(bucket="bucket_blah", collection="coll_blah") assert self.client.session == client_clone.session assert self.client.session.server_url == client_clone.session.server_url assert self.client.session.auth == client_clone.session.auth assert self.client.session.nb_retry == client_clone.session.nb_retry assert self.client.session.retry_after == client_clone.session.retry_after assert self.client._bucket_name != client_clone._bucket_name assert self.client._collection_name != client_clone._collection_name assert client_clone._bucket_name == "bucket_blah" assert client_clone._collection_name == "coll_blah" def test_client_clone_with_auth_and_server_url_bucket_and_collection(self): client_clone = self.client.clone( auth=("reviewer", ""), server_url="https://kinto.notmyidea.org/v1", bucket="bucket_blah", collection="coll_blah") assert self.client.session != client_clone.session assert self.client.session.server_url != client_clone.session.server_url assert self.client.session.auth != client_clone.session.auth assert self.client._bucket_name != client_clone._bucket_name assert self.client._collection_name != client_clone._collection_name assert client_clone.session.auth == ("reviewer", "") assert client_clone.session.server_url == "https://kinto.notmyidea.org/v1" assert client_clone._bucket_name == "bucket_blah" assert client_clone._collection_name == "coll_blah"
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 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