diff --git a/tests/bugs/core_4964_test.py b/tests/bugs/core_4964_test.py index 69ea1246..81836d2f 100644 --- a/tests/bugs/core_4964_test.py +++ b/tests/bugs/core_4964_test.py @@ -1,140 +1,186 @@ -#coding:utf-8 - -""" -ID: issue-5255 -ISSUE: 5255 -JIRA: CORE-4964 -FBTEST: bugs.core_4964 -TITLE: Real errors during connect to security database are hidden by Srp user manager. Errors should be logged no matter what AuthServer is used -DESCRIPTION: - Test does following: - 1) creates temporary user using plugin Srp (in order to avoid occasional connect as SYSDBA using Legacy plugin); - 2) makes copy of test DB to file which is specified n databases.conf as database for alias defined by variable with name REQUIRED_ALIAS - (its value: 'tmp_4964_alias'; test will try to connect to this file via ALIAS from pre-created databases.conf); - 3) uses pre-created databases.conf which has alias and SecurityDatabase parameter in its details. - This parameter that points to existing file that for sure can NOT be a Firebird database - (file $(dir_conf)/firebird.msg is used for this purpose). - - Then we: - 1) obtain content of server firebird.log; - 2) try to make connect to alias and (as expected) get error; - 3) obtain again content of server firebird.log and compare to origin one. - -NOTES: - [02.08.2022] pzotov - 1. One need to be sure that firebird.conf does NOT contain DatabaseAccess = None. - 2. Value of REQUIRED_ALIAS must be EXACTLY the same as alias specified in the pre-created databases.conf - (for LINUX this equality is case-sensitive, even when aliases are compared!) - 3. Make sure that firebird was launched by user who is currently runs this test. - Otherwise shutil.copy2() failes with "[Errno 13] Permission denied". - 4. Content of databases.conf must be taken from $QA_ROOT/files/qa-databases.conf (one need to replace it before every test session). - Discussed with pcisar, letters since 30-may-2022 13:48, subject: - "new qa, core_4964_test.py: strange outcome when use... shutil.copy() // comparing to shutil.copy2()" - - Checked on 5.0.0.591, 4.0.1.2692, 3.0.8.33535 - both on Windows and Linux. -""" - -import re -import time -from pathlib import Path -from difflib import unified_diff - -import pytest -from firebird.qa import * - -substitutions = [('[ \t]+', ' '), ('file .* is not a valid database', 'file is not a valid database'), ] - -REQUIRED_ALIAS = 'tmp_core_4964_alias' - -db = db_factory() -act = python_act('db', substitutions=substitutions) -tmp_user = user_factory('db', name='tmp$c4964', password='123', plugin = 'Srp') - -expected_stdout_isql = """ - Statement failed, SQLSTATE = 08006 - Error occurred during login, please check server firebird.log for details -""" - -expected_stdout_log_diff = """ - Authentication error - file is not a valid database -""" - -@pytest.mark.version('>=3.0') -def test_1(act: Action, tmp_user: User, capsys): - - fblog_1 = act.get_firebird_log() - - # Scan line-by-line through databases.conf, find line starting with REQUIRED_ALIAS and extract name of file that - # must be created in the $(dir_sampleDb)/qa/ folder. This name will be used further as target database (tmp_fdb). - # NOTE: we have to SKIP lines which are commented out, i.e. if they starts with '#': - p_required_alias_ptn = re.compile( '^(?!#)((^|\\s+)' + REQUIRED_ALIAS + ')\\s*=\\s*\\$\\(dir_sampleDb\\)/qa/', re.IGNORECASE ) - fname_in_dbconf = None - - with open(act.home_dir/'databases.conf', 'r') as f: - for line in f: - if p_required_alias_ptn.search(line): - # If databases.conf contains line like this: - # tmp_4964_alias = $(dir_sampleDb)/qa/tmp_qa_4964.fdb - # - then we extract filename: 'tmp_qa_4964.fdb' (see below): - fname_in_dbconf = Path(line.split('=')[1].strip()).name - break - - # if 'fname_in_dbconf' remains undefined here then propably REQUIRED_ALIAS not equals to specified in the databases.conf! - # - assert fname_in_dbconf - - # Full path + filename of database to which we will try to connect: - # - tmp_fdb = Path( act.vars['sample_dir'], 'qa', fname_in_dbconf ) - - # PermissionError: [Errno 13] Permission denied --> probably because - # Firebird was started by root rather than current (non-privileged) user. - # - tmp_fdb.write_bytes(act.db.db_path.read_bytes()) - - check_sql = f''' - set bail on; - set list on; - connect '{act.host+":" if act.host else ""}{tmp_fdb}' user {tmp_user.name} password {tmp_user.password}; - -- This can occus only if we databases.conf contains {REQUIRED_ALIAS} - -- but without reference to invalid security DB (e.g., alias without curly braces at all): - select mon$database_name as "UNEXPECTED CONNECTION:" from mon$database; - quit; - ''' - - ############################################################################################################### - # POINT-1: check that ISQL raises: - # "SQLSTATE = 08006 / Error occurred during login, please check server firebird.log ..." - # - act.expected_stdout = expected_stdout_isql - try: - act.isql(switches = ['-q'], input = check_sql, connect_db=False, credentials = False, combine_output = True) - finally: - tmp_fdb.unlink() - - assert act.clean_stdout == act.clean_expected_stdout - act.reset() - - time.sleep(1) # Allow content of firebird log be fully flushed on disk. - fblog_2 = act.get_firebird_log() - - diff_patterns = [ - "\\+\\s+Authentication error", - "\\+\\s+file .* is not a valid database", - ] - diff_patterns = [re.compile(s) for s in diff_patterns] - - for line in unified_diff(fblog_1, fblog_2): - if line.startswith('+'): - if act.match_any(line, diff_patterns): - print(line.split('+')[-1]) - - ############################################################################################################### - # POINT-2: check that diff between firebird.log initial and current content has phrases - # 'Authentication error' and '... file is not a valid database': - # - act.expected_stdout = expected_stdout_log_diff - act.stdout = capsys.readouterr().out - assert act.clean_stdout == act.clean_expected_stdout - act.reset() +#coding:utf-8 + +""" +ID: issue-5255 +ISSUE: 5255 +JIRA: CORE-4964 +FBTEST: bugs.core_4964 +TITLE: Real errors during connect to security database are hidden by Srp user manager. Errors should be logged no matter what AuthServer is used +DESCRIPTION: + Test does following: + 1) creates temporary user using plugin Srp (in order to avoid occasional connect as SYSDBA using Legacy plugin); + 2) makes copy of test DB to file which is specified n databases.conf as database for alias defined by variable with name REQUIRED_ALIAS + (its value: 'tmp_4964_alias'; test will try to connect to this file via ALIAS from pre-created databases.conf); + 3) uses pre-created databases.conf which has alias and SecurityDatabase parameter in its details. + This parameter that points to existing file that for sure can NOT be a Firebird database + (file $(dir_conf)/firebird.msg is used for this purpose). + + Then we: + 1) obtain content of server firebird.log; + 2) try to make connect to alias and (as expected) get error; + 3) obtain again content of server firebird.log and compare to origin one. + +NOTES: + [02.08.2022] pzotov + 1. One need to be sure that firebird.conf does NOT contain DatabaseAccess = None. + 2. Value of REQUIRED_ALIAS must be EXACTLY the same as alias specified in the pre-created databases.conf + (for LINUX this equality is case-sensitive, even when aliases are compared!) + 3. Make sure that firebird was launched by user who is currently runs this test. + Otherwise shutil.copy2() failes with "[Errno 13] Permission denied". + 4. Content of databases.conf must be taken from $QA_ROOT/files/qa-databases.conf (one need to replace it before every test session). + Discussed with pcisar, letters since 30-may-2022 13:48, subject: + "new qa, core_4964_test.py: strange outcome when use... shutil.copy() // comparing to shutil.copy2()" + + [31.07.2024] pzotov + Replaced assert for ISQL output: added diff_patterns that must filter STDERR because we have to suppress message with text + "file ... is not a valid database" as it can be seen only in dev-builds. + Expected ISQL output must be compared with filtered capsys.readouterr().out rather than with act.stdout + Noted by Dimitry Sibiryakov, https://github.com/FirebirdSQL/firebird-qa/issues/27 + + Checked on 5.0.0.591, 4.0.1.2692, 3.0.8.33535 - both on Windows and Linux. +""" + +import re +import time +from pathlib import Path +from difflib import unified_diff + +import pytest +from firebird.qa import * + +substitutions = [ + ('[ \t]+', ' ') + ,('(-)?file .* is not a valid database', 'file is not a valid database') + ] + +REQUIRED_ALIAS = 'tmp_core_4964_alias' + +db = db_factory() +act = python_act('db', substitutions = substitutions) +tmp_user = user_factory('db', name='tmp$c4964', password='123', plugin = 'Srp') + +expected_stdout_isql = """ + Statement failed, SQLSTATE = 08006 + Error occurred during login, please check server firebird.log for details +""" + +expected_stdout_log_diff = """ + Authentication error + file is not a valid database +""" + +@pytest.mark.version('>=3.0') +def test_1(act: Action, tmp_user: User, capsys): + + fblog_1 = act.get_firebird_log() + + # Scan line-by-line through databases.conf, find line starting with REQUIRED_ALIAS and extract name of file that + # must be created in the $(dir_sampleDb)/qa/ folder. This name will be used further as target database (tmp_fdb). + # NOTE: we have to SKIP lines which are commented out, i.e. if they starts with '#': + p_required_alias_ptn = re.compile( '^(?!#)((^|\\s+)' + REQUIRED_ALIAS + ')\\s*=\\s*\\$\\(dir_sampleDb\\)/qa/', re.IGNORECASE ) + fname_in_dbconf = None + + with open(act.home_dir/'databases.conf', 'r') as f: + for line in f: + if p_required_alias_ptn.search(line): + # If databases.conf contains line like this: + # tmp_4964_alias = $(dir_sampleDb)/qa/tmp_qa_4964.fdb + # - then we extract filename: 'tmp_qa_4964.fdb' (see below): + fname_in_dbconf = Path(line.split('=')[1].strip()).name + break + + # if 'fname_in_dbconf' remains undefined here then propably REQUIRED_ALIAS not equals to specified in the databases.conf! + # + assert fname_in_dbconf + + # Full path + filename of database to which we will try to connect: + # + tmp_fdb = Path( act.vars['sample_dir'], 'qa', fname_in_dbconf ) + + # PermissionError: [Errno 13] Permission denied --> probably because + # Firebird was started by root rather than current (non-privileged) user. + # + tmp_fdb.write_bytes(act.db.db_path.read_bytes()) + + check_sql = f''' + set bail on; + set list on; + connect '{act.host+":" if act.host else ""}{tmp_fdb}' user {tmp_user.name} password {tmp_user.password}; + -- This can occus only if we databases.conf contains {REQUIRED_ALIAS} + -- but without reference to invalid security DB (e.g., alias without curly braces at all): + select mon$database_name as "UNEXPECTED CONNECTION:" from mon$database; + quit; + ''' + + ############################################################################################################### + # POINT-1: check that ISQL raises: + # "SQLSTATE = 08006 / Error occurred during login, please check server firebird.log ..." + # + + # release build: + # ================================== + # Statement failed, SQLSTATE = 08006 + # Error occurred during login, please check server firebird.log for details + # ================================== + + # dev-build: + # ================================== + # Statement failed, SQLSTATE = 08006 + # Error occurred during login, please check server firebird.log for details + # -file ... is not a valid database + # ================================== + # Last line ("file ... is not a valid database") will be suppressed by substitutions set: + # + + isql_err_diff_patterns = [ + "Statement failed, SQLSTATE = 08006" + ,"Error occurred during login, please check server firebird.log for details" + ] + isql_err_diff_patterns = [re.compile(s) for s in isql_err_diff_patterns] + + act.expected_stdout = expected_stdout_isql + try: + act.isql(switches = ['-q'], input = check_sql, connect_db=False, credentials = False, combine_output = True) + finally: + tmp_fdb.unlink() + + # ::: NB ::: + # Expected ISQL output must be compared with filtered capsys.readouterr().out rather than with act.stdout + for line in act.stdout.splitlines(): + if act.match_any(line, isql_err_diff_patterns): + print(line) + + act.stdout = capsys.readouterr().out + assert act.clean_stdout == act.clean_expected_stdout + act.reset() + + #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + time.sleep(1) # Allow content of firebird log be fully flushed on disk. + fblog_2 = act.get_firebird_log() + + fb_log_diff_patterns = [ + "\\+\\s+Authentication error" + ,"\\+\\s+file .* is not a valid database" + ] + fb_log_diff_patterns = [re.compile(s) for s in fb_log_diff_patterns] + + # BOTH release and dev build will print in firebird.log: + # + # Authentication error + # file .* is not a valid database + # + for line in unified_diff(fblog_1, fblog_2): + if line.startswith('+'): + if act.match_any(line, fb_log_diff_patterns): + print(line.split('+')[-1]) + + ############################################################################################################### + # POINT-2: check that diff between firebird.log initial and current content has phrases + # 'Authentication error' and '... file is not a valid database': + # + act.expected_stdout = expected_stdout_log_diff + act.stdout = capsys.readouterr().out + assert act.clean_stdout == act.clean_expected_stdout + act.reset() +