def test_put_doc(self): self.response_val = {"rev": "doc-rev"}, {} doc = Document("doc-id", None, '{"v": 1}') res = self.db.put_doc(doc) self.assertEqual("doc-rev", res) self.assertEqual("doc-rev", doc.rev) self.assertEqual(("PUT", ["doc", "doc-id"], {}, '{"v": 1}', "application/json"), self.got) self.response_val = {"rev": "doc-rev-2"}, {} doc.content = {"v": 2} res = self.db.put_doc(doc) self.assertEqual("doc-rev-2", res) self.assertEqual("doc-rev-2", doc.rev) self.assertEqual(("PUT", ["doc", "doc-id"], {"old_rev": "doc-rev"}, '{"v": 2}', "application/json"), self.got)
def _parse_sync_stream(self, data, return_doc_cb): parts = data.splitlines() # one at a time if not parts or parts[0] != '[': raise BrokenSyncStream data = parts[1:-1] if data: line, comma = utils.check_and_strip_comma(data[0]) res = simplejson.loads(line) for entry in data[1:]: if not comma: # missing in between comma raise BrokenSyncStream line, comma = utils.check_and_strip_comma(entry) entry = simplejson.loads(line) doc = Document(entry['id'], entry['rev'], entry['content']) return_doc_cb(doc, entry['gen'], entry['trans_id']) if parts[-1] != ']': try: partdic = simplejson.loads(parts[-1]) except ValueError: pass else: if isinstance(partdic, dict): self._error(partdic) raise BrokenSyncStream if comma: # bad extra comma raise BrokenSyncStream return res
def post_put(self, id, rev, content, gen, trans_id, number_of_docs, doc_idx): """ Put one incoming document into the server replica. :param id: The id of the incoming document. :type id: str :param rev: The revision of the incoming document. :type rev: str :param content: The content of the incoming document. :type content: dict :param gen: The source replica generation corresponding to the revision of the incoming document. :type gen: int :param trans_id: The source replica transaction id corresponding to the revision of the incoming document. :type trans_id: str :param number_of_docs: The total amount of documents sent on this sync session. :type number_of_docs: int :param doc_idx: The index of the current document. :type doc_idx: int """ doc = Document(id, rev, content) self.sync_exch.insert_doc_from_source(doc, gen, trans_id, number_of_docs=number_of_docs, doc_idx=doc_idx, sync_id=self._sync_id)
def test_put_doc(self): self.response_val = {'rev': 'doc-rev'}, {} doc = Document('doc-id', None, '{"v": 1}') res = self.db.put_doc(doc) self.assertEqual('doc-rev', res) self.assertEqual('doc-rev', doc.rev) self.assertEqual(('PUT', ['doc', 'doc-id'], {}, '{"v": 1}', 'application/json'), self.got) self.response_val = {'rev': 'doc-rev-2'}, {} doc.content = {"v": 2} res = self.db.put_doc(doc) self.assertEqual('doc-rev-2', res) self.assertEqual('doc-rev-2', doc.rev) self.assertEqual(('PUT', ['doc', 'doc-id'], {'old_rev': 'doc-rev'}, '{"v": 2}', 'application/json'), self.got)
def test_delete_doc(self): self.response_val = {'rev': 'doc-rev-gone'}, {} doc = Document('doc-id', 'doc-rev', None) self.db.delete_doc(doc) self.assertEqual('doc-rev-gone', doc.rev) self.assertEqual(('DELETE', ['doc', 'doc-id'], {'old_rev': 'doc-rev'}, None, None), self.got)
def _parse_sync_stream(self, data, return_doc_cb, ensure_callback=None): parts = data.splitlines() # one at a time if not parts or parts[0] != '[': raise BrokenSyncStream data = parts[1:-1] comma = False if data: line, comma = utils.check_and_strip_comma(data[0]) res = json.loads(line) if ensure_callback and 'replica_uid' in res: ensure_callback(res['replica_uid']) for entry in data[1:]: if not comma: # missing in between comma raise BrokenSyncStream line, comma = utils.check_and_strip_comma(entry) entry = json.loads(line) doc = Document(entry['id'], entry['rev'], entry['content']) return_doc_cb(doc, entry['gen'], entry['trans_id']) if parts[-1] != ']': try: partdic = json.loads(parts[-1]) except ValueError: pass else: if isinstance(partdic, dict): self._error(partdic) raise BrokenSyncStream if not data or comma: # no entries or bad extra comma raise BrokenSyncStream return res
def put(self, content, old_rev=None): doc = Document(self.id, old_rev, content) doc_rev = self.db.put_doc(doc) if old_rev is None: status = 201 # created else: status = 200 self.responder.send_response_json(status, rev=doc_rev)
def test_doc_ids_needing_quoting(self): db0 = self.request_state._create_database('db0') db = http_database.HTTPDatabase.open_database(self.getURL('db0'), create=False) doc = Document('%fff', None, '{}') db.put_doc(doc) self.assertGetDoc(db0, '%fff', doc.rev, '{}', False) self.assertGetDoc(db, '%fff', doc.rev, '{}', False)
def test_cmp_to_pydoc_not_equal_conflicts(self): cdoc = self.make_document('doc-id', 'uid:1', tests.simple_doc) pydoc = Document('doc-id', 'uid:1', tests.simple_doc, has_conflicts=True) self.assertNotEqual(cdoc, pydoc) self.assertNotEqual(pydoc, cdoc)
def __init__(self, doc_id=None, rev=None, json='{}', has_conflicts=False, syncable=True): """ Container for handling an encryptable document. @param doc_id: The unique document identifier. @type doc_id: str @param rev: The revision identifier of the document. @type rev: str @param json: The JSON string for this document. @type json: str @param has_conflicts: Boolean indicating if this document has conflicts @type has_conflicts: bool @param syncable: Should this document be synced with remote replicas? @type syncable: bool """ Document.__init__(self, doc_id, rev, json, has_conflicts) self._syncable = syncable
def _prune_conflicts(self, doc, doc_vcr): if self._has_conflicts(doc.doc_id): autoresolved = False remaining_conflicts = [] cur_conflicts = self._conflicts[doc.doc_id] for c_rev, c_doc in cur_conflicts: c_vcr = vectorclock.VectorClockRev(c_rev) if doc_vcr.is_newer(c_vcr): continue if doc.same_content_as(Document(doc.doc_id, c_rev, c_doc)): doc_vcr.maximize(c_vcr) autoresolved = True continue remaining_conflicts.append((c_rev, c_doc)) if autoresolved: doc_vcr.increment(self._replica_uid) doc.rev = doc_vcr.as_str() self._replace_conflicts(doc, remaining_conflicts)
def run(self, database, doc_id, doc_rev, infile): if infile is None: infile = self.stdin try: db = self._open(database, create=False) doc = Document(doc_id, doc_rev, infile.read()) doc_rev = db.put_doc(doc) self.stderr.write('rev: %s\n' % (doc_rev, )) except errors.DatabaseDoesNotExist: self.stderr.write("Database does not exist.\n") except errors.RevisionConflict: if db.get_doc(doc_id) is None: self.stderr.write("Document does not exist.\n") else: self.stderr.write("Given revision is not current.\n") except errors.ConflictedDoc: self.stderr.write( "Document has conflicts.\n" "Inspect with get-doc-conflicts, then resolve.\n") else: return return 1
def test_cmp_to_pydoc_not_equal_content(self): cdoc = self.make_document('doc-id', 'uid:1', tests.simple_doc) pydoc = Document('doc-id', 'uid:1', tests.nested_doc) self.assertNotEqual(cdoc, pydoc) self.assertNotEqual(pydoc, cdoc)
def create_doc(doc_id, rev, content, has_conflicts=False): return Document(doc_id, rev, content, has_conflicts=has_conflicts)
def make_document_for_test(test, doc_id, rev, content, has_conflicts=False): return Document(doc_id, rev, content, has_conflicts=has_conflicts)
def make_document(self, doc_id, doc_rev, content, has_conflicts): return Document(doc_id, doc_rev, content, has_conflicts)
def delete(self, old_rev=None): doc = Document(self.id, old_rev, None) self.db.delete_doc(doc) self.responder.send_response_json(200, rev=doc.rev)
def run(self, database, doc_id, doc_rev): db = self._open(database, create=False) doc = Document(doc_id, doc_rev, None) db.delete_doc(doc) self.stderr.write('rev: %s\n' % (doc.rev, ))
def post_stream_entry(self, id, rev, content, gen, trans_id): doc = Document(id, rev, content) self.sync_exch.insert_doc_from_source(doc, gen, trans_id)
def assertPyDocEqualCDoc(self, *args, **kwargs): cdoc = self.make_document(*args, **kwargs) pydoc = Document(*args, **kwargs) self.assertEqual(pydoc, cdoc) self.assertEqual(cdoc, pydoc)