This class uses the query generator (query_generator.py) along with the query profile (query_profile.py) to randomly generate queries then executes the queries on the reference and test databases, then compares the results.
| 611 | |
| 612 | |
| 613 | class QueryResultDiffSearcher(object): |
| 614 | '''This class uses the query generator (query_generator.py) along with the |
| 615 | query profile (query_profile.py) to randomly generate queries then executes the |
| 616 | queries on the reference and test databases, then compares the results. |
| 617 | ''' |
| 618 | |
| 619 | # Sometimes things get into a bad state and the same error loops forever |
| 620 | ABORT_ON_REPEAT_ERROR_COUNT = 2 |
| 621 | |
| 622 | COPY_TABLE_SUFFIX = '__qgen_copy' |
| 623 | |
| 624 | def __init__(self, query_profile, ref_conn, test_conn): |
| 625 | '''query_profile should be an instance of one of the profiles in query_profile.py''' |
| 626 | self.query_profile = query_profile |
| 627 | self.ref_conn = ref_conn |
| 628 | self.test_conn = test_conn |
| 629 | with ref_conn.cursor() as ref_cursor: |
| 630 | with test_conn.cursor() as test_cursor: |
| 631 | self.common_tables = DbCursor.describe_common_tables([ref_cursor, test_cursor]) |
| 632 | if not self.common_tables: |
| 633 | raise Exception("Unable to find a common set of tables in both databases") |
| 634 | |
| 635 | def _concurrently_copy_table(self, src_table): |
| 636 | """ |
| 637 | Given a Table object, create another Table with the same schema and return the new |
| 638 | Table object. The schema will be created in both the test and reference databases. |
| 639 | |
| 640 | The data is then copied in both the ref and test databases using threads. |
| 641 | """ |
| 642 | with test_conn.cursor() as test_cursor: |
| 643 | test_cursor.execute('SHOW CREATE TABLE {0}'.format(src_table.name)) |
| 644 | (create_table_sql,) = test_cursor.fetchall()[0] |
| 645 | new_table_name = src_table.name + self.COPY_TABLE_SUFFIX |
| 646 | create_table_sql = create_table_sql.replace(src_table.name, new_table_name, 1) |
| 647 | test_cursor.drop_table(new_table_name) |
| 648 | test_cursor.execute(create_table_sql) |
| 649 | new_table = test_cursor.describe_table(new_table_name) |
| 650 | with ref_conn.cursor() as ref_cursor: |
| 651 | ref_cursor.drop_table(new_table_name) |
| 652 | ref_cursor.create_table(new_table) |
| 653 | |
| 654 | copy_select_query = Query() |
| 655 | copy_select_query.select_clause = SelectClause( |
| 656 | [SelectItem(col) for col in src_table.cols]) |
| 657 | copy_select_query.from_clause = FromClause(src_table) |
| 658 | |
| 659 | if new_table.primary_keys: |
| 660 | conflict_action = InsertClause.CONFLICT_ACTION_IGNORE |
| 661 | else: |
| 662 | conflict_action = InsertClause.CONFLICT_ACTION_DEFAULT |
| 663 | |
| 664 | table_copy_statement = InsertStatement( |
| 665 | insert_clause=InsertClause(new_table, conflict_action=conflict_action), |
| 666 | select_query=copy_select_query, execution=StatementExecutionMode.DML_SETUP) |
| 667 | |
| 668 | result = self.query_result_comparator.compare_query_results(table_copy_statement) |
| 669 | if result.error: |
| 670 | raise Exception('setup SQL to copy table failed: {0}'.format(result.error)) |
no outgoing calls
no test coverage detected