Esempio n. 1
0
    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")
Esempio n. 2
0
    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')
Esempio n. 3
0
    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')
Esempio n. 4
0
    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!"
Esempio n. 5
0
    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!'
Esempio n. 6
0
    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!'
Esempio n. 7
0
class CollectionTest(unittest.TestCase):

    def setUp(self):
        self.session = mock.MagicMock()
        mock_response(self.session)
        self.client = Client(session=self.session, bucket='mybucket')

    def test_collection_names_are_slugified(self):
        self.client.get_collection('my collection')
        url = '/buckets/mybucket/collections/my-collection'
        self.session.request.assert_called_with('get', url)

    def test_collection_creation_issues_an_http_put(self):
        self.client.create_collection(
            'mycollection',
            permissions=mock.sentinel.permissions)

        url = '/buckets/mybucket/collections/mycollection'
        self.session.request.assert_called_with(
            'put', url, data=None, permissions=mock.sentinel.permissions,
            headers=DO_NOT_OVERWRITE)

    def test_data_can_be_sent_on_creation(self):
        self.client.create_collection(
            'mycollection',
            'testbucket',
            data={'foo': 'bar'})

        self.session.request.assert_called_with(
            'put',
            '/buckets/testbucket/collections/mycollection',
            data={'foo': 'bar'},
            permissions=None,
            headers=DO_NOT_OVERWRITE)

    def test_collection_update_issues_an_http_put(self):
        self.client.update_collection(
            {'foo': 'bar'},
            collection='mycollection',
            permissions=mock.sentinel.permissions)

        url = '/buckets/mybucket/collections/mycollection'
        self.session.request.assert_called_with(
            'put', url, data={'foo': 'bar'},
            permissions=mock.sentinel.permissions, headers=None)

    def test_update_handles_last_modified(self):
        self.client.update_collection(
            {'foo': 'bar'},
            collection='mycollection',
            last_modified=1234)

        url = '/buckets/mybucket/collections/mycollection'
        headers = {'If-Match': '"1234"'}
        self.session.request.assert_called_with(
            'put', url, data={'foo': 'bar'},
            headers=headers, permissions=None)

    def test_collection_update_use_an_if_match_header(self):
        data = {'foo': 'bar', 'last_modified': '1234'}
        self.client.update_collection(
            data,
            collection='mycollection',
            permissions=mock.sentinel.permissions)

        url = '/buckets/mybucket/collections/mycollection'
        self.session.request.assert_called_with(
            'put', url, data={'foo': 'bar', 'last_modified': '1234'},
            permissions=mock.sentinel.permissions,
            headers={'If-Match': '"1234"'})

    def test_patch_collection_issues_an_http_patch(self):
        self.client.patch_collection(
            collection='mycollection',
            data={'key': 'secret'})

        url = '/buckets/mybucket/collections/mycollection'
        self.session.request.assert_called_with(
            'patch', url, data={'key': 'secret'}, headers=None,
            permissions=None)

    def test_patch_collection_handles_last_modified(self):
        self.client.patch_collection(
            collection='mycollection',
            data={'key': 'secret'},
            last_modified=1234)

        url = '/buckets/mybucket/collections/mycollection'
        headers = {'If-Match': '"1234"'}
        self.session.request.assert_called_with(
            'patch', url, data={'key': 'secret'}, headers=headers,
            permissions=None)

    def test_get_collections_returns_the_list_of_collections(self):
        mock_response(
            self.session,
            data=[
                {'id': 'foo', 'last_modified': '12345'},
                {'id': 'bar', 'last_modified': '59874'},
            ])

        collections = self.client.get_collections(bucket='default')
        assert list(collections) == [
            {'id': 'foo', 'last_modified': '12345'},
            {'id': 'bar', 'last_modified': '59874'},
        ]

    def test_collection_can_delete_all_its_records(self):
        self.client.delete_records(bucket='abucket', collection='acollection')
        url = '/buckets/abucket/collections/acollection/records'
        self.session.request.assert_called_with('delete', url, headers=None)

    def test_delete_is_issued_on_list_deletion(self):
        self.client.delete_collections(bucket='mybucket')
        url = '/buckets/mybucket/collections'
        self.session.request.assert_called_with('delete', url, headers=None)

    def test_collection_can_be_deleted(self):
        data = {}
        mock_response(self.session, data=data)
        deleted = self.client.delete_collection('mycollection')
        assert deleted == data
        url = '/buckets/mybucket/collections/mycollection'
        self.session.request.assert_called_with('delete', url, headers=None)

    def test_collection_delete_if_match(self):
        data = {}
        mock_response(self.session, data=data)
        deleted = self.client.delete_collection(
            'mycollection',
            last_modified=1234)
        assert deleted == data
        url = '/buckets/mybucket/collections/mycollection'
        self.session.request.assert_called_with(
            'delete', url, headers={'If-Match': '"1234"'})

    def test_collection_delete_if_match_not_included_if_not_safe(self):
        data = {}
        mock_response(self.session, data=data)
        deleted = self.client.delete_collection(
            'mycollection',
            last_modified=1324,
            safe=False)
        assert deleted == data
        url = '/buckets/mybucket/collections/mycollection'
        self.session.request.assert_called_with('delete', url, headers=None)

    def test_get_or_create_doesnt_raise_in_case_of_conflict(self):
        data = {
            'permissions': mock.sentinel.permissions,
            'data': {'foo': 'bar'}
        }
        self.session.request.side_effect = [
            get_http_error(status=412),
            (data, None)
        ]
        returned_data = self.client.create_collection(
            bucket="buck",
            collection="coll",
            if_not_exists=True)  # Should not raise.
        assert returned_data == data

    def test_get_or_create_raise_in_other_cases(self):
        self.session.request.side_effect = get_http_error(status=500)
        with self.assertRaises(KintoException):
            self.client.create_collection(
                bucket="buck",
                collection="coll",
                if_not_exists=True)
Esempio n. 8
0
class CollectionTest(unittest.TestCase):
    def setUp(self):
        self.session = mock.MagicMock()
        mock_response(self.session)
        self.client = Client(session=self.session, bucket="mybucket")

    def test_collection_names_are_slugified(self):
        self.client.get_collection("my collection")
        url = "/buckets/mybucket/collections/my-collection"
        self.session.request.assert_called_with("get", url)

    def test_collection_creation_issues_an_http_put(self):
        self.client.create_collection("mycollection", permissions=mock.sentinel.permissions)

        url = "/buckets/mybucket/collections/mycollection"
        self.session.request.assert_called_with(
            "put", url, data=None, permissions=mock.sentinel.permissions, headers=DO_NOT_OVERWRITE
        )

    def test_data_can_be_sent_on_creation(self):
        self.client.create_collection("mycollection", "testbucket", data={"foo": "bar"})

        self.session.request.assert_called_with(
            "put",
            "/buckets/testbucket/collections/mycollection",
            data={"foo": "bar"},
            permissions=None,
            headers=DO_NOT_OVERWRITE,
        )

    def test_collection_update_issues_an_http_put(self):
        self.client.update_collection({"foo": "bar"}, collection="mycollection", permissions=mock.sentinel.permissions)

        url = "/buckets/mybucket/collections/mycollection"
        self.session.request.assert_called_with(
            "put", url, data={"foo": "bar"}, permissions=mock.sentinel.permissions, headers=None
        )

    def test_update_handles_last_modified(self):
        self.client.update_collection({"foo": "bar"}, collection="mycollection", last_modified=1234)

        url = "/buckets/mybucket/collections/mycollection"
        headers = {"If-Match": '"1234"'}
        self.session.request.assert_called_with("put", url, data={"foo": "bar"}, headers=headers, permissions=None)

    def test_collection_update_use_an_if_match_header(self):
        data = {"foo": "bar", "last_modified": "1234"}
        self.client.update_collection(data, collection="mycollection", permissions=mock.sentinel.permissions)

        url = "/buckets/mybucket/collections/mycollection"
        self.session.request.assert_called_with(
            "put",
            url,
            data={"foo": "bar", "last_modified": "1234"},
            permissions=mock.sentinel.permissions,
            headers={"If-Match": '"1234"'},
        )

    def test_patch_collection_issues_an_http_patch(self):
        self.client.patch_collection(collection="mycollection", data={"key": "secret"})

        url = "/buckets/mybucket/collections/mycollection"
        self.session.request.assert_called_with("patch", url, data={"key": "secret"}, headers=None, permissions=None)

    def test_patch_collection_handles_last_modified(self):
        self.client.patch_collection(collection="mycollection", data={"key": "secret"}, last_modified=1234)

        url = "/buckets/mybucket/collections/mycollection"
        headers = {"If-Match": '"1234"'}
        self.session.request.assert_called_with("patch", url, data={"key": "secret"}, headers=headers, permissions=None)

    def test_get_collections_returns_the_list_of_collections(self):
        mock_response(
            self.session, data=[{"id": "foo", "last_modified": "12345"}, {"id": "bar", "last_modified": "59874"}]
        )

        collections = self.client.get_collections(bucket="default")
        assert list(collections) == [{"id": "foo", "last_modified": "12345"}, {"id": "bar", "last_modified": "59874"}]

    def test_collection_can_delete_a_list_of_records(self):
        self.client.delete_records(["1234", "5678"])
        # url = '/buckets/mybucket/collections/mycollection/records/9'
        # XXX check that the delete is done in a BATCH.

    def test_collection_can_be_deleted(self):
        data = {}
        mock_response(self.session, data=data)
        deleted = self.client.delete_collection("mycollection")
        assert deleted == data
        url = "/buckets/mybucket/collections/mycollection"
        self.session.request.assert_called_with("delete", url, headers=None)

    def test_collection_delete_if_match(self):
        data = {}
        mock_response(self.session, data=data)
        deleted = self.client.delete_collection("mycollection", last_modified=1234)
        assert deleted == data
        url = "/buckets/mybucket/collections/mycollection"
        self.session.request.assert_called_with("delete", url, headers={"If-Match": '"1234"'})

    def test_collection_delete_if_match_not_included_if_not_safe(self):
        data = {}
        mock_response(self.session, data=data)
        deleted = self.client.delete_collection("mycollection", last_modified=1324, safe=False)
        assert deleted == data
        url = "/buckets/mybucket/collections/mycollection"
        self.session.request.assert_called_with("delete", url, headers=None)

    def test_get_or_create_doesnt_raise_in_case_of_conflict(self):
        data = {"permissions": mock.sentinel.permissions, "data": {"foo": "bar"}}
        self.session.request.side_effect = [get_http_error(status=412), (data, None)]
        returned_data = self.client.create_collection(
            bucket="buck", collection="coll", if_not_exists=True
        )  # Should not raise.
        assert returned_data == data

    def test_get_or_create_raise_in_other_cases(self):
        self.session.request.side_effect = get_http_error(status=500)
        with self.assertRaises(KintoException):
            self.client.create_collection(bucket="buck", collection="coll", if_not_exists=True)
Esempio n. 9
0
class FunctionalTest(unittest2.TestCase):

    def __init__(self, *args, **kwargs):
        super(FunctionalTest, self).__init__(*args, **kwargs)
        # XXX Read the configuration from env variables.
        self.server_url = SERVER_URL
        self.auth = DEFAULT_AUTH

        # Read the configuration.
        self.config = configparser.RawConfigParser()
        self.config.read(os.path.join(__HERE__, 'config/kinto.ini'))
        self.client = Client(server_url=self.server_url, auth=self.auth)

    def tearDown(self):
        # Delete all the created objects
        flush_url = urljoin(self.server_url, '/__flush__')
        resp = requests.post(flush_url)
        resp.raise_for_status()

    def get_user_id(self, credentials):
        hmac_secret = self.config.get('app:main', 'cliquet.userid_hmac_secret')
        credentials = '%s:%s' % credentials
        digest = cliquet_utils.hmac_digest(hmac_secret, credentials)
        return 'basicauth:%s' % digest

    def test_bucket_creation(self):
        bucket = self.client.create_bucket('mozilla')
        user_id = self.get_user_id(self.auth)
        assert user_id in bucket['permissions']['write']

    def test_bucket_creation_if_not_exists(self):
        self.client.create_bucket('mozilla')
        # Should not raise.
        self.client.create_bucket('mozilla', if_not_exists=True)

    def test_bucket_retrieval(self):
        self.client.create_bucket('mozilla')
        self.client.get_bucket('mozilla')
        # XXX Add permissions handling during creation and check they are
        # present during retrieval.

    def test_bucket_retrieval_fails_when_not_created(self):
        self.assertRaises(BucketNotFound, self.client.get_bucket,
                          'non-existent')

    def test_bucket_deletion(self):
        self.client.create_bucket('mozilla')
        self.client.delete_bucket('mozilla')
        self.assertRaises(BucketNotFound, self.client.get_bucket, 'mozilla')

    def test_bucket_save(self):
        self.client.create_bucket('mozilla', permissions={'write': ['alexis']})
        bucket = self.client.get_bucket('mozilla')
        assert 'alexis' in bucket['permissions']['write']

    def test_collection_creation(self):
        self.client.create_bucket('mozilla')
        self.client.create_collection(
            'payments', bucket='mozilla',
            permissions={'write': ['alexis', ]}
        )

        # Test retrieval of a collection gets the permissions as well.
        collection = self.client.get_collection('payments', bucket='mozilla')
        assert 'alexis' in collection['permissions']['write']

    def test_collection_creation_if_not_exists(self):
        self.client.create_bucket('mozilla')
        self.client.create_collection('payments', bucket='mozilla')
        # Should not raise.
        self.client.create_collection('payments', bucket='mozilla',
                                      if_not_exists=True)

    def test_collection_list(self):
        self.client.create_bucket('mozilla')
        self.client.create_collection('receipts', bucket='mozilla')
        self.client.create_collection('assets', bucket='mozilla')

        # The returned collections should be strings.
        collections = self.client.get_collections('mozilla')
        self.assertEquals(2, len(collections))

        self.assertEquals(set([coll['id'] for coll in collections]),
                          set(['receipts', 'assets']))

    def test_collection_deletion(self):
        self.client.create_bucket('mozilla')
        self.client.create_collection('payments', bucket='mozilla')
        self.client.delete_collection('payments', bucket='mozilla')
        assert len(self.client.get_collections(bucket='mozilla')) == 0

    def test_record_creation_and_retrieval(self):
        client = Client(server_url=self.server_url, auth=self.auth,
                        bucket='mozilla', collection='payments')
        client.create_bucket()
        client.create_collection()
        created = client.create_record(data={'foo': 'bar'},
                                       permissions={'read': ['alexis']})
        record = client.get_record(created['data']['id'])
        assert 'alexis' in record['permissions']['read']

    def test_records_list_retrieval(self):
        client = Client(server_url=self.server_url, auth=self.auth,
                        bucket='mozilla', collection='payments')
        client.create_bucket()
        client.create_collection()
        client.create_record(data={'foo': 'bar'},
                             permissions={'read': ['alexis']})
        records = client.get_records()
        assert len(records) == 1

    def test_records_paginated_list_retrieval(self):
        client = Client(server_url=self.server_url, auth=self.auth,
                        bucket='mozilla', collection='payments')
        client.create_bucket()
        client.create_collection()
        for i in range(10):
            client.create_record(data={'foo': 'bar'},
                                 permissions={'read': ['alexis']})
        # Kinto is running with kinto.paginate_by = 5
        records = client.get_records()
        assert len(records) == 10

    def test_single_record_save(self):
        client = Client(server_url=self.server_url, auth=self.auth,
                        bucket='mozilla', collection='payments')
        client.create_bucket()
        client.create_collection()
        created = client.create_record(data={'foo': 'bar'},
                                       permissions={'read': ['alexis']})
        created['data']['bar'] = 'baz'

        # XXX enhance this in order to have to pass only one argument, created.
        client.update_record(id=created['data']['id'], data=created['data'])

        retrieved = client.get_record(created['data']['id'])
        assert 'alexis' in retrieved['permissions']['read']
        assert retrieved['data']['foo'] == u'bar'
        assert retrieved['data']['bar'] == u'baz'
        assert created['data']['id'] == retrieved['data']['id']

    def test_single_record_doesnt_overwrite(self):
        client = Client(server_url=self.server_url, auth=self.auth,
                        bucket='mozilla', collection='payments')
        client.create_bucket()
        client.create_collection()
        created = client.create_record(data={'foo': 'bar'},
                                       permissions={'read': ['alexis']})

        with self.assertRaises(KintoException):
            # Create a second record with the ID of the first one.
            client.create_record(data={'id': created['data']['id'],
                                       'bar': 'baz'})

    def test_single_record_creation_if_not_exists(self):
        client = Client(server_url=self.server_url, auth=self.auth,
                        bucket='mozilla', collection='payments')
        client.create_bucket()
        client.create_collection()
        created = client.create_record(data={'foo': 'bar'})
        client.create_record(data={'id': created['data']['id'],
                                   'bar': 'baz'},
                             if_not_exists=True)

    def test_single_record_can_overwrite(self):
        client = Client(server_url=self.server_url, auth=self.auth,
                        bucket='mozilla', collection='payments')
        client.create_bucket()
        client.create_collection()
        created = client.create_record(data={'foo': 'bar'},
                                       permissions={'read': ['alexis']})

        client.create_record(data={'id': created['data']['id'],
                                   'bar': 'baz'}, safe=False)

    def test_one_record_deletion(self):
        client = Client(server_url=self.server_url, auth=self.auth,
                        bucket='mozilla', collection='payments')
        client.create_bucket()
        client.create_collection()
        record = client.create_record({'foo': 'bar'})
        deleted = client.delete_record(record['data']['id'])
        assert deleted['deleted'] is True
        assert len(client.get_records()) == 0

    def test_bucket_sharing(self):
        alice_credentials = ('alice', 'p4ssw0rd')
        alice_userid = self.get_user_id(alice_credentials)

        # Create a bucket and share it with alice.
        self.client.create_bucket('shared-bucket',
                                  permissions={'read': [alice_userid, ]})

        alice_client = Client(server_url=self.server_url,
                              auth=alice_credentials)
        alice_client.get_bucket('shared-bucket')

    def test_updating_data_on_a_collection(self):
        client = Client(server_url=self.server_url, auth=self.auth,
                        bucket='mozilla', collection='payments')
        client.create_bucket()
        client.create_collection()

        client.patch_collection(data={'secret': 'psssssst!'})
        collection = client.get_collection()
        assert collection['data']['secret'] == 'psssssst!'

    def test_collection_sharing(self):
        alice_credentials = ('alice', 'p4ssw0rd')
        alice_userid = self.get_user_id(alice_credentials)

        self.client.create_bucket('bob-bucket')
        self.client.create_collection(
            'shared',
            bucket='bob-bucket',
            permissions={'read': [alice_userid, ]})

        # Try to read the collection as Alice.
        alice_client = Client(server_url=self.server_url,
                              auth=alice_credentials)
        alice_client.get_collection('shared', bucket='bob-bucket')

    def test_record_sharing(self):
        alice_credentials = ('alice', 'p4ssw0rd')
        alice_userid = self.get_user_id(alice_credentials)

        # Create a record, and share it with Alice.
        self.client.create_bucket('bob-bucket')
        self.client.create_collection('bob-personal-collection',
                                      bucket='bob-bucket')
        record = self.client.create_record(
            data={'foo': 'bar'},
            permissions={'read': [alice_userid, ]},
            bucket='bob-bucket',
            collection='bob-personal-collection')

        # Try to read the record as Alice
        alice_client = Client(server_url=self.server_url,
                              auth=alice_credentials)
        record = alice_client.get_record(
            id=record['data']['id'],
            bucket='bob-bucket',
            collection='bob-personal-collection')

        assert record['data']['foo'] == 'bar'

    def test_request_batching(self):
        with self.client.batch(bucket='mozilla', collection='fonts') as batch:
            batch.create_bucket()
            batch.create_collection()
            batch.create_record(data={'foo': 'bar'},
                                permissions={'read': ['natim']})
            batch.create_record(data={'bar': 'baz'},
                                permissions={'read': ['alexis']})

        records = self.client.get_records(bucket='mozilla', collection='fonts')
        assert len(records) == 2

    def test_replication(self):
        # First, create a few records on the first kinto collection.
        with self.client.batch(bucket='origin', collection='coll') as batch:
            batch.create_bucket()
            batch.create_collection()

            for n in range(10):
                batch.create_record(data={'foo': 'bar', 'n': n})

        origin = Client(
            server_url=self.server_url,
            auth=self.auth,
            bucket='origin',
            collection='coll'
        )
        destination = Client(
            server_url=self.server_url,
            auth=self.auth,
            bucket='destination',
            collection='coll')

        replication.replicate(origin, destination)
        records = self.client.get_records(bucket='destination',
                                          collection='coll')
        assert len(records) == 10
Esempio n. 10
0
class FunctionalTest(unittest2.TestCase):

    def __init__(self, *args, **kwargs):
        super(FunctionalTest, self).__init__(*args, **kwargs)
        self.auth = DEFAULT_AUTH
        self.private_key = os.path.join(__HERE__, 'config/ecdsa.private.pem')

        self.signer_config = configparser.RawConfigParser()
        self.signer_config.read(os.path.join(__HERE__, 'config/signer.ini'))
        priv_key = self.signer_config.get(
            'app:main', 'kinto.signer.ecdsa.private_key')
        self.signer = ECDSASigner(private_key=priv_key)

        # Setup the kinto clients for the source and destination.
        self._auth = DEFAULT_AUTH
        self._server_url = SERVER_URL
        self._source_bucket = "source"
        self._destination_bucket = "destination"
        self._collection_id = "collection1"

        self.source = Client(
            server_url=self._server_url,
            auth=self._auth,
            bucket=self._source_bucket,
            collection=self._collection_id)

        self.destination = Client(
            server_url=self._server_url,
            auth=self._auth,
            bucket=self._destination_bucket,
            collection=self._collection_id)

    def tearDown(self):
        # Delete all the created objects.
        self._flush_server(self._server_url)

    def _flush_server(self, server_url):
        flush_url = urljoin(server_url, '/__flush__')
        resp = requests.post(flush_url)
        resp.raise_for_status()

    def test_destination_creation_and_new_records_signature(self):
        self.source.create_bucket()
        self.source.create_collection()

        # Send new data to the signer.
        with self.source.batch() as batch:
            for n in range(0, 10):
                batch.create_record(data={'newdata': n})

        source_records = self.source.get_records()
        assert len(source_records) == 10

        # Trigger a signature.
        self.source.update_collection(
            data={'status': 'to-sign'},
            method="put")

        # Ensure the remote data is signed properly.
        data = self.destination.get_collection()
        signature = data['data']['signature']
        assert signature is not None

        records = self.destination.get_records()
        assert len(records) == 10
        serialized_records = canonical_json(records)
        self.signer.verify(serialized_records, signature)

        # the status of the source collection should be "signed".
        source_collection = self.source.get_collection()['data']
        assert source_collection['status'] == 'signed'

    def test_records_deletion_and_signature(self):
        self.source.create_bucket()
        self.source.create_collection()

        # Create some data on the source collection and send it.
        with self.source.batch() as batch:
            for n in range(0, 10):
                batch.create_record(data={'newdata': n})

        source_records = self.source.get_records()
        assert len(source_records) == 10

        # Trigger a signature.
        self.source.update_collection(data={'status': 'to-sign'}, method="put")

        # Wait so the new last_modified timestamp will be greater than the
        # one from the previous records.
        time.sleep(0.01)
        # Now delete one record on the source and trigger another signature.
        self.source.delete_record(source_records[0]['id'])
        self.source.update_collection(data={'status': 'to-sign'}, method="put")

        records = self.destination.get_records()
        assert len(records) == 9

        data = self.destination.get_collection()
        signature = data['data']['signature']
        assert signature is not None

        serialized_records = canonical_json(records)
        # This raises when the signature is invalid.
        self.signer.verify(serialized_records, signature)
Esempio n. 11
0
class CollectionTest(unittest.TestCase):
    def setUp(self):
        self.session = mock.MagicMock()
        mock_response(self.session)
        self.client = Client(session=self.session, bucket='mybucket')

    def test_collection_names_are_slugified(self):
        self.client.get_collection('my collection')
        url = '/buckets/mybucket/collections/my-collection'
        self.session.request.assert_called_with('get', url)

    def test_collection_creation_issues_an_http_put(self):
        self.client.create_collection('mycollection',
                                      permissions=mock.sentinel.permissions)

        url = '/buckets/mybucket/collections/mycollection'
        self.session.request.assert_called_with(
            'put',
            url,
            data=None,
            permissions=mock.sentinel.permissions,
            headers=DO_NOT_OVERWRITE)

    def test_data_can_be_sent_on_creation(self):
        self.client.create_collection('mycollection',
                                      'testbucket',
                                      data={'foo': 'bar'})

        self.session.request.assert_called_with(
            'put',
            '/buckets/testbucket/collections/mycollection',
            data={'foo': 'bar'},
            permissions=None,
            headers=DO_NOT_OVERWRITE)

    def test_collection_update_issues_an_http_put(self):
        self.client.update_collection({'foo': 'bar'},
                                      collection='mycollection',
                                      permissions=mock.sentinel.permissions)

        url = '/buckets/mybucket/collections/mycollection'
        self.session.request.assert_called_with(
            'put',
            url,
            data={'foo': 'bar'},
            permissions=mock.sentinel.permissions,
            headers=None)

    def test_update_handles_last_modified(self):
        self.client.update_collection({'foo': 'bar'},
                                      collection='mycollection',
                                      last_modified=1234)

        url = '/buckets/mybucket/collections/mycollection'
        headers = {'If-Match': '"1234"'}
        self.session.request.assert_called_with('put',
                                                url,
                                                data={'foo': 'bar'},
                                                headers=headers,
                                                permissions=None)

    def test_collection_update_use_an_if_match_header(self):
        data = {'foo': 'bar', 'last_modified': '1234'}
        self.client.update_collection(data,
                                      collection='mycollection',
                                      permissions=mock.sentinel.permissions)

        url = '/buckets/mybucket/collections/mycollection'
        self.session.request.assert_called_with(
            'put',
            url,
            data={
                'foo': 'bar',
                'last_modified': '1234'
            },
            permissions=mock.sentinel.permissions,
            headers={'If-Match': '"1234"'})

    def test_patch_collection_issues_an_http_patch(self):
        self.client.patch_collection(collection='mycollection',
                                     data={'key': 'secret'})

        url = '/buckets/mybucket/collections/mycollection'
        self.session.request.assert_called_with('patch',
                                                url,
                                                data={'key': 'secret'},
                                                headers=None,
                                                permissions=None)

    def test_patch_collection_handles_last_modified(self):
        self.client.patch_collection(collection='mycollection',
                                     data={'key': 'secret'},
                                     last_modified=1234)

        url = '/buckets/mybucket/collections/mycollection'
        headers = {'If-Match': '"1234"'}
        self.session.request.assert_called_with('patch',
                                                url,
                                                data={'key': 'secret'},
                                                headers=headers,
                                                permissions=None)

    def test_get_collections_returns_the_list_of_collections(self):
        mock_response(self.session,
                      data=[
                          {
                              'id': 'foo',
                              'last_modified': '12345'
                          },
                          {
                              'id': 'bar',
                              'last_modified': '59874'
                          },
                      ])

        collections = self.client.get_collections(bucket='default')
        assert list(collections) == [
            {
                'id': 'foo',
                'last_modified': '12345'
            },
            {
                'id': 'bar',
                'last_modified': '59874'
            },
        ]

    def test_collection_can_delete_all_its_records(self):
        self.client.delete_records(bucket='abucket', collection='acollection')
        url = '/buckets/abucket/collections/acollection/records'
        self.session.request.assert_called_with('delete', url, headers=None)

    def test_delete_is_issued_on_list_deletion(self):
        self.client.delete_collections(bucket='mybucket')
        url = '/buckets/mybucket/collections'
        self.session.request.assert_called_with('delete', url, headers=None)

    def test_collection_can_be_deleted(self):
        data = {}
        mock_response(self.session, data=data)
        deleted = self.client.delete_collection('mycollection')
        assert deleted == data
        url = '/buckets/mybucket/collections/mycollection'
        self.session.request.assert_called_with('delete', url, headers=None)

    def test_collection_delete_if_match(self):
        data = {}
        mock_response(self.session, data=data)
        deleted = self.client.delete_collection('mycollection',
                                                last_modified=1234)
        assert deleted == data
        url = '/buckets/mybucket/collections/mycollection'
        self.session.request.assert_called_with('delete',
                                                url,
                                                headers={'If-Match': '"1234"'})

    def test_collection_delete_if_match_not_included_if_not_safe(self):
        data = {}
        mock_response(self.session, data=data)
        deleted = self.client.delete_collection('mycollection',
                                                last_modified=1324,
                                                safe=False)
        assert deleted == data
        url = '/buckets/mybucket/collections/mycollection'
        self.session.request.assert_called_with('delete', url, headers=None)

    def test_get_or_create_doesnt_raise_in_case_of_conflict(self):
        data = {
            'permissions': mock.sentinel.permissions,
            'data': {
                'foo': 'bar'
            }
        }
        self.session.request.side_effect = [
            get_http_error(status=412), (data, None)
        ]
        returned_data = self.client.create_collection(
            bucket="buck", collection="coll",
            if_not_exists=True)  # Should not raise.
        assert returned_data == data

    def test_get_or_create_raise_in_other_cases(self):
        self.session.request.side_effect = get_http_error(status=500)
        with self.assertRaises(KintoException):
            self.client.create_collection(bucket="buck",
                                          collection="coll",
                                          if_not_exists=True)
Esempio n. 12
0
class FunctionalTest(unittest2.TestCase):
    def __init__(self, *args, **kwargs):
        super(FunctionalTest, self).__init__(*args, **kwargs)
        # XXX Read the configuration from env variables.
        self.server_url = SERVER_URL
        self.auth = DEFAULT_AUTH

        # Read the configuration.
        self.config = configparser.RawConfigParser()
        self.config.read(os.path.join(__HERE__, 'config/kinto.ini'))
        self.client = Client(server_url=self.server_url, auth=self.auth)

    def tearDown(self):
        # Delete all the created objects
        flush_url = urljoin(self.server_url, '/__flush__')
        resp = requests.post(flush_url)
        resp.raise_for_status()

    def get_user_id(self, credentials):
        hmac_secret = self.config.get('app:main', 'kinto.userid_hmac_secret')
        credentials = '%s:%s' % credentials
        digest = cliquet_utils.hmac_digest(hmac_secret, credentials)
        return 'basicauth:%s' % digest

    def test_bucket_creation(self):
        bucket = self.client.create_bucket('mozilla')
        user_id = self.get_user_id(self.auth)
        assert user_id in bucket['permissions']['write']

    def test_bucket_creation_if_not_exists(self):
        self.client.create_bucket('mozilla')
        # Should not raise.
        self.client.create_bucket('mozilla', if_not_exists=True)

    def test_buckets_retrieval(self):
        self.client.create_bucket('mozilla')
        buckets = self.client.get_buckets()
        assert len(buckets) == 1

    def test_bucket_retrieval(self):
        self.client.create_bucket('mozilla')
        self.client.get_bucket('mozilla')
        # XXX Add permissions handling during creation and check they are
        # present during retrieval.

    def test_bucket_modification(self):
        bucket = self.client.create_bucket('mozilla', data={'version': 1})
        assert bucket['data']['version'] == 1
        bucket = self.client.patch_bucket('mozilla', data={'author': 'you'})
        assert bucket['data']['version'] == 1
        assert bucket['data']['author'] == 'you'
        bucket = self.client.update_bucket('mozilla', data={'date': 'today'})
        assert bucket['data']['date'] == 'today'
        assert 'version' not in bucket['data']

    def test_bucket_retrieval_fails_when_not_created(self):
        self.assertRaises(BucketNotFound, self.client.get_bucket,
                          'non-existent')

    def test_bucket_deletion(self):
        self.client.create_bucket('mozilla')
        self.client.delete_bucket('mozilla')
        self.assertRaises(BucketNotFound, self.client.get_bucket, 'mozilla')

    def test_buckets_deletion(self):
        self.client.create_bucket('mozilla')
        buckets = self.client.delete_buckets()
        assert buckets[0]['id'] == 'mozilla'
        self.assertRaises(BucketNotFound, self.client.get_bucket, 'mozilla')

    def test_bucket_save(self):
        self.client.create_bucket('mozilla', permissions={'write': ['alexis']})
        bucket = self.client.get_bucket('mozilla')
        assert 'alexis' in bucket['permissions']['write']

    def test_collection_creation(self):
        self.client.create_bucket('mozilla')
        self.client.create_collection('payments',
                                      bucket='mozilla',
                                      permissions={'write': [
                                          'alexis',
                                      ]})

        # Test retrieval of a collection gets the permissions as well.
        collection = self.client.get_collection('payments', bucket='mozilla')
        assert 'alexis' in collection['permissions']['write']

    def test_collection_creation_if_not_exists(self):
        self.client.create_bucket('mozilla')
        self.client.create_collection('payments', bucket='mozilla')
        # Should not raise.
        self.client.create_collection('payments',
                                      bucket='mozilla',
                                      if_not_exists=True)

    def test_collection_list(self):
        self.client.create_bucket('mozilla')
        self.client.create_collection('receipts', bucket='mozilla')
        self.client.create_collection('assets', bucket='mozilla')

        # The returned collections should be strings.
        collections = self.client.get_collections('mozilla')
        self.assertEquals(2, len(collections))

        self.assertEquals(set([coll['id'] for coll in collections]),
                          set(['receipts', 'assets']))

    def test_collection_deletion(self):
        self.client.create_bucket('mozilla')
        self.client.create_collection('payments', bucket='mozilla')
        self.client.delete_collection('payments', bucket='mozilla')
        assert len(self.client.get_collections(bucket='mozilla')) == 0

    def test_collections_deletion(self):
        self.client.create_bucket('mozilla')
        self.client.create_collection('amo', bucket='mozilla')
        self.client.create_collection('blocklist', bucket='mozilla')
        self.client.delete_collections(bucket='mozilla')
        assert len(self.client.get_collections(bucket='mozilla')) == 0

    def test_record_creation_and_retrieval(self):
        client = Client(server_url=self.server_url,
                        auth=self.auth,
                        bucket='mozilla',
                        collection='payments')
        client.create_bucket()
        client.create_collection()
        created = client.create_record(data={'foo': 'bar'},
                                       permissions={'read': ['alexis']})
        record = client.get_record(created['data']['id'])
        assert 'alexis' in record['permissions']['read']

    def test_records_list_retrieval(self):
        client = Client(server_url=self.server_url,
                        auth=self.auth,
                        bucket='mozilla',
                        collection='payments')
        client.create_bucket()
        client.create_collection()
        client.create_record(data={'foo': 'bar'},
                             permissions={'read': ['alexis']})
        records = client.get_records()
        assert len(records) == 1

    def test_records_paginated_list_retrieval(self):
        client = Client(server_url=self.server_url,
                        auth=self.auth,
                        bucket='mozilla',
                        collection='payments')
        client.create_bucket()
        client.create_collection()
        for i in range(10):
            client.create_record(data={'foo': 'bar'},
                                 permissions={'read': ['alexis']})
        # Kinto is running with kinto.paginate_by = 5
        records = client.get_records()
        assert len(records) == 10

    def test_single_record_save(self):
        client = Client(server_url=self.server_url,
                        auth=self.auth,
                        bucket='mozilla',
                        collection='payments')
        client.create_bucket()
        client.create_collection()
        created = client.create_record(data={'foo': 'bar'},
                                       permissions={'read': ['alexis']})
        created['data']['bar'] = 'baz'

        # XXX enhance this in order to have to pass only one argument, created.
        client.update_record(id=created['data']['id'], data=created['data'])

        retrieved = client.get_record(created['data']['id'])
        assert 'alexis' in retrieved['permissions']['read']
        assert retrieved['data']['foo'] == u'bar'
        assert retrieved['data']['bar'] == u'baz'
        assert created['data']['id'] == retrieved['data']['id']

    def test_single_record_doesnt_overwrite(self):
        client = Client(server_url=self.server_url,
                        auth=self.auth,
                        bucket='mozilla',
                        collection='payments')
        client.create_bucket()
        client.create_collection()
        created = client.create_record(data={'foo': 'bar'},
                                       permissions={'read': ['alexis']})

        with self.assertRaises(KintoException):
            # Create a second record with the ID of the first one.
            client.create_record(data={
                'id': created['data']['id'],
                'bar': 'baz'
            })

    def test_single_record_creation_if_not_exists(self):
        client = Client(server_url=self.server_url,
                        auth=self.auth,
                        bucket='mozilla',
                        collection='payments')
        client.create_bucket()
        client.create_collection()
        created = client.create_record(data={'foo': 'bar'})
        client.create_record(data={
            'id': created['data']['id'],
            'bar': 'baz'
        },
                             if_not_exists=True)

    def test_single_record_can_overwrite(self):
        client = Client(server_url=self.server_url,
                        auth=self.auth,
                        bucket='mozilla',
                        collection='payments')
        client.create_bucket()
        client.create_collection()
        created = client.create_record(data={'foo': 'bar'},
                                       permissions={'read': ['alexis']})

        client.create_record(data={
            'id': created['data']['id'],
            'bar': 'baz'
        },
                             safe=False)

    def test_one_record_deletion(self):
        client = Client(server_url=self.server_url,
                        auth=self.auth,
                        bucket='mozilla',
                        collection='payments')
        client.create_bucket()
        client.create_collection()
        record = client.create_record({'foo': 'bar'})
        deleted = client.delete_record(record['data']['id'])
        assert deleted['deleted'] is True
        assert len(client.get_records()) == 0

    def test_multiple_record_deletion(self):
        client = Client(server_url=self.server_url,
                        auth=self.auth,
                        bucket='mozilla',
                        collection='payments')
        client.create_bucket()
        client.create_collection()
        client.create_record({'foo': 'bar'})
        client.delete_records()
        assert len(client.get_records()) == 0

    def test_bucket_sharing(self):
        alice_credentials = ('alice', 'p4ssw0rd')
        alice_userid = self.get_user_id(alice_credentials)

        # Create a bucket and share it with alice.
        self.client.create_bucket('shared-bucket',
                                  permissions={'read': [
                                      alice_userid,
                                  ]})

        alice_client = Client(server_url=self.server_url,
                              auth=alice_credentials)
        alice_client.get_bucket('shared-bucket')

    def test_updating_data_on_a_collection(self):
        client = Client(server_url=self.server_url,
                        auth=self.auth,
                        bucket='mozilla',
                        collection='payments')
        client.create_bucket()
        client.create_collection()

        client.patch_collection(data={'secret': 'psssssst!'})
        collection = client.get_collection()
        assert collection['data']['secret'] == 'psssssst!'

    def test_collection_sharing(self):
        alice_credentials = ('alice', 'p4ssw0rd')
        alice_userid = self.get_user_id(alice_credentials)

        self.client.create_bucket('bob-bucket')
        self.client.create_collection('shared',
                                      bucket='bob-bucket',
                                      permissions={'read': [
                                          alice_userid,
                                      ]})

        # Try to read the collection as Alice.
        alice_client = Client(server_url=self.server_url,
                              auth=alice_credentials)
        alice_client.get_collection('shared', bucket='bob-bucket')

    def test_record_sharing(self):
        alice_credentials = ('alice', 'p4ssw0rd')
        alice_userid = self.get_user_id(alice_credentials)

        # Create a record, and share it with Alice.
        self.client.create_bucket('bob-bucket')
        self.client.create_collection('bob-personal-collection',
                                      bucket='bob-bucket')
        record = self.client.create_record(
            data={'foo': 'bar'},
            permissions={'read': [
                alice_userid,
            ]},
            bucket='bob-bucket',
            collection='bob-personal-collection')

        # Try to read the record as Alice
        alice_client = Client(server_url=self.server_url,
                              auth=alice_credentials)
        record = alice_client.get_record(id=record['data']['id'],
                                         bucket='bob-bucket',
                                         collection='bob-personal-collection')

        assert record['data']['foo'] == 'bar'

    def test_request_batching(self):
        with self.client.batch(bucket='mozilla', collection='fonts') as batch:
            batch.create_bucket()
            batch.create_collection()
            batch.create_record(data={'foo': 'bar'},
                                permissions={'read': ['natim']})
            batch.create_record(data={'bar': 'baz'},
                                permissions={'read': ['alexis']})

        records = self.client.get_records(bucket='mozilla', collection='fonts')
        assert len(records) == 2

    def test_replication(self):
        # First, create a few records on the first kinto collection.
        with self.client.batch(bucket='origin', collection='coll') as batch:
            batch.create_bucket()
            batch.create_collection()

            for n in range(10):
                batch.create_record(data={'foo': 'bar', 'n': n})

        origin = Client(server_url=self.server_url,
                        auth=self.auth,
                        bucket='origin',
                        collection='coll')
        destination = Client(server_url=self.server_url,
                             auth=self.auth,
                             bucket='destination',
                             collection='coll')

        replication.replicate(origin, destination)
        records = self.client.get_records(bucket='destination',
                                          collection='coll')
        assert len(records) == 10
Esempio n. 13
0
class FunctionalTest(unittest2.TestCase):
    def __init__(self, *args, **kwargs):
        super(FunctionalTest, self).__init__(*args, **kwargs)
        # XXX Read the configuration from env variables.
        self.server_url = SERVER_URL
        self.auth = DEFAULT_AUTH

        # Read the configuration.
        self.config = configparser.RawConfigParser()
        self.config.read(os.path.join(__HERE__, "config/kinto.ini"))
        self.client = Client(server_url=self.server_url, auth=self.auth)

    def tearDown(self):
        # Delete all the created objects
        flush_url = urljoin(self.server_url, "/__flush__")
        resp = requests.post(flush_url)
        resp.raise_for_status()

    def get_user_id(self, credentials):
        hmac_secret = self.config.get("app:main", "kinto.userid_hmac_secret")
        credentials = "%s:%s" % credentials
        digest = cliquet_utils.hmac_digest(hmac_secret, credentials)
        return "basicauth:%s" % digest

    def test_bucket_creation(self):
        bucket = self.client.create_bucket("mozilla")
        user_id = self.get_user_id(self.auth)
        assert user_id in bucket["permissions"]["write"]

    def test_bucket_creation_if_not_exists(self):
        self.client.create_bucket("mozilla")
        # Should not raise.
        self.client.create_bucket("mozilla", if_not_exists=True)

    def test_buckets_retrieval(self):
        self.client.create_bucket("mozilla")
        buckets = self.client.get_buckets()
        assert len(buckets) == 1

    def test_bucket_retrieval(self):
        self.client.create_bucket("mozilla")
        self.client.get_bucket("mozilla")
        # XXX Add permissions handling during creation and check they are
        # present during retrieval.

    def test_bucket_modification(self):
        bucket = self.client.create_bucket("mozilla", data={"version": 1})
        assert bucket["data"]["version"] == 1
        bucket = self.client.patch_bucket("mozilla", data={"author": "you"})
        assert bucket["data"]["version"] == 1
        assert bucket["data"]["author"] == "you"
        bucket = self.client.update_bucket("mozilla", data={"date": "today"})
        assert bucket["data"]["date"] == "today"
        assert "version" not in bucket["data"]

    def test_bucket_retrieval_fails_when_not_created(self):
        self.assertRaises(BucketNotFound, self.client.get_bucket, "non-existent")

    def test_bucket_deletion(self):
        self.client.create_bucket("mozilla")
        self.client.delete_bucket("mozilla")
        self.assertRaises(BucketNotFound, self.client.get_bucket, "mozilla")

    def test_buckets_deletion(self):
        self.client.create_bucket("mozilla")
        buckets = self.client.delete_buckets()
        assert buckets[0]["id"] == "mozilla"
        self.assertRaises(BucketNotFound, self.client.get_bucket, "mozilla")

    def test_bucket_save(self):
        self.client.create_bucket("mozilla", permissions={"write": ["alexis"]})
        bucket = self.client.get_bucket("mozilla")
        assert "alexis" in bucket["permissions"]["write"]

    def test_collection_creation(self):
        self.client.create_bucket("mozilla")
        self.client.create_collection("payments", bucket="mozilla", permissions={"write": ["alexis"]})

        # Test retrieval of a collection gets the permissions as well.
        collection = self.client.get_collection("payments", bucket="mozilla")
        assert "alexis" in collection["permissions"]["write"]

    def test_collection_creation_if_not_exists(self):
        self.client.create_bucket("mozilla")
        self.client.create_collection("payments", bucket="mozilla")
        # Should not raise.
        self.client.create_collection("payments", bucket="mozilla", if_not_exists=True)

    def test_collection_list(self):
        self.client.create_bucket("mozilla")
        self.client.create_collection("receipts", bucket="mozilla")
        self.client.create_collection("assets", bucket="mozilla")

        # The returned collections should be strings.
        collections = self.client.get_collections("mozilla")
        self.assertEquals(2, len(collections))

        self.assertEquals(set([coll["id"] for coll in collections]), set(["receipts", "assets"]))

    def test_collection_deletion(self):
        self.client.create_bucket("mozilla")
        self.client.create_collection("payments", bucket="mozilla")
        self.client.delete_collection("payments", bucket="mozilla")
        assert len(self.client.get_collections(bucket="mozilla")) == 0

    def test_collections_deletion(self):
        self.client.create_bucket("mozilla")
        self.client.create_collection("amo", bucket="mozilla")
        self.client.create_collection("blocklist", bucket="mozilla")
        self.client.delete_collections(bucket="mozilla")
        assert len(self.client.get_collections(bucket="mozilla")) == 0

    def test_record_creation_and_retrieval(self):
        client = Client(server_url=self.server_url, auth=self.auth, bucket="mozilla", collection="payments")
        client.create_bucket()
        client.create_collection()
        created = client.create_record(data={"foo": "bar"}, permissions={"read": ["alexis"]})
        record = client.get_record(created["data"]["id"])
        assert "alexis" in record["permissions"]["read"]

    def test_records_list_retrieval(self):
        client = Client(server_url=self.server_url, auth=self.auth, bucket="mozilla", collection="payments")
        client.create_bucket()
        client.create_collection()
        client.create_record(data={"foo": "bar"}, permissions={"read": ["alexis"]})
        records = client.get_records()
        assert len(records) == 1

    def test_records_paginated_list_retrieval(self):
        client = Client(server_url=self.server_url, auth=self.auth, bucket="mozilla", collection="payments")
        client.create_bucket()
        client.create_collection()
        for i in range(10):
            client.create_record(data={"foo": "bar"}, permissions={"read": ["alexis"]})
        # Kinto is running with kinto.paginate_by = 5
        records = client.get_records()
        assert len(records) == 10

    def test_single_record_save(self):
        client = Client(server_url=self.server_url, auth=self.auth, bucket="mozilla", collection="payments")
        client.create_bucket()
        client.create_collection()
        created = client.create_record(data={"foo": "bar"}, permissions={"read": ["alexis"]})
        created["data"]["bar"] = "baz"

        # XXX enhance this in order to have to pass only one argument, created.
        client.update_record(id=created["data"]["id"], data=created["data"])

        retrieved = client.get_record(created["data"]["id"])
        assert "alexis" in retrieved["permissions"]["read"]
        assert retrieved["data"]["foo"] == u"bar"
        assert retrieved["data"]["bar"] == u"baz"
        assert created["data"]["id"] == retrieved["data"]["id"]

    def test_single_record_doesnt_overwrite(self):
        client = Client(server_url=self.server_url, auth=self.auth, bucket="mozilla", collection="payments")
        client.create_bucket()
        client.create_collection()
        created = client.create_record(data={"foo": "bar"}, permissions={"read": ["alexis"]})

        with self.assertRaises(KintoException):
            # Create a second record with the ID of the first one.
            client.create_record(data={"id": created["data"]["id"], "bar": "baz"})

    def test_single_record_creation_if_not_exists(self):
        client = Client(server_url=self.server_url, auth=self.auth, bucket="mozilla", collection="payments")
        client.create_bucket()
        client.create_collection()
        created = client.create_record(data={"foo": "bar"})
        client.create_record(data={"id": created["data"]["id"], "bar": "baz"}, if_not_exists=True)

    def test_single_record_can_overwrite(self):
        client = Client(server_url=self.server_url, auth=self.auth, bucket="mozilla", collection="payments")
        client.create_bucket()
        client.create_collection()
        created = client.create_record(data={"foo": "bar"}, permissions={"read": ["alexis"]})

        client.create_record(data={"id": created["data"]["id"], "bar": "baz"}, safe=False)

    def test_one_record_deletion(self):
        client = Client(server_url=self.server_url, auth=self.auth, bucket="mozilla", collection="payments")
        client.create_bucket()
        client.create_collection()
        record = client.create_record({"foo": "bar"})
        deleted = client.delete_record(record["data"]["id"])
        assert deleted["deleted"] is True
        assert len(client.get_records()) == 0

    def test_multiple_record_deletion(self):
        client = Client(server_url=self.server_url, auth=self.auth, bucket="mozilla", collection="payments")
        client.create_bucket()
        client.create_collection()
        client.create_record({"foo": "bar"})
        client.delete_records()
        assert len(client.get_records()) == 0

    def test_bucket_sharing(self):
        alice_credentials = ("alice", "p4ssw0rd")
        alice_userid = self.get_user_id(alice_credentials)

        # Create a bucket and share it with alice.
        self.client.create_bucket("shared-bucket", permissions={"read": [alice_userid]})

        alice_client = Client(server_url=self.server_url, auth=alice_credentials)
        alice_client.get_bucket("shared-bucket")

    def test_updating_data_on_a_collection(self):
        client = Client(server_url=self.server_url, auth=self.auth, bucket="mozilla", collection="payments")
        client.create_bucket()
        client.create_collection()

        client.patch_collection(data={"secret": "psssssst!"})
        collection = client.get_collection()
        assert collection["data"]["secret"] == "psssssst!"

    def test_collection_sharing(self):
        alice_credentials = ("alice", "p4ssw0rd")
        alice_userid = self.get_user_id(alice_credentials)

        self.client.create_bucket("bob-bucket")
        self.client.create_collection("shared", bucket="bob-bucket", permissions={"read": [alice_userid]})

        # Try to read the collection as Alice.
        alice_client = Client(server_url=self.server_url, auth=alice_credentials)
        alice_client.get_collection("shared", bucket="bob-bucket")

    def test_record_sharing(self):
        alice_credentials = ("alice", "p4ssw0rd")
        alice_userid = self.get_user_id(alice_credentials)

        # Create a record, and share it with Alice.
        self.client.create_bucket("bob-bucket")
        self.client.create_collection("bob-personal-collection", bucket="bob-bucket")
        record = self.client.create_record(
            data={"foo": "bar"},
            permissions={"read": [alice_userid]},
            bucket="bob-bucket",
            collection="bob-personal-collection",
        )

        # Try to read the record as Alice
        alice_client = Client(server_url=self.server_url, auth=alice_credentials)
        record = alice_client.get_record(
            id=record["data"]["id"], bucket="bob-bucket", collection="bob-personal-collection"
        )

        assert record["data"]["foo"] == "bar"

    def test_request_batching(self):
        with self.client.batch(bucket="mozilla", collection="fonts") as batch:
            batch.create_bucket()
            batch.create_collection()
            batch.create_record(data={"foo": "bar"}, permissions={"read": ["natim"]})
            batch.create_record(data={"bar": "baz"}, permissions={"read": ["alexis"]})

        records = self.client.get_records(bucket="mozilla", collection="fonts")
        assert len(records) == 2

    def test_replication(self):
        # First, create a few records on the first kinto collection.
        with self.client.batch(bucket="origin", collection="coll") as batch:
            batch.create_bucket()
            batch.create_collection()

            for n in range(10):
                batch.create_record(data={"foo": "bar", "n": n})

        origin = Client(server_url=self.server_url, auth=self.auth, bucket="origin", collection="coll")
        destination = Client(server_url=self.server_url, auth=self.auth, bucket="destination", collection="coll")

        replication.replicate(origin, destination)
        records = self.client.get_records(bucket="destination", collection="coll")
        assert len(records) == 10