Skip to content

Commit

Permalink
Issue #152: probes unit tests. (#253)
Browse files Browse the repository at this point in the history
- renamed one of the tests to reflect what it actually does.
	    - when  #241 is fixed, tests will need to be adjusted as well.
  • Loading branch information
vqmarkman authored Sep 6, 2023
1 parent 37c470f commit bd7bb02
Show file tree
Hide file tree
Showing 4 changed files with 267 additions and 101 deletions.
12 changes: 12 additions & 0 deletions test/common_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,15 @@ def delete_list_of_labels(conn, sql):
assert "done" in str(
run_proc(conn, delete_label_statement)
), "Stored procedure output does not match expected result!"


def delete_list_of_probes(conn, sql):
print(f"[INFO] SQL in delete function: {sql}")

with conn() as cnx:
cur = cnx.cursor()
for name in cur.execute(sql).fetchall():
delete_probe_statement = f"call ADMIN.DELETE_PROBE('{name[0]}');"
assert "done" in str(
run_proc(conn, delete_probe_statement)
), "Stored procedure output does not match expected result!"
8 changes: 7 additions & 1 deletion test/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import datetime
import pytest
from contextlib import contextmanager
from common_utils import delete_list_of_labels
from common_utils import delete_list_of_labels, delete_list_of_probes

sys.path.append("../deploy")
import helpers # noqa E402
Expand Down Expand Up @@ -62,3 +62,9 @@ def timestamp_string(conn):

# call a function that deletes all the labels that were created in the session
delete_list_of_labels(conn, sql)

sql = f"select name from INTERNAL.PROBES where name like '%{ts}%'"
print(f"[INFO] SQL stmt to find all the probes: {sql}")

# call a function that deletes all the labels that were created in the session
delete_list_of_probes(conn, sql)
237 changes: 137 additions & 100 deletions test/unit/test_probe_procs.py
Original file line number Diff line number Diff line change
@@ -1,111 +1,148 @@
from __future__ import annotations

import pytest
from common_utils import generate_unique_name
from common_utils import run_proc
from common_utils import row_count
from common_utils import run_sql
import time


def test_initialize_then_migrate_probes(conn, timestamp_string):
# step 1: clean up the probes table and predefined_probes table
sql = "truncate table internal.probes"
assert "successfully" in str(
run_sql(conn, sql)
), "SQL output does not match expected result!"
def test_smoke_create_drop_probe(conn, timestamp_string):
probe = generate_unique_name("probe", timestamp_string)
sql = f"CALL ADMIN.CREATE_PROBE('{probe}', 'rows_produced > 100', True :: BOOLEAN, 'SLACK', '[email protected]', 'SLACK', False :: BOOLEAN);"

# create_probe returns NULL in case of successful probe creation
assert run_proc(conn, sql) is None, "Stored procedure did not return NULL value!"

# make sure it was created with correct properties
sql = f"""select count(*) from INTERNAL.probes where
name = '{probe}' and
condition = 'rows_produced > 100' and
notify_writer and
notify_writer_method = 'SLACK' and
notify_other = '[email protected]' and
notify_other_method = 'SLACK' and
probe_created_at is null and
probe_modified_at is not null and
not cancel and
enabled is null
"""
assert row_count(conn, sql) == 1, "Probe was not found!"

# drop probe
sql = f"call ADMIN.DELETE_PROBE('{probe}');"
assert run_proc(conn, sql) == "done", "Stored procedure did not return NULL value!"


# Test that validates that we get correct error on attempt to create probe with existing name
def test_create_probe_with_existing_name(conn, timestamp_string):

probe = generate_unique_name("probe", timestamp_string)
sql = f"CALL ADMIN.CREATE_PROBE('{probe}', 'rows_produced > 100', True :: BOOLEAN, 'SLACK', '[email protected]', 'SLACK', False :: BOOLEAN);"
assert run_proc(conn, sql) is None, "Stored procedure did not return NULL value!"

assert (
run_proc(conn, sql)
== "A probe with this name already exists. Please choose a distinct name."
), "Stored procedure output does not match expected result!"

sql = "truncate table internal.predefined_probes"
assert "successfully" in str(
run_sql(conn, sql)
), "SQL output does not match expected result!"

# step 2: clean up the flag in internal.config
sql = "delete from internal.config where KEY = 'PROBES_INITED'"
run_sql(conn, sql)
def test_smoke_update_probe(conn, timestamp_string):
probe = generate_unique_name("probe", timestamp_string)
sql = f"CALL ADMIN.CREATE_PROBE('{probe}', 'compilation_time > 50000', True :: BOOLEAN, 'EMAIL', '[email protected]', 'EMAIL', False :: BOOLEAN);"

# create_probe returns NULL in case of successful probe creation
assert run_proc(conn, sql) is None, "Stored procedure did not return NULL value!"

# make sure it was created with correct properties
sql = f"""select count(*) from INTERNAL.probes where
name = '{probe}' and
condition = 'compilation_time > 50000' and
notify_writer and
notify_writer_method = 'EMAIL' and
notify_other = '[email protected]' and
notify_other_method = 'EMAIL' and
probe_created_at is null and
probe_modified_at is not null and
not cancel and
enabled is null
"""
assert row_count(conn, sql) == 1, "Label was not found!"

# update probe
sql = f"CALL ADMIN.UPDATE_PROBE('{probe}', '{probe}', 'rows_produced = 1000', True :: BOOLEAN, 'SLACK', '[email protected]', 'SLACK', False :: BOOLEAN);"
assert run_proc(conn, sql) is None, "Stored procedure did not return NULL value!"

# step 3: populate predefined_probes table
sql = "CALL INTERNAL.POPULATE_PREDEFINED_PROBES();"
# validate that probe was updated correctly
sql = f"""select count(*) from INTERNAL.probes where
name = '{probe}' and
condition = 'rows_produced = 1000' and
notify_writer and
notify_writer_method = 'SLACK' and
notify_other = '[email protected]' and
notify_other_method = 'SLACK' and
probe_created_at is null and
probe_modified_at is not null and
not cancel and
enabled is null
"""
assert row_count(conn, sql) == 1, "Probe was not found!"


# Test that validates that we can create/drop probe with empty string for name
# Legal in Snowflake
def test_create_probe_with_empty_string_name(conn, timestamp_string):

sql = "CALL ADMIN.CREATE_PROBE('', 'compilation_time > 50000', True :: BOOLEAN, 'EMAIL', '[email protected]', 'EMAIL', False :: BOOLEAN);"
assert run_proc(conn, sql) is None, "Stored procedure did not return NULL value!"

sql = "select count(*) from internal.PREDEFINED_PROBES"
output = row_count(conn, sql)
assert output > 0, "SQL output " + str(output) + " does not match expected result!"

# step 4: call internal.initialize_probes()
sql = "call INTERNAL.INITIALIZE_PROBES()"
output = str(run_sql(conn, sql))
assert "True" in output, "SQL output" + output + " does not match expected result!"

# step 5: verify rows in probes table
sql = "select count(*) from internal.PROBES"
output = row_count(conn, sql)
assert output > 0, "SQL output " + str(output) + " does not match expected result!"

# step 6: verify flag in internal.config
sql = "call internal.get_config('PROBES_INITED')"
output = str(run_sql(conn, sql))
assert "True" in output, "SQL output" + output + " does not match expected result!"

# step 7: call internal.initialize_probes() again
sql = "call INTERNAL.INITIALIZE_PROBES()"
output = str(run_sql(conn, sql))
assert "False" in output, "SQL output" + output + " does not match expected result!"

# step 8: verify rows in probes table
sql = "select count(*) from internal.PROBES"
output = row_count(conn, sql)
assert output > 0, "SQL output " + str(output) + " does not match expected result!"

# step 9: sleep 5 seconds
time.sleep(5)

# step 10: call internal.migrate_predefined_probes()
sql = "call INTERNAL.MIGRATE_PREDEFINED_PROBES(5)"
output = str(run_sql(conn, sql))
assert "True" in output, "SQL output" + output + " does not match expected result!"

# step 11: insert a new predefined probe to PREDEFIEND_PROBES
sql = "INSERT INTO INTERNAL.PREDEFINED_PROBES (name, condition, PROBE_CREATED_AT, PROBE_MODIFIED_AT) values ('NEW PREDEFINED PROBE', 'bytes_scanned > 10000', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)"
run_sql(conn, sql)

# step 12: call internal.migrate_predefined_probes(). Migration should return true, since we have a new predefined probe.
sql = "call INTERNAL.MIGRATE_PREDEFINED_PROBES(5)"
output = str(run_sql(conn, sql))
assert "True" in output, "SQL output" + output + " does not match expected result!"

# step 13: verify probes table has the new added predefinend probe "NEW PREDEFINED PROBE"
sql = "select count(*) from internal.PROBES where name = 'NEW PREDEFINED PROBE'"
rowcount = row_count(conn, sql)
assert rowcount == 1, (
"SQL output " + str(rowcount) + " does not match expected result!"
)

# step 14: update the condition of 'NEW PREDEFINED PROBE'
sql = "UPDATE INTERNAL.PREDEFINED_PROBES SET CONDITION = 'bytes_scanned > 20000 ' where NAME = 'NEW PREDEFINED PROBE'"
run_sql(conn, sql)

# step 15: call internal.migrate_predefined_probes(). Migration should return true, since we modify condition of one old predefined probes.
time.sleep(5)

sql = "call INTERNAL.MIGRATE_PREDEFINED_probes(5)"
output = str(run_sql(conn, sql))
assert "True" in output, "SQL output" + output + " does not match expected result!"

# step 16: insert a row into user's PROBES
sql = "INSERT INTO INTERNAL.PROBES (name, condition, PROBE_CREATED_AT, PROBE_MODIFIED_AT) values ('test', 'bytes_scanned > 100', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)"
run_sql(conn, sql)

## step 17: MIGRATE_PREDEFINED_PROBES should return False, because user adds one PROBE
sql = "call INTERNAL.MIGRATE_PREDEFINED_PROBES(5)"
output = str(run_sql(conn, sql))
assert "False" in output, "SQL output" + output + " does not match expected result!"

# step 18: clean up the probes table and predefined_probes table
sql = "truncate table internal.probes"
assert "successfully" in str(
run_sql(conn, sql)
), "SQL output does not match expected result!"

sql = "truncate table internal.predefined_probes"
assert "successfully" in str(
run_sql(conn, sql)
), "SQL output does not match expected result!"
sql = "call ADMIN.DELETE_PROBE('');"
assert "done" in str(
run_proc(conn, sql)
), "Stored procedure output does not match expected result!"


# List of test cases with statements and expected error messages
test_cases = [
(
"CALL ADMIN.CREATE_PROBE(NULL, 'rows_produced > 100', True :: BOOLEAN, 'SLACK', '[email protected]', 'SLACK', False :: BOOLEAN);",
"Name must not be null.",
),
(
"CALL ADMIN.CREATE_PROBE('{probe}', NULL, True :: BOOLEAN, 'SLACK', '[email protected]', 'SLACK', False :: BOOLEAN);",
"Condition must not be null.",
),
(
"CALL ADMIN.CREATE_PROBE('{probe}', 'x=y and z is not null', True :: BOOLEAN, 'SLACK', '[email protected]', 'SLACK', False :: BOOLEAN);",
"Invalid condition SQL. Please check your syntax.",
),
(
"CALL ADMIN.CREATE_PROBE('{probe}', 'blah blah and ', True :: BOOLEAN, 'SLACK', '[email protected]', 'SLACK', False :: BOOLEAN);",
"Invalid condition SQL. Please check your syntax.",
),
(
"CALL ADMIN.UPDATE_PROBE('{probe}', NULL, 'compilation_time > 3000', True :: BOOLEAN, 'SLACK', '[email protected]', 'SLACK', False :: BOOLEAN);",
"Name must not be null.",
),
(
"CALL ADMIN.UPDATE_PROBE('{probe}', 'new_probe_name', NULL, True :: BOOLEAN, 'SLACK', '[email protected]', 'SLACK', False :: BOOLEAN);",
"Condition must not be null.",
),
(
"CALL ADMIN.UPDATE_PROBE('{probe}', 'new_probe_name', 'x=y and z is not null', True :: BOOLEAN, 'SLACK', '[email protected]', 'SLACK', False :: BOOLEAN);",
"Invalid condition SQL. Please check your syntax.",
),
(
"CALL ADMIN.UPDATE_PROBE('{probe}', 'new_probe_name', 'x=y and z is not null', True :: BOOLEAN, 'SLACK', '[email protected]', 'SLACK', False :: BOOLEAN);",
"Invalid condition SQL. Please check your syntax.",
),
]

# Test that validates that correct error message was returned
@pytest.mark.parametrize("statement, expected_error", test_cases)
def test_error_message(conn, timestamp_string, statement, expected_error):

probe = generate_unique_name("probe", timestamp_string)
sql = statement.format(probe=probe)
assert expected_error in str(
run_proc(conn, sql)
), "Stored procedure output does not match expected result!"
111 changes: 111 additions & 0 deletions test/unit/test_probe_upgrade.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
from __future__ import annotations

from common_utils import run_proc
from common_utils import row_count
from common_utils import run_sql
import time


def test_initialize_then_migrate_probes(conn, timestamp_string):
# step 1: clean up the probes table and predefined_probes table
sql = "truncate table internal.probes"
assert "successfully" in str(
run_sql(conn, sql)
), "SQL output does not match expected result!"

sql = "truncate table internal.predefined_probes"
assert "successfully" in str(
run_sql(conn, sql)
), "SQL output does not match expected result!"

# step 2: clean up the flag in internal.config
sql = "delete from internal.config where KEY = 'PROBES_INITED'"
run_sql(conn, sql)

# step 3: populate predefined_probes table
sql = "CALL INTERNAL.POPULATE_PREDEFINED_PROBES();"
assert run_proc(conn, sql) is None, "Stored procedure did not return NULL value!"

sql = "select count(*) from internal.PREDEFINED_PROBES"
output = row_count(conn, sql)
assert output > 0, "SQL output " + str(output) + " does not match expected result!"

# step 4: call internal.initialize_probes()
sql = "call INTERNAL.INITIALIZE_PROBES()"
output = str(run_sql(conn, sql))
assert "True" in output, "SQL output" + output + " does not match expected result!"

# step 5: verify rows in probes table
sql = "select count(*) from internal.PROBES"
output = row_count(conn, sql)
assert output > 0, "SQL output " + str(output) + " does not match expected result!"

# step 6: verify flag in internal.config
sql = "call internal.get_config('PROBES_INITED')"
output = str(run_sql(conn, sql))
assert "True" in output, "SQL output" + output + " does not match expected result!"

# step 7: call internal.initialize_probes() again
sql = "call INTERNAL.INITIALIZE_PROBES()"
output = str(run_sql(conn, sql))
assert "False" in output, "SQL output" + output + " does not match expected result!"

# step 8: verify rows in probes table
sql = "select count(*) from internal.PROBES"
output = row_count(conn, sql)
assert output > 0, "SQL output " + str(output) + " does not match expected result!"

# step 9: sleep 5 seconds
time.sleep(5)

# step 10: call internal.migrate_predefined_probes()
sql = "call INTERNAL.MIGRATE_PREDEFINED_PROBES(5)"
output = str(run_sql(conn, sql))
assert "True" in output, "SQL output" + output + " does not match expected result!"

# step 11: insert a new predefined probe to PREDEFIEND_PROBES
sql = "INSERT INTO INTERNAL.PREDEFINED_PROBES (name, condition, PROBE_CREATED_AT, PROBE_MODIFIED_AT) values ('NEW PREDEFINED PROBE', 'bytes_scanned > 10000', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)"
run_sql(conn, sql)

# step 12: call internal.migrate_predefined_probes(). Migration should return true, since we have a new predefined probe.
sql = "call INTERNAL.MIGRATE_PREDEFINED_PROBES(5)"
output = str(run_sql(conn, sql))
assert "True" in output, "SQL output" + output + " does not match expected result!"

# step 13: verify probes table has the new added predefinend probe "NEW PREDEFINED PROBE"
sql = "select count(*) from internal.PROBES where name = 'NEW PREDEFINED PROBE'"
rowcount = row_count(conn, sql)
assert rowcount == 1, (
"SQL output " + str(rowcount) + " does not match expected result!"
)

# step 14: update the condition of 'NEW PREDEFINED PROBE'
sql = "UPDATE INTERNAL.PREDEFINED_PROBES SET CONDITION = 'bytes_scanned > 20000 ' where NAME = 'NEW PREDEFINED PROBE'"
run_sql(conn, sql)

# step 15: call internal.migrate_predefined_probes(). Migration should return true, since we modify condition of one old predefined probes.
time.sleep(5)

sql = "call INTERNAL.MIGRATE_PREDEFINED_probes(5)"
output = str(run_sql(conn, sql))
assert "True" in output, "SQL output" + output + " does not match expected result!"

# step 16: insert a row into user's PROBES
sql = "INSERT INTO INTERNAL.PROBES (name, condition, PROBE_CREATED_AT, PROBE_MODIFIED_AT) values ('test', 'bytes_scanned > 100', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)"
run_sql(conn, sql)

## step 17: MIGRATE_PREDEFINED_PROBES should return False, because user adds one PROBE
sql = "call INTERNAL.MIGRATE_PREDEFINED_PROBES(5)"
output = str(run_sql(conn, sql))
assert "False" in output, "SQL output" + output + " does not match expected result!"

# step 18: clean up the probes table and predefined_probes table
sql = "truncate table internal.probes"
assert "successfully" in str(
run_sql(conn, sql)
), "SQL output does not match expected result!"

sql = "truncate table internal.predefined_probes"
assert "successfully" in str(
run_sql(conn, sql)
), "SQL output does not match expected result!"

0 comments on commit bd7bb02

Please sign in to comment.