def test_update_field_maxretries(self, m_save): """ Test that conflict retries work for updating a single field. """ # Create a doc doc = Document(self.db, 'julia006') doc['name'] = 'julia' doc['age'] = 6 doc.create() self.assertTrue(doc['_rev'].startswith('1-')) self.assertEqual(doc['age'], 6) # Mock conflicts when saving updates m_save.side_effect = requests.HTTPError( response=mock.Mock(status_code=409, reason='conflict')) # Tests that failing on retry eventually throws with self.assertRaises(requests.HTTPError) as cm: doc.update_field(doc.field_set, 'age', 7, max_tries=2) # There is an off-by-one error for "max_tries" # It really means max_retries i.e. 1 attempt # followed by a max of 2 retries self.assertEqual(m_save.call_count, 3) self.assertEqual(cm.exception.response.status_code, 409) self.assertEqual(cm.exception.response.reason, 'conflict') # Fetch again before asserting, otherwise we assert against # the locally updated age field doc.fetch() self.assertFalse(doc['_rev'].startswith('2-')) self.assertNotEqual(doc['age'], 7)
def test_update_field_success_on_retry(self): """ Test that conflict retries work for updating a single field. """ # Create a doc doc = Document(self.db, 'julia006') doc['name'] = 'julia' doc['age'] = 6 doc.create() self.assertTrue(doc['_rev'].startswith('1-')) self.assertEqual(doc['age'], 6) # Mock when saving the document # 1st call throw a 409 # 2nd call delegate to the real doc.save() with mock.patch('cloudant.document.Document.save', side_effect=[ requests.HTTPError(response=mock.Mock( status_code=409, reason='conflict')), doc.save() ]) as m_save: # A list of side effects containing only 1 element doc.update_field(doc.field_set, 'age', 7, max_tries=1) # Two calls to save, one with a 409 and one that succeeds self.assertEqual(m_save.call_count, 2) # Check that the _rev and age field were updated self.assertTrue(doc['_rev'].startswith('2-')) self.assertEqual(doc['age'], 7)
def test_document_exists(self): """ Test whether a document exists remotely """ doc = Document(self.db) self.assertFalse(doc.exists()) doc['_id'] = 'julia006' self.assertFalse(doc.exists()) doc.create() self.assertTrue(doc.exists())
def test_create_existing_document(self): """ Test creating an already existing document """ doc = Document(self.db, 'julia006') doc.create() with self.assertRaises(requests.HTTPError) as cm: doc.create() err = cm.exception self.assertEqual(err.response.status_code, 409)
def test_document_exists(self): """ Tests that the result of True is expected when the document exists, and False is expected when the document is nonexistent remotely. """ doc = Document(self.db) self.assertFalse(doc.exists()) doc['_id'] = 'julia006' self.assertFalse(doc.exists()) doc.create() self.assertTrue(doc.exists())
def test_fetch_existing_document_with_docid(self): """ Test fetching document content from an existing document """ doc = Document(self.db, 'julia006') doc['name'] = 'julia' doc['age'] = 6 doc.create() new_doc = Document(self.db, 'julia006') new_doc.fetch() self.assertEqual(new_doc, doc)
def test_create_existing_document(self): """ Test creating an already existing document """ doc = Document(self.db, 'julia006') doc.create() try: doc.create() self.fail('Above statement should raise an Exception') except requests.HTTPError as err: self.assertEqual(err.response.status_code, 409)
def test_create_document_with_docid(self): """ Test creating a document providing an id """ doc = Document(self.db, 'julia006') doc['name'] = 'julia' doc['age'] = 6 self.assertFalse(doc.exists()) self.assertIsNone(doc.get('_rev')) doc.create() self.assertTrue(doc.exists()) self.assertTrue(doc.get('_rev').startswith('1-'))
def test_fetch_existing_document_with_docid_encoded_url(self): """ Test fetching document content from an existing document where the document id requires an encoded url """ doc = Document(self.db, 'http://example.com') doc['name'] = 'julia' doc['age'] = 6 doc.create() new_doc = Document(self.db, 'http://example.com') new_doc.fetch() self.assertEqual(new_doc, doc)
def test_create_document_with_docid_encoded_url(self): """ Test creating a document providing an id that has an encoded url """ doc = Document(self.db, 'http://example.com') doc['name'] = 'julia' doc['age'] = 6 self.assertFalse(doc.exists()) self.assertIsNone(doc.get('_rev')) doc.create() self.assertTrue(doc.exists()) self.assertTrue(doc.get('_rev').startswith('1-'))
def test_create_existing_document(self): """ Test creating an already existing document """ doc = Document(self.db, 'julia006') doc.create() with self.assertRaises(requests.HTTPError) as cm: doc.create() err = cm.exception self.assertEqual( err.response.status_code, 409 )
def post(self): body = load_body(scrap_schema) db = get_scraps_db() doc = Document(db) data = scrap_schema.dump(body).data body = data.pop('body') content_type = data.pop('content_type') doc.update(**data) doc.create() doc.put_attachment('body', content_type, body) return doc
def test_delete_document_success(self): """ Test that we can remove a document from the remote database successfully. """ doc = Document(self.db, 'julia006') doc['name'] = 'julia' doc['age'] = 6 doc['pets'] = ['cat', 'dog'] doc.create() self.assertTrue(doc.exists()) doc.delete() self.assertFalse(doc.exists()) self.assertEqual(doc, {'_id': 'julia006'})
def test_delete_document_success_with_encoded_url(self): """ Test that we can remove a document from the remote database successfully when the document id requires an encoded url. """ doc = Document(self.db, 'http://example.com') doc['name'] = 'julia' doc['age'] = 6 doc['pets'] = ['cat', 'dog'] doc.create() self.assertTrue(doc.exists()) doc.delete() self.assertFalse(doc.exists()) self.assertEqual(doc, {'_id': 'http://example.com'})
def test_update_field(self): """ Test that we can update a single field remotely using the update_field method. """ doc = Document(self.db, 'julia006') doc['name'] = 'julia' doc['age'] = 6 doc['pets'] = ['cat', 'dog'] doc.create() self.assertTrue(doc['_rev'].startswith('1-')) self.assertEqual(doc['pets'], ['cat', 'dog']) doc.update_field(doc.list_field_append, 'pets', 'fish') self.assertTrue(doc['_rev'].startswith('2-')) self.assertEqual(doc['pets'], ['cat', 'dog', 'fish'])
def test_document_context_manager(self): """ Test that the __enter__ and __exit__ methods perform as expected when initiated through a document context manager. """ new_doc = Document(self.db, 'julia006') new_doc.create() self.assertTrue(new_doc.exists()) del new_doc with Document(self.db, 'julia006') as doc: self.assertTrue(all(x in list(doc.keys()) for x in ['_id', '_rev'])) self.assertTrue(doc['_rev'].startswith('1-')) doc['name'] = 'julia' doc['age'] = 6 self.assertTrue(doc['_rev'].startswith('2-')) self.assertEqual(self.db['julia006'], doc)
def test_document_crud(self): """test basic crud operations with mocked backend""" doc = Document(self.database, "DUCKUMENT") # exists mock_resp = mock.Mock() mock_resp.status_code = 200 self.mock_session.get.return_value = mock_resp self.assertTrue(doc.exists()) self.assertTrue(self.mock_session.get.called) self.mock_session.get.assert_has_calls( [ mock.call('https://bob.cloudant.com/unittest/DUCKUMENT') ] ) self.mock_session.get.reset_mock() # create mock_resp = mock.Mock() mock_resp.raise_for_status = mock.Mock() mock_resp.status_code = 200 mock_resp.json = mock.Mock() mock_resp.json.return_value = {'id': 'DUCKUMENT', 'rev': 'DUCK2'} self.mock_session.post.return_value = mock_resp doc.create() self.assertEqual(doc['_rev'], 'DUCK2') self.assertEqual(doc['_id'], 'DUCKUMENT') self.assertTrue(self.mock_session.post.called) self.mock_session.post.reset_mock() # fetch mock_resp = mock.Mock() mock_resp.status_code = 200 mock_resp.raise_for_status = mock.Mock() mock_resp.json = mock.Mock() mock_resp.json.return_value = { '_id': 'DUCKUMENT', '_rev': 'DUCK2', 'herp': 'HERP', 'derp': 'DERP' } self.mock_session.get.return_value = mock_resp doc.fetch() self.assertTrue('herp' in doc) self.assertTrue('derp' in doc) self.assertEqual(doc['herp'], 'HERP') self.assertEqual(doc['derp'], 'DERP') self.assertTrue(self.mock_session.get.called) self.mock_session.get.assert_has_calls( [ mock.call('https://bob.cloudant.com/unittest/DUCKUMENT') ] ) self.mock_session.get.reset_mock() # save mock_put_resp = mock.Mock() mock_put_resp.status_code = 200 mock_put_resp.raise_for_status = mock.Mock() mock_put_resp.json = mock.Mock() mock_put_resp.json.return_value = {'id': 'DUCKUMENT', 'rev': 'DUCK3'} self.mock_session.put.return_value = mock_put_resp mock_get_resp = mock.Mock() mock_get_resp.status_code = 200 self.mock_session.get.return_value = mock_get_resp doc.save() self.assertEqual(doc['_rev'], 'DUCK3') self.assertEqual(doc['_id'], 'DUCKUMENT') self.assertTrue(self.mock_session.get.called) self.assertTrue(self.mock_session.put.called) self.mock_session.get.assert_has_calls( [ mock.call('https://bob.cloudant.com/unittest/DUCKUMENT') ] ) self.mock_session.put.assert_has_calls( [ mock.call( 'https://bob.cloudant.com/unittest/DUCKUMENT', headers={'Content-Type': 'application/json'}, data=mock.ANY ) ] ) self.mock_session.get.reset_mock() self.mock_session.put.reset_mock() # delete mock_resp = mock.Mock() mock_resp.status_code = 200 mock_resp.raise_for_status = mock.Mock() self.mock_session.delete.return_value = mock_resp doc.delete() self.assertTrue(self.mock_session.delete.called) self.mock_session.delete.assert_has_calls( [ mock.call( 'https://bob.cloudant.com/unittest/DUCKUMENT', params={'rev': 'DUCK3'} ) ] ) self.mock_session.delete.reset_mock() # test delete with no rev explodes as expected self.assertRaises(CloudantException, doc.delete)