Пример #1
0
class DbTestClassBase(object):
    # Inherit from `object` so unittest doesn't think these are tests which
    # should be run

    @classmethod
    def setUpClass(cls):
        # print("doing setup with", cls.param)
        set_det_id(True)  # handles must be deterministic for this test
        cls.dbstate = DbState()
        cls.dbman = CLIDbManager(cls.dbstate)
        dirpath, _name = cls.dbman.create_new_db_cli("Test: %s" % cls.param,
                                                     dbid=cls.param)
        cls.db = make_database(cls.param)
        cls.db.load(dirpath, None)

    @classmethod
    def tearDownClass(cls):
        # print("tear down", cls.param)
        cls.db.close()
        cls.dbman.remove_database("Test: %s" % cls.param)

    def __add_person(self, gender, first_name, surname, trans):
        person = Person()
        person.gender = gender
        _name = person.primary_name
        _name.first_name = first_name
        surname1 = Surname()
        surname1.surname = surname
        _name.set_surname_list([surname1])
        self.db.add_person(person, trans)
        return person

    def __add_note(self, text, trans):
        note = Note(text=text)
        self.db.add_note(note, trans)
        return note

    def __add_family(self, father, mother, trans):
        family = Family()
        family.set_father_handle(father.handle)
        family.set_mother_handle(mother.handle)
        fam_handle = self.db.add_family(family, trans)
        father.add_family_handle(fam_handle)
        mother.add_family_handle(fam_handle)
        self.db.commit_person(father, trans)
        self.db.commit_person(mother, trans)
        return family

    def __setup_callbacks(self):
        self.db.connect("family-add", self._family_add)
        self.db.connect("family-update", self._family_update)
        self.db.connect("family-delete", self._family_delete)
        self.db.connect("person-add", self._person_add)
        self.db.connect("person-update", self._person_update)
        self.db.connect("person-delete", self._person_delete)
        self.db.connect("note-add", self._note_add)
        self.db.connect("note-update", self._note_update)
        self.db.connect("note-delete", self._note_delete)
        # we will also test the CallbackManager by watching a single person
        self.cm_sigs = []
        self.callman = CallbackManager(self.db)
        self.callman.register_callbacks({
            'person-delete': self._cm_pers_delete,
            'person-update': self._cm_pers_update,
            'person-add': self._cm_pers_add
        })
        self.callman.connect_all(keys=['person'])
        self.callman.register_handles(
            {'person': ['0000000300000003', '0000000700000007']})

    def _family_add(self, *args):
        self._log_sig("family-add", args)

    def _family_update(self, *args):
        self._log_sig("family-update", args)

    def _family_delete(self, *args):
        self._log_sig("family-delete", args)

    def _person_add(self, *args):
        self._log_sig("person-add", args)

    def _person_update(self, *args):
        self._log_sig("person-update", args)

    def _person_delete(self, *args):
        self._log_sig("person-delete", args)

    def _note_add(self, *args):
        self._log_sig("note-add", args)

    def _note_update(self, *args):
        self._log_sig("note-update", args)

    def _note_delete(self, *args):
        self._log_sig("note-delete", args)

    def _log_sig(self, sig, args):
        print("('%s', %s)," % (sig, args))
        self.sigs.append((sig, args[0]))

    def _cm_pers_add(self, *args):
        self.cm_sigs.append(("person-add", args[0]))

    def _cm_pers_update(self, *args):
        self.cm_sigs.append(("person-update", args[0]))

    def _cm_pers_delete(self, *args):
        self.cm_sigs.append(("person-delete", args[0]))

    def test_one(self):
        self.__setup_callbacks()
        self.sigs = []
        with DbTxn('Add test objects', self.db) as trans:
            father1 = self.__add_person(Person.MALE, 'John', 'Allen', trans)
            mother1 = self.__add_person(Person.FEMALE, 'Mary', 'Allen', trans)
            father2 = self.__add_person(Person.MALE, 'John', 'Baker', trans)
            mother2 = self.__add_person(Person.FEMALE, 'Mary', 'Baker', trans)
            family1 = self.__add_family(father1, mother1, trans)
            family2 = self.__add_family(father2, mother2, trans)
        self.callman.register_obj(father2, directonly=True)
        self.callman.register_obj(father2, directonly=False)
        sigs = [('person-add', [
            '0000000100000001', '0000000200000002', '0000000300000003',
            '0000000400000004'
        ]), ('family-add', ['0000000500000005', '0000000600000006']),
                ('person-update', [
                    '0000000100000001', '0000000200000002', '0000000300000003',
                    '0000000400000004'
                ])]
        self.assertEqual(sigs, self.sigs, msg="make families")
        # save state for later undo/redo check
        step1 = (family1, father1, mother1, family2, father2, mother2)
        fam_cnt = self.db.get_number_of_families()
        pers_cnt = self.db.get_number_of_people()
        self.assertEqual(fam_cnt, 2, msg="make families check")
        self.assertEqual(pers_cnt, 4, msg="make families persons check")

        # lets do a family merge, this will not only combine the families, but
        # also combine the the fathers and mothers as well
        self.sigs = []
        query = MergeFamilyQuery(self.db, family1, family2, father1.handle,
                                 mother1.handle)
        query.execute()
        sigs = [('person-delete', ['0000000300000003', '0000000400000004']),
                ('family-delete', ['0000000600000006']),
                ('person-update', [
                    '0000000100000001', '0000000200000002', '0000000100000001',
                    '0000000200000002'
                ]), ('family-update', ['0000000500000005'])]
        self.assertEqual(sigs, self.sigs, msg="merge families")
        fam_cnt = self.db.get_number_of_families()
        pers_cnt = self.db.get_number_of_people()
        self.assertEqual(fam_cnt, 1, msg="merge families check")
        self.assertEqual(pers_cnt, 2, msg="merge families persons check")
        # save new family'people for later redo check
        family1 = self.db.get_family_from_handle(family1.handle)
        father1 = self.db.get_person_from_handle(father1.handle)
        mother1 = self.db.get_person_from_handle(mother1.handle)
        step2 = (family1, father1, mother1)

        # we check that update and add signals are not emitted if the same
        # object is deleted in the same transation
        self.sigs = []
        with DbTxn('Note add/update/delete', self.db) as trans:
            note = self.__add_note("some text", trans)
            note.set("some other text")
            self.db.commit_note(note, trans)
            self.db.remove_note(note.handle, trans)
        sigs = [('note-delete', ['0000000700000007'])]
        self.assertEqual(sigs, self.sigs, msg="note signals check")
        note_cnt = self.db.get_number_of_notes()
        self.assertEqual(note_cnt, 0, msg="note check")

        # Test some undos, start with the note undo
        self.sigs = []
        self.db.undo()
        sigs = [('note-delete', ['0000000700000007'])]
        self.assertEqual(sigs, self.sigs, msg="undo note signals check")

        # Test merge undo
        self.sigs = []
        self.db.undo()
        sigs = [('person-add', ['0000000400000004', '0000000300000003']),
                ('family-add', ['0000000600000006']),
                ('person-update', [
                    '0000000200000002', '0000000100000001', '0000000200000002',
                    '0000000100000001'
                ]),
                ('family-update',
                 ['0000000500000005', '0000000600000006', '0000000600000006'])]
        self.assertEqual(sigs, self.sigs, msg="undo merge signals check")
        fam_cnt = self.db.get_number_of_families()
        pers_cnt = self.db.get_number_of_people()
        self.assertEqual(fam_cnt, 2, msg="undo merge families check")
        self.assertEqual(pers_cnt, 4, msg="undo merge families persons check")
        #step1 = (family1, father1, mother1, family2, father2, mother2)
        obj_s = self.db.get_family_from_handle(family1.handle).serialize()
        self.assertEqual(obj_s,
                         step1[0].serialize(),
                         msg="undo merge families fam1 check")
        obj_s = self.db.get_person_from_handle(father1.handle).serialize()
        self.assertEqual(obj_s,
                         step1[1].serialize(),
                         msg="undo merge families father1 check")
        obj_s = self.db.get_person_from_handle(mother1.handle).serialize()
        self.assertEqual(obj_s,
                         step1[2].serialize(),
                         msg="undo merge families mother1 check")
        obj_s = self.db.get_family_from_handle(family2.handle).serialize()
        self.assertEqual(obj_s,
                         step1[3].serialize(),
                         msg="undo merge families fam2 check")
        obj_s = self.db.get_person_from_handle(father2.handle).serialize()
        self.assertEqual(obj_s,
                         step1[4].serialize(),
                         msg="undo merge families father2 check")
        obj_s = self.db.get_person_from_handle(mother2.handle).serialize()
        self.assertEqual(obj_s,
                         step1[5].serialize(),
                         msg="undo merge families mother2 check")

        # Test family build undo
        self.sigs = []
        self.db.undo()
        sigs = [('person-delete', [
            '0000000400000004', '0000000300000003', '0000000200000002',
            '0000000100000001'
        ]), ('family-delete', ['0000000600000006', '0000000500000005'])]
        self.assertEqual(sigs,
                         self.sigs,
                         msg="undo family build signals check")
        fam_cnt = self.db.get_number_of_families()
        pers_cnt = self.db.get_number_of_people()
        self.assertEqual(fam_cnt, 0, msg="undo make families check")
        self.assertEqual(pers_cnt, 0, msg="undo make families persons check")

        # Test family build redo
        self.sigs = []
        self.db.redo()
        sigs = [('person-add', [
            '0000000100000001', '0000000200000002', '0000000300000003',
            '0000000400000004'
        ]), ('family-add', ['0000000500000005', '0000000600000006']),
                ('person-update', [
                    '0000000100000001', '0000000200000002', '0000000300000003',
                    '0000000400000004'
                ])]
        self.assertEqual(sigs,
                         self.sigs,
                         msg="redo family build signals check")
        fam_cnt = self.db.get_number_of_families()
        pers_cnt = self.db.get_number_of_people()
        self.assertEqual(fam_cnt, 2, msg="redo make families check")
        self.assertEqual(pers_cnt, 4, msg="redo make families persons check")
        #step1 = (family1, father1, mother1, family2, father2, mother2)
        obj_s = self.db.get_family_from_handle(family1.handle).serialize()
        self.assertEqual(obj_s,
                         step1[0].serialize(),
                         msg="redo merge families fam1 check")
        obj_s = self.db.get_person_from_handle(father1.handle).serialize()
        self.assertEqual(obj_s,
                         step1[1].serialize(),
                         msg="redo merge families father1 check")
        obj_s = self.db.get_person_from_handle(mother1.handle).serialize()
        self.assertEqual(obj_s,
                         step1[2].serialize(),
                         msg="redo merge families mother1 check")
        obj_s = self.db.get_family_from_handle(family2.handle).serialize()
        self.assertEqual(obj_s,
                         step1[3].serialize(),
                         msg="redo merge families fam2 check")
        obj_s = self.db.get_person_from_handle(father2.handle).serialize()
        self.assertEqual(obj_s,
                         step1[4].serialize(),
                         msg="redo merge families father2 check")
        obj_s = self.db.get_person_from_handle(mother2.handle).serialize()
        self.assertEqual(obj_s,
                         step1[5].serialize(),
                         msg="redo merge families mother2 check")

        # Test family merge redo
        self.sigs = []
        self.db.redo()
        sigs = [('person-delete', ['0000000300000003', '0000000400000004']),
                ('family-delete', ['0000000600000006']),
                ('person-update', [
                    '0000000100000001', '0000000200000002', '0000000100000001',
                    '0000000200000002'
                ]), ('family-update', ['0000000500000005'])]
        self.assertEqual(sigs, self.sigs, msg="merge families")
        fam_cnt = self.db.get_number_of_families()
        pers_cnt = self.db.get_number_of_people()
        self.assertEqual(fam_cnt, 1, msg="merge families check")
        self.assertEqual(pers_cnt, 2, msg="merge families persons check")
        #step2 = (family1, father1, mother1)
        obj_s = self.db.get_family_from_handle(family1.handle).serialize()
        self.assertEqual(obj_s,
                         step2[0].serialize(),
                         msg="undo merge families fam1 check")
        obj_s = self.db.get_person_from_handle(father1.handle).serialize()
        self.assertEqual(obj_s,
                         step2[1].serialize(),
                         msg="undo merge families father1 check")
        obj_s = self.db.get_person_from_handle(mother1.handle).serialize()
        self.assertEqual(obj_s,
                         step2[2].serialize(),
                         msg="undo merge families mother1 check")

        # Test note redo
        self.sigs = []
        self.db.redo()
        sigs = [('note-delete', ['0000000700000007'])]
        self.assertEqual(sigs, self.sigs, msg="undo note signals check")

        # now lets see if the callback manager is doing its job
        # print(self.cm_sigs)
        sigs = [('person-add', ['0000000300000003']),
                ('person-update', ['0000000300000003']),
                ('person-delete', ['0000000300000003']),
                ('person-add', ['0000000300000003']),
                ('person-delete', ['0000000300000003']),
                ('person-add', ['0000000300000003']),
                ('person-update', ['0000000300000003']),
                ('person-delete', ['0000000300000003'])]

        self.assertEqual(sigs,
                         self.cm_sigs,
                         msg="callback manager signals check")
        self.callman.unregister_handles({'person': ['0000000300000003']})
        # we have to look deep into cm to see if handles are really deleted
        cm_persons = self.callman._CallbackManager__handles['person']
        self.assertEqual(cm_persons, ['0000000700000007'],
                         msg="Callback Manager unregister check")
        self.callman.unregister_all()
        # we have to look deep into cm to see if handles are really deleted
        cm_persons = self.callman._CallbackManager__handles['person']
        self.assertEqual(cm_persons, [],
                         msg="Callback Manager unregister check")
        # we have to look deep into cm to see if callbacks are really deleted
        cm_padd_key = self.callman._CallbackManager__callbacks['person-add'][1]
        self.assertEqual(cm_padd_key, 10, msg="Callback Manager cb check")
        self.callman.disconnect_all()
        # we have to look deep into cm to see if callbacks are really deleted
        cm_padd_key = self.callman._CallbackManager__callbacks['person-add'][1]
        self.assertEqual(cm_padd_key,
                         None,
                         msg="Callback Manager disconnect cb check")
Пример #2
0
class DbGUIElement(object):
    """
    Most interaction with the DB should be done via the callman attribute.
    On initialization, the method :meth:`_connect_db_signals` is called.
    Inheriting objects are advised to group the setup of the callman attribute
    here.

    .. attribute callman: a :class:`.CallbackManager` object, to be used to
                          track specific changes in the db and set up callbacks
    """
    def __init__(self, database):
        self.callman = CallbackManager(database)
        self._connect_db_signals()

    def _add_db_signal(self, name, callback):
        """
        Convenience function to add a custom db signal. The attributes are just
        passed to the callman object.
        For primary objects, use the register method of the callman attribute.

        :param name: name of the signal to connect to
        :type name: string
        :param callback: function to call when signal is emitted
        :type callback: a funtion or method with the correct signature for the
                signal
        """
        self.callman.add_db_signal(name, callback)

    def _connect_db_signals(self):
        """
        Convenience method that is called on initialization of DbGUIElement.
        Use this to group setup of the callman attribute.
        Also called in _change_db method
        """
        pass

    def _cleanup_callbacks(self):
        """
        Remove all db callbacks.
        This is done automatically on destruction of the object, but is
        normally needed earlier, calling this method does so.
        Use _change_db method if you need to remove the callbacks because the
        database has changed
        """
        database = self.callman.database
        if database.is_open():
            #a closed database has disconnected all signals
            self.callman.disconnect_all()
        #set a new callback manager
        self.callman = CallbackManager(database)

    def _change_db(self, database):
        """
        Change the database the GUI element works on to database.
        This removes all callbacks and all registered handles.

        :param database: the new database to connect to
        """
        dbold = self.callman.database
        if dbold.is_open():
            #a closed database has disconnected all signals
            self.callman.disconnect_all()
        #set a new callback manager on new database
        self.callman = CallbackManager(database)
        self._connect_db_signals()
Пример #3
0
class DbGUIElement(object):
    """
    Most interaction with the DB should be done via the callman attribute.
    On initialization, the method :meth:`_connect_db_signals` is called.
    Inheriting objects are advised to group the setup of the callman attribute
    here.

    .. attribute callman: a :class:`.CallbackManager` object, to be used to
                          track specific changes in the db and set up callbacks
    """
    def __init__(self, database):
        self.callman = CallbackManager(database)
        self._connect_db_signals()

    def _add_db_signal(self, name, callback):
        """
        Convenience function to add a custom db signal. The attributes are just
        passed to the callman object.
        For primary objects, use the register method of the callman attribute.

        :param name: name of the signal to connect to
        :type name: string
        :param callback: function to call when signal is emitted
        :type callback: a funtion or method with the correct signature for the
                signal
        """
        self.callman.add_db_signal(name, callback)

    def _connect_db_signals(self):
        """
        Convenience method that is called on initialization of DbGUIElement.
        Use this to group setup of the callman attribute.
        Also called in _change_db method
        """
        pass

    def _cleanup_callbacks(self):
        """
        Remove all db callbacks.
        This is done automatically on destruction of the object, but is
        normally needed earlier, calling this method does so.
        Use _change_db method if you need to remove the callbacks because the
        database has changed
        """
        database = self.callman.database
        if database.is_open():
            #a closed database has disconnected all signals
            self.callman.disconnect_all()
        #set a new callback manager
        self.callman = CallbackManager(database)

    def _change_db(self, database):
        """
        Change the database the GUI element works on to database.
        This removes all callbacks and all registered handles.

        :param database: the new database to connect to
        """
        dbold = self.callman.database
        if dbold.is_open():
            #a closed database has disconnected all signals
            self.callman.disconnect_all()
        #set a new callback manager on new database
        self.callman = CallbackManager(database)
        self._connect_db_signals()
Пример #4
0
class DbTestClassBase(object):
    # Inherit from `object` so unittest doesn't think these are tests which
    # should be run

    @classmethod
    def setUpClass(cls):
        # print("doing setup with", cls.param)
        set_det_id(True)  # handles must be deterministic for this test
        cls.dbstate = DbState()
        cls.dbman = CLIDbManager(cls.dbstate)
        dirpath, _name = cls.dbman.create_new_db_cli("Test: %s" % cls.param,
                                                     dbid=cls.param)
        cls.db = make_database(cls.param)
        cls.db.load(dirpath, None)

    @classmethod
    def tearDownClass(cls):
        # print("tear down", cls.param)
        cls.db.close()
        cls.dbman.remove_database("Test: %s" % cls.param)

    def __add_person(self, gender, first_name, surname, trans):
        person = Person()
        person.gender = gender
        _name = person.primary_name
        _name.first_name = first_name
        surname1 = Surname()
        surname1.surname = surname
        _name.set_surname_list([surname1])
        self.db.add_person(person, trans)
        return person

    def __add_note(self, text, trans):
        note = Note(text=text)
        self.db.add_note(note, trans)
        return note

    def __add_family(self, father, mother, trans):
        family = Family()
        family.set_father_handle(father.handle)
        family.set_mother_handle(mother.handle)
        fam_handle = self.db.add_family(family, trans)
        father.add_family_handle(fam_handle)
        mother.add_family_handle(fam_handle)
        self.db.commit_person(father, trans)
        self.db.commit_person(mother, trans)
        return family

    def __setup_callbacks(self):
        self.db.connect("family-add", self._family_add)
        self.db.connect("family-update", self._family_update)
        self.db.connect("family-delete", self._family_delete)
        self.db.connect("person-add", self._person_add)
        self.db.connect("person-update", self._person_update)
        self.db.connect("person-delete", self._person_delete)
        self.db.connect("note-add", self._note_add)
        self.db.connect("note-update", self._note_update)
        self.db.connect("note-delete", self._note_delete)
        # we will also test the CallbackManager by watching a single person
        self.cm_sigs = []
        self.callman = CallbackManager(self.db)
        self.callman.register_callbacks({'person-delete': self._cm_pers_delete,
                                         'person-update': self._cm_pers_update,
                                         'person-add': self._cm_pers_add})
        self.callman.connect_all(keys=['person'])
        self.callman.register_handles({'person': ['0000000300000003',
                                                  '0000000700000007']})

    def _family_add(self, *args):
        self._log_sig("family-add", args)

    def _family_update(self, *args):
        self._log_sig("family-update", args)

    def _family_delete(self, *args):
        self._log_sig("family-delete", args)

    def _person_add(self, *args):
        self._log_sig("person-add", args)

    def _person_update(self, *args):
        self._log_sig("person-update", args)

    def _person_delete(self, *args):
        self._log_sig("person-delete", args)

    def _note_add(self, *args):
        self._log_sig("note-add", args)

    def _note_update(self, *args):
        self._log_sig("note-update", args)

    def _note_delete(self, *args):
        self._log_sig("note-delete", args)

    def _log_sig(self, sig, args):
        print("('%s', %s)," % (sig, args))
        self.sigs.append((sig, args[0]))

    def _cm_pers_add(self, *args):
        self.cm_sigs.append(("person-add", args[0]))

    def _cm_pers_update(self, *args):
        self.cm_sigs.append(("person-update", args[0]))

    def _cm_pers_delete(self, *args):
        self.cm_sigs.append(("person-delete", args[0]))

    def test_one(self):
        self.__setup_callbacks()
        self.sigs = []
        with DbTxn('Add test objects', self.db) as trans:
            father1 = self.__add_person(Person.MALE, 'John', 'Allen', trans)
            mother1 = self.__add_person(Person.FEMALE, 'Mary', 'Allen', trans)
            father2 = self.__add_person(Person.MALE, 'John', 'Baker', trans)
            mother2 = self.__add_person(Person.FEMALE, 'Mary', 'Baker', trans)
            family1 = self.__add_family(father1, mother1, trans)
            family2 = self.__add_family(father2, mother2, trans)
        self.callman.register_obj(father2, directonly=True)
        self.callman.register_obj(father2, directonly=False)
        sigs = [
            ('person-add', ['0000000100000001', '0000000200000002',
                            '0000000300000003', '0000000400000004']),
            ('family-add', ['0000000500000005', '0000000600000006']),
            ('person-update', ['0000000100000001', '0000000200000002',
                               '0000000300000003', '0000000400000004'])]
        self.assertEqual(sigs, self.sigs, msg="make families")
        # save state for later undo/redo check
        step1 = (family1, father1, mother1, family2, father2, mother2)
        fam_cnt = self.db.get_number_of_families()
        pers_cnt = self.db.get_number_of_people()
        self.assertEqual(fam_cnt, 2, msg="make families check")
        self.assertEqual(pers_cnt, 4, msg="make families persons check")

        # lets do a family merge, this will not only combine the families, but
        # also combine the the fathers and mothers as well
        self.sigs = []
        query = MergeFamilyQuery(self.db, family1, family2,
                                 father1.handle, mother1.handle)
        query.execute()
        sigs = [
            ('person-delete', ['0000000300000003', '0000000400000004']),
            ('family-delete', ['0000000600000006']),
            ('person-update', ['0000000100000001', '0000000200000002',
                               '0000000100000001', '0000000200000002']),
            ('family-update', ['0000000500000005'])]
        self.assertEqual(sigs, self.sigs, msg="merge families")
        fam_cnt = self.db.get_number_of_families()
        pers_cnt = self.db.get_number_of_people()
        self.assertEqual(fam_cnt, 1, msg="merge families check")
        self.assertEqual(pers_cnt, 2, msg="merge families persons check")
        # save new family'people for later redo check
        family1 = self.db.get_family_from_handle(family1.handle)
        father1 = self.db.get_person_from_handle(father1.handle)
        mother1 = self.db.get_person_from_handle(mother1.handle)
        step2 = (family1, father1, mother1)

        # we check that update and add signals are not emitted if the same
        # object is deleted in the same transation
        self.sigs = []
        with DbTxn('Note add/update/delete', self.db) as trans:
            note = self.__add_note("some text", trans)
            note.set("some other text")
            self.db.commit_note(note, trans)
            self.db.remove_note(note.handle, trans)
        sigs = [
            ('note-delete', ['0000000700000007'])]
        self.assertEqual(sigs, self.sigs, msg="note signals check")
        note_cnt = self.db.get_number_of_notes()
        self.assertEqual(note_cnt, 0, msg="note check")

        # Test some undos, start with the note undo
        self.sigs = []
        self.db.undo()
        sigs = [('note-delete', ['0000000700000007'])]
        self.assertEqual(sigs, self.sigs, msg="undo note signals check")

        # Test merge undo
        self.sigs = []
        self.db.undo()
        sigs = [
            ('person-add', ['0000000400000004', '0000000300000003']),
            ('family-add', ['0000000600000006']),
            ('person-update', ['0000000200000002', '0000000100000001',
                               '0000000200000002', '0000000100000001']),
            ('family-update', ['0000000500000005', '0000000600000006',
                               '0000000600000006'])]
        self.assertEqual(sigs, self.sigs, msg="undo merge signals check")
        fam_cnt = self.db.get_number_of_families()
        pers_cnt = self.db.get_number_of_people()
        self.assertEqual(fam_cnt, 2, msg="undo merge families check")
        self.assertEqual(pers_cnt, 4, msg="undo merge families persons check")
        #step1 = (family1, father1, mother1, family2, father2, mother2)
        obj_s = self.db.get_family_from_handle(family1.handle).serialize()
        self.assertEqual(obj_s, step1[0].serialize(),
                         msg="undo merge families fam1 check")
        obj_s = self.db.get_person_from_handle(father1.handle).serialize()
        self.assertEqual(obj_s, step1[1].serialize(),
                         msg="undo merge families father1 check")
        obj_s = self.db.get_person_from_handle(mother1.handle).serialize()
        self.assertEqual(obj_s, step1[2].serialize(),
                         msg="undo merge families mother1 check")
        obj_s = self.db.get_family_from_handle(family2.handle).serialize()
        self.assertEqual(obj_s, step1[3].serialize(),
                         msg="undo merge families fam2 check")
        obj_s = self.db.get_person_from_handle(father2.handle).serialize()
        self.assertEqual(obj_s, step1[4].serialize(),
                         msg="undo merge families father2 check")
        obj_s = self.db.get_person_from_handle(mother2.handle).serialize()
        self.assertEqual(obj_s, step1[5].serialize(),
                         msg="undo merge families mother2 check")

        # Test family build undo
        self.sigs = []
        self.db.undo()
        sigs = [
            ('person-delete', ['0000000400000004', '0000000300000003',
                               '0000000200000002', '0000000100000001']),
            ('family-delete', ['0000000600000006', '0000000500000005'])]
        self.assertEqual(sigs, self.sigs, msg="undo family build signals check")
        fam_cnt = self.db.get_number_of_families()
        pers_cnt = self.db.get_number_of_people()
        self.assertEqual(fam_cnt, 0, msg="undo make families check")
        self.assertEqual(pers_cnt, 0, msg="undo make families persons check")

        # Test family build redo
        self.sigs = []
        self.db.redo()
        sigs = [
            ('person-add', ['0000000100000001', '0000000200000002',
                            '0000000300000003', '0000000400000004']),
            ('family-add', ['0000000500000005', '0000000600000006']),
            ('person-update', ['0000000100000001', '0000000200000002',
                               '0000000300000003', '0000000400000004'])]
        self.assertEqual(sigs, self.sigs, msg="redo family build signals check")
        fam_cnt = self.db.get_number_of_families()
        pers_cnt = self.db.get_number_of_people()
        self.assertEqual(fam_cnt, 2, msg="redo make families check")
        self.assertEqual(pers_cnt, 4, msg="redo make families persons check")
        #step1 = (family1, father1, mother1, family2, father2, mother2)
        obj_s = self.db.get_family_from_handle(family1.handle).serialize()
        self.assertEqual(obj_s, step1[0].serialize(),
                         msg="redo merge families fam1 check")
        obj_s = self.db.get_person_from_handle(father1.handle).serialize()
        self.assertEqual(obj_s, step1[1].serialize(),
                         msg="redo merge families father1 check")
        obj_s = self.db.get_person_from_handle(mother1.handle).serialize()
        self.assertEqual(obj_s, step1[2].serialize(),
                         msg="redo merge families mother1 check")
        obj_s = self.db.get_family_from_handle(family2.handle).serialize()
        self.assertEqual(obj_s, step1[3].serialize(),
                         msg="redo merge families fam2 check")
        obj_s = self.db.get_person_from_handle(father2.handle).serialize()
        self.assertEqual(obj_s, step1[4].serialize(),
                         msg="redo merge families father2 check")
        obj_s = self.db.get_person_from_handle(mother2.handle).serialize()
        self.assertEqual(obj_s, step1[5].serialize(),
                         msg="redo merge families mother2 check")

        # Test family merge redo
        self.sigs = []
        self.db.redo()
        sigs = [
            ('person-delete', ['0000000300000003', '0000000400000004']),
            ('family-delete', ['0000000600000006']),
            ('person-update', ['0000000100000001', '0000000200000002',
                               '0000000100000001', '0000000200000002']),
            ('family-update', ['0000000500000005'])]
        self.assertEqual(sigs, self.sigs, msg="merge families")
        fam_cnt = self.db.get_number_of_families()
        pers_cnt = self.db.get_number_of_people()
        self.assertEqual(fam_cnt, 1, msg="merge families check")
        self.assertEqual(pers_cnt, 2, msg="merge families persons check")
        #step2 = (family1, father1, mother1)
        obj_s = self.db.get_family_from_handle(family1.handle).serialize()
        self.assertEqual(obj_s, step2[0].serialize(),
                         msg="undo merge families fam1 check")
        obj_s = self.db.get_person_from_handle(father1.handle).serialize()
        self.assertEqual(obj_s, step2[1].serialize(),
                         msg="undo merge families father1 check")
        obj_s = self.db.get_person_from_handle(mother1.handle).serialize()
        self.assertEqual(obj_s, step2[2].serialize(),
                         msg="undo merge families mother1 check")

        # Test note redo
        self.sigs = []
        self.db.redo()
        sigs = [('note-delete', ['0000000700000007'])]
        self.assertEqual(sigs, self.sigs, msg="undo note signals check")

        # now lets see if the callback manager is doing its job
        # print(self.cm_sigs)
        sigs = [
            ('person-add', ['0000000300000003']),
            ('person-update', ['0000000300000003']),
            ('person-delete', ['0000000300000003']),
            ('person-add', ['0000000300000003']),
            ('person-delete', ['0000000300000003']),
            ('person-add', ['0000000300000003']),
            ('person-update', ['0000000300000003']),
            ('person-delete', ['0000000300000003'])]

        self.assertEqual(sigs, self.cm_sigs,
                         msg="callback manager signals check")
        self.callman.unregister_handles({'person': ['0000000300000003']})
        # we have to look deep into cm to see if handles are really deleted
        cm_persons = self.callman._CallbackManager__handles['person']
        self.assertEqual(cm_persons, ['0000000700000007'],
                         msg="Callback Manager unregister check")
        self.callman.unregister_all()
        # we have to look deep into cm to see if handles are really deleted
        cm_persons = self.callman._CallbackManager__handles['person']
        self.assertEqual(cm_persons, [],
                         msg="Callback Manager unregister check")
        # we have to look deep into cm to see if callbacks are really deleted
        cm_padd_key = self.callman._CallbackManager__callbacks['person-add'][1]
        self.assertEqual(cm_padd_key, 10,
                         msg="Callback Manager cb check")
        self.callman.disconnect_all()
        # we have to look deep into cm to see if callbacks are really deleted
        cm_padd_key = self.callman._CallbackManager__callbacks['person-add'][1]
        self.assertEqual(cm_padd_key, None,
                         msg="Callback Manager disconnect cb check")