def setUp(self):
        print('setup')

        if hasattr(UserTable, 'test_column1'):
            try:
                delattr(UserTable, 'test_column1')
            except:
                pass
            sa.inspect(UserTable).mapper._expire_memoizations()
            del sa.inspect(UserTable).mapper.columns['test_column1']
            del sa.inspect(UserTable).mapper._props['test_column1']

        if hasattr(UserTable, 'test_column3'):
            try:
                delattr(UserTable, 'test_column3')
            except:
                pass
            sa.inspect(UserTable).mapper._expire_memoizations()
            del sa.inspect(UserTable).mapper.columns['test_column3']
            del sa.inspect(UserTable).mapper._props['test_column3']

        try:
            delete_cmd = 'drop table {}'
            self.engine.execute(delete_cmd.format(UserTable.__tablename__))
        except Exception as e:
            pass

        Base.metadata.create_all(self.engine)
        UserTable.register(ArchiveTable, self.engine)
        MultiColumnUserTable.register(MultiColumnArchiveTable, self.engine)
        self.p1 = dict(product_id=10, col1='foobar', col2=10, col3=1)
        self.p2 = dict(product_id=11, col1='baz', col2=11, col3=1)
        self.p3 = dict(product_id=2546, col1='test', col2=12, col3=0)

        self.session = self.Session()
    def test_insert_new_product_with_user(self):
        p = UserTable(**self.p1)
        p.updated_by('test_user')
        self._add_and_test_version(p, 0)

        self._verify_row(self.p1, 0)
        self._verify_archive(self.p1, 0, log_id=p.va_id, user='******')
    def test_va_diff_new_column_and_del_column(self):
        p = UserTable(**self.p1)
        p._updated_by = '1'
        self._add_and_test_version(p, 0)

        print("111", p.__table__.c)
        self.addTestNullableColumn()
        p = self.session.query(UserTable).get(p.id)
        print("222", p.__table__.c)
        p.col1 = 'test'
        p.test_column1 = 'tc1'
        p._updated_by = '2'
        self.session.commit()

        res = UserTable.va_diff(self.session, va_id=p.va_id)
        print("RESULT", res)
        self.assertEqual(
            res, {
                'va_prev_version': 0,
                'va_version': 1,
                'prev_user_id': '1',
                'user_id': '2',
                'change': {
                    'col1': {
                        'this': 'test',
                        'prev': 'foobar'
                    },
                    'test_column1': {
                        'prev': None,
                        'this': 'tc1',
                    }
                }
            })
        print("PASSED")
        self.deleteTestNullableColumn()
        print("DELETED")
        p = self.session.query(UserTable).get(p.id)
        print("P COLS", p.__table__.c)
        p.col1 = 'test2'
        p._updated_by = '1'
        self.session.commit()
        res = UserTable.va_diff(self.session, va_id=p.va_id)
        print("ANOTHER RES", res)
        self.assertEqual(
            res, {
                'va_prev_version': 1,
                'va_version': 2,
                'prev_user_id': '2',
                'user_id': '1',
                'change': {
                    'col1': {
                        'this': 'test2',
                        'prev': 'test'
                    },
                    'test_column1': {
                        'prev': 'tc1',
                        'this': None,
                    }
                }
            })
 def test_va_list_by_pk_fail(self):
     p = UserTable(**self.p1)
     self._add_and_test_version(p, 0)
     p = self.session.query(UserTable).get(p.id)
     p.col1 = 'test'
     self.session.commit()
     with self.assertRaises(LogIdentifyError):
         UserTable.va_list_by_pk(self.session)
Exemple #5
0
 def setUp(self):
     Base.metadata.create_all(self.engine)
     UserTable.register(ArchiveTable, self.engine)
     MultiColumnUserTable.register(MultiColumnArchiveTable, self.engine)
     self.p1 = dict(product_id=10, col1='foobar', col2=10, col3=1)
     self.p2 = dict(product_id=11, col1='baz', col2=11, col3=1)
     self.p3 = dict(product_id=2546, col1='test', col2=12, col3=0)
     self.session = self.Session()
    def test_insert_new_product(self):
        self.assertTrue(versionalchemy.is_initialized())
        p = UserTable(**self.p1)
        p.col4 = 11
        self._add_and_test_version(p, 0)

        expected = dict(other_name=11, **self.p1)
        self._verify_row(expected, 0)
        self._verify_archive(expected, 0, log_id=p.va_id)
Exemple #7
0
 def test_update_no_changes(self):
     '''
     Add an unchanged row and make sure the version does not get bumped.
     '''
     p = UserTable(**self.p1)
     self._add_and_test_version(p, 0)
     p.col1 = self.p1['col1']
     self.session.add(p)
     self.session.commit()
     self._verify_archive(self.p1, 0)
     self.assertEqual(len(self.session.query(ArchiveTable).all()), 1)
Exemple #8
0
def engine():
    """Session-wide test database engine."""
    drop_test_db()
    create_test_db()
    savage.init()
    _engine = create_engine(get_test_database_url(),
                            json_serializer=savage_json_serializer)
    Base.metadata.create_all(_engine)
    UserTable.register(ArchiveTable, _engine)
    MultiColumnUserTable.register(MultiColumnArchiveTable, _engine)
    yield _engine
    _engine.dispose()
    drop_test_db()
 def test_va_get_by_va_id(self):
     p = UserTable(**self.p1)
     self._add_and_test_version(p, 0)
     p = self.session.query(UserTable).get(p.id)
     res = p.va_get(self.session, va_id=p.va_id)
     self.assertEqual(
         res, {
             'other_name': None,
             'id': p.id,
             'product_id': p.product_id,
             'col1': p.col1,
             'col2': p.col2,
             'col3': p.col3,
             'va_id': p.va_id
         })
Exemple #10
0
    def test_delete_with_user(self):
        p = UserTable(**self.p1)
        p.updated_by('test_user')
        self._add_and_test_version(p, 0)

        self.session.delete(p)
        self.session.flush()
        self.assertEquals(
            len(
                self.session.execute(
                    sa.select([UserTable
                               ]).where(UserTable.product_id ==
                                        self.p1['product_id'])).fetchall()), 0)
        self._verify_archive(self.p1, 0)
        self._verify_archive(self.p1, 1, deleted=True, user='******')
    def test_restore_row_with_non_default_column(self):
        p = UserTable(**self.p1)
        self._add_and_test_version(p, 0)
        p = self.session.query(UserTable).get(p.id)
        first_version = p.va_id
        p.col1 = 'test'
        self.session.commit()
        p = self.session.query(UserTable).get(p.id)
        self.assertEqual(p.col1, 'test')
        self.assertEqual(p.va_id, first_version + 1,
                         'Version should be increased')
        self.addTestNoDefaultNoNullColumn()
        p = self.session.query(UserTable).get(p.id)

        with self.assertRaises(RestoreError):
            p.va_restore(self.session, first_version)
Exemple #12
0
    def test_product_update(self):
        p = UserTable(**self.p1)
        self._add_and_test_version(p, 0)

        p.col1 = 'new'
        p.col2 = -1
        self._add_and_test_version(p, 1)

        self._verify_row(dict(self.p1, **{'col1': 'new', 'col2': -1}), 1)
        self._verify_archive(self.p1, 0)
        self._verify_archive(dict(self.p1, **{
            'col1': 'new',
            'col2': -1,
        }),
                             1,
                             log_id=p.va_id)
Exemple #13
0
    def test_archive_table_collision_fails_1(self):
        """
        Try to insert two records with the same version and foreign key in the same transaction
        and ensure the write fails. In other words, ensure the unique constraint
        is correctly imposed on the archive table.
        """
        # Insert an element so it exists in the archive table
        p = UserTable(**self.p1)
        self._add_and_test_version(p, 0)

        to_insert = {
            'va_version': 1,
            'va_deleted': False,
            'user_id': 'bar',
            'va_updated_at': datetime.now(),
            'va_data': {},
            'product_id': p.product_id,
        }
        self.session.add(ArchiveTable(**to_insert))
        to_insert = {
            'va_version': 1,
            'va_deleted': True,
            'user_id': 'foo',
            'va_updated_at': datetime.now(),
            'va_data': {},
            'product_id': p.product_id,
        }
        self.session.add(ArchiveTable(**to_insert))
        with self.assertRaises(IntegrityError):
            self.session.flush()
Exemple #14
0
 def __init__(self, methodName='runTest'):
     self.engine1 = sa.create_engine(self.DATABASE_URL,
                                     isolation_level='READ UNCOMMITTED',
                                     echo='debug',
                                     logging_name='engine1')
     self.engine2 = sa.create_engine(self.DATABASE_URL,
                                     isolation_level='READ UNCOMMITTED',
                                     echo='debug',
                                     logging_name='engine2')
     self.Session1 = sessionmaker(bind=self.engine1)
     self.Session2 = sessionmaker(bind=self.engine2)
     Base.metadata.create_all(self.engine1)
     UserTable.register(ArchiveTable, self.engine1)
     UserTable.register(ArchiveTable, self.engine1)
     self.p1 = dict(product_id=10, col1='foobar', col2=10, col3=True)
     super(TestConcurrentUpdate, self).__init__(methodName)
Exemple #15
0
    def test_product_update_fails(self):
        """
        Insert a product. Construct a new ORM object with the same id as the inserted object
        and make sure the insertion fails.
        """
        # Initial product insert
        p = UserTable(**self.p1)
        self._add_and_test_version(p, 0)

        # Create a new row with the same primary key and try to insert it
        p_up = dict(
            col1='newcol',
            col2=5,
            col3=False,
            product_id=10,
        )
        p_up_row = UserTable(**p_up)
        with self.assertRaises(IntegrityError):
            self._add_and_test_version(p_up_row, 1)
    def test_insert_multiple_products(self):
        p1 = UserTable(**self.p1)
        p2 = UserTable(**self.p2)
        p3 = UserTable(**self.p3)
        self.session.add_all([p1, p2, p3])
        self.session.flush()
        self.assertEquals(p1.version(self.session), 0)
        self.assertEquals(p2.version(self.session), 0)
        self.assertEquals(p3.version(self.session), 0)

        # Assert the columns match
        expected = [self.p1, self.p2, self.p3]
        ids = [p1.va_id, p2.va_id, p3.va_id]
        for i, p in enumerate(expected):
            self._verify_row(p, 0)
            self._verify_archive(p, 0, log_id=ids[i])
Exemple #17
0
    def setUp(self):
        super(TestGetAPI, self).setUp()
        self.p1_history, self.p2_history, self.p3_history = [], [], []

        self.t1 = datetime.utcfromtimestamp(10)
        p1 = UserTable(**self.p1)
        p3 = UserTable(**self.p3)
        with mock.patch('versionalchemy.models.datetime') as p:
            p.now.return_value = self.t1
            self.session.add_all([p1, p3])
            self.session.flush()
            self.p1_history.append(self._history(p1, self.t1, 0))
            self.p3_history.append(self._history(p3, self.t1, 0))

        self.t2 = datetime.utcfromtimestamp(20)
        p1.col1 = 'change1'
        p2 = UserTable(**self.p2)
        with mock.patch('versionalchemy.models.datetime') as p:
            p.now.return_value = self.t2
            self.session.add_all([p1, p2])
            self.session.flush()
            self.p1_history.append(self._history(p1, self.t2, 1))
            self.p2_history.append(self._history(p2, self.t2, 0))

        self.t3 = datetime.utcfromtimestamp(30)
        p1.col3 = False
        p1.col1 = 'change2'
        with mock.patch('versionalchemy.models.datetime') as p:
            p.now.return_value = self.t3
            self.session.add(p1)
            self.session.flush()
            self.p1_history.append(self._history(p1, self.t3, 2))

        self.t4 = datetime.utcfromtimestamp(40)
        p1.col2 = 15
        p2.col2 = 12
        with mock.patch('versionalchemy.models.datetime') as p:
            p.now.return_value = self.t4
            self.session.add_all([p1, p2])
            self.session.flush()
            self.p1_history.append(self._history(p1, self.t4, 3))
            self.p2_history.append(self._history(p2, self.t4, 1))
    def test_va_diff_basic_va_version(self):
        p = UserTable(**self.p1)
        p._updated_by = '1'
        self._add_and_test_version(p, 0)
        p = self.session.query(UserTable).get(p.id)

        p.col1 = 'test'
        p._updated_by = '2'
        self.session.commit()
        log = self.session.query(ArchiveTable).get(p.va_id)

        res = UserTable.va_diff(self.session, log.va_version)
        self.assertEqual(
            res, {
                'va_prev_version': 0,
                'va_version': 1,
                'prev_user_id': '1',
                'user_id': '2',
                'change': {
                    'col1': {
                        'this': 'test',
                        'prev': 'foobar'
                    }
                }
            })
Exemple #19
0
    def setUp(self):
        super(TestDeleteAPI, self).setUp()

        p1 = UserTable(**self.p1)
        p3 = UserTable(**self.p3)
        self.session.add_all([p1, p3])
        self.session.flush()

        p1.col1 = 'change1'
        p2 = UserTable(**self.p2)
        self.session.add_all([p1, p2])
        self.session.flush()

        p1.col3 = False
        p1.col1 = 'change2'
        self.session.add(p1)
        self.session.flush()

        p1.col2 = 15
        p2.col2 = 12
        self.session.add_all([p1, p2])
        self.session.flush()
Exemple #20
0
    def test_insert_after_delete(self):
        """
        Inserting a row that has already been deleted should version where it left off
        (not at 0).
        """
        p = UserTable(**self.p1)
        self._add_and_test_version(p, 0)

        self.session.delete(p)
        self.session.flush()

        p_new = dict(self.p1, **{
            'col1': 'changed',
            'col2': 139,
        })
        q = UserTable(**p_new)
        self._add_and_test_version(q, 2)

        self._verify_row(p_new, 2)
        self._verify_archive(self.p1, 0)
        self._verify_archive(self.p1, 1, deleted=True)
        self._verify_archive(p_new, 2)
Exemple #21
0
    def test_concurrent_product_updates(self):
        """
        Assert that if two separate sessions try to update a product row,
        one succeeds and the other fails.
        """
        p1 = UserTable(**self.p1)

        # Create two sessions
        session1 = self.Session1()
        session2 = self.Session2()

        # Add the initial row and flush it to the table
        session1.add(p1)
        session1.commit()

        # Update 1 in session1
        p1.col1 = 'changed col 1'
        session1.add(p1)

        # Update 2 in session 2
        p2 = session2.query(UserTable).all()[0]
        p2.col2 = 1245600
        session2.add(p2)

        # this flush should succeed
        session2.commit()
        session2.close()

        # this flush should fail
        session1.commit()
        session1.close()

        final = dict(self.p1, **{'col1': 'changed col 1', 'col2': 1245600})
        self._verify_row(final, 2, session=session1)

        history = [self.p1, dict(self.p1, **{'col2': 1245600}), final]
        for i, expected in enumerate(history):
            self._verify_archive(expected, i, session=session1)
 def test_va_diff_all(self):
     p = UserTable(**self.p1)
     p._updated_by = '1'
     self._add_and_test_version(p, 0)
     p = self.session.query(UserTable).get(p.id)
     p.col1 = 'test'
     p._updated_by = '2'
     self.session.commit()
     res = UserTable.va_diff_all_by_pk(self.session,
                                       product_id=p.product_id)
     expected_result = [{
         'va_prev_version': None,
         'va_version': 0,
         'prev_user_id': None,
         'user_id': '1',
         'change': {
             'col1': {
                 'this': 'foobar',
                 'prev': None
             },
             'col2': {
                 'this': 10,
                 'prev': None
             },
             'col3': {
                 'prev': None,
                 'this': 1
             },
             'product_id': {
                 'prev': None,
                 'this': 10
             },
             'id': {
                 'this': 1,
                 'prev': None
             }
         }
     }, {
         'va_prev_version': 0,
         'va_version': 1,
         'prev_user_id': '1',
         'user_id': '2',
         'change': {
             'col1': {
                 'this': 'test',
                 'prev': 'foobar'
             }
         }
     }]
     self.assertEqual(res, expected_result)
     res = p.va_diff_all(self.session)
     self.assertEqual(res, expected_result)
    def test_va_list(self):
        p = UserTable(**self.p1)
        self._add_and_test_version(p, 0)
        p = self.session.query(UserTable).get(p.id)
        first_version = p.va_id
        p.col1 = 'test'
        self.session.commit()
        res = p.va_list(self.session)

        expected_response = [
            {
                'va_id': first_version,
                'user_id': None,
                'va_version': 0
            },
            {
                'va_id': first_version + 1,
                'user_id': None,
                'va_version': 1
            },
        ]
        self.assertEqual(res, expected_response)
        res = UserTable.va_list_by_pk(self.session, product_id=p.product_id)
        self.assertEqual(res, expected_response)
    def test_va_diff_first_version(self):
        p = UserTable(**self.p1)
        p._updated_by = '1'
        self._add_and_test_version(p, 0)
        p = self.session.query(UserTable).get(p.id)

        res = UserTable.va_diff(self.session, va_id=p.va_id)
        self.assertEqual(
            res, {
                'va_prev_version': None,
                'va_version': 0,
                'prev_user_id': None,
                'user_id': '1',
                'change': {
                    'col1': {
                        'this': 'foobar',
                        'prev': None
                    },
                    'col2': {
                        'this': 10,
                        'prev': None
                    },
                    'col3': {
                        'prev': None,
                        'this': 1
                    },
                    'product_id': {
                        'prev': None,
                        'this': 10
                    },
                    'id': {
                        'this': 1,
                        'prev': None
                    }
                }
            })
Exemple #25
0
    def test_product_update_with_user(self):
        p = UserTable(**self.p1)
        p.updated_by('test_user1')
        self._add_and_test_version(p, 0)

        p.col1 = 'new'
        p.col2 = -1
        p.updated_by('test_user2')
        self._add_and_test_version(p, 1)

        self._verify_row(dict(self.p1, **{'col1': 'new', 'col2': -1}), 1)
        self._verify_archive(self.p1, 0, user='******')
        self._verify_archive(dict(self.p1, **{
            'col1': 'new',
            'col2': -1,
        }),
                             1,
                             user='******',
                             log_id=p.va_id)
 def test_restore_row_with_new_nullable_column_by_va_version(self):
     p = UserTable(**self.p1)
     self._add_and_test_version(p, 0)
     p = self.session.query(UserTable).get(p.id)
     log = self.session.query(ArchiveTable).get(p.va_id)
     first_va_version = log.va_version
     p.col1 = 'test'
     p.col2 = 10
     self.session.commit()
     p = self.session.query(UserTable).get(p.id)
     self.assertEqual(p.col1, 'test')
     self.assertEqual(p.col2, 10)
     self.addTestNullableColumn()
     p = self.session.query(UserTable).get(p.id)
     p.va_restore(self.session, first_va_version)
     p = self.session.query(UserTable).get(p.id)
     self.assertEqual(p.col1, self.p1['col1'])
     self.assertEqual(p.col2, self.p1['col2'])
     self.assertEqual(p.test_column1, None)
 def test_va_get_all(self):
     p = UserTable(**self.p1)
     p._updated_by = '1'
     self._add_and_test_version(p, 0)
     p = self.session.query(UserTable).get(p.id)
     p.col1 = 'test'
     p._updated_by = '2'
     self.session.commit()
     expected_result = [{
         'record': {
             'col1': 'foobar',
             'col2': 10,
             'col3': 1,
             'id': 1,
             'other_name': None,
             'product_id': 10
         },
         'user_id': '1',
         'va_id': 1,
         'va_version': 0
     }, {
         'record': {
             'col1': 'test',
             'col2': 10,
             'col3': 1,
             'id': 1,
             'other_name': None,
             'product_id': 10
         },
         'user_id': '2',
         'va_id': 2,
         'va_version': 1
     }]
     res = p.va_get_all(self.session)
     self.assertEqual(res, expected_result)
     res = UserTable.va_get_all_by_pk(self.session, product_id=p.product_id)
     self.assertEqual(res, expected_result)
 def test_restore_row_with_new_nullable_column_by_va_id(self):
     p = UserTable(**self.p1)
     self._add_and_test_version(p, 0)
     p = self.session.query(UserTable).get(p.id)
     first_va_id = p.va_id
     p.col1 = 'test'
     p.col2 = 10
     self.session.commit()
     p = self.session.query(UserTable).get(p.id)
     self.assertEqual(p.col1, 'test')
     self.assertEqual(p.col2, 10)
     self.assertEqual(p.va_id, first_va_id + 1, 'va_id should be increased')
     self.addTestNullableColumn()
     p = self.session.query(UserTable).get(p.id)
     p.va_restore(self.session, va_id=first_va_id)
     p = self.session.query(UserTable).get(p.id)
     self.assertEqual(p.col1, self.p1['col1'])
     self.assertEqual(p.col2, self.p1['col2'])
     self.assertEqual(p.test_column1, None)
     self.assertEqual(p.va_id, first_va_id + 2)
Exemple #29
0
    def test_multiple_product_updates(self):
        """
        Update a product multiple times and ensure each one gets
        correctly versioned.
        """
        p = UserTable(**self.p1)
        self._add_and_test_version(p, 0)

        p.col1 = 'new'
        p.col2 = -1
        self._add_and_test_version(p, 1)

        p.col1 = 'third change'
        p.col2 = 139
        p.col3 = False
        self._add_and_test_version(p, 2)

        self._verify_row(
            dict(self.p1, **{
                'col1': 'third change',
                'col2': 139,
                'col3': False,
            }), 1)
        self._verify_archive(self.p1, 0)
        self._verify_archive(dict(self.p1, **{
            'col1': 'new',
            'col2': -1,
        }), 1)
        self._verify_archive(dict(
            self.p1, **{
                'col1': 'third change',
                'col2': 139,
                'col3': False,
            }),
                             2,
                             log_id=p.va_id)
Exemple #30
0
 def test_paging_results(self):
     self.session.execute('delete from {}'.format(UserTable.__tablename__))
     self.session.execute('delete from {}'.format(ArchiveTable.__tablename__))
     t = datetime.utcfromtimestamp(10000)
     with mock.patch('versionalchemy.models.datetime') as p:
         p.now.return_value = t
         history = []
         self.p1['col2'] = 0
         p1 = UserTable(**self.p1)
         self.session.add(p1)
         self.session.commit()
         history.append(self._history(p1, t, self.p1['col2']))
         # make 500 changes
         for i in xrange(500):
             self.p1['col2'] += 1
             self.p1['col3'] = int(i < 250)
             self.p1['col1'] = 'foobar' + '1' * ((i + 1) / 10)
             [setattr(p1, k, v) for k, v in self.p1.iteritems()]
             self.session.add(p1)
             self.session.commit()
             history.append(self._history(p1, t, self.p1['col2']))
         result = get(
             UserTable,
             self.session,
             t1=datetime.utcfromtimestamp(0),
             t2=datetime.utcfromtimestamp(10000000000),
             page=1,
             page_size=1000,
         )
         self._assert_result(result, history)
         result = get(
             UserTable,
             self.session,
             t1=datetime.utcfromtimestamp(0),
             t2=datetime.utcfromtimestamp(10000000000),
             page=1,
             page_size=100
         )
         self._assert_result(result, history[:100])
         result = get(
             UserTable,
             self.session,
             t1=datetime.utcfromtimestamp(0),
             t2=datetime.utcfromtimestamp(10000000000),
             page=3,
             page_size=100
         )
         self._assert_result(result, history[200:300])
         result = get(
             UserTable,
             self.session,
             t1=datetime.utcfromtimestamp(0),
             t2=datetime.utcfromtimestamp(10000000000),
             page=5,
             page_size=100
         )
         self._assert_result(result, history[400:500])
         result = get(
             UserTable,
             self.session,
             t1=datetime.utcfromtimestamp(0),
             t2=datetime.utcfromtimestamp(10000000000),
             fields=['col1'],
             page=1,
             page_size=80
         )
         self._assert_result(result, history[0:80:10], fields=['col1'])