def test_rewrite_rule(self): """ Test that design document URL is rewritten to the expected test document. """ ddoc = DesignDocument(self.db, '_design/ddoc001') ddoc['rewrites'] = [ {"from": "", "to": "/../../rewrite_doc", "method": "GET", "query": {} } ] self.assertIsInstance(ddoc.rewrites, list) self.assertIsInstance(ddoc.rewrites[0], dict) ddoc.save() doc = Document(self.db, 'rewrite_doc') doc.save() resp = self.client.r_session.get('/'.join([ddoc.document_url, '_rewrite'])) self.assertEquals( resp.json(), { '_id': 'rewrite_doc', '_rev': doc['_rev'] } )
def test_appended_error_message_using_save_with_invalid_key(self): """ Test that saving a document with an invalid remote key will throw an HTTPError with additional error details from util method append_response_error_content. """ # First create the document doc = Document(self.db, 'julia006') # Add an invalid key and try to save document doc['_invalid_key'] = 'jules' with self.assertRaises(requests.HTTPError) as cm: doc.save() err = cm.exception # Should be a 400 error code, but CouchDB 1.6 issues a 500 if err.response.status_code == 500: # Check this is CouchDB 1.x self.assertTrue(self.client.r_session.head(self.url).headers['Server'].find('CouchDB/1.') >= 0, '500 returned but was not CouchDB 1.x') self.assertEqual( str(err.response.reason), 'Internal Server Error doc_validation Bad special document member: _invalid_key' ) else: self.assertEqual( str(err.response.reason), 'Bad Request doc_validation Bad special document member: _invalid_key' ) self.assertEqual( err.response.status_code, 400 )
def test_appended_error_message_using_save_with_invalid_key(self): """ Test that saving a document with an invalid remote key will throw an HTTPError with additional error details from util method append_response_error_content. """ # First create the document doc = Document(self.db, 'julia006') # Add an invalid key and try to save document doc['_invalid_key'] = 'jules' with self.assertRaises(requests.HTTPError) as cm: doc.save() err = cm.exception # Should be a 400 error code, but CouchDB 1.6 issues a 500 if err.response.status_code == 500: #Check this is CouchDB 1.6 self.assertTrue(self.client.r_session.head(self.url).headers['Server'].find('CouchDB/1.6.') >= 0, '500 returned but was not CouchDB 1.6.x') self.assertEqual( str(err.response.reason), 'Internal Server Error doc_validation Bad special document member: _invalid_key' ) else: self.assertEqual( str(err.response.reason), 'Bad Request doc_validation Bad special document member: _invalid_key' ) self.assertEqual( err.response.status_code, 400 )
def new_transaction_doc(self, symbol, quantity, price, fee, action): xactiondoc = Document(self.db) xactiondoc['type'] = 'transaction' xactiondoc['action'] = action xactiondoc['quantity'] = quantity xactiondoc['date'] = strftime("%Y-%m-%d %H:%M:%S") xactiondoc['fee'] = fee xactiondoc['price'] = price if action == 'deposit' or action == 'withdrawl': xactiondoc['symbol'] = 'Cash' xactiondoc['price'] = 1 else: #otherwise use symbol passed and check to see if updating cash is needed xactiondoc['symbol'] = symbol xactiondoc.save()
def test_create_document_using_save(self): """ Test that save functionality works. If a document does not exist remotely then create it. """ doc = Document(self.db, 'julia006') doc['name'] = 'julia' doc['age'] = 6 self.assertIsNone(doc.get('_rev')) doc.save() self.assertTrue(doc.exists()) self.assertTrue(doc['_rev'].startswith('1-')) remote_doc = Document(self.db, 'julia006') remote_doc.fetch() self.assertEqual(remote_doc, doc)
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_request_fails_after_client_disconnects(self): """ Test that after disconnecting from a client any objects created based on that client are not able to make requests. """ self.client.connect() doc = Document(self.db, 'julia001') doc.save() self.client.disconnect() try: with self.assertRaises(AttributeError): doc.fetch() self.assertIsNone(doc.r_session) finally: self.client.connect()
def test_update_document_with_encoded_url(self): """ Test that updating a document where the document id requires that the document url be encoded is successful. """ # First create the document doc = Document(self.db, 'http://example.com') doc['name'] = 'julia' doc['age'] = 6 doc.save() # Now test that the document gets updated doc['name'] = 'jules' doc.save() self.assertTrue(doc['_rev'].startswith('2-')) remote_doc = Document(self.db, 'http://example.com') remote_doc.fetch() self.assertEqual(remote_doc, doc) self.assertEqual(remote_doc['name'], 'jules')
def test_update_document_using_save(self): """ Test that save functionality works. If a document exists remotely then update it. """ # First create the document doc = Document(self.db, 'julia006') doc['name'] = 'julia' doc['age'] = 6 doc.save() # Now test that the document gets updated doc['name'] = 'jules' doc.save() self.assertTrue(doc['_rev'].startswith('2-')) remote_doc = Document(self.db, 'julia006') remote_doc.fetch() self.assertEqual(remote_doc, doc) self.assertEqual(remote_doc['name'], 'jules')
def checkToken(token): if token == 'test': return 'test' if token == None: return None tokendb = crecli()['token'] tokendoc = Document(tokendb, token) if not tokendoc.exists(): return None if tokendb[token]['time'] > str(datetime.datetime.now() - datetime.timedelta( seconds=7)).split('.')[0]: tokendoc = tokendb[token] tokendoc['time'] = str(datetime.datetime.now()).split('.')[0] tokendoc.save() return tokendoc['name'] else: return None
def test_appended_error_message_using_save_with_invalid_key(self): """ Test that saving a document with an invalid remote key will throw an HTTPError with additional error details from util method append_response_error_content. """ # First create the document doc = Document(self.db, 'julia006') # Add an invalid key and try to save document doc['_invalid_key'] = 'jules' with self.assertRaises(requests.HTTPError) as cm: doc.save() err = cm.exception self.assertEqual( str(err.response.reason), 'Internal Server Error doc_validation Bad special document member: _invalid_key' ) self.assertEqual(err.response.status_code, 500)
def test_save_non_exists(self): """cover save case where doc doesnt exist""" mock_resp = mock.Mock() mock_resp.status_code = 404 self.mock_session.get.return_value = mock_resp mock_post = mock.Mock() mock_post.raise_for_status = mock.Mock() mock_post.json = mock.Mock() mock_post.json.return_value = {'id': "created", "rev": "created"} mock_put = mock.Mock() mock_put.raise_for_status = mock.Mock() self.mock_session.post.return_value = mock_post self.mock_session.put.return_value = mock_put doc = Document(self.database, "DUCKUMENT") doc.save() self.assertEqual(doc['_id'], "created") self.assertEqual(doc['_rev'], "created")
def test_document_custom_json_encoder_and_decoder(self): dt_format = '%Y-%m-%dT%H:%M:%S' class DTEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, datetime): return { '_type': 'datetime', 'value': obj.strftime(dt_format) } return super(DTEncoder, self).default(obj) class DTDecoder(json.JSONDecoder): def __init__(self, *args, **kwargs): json.JSONDecoder.__init__(self, object_hook=self.object_hook, *args, **kwargs) def object_hook(self, obj): if '_type' not in obj: return obj if obj['_type'] == 'datetime': return datetime.strptime(obj['value'], dt_format) return obj doc = Document(self.db, encoder=DTEncoder) doc['name'] = 'julia' doc['dt'] = datetime(2018, 7, 9, 15, 11, 10, 0) doc.save() raw_doc = self.db.all_docs(include_docs=True)['rows'][0]['doc'] self.assertEqual(raw_doc['name'], 'julia') self.assertEqual(raw_doc['dt']['_type'], 'datetime') self.assertEqual(raw_doc['dt']['value'], '2018-07-09T15:11:10') doc2 = Document(self.db, doc['_id'], decoder=DTDecoder) doc2.fetch() self.assertEqual(doc2['dt'], doc['dt'])
def test_document_context_manager_update_failure_on_error(self): """ Test that the document context manager skips document update if there is an error. """ # Create the document. doc = Document(self.db, 'julia006') doc['name'] = 'julia' doc['age'] = 6 doc.save() # Make a document update and then raise an error. with self.assertRaises(ZeroDivisionError), Document( self.db, 'julia006') as doc: doc['age'] = 7 raise ZeroDivisionError() # Assert the change persists locally. self.assertEqual(doc['age'], 7) # Assert the document has not been saved to remote server. self.assertTrue(doc['_rev'].startswith('1-')) self.assertEqual(self.db['julia006']['age'], 6)
# print(row) # db.create_document(row) # data = pd.read_csv('./resources/years.csv', encoding='windows-1255') # # data_json = json.loads(data.to_json(orient='records')) # # for row in data_json: # for key, value in row.items(): # if key=='plot' or value is None: # continue # newRow = {} # newRow['plot']=row['plot'] # newRow['year']=int(key) # newRow['crop']=value # newRow['type']='years' # #print (newRow) # db.create_document(newRow) species = getSpecies(db)['docs'] # Retrieve documents where the name field is 'foo' selector = {'type': {'$eq': 'species'}} docs = db.get_query_result(selector) for doc in docs: # Create Document object from dict updated_doc = Document(db, doc['_id']) print(updated_doc) updated_doc['_id'] = doc['Variety'] updated_doc.save() print(updated_doc)
def save_doc(self, doc: Document, key, value): doc.fetch() doc['key'] = key doc['value'] = value doc.save()
def save_doc(self, doc, encode_attachments=True, force_update=False, **params): """ Save a document. It will use the `_id` member of the document or request a new uuid from CouchDB. IDs are attached to documents on the client side because POST has the curious property of being automatically retried by proxies in the event of network segmentation and lost responses. (Idee from `Couchrest <http://github.com/jchris/couchrest/>`) @param doc: dict. doc is updated with doc '_id' and '_rev' properties returned by CouchDB server when you save. @param force_update: boolean, if there is conlict, try to update with latest revision @param params, list of optionnal params, like batch="ok" @return res: result of save. doc is updated in the mean time """ if doc is None: doc1 = {} else: doc1, schema = _maybe_serialize(doc) if '_attachments' in doc1 and encode_attachments: doc1['_attachments'] = resource.encode_attachments(doc['_attachments']) if '_id' in doc1: docid = doc1['_id'] if six.PY3 else doc1['_id'].encode('utf-8') couch_doc = Document(self.cloudant_database, docid) couch_doc.update(doc1) try: # Copied from Document.save to ensure that a deleted doc cannot be saved. headers = {} headers.setdefault('Content-Type', 'application/json') put_resp = couch_doc.r_session.put( couch_doc.document_url, data=couch_doc.json(), headers=headers ) put_resp.raise_for_status() data = put_resp.json() super(Document, couch_doc).__setitem__('_rev', data['rev']) except HTTPError as e: if e.response.status_code != 409: raise if force_update: couch_doc['_rev'] = self.get_rev(docid) couch_doc.save() else: raise ResourceConflict res = couch_doc else: res = self.cloudant_database.create_document(doc1) if 'batch' in params and ('id' in res or '_id' in res): doc1.update({ '_id': res.get('_id')}) else: doc1.update({'_id': res.get('_id'), '_rev': res.get('_rev')}) if schema: for key, value in six.iteritems(doc.__class__.wrap(doc1)): doc[key] = value else: doc.update(doc1) return { 'id': res['_id'], 'rev': res['_rev'], 'ok': True, }
def save_doc(self, doc, encode_attachments=True, force_update=False, **params): """ Save a document. It will use the `_id` member of the document or request a new uuid from CouchDB. IDs are attached to documents on the client side because POST has the curious property of being automatically retried by proxies in the event of network segmentation and lost responses. (Idee from `Couchrest <http://github.com/jchris/couchrest/>`) @param doc: dict. doc is updated with doc '_id' and '_rev' properties returned by CouchDB server when you save. @param force_update: boolean, if there is conlict, try to update with latest revision @param params, list of optionnal params, like batch="ok" @return res: result of save. doc is updated in the mean time """ if doc is None: doc1 = {} else: doc1, schema = _maybe_serialize(doc) if '_attachments' in doc1 and encode_attachments: doc1['_attachments'] = resource.encode_attachments( doc['_attachments']) if '_id' in doc1: docid = doc1['_id'] if six.PY3 else doc1['_id'].encode('utf-8') couch_doc = Document(self.cloudant_database, docid) couch_doc.update(doc1) try: # Copied from Document.save to ensure that a deleted doc cannot be saved. headers = {} headers.setdefault('Content-Type', 'application/json') put_resp = couch_doc.r_session.put(couch_doc.document_url, data=couch_doc.json(), headers=headers) put_resp.raise_for_status() data = put_resp.json() super(Document, couch_doc).__setitem__('_rev', data['rev']) except HTTPError as e: if e.response.status_code != 409: raise if force_update: couch_doc['_rev'] = self.get_rev(docid) couch_doc.save() else: raise ResourceConflict res = couch_doc else: res = self.cloudant_database.create_document(doc1) if 'batch' in params and ('id' in res or '_id' in res): doc1.update({'_id': res.get('_id')}) else: doc1.update({'_id': res.get('_id'), '_rev': res.get('_rev')}) if schema: for key, value in six.iteritems(doc.__class__.wrap(doc1)): doc[key] = value else: doc.update(doc1) return { 'id': res['_id'], 'rev': res['_rev'], 'ok': True, }
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)