dataops-testgen 2.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (270) hide show
  1. dataops_testgen-2.2.0.dist-info/LICENSE +203 -0
  2. dataops_testgen-2.2.0.dist-info/METADATA +287 -0
  3. dataops_testgen-2.2.0.dist-info/NOTICE +5 -0
  4. dataops_testgen-2.2.0.dist-info/RECORD +270 -0
  5. dataops_testgen-2.2.0.dist-info/WHEEL +5 -0
  6. dataops_testgen-2.2.0.dist-info/entry_points.txt +2 -0
  7. dataops_testgen-2.2.0.dist-info/top_level.txt +1 -0
  8. testgen/__init__.py +0 -0
  9. testgen/__main__.py +770 -0
  10. testgen/commands/__init__.py +0 -0
  11. testgen/commands/queries/__init__.py +0 -0
  12. testgen/commands/queries/execute_cat_tests_query.py +95 -0
  13. testgen/commands/queries/execute_tests_query.py +160 -0
  14. testgen/commands/queries/generate_tests_query.py +94 -0
  15. testgen/commands/queries/profiling_query.py +366 -0
  16. testgen/commands/queries/test_parameter_validation_query.py +88 -0
  17. testgen/commands/run_execute_cat_tests.py +162 -0
  18. testgen/commands/run_execute_tests.py +168 -0
  19. testgen/commands/run_generate_tests.py +107 -0
  20. testgen/commands/run_get_entities.py +122 -0
  21. testgen/commands/run_launch_db_config.py +84 -0
  22. testgen/commands/run_observability_exporter.py +330 -0
  23. testgen/commands/run_profiling_bridge.py +495 -0
  24. testgen/commands/run_quick_start.py +168 -0
  25. testgen/commands/run_setup_profiling_tools.py +96 -0
  26. testgen/commands/run_test_definition.py +146 -0
  27. testgen/commands/run_test_parameter_validation.py +135 -0
  28. testgen/commands/run_upgrade_db_config.py +156 -0
  29. testgen/common/__init__.py +8 -0
  30. testgen/common/clean_sql.py +53 -0
  31. testgen/common/credentials.py +25 -0
  32. testgen/common/database/__init__.py +0 -0
  33. testgen/common/database/database_service.py +629 -0
  34. testgen/common/database/flavor/__init__.py +0 -0
  35. testgen/common/database/flavor/flavor_service.py +75 -0
  36. testgen/common/database/flavor/mssql_flavor_service.py +34 -0
  37. testgen/common/database/flavor/postgresql_flavor_service.py +5 -0
  38. testgen/common/database/flavor/redshift_flavor_service.py +22 -0
  39. testgen/common/database/flavor/snowflake_flavor_service.py +69 -0
  40. testgen/common/database/flavor/trino_flavor_service.py +21 -0
  41. testgen/common/date_service.py +68 -0
  42. testgen/common/display_service.py +85 -0
  43. testgen/common/docker_service.py +76 -0
  44. testgen/common/encrypt.py +55 -0
  45. testgen/common/get_pipeline_parms.py +57 -0
  46. testgen/common/logs.py +79 -0
  47. testgen/common/process_service.py +62 -0
  48. testgen/common/read_file.py +69 -0
  49. testgen/settings.py +440 -0
  50. testgen/template/dbsetup/010_create_base_schema.sql +2 -0
  51. testgen/template/dbsetup/020_create_standard_functions_sprocs.sql +179 -0
  52. testgen/template/dbsetup/030_initialize_new_schema_structure.sql +735 -0
  53. testgen/template/dbsetup/040_populate_new_schema_project.sql +59 -0
  54. testgen/template/dbsetup/050_populate_new_schema_metadata.sql +1517 -0
  55. testgen/template/dbsetup/060_create_standard_views.sql +248 -0
  56. testgen/template/dbsetup/070_create_default_users.sql +17 -0
  57. testgen/template/dbsetup/075_grant_role_rights.sql +43 -0
  58. testgen/template/dbsetup/080_set_current_revision.sql +5 -0
  59. testgen/template/dbupgrade/0100_incremental_upgrade.sql +5 -0
  60. testgen/template/dbupgrade/0101_incremental_upgrade.sql +15 -0
  61. testgen/template/dbupgrade/0102_incremental_upgrade.sql +4 -0
  62. testgen/template/dbupgrade/0103_incremental_upgrade.sql +22 -0
  63. testgen/template/dbupgrade/0104_incremental_upgrade.sql +44 -0
  64. testgen/template/dbupgrade/0105_incremental_upgrade.sql +1 -0
  65. testgen/template/dbupgrade/0106_incremental_upgrade.sql +5 -0
  66. testgen/template/dbupgrade/0107_incremental_upgrade.sql +3 -0
  67. testgen/template/dbupgrade_helpers/get_tg_revision.sql +2 -0
  68. testgen/template/exec_cat_tests/ex_cat_build_agg_table_tests.sql +116 -0
  69. testgen/template/exec_cat_tests/ex_cat_get_distinct_tables.sql +11 -0
  70. testgen/template/exec_cat_tests/ex_cat_results_parse.sql +69 -0
  71. testgen/template/exec_cat_tests/ex_cat_retrieve_agg_test_parms.sql +6 -0
  72. testgen/template/exec_cat_tests/ex_cat_test_query.sql +8 -0
  73. testgen/template/execution/ex_finalize_test_run_results.sql +37 -0
  74. testgen/template/execution/ex_get_tests_non_cat.sql +47 -0
  75. testgen/template/execution/ex_update_test_record_in_testrun_table.sql +27 -0
  76. testgen/template/execution/ex_write_test_record_to_testrun_table.sql +6 -0
  77. testgen/template/flavors/generic/exec_query_tests/ex_aggregate_match_no_drops_generic.sql +48 -0
  78. testgen/template/flavors/generic/exec_query_tests/ex_aggregate_match_num_incr_generic.sql +34 -0
  79. testgen/template/flavors/generic/exec_query_tests/ex_aggregate_match_percent_above_generic.sql +49 -0
  80. testgen/template/flavors/generic/exec_query_tests/ex_aggregate_match_percent_within_generic.sql +49 -0
  81. testgen/template/flavors/generic/exec_query_tests/ex_aggregate_match_same_generic.sql +49 -0
  82. testgen/template/flavors/generic/exec_query_tests/ex_custom_query_generic.sql +39 -0
  83. testgen/template/flavors/generic/exec_query_tests/ex_data_match_2way_generic.sql +58 -0
  84. testgen/template/flavors/generic/exec_query_tests/ex_data_match_generic.sql +44 -0
  85. testgen/template/flavors/generic/exec_query_tests/ex_prior_match_generic.sql +37 -0
  86. testgen/template/flavors/generic/exec_query_tests/ex_relative_entropy_generic.sql +53 -0
  87. testgen/template/flavors/generic/exec_query_tests/ex_window_match_no_drops_generic.sql +46 -0
  88. testgen/template/flavors/generic/exec_query_tests/ex_window_match_same_generic.sql +59 -0
  89. testgen/template/flavors/generic/profiling/contingency_counts.sql +3 -0
  90. testgen/template/flavors/generic/validate_tests/ex_get_project_column_list_generic.sql +3 -0
  91. testgen/template/flavors/mssql/exec_query_tests/ex_relative_entropy_mssql.sql +53 -0
  92. testgen/template/flavors/mssql/profiling/project_ddf_query_mssql.sql +35 -0
  93. testgen/template/flavors/mssql/profiling/project_profiling_query_mssql.yaml +246 -0
  94. testgen/template/flavors/mssql/profiling/project_secondary_profiling_query_mssql.sql +36 -0
  95. testgen/template/flavors/mssql/setup_profiling_tools/00_drop_existing_functions_mssql.sql +8 -0
  96. testgen/template/flavors/mssql/setup_profiling_tools/01_create_functions_mssql.sql +12 -0
  97. testgen/template/flavors/mssql/setup_profiling_tools/02_create_functions_mssql.sql +54 -0
  98. testgen/template/flavors/mssql/setup_profiling_tools/create_qc_schema_mssql.sql +4 -0
  99. testgen/template/flavors/mssql/setup_profiling_tools/grant_execute_privileges_mssql.sql +1 -0
  100. testgen/template/flavors/postgresql/exec_query_tests/ex_window_match_no_drops_postgresql.sql +46 -0
  101. testgen/template/flavors/postgresql/exec_query_tests/ex_window_match_same_postgresql.sql +59 -0
  102. testgen/template/flavors/postgresql/profiling/project_ddf_query_postgresql.sql +42 -0
  103. testgen/template/flavors/postgresql/profiling/project_profiling_query_postgresql.yaml +225 -0
  104. testgen/template/flavors/postgresql/profiling/project_secondary_profiling_query_postgresql.sql +28 -0
  105. testgen/template/flavors/postgresql/setup_profiling_tools/create_functions_postgresql.sql +157 -0
  106. testgen/template/flavors/postgresql/setup_profiling_tools/create_qc_schema_postgresql.sql +1 -0
  107. testgen/template/flavors/postgresql/setup_profiling_tools/grant_execute_privileges_postgresql.sql +2 -0
  108. testgen/template/flavors/redshift/profiling/project_ddf_query_redshift.sql +38 -0
  109. testgen/template/flavors/redshift/profiling/project_profiling_query_redshift.yaml +221 -0
  110. testgen/template/flavors/redshift/profiling/project_secondary_profiling_query_redshift.sql +29 -0
  111. testgen/template/flavors/redshift/setup_profiling_tools/create_functions_redshift.sql +115 -0
  112. testgen/template/flavors/redshift/setup_profiling_tools/create_qc_schema_redshift.sql +1 -0
  113. testgen/template/flavors/redshift/setup_profiling_tools/grant_execute_privileges_redshift.sql +2 -0
  114. testgen/template/flavors/snowflake/profiling/project_ddf_query_snowflake.sql +38 -0
  115. testgen/template/flavors/snowflake/profiling/project_profiling_query_snowflake.yaml +220 -0
  116. testgen/template/flavors/snowflake/profiling/project_secondary_profiling_query_snowflake.sql +29 -0
  117. testgen/template/flavors/snowflake/setup_profiling_tools/create_functions_snowflake.sql +69 -0
  118. testgen/template/flavors/snowflake/setup_profiling_tools/create_qc_schema_snowflake.sql +1 -0
  119. testgen/template/flavors/snowflake/setup_profiling_tools/grant_execute_privileges_snowflake.sql +6 -0
  120. testgen/template/flavors/trino/profiling/project_profiling_query_trino.yaml +219 -0
  121. testgen/template/flavors/trino/setup_profiling_tools/create_functions_trino.sql +92 -0
  122. testgen/template/flavors/trino/setup_profiling_tools/create_qc_schema_trino.sql +1 -0
  123. testgen/template/gen_funny_cat_tests/gen_test_constant.sql +104 -0
  124. testgen/template/gen_funny_cat_tests/gen_test_distinct_value_ct.sql +98 -0
  125. testgen/template/gen_funny_cat_tests/gen_test_row_ct.sql +57 -0
  126. testgen/template/gen_funny_cat_tests/gen_test_row_ct_pct.sql +59 -0
  127. testgen/template/generation/gen_delete_old_tests.sql +5 -0
  128. testgen/template/generation/gen_insert_test_suite.sql +5 -0
  129. testgen/template/generation/gen_retrieve_or_insert_test_suite.sql +58 -0
  130. testgen/template/generation/gen_standard_test_type_list.sql +13 -0
  131. testgen/template/generation/gen_standard_tests.sql +48 -0
  132. testgen/template/get_entities/get_connection.sql +21 -0
  133. testgen/template/get_entities/get_connections_list.sql +9 -0
  134. testgen/template/get_entities/get_latest.sql +4 -0
  135. testgen/template/get_entities/get_profile.sql +12 -0
  136. testgen/template/get_entities/get_profile_info.sql +17 -0
  137. testgen/template/get_entities/get_profile_list.sql +17 -0
  138. testgen/template/get_entities/get_profile_screen.sql +275 -0
  139. testgen/template/get_entities/get_project_list.sql +6 -0
  140. testgen/template/get_entities/get_table_group_list.sql +10 -0
  141. testgen/template/get_entities/get_test_generation_list.sql +18 -0
  142. testgen/template/get_entities/get_test_info.sql +41 -0
  143. testgen/template/get_entities/get_test_results_for_run_cli.sql +16 -0
  144. testgen/template/get_entities/get_test_run_list.sql +24 -0
  145. testgen/template/get_entities/get_test_suite.sql +13 -0
  146. testgen/template/get_entities/get_test_suite_list.sql +18 -0
  147. testgen/template/get_entities/list_test_types.sql +4 -0
  148. testgen/template/observability/get_event_data.sql +23 -0
  149. testgen/template/observability/get_test_results.sql +41 -0
  150. testgen/template/observability/update_test_results_exported_to_observability.sql +12 -0
  151. testgen/template/parms/parms_profiling.sql +34 -0
  152. testgen/template/parms/parms_test_execution.sql +13 -0
  153. testgen/template/parms/parms_test_gen.sql +23 -0
  154. testgen/template/profiling/contingency_columns.sql +7 -0
  155. testgen/template/profiling/datatype_suggestions.sql +56 -0
  156. testgen/template/profiling/functional_datatype.sql +523 -0
  157. testgen/template/profiling/functional_tabletype_stage.sql +48 -0
  158. testgen/template/profiling/functional_tabletype_update.sql +8 -0
  159. testgen/template/profiling/pii_flag.sql +133 -0
  160. testgen/template/profiling/profile_anomalies_screen_column.sql +22 -0
  161. testgen/template/profiling/profile_anomalies_screen_multi_column.sql +58 -0
  162. testgen/template/profiling/profile_anomalies_screen_table.sql +22 -0
  163. testgen/template/profiling/profile_anomalies_screen_table_dates.sql +30 -0
  164. testgen/template/profiling/profile_anomalies_screen_variants.sql +40 -0
  165. testgen/template/profiling/profile_anomaly_types_get.sql +3 -0
  166. testgen/template/profiling/project_get_table_sample_count.sql +22 -0
  167. testgen/template/profiling/project_profile_run_record_insert.sql +8 -0
  168. testgen/template/profiling/project_profile_run_record_update.sql +5 -0
  169. testgen/template/profiling/project_profile_run_record_update_status.sql +5 -0
  170. testgen/template/profiling/project_update_profile_results_to_estimates.sql +32 -0
  171. testgen/template/profiling/refresh_anomalies.sql +33 -0
  172. testgen/template/profiling/refresh_data_chars_from_profiling.sql +156 -0
  173. testgen/template/profiling/secondary_profiling_columns.sql +12 -0
  174. testgen/template/profiling/secondary_profiling_delete.sql +4 -0
  175. testgen/template/profiling/secondary_profiling_update.sql +18 -0
  176. testgen/template/quick_start/populate_target_data.sql +1077 -0
  177. testgen/template/quick_start/recreate_target_data_schema.sql +167 -0
  178. testgen/template/quick_start/update_target_data.sql +100 -0
  179. testgen/template/updates/create_tmp_test_definition.sql +19 -0
  180. testgen/template/updates/get_test_def_parms.sql +38 -0
  181. testgen/template/updates/populate_stg_test_definitions.sql +184 -0
  182. testgen/template/validate_tests/ex_disable_tests_test_definitions.sql +5 -0
  183. testgen/template/validate_tests/ex_flag_tests_test_definitions.sql +64 -0
  184. testgen/template/validate_tests/ex_get_project_column_list_generic.sql +3 -0
  185. testgen/template/validate_tests/ex_get_test_column_list_tg.sql +65 -0
  186. testgen/template/validate_tests/ex_write_test_val_errors.sql +22 -0
  187. testgen/ui/__init__.py +0 -0
  188. testgen/ui/app.py +98 -0
  189. testgen/ui/assets/dk_logo.svg +46 -0
  190. testgen/ui/assets/question_mark.png +0 -0
  191. testgen/ui/assets/scripts.js +68 -0
  192. testgen/ui/assets/style.css +140 -0
  193. testgen/ui/bootstrap.py +109 -0
  194. testgen/ui/components/__init__.py +0 -0
  195. testgen/ui/components/frontend/css/KFOlCnqEu92Fr1MmEU9fBBc4.woff2 +0 -0
  196. testgen/ui/components/frontend/css/KFOlCnqEu92Fr1MmEU9fChc4EsA.woff2 +0 -0
  197. testgen/ui/components/frontend/css/KFOmCnqEu92Fr1Mu4mxK.woff2 +0 -0
  198. testgen/ui/components/frontend/css/KFOmCnqEu92Fr1Mu7GxKOzY.woff2 +0 -0
  199. testgen/ui/components/frontend/css/material-symbols-rounded.css +24 -0
  200. testgen/ui/components/frontend/css/material-symbols-rounded.woff2 +0 -0
  201. testgen/ui/components/frontend/css/roboto-font-faces.css +35 -0
  202. testgen/ui/components/frontend/css/shared.css +36 -0
  203. testgen/ui/components/frontend/img/dk_logo.svg +46 -0
  204. testgen/ui/components/frontend/index.html +17 -0
  205. testgen/ui/components/frontend/js/components/breadcrumbs.js +86 -0
  206. testgen/ui/components/frontend/js/components/button.js +66 -0
  207. testgen/ui/components/frontend/js/components/location.js +62 -0
  208. testgen/ui/components/frontend/js/components/select.js +75 -0
  209. testgen/ui/components/frontend/js/components/sidebar.js +358 -0
  210. testgen/ui/components/frontend/js/main.js +99 -0
  211. testgen/ui/components/frontend/js/streamlit.js +19 -0
  212. testgen/ui/components/frontend/js/van.min.js +1 -0
  213. testgen/ui/components/utils/__init__.py +0 -0
  214. testgen/ui/components/utils/callbacks.py +51 -0
  215. testgen/ui/components/utils/component.py +13 -0
  216. testgen/ui/components/widgets/__init__.py +6 -0
  217. testgen/ui/components/widgets/breadcrumbs.py +32 -0
  218. testgen/ui/components/widgets/location.py +65 -0
  219. testgen/ui/components/widgets/modal.py +97 -0
  220. testgen/ui/components/widgets/sidebar.py +69 -0
  221. testgen/ui/navigation/__init__.py +0 -0
  222. testgen/ui/navigation/menu.py +42 -0
  223. testgen/ui/navigation/page.py +20 -0
  224. testgen/ui/navigation/router.py +63 -0
  225. testgen/ui/queries/__init__.py +0 -0
  226. testgen/ui/queries/authentication_queries.py +47 -0
  227. testgen/ui/queries/connection_queries.py +121 -0
  228. testgen/ui/queries/profiling_queries.py +148 -0
  229. testgen/ui/queries/project_queries.py +9 -0
  230. testgen/ui/queries/table_group_queries.py +186 -0
  231. testgen/ui/queries/test_definition_queries.py +270 -0
  232. testgen/ui/queries/test_run_queries.py +32 -0
  233. testgen/ui/queries/test_suite_queries.py +145 -0
  234. testgen/ui/scripts/__init__.py +0 -0
  235. testgen/ui/scripts/patch_streamlit.py +111 -0
  236. testgen/ui/services/__init__.py +0 -0
  237. testgen/ui/services/authentication_service.py +119 -0
  238. testgen/ui/services/connection_service.py +220 -0
  239. testgen/ui/services/database_service.py +282 -0
  240. testgen/ui/services/form_service.py +1008 -0
  241. testgen/ui/services/javascript_service.py +44 -0
  242. testgen/ui/services/query_service.py +316 -0
  243. testgen/ui/services/string_service.py +12 -0
  244. testgen/ui/services/table_group_service.py +130 -0
  245. testgen/ui/services/test_definition_service.py +117 -0
  246. testgen/ui/services/test_run_service.py +13 -0
  247. testgen/ui/services/test_suite_service.py +76 -0
  248. testgen/ui/services/toolbar_service.py +77 -0
  249. testgen/ui/session.py +46 -0
  250. testgen/ui/views/__init__.py +0 -0
  251. testgen/ui/views/app_log_modal.py +92 -0
  252. testgen/ui/views/connections.py +72 -0
  253. testgen/ui/views/connections_base.py +367 -0
  254. testgen/ui/views/login.py +40 -0
  255. testgen/ui/views/not_found.py +16 -0
  256. testgen/ui/views/overview.py +34 -0
  257. testgen/ui/views/profiling_anomalies.py +501 -0
  258. testgen/ui/views/profiling_details.py +335 -0
  259. testgen/ui/views/profiling_modal.py +40 -0
  260. testgen/ui/views/profiling_results.py +206 -0
  261. testgen/ui/views/profiling_summary.py +177 -0
  262. testgen/ui/views/project_settings.py +74 -0
  263. testgen/ui/views/table_groups.py +530 -0
  264. testgen/ui/views/test_definitions.py +1020 -0
  265. testgen/ui/views/test_results.py +908 -0
  266. testgen/ui/views/test_runs.py +195 -0
  267. testgen/ui/views/test_suites.py +545 -0
  268. testgen/utils/__init__.py +0 -0
  269. testgen/utils/plugins.py +17 -0
  270. testgen/utils/singleton.py +14 -0
@@ -0,0 +1,366 @@
1
+ import typing
2
+
3
+ from testgen.common import date_service, read_template_sql_file, read_template_yaml_file
4
+
5
+
6
+ class CProfilingSQL:
7
+ template_path = ""
8
+ dctTemplates: typing.ClassVar = {}
9
+ dctSnippetTemplate: typing.ClassVar = {}
10
+
11
+ project_code = ""
12
+ connection_id = ""
13
+ table_groups_id = ""
14
+ flavor = ""
15
+ run_date = ""
16
+ data_qc_schema = ""
17
+ data_schema = ""
18
+ data_table = ""
19
+
20
+ col_name = ""
21
+ col_gen_type = ""
22
+ col_type = ""
23
+ col_ordinal_position = "0"
24
+
25
+ col_max_char_length = 0
26
+ col_is_decimal = ""
27
+ col_top_freq_update = ""
28
+
29
+ parm_table_set = None
30
+ parm_table_include_mask = None
31
+ parm_table_exclude_mask = None
32
+ parm_do_patterns = "Y"
33
+ parm_max_pattern_length = 30
34
+ parm_do_freqs = "Y"
35
+ parm_max_freq_length = 30
36
+ parm_vldb_flag = "N"
37
+ parm_do_sample = "N"
38
+ parm_sample_size = ""
39
+ profile_run_id = ""
40
+ profile_id_column_mask = ""
41
+ profile_sk_column_mask = ""
42
+ profile_use_sampling = ""
43
+ profile_sample_percent = ""
44
+ profile_sample_min_count = ""
45
+
46
+ sampling_table = ""
47
+ sample_ratio = ""
48
+
49
+ process_id = None
50
+
51
+ contingency_max_values = "4"
52
+ contingency_columns = ""
53
+
54
+ exception_message = ""
55
+
56
+ def __init__(self, strProjectCode, flavor):
57
+ self.flavor = flavor
58
+ self.project_code = strProjectCode
59
+ # Defaults
60
+ self.run_date = date_service.get_now_as_string()
61
+ self.col_ordinal_position = "0"
62
+ self.col_max_char_length = 0
63
+ self.parm_do_patterns = "Y"
64
+ self.parm_max_pattern_length = 25
65
+ self.parm_do_freqs = "Y"
66
+ self.parm_max_freq_length = 25
67
+ self.parm_vldb_flag = "N"
68
+ self.parm_do_sample = "N"
69
+ self.today = date_service.get_now_as_string()
70
+
71
+ def ReplaceParms(self, strInputString):
72
+ strInputString = strInputString.replace("{PROJECT_CODE}", self.project_code)
73
+ strInputString = strInputString.replace("{CONNECTION_ID}", self.connection_id)
74
+ strInputString = strInputString.replace("{TABLE_GROUPS_ID}", self.table_groups_id)
75
+ strInputString = strInputString.replace("{RUN_DATE}", self.run_date)
76
+ strInputString = strInputString.replace("{DATA_SCHEMA}", self.data_schema)
77
+ strInputString = strInputString.replace("{DATA_QC_SCHEMA}", self.data_qc_schema)
78
+ strInputString = strInputString.replace("{DATA_TABLE}", self.data_table)
79
+ strInputString = strInputString.replace("{COL_NAME}", self.col_name)
80
+ strInputString = strInputString.replace("{COL_NAME_SANITIZED}", self.col_name.replace("'", "''"))
81
+ strInputString = strInputString.replace("{COL_GEN_TYPE}", self.col_gen_type)
82
+ strInputString = strInputString.replace("{COL_TYPE}", self.col_type)
83
+ strInputString = strInputString.replace("{COL_POS}", str(self.col_ordinal_position))
84
+ strInputString = strInputString.replace("{TOP_FREQ}", self.col_top_freq_update)
85
+ strInputString = strInputString.replace("{PROFILE_RUN_ID}", self.profile_run_id)
86
+ strInputString = strInputString.replace("{PROFILE_ID_COLUMN_MASK}", self.profile_id_column_mask)
87
+ strInputString = strInputString.replace("{PROFILE_SK_COLUMN_MASK}", self.profile_sk_column_mask)
88
+ strInputString = strInputString.replace("{START_TIME}", self.today)
89
+ strInputString = strInputString.replace("{NOW}", date_service.get_now_as_string())
90
+ strInputString = strInputString.replace("{EXCEPTION_MESSAGE}", self.exception_message)
91
+ strInputString = strInputString.replace("{SAMPLING_TABLE}", self.sampling_table)
92
+ strInputString = strInputString.replace("{SAMPLE_SIZE}", str(self.parm_sample_size))
93
+ strInputString = strInputString.replace("{PROFILE_USE_SAMPLING}", self.profile_use_sampling)
94
+ strInputString = strInputString.replace("{PROFILE_SAMPLE_PERCENT}", self.profile_sample_percent)
95
+ strInputString = strInputString.replace("{PROFILE_SAMPLE_MIN_COUNT}", str(self.profile_sample_min_count))
96
+ strInputString = strInputString.replace("{PROFILE_SAMPLE_RATIO}", str(self.sample_ratio))
97
+ strInputString = strInputString.replace("{PARM_MAX_PATTERN_LENGTH}", str(self.parm_max_pattern_length))
98
+ strInputString = strInputString.replace("{CONTINGENCY_COLUMNS}", self.contingency_columns)
99
+ strInputString = strInputString.replace("{CONTINGENCY_MAX_VALUES}", self.contingency_max_values)
100
+ strInputString = strInputString.replace("{PROCESS_ID}", str(self.process_id))
101
+
102
+ return strInputString
103
+
104
+ def GetSecondProfilingColumnsQuery(self):
105
+ # Runs on DK Postgres Server
106
+ strQ = self.ReplaceParms(read_template_sql_file("secondary_profiling_columns.sql", sub_directory="profiling"))
107
+ return strQ
108
+
109
+ def GetSecondProfilingUpdateQuery(self):
110
+ # Runs on DK Postgres Server
111
+ strQ = self.ReplaceParms(read_template_sql_file("secondary_profiling_update.sql", sub_directory="profiling"))
112
+ return strQ
113
+
114
+ def GetSecondProfilingStageDeleteQuery(self):
115
+ # Runs on DK Postgres Server
116
+ strQ = self.ReplaceParms(read_template_sql_file("secondary_profiling_delete.sql", sub_directory="profiling"))
117
+ return strQ
118
+
119
+ def GetDataTypeSuggestionUpdateQuery(self):
120
+ # Runs on DK Postgres Server
121
+ strQ = self.ReplaceParms(read_template_sql_file("datatype_suggestions.sql", sub_directory="profiling"))
122
+ return strQ
123
+
124
+ def GetFunctionalDataTypeUpdateQuery(self):
125
+ # Runs on DK Postgres Server
126
+ strQ = self.ReplaceParms(read_template_sql_file("functional_datatype.sql", sub_directory="profiling"))
127
+ return strQ
128
+
129
+ def GetFunctionalTableTypeStageQuery(self):
130
+ # Runs on DK Postgres Server
131
+ strQ = self.ReplaceParms(read_template_sql_file("functional_tabletype_stage.sql", sub_directory="profiling"))
132
+ return strQ
133
+
134
+ def GetFunctionalTableTypeUpdateQuery(self):
135
+ # Runs on DK Postgres Server
136
+ strQ = self.ReplaceParms(read_template_sql_file("functional_tabletype_update.sql", sub_directory="profiling"))
137
+ return strQ
138
+
139
+ def GetPIIFlagUpdateQuery(self):
140
+ # Runs on DK Postgres Server
141
+ strQ = self.ReplaceParms(read_template_sql_file("pii_flag.sql", sub_directory="profiling"))
142
+ return strQ
143
+
144
+ def GetAnomalyRefreshQuery(self):
145
+ # Runs on DK Postgres Server
146
+ strQ = self.ReplaceParms(read_template_sql_file("refresh_anomalies.sql", sub_directory="profiling"))
147
+ return strQ
148
+
149
+ def GetAnomalyTestTypesQuery(self):
150
+ # Runs on DK Postgres Server
151
+ strQ = self.ReplaceParms(read_template_sql_file("profile_anomaly_types_get.sql", sub_directory="profiling"))
152
+ return strQ
153
+
154
+ def GetAnomalyTestQuery(self, dct_test_type):
155
+ # Runs on DK Postgres Server
156
+ strQ = None
157
+
158
+ match dct_test_type["data_object"]:
159
+ case "Column":
160
+ strQ = read_template_sql_file("profile_anomalies_screen_column.sql", sub_directory="profiling")
161
+ case "Multi-Col":
162
+ strQ = read_template_sql_file("profile_anomalies_screen_multi_column.sql", sub_directory="profiling")
163
+ case "Dates":
164
+ strQ = read_template_sql_file("profile_anomalies_screen_table_dates.sql", sub_directory="profiling")
165
+ case "Table":
166
+ strQ = read_template_sql_file("profile_anomalies_screen_table.sql", sub_directory="profiling")
167
+ case "Variant":
168
+ strQ = read_template_sql_file("profile_anomalies_screen_variants.sql", sub_directory="profiling")
169
+
170
+ if strQ:
171
+ strQ = strQ.replace("{ANOMALY_ID}", dct_test_type["id"])
172
+ strQ = strQ.replace("{DETAIL_EXPRESSION}", dct_test_type["detail_expression"])
173
+ strQ = strQ.replace("{ANOMALY_CRITERIA}", dct_test_type["anomaly_criteria"])
174
+ strQ = self.ReplaceParms(strQ)
175
+
176
+ return strQ
177
+
178
+ def GetDataCharsRefreshQuery(self):
179
+ # Runs on DK Postgres Server
180
+ strQ = self.ReplaceParms(
181
+ read_template_sql_file("refresh_data_chars_from_profiling.sql", sub_directory="profiling")
182
+ )
183
+ return strQ
184
+
185
+ def GetProfileRunInfoRecordsQuery(self):
186
+ # Runs on DK Postgres Server
187
+ strQ = self.ReplaceParms(
188
+ read_template_sql_file("project_profile_run_record_insert.sql", sub_directory="profiling")
189
+ )
190
+ return strQ
191
+
192
+ def GetProfileRunInfoRecordUpdateQuery(self):
193
+ # Runs on DK Postgres Server
194
+ strQ = self.ReplaceParms(
195
+ read_template_sql_file("project_profile_run_record_update.sql", sub_directory="profiling")
196
+ )
197
+ return strQ
198
+
199
+ def GetDDFQuery(self):
200
+ # Runs on Project DB
201
+
202
+ strQ = self.ReplaceParms(
203
+ read_template_sql_file(
204
+ f"project_ddf_query_{self.flavor}.sql", sub_directory=f"flavors/{self.flavor}/profiling"
205
+ )
206
+ )
207
+
208
+ strTableCriteria = ""
209
+ if self.parm_table_set:
210
+ strTableCriteria += " AND c.table_name IN (" + self.parm_table_set + ")"
211
+ strTableCriteria += self._get_mask_query(self.parm_table_include_mask, is_include=True)
212
+ strTableCriteria += self._get_mask_query(self.parm_table_exclude_mask, is_include=False)
213
+ strQ = strQ.replace("{TABLE_CRITERIA}", strTableCriteria)
214
+
215
+ return strQ
216
+
217
+ def _get_mask_query(self, mask, is_include):
218
+ sub_query = ""
219
+ if mask:
220
+ sub_query += " AND (" if is_include else " AND NOT ("
221
+ is_first = True
222
+ for item in mask.split(","):
223
+ if not is_first:
224
+ sub_query += " OR "
225
+ sub_query += "(c.table_name LIKE '" + item.strip() + "')"
226
+ is_first = False
227
+ sub_query += ")"
228
+ return sub_query
229
+
230
+ def GetFunctionCreatorQuery(self):
231
+ # Runs on Project DB
232
+ strQ = self.ReplaceParms(
233
+ read_template_sql_file(
234
+ f"project_function_creator_{self.flavor}.sql",
235
+ sub_directory=f"flavors/{self.flavor}/setup_profiling_tools",
236
+ )
237
+ )
238
+ return strQ
239
+
240
+ def GetProfilingQuery(self):
241
+ # Runs on Project DB
242
+ if not self.dctSnippetTemplate:
243
+ self.dctSnippetTemplate = read_template_yaml_file(
244
+ f"project_profiling_query_{self.flavor}.yaml", sub_directory=f"flavors/{self.flavor}/profiling"
245
+ )
246
+
247
+ dctSnippetTemplate = self.dctSnippetTemplate
248
+
249
+ # Assemble in function
250
+ strQ = ""
251
+
252
+ if self.parm_do_sample == "Y":
253
+ strQ += dctSnippetTemplate["strTemplate01_sampling"]
254
+ else:
255
+ strQ += dctSnippetTemplate["strTemplate01_else"]
256
+
257
+ strQ += dctSnippetTemplate["strTemplate02_all"]
258
+
259
+ if self.col_gen_type in ["A", "D", "N"]:
260
+ strQ += dctSnippetTemplate["strTemplate03_ADN"]
261
+ else:
262
+ strQ += dctSnippetTemplate["strTemplate03_else"]
263
+
264
+ if self.col_gen_type == "A":
265
+ strQ += dctSnippetTemplate["strTemplate04_A"]
266
+ elif self.col_gen_type == "N":
267
+ strQ += dctSnippetTemplate["strTemplate04_N"]
268
+ else:
269
+ strQ += dctSnippetTemplate["strTemplate04_else"]
270
+
271
+ if self.col_gen_type == "A":
272
+ strQ += dctSnippetTemplate["strTemplate05_A"]
273
+ else:
274
+ strQ += dctSnippetTemplate["strTemplate05_else"]
275
+
276
+ if self.col_gen_type == "A" and self.parm_do_patterns == "Y":
277
+ strQ += dctSnippetTemplate["strTemplate06_A_patterns"]
278
+ else:
279
+ strQ += dctSnippetTemplate["strTemplate06_else"]
280
+
281
+ strQ += dctSnippetTemplate["strTemplate07_else"]
282
+
283
+ if self.col_gen_type == "N":
284
+ strQ += dctSnippetTemplate["strTemplate08_N"]
285
+ else:
286
+ strQ += dctSnippetTemplate["strTemplate08_else"]
287
+
288
+ if self.col_gen_type == "N" and self.col_is_decimal == True:
289
+ strQ += dctSnippetTemplate["strTemplate10_N_dec"]
290
+ else:
291
+ strQ += dctSnippetTemplate["strTemplate10_else"]
292
+
293
+ if self.col_gen_type == "D":
294
+ strQ += dctSnippetTemplate["strTemplate11_D"]
295
+ else:
296
+ strQ += dctSnippetTemplate["strTemplate11_else"]
297
+ if self.col_gen_type == "B":
298
+ strQ += dctSnippetTemplate["strTemplate12_B"]
299
+ else:
300
+ strQ += dctSnippetTemplate["strTemplate12_else"]
301
+
302
+ strQ += dctSnippetTemplate["strTemplate13_ALL"]
303
+
304
+ if self.col_gen_type == "A":
305
+ if self.parm_do_patterns == "Y":
306
+ strQ += dctSnippetTemplate["strTemplate14_A_do_patterns"]
307
+ else:
308
+ strQ += dctSnippetTemplate["strTemplate14_A_no_patterns"]
309
+ else:
310
+ strQ += dctSnippetTemplate["strTemplate14_else"]
311
+
312
+ strQ += dctSnippetTemplate["strTemplate15_ALL"]
313
+
314
+ strQ += dctSnippetTemplate["strTemplate16_ALL"]
315
+
316
+ if self.parm_do_sample == "Y":
317
+ strQ += dctSnippetTemplate["strTemplate98_sampling"]
318
+ else:
319
+ strQ += dctSnippetTemplate["strTemplate98_else"]
320
+
321
+ if self.col_gen_type == "N":
322
+ strQ += dctSnippetTemplate["strTemplate99_N"]
323
+ else:
324
+ strQ += dctSnippetTemplate["strTemplate99_else"]
325
+
326
+ if self.parm_do_sample == "Y":
327
+ strQ += dctSnippetTemplate["strTemplate100_sampling"]
328
+
329
+ strQ = self.ReplaceParms(strQ)
330
+
331
+ return strQ
332
+
333
+ def GetSecondProfilingQuery(self):
334
+ # Runs on Project DB
335
+ strQ = self.ReplaceParms(
336
+ read_template_sql_file(
337
+ f"project_secondary_profiling_query_{self.flavor}.sql", sub_directory=f"flavors/{self.flavor}/profiling"
338
+ )
339
+ )
340
+ return strQ
341
+
342
+ def GetTableSampleCount(self):
343
+ # Runs on Project DB
344
+ strQ = self.ReplaceParms(
345
+ read_template_sql_file("project_get_table_sample_count.sql", sub_directory="profiling")
346
+ )
347
+ return strQ
348
+
349
+ def GetContingencyColumns(self):
350
+ # Runs on Project DB
351
+ strQ = self.ReplaceParms(read_template_sql_file("contingency_columns.sql", sub_directory="profiling"))
352
+ return strQ
353
+
354
+ def GetContingencyCounts(self):
355
+ # Runs on Project DB
356
+ strQ = self.ReplaceParms(
357
+ read_template_sql_file("contingency_counts.sql", sub_directory="flavors/generic/profiling")
358
+ )
359
+ return strQ
360
+
361
+ def UpdateProfileResultsToEst(self):
362
+ # Runs on Project DB
363
+ strQ = self.ReplaceParms(
364
+ read_template_sql_file("project_update_profile_results_to_estimates.sql", sub_directory="profiling")
365
+ )
366
+ return strQ
@@ -0,0 +1,88 @@
1
+ import typing
2
+
3
+ from testgen.common import CleanSQL, date_service, read_template_sql_file
4
+
5
+
6
+ class CTestParamValidationSQL:
7
+ flavor = ""
8
+ run_date = ""
9
+ test_run_id = ""
10
+ project_code = ""
11
+ test_suite = ""
12
+ test_schemas = ""
13
+ missing_columns = ""
14
+ missing_tables = ""
15
+ exception_message = ""
16
+ flag_val = ""
17
+
18
+ # Test Set Parameters
19
+ dctTestParms: typing.ClassVar = {}
20
+
21
+ def __init__(self, strProjectCode, strFlavor, strTestSuite):
22
+ self.project_code = strProjectCode
23
+ self.flavor = strFlavor
24
+ self.test_suite = strTestSuite
25
+ self.today = date_service.get_now_as_string()
26
+
27
+ def _ReplaceParms(self, strInputString):
28
+ strInputString = strInputString.replace("{PROJECT_CODE}", self.project_code)
29
+ strInputString = strInputString.replace("{TEST_SUITE}", self.test_suite)
30
+ strInputString = strInputString.replace("{RUN_DATE}", self.run_date)
31
+ strInputString = strInputString.replace("{TEST_RUN_ID}", self.test_run_id)
32
+ strInputString = strInputString.replace("{FLAG}", self.flag_val)
33
+ strInputString = strInputString.replace("{TEST_SCHEMAS}", self.test_schemas)
34
+ strInputString = strInputString.replace("{MISSING_COLUMNS}", self.missing_columns)
35
+ strInputString = strInputString.replace("{MISSING_TABLES}", self.missing_tables)
36
+ strInputString = strInputString.replace("{EXCEPTION_MESSAGE}", self.exception_message)
37
+ strInputString = strInputString.replace("{MISSING_COLUMNS_NO_QUOTES}", self.missing_columns.replace("'", ""))
38
+ strInputString = strInputString.replace("{MISSING_TABLES_NO_QUOTES}", self.missing_tables.replace("'", ""))
39
+ strInputString = strInputString.replace("{START_TIME}", self.today)
40
+ strInputString = strInputString.replace("{NOW}", date_service.get_now_as_string())
41
+
42
+ for parm, value in self.dctTestParms.items():
43
+ strInputString = strInputString.replace("{" + parm.upper() + "}", value)
44
+
45
+ return strInputString
46
+
47
+ def ClearTestParms(self):
48
+ # Test Set Parameters
49
+ pass
50
+
51
+ def GetTestValidationColumns(self, booClean):
52
+ # Runs on DK DB
53
+ strQ = self._ReplaceParms(read_template_sql_file("ex_get_test_column_list_tg.sql", "validate_tests"))
54
+ if booClean:
55
+ strQ = CleanSQL(strQ)
56
+
57
+ return strQ
58
+
59
+ def GetProjectTestValidationColumns(self):
60
+ # Runs on Project DB
61
+ strQ = self._ReplaceParms(
62
+ read_template_sql_file("ex_get_project_column_list_generic.sql", "flavors/generic/validate_tests")
63
+ )
64
+
65
+ return strQ
66
+
67
+ def FlagTestsWithFailedValidation(self):
68
+ # Runs on Project DB
69
+ strQ = self._ReplaceParms(read_template_sql_file("ex_flag_tests_test_definitions.sql", "validate_tests"))
70
+
71
+ return strQ
72
+
73
+ def DisableTestsWithFailedValidation(self):
74
+ # Runs on Project DB
75
+ strQ = self._ReplaceParms(read_template_sql_file("ex_disable_tests_test_definitions.sql", "validate_tests"))
76
+
77
+ return strQ
78
+
79
+ def ReportTestValidationErrors(self):
80
+ # Runs on Project DB
81
+ strQ = self._ReplaceParms(read_template_sql_file("ex_write_test_val_errors.sql", "validate_tests"))
82
+
83
+ return strQ
84
+
85
+ def PushTestRunStatusUpdateSQL(self):
86
+ strQ = self._ReplaceParms(read_template_sql_file("ex_update_test_record_in_testrun_table.sql", "execution"))
87
+
88
+ return strQ
@@ -0,0 +1,162 @@
1
+ import logging
2
+
3
+ from testgen.commands.queries.execute_cat_tests_query import CCATExecutionSQL
4
+ from testgen.common import (
5
+ AssignConnectParms,
6
+ RetrieveDBResultsToDictList,
7
+ RetrieveTestExecParms,
8
+ RunActionQueryList,
9
+ RunThreadedRetrievalQueryList,
10
+ WriteListToDB,
11
+ )
12
+
13
+ LOG = logging.getLogger("testgen")
14
+
15
+
16
+ def RetrieveTargetTables(clsCATExecute):
17
+ # Gets distinct list of tables to be tested, to aggregate tests by table, from dk db
18
+ strQuery = clsCATExecute.GetDistinctTablesSQL()
19
+ lstTables = RetrieveDBResultsToDictList("DKTG", strQuery)
20
+
21
+ if len(lstTables) == 0:
22
+ LOG.info("0 tables in the list for CAT test execution.")
23
+
24
+ return lstTables
25
+
26
+
27
+ def AggregateTableTests(clsCATExecute):
28
+ # Writes records of aggregated tests per table and sequence number
29
+ # (to prevent table queries from getting too large) to dk db.
30
+ strQuery = clsCATExecute.GetAggregateTableTestSQL()
31
+ lstQueries = [strQuery]
32
+ RunActionQueryList("DKTG", lstQueries)
33
+
34
+
35
+ def RetrieveTestParms(clsCATExecute):
36
+ # Retrieves records of aggregated tests to run as queries from dk db
37
+ strQuery = clsCATExecute.GetAggregateTestParmsSQL()
38
+ lstResults = RetrieveDBResultsToDictList("DKTG", strQuery)
39
+
40
+ return lstResults
41
+
42
+
43
+ def PrepCATQueries(clsCATExecute, lstCATParms):
44
+ # Prepares CAT Queries and populates query list
45
+ LOG.info("CurrentStep: Preparing CAT Queries")
46
+ lstQueries = []
47
+ for dctCATQuery in lstCATParms:
48
+ clsCATExecute.target_schema = dctCATQuery["schema_name"]
49
+ clsCATExecute.target_table = dctCATQuery["table_name"]
50
+ clsCATExecute.dctTestParms = dctCATQuery
51
+ strQuery = clsCATExecute.PrepCATQuerySQL()
52
+ lstQueries.append(strQuery)
53
+
54
+ return lstQueries
55
+
56
+
57
+ def ParseCATResults(clsCATExecute):
58
+ # Parses aggregate results to individual test_result records at dk db
59
+ strQuery = clsCATExecute.GetCATResultsParseSQL()
60
+ RunActionQueryList("DKTG", [strQuery])
61
+
62
+
63
+ def FinalizeTestRun(clsCATExecute):
64
+ lstQueries = [clsCATExecute.FinalizeTestResultsSQL(), clsCATExecute.PushTestRunStatusUpdateSQL()]
65
+ RunActionQueryList(("DKTG"), lstQueries)
66
+
67
+
68
+ def run_cat_test_queries(
69
+ strTestRunID, strTestTime, strProjectCode, strTestSuite, error_msg, minutes_offset=0, spinner=None
70
+ ):
71
+ # PARAMETERS AND SET-UP
72
+ booErrors = False
73
+ LOG.info("CurrentStep: Retrieving Parameters")
74
+
75
+ dctParms = RetrieveTestExecParms(strProjectCode, strTestSuite)
76
+
77
+ LOG.info("CurrentStep: Initializing CAT Query Generator")
78
+ clsCATExecute = CCATExecutionSQL(
79
+ strProjectCode, strTestSuite, dctParms["sql_flavor"], dctParms["max_query_chars"], minutes_offset
80
+ )
81
+ clsCATExecute.test_run_id = strTestRunID
82
+ clsCATExecute.run_date = strTestTime
83
+ clsCATExecute.exception_message += error_msg
84
+
85
+ # Set Project Connection Params in common.db_bridgers from retrieved params
86
+ LOG.info("CurrentStep: Assigning Connection Parms")
87
+ AssignConnectParms(
88
+ dctParms["project_code"],
89
+ dctParms["connection_id"],
90
+ dctParms["project_host"],
91
+ dctParms["project_port"],
92
+ dctParms["project_db"],
93
+ dctParms["table_group_schema"],
94
+ dctParms["project_user"],
95
+ dctParms["sql_flavor"],
96
+ dctParms["url"],
97
+ dctParms["connect_by_url"],
98
+ dctParms["connect_by_key"],
99
+ dctParms["private_key"],
100
+ dctParms["private_key_passphrase"],
101
+ "PROJECT",
102
+ )
103
+
104
+ # START TEST EXECUTION
105
+
106
+ if spinner:
107
+ spinner.next()
108
+
109
+ lstAllResults = []
110
+
111
+ try:
112
+ # Retrieve distinct target tables from metadata
113
+ LOG.info("CurrentStep: Retrieving Target Tables")
114
+ lstTables = RetrieveTargetTables(clsCATExecute)
115
+ LOG.info("Test Tables Identified: %s", len(lstTables))
116
+
117
+ if lstTables:
118
+ LOG.info("CurrentStep: Aggregating CAT Tests per Table")
119
+ for dctTable in lstTables:
120
+ clsCATExecute.target_schema = dctTable["schema_name"]
121
+ clsCATExecute.target_table = dctTable["table_name"]
122
+ clsCATExecute.replace_qc_schema = dctTable["replace_qc_schema"]
123
+ AggregateTableTests(clsCATExecute)
124
+
125
+ LOG.info("CurrentStep: Retrieving CAT Tests to Run")
126
+ lstCATParms = RetrieveTestParms(clsCATExecute)
127
+
128
+ lstCATQueries = PrepCATQueries(clsCATExecute, lstCATParms)
129
+ if lstCATQueries:
130
+ LOG.info("CurrentStep: Performing CAT Tests")
131
+ lstAllResults, lstResultColumnNames, intErrors = RunThreadedRetrievalQueryList(
132
+ "PROJECT", lstCATQueries, dctParms["max_threads"], spinner
133
+ )
134
+
135
+ if lstAllResults:
136
+ LOG.info("CurrentStep: Saving CAT Results")
137
+ # Write aggregate result records to aggregate result table at dk db
138
+ WriteListToDB("DKTG", lstAllResults, lstResultColumnNames, "working_agg_cat_results")
139
+ LOG.info("CurrentStep: Parsing CAT Results")
140
+ ParseCATResults(clsCATExecute)
141
+ LOG.info("Test results successfully parsed.")
142
+ if intErrors > 0:
143
+ booErrors = True
144
+ cat_error_msg = f"Errors were encountered executing aggregate tests. ({intErrors} errors occurred.) Please check log."
145
+ LOG.warning(cat_error_msg)
146
+ clsCATExecute.exception_message += cat_error_msg
147
+ else:
148
+ LOG.info("No valid tests were available to perform")
149
+
150
+ except Exception as e:
151
+ booErrors = True
152
+ sqlsplit = e.args[0].split("[SQL", 1)
153
+ errorline = sqlsplit[0].replace("'", "''") if len(sqlsplit) > 0 else "unknown error"
154
+ clsCATExecute.exception_message += f"{type(e).__name__}: {errorline}"
155
+ raise
156
+
157
+ else:
158
+ return booErrors
159
+
160
+ finally:
161
+ LOG.info("Finalizing test run")
162
+ FinalizeTestRun(clsCATExecute)