def test_ValidationsStore_with_InMemoryStoreBackend(): my_store = ValidationsStore( store_backend={ "module_name": "great_expectations.data_context.store", "class_name": "InMemoryStoreBackend", }) with pytest.raises(TypeError): my_store.get("not_a_ValidationResultIdentifier") ns_1 = ValidationResultIdentifier.from_tuple( ("a", "b", "c", "quarantine", "prod-100")) my_store.set(ns_1, ExpectationSuiteValidationResult(success=True)) assert my_store.get(ns_1) == ExpectationSuiteValidationResult( success=True, statistics={}, results=[]) ns_2 = ValidationResultIdentifier.from_tuple( ("a", "b", "c", "quarantine", "prod-200")) my_store.set(ns_2, ExpectationSuiteValidationResult(success=False)) assert my_store.get(ns_2) == ExpectationSuiteValidationResult( success=False, statistics={}, results=[]) assert set(my_store.list_keys()) == { ns_1, ns_2, }
def test_StoreAction(): fake_in_memory_store = ValidationsStore(root_directory=None, store_backend={ "class_name": "InMemoryStoreBackend", }) stores = {"fake_in_memory_store": fake_in_memory_store} # NOTE: This is a hack meant to last until we implement runtime_configs class Object(object): pass data_context = Object() data_context.stores = stores action = StoreAction( data_context=data_context, target_store_name="fake_in_memory_store", ) assert fake_in_memory_store.list_keys() == [] vr_id = "ValidationResultIdentifier.my_db.default_generator.my_table.default_expectations.prod_20190801" action.run(validation_result_suite_identifier=ValidationResultIdentifier( from_string=vr_id), validation_result_suite={}, data_asset=None) assert len(fake_in_memory_store.list_keys()) == 1 assert fake_in_memory_store.list_keys()[0].to_string( ) == "ValidationResultIdentifier.my_db.default_generator.my_table.default_expectations.prod_20190801" assert fake_in_memory_store.get( ValidationResultIdentifier( from_string= "ValidationResultIdentifier.my_db.default_generator.my_table.default_expectations.prod_20190801" )) == {}
def test_ValidationsStore_with_TupleFileSystemStoreBackend(tmp_path_factory): path = str( tmp_path_factory.mktemp( "test_ValidationResultStore_with_TupleFileSystemStoreBackend__dir") ) project_path = str(tmp_path_factory.mktemp("my_dir")) my_store = ValidationsStore( store_backend={ "module_name": "great_expectations.data_context.store", "class_name": "TupleFilesystemStoreBackend", "base_directory": "my_store/", }, runtime_environment={"root_directory": path}, ) with pytest.raises(TypeError): my_store.get("not_a_ValidationResultIdentifier") ns_1 = ValidationResultIdentifier( expectation_suite_identifier=ExpectationSuiteIdentifier( "asset.quarantine"), run_id="prod-100", batch_identifier="batch_id", ) my_store.set(ns_1, ExpectationSuiteValidationResult(success=True)) assert my_store.get(ns_1) == ExpectationSuiteValidationResult( success=True, statistics={}, results=[]) ns_2 = ValidationResultIdentifier.from_tuple(( "asset", "quarantine", "prod-20", datetime.datetime.now(datetime.timezone.utc), "batch_id", )) my_store.set(ns_2, ExpectationSuiteValidationResult(success=False)) assert my_store.get(ns_2) == ExpectationSuiteValidationResult( success=False, statistics={}, results=[]) print(my_store.list_keys()) assert set(my_store.list_keys()) == { ns_1, ns_2, } print(gen_directory_tree_str(path)) assert (gen_directory_tree_str(path) == """\ test_ValidationResultStore_with_TupleFileSystemStoreBackend__dir0/ my_store/ asset/ quarantine/ prod-100/ 20190926T134241.000000Z/ batch_id.json prod-20/ 20190926T134241.000000Z/ batch_id.json """)
def test_StoreAction(): fake_in_memory_store = ValidationsStore( store_backend={ "class_name": "InMemoryStoreBackend", } ) stores = {"fake_in_memory_store": fake_in_memory_store} class Object: ge_cloud_mode = False data_context = Object() data_context.stores = stores action = StoreValidationResultAction( data_context=data_context, target_store_name="fake_in_memory_store", ) assert fake_in_memory_store.list_keys() == [] action.run( validation_result_suite_identifier=ValidationResultIdentifier( expectation_suite_identifier=ExpectationSuiteIdentifier( expectation_suite_name="default_expectations" ), run_id=RunIdentifier(run_name="prod_20190801"), batch_identifier="1234", ), validation_result_suite=ExpectationSuiteValidationResult( success=False, results=[] ), data_asset=None, ) expected_run_id = RunIdentifier( run_name="prod_20190801", run_time="20190926T134241.000000Z" ) assert len(fake_in_memory_store.list_keys()) == 1 stored_identifier = fake_in_memory_store.list_keys()[0] assert stored_identifier.batch_identifier == "1234" assert ( stored_identifier.expectation_suite_identifier.expectation_suite_name == "default_expectations" ) assert stored_identifier.run_id == expected_run_id assert fake_in_memory_store.get( ValidationResultIdentifier( expectation_suite_identifier=ExpectationSuiteIdentifier( expectation_suite_name="default_expectations" ), run_id=expected_run_id, batch_identifier="1234", ) ) == ExpectationSuiteValidationResult(success=False, results=[])
def test_ValidationsStore_with_DatabaseStoreBackend(sa): # Use sqlite so we don't require postgres for this test. connection_kwargs = {"drivername": "sqlite"} # First, demonstrate that we pick up default configuration my_store = ValidationsStore( store_backend={ "class_name": "DatabaseStoreBackend", "credentials": connection_kwargs, } ) with pytest.raises(TypeError): my_store.get("not_a_ValidationResultIdentifier") ns_1 = ValidationResultIdentifier( expectation_suite_identifier=ExpectationSuiteIdentifier( expectation_suite_name="asset.quarantine", ), run_id="20191007T151224.1234Z_prod_100", batch_identifier="batch_id", ) my_store.set(ns_1, ExpectationSuiteValidationResult(success=True)) assert my_store.get(ns_1) == ExpectationSuiteValidationResult( success=True, statistics={}, results=[] ) ns_2 = ValidationResultIdentifier( expectation_suite_identifier=ExpectationSuiteIdentifier( expectation_suite_name="asset.quarantine", ), run_id="20191007T151224.1234Z_prod_200", batch_identifier="batch_id", ) my_store.set(ns_2, ExpectationSuiteValidationResult(success=False)) assert my_store.get(ns_2) == ExpectationSuiteValidationResult( success=False, statistics={}, results=[] ) assert set(my_store.list_keys()) == { ns_1, ns_2, } """ What does this test and why? A Store should be able to report it's store_backend_id which is set when the StoreBackend is instantiated. """ # Check that store_backend_id exists can be read assert my_store.store_backend_id is not None # Check that store_backend_id is a valid UUID assert test_utils.validate_uuid4(my_store.store_backend_id)
def test_ValidationsStore_with_TupleS3StoreBackend(): bucket = "test_validation_store_bucket" prefix = "test/prefix" # create a bucket in Moto's mock AWS environment conn = boto3.resource("s3", region_name="us-east-1") conn.create_bucket(Bucket=bucket) # First, demonstrate that we pick up default configuration including from an S3TupleS3StoreBackend my_store = ValidationsStore(store_backend={ "class_name": "TupleS3StoreBackend", "bucket": bucket, "prefix": prefix, }) with pytest.raises(TypeError): my_store.get("not_a_ValidationResultIdentifier") ns_1 = ValidationResultIdentifier( expectation_suite_identifier=ExpectationSuiteIdentifier( expectation_suite_name="asset.quarantine", ), run_id="20191007T151224.1234Z_prod_100", batch_identifier="batch_id", ) my_store.set(ns_1, ExpectationSuiteValidationResult(success=True)) assert my_store.get(ns_1) == ExpectationSuiteValidationResult( success=True, statistics={}, results=[]) ns_2 = ValidationResultIdentifier( expectation_suite_identifier=ExpectationSuiteIdentifier( expectation_suite_name="asset.quarantine", ), run_id="20191007T151224.1234Z_prod_200", batch_identifier="batch_id", ) my_store.set(ns_2, ExpectationSuiteValidationResult(success=False)) assert my_store.get(ns_2) == ExpectationSuiteValidationResult( success=False, statistics={}, results=[]) # Verify that internals are working as expected, including the default filepath assert { s3_object_info["Key"] for s3_object_info in boto3.client("s3").list_objects_v2( Bucket=bucket, Prefix=prefix)["Contents"] } == { "test/prefix/asset/quarantine/20191007T151224.1234Z_prod_100/20190926T134241.000000Z/batch_id.json", "test/prefix/asset/quarantine/20191007T151224.1234Z_prod_200/20190926T134241.000000Z/batch_id.json", } print(my_store.list_keys()) assert set(my_store.list_keys()) == { ns_1, ns_2, }
def test_ValidationsStore_with_InMemoryStoreBackend(): my_store = ValidationsStore( store_backend={ "module_name": "great_expectations.data_context.store", "class_name": "InMemoryStoreBackend", } ) with pytest.raises(TypeError): my_store.get("not_a_ValidationResultIdentifier") ns_1 = ValidationResultIdentifier.from_tuple( ( "a", "b", "c", "quarantine", datetime.datetime.now(datetime.timezone.utc), "prod-100", ) ) my_store.set(ns_1, ExpectationSuiteValidationResult(success=True)) assert my_store.get(ns_1) == ExpectationSuiteValidationResult( success=True, statistics={}, results=[] ) ns_2 = ValidationResultIdentifier.from_tuple( ( "a", "b", "c", "quarantine", datetime.datetime.now(datetime.timezone.utc), "prod-200", ) ) my_store.set(ns_2, ExpectationSuiteValidationResult(success=False)) assert my_store.get(ns_2) == ExpectationSuiteValidationResult( success=False, statistics={}, results=[] ) assert set(my_store.list_keys()) == { ns_1, ns_2, } """ What does this test and why? A Store should be able to report it's store_backend_id which is set when the StoreBackend is instantiated. """ # Check that store_backend_id exists can be read assert my_store.store_backend_id is not None # Check that store_backend_id is a valid UUID assert test_utils.validate_uuid4(my_store.store_backend_id)
def validation_result_suite_id(): return ValidationResultIdentifier( expectation_suite_identifier=ExpectationSuiteIdentifier( "asset.default"), run_id=RunIdentifier(run_name="test_100"), batch_identifier="1234", )
def test_SlackNotificationAction(data_context): renderer = { "module_name": "great_expectations.render.renderer.slack_renderer", "class_name": "SlackRenderer", } slack_webhook = "https://hooks.slack.com/services/test/slack/webhook" notify_on = "all" slack_action = SlackNotificationAction( data_context=data_context, renderer=renderer, slack_webhook=slack_webhook, notify_on=notify_on ) validation_result_suite = ExpectationSuiteValidationResult(results=[], success=True, statistics={'evaluated_expectations': 0, 'successful_expectations': 0, 'unsuccessful_expectations': 0, 'success_percent': None}, meta={ 'great_expectations.__version__': 'v0.8.0__develop', 'expectation_suite_name': 'asset.default', 'run_id': 'test_100'}) validation_result_suite_id = ValidationResultIdentifier(expectation_suite_identifier=ExpectationSuiteIdentifier( "asset.default"), run_id="test_100", batch_identifier="1234") # TODO: improve this test - currently it is verifying a failed call to Slack assert slack_action.run( validation_result_suite_identifier=validation_result_suite_id, validation_result_suite=validation_result_suite, data_asset=None ) == None
def test_StoreMetricsAction_column_metric(basic_in_memory_data_context_for_validation_operator): action = StoreMetricsAction( data_context=basic_in_memory_data_context_for_validation_operator, requested_metrics={ "*": [ { "column": { "provider_id": ["expect_column_values_to_be_unique.result.unexpected_count"] } }, "statistics.evaluated_expectations", "statistics.successful_expectations" ] }, target_store_name="metrics_store" ) validation_result = ExpectationSuiteValidationResult( success=False, meta={ "expectation_suite_name": "foo", "run_id": "bar" }, results=[ ExpectationValidationResult( meta={}, result={ "element_count": 10, "missing_count": 0, "missing_percent": 0.0, "unexpected_count": 7, "unexpected_percent": 0.0, "unexpected_percent_nonmissing": 0.0, "partial_unexpected_list": [] }, success=True, expectation_config=ExpectationConfiguration( expectation_type="expect_column_values_to_be_unique", kwargs={ "column": "provider_id", "result_format": "BASIC" } ), exception_info=None ) ], statistics={ "evaluated_expectations": 5, "successful_expectations": 3 } ) action.run(validation_result, ValidationResultIdentifier.from_object(validation_result), data_asset=None) assert basic_in_memory_data_context_for_validation_operator.stores["metrics_store"].get(ValidationMetricIdentifier( run_id="bar", expectation_suite_identifier=ExpectationSuiteIdentifier("foo"), metric_name="expect_column_values_to_be_unique.result.unexpected_count", metric_kwargs_id="column=provider_id" )) == 7
def _run_actions( self, batch, expectation_suite_identifier, expectation_suite, batch_validation_result, run_id, ): """ Runs all actions configured for this operator on the result of validating one batch against one expectation suite. If an action fails with an exception, the method does not continue. :param batch: :param expectation_suite: :param batch_validation_result: :param run_id: :return: a dictionary: {action name -> result returned by the action} """ batch_actions_results = {} for action in self.action_list: # NOTE: Eugene: 2019-09-23: log the info about the batch and the expectation suite logger.debug( "Processing validation action with name {}".format(action["name"]) ) if isinstance(batch, Validator): batch_identifier = batch.active_batch_id else: batch_identifier = batch.batch_id validation_result_id = ValidationResultIdentifier( expectation_suite_identifier=expectation_suite_identifier, run_id=run_id, batch_identifier=batch_identifier, ) try: action_result = self.actions[action["name"]].run( validation_result_suite_identifier=validation_result_id, validation_result_suite=batch_validation_result, data_asset=batch, payload=batch_actions_results, ) # add action_result batch_actions_results[action["name"]] = ( {} if action_result is None else action_result ) batch_actions_results[action["name"]]["class"] = action["action"][ "class_name" ] except Exception as e: logger.exception( "Error running action with name {}".format(action["name"]) ) raise e return batch_actions_results
def test_ValidationResultIdentifier__init__totally_nested(): my_id = ValidationResultIdentifier(coerce_types=True, **{ "expectation_suite_identifier": { "data_asset_name": { "datasource": "a", "generator": "b", "generator_asset": "c", }, "expectation_suite_name": "failure", }, "run_id": "testing-12345", }) assert my_id.to_string( ) == "ValidationResultIdentifier.a.b.c.failure.testing-12345"
def validation_result_suite_extended_id(): return ValidationResultIdentifier( expectation_suite_identifier=ExpectationSuiteIdentifier( "asset.default"), run_id=RunIdentifier(run_name="test_100", run_time="Tue May 08 15:14:45 +0800 2012"), batch_identifier=BatchIdentifier(batch_identifier="1234", data_asset_name="asset"), )
def test_ValidationResultIdentifier__init__entirely_flat(): ValidationResultIdentifier( "a", "b", "c", "warning", "testing-12345", coerce_types=True, )
def test_ValidationResultIdentifier__init__partially_flat(): ValidationResultIdentifier(coerce_types=True, **{ "expectation_suite_identifier": { "data_asset_name": ("a", "b", "c"), "expectation_suite_name": "hello", }, "run_id": "testing-12345", })
def test_ValidationResultIdentifier__init__mostly_nested(): ValidationResultIdentifier(coerce_types=True, **{ "expectation_suite_identifier": { "data_asset_name": ("a", "b", "c"), "expectation_suite_name": "warning", }, "run_id": "testing-12345", })
def test_ValidationsStore_with_DatabaseStoreBackend(sa): # Use sqlite so we don't require postgres for this test. connection_kwargs = {"drivername": "sqlite"} # First, demonstrate that we pick up default configuration my_store = ValidationsStore( store_backend={ "class_name": "DatabaseStoreBackend", "credentials": connection_kwargs, } ) with pytest.raises(TypeError): my_store.get("not_a_ValidationResultIdentifier") ns_1 = ValidationResultIdentifier( expectation_suite_identifier=ExpectationSuiteIdentifier( expectation_suite_name="asset.quarantine", ), run_id="20191007T151224.1234Z_prod_100", batch_identifier="batch_id", ) my_store.set(ns_1, ExpectationSuiteValidationResult(success=True)) assert my_store.get(ns_1) == ExpectationSuiteValidationResult( success=True, statistics={}, results=[] ) ns_2 = ValidationResultIdentifier( expectation_suite_identifier=ExpectationSuiteIdentifier( expectation_suite_name="asset.quarantine", ), run_id="20191007T151224.1234Z_prod_200", batch_identifier="batch_id", ) my_store.set(ns_2, ExpectationSuiteValidationResult(success=False)) assert my_store.get(ns_2) == ExpectationSuiteValidationResult( success=False, statistics={}, results=[] ) assert set(my_store.list_keys()) == { ns_1, ns_2, }
def test_HtmlSiteStore_filesystem_backend(tmp_path_factory): path = str(tmp_path_factory.mktemp('test_HtmlSiteStore_with_TupleFileSystemStoreBackend__dir')) my_store = HtmlSiteStore( store_backend={ "class_name": "TupleFilesystemStoreBackend", "base_directory": "my_store" }, runtime_environment={ "root_directory": path } ) with pytest.raises(TypeError): my_store.get("not_a_ValidationResultIdentifier") with pytest.raises(ValidationError): my_store.get(validationResultIdentifierSchema.load({}).data) ns_1 = SiteSectionIdentifier( site_section_name="validations", resource_identifier=ValidationResultIdentifier.from_tuple(('a', 'b', 'c', 'quarantine', 'prod-100')) ) my_store.set(ns_1, "aaa") # assert my_store.get(ns_1) == "aaa" ns_2 = SiteSectionIdentifier( site_section_name="validations", resource_identifier=ValidationResultIdentifier.from_tuple(('a', 'b', 'c', 'quarantine', 'prod-20')) ) my_store.set(ns_2, "bbb") # assert my_store.get(ns_2) == {"B": "bbb"} print(my_store.list_keys()) # WARNING: OBSERVE THAT SITE_SECTION_NAME IS LOST IN THE CALL TO LIST_KEYS assert set(my_store.list_keys()) == { ns_1.resource_identifier, ns_2.resource_identifier, } print(gen_directory_tree_str(path)) assert gen_directory_tree_str(path) == """\
def _convert_tuple_to_resource_identifier(self, tuple_): if tuple_[0] == "expectations": resource_identifier = ExpectationSuiteIdentifier(*tuple_[1]) elif tuple_[0] == "validations": resource_identifier = ValidationResultIdentifier(*tuple_[1]) else: raise Exception("unknown section name: " + tuple_[0]) new_identifier = SiteSectionIdentifier( site_section_name=tuple_[0], resource_identifier=resource_identifier) return new_identifier
def test_ValidationResultIdentifier__init__mostly_nested_with_typed_child(): ValidationResultIdentifier(coerce_types=True, **{ "expectation_suite_identifier": { "data_asset_name": DataAssetIdentifier("a", "b", "c"), "expectation_suite_name": "quarantine", }, "run_id": "testing-12345", })
def ge_validation_result_suite_id() -> ValidationResultIdentifier: validation_result_suite_id = ValidationResultIdentifier( expectation_suite_identifier=ExpectationSuiteIdentifier( "asset.default"), run_id=RunIdentifier( run_name="test_100", run_time=datetime.fromtimestamp(1640701702, tz=timezone.utc), ), batch_identifier="010ef8c1cd417910b971f4468f024ec5", ) return validation_result_suite_id
def test_ValidationResultIdentifier__init__nested_except_the_top_layer(): ValidationResultIdentifier( { "data_asset_name": { "datasource": "a", "generator": "b", "generator_asset": "c", }, "expectation_suite_name": "hello", }, "testing-12345", coerce_types=True)
def test_SlackNotificationAction(data_context): renderer = { "module_name": "great_expectations.render.renderer.slack_renderer", "class_name": "SlackRenderer", } slack_webhook = "https://hooks.slack.com/services/test/slack/webhook" notify_on = "all" slack_action = SlackNotificationAction(data_context=data_context, renderer=renderer, slack_webhook=slack_webhook, notify_on=notify_on) validation_result_suite = { 'results': [], 'success': True, 'statistics': { 'evaluated_expectations': 0, 'successful_expectations': 0, 'unsuccessful_expectations': 0, 'success_percent': None }, 'meta': { 'great_expectations.__version__': 'v0.8.0__develop', 'data_asset_name': { 'datasource': 'x', 'generator': 'y', 'generator_asset': 'z' }, 'expectation_suite_name': 'default', 'run_id': '2019-09-25T060538.829112Z' } } validation_result_suite_id = ValidationResultIdentifier( **{ 'expectation_suite_identifier': { 'data_asset_name': { 'datasource': 'x', 'generator': 'y', 'generator_asset': 'z' }, 'expectation_suite_name': 'default' }, 'run_id': 'test_100' }) #TODO: improve this test - currently it is verifying a failed call to Slack assert slack_action.run( validation_result_suite_identifier=validation_result_suite_id, validation_result_suite=validation_result_suite, data_asset=None) == None
def test_resource_key_passes_run_name_filter(): resource_key = ValidationResultIdentifier( expectation_suite_identifier=ExpectationSuiteIdentifier("test_suite"), run_id=RunIdentifier(run_name="foofooprofilingfoo"), batch_identifier="f14c3d2f6e8028c2db0c25edabdb0d61", ) assert (resource_key_passes_run_name_filter( resource_key, run_name_filter={"equals": "profiling"}) is False) assert (resource_key_passes_run_name_filter( resource_key, run_name_filter={"equals": "foofooprofilingfoo"}) is True) assert (resource_key_passes_run_name_filter( resource_key, run_name_filter={"not_equals": "profiling"}) is True) assert (resource_key_passes_run_name_filter( resource_key, run_name_filter={"not_equals": "foofooprofilingfoo"}) is False) assert (resource_key_passes_run_name_filter( resource_key, run_name_filter={"includes": "profiling"}) is True) assert (resource_key_passes_run_name_filter( resource_key, run_name_filter={"includes": "foobar"}) is False) assert (resource_key_passes_run_name_filter( resource_key, run_name_filter={"not_includes": "foobar"}) is True) assert (resource_key_passes_run_name_filter( resource_key, run_name_filter={"not_includes": "profiling"}) is False) assert (resource_key_passes_run_name_filter( resource_key, run_name_filter={"matches_regex": "(foo){2}profiling(" "foo)+"}, ) is True) assert (resource_key_passes_run_name_filter( resource_key, run_name_filter={"matches_regex": "(foo){3}profiling(" "foo)+"}, ) is False) with pytest.warns(DeprecationWarning): assert (resource_key_passes_run_name_filter( resource_key, run_name_filter={"eq": "profiling"}) is False) assert (resource_key_passes_run_name_filter( resource_key, run_name_filter={"eq": "foofooprofilingfoo"}) is True) with pytest.warns(DeprecationWarning): assert (resource_key_passes_run_name_filter( resource_key, run_name_filter={"ne": "profiling"}) is True) assert (resource_key_passes_run_name_filter( resource_key, run_name_filter={"ne": "foofooprofilingfoo"}) is False)
def test_OrderedKeysDotDict__zip_keys_and_args_to_dict(): assert ValidationResultIdentifier._zip_keys_and_args_to_dict( ["a", "b", "c", "warning", "testing-12345"], ) == { "expectation_suite_identifier": ["a", "b", "c", "warning"], "run_id": "testing-12345" } assert ExpectationSuiteIdentifier._zip_keys_and_args_to_dict( ["a", "b", "c", "warning"]) == { "data_asset_name": ["a", "b", "c"], "expectation_suite_name": "warning", } assert ValidationResultIdentifier._zip_keys_and_args_to_dict( ["a", "b", "c", "hello", "testing-12345"]) == { "expectation_suite_identifier": [ "a", "b", "c", "hello", ], "run_id": "testing-12345" }
def test_resource_identifier_to_string(): assert ValidationResultIdentifier( coerce_types=True, **{ "expectation_suite_identifier": { "data_asset_name": { "datasource": "a", "generator": "b", "generator_asset": "c", }, "expectation_suite_name": "hello", }, "run_id": "testing-12345", }).to_string( ) == "ValidationResultIdentifier.a.b.c.hello.testing-12345"