示例#1
0
    def test_sync_autoresolves(self):
        """
        Test for sync autoresolve remote.

        This test was adapted because the remote database receives encrypted
        content and so it can't compare documents contents to autoresolve.
        """
        # The remote database can't autoresolve conflicts based on magic
        # content convergence, so we modify this test to leave the possibility
        # of the remode document ending up in conflicted state.
        self.db1 = self.create_database('test1', 'source')
        self.db2 = self.create_database('test2', 'target')
        doc1 = self.db1.create_doc_from_json(tests.simple_doc, doc_id='doc')
        rev1 = doc1.rev
        doc2 = self.db2.create_doc_from_json(tests.simple_doc, doc_id='doc')
        rev2 = doc2.rev
        self.sync(self.db1, self.db2)
        doc = self.db1.get_doc('doc')
        self.assertFalse(doc.has_conflicts)
        # if remote content is in conflicted state, then document revisions
        # will be different.
        #self.assertEqual(doc.rev, self.db2.get_doc('doc').rev)
        v = vectorclock.VectorClockRev(doc.rev)
        self.assertTrue(v.is_newer(vectorclock.VectorClockRev(rev1)))
        self.assertTrue(v.is_newer(vectorclock.VectorClockRev(rev2)))
示例#2
0
 def test_sync_autoresolves_moar(self):
     # here we test that when a database that has a conflicted document is
     # the source of a sync, and the target database has a revision of the
     # conflicted document that is newer than the source database's, and
     # that target's database's document's content is the same as the
     # source's document's conflict's, the source's document's conflict gets
     # autoresolved, and the source's document's revision bumped.
     #
     # idea is as follows:
     # A          B
     # a1         -
     #   `------->
     # a1         a1
     # v          v
     # a2         a1b1
     #   `------->
     # a1b1+a2    a1b1
     #            v
     # a1b1+a2    a1b2 (a1b2 has same content as a2)
     #   `------->
     # a3b2       a1b2 (autoresolved)
     #   `------->
     # a3b2       a3b2
     self.db1.create_doc(simple_doc, doc_id='doc')
     self.sync(self.db1, self.db2)
     for db, content in [(self.db1, '{}'), (self.db2, '{"hi": 42}')]:
         doc = db.get_doc('doc')
         doc.set_json(content)
         db.put_doc(doc)
     self.sync(self.db1, self.db2)
     # db1 and db2 now both have a doc of {hi:42}, but db1 has a conflict
     doc = self.db1.get_doc('doc')
     rev1 = doc.rev
     self.assertTrue(doc.has_conflicts)
     # set db2 to have a doc of {} (same as db1 before the conflict)
     doc = self.db2.get_doc('doc')
     doc.set_json('{}')
     self.db2.put_doc(doc)
     rev2 = doc.rev
     # sync it across
     self.sync(self.db1, self.db2)
     # tadaa!
     doc = self.db1.get_doc('doc')
     self.assertFalse(doc.has_conflicts)
     vec1 = vectorclock.VectorClockRev(rev1)
     vec2 = vectorclock.VectorClockRev(rev2)
     vec3 = vectorclock.VectorClockRev(doc.rev)
     self.assertTrue(vec3.is_newer(vec1))
     self.assertTrue(vec3.is_newer(vec2))
     # because the conflict is on the source, sync it another time
     self.sync(self.db1, self.db2)
     # make sure db2 now has the exact same thing
     self.assertEqual(self.db1.get_doc('doc'), self.db2.get_doc('doc'))
示例#3
0
 def test_sync_autoresolves(self):
     doc1 = self.db1.create_doc(simple_doc, doc_id='doc')
     rev1 = doc1.rev
     doc2 = self.db2.create_doc(simple_doc, doc_id='doc')
     rev2 = doc2.rev
     self.sync(self.db1, self.db2)
     doc = self.db1.get_doc('doc')
     self.assertFalse(doc.has_conflicts)
     self.assertEqual(doc.rev, self.db2.get_doc('doc').rev)
     v = vectorclock.VectorClockRev(doc.rev)
     self.assertTrue(v.is_newer(vectorclock.VectorClockRev(rev1)))
     self.assertTrue(v.is_newer(vectorclock.VectorClockRev(rev2)))
示例#4
0
 def test_resolve_simple(self):
     self.assertTrue(self.db.get_doc('my-doc').has_conflicts)
     cmd = self.make_command(client.CmdResolve)
     inf = cStringIO.StringIO(tests.nested_doc)
     cmd.run(self.db_path, 'my-doc', [self.doc1.rev, self.doc2.rev], inf)
     doc = self.db.get_doc('my-doc')
     vec = vectorclock.VectorClockRev(doc.rev)
     self.assertTrue(vec.is_newer(vectorclock.VectorClockRev(
         self.doc1.rev)))
     self.assertTrue(vec.is_newer(vectorclock.VectorClockRev(
         self.doc2.rev)))
     self.assertGetDoc(self.db, 'my-doc', doc.rev, tests.nested_doc, False)
     self.assertEqual('', cmd.stdout.getvalue())
     self.assertEqual('rev: %s\n' % (doc.rev, ), cmd.stderr.getvalue())
示例#5
0
 def _force_doc_sync_conflict(self, doc):
     my_doc = self._get_doc(doc.doc_id)
     c = self._db_handle.cursor()
     self._prune_conflicts(doc, vectorclock.VectorClockRev(doc.rev))
     self._add_conflict(c, doc.doc_id, my_doc.rev, my_doc.get_json())
     doc.has_conflicts = True
     self._put_and_update_indexes(my_doc, doc)
示例#6
0
文件: inmemory.py 项目: dgreisen/u2db
 def _force_doc_sync_conflict(self, doc):
     my_doc = self._get_doc(doc.doc_id)
     self._prune_conflicts(doc, vectorclock.VectorClockRev(doc.rev))
     self._conflicts.setdefault(doc.doc_id, []).append(
         (my_doc.rev, my_doc.get_json()))
     doc.has_conflicts = True
     self._put_and_update_indexes(my_doc, doc)
示例#7
0
    def _prune_conflicts(self, doc, doc_vcr):
        """
        Prune conflicts that are older then the current document's revision, or
        whose content match to the current document's content.
        Originally in u1db.CommonBackend

        :param doc: The document to have conflicts pruned.
        :type doc: ServerDocument
        :param doc_vcr: A vector clock representing the current document's
                        revision.
        :type doc_vcr: u1db.vectorclock.VectorClock
        """
        if doc.has_conflicts:
            autoresolved = False
            c_revs_to_prune = []
            for c_doc in doc._conflicts:
                c_vcr = vectorclock.VectorClockRev(c_doc.rev)
                if doc_vcr.is_newer(c_vcr):
                    c_revs_to_prune.append(c_doc.rev)
                elif doc.same_content_as(c_doc):
                    c_revs_to_prune.append(c_doc.rev)
                    doc_vcr.maximize(c_vcr)
                    autoresolved = True
            if autoresolved:
                doc_vcr.increment(self._replica_uid)
                doc.rev = doc_vcr.as_str()
            doc.delete_conflicts(c_revs_to_prune)
示例#8
0
    def _force_doc_sync_conflict(self, doc):
        """
        Add a conflict and force a document put.

        :param doc: The document to be put.
        :type doc: ServerDocument
        """
        my_doc = self._get_doc(doc.doc_id)
        self._prune_conflicts(doc, vectorclock.VectorClockRev(doc.rev))
        doc.add_conflict(
            self._factory(doc.doc_id, my_doc.rev, my_doc.get_json()))
        doc.has_conflicts = True
        self._put_doc(my_doc, doc)
示例#9
0
 def _prune_conflicts(self, doc, doc_vcr):
     if self._has_conflicts(doc.doc_id):
         autoresolved = False
         c_revs_to_prune = []
         for c_doc in self._get_conflicts(doc.doc_id):
             c_vcr = vectorclock.VectorClockRev(c_doc.rev)
             if doc_vcr.is_newer(c_vcr):
                 c_revs_to_prune.append(c_doc.rev)
             elif doc.same_content_as(c_doc):
                 c_revs_to_prune.append(c_doc.rev)
                 doc_vcr.maximize(c_vcr)
                 autoresolved = True
         if autoresolved:
             doc_vcr.increment(self._replica_uid)
             doc.rev = doc_vcr.as_str()
         c = self._db_handle.cursor()
         self._delete_conflicts(c, doc, c_revs_to_prune)
示例#10
0
文件: inmemory.py 项目: dgreisen/u2db
 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)