Returns an instance of SearchResults, which is a summary report. This method oversees the generation, execution, and comparison of queries. number_of_test_queries should an integer indicating the maximum number of queries to generate and execute.
(self, number_of_test_queries, stop_on_result_mismatch, stop_on_crash,
query_timeout_seconds)
| 673 | return new_table |
| 674 | |
| 675 | def search(self, number_of_test_queries, stop_on_result_mismatch, stop_on_crash, |
| 676 | query_timeout_seconds): |
| 677 | '''Returns an instance of SearchResults, which is a summary report. This method |
| 678 | oversees the generation, execution, and comparison of queries. |
| 679 | |
| 680 | number_of_test_queries should an integer indicating the maximum number of queries |
| 681 | to generate and execute. |
| 682 | ''' |
| 683 | start_time = time() |
| 684 | self.query_result_comparator = QueryResultComparator( |
| 685 | self.query_profile, self.ref_conn, self.test_conn, query_timeout_seconds) |
| 686 | query_count = 0 |
| 687 | queries_resulted_in_data_count = 0 |
| 688 | mismatch_count = 0 |
| 689 | query_timeout_count = 0 |
| 690 | known_error_count = 0 |
| 691 | test_crash_count = 0 |
| 692 | last_error = None |
| 693 | repeat_error_count = 0 |
| 694 | count_effective_dml_statements = 0 |
| 695 | count_rows_affected_by_dml = 0 |
| 696 | |
| 697 | while number_of_test_queries > query_count: |
| 698 | statement_type = self.query_profile.choose_statement() |
| 699 | statement_generator = get_generator(statement_type)(self.query_profile) |
| 700 | dml_table = None |
| 701 | if issubclass(statement_type, (InsertStatement,)): |
| 702 | dml_choice_src_table = self.query_profile.choose_table(self.common_tables) |
| 703 | # Copy the table we want to INSERT/UPSERT INTO. Do this for the following reasons: |
| 704 | # |
| 705 | # 1. If we don't copy, the tables will get larger and larger |
| 706 | # 2. If we want to avoid tables getting larger and larger, we have to come up |
| 707 | # with some threshold about when to cut and start over. |
| 708 | # 3. If we keep INSERT/UPSERTing into tables and finally find a crash, we have to |
| 709 | # replay all previous INSERT/UPSERTs again. Those INSERTs may not produce the |
| 710 | # same rows as before. To maximize the chance of bug reproduction, run every |
| 711 | # INSERT/UPSERT on a pristine table. |
| 712 | dml_table = self._concurrently_copy_table(dml_choice_src_table) |
| 713 | statement = statement_generator.generate_statement( |
| 714 | self.common_tables, dml_table=dml_table) |
| 715 | if isinstance(statement, Query): |
| 716 | # we can re-write statement execution here to possibly be a CREATE TABLE AS SELECT |
| 717 | # or CREATE VIEW AS SELECT |
| 718 | statement.execution = self.query_profile.get_query_execution() |
| 719 | query_count += 1 |
| 720 | LOG.info('Running query #%s', query_count) |
| 721 | result = self.query_result_comparator.compare_query_results(statement) |
| 722 | if result.query_resulted_in_data: |
| 723 | queries_resulted_in_data_count += 1 |
| 724 | if result.modified_rows_count: |
| 725 | count_effective_dml_statements += 1 |
| 726 | count_rows_affected_by_dml += abs( |
| 727 | result.modified_rows_count - self._dml_table_size) |
| 728 | if isinstance(result.exception, DataLimitExceeded) \ |
| 729 | or isinstance(result.exception, TypeOverflow): |
| 730 | continue |
| 731 | if result.error: |
| 732 | # TODO: These first two come from psycopg2, the postgres driver. Maybe we should |