Skip to content

Commit 808a14f

Browse files
Merge pull request #48 from DataKitchen/release/4.22.2
Release/4.22.2
2 parents f6bb51e + eaeb1f7 commit 808a14f

File tree

108 files changed

+1657
-720
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

108 files changed

+1657
-720
lines changed

README.md

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -168,11 +168,7 @@ Verify that you can login to the UI with the `TESTGEN_USERNAME` and `TESTGEN_PAS
168168
The [Data Observability quickstart](https://docs.datakitchen.io/articles/open-source-data-observability/data-observability-overview) walks you through DataOps Data Quality TestGen capabilities to demonstrate how it covers critical use cases for data and analytic teams.
169169

170170
```shell
171-
testgen quick-start --delete-target-db
172-
testgen run-profile --table-group-id 0ea85e17-acbe-47fe-8394-9970725ad37d
173-
testgen run-test-generation --table-group-id 0ea85e17-acbe-47fe-8394-9970725ad37d
174-
testgen run-tests --project-key DEFAULT --test-suite-key default-suite-1
175-
testgen quick-start --simulate-fast-forward
171+
testgen quick-start
176172
```
177173

178174
In the TestGen UI, you will see that new data profiling and test results have been generated.

docs/local_development.md

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,7 @@ testgen setup-system-db --yes
9393

9494
Seed the demo data.
9595
```shell
96-
testgen quick-start --delete-target-db
97-
testgen run-profile --table-group-id 0ea85e17-acbe-47fe-8394-9970725ad37d
98-
testgen run-test-generation --table-group-id 0ea85e17-acbe-47fe-8394-9970725ad37d
99-
testgen run-tests --project-key DEFAULT --test-suite-key default-suite-1
100-
testgen quick-start --simulate-fast-forward
96+
testgen quick-start
10197
```
10298

10399
### Run the Application

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ build-backend = "setuptools.build_meta"
88

99
[project]
1010
name = "dataops-testgen"
11-
version = "4.20.4"
11+
version = "4.22.2"
1212
description = "DataKitchen's Data Quality DataOps TestGen"
1313
authors = [
1414
{ "name" = "DataKitchen, Inc.", "email" = "[email protected]" },

testgen/__main__.py

Lines changed: 30 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,9 @@ def cli(ctx: Context, verbose: bool):
117117
@click.option(
118118
"-tg",
119119
"--table-group-id",
120-
required=False,
120+
required=True,
121121
type=click.STRING,
122122
help="The identifier for the table group used during a profile run. Use a table_group_id shown in list-table-groups.",
123-
default=None,
124123
)
125124
def run_profile(configuration: Configuration, table_group_id: str):
126125
click.echo(f"run-profile with table_group_id: {table_group_id}")
@@ -136,16 +135,15 @@ def run_profile(configuration: Configuration, table_group_id: str):
136135
"-tg",
137136
"--table-group-id",
138137
help="The identifier for the table group used during a profile run. Use a table_group_id shown in list-table-groups.",
139-
required=False,
138+
required=True,
140139
type=click.STRING,
141-
default=None,
142140
)
143141
@click.option(
144142
"-ts",
145143
"--test-suite-key",
146144
help="The identifier for a test suite. Use a test_suite_key shown in list-test-suites.",
147-
required=False,
148-
default=settings.DEFAULT_TEST_SUITE_KEY,
145+
required=True,
146+
type=click.STRING,
149147
)
150148
@click.option(
151149
"-gs",
@@ -339,27 +337,6 @@ def list_test_runs(configuration: Configuration, project_key: str, test_suite_ke
339337

340338

341339
@cli.command("quick-start", help="Use to generate sample target database, for demo purposes.")
342-
@click.option(
343-
"--delete-target-db",
344-
help="Will delete the current target database, if it exists",
345-
is_flag=True,
346-
default=False,
347-
)
348-
@click.option(
349-
"--iteration",
350-
"-i",
351-
default=0,
352-
required=False,
353-
help="The monthly data increment snapshot. Can be 0, 1, 2 or 3. 0 is the initial data.",
354-
)
355-
@click.option(
356-
"--simulate-fast-forward",
357-
"-s",
358-
default=False,
359-
is_flag=True,
360-
required=False,
361-
help="For demo purposes, simulates that some time pass by and the target data is changing. This will call the iterations in order.",
362-
)
363340
@click.option(
364341
"--observability-api-url",
365342
help="Observability API url to be able to export TestGen data to Observability using the command 'export-observability'",
@@ -375,11 +352,10 @@ def list_test_runs(configuration: Configuration, project_key: str, test_suite_ke
375352
default="",
376353
)
377354
@pass_configuration
355+
@click.pass_context
378356
def quick_start(
357+
ctx: Context,
379358
configuration: Configuration,
380-
delete_target_db: bool,
381-
iteration: int,
382-
simulate_fast_forward: bool,
383359
observability_api_url: str,
384360
observability_api_key: str,
385361
):
@@ -388,19 +364,32 @@ def quick_start(
388364
if observability_api_key:
389365
settings.OBSERVABILITY_API_KEY = observability_api_key
390366

391-
# Check if this is an increment or the initial state
392-
if iteration == 0 and not simulate_fast_forward:
393-
click.echo("quick-start command")
394-
run_quick_start(delete_target_db)
367+
click.echo("quick-start command")
368+
run_quick_start(delete_target_db=True)
369+
370+
click.echo("loading initial data")
371+
run_quick_start_increment(0)
372+
minutes_offset = -30*24*60 # 1 month ago
373+
table_group_id="0ea85e17-acbe-47fe-8394-9970725ad37d"
395374

396-
if not simulate_fast_forward:
375+
click.echo(f"run-profile with table_group_id: {table_group_id}")
376+
spinner = None
377+
if not configuration.verbose:
378+
spinner = MoonSpinner("Processing ... ")
379+
message = run_profiling_queries(table_group_id, spinner=spinner, minutes_offset=minutes_offset)
380+
click.echo("\n" + message)
381+
382+
LOG.info(f"run-test-generation with table_group_id: {table_group_id} test_suite: {settings.DEFAULT_TEST_SUITE_KEY}")
383+
message = run_test_gen_queries(table_group_id, settings.DEFAULT_TEST_SUITE_KEY)
384+
click.echo("\n" + message)
385+
386+
run_execution_steps(settings.PROJECT_KEY, settings.DEFAULT_TEST_SUITE_KEY, minutes_offset=minutes_offset)
387+
388+
for iteration in range(1, 4):
389+
click.echo(f"Running iteration: {iteration} / 3")
390+
minutes_offset = -10*24*60 * (3-iteration)
397391
run_quick_start_increment(iteration)
398-
else:
399-
for iteration in range(1, 4):
400-
click.echo(f"Running iteration: {iteration} / 3")
401-
minutes_offset = 2 * iteration
402-
run_quick_start_increment(iteration)
403-
run_execution_steps(settings.PROJECT_KEY, settings.DEFAULT_TEST_SUITE_KEY, minutes_offset=minutes_offset)
392+
run_execution_steps(settings.PROJECT_KEY, settings.DEFAULT_TEST_SUITE_KEY, minutes_offset=minutes_offset)
404393

405394
click.echo("Quick start has successfully finished.")
406395

testgen/commands/queries/execute_tests_query.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,11 @@ def GetTestsNonCAT(self) -> tuple[str, dict]:
143143
query = CleanSQL(query)
144144
return query, params
145145

146-
def AddTestRecordtoTestRunTable(self) -> tuple[str, dict]:
147-
# Runs on App database
148-
return self._get_query("ex_write_test_record_to_testrun_table.sql")
146+
def GetHistoricThresholdUpdate(self) -> tuple[str, dict]:
147+
query, params = self._get_query("ex_update_history_threshold_last_n.sql")
148+
if self._use_clean:
149+
query = CleanSQL(query)
150+
return query, params
149151

150152
def PushTestRunStatusUpdateSQL(self) -> tuple[str, dict]:
151153
# Runs on App database

testgen/commands/queries/generate_tests_query.py

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
from typing import ClassVar, TypedDict
33

44
from testgen.common import CleanSQL, date_service, read_template_sql_file
5-
from testgen.common.database.database_service import get_queries_for_command, replace_params
5+
from testgen.common.database.database_service import replace_params
6+
from testgen.common.read_file import get_template_files
67

78
LOG = logging.getLogger("testgen")
89

@@ -67,11 +68,35 @@ def GetTestTypesSQL(self) -> tuple[str, dict]:
6768

6869
def GetTestDerivationQueriesAsList(self, template_directory: str) -> list[tuple[str, dict]]:
6970
# Runs on App database
70-
params = self._get_params()
71-
queries = get_queries_for_command(template_directory, params)
72-
if self._use_clean:
73-
queries = [ CleanSQL(query) for query in queries ]
74-
return [ (query, params) for query in queries ]
71+
generic_template_directory = template_directory
72+
flavor_template_directory = f"flavors.{self.sql_flavor}.{template_directory}"
73+
74+
query_templates = {}
75+
try:
76+
for query_file in get_template_files(r"^.*sql$", generic_template_directory):
77+
query_templates[query_file.name] = generic_template_directory
78+
except:
79+
LOG.debug(
80+
f"query template '{generic_template_directory}' directory does not exist",
81+
exc_info=True,
82+
stack_info=True,
83+
)
84+
85+
try:
86+
for query_file in get_template_files(r"^.*sql$", flavor_template_directory):
87+
query_templates[query_file.name] = flavor_template_directory
88+
except:
89+
LOG.debug(
90+
f"query template '{generic_template_directory}' directory does not exist",
91+
exc_info=True,
92+
stack_info=True,
93+
)
94+
95+
queries = []
96+
for filename, sub_directory in query_templates.items():
97+
queries.append(self._get_query(filename, sub_directory=sub_directory))
98+
99+
return queries
75100

76101
def GetTestQueriesFromGenericFile(self) -> tuple[str, dict]:
77102
# Runs on App database

testgen/commands/queries/profiling_query.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,18 @@ class CProfilingSQL:
5151
contingency_columns = ""
5252

5353
exception_message = ""
54+
minutes_offset = 0
5455

5556
_data_chars_sql: CRefreshDataCharsSQL = None
5657
_rollup_scores_sql: CRollupScoresSQL = None
5758

58-
def __init__(self, strProjectCode, flavor):
59+
def __init__(self, strProjectCode, flavor, minutes_offset=0):
5960
self.flavor = flavor
6061
self.project_code = strProjectCode
6162
# Defaults
62-
self.run_date = date_service.get_now_as_string()
63-
self.today = date_service.get_now_as_string()
63+
self.run_date = date_service.get_now_as_string_with_offset(minutes_offset)
64+
self.today = date_service.get_now_as_string_with_offset(minutes_offset)
65+
self.minutes_offset = minutes_offset
6466

6567
def _get_data_chars_sql(self) -> CRefreshDataCharsSQL:
6668
if not self._data_chars_sql:
@@ -102,7 +104,7 @@ def _get_params(self) -> dict:
102104
"PROFILE_ID_COLUMN_MASK": self.profile_id_column_mask,
103105
"PROFILE_SK_COLUMN_MASK": self.profile_sk_column_mask,
104106
"START_TIME": self.today,
105-
"NOW_TIMESTAMP": date_service.get_now_as_string(),
107+
"NOW_TIMESTAMP": date_service.get_now_as_string_with_offset(minutes_offset=self.minutes_offset),
106108
"EXCEPTION_MESSAGE": self.exception_message,
107109
"SAMPLING_TABLE": self.sampling_table,
108110
"SAMPLE_SIZE": int(self.parm_sample_size),

testgen/commands/run_execute_tests.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ def run_test_queries(
6868
clsExecute.process_id = process_service.get_current_process_id()
6969

7070
try:
71+
# Update Historic Test Thresholds
72+
LOG.info("CurrentStep: Updating Historic Test Thresholds")
73+
execute_db_queries([clsExecute.GetHistoricThresholdUpdate()])
74+
7175
# Retrieve non-CAT Queries
7276
LOG.info("CurrentStep: Retrieve Non-CAT Queries")
7377
lstTestSet = fetch_dict_from_db(*clsExecute.GetTestsNonCAT())
@@ -123,7 +127,7 @@ def run_execution_steps_in_background(project_code, test_suite):
123127
empty_cache()
124128
background_thread = threading.Thread(
125129
target=run_execution_steps,
126-
args=(project_code, test_suite, session.username),
130+
args=(project_code, test_suite, session.auth.user_display),
127131
)
128132
background_thread.start()
129133
else:

testgen/commands/run_profiling_bridge.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ def run_profiling_in_background(table_group_id):
211211
empty_cache()
212212
background_thread = threading.Thread(
213213
target=run_profiling_queries,
214-
args=(table_group_id, session.username),
214+
args=(table_group_id, session.auth.user_display),
215215
)
216216
background_thread.start()
217217
else:
@@ -221,7 +221,7 @@ def run_profiling_in_background(table_group_id):
221221

222222

223223
@with_database_session
224-
def run_profiling_queries(table_group_id: str, username: str | None = None, spinner: Spinner | None = None):
224+
def run_profiling_queries(table_group_id: str, username: str | None = None, spinner: Spinner | None = None, minutes_offset: int = 0):
225225
if table_group_id is None:
226226
raise ValueError("Table Group ID was not specified")
227227

@@ -240,7 +240,7 @@ def run_profiling_queries(table_group_id: str, username: str | None = None, spin
240240
params = get_profiling_params(table_group_id)
241241

242242
LOG.info("CurrentStep: Initializing Query Generator")
243-
clsProfiling = CProfilingSQL(params["project_code"], connection.sql_flavor)
243+
clsProfiling = CProfilingSQL(params["project_code"], connection.sql_flavor, minutes_offset=minutes_offset)
244244

245245
# Set General Parms
246246
clsProfiling.table_groups_id = table_group_id

testgen/common/date_service.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ def parse_now(value: str) -> datetime:
1717

1818
def get_now_as_string_with_offset(minutes_offset):
1919
ret = datetime.utcnow()
20-
if minutes_offset > 0:
21-
ret = ret + timedelta(minutes=minutes_offset)
20+
ret = ret + timedelta(minutes=minutes_offset)
2221
return ret.strftime("%Y-%m-%d %H:%M:%S")
2322

2423

0 commit comments

Comments
 (0)