def test__templater_dbt_skips_disabled_model(in_dbt_project_dir, dbt_templater): # noqa """A disabled dbt model should be skipped.""" with pytest.raises(SQLTemplaterSkipFile, match=r"model was disabled"): dbt_templater.process( in_str="", fname="models/my_new_project/disabled_model.sql", config=FluffConfig(configs=DBT_FLUFF_CONFIG), )
def test__templater_dbt_templating_absolute_path( in_dbt_project_dir, dbt_templater # noqa ): """Test that absolute path of input path does not cause RuntimeError.""" try: dbt_templater.process( in_str="", fname=os.path.abspath("models/my_new_project/use_var.sql"), config=FluffConfig(configs=DBT_FLUFF_CONFIG), ) except Exception as e: pytest.fail(f"Unexpected RuntimeError: {e}")
def test__templater_dbt_skips_file( path, reason, dbt_templater, project_dir # noqa: F811 ): """A disabled dbt model should be skipped.""" with pytest.raises(SQLFluffSkipFile, match=reason): dbt_templater.process( in_str="", fname=os.path.join(project_dir, path), config=FluffConfig(configs=DBT_FLUFF_CONFIG), )
def test__templater_dbt_missing(dbt_templater): # noqa """Check that a nice error is returned when dbt module is missing.""" try: import dbt # noqa: F401 pytest.skip(msg="dbt is installed") except ModuleNotFoundError: pass with pytest.raises(ModuleNotFoundError, match=r"pip install sqlfluff\[dbt\]"): dbt_templater.process( in_str="", fname="models/my_new_project/test.sql", config=FluffConfig(configs=DBT_FLUFF_CONFIG), )
def test__templater_dbt_handle_exceptions( project_dir, dbt_templater, fname, exception_msg # noqa: F811 ): """Test that exceptions during compilation are returned as violation.""" from dbt.adapters.factory import get_adapter src_fpath = "test/fixtures/dbt/error_models/" + fname target_fpath = os.path.abspath( os.path.join(project_dir, "models/my_new_project/", fname)) # We move the file that throws an error in and out of the project directory # as dbt throws an error if a node fails to parse while computing the DAG os.rename(src_fpath, target_fpath) try: _, violations = dbt_templater.process( in_str="", fname=target_fpath, config=FluffConfig(configs=DBT_FLUFF_CONFIG), ) finally: get_adapter(dbt_templater.dbt_config).connections.release() os.rename(target_fpath, src_fpath) assert violations # NB: Replace slashes to deal with different plaform paths being returned. assert violations[0].desc().replace("\\", "/").startswith(exception_msg)
def test__templater_dbt_templating_test_lex( project_dir, dbt_templater, fname # noqa: F811 ): """Demonstrate the lexer works on both dbt models and dbt tests. Handle any number of newlines. """ source_fpath = os.path.join(project_dir, fname) with open(source_fpath, "r") as source_dbt_model: source_dbt_sql = source_dbt_model.read() n_trailing_newlines = len(source_dbt_sql) - len( source_dbt_sql.rstrip("\n")) lexer = Lexer(config=FluffConfig(configs=DBT_FLUFF_CONFIG)) templated_file, _ = dbt_templater.process( in_str="", fname=os.path.join(project_dir, fname), config=FluffConfig(configs=DBT_FLUFF_CONFIG), ) tokens, lex_vs = lexer.lex(templated_file) assert (templated_file.source_str == "select a\nfrom table_a" + "\n" * n_trailing_newlines) assert (templated_file.templated_str == "select a\nfrom table_a" + "\n" * n_trailing_newlines)
def _run_templater_and_verify_result(dbt_templater, project_dir, fname): # noqa: F811 templated_file, _ = dbt_templater.process( in_str="", fname=os.path.join(project_dir, "models/my_new_project/", fname), config=FluffConfig(configs=DBT_FLUFF_CONFIG), ) template_output_folder_path = Path( "plugins/sqlfluff-templater-dbt/test/fixtures/dbt/templated_output/") fixture_path = _get_fixture_path(template_output_folder_path, fname) assert str(templated_file) == fixture_path.read_text()
def test__templater_dbt_templating_result( in_dbt_project_dir, dbt_templater, fname # noqa ): """Test that input sql file gets templated into output sql file.""" templated_file, _ = dbt_templater.process( in_str="", fname="models/my_new_project/" + fname, config=FluffConfig(configs=DBT_FLUFF_CONFIG), ) # the dbt compiler gets rid of new lines assert str(templated_file) + "\n" == open("../dbt/" + fname).read()
def test__templater_dbt_templating_test_lex(in_dbt_project_dir, dbt_templater): # noqa """A test to demonstrate _tests_as_models works on dbt tests by temporarily making them models.""" lexer = Lexer(config=FluffConfig(configs=DBT_FLUFF_CONFIG)) templated_file, _ = dbt_templater.process( in_str="", fname="tests/test.sql", config=FluffConfig(configs=DBT_FLUFF_CONFIG), ) tokens, lex_vs = lexer.lex(templated_file) assert templated_file.source_str == "select * from a" assert templated_file.templated_str == "select * from a"
def test__templater_dbt_templating_result( project_dir, dbt_templater, fname # noqa: F811 ): """Test that input sql file gets templated into output sql file.""" templated_file, _ = dbt_templater.process( in_str="", fname=os.path.join(project_dir, "models/my_new_project/", fname), config=FluffConfig(configs=DBT_FLUFF_CONFIG), ) assert str(templated_file) == open("test/fixtures/dbt/" + fname).read()
def test__context_in_config_is_loaded( project_dir, dbt_templater, model_path, var_value # noqa: F811 ): """Test that variables inside .sqlfluff are passed to dbt.""" context = {"passed_through_cli": var_value} if var_value else {} config_dict = deepcopy(DBT_FLUFF_CONFIG) config_dict["templater"]["dbt"]["context"] = context config = FluffConfig(config_dict) fname = os.path.abspath(os.path.join(project_dir, model_path)) processed, violations = dbt_templater.process(in_str="", fname=fname, config=config) assert violations == [] assert str(var_value) in processed.templated_str
def test__templater_dbt_templating_test_lex( in_dbt_project_dir, dbt_templater, fname # noqa ): """A test to demonstrate the lexer works on both dbt models (with any # of trailing newlines) and dbt tests.""" with open(fname, "r") as source_dbt_model: source_dbt_sql = source_dbt_model.read() n_trailing_newlines = len(source_dbt_sql) - len( source_dbt_sql.rstrip("\n")) lexer = Lexer(config=FluffConfig(configs=DBT_FLUFF_CONFIG)) templated_file, _ = dbt_templater.process( in_str="", fname=fname, config=FluffConfig(configs=DBT_FLUFF_CONFIG), ) tokens, lex_vs = lexer.lex(templated_file) assert (templated_file.source_str == "select a\nfrom table_a" + "\n" * n_trailing_newlines) assert (templated_file.templated_str == "select a\nfrom table_a" + "\n" * n_trailing_newlines)
def test__templater_dbt_handle_database_connection_failure( set_relations_cache, project_dir, dbt_templater # noqa: F811 ): """Test the result of a failed database connection.""" from dbt.adapters.factory import get_adapter set_relations_cache.side_effect = DbtFailedToConnectException( "dummy error") src_fpath = ( "plugins/sqlfluff-templater-dbt/test/fixtures/dbt/error_models" "/exception_connect_database.sql") target_fpath = os.path.abspath( os.path.join(project_dir, "models/my_new_project/exception_connect_database.sql")) dbt_fluff_config_fail = DBT_FLUFF_CONFIG.copy() dbt_fluff_config_fail["templater"]["dbt"][ "profiles_dir"] = "plugins/sqlfluff-templater-dbt/test/fixtures/dbt/profiles_yml_fail" # We move the file that throws an error in and out of the project directory # as dbt throws an error if a node fails to parse while computing the DAG os.rename(src_fpath, target_fpath) try: _, violations = dbt_templater.process( in_str="", fname=target_fpath, config=FluffConfig(configs=DBT_FLUFF_CONFIG), ) finally: get_adapter(dbt_templater.dbt_config).connections.release() os.rename(target_fpath, src_fpath) assert violations # NB: Replace slashes to deal with different plaform paths being returned. assert (violations[0].desc().replace( "\\", "/").startswith("dbt tried to connect to the database"))