mirror of
https://github.com/FirebirdSQL/firebird-qa.git
synced 2025-01-22 13:33:07 +01:00
Added/Updated tests\bugs\gh_7598_test.py: Checked on 5.0.0.1058 SS/CS -- all OK.
This commit is contained in:
parent
08bb450bc7
commit
e54a4adf37
172
tests/bugs/gh_7598_test.py
Normal file
172
tests/bugs/gh_7598_test.py
Normal file
@ -0,0 +1,172 @@
|
||||
#coding:utf-8
|
||||
|
||||
"""
|
||||
ID: issue-7598
|
||||
ISSUE: https://github.com/FirebirdSQL/firebird/issues/7598
|
||||
TITLE: Wrong detection of must-be-delimited user names
|
||||
DESCRIPTION:
|
||||
Test uses pre-defined alias ('TMP_GH_7598_ALIAS') for which we set two parameters:
|
||||
* MaxStatementCacheSize = 32K
|
||||
* DeadlockTimeout = 1
|
||||
Also, we create common temporary database (NOT "aliased") for which MaxStatementCacheSize will be default.
|
||||
This database is used for adding initial data (otherwise problems raised with aliased database on build
|
||||
5.0.0.1057 because of very low value of MaxStatementCacheSize ==> one can not reproduce bug).
|
||||
Then this DB is moved to the file that is defined by TMP_GH_7598_ALIAS and we can perform test per se.
|
||||
After first connection if made and several rows are fetched, we launch ISQL as async child process and
|
||||
try to create table in it (see ticket example). On build before fix this ISQL can either hang or raise
|
||||
'deadlock' exception (we use DeadlockTimeout = 1 in order to reduce waiting time for that).
|
||||
On 5.0.1058 ISQL must finish without problems: table 'test2' must be created successfully.
|
||||
|
||||
NOTES:
|
||||
[30.05.2023] pzotov
|
||||
1. One need to be sure that firebird.conf does NOT contain DatabaseAccess = None.
|
||||
2. Test uses pre-created databases.conf which has alias defined by variable REQUIRED_ALIAS.
|
||||
Database file for that alias must NOT exist in the QA_root/files/qa/ subdirectory: it will be created here.
|
||||
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()"
|
||||
3. 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!)
|
||||
|
||||
Confirmed 'deadlock' error on 5.0.0.1057 but only when use MaxStatementCacheSize = 32K. COULD NOT reproduce hang.
|
||||
Checked on 5.0.0.1058 SS/CS -- all OK.
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import locale
|
||||
import shutil
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
import time
|
||||
|
||||
import pytest
|
||||
from firebird.qa import *
|
||||
from firebird.driver import DatabaseError
|
||||
|
||||
# Name of alias for self-security DB in the QA_root/files/qa-databases.conf.
|
||||
# This file must be copied manually to each testing FB homw folder, with replacing
|
||||
# databases.conf there:
|
||||
#
|
||||
REQUIRED_ALIAS = 'tmp_gh_7598_alias'
|
||||
|
||||
DB_PAGE_SIZE = 8192
|
||||
INIT_ROWS_CNT = 500000
|
||||
MAX_WAIT_FOR_ISQL_FINISH = 3
|
||||
|
||||
db = db_factory(filename = '#' + REQUIRED_ALIAS)
|
||||
db_clone = db_factory(page_size = DB_PAGE_SIZE, do_not_drop = True)
|
||||
|
||||
act = python_act('db', substitutions=[('[ \t]+', ' '), ] )
|
||||
act_clone = python_act('db_clone')
|
||||
|
||||
tmp_sql = temp_file(filename = 'tmp_gh_7598.tmp.sql')
|
||||
tmp_log = temp_file(filename = 'tmp_gh_7598.tmp.log')
|
||||
|
||||
@pytest.mark.version('>=5.0')
|
||||
def test_1(act: Action, act_clone: Action, tmp_sql: Path, tmp_log: Path, capsys):
|
||||
|
||||
# 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_7598_alias = $(dir_sampleDb)/qa/tmp_gh_7598.fdb
|
||||
# - then we extract filename: 'tmp_gh_7598.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
|
||||
|
||||
test_db_file = ''
|
||||
with act.db.connect(no_db_triggers = True) as con:
|
||||
con.execute_immediate('alter database set linger to 0')
|
||||
con.commit()
|
||||
test_db_file = con.info.name
|
||||
|
||||
|
||||
sql_init = f'''
|
||||
set bail on;
|
||||
-- set echo on;
|
||||
connect '{act_clone.db.db_path}' user {act.db.user}; -- password '{act.db.password}';
|
||||
create table test1(id int, str1 varchar(50));
|
||||
commit;
|
||||
set term ^;
|
||||
create or alter procedure gen_data(i int) as
|
||||
begin
|
||||
while (i > 0) do
|
||||
begin
|
||||
insert into test1(id, str1) values (:i, '01234567890123456789012345678901234567890123456789');
|
||||
i = i - 1;
|
||||
end
|
||||
end^
|
||||
|
||||
set term ;^
|
||||
|
||||
execute procedure gen_data({INIT_ROWS_CNT});
|
||||
commit;
|
||||
create index test1_id on test1 (id);
|
||||
commit;
|
||||
'''
|
||||
|
||||
act.expected_stdout = ''
|
||||
act.isql(switches = ['-q'], input = sql_init, connect_db=False, credentials = False, combine_output = True, io_enc = locale.getpreferredencoding())
|
||||
assert act.clean_stdout == act.clean_expected_stdout
|
||||
act.reset()
|
||||
|
||||
shutil.move( act_clone.db.db_path, test_db_file)
|
||||
|
||||
with act.db.connect() as con1:
|
||||
cur1 = con1.cursor()
|
||||
for r in cur1.execute('select first 10 * from test1 where ID > 0'):
|
||||
pass
|
||||
con1.commit()
|
||||
|
||||
###################################
|
||||
# NB: do NOT close connection here!
|
||||
###################################
|
||||
|
||||
sql_test = f'''
|
||||
set bail on;
|
||||
set list on;
|
||||
-- set autoddl off;
|
||||
-- set echo on;
|
||||
connect 'localhost:{REQUIRED_ALIAS}' user {act.db.user} password '{act.db.password}';
|
||||
create table test2(id int);
|
||||
commit; -- this issued 'deadlock' before fix.
|
||||
select 1 as table_created from rdb$relations where rdb$relation_name = upper('test2');
|
||||
quit;
|
||||
'''
|
||||
tmp_sql.write_bytes(sql_test.encode('utf-8'))
|
||||
|
||||
with open(tmp_log,'w') as f_log:
|
||||
p = subprocess.Popen( [ act.vars['isql'],
|
||||
'-q',
|
||||
'-i', tmp_sql
|
||||
],
|
||||
stdout = f_log, stderr = subprocess.STDOUT
|
||||
)
|
||||
for i in range(MAX_WAIT_FOR_ISQL_FINISH):
|
||||
time.sleep(1)
|
||||
if p.poll():
|
||||
break
|
||||
|
||||
if not p.poll():
|
||||
p.terminate()
|
||||
|
||||
for line in tmp_log.read_text().splitlines():
|
||||
if line.split():
|
||||
print(line)
|
||||
|
||||
act.expected_stdout = 'TABLE_CREATED 1'
|
||||
act.stdout = capsys.readouterr().out
|
||||
assert act.clean_stdout == act.clean_expected_stdout
|
||||
act.reset()
|
Loading…
Reference in New Issue
Block a user