mirror of
https://github.com/FirebirdSQL/firebird-qa.git
synced 2025-02-02 02:40:42 +01:00
More Python test and test enhancements
This commit is contained in:
parent
d5b6620e62
commit
20bd6d4e74
@ -171,7 +171,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
user_1 = user_factory(name="Nebuchadnezzar2_King_of_Babylon",
|
||||
user_1 = user_factory('db_1', name="Nebuchadnezzar2_King_of_Babylon",
|
||||
password="Nebu_King_of_Babylon")
|
||||
|
||||
expected_stdout_1 = """
|
||||
@ -183,9 +183,13 @@ SEC$LAST_NAME Nebuchadnezzar5_King_of_Babylon
|
||||
|
||||
@pytest.mark.version('>=3.0')
|
||||
def test_1(act_1: Action, user_1: User):
|
||||
user_1.update(first_name="Nebuchadnezzar3_King_of_Babylon",
|
||||
middle_name="Nebuchadnezzar4_King_of_Babylon",
|
||||
last_name="Nebuchadnezzar5_King_of_Babylon")
|
||||
with act_1.connect_server() as srv:
|
||||
sec_db = srv.info.security_database
|
||||
act_1.svcmgr(switches=['action_modify_user', 'dbname', sec_db,
|
||||
'sec_username', user_1.name,
|
||||
'sec_firstname', 'Nebuchadnezzar3_King_of_Babylon',
|
||||
'sec_middlename', 'Nebuchadnezzar4_King_of_Babylon',
|
||||
'sec_lastname', 'Nebuchadnezzar5_King_of_Babylon'])
|
||||
#
|
||||
act_1.script = f"""set list on;
|
||||
select sec$user_name, sec$first_name, sec$middle_name, sec$last_name from sec$users
|
||||
|
@ -74,9 +74,9 @@ expected_stdout_1 = """
|
||||
TMP$C1642_MICK OK.
|
||||
"""
|
||||
|
||||
user_1 = user_factory(name='tmp$c1642_alan', password='123')
|
||||
user_2 = user_factory(name='tmp$c1642_john', password = '456')
|
||||
user_3 = user_factory(name='tmp$c1642_mick', password = '789')
|
||||
user_1 = user_factory('db_1', name='tmp$c1642_alan', password='123')
|
||||
user_2 = user_factory('db_1', name='tmp$c1642_john', password = '456')
|
||||
user_3 = user_factory('db_1', name='tmp$c1642_mick', password = '789')
|
||||
|
||||
@pytest.mark.version('>=2.5')
|
||||
def test_1(act_1: Action, user_1: User, user_2: User, user_3: User, capsys):
|
||||
|
@ -137,7 +137,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
user_1 = user_factory(name='TMP$C1845', password='QweRtyUi')
|
||||
user_1 = user_factory('db_1', name='TMP$C1845', password='QweRtyUi')
|
||||
|
||||
@pytest.mark.version('>=2.5')
|
||||
def test_1(act_1: Action, user_1: User):
|
||||
|
@ -133,7 +133,7 @@ expected_stdout_1 = """
|
||||
Successfully finished script
|
||||
"""
|
||||
|
||||
user_1 = user_factory(name='TMP$C1972', password='123')
|
||||
user_1 = user_factory('db_1', name='TMP$C1972', password='123')
|
||||
|
||||
@pytest.mark.version('>=2.1.1')
|
||||
def test_1(act_1: Action, user_1: User):
|
||||
|
@ -183,8 +183,8 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
user_1 = user_factory(name='tmp$c2004_foo', password='123')
|
||||
user_2 = user_factory(name='tmp$c2004_bar', password='456')
|
||||
user_1 = user_factory('db_1', name='tmp$c2004_foo', password='123', plugin='Srp', active=False, admin=True)
|
||||
user_2 = user_factory('db_1', name='tmp$c2004_bar', password='456', plugin='Srp', active=False)
|
||||
|
||||
expected_stdout_1 = """
|
||||
MSG init_state
|
||||
@ -216,15 +216,11 @@ After line 19 in file tmp_check_2004.sql
|
||||
def test_1(act_1: Action, user_1: User, user_2: User):
|
||||
act_1.script = f'''
|
||||
set list on;
|
||||
commit;
|
||||
create or alter user tmp$c2004_foo password '123' inactive using plugin Srp grant admin role;
|
||||
|
||||
-- NB: currently it seems strange that one need to grant rdb$admin to 'foo'
|
||||
-- For what reason this role need to be added if 'foo' does his actions only in security_db ?
|
||||
-- Sent letter to dimitr and alex, 10-mar-18 16:00
|
||||
grant rdb$admin to tmp$c2004_foo;
|
||||
|
||||
create or alter user tmp$c2004_bar password '456' inactive using plugin Srp;
|
||||
commit;
|
||||
|
||||
set count on;
|
||||
|
@ -14,7 +14,7 @@
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, python_act, Action, user_factory, User
|
||||
from firebird.qa import db_factory, python_act, Action, user_factory, User, role_factory, Role
|
||||
|
||||
# version: 2.5
|
||||
# resources: None
|
||||
@ -116,8 +116,8 @@ db_1 = db_factory(sql_dialect=3, init='')
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
user_mike = user_factory(name='tmp$c2233_mike', password='456')
|
||||
user_adam = user_factory(name='tmp$c2233_adam', password='123')
|
||||
user_mike = user_factory('db_1', name='tmp$c2233_mike', password='456')
|
||||
user_adam = user_factory('db_1', name='tmp$c2233_adam', password='123')
|
||||
|
||||
expected_stdout_1 = """
|
||||
WHO_AM_I : TMP$C2233_MIKE
|
||||
@ -141,11 +141,13 @@ expected_stdout_1 = """
|
||||
MON_ATT_CNT : 1
|
||||
"""
|
||||
|
||||
boss = role_factory('db_1', name='tmp$r2233_boss')
|
||||
acnt = role_factory('db_1', name='tmp$r2233_acnt')
|
||||
|
||||
@pytest.mark.version('>=2.5')
|
||||
def test_1(act_1: Action, user_mike: User, user_adam: User, capsys):
|
||||
def test_1(act_1: Action, user_mike: User, user_adam: User, boss: Role, acnt: Role, capsys):
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
with act_1.db.connect() as con, act_1.test_role('tmp$r2233_boss') as boss,\
|
||||
act_1.test_role('tmp$r2233_acnt') as acnt:
|
||||
with act_1.db.connect() as con:
|
||||
c = con.cursor()
|
||||
c.execute('grant tmp$r2233_boss to tmp$c2233_adam')
|
||||
c.execute('grant tmp$r2233_acnt to tmp$c2233_adam')
|
||||
|
@ -45,7 +45,7 @@
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
from firebird.qa import db_factory, python_act, Action
|
||||
|
||||
# version: 2.5
|
||||
# resources: None
|
||||
@ -372,7 +372,8 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
1 attachment
|
||||
@ -385,8 +386,7 @@ expected_stdout_1 = """
|
||||
"""
|
||||
|
||||
@pytest.mark.version('>=2.5')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
def test_1(act_1: Action):
|
||||
pytest.skip("New implementation postponed")
|
||||
|
||||
|
||||
|
@ -263,13 +263,13 @@ test_script_1 = """
|
||||
set term ;^
|
||||
"""
|
||||
|
||||
trace_1 = ['exclude_filter = %no_trace%',
|
||||
'log_connections = true',
|
||||
trace_1 = ['log_connections = true',
|
||||
'log_transactions = true',
|
||||
'log_statement_finish = true',
|
||||
'print_plan = true',
|
||||
'print_perf = true',
|
||||
'time_threshold = 0'
|
||||
'time_threshold = 0',
|
||||
'exclude_filter = %no_trace%',
|
||||
]
|
||||
|
||||
@pytest.mark.version('>=3.0')
|
||||
|
@ -351,8 +351,7 @@ expected_stdout_1 = """
|
||||
"""
|
||||
|
||||
@pytest.mark.version('>=2.5.1')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
pytest.skip("New implementation postponed")
|
||||
|
||||
|
||||
|
@ -203,4 +203,3 @@ Expected line found.
|
||||
@pytest.mark.version('>=2.5.2')
|
||||
def test_1(db_1):
|
||||
pytest.skip("Implementation is complicated, and IMHO not worth of realization")
|
||||
#pytest.fail("Test not IMPLEMENTED")
|
||||
|
@ -91,7 +91,7 @@ expected_stdout_1 = """
|
||||
WHO_IS_OWNER TMP_U4218
|
||||
"""
|
||||
|
||||
test_user_1: User = user_factory(name='TMP_U4218', password='123')
|
||||
test_user_1: User = user_factory('db_1', name='TMP_U4218', password='123')
|
||||
|
||||
test_db_1 = temp_file('owner-db.fdb')
|
||||
|
||||
@ -102,11 +102,11 @@ def test_1(act_1: Action, test_user_1: User, test_db_1: Path):
|
||||
c.execute('grant create database to user TMP_U4218')
|
||||
con.commit()
|
||||
test_script_1 = f"""
|
||||
create database 'localhost:{str(test_db_1)}' user 'TMP_U4218' password '123';
|
||||
create database 'localhost:{test_db_1}' user 'TMP_U4218' password '123';
|
||||
set list on;
|
||||
select current_user as who_am_i, mon$owner as who_is_owner from mon$database;
|
||||
commit;
|
||||
connect 'localhost:{str(test_db_1)}';
|
||||
connect 'localhost:{test_db_1}';
|
||||
select current_user as who_am_i, mon$owner as who_is_owner from mon$database;
|
||||
commit;
|
||||
drop database;
|
||||
|
@ -111,10 +111,10 @@ expected_stdout_1 = """
|
||||
"""
|
||||
|
||||
|
||||
user_bill = user_factory(name='TMP$C4503_BILL', password='123')
|
||||
user_john = user_factory(name='TMP$C4503_JOHN', password='456')
|
||||
user_mick = user_factory(name='TMP$C4503_MICK', password='789')
|
||||
user_boss = user_factory(name='TMP$C4503_BOSS', password='000')
|
||||
user_bill = user_factory('db_1', name='TMP$C4503_BILL', password='123')
|
||||
user_john = user_factory('db_1', name='TMP$C4503_JOHN', password='456')
|
||||
user_mick = user_factory('db_1', name='TMP$C4503_MICK', password='789')
|
||||
user_boss = user_factory('db_1', name='TMP$C4503_BOSS', password='000')
|
||||
|
||||
@pytest.mark.version('>=3.0')
|
||||
def test_1(act_1: Action, user_bill: User, user_john: User, user_mick: User, user_boss: User):
|
||||
|
@ -90,7 +90,7 @@ expected_stdout_1 = """
|
||||
ISQL using NON sysdba user account finished.
|
||||
"""
|
||||
|
||||
user_1 = user_factory(name='tmp$c4648', password='123')
|
||||
user_1 = user_factory('db_1', name='tmp$c4648', password='123')
|
||||
temp_db_1 = temp_file('tmp4648.fdb')
|
||||
|
||||
@pytest.mark.version('>=3.0')
|
||||
@ -126,7 +126,7 @@ def test_1(act_1: Action, user_1: User, temp_db_1: Path, capsys):
|
||||
commit;
|
||||
"""
|
||||
print ('Starting ISQL using NON sysdba user account...')
|
||||
act_1.isql(switches=['-q', '-user', 'tmp$c4648', '-pas', '123', f'localhost:{temp_db_1}'],
|
||||
act_1.isql(switches=['-q', '-user', 'tmp$c4648', '-pas', '123', act_1.get_dsn(temp_db_1)],
|
||||
connect_db=False, input=script, credentials=False)
|
||||
print(act_1.stdout)
|
||||
print ('ISQL using NON sysdba user account finished.')
|
||||
|
@ -290,8 +290,8 @@ expected_stdout_1 = """
|
||||
-- gdscode list for blocked: 335544926
|
||||
"""
|
||||
|
||||
dba_privileged_user = user_factory(name='tmp_c4731_cooldba', password='123')
|
||||
non_privileged_user = user_factory(name='tmp_c4731_manager', password='123')
|
||||
dba_privileged_user = user_factory('db_1', name='tmp_c4731_cooldba', password='123')
|
||||
non_privileged_user = user_factory('db_1', name='tmp_c4731_manager', password='123')
|
||||
|
||||
@pytest.mark.version('>=3.0')
|
||||
def test_1(act_1: Action, dba_privileged_user: User, non_privileged_user: User, capsys):
|
||||
|
@ -36,7 +36,7 @@
|
||||
# qmid: bugs.core_4743
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, python_act, Action, user_factory, User
|
||||
from firebird.qa import db_factory, python_act, Action, user_factory, User, role_factory, Role
|
||||
|
||||
# version: 4.0
|
||||
# resources: None
|
||||
@ -442,27 +442,26 @@ expected_stdout_1 = """
|
||||
privilege:exec : YES
|
||||
"""
|
||||
|
||||
non_acii_user = user_factory(name='"Вася Пупкин"', password= '123', encoding= 'utf8')
|
||||
non_acii_user = user_factory('db_1', name='"Вася Пупкин"', password= '123')
|
||||
test_role = role_factory('db_1', name='"Старший дворник"')
|
||||
|
||||
@pytest.mark.version('>=4.0')
|
||||
def test_1(act_1: Action, non_acii_user: User, capsys):
|
||||
with act_1.test_role('"Старший дворник"', charset= 'utf8'):
|
||||
act_1.isql(switches=['-b', '-q'], input=ddl_script_1)
|
||||
print(act_1.stdout)
|
||||
with act_1.db.connect(user=non_acii_user.name, password=non_acii_user.password,
|
||||
role='"Старший дворник"') as con:
|
||||
cur = con.cursor()
|
||||
cur.execute('select m.mon$user,m.mon$role from mon$attachments m where m.mon$attachment_id = current_connection')
|
||||
col = cur.description
|
||||
for r in cur:
|
||||
for i in range(len(col)):
|
||||
def test_1(act_1: Action, non_acii_user: User, test_role: Role, capsys):
|
||||
act_1.isql(switches=['-b', '-q'], input=ddl_script_1)
|
||||
print(act_1.stdout)
|
||||
with act_1.db.connect(user=non_acii_user.name, password=non_acii_user.password, role=test_role.name) as con:
|
||||
cur = con.cursor()
|
||||
cur.execute('select m.mon$user,m.mon$role from mon$attachments m where m.mon$attachment_id = current_connection')
|
||||
col = cur.description
|
||||
for r in cur:
|
||||
for i in range(len(col)):
|
||||
print(' '.join((col[i][0], ':', r[i])))
|
||||
cur.execute("select v.* from v_current_privileges v")
|
||||
col = cur.description
|
||||
for r in cur:
|
||||
for i in range(len(col)):
|
||||
if 'privilege:' not in col[i][0] or 'privilege:' in col[i][0] and r[i] == 'YES':
|
||||
print(' '.join((col[i][0], ':', r[i])))
|
||||
cur.execute("select v.* from v_current_privileges v")
|
||||
col = cur.description
|
||||
for r in cur:
|
||||
for i in range(len(col)):
|
||||
if 'privilege:' not in col[i][0] or 'privilege:' in col[i][0] and r[i] == 'YES':
|
||||
print(' '.join((col[i][0], ':', r[i])))
|
||||
#
|
||||
act_1.reset()
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
|
@ -171,7 +171,7 @@ act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
#NON_ASCII_USER_AFTER_DROP 0
|
||||
#"""
|
||||
|
||||
non_ascii_user = user_factory(name='"Εὐκλείδης"', password='123', encoding='utf8')
|
||||
non_ascii_user = user_factory('db_1', name='"Εὐκλείδης"', password='123')
|
||||
|
||||
@pytest.mark.version('>=4.0')
|
||||
def test_1(act_1: Action, non_ascii_user: User):
|
||||
|
@ -137,7 +137,7 @@ expected_stdout_1 = """
|
||||
Records affected: 1
|
||||
"""
|
||||
|
||||
test_user_1 = user_factory(name='tmp$c4768_1', password='123')
|
||||
test_user_1 = user_factory('db_1', name='tmp$c4768_1', password='123')
|
||||
|
||||
@pytest.mark.version('>=3.0')
|
||||
def test_1(act_1: Action, test_user_1: User):
|
||||
|
@ -51,7 +51,8 @@
|
||||
import pytest
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from firebird.qa import db_factory, python_act, Action, temp_file, user_factory, User
|
||||
from firebird.qa import db_factory, python_act, Action, temp_file, user_factory, User, \
|
||||
role_factory, Role
|
||||
|
||||
# version: 3.0.5
|
||||
# resources: None
|
||||
@ -228,7 +229,7 @@ expected_stderr_1 = """
|
||||
-Exiting before completion due to errors
|
||||
"""
|
||||
|
||||
test_user_1 = user_factory(name='tmp$c4821_boss', password='123')
|
||||
test_user_1 = user_factory('db_1', name='tmp$c4821_boss', password='123')
|
||||
|
||||
fdb_test1 = temp_file('tmp_4821_test1.fdb')
|
||||
fdb_test2 = temp_file('tmp_4821_test2.fdb')
|
||||
@ -236,76 +237,80 @@ fbk_name = temp_file('tmp_4821_test2.fbk')
|
||||
fdb_restored_using_gbak = temp_file('tmp_4821_restored.gbak.fdb')
|
||||
fdb_restored_using_smgr = temp_file('tmp_4821_restored.smgr.fdb')
|
||||
fdb_restored_unexpected = temp_file('tmp_4821_restored.no_grant.fdb')
|
||||
test_role = role_factory('db_1', name='tmp$db_creator')
|
||||
|
||||
@pytest.mark.version('>=3.0.5')
|
||||
def test_1(act_1: Action, test_user_1: User, capsys, fdb_test1: Path, fdb_test2: Path,
|
||||
fbk_name: Path, fdb_restored_using_gbak: Path, fdb_restored_using_smgr: Path,
|
||||
fdb_restored_unexpected: Path):
|
||||
with act_1.test_role('tmp$db_creator'):
|
||||
with act_1.db.connect() as con:
|
||||
#con.execute_immediate('revoke all on all from tmp$c4821_boss')
|
||||
con.execute_immediate('grant create database to role tmp$db_creator')
|
||||
con.execute_immediate('grant tmp$db_creator to tmp$c4821_boss')
|
||||
con.commit()
|
||||
#
|
||||
sql_test = f"""
|
||||
create database 'localhost:{fdb_test1}' user tmp$c4821_boss password '123';
|
||||
select mon$database_name as created_db_name from mon$database;
|
||||
rollback;
|
||||
create database 'localhost:{fdb_test2}' user tmp$c4821_boss password '123' role tmp$db_creator;
|
||||
set list on;
|
||||
select mon$database_name as created_db_name from mon$database;
|
||||
"""
|
||||
act_1.isql(switches=['-q'], input=sql_test)
|
||||
print(act_1.stdout)
|
||||
# Must PASS because user tmp$c4821_boss is the owner of this DB:
|
||||
act_1.reset()
|
||||
act_1.gbak(switches=['-b', '-user', 'tmp$c4821_boss', '-pas', '123',
|
||||
f'localhost:{fdb_test2}', str(fbk_name)],
|
||||
credentials=False)
|
||||
# Must FAIL because we do not specify role, with text:
|
||||
# "gbak: ERROR:no permission for CREATE access to DATABASE ... / gbak: ERROR:failed to create database localhost:tmp_4821_restored.gbak.fdb"
|
||||
act_1.reset()
|
||||
act_1.expected_stderr = "Must FAIL because we do not specify role"
|
||||
act_1.gbak(switches=['-rep', '-user', 'tmp$c4821_boss', '-pas', '123',
|
||||
str(fbk_name), f'localhost:{fdb_restored_using_gbak}'],
|
||||
credentials=False)
|
||||
print(act_1.stderr, file=sys.stderr)
|
||||
# Must PASS because we DO specify role:
|
||||
act_1.reset()
|
||||
act_1.gbak(switches=['-rep', '-user', 'tmp$c4821_boss', '-pas', '123', '-role', 'tmp$db_creator',
|
||||
str(fbk_name), f'localhost:{fdb_restored_using_gbak}'],
|
||||
credentials=False)
|
||||
#
|
||||
act_1.reset()
|
||||
act_1.isql(switches=['-user', act_1.db.user, '-password', act_1.db.password,
|
||||
f'localhost:{fdb_restored_using_gbak}'], connect_db=False,
|
||||
input='set list on; select mon$database_name as fdb_restored_using_gbak from mon$database;')
|
||||
print(act_1.stdout)
|
||||
# Must FAIL because we do not specify role, with text: "no permission for CREATE access to DATABASE ... / failed to create database tmp_4821_restored.smgr.fdb"
|
||||
act_1.reset()
|
||||
act_1.expected_stderr = "Must FAIL because we do not specify role"
|
||||
act_1.svcmgr(switches=['localhost:service_mgr', 'user', 'tmp$c4821_boss', 'password', '123',
|
||||
'action_restore', 'res_replace', 'bkp_file', str(fbk_name),
|
||||
'dbname', str(fdb_restored_using_smgr)], connect_mngr=False)
|
||||
print(act_1.stderr, file=sys.stderr)
|
||||
# Must PASS because we DO specify role:
|
||||
act_1.reset()
|
||||
act_1.svcmgr(switches=['localhost:service_mgr', 'user', 'tmp$c4821_boss', 'password', '123',
|
||||
'role', 'tmp$db_creator', 'action_restore', 'res_replace',
|
||||
'bkp_file', str(fbk_name), 'dbname', str(fdb_restored_using_smgr)],
|
||||
connect_mngr=False)
|
||||
#
|
||||
act_1.reset()
|
||||
act_1.isql(switches=['-user', act_1.db.user, '-password', act_1.db.password,
|
||||
f'localhost:{fdb_restored_using_gbak}'], connect_db=False,
|
||||
input='set list on; select mon$database_name as fdb_restored_using_smgr from mon$database;')
|
||||
print(act_1.stdout)
|
||||
#
|
||||
act_1.reset()
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
act_1.expected_stderr = expected_stderr_1
|
||||
act_1.stdout = capsys.readouterr().out
|
||||
act_1.stderr = capsys.readouterr().err
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
assert act_1.clean_stderr == act_1.clean_expected_stderr
|
||||
fdb_restored_unexpected: Path, test_role: Role):
|
||||
with act_1.db.connect() as con:
|
||||
# Next lines are here to show that role really exists
|
||||
c = con.cursor()
|
||||
c.execute('select * from rdb$roles')
|
||||
act_1.print_data_list(c)
|
||||
# yet next statement fails anyway with: SQL role TMP$DB_CREATOR does not exist
|
||||
con.execute_immediate(f'grant create database to role {test_role.name}')
|
||||
con.execute_immediate(f'grant {test_role.name} to {test_user_1.name}')
|
||||
con.commit()
|
||||
#
|
||||
sql_test = f"""
|
||||
create database 'localhost:{fdb_test1}' user {test_user_1.name} password '123';
|
||||
select mon$database_name as created_db_name from mon$database;
|
||||
rollback;
|
||||
create database 'localhost:{fdb_test2}' user {test_user_1.name} password '123' role {test_role.name};
|
||||
set list on;
|
||||
select mon$database_name as created_db_name from mon$database;
|
||||
"""
|
||||
act_1.isql(switches=['-q'], input=sql_test)
|
||||
print(act_1.stdout)
|
||||
# Must PASS because user test_user_1 is the owner of this DB:
|
||||
act_1.reset()
|
||||
act_1.gbak(switches=['-b', '-user', test_user_1.name, '-pas', '123',
|
||||
act_1.get_dsn(fdb_test2), str(fbk_name)],
|
||||
credentials=False)
|
||||
# Must FAIL because we do not specify role, with text:
|
||||
# "gbak: ERROR:no permission for CREATE access to DATABASE ... / gbak: ERROR:failed to create database localhost:tmp_4821_restored.gbak.fdb"
|
||||
act_1.reset()
|
||||
act_1.expected_stderr = "Must FAIL because we do not specify role"
|
||||
act_1.gbak(switches=['-rep', '-user', test_user_1.name, '-pas', '123',
|
||||
str(fbk_name), act_1.get_dsn(fdb_restored_using_gbak)],
|
||||
credentials=False)
|
||||
print(act_1.stderr, file=sys.stderr)
|
||||
# Must PASS because we DO specify role:
|
||||
act_1.reset()
|
||||
act_1.gbak(switches=['-rep', '-user', test_user_1.name, '-pas', '123', '-role', test_role.name,
|
||||
str(fbk_name), act_1.get_dsn(fdb_restored_using_gbak)],
|
||||
credentials=False)
|
||||
#
|
||||
act_1.reset()
|
||||
act_1.isql(switches=['-user', act_1.db.user, '-password', act_1.db.password,
|
||||
act_1.get_dsn(fdb_restored_using_gbak)], connect_db=False,
|
||||
input='set list on; select mon$database_name as fdb_restored_using_gbak from mon$database;')
|
||||
print(act_1.stdout)
|
||||
# Must FAIL because we do not specify role, with text: "no permission for CREATE access to DATABASE ... / failed to create database tmp_4821_restored.smgr.fdb"
|
||||
act_1.reset()
|
||||
act_1.expected_stderr = "Must FAIL because we do not specify role"
|
||||
act_1.svcmgr(switches=[f'{act_1.host}:service_mgr', 'user', test_user_1.name, 'password', '123',
|
||||
'action_restore', 'res_replace', 'bkp_file', str(fbk_name),
|
||||
'dbname', str(fdb_restored_using_smgr)], connect_mngr=False)
|
||||
print(act_1.stderr, file=sys.stderr)
|
||||
# Must PASS because we DO specify role:
|
||||
act_1.reset()
|
||||
act_1.svcmgr(switches=[f'{act_1.host}:service_mgr', 'user', test_user_1.name, 'password', '123',
|
||||
'role', test_role.name, 'action_restore', 'res_replace',
|
||||
'bkp_file', str(fbk_name), 'dbname', str(fdb_restored_using_smgr)],
|
||||
connect_mngr=False)
|
||||
#
|
||||
act_1.reset()
|
||||
act_1.isql(switches=['-user', act_1.db.user, '-password', act_1.db.password,
|
||||
act_1.get_dsn(fdb_restored_using_gbak)], connect_db=False,
|
||||
input='set list on; select mon$database_name as fdb_restored_using_smgr from mon$database;')
|
||||
print(act_1.stdout)
|
||||
#
|
||||
act_1.reset()
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
act_1.expected_stderr = expected_stderr_1
|
||||
act_1.stdout = capsys.readouterr().out
|
||||
act_1.stderr = capsys.readouterr().err
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
assert act_1.clean_stderr == act_1.clean_expected_stderr
|
||||
|
@ -163,5 +163,4 @@ expected_stdout_1 = """
|
||||
|
||||
@pytest.mark.version('>=3.0')
|
||||
def test_1(db_1):
|
||||
pytest.skip("Test requires manipulation with firebird.conf")
|
||||
#pytest.fail("Test not IMPLEMENTED")
|
||||
pytest.skip("Requires changes to databases.conf")
|
||||
|
@ -123,7 +123,7 @@ def test_1(act_1: Action, capsys):
|
||||
print(act_1.stdout)
|
||||
# Trying to move database online using REMOTE protocol:
|
||||
act_1.reset()
|
||||
act_1.gfix(switches=['-online', f'localhost:{act_1.db.db_path}'])
|
||||
act_1.gfix(switches=['-online', act_1.db.dsn])
|
||||
print(act_1.stdout)
|
||||
# Note: gfix attachment via remote protocol refects with following lines in trace:
|
||||
# 2015-08-24T18:30:03.8520 (3256:01B526A8) ATTACH_DATABASE
|
||||
|
@ -260,5 +260,4 @@ expected_stdout_1 = """
|
||||
|
||||
@pytest.mark.version('>=3.0')
|
||||
def test_1(db_1):
|
||||
pytest.skip("Test requires manipulation with databases.conf")
|
||||
#pytest.fail("Test not IMPLEMENTED")
|
||||
pytest.skip("Requires changes to databases.conf")
|
||||
|
@ -43,8 +43,7 @@
|
||||
# http://web.firebirdsql.org/download/prerelease/results/archive/3.0.2.32630/bugs.core_5034.html
|
||||
#
|
||||
# [pcisar] 26.11.2021
|
||||
# New implementation should be done using multiprocessing Python module
|
||||
# Postponed for later due to complexity
|
||||
# New implementation postponed for later time due to complexity
|
||||
# tracker_id: CORE-5034
|
||||
# min_versions: ['3.0']
|
||||
# versions: 3.0
|
||||
@ -245,7 +244,7 @@ init_script_1 = """
|
||||
commit;
|
||||
"""
|
||||
|
||||
db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
db_1 = db_factory(sql_dialect=3) # , init=init_script_1) commented out to speed up SKIP, uncomment when implemented
|
||||
|
||||
# test_script_1
|
||||
#---
|
||||
@ -461,8 +460,7 @@ expected_stdout_1 = """
|
||||
"""
|
||||
|
||||
@pytest.mark.version('>=3.0')
|
||||
@pytest.mark.xfail
|
||||
def test_1(act_1: Action):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
pytest.skip("New implementation postponed")
|
||||
|
||||
|
||||
|
@ -2,16 +2,16 @@
|
||||
#
|
||||
# id: bugs.core_5248
|
||||
# title: Improve consistency in GRANT syntax between roles and privileges according to SQL standard
|
||||
# decription:
|
||||
# decription:
|
||||
# Checked on 4.0.0.249; 3.0.1.32585
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-5248
|
||||
# min_versions: ['3.0.1']
|
||||
# versions: 3.0.1, 4.0
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
from firebird.qa import db_factory, isql_act, Action, user_factory, User, role_factory, Role
|
||||
|
||||
# version: 3.0.1
|
||||
# resources: None
|
||||
@ -122,11 +122,11 @@ test_script_2 = """
|
||||
select
|
||||
current_user as who_am_i
|
||||
,p.RDB$USER as who_was_granted
|
||||
,p.RDB$PRIVILEGE as privilege_type
|
||||
,p.RDB$RELATION_NAME as role_name
|
||||
,p.RDB$PRIVILEGE as privilege_type
|
||||
,p.RDB$RELATION_NAME as role_name
|
||||
,r.RDB$OWNER_NAME as role_owner
|
||||
,p.RDB$GRANTOR as granted_by
|
||||
,p.RDB$GRANT_OPTION as grant_option
|
||||
,p.RDB$GRANT_OPTION as grant_option
|
||||
from rdb$user_privileges p
|
||||
left join rdb$roles r on p.rdb$relation_name = r.rdb$role_name
|
||||
where p.rdb$object_type=13
|
||||
@ -221,7 +221,7 @@ test_script_2 = """
|
||||
-- -no permission for DROP access to ROLE TEST_ROLE1
|
||||
|
||||
drop role test_role1; -- should fail: this user is not owner of this role and he was not granted to use it with admin option
|
||||
|
||||
|
||||
set count off;
|
||||
select count(*) from rdb$roles where rdb$role_name = 'TEST_ROLE1';
|
||||
set count on;
|
||||
@ -266,52 +266,52 @@ act_2 = isql_act('db_2', test_script_2, substitutions=substitutions_2)
|
||||
|
||||
expected_stdout_2 = """
|
||||
WHO_AM_I SYSDBA
|
||||
WHO_WAS_GRANTED TMP$C5248_USR1
|
||||
PRIVILEGE_TYPE M
|
||||
ROLE_NAME TEST_ROLE1
|
||||
ROLE_OWNER TMP$C5248_USR0
|
||||
GRANTED_BY SYSDBA
|
||||
WHO_WAS_GRANTED TMP$C5248_USR1
|
||||
PRIVILEGE_TYPE M
|
||||
ROLE_NAME TEST_ROLE1
|
||||
ROLE_OWNER TMP$C5248_USR0
|
||||
GRANTED_BY SYSDBA
|
||||
GRANT_OPTION 2
|
||||
|
||||
WHO_AM_I SYSDBA
|
||||
WHO_WAS_GRANTED TMP$C5248_USR2
|
||||
PRIVILEGE_TYPE M
|
||||
ROLE_NAME TEST_ROLE1
|
||||
ROLE_OWNER TMP$C5248_USR0
|
||||
GRANTED_BY TMP$C5248_USR1
|
||||
WHO_WAS_GRANTED TMP$C5248_USR2
|
||||
PRIVILEGE_TYPE M
|
||||
ROLE_NAME TEST_ROLE1
|
||||
ROLE_OWNER TMP$C5248_USR0
|
||||
GRANTED_BY TMP$C5248_USR1
|
||||
GRANT_OPTION 0
|
||||
|
||||
|
||||
Records affected: 2
|
||||
|
||||
WHO_AM_I SYSDBA
|
||||
WHO_WAS_GRANTED TMP$C5248_USR2
|
||||
PRIVILEGE_TYPE M
|
||||
ROLE_NAME TEST_ROLE1
|
||||
ROLE_OWNER TMP$C5248_USR0
|
||||
GRANTED_BY TMP$C5248_USR1
|
||||
WHO_WAS_GRANTED TMP$C5248_USR2
|
||||
PRIVILEGE_TYPE M
|
||||
ROLE_NAME TEST_ROLE1
|
||||
ROLE_OWNER TMP$C5248_USR0
|
||||
GRANTED_BY TMP$C5248_USR1
|
||||
GRANT_OPTION 0
|
||||
|
||||
|
||||
Records affected: 1
|
||||
|
||||
WHO_AM_I TMP$C5248_USR1
|
||||
WHO_WAS_GRANTED TMP$C5248_USR1
|
||||
PRIVILEGE_TYPE M
|
||||
ROLE_NAME TEST_ROLE1
|
||||
ROLE_OWNER TMP$C5248_USR0
|
||||
GRANTED_BY SYSDBA
|
||||
WHO_WAS_GRANTED TMP$C5248_USR1
|
||||
PRIVILEGE_TYPE M
|
||||
ROLE_NAME TEST_ROLE1
|
||||
ROLE_OWNER TMP$C5248_USR0
|
||||
GRANTED_BY SYSDBA
|
||||
GRANT_OPTION 2
|
||||
|
||||
|
||||
Records affected: 1
|
||||
|
||||
WHO_AM_I TMP$C5248_USR0
|
||||
WHO_WAS_GRANTED TMP$C5248_USR3
|
||||
PRIVILEGE_TYPE M
|
||||
ROLE_NAME TEST_ROLE1
|
||||
ROLE_OWNER TMP$C5248_USR0
|
||||
GRANTED_BY SYSDBA
|
||||
WHO_WAS_GRANTED TMP$C5248_USR3
|
||||
PRIVILEGE_TYPE M
|
||||
ROLE_NAME TEST_ROLE1
|
||||
ROLE_OWNER TMP$C5248_USR0
|
||||
GRANTED_BY SYSDBA
|
||||
GRANT_OPTION 0
|
||||
|
||||
|
||||
@ -319,30 +319,30 @@ expected_stdout_2 = """
|
||||
Records affected: 0
|
||||
|
||||
WHO_AM_I TMP$C5248_USR1
|
||||
WHO_WAS_GRANTED TMP$C5248_USR1
|
||||
PRIVILEGE_TYPE M
|
||||
ROLE_NAME TEST_ROLE1
|
||||
ROLE_OWNER TMP$C5248_USR0
|
||||
GRANTED_BY SYSDBA
|
||||
WHO_WAS_GRANTED TMP$C5248_USR1
|
||||
PRIVILEGE_TYPE M
|
||||
ROLE_NAME TEST_ROLE1
|
||||
ROLE_OWNER TMP$C5248_USR0
|
||||
GRANTED_BY SYSDBA
|
||||
GRANT_OPTION 2
|
||||
|
||||
WHO_AM_I TMP$C5248_USR1
|
||||
WHO_WAS_GRANTED TMP$C5248_USR3
|
||||
PRIVILEGE_TYPE M
|
||||
ROLE_NAME TEST_ROLE1
|
||||
ROLE_OWNER TMP$C5248_USR0
|
||||
GRANTED_BY SYSDBA
|
||||
WHO_WAS_GRANTED TMP$C5248_USR3
|
||||
PRIVILEGE_TYPE M
|
||||
ROLE_NAME TEST_ROLE1
|
||||
ROLE_OWNER TMP$C5248_USR0
|
||||
GRANTED_BY SYSDBA
|
||||
GRANT_OPTION 0
|
||||
|
||||
|
||||
Records affected: 2
|
||||
|
||||
WHO_AM_I TMP$C5248_USR1
|
||||
WHO_WAS_GRANTED TMP$C5248_USR1
|
||||
PRIVILEGE_TYPE M
|
||||
ROLE_NAME TEST_ROLE1
|
||||
ROLE_OWNER TMP$C5248_USR0
|
||||
GRANTED_BY SYSDBA
|
||||
WHO_WAS_GRANTED TMP$C5248_USR1
|
||||
PRIVILEGE_TYPE M
|
||||
ROLE_NAME TEST_ROLE1
|
||||
ROLE_OWNER TMP$C5248_USR0
|
||||
GRANTED_BY SYSDBA
|
||||
GRANT_OPTION 2
|
||||
|
||||
|
||||
@ -351,27 +351,27 @@ expected_stdout_2 = """
|
||||
COUNT 1
|
||||
|
||||
WHO_AM_I TMP$C5248_USR0
|
||||
WHO_WAS_GRANTED TMP$C5248_USR1
|
||||
PRIVILEGE_TYPE M
|
||||
ROLE_NAME TEST_ROLE1
|
||||
ROLE_OWNER TMP$C5248_USR0
|
||||
GRANTED_BY SYSDBA
|
||||
WHO_WAS_GRANTED TMP$C5248_USR1
|
||||
PRIVILEGE_TYPE M
|
||||
ROLE_NAME TEST_ROLE1
|
||||
ROLE_OWNER TMP$C5248_USR0
|
||||
GRANTED_BY SYSDBA
|
||||
GRANT_OPTION 2
|
||||
|
||||
WHO_AM_I TMP$C5248_USR0
|
||||
WHO_WAS_GRANTED TMP$C5248_USR3
|
||||
PRIVILEGE_TYPE M
|
||||
ROLE_NAME TEST_ROLE1
|
||||
ROLE_OWNER TMP$C5248_USR0
|
||||
GRANTED_BY SYSDBA
|
||||
WHO_WAS_GRANTED TMP$C5248_USR3
|
||||
PRIVILEGE_TYPE M
|
||||
ROLE_NAME TEST_ROLE1
|
||||
ROLE_OWNER TMP$C5248_USR0
|
||||
GRANTED_BY SYSDBA
|
||||
GRANT_OPTION 0
|
||||
|
||||
WHO_AM_I TMP$C5248_USR0
|
||||
WHO_WAS_GRANTED TMP$C5248_USR2
|
||||
PRIVILEGE_TYPE M
|
||||
ROLE_NAME TEST_ROLE1
|
||||
ROLE_OWNER TMP$C5248_USR0
|
||||
GRANTED_BY TMP$C5248_USR1
|
||||
WHO_WAS_GRANTED TMP$C5248_USR2
|
||||
PRIVILEGE_TYPE M
|
||||
ROLE_NAME TEST_ROLE1
|
||||
ROLE_OWNER TMP$C5248_USR0
|
||||
GRANTED_BY TMP$C5248_USR1
|
||||
GRANT_OPTION 0
|
||||
|
||||
|
||||
@ -380,27 +380,27 @@ expected_stdout_2 = """
|
||||
Records affected: 0
|
||||
|
||||
WHO_AM_I TMP$C5248_USR1
|
||||
WHO_WAS_GRANTED TMP$C5248_USR1
|
||||
PRIVILEGE_TYPE M
|
||||
ROLE_NAME TEST_ROLE1
|
||||
ROLE_OWNER TMP$C5248_USR0
|
||||
GRANTED_BY SYSDBA
|
||||
WHO_WAS_GRANTED TMP$C5248_USR1
|
||||
PRIVILEGE_TYPE M
|
||||
ROLE_NAME TEST_ROLE1
|
||||
ROLE_OWNER TMP$C5248_USR0
|
||||
GRANTED_BY SYSDBA
|
||||
GRANT_OPTION 2
|
||||
|
||||
WHO_AM_I TMP$C5248_USR1
|
||||
WHO_WAS_GRANTED TMP$C5248_USR3
|
||||
PRIVILEGE_TYPE M
|
||||
ROLE_NAME TEST_ROLE1
|
||||
ROLE_OWNER TMP$C5248_USR0
|
||||
GRANTED_BY SYSDBA
|
||||
WHO_WAS_GRANTED TMP$C5248_USR3
|
||||
PRIVILEGE_TYPE M
|
||||
ROLE_NAME TEST_ROLE1
|
||||
ROLE_OWNER TMP$C5248_USR0
|
||||
GRANTED_BY SYSDBA
|
||||
GRANT_OPTION 0
|
||||
|
||||
WHO_AM_I TMP$C5248_USR1
|
||||
WHO_WAS_GRANTED TMP$C5248_USR2
|
||||
PRIVILEGE_TYPE M
|
||||
ROLE_NAME TEST_ROLE1
|
||||
ROLE_OWNER TMP$C5248_USR0
|
||||
GRANTED_BY TMP$C5248_USR1
|
||||
WHO_WAS_GRANTED TMP$C5248_USR2
|
||||
PRIVILEGE_TYPE M
|
||||
ROLE_NAME TEST_ROLE1
|
||||
ROLE_OWNER TMP$C5248_USR0
|
||||
GRANTED_BY TMP$C5248_USR1
|
||||
GRANT_OPTION 0
|
||||
|
||||
Records affected: 3
|
||||
@ -419,8 +419,17 @@ expected_stderr_2 = """
|
||||
-no permission for DROP access to ROLE TEST_ROLE1
|
||||
"""
|
||||
|
||||
|
||||
usr0_2 = user_factory('db_2', name='tmp$c5248_usr0', password='c5248$u0')
|
||||
usr1_2 = user_factory('db_2', name='tmp$c5248_usr1', password='c5248$u1')
|
||||
usr2_2 = user_factory('db_2', name='tmp$c5248_usr2', password='c5248$u2')
|
||||
usr3_2 = user_factory('db_2', name='tmp$c5248_usr3', password='c5248$u3')
|
||||
usrx_2 = user_factory('db_2', name='tmp$c5248_usrx', password='c5248$ux')
|
||||
test_role_2 = role_factory('db_2', name='test_role1')
|
||||
|
||||
@pytest.mark.version('>=4.0')
|
||||
def test_2(act_2: Action):
|
||||
def test_2(act_2: Action, usr0_2: User, usr1_2: User, usr2_2: User, usr3_2: User,
|
||||
usrx_2: User, test_role_2: Role):
|
||||
act_2.expected_stdout = expected_stdout_2
|
||||
act_2.expected_stderr = expected_stderr_2
|
||||
act_2.execute()
|
||||
|
@ -17,7 +17,7 @@
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, python_act, Action, user_factory, User
|
||||
from firebird.qa import db_factory, python_act, Action, user_factory, User, role_factory, Role
|
||||
|
||||
# version: 4.0
|
||||
# resources: None
|
||||
@ -225,8 +225,9 @@ trace_1 = ['time_threshold = 0',
|
||||
'log_statement_prepare = true',
|
||||
]
|
||||
|
||||
user_1_a = user_factory(name='TMP$C5269_1', password='123')
|
||||
user_1_b = user_factory(name='TMP$C5269_2', password='456')
|
||||
user_1_a = user_factory('db_1', name='TMP$C5269_1', password='123')
|
||||
user_1_b = user_factory('db_1', name='TMP$C5269_2', password='456')
|
||||
test_role = role_factory('db_1', name='role_for_trace_any_attachment')
|
||||
|
||||
test_script_1_a = """
|
||||
set list on;
|
||||
@ -237,22 +238,21 @@ where p.rdb$user = upper('TMP$C5269_2');
|
||||
"""
|
||||
|
||||
@pytest.mark.version('>=4.0')
|
||||
def test_1(act_1: Action, user_1_a: User, user_1_b: User):
|
||||
with act_1.test_role('role_for_trace_any_attachment'):
|
||||
with act_1.db.connect() as con:
|
||||
con.execute_immediate('alter role role_for_trace_any_attachment set system privileges to TRACE_ANY_ATTACHMENT')
|
||||
con.commit()
|
||||
con.execute_immediate('grant role_for_trace_any_attachment to user TMP$C5269_2')
|
||||
con.commit()
|
||||
act_1.expected_stdout = expected_stdout_1_a
|
||||
act_1.isql(switches=[], input=test_script_1_a)
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
# Run trace
|
||||
with act_1.trace(db_events=trace_1), act_1.db.connect(user='TMP$C5269_1', password='123') as con:
|
||||
c = con.cursor()
|
||||
c.execute('select current_user from rdb$database')
|
||||
# Check
|
||||
act_1.reset()
|
||||
act_1.expected_stdout = expected_stdout_1_b
|
||||
act_1.trace_to_stdout()
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
def test_1(act_1: Action, user_1_a: User, user_1_b: User, test_role: Role):
|
||||
with act_1.db.connect() as con:
|
||||
con.execute_immediate('alter role role_for_trace_any_attachment set system privileges to TRACE_ANY_ATTACHMENT')
|
||||
con.commit()
|
||||
con.execute_immediate('grant role_for_trace_any_attachment to user TMP$C5269_2')
|
||||
con.commit()
|
||||
act_1.expected_stdout = expected_stdout_1_a
|
||||
act_1.isql(switches=[], input=test_script_1_a)
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
# Run trace
|
||||
with act_1.trace(db_events=trace_1), act_1.db.connect(user='TMP$C5269_1', password='123') as con:
|
||||
c = con.cursor()
|
||||
c.execute('select current_user from rdb$database')
|
||||
# Check
|
||||
act_1.reset()
|
||||
act_1.expected_stdout = expected_stdout_1_b
|
||||
act_1.trace_to_stdout()
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
@ -12,7 +12,8 @@
|
||||
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
from firebird.qa import db_factory, python_act, Action, user_factory, User, temp_file
|
||||
from firebird.qa import db_factory, python_act, Action, user_factory, User, temp_file, \
|
||||
role_factory, Role
|
||||
|
||||
# version: 4.0
|
||||
# resources: None
|
||||
@ -75,8 +76,10 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
user_1 = user_factory(name='tmp$c5291_1', password='123')
|
||||
user_2 = user_factory(name='tmp$c5291_2', password='456')
|
||||
user_1 = user_factory('db_1', name='tmp$c5291_1', password='123')
|
||||
user_2 = user_factory('db_1', name='tmp$c5291_2', password='456')
|
||||
test_role = role_factory('db_1', name='role_for_use_gbak_utility')
|
||||
|
||||
fbk_file = temp_file('tmp_core_5291.fbk')
|
||||
fdb_file_1 = temp_file('tmp_core_5291_1.fdb')
|
||||
fdb_file_2 = temp_file('tmp_core_5291_2.fdb')
|
||||
@ -103,43 +106,42 @@ expected_stderr_1 = """
|
||||
|
||||
@pytest.mark.version('>=4.0')
|
||||
def test_1(act_1: Action, user_1: User, user_2: User, fbk_file: Path, fdb_file_1: Path,
|
||||
fdb_file_2: Path, capsys):
|
||||
with act_1.test_role('role_for_use_gbak_utility'):
|
||||
with act_1.db.connect() as con:
|
||||
con.execute_immediate('alter role role_for_use_gbak_utility set system privileges to USE_GBAK_UTILITY, SELECT_ANY_OBJECT_IN_DATABASE')
|
||||
con.commit()
|
||||
con.execute_immediate('grant default role_for_use_gbak_utility to user tmp$c5291_2')
|
||||
con.commit()
|
||||
#
|
||||
act_1.gbak(switches=['-b', act_1.db.dsn, str(fbk_file)])
|
||||
# User 1
|
||||
act_1.reset()
|
||||
act_1.expected_stderr = "We expect errors"
|
||||
act_1.gbak(switches=['-se', 'localhost:service_mgr', '-rep', str(fbk_file),
|
||||
str(fdb_file_1), '-user', user_1.name, '-pas', user_1.password],
|
||||
credentials=False)
|
||||
print(act_1.stderr)
|
||||
# User 1
|
||||
act_1.reset()
|
||||
act_1.expected_stderr = "We expect errors"
|
||||
act_1.gbak(switches=['-rep', str(fbk_file), f'localhost:{fdb_file_2}',
|
||||
'-user', user_1.name, '-pas', user_1.password], credentials=False)
|
||||
print(act_1.stderr)
|
||||
# User 2
|
||||
act_1.reset()
|
||||
act_1.expected_stderr = "We expect errors"
|
||||
act_1.gbak(switches=['-se', 'localhost:service_mgr', '-rep', str(fbk_file),
|
||||
str(fdb_file_1), '-user', user_2.name, '-pas', user_2.password],
|
||||
credentials=False)
|
||||
print(act_1.stderr)
|
||||
# User 2
|
||||
act_1.reset()
|
||||
act_1.expected_stderr = "We expect errors"
|
||||
act_1.gbak(switches=['-rep', str(fbk_file), f'localhost:{fdb_file_2}',
|
||||
'-user', user_2.name, '-pas', user_2.password], credentials=False)
|
||||
print(act_1.stderr)
|
||||
#
|
||||
act_1.reset()
|
||||
act_1.expected_stderr = expected_stderr_1
|
||||
act_1.stderr = capsys.readouterr().out
|
||||
assert act_1.clean_stderr == act_1.clean_expected_stderr
|
||||
fdb_file_2: Path, test_role: Role, capsys):
|
||||
with act_1.db.connect() as con:
|
||||
con.execute_immediate('alter role role_for_use_gbak_utility set system privileges to USE_GBAK_UTILITY, SELECT_ANY_OBJECT_IN_DATABASE')
|
||||
con.commit()
|
||||
con.execute_immediate('grant default role_for_use_gbak_utility to user tmp$c5291_2')
|
||||
con.commit()
|
||||
#
|
||||
act_1.gbak(switches=['-b', act_1.db.dsn, str(fbk_file)])
|
||||
# User 1
|
||||
act_1.reset()
|
||||
act_1.expected_stderr = "We expect errors"
|
||||
act_1.gbak(switches=['-se', 'localhost:service_mgr', '-rep', str(fbk_file),
|
||||
str(fdb_file_1), '-user', user_1.name, '-pas', user_1.password],
|
||||
credentials=False)
|
||||
print(act_1.stderr)
|
||||
# User 1
|
||||
act_1.reset()
|
||||
act_1.expected_stderr = "We expect errors"
|
||||
act_1.gbak(switches=['-rep', str(fbk_file), act_1.get_dsn(fdb_file_2),
|
||||
'-user', user_1.name, '-pas', user_1.password], credentials=False)
|
||||
print(act_1.stderr)
|
||||
# User 2
|
||||
act_1.reset()
|
||||
act_1.expected_stderr = "We expect errors"
|
||||
act_1.gbak(switches=['-se', f'{act_1.host}:service_mgr', '-rep', str(fbk_file),
|
||||
str(fdb_file_1), '-user', user_2.name, '-pas', user_2.password],
|
||||
credentials=False)
|
||||
print(act_1.stderr)
|
||||
# User 2
|
||||
act_1.reset()
|
||||
act_1.expected_stderr = "We expect errors"
|
||||
act_1.gbak(switches=['-rep', str(fbk_file), act_1.get_dsn(fdb_file_2),
|
||||
'-user', user_2.name, '-pas', user_2.password], credentials=False)
|
||||
print(act_1.stderr)
|
||||
#
|
||||
act_1.reset()
|
||||
act_1.expected_stderr = expected_stderr_1
|
||||
act_1.stderr = capsys.readouterr().out
|
||||
assert act_1.clean_stderr == act_1.clean_expected_stderr
|
||||
|
@ -126,5 +126,5 @@ def test_1(act_1: Action, fbk_file: Path, fdb_file_1: Path, fdb_file_2: Path):
|
||||
db_file_pages=[100000])
|
||||
srv.wait()
|
||||
# Only 'gfix -v' raised error. Online validation works fine:
|
||||
act_1.gfix(switches=['-v', f'localhost:{fdb_file_1}'])
|
||||
act_1.gfix(switches=['-v', act_1.get_dsn(fdb_file_1)])
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
@ -194,9 +194,9 @@ def test_1(act_1: Action, fbk_file_1: Path, fdb_file_1: Path, capsys):
|
||||
act_1.reset()
|
||||
act_1.gbak(switches=['-b', act_1.db.dsn, str(fbk_file_1), '-include', p])
|
||||
act_1.reset()
|
||||
act_1.gbak(switches=['-rep', str(fbk_file_1), f'localhost:{fdb_file_1}'])
|
||||
act_1.gbak(switches=['-rep', str(fbk_file_1), act_1.get_dsn(fdb_file_1)])
|
||||
act_1.reset()
|
||||
act_1.isql(switches=[f'localhost:{fdb_file_1}'], connect_db=False,
|
||||
act_1.isql(switches=[act_1.get_dsn(fdb_file_1)], connect_db=False,
|
||||
input=f"set heading off; select {i} ptn_indx, q'{{{p}}}' as ptn_text, v.* from v_test v;")
|
||||
print(act_1.stdout)
|
||||
# 2. Check interaction between -INCLUDE_DATA and -SKIP_DATA switches for a table:
|
||||
@ -215,9 +215,9 @@ def test_1(act_1: Action, fbk_file_1: Path, fdb_file_1: Path, capsys):
|
||||
act_1.reset()
|
||||
act_1.gbak(switches=['-b', act_1.db.dsn, str(fbk_file_1), '-include_data', p, '-skip_data', skip_ptn])
|
||||
act_1.reset()
|
||||
act_1.gbak(switches=['-rep', str(fbk_file_1), f'localhost:{fdb_file_1}'])
|
||||
act_1.gbak(switches=['-rep', str(fbk_file_1), act_1.get_dsn(fdb_file_1)])
|
||||
act_1.reset()
|
||||
act_1.isql(switches=[f'localhost:{fdb_file_1}'], connect_db=False,
|
||||
act_1.isql(switches=[act_1.get_dsn(fdb_file_1)], connect_db=False,
|
||||
input=f"set heading off; select {i} ptn_indx, q'{{{p}}}' as include_ptn, q'{{{skip_ptn}}}' as exclude_ptn, v.* from v_test v;")
|
||||
print(act_1.stdout)
|
||||
# Check
|
||||
|
@ -182,12 +182,12 @@ fdb_file_1 = temp_file('core_5576.fdb')
|
||||
def test_1(act_1: Action, fbk_file_1: Path, fdb_file_1: Path):
|
||||
act_1.gbak(switches=['-b', act_1.db.dsn, str(fbk_file_1)])
|
||||
act_1.reset()
|
||||
act_1.gbak(switches=['-rep', str(fbk_file_1), f'localhost:{fdb_file_1}'])
|
||||
act_1.gbak(switches=['-rep', str(fbk_file_1), act_1.get_dsn(fdb_file_1)])
|
||||
#
|
||||
for i in range(2): # Run isql twice!
|
||||
act_1.reset()
|
||||
act_1.expected_stdout = expected_stdout_1_a
|
||||
act_1.isql(switches=[f'localhost:{fdb_file_1}'], connect_db=False,
|
||||
act_1.isql(switches=[act_1.get_dsn(fdb_file_1)], connect_db=False,
|
||||
input='set list on;select 1 x1 from test where i=1 with lock;')
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
# Validate the database
|
||||
|
@ -191,7 +191,7 @@ def test_1(act_1: Action, fdb_file_1: Path, fbk_file_1: Path, shd_file_1: Path):
|
||||
shd_file_1.unlink()
|
||||
#
|
||||
act_1.reset()
|
||||
act_1.gbak(switches=['-c', '-use_all_space', str(fbk_file_1), f'localhost:{fdb_file_1}'])
|
||||
act_1.gbak(switches=['-c', '-use_all_space', str(fbk_file_1), act_1.get_dsn(fdb_file_1)])
|
||||
# Check that we have the same data in DB tables
|
||||
sql_text = """
|
||||
set list on;
|
||||
@ -200,5 +200,5 @@ def test_1(act_1: Action, fdb_file_1: Path, fbk_file_1: Path, shd_file_1: Path):
|
||||
"""
|
||||
act_1.reset()
|
||||
act_1.expected_stdout = expected_stdout_1_b
|
||||
act_1.isql(switches=['-q', f'localhost:{fdb_file_1}'], input=sql_text, connect_db=False)
|
||||
act_1.isql(switches=['-q', act_1.get_dsn(fdb_file_1)], input=sql_text, connect_db=False)
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
@ -166,5 +166,5 @@ def test_1(act_1: Action, fbk_file_1: Path, fdb_file_1: Path):
|
||||
srv.wait()
|
||||
#
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
act_1.isql(switches=['-q', f'localhost:{fdb_file_1}'], input=test_script_1, connect_db=False)
|
||||
act_1.isql(switches=['-q', act_1.get_dsn(fdb_file_1)], input=test_script_1, connect_db=False)
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
@ -173,7 +173,7 @@ fdb_file = temp_file('tmp_core_5771.fdb')
|
||||
@pytest.mark.version('>=4.0')
|
||||
def test_1(act_1: Action, fbk_file: Path, fdb_file: Path):
|
||||
act_1.gbak(switches=['-b', act_1.db.dsn, str(fbk_file)])
|
||||
act_1.gbak(switches=['-rep', str(fbk_file), f'localhost:{fdb_file}'])
|
||||
act_1.gbak(switches=['-rep', str(fbk_file), act_1.get_dsn(fdb_file)])
|
||||
#
|
||||
log_before = act_1.get_firebird_log()
|
||||
#
|
||||
|
@ -170,7 +170,7 @@ expected_stdout_1 = """
|
||||
Records affected: 0
|
||||
"""
|
||||
|
||||
test_user = user_factory(name='tmp$c5790', password='123')
|
||||
test_user = user_factory('db_1', name='tmp$c5790', password='123')
|
||||
fdb_file = temp_file('tmp_5790.fdb')
|
||||
|
||||
@pytest.mark.version('>=3.0.4')
|
||||
|
@ -274,10 +274,10 @@ def test_1(act_1: Action, fbk_file: Path, fdb_file: Path):
|
||||
act_1.reset()
|
||||
act_1.gbak(switches=['-b', act_1.db.dsn, str(fbk_file)])
|
||||
act_1.reset()
|
||||
act_1.gbak(switches=['-c', str(fbk_file), f'localhost:{fdb_file}'])
|
||||
act_1.gbak(switches=['-c', str(fbk_file), act_1.get_dsn(fdb_file)])
|
||||
# Query RDB$TRIGGERS after b/r:
|
||||
act_1.reset()
|
||||
act_1.isql(switches=[f'localhost:{fdb_file}'], input=test_script_1, connect_db=False)
|
||||
act_1.isql(switches=[act_1.get_dsn(fdb_file)], input=test_script_1, connect_db=False)
|
||||
meta_after = [line for line in act_1.stdout.splitlines() if not line.startswith('BLOB_ID_FOR_TRG')]
|
||||
# Check
|
||||
assert list(unified_diff(meta_before, meta_after)) == []
|
||||
|
@ -198,5 +198,5 @@ def test_1(act_1: Action, fbk_file: Path, fdb_file: Path):
|
||||
srv.database.restore(backup=fbk_file, database=fdb_file)
|
||||
srv.wait()
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
act_1.isql(switches=[f'localhost:{fdb_file}'], input=test_script_1, connect_db=False)
|
||||
act_1.isql(switches=[act_1.get_dsn(fdb_file)], input=test_script_1, connect_db=False)
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
@ -178,7 +178,7 @@ sp_invoker_ddl = """
|
||||
end
|
||||
"""
|
||||
|
||||
test_user = user_factory(name='TMP$C5892', password='123')
|
||||
test_user = user_factory('db_1', name='TMP$C5892', password='123')
|
||||
|
||||
@pytest.mark.version('>=4.0')
|
||||
def test_1(act_1: Action, test_user: User, capsys):
|
||||
|
@ -151,10 +151,10 @@ def test_1(act_1: Action, fdb_112_file: Path, fbk_file: Path):
|
||||
act_1.reset()
|
||||
act_1.gbak(switches=['-b', act_1.db.dsn, str(fbk_file)])
|
||||
act_1.reset()
|
||||
act_1.gbak(switches=['-rep', str(fbk_file), f'localhost:{fdb_112_file}'])
|
||||
act_1.gbak(switches=['-rep', str(fbk_file), act_1.get_dsn(fdb_112_file)])
|
||||
#
|
||||
act_1.reset()
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
act_1.isql(switches=['-q', f'localhost:{fdb_112_file}'], connect_db=False,
|
||||
act_1.isql(switches=['-q', act_1.get_dsn(fdb_112_file)], connect_db=False,
|
||||
input='set list on; select sign(current_connection) as restore_with_replace_result from rdb$database;')
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
@ -31,9 +31,9 @@ import pytest
|
||||
from pathlib import Path
|
||||
from firebird.qa import db_factory, python_act, Action, user_factory, User
|
||||
|
||||
user_0 = user_factory(name='tmp$c6078_0', password='123')
|
||||
user_1 = user_factory(name='tmp$c6078_1', password='123')
|
||||
user_2 = user_factory(name='tmp$c6078_2', password='456')
|
||||
user_0_1 = user_factory('db_1', name='tmp$c6078_0', password='123')
|
||||
user_1_1 = user_factory('db_1', name='tmp$c6078_1', password='123')
|
||||
user_2_1 = user_factory('db_1', name='tmp$c6078_2', password='456')
|
||||
|
||||
# version: 3.0.5
|
||||
# resources: None
|
||||
@ -271,7 +271,7 @@ expected_stdout_1 = """
|
||||
"""
|
||||
|
||||
@pytest.mark.version('>=3.0.5,<4')
|
||||
def test_1(act_1: Action, user_0: User, user_1: User, user_2: User):
|
||||
def test_1(act_1: Action, user_0_1: User, user_1_1: User, user_2_1: User):
|
||||
script_vars = {'dsn': act_1.db.dsn,
|
||||
'user_name': act_1.db.user,
|
||||
'user_password': act_1.db.password,}
|
||||
@ -368,6 +368,10 @@ db_2 = db_factory(sql_dialect=3, init=init_script_2)
|
||||
|
||||
act_2 = python_act('db_2', substitutions=substitutions_2)
|
||||
|
||||
user_0_2 = user_factory('db_2', name='tmp$c6078_0', password='123')
|
||||
user_1_2 = user_factory('db_2', name='tmp$c6078_1', password='123')
|
||||
user_2_2 = user_factory('db_2', name='tmp$c6078_2', password='456')
|
||||
|
||||
expected_stdout_2 = """
|
||||
Statement failed, SQLSTATE = 28000
|
||||
modify record error
|
||||
@ -524,7 +528,7 @@ expected_stdout_2 = """
|
||||
"""
|
||||
|
||||
@pytest.mark.version('>=4.0')
|
||||
def test_2(act_2: Action, user_0: User, user_1: User, user_2: User):
|
||||
def test_2(act_2: Action, user_0_2: User, user_1_2: User, user_2_2: User):
|
||||
script_vars = {'dsn': act_2.db.dsn,
|
||||
'user_name': act_2.db.user,
|
||||
'user_password': act_2.db.password,}
|
||||
|
@ -2,50 +2,56 @@
|
||||
#
|
||||
# id: bugs.core_6141
|
||||
# title: fbsvcmgr action_repair rpr_list_limbo_trans does not show list of transactions in LIMBO state
|
||||
# decription:
|
||||
# decription:
|
||||
# Test creates two databases with the same DDL (single table with single field): DBNAME_A, DBNAME_B.
|
||||
# Then it makes instance of fdb.ConnectionGroup() for adding to it two connections (start distibuted work).
|
||||
# First connection adds bulk of records, each in separate transaction. Second connection adds only one record.
|
||||
# Number of separate transactions which are used for inserting records see in variable LIMBO_COUNT,
|
||||
# Number of separate transactions which are used for inserting records see in variable LIMBO_COUNT,
|
||||
# and it must be not less then 150 (at least for the moment when this test is written: dec-2019).
|
||||
# Then we change state of DBNAME_A to full shutdown, without doing commit or retain before this.
|
||||
# Finally, we return this database state to online.
|
||||
# Since that point header of DBNAME_A contains some data about limbo transactions.
|
||||
# We make output of them using two ways: gfix -list and fbsvcmgr rpr_list_limbo_trans.
|
||||
# Output should contain lines with ID of transactions in limbo state.
|
||||
# Output should contain lines with ID of transactions in limbo state.
|
||||
# NOTE: NOT ALL TRANSACTIONS CAN BE SHOWN BECAUSE THEIR LIST CAN BE EXTREMELY LONG.
|
||||
# We count number of lines with limbo info using regexp and check that number of these lines equal to expected,
|
||||
# ignoring concrete values of transaction IDs.
|
||||
#
|
||||
#
|
||||
# NB-1.
|
||||
# Output from gfix and fbsvcmgr differs, see pattern_for_limbo_in_gfix_output and pattern_for_limbo_in_fsvc_output.
|
||||
#
|
||||
# NB-2.
|
||||
#
|
||||
# NB-2.
|
||||
# Only 'gfix -list' produces output which final row is: "More limbo transactions than fit. Try again".
|
||||
# No such message in the output of fbsvcmgr, it just show some Tx ID (last that it can display).
|
||||
#
|
||||
#
|
||||
# Checked on:
|
||||
# 4.0.0.1691 SS: 6.718s.
|
||||
# 4.0.0.1691 CS: 6.532s.
|
||||
# 3.0.5.33212 SS: 4.152s.
|
||||
# 3.0.5.33212 CS: 5.770s.
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-6141
|
||||
# min_versions: ['3.0']
|
||||
# versions: 3.0
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
import re
|
||||
from firebird.qa import db_factory, python_act, Action, Database
|
||||
from firebird.driver import tpb, Isolation, DistributedTransactionManager, ShutdownMode, \
|
||||
ShutdownMethod
|
||||
|
||||
# version: 3.0
|
||||
# resources: None
|
||||
|
||||
substitutions_1 = [('[ \t]+', ' ')]
|
||||
|
||||
init_script_1 = """"""
|
||||
init_script_1 = """
|
||||
create table test(id int, x int, constraint test_pk primary key(id) using index test_pk) ;
|
||||
"""
|
||||
|
||||
db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
db_1_a = db_factory(sql_dialect=3, init=init_script_1, filename='core_6141_a.fdb')
|
||||
db_1_b = db_factory(sql_dialect=3, init=init_script_1, filename='core_6141_b.fdb')
|
||||
|
||||
# test_script_1
|
||||
#---
|
||||
@ -55,28 +61,28 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# import subprocess
|
||||
# import re
|
||||
# from fdb import services
|
||||
#
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
# db_conn.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def flush_and_close( file_handle ):
|
||||
# # https://docs.python.org/2/library/os.html#os.fsync
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
|
||||
# global os
|
||||
#
|
||||
#
|
||||
# file_handle.flush()
|
||||
# if file_handle.mode not in ('r', 'rb') and file_handle.name != os.devnull:
|
||||
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
|
||||
# os.fsync(file_handle.fileno())
|
||||
# file_handle.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def cleanup( f_names_list ):
|
||||
# global os
|
||||
# for f in f_names_list:
|
||||
@ -87,50 +93,50 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# else:
|
||||
# print('Unrecognized type of element:', f, ' - can not be treated as file.')
|
||||
# del_name = None
|
||||
#
|
||||
#
|
||||
# if del_name and os.path.isfile( del_name ):
|
||||
# os.remove( del_name )
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# DBNAME_A = os.path.join(context['temp_directory'],'tmp_6141_a.fdb')
|
||||
# DBNAME_B = os.path.join(context['temp_directory'],'tmp_6141_b.fdb')
|
||||
#
|
||||
#
|
||||
# LIMBO_COUNT = 255
|
||||
# cleanup( (DBNAME_A,DBNAME_B) )
|
||||
#
|
||||
#
|
||||
# con1 = fdb.create_database( dsn = 'localhost:' + DBNAME_A)
|
||||
# con2 = fdb.create_database( dsn = 'localhost:' + DBNAME_B)
|
||||
# con1.execute_immediate( 'create table test(id int, x int, constraint test_pk primary key(id) using index test_pk)' )
|
||||
# con1.commit()
|
||||
#
|
||||
#
|
||||
# con2.execute_immediate( 'create table test(id int, x int, constraint test_pk primary key(id) using index test_pk)' )
|
||||
# con2.commit()
|
||||
#
|
||||
#
|
||||
# con1.close()
|
||||
# con2.close()
|
||||
#
|
||||
#
|
||||
# cgr = fdb.ConnectionGroup()
|
||||
#
|
||||
#
|
||||
# con1 = fdb.connect( dsn = 'localhost:' + DBNAME_A)
|
||||
# con2 = fdb.connect( dsn = 'localhost:' + DBNAME_B)
|
||||
#
|
||||
#
|
||||
# cgr.add(con1)
|
||||
# cgr.add(con2)
|
||||
#
|
||||
#
|
||||
# # https://pythonhosted.org/fdb/reference.html#fdb.TPB
|
||||
# # https://pythonhosted.org/fdb/reference.html#fdb.Connection.trans
|
||||
#
|
||||
#
|
||||
# custom_tpb = fdb.TPB()
|
||||
# custom_tpb.access_mode = fdb.isc_tpb_write
|
||||
# custom_tpb.isolation_level = (fdb.isc_tpb_read_committed, fdb.isc_tpb_rec_version)
|
||||
# custom_tpb.lock_resolution = fdb.isc_tpb_nowait
|
||||
#
|
||||
#
|
||||
# tx1_list=[]
|
||||
# for i in range(0, LIMBO_COUNT):
|
||||
# tx1_list += [ con1.trans( default_tpb = custom_tpb ) ]
|
||||
#
|
||||
#
|
||||
# cur_list=[]
|
||||
# for i, tx1 in enumerate(tx1_list):
|
||||
# tx1.begin()
|
||||
@ -138,63 +144,63 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# cur.execute( "insert into test(id, x) values( ?, ? )", ( i, i*11111 ) )
|
||||
# cur.close()
|
||||
# tx1.prepare()
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# tx2 = con2.trans( default_tpb = custom_tpb )
|
||||
# cur2=tx2.cursor()
|
||||
# cur2.execute( "insert into test(id, x) values( ?, ? )", (-2, -2222222) )
|
||||
# cur2.close()
|
||||
#
|
||||
#
|
||||
# tx2.prepare()
|
||||
# tx2.commit()
|
||||
#
|
||||
#
|
||||
# svc = services.connect(host='localhost', user=user_name, password=user_password)
|
||||
# svc.shutdown( DBNAME_A, services.SHUT_FULL, services.SHUT_FORCE, 0)
|
||||
#
|
||||
#
|
||||
# print('Database <DBNAME_A> is in full shutdown state now.')
|
||||
#
|
||||
#
|
||||
# for tx1 in tx1_list:
|
||||
# try:
|
||||
# tx1.close()
|
||||
# except:
|
||||
# pass
|
||||
#
|
||||
# # Result for DBNAME_A when it will be returned online
|
||||
#
|
||||
# # Result for DBNAME_A when it will be returned online
|
||||
# # and we query table TEST:
|
||||
# # Statement failed, SQLSTATE = HY000
|
||||
# # record from transaction <N> is stuck in limbo
|
||||
# # See also "gfix -list <disk>\\path o\\dbname_a"
|
||||
#
|
||||
#
|
||||
# cgr.clear()
|
||||
# print('ConnectionGroup instance has been cleared.')
|
||||
#
|
||||
#
|
||||
# svc.bring_online( DBNAME_A, services.SHUT_NORMAL )
|
||||
# print('Database <DBNAME_A> has been brought ONLINE.')
|
||||
#
|
||||
#
|
||||
# svc.close()
|
||||
# con2.close()
|
||||
#
|
||||
#
|
||||
# try:
|
||||
# # This will fail for sure because DB state was changed to full shutdown
|
||||
# con1.close()
|
||||
# except:
|
||||
# pass
|
||||
#
|
||||
#
|
||||
# f_gfix_list_log=open( os.path.join(context['temp_directory'],'tmp_6141_gfix_list.log'), 'w', buffering = 0)
|
||||
# subprocess.call( [ context['gfix_path'], '-list', DBNAME_A ], stdout=f_gfix_list_log, stderr=subprocess.STDOUT )
|
||||
# flush_and_close( f_gfix_list_log )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# f_svc_list_log=open( os.path.join(context['temp_directory'],'tmp_6141_fbsvc_list.log'), 'w', buffering = 0)
|
||||
# subprocess.call( [ context['fbsvcmgr_path'], 'localhost:service_mgr', 'action_repair', 'rpr_list_limbo_trans', 'dbname', DBNAME_A ], stdout=f_svc_list_log, stderr=subprocess.STDOUT )
|
||||
# flush_and_close( f_svc_list_log )
|
||||
#
|
||||
#
|
||||
# pattern_for_limbo_in_gfix_output=re.compile('Transaction\\s+\\d+\\s+.*limbo', re.IGNORECASE)
|
||||
# pattern_for_limbo_in_fsvc_output=re.compile('Transaction\\s+in\\s+limbo:\\s+\\d+', re.IGNORECASE)
|
||||
#
|
||||
#
|
||||
# for i,g in enumerate( (f_gfix_list_log, f_svc_list_log) ):
|
||||
# lines_with_limbo_info=0
|
||||
# log_name = 'gfix -list' if i== 0 else 'fbsvcmgr rpr_list_limbo_trans'
|
||||
# log_name = 'gfix -list' if i== 0 else 'fbsvcmgr rpr_list_limbo_trans'
|
||||
# pattern_for_match = pattern_for_limbo_in_gfix_output if i==0 else pattern_for_limbo_in_fsvc_output
|
||||
# msg = "Number of lines related to limbo Tx in '%(log_name)s' output: " % locals()
|
||||
# with open( g.name,'r') as f:
|
||||
@ -204,28 +210,84 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# else:
|
||||
# print( 'Additional output from ' + ('GFIX: ' if i==0 else 'FBSVCMGR: ') + line )
|
||||
# print( msg + str(lines_with_limbo_info) )
|
||||
#
|
||||
#
|
||||
# # CLEANUP
|
||||
# #########
|
||||
# time.sleep(1)
|
||||
# cleanup( (DBNAME_A, DBNAME_B, f_gfix_list_log.name, f_svc_list_log.name) )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1_a', substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
Database <DBNAME_A> is in full shutdown state now.
|
||||
ConnectionGroup instance has been cleared.
|
||||
Database <DBNAME_A> has been brought ONLINE.
|
||||
Additional output from GFIX: More limbo transactions than fit. Try again
|
||||
Number of lines related to limbo Tx in 'gfix -list' output: 146
|
||||
Number of lines related to limbo Tx in 'fbsvcmgr rpr_list_limbo_trans' output: 146
|
||||
"""
|
||||
"""
|
||||
|
||||
LIMBO_COUNT = 255
|
||||
|
||||
@pytest.mark.version('>=3.0')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
|
||||
|
||||
def test_1(act_1: Action, db_1_b: Database, capsys):
|
||||
#pytest.skip('PROBLEM WITH TEST')
|
||||
# On Firebird 4, the fbsvcmngr reports error:
|
||||
# unavailable database
|
||||
# gfix works fine, although the outpout is more verbose than original test expected
|
||||
dt_list = []
|
||||
custom_tpb = tpb(isolation=Isolation.READ_COMMITTED_RECORD_VERSION, lock_timeout=0)
|
||||
with act_1.db.connect() as con1, db_1_b.connect() as con2:
|
||||
for i in range(LIMBO_COUNT):
|
||||
dt = DistributedTransactionManager([con1, con2], custom_tpb)
|
||||
dt_list.append(dt)
|
||||
cur1 = dt.cursor(con1)
|
||||
cur1.execute("insert into test (id, x) values (?, ?)", [i, i * 11111])
|
||||
cur1.close()
|
||||
cur2 = dt.cursor(con2)
|
||||
cur2.execute("insert into test (id, x) values (?, ?)", [-i, i * -2222])
|
||||
cur2.close()
|
||||
for dtc in dt_list:
|
||||
# Initiate distributed commit: phase-1
|
||||
dtc.prepare()
|
||||
# Shut down the first database
|
||||
with act_1.connect_server() as srv:
|
||||
srv.database.shutdown(database=act_1.db.db_path, mode=ShutdownMode.FULL,
|
||||
method=ShutdownMethod.FORCED, timeout=0)
|
||||
#
|
||||
while dt_list:
|
||||
dtc = dt_list.pop()
|
||||
dtc._tra = None # Needed hack to bypass commit and exception
|
||||
dtc.close()
|
||||
#
|
||||
with act_1.connect_server() as srv:
|
||||
srv.database.bring_online(database=act_1.db.db_path)
|
||||
#
|
||||
act_1.gfix(switches=['-list', act_1.db.dsn])
|
||||
gfix_log = act_1.stdout
|
||||
#
|
||||
act_1.reset()
|
||||
# Set EXPECTED_STDERR so we can get over "unavailable database" error and fail on assert
|
||||
# Remove when svcmgr issue is resolved
|
||||
act_1.expected_stderr = "We expect errors"
|
||||
act_1.svcmgr(switches=['action_repair', 'rpr_list_limbo_trans', 'dbname', act_1.db.dsn])
|
||||
mngr_log = act_1.stdout
|
||||
#print(act_1.stderr)
|
||||
#
|
||||
pattern_for_gfix_output = re.compile('Transaction\\s+\\d+\\s+.*limbo', re.IGNORECASE)
|
||||
pattern_for_fsvc_output = re.compile('Transaction\\s+in\\s+limbo:\\s+\\d+', re.IGNORECASE)
|
||||
#
|
||||
for log_name, limbo_log, pattern in [('gfix -list', gfix_log, pattern_for_gfix_output),
|
||||
('fbsvcmgr rpr_list_limbo_trans', mngr_log, pattern_for_fsvc_output)]:
|
||||
lines_with_limbo_info = 0
|
||||
msg = f"Number of lines related to limbo Tx in '{log_name}' output: "
|
||||
for line in limbo_log.splitlines():
|
||||
if pattern.search(line):
|
||||
lines_with_limbo_info += 1
|
||||
#else:
|
||||
#print(f'Additional output from {log_name}: {line}')
|
||||
print(msg + str(lines_with_limbo_info))
|
||||
# Check
|
||||
act_1.reset()
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
act_1.stdout = capsys.readouterr().out
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
@ -2,24 +2,25 @@
|
||||
#
|
||||
# id: bugs.core_6145
|
||||
# title: Wrong result in "similar to" with non latin characters
|
||||
# decription:
|
||||
# decription:
|
||||
# Confirmed bug on 4.0.0.1607
|
||||
# Checked on:
|
||||
# 4.0.0.1614: OK, 1.509s.
|
||||
# 3.0.5.33171: OK, 0.682s.
|
||||
# 2.5.9.27142: OK, 0.629s.
|
||||
#
|
||||
# 2.5.9.27142: OK, 0.629s.
|
||||
#
|
||||
# 15.04.2021. Adapted for run both on Windows and Linux. Checked on:
|
||||
# Windows: 4.0.0.2416
|
||||
# Linux: 4.0.0.2416
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-6145
|
||||
# min_versions: ['2.5.0']
|
||||
# versions: 2.5
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
from pathlib import Path
|
||||
from firebird.qa import db_factory, python_act, Action, temp_file
|
||||
|
||||
# version: 2.5
|
||||
# resources: None
|
||||
@ -32,33 +33,33 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
|
||||
|
||||
# test_script_1
|
||||
#---
|
||||
#
|
||||
#
|
||||
# import os
|
||||
# import time
|
||||
# import subprocess
|
||||
#
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
#
|
||||
#
|
||||
# db_conn.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def flush_and_close( file_handle ):
|
||||
# # https://docs.python.org/2/library/os.html#os.fsync
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
|
||||
# global os
|
||||
#
|
||||
#
|
||||
# file_handle.flush()
|
||||
# if file_handle.mode not in ('r', 'rb') and file_handle.name != os.devnull:
|
||||
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
|
||||
# os.fsync(file_handle.fileno())
|
||||
# file_handle.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def cleanup( f_names_list ):
|
||||
# global os
|
||||
# for i in range(len( f_names_list )):
|
||||
@ -70,64 +71,65 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
|
||||
# print('Unrecognized type of element:', f_names_list[i], ' - can not be treated as file.')
|
||||
# print('type(f_names_list[i])=',type(f_names_list[i]))
|
||||
# del_name = None
|
||||
#
|
||||
#
|
||||
# if del_name and os.path.isfile( del_name ):
|
||||
# os.remove( del_name )
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# non_ascii_ddl='''
|
||||
# set bail on;
|
||||
# set list on;
|
||||
# set names win1251;
|
||||
# connect '%(dsn)s' user '%(user_name)s' password '%(user_password)s';
|
||||
#
|
||||
#
|
||||
# set count on;
|
||||
# set heading off;
|
||||
# -- NB: When this script is Python variable then we have to use DUPLICATE percent signs!
|
||||
# -- Otherwise get: "not enough arguments for format string"
|
||||
# select 1 result_1 from rdb$database where 'я' similar to '%%Я%%';
|
||||
# select 2 result_2 from rdb$database where 'Я' similar to '%%я%%';
|
||||
# select 3 result_3 from rdb$database where 'я' similar to '[Яя]';
|
||||
# select 1 result_1 from rdb$database where 'я' similar to '%%Я%%';
|
||||
# select 2 result_2 from rdb$database where 'Я' similar to '%%я%%';
|
||||
# select 3 result_3 from rdb$database where 'я' similar to '[Яя]';
|
||||
# select 4 result_4 from rdb$database where 'Я' similar to 'я';
|
||||
# select 5 result_5 from rdb$database where 'Я' similar to 'Я';
|
||||
# select 6 result_6 from rdb$database where 'Я' similar to '[яЯ]';
|
||||
# ''' % dict(globals(), **locals())
|
||||
#
|
||||
#
|
||||
# f_ddl_sql = open( os.path.join(context['temp_directory'], 'tmp_6145_w1251.sql'), 'w' )
|
||||
# f_ddl_sql.write( non_ascii_ddl.decode('utf8').encode('cp1251') )
|
||||
# flush_and_close( f_ddl_sql )
|
||||
#
|
||||
#
|
||||
# f_run_log = open( os.path.join(context['temp_directory'],'tmp_6145.log'), 'w')
|
||||
# f_run_err = open( os.path.join(context['temp_directory'],'tmp_6145.err'), 'w')
|
||||
#
|
||||
#
|
||||
# subprocess.call( [context['isql_path'], "-q", "-i", f_ddl_sql.name ],
|
||||
# stdout = f_run_log,
|
||||
# stderr = f_run_err
|
||||
# )
|
||||
#
|
||||
#
|
||||
# flush_and_close( f_run_log )
|
||||
# flush_and_close( f_run_err )
|
||||
#
|
||||
#
|
||||
# with open( f_run_log.name, 'r') as f:
|
||||
# for line in f:
|
||||
# if line.strip():
|
||||
# print( line.strip().decode("cp1251").encode('utf8') )
|
||||
#
|
||||
#
|
||||
# with open( f_run_err.name, 'r') as f:
|
||||
# for line in f:
|
||||
# out_txt='UNEXPECTED STDERR: ';
|
||||
# if line.strip():
|
||||
# print( out_txt + line.strip().decode("cp1251").encode('utf8') )
|
||||
#
|
||||
#
|
||||
# # cleanup:
|
||||
# ##########
|
||||
# time.sleep(1)
|
||||
# #cleanup( (f_ddl_sql, f_run_log, f_run_err) )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
Records affected: 0
|
||||
@ -139,11 +141,26 @@ expected_stdout_1 = """
|
||||
Records affected: 1
|
||||
RESULT_6 6
|
||||
Records affected: 1
|
||||
"""
|
||||
"""
|
||||
|
||||
test_script = temp_file('test-script.sql')
|
||||
|
||||
@pytest.mark.version('>=2.5')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
|
||||
|
||||
def test_1(act_1: Action, test_script: Path):
|
||||
test_script.write_text("""
|
||||
set bail on;
|
||||
set list on;
|
||||
set count on;
|
||||
set heading off;
|
||||
-- NB: When this script is Python variable then we have to use DUPLICATE percent signs!
|
||||
-- Otherwise get: "not enough arguments for format string"
|
||||
select 1 result_1 from rdb$database where 'я' similar to '%%Я%%';
|
||||
select 2 result_2 from rdb$database where 'Я' similar to '%%я%%';
|
||||
select 3 result_3 from rdb$database where 'я' similar to '[Яя]';
|
||||
select 4 result_4 from rdb$database where 'Я' similar to 'я';
|
||||
select 5 result_5 from rdb$database where 'Я' similar to 'Я';
|
||||
select 6 result_6 from rdb$database where 'Я' similar to '[яЯ]';
|
||||
""", encoding='cp1251')
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
act_1.isql(switches=[], input_file=test_script, charset='WIN1251')
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
@ -2,23 +2,23 @@
|
||||
#
|
||||
# id: bugs.core_6147
|
||||
# title: PLG$SRP table, PLG$SRP_VIEW View instructions are strangely added in the metadata script extracted when Windows trusted authentication is enabled
|
||||
# decription:
|
||||
# decription:
|
||||
# ::: NOTE :::
|
||||
# References to the table PLG$SRP and view PLG$SRP_VIEW *always* present in extracted metadata,
|
||||
# regardless of using auth plugin (and this is NOT a bug!).
|
||||
#
|
||||
#
|
||||
# Fix was introduced in 4.0.0.2087: extracted metadata must contain "OR ALTER" clause in:
|
||||
# CREATE OR ALTER GLOBAL MAPPING TRUSTED_AUTH_C6147 ...
|
||||
# ^^^^^^^^
|
||||
# Builds before 4.0.0.2084 did not add this clause in extracted metadata script (checked 4.0.0.2076).
|
||||
# (see also discussion with Alex, 02-jun-2020 08:23).
|
||||
#
|
||||
#
|
||||
# ### NB ###
|
||||
# For unclear reason ALTER EXTERNAL CONNECTIONS POOL CLEAR ALL + DROP DATABASE do not work as expected in this test:
|
||||
# test DB remains opened by firebird.exe about 5...7 seconds after test finish, and 'drop database' does not issues any error.
|
||||
# Because of this it was decided to forcedly change DB state to full shutdown in order to have ability to drop it.
|
||||
# 22.02.2021: perhaps, this was somehow related to core-6441.
|
||||
#
|
||||
#
|
||||
# NOTES FOR WINDOWS:
|
||||
# ##################
|
||||
# We create copy of %FIREBIRD_HOME%\\database.conf and change it content by adding lines:
|
||||
@ -29,25 +29,25 @@
|
||||
# Then we create trest DB in embedded mode, create SYSDBA that belongs to this DB and create global mapping.
|
||||
# We check content of rdb$auth_mapping table after this step in order to ensure that mapping was actually created.
|
||||
# After this we do connect to DB using Win_SSPI and extract metadata.
|
||||
#
|
||||
#
|
||||
# NOTES FOR LINUX:
|
||||
# ################
|
||||
# 03-mar-2021. This test can run on Linux but we have to use plugin = Srp instead of win_sspi.
|
||||
# This is done by check result of os.name (see below).
|
||||
# Local mapping (i.e. in RDB$DATABASE) will *not* be created in this case (in contrary to win_sspi),
|
||||
# thus we create and drop it "manually" in order to pass expected results check.
|
||||
#
|
||||
#
|
||||
# Checked on:
|
||||
# * Windows: 4.0.0.2377 SS/CS (done for both win_sspi and Srp, but only win_sspi is used in this test for Windows)
|
||||
# * Linux: 4.0.0.2377 SS/CS (done for Srp)
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-6147
|
||||
# min_versions: ['4.0']
|
||||
# versions: 4.0
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
from firebird.qa import db_factory, python_act, Action
|
||||
|
||||
# version: 4.0
|
||||
# resources: None
|
||||
@ -60,7 +60,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
|
||||
# test_script_1
|
||||
#---
|
||||
#
|
||||
#
|
||||
# import os
|
||||
# import subprocess
|
||||
# import datetime
|
||||
@ -68,9 +68,9 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# import shutil
|
||||
# import re
|
||||
# from fdb import services
|
||||
#
|
||||
#
|
||||
# this_fdb = db_conn.database_name
|
||||
#
|
||||
#
|
||||
# if os.name == 'nt':
|
||||
# # On Windows we test what it was initially described in the ticket (trusted auth.):
|
||||
# PLUGIN_FOR_MAPPING = 'win_sspi'
|
||||
@ -78,8 +78,8 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# # On Linux currently we can check only Srp plugin
|
||||
# # but results must be the same as for win_sspi:
|
||||
# PLUGIN_FOR_MAPPING = 'Srp'
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# # 23.08.2020: !!! REMOVING OS-VARIABLE ISC_USER IS MANDATORY HERE !!!
|
||||
# # This variable could be set by other .fbts which was performed before current within batch mode (i.e. when fbt_run is called from <rundaily>)
|
||||
# # NB: os.unsetenv('ISC_USER') actually does NOT affect on content of os.environ dictionary, see: https://docs.python.org/2/library/os.html
|
||||
@ -89,26 +89,26 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# del os.environ["ISC_USER"]
|
||||
# except KeyError as e:
|
||||
# pass
|
||||
#
|
||||
#
|
||||
# db_conn.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def flush_and_close( file_handle ):
|
||||
# # https://docs.python.org/2/library/os.html#os.fsync
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
|
||||
# global os
|
||||
#
|
||||
#
|
||||
# file_handle.flush()
|
||||
# if file_handle.mode not in ('r', 'rb') and file_handle.name != os.devnull:
|
||||
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
|
||||
# os.fsync(file_handle.fileno())
|
||||
# file_handle.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def cleanup( f_names_list ):
|
||||
# global os
|
||||
# for f in f_names_list:
|
||||
@ -119,29 +119,29 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# else:
|
||||
# print('Unrecognized type of element:', f, ' - can not be treated as file.')
|
||||
# del_name = None
|
||||
#
|
||||
#
|
||||
# if del_name and os.path.isfile( del_name ):
|
||||
# os.remove( del_name )
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# svc = services.connect(host='localhost', user= user_name, password= user_password)
|
||||
# fb_home = svc.get_home_directory()
|
||||
# svc.close()
|
||||
# # Resut: fb_home is full path to FB instance home (with trailing slash).
|
||||
#
|
||||
#
|
||||
# dts = datetime.datetime.now().strftime("%y%m%d_%H%M%S")
|
||||
#
|
||||
#
|
||||
# dbconf = os.path.join( fb_home, 'databases.conf')
|
||||
# dbcbak = os.path.join( fb_home, 'databases_'+dts+'.bak')
|
||||
#
|
||||
#
|
||||
# shutil.copy2( dbconf, dbcbak )
|
||||
#
|
||||
#
|
||||
# tmp_fdb=os.path.join(context['temp_directory'],'tmp_6147.fdb')
|
||||
# cleanup( (tmp_fdb,) )
|
||||
#
|
||||
#
|
||||
# text2app='''
|
||||
#
|
||||
#
|
||||
# # Temporarily added by fbtest, CORE-6147. Should be removed auto:
|
||||
# ##############################
|
||||
# tmp_alias_6147 = %(tmp_fdb)s
|
||||
@ -150,13 +150,13 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# }
|
||||
# ##############################
|
||||
# ''' % locals()
|
||||
#
|
||||
#
|
||||
# f_dbconf=open( dbconf, 'a')
|
||||
# f_dbconf.seek(0, 2)
|
||||
# f_dbconf.write( text2app )
|
||||
# flush_and_close( f_dbconf )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# SHOW_MAP_INFO_QUERY = '''
|
||||
# set count on;
|
||||
# -- set echo on;
|
||||
@ -169,7 +169,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# set width map_to 10;
|
||||
# select * from v_map_info;
|
||||
# '''
|
||||
#
|
||||
#
|
||||
# if PLUGIN_FOR_MAPPING == 'Srp':
|
||||
# db_connect_string = this_fdb
|
||||
# sql_txt= '''
|
||||
@ -193,14 +193,14 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# create user %(user_name)s password '%(user_password)s';
|
||||
# commit;
|
||||
# ''' % dict(globals(), **locals())
|
||||
#
|
||||
#
|
||||
# sql_txt += '''
|
||||
# -- ::: NB :::
|
||||
# -- When used plugin is win_sspi then *TWO* mappings will be created here: "local' (in rdb$auth_mapping)
|
||||
# -- and g;pbal (in sec$global_auth_mapping). This is NOT so when used plugin = Srp (only global mapping will be made).
|
||||
# create or alter global mapping trusted_auth_c6147 using plugin %(PLUGIN_FOR_MAPPING)s from any user to user;
|
||||
# commit;
|
||||
#
|
||||
# commit;
|
||||
#
|
||||
# recreate view v_map_info as
|
||||
# select
|
||||
# map_name
|
||||
@ -237,27 +237,27 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# and t.map_plugin = upper('%(PLUGIN_FOR_MAPPING)s')
|
||||
# ;
|
||||
# commit;
|
||||
#
|
||||
#
|
||||
# %(SHOW_MAP_INFO_QUERY)s
|
||||
#
|
||||
#
|
||||
# ''' % dict(globals(), **locals())
|
||||
#
|
||||
#
|
||||
# f_prepare_sql = open( os.path.join(context['temp_directory'],'tmp_6147_prepare.sql'), 'w')
|
||||
# f_prepare_sql.write(sql_txt)
|
||||
# flush_and_close( f_prepare_sql )
|
||||
#
|
||||
#
|
||||
# f_prepare_log=open( os.path.join(context['temp_directory'],'tmp_6147_prepare.log'), 'w')
|
||||
# subprocess.call( [ context['isql_path'], "-q", "-i", f_prepare_sql.name ], stdout=f_prepare_log, stderr=subprocess.STDOUT )
|
||||
# flush_and_close( f_prepare_log )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# # Extract metadata from test DB:
|
||||
# ##################
|
||||
# f_medatata_log=open( os.path.join(context['temp_directory'],'tmp_6147_meta.mapping.sql'), 'w')
|
||||
# subprocess.call( [ context['isql_path'], '-x', 'localhost:%(db_connect_string)s' % locals(),'-user', user_name, '-pas', user_password ], stdout=f_medatata_log, stderr=subprocess.STDOUT )
|
||||
# flush_and_close( f_medatata_log )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# # Remove global mapping:
|
||||
# ########################
|
||||
# f_cleanup_sql = open( os.path.join(context['temp_directory'],'tmp_6147_cleanup.sql'), 'w')
|
||||
@ -277,66 +277,66 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# connect 'localhost:%(db_connect_string)s' user %(user_name)s password '%(user_password)s';
|
||||
# drop global mapping trusted_auth_c6147;
|
||||
# ''' % dict(globals(), **locals())
|
||||
#
|
||||
#
|
||||
# if PLUGIN_FOR_MAPPING == 'Srp':
|
||||
# sql_txt += '''
|
||||
# -- Delete record from rdb$auth_mapping (only when used plugin = 'Srp'):
|
||||
# drop mapping trusted_auth_c6147;
|
||||
# '''
|
||||
#
|
||||
# sql_txt += '''
|
||||
#
|
||||
# sql_txt += '''
|
||||
# commit;
|
||||
#
|
||||
#
|
||||
# %(SHOW_MAP_INFO_QUERY)s
|
||||
# quit;
|
||||
#
|
||||
#
|
||||
# -- DOES NOT HELP! DATABASE FILE REMAINS OPENED BY FIREBIRD!
|
||||
# -- ALTER EXTERNAL CONNECTIONS POOL CLEAR ALL; -- !! mandatory otherwise database file will be kept by engine and fbtest will not able to drop it !!
|
||||
# -- drop database; --> does not raise errot when clear pool but DB file still remains opened !!!
|
||||
# ''' % dict(globals(), **locals())
|
||||
#
|
||||
#
|
||||
# f_cleanup_sql.write(sql_txt)
|
||||
# flush_and_close( f_cleanup_sql )
|
||||
#
|
||||
#
|
||||
# # DROP MAPPING:
|
||||
# ###############
|
||||
# f_cleanup_log = open( os.path.join(context['temp_directory'],'tmp_6147_cleanup.log'), 'w')
|
||||
# subprocess.call( [ context['isql_path'], "-q", "-i", f_cleanup_sql.name ], stdout=f_cleanup_log, stderr=subprocess.STDOUT )
|
||||
# flush_and_close( f_cleanup_log )
|
||||
#
|
||||
#
|
||||
# subprocess.call( [context['gfix_path'], 'localhost:%(db_connect_string)s' % locals(), '-shut', 'single', '-force', '0', '-user', user_name, '-pas', user_password] )
|
||||
#
|
||||
#
|
||||
# # RESTORE original config:
|
||||
# ##########################
|
||||
# shutil.move( dbcbak, dbconf)
|
||||
#
|
||||
#
|
||||
# with open(f_prepare_log.name, 'r') as f:
|
||||
# for line in f:
|
||||
# if line.split():
|
||||
# print('AFTER_MADE_MAPPING: ' + line)
|
||||
#
|
||||
#
|
||||
# allowed_patterns = (
|
||||
# re.compile('MAPPING TRUSTED_AUTH_C6147', re.IGNORECASE)
|
||||
# ,re.compile('SQLSTATE', re.IGNORECASE)
|
||||
# ,re.compile('Missing security', re.IGNORECASE)
|
||||
# ,re.compile('Your user', re.IGNORECASE)
|
||||
# )
|
||||
#
|
||||
#
|
||||
# with open(f_medatata_log.name, 'r') as f:
|
||||
# for line in f:
|
||||
# match2some = [ p.search(line) for p in allowed_patterns ]
|
||||
# if max(match2some):
|
||||
# print('EXTRACTED_METADATA: ' + line)
|
||||
#
|
||||
#
|
||||
# with open(f_cleanup_log.name, 'r') as f:
|
||||
# for line in f:
|
||||
# if line.split():
|
||||
# print('AFTER_DROP_MAPPING: ' + line)
|
||||
#
|
||||
#
|
||||
# # CLEANUP:
|
||||
# ##########
|
||||
# time.sleep(1)
|
||||
# f_list=(
|
||||
# f_list=(
|
||||
# f_prepare_sql
|
||||
# ,f_prepare_log
|
||||
# ,f_medatata_log
|
||||
@ -345,17 +345,18 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# ,tmp_fdb
|
||||
# )
|
||||
# cleanup( f_list )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
AFTER_MADE_MAPPING: MAP_NAME MAP_TYPE FROM_TYPE MAP_FROM TO_TYPE MAP_TO
|
||||
AFTER_MADE_MAPPING: =============================== ========== ========== ========== ======= ==========
|
||||
AFTER_MADE_MAPPING: TRUSTED_AUTH_C6147 local USER * 0 <null>
|
||||
AFTER_MADE_MAPPING: TRUSTED_AUTH_C6147 global USER * 0 <null>
|
||||
AFTER_MADE_MAPPING: MAP_NAME MAP_TYPE FROM_TYPE MAP_FROM TO_TYPE MAP_TO
|
||||
AFTER_MADE_MAPPING: =============================== ========== ========== ========== ======= ==========
|
||||
AFTER_MADE_MAPPING: TRUSTED_AUTH_C6147 local USER * 0 <null>
|
||||
AFTER_MADE_MAPPING: TRUSTED_AUTH_C6147 global USER * 0 <null>
|
||||
AFTER_MADE_MAPPING: Records affected: 2
|
||||
|
||||
EXTRACTED_METADATA: CREATE MAPPING TRUSTED_AUTH_C6147 USING PLUGIN
|
||||
@ -363,11 +364,10 @@ EXTRACTED_METADATA: CREATE OR ALTER GLOBAL MAPPING TRUSTED_AUTH_C6147 USING PLUG
|
||||
|
||||
AFTER_DROP_MAPPING: Records affected: 0
|
||||
|
||||
"""
|
||||
"""
|
||||
|
||||
@pytest.mark.version('>=4.0')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
def test_1(act_1: Action):
|
||||
pytest.skip("Requires change to databases.conf")
|
||||
|
||||
|
||||
|
@ -2,11 +2,11 @@
|
||||
#
|
||||
# id: bugs.core_6158
|
||||
# title: substring similar - extra characters in the result for non latin characters
|
||||
# decription:
|
||||
# Confirmed regression on build 4.0.0.1629, 4.0.0.1631
|
||||
# decription:
|
||||
# Confirmed regression on build 4.0.0.1629, 4.0.0.1631
|
||||
# Worked as expected on 4.0.0.1535 (build 24.06.2019, before replacement old regexp library with 're2')
|
||||
# Works fine on: 4.0.0.1632 (build 19.10.2019)
|
||||
#
|
||||
#
|
||||
# 05-mar-2021. Re-implemented in order to have ability to run this test on Linux.
|
||||
# Test encodes to UTF8 all needed statements (SET NAMES; CONNECT; DDL and DML) and stores this text in .sql file.
|
||||
# NOTE: 'SET NAMES' contain character set that must be used for reproducing problem (WIN1251 in this test).
|
||||
@ -16,15 +16,16 @@
|
||||
# Checked on:
|
||||
# * Windows: 4.0.0.2377
|
||||
# * Linux: 4.0.0.2379
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-6158
|
||||
# min_versions: ['4.0']
|
||||
# versions: 4.0
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
from pathlib import Path
|
||||
from firebird.qa import db_factory, python_act, Action, temp_file
|
||||
|
||||
# version: 4.0
|
||||
# resources: None
|
||||
@ -37,31 +38,31 @@ db_1 = db_factory(charset='WIN1251', sql_dialect=3, init=init_script_1)
|
||||
|
||||
# test_script_1
|
||||
#---
|
||||
#
|
||||
#
|
||||
# import os
|
||||
# import codecs
|
||||
# import subprocess
|
||||
# import time
|
||||
# engine = db_conn.engine_version
|
||||
# db_conn.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def flush_and_close( file_handle ):
|
||||
# # https://docs.python.org/2/library/os.html#os.fsync
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
|
||||
# global os
|
||||
#
|
||||
#
|
||||
# file_handle.flush()
|
||||
# if file_handle.mode not in ('r', 'rb') and file_handle.name != os.devnull:
|
||||
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
|
||||
# os.fsync(file_handle.fileno())
|
||||
# file_handle.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def cleanup( f_names_list ):
|
||||
# global os
|
||||
# for i in range(len( f_names_list )):
|
||||
@ -72,22 +73,22 @@ db_1 = db_factory(charset='WIN1251', sql_dialect=3, init=init_script_1)
|
||||
# else:
|
||||
# print('Unrecognized type of element:', f_names_list[i], ' - can not be treated as file.')
|
||||
# del_name = None
|
||||
#
|
||||
#
|
||||
# if del_name and os.path.isfile( del_name ):
|
||||
# os.remove( del_name )
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# # Put patterns outside of sql_txt in order to avoid replacement percent sign
|
||||
# # with its duplicate ('%' --> '%%') because of Python substitution requirements:
|
||||
# pattern_01 = '%/#*(=){3,}#"%#"(=){3,}#*/%'
|
||||
# pattern_02 = '%/#*(#-){3,}#"%#"(#-){3,}#*/%'
|
||||
#
|
||||
#
|
||||
# sql_txt=''' set bail on;
|
||||
# set names win1251;
|
||||
# connect '%(dsn)s' user '%(user_name)s' password '%(user_password)s';
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# -- This is needed to get "cannot transliterate character between character sets"
|
||||
# -- on build 4.0.0.1631, see comment in the tracker 18/Oct/19 02:57 PM:
|
||||
# create domain T_A64 as varchar (64) character set WIN1251 collate WIN1251;
|
||||
@ -97,10 +98,10 @@ db_1 = db_factory(charset='WIN1251', sql_dialect=3, init=init_script_1)
|
||||
# insert into VALUT_LIST (NAME) values ('Турецкая лира');
|
||||
# insert into VALUT_LIST (NAME) values ('Доллар США');
|
||||
# commit;
|
||||
#
|
||||
#
|
||||
# set list on;
|
||||
# set blob all;
|
||||
#
|
||||
#
|
||||
# select substring('
|
||||
# aaa
|
||||
# /*==== Комментарий между символами "равно" ====*/
|
||||
@ -112,53 +113,92 @@ db_1 = db_factory(charset='WIN1251', sql_dialect=3, init=init_script_1)
|
||||
# jjj
|
||||
# ' similar '%(pattern_01)s' escape '#') as result1
|
||||
# from rdb$database;
|
||||
#
|
||||
#
|
||||
# -- additional check for special character '-' as delimiter:
|
||||
# select substring('здесь написан /*---- Комментарий между символами "дефис" ----*/ - и больше ничего!' similar '%(pattern_02)s' escape '#') as result2
|
||||
# from rdb$database;
|
||||
#
|
||||
#
|
||||
# -- Confirmed fail on 4.0.0.1631 with "cannot transliterate character between character sets":
|
||||
# select substring(list(T.NAME, '; ') from 1 for 250) as result_3_blob_id from VALUT_LIST T;
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# ''' % dict(globals(), **locals())
|
||||
#
|
||||
#
|
||||
# f_run_sql = open( os.path.join(context['temp_directory'], 'tmp_6158_win1251.sql'), 'w' )
|
||||
# f_run_sql.write( sql_txt.decode('utf8').encode('cp1251') )
|
||||
# flush_and_close( f_run_sql )
|
||||
#
|
||||
#
|
||||
# # result: file tmp_6158_win1251.sql is encoded in win1251
|
||||
#
|
||||
#
|
||||
# f_run_log = open( os.path.splitext(f_run_sql.name)[0]+'.log', 'w')
|
||||
# subprocess.call( [ context['isql_path'], '-q', '-i', f_run_sql.name ],
|
||||
# stdout = f_run_log,
|
||||
# stderr = subprocess.STDOUT
|
||||
# )
|
||||
# flush_and_close( f_run_log ) # result: output will be encoded in win1251
|
||||
#
|
||||
#
|
||||
# with codecs.open(f_run_log.name, 'r', encoding='cp1251' ) as f:
|
||||
# result_in_win1251 = f.readlines()
|
||||
#
|
||||
#
|
||||
# for i in result_in_win1251:
|
||||
# print( i.encode('utf8') )
|
||||
#
|
||||
#
|
||||
# # cleanup:
|
||||
# ###########
|
||||
# cleanup( (f_run_sql, f_run_log) )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
RESULT1 = Комментарий между символами "равно" =
|
||||
RESULT2 - Комментарий между символами "дефис" -
|
||||
Российский рубль; Турецкая лира; Доллар США
|
||||
"""
|
||||
"""
|
||||
|
||||
test_script = temp_file('test-script.sql')
|
||||
|
||||
@pytest.mark.version('>=4.0')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
def test_1(act_1: Action, test_script: Path):
|
||||
pattern_01 = '%/#*(=){3,}#"%#"(=){3,}#*/%'
|
||||
pattern_02 = '%/#*(#-){3,}#"%#"(#-){3,}#*/%'
|
||||
test_script.write_text(f"""
|
||||
-- This is needed to get "cannot transliterate character between character sets"
|
||||
-- on build 4.0.0.1631, see comment in the tracker 18/Oct/19 02:57 PM:
|
||||
create domain T_A64 as varchar (64) character set WIN1251 collate WIN1251;
|
||||
create table VALUT_LIST (NAME T_A64 not null);
|
||||
commit;
|
||||
insert into VALUT_LIST (NAME) values ('Российский рубль');
|
||||
insert into VALUT_LIST (NAME) values ('Турецкая лира');
|
||||
insert into VALUT_LIST (NAME) values ('Доллар США');
|
||||
commit;
|
||||
|
||||
set list on;
|
||||
set blob all;
|
||||
|
||||
select substring('
|
||||
aaa
|
||||
/*==== Комментарий между символами "равно" ====*/
|
||||
bbb
|
||||
ccc
|
||||
ddd
|
||||
eee
|
||||
fff
|
||||
jjj
|
||||
' similar '{pattern_01}' escape '#') as result1
|
||||
from rdb$database;
|
||||
|
||||
-- additional check for special character '-' as delimiter:
|
||||
select substring('здесь написан /*---- Комментарий между символами "дефис" ----*/ - и больше ничего!' similar '{pattern_02}' escape '#') as result2
|
||||
from rdb$database;
|
||||
|
||||
-- Confirmed fail on 4.0.0.1631 with "cannot transliterate character between character sets":
|
||||
select substring(list(T.NAME, '; ') from 1 for 250) as result_3_blob_id from VALUT_LIST T;
|
||||
""", encoding='cp1251')
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
act_1.isql(switches=['-q'], input_file=test_script, charset='win1251')
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
||||
|
||||
|
@ -2,67 +2,67 @@
|
||||
#
|
||||
# id: bugs.core_6163
|
||||
# title: Generator pages are not encrypted
|
||||
# decription:
|
||||
# decription:
|
||||
# Database in this test is encrypted using IBSurgeon Demo Encryption package
|
||||
# ( https://ib-aid.com/download-demo-firebird-encryption-plugin/ ; https://ib-aid.com/download/crypt/CryptTest.zip )
|
||||
# License file plugins\\dbcrypt.conf with unlimited expiration was provided by IBSurgeon to Firebird Foundation (FF).
|
||||
# This file was preliminary stored in FF Test machine.
|
||||
# Test assumes that this file and all neccessary libraries already were stored into FB_HOME and %FB_HOME%\\plugins.
|
||||
#
|
||||
#
|
||||
# Anyone who wants to run this test on his own machine must
|
||||
# 1) download https://ib-aid.com/download/crypt/CryptTest.zip AND
|
||||
# 1) download https://ib-aid.com/download/crypt/CryptTest.zip AND
|
||||
# 2) PURCHASE LICENSE and get from IBSurgeon file plugins\\dbcrypt.conf with apropriate expiration date and other info.
|
||||
#
|
||||
#
|
||||
# ################################################ ! ! ! N O T E ! ! ! ##############################################
|
||||
# FF tests storage (aka "fbt-repo") does not (and will not) contain any license file for IBSurgeon Demo Encryption package!
|
||||
# #########################################################################################################################
|
||||
#
|
||||
# Several sequences are created in this test.
|
||||
#
|
||||
# Several sequences are created in this test.
|
||||
# Then we obtain generator page ID and page size by querying RDB$PAGES and MON$DATABASE tables.
|
||||
# After this, we check that values of sequences *PRESENT* in NON-encrypted database by opening DB file in 'rb' mode
|
||||
# and reading content of its generator page.
|
||||
# Further, we encrypt database and wait for 1 second in order to give engine complete this job.
|
||||
# Finally, we read generator page again. NO any value of secuences must be found at this point.
|
||||
#
|
||||
#
|
||||
# Encryprion is performed by 'alter database encrypt with <plugin_name> key ...' statement,
|
||||
# where <plugin_name> = dbcrypt - is the name of .dll in FB_HOME\\plugins\\ folder that implements encryption.
|
||||
#
|
||||
#
|
||||
# === NOTE-1 ===
|
||||
# In case of "Crypt plugin DBCRYPT failed to load/607/335544351" check that all
|
||||
# In case of "Crypt plugin DBCRYPT failed to load/607/335544351" check that all
|
||||
# needed files from IBSurgeon Demo Encryption package exist in %FB_HOME% and %FB_HOME%\\plugins
|
||||
# %FB_HOME%:
|
||||
# 283136 fbcrypt.dll
|
||||
# 2905600 libcrypto-1_1-x64.dll
|
||||
# 481792 libssl-1_1-x64.dll
|
||||
#
|
||||
#
|
||||
# %FB_HOME%\\plugins:
|
||||
# 297984 dbcrypt.dll
|
||||
# 306176 keyholder.dll
|
||||
# 108 DbCrypt.conf
|
||||
# 856 keyholder.conf
|
||||
#
|
||||
#
|
||||
# === NOTE-2 ===
|
||||
# Version of DbCrypt.dll of october-2018 must be replaced because it has hard-coded
|
||||
# Version of DbCrypt.dll of october-2018 must be replaced because it has hard-coded
|
||||
# date of expiration rather than reading it from DbCrypt.conf !!
|
||||
#
|
||||
#
|
||||
# === NOTE-3 ===
|
||||
# firebird.conf must contain following line:
|
||||
# KeyHolderPlugin = KeyHolder
|
||||
#
|
||||
#
|
||||
# Confirmed non-encrypted content of generators page on: 4.0.0.1627; 3.0.5.33178.
|
||||
# Checked on: 4.0.0.1633: OK, 2.260s; 3.0.5.33180: OK, 1.718s.
|
||||
#
|
||||
#
|
||||
# :::::::::::::::::::::::::::::::::::::::: NB ::::::::::::::::::::::::::::::::::::
|
||||
# 18.08.2020. FB 4.x has incompatible behaviour with all previous versions since build 4.0.0.2131 (06-aug-2020):
|
||||
# statement 'alter sequence <seq_name> restart with 0' changes rdb$generators.rdb$initial_value to -1 thus next call
|
||||
# gen_id(<seq_name>,1) will return 0 (ZERO!) rather than 1.
|
||||
# gen_id(<seq_name>,1) will return 0 (ZERO!) rather than 1.
|
||||
# See also CORE-6084 and its fix: https://github.com/FirebirdSQL/firebird/commit/23dc0c6297825b2e9006f4d5a2c488702091033d
|
||||
# ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
# This is considered as *expected* and is noted in doc/README.incompatibilities.3to4.txt
|
||||
#
|
||||
#
|
||||
# Because of this, it was decided to make separate section for check results of FB 4.x
|
||||
# Checked on 4.0.0.2164, 3.0.7.33356
|
||||
#
|
||||
#
|
||||
# 28.02.2021
|
||||
# For unknown reason 3.x and 4.x Classic hangs during run this test, both on Linux and (unexpectedly) Windows.
|
||||
# Fortunately, simple solution was found.
|
||||
@ -72,17 +72,17 @@
|
||||
# within ONE attachment to the database that is created by ISQL.
|
||||
# Because of this, 'init_script' contains special table and procedure for making pauses: 'tets' and 'sp_delay'.
|
||||
# Procedure 'sp_delay' must be called within Tx which was declared as SET TRANSACTION LOCK TIMEOU <N> where <N> = 1...3.
|
||||
#
|
||||
#
|
||||
# Checked on: 4.0.0.2372 SS/CS; 3.0.8.33420 SS/CS.
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-6163
|
||||
# min_versions: ['3.0.5']
|
||||
# versions: 3.0.5, 4.0
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
from firebird.qa import db_factory, python_act, Action
|
||||
|
||||
# version: 3.0.5
|
||||
# resources: None
|
||||
@ -103,7 +103,7 @@ init_script_1 = """
|
||||
-- #########################################################
|
||||
in autonomous transaction do
|
||||
insert into test(x) values(:r); -- this will cause delay because of duplicate in index
|
||||
when any do
|
||||
when any do
|
||||
begin
|
||||
-- nop --
|
||||
end
|
||||
@ -112,25 +112,25 @@ init_script_1 = """
|
||||
^
|
||||
set term ;^
|
||||
commit;
|
||||
"""
|
||||
"""
|
||||
|
||||
db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
|
||||
# test_script_1
|
||||
#---
|
||||
#
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# import binascii
|
||||
# import time
|
||||
# #import shutil
|
||||
#
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
#
|
||||
#
|
||||
# this_fdb = db_conn.database_name
|
||||
# # ::: NB ::: DO NOT close db_conn now! We can close it only after encryption will finish!
|
||||
#
|
||||
#
|
||||
# db_conn.execute_immediate('create sequence gen_ba0bab start with 12192683')
|
||||
# db_conn.execute_immediate('create sequence gen_badf00d start with 195948557')
|
||||
# db_conn.execute_immediate('create sequence gen_caca0 start with 830624')
|
||||
@ -139,46 +139,46 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# db_conn.execute_immediate('create sequence gen_decade start with 14600926')
|
||||
# db_conn.execute_immediate('create sequence gen_7FFFFFFF start with 2147483647')
|
||||
# db_conn.commit()
|
||||
#
|
||||
#
|
||||
# ######################################################################################
|
||||
#
|
||||
#
|
||||
# def check_page_for_readable_values(dbname, gen_page_number, pg_size, check_sequence_values):
|
||||
#
|
||||
#
|
||||
# global binascii
|
||||
#
|
||||
#
|
||||
# db_handle = open( dbname, "rb")
|
||||
# db_handle.seek( gen_page_number * pg_size )
|
||||
# page_content = db_handle.read( pg_size )
|
||||
# # read_binary_content( db_handle, gen_page_number * pg_size, pg_size )
|
||||
# db_handle.close()
|
||||
# page_as_hex=binascii.hexlify( page_content )
|
||||
#
|
||||
#
|
||||
# # Iterate for each sequence value:
|
||||
# for n in check_sequence_values:
|
||||
#
|
||||
#
|
||||
# # Get HEX representation of digital value.
|
||||
# # NOTE: format( 830624, 'x') is 'caca0' contains five (odd number!) characters.
|
||||
# hex_string = format(abs(n),'x')
|
||||
#
|
||||
#
|
||||
# # Here we 'pad' hex representation to EVEN number of digits in it,
|
||||
# # otherwise binascii.hexlify fails with "Odd-length string error":
|
||||
# hex_string = ''.join( ('0' * ( len(hex_string)%2 ), hex_string ) )
|
||||
#
|
||||
#
|
||||
# # ::: NOTE :::
|
||||
# # Generator value is stored in REVERSED bytes order.
|
||||
# # dec 830624 --> hex 0x0caca0 --> 0c|ac|a0 --> stored in page as three bytes: {a0; ac; 0c}
|
||||
#
|
||||
#
|
||||
# # Decode string that is stored in variable 'hex_string' to HEX number,
|
||||
# # REVERSE its bytes and convert it to string again for further search
|
||||
# # in page content:
|
||||
# n_as_reversed_hex = binascii.hexlify( hex_string.decode('hex')[::-1] )
|
||||
#
|
||||
#
|
||||
# print(n, n_as_reversed_hex, 'FOUND.' if n_as_reversed_hex in page_as_hex else 'NOT FOUND.' )
|
||||
# # print(n, n_as_reversed_hex, 'UNEXPECTEDLY FOUND AT POS. ' + '{:5d}'.format( page_as_hex.index(n_as_reversed_hex) ) if n_as_reversed_hex in page_as_hex else 'Not found (expected).' )
|
||||
#
|
||||
#
|
||||
# ######################################################################################
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# cur=db_conn.cursor()
|
||||
# get_current_seq_values='''
|
||||
# execute block returns( gen_curr bigint) as
|
||||
@ -193,15 +193,15 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# end
|
||||
# end
|
||||
# '''
|
||||
#
|
||||
#
|
||||
# # Obtain current values of user generators:
|
||||
# # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
# cur.execute(get_current_seq_values)
|
||||
# check_sequence_values=[]
|
||||
# for r in cur:
|
||||
# check_sequence_values += r[0],
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# # Obtain page size and number of generators page:
|
||||
# # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
# cur.execute('select m.mon$page_size,min(rdb$page_number) from mon$database m cross join rdb$pages p where p.rdb$page_type = 9 group by 1')
|
||||
@ -212,12 +212,12 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# # print(r[0],r[1])
|
||||
# cur.close()
|
||||
# db_conn.close()
|
||||
#
|
||||
#
|
||||
# # Read gen page, convert it to hex and check whether generator values can be found there or no:
|
||||
# # Expected result: YES for all values because DB not encrypted now.
|
||||
# # ~~~~~~~~~~~~~~~
|
||||
# check_page_for_readable_values(this_fdb, gen_page_number, pg_size, check_sequence_values)
|
||||
#
|
||||
#
|
||||
# # 27.02.2021.
|
||||
# # Name of encryption plugin depends on OS:
|
||||
# # * for Windows we (currently) use plugin by IBSurgeon, its name is 'dbcrypt';
|
||||
@ -231,39 +231,40 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# # ** 'fbSampleDbCrypt' for FB 4.x+
|
||||
# #
|
||||
# PLUGIN_NAME = 'dbcrypt' if os.name == 'nt' else ( '"DbCrypt_example"' if db_conn.engine_version < 4 else '"fbSampleDbCrypt"' )
|
||||
#
|
||||
#
|
||||
# sql_cmd='''
|
||||
# -- ################################################
|
||||
# -- ### e n c r y p t d a t a b a s e ###
|
||||
# -- ################################################
|
||||
# alter database encrypt with %(PLUGIN_NAME)s key Red;
|
||||
# commit;
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# -- 01.03.2021: we have to wait for several seconds
|
||||
# -- until encryption will be finished. But we must do
|
||||
# -- this delay within the same attachment as those that
|
||||
# -- launched encryption process.
|
||||
# -- The reason of that weird effect currently is unknown.
|
||||
# -- Here we make pause using 'set transaction lock timeout':
|
||||
#
|
||||
#
|
||||
# set transaction lock timeout 2; -- THIS LOCK TIMEOUT SERVES ONLY FOR DELAY
|
||||
# execute procedure sp_delay;
|
||||
# rollback;
|
||||
# show database;
|
||||
# quit;
|
||||
# ''' % locals()
|
||||
#
|
||||
#
|
||||
# runProgram('isql', [ dsn ], sql_cmd)
|
||||
#
|
||||
#
|
||||
# # Read again gen page, convert it to hex and check whether generator values can be found there or no.
|
||||
# # Expected result: NOT for all values because DB was encrypted.
|
||||
# # ~~~~~~~~~~~~~~~~
|
||||
# check_page_for_readable_values(this_fdb, gen_page_number, pg_size, check_sequence_values)
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
12192683 ab0bba FOUND.
|
||||
@ -283,12 +284,11 @@ Database encrypted
|
||||
14598366 dec0de NOT FOUND.
|
||||
14600926 decade NOT FOUND.
|
||||
2147483647 ffffff7f NOT FOUND.
|
||||
"""
|
||||
"""
|
||||
|
||||
@pytest.mark.version('>=3.0.5')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
@pytest.mark.version('>=3.0.5,<4')
|
||||
def test_1(act_1: Action):
|
||||
pytest.skip("Requires encryption plugin")
|
||||
|
||||
|
||||
# version: 4.0
|
||||
@ -310,7 +310,7 @@ init_script_2 = """
|
||||
-- #########################################################
|
||||
in autonomous transaction do
|
||||
insert into test(x) values(:r); -- this will cause delay because of duplicate in index
|
||||
when any do
|
||||
when any do
|
||||
begin
|
||||
-- nop --
|
||||
end
|
||||
@ -320,22 +320,22 @@ init_script_2 = """
|
||||
set term ;^
|
||||
commit;
|
||||
|
||||
"""
|
||||
"""
|
||||
|
||||
db_2 = db_factory(sql_dialect=3, init=init_script_2)
|
||||
|
||||
# test_script_2
|
||||
#---
|
||||
#
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# import binascii
|
||||
# import time
|
||||
#
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
# this_fdb = db_conn.database_name
|
||||
#
|
||||
#
|
||||
# db_conn.execute_immediate('create sequence gen_ba0bab start with 12192683')
|
||||
# db_conn.execute_immediate('create sequence gen_badf00d start with 195948557')
|
||||
# db_conn.execute_immediate('create sequence gen_caca0 start with 830624')
|
||||
@ -344,47 +344,47 @@ db_2 = db_factory(sql_dialect=3, init=init_script_2)
|
||||
# db_conn.execute_immediate('create sequence gen_decade start with 14600926')
|
||||
# db_conn.execute_immediate('create sequence gen_7FFFFFFF start with 2147483647')
|
||||
# db_conn.commit()
|
||||
#
|
||||
#
|
||||
# # ::: NB ::: DO NOT close db_conn now! We can close it only after encryption will finish!
|
||||
#
|
||||
#
|
||||
# ######################################################################################
|
||||
#
|
||||
#
|
||||
# def check_page_for_readable_values(dbname, gen_page_number, pg_size, check_sequence_values):
|
||||
#
|
||||
#
|
||||
# global binascii
|
||||
#
|
||||
#
|
||||
# db_handle = open( dbname, "rb")
|
||||
# db_handle.seek( gen_page_number * pg_size )
|
||||
# page_content = db_handle.read( pg_size )
|
||||
# # read_binary_content( db_handle, gen_page_number * pg_size, pg_size )
|
||||
# db_handle.close()
|
||||
# page_as_hex=binascii.hexlify( page_content )
|
||||
#
|
||||
#
|
||||
# # Iterate for each sequence value:
|
||||
# for n in check_sequence_values:
|
||||
#
|
||||
#
|
||||
# # Get HEX representation of digital value.
|
||||
# # NOTE: format( 830624, 'x') is 'caca0' contains five (odd number!) characters.
|
||||
# hex_string = format(abs(n),'x')
|
||||
#
|
||||
#
|
||||
# # Here we 'pad' hex representation to EVEN number of digits in it,
|
||||
# # otherwise binascii.hexlify fails with "Odd-length string error":
|
||||
# hex_string = ''.join( ('0' * ( len(hex_string)%2 ), hex_string ) )
|
||||
#
|
||||
#
|
||||
# # ::: NOTE :::
|
||||
# # Generator value is stored in REVERSED bytes order.
|
||||
# # dec 830624 --> hex 0x0caca0 --> 0c|ac|a0 --> stored in page as three bytes: {a0; ac; 0c}
|
||||
#
|
||||
#
|
||||
# # Decode string that is stored in variable 'hex_string' to HEX number,
|
||||
# # REVERSE its bytes and convert it to string again for further search
|
||||
# # in page content:
|
||||
# n_as_reversed_hex = binascii.hexlify( hex_string.decode('hex')[::-1] )
|
||||
#
|
||||
#
|
||||
# print(n, n_as_reversed_hex, 'FOUND.' if n_as_reversed_hex in page_as_hex else 'NOT FOUND.' )
|
||||
# # print(n, n_as_reversed_hex, 'UNEXPECTEDLY FOUND AT POS. ' + '{:5d}'.format( page_as_hex.index(n_as_reversed_hex) ) if n_as_reversed_hex in page_as_hex else 'Not found (expected).' )
|
||||
#
|
||||
#
|
||||
# ######################################################################################
|
||||
#
|
||||
#
|
||||
# cur=db_conn.cursor()
|
||||
# get_current_seq_values='''
|
||||
# execute block returns( gen_curr bigint) as
|
||||
@ -399,7 +399,7 @@ db_2 = db_factory(sql_dialect=3, init=init_script_2)
|
||||
# end
|
||||
# end
|
||||
# '''
|
||||
#
|
||||
#
|
||||
# # Obtain current values of user generators:
|
||||
# # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
# cur.execute(get_current_seq_values)
|
||||
@ -407,9 +407,9 @@ db_2 = db_factory(sql_dialect=3, init=init_script_2)
|
||||
# for r in cur:
|
||||
# check_sequence_values += r[0],
|
||||
# #print('check_sequence_values=',check_sequence_values)
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# # Obtain page size and number of generators page:
|
||||
# # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
# cur.execute('select m.mon$page_size,min(rdb$page_number) from mon$database m cross join rdb$pages p where p.rdb$page_type = 9 group by 1')
|
||||
@ -418,22 +418,22 @@ db_2 = db_factory(sql_dialect=3, init=init_script_2)
|
||||
# pg_size=r[0]
|
||||
# gen_page_number=r[1]
|
||||
# # print(r[0],r[1])
|
||||
#
|
||||
#
|
||||
# # 28.02.2021, temporary:
|
||||
# srv_mode='UNKNOWN'
|
||||
# cur.execute("select rdb$config_value from rdb$config where rdb$config_name='ServerMode'")
|
||||
# for r in cur:
|
||||
# srv_mode=r[0]
|
||||
#
|
||||
#
|
||||
# cur.close()
|
||||
# db_conn.close()
|
||||
#
|
||||
#
|
||||
# # Read gen page, convert it to hex and check whether generator values can be found there or no:
|
||||
# # Expected result: YES for all values because DB not encrypted now.
|
||||
# # ~~~~~~~~~~~~~~~
|
||||
# check_page_for_readable_values(this_fdb, gen_page_number, pg_size, check_sequence_values)
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# # 27.02.2021.
|
||||
# # Name of encryption plugin depends on OS:
|
||||
# # * for Windows we (currently) use plugin by IBSurgeon, its name is 'dbcrypt';
|
||||
@ -447,21 +447,21 @@ db_2 = db_factory(sql_dialect=3, init=init_script_2)
|
||||
# # ** 'fbSampleDbCrypt' for FB 4.x+
|
||||
# #
|
||||
# PLUGIN_NAME = 'dbcrypt' if os.name == 'nt' else ( '"DbCrypt_example"' if db_conn.engine_version < 4 else '"fbSampleDbCrypt"' )
|
||||
#
|
||||
#
|
||||
# sql_cmd='''
|
||||
# -- ################################################
|
||||
# -- ### e n c r y p t d a t a b a s e ###
|
||||
# -- ################################################
|
||||
# alter database encrypt with %(PLUGIN_NAME)s key Red;
|
||||
# commit;
|
||||
#
|
||||
#
|
||||
# -- 01.03.2021: we have to wait for several seconds
|
||||
# -- until encryption will be finished. But we must do
|
||||
# -- this delay within the same attachment as those that
|
||||
# -- launched encryption process.
|
||||
# -- The reason of that weird effect currently is unknown.
|
||||
# -- Here we make pause using 'set transaction lock timeout':
|
||||
#
|
||||
#
|
||||
# -- 20.04.2021: increased delay from 2 to 3 seconds.
|
||||
# -- Otherwise can get "... crypt thread not complete":
|
||||
# set transaction lock timeout 3; -- THIS LOCK TIMEOUT SERVES ONLY FOR DELAY
|
||||
@ -470,17 +470,18 @@ db_2 = db_factory(sql_dialect=3, init=init_script_2)
|
||||
# show database;
|
||||
# quit;
|
||||
# ''' % locals()
|
||||
#
|
||||
#
|
||||
# runProgram('isql', [ dsn ], sql_cmd)
|
||||
#
|
||||
#
|
||||
# # Read again gen page, convert it to hex and check whether generator values can be found there or no.
|
||||
# # Expected result: NOT FOUND, for all values (because DB was encrypted).
|
||||
# # ~~~~~~~~~~~~~~~~
|
||||
# check_page_for_readable_values(this_fdb, gen_page_number, pg_size, check_sequence_values)
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_2 = python_act('db_2', test_script_2, substitutions=substitutions_2)
|
||||
|
||||
act_2 = python_act('db_2', substitutions=substitutions_2)
|
||||
|
||||
expected_stdout_2 = """
|
||||
12192682 aa0bba FOUND.
|
||||
@ -503,8 +504,7 @@ Database encrypted
|
||||
"""
|
||||
|
||||
@pytest.mark.version('>=4.0')
|
||||
@pytest.mark.xfail
|
||||
def test_2(db_2):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
def test_2(act_2: Action):
|
||||
pytest.skip("Requires encryption plugin")
|
||||
|
||||
|
||||
|
@ -2,24 +2,24 @@
|
||||
#
|
||||
# id: bugs.core_6166
|
||||
# title: Problems with long object names (> 255 bytes)
|
||||
# decription:
|
||||
# decription:
|
||||
# We define several objects with non-ascii names of max allowed length (63 characters) and make check statements.
|
||||
# Result no matter, but these statements must finished without errors.
|
||||
# Then we extract metadata and add the same set of check statements to this sql script.
|
||||
# Applying of this script to empty (another) database must end also without any error.
|
||||
#
|
||||
# Confirmed problem on 4.0.0.1633: ISQL crashed when performing script which contains DDL with non-ascii names
|
||||
#
|
||||
# Confirmed problem on 4.0.0.1633: ISQL crashed when performing script which contains DDL with non-ascii names
|
||||
# of max allowed len (63 characters).
|
||||
#
|
||||
# Checked on 4.0.0.1635: OK, 4.821s.
|
||||
#
|
||||
#
|
||||
# Checked on 4.0.0.1635: OK, 4.821s.
|
||||
#
|
||||
# tracker_id: CORE-6166
|
||||
# min_versions: ['4.0']
|
||||
# versions: 4.0
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
from firebird.qa import db_factory, python_act, Action
|
||||
|
||||
# version: 4.0
|
||||
# resources: None
|
||||
@ -32,32 +32,32 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
|
||||
|
||||
# test_script_1
|
||||
#---
|
||||
#
|
||||
#
|
||||
# import os
|
||||
# import subprocess
|
||||
# import time
|
||||
#
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
# db_conn.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def flush_and_close( file_handle ):
|
||||
# # https://docs.python.org/2/library/os.html#os.fsync
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
|
||||
# global os
|
||||
#
|
||||
#
|
||||
# file_handle.flush()
|
||||
# if file_handle.mode not in ('r', 'rb') and file_handle.name != os.devnull:
|
||||
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
|
||||
# os.fsync(file_handle.fileno())
|
||||
# file_handle.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def cleanup( f_names_list ):
|
||||
# global os
|
||||
# for f in f_names_list:
|
||||
@ -68,14 +68,14 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
|
||||
# else:
|
||||
# print('Unrecognized type of element:', f, ' - can not be treated as file.')
|
||||
# del_name = None
|
||||
#
|
||||
#
|
||||
# if del_name and os.path.isfile( del_name ):
|
||||
# os.remove( del_name )
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# sql_ddl='''
|
||||
#
|
||||
#
|
||||
# sql_ddl='''
|
||||
# set term ^;
|
||||
# recreate package "ПакетДляРешенияЛинейныхГиперболическихИТрансцендентныхУравнений" as
|
||||
# begin
|
||||
@ -93,7 +93,7 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
|
||||
# begin
|
||||
# return 456;
|
||||
# end
|
||||
#
|
||||
#
|
||||
# end
|
||||
# ^
|
||||
# set term ;^
|
||||
@ -110,93 +110,149 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
|
||||
# ,"КоэффициентЧДляЛинейныхГиперболическихИТрансцендентныхУравнений"
|
||||
# );
|
||||
# commit;
|
||||
#
|
||||
#
|
||||
# '''
|
||||
#
|
||||
#
|
||||
# sql_chk='''
|
||||
#
|
||||
# show package;
|
||||
#
|
||||
# show package;
|
||||
# show index "КоэффициентыДляЛинейныхГиперболическихИТрансцендентныхУравнений";
|
||||
# set list on;
|
||||
# select "ПакетДляРешенияЛинейныхГиперболическихИТрансцендентныхУравнений"."МетодЗейделяДляЛинейныхГиперболическихИТрансцендентныхУравнений"() from rdb$database;
|
||||
# select "ПакетДляРешенияЛинейныхГиперболическихИТрансцендентныхУравнений"."МетодНьютонаДляЛинейныхГиперболическихИТрансцендентныхУравнений"() from rdb$database;
|
||||
# rollback;
|
||||
# '''
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# f_chk_query_sql=open( os.path.join(context['temp_directory'],'tmp_6166_chk_query.sql'), 'w')
|
||||
# f_chk_query_sql.write( sql_ddl + sql_chk )
|
||||
# flush_and_close( f_chk_query_sql )
|
||||
#
|
||||
#
|
||||
# f_chk_query_log = open( os.path.join(context['temp_directory'],'tmp_isql_6166_chk_query.log'), 'w' )
|
||||
# f_chk_query_err = open( os.path.join(context['temp_directory'],'tmp_isql_6166_chk_query.err'), 'w')
|
||||
# subprocess.call( [context['isql_path'], dsn, "-ch", "utf8", "-i", f_chk_query_sql.name], stdout=f_chk_query_log, stderr=f_chk_query_err )
|
||||
# flush_and_close( f_chk_query_log )
|
||||
# flush_and_close( f_chk_query_err )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# if os.path.getsize( f_chk_query_err.name ) == 0:
|
||||
# with open( f_chk_query_log.name,'r') as f:
|
||||
# for line in f:
|
||||
# if line.split():
|
||||
# print('CHECK STATEMENTS, INITIAL: '+line)
|
||||
#
|
||||
#
|
||||
# f_chk_metadata_sql=open( os.path.join(context['temp_directory'],'tmp_6166_metadata.sql'), 'w')
|
||||
# subprocess.call( [context['isql_path'], dsn, "-ch", "utf8", "-x" ], stdout=f_chk_metadata_sql, stderr=subprocess.STDOUT )
|
||||
# f_chk_metadata_sql.write( sql_chk )
|
||||
# flush_and_close( f_chk_metadata_sql )
|
||||
#
|
||||
#
|
||||
# f_chk_metadata_fdb = os.path.join(context['temp_directory'],'tmp_6166_metadata.fdb')
|
||||
# if os.path.isfile( f_chk_metadata_fdb ):
|
||||
# os.remove( f_chk_metadata_fdb )
|
||||
# chk_conn = fdb.create_database( dsn = 'localhost:'+f_chk_metadata_fdb )
|
||||
# chk_conn.close()
|
||||
#
|
||||
#
|
||||
# f_chk_metadata_log = open( os.path.join(context['temp_directory'],'tmp_6166_metadata.log'), 'w' )
|
||||
# f_chk_metadata_err = open( os.path.join(context['temp_directory'],'tmp_6166_metadata.err'), 'w' )
|
||||
# subprocess.call( [context['isql_path'], 'localhost:'+f_chk_metadata_fdb, "-ch", "utf8", "-i", f_chk_metadata_sql.name ], stdout=f_chk_metadata_log, stderr=f_chk_metadata_err )
|
||||
# flush_and_close( f_chk_metadata_log )
|
||||
# flush_and_close( f_chk_metadata_err )
|
||||
#
|
||||
#
|
||||
# with open( f_chk_metadata_err.name,'r') as f:
|
||||
# for line in f:
|
||||
# if line.split():
|
||||
# print('UNEXPECTED ERROR IN THE EXTRACTED METADATA SQL: '+line)
|
||||
#
|
||||
#
|
||||
# with open( f_chk_metadata_log.name,'r') as f:
|
||||
# for line in f:
|
||||
# if line.split():
|
||||
# print('CHECK STATEMENTS ON EXTRACTED METADATA: '+line)
|
||||
#
|
||||
#
|
||||
# else:
|
||||
# with open( f_chk_query_err.name,'r') as f:
|
||||
# for line in f:
|
||||
# if line.split():
|
||||
# print('UNEXPECTED ERROR IN INITIAL CHECK STATEMENTS: '+line)
|
||||
#
|
||||
#
|
||||
# # cleanup:
|
||||
# ##########
|
||||
# ##########
|
||||
# time.sleep(1)
|
||||
# cleanup( ( f_chk_query_sql, f_chk_query_log, f_chk_query_err, f_chk_metadata_sql, f_chk_metadata_log, f_chk_metadata_err,f_chk_metadata_fdb ) )
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
CHECK STATEMENTS, INITIAL: ПакетДляРешенияЛинейныхГиперболическихИТрансцендентныхУравнений
|
||||
CHECK STATEMENTS, INITIAL: КоэффициентыЛинейныхГиперболическихИТрансцендентныхУравненийЦЫЧ UNIQUE INDEX ON КоэффициентыДляЛинейныхГиперболическихИТрансцендентныхУравнений(КоэффициентЦДляЛинейныхГиперболическихИТрансцендентныхУравнений, КоэффициентЫДляЛинейныхГиперболическихИТрансцендентныхУравнений, КоэффициентЧДляЛинейныхГиперболическихИТрансцендентныхУравнений)
|
||||
CHECK STATEMENTS, INITIAL: МетодЗейделяДляЛинейныхГиперболическихИТрансцендентныхУравнений 123
|
||||
CHECK STATEMENTS, INITIAL: МетодНьютонаДляЛинейныхГиперболическихИТрансцендентныхУравнений 456
|
||||
|
||||
CHECK STATEMENTS ON EXTRACTED METADATA: ПакетДляРешенияЛинейныхГиперболическихИТрансцендентныхУравнений
|
||||
CHECK STATEMENTS ON EXTRACTED METADATA: КоэффициентыЛинейныхГиперболическихИТрансцендентныхУравненийЦЫЧ UNIQUE INDEX ON КоэффициентыДляЛинейныхГиперболическихИТрансцендентныхУравнений(КоэффициентЦДляЛинейныхГиперболическихИТрансцендентныхУравнений, КоэффициентЫДляЛинейныхГиперболическихИТрансцендентныхУравнений, КоэффициентЧДляЛинейныхГиперболическихИТрансцендентныхУравнений)
|
||||
CHECK STATEMENTS ON EXTRACTED METADATA: МетодЗейделяДляЛинейныхГиперболическихИТрансцендентныхУравнений 123
|
||||
CHECK STATEMENTS ON EXTRACTED METADATA: МетодНьютонаДляЛинейныхГиперболическихИТрансцендентныхУравнений 456
|
||||
"""
|
||||
ПакетДляРешенияЛинейныхГиперболическихИТрансцендентныхУравнений
|
||||
КоэффициентыЛинейныхГиперболическихИТрансцендентныхУравненийЦЫЧ UNIQUE INDEX ON КоэффициентыДляЛинейныхГиперболическихИТрансцендентныхУравнений(КоэффициентЦДляЛинейныхГиперболическихИТрансцендентныхУравнений, КоэффициентЫДляЛинейныхГиперболическихИТрансцендентныхУравнений, КоэффициентЧДляЛинейныхГиперболическихИТрансцендентныхУравнений)
|
||||
МетодЗейделяДляЛинейныхГиперболическихИТрансцендентныхУравнений 123
|
||||
МетодНьютонаДляЛинейныхГиперболическихИТрансцендентныхУравнений 456
|
||||
"""
|
||||
|
||||
ddl_script = """
|
||||
set term ^;
|
||||
recreate package "ПакетДляРешенияЛинейныхГиперболическихИТрансцендентныхУравнений" as
|
||||
begin
|
||||
function "МетодЗейделяДляЛинейныхГиперболическихИТрансцендентныхУравнений"() returns int;
|
||||
function "МетодНьютонаДляЛинейныхГиперболическихИТрансцендентныхУравнений"() returns int;
|
||||
end
|
||||
^
|
||||
recreate package body "ПакетДляРешенияЛинейныхГиперболическихИТрансцендентныхУравнений" as
|
||||
begin
|
||||
function "МетодЗейделяДляЛинейныхГиперболическихИТрансцендентныхУравнений"() returns int as
|
||||
begin
|
||||
return 123;
|
||||
end
|
||||
function "МетодНьютонаДляЛинейныхГиперболическихИТрансцендентныхУравнений"() returns int as
|
||||
begin
|
||||
return 456;
|
||||
end
|
||||
|
||||
end
|
||||
^
|
||||
set term ;^
|
||||
commit;
|
||||
create table "КоэффициентыДляЛинейныхГиперболическихИТрансцендентныхУравнений" (
|
||||
"КоэффициентЦДляЛинейныхГиперболическихИТрансцендентныхУравнений" int
|
||||
,"КоэффициентЫДляЛинейныхГиперболическихИТрансцендентныхУравнений" int
|
||||
,"КоэффициентЧДляЛинейныхГиперболическихИТрансцендентныхУравнений" int
|
||||
);
|
||||
create unique index "КоэффициентыЛинейныхГиперболическихИТрансцендентныхУравненийЦЫЧ"
|
||||
on "КоэффициентыДляЛинейныхГиперболическихИТрансцендентныхУравнений" (
|
||||
"КоэффициентЦДляЛинейныхГиперболическихИТрансцендентныхУравнений"
|
||||
,"КоэффициентЫДляЛинейныхГиперболическихИТрансцендентныхУравнений"
|
||||
,"КоэффициентЧДляЛинейныхГиперболическихИТрансцендентныхУравнений"
|
||||
);
|
||||
commit;
|
||||
"""
|
||||
|
||||
test_script = """
|
||||
show package;
|
||||
show index "КоэффициентыДляЛинейныхГиперболическихИТрансцендентныхУравнений";
|
||||
set list on;
|
||||
select "ПакетДляРешенияЛинейныхГиперболическихИТрансцендентныхУравнений"."МетодЗейделяДляЛинейныхГиперболическихИТрансцендентныхУравнений"() from rdb$database;
|
||||
select "ПакетДляРешенияЛинейныхГиперболическихИТрансцендентныхУравнений"."МетодНьютонаДляЛинейныхГиперболическихИТрансцендентныхУравнений"() from rdb$database;
|
||||
rollback;
|
||||
"""
|
||||
|
||||
@pytest.mark.version('>=4.0')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
|
||||
|
||||
def test_1(act_1: Action):
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
act_1.isql(switches=[], input=ddl_script + test_script, charset='utf8')
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
# Extract metadata
|
||||
act_1.reset()
|
||||
act_1.isql(switches=['-x'], charset='utf8')
|
||||
meta = act_1.stdout
|
||||
# drop + recreate database
|
||||
act_1.db.drop()
|
||||
act_1.db.create(charset='UTF8', sql_dialect=3)
|
||||
# Recereate metadata
|
||||
act_1.reset()
|
||||
act_1.isql(switches=[], input=meta, charset='utf8')
|
||||
# Check 2
|
||||
act_1.reset()
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
act_1.isql(switches=[], input=test_script, charset='utf8')
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
@ -2,34 +2,35 @@
|
||||
#
|
||||
# id: bugs.core_6182
|
||||
# title: ExtConnPoolLifeTime acts as countdown for activity in MOST RECENT database (of several) rather then separate for each of used databases
|
||||
# decription:
|
||||
# decription:
|
||||
# We create one main ('head') DB (only for make single attach to it) and four test databases for making EDS connections to each of them from main DB.
|
||||
# Special user is created using LEGACY plugin because of comment in the ticket by hvlad 06/Nov/19 01:36 PM.
|
||||
# ~~~~~~
|
||||
# Then we do subsequent connections to each of these databases using EDS mechanism, with delay betnwe them (and also with final delay).
|
||||
# Then we do subsequent connections to each of these databases using EDS mechanism, with delay between them (and also with final delay).
|
||||
# Total sum of seconds that execution was paused is 4 * TDELAY - must be GREATER than config parameter ExtConnPoolLifeTime.
|
||||
# After last delay will elapsed, we again establish connections to each of these databases and try to execute DROP DATABASE statements.
|
||||
#
|
||||
#
|
||||
# Main idea: FIRST of this databases (which was firstly used to EDS connection) must have NO any attachments in its ExtPool and DROP must pass w/o any problems.
|
||||
#
|
||||
#
|
||||
# ::: NOTE ::: ATTENTION ::: ACHTUNG :::
|
||||
#
|
||||
#
|
||||
# We can not issue 'DROP DATABASE' immediately becase if some connection remains in ExtPool then FDB will raise exception that can not be catched.
|
||||
# For this reason we have to kill all attachments using 'DELETE FROM MON$ATTACHMENTS' statement. Number of attachments that were deleted will show
|
||||
# whether there was some 'auxiliary' connections or not. For the first of checked databases this number must be 0 (zero).
|
||||
# whether there was some 'auxiliary' connections or not. For the first of checked databases this number must be 0 (zero).
|
||||
# Otherwise one can state that the problem with ExtPool still exists.
|
||||
#
|
||||
#
|
||||
# Checked on:
|
||||
# 4.0.0.1646 SS/SC: ~19s (most of time is idle because of delays that is necessary for check that connections disappeared from ExtPool)
|
||||
# 4.0.0.1646 CS: 21.339s - but this test is not needed for this acrh.
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-6182
|
||||
# min_versions: ['4.0']
|
||||
# versions: 4.0
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
import time
|
||||
from firebird.qa import db_factory, python_act, Action, user_factory, User, Database
|
||||
|
||||
# version: 4.0
|
||||
# resources: None
|
||||
@ -38,44 +39,49 @@ substitutions_1 = []
|
||||
|
||||
init_script_1 = """"""
|
||||
|
||||
db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
db_1 = db_factory(sql_dialect=3, init=init_script_1, filename='core_6182-main.fdb')
|
||||
db_1_a = db_factory(sql_dialect=3, init=init_script_1, filename='core_6182-1.fdb')
|
||||
db_1_b = db_factory(sql_dialect=3, init=init_script_1, filename='core_6182-2.fdb')
|
||||
db_1_c = db_factory(sql_dialect=3, init=init_script_1, filename='core_6182-3.fdb')
|
||||
db_1_d = db_factory(sql_dialect=3, init=init_script_1, filename='core_6182-4.fdb')
|
||||
|
||||
|
||||
# test_script_1
|
||||
#---
|
||||
#
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# import time
|
||||
# import subprocess
|
||||
# import fdb
|
||||
# from fdb import services
|
||||
#
|
||||
#
|
||||
# DB_PATH = context['temp_directory']
|
||||
# # os.sep.join( db_conn.database_name.split(os.sep)[:-1] )
|
||||
#
|
||||
#
|
||||
# DB_USER=user_name
|
||||
# DB_PSWD=user_password
|
||||
#
|
||||
#
|
||||
# EDS_USER='tmp$c6182_leg'
|
||||
# EDS_PSWD='123'
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def flush_and_close( file_handle ):
|
||||
# # https://docs.python.org/2/library/os.html#os.fsync
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
|
||||
# global os
|
||||
#
|
||||
#
|
||||
# file_handle.flush()
|
||||
# if file_handle.mode not in ('r', 'rb') and file_handle.name != os.devnull:
|
||||
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
|
||||
# os.fsync(file_handle.fileno())
|
||||
# file_handle.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def cleanup( f_names_list ):
|
||||
# global os
|
||||
# for f in f_names_list:
|
||||
@ -86,20 +92,20 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# else:
|
||||
# print('Unrecognized type of element:', f, ' - can not be treated as file.')
|
||||
# del_name = None
|
||||
#
|
||||
#
|
||||
# if del_name and os.path.isfile( del_name ):
|
||||
# os.remove( del_name )
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# TDELAY=3
|
||||
# DB_CNT=4
|
||||
#
|
||||
#
|
||||
# ddl_main='''
|
||||
# set bail on;
|
||||
# create or alter user %(EDS_USER)s password '%(EDS_PSWD)s' using plugin Legacy_UserManager;
|
||||
# commit;
|
||||
#
|
||||
#
|
||||
# set term ^;
|
||||
# create procedure sp_do_eds ( a_target_db varchar(128) ) returns( source_dts timestamp, who_is_connecting varchar(128), source_db varchar(128), target_db varchar(128), target_dts timestamp ) as
|
||||
# begin
|
||||
@ -124,12 +130,12 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# grant drop database to %(EDS_USER)s;
|
||||
# commit;
|
||||
# ''' % locals()
|
||||
#
|
||||
#
|
||||
# f_isql1=open( os.path.join(context['temp_directory'],'tmp-c6182-ddl1.sql'), 'w')
|
||||
# f_isql1.write( ddl_main )
|
||||
# flush_and_close( f_isql1 )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# ddl_eds='''
|
||||
# set bail on;
|
||||
# set term ^;
|
||||
@ -139,7 +145,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# num_of_killed = 0;
|
||||
# for
|
||||
# select mon$attachment_id as killed_att
|
||||
# from mon$attachments
|
||||
# from mon$attachments
|
||||
# where mon$system_flag is distinct from 1 and mon$attachment_id != current_connection
|
||||
# as cursor c
|
||||
# do
|
||||
@ -156,26 +162,26 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# grant execute on procedure sp_del_att to public;
|
||||
# commit;
|
||||
# '''
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# f_isql2=open( os.path.join(context['temp_directory'],'tmp-c6182-ddl2.sql'), 'w')
|
||||
# f_isql2.write( ddl_eds )
|
||||
# flush_and_close( f_isql2 )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# for i in range(0, DB_CNT+1):
|
||||
# dbx = os.path.join( DB_PATH, ( ('c6182_tmp4eds.%d.fdb' % i) if i > 0 else 'c6182_tmpmain.fdb' ) )
|
||||
# cleanup( (dbx,) )
|
||||
#
|
||||
#
|
||||
# con=fdb.create_database(dsn = 'localhost:' + dbx, user = user_name, password = user_password)
|
||||
# con.close()
|
||||
# subprocess.call( [context['isql_path'], '-user', DB_USER, '-pas', DB_PSWD, 'localhost:' + dbx, '-i', (f_isql1.name if i==0 else f_isql2.name) ])
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# #-----------------------------------------
|
||||
#
|
||||
#
|
||||
# con = fdb.connect( dsn = 'localhost:' + os.path.join(DB_PATH, 'c6182_tmpmain.fdb'), user = EDS_USER, password = EDS_PSWD)
|
||||
#
|
||||
#
|
||||
# cur = con.cursor()
|
||||
# for i in range(1, DB_CNT+1):
|
||||
# dbx = os.path.join( DB_PATH, ('c6182_tmp4eds.%d.fdb' % i) )
|
||||
@ -183,20 +189,20 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# for r in cur:
|
||||
# pass
|
||||
# # 2debug only: print(r)
|
||||
#
|
||||
#
|
||||
# cur.close()
|
||||
# con.commit()
|
||||
#
|
||||
#
|
||||
# time.sleep( TDELAY )
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
# con.drop_database()
|
||||
# con.close()
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# for i in range(1, DB_CNT+1):
|
||||
# dbx = os.path.join( DB_PATH, ('c6182_tmp4eds.%d.fdb' % i) )
|
||||
#
|
||||
#
|
||||
# con = fdb.connect( 'localhost:' + dbx, user = user_name, password = user_password)
|
||||
# cur = con.cursor()
|
||||
# cur.callproc( 'sp_del_att' )
|
||||
@ -206,20 +212,20 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# else:
|
||||
# # All subseq. databases are not interested for us
|
||||
# pass
|
||||
#
|
||||
#
|
||||
# cur.close()
|
||||
# con.commit()
|
||||
#
|
||||
#
|
||||
# try:
|
||||
# con.drop_database()
|
||||
# except Exception as e:
|
||||
# ls=repr(e).split('\\n')
|
||||
# ls=repr(e).split('\\n')
|
||||
# print( ls[-2] )
|
||||
# finally:
|
||||
# con.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# svc = services.connect( host='localhost', user = user_name, password = user_password)
|
||||
# for i in range(1, DB_CNT+1):
|
||||
# dbx = os.path.join( DB_PATH, ('c6182_tmp4eds.%d.fdb' % i) )
|
||||
@ -228,7 +234,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# svc.shutdown(database = dbx, shutdown_mode = fdb.services.SHUT_FULL, shutdown_method = fdb.services.SHUT_FORCE, timeout = 0 )
|
||||
# svc.bring_online( database = dbx )
|
||||
# os.remove(dbx)
|
||||
#
|
||||
#
|
||||
# # commented 05.01.2020:
|
||||
# #######################
|
||||
# # Unable to perform the requested Service API action:
|
||||
@ -237,26 +243,107 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# # -85
|
||||
# # 335544753
|
||||
# # ---xxx --- svc.remove_user( EDS_USER )
|
||||
#
|
||||
#
|
||||
# svc.close()
|
||||
#
|
||||
#
|
||||
# # Use ISQL instead of FDB Services instance to drop user which was created with Legacy_UserManager plugin
|
||||
# # and this plugin now is NOT in the head of UserManager config parameter:
|
||||
# runProgram(context['isql_path'],[ dsn, '-user', DB_USER, '-pas', DB_PSWD ], 'drop user %(EDS_USER)s using plugin Legacy_UserManager;' % locals() )
|
||||
#
|
||||
#
|
||||
# cleanup( (f_isql1, f_isql2) )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
Number of deleted attachments for DB # 1: 0
|
||||
"""
|
||||
"""
|
||||
|
||||
ddl_eds = """
|
||||
set bail on;
|
||||
set term ^;
|
||||
-- create procedure sp_del_att returns( list_of_killed varchar(255) ) as
|
||||
create procedure sp_del_att returns( num_of_killed smallint ) as
|
||||
begin
|
||||
num_of_killed = 0;
|
||||
for
|
||||
select mon$attachment_id as killed_att
|
||||
from mon$attachments
|
||||
where mon$system_flag is distinct from 1 and mon$attachment_id != current_connection
|
||||
as cursor c
|
||||
do
|
||||
begin
|
||||
-- list_of_killed = list_of_killed || c.killed_att || ',';
|
||||
delete from mon$attachments where current of c;
|
||||
num_of_killed = num_of_killed + 1;
|
||||
end
|
||||
suspend;
|
||||
end
|
||||
^
|
||||
set term ;^
|
||||
commit;
|
||||
grant execute on procedure sp_del_att to public;
|
||||
commit;
|
||||
"""
|
||||
|
||||
eds_user = user_factory('db_1', name='tmp$c6182_leg', password='123', plugin='Legacy_UserManager')
|
||||
|
||||
TDELAY = 3
|
||||
|
||||
def init_main_db(act_1: Action, eds_user: User):
|
||||
ddl_script = f"""
|
||||
set bail on;
|
||||
set term ^;
|
||||
create procedure sp_do_eds ( a_target_db varchar(128) ) returns( source_dts timestamp, who_is_connecting varchar(128), source_db varchar(128), target_db varchar(128), target_dts timestamp ) as
|
||||
begin
|
||||
source_dts = cast('now' as timestamp);
|
||||
for
|
||||
execute statement
|
||||
('select cast(? as varchar(128)) as connect_from_db, current_user, mon$database_name as connect_to_db, cast(''now'' as timestamp) from mon$database')
|
||||
( rdb$get_context('SYSTEM', 'DB_NAME') )
|
||||
on external
|
||||
'localhost:' || a_target_db
|
||||
as
|
||||
user '{eds_user.name}'
|
||||
password '{eds_user.password}'
|
||||
into who_is_connecting, source_db, target_db, target_dts
|
||||
do
|
||||
suspend;
|
||||
end
|
||||
^
|
||||
set term ;^
|
||||
commit;
|
||||
grant execute on procedure sp_do_eds to {eds_user.name};
|
||||
grant drop database to {eds_user.name};
|
||||
commit;
|
||||
"""
|
||||
act_1.isql(switches=[], input=ddl_script)
|
||||
|
||||
|
||||
@pytest.mark.version('>=4.0')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
|
||||
|
||||
def test_1(act_1: Action, db_1_a: Database, db_1_b: Database, db_1_c: Database,
|
||||
db_1_d: Database, eds_user: User, capsys):
|
||||
#pytest.skip("Test not IMPLEMENTED")
|
||||
init_main_db(act_1, eds_user)
|
||||
for db in [db_1_a, db_1_b, db_1_c, db_1_d]:
|
||||
act_1.reset()
|
||||
act_1.isql(switches=[db.dsn], input=ddl_eds, connect_db=False)
|
||||
#
|
||||
with act_1.db.connect(user=eds_user.name, password=eds_user.password) as con:
|
||||
with con.cursor() as c:
|
||||
for db in [db_1_a, db_1_b, db_1_c, db_1_d]:
|
||||
c.execute('select * from sp_do_eds(?)', [db.db_path]).fetchall()
|
||||
time.sleep(TDELAY)
|
||||
#
|
||||
for db in [db_1_a, db_1_b, db_1_c, db_1_d]:
|
||||
with db.connect() as con:
|
||||
c = con.cursor()
|
||||
row = c.call_procedure('sp_del_att')
|
||||
if db is db_1_a:
|
||||
print(f'Number of deleted attachments for DB # 1: {row[0]}')
|
||||
#
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
act_1.stdout = capsys.readouterr().out
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
@ -2,7 +2,7 @@
|
||||
#
|
||||
# id: bugs.core_6208
|
||||
# title: Grant lost in security.db after backup/restore cycle
|
||||
# decription:
|
||||
# decription:
|
||||
# Ticket shows scenario with local protocol which allows security.db to be overwritten.
|
||||
# This can not be done when we work using remote protocol, but we can exploit ability
|
||||
# to change security DB. This is done by specifying parameter SecurityDatabase in databases.conf
|
||||
@ -10,40 +10,40 @@
|
||||
# tmp_6208 = <path__and_name_of_test_database> {
|
||||
# SecurityDatabase = tmp_6208
|
||||
# }
|
||||
#
|
||||
#
|
||||
# Test DB is named here 'fdb_init' and it is created by file copy of $FB_HOME\\securityN.db
|
||||
# Then file 'databases.conf' as adjusted so that SecurityDatabase will point to this test DB.
|
||||
# After this we can connect to $fdb_ini, create user (his name: 'TMP6208DBA') and give him
|
||||
# After this we can connect to $fdb_ini, create user (his name: 'TMP6208DBA') and give him
|
||||
# privilege to create database.
|
||||
#
|
||||
#
|
||||
# Futher, we make backup of this test DB and restore it. New database name is 'fdb_rest'.
|
||||
# After this, we change state of test DB to full shutdown and overwrite it by $fdb_rest.
|
||||
# Finaly, we make connection to this DB (that was just overwritten) and check that output
|
||||
# of 'show grants' command contains:
|
||||
#
|
||||
#
|
||||
# GRANT CREATE DATABASE TO USER TMP6208DBA
|
||||
#
|
||||
#
|
||||
# Confirmed lost of grant on 4.0.0.1691 (build 14-dec-2019).
|
||||
#
|
||||
#
|
||||
# 26.08.2020.
|
||||
# IT CRUSIAL FOR THIS TEST DO MAKE ALL RESTORE AND FURTHER ACTIONS IN LOCAL/EMBEDDED PROTOCOL.
|
||||
# Discissed with Alex, see letter 24.08.2020 19:49.
|
||||
#
|
||||
#
|
||||
# Main problem is in SuperClassic: after restore finish, we can not connect to this DB by TCP,
|
||||
# error is
|
||||
# "Statement failed, SQLSTATE = 08006 / Error occurred during login, please check server firebird.log for details"
|
||||
# Server log contains in this case: "Srp Server / connection shutdown / Database is shutdown."
|
||||
#
|
||||
#
|
||||
# Checked initially on 4.0.0.1712 SC: 11s, 4.0.0.1714 SS, CS (7s, 16s).
|
||||
# Checked again 26.08.2020 on 4.0.0.2173 SS/CS/SC.
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-6208
|
||||
# min_versions: ['4.0']
|
||||
# versions: 4.0
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
from firebird.qa import db_factory, python_act, Action
|
||||
|
||||
# version: 4.0
|
||||
# resources: None
|
||||
@ -56,7 +56,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
|
||||
# test_script_1
|
||||
#---
|
||||
#
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# import time
|
||||
@ -64,30 +64,30 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# import shutil
|
||||
# from subprocess import PIPE
|
||||
# from fdb import services
|
||||
#
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
# this_db = db_conn.database_name
|
||||
# fb_vers = str(db_conn.engine_version)[:1] # character for security.db file: engine = 4.0 --> '4'
|
||||
# db_conn.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def flush_and_close( file_handle ):
|
||||
# # https://docs.python.org/2/library/os.html#os.fsync
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
|
||||
# global os
|
||||
#
|
||||
#
|
||||
# file_handle.flush()
|
||||
# if file_handle.mode not in ('r', 'rb') and file_handle.name != os.devnull:
|
||||
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
|
||||
# os.fsync(file_handle.fileno())
|
||||
# file_handle.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def cleanup( f_names_list ):
|
||||
# global os
|
||||
# for f in f_names_list:
|
||||
@ -98,14 +98,14 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# else:
|
||||
# print('Unrecognized type of element:', f, ' - can not be treated as file.')
|
||||
# del_name = None
|
||||
#
|
||||
#
|
||||
# if del_name and os.path.isfile( del_name ):
|
||||
# os.remove( del_name )
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def svc_get_fb_log( fb_home, f_fb_log ):
|
||||
#
|
||||
#
|
||||
# global subprocess
|
||||
# subprocess.call( [ fb_home + "fbsvcmgr",
|
||||
# "localhost:service_mgr",
|
||||
@ -114,26 +114,26 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# stdout=f_fb_log, stderr=subprocess.STDOUT
|
||||
# )
|
||||
# return
|
||||
#
|
||||
#
|
||||
# svc = services.connect(host='localhost', user= user_name, password= user_password)
|
||||
# fb_home = svc.get_home_directory()
|
||||
# svc.close()
|
||||
# dbconf = os.path.join(fb_home, 'databases.conf')
|
||||
# dbcbak = os.path.join(fb_home, 'databases.bak')
|
||||
#
|
||||
#
|
||||
# sec_db = context['isc4_path']
|
||||
#
|
||||
#
|
||||
# fdb_init = os.path.join(context['temp_directory'],'tmp_6208_initial.fdb')
|
||||
# fdb_bkup = os.path.join(context['temp_directory'],'tmp_6208_initial.fbk')
|
||||
# fdb_rest = os.path.join(context['temp_directory'],'tmp_6208_restored.fdb')
|
||||
#
|
||||
#
|
||||
# cleanup( (fdb_init, fdb_rest) )
|
||||
#
|
||||
#
|
||||
# shutil.copy2( sec_db, fdb_init )
|
||||
#
|
||||
#
|
||||
# # Resut: fb_home is full path to FB instance home (with trailing slash).
|
||||
# shutil.copy2( dbconf, dbcbak)
|
||||
#
|
||||
#
|
||||
# alias_data='''
|
||||
# # Added temporarily for executing test core_6208.fbt
|
||||
# tmp_6208 = %(fdb_init)s {
|
||||
@ -141,12 +141,12 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# SecurityDatabase = tmp_6208
|
||||
# }
|
||||
# ''' % locals()
|
||||
#
|
||||
#
|
||||
# f_dbconf=open( dbconf,'a', buffering = 0)
|
||||
# f_dbconf.seek(0, 2)
|
||||
# f_dbconf.write(alias_data)
|
||||
# flush_and_close( f_dbconf )
|
||||
#
|
||||
#
|
||||
# sql_init='''
|
||||
# set bail on;
|
||||
# create or alter user tmp6208dba password '123' using plugin Srp;
|
||||
@ -155,40 +155,40 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# commit;
|
||||
# '''
|
||||
# runProgram('isql',[ fdb_init ], sql_init)
|
||||
#
|
||||
#
|
||||
# #########################################################################
|
||||
#
|
||||
#
|
||||
# f_backup_log = open( os.path.join(context['temp_directory'],'tmp_6208.backup.log'), 'w', buffering = 0)
|
||||
# f_backup_err = open( ''.join( (os.path.splitext(f_backup_log.name)[0], '.err' ) ), 'w', buffering = 0)
|
||||
#
|
||||
#
|
||||
# subprocess.call( [ context['gfix_path'], '-h', '54321', fdb_init ], stdout = f_backup_log, stderr = f_backup_err)
|
||||
# subprocess.call( [ context['gstat_path'], '-h', fdb_init ], stdout = f_backup_log, stderr = f_backup_err)
|
||||
# subprocess.call( [ context['gbak_path'], '-b', fdb_init, fdb_bkup, '-v', '-st', 'tdrw' ], stdout = f_backup_log, stderr = f_backup_err)
|
||||
#
|
||||
#
|
||||
# flush_and_close( f_backup_log )
|
||||
# flush_and_close( f_backup_err )
|
||||
#
|
||||
#
|
||||
# ########################################################################
|
||||
#
|
||||
#
|
||||
# cleanup( (fdb_rest,) )
|
||||
#
|
||||
#
|
||||
# f_restore_log = open( os.path.join(context['temp_directory'],'tmp_6208.restore.log'), 'w', buffering = 0)
|
||||
# f_restore_err = open( ''.join( (os.path.splitext(f_restore_log.name)[0], '.err' ) ), 'w', buffering = 0)
|
||||
#
|
||||
#
|
||||
# subprocess.call( [ context['gbak_path'], '-c', fdb_bkup, fdb_rest, '-v', '-st', 'tdrw' ], stdout = f_restore_log, stderr = f_restore_err)
|
||||
#
|
||||
#
|
||||
# flush_and_close( f_restore_log )
|
||||
# flush_and_close( f_restore_err )
|
||||
#
|
||||
#
|
||||
# ########################################################################
|
||||
#
|
||||
#
|
||||
# runProgram('gfix',['-shut', 'full', '-force', '0', fdb_init] )
|
||||
# runProgram('gfix',['-shut', 'full', '-force', '0', fdb_rest] )
|
||||
#
|
||||
#
|
||||
# shutil.move( fdb_rest, fdb_init )
|
||||
#
|
||||
#
|
||||
# runProgram('gfix',['-online', fdb_init] )
|
||||
#
|
||||
#
|
||||
# sql_chk='''
|
||||
# set bail on;
|
||||
# set list on;
|
||||
@ -213,9 +213,9 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# from mon$database d
|
||||
# join mon$attachments a on a.mon$attachment_id = current_connection
|
||||
# cross join rdb$database r
|
||||
#
|
||||
#
|
||||
# ;
|
||||
#
|
||||
#
|
||||
# select
|
||||
# s.sec$user_name as "sec$users.sec_user"
|
||||
# ,c.sec$user_type as "sec$db_creators.sec$user_type"
|
||||
@ -223,43 +223,44 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# left join sec$db_creators c on s.sec$user_name = c.sec$user
|
||||
# where sec$user_name = upper('TMP6208DBA');
|
||||
# rollback;
|
||||
#
|
||||
#
|
||||
# connect '%(fdb_init)s';
|
||||
# drop user tmp6208dba using plugin Srp;
|
||||
# commit;
|
||||
# ''' % locals()
|
||||
#
|
||||
#
|
||||
# f_chk_sql = open( os.path.join(context['temp_directory'],'tmp_6208_chk.sql'), 'w', buffering = 0)
|
||||
# f_chk_sql.write(sql_chk)
|
||||
# flush_and_close( f_chk_sql )
|
||||
#
|
||||
#
|
||||
# f_chk_log = open( os.path.join(context['temp_directory'],'tmp_6208_chk.log'), 'w', buffering = 0)
|
||||
# subprocess.call( [context['isql_path'], "-q", "-i", f_chk_sql.name ], stdout = f_chk_log, stderr = subprocess.STDOUT)
|
||||
# flush_and_close( f_chk_log )
|
||||
#
|
||||
#
|
||||
# #######runProgram('isql',[ fdb_init ], 'drop user tmp6208dba using plugin Srp; commit;')
|
||||
#
|
||||
#
|
||||
# f_shut_log = open( os.path.join(context['temp_directory'],'tmp_6208_shut.log'), 'w', buffering = 0)
|
||||
# subprocess.call( [ context['gfix_path'], "-shut", "full", "-force", "0", fdb_init ], stdout = f_shut_log, stderr = subprocess.STDOUT)
|
||||
# subprocess.call( [ context['gstat_path'], "-h", fdb_init ], stdout = f_shut_log, stderr = subprocess.STDOUT)
|
||||
# flush_and_close( f_shut_log )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# # Restore previous content:
|
||||
# shutil.move( dbcbak, dbconf )
|
||||
#
|
||||
#
|
||||
# with open(f_chk_log.name,'r') as f:
|
||||
# for line in f:
|
||||
# print(line)
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# # cleanup:
|
||||
# ##########
|
||||
# time.sleep(1)
|
||||
# cleanup( (f_backup_log, f_backup_err, f_restore_log, f_restore_err, f_chk_sql, f_chk_log, f_shut_log, fdb_init, fdb_bkup) )
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
mon$database.mon$owner SYSDBA
|
||||
@ -268,11 +269,10 @@ expected_stdout_1 = """
|
||||
WHOAMI TMP6208DBA
|
||||
sec$users.sec_user TMP6208DBA
|
||||
sec$db_creators.sec$user_type 8
|
||||
"""
|
||||
"""
|
||||
|
||||
@pytest.mark.version('>=4.0')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
def test_1(act_1: Action):
|
||||
pytest.skip("Requires change to databases.conf")
|
||||
|
||||
|
||||
|
@ -2,16 +2,17 @@
|
||||
#
|
||||
# id: bugs.core_6211
|
||||
# title: Command "ISQL -X" can not extract ROLE name when use multi-byte charset for connection (4.x only is affected)
|
||||
# decription:
|
||||
# Checked on 4.0.0.1713: 1.219s.
|
||||
#
|
||||
# decription:
|
||||
# Checked on 4.0.0.1713: 1.219s.
|
||||
#
|
||||
# tracker_id: CORE-6211
|
||||
# min_versions: ['4.0']
|
||||
# versions: 4.0
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
#from pathlib import Path
|
||||
from firebird.qa import db_factory, python_act, Action, temp_file
|
||||
|
||||
# version: 4.0
|
||||
# resources: None
|
||||
@ -29,28 +30,28 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# import difflib
|
||||
# import subprocess
|
||||
# from fdb import services
|
||||
#
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
# this_db = db_conn.database_name
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def flush_and_close( file_handle ):
|
||||
# # https://docs.python.org/2/library/os.html#os.fsync
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
|
||||
# global os
|
||||
#
|
||||
#
|
||||
# file_handle.flush()
|
||||
# if file_handle.mode not in ('r', 'rb') and file_handle.name != os.devnull:
|
||||
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
|
||||
# os.fsync(file_handle.fileno())
|
||||
# file_handle.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def cleanup( f_names_list ):
|
||||
# global os
|
||||
# for f in f_names_list:
|
||||
@ -61,41 +62,41 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# else:
|
||||
# print('Unrecognized type of element:', f, ' - can not be treated as file.')
|
||||
# del_name = None
|
||||
#
|
||||
#
|
||||
# if del_name and os.path.isfile( del_name ):
|
||||
# os.remove( del_name )
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# sql_ddl='''
|
||||
# set bail on;
|
||||
# create role Nachalnik4ukotkiNachalnik4ukotkiNachalnik4ukotkiNachalnik4ukotk; -- ASCII only
|
||||
# create role "НачальникЧукоткиНачальникЧукоткиНачальникЧукоткиНачальникЧукотк"; -- Cyrillic, two bytes per character
|
||||
# create role "НачальникЧукоткиНачальникЧукоткиНачальникЧукоткиНачальникЧукотк"; -- Cyrillic, two bytes per character
|
||||
# create role "‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰"; -- U+2030 PER MILLE SIGN, three bytes per character: E2 80 B0
|
||||
# create role "🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀"; -- U+1F680 ROCKET, four bytes per character: F0 9F 9A 80
|
||||
# commit;
|
||||
# commit;
|
||||
# set list on;
|
||||
# set count on;
|
||||
# select rdb$role_name as r_name from rdb$roles where rdb$system_flag is distinct from 1;
|
||||
# '''
|
||||
#
|
||||
#
|
||||
# f_init_ddl=open( os.path.join(context['temp_directory'],'tmp_6211_init_ddl.sql'), 'w', buffering = 0)
|
||||
# f_init_ddl.write(sql_ddl)
|
||||
# flush_and_close( f_init_ddl )
|
||||
#
|
||||
#
|
||||
# f_init_log = open( os.path.join(context['temp_directory'],'tmp_6211_init_ddl.log'), 'w', buffering = 0)
|
||||
# f_init_err = open( os.path.join(context['temp_directory'],'tmp_6211_init_ddl.err'), 'w', buffering = 0)
|
||||
# subprocess.call( [ context['isql_path'], dsn, '-ch', 'utf8', '-i', f_init_ddl.name ], stdout = f_init_log,stderr = f_init_err)
|
||||
# flush_and_close( f_init_log )
|
||||
# flush_and_close( f_init_err )
|
||||
#
|
||||
#
|
||||
# f_meta_log1 = open( os.path.join(context['temp_directory'],'tmp_6211_extracted_meta.sql'), 'w', buffering = 0)
|
||||
# f_meta_err1 = open( os.path.join(context['temp_directory'],'tmp_6211_extracted_meta.err'), 'w', buffering = 0)
|
||||
# subprocess.call( [ context['isql_path'], dsn, '-x', '-ch', 'utf8' ], stdout = f_meta_log1, stderr = f_meta_err1)
|
||||
# flush_and_close( f_meta_log1 )
|
||||
# flush_and_close( f_meta_err1 )
|
||||
#
|
||||
#
|
||||
# f_list=(f_init_err, f_meta_err1,)
|
||||
# for i in range(len(f_list)):
|
||||
# f_name=f_list[i].name
|
||||
@ -103,30 +104,47 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# with open( f_name,'r') as f:
|
||||
# for line in f:
|
||||
# print("Unexpected STDERR, file "+f_name+": "+line)
|
||||
#
|
||||
#
|
||||
# with open( f_meta_log1.name,'r') as f:
|
||||
# for line in f:
|
||||
# if 'CREATE ROLE' in line:
|
||||
# print(line)
|
||||
#
|
||||
#
|
||||
# # cleanup:
|
||||
# ##########
|
||||
# time.sleep(1)
|
||||
# cleanup( ( f_init_ddl, f_init_log, f_init_err, f_meta_err1, f_meta_log1, f_meta_err1 ) )
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
CREATE ROLE NACHALNIK4UKOTKINACHALNIK4UKOTKINACHALNIK4UKOTKINACHALNIK4UKOTK;
|
||||
CREATE ROLE "НачальникЧукоткиНачальникЧукоткиНачальникЧукоткиНачальникЧукотк";
|
||||
CREATE ROLE "‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰";
|
||||
CREATE ROLE "🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀";
|
||||
"""
|
||||
"""
|
||||
|
||||
#test_script = temp_file('test-script.sql')
|
||||
|
||||
ddl_script = """
|
||||
set bail on;
|
||||
create role Nachalnik4ukotkiNachalnik4ukotkiNachalnik4ukotkiNachalnik4ukotk; -- ASCII only
|
||||
create role "НачальникЧукоткиНачальникЧукоткиНачальникЧукоткиНачальникЧукотк"; -- Cyrillic, two bytes per character
|
||||
create role "‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰‰"; -- U+2030 PER MILLE SIGN, three bytes per character: E2 80 B0
|
||||
create role "🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀"; -- U+1F680 ROCKET, four bytes per character: F0 9F 9A 80
|
||||
commit;
|
||||
set list on;
|
||||
set count on;
|
||||
select rdb$role_name as r_name from rdb$roles where rdb$system_flag is distinct from 1;
|
||||
"""
|
||||
|
||||
@pytest.mark.version('>=4.0')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
|
||||
|
||||
def test_1(act_1: Action):
|
||||
act_1.isql(switches=[], input=ddl_script)
|
||||
act_1.reset()
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
act_1.isql(switches=['-x'])
|
||||
act_1.stdout = '\n'.join([line for line in act_1.stdout.splitlines() if 'CREATE ROLE' in line])
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
@ -2,25 +2,26 @@
|
||||
#
|
||||
# id: bugs.core_6227
|
||||
# title: isc_info_svc_user_dbpath always returns alias of main security database
|
||||
# decription:
|
||||
# decription:
|
||||
# String returned by sevrice manager for 'info_user_dbpath' query must contain PATH + file/alias
|
||||
# rather than only file name or alias of security.db.
|
||||
# If we call os.path.split() then this string will be splitted onto PATH and ALIAS.
|
||||
# The first token (PATH) must contain at least one character if we try to split it using os.sep delimiter.
|
||||
# We check that length of this path is more than zero.
|
||||
# We check that length of this path is more than zero.
|
||||
# Note that befor fix reply was: ('', security.db') - so the PATH was empty string rather that None!
|
||||
#
|
||||
#
|
||||
# Checked on:
|
||||
# 4.0.0.1726 SS: 1.849s.
|
||||
# 3.0.5.33232 SS: 0.704s.
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-6227
|
||||
# min_versions: ['3.0.5']
|
||||
# versions: 3.0.5
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
import os
|
||||
from firebird.qa import db_factory, python_act, Action
|
||||
|
||||
# version: 3.0.5
|
||||
# resources: None
|
||||
@ -33,27 +34,22 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
|
||||
# test_script_1
|
||||
#---
|
||||
#
|
||||
#
|
||||
# import os
|
||||
# from fdb import services
|
||||
#
|
||||
#
|
||||
# svc = services.connect(host='localhost', user= user_name, password= user_password)
|
||||
# security_db_info = svc.get_security_database_path()
|
||||
# svc.close()
|
||||
#
|
||||
#
|
||||
# print( 'Is DIRECTORY included into security DB info ? => ', ( 'YES' if os.path.split(security_db_info)[0] else ('NO. >' + security_db_info + '<' ) ) )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
Is DIRECTORY included into security DB info ? => YES
|
||||
"""
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
@pytest.mark.version('>=3.0.5')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
|
||||
|
||||
def test_1(act_1: Action):
|
||||
with act_1.connect_server() as srv:
|
||||
assert os.path.split(srv.info.security_database)[0]
|
||||
|
@ -2,34 +2,62 @@
|
||||
#
|
||||
# id: bugs.core_6233
|
||||
# title: Wrong dependencies of stored function on view after backup and restore
|
||||
# decription:
|
||||
# decription:
|
||||
# We make backup of this test DB and restore it to other name using PIPE mechanism
|
||||
# in order to skip creation of unneeded .fbk file
|
||||
# See: https://docs.python.org/2/library/subprocess.html#replacing-shell-pipeline
|
||||
# Confirmed bug on 4.0.0.1740.
|
||||
# Checked on 4.0.0.1743: works OK.
|
||||
# Checked result of backporting fix to on 3.0.6.33265: OK.
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-6233
|
||||
# min_versions: ['3.0.6']
|
||||
# versions: 3.0.6
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
from io import BytesIO
|
||||
from pathlib import Path
|
||||
from firebird.qa import db_factory, python_act, Action, temp_file
|
||||
|
||||
# version: 3.0.6
|
||||
# resources: None
|
||||
|
||||
substitutions_1 = []
|
||||
|
||||
init_script_1 = """"""
|
||||
init_script_1 = """
|
||||
set bail on;
|
||||
create or alter procedure p1 as begin end;
|
||||
create or alter function f1 returns integer as begin end;
|
||||
commit;
|
||||
|
||||
set term ^;
|
||||
create or alter view v1 as
|
||||
select 1 as n from rdb$database
|
||||
^
|
||||
|
||||
create or alter function f1 returns integer as
|
||||
declare ret integer;
|
||||
begin
|
||||
select n from v1 into ret;
|
||||
return ret;
|
||||
end
|
||||
^
|
||||
|
||||
create or alter procedure p1 returns (ret integer) as
|
||||
begin
|
||||
select n from v1 into ret;
|
||||
end
|
||||
^
|
||||
set term ;^
|
||||
commit;
|
||||
"""
|
||||
|
||||
db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
|
||||
# test_script_1
|
||||
#---
|
||||
#
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# import time
|
||||
@ -37,29 +65,29 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# import shutil
|
||||
# from subprocess import PIPE
|
||||
# from fdb import services
|
||||
#
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
# this_db = db_conn.database_name
|
||||
# db_conn.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def flush_and_close( file_handle ):
|
||||
# # https://docs.python.org/2/library/os.html#os.fsync
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
|
||||
# global os
|
||||
#
|
||||
#
|
||||
# file_handle.flush()
|
||||
# if file_handle.mode not in ('r', 'rb') and file_handle.name != os.devnull:
|
||||
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
|
||||
# os.fsync(file_handle.fileno())
|
||||
# file_handle.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def cleanup( f_names_list ):
|
||||
# global os
|
||||
# for f in f_names_list:
|
||||
@ -70,26 +98,26 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# else:
|
||||
# print('Unrecognized type of element:', f, ' - can not be treated as file.')
|
||||
# del_name = None
|
||||
#
|
||||
#
|
||||
# if del_name and os.path.isfile( del_name ):
|
||||
# os.remove( del_name )
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# fdb_rest = os.path.join(context['temp_directory'],'tmp_6233_restored.fdb')
|
||||
# cleanup( (fdb_rest,) )
|
||||
#
|
||||
#
|
||||
# sql_init='''
|
||||
# set bail on;
|
||||
# create or alter procedure p1 as begin end;
|
||||
# create or alter function f1 returns integer as begin end;
|
||||
# commit;
|
||||
#
|
||||
#
|
||||
# set term ^;
|
||||
# create or alter view v1 as
|
||||
# select 1 as n from rdb$database
|
||||
# ^
|
||||
#
|
||||
#
|
||||
# create or alter function f1 returns integer as
|
||||
# declare ret integer;
|
||||
# begin
|
||||
@ -97,7 +125,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# return ret;
|
||||
# end
|
||||
# ^
|
||||
#
|
||||
#
|
||||
# create or alter procedure p1 returns (ret integer) as
|
||||
# begin
|
||||
# select n from v1 into ret;
|
||||
@ -105,11 +133,11 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# ^
|
||||
# set term ;^
|
||||
# commit;
|
||||
#
|
||||
#
|
||||
# '''
|
||||
# runProgram('isql', [ dsn], sql_init)
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# # https://docs.python.org/2/library/subprocess.html#replacing-shell-pipeline
|
||||
# # output=`dmesg | grep hda`
|
||||
# # becomes:
|
||||
@ -118,13 +146,13 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# # p1.stdout.close() # Allow p1 to receive a SIGPIPE if p2 exits.
|
||||
# # output = p2.communicate()[0]
|
||||
# # gbak -b localhost:$fdb_init stdout | gbak -rep stdin localhost:$fdb_rest
|
||||
#
|
||||
#
|
||||
# p_sender = subprocess.Popen( [ context['gbak_path'], '-b', dsn, 'stdout' ], stdout=PIPE)
|
||||
# p_getter = subprocess.Popen( [ context['gbak_path'], '-c', 'stdin', 'localhost:' + fdb_rest ], stdin = p_sender.stdout, stdout = PIPE )
|
||||
# p_sender.stdout.close()
|
||||
# p_getter_stdout, p_getter_stderr = p_getter.communicate()
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# sql_chk='''
|
||||
# set list on;
|
||||
# set count on;
|
||||
@ -134,13 +162,24 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# from rdb$dependencies
|
||||
# order by 1,2;
|
||||
# '''
|
||||
#
|
||||
#
|
||||
# runProgram('isql',[ 'localhost:' + fdb_rest ], sql_chk)
|
||||
#
|
||||
#
|
||||
# cleanup( (fdb_rest,) )
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
test_script_1 = """
|
||||
set list on;
|
||||
set count on;
|
||||
select
|
||||
RDB$DEPENDENT_NAME as dep_name
|
||||
,RDB$DEPENDED_ON_NAME as dep_on_name
|
||||
from rdb$dependencies
|
||||
order by 1,2;
|
||||
"""
|
||||
|
||||
expected_stdout_1 = """
|
||||
DEP_NAME F1
|
||||
@ -154,11 +193,20 @@ expected_stdout_1 = """
|
||||
DEP_NAME V1
|
||||
DEP_ON_NAME RDB$DATABASE
|
||||
Records affected: 5
|
||||
"""
|
||||
"""
|
||||
|
||||
fdb_restored = temp_file('core_6233_restored.fdb')
|
||||
|
||||
@pytest.mark.version('>=3.0.6')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
def test_1(act_1: Action, fdb_restored: Path):
|
||||
with act_1.connect_server() as srv:
|
||||
backup = BytesIO()
|
||||
srv.database.local_backup(database=act_1.db.db_path, backup_stream=backup)
|
||||
backup.seek(0)
|
||||
srv.database.local_restore(database=fdb_restored, backup_stream=backup)
|
||||
#
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
act_1.isql(switches=[act_1.get_dsn(fdb_restored)], input=test_script_1, connect_db=False)
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
||||
|
||||
|
@ -2,24 +2,24 @@
|
||||
#
|
||||
# id: bugs.core_6236
|
||||
# title: RDB$TIME_ZONE_UTIL package has wrong privilege for PUBLIC
|
||||
# decription:
|
||||
# decription:
|
||||
# Thanks Adriano for suggestion about this test implementation.
|
||||
# We create non-privileged user ('tmp$c6236') and do connect of him
|
||||
# with trying to use package function rdb$time_zone_util.database_version().
|
||||
# It must pass without any errors (result of call no matter).
|
||||
#
|
||||
#
|
||||
# Confirmed exception on 4.0.0.1714: no permission for EXECUTE access to PACKAGE RDB$TIME_ZONE_UTIL
|
||||
# Checked on 4.0.0.1740 SS: 1.400s - works fine.
|
||||
# ::: NB :::
|
||||
# Command 'SHOW GRANTS' does not display privileges on system objects thus we do not use it here.
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-6236
|
||||
# min_versions: ['4.0.0']
|
||||
# versions: 4.0
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
from firebird.qa import db_factory, python_act, Action, user_factory, User
|
||||
|
||||
# version: 4.0
|
||||
# resources: None
|
||||
@ -35,13 +35,13 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# import os
|
||||
# import sys
|
||||
# import inspect
|
||||
#
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
#
|
||||
#
|
||||
# db_conn.execute_immediate("create or alter user tmp$c6236 password '123'")
|
||||
# db_conn.commit()
|
||||
#
|
||||
#
|
||||
# con = fdb.connect( dsn = dsn, user = 'tmp$c6236', password ='123' )
|
||||
# cur = con.cursor()
|
||||
# try:
|
||||
@ -53,23 +53,30 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# except Exception as e:
|
||||
# print('Unexpected exception in ', inspect.stack()[0][3], ': ', sys.exc_info()[0])
|
||||
# print(e)
|
||||
#
|
||||
#
|
||||
# cur.close()
|
||||
# con.close()
|
||||
#
|
||||
#
|
||||
# db_conn.execute_immediate("drop user tmp$c6236")
|
||||
# db_conn.commit()
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
DB_VERS_DEFINED : True
|
||||
"""
|
||||
DB_VERS_DEFINED True
|
||||
"""
|
||||
|
||||
test_user = user_factory('db_1', name='tmp$c6236', password='123')
|
||||
|
||||
@pytest.mark.version('>=4.0')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
|
||||
|
||||
def test_1(act_1: Action, test_user: User, capsys):
|
||||
with act_1.db.connect(user=test_user.name, password=test_user.password) as con:
|
||||
c = con.cursor()
|
||||
c.execute('select rdb$time_zone_util.database_version() is not null as db_vers_defined from rdb$database')
|
||||
act_1.print_data_list(c)
|
||||
# Check
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
act_1.stdout = capsys.readouterr().out
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
@ -2,21 +2,21 @@
|
||||
#
|
||||
# id: bugs.core_6237
|
||||
# title: Performance problem when using SRP plugin
|
||||
# decription:
|
||||
# decription:
|
||||
# :::::::::::::::::::: N O T A B E N E :::::::::::::::::
|
||||
# It is crusial for this test that firebird.conf have following _SEQUENCE_ of auth-plugins: Srp, ..., Legacy_Auth
|
||||
# It is crucial for this test that firebird.conf have following _SEQUENCE_ of auth-plugins: Srp, ..., Legacy_Auth
|
||||
# -- i.e. Srp must be specified BEFORE Legacy.
|
||||
# Slow time of attach establishing can NOT be seen otherwise; rather almost no difference will be in that case.
|
||||
# :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
#
|
||||
#
|
||||
# Test creates two users: one usingLegacy plugin and second using Srp.
|
||||
# Then we make ~20...30 pairs of attach/detach by each of these users and get total time difference for these actions.
|
||||
# Ratio between these total differences must be limited with threshold. Its value was determined after dozen of runs
|
||||
# and it seems to be reasonable assign to it value 1.25 (see MIN_RATIO_THRESHOLD in the code).
|
||||
#
|
||||
# Test output will contain ALERT if total time of <attaches_using_Srp> vs <attaches_using_Legacy>
|
||||
#
|
||||
# Test output will contain ALERT if total time of <attaches_using_Srp> vs <attaches_using_Legacy>
|
||||
# will be greater than MIN_RATIO_THRESHOLD.
|
||||
#
|
||||
#
|
||||
# Reproduced on on several builds 4.x before 17.01.2020 (tested: 4.0.0.1712 CS, 4.0.0.1731 CS - got ratio = ~1.95).
|
||||
# Reproduced also on 3.0.5.33221 Classic - got ratio ~1.50 ... 1.70; could NOT reproduce on 3.0.5 SuperClassic / SuperServer.
|
||||
# Checked on:
|
||||
@ -24,15 +24,16 @@
|
||||
# 4.0.0.1763 CS: 23.725s.
|
||||
# 3.0.6.33240 SS: 7.294s.
|
||||
# 3.0.6.33240 CS: 17.407s.
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-6237
|
||||
# min_versions: ['3.0.5']
|
||||
# versions: 3.0.5
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
import datetime
|
||||
from firebird.qa import db_factory, python_act, Action, user_factory, User
|
||||
|
||||
# version: 3.0.5
|
||||
# resources: None
|
||||
@ -48,78 +49,100 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# import os
|
||||
# import datetime
|
||||
# from datetime import timedelta
|
||||
#
|
||||
#
|
||||
# def showtime():
|
||||
# global datetime
|
||||
# return ''.join( (datetime.datetime.now().strftime("%H:%M:%S.%f")[:12],'.') )
|
||||
#
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
#
|
||||
#
|
||||
# # Number of attach/detach actions for each of checked plugin:
|
||||
# N_ITER=50
|
||||
#
|
||||
#
|
||||
# # Minimal ratio (for ALERT) between total time when Srp is used vs such value for Legacy auth plugin.
|
||||
# # Will be evaluated as datediff(millisecond ...) that were spent for making N_ITER attach/detach actions.
|
||||
#
|
||||
#
|
||||
# MIN_RATIO_THRESHOLD = 1.41
|
||||
# # ^
|
||||
# # ###################
|
||||
# # ### THRESHOLD ###
|
||||
# # ###################
|
||||
#
|
||||
#
|
||||
# db_conn.execute_immediate("create or alter user tmp_c6237_leg password 'leg' using plugin Legacy_UserManager")
|
||||
# db_conn.execute_immediate("create or alter user tmp_c6237_srp password 'srp' using plugin Srp")
|
||||
# db_conn.commit()
|
||||
# db_conn.close()
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# elap_ms_for_leg_auth, elap_ms_for_srp_auth = 0,0
|
||||
#
|
||||
#
|
||||
# for j in range(0,2):
|
||||
# v_user = 'tmp_c6237_leg' if j==0 else 'tmp_c6237_srp'
|
||||
# v_pass = 'leg' if j==0 else 'srp'
|
||||
#
|
||||
#
|
||||
# ta = datetime.datetime.now()
|
||||
# for i in range(0, N_ITER):
|
||||
# conx=fdb.connect(dsn = dsn, user = v_user, password = v_pass )
|
||||
# conx.close()
|
||||
#
|
||||
#
|
||||
# tb = datetime.datetime.now()
|
||||
# diff=tb-ta
|
||||
#
|
||||
#
|
||||
# if j == 0:
|
||||
# elap_ms_for_leg_auth = int(diff.seconds) * 1000 + diff.microseconds / 1000
|
||||
# else:
|
||||
# elap_ms_for_srp_auth = int(diff.seconds) * 1000 + diff.microseconds / 1000
|
||||
#
|
||||
#
|
||||
# db_conn = fdb.connect(dsn = dsn)
|
||||
# db_conn.execute_immediate("drop user tmp_c6237_leg using plugin Legacy_UserManager")
|
||||
# db_conn.execute_immediate("drop user tmp_c6237_srp using plugin Srp")
|
||||
# db_conn.commit()
|
||||
# db_conn.close()
|
||||
#
|
||||
#
|
||||
# # print( 'Legacy, ms: ', elap_ms_for_leg_auth, '; Srp, ms: ', elap_ms_for_srp_auth, '; 1.00 * elap_ms_for_srp_auth / elap_ms_for_leg_auth=', 1.00 * elap_ms_for_srp_auth / elap_ms_for_leg_auth )
|
||||
#
|
||||
#
|
||||
# elapsed_time_ratio = 1.00 * elap_ms_for_srp_auth / elap_ms_for_leg_auth
|
||||
# if elapsed_time_ratio < MIN_RATIO_THRESHOLD:
|
||||
# msg = 'EXPECTED. Ratio of total elapsed time when use Srp vs Legacy is less then threshold.'
|
||||
# else:
|
||||
# msg = 'Ratio Srp/Legacy: %(elapsed_time_ratio)s - is GREATER than threshold = %(MIN_RATIO_THRESHOLD)s. Total time spent for Srp: %(elap_ms_for_srp_auth)s ms; for Legacy: %(elap_ms_for_leg_auth)s ms.' % locals()
|
||||
#
|
||||
#
|
||||
# print(msg)
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
EXPECTED. Ratio of total elapsed time when use Srp vs Legacy is less then threshold.
|
||||
"""
|
||||
|
||||
leg_user = user_factory('db_1', name='tmp_c6237_leg', password='123', plugin='Legacy_UserManager')
|
||||
srp_user = user_factory('db_1', name='tmp_c6237_srp', password='123', plugin='Srp')
|
||||
|
||||
@pytest.mark.version('>=3.0.5')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
|
||||
|
||||
def test_1(act_1: Action, leg_user: User, srp_user: User, capsys):
|
||||
N_ITER = 50
|
||||
MIN_RATIO_THRESHOLD = 1.41
|
||||
elapsed = {leg_user.name: 0, srp_user.name: 0}
|
||||
#
|
||||
for user in [leg_user, srp_user]:
|
||||
start = datetime.datetime.now()
|
||||
for i in range(N_ITER):
|
||||
with act_1.db.connect(user=user.name, password=user.password):
|
||||
pass
|
||||
stop = datetime.datetime.now()
|
||||
diff = stop - start
|
||||
elapsed[user.name] = int(diff.seconds) * 1000 + diff.microseconds / 1000
|
||||
#
|
||||
elapsed_time_ratio = 1.00 * elapsed[srp_user.name] / elapsed[leg_user.name]
|
||||
if elapsed_time_ratio < MIN_RATIO_THRESHOLD:
|
||||
print('EXPECTED. Ratio of total elapsed time when use Srp vs Legacy is less then threshold.')
|
||||
else:
|
||||
print(f'Ratio Srp/Legacy: {elapsed_time_ratio} - is GREATER than threshold = {MIN_RATIO_THRESHOLD}. Total time spent for Srp: {elapsed[srp_user.name]} ms; for Legacy: {elapsed[leg_user.name]} ms.')
|
||||
#
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
act_1.stdout = capsys.readouterr().out
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
@ -2,18 +2,18 @@
|
||||
#
|
||||
# id: bugs.core_6246
|
||||
# title: Problem with too many number of columns in resultset.
|
||||
# decription:
|
||||
# decription:
|
||||
# We create .sql with 32767 columns and run it with requirement to display SQLDA.
|
||||
# All lines in produced output with 'charset: ' substring must contain only one value:
|
||||
# * '3' for FB 3.x; '4' for FB 4.x.
|
||||
# If some charset ID differs from expected, we raise error and terminate check furter lines.
|
||||
#
|
||||
#
|
||||
# Confirmed bug on 3.0.6.33272: first 32108 fields are shown in SQLDA with 'charset: 0 NONE'.
|
||||
# String 'charset: 3 UNICODE_FSS' appeared only since 32109-th column and up to the end.
|
||||
#
|
||||
#
|
||||
# Checked on 3.0.6.33273 - works fine.
|
||||
# Checked on 4.0.0.2353 - works fine // 30.01.2021
|
||||
#
|
||||
#
|
||||
# Comment before 30-jan-2021:
|
||||
# ---------------------------
|
||||
# Attempt to run query with 32767 columns on 4.0 will raise:
|
||||
@ -23,14 +23,14 @@
|
||||
# Will be removed after fix CORE-6216 (see commet by Adriano in CORE-6246, date: 22/Mar/20 01:40 AM).
|
||||
# ---------------------------
|
||||
# 30.01.2021: CORE-6212 was fixed. Section for 4.0 deleted; common code is used for 3.x and 4.x.
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-6246
|
||||
# min_versions: ['3.0.6']
|
||||
# versions: 3.0.6
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
from firebird.qa import db_factory, python_act, Action
|
||||
|
||||
# version: 3.0.6
|
||||
# resources: None
|
||||
@ -47,28 +47,28 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# import sys
|
||||
# import subprocess
|
||||
# from fdb import services
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def cleanup( f_names_list ):
|
||||
# global os
|
||||
# for i in range(len( f_names_list )):
|
||||
# if os.path.isfile( f_names_list[i]):
|
||||
# os.remove( f_names_list[i] )
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
#
|
||||
#
|
||||
# fb_major=db_conn.engine_version # type: double!
|
||||
# db_conn.close()
|
||||
#
|
||||
#
|
||||
# MAX_FOR_PASS=32767
|
||||
# #MAX_FOR_PASS=32
|
||||
#
|
||||
#
|
||||
# fld_list = ','.join( ('x1.rdb$field_name',) * MAX_FOR_PASS )
|
||||
#
|
||||
#
|
||||
# # Create .sql with <MAX_FOR_PASS> columns:
|
||||
# ##########################################
|
||||
# sql_test='''
|
||||
@ -78,21 +78,21 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# %(fld_list)s
|
||||
# from rdb$fields as x1 rows 1;
|
||||
# ''' % locals()
|
||||
#
|
||||
#
|
||||
# f_pass_sql = open( os.path.join(context['temp_directory'],'tmp_6246_pass.sql'), 'w', buffering = 0)
|
||||
# f_pass_sql.write( sql_test )
|
||||
# f_pass_sql.close()
|
||||
#
|
||||
#
|
||||
# f_pass_log = open( '.'.join( (os.path.splitext( f_pass_sql.name )[0], 'log') ), 'w', buffering = 0)
|
||||
# f_pass_err = open( '.'.join( (os.path.splitext( f_pass_sql.name )[0], 'err') ), 'w', buffering = 0)
|
||||
#
|
||||
#
|
||||
# # This can take about 25-30 seconds:
|
||||
# ####################################
|
||||
# subprocess.call( [ context['isql_path'], dsn, '-q', '-i', f_pass_sql.name ], stdout = f_pass_log, stderr = f_pass_err)
|
||||
#
|
||||
#
|
||||
# f_pass_log.close()
|
||||
# f_pass_err.close()
|
||||
#
|
||||
#
|
||||
# # Checks:
|
||||
# #########
|
||||
# # 1. Result of STDERR must be empty:
|
||||
@ -100,9 +100,9 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# for line in f:
|
||||
# if line.split():
|
||||
# print('UNEXPECTED STDERR: '+line)
|
||||
#
|
||||
#
|
||||
# # 1. For FB 3.x: only "charset: 3" must present in any string that describes column:
|
||||
# # NN: sqltype: 452 TEXT Nullable scale: 0 subtype: 0 len: 93 charset: 3 UNICODE_FSS
|
||||
# # NN: sqltype: 452 TEXT Nullable scale: 0 subtype: 0 len: 93 charset: 3 UNICODE_FSS
|
||||
# # ^
|
||||
# # 0 1 2 3 4 5 6 7 8 9 10 11 12 13
|
||||
# # 2. For FB 4.x: only "charset: 4" must present in any string that describes column:
|
||||
@ -113,11 +113,11 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# # we must check this token
|
||||
# #
|
||||
# # where 'NN:' is '01:', '02:', '03:', ... '32767:'
|
||||
#
|
||||
#
|
||||
# ############## ::: N O T E ::: #################
|
||||
# expected_charset_id = '3' if fb_major < 4 else '4'
|
||||
# ##################################################
|
||||
#
|
||||
#
|
||||
# charset_id_position = -1
|
||||
# i=0
|
||||
# with open(f_pass_log.name,'r') as f:
|
||||
@ -126,28 +126,65 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# if 'sqltype:' in line:
|
||||
# if charset_id_position < 0:
|
||||
# charset_id_position = [ (n,w) for n,w in enumerate( line.split() ) if w.lower() == 'charset:'.lower() ][0][0] + 1
|
||||
#
|
||||
#
|
||||
# # charset_id = line.split()[-2]
|
||||
# charset_id = line.split()[ charset_id_position ]
|
||||
# if charset_id != expected_charset_id:
|
||||
# print('At least one UNEXPECTED charset in SQLDA at position: %d. Line No: %d, charset_id: %s' % (charset_id_position, i, charset_id) )
|
||||
# print(line)
|
||||
# break
|
||||
#
|
||||
#
|
||||
# if charset_id_position < 0:
|
||||
# # ISQL log is empty or not contains 'sqltype:' in any line.
|
||||
# print('UNEXPECTED RESULT: no lines with expected pattern found.')
|
||||
#
|
||||
#
|
||||
# cleanup( [ i.name for i in ( f_pass_sql, f_pass_log, f_pass_err) ] )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
|
||||
@pytest.mark.version('>=3.0.6')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
|
||||
|
||||
def test_1(act_1: Action):
|
||||
MAX_FOR_PASS = 32767
|
||||
fld_list = ','.join(['x1.rdb$field_name' for i in range(MAX_FOR_PASS)])
|
||||
test_script = f"""
|
||||
set sqlda_display on;
|
||||
set planonly;
|
||||
select
|
||||
{fld_list}
|
||||
from rdb$fields as x1 rows 1;
|
||||
"""
|
||||
act_1.isql(switches=['-q'], input=test_script)
|
||||
# 1. For FB 3.x: only "charset: 3" must present in any string that describes column:
|
||||
# NN: sqltype: 452 TEXT Nullable scale: 0 subtype: 0 len: 93 charset: 3 UNICODE_FSS
|
||||
# ^
|
||||
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13
|
||||
# 2. For FB 4.x: only "charset: 4" must present in any string that describes column:
|
||||
# NN: sqltype: 452 TEXT Nullable scale: 0 subtype: 0 len: 252 charset: 4 UTF8
|
||||
# ^
|
||||
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13
|
||||
# ^
|
||||
# we must check this token
|
||||
# where 'NN:' is '01:', '02:', '03:', ... '32767:'
|
||||
expected_charset_id = '3' if act_1.is_version('<4') else '4'
|
||||
charset_id_position = -1
|
||||
i = 0
|
||||
for line in act_1.stdout.splitlines():
|
||||
i += 1
|
||||
if 'sqltype:' in line:
|
||||
elements = line.split()
|
||||
if charset_id_position < 0:
|
||||
charset_id_position = [(n, w) for n, w in enumerate(elements) if w.lower() == 'charset:'][0][0] + 1
|
||||
# charset_id = elements[-2]
|
||||
charset_id = elements[charset_id_position]
|
||||
if charset_id != expected_charset_id:
|
||||
print(f'At least one UNEXPECTED charset in SQLDA at position: {charset_id_position}. Line No: {i}, charset_id: {charset_id}')
|
||||
print(line)
|
||||
pytest.fail("UNEXPECTED charset in SQLDA")
|
||||
#
|
||||
if charset_id_position < 0:
|
||||
# ISQL log is empty or not contains 'sqltype:' in any line.
|
||||
pytest.fail('No lines with expected pattern found.')
|
||||
|
@ -2,49 +2,87 @@
|
||||
#
|
||||
# id: bugs.core_6248
|
||||
# title: A number of errors when database name is longer than 255 symbols
|
||||
# decription:
|
||||
# decription:
|
||||
# Test verifies that one may to create DB with total path plus name length L = 255 and 259 characters.
|
||||
# Each DB is then subject for 'gbak -b', 'gbak -c', 'gstat -h', 'gfix -sweep' and 'gfix -v -full'.
|
||||
# All these commands must NOT issue something to their STDERR.
|
||||
#
|
||||
#
|
||||
# STDOUT-log of initial SQL must contain full DB name.
|
||||
# Changed part of firebird.log for SWEEP and VALIDATION also must have full DB name (this is verified using regexp):
|
||||
# +[tab]Database: C:\\FBTESTING\\QA\\FBT-REPO\\TMP\\ABC.FDB // for validation
|
||||
# +[tab]Database "C:\\FBTESTING\\QA\\FBT-REPO\\TMP\\ABC.FDB // for sweep
|
||||
#
|
||||
#
|
||||
# STDOUT-logs of backup, restore and gstat currently (09-mar-2020) have only truncated name (~235...241 chars).
|
||||
# This may change in the future if FB developers will decide to fix this small inconveniences.
|
||||
#
|
||||
#
|
||||
# For L=259 we must see in backup log following phrase:
|
||||
# gbak:text for attribute 7 is too large in put_asciz(), truncating to 255 bytes
|
||||
# gbak:text for attribute 7 is too large in put_asciz(), truncating to 255 bytes
|
||||
# - but currently this is not checked here.
|
||||
#
|
||||
#
|
||||
# Checked on 4.0.0.1796.
|
||||
# Checked on 4.0.0.2353: rdb$get_context('SYSTEM','DB_NAME') do not cut off full path and name to database
|
||||
# and can return string with length = 32K, i.e. exceeding length of mon$database_name.
|
||||
# See commit of 29-01-2021:
|
||||
# https://github.com/FirebirdSQL/firebird/commit/d4835cab7f48288490ed83541132555c5cd0376d
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-6248
|
||||
# min_versions: ['4.0']
|
||||
# versions: 4.0
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
import re
|
||||
import time
|
||||
from difflib import unified_diff
|
||||
from firebird.qa import db_factory, python_act, Action, Database
|
||||
from firebird.driver import SrvRepairFlag
|
||||
|
||||
# version: 4.0
|
||||
# resources: None
|
||||
|
||||
substitutions_1 = []
|
||||
|
||||
init_script_1 = """"""
|
||||
init_script_1 = """
|
||||
set list on;
|
||||
|
||||
db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
create exception exc_dbname_diff q'{Value in mon$database.mon$database_name differs from rdb$get_context('SYSTEM', 'DB_NAME'):@1@2@3=== vs ===@4@5}';
|
||||
set term ^;
|
||||
execute block returns(
|
||||
mon_database_column varchar(260)
|
||||
,sys_context_db_name varchar(260)
|
||||
) as
|
||||
declare lf char(1) = x'0A';
|
||||
begin
|
||||
select
|
||||
mon$database_name as mon_database_column
|
||||
from mon$database
|
||||
into mon_database_column;
|
||||
|
||||
sys_context_db_name = rdb$get_context('SYSTEM', 'DB_NAME');
|
||||
|
||||
if ( substring( sys_context_db_name from 1 for 255 ) is distinct from mon_database_column ) then
|
||||
begin
|
||||
exception exc_dbname_diff using(
|
||||
lf
|
||||
,mon_database_column
|
||||
,lf
|
||||
,lf
|
||||
,sys_context_db_name
|
||||
);
|
||||
end
|
||||
|
||||
suspend;
|
||||
end
|
||||
^
|
||||
set term ;^
|
||||
commit;
|
||||
"""
|
||||
|
||||
db_1 = db_factory(sql_dialect=3)
|
||||
|
||||
# test_script_1
|
||||
#---
|
||||
#
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# import tempfile
|
||||
@ -53,29 +91,29 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# import time
|
||||
# import subprocess
|
||||
# from fdb import services
|
||||
#
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
# this_db = db_conn.database_name
|
||||
# db_conn.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def flush_and_close( file_handle ):
|
||||
# # https://docs.python.org/2/library/os.html#os.fsync
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
|
||||
# global os
|
||||
#
|
||||
#
|
||||
# file_handle.flush()
|
||||
# if file_handle.mode not in ('r', 'rb') and file_handle.name != os.devnull:
|
||||
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
|
||||
# os.fsync(file_handle.fileno())
|
||||
# file_handle.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def cleanup( f_names_list ):
|
||||
# global os
|
||||
# for f in f_names_list:
|
||||
@ -86,14 +124,14 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# else:
|
||||
# print('Unrecognized type of element:', f, ' - can not be treated as file.')
|
||||
# del_name = None
|
||||
#
|
||||
#
|
||||
# if del_name and os.path.isfile( del_name ):
|
||||
# os.remove( del_name )
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def svc_get_fb_log( f_fb_log ):
|
||||
#
|
||||
#
|
||||
# global subprocess
|
||||
# subprocess.call([ context['fbsvcmgr_path'],
|
||||
# "localhost:service_mgr",
|
||||
@ -101,34 +139,34 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# ],
|
||||
# stdout=f_fb_log, stderr=subprocess.STDOUT
|
||||
# )
|
||||
#
|
||||
#
|
||||
# return
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def check_long_dbname(required_name_len, chars2fil):
|
||||
#
|
||||
#
|
||||
# global time, tempfile, subprocess, difflib
|
||||
# global flush_and_close, cleanup, svc_get_fb_log, re
|
||||
#
|
||||
#
|
||||
# MINIMAL_LEN_TO_SHOW=255
|
||||
# REDUCE_NAME_LEN_BY=0
|
||||
#
|
||||
#
|
||||
# folder = tempfile.gettempdir()
|
||||
# folder = context['temp_directory']
|
||||
# #folder = os.path.dirname(os.path.abspath(__file__))
|
||||
#
|
||||
#
|
||||
# f_name = ( chars2fil * 1000) [ : required_name_len - len(folder) - len('.fdb') - REDUCE_NAME_LEN_BY ] + '.fdb'
|
||||
#
|
||||
#
|
||||
# dbname = os.path.join( folder, f_name )
|
||||
#
|
||||
#
|
||||
# bkname = dbname[:-4] + '.fbk'
|
||||
#
|
||||
#
|
||||
# cleanup( (dbname,) )
|
||||
#
|
||||
#
|
||||
# sql_ddl=''' create database 'localhost:%(dbname)s';
|
||||
# set list on;
|
||||
#
|
||||
#
|
||||
# create exception exc_dbname_diff q'{Value in mon$database.mon$database_name differs from rdb$get_context('SYSTEM', 'DB_NAME'):@1@2@3=== vs ===@4@5}';
|
||||
# set term ^;
|
||||
# execute block returns(
|
||||
@ -141,9 +179,9 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# mon$database_name as mon_database_column
|
||||
# from mon$database
|
||||
# into mon_database_column;
|
||||
#
|
||||
#
|
||||
# sys_context_db_name = rdb$get_context('SYSTEM', 'DB_NAME');
|
||||
#
|
||||
#
|
||||
# if ( substring( sys_context_db_name from 1 for 255 ) is distinct from mon_database_column ) then
|
||||
# begin
|
||||
# exception exc_dbname_diff using(
|
||||
@ -154,163 +192,162 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# ,sys_context_db_name
|
||||
# );
|
||||
# end
|
||||
#
|
||||
#
|
||||
# suspend;
|
||||
# end
|
||||
# ^
|
||||
# set term ;^
|
||||
# commit;
|
||||
# ''' % locals()
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# f_sql_chk = open( os.path.join(context['temp_directory'],'tmp_6248_ddl.sql'), 'w')
|
||||
# f_sql_chk.write(sql_ddl)
|
||||
# flush_and_close( f_sql_chk )
|
||||
#
|
||||
#
|
||||
# ########################################################################
|
||||
#
|
||||
#
|
||||
# f_ddl_log = open( os.path.join(context['temp_directory'],'tmp_6248.ddl_'+str(required_name_len)+'.log'), 'w', buffering = 0)
|
||||
# f_ddl_err = open( ''.join( (os.path.splitext(f_sql_chk.name)[0], '.err' ) ), 'w', buffering = 0)
|
||||
#
|
||||
#
|
||||
# subprocess.call( [ context['isql_path'], '-q', '-i', f_sql_chk.name ], stdout = f_ddl_log, stderr = f_ddl_err)
|
||||
#
|
||||
#
|
||||
# flush_and_close( f_ddl_log )
|
||||
# flush_and_close( f_ddl_err )
|
||||
#
|
||||
#
|
||||
# ########################################################################
|
||||
#
|
||||
#
|
||||
# f_backup_log = open( os.path.join(context['temp_directory'],'tmp_6248.backup_'+str(required_name_len)+'.log'), 'w', buffering = 0)
|
||||
# f_backup_err = open( ''.join( (os.path.splitext(f_backup_log.name)[0], '.err' ) ), 'w', buffering = 0)
|
||||
#
|
||||
#
|
||||
# subprocess.call( [ context['gbak_path'], '-b', '-se', 'localhost:servce_mgr', dbname, bkname, '-v', '-st', 'tdrw' ], stdout = f_backup_log, stderr = f_backup_err)
|
||||
#
|
||||
#
|
||||
# flush_and_close( f_backup_log )
|
||||
# flush_and_close( f_backup_err )
|
||||
#
|
||||
#
|
||||
# ########################################################################
|
||||
#
|
||||
#
|
||||
# os.remove(dbname)
|
||||
#
|
||||
#
|
||||
# f_restore_log = open( os.path.join(context['temp_directory'],'tmp_6248.restore_'+str(required_name_len)+'.log'), 'w', buffering = 0)
|
||||
# f_restore_err = open( ''.join( (os.path.splitext(f_restore_log.name)[0], '.err' ) ), 'w', buffering = 0)
|
||||
#
|
||||
#
|
||||
# subprocess.call( [ context['gbak_path'], '-rep', '-se', 'localhost:servce_mgr', bkname, dbname, '-v', '-st', 'tdrw' ], stdout = f_restore_log, stderr = f_restore_err)
|
||||
#
|
||||
#
|
||||
# flush_and_close( f_restore_log )
|
||||
# flush_and_close( f_restore_err )
|
||||
#
|
||||
#
|
||||
# ########################################################################
|
||||
#
|
||||
#
|
||||
# f_gstat_log = open( os.path.join(context['temp_directory'],'tmp_6248.gstat_'+str(required_name_len)+'.log'), 'w', buffering = 0)
|
||||
# f_gstat_err = open( ''.join( (os.path.splitext(f_gstat_log.name)[0], '.err' ) ), 'w', buffering = 0)
|
||||
#
|
||||
#
|
||||
# subprocess.call( [ context['gstat_path'], '-h', 'localhost:' + dbname ], stdout = f_gstat_log, stderr = f_gstat_err)
|
||||
#
|
||||
#
|
||||
# flush_and_close( f_gstat_log )
|
||||
# flush_and_close( f_gstat_err )
|
||||
#
|
||||
#
|
||||
# ########################################################################
|
||||
#
|
||||
#
|
||||
# f_fblog_sweep_before = open( os.path.join(context['temp_directory'],'tmp_6248.fblog_before_sweep_'+str(required_name_len)+'.log'), 'w', buffering = 0)
|
||||
# svc_get_fb_log( f_fblog_sweep_before )
|
||||
# flush_and_close( f_fblog_sweep_before )
|
||||
#
|
||||
#
|
||||
# f_sweep_log = open( os.path.join(context['temp_directory'],'tmp_6248.sweep_'+str(required_name_len)+'.log'), 'w', buffering = 0)
|
||||
# f_sweep_err = open( ''.join( (os.path.splitext(f_sweep_log.name)[0], '.err' ) ), 'w', buffering = 0)
|
||||
#
|
||||
#
|
||||
# subprocess.call( [ context['fbsvcmgr_path'], 'localhost:service_mgr', 'action_repair', 'dbname', dbname, 'rpr_sweep_db' ], stdout = f_sweep_log, stderr = f_sweep_err)
|
||||
#
|
||||
#
|
||||
# flush_and_close( f_sweep_log )
|
||||
# flush_and_close( f_sweep_err )
|
||||
#
|
||||
#
|
||||
# # Here we let firebird.log to be fulfilled with text about just finished SWEEP:
|
||||
# time.sleep(1)
|
||||
#
|
||||
#
|
||||
# f_fblog_sweep_after = open( os.path.join(context['temp_directory'],'tmp_6248.fblog_after_sweep_'+str(required_name_len)+'.log'), 'w', buffering = 0)
|
||||
# svc_get_fb_log( f_fblog_sweep_after )
|
||||
# flush_and_close( f_fblog_sweep_after )
|
||||
#
|
||||
#
|
||||
# oldfb=open(f_fblog_sweep_before.name, 'r')
|
||||
# newfb=open(f_fblog_sweep_after.name, 'r')
|
||||
#
|
||||
#
|
||||
# difftext = ''.join(difflib.unified_diff(
|
||||
# oldfb.readlines(),
|
||||
# oldfb.readlines(),
|
||||
# newfb.readlines()
|
||||
# ))
|
||||
# oldfb.close()
|
||||
# newfb.close()
|
||||
#
|
||||
#
|
||||
# f_diff_sweep = open( os.path.join(context['temp_directory'],'tmp_6248.fblog_diff_sweep_'+str(required_name_len)+'.log'), 'w', buffering = 0)
|
||||
# f_diff_sweep.write(difftext)
|
||||
# flush_and_close( f_diff_sweep )
|
||||
#
|
||||
#
|
||||
# ########################################################################
|
||||
#
|
||||
#
|
||||
# f_fblog_validate_before = open( os.path.join(context['temp_directory'],'tmp_6248.fblog_before_validate_'+str(required_name_len)+'.log'), 'w', buffering = 0)
|
||||
# svc_get_fb_log( f_fblog_validate_before )
|
||||
# flush_and_close( f_fblog_validate_before )
|
||||
#
|
||||
#
|
||||
# f_valid_log = open( os.path.join(context['temp_directory'],'tmp_6248.valid_'+str(required_name_len)+'.log'), 'w', buffering = 0)
|
||||
# f_valid_err = open( ''.join( (os.path.splitext(f_valid_log.name)[0], '.err' ) ), 'w', buffering = 0)
|
||||
#
|
||||
#
|
||||
# subprocess.call( [ context['fbsvcmgr_path'], 'localhost:service_mgr', 'action_repair', 'dbname', dbname, 'rpr_validate_db', 'rpr_full' ], stdout = f_valid_log, stderr = f_valid_err)
|
||||
#
|
||||
#
|
||||
# flush_and_close( f_valid_log )
|
||||
# flush_and_close( f_valid_err )
|
||||
#
|
||||
#
|
||||
# # Here we let firebird.log to be fulfilled with text about just finished VALIDATION:
|
||||
# time.sleep(1)
|
||||
#
|
||||
#
|
||||
# f_fblog_validate_after = open( os.path.join(context['temp_directory'],'tmp_6248.fblog_after_validate_'+str(required_name_len)+'.log'), 'w', buffering = 0)
|
||||
# svc_get_fb_log( f_fblog_validate_after )
|
||||
# flush_and_close( f_fblog_validate_after )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# f_fblog_validate_after = open( os.path.join(context['temp_directory'],'tmp_6248.fblog_after_validate_'+str(required_name_len)+'.log'), 'w', buffering = 0)
|
||||
# svc_get_fb_log( f_fblog_validate_after )
|
||||
# flush_and_close( f_fblog_validate_after )
|
||||
#
|
||||
#
|
||||
# oldfb=open(f_fblog_validate_before.name, 'r')
|
||||
# newfb=open(f_fblog_validate_after.name, 'r')
|
||||
#
|
||||
#
|
||||
# difftext = ''.join(difflib.unified_diff(
|
||||
# oldfb.readlines(),
|
||||
# oldfb.readlines(),
|
||||
# newfb.readlines()
|
||||
# ))
|
||||
# oldfb.close()
|
||||
# newfb.close()
|
||||
#
|
||||
#
|
||||
# f_diff_validate = open( os.path.join(context['temp_directory'],'tmp_6248.fblog_diff_validate_'+str(required_name_len)+'.log'), 'w', buffering = 0)
|
||||
# f_diff_validate.write(difftext)
|
||||
# flush_and_close( f_diff_validate )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# ########################################################################
|
||||
#
|
||||
#
|
||||
# chk_list = (f_ddl_err, f_backup_err, f_restore_err, f_gstat_err, f_sweep_err, f_valid_err)
|
||||
# for c in chk_list:
|
||||
# with open(c.name,'r') as f:
|
||||
# for line in f:
|
||||
# if line.split():
|
||||
# print('UNEXPECTED ERROR, file:' + c.name +': ', line )
|
||||
#
|
||||
#
|
||||
# dbname_present_map = {}
|
||||
#
|
||||
#
|
||||
# # diff VALIDATION:
|
||||
# # +[tab]Database: C:\\FBTESTING\\QA\\FBT-REPO\\TMP\\ABC.FDB
|
||||
# # diff SWEEP:
|
||||
# # +[tab]Database "C:\\FBTESTING\\QA\\FBT-REPO\\TMP\\ABC.FDB
|
||||
# dbptrn = re.compile('\\+\\s+Database[:]{0,1}\\s+"{0,1}', re.IGNORECASE)
|
||||
#
|
||||
#
|
||||
# # STDOUT results: we have to check that AT LEAST 255 characters of database name present in log.
|
||||
# chk_list = (f_ddl_log, f_backup_log, f_restore_log, f_gstat_log, f_diff_sweep, f_diff_validate)
|
||||
# for c in chk_list:
|
||||
#
|
||||
#
|
||||
# # Name of STDOUT-log will serve as KEY for dbname_present_map{}, e.g.:
|
||||
# # C:\\FBTESTING\\qa
|
||||
# bt-repo mp mp_6248.backup_255.log --> tmp_6248.backup_255
|
||||
# # C:\\FBTESTING\\qa\\fbt-repo\\tmp\\tmp_6248.backup_255.log --> tmp_6248.backup_255
|
||||
# stdout_file = os.path.split( os.path.splitext( c.name )[0] )[1]
|
||||
#
|
||||
#
|
||||
# dbname_present_map[ stdout_file ] = 'DB NAME NOT FOUND'
|
||||
# with open(c.name,'r') as f:
|
||||
# for line in f:
|
||||
@ -321,46 +358,100 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# elif dbname[:128].upper() in line.upper():
|
||||
# dbname_present_map[ stdout_file ] = 'found truncated DB name.'
|
||||
# break
|
||||
#
|
||||
#
|
||||
# for k,v in sorted( dbname_present_map.items() ):
|
||||
# print(k, ':', v)
|
||||
#
|
||||
#
|
||||
# # Other STDOUT results will be analyzed after get developers resolution about
|
||||
# # truncation of DB names to ~235...241 characters.
|
||||
# # See notes of: 06/Mar/20 06:38 AM; 06/Mar/20 06:45 AM; 09/Mar/20 07:53 AM.
|
||||
# # Currently we do nothing and just remove them:
|
||||
#
|
||||
#
|
||||
# time.sleep(1)
|
||||
# cleanup( (f_sql_chk.name, bkname, dbname, f_ddl_err, f_backup_err, f_restore_err, f_gstat_err, f_sweep_err, f_valid_err, f_ddl_log, f_backup_log, f_restore_log, f_gstat_log, f_sweep_log, f_valid_log, f_fblog_sweep_before, f_fblog_sweep_after, f_diff_sweep, f_fblog_validate_before, f_fblog_validate_after, f_diff_validate) )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# check_long_dbname(255, 'abc255def')
|
||||
# check_long_dbname(259, 'qwe259rty')
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
tmp_6248.backup_255 : found truncated DB name.
|
||||
tmp_6248.ddl_255 : found at least 255 characters
|
||||
tmp_6248.fblog_diff_sweep_255 : found at least 255 characters
|
||||
tmp_6248.fblog_diff_validate_255 : found at least 255 characters
|
||||
tmp_6248.gstat_255 : found truncated DB name.
|
||||
tmp_6248.restore_255 : found truncated DB name.
|
||||
ddl : found at least 255 characters
|
||||
backup : found truncated DB name.
|
||||
restore : found truncated DB name.
|
||||
gstat : found truncated DB name.
|
||||
fblog_diff_sweep : found at least 255 characters
|
||||
fblog_diff_validate : found at least 255 characters
|
||||
"""
|
||||
|
||||
@pytest.fixture
|
||||
def test_db(request: pytest.FixtureRequest, db_path) -> Database:
|
||||
required_name_len = request.param[0]
|
||||
chars2fil = request.param[1]
|
||||
filename = (chars2fil * 1000)[:required_name_len - len(str(db_path)) - 4] + '.fdb'
|
||||
db = Database(db_path, filename)
|
||||
db.create()
|
||||
yield db
|
||||
db.drop()
|
||||
|
||||
MINIMAL_LEN_TO_SHOW = 255
|
||||
|
||||
PATTERN = re.compile('\\+\\s+Database[:]{0,1}\\s+"{0,1}', re.IGNORECASE)
|
||||
|
||||
def check_filename_presence(lines, *, log_name: str, db: Database):
|
||||
filename = str(db.db_path) # To convert Path to string
|
||||
for line in lines:
|
||||
if log_name not in ('fblog_diff_sweep', 'fblog_diff_validate') or line.startswith('+') and PATTERN.search(line):
|
||||
if filename[:MINIMAL_LEN_TO_SHOW].upper() in line.upper():
|
||||
print(f'{log_name} : found at least {str(MINIMAL_LEN_TO_SHOW)} characters')
|
||||
return
|
||||
elif filename[:128].upper() in line.upper():
|
||||
print(f'{log_name} : found truncated DB name.')
|
||||
return
|
||||
print(f'{log_name} : DB NAME NOT FOUND')
|
||||
|
||||
tmp_6248.backup_259 : found truncated DB name.
|
||||
tmp_6248.ddl_259 : found at least 255 characters
|
||||
tmp_6248.fblog_diff_sweep_259 : found at least 255 characters
|
||||
tmp_6248.fblog_diff_validate_259 : found at least 255 characters
|
||||
tmp_6248.gstat_259 : found truncated DB name.
|
||||
tmp_6248.restore_259 : found truncated DB name.
|
||||
"""
|
||||
|
||||
@pytest.mark.version('>=4.0')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
|
||||
|
||||
@pytest.mark.parametrize('test_db', [pytest.param((255, 'abc255def'), id='255'),
|
||||
pytest.param((259, 'qwe259rty'), id='259')], indirect=True)
|
||||
def test_1(act_1: Action, test_db: Database, capsys):
|
||||
# INIT test
|
||||
act_1.isql(switches=['-q', test_db.dsn], input=init_script_1, connect_db=False)
|
||||
check_filename_presence(act_1.stdout.splitlines(), log_name='ddl', db=test_db)
|
||||
# GBAK BACKUP test
|
||||
backup_name = test_db.db_path.with_name(f"tmp_6248_backup_{len(test_db.db_path.with_suffix('').name)}.fbk")
|
||||
act_1.reset()
|
||||
act_1.gbak(switches=['-b', '-se', 'localhost:servce_mgr', '-v', '-st', 'tdwr', str(test_db.db_path), str(backup_name)])
|
||||
check_filename_presence(act_1.stdout.splitlines(), log_name='backup', db=test_db)
|
||||
# GBAK RESTORE test
|
||||
act_1.reset()
|
||||
act_1.gbak(switches=['-rep', '-se', 'localhost:servce_mgr', '-v', '-st', 'tdwr', str(backup_name), str(test_db.db_path)])
|
||||
check_filename_presence(act_1.stdout.splitlines(), log_name='restore', db=test_db)
|
||||
# GSTAT test
|
||||
act_1.reset()
|
||||
act_1.gstat(switches=['-h', test_db.dsn], connect_db=False)
|
||||
check_filename_presence(act_1.stdout.splitlines(), log_name='gstat', db=test_db)
|
||||
# SWEEP test
|
||||
log_before = act_1.get_firebird_log()
|
||||
with act_1.connect_server() as srv:
|
||||
srv.database.sweep(database=test_db.db_path)
|
||||
time.sleep(1) # Let firebird.log to be fulfilled with text about just finished SWEEP
|
||||
log_after = act_1.get_firebird_log()
|
||||
check_filename_presence(list(unified_diff(log_before, log_after)), log_name='fblog_diff_sweep', db=test_db)
|
||||
# VALIDATE test
|
||||
log_before = act_1.get_firebird_log()
|
||||
with act_1.connect_server() as srv:
|
||||
srv.database.repair(database=test_db.db_path, flags=SrvRepairFlag.FULL | SrvRepairFlag.VALIDATE_DB)
|
||||
time.sleep(1) # Let firebird.log to be fulfilled with text about just finished VALIDATION
|
||||
log_after = act_1.get_firebird_log()
|
||||
check_filename_presence(list(unified_diff(log_before, log_after)), log_name='fblog_diff_validate', db=test_db)
|
||||
# Check
|
||||
act_1.reset()
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
act_1.stdout = capsys.readouterr().out
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
@ -2,28 +2,30 @@
|
||||
#
|
||||
# id: bugs.core_6250
|
||||
# title: Signature mismatch when creating package body on identical packaged procedure header
|
||||
# decription:
|
||||
# decription:
|
||||
# Thank Adriano for suggestion.
|
||||
# Bug existed because backup/restore process changed value of RDB$PROCEDURE_PARAMETERS.RDB$NULL_FLAG
|
||||
# for procedure parameter from NULL to 0 (zero).
|
||||
# Test creates trivial package and stores its package body in variable that will be used after b/r.
|
||||
# Then we do backup / restore and attempt to apply this stored package body again, see 'sql_pk_body'.
|
||||
#
|
||||
#
|
||||
# Confirmed bug on: 4.0.0.1766, 3.0.6.33247. Attempt to apply 'recreate package ...' with the same SQL code fails with:
|
||||
# Statement failed, SQLSTATE = 42000 / ... / -Procedure ... has a signature mismatch on package body ...
|
||||
# Bug was partially fixed in snapshots 4.0.0.1782 and 3.0.6.33252: problem remained if procedure parameter was of built-in
|
||||
# datatype rather than domain (i.e. this parameter type was TIMESTAMP or INT etc, instead of apropriate domain).
|
||||
#
|
||||
#
|
||||
# Completely fixed in snapshots 4.0.0.1783 and 3.0.6.33254 (checked 23.02.2020).
|
||||
# Added special check for parameter that is declared of built-in datatype rather than domain.
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-6250
|
||||
# min_versions: ['3.0.6']
|
||||
# versions: 3.0.6
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
from io import BytesIO
|
||||
from pathlib import Path
|
||||
from firebird.qa import db_factory, python_act, Action, temp_file
|
||||
|
||||
# version: 3.0.6
|
||||
# resources: None
|
||||
@ -36,40 +38,40 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
|
||||
# test_script_1
|
||||
#---
|
||||
#
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# import time
|
||||
# import subprocess
|
||||
# from fdb import services
|
||||
# from subprocess import PIPE
|
||||
#
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
#
|
||||
#
|
||||
# dba_privileged_name = 'tmp_c6250_cooldba'
|
||||
# non_privileged_name = 'tmp_c6250_manager'
|
||||
#
|
||||
#
|
||||
# this_db = db_conn.database_name
|
||||
# db_conn.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def flush_and_close( file_handle ):
|
||||
# # https://docs.python.org/2/library/os.html#os.fsync
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
|
||||
# global os
|
||||
#
|
||||
#
|
||||
# file_handle.flush()
|
||||
# if file_handle.mode not in ('r', 'rb') and file_handle.name != os.devnull:
|
||||
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
|
||||
# os.fsync(file_handle.fileno())
|
||||
# file_handle.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def cleanup( f_names_list ):
|
||||
# global os
|
||||
# for f in f_names_list:
|
||||
@ -80,17 +82,17 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# else:
|
||||
# print('Unrecognized type of element:', f, ' - can not be treated as file.')
|
||||
# del_name = None
|
||||
#
|
||||
#
|
||||
# if del_name and os.path.isfile( del_name ):
|
||||
# os.remove( del_name )
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# fdb_rest = os.path.join(context['temp_directory'],'tmp_6250_restored.fdb')
|
||||
#
|
||||
#
|
||||
# cleanup( (fdb_rest,) )
|
||||
#
|
||||
# # This part of DDL will be used twise:
|
||||
#
|
||||
# # This part of DDL will be used twice:
|
||||
# sql_pk_body = '''
|
||||
# set term ^;
|
||||
# recreate package body pg_test1 as
|
||||
@ -105,7 +107,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# ^
|
||||
# set term ;^
|
||||
# '''
|
||||
#
|
||||
#
|
||||
# sql_init = '''
|
||||
# create domain dm_dts timestamp;
|
||||
# commit;
|
||||
@ -121,34 +123,34 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# end
|
||||
# ^
|
||||
# set term ;^
|
||||
#
|
||||
#
|
||||
# %(sql_pk_body)s
|
||||
#
|
||||
#
|
||||
# commit;
|
||||
# ''' % dict(globals(), **locals())
|
||||
#
|
||||
#
|
||||
# runProgram('isql',[ 'localhost:' + this_db ], sql_init )
|
||||
#
|
||||
#
|
||||
# # https://docs.python.org/2/library/subprocess.html#replacing-shell-pipeline
|
||||
# # gbak -b localhost:$fdb_init stdout | gbak -rep stdin localhost:$fdb_rest
|
||||
#
|
||||
#
|
||||
# p_sender = subprocess.Popen( [ context['gbak_path'], '-b', 'localhost:' + this_db, 'stdout' ], stdout=PIPE)
|
||||
# p_getter = subprocess.Popen( [ context['gbak_path'], '-c', 'stdin', 'localhost:' + fdb_rest ], stdin = p_sender.stdout, stdout = PIPE )
|
||||
# p_sender.stdout.close()
|
||||
# p_getter_stdout, p_getter_stderr = p_getter.communicate()
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# f_sql_pk_body = open( os.path.join(context['temp_directory'],'tmp_core_6250_run.sql'), 'w', buffering = 0)
|
||||
# f_sql_pk_body.write( sql_pk_body )
|
||||
# flush_and_close( f_sql_pk_body )
|
||||
#
|
||||
#
|
||||
# f_run_pk_body_log = open( '.'.join( (os.path.splitext( f_sql_pk_body.name )[0], 'log') ), 'w', buffering = 0)
|
||||
# f_run_pk_body_err = open( '.'.join( (os.path.splitext( f_sql_pk_body.name )[0], 'err') ), 'w', buffering = 0)
|
||||
# subprocess.call( [ context['isql_path'], 'localhost:' + fdb_rest, '-q', '-i', f_sql_pk_body.name ], stdout = f_run_pk_body_log, stderr = f_run_pk_body_err)
|
||||
# flush_and_close( f_run_pk_body_log )
|
||||
# flush_and_close( f_run_pk_body_err )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# # Check for UNEXPECTED output:
|
||||
# #############################
|
||||
# for g in ( f_run_pk_body_log, f_run_pk_body_err):
|
||||
@ -156,20 +158,64 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# for line in f:
|
||||
# if line.strip():
|
||||
# print( 'UNEXPECTED ' +('STDOUT' if g == f_run_pk_body_log else 'STDERR')+ ': ' + line )
|
||||
#
|
||||
#
|
||||
# # Cleanup
|
||||
# #########
|
||||
# time.sleep(1)
|
||||
# cleanup( [ i.name for i in ( f_sql_pk_body, f_run_pk_body_log, f_run_pk_body_err, ) ] + [ fdb_rest, ] )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
sql_pk_body = """
|
||||
set term ^;
|
||||
recreate package body pg_test1 as
|
||||
begin
|
||||
procedure sp_test1 ( a_since dm_dts ) as begin end
|
||||
end
|
||||
^
|
||||
recreate package body pg_test2 as
|
||||
begin
|
||||
procedure sp_test2 ( a_since timestamp ) as begin end
|
||||
end
|
||||
^
|
||||
set term ;^
|
||||
"""
|
||||
|
||||
sql_init = f"""
|
||||
create domain dm_dts timestamp;
|
||||
commit;
|
||||
set term ^;
|
||||
create or alter package pg_test1 as
|
||||
begin
|
||||
procedure sp_test1 ( a_since dm_dts ) ;
|
||||
end
|
||||
^
|
||||
create or alter package pg_test2 as
|
||||
begin
|
||||
procedure sp_test2 ( a_since timestamp ) ;
|
||||
end
|
||||
^
|
||||
set term ;^
|
||||
|
||||
{sql_pk_body}
|
||||
|
||||
commit;
|
||||
"""
|
||||
|
||||
fdb_restored = temp_file('tmp_6250_restored.fdb')
|
||||
|
||||
@pytest.mark.version('>=3.0.6')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
|
||||
|
||||
def test_1(act_1: Action, fdb_restored: Path):
|
||||
act_1.isql(switches=[], input=sql_init)
|
||||
backup = BytesIO()
|
||||
with act_1.connect_server() as srv:
|
||||
srv.database.local_backup(database=act_1.db.db_path, backup_stream=backup)
|
||||
backup.seek(0)
|
||||
srv.database.local_restore(database=fdb_restored, backup_stream=backup)
|
||||
#
|
||||
act_1.reset()
|
||||
act_1.isql(switches=['-q', act_1.get_dsn(fdb_restored)], input=sql_pk_body, connect_db=False)
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
@ -2,14 +2,14 @@
|
||||
#
|
||||
# id: bugs.core_6262
|
||||
# title: SHOW DOMAIN/TABLE does not display character set of system objects
|
||||
# decription:
|
||||
# decription:
|
||||
# We gather all system domains which belongs to TEXT family by query to rdb$fields.
|
||||
# Then for each record from its resulset we issue statement: 'SHOW DOMAIN ... ;'
|
||||
# and write it to .SQL file. After all records will be processed, we run ISQL and
|
||||
# perform this script. Every row from its output must contain phrase 'CHARACTER SET'.
|
||||
#
|
||||
#
|
||||
# Checked on 4.0.0.1803.
|
||||
#
|
||||
#
|
||||
# ::: NB ::: additional filtering: "where f.rdb$character_set_id > 1" is needed when
|
||||
# we query rdb$fields. Otherwise we get some domains without 'CHARACTER SET' phrases
|
||||
# domains definition:
|
||||
@ -20,14 +20,14 @@
|
||||
# RDB$MESSAGE VARCHAR(1023) Nullable
|
||||
# rdb$character_set_id=1:
|
||||
# RDB$SYSTEM_PRIVILEGES BINARY(8) Nullable
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-6262
|
||||
# min_versions: ['4.0']
|
||||
# versions: 4.0
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
from firebird.qa import db_factory, python_act, Action
|
||||
|
||||
# version: 4.0
|
||||
# resources: None
|
||||
@ -40,33 +40,33 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
|
||||
# test_script_1
|
||||
#---
|
||||
#
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# import time
|
||||
# import subprocess
|
||||
# from fdb import services
|
||||
#
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def flush_and_close( file_handle ):
|
||||
# # https://docs.python.org/2/library/os.html#os.fsync
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
|
||||
# global os
|
||||
#
|
||||
#
|
||||
# file_handle.flush()
|
||||
# if file_handle.mode not in ('r', 'rb') and file_handle.name != os.devnull:
|
||||
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
|
||||
# os.fsync(file_handle.fileno())
|
||||
# file_handle.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def cleanup( f_names_list ):
|
||||
# global os
|
||||
# for f in f_names_list:
|
||||
@ -77,14 +77,14 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# else:
|
||||
# print('Unrecognized type of element:', f, ' - can not be treated as file.')
|
||||
# del_name = None
|
||||
#
|
||||
#
|
||||
# if del_name and os.path.isfile( del_name ):
|
||||
# os.remove( del_name )
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# f_sql_chk = open( os.path.join(context['temp_directory'],'tmp_6262_chk.sql'), 'w')
|
||||
#
|
||||
#
|
||||
# cur = db_conn.cursor()
|
||||
# sql='''
|
||||
# select 'show domain '|| trim(f.rdb$field_name) ||';' as show_expr
|
||||
@ -92,25 +92,25 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# where f.rdb$character_set_id > 1
|
||||
# order by f.rdb$field_name
|
||||
# '''
|
||||
#
|
||||
#
|
||||
# cur.execute(sql)
|
||||
# text_domains_count = 0
|
||||
# for r in cur:
|
||||
# f_sql_chk.write( r[0]+os.linesep )
|
||||
# text_domains_count += 1
|
||||
#
|
||||
#
|
||||
# flush_and_close( f_sql_chk )
|
||||
# db_conn.close()
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# f_sql_log = open( ''.join( (os.path.splitext(f_sql_chk.name)[0], '.log' ) ), 'w')
|
||||
# f_sql_err = open( ''.join( (os.path.splitext(f_sql_log.name)[0], '.err' ) ), 'w')
|
||||
#
|
||||
#
|
||||
# subprocess.call( [ context['isql_path'], dsn, '-i', f_sql_chk.name ], stdout = f_sql_log, stderr = f_sql_err)
|
||||
#
|
||||
#
|
||||
# flush_and_close( f_sql_log )
|
||||
# flush_and_close( f_sql_err )
|
||||
#
|
||||
#
|
||||
# # Checks:
|
||||
# #########
|
||||
# # 1. Result of STDERR must be empty:
|
||||
@ -118,11 +118,11 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# for line in f:
|
||||
# if line.split():
|
||||
# print('UNEXPECTED STDERR: '+line)
|
||||
#
|
||||
#
|
||||
# # 2. All <text_domains_count> lines in STDOUT have to contain phrase 'CHARACTER SET':
|
||||
#
|
||||
#
|
||||
# lines_with_charset, lines_without_charset = 0, 0
|
||||
#
|
||||
#
|
||||
# with open(f_sql_log.name,'r') as f:
|
||||
# for line in f:
|
||||
# if line.split():
|
||||
@ -130,30 +130,62 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# lines_with_charset += 1
|
||||
# else:
|
||||
# lines_without_charset += 1
|
||||
#
|
||||
#
|
||||
# if lines_with_charset > 0:
|
||||
# print('Number of lines with specified charset: ' + ( 'SAME AS' if lines_with_charset == text_domains_count else str(lines_with_charset)+' - LESS THEN' ) + ' NUMBER OF TEXT DOMAINS' )
|
||||
# else:
|
||||
# print('SOMETHING WAS WRONG: COULD NOT FIND ANY LINE WITH "CHARACTER SET" PHRASE')
|
||||
#
|
||||
#
|
||||
# print('Number of lines with missed charset:',lines_without_charset)
|
||||
#
|
||||
#
|
||||
# # cleanup
|
||||
# #########
|
||||
# time.sleep(1)
|
||||
# cleanup( (f_sql_chk, f_sql_log, f_sql_err ) )
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
Number of lines with specified charset: SAME AS NUMBER OF TEXT DOMAINS
|
||||
Number of lines with missed charset: 0
|
||||
"""
|
||||
"""
|
||||
|
||||
@pytest.mark.version('>=4.0')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
|
||||
def test_1(act_1: Action, capsys):
|
||||
sql = """
|
||||
select 'show domain '|| trim(f.rdb$field_name) ||';' as show_expr
|
||||
from rdb$fields f
|
||||
where f.rdb$character_set_id > 1
|
||||
order by f.rdb$field_name
|
||||
"""
|
||||
chk_script = []
|
||||
with act_1.db.connect() as con:
|
||||
c = con.cursor()
|
||||
text_domains_count = 0
|
||||
for row in c.execute(sql):
|
||||
chk_script.append(row[0])
|
||||
text_domains_count += 1
|
||||
#
|
||||
act_1.isql(switches=[], input='\n'.join(chk_script))
|
||||
# Checks
|
||||
lines_with_charset = lines_without_charset = 0
|
||||
for line in act_1.stdout.splitlines():
|
||||
if line.split():
|
||||
if 'CHARACTER SET' in line:
|
||||
lines_with_charset += 1
|
||||
else:
|
||||
lines_without_charset += 1
|
||||
#
|
||||
if lines_with_charset > 0:
|
||||
result = 'SAME AS' if lines_with_charset == text_domains_count else f'{lines_with_charset} - LESS THAN'
|
||||
print(f'Number of lines with specified charset: {result} NUMBER OF TEXT DOMAINS')
|
||||
else:
|
||||
print('SOMETHING WAS WRONG: COULD NOT FIND ANY LINE WITH "CHARACTER SET" PHRASE')
|
||||
|
||||
print('Number of lines with missed charset:', lines_without_charset)
|
||||
act_1.reset()
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
act_1.stdout = capsys.readouterr().out
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
@ -2,17 +2,19 @@
|
||||
#
|
||||
# id: bugs.core_6265
|
||||
# title: mapping rules destroyed by backup / restore
|
||||
# decription:
|
||||
# decription:
|
||||
# Confirmed bug on: 4.0.0.1796 CS; 3.0.6.33247 CS.
|
||||
# Works fine on: 4.0.0.1806 SS; 3.0.6.33272 CS.
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-6265
|
||||
# min_versions: ['3.0.6']
|
||||
# versions: 3.0.6
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
from io import BytesIO
|
||||
from pathlib import Path
|
||||
from firebird.qa import db_factory, python_act, Action, role_factory, Role, temp_file
|
||||
|
||||
# version: 3.0.6
|
||||
# resources: None
|
||||
@ -31,28 +33,28 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# import subprocess
|
||||
# from subprocess import PIPE
|
||||
# from fdb import services
|
||||
#
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
# db_conn.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def flush_and_close( file_handle ):
|
||||
# # https://docs.python.org/2/library/os.html#os.fsync
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
|
||||
# global os
|
||||
#
|
||||
#
|
||||
# file_handle.flush()
|
||||
# if file_handle.mode not in ('r', 'rb') and file_handle.name != os.devnull:
|
||||
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
|
||||
# os.fsync(file_handle.fileno())
|
||||
# file_handle.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def cleanup( f_names_list ):
|
||||
# global os
|
||||
# for f in f_names_list:
|
||||
@ -63,47 +65,47 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# else:
|
||||
# print('Unrecognized type of element:', f, ' - can not be treated as file.')
|
||||
# del_name = None
|
||||
#
|
||||
#
|
||||
# if del_name and os.path.isfile( del_name ):
|
||||
# os.remove( del_name )
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# sql_init='''
|
||||
# create role boss;
|
||||
# create mapping map_boss using plugin win_sspi from user Bill to role boss;
|
||||
# commit;
|
||||
# create view v_map as
|
||||
# select
|
||||
# rdb$map_name,
|
||||
# rdb$map_using,
|
||||
# rdb$map_plugin,
|
||||
# rdb$map_db,
|
||||
# rdb$map_from_type,
|
||||
# rdb$map_from,
|
||||
# rdb$map_to_type,
|
||||
# rdb$map_to
|
||||
# select
|
||||
# rdb$map_name,
|
||||
# rdb$map_using,
|
||||
# rdb$map_plugin,
|
||||
# rdb$map_db,
|
||||
# rdb$map_from_type,
|
||||
# rdb$map_from,
|
||||
# rdb$map_to_type,
|
||||
# rdb$map_to
|
||||
# from rdb$auth_mapping;
|
||||
# commit;
|
||||
# set list on;
|
||||
# set count on;
|
||||
# select * from v_map;
|
||||
# '''
|
||||
#
|
||||
#
|
||||
# f_init_sql = open( os.path.join(context['temp_directory'],'tmp_6265.sql'), 'w', buffering = 0)
|
||||
# f_init_sql.write( sql_init )
|
||||
# flush_and_close( f_init_sql )
|
||||
#
|
||||
#
|
||||
# f_init_log = open( '.'.join( (os.path.splitext( f_init_sql.name )[0], 'log') ), 'w', buffering = 0)
|
||||
# subprocess.call( [ context['isql_path'], dsn, '-q', '-i', f_init_sql.name ], stdout = f_init_log, stderr = subprocess.STDOUT)
|
||||
# flush_and_close( f_init_log )
|
||||
#
|
||||
#
|
||||
# this_restored_1=os.path.join(context['temp_directory'],'tmp_6265_1.tmp')
|
||||
# this_restored_2=os.path.join(context['temp_directory'],'tmp_6265_2.tmp')
|
||||
#
|
||||
#
|
||||
# cleanup( (this_restored_1, this_restored_2) )
|
||||
#
|
||||
#
|
||||
# # https://docs.python.org/2/library/subprocess.html#replacing-shell-pipeline
|
||||
# # output=`dmesg | grep hda`
|
||||
# # becomes:
|
||||
@ -112,35 +114,36 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# # p1.stdout.close() # Allow p1 to receive a SIGPIPE if p2 exits.
|
||||
# # output = p2.communicate()[0]
|
||||
# # gbak -b localhost:$fdb_init stdout | gbak -rep stdin localhost:$fdb_rest
|
||||
#
|
||||
#
|
||||
# # BACKUP-RESTORE #1:
|
||||
# # ~~~~~~~~~~~~~~~~~~
|
||||
# p_sender = subprocess.Popen( [ context['gbak_path'], '-b', dsn, 'stdout' ], stdout=PIPE)
|
||||
# p_getter = subprocess.Popen( [ context['gbak_path'], '-c', 'stdin', 'localhost:' + this_restored_1 ], stdin = p_sender.stdout, stdout = PIPE )
|
||||
# p_sender.stdout.close()
|
||||
# p_getter_stdout, p_getter_stderr = p_getter.communicate()
|
||||
#
|
||||
#
|
||||
# #---------------------------------------------------------
|
||||
#
|
||||
#
|
||||
# # BACKUP-RESTORE #2:
|
||||
# # ~~~~~~~~~~~~~~~~~~
|
||||
# p_sender = subprocess.Popen( [ context['gbak_path'], '-b', 'localhost:' + this_restored_1, 'stdout' ], stdout=PIPE)
|
||||
# p_getter = subprocess.Popen( [ context['gbak_path'], '-c', 'stdin', 'localhost:' + this_restored_2 ], stdin = p_sender.stdout, stdout = PIPE )
|
||||
# p_sender.stdout.close()
|
||||
# p_getter_stdout, p_getter_stderr = p_getter.communicate()
|
||||
#
|
||||
#
|
||||
# #----------------------------------------------------------
|
||||
#
|
||||
#
|
||||
# runProgram(context['isql_path'],[ 'localhost:' + this_restored_2 ], 'set list on; set count on; select * from v_map;')
|
||||
#
|
||||
#
|
||||
# # cleanup:
|
||||
# ##########
|
||||
# time.sleep(1)
|
||||
# cleanup( (this_restored_1, this_restored_2, f_init_sql, f_init_log) )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
RDB$MAP_NAME MAP_BOSS
|
||||
@ -152,11 +155,53 @@ expected_stdout_1 = """
|
||||
RDB$MAP_TO_TYPE 1
|
||||
RDB$MAP_TO BOSS
|
||||
Records affected: 1
|
||||
"""
|
||||
"""
|
||||
|
||||
init_ddl = """
|
||||
--create role boss;
|
||||
create mapping map_boss using plugin win_sspi from user Bill to role boss;
|
||||
commit;
|
||||
create view v_map as
|
||||
select
|
||||
rdb$map_name,
|
||||
rdb$map_using,
|
||||
rdb$map_plugin,
|
||||
rdb$map_db,
|
||||
rdb$map_from_type,
|
||||
rdb$map_from,
|
||||
rdb$map_to_type,
|
||||
rdb$map_to
|
||||
from rdb$auth_mapping;
|
||||
commit;
|
||||
set list on;
|
||||
set count on;
|
||||
select * from v_map;
|
||||
"""
|
||||
|
||||
boss_role = role_factory('db_1', name='boss')
|
||||
|
||||
restored_db_1 = temp_file('tmp_6265_1.fdb')
|
||||
restored_db_2 = temp_file('tmp_6265_2.fdb')
|
||||
|
||||
@pytest.mark.version('>=3.0.6')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
|
||||
|
||||
def test_1(act_1: Action, boss_role: Role, restored_db_1: Path, restored_db_2: Path):
|
||||
act_1.isql(switches=['-q'], input=init_ddl)
|
||||
#
|
||||
backup = BytesIO()
|
||||
with act_1.connect_server() as srv:
|
||||
# BACKUP-RESTORE #1:
|
||||
srv.database.local_backup(database=act_1.db.db_path, backup_stream=backup)
|
||||
backup.seek(0)
|
||||
srv.database.local_restore(database=restored_db_1, backup_stream=backup)
|
||||
# BACKUP-RESTORE #2:
|
||||
backup.seek(0)
|
||||
backup.truncate()
|
||||
srv.database.local_backup(database=restored_db_1, backup_stream=backup)
|
||||
backup.seek(0)
|
||||
srv.database.local_restore(database=restored_db_2, backup_stream=backup)
|
||||
# Check
|
||||
act_1.reset()
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
act_1.isql(switches=[act_1.get_dsn(restored_db_2)], connect_db=False,
|
||||
input='set list on; set count on; select * from v_map;')
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
@ -2,19 +2,21 @@
|
||||
#
|
||||
# id: bugs.core_6266
|
||||
# title: Deleting records from MON$ATTACHMENTS using ORDER BY clause doesn't close the corresponding attachments
|
||||
# decription:
|
||||
# decription:
|
||||
# Old title: Don't close attach while deleting record from MON$ATTACHMENTS using ORDER BY clause.
|
||||
# Confirmed bug on 3.0.6.33271.
|
||||
# Checked on 3.0.6.33272 (SS/CS) - works fine.
|
||||
# 22.04.2020. Checked separately on 4.0.0.1931 SS/CS: all OK. FB 4.0 can also be tested since this build.
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-6266
|
||||
# min_versions: ['3.0.0']
|
||||
# versions: 3.0
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
import time
|
||||
from firebird.qa import db_factory, python_act, Action
|
||||
from firebird.driver import DatabaseError
|
||||
|
||||
# version: 3.0
|
||||
# resources: None
|
||||
@ -31,41 +33,41 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# import sys
|
||||
# import time
|
||||
# import fdb
|
||||
#
|
||||
#
|
||||
# ATT_CNT=5
|
||||
# ATT_DELAY=1
|
||||
#
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
#
|
||||
#
|
||||
# db_conn.close()
|
||||
#
|
||||
#
|
||||
# con_list={}
|
||||
# for i in range(0, ATT_CNT):
|
||||
# if i > 0:
|
||||
# time.sleep( ATT_DELAY )
|
||||
#
|
||||
#
|
||||
# c = fdb.connect(dsn = dsn)
|
||||
# a = c.attachment_id
|
||||
# con_list[ i ] = (a, c)
|
||||
# # print('created attachment ', (a,c) )
|
||||
#
|
||||
#
|
||||
# con_admin = con_list[0][1]
|
||||
#
|
||||
#
|
||||
# #print(con_admin.firebird_version)
|
||||
#
|
||||
#
|
||||
# # this removes ALL connections --> should NOT be used for reproducing ticket issue:
|
||||
# #con_admin.execute_immediate('delete from mon$attachments where mon$attachment_id != current_connection order by mon$timestamp')
|
||||
#
|
||||
#
|
||||
# # this removes ALL connections --> should NOT be used for reproducing ticket issue:
|
||||
# #con_admin.execute_immediate('delete from mon$attachments where mon$system_flag is distinct from 1 and mon$attachment_id != current_connection order by mon$timestamp')
|
||||
#
|
||||
#
|
||||
# # This DOES NOT remove all attachments (only 'last' in order of timestamp), but
|
||||
# # DELETE statement must NOT contain phrase 'mon$attachment_id != current_connection':
|
||||
# con_admin.execute_immediate('delete from mon$attachments where mon$system_flag is distinct from 1 order by mon$timestamp')
|
||||
#
|
||||
#
|
||||
# con_admin.commit()
|
||||
#
|
||||
#
|
||||
# cur_admin = con_admin.cursor()
|
||||
# cur_admin.execute('select mon$attachment_id,mon$user from mon$attachments where mon$system_flag is distinct from 1 and mon$attachment_id != current_connection' )
|
||||
# i=0
|
||||
@ -73,11 +75,11 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# print( '### ACHTUNG ### STILL ALIVE ATTACHMENT DETECTED: ', r[0], r[1].strip(), '###' )
|
||||
# i += 1
|
||||
# print('Number of attachments that remains alive: ',i)
|
||||
#
|
||||
#
|
||||
# cur_admin.close()
|
||||
#
|
||||
#
|
||||
# #print('Final cleanup before quit from Python.')
|
||||
#
|
||||
#
|
||||
# for k,v in sorted( con_list.items() ):
|
||||
# #print('attempt to close attachment ', v[0] )
|
||||
# try:
|
||||
@ -87,18 +89,45 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# pass
|
||||
# #print('Got exception:', sys.exc_info()[0])
|
||||
# #print(e[0])
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
Number of attachments that remains alive: 0
|
||||
"""
|
||||
Number of attachments that remains alive: 0
|
||||
"""
|
||||
|
||||
@pytest.mark.version('>=3.0')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
|
||||
|
||||
def test_1(act_1: Action, capsys):
|
||||
ATT_CNT = 5
|
||||
ATT_DELAY = 1
|
||||
#
|
||||
con_list = []
|
||||
for i in range(ATT_CNT):
|
||||
if i > 0:
|
||||
time.sleep(ATT_DELAY)
|
||||
con_list.append(act_1.db.connect())
|
||||
con_admin = con_list[0]
|
||||
# This DOES NOT remove all attachments (only 'last' in order of timestamp), but
|
||||
# DELETE statement must NOT contain phrase 'mon$attachment_id != current_connection':
|
||||
con_admin.execute_immediate('delete from mon$attachments where mon$system_flag is distinct from 1 order by mon$timestamp')
|
||||
con_admin.commit()
|
||||
#
|
||||
cur_admin = con_admin.cursor()
|
||||
cur_admin.execute('select mon$attachment_id,mon$user from mon$attachments where mon$system_flag is distinct from 1 and mon$attachment_id != current_connection')
|
||||
i = 0
|
||||
for r in cur_admin:
|
||||
print('STILL ALIVE ATTACHMENT DETECTED: ', r[0], r[1].strip())
|
||||
i += 1
|
||||
print(f'Number of attachments that remains alive: {i}')
|
||||
for con in con_list:
|
||||
try:
|
||||
con.close()
|
||||
except DatabaseError:
|
||||
pass
|
||||
# Check
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
act_1.stdout = capsys.readouterr().out
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
@ -2,14 +2,14 @@
|
||||
#
|
||||
# id: bugs.core_6272
|
||||
# title: Failed attach to database not traced
|
||||
# decription:
|
||||
# decription:
|
||||
# NB: connect to services must be done using LOCAL protocol rather than remote.
|
||||
# Otherwise trace log will have only records about connect/disconnect to security.db.
|
||||
# NO messages about failed search of non-existing database will appear.
|
||||
# This is known bug, see Alex's issue in the tracker, 07-apr-2020 10:39.
|
||||
#
|
||||
#
|
||||
# Checked on 4.0.0.1865 SS/CS.
|
||||
#
|
||||
#
|
||||
# 04-mar-2021.
|
||||
# Adapted to be run both on Windows and Linux.
|
||||
# NOTE-1. There is difference between Windows and Linux message for gdscode = 335544344:
|
||||
@ -18,14 +18,17 @@
|
||||
# NOTE-2. Some messages can appear in the trace log ONE or TWO times (SS/CS ?).
|
||||
# Because of this, we are interested only for at least one occurence of each message
|
||||
# rather than for each of them (see 'found_patterns', type: set()).
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-6272
|
||||
# min_versions: ['4.0.0']
|
||||
# versions: 4.0
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
import re
|
||||
from pathlib import Path
|
||||
from firebird.qa import db_factory, python_act, Action, Database, temp_file, ServerKeeper
|
||||
from firebird.driver import DatabaseError
|
||||
|
||||
# version: 4.0
|
||||
# resources: None
|
||||
@ -35,41 +38,43 @@ substitutions_1 = []
|
||||
init_script_1 = """"""
|
||||
|
||||
db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
db_1_nonexistent = db_factory(sql_dialect=3, filename='does_not_exists',
|
||||
do_not_create=True, do_not_drop=True)
|
||||
|
||||
# test_script_1
|
||||
#---
|
||||
#
|
||||
#
|
||||
# import os
|
||||
# import subprocess
|
||||
# import time
|
||||
# import re
|
||||
# from fdb import services
|
||||
# from subprocess import Popen
|
||||
#
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
#
|
||||
#
|
||||
# # Obtain engine version:
|
||||
# engine = str(db_conn.engine_version) # convert to text because 'float' object has no attribute 'startswith'
|
||||
# db_conn.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def flush_and_close( file_handle ):
|
||||
# # https://docs.python.org/2/library/os.html#os.fsync
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
|
||||
# global os
|
||||
#
|
||||
#
|
||||
# file_handle.flush()
|
||||
# if file_handle.mode not in ('r', 'rb') and file_handle.name != os.devnull:
|
||||
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
|
||||
# os.fsync(file_handle.fileno())
|
||||
# file_handle.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def cleanup( f_names_list ):
|
||||
# global os
|
||||
# for f in f_names_list:
|
||||
@ -80,12 +85,12 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# else:
|
||||
# print('Unrecognized type of element:', f, ' - can not be treated as file.')
|
||||
# del_name = None
|
||||
#
|
||||
#
|
||||
# if del_name and os.path.isfile( del_name ):
|
||||
# os.remove( del_name )
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# txt = '''
|
||||
# database
|
||||
# {
|
||||
@ -95,35 +100,35 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# log_initfini = false
|
||||
# }
|
||||
# '''
|
||||
#
|
||||
#
|
||||
# f_trc_cfg=open( os.path.join(context['temp_directory'],'tmp_trace_6272.cfg'), 'w')
|
||||
# f_trc_cfg.write(txt)
|
||||
# flush_and_close( f_trc_cfg )
|
||||
#
|
||||
#
|
||||
# # ##############################################################
|
||||
# # S T A R T T R A C E i n S E P A R A T E P R O C E S S
|
||||
# # ##############################################################
|
||||
#
|
||||
#
|
||||
# f_trc_log=open( os.path.join(context['temp_directory'],'tmp_trace_6272.log'), "w")
|
||||
# f_trc_err=open( os.path.join(context['temp_directory'],'tmp_trace_6272.err'), "w")
|
||||
#
|
||||
#
|
||||
# # ::: NB ::: DO NOT USE 'localhost:service_mgr' here! Use only local protocol:
|
||||
# p_trace = Popen( [ context['fbsvcmgr_path'], 'service_mgr', 'action_trace_start' , 'trc_cfg', f_trc_cfg.name],stdout=f_trc_log,stderr=f_trc_err)
|
||||
#
|
||||
#
|
||||
# time.sleep(1)
|
||||
#
|
||||
#
|
||||
# # ####################################################
|
||||
# # G E T A C T I V E T R A C E S E S S I O N I D
|
||||
# # ####################################################
|
||||
# # Save active trace session info into file for further parsing it and obtain session_id back (for stop):
|
||||
#
|
||||
#
|
||||
# f_trc_lst = open( os.path.join(context['temp_directory'],'tmp_trace_6272.lst'), 'w')
|
||||
# subprocess.call([ context['fbsvcmgr_path'], 'localhost:service_mgr', 'action_trace_list'], stdout=f_trc_lst)
|
||||
# flush_and_close( f_trc_lst )
|
||||
#
|
||||
#
|
||||
# # !!! DO NOT REMOVE THIS LINE !!!
|
||||
# time.sleep(1)
|
||||
#
|
||||
#
|
||||
# trcssn=0
|
||||
# with open( f_trc_lst.name,'r') as f:
|
||||
# for line in f:
|
||||
@ -134,22 +139,22 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# trcssn=word
|
||||
# i=i+1
|
||||
# break
|
||||
#
|
||||
#
|
||||
# # Result: `trcssn` is ID of active trace session. Now we have to terminate it:
|
||||
#
|
||||
#
|
||||
# #------------------------------------------------
|
||||
#
|
||||
#
|
||||
# try:
|
||||
# con = fdb.connect(dsn = 'localhost:non_such_alias')
|
||||
# except Exception,e:
|
||||
# # print('Error:', e)
|
||||
# pass
|
||||
#
|
||||
#
|
||||
# #------------------------------------------------
|
||||
#
|
||||
#
|
||||
# # Let trace log to be entirely written on disk:
|
||||
# time.sleep(1)
|
||||
#
|
||||
#
|
||||
# # ####################################################
|
||||
# # S E N D R E Q U E S T T R A C E T O S T O P
|
||||
# # ####################################################
|
||||
@ -159,49 +164,84 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# fn_nul.close()
|
||||
# # DO NOT REMOVE THIS LINE:
|
||||
# time.sleep(1)
|
||||
#
|
||||
#
|
||||
# p_trace.terminate()
|
||||
# flush_and_close( f_trc_log )
|
||||
# flush_and_close( f_trc_err )
|
||||
#
|
||||
#
|
||||
# # Every of following patterns must be found at *least* one time in the trace log:
|
||||
# allowed_patterns = [
|
||||
# allowed_patterns = [
|
||||
# re.compile('FAILED\\s+ATTACH_DATABASE', re.IGNORECASE)
|
||||
# ,re.compile('ERROR\\s+AT\\s+JProvider(:){1,2}attachDatabase', re.IGNORECASE)
|
||||
# # ::: NB ::: windows and linux messages *differ* for this gdscode:
|
||||
# ,re.compile('335544344\\s*(:)?\\s+I(/)?O\\s+error', re.IGNORECASE)
|
||||
# ,re.compile('335544344\\s*(:)?\\s+I(/)?O\\s+error', re.IGNORECASE)
|
||||
# ,re.compile('335544734\\s*(:)\\s+?Error\\s+while', re.IGNORECASE)
|
||||
# ]
|
||||
# found_patterns = set()
|
||||
#
|
||||
#
|
||||
# with open(f_trc_log.name, 'r') as f:
|
||||
# for line in f:
|
||||
# for p in allowed_patterns:
|
||||
# if p.search(line):
|
||||
# found_patterns.add( p.pattern )
|
||||
#
|
||||
#
|
||||
# # cleanup:
|
||||
# ##########
|
||||
# time.sleep(1)
|
||||
# cleanup( ( f_trc_log, f_trc_err, f_trc_cfg, f_trc_lst ) )
|
||||
#
|
||||
#
|
||||
# for p in sorted(found_patterns):
|
||||
# print('FOUND pattern: ' + p)
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
FOUND pattern: 335544344\\s*(:)?\\s+I(/)?O\\s+error
|
||||
FOUND pattern: 335544734\\s*(:)\\s+?Error\\s+while
|
||||
FOUND pattern: ERROR\\s+AT\\s+JProvider(:){1,2}attachDatabase
|
||||
FOUND pattern: FAILED\\s+ATTACH_DATABASE
|
||||
"""
|
||||
"""
|
||||
|
||||
trace_1 = """
|
||||
database
|
||||
{
|
||||
enabled = true
|
||||
log_connections = true
|
||||
log_errors = true
|
||||
log_initfini = false
|
||||
}
|
||||
""".splitlines()
|
||||
|
||||
trace_conf = temp_file('trace.conf')
|
||||
|
||||
@pytest.mark.version('>=4.0')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
|
||||
|
||||
def test_1(act_1: Action, db_1_nonexistent: Database, trace_conf: Path, capsys):
|
||||
with ServerKeeper(act_1, None): # User embedded server for trace
|
||||
with act_1.trace(config=trace_1):
|
||||
try:
|
||||
with db_1_nonexistent.connect():
|
||||
pass
|
||||
except DatabaseError:
|
||||
pass
|
||||
# Process trace
|
||||
# Every of following patterns must be found at *least* once in the trace log:
|
||||
allowed_patterns = [re.compile('FAILED\\s+ATTACH_DATABASE', re.IGNORECASE),
|
||||
re.compile('ERROR\\s+AT\\s+JProvider(:){1,2}attachDatabase', re.IGNORECASE),
|
||||
# ::: NB ::: windows and linux messages *differ* for this gdscode:
|
||||
re.compile('335544344\\s*(:)?\\s+I(/)?O\\s+error', re.IGNORECASE),
|
||||
re.compile('335544734\\s*(:)\\s+?Error\\s+while', re.IGNORECASE),
|
||||
]
|
||||
found_patterns = set()
|
||||
for line in act_1.trace_log:
|
||||
for p in allowed_patterns:
|
||||
if p.search(line):
|
||||
found_patterns.add(p.pattern)
|
||||
for p in sorted(found_patterns):
|
||||
print(f'FOUND pattern: {p}')
|
||||
# Check
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
act_1.stdout = capsys.readouterr().out
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
@ -2,7 +2,7 @@
|
||||
#
|
||||
# id: bugs.core_6278
|
||||
# title: Efficient table scans for DBKEY-based range conditions
|
||||
# decription:
|
||||
# decription:
|
||||
# We create table with very wide column and add there about 300 rows from rdb$types, with random data
|
||||
# (in order to prevent RLE-compression which eventually can reduce number of data pages).
|
||||
# Then we extract all values of rdb$db_key from this table and take into processing two of them.
|
||||
@ -10,21 +10,22 @@
|
||||
# distance from final db_key.
|
||||
# Finally we launch trace and start query with SCOPED expression for RDB$DB_KEY:
|
||||
# select count(*) from tmp_test_6278 where rdb$db_key between ? and ?
|
||||
#
|
||||
#
|
||||
# Trace must contain after this explained plan with "lower bound, upper bound" phrase and table statistics
|
||||
# which shows number of reads = count of rows plus 1.
|
||||
# ::: NOTE:::
|
||||
# Before fix trace table statistics did not reflect scoped WHERE-expression on RDB$DB_KEY column.
|
||||
#
|
||||
#
|
||||
# Checked on 4.0.0.1869 - works fine.
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-6278
|
||||
# min_versions: ['4.0.0']
|
||||
# versions: 4.0
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
import re
|
||||
from firebird.qa import db_factory, python_act, Action
|
||||
|
||||
# version: 4.0
|
||||
# resources: None
|
||||
@ -37,35 +38,35 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
|
||||
# test_script_1
|
||||
#---
|
||||
#
|
||||
#
|
||||
# import os
|
||||
# import subprocess
|
||||
# import time
|
||||
# import re
|
||||
# from fdb import services
|
||||
# from subprocess import Popen
|
||||
#
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
# db_conn.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def flush_and_close( file_handle ):
|
||||
# # https://docs.python.org/2/library/os.html#os.fsync
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
|
||||
# global os
|
||||
#
|
||||
#
|
||||
# file_handle.flush()
|
||||
# if file_handle.mode not in ('r', 'rb') and file_handle.name != os.devnull:
|
||||
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
|
||||
# os.fsync(file_handle.fileno())
|
||||
# file_handle.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def cleanup( f_names_list ):
|
||||
# global os
|
||||
# for f in f_names_list:
|
||||
@ -76,12 +77,12 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# else:
|
||||
# print('Unrecognized type of element:', f, ' - can not be treated as file.')
|
||||
# del_name = None
|
||||
#
|
||||
#
|
||||
# if del_name and os.path.isfile( del_name ):
|
||||
# os.remove( del_name )
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# txt = '''
|
||||
# database=%[\\\\\\\\/]security?.fdb
|
||||
# {
|
||||
@ -94,45 +95,45 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# time_threshold = 0
|
||||
# log_errors = false
|
||||
# log_statement_finish = true
|
||||
#
|
||||
#
|
||||
# exclude_filter = "%(execute block)%"
|
||||
# include_filter = "%(select count)%"
|
||||
#
|
||||
#
|
||||
# #log_statement_prepare = true
|
||||
# print_perf = true
|
||||
# print_plan = true
|
||||
# explain_plan = true
|
||||
# }
|
||||
# '''
|
||||
#
|
||||
#
|
||||
# f_trc_cfg=open( os.path.join(context['temp_directory'],'tmp_trace_6278.cfg'), 'w', buffering = 0)
|
||||
# f_trc_cfg.write(txt)
|
||||
# flush_and_close( f_trc_cfg )
|
||||
#
|
||||
#
|
||||
# # ##############################################################
|
||||
# # S T A R T T R A C E i n S E P A R A T E P R O C E S S
|
||||
# # ##############################################################
|
||||
#
|
||||
#
|
||||
# f_trc_log=open( os.path.join(context['temp_directory'],'tmp_trace_6278.log'), "w", buffering = 0)
|
||||
# f_trc_err=open( os.path.join(context['temp_directory'],'tmp_trace_6278.err'), "w", buffering = 0)
|
||||
#
|
||||
#
|
||||
# # ::: NB ::: DO NOT USE 'localhost:service_mgr' here! Use only local protocol:
|
||||
# p_trace = Popen( [ context['fbsvcmgr_path'], 'service_mgr', 'action_trace_start' , 'trc_cfg', f_trc_cfg.name],stdout=f_trc_log,stderr=f_trc_err)
|
||||
#
|
||||
#
|
||||
# time.sleep(1)
|
||||
#
|
||||
#
|
||||
# # ####################################################
|
||||
# # G E T A C T I V E T R A C E S E S S I O N I D
|
||||
# # ####################################################
|
||||
# # Save active trace session info into file for further parsing it and obtain session_id back (for stop):
|
||||
#
|
||||
#
|
||||
# f_trc_lst = open( os.path.join(context['temp_directory'],'tmp_trace_6278.lst'), 'w', buffering = 0)
|
||||
# subprocess.call([ context['fbsvcmgr_path'], 'localhost:service_mgr', 'action_trace_list'], stdout=f_trc_lst)
|
||||
# flush_and_close( f_trc_lst )
|
||||
#
|
||||
#
|
||||
# # !!! DO NOT REMOVE THIS LINE !!!
|
||||
# time.sleep(1)
|
||||
#
|
||||
#
|
||||
# trcssn=0
|
||||
# with open( f_trc_lst.name,'r') as f:
|
||||
# for line in f:
|
||||
@ -143,9 +144,9 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# trcssn=word
|
||||
# i=i+1
|
||||
# break
|
||||
#
|
||||
#
|
||||
# # Result: `trcssn` is ID of active trace session. Now we have to terminate it:
|
||||
#
|
||||
#
|
||||
# #------------------------------------------------
|
||||
# sql = '''
|
||||
# recreate table tmp_test_6278(s varchar(32700));
|
||||
@ -173,9 +174,9 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# where
|
||||
# ra = (ra+rd)/3
|
||||
# or rd = (ra+rd)/3
|
||||
# ) x
|
||||
# ) x
|
||||
# into dbkey_1, dbkey_2;
|
||||
#
|
||||
#
|
||||
# sttm = q'{select count(*) from tmp_test_6278 where rdb$db_key between ? and ?}';
|
||||
# execute statement (sttm) (dbkey_1, dbkey_2) into count_intermediate_rows;
|
||||
# suspend;
|
||||
@ -184,14 +185,14 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# set term ;^
|
||||
# commit;
|
||||
# '''
|
||||
#
|
||||
#
|
||||
# f_sql_cmd=open( os.path.join(context['temp_directory'],'tmp_c6278_run.sql'), 'w')
|
||||
# f_sql_cmd.write(sql)
|
||||
# flush_and_close( f_sql_cmd )
|
||||
#
|
||||
#
|
||||
# f_isql_log=open( os.path.join(context['temp_directory'],'tmp_c6278_run.log'), 'w', buffering = 0)
|
||||
# f_isql_err=open( os.path.join(context['temp_directory'],'tmp_c6278_run.err'), 'w', buffering = 0)
|
||||
#
|
||||
#
|
||||
# ######################
|
||||
# # S T A R T I S Q L
|
||||
# ######################
|
||||
@ -201,12 +202,12 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# )
|
||||
# flush_and_close( f_isql_log )
|
||||
# flush_and_close( f_isql_err )
|
||||
#
|
||||
#
|
||||
# #------------------------------------------------
|
||||
#
|
||||
#
|
||||
# # Let trace log to be entirely written on disk:
|
||||
# time.sleep(1)
|
||||
#
|
||||
#
|
||||
# # ####################################################
|
||||
# # S E N D R E Q U E S T T R A C E T O S T O P
|
||||
# # ####################################################
|
||||
@ -216,37 +217,37 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# fn_nul.close()
|
||||
# # DO NOT REMOVE THIS LINE:
|
||||
# time.sleep(1)
|
||||
#
|
||||
#
|
||||
# p_trace.terminate()
|
||||
# flush_and_close( f_trc_log )
|
||||
# flush_and_close( f_trc_err )
|
||||
#
|
||||
#
|
||||
# allowed_patterns = [
|
||||
#
|
||||
#
|
||||
# allowed_patterns = [
|
||||
# re.compile(' Table "TMP_TEST_6278"', re.IGNORECASE)
|
||||
# ,re.compile('TMP_TEST_6278\\s+\\d+', re.IGNORECASE)
|
||||
# ]
|
||||
#
|
||||
#
|
||||
# #----------------------------------------------------------------------
|
||||
#
|
||||
#
|
||||
# # Parse STDOUT result of ISQL: extract from log result of
|
||||
# # select count(*) from tmp_test_6278 where rdb$db_key between ? and ?.
|
||||
# # It must be ~1/3 of rows in RDB$TYPES table for empty database:
|
||||
#
|
||||
#
|
||||
# with open(f_isql_log.name, 'r') as f:
|
||||
# for line in f:
|
||||
# if line.split():
|
||||
# count_intermediate_rows = int( line.rstrip().split()[0] )
|
||||
# break
|
||||
#
|
||||
#
|
||||
# # Result of STDERR for ISQL must be empty:
|
||||
# with open(f_isql_err.name, 'r') as f:
|
||||
# for line in f:
|
||||
# if line.split():
|
||||
# print('UNEXPECTED STDERR IN ISQL RESULT: ' + line)
|
||||
#
|
||||
#
|
||||
# #---------------------------------------------------------------------
|
||||
#
|
||||
#
|
||||
# # Parse trace log:
|
||||
# # 1. Extract token from EXPLAINED plan: it must contain "lower bound, upper bound" clause that was introduced by this ticket;
|
||||
# # 2. Number of reads (currently they are shown under NATURAL read column) must be equal to result obtained in ISQL, plus 1.
|
||||
@ -262,24 +263,96 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# print( 'Reads difference: ' + ('EXPECTED.' if (trace_reads_statistics - count_intermediate_rows) <= 1 else 'UNEXPECTED: ' + str( (trace_reads_statistics - count_intermediate_rows) ) ) )
|
||||
# else:
|
||||
# print(line)
|
||||
#
|
||||
#
|
||||
# # CLEANUP:
|
||||
# ##########
|
||||
# time.sleep(1)
|
||||
# cleanup( ( f_trc_log, f_trc_err, f_trc_cfg, f_trc_lst, f_isql_log, f_isql_err, f_sql_cmd ) )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
-> Table "TMP_TEST_6278" Full Scan (lower bound, upper bound)
|
||||
Reads difference: EXPECTED.
|
||||
"""
|
||||
"""
|
||||
|
||||
test_script_1 = """
|
||||
recreate table tmp_test_6278 (s varchar(32700)) ;
|
||||
insert into tmp_test_6278 select lpad('', 32700, uuid_to_char(gen_uuid())) from rdb$types ;
|
||||
commit ;
|
||||
set heading off ;
|
||||
set term ^ ;
|
||||
execute block returns(
|
||||
count_intermediate_rows int
|
||||
) as
|
||||
declare dbkey_1 char(8) character set octets ;
|
||||
declare dbkey_2 char(8) character set octets ;
|
||||
declare sttm varchar(255) ;
|
||||
begin
|
||||
select max(iif( ri=1, dbkey, null)), max(iif( ri=2, dbkey, null))
|
||||
from (
|
||||
select dbkey, row_number()over(order by dbkey) ri
|
||||
from (
|
||||
select
|
||||
dbkey
|
||||
,row_number()over(order by dbkey) ra
|
||||
,row_number()over(order by dbkey desc) rd
|
||||
from (select rdb$db_key as dbkey from tmp_test_6278)
|
||||
)
|
||||
where
|
||||
ra = (ra+rd)/3
|
||||
or rd = (ra+rd)/3
|
||||
) x
|
||||
into dbkey_1, dbkey_2 ;
|
||||
|
||||
sttm = q'{select count(*) from tmp_test_6278 where rdb$db_key between ? and ?}' ;
|
||||
execute statement (sttm) (dbkey_1, dbkey_2) into count_intermediate_rows ;
|
||||
suspend ;
|
||||
end ^
|
||||
set term ; ^
|
||||
commit ;
|
||||
"""
|
||||
|
||||
trace_1 = ['log_statement_finish = true',
|
||||
'print_plan = true',
|
||||
'print_perf = true',
|
||||
'explain_plan = true',
|
||||
'time_threshold = 0',
|
||||
'log_initfini = false',
|
||||
'exclude_filter = "%(execute block)%"',
|
||||
'include_filter = "%(select count)%"',
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.version('>=4.0')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
|
||||
def test_1(act_1: Action, capsys):
|
||||
allowed_patterns = [re.compile(' Table "TMP_TEST_6278"', re.IGNORECASE),
|
||||
re.compile('TMP_TEST_6278\\s+\\d+', re.IGNORECASE)
|
||||
]
|
||||
|
||||
with act_1.trace(db_events=trace_1, encoding='utf8'):
|
||||
act_1.isql(switches=['-q'], input=test_script_1, charset='none')
|
||||
# Process isql output
|
||||
for line in act_1.stdout.splitlines():
|
||||
if elements := line.rstrip().split():
|
||||
print(f'{elements=}')
|
||||
count_intermediate_rows = int(elements[0])
|
||||
break
|
||||
# Process trace
|
||||
for line in act_1.trace_log:
|
||||
for p in allowed_patterns:
|
||||
if p.search(line):
|
||||
if line.startswith('TMP_TEST_6278'):
|
||||
trace_reads_statistics = int(line.rstrip().split()[1])
|
||||
result = ('EXPECTED.' if (trace_reads_statistics - count_intermediate_rows) <= 1
|
||||
else f'UNEXPECTED: {trace_reads_statistics - count_intermediate_rows}')
|
||||
print(f'Reads difference: {result}')
|
||||
else:
|
||||
print(line)
|
||||
# Check
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
act_1.stdout
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
@ -2,8 +2,8 @@
|
||||
#
|
||||
# id: bugs.core_6279
|
||||
# title: Put options in user management statements in any order
|
||||
# decription:
|
||||
# According to new syntax that is described in doc\\sql.extensions\\README.user_management, any statement that
|
||||
# decription:
|
||||
# According to new syntax that is described in doc\\sql.extensions\\README.user_management, any statement that
|
||||
# creates or modifies user, must now look like this:
|
||||
# CREATE OR ALTER USER name [ SET ] [ options ];
|
||||
# where OPTIONS is a list of following options:
|
||||
@ -15,72 +15,118 @@
|
||||
# - INACTIVE
|
||||
# - USING PLUGIN name
|
||||
# - TAGS ( tag [, tag [, tag ...]] )
|
||||
#
|
||||
#
|
||||
# We add all options from this list, except 'INACTIVE', as separate records to the table 'TSYNTAX', field: 'token'.
|
||||
# Then we generate all possible combinations of these options with requirement that each of them occurs in a generated
|
||||
# record only once (see: f_generate_sql_with_combos).
|
||||
# Query will contain 7 columns, one per each option, and we further concatenate them to the string.
|
||||
# As result, this 'suffix part' will contain all tokens in all possible places will be created.
|
||||
# Query will contain 7 columns, one per each option, and we further concatenate them to the string.
|
||||
# As result, this 'suffix part' will contain all tokens in all possible places will be created.
|
||||
# We will add this 'suffix part' to 'create or alter user ...' statement.
|
||||
#
|
||||
#
|
||||
# Finally, we redirect result of this query to a new .sql script (see: f_ddl_combinations_script) and run it.
|
||||
# NOTE: total number of 'CREATE OR ALTER USER' statements in it will be 10080.
|
||||
#
|
||||
#
|
||||
# Result of this .sql must be EMPTY: all statements have to be executed without error.
|
||||
#
|
||||
#
|
||||
# It is crusial for this test to make .sql script run within SINGLE transaction otherwise performance will suffer.
|
||||
# Also, we must inject 'SET BAIL ON;' at the start line of this script in order to make it stop when first error occurs.
|
||||
#
|
||||
#
|
||||
# Checked on 4.0.0.1876 SS/CS: OK, 6.659/7.722s
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-6279
|
||||
# min_versions: ['4.0']
|
||||
# versions: 4.0
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
from firebird.qa import db_factory, python_act, Action, user_factory, User
|
||||
|
||||
# version: 4.0
|
||||
# resources: None
|
||||
|
||||
substitutions_1 = []
|
||||
|
||||
init_script_1 = """"""
|
||||
init_script_1 = """
|
||||
recreate table tsyntax( token varchar(100) );
|
||||
commit;
|
||||
insert into tsyntax( token ) values( 'password ''bar'' ' );
|
||||
insert into tsyntax( token ) values( 'firstname ''john'' ' );
|
||||
insert into tsyntax( token ) values( 'middlename ''ozzy'' ' );
|
||||
insert into tsyntax( token ) values( 'lastname ''osbourne'' ' );
|
||||
insert into tsyntax( token ) values( 'active' );
|
||||
insert into tsyntax( token ) values( 'inactive' );
|
||||
insert into tsyntax( token ) values( 'using plugin Srp' );
|
||||
insert into tsyntax( token ) values( 'tags ( foo = ''bar'', rio = ''gee'' )' );
|
||||
commit;
|
||||
|
||||
db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
set heading off;
|
||||
select 'set bail on;' from rdb$database union all
|
||||
select 'set echo off;' from rdb$database union all
|
||||
select 'commit;' from rdb$database union all
|
||||
select 'set autoddl off;' from rdb$database union all
|
||||
select 'commit;' from rdb$database
|
||||
;
|
||||
|
||||
with
|
||||
t as (
|
||||
select *
|
||||
from tsyntax x
|
||||
where x.token not in ('inactive')
|
||||
)
|
||||
,b as (
|
||||
select trim(a.token) as a, trim(b.token) as b, trim(c.token) as c, trim(d.token) as d, trim(e.token) as e, trim(f.token) as f, trim(g.token) as g
|
||||
from t a
|
||||
left join t b on b.token not in (a.token)
|
||||
left join t c on c.token not in (a.token, b.token)
|
||||
left join t d on d.token not in (a.token, b.token, c.token)
|
||||
left join t e on e.token not in (a.token, b.token, c.token, d.token)
|
||||
left join t f on f.token not in (a.token, b.token, c.token, d.token, e.token)
|
||||
left join t g on g.token not in (a.token, b.token, c.token, d.token, e.token, f.token)
|
||||
)
|
||||
,c as (
|
||||
select a || ' ' || b || ' ' || c || ' ' || d || ' ' || e || ' ' || f || ' ' || g || ';' as ddl_expr
|
||||
from b
|
||||
)
|
||||
select 'create or alter user tmp$c6279 ' || ddl_expr from c
|
||||
union all
|
||||
select 'create or alter user tmp$c6279 ' || replace(ddl_expr, ' active', ' inactive') from c;
|
||||
|
||||
select 'rollback;' from rdb$database ;
|
||||
"""
|
||||
|
||||
db_1 = db_factory(sql_dialect=3) # init_script_1 is executed manually
|
||||
|
||||
# test_script_1
|
||||
#---
|
||||
#
|
||||
#
|
||||
# import os
|
||||
# import time
|
||||
# import subprocess
|
||||
# from subprocess import Popen
|
||||
# from fdb import services
|
||||
#
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
#
|
||||
#
|
||||
# db_conn.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def flush_and_close( file_handle ):
|
||||
# # https://docs.python.org/2/library/os.html#os.fsync
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
|
||||
# global os
|
||||
#
|
||||
#
|
||||
# file_handle.flush()
|
||||
# if file_handle.mode not in ('r', 'rb') and file_handle.name != os.devnull:
|
||||
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
|
||||
# os.fsync(file_handle.fileno())
|
||||
# file_handle.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def cleanup( f_names_list ):
|
||||
# global os
|
||||
# for f in f_names_list:
|
||||
@ -91,12 +137,12 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# else:
|
||||
# print('Unrecognized type of element:', f, ' - can not be treated as file.')
|
||||
# del_name = None
|
||||
#
|
||||
#
|
||||
# if del_name and os.path.isfile( del_name ):
|
||||
# os.remove( del_name )
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# sql_init='''
|
||||
# recreate table tsyntax( token varchar(100) );
|
||||
# commit;
|
||||
@ -109,7 +155,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# insert into tsyntax( token ) values( 'using plugin Srp' );
|
||||
# insert into tsyntax( token ) values( 'tags ( foo = ''bar'', rio = ''gee'' )' );
|
||||
# commit;
|
||||
#
|
||||
#
|
||||
# set heading off;
|
||||
# select 'set bail on;' from rdb$database union all
|
||||
# select 'set echo off;' from rdb$database union all
|
||||
@ -117,7 +163,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# select 'set autoddl off;' from rdb$database union all
|
||||
# select 'commit;' from rdb$database
|
||||
# ;
|
||||
#
|
||||
#
|
||||
# with
|
||||
# t as (
|
||||
# select *
|
||||
@ -141,37 +187,37 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# select 'create or alter user tmp$c6279 ' || ddl_expr from c
|
||||
# union all
|
||||
# select 'create or alter user tmp$c6279 ' || replace(ddl_expr, ' active', ' inactive') from c;
|
||||
#
|
||||
#
|
||||
# select 'rollback;' from rdb$database
|
||||
# ;
|
||||
#
|
||||
#
|
||||
# '''
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# f_generate_sql_with_combos=open( os.path.join(context['temp_directory'],'tmp_c6279_pre.sql'), 'w')
|
||||
# f_generate_sql_with_combos.write(sql_init)
|
||||
# flush_and_close( f_generate_sql_with_combos )
|
||||
#
|
||||
#
|
||||
# f_ddl_combinations_script=open( os.path.join(context['temp_directory'],'tmp_c6279_run.sql'), 'w', buffering = 0)
|
||||
# f_create_combinations_err=open( os.path.join(context['temp_directory'],'tmp_c6279_pre.err'), 'w', buffering = 0)
|
||||
#
|
||||
#
|
||||
# # PREPARING. GENERATE .SQL STATEMENTS WITH ALL POSSIBLE COMBINATIONS OF OPTIONS:
|
||||
# ############
|
||||
# subprocess.call( [context['isql_path'], dsn, '-q', '-i', f_generate_sql_with_combos.name], stdout=f_ddl_combinations_script, stderr=f_create_combinations_err )
|
||||
# flush_and_close( f_ddl_combinations_script )
|
||||
# flush_and_close( f_create_combinations_err )
|
||||
#
|
||||
#
|
||||
# #------------------------------------------------------------------------------------------------
|
||||
#
|
||||
#
|
||||
# f_run_ddl_combinations_log=open( os.path.join(context['temp_directory'],'tmp_c6279_run.log'), 'w', buffering = 0)
|
||||
# f_run_ddl_combinations_err=open( os.path.join(context['temp_directory'],'tmp_c6279_run.err'), 'w', buffering = 0)
|
||||
#
|
||||
#
|
||||
# # MAIN QUERY. CHECK ALL POSSIBLE COMBINATIONS OF OPTIONS:
|
||||
# #############
|
||||
# subprocess.call( [context['isql_path'], dsn, '-q', '-i', f_ddl_combinations_script.name], stdout=f_run_ddl_combinations_log, stderr=f_run_ddl_combinations_err )
|
||||
# flush_and_close( f_run_ddl_combinations_log )
|
||||
# flush_and_close( f_run_ddl_combinations_err )
|
||||
#
|
||||
#
|
||||
# # Checks:
|
||||
# #########
|
||||
# # Both for prepare (creating main .sql) and for main sql script STDOUT and STDERR must be empty:
|
||||
@ -180,20 +226,24 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# for line in f:
|
||||
# if line.split():
|
||||
# print('UNEXPECTED OUTPUT IN ISQL RESULT: ' + line.strip() +'; file: ' + r.name )
|
||||
#
|
||||
#
|
||||
# # Cleanup:
|
||||
# ##########
|
||||
# time.sleep(1)
|
||||
#
|
||||
#
|
||||
# cleanup( ( f_generate_sql_with_combos,f_ddl_combinations_script,f_create_combinations_err,f_run_ddl_combinations_log,f_run_ddl_combinations_err ) )
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
test_user = user_factory('db_1', name='tmp$c6279', password='123')
|
||||
|
||||
@pytest.mark.version('>=4.0')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
|
||||
|
||||
def test_1(act_1: Action, test_user: User):
|
||||
act_1.isql(switches=['-q'], input=init_script_1)
|
||||
ddl_combinations_script = act_1.stdout
|
||||
#
|
||||
act_1.reset()
|
||||
act_1.isql(switches=['-q'], input=ddl_combinations_script)
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout # Must be ampty
|
||||
|
@ -2,18 +2,21 @@
|
||||
#
|
||||
# id: bugs.core_6280
|
||||
# title: MERGE statement loses parameters in WHEN (NOT) MATCHED clause that will never be matched, crashes server in some situations
|
||||
# decription:
|
||||
# decription:
|
||||
# Confirmed crash on WI-V3.0.5.33220, WI-T4.0.0.1871 - but only when run MERGE statements with parameters from Python. NO crash when run it from ISQL.
|
||||
# No crash on 4.0.0.1881, but message "No SQLDA for input values provided" will raise for any number of input parameters: 2 or 3.
|
||||
# 18.04.2020: checked on 3.0.6.33288. Reduced minimal allowed version to 3.0.6.
|
||||
#
|
||||
#
|
||||
# [pcisar] 14.12.2021
|
||||
# It's impossible to reimplement it with new driver.
|
||||
# tracker_id: CORE-6280
|
||||
# min_versions: ['3.0.6']
|
||||
# versions: 3.0.6
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
from firebird.qa import db_factory, python_act, Action
|
||||
from firebird.driver import DatabaseError
|
||||
|
||||
# version: 3.0.6
|
||||
# resources: None
|
||||
@ -28,7 +31,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
|
||||
# test_script_1
|
||||
#---
|
||||
#
|
||||
#
|
||||
# cur=db_conn.cursor()
|
||||
# stm='''
|
||||
# merge into t
|
||||
@ -40,7 +43,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# when not matched then
|
||||
# insert (i, j) values (1, ?)
|
||||
# '''
|
||||
#
|
||||
#
|
||||
# try:
|
||||
# cur.execute( stm ) (1,2,)
|
||||
# # cur.execute( stm ) (1,2,3,) -- also leads to "No SQLDA for input values provided"
|
||||
@ -49,10 +52,11 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# finally:
|
||||
# cur.close()
|
||||
# db_conn.close()
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
Error while executing SQL statement:
|
||||
@ -60,11 +64,29 @@ expected_stdout_1 = """
|
||||
- Dynamic SQL Error
|
||||
- SQLDA error
|
||||
- No SQLDA for input values provided
|
||||
"""
|
||||
"""
|
||||
|
||||
@pytest.mark.version('>=3.0.6')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
|
||||
|
||||
def test_1(act_1: Action):
|
||||
pytest.skip("Implementation needs review")
|
||||
with act_1.db.connect() as con:
|
||||
c = con.cursor()
|
||||
cmd = """
|
||||
merge into t
|
||||
using (select 1 x from rdb$database) on 1 = 1
|
||||
when matched then
|
||||
update set j = ?
|
||||
when matched and i = ? then
|
||||
delete
|
||||
when not matched then
|
||||
insert (i, j) values (1, ?)
|
||||
"""
|
||||
# PROBLEM:
|
||||
# Original test used two parameter values where 3 parameters are expected, but
|
||||
# new driver does not even allow that as it checks number of values with number of
|
||||
# parameters - returned by iMessageMetadata.get_count().
|
||||
# ALSO, as new driver uses OO API, it does not use SQLDA structures at all.
|
||||
#with pytest.raises(DatabaseError):
|
||||
#c.execute(cmd, [1, 2])
|
||||
# Next passes ok on v4.0.0.2496, but does it really tests the original issue?
|
||||
c.execute(cmd, [1, 2, 3])
|
||||
|
@ -2,7 +2,7 @@
|
||||
#
|
||||
# id: bugs.core_6309
|
||||
# title: fbsvcmgr can not decode information buffer returned by gfix list limbo service
|
||||
# decription:
|
||||
# decription:
|
||||
# Test creates two databases and uses fdb.ConnectionGroup() for working with them using two connections.
|
||||
# Then we add several rows in both databases (using autonomous transactions for one of them) and change state
|
||||
# of this DB to full shutdown (see 'dbname_a').
|
||||
@ -13,11 +13,10 @@
|
||||
# We check that number of lines which are issued by these utilities is equal.
|
||||
# NB-1: concrete numbers of transactions will DIFFER on SS/SC/CS. We must check only *number* of lines.
|
||||
# NB-2: we can not use svc.get_limbo_transaction_ids( <dbname> ) because FDB raises exception:
|
||||
# File "builddist.win-amd64\\egg
|
||||
# db\\services.py", line 736, in get_limbo_transaction_ids
|
||||
# File "build\\bdist.win-amd64\\egg\\fdb\\services.py", line 736, in get_limbo_transaction_ids
|
||||
# struct.error: unpack requires a string argument of length 4
|
||||
# Because of this, external child processes are called to obtain Tx list: gfix and fbcvmgr.
|
||||
#
|
||||
#
|
||||
# Confirmed bug on 4.0.0.1633: fbsvcmgr issues 0 rows instead of expected 146.
|
||||
# Checked on:
|
||||
# 4.0.0.2195 SS: 5.967s.
|
||||
@ -25,27 +24,32 @@
|
||||
# 4.0.0.2195 CS: 7.313s.
|
||||
# 3.0.7.33358 SS: 4.973s.
|
||||
# 3.0.7.33358 CS: 5.698s.
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-6309
|
||||
# min_versions: ['3.0.7']
|
||||
# versions: 3.0.7
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
import re
|
||||
from firebird.qa import db_factory, python_act, Action, Database
|
||||
from firebird.driver import DistributedTransactionManager, ShutdownMode, ShutdownMethod
|
||||
|
||||
# version: 3.0.7
|
||||
# resources: None
|
||||
|
||||
substitutions_1 = []
|
||||
|
||||
init_script_1 = """"""
|
||||
init_script_1 = """
|
||||
create table test(id int, x int, constraint test_pk primary key(id) using index test_pk) ;
|
||||
"""
|
||||
|
||||
db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
db_1_a = db_factory(sql_dialect=3, init=init_script_1, filename='core_6309_a.fdb')
|
||||
db_1_b = db_factory(sql_dialect=3, init=init_script_1, filename='core_6309_b.fdb')
|
||||
|
||||
# test_script_1
|
||||
#---
|
||||
#
|
||||
#
|
||||
# import sys
|
||||
# import os
|
||||
# import shutil
|
||||
@ -55,32 +59,32 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# from datetime import timedelta
|
||||
# import subprocess
|
||||
# from fdb import services
|
||||
#
|
||||
#
|
||||
# LIMBO_COUNT = 250
|
||||
#
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
#
|
||||
#
|
||||
# db_name=db_conn.database_name
|
||||
# db_conn.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def flush_and_close( file_handle ):
|
||||
# # https://docs.python.org/2/library/os.html#os.fsync
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
|
||||
# global os
|
||||
#
|
||||
#
|
||||
# file_handle.flush()
|
||||
# if file_handle.mode not in ('r', 'rb') and file_handle.name != os.devnull:
|
||||
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
|
||||
# os.fsync(file_handle.fileno())
|
||||
# file_handle.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def cleanup( f_names_list ):
|
||||
# global os
|
||||
# for f in f_names_list:
|
||||
@ -91,35 +95,35 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# else:
|
||||
# print('Unrecognized type of element:', f, ' - can not be treated as file.')
|
||||
# del_name = None
|
||||
#
|
||||
#
|
||||
# if del_name and os.path.isfile( del_name ):
|
||||
# os.remove( del_name )
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# dbname_a=os.path.join(context['temp_directory'],'c6309_a.fdb')
|
||||
# dbname_b=os.path.join(context['temp_directory'],'c6309_b.fdb')
|
||||
#
|
||||
#
|
||||
# cleanup( (dbname_a, dbname_b) )
|
||||
#
|
||||
#
|
||||
# con1 = fdb.create_database( dsn = 'localhost:' + dbname_a )
|
||||
# con2 = fdb.create_database( dsn = 'localhost:' + dbname_b )
|
||||
#
|
||||
#
|
||||
# init_ddl = 'create table test(id int, x int, constraint test_pk primary key(id) using index test_pk)'
|
||||
# con1.execute_immediate(init_ddl)
|
||||
# con1.commit()
|
||||
#
|
||||
#
|
||||
# con2.execute_immediate(init_ddl)
|
||||
# con2.commit()
|
||||
#
|
||||
#
|
||||
# cgr = fdb.ConnectionGroup()
|
||||
# cgr.add(con1)
|
||||
# cgr.add(con2)
|
||||
#
|
||||
#
|
||||
# tx1_list=[]
|
||||
# for i in range(0, LIMBO_COUNT):
|
||||
# tx1_list += [ con1.trans() ]
|
||||
#
|
||||
#
|
||||
# cur_list=[]
|
||||
# for i, tx1 in enumerate(tx1_list):
|
||||
# tx1.begin()
|
||||
@ -127,93 +131,144 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# cur.execute( "insert into test(id, x) values( ?, ? )", ( i, i*11111 ) )
|
||||
# cur.close()
|
||||
# tx1.prepare()
|
||||
#
|
||||
#
|
||||
# tx2 = con2.trans()
|
||||
# cur2=tx2.cursor()
|
||||
# cur2.execute( "insert into test(id, x) values( ?, ? )", (-2, -2222222) )
|
||||
# cur2.close()
|
||||
#
|
||||
#
|
||||
# tx2.prepare()
|
||||
# tx2.commit()
|
||||
#
|
||||
#
|
||||
# svc = services.connect(host='localhost', user=user_name, password=user_password)
|
||||
# svc.shutdown( dbname_a, services.SHUT_FULL, services.SHUT_FORCE, 0)
|
||||
#
|
||||
#
|
||||
# for tx1 in tx1_list:
|
||||
# try:
|
||||
# tx1.close()
|
||||
# except:
|
||||
# pass
|
||||
#
|
||||
# # Result for DBNAME_A when it will be returned online
|
||||
#
|
||||
# # Result for DBNAME_A when it will be returned online
|
||||
# # and we query table TEST:
|
||||
# # Statement failed, SQLSTATE = HY000
|
||||
# # record from transaction <N> is stuck in limbo
|
||||
# # See also "gfix -list <disk>\\path o\\dbname_a"
|
||||
#
|
||||
#
|
||||
# cgr.clear()
|
||||
# svc.bring_online( dbname_a, services.SHUT_NORMAL )
|
||||
# svc.close()
|
||||
# con2.close()
|
||||
#
|
||||
#
|
||||
# try:
|
||||
# # This will fail for sure because DB state was changed to full shutdown
|
||||
# con1.close()
|
||||
# except:
|
||||
# pass
|
||||
#
|
||||
#
|
||||
# svc.close()
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# f_limbo_gfix=open( os.path.join(context['temp_directory'],'tmp_c6309_gfix_list.log'), 'w', buffering=0)
|
||||
# subprocess.call( [ context['gfix_path'], "localhost:" + dbname_a, "-list" ], stdout=f_limbo_gfix, stderr=subprocess.STDOUT )
|
||||
# flush_and_close( f_limbo_gfix )
|
||||
#
|
||||
#
|
||||
# f_limbo_fbsvc=open( os.path.join(context['temp_directory'],'tmp_c6309_fbsvc_list.log'), 'w', buffering=0)
|
||||
# subprocess.call( [ context['fbsvcmgr_path'], "localhost:service_mgr", "action_repair", "rpr_list_limbo_trans", "dbname", dbname_a], stdout=f_limbo_fbsvc, stderr=subprocess.STDOUT )
|
||||
# flush_and_close( f_limbo_fbsvc )
|
||||
#
|
||||
#
|
||||
# # 'gfix -list' issues:
|
||||
# # Transaction 3 is in limbo.
|
||||
# # Transaction 5 is in limbo.
|
||||
# # ...
|
||||
# # (totally 146 lines + "More limbo transactions than fit. Try again")
|
||||
#
|
||||
#
|
||||
# # 'fbsvcmgr rpr_list_limbo_trans' issues:
|
||||
# # Transaction in limbo: 3
|
||||
# # Transaction in limbo: 5
|
||||
# # ...
|
||||
# # (totally exactly 146 lines, without any other message).
|
||||
#
|
||||
#
|
||||
# p=re.compile( 'Transaction\\s+(\\d+\\s+(is\\s+)?in\\s+limbo)|(in\\s+limbo(:)?\\s+\\d+)', re.IGNORECASE )
|
||||
#
|
||||
#
|
||||
# f_list = (f_limbo_gfix, f_limbo_fbsvc)
|
||||
# found_limbos = [0, 0]
|
||||
# for i, g in enumerate(f_list):
|
||||
# with open(g.name, 'r') as f:
|
||||
# for line in f:
|
||||
# found_limbos[i] += 1 if p.search(line) else 0
|
||||
#
|
||||
#
|
||||
# for x in found_limbos:
|
||||
# print(x)
|
||||
#
|
||||
#
|
||||
# # Cleanup
|
||||
# ##########
|
||||
# time.sleep(1)
|
||||
# cleanup( (f_limbo_gfix, f_limbo_fbsvc, dbname_a, dbname_b) )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1_a', substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
146
|
||||
146
|
||||
"""
|
||||
"""
|
||||
|
||||
LIMBO_COUNT = 250
|
||||
|
||||
@pytest.mark.version('>=3.0.7')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
def test_1(act_1: Action, db_1_b: Database):
|
||||
#pytest.skip('PROBLEM WITH TEST')
|
||||
# On Firebird 4, the fbsvcmngr reports error:
|
||||
# unavailable database
|
||||
# gfix works fine, although the outpout is more verbose than original test expected
|
||||
dt_list = []
|
||||
with act_1.db.connect() as con1, db_1_b.connect() as con2:
|
||||
for i in range(LIMBO_COUNT):
|
||||
dt = DistributedTransactionManager([con1, con2])
|
||||
dt_list.append(dt)
|
||||
cur1 = dt.cursor(con1)
|
||||
cur1.execute("insert into test (id, x) values (?, ?)", [i, i * 11111])
|
||||
cur1.close()
|
||||
cur2 = dt.cursor(con2)
|
||||
cur2.execute("insert into test (id, x) values (?, ?)", [-i, i * -2222])
|
||||
cur2.close()
|
||||
for dtc in dt_list:
|
||||
# Initiate distributed commit: phase-1
|
||||
dtc.prepare()
|
||||
# Shut down the first database
|
||||
with act_1.connect_server() as srv:
|
||||
srv.database.shutdown(database=act_1.db.db_path, mode=ShutdownMode.FULL,
|
||||
method=ShutdownMethod.FORCED, timeout=0)
|
||||
#
|
||||
while dt_list:
|
||||
dtc = dt_list.pop()
|
||||
dtc._tra = None # Needed hack to bypass commit and exception
|
||||
dtc.close()
|
||||
#
|
||||
with act_1.connect_server() as srv:
|
||||
srv.database.bring_online(database=act_1.db.db_path)
|
||||
#
|
||||
act_1.gfix(switches=['-list', act_1.db.dsn])
|
||||
gfix_log = act_1.stdout
|
||||
#
|
||||
act_1.reset()
|
||||
# Set EXPECTED_STDERR so we can get over "unavailable database" error and fail on assert
|
||||
# Remove when svcmgr issue is resolved
|
||||
act_1.expected_stderr = "We expect errors"
|
||||
act_1.svcmgr(switches=['action_repair', 'rpr_list_limbo_trans', 'dbname', act_1.db.dsn])
|
||||
mngr_log = act_1.stdout
|
||||
#print(act_1.stderr)
|
||||
#
|
||||
pattern = re.compile('Transaction\\s+(\\d+\\s+(is\\s+)?in\\s+limbo)|(in\\s+limbo(:)?\\s+\\d+)', re.IGNORECASE)
|
||||
found_limbos = [0, 0]
|
||||
#
|
||||
for i, limbo_log in enumerate([gfix_log, mngr_log]):
|
||||
for line in limbo_log.splitlines():
|
||||
found_limbos[i] += 1 if pattern.search(line) else 0
|
||||
# Check [gfix, svsmgr]
|
||||
assert found_limbos == [146, 146]
|
||||
|
||||
|
||||
|
@ -2,18 +2,20 @@
|
||||
#
|
||||
# id: bugs.core_6316
|
||||
# title: Unable to specify new 32k page size
|
||||
# decription:
|
||||
# decription:
|
||||
# NOTE. Issues remain for some kind of commands: parser should be more rigorous.
|
||||
# Sent letter to Alex and Dmitry, 29.05.2020 12:28.
|
||||
# Checked on 4.0.0.2006.
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-6316
|
||||
# min_versions: ['4.0']
|
||||
# versions: 4.0
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
from pathlib import Path
|
||||
from firebird.qa import db_factory, python_act, Action, temp_file
|
||||
from firebird.driver import DatabaseError, ShutdownMode, ShutdownMethod
|
||||
|
||||
# version: 4.0
|
||||
# resources: None
|
||||
@ -22,16 +24,16 @@ substitutions_1 = [('Token unknown.*line.*', 'Token unknown')]
|
||||
|
||||
init_script_1 = """"""
|
||||
|
||||
db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
db_1 = db_factory(sql_dialect=3, init=init_script_1, do_not_create=True)
|
||||
|
||||
# test_script_1
|
||||
#---
|
||||
#
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# #import fdb
|
||||
# from fdb import services
|
||||
#
|
||||
#
|
||||
# DB_NAME=os.path.join(context['temp_directory'],'tmp_6316.fdb')
|
||||
# DB_USER=user_name
|
||||
# DB_PSWD=user_password
|
||||
@ -84,26 +86,26 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# ,"qwerty"
|
||||
# ,"-32768"
|
||||
# )
|
||||
#
|
||||
#
|
||||
# sttm_proto="create database 'localhost:%(DB_NAME)s' user %(DB_USER)s password '%(DB_PSWD)s' page_size %(i)s"
|
||||
#
|
||||
#
|
||||
# svc = services.connect( user = DB_USER, password = DB_PSWD )
|
||||
# #k=0
|
||||
# for i in page_list:
|
||||
# for j in (1,2):
|
||||
# if os.path.isfile(DB_NAME):
|
||||
# os.remove(DB_NAME)
|
||||
#
|
||||
#
|
||||
# try:
|
||||
# # ::: NB ::: No error occured until we specify 'DEFAULT CHARACTER SET ....'
|
||||
# sttm_actual = sttm_proto % locals() + ( ' default character set win1251' if j==1 else '' )
|
||||
#
|
||||
#
|
||||
# #print('Try create with page_size=%(i)s, clause "DEFAULT CHARACTER SET": ' % locals() + ( 'present' if 'default character set' in sttm_actual else 'absent' ) )
|
||||
# print('')
|
||||
# print(sttm_actual.replace("'localhost:%(DB_NAME)s'" % locals(), "...").replace("user %(DB_USER)s " % locals(), '').replace("password '%(DB_PSWD)s' " % locals(), ''))
|
||||
# con = None
|
||||
# con = fdb.create_database( sql = sttm_actual)
|
||||
#
|
||||
#
|
||||
# if con:
|
||||
# con.execute_immediate('alter database set linger to 0')
|
||||
# con.commit()
|
||||
@ -113,91 +115,84 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# print('DB created. Actual page_size:', r[1] )
|
||||
# cur.close()
|
||||
# con.close()
|
||||
#
|
||||
#
|
||||
# if os.path.isfile(DB_NAME):
|
||||
# svc.shutdown( DB_NAME, services.SHUT_FULL, services.SHUT_FORCE, 0)
|
||||
# os.remove(DB_NAME)
|
||||
#
|
||||
#
|
||||
# except Exception as e:
|
||||
# print(e[0])
|
||||
#
|
||||
#
|
||||
# svc.close()
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
create database ... page_size 9223372036854775809 default character set win1251
|
||||
Error while creating database:
|
||||
- SQLCODE: -104
|
||||
- Dynamic SQL Error
|
||||
- SQL error code = -104
|
||||
- Token unknown
|
||||
- 9223372036854775809
|
||||
Statement failed, SQLSTATE = 42000
|
||||
Dynamic SQL Error
|
||||
-SQL error code = -104
|
||||
-Token unknown
|
||||
-9223372036854775809
|
||||
create database ... page_size 9223372036854775809
|
||||
DB created. Actual page_size: 32768
|
||||
create database ... page_size 9223372036854775808 default character set win1251
|
||||
Error while creating database:
|
||||
- SQLCODE: -104
|
||||
- Dynamic SQL Error
|
||||
- SQL error code = -104
|
||||
- Token unknown
|
||||
- 9223372036854775808
|
||||
Statement failed, SQLSTATE = 42000
|
||||
Dynamic SQL Error
|
||||
-SQL error code = -104
|
||||
-Token unknown
|
||||
-9223372036854775808
|
||||
create database ... page_size 9223372036854775808
|
||||
DB created. Actual page_size: 32768
|
||||
create database ... page_size 9223372036854775807 default character set win1251
|
||||
Error while creating database:
|
||||
- SQLCODE: -104
|
||||
- Dynamic SQL Error
|
||||
- SQL error code = -104
|
||||
- Token unknown
|
||||
- 9223372036854775807
|
||||
Statement failed, SQLSTATE = 42000
|
||||
Dynamic SQL Error
|
||||
-SQL error code = -104
|
||||
-Token unknown
|
||||
-9223372036854775807
|
||||
create database ... page_size 9223372036854775807
|
||||
DB created. Actual page_size: 32768
|
||||
create database ... page_size 4294967297 default character set win1251
|
||||
Error while creating database:
|
||||
- SQLCODE: -104
|
||||
- Dynamic SQL Error
|
||||
- SQL error code = -104
|
||||
- Token unknown
|
||||
- 4294967297
|
||||
Statement failed, SQLSTATE = 42000
|
||||
Dynamic SQL Error
|
||||
-SQL error code = -104
|
||||
-Token unknown
|
||||
-4294967297
|
||||
create database ... page_size 4294967297
|
||||
DB created. Actual page_size: 32768
|
||||
create database ... page_size 4294967296 default character set win1251
|
||||
Error while creating database:
|
||||
- SQLCODE: -104
|
||||
- Dynamic SQL Error
|
||||
- SQL error code = -104
|
||||
- Token unknown
|
||||
- 4294967296
|
||||
Statement failed, SQLSTATE = 42000
|
||||
Dynamic SQL Error
|
||||
-SQL error code = -104
|
||||
-Token unknown
|
||||
-4294967296
|
||||
create database ... page_size 4294967296
|
||||
DB created. Actual page_size: 32768
|
||||
create database ... page_size 4294967295 default character set win1251
|
||||
Error while creating database:
|
||||
- SQLCODE: -104
|
||||
- Dynamic SQL Error
|
||||
- SQL error code = -104
|
||||
- Token unknown
|
||||
- 4294967295
|
||||
Statement failed, SQLSTATE = 42000
|
||||
Dynamic SQL Error
|
||||
-SQL error code = -104
|
||||
-Token unknown
|
||||
-4294967295
|
||||
create database ... page_size 4294967295
|
||||
DB created. Actual page_size: 32768
|
||||
create database ... page_size 2147483649 default character set win1251
|
||||
Error while creating database:
|
||||
- SQLCODE: -104
|
||||
- Dynamic SQL Error
|
||||
- SQL error code = -104
|
||||
- Token unknown
|
||||
- 2147483649
|
||||
Statement failed, SQLSTATE = 42000
|
||||
Dynamic SQL Error
|
||||
-SQL error code = -104
|
||||
-Token unknown
|
||||
-2147483649
|
||||
create database ... page_size 2147483649
|
||||
DB created. Actual page_size: 32768
|
||||
create database ... page_size 2147483648 default character set win1251
|
||||
Error while creating database:
|
||||
- SQLCODE: -104
|
||||
- Dynamic SQL Error
|
||||
- SQL error code = -104
|
||||
- Token unknown
|
||||
- 2147483648
|
||||
Statement failed, SQLSTATE = 42000
|
||||
Dynamic SQL Error
|
||||
-SQL error code = -104
|
||||
-Token unknown
|
||||
-2147483648
|
||||
create database ... page_size 2147483648
|
||||
DB created. Actual page_size: 32768
|
||||
create database ... page_size 2147483647 default character set win1251
|
||||
@ -341,51 +336,116 @@ expected_stdout_1 = """
|
||||
create database ... page_size 0x3FF
|
||||
DB created. Actual page_size: 8192
|
||||
create database ... page_size default default character set win1251
|
||||
Error while creating database:
|
||||
- SQLCODE: -104
|
||||
- Dynamic SQL Error
|
||||
- SQL error code = -104
|
||||
- Token unknown
|
||||
- default
|
||||
Statement failed, SQLSTATE = 42000
|
||||
Dynamic SQL Error
|
||||
-SQL error code = -104
|
||||
-Token unknown
|
||||
-default
|
||||
create database ... page_size default
|
||||
DB created. Actual page_size: 8192
|
||||
create database ... page_size null default character set win1251
|
||||
Error while creating database:
|
||||
- SQLCODE: -104
|
||||
- Dynamic SQL Error
|
||||
- SQL error code = -104
|
||||
- Token unknown
|
||||
- null
|
||||
Statement failed, SQLSTATE = 42000
|
||||
Dynamic SQL Error
|
||||
-SQL error code = -104
|
||||
-Token unknown
|
||||
-null
|
||||
create database ... page_size null
|
||||
DB created. Actual page_size: 8192
|
||||
create database ... page_size qwerty default character set win1251
|
||||
Error while creating database:
|
||||
- SQLCODE: -104
|
||||
- Dynamic SQL Error
|
||||
- SQL error code = -104
|
||||
- Token unknown
|
||||
- qwerty
|
||||
Statement failed, SQLSTATE = 42000
|
||||
Dynamic SQL Error
|
||||
-SQL error code = -104
|
||||
-Token unknown
|
||||
-qwerty
|
||||
create database ... page_size qwerty
|
||||
DB created. Actual page_size: 8192
|
||||
create database ... page_size -32768 default character set win1251
|
||||
Error while creating database:
|
||||
- SQLCODE: -104
|
||||
- Dynamic SQL Error
|
||||
- SQL error code = -104
|
||||
- Token unknown
|
||||
- -
|
||||
Statement failed, SQLSTATE = 42000
|
||||
Dynamic SQL Error
|
||||
-SQL error code = -104
|
||||
-Token unknown
|
||||
--
|
||||
create database ... page_size -32768
|
||||
Error while creating database:
|
||||
- SQLCODE: -104
|
||||
- Dynamic SQL Error
|
||||
- SQL error code = -104
|
||||
- Token unknown
|
||||
- -
|
||||
"""
|
||||
Statement failed, SQLSTATE = 42000
|
||||
Dynamic SQL Error
|
||||
-SQL error code = -104
|
||||
-Token unknown
|
||||
--
|
||||
"""
|
||||
|
||||
page_list= ['9223372036854775809',
|
||||
'9223372036854775808',
|
||||
'9223372036854775807',
|
||||
'4294967297',
|
||||
'4294967296',
|
||||
'4294967295',
|
||||
'2147483649',
|
||||
'2147483648',
|
||||
'2147483647',
|
||||
'65537',
|
||||
'32769',
|
||||
'32768',
|
||||
'32767',
|
||||
'16385',
|
||||
'16384',
|
||||
'16383',
|
||||
'8193',
|
||||
'8192',
|
||||
'8191',
|
||||
'4097',
|
||||
'4096',
|
||||
'4095',
|
||||
'2049',
|
||||
'2048',
|
||||
'2047',
|
||||
'1025',
|
||||
'1024',
|
||||
'1023',
|
||||
'0',
|
||||
'0x10000',
|
||||
'0xFFFF',
|
||||
'0x8000',
|
||||
'0x7FFF',
|
||||
'0x4000',
|
||||
'0x3FFF',
|
||||
'0x2000',
|
||||
'0x1FFF',
|
||||
'0x1000',
|
||||
'0xFFF',
|
||||
'0x800',
|
||||
'0x7FF',
|
||||
'0x400',
|
||||
'0x3FF',
|
||||
'default',
|
||||
'null',
|
||||
'qwerty',
|
||||
'-32768'
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.version('>=4.0')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
|
||||
|
||||
def test_1(act_1: Action, capsys):
|
||||
with act_1.connect_server() as srv:
|
||||
for page_size in page_list:
|
||||
for charset in [' default character set win1251', '']:
|
||||
cmd = f"create database '{act_1.db.dsn}' user {act_1.db.user} password '{act_1.db.password}' page_size {page_size}{charset}"
|
||||
print(f'create database ... page_size {page_size}{charset}')
|
||||
act_1.reset()
|
||||
act_1.isql(switches=['-q', '-b'], input=f'{cmd}; ALTER DATABASE SET LINGER TO 0;',
|
||||
combine_output=True, connect_db=False, credentials=False)
|
||||
print(act_1.stdout)
|
||||
#
|
||||
if act_1.db.db_path.is_file():
|
||||
with act_1.db.connect() as con:
|
||||
print('DB created. Actual page_size:', con.info.page_size)
|
||||
srv.database.shutdown(database=act_1.db.db_path, mode=ShutdownMode.FULL,
|
||||
method=ShutdownMethod.FORCED, timeout=0)
|
||||
srv.database.bring_online(database=act_1.db.db_path)
|
||||
act_1.db.drop()
|
||||
#
|
||||
act_1.reset()
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
act_1.stdout = capsys.readouterr().out
|
||||
#
|
||||
act_1.db.create() # to ensure clean teardown
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
@ -2,37 +2,37 @@
|
||||
#
|
||||
# id: bugs.core_6319
|
||||
# title: NBACKUP locks db file on error
|
||||
# decription:
|
||||
# decription:
|
||||
# We create level-0 copy of test DB (so called "stand-by DB") and obtain DB backup GUID for just performed action.
|
||||
# Then we create incremental copy using this GUID ("nbk_level_1") and obtain new DB backup GUID again.
|
||||
# After this we repeat - create next incrementa copy using this (new) GUID ("nbk_level_2").
|
||||
#
|
||||
#
|
||||
# (note: cursor for 'select h.rdb$guid from rdb$backup_history h order by h.rdb$backup_id desc rows 1' can be used
|
||||
# to get last database backup GUID instead of running 'gstat -h').
|
||||
#
|
||||
# Further, we try to apply two incrementa copies but in WRONG order of restore: specify <nbk_level_2> twise instead
|
||||
#
|
||||
# Further, we try to apply two incremental copies but in WRONG order of restore: specify <nbk_level_2> twice instead
|
||||
# of proper order: <nbk_level_1> and after this - <nbk_level_2>.
|
||||
#
|
||||
#
|
||||
# First and second attempts should issue THE SAME message:
|
||||
# "Wrong order of backup files or invalid incremental backup file detected, file: <nbk_02>".
|
||||
#
|
||||
#
|
||||
# We do this check both for NBACKUP and FBSVCMGR.
|
||||
#
|
||||
#
|
||||
# Confirmed bug on 4.0.0.2000: second attempt to run restore using FBSVCMGR issues:
|
||||
# =====
|
||||
# Error opening database file: [disk]:\\path o\\standby_db.dfb
|
||||
# process cannot access the file <nbk_level_2> because it is being used by another process
|
||||
# =====
|
||||
# - and file <nbk_level_2> could not be deleted after this until restart of FB.
|
||||
#
|
||||
#
|
||||
# Works fine on 4.0.0.2025 CS/SS.
|
||||
# 13.06.2020: adapted for use both in 3.x and 4.x; checked on 4.0.0.2037, 3.0.6.33307 - all OK.
|
||||
#
|
||||
#
|
||||
# ::: NOTE :::
|
||||
# bug has nothing with '-inplace' option that present only in FB 4.x - it was also in FB 3.x.
|
||||
# Fix for 3.x was 11.06.2020 12:36, include in "aedc22: Fixed assert in Statement::freeClientData()",
|
||||
# Fix for 3.x was 11.06.2020 12:36, include in "aedc22: Fixed assert in Statement::freeClientData()",
|
||||
# see: https://github.com/FirebirdSQL/firebird/commit/fdf758099c6872579ad6b825027fe81fea3ae1b5
|
||||
#
|
||||
#
|
||||
# 20.01.2021. CRITICAL NOTE (detected when run tests against HQbird 33288, ServerMode = Classic).
|
||||
# #########################
|
||||
# Method "codecs.open()" must be used to process logs, instead of 'plain' open() !
|
||||
@ -43,26 +43,27 @@
|
||||
# -ERROR WHILE TRYING TO OPEN FILE
|
||||
# <The process cannot access the file because the file is being occupied by another process.> // <<< CAN BE IN LOCALIZED FORM!
|
||||
# SQLCODE:-902
|
||||
#
|
||||
#
|
||||
# Because of this, fbt_db utility will fail on attempt to store in ANNOTATIONS table such message with "335544849 : Malformed string".
|
||||
# The worst part is that no any other tests will be saved, i.e. we will have DB with EMPTY result, despite the fact that a problem
|
||||
# occured only on one test (the reason is that fbt_db does all actions within the single transaction).
|
||||
#
|
||||
#
|
||||
# Because of this all messages that are iussued by nbackup/fbsvcmgr or all other utilities must be handled using codecs.open()
|
||||
# method with request to IGNORE all non-ascii character (do NOT try to show it) and take next one.
|
||||
# Example: "with codecs.open( e.name, 'r', encoding = 'utf-8', errors = 'ignore' ) as f: ..."
|
||||
#
|
||||
#
|
||||
# Checked (after replace "open(): with "codecs.open(... errors = 'ignore')" call) on:
|
||||
# 4.0.0.2307 SS: 2.639s; 4.0.0.2324 CS: 3.610s; 3.0.8.33401 SS: 2.210s; 3.0.8.33401 CS: 3.400s.
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-6319
|
||||
# min_versions: ['3.0.6']
|
||||
# versions: 3.0.6
|
||||
# qmid:
|
||||
# qmid:
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
from pathlib import Path
|
||||
from firebird.qa import db_factory, python_act, Action, temp_file
|
||||
|
||||
# version: 3.0.6
|
||||
# resources: None
|
||||
@ -75,44 +76,44 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
|
||||
# test_script_1
|
||||
#---
|
||||
#
|
||||
#
|
||||
# import os
|
||||
# import subprocess
|
||||
# import time
|
||||
# import shutil
|
||||
# import codecs
|
||||
#
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
#
|
||||
#
|
||||
# db_source=db_conn.database_name
|
||||
#
|
||||
#
|
||||
# nbk_level_0 = os.path.splitext(db_source)[0] + '.standby.fdb'
|
||||
#
|
||||
#
|
||||
# # this is for 3.x only by using command:
|
||||
# # nbackup -r db_3x_restore nbk_level_0 nbk_level_1 nbk_level_2
|
||||
# db_3x_restore = os.path.splitext(db_source)[0] + '.restored_in_3x.fdb'
|
||||
#
|
||||
#
|
||||
# nbk_level_1 = os.path.splitext(db_source)[0] + '.nbk_01'
|
||||
# nbk_level_2 = os.path.splitext(db_source)[0] + '.nbk_02'
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def flush_and_close( file_handle ):
|
||||
# # https://docs.python.org/2/library/os.html#os.fsync
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
|
||||
# global os
|
||||
#
|
||||
#
|
||||
# file_handle.flush()
|
||||
# if file_handle.mode not in ('r', 'rb') and file_handle.name != os.devnull:
|
||||
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
|
||||
# os.fsync(file_handle.fileno())
|
||||
# file_handle.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def cleanup( f_names_list ):
|
||||
# global os
|
||||
# for f in f_names_list:
|
||||
@ -123,14 +124,14 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# else:
|
||||
# print('Unrecognized type of element:', f, ' - can not be treated as file.')
|
||||
# del_name = None
|
||||
#
|
||||
#
|
||||
# if del_name and os.path.isfile( del_name ):
|
||||
# os.remove( del_name )
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# cleanup( (db_3x_restore, nbk_level_0, nbk_level_1, nbk_level_2,) )
|
||||
#
|
||||
#
|
||||
# # 1. Create standby copy: make clone of source DB using nbackup -b 0:
|
||||
# ########################
|
||||
# f_nbk0_log=open( os.path.join(context['temp_directory'],'tmp_nbk0_6319.log'), 'w')
|
||||
@ -138,124 +139,124 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# subprocess.call( [ context['nbackup_path'], '-b', '0', db_source, nbk_level_0], stdout=f_nbk0_log, stderr=f_nbk0_err )
|
||||
# flush_and_close( f_nbk0_log )
|
||||
# flush_and_close( f_nbk0_err )
|
||||
#
|
||||
#
|
||||
# get_last_bkup_guid_sttm = 'select h.rdb$guid from rdb$backup_history h order by h.rdb$backup_id desc rows 1'
|
||||
#
|
||||
#
|
||||
# # Read DB-backup GUID after this 1st nbackup run:
|
||||
# #####################
|
||||
# cur = db_conn.cursor()
|
||||
# cur.execute(get_last_bkup_guid_sttm)
|
||||
# for r in cur:
|
||||
# db_guid = r[0]
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# # Create 1st copy using just obtained DB backup GUID:
|
||||
# ############
|
||||
# nbk_call_01 = [ context['nbackup_path'], '-b' ] + ( [ db_guid ] if db_conn.engine_version >= 4.0 else [ '1' ] ) + [ db_source, nbk_level_1 ]
|
||||
#
|
||||
#
|
||||
# f_nbk1_log=open( os.path.join(context['temp_directory'],'tmp_nbk1_6319.log'), 'w')
|
||||
# f_nbk1_err=open( os.path.join(context['temp_directory'],'tmp_nbk1_6319.err'), 'w')
|
||||
# subprocess.call( nbk_call_01, stdout=f_nbk1_log, stderr=f_nbk1_err )
|
||||
# flush_and_close( f_nbk1_log )
|
||||
# flush_and_close( f_nbk1_err )
|
||||
#
|
||||
#
|
||||
# # Re-read DB backup GUID: it is changed after each new nbackup!
|
||||
# ########################
|
||||
# cur.execute(get_last_bkup_guid_sttm)
|
||||
# for r in cur:
|
||||
# db_guid = r[0]
|
||||
#
|
||||
#
|
||||
# # Create 2nd copy using LAST obtained GUID of backup:
|
||||
# ############
|
||||
# nbk_call_02 = [ context['nbackup_path'], '-b' ] + ( [ db_guid ] if db_conn.engine_version >= 4.0 else [ '2' ] ) + [ db_source, nbk_level_2 ]
|
||||
#
|
||||
#
|
||||
# f_nbk2_log=open( os.path.join(context['temp_directory'],'tmp_nbk2_6319.log'), 'w')
|
||||
# f_nbk2_err=open( os.path.join(context['temp_directory'],'tmp_nbk2_6319.err'), 'w')
|
||||
# subprocess.call( nbk_call_02, stdout=f_nbk2_log, stderr=f_nbk2_err )
|
||||
# flush_and_close( f_nbk2_log )
|
||||
# flush_and_close( f_nbk2_err )
|
||||
#
|
||||
#
|
||||
# # Try to merge standby DB and SECOND copy, i.e. wrongly skip 1st incremental copy.
|
||||
# # NB: we do this TWISE. And both time this attempt should fail with:
|
||||
# # "Wrong order of backup files or invalid incremental backup file detected, file: ..."
|
||||
# ########################
|
||||
#
|
||||
#
|
||||
# if db_conn.engine_version >= 4.0:
|
||||
# nbk_wrong_call = [ context['nbackup_path'], '-inplace', '-restore', 'localhost:'+ nbk_level_0, nbk_level_2]
|
||||
# else:
|
||||
# # Invalid level 2 of incremental backup file: C:/FBTESTING/qa/fbt-repo/tmp/tmp_core_6319.nbk_02, expected 1
|
||||
# nbk_wrong_call = [ context['nbackup_path'], '-restore', db_3x_restore, nbk_level_0, nbk_level_2]
|
||||
#
|
||||
#
|
||||
# f_nbk_poor_log=open( os.path.join(context['temp_directory'],'tmp_nbk_poor_6319.log'), 'w')
|
||||
# f_nbk_poor_err=open( os.path.join(context['temp_directory'],'tmp_nbk_poor_6319.err'), 'w')
|
||||
#
|
||||
#
|
||||
# cleanup( (db_3x_restore,) )
|
||||
# subprocess.call( nbk_wrong_call, stdout=f_nbk_poor_log, stderr=f_nbk_poor_err ) # [1]
|
||||
# cleanup( (db_3x_restore,) )
|
||||
# subprocess.call( nbk_wrong_call, stdout=f_nbk_poor_log, stderr=f_nbk_poor_err ) # [2]
|
||||
#
|
||||
#
|
||||
# # FB 3.0.6.33307:
|
||||
# #Invalid level 2 of incremental backup file: <nbk_02>, expected 1
|
||||
# #Invalid level 2 of incremental backup file: <nbk_02>, expected 1
|
||||
# # FB 4.0.0.2037:
|
||||
# # Wrong order of backup files or invalid incremental backup file detected, file: <nbk_02>
|
||||
# # Wrong order of backup files or invalid incremental backup file detected, file: <nbk_02>
|
||||
#
|
||||
#
|
||||
# flush_and_close( f_nbk_poor_log )
|
||||
# flush_and_close( f_nbk_poor_err )
|
||||
#
|
||||
#
|
||||
# cleanup( (db_3x_restore,) )
|
||||
#
|
||||
#
|
||||
# # Try to do the same using FBSVCMGR.
|
||||
# # We also do this twise and both attempts must finish the same as previous pair:
|
||||
# # Wrong order of backup files or invalid incremental backup file detected, file: C:/FBTESTING/qa/fbt-repo/tmp/tmp_core_6319.nbk_02
|
||||
#
|
||||
#
|
||||
# if db_conn.engine_version >= 4.0:
|
||||
# fbsvc_call_01 = [ context['fbsvcmgr_path'], 'localhost:service_mgr', 'action_nrest', 'nbk_inplace', 'dbname', nbk_level_0, 'nbk_file', nbk_level_1]
|
||||
# fbsvc_call_02 = [ context['fbsvcmgr_path'], 'localhost:service_mgr', 'action_nrest', 'nbk_inplace', 'dbname', nbk_level_0, 'nbk_file', nbk_level_2]
|
||||
# else:
|
||||
# fbsvc_call_01 = [ context['fbsvcmgr_path'], 'localhost:service_mgr', 'action_nrest', 'dbname', db_3x_restore, 'nbk_file', nbk_level_0, 'nbk_file', nbk_level_1, 'nbk_file', nbk_level_2]
|
||||
# fbsvc_call_02 = [ context['fbsvcmgr_path'], 'localhost:service_mgr', 'action_nrest', 'dbname', db_3x_restore, 'nbk_file', nbk_level_0, 'nbk_file', nbk_level_2, 'nbk_file', nbk_level_2]
|
||||
#
|
||||
#
|
||||
# # On 4.0.0.2000 second attempt raised:
|
||||
# # Error opening database file: [disk]:\\path o\\standby_db.dfb
|
||||
# # process cannot access the file <nbk_level_2> because it is being used by another process
|
||||
# ####################
|
||||
# f_svc_poor_log=open( os.path.join(context['temp_directory'],'tmp_svc_res_poor_6319.log'), 'w')
|
||||
# f_svc_poor_err=open( os.path.join(context['temp_directory'],'tmp_svc_res_poor_6319.err'), 'w')
|
||||
#
|
||||
#
|
||||
# cleanup( (db_3x_restore,) )
|
||||
# subprocess.call( fbsvc_call_02, stdout=f_svc_poor_log, stderr=f_svc_poor_err ) # [1]
|
||||
# cleanup( (db_3x_restore,) )
|
||||
# subprocess.call( fbsvc_call_02, stdout=f_svc_poor_log, stderr=f_svc_poor_err ) # [2]
|
||||
#
|
||||
#
|
||||
# # FB 3.0.6.33307:
|
||||
# #Invalid level 2 of incremental backup file: C:/FBTESTING/qa/fbt-repo/tmp/tmp_core_6319.nbk_02, expected 1
|
||||
# #Invalid level 2 of incremental backup file: C:/FBTESTING/qa/fbt-repo/tmp/tmp_core_6319.nbk_02, expected 1
|
||||
# # FB 4.0.0.2037:
|
||||
# # Wrong order of backup files or invalid incremental backup file detected, file: <nbk_02>
|
||||
# # Wrong order of backup files or invalid incremental backup file detected, file: <nbk_02>
|
||||
#
|
||||
#
|
||||
# flush_and_close( f_svc_poor_log )
|
||||
# flush_and_close( f_svc_poor_err )
|
||||
# cleanup( (db_3x_restore,) )
|
||||
#
|
||||
#
|
||||
# # Try to apply incremental copies in proper order, also using FBSVCMGR.
|
||||
# # No errors must occur in this case:
|
||||
# ####################################
|
||||
# f_svc_good_log=open( os.path.join(context['temp_directory'],'tmp_svc_res_good_6319.log'), 'w')
|
||||
# f_svc_good_err=open( os.path.join(context['temp_directory'],'tmp_svc_res_good_6319.err'), 'w')
|
||||
#
|
||||
#
|
||||
# cleanup( (db_3x_restore,) )
|
||||
#
|
||||
#
|
||||
# subprocess.call( fbsvc_call_01, stdout=f_svc_good_log, stderr=f_svc_good_err )
|
||||
# if db_conn.engine_version >= 4.0:
|
||||
# subprocess.call( fbsvc_call_02, stdout=f_svc_good_log, stderr=f_svc_good_err )
|
||||
#
|
||||
#
|
||||
# flush_and_close( f_svc_good_log )
|
||||
# flush_and_close( f_svc_good_err )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# # Check. All of these files must be empty:
|
||||
# ###################################
|
||||
# f_list=(f_nbk0_err, f_nbk1_err, f_nbk2_err, f_nbk_poor_log, f_svc_poor_log, f_svc_good_log, f_svc_good_err)
|
||||
@ -265,7 +266,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# for line in f:
|
||||
# if line.split():
|
||||
# print( 'UNEXPECTED output in file '+f_list[i].name+': '+line.upper() )
|
||||
#
|
||||
#
|
||||
# # BOTH lines in every of: {f_nbk_poor_err, f_svc_poor_err} -- must be equal:
|
||||
# # "Wrong order of backup files or invalid incremental backup file detected, file ..."
|
||||
# for e in (f_nbk_poor_err, f_svc_poor_err):
|
||||
@ -281,26 +282,123 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# print( 'Attempt %d. Error message is expected.' % i )
|
||||
# else:
|
||||
# print( ('Attempt %d. Error message is UNEXPECTED: ' + line + ', file: ' + e.name ) % i )
|
||||
#
|
||||
#
|
||||
# # Cleanup.
|
||||
# ##########
|
||||
# time.sleep(1)
|
||||
# cleanup( (f_nbk0_log,f_nbk0_err, f_nbk1_log,f_nbk1_err, f_nbk2_log,f_nbk2_err, f_nbk_poor_log, f_nbk_poor_err, f_svc_poor_log, f_svc_poor_err, f_svc_good_log, f_svc_good_err, db_3x_restore, nbk_level_0, nbk_level_1, nbk_level_2 ) )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
Attempt 1. Error message is expected.
|
||||
Attempt 2. Error message is expected.
|
||||
Attempt 1. Error message is expected.
|
||||
Attempt 2. Error message is expected.
|
||||
"""
|
||||
"""
|
||||
|
||||
# nbk_level_0 = os.path.splitext(db_source)[0] + '.standby.fdb'
|
||||
#
|
||||
# # this is for 3.x only by using command:
|
||||
# # nbackup -r db_3x_restore nbk_level_0 nbk_level_1 nbk_level_2
|
||||
# db_3x_restore = os.path.splitext(db_source)[0] + '.restored_in_3x.fdb'
|
||||
#
|
||||
# nbk_level_1 = os.path.splitext(db_source)[0] + '.nbk_01'
|
||||
# nbk_level_2 = os.path.splitext(db_source)[0] + '.nbk_02'
|
||||
|
||||
nbk_level_0 = temp_file('core_6319_standby.fdb')
|
||||
nbk_level_1 = temp_file('core_6319.nbk_01')
|
||||
nbk_level_2 = temp_file('core_6319.nbk_02')
|
||||
db_3x_restore = temp_file('core_6319_restored_in_3x.nbk_02')
|
||||
|
||||
@pytest.mark.version('>=3.0.6')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
def test_1(act_1: Action, db_3x_restore: Path, nbk_level_0: Path, nbk_level_1: Path,
|
||||
nbk_level_2: Path, capsys):
|
||||
|
||||
def cleanup(files):
|
||||
for item in files:
|
||||
if item.is_file():
|
||||
item.unlink()
|
||||
|
||||
def check_stderr(step: int, source: str):
|
||||
for line in act_1.stderr.splitlines():
|
||||
if line:
|
||||
if act_1.is_version('<4') and 'Invalid level 2 of incremental backup file' in line:
|
||||
print(f'Attempt {step}. Error message is expected.')
|
||||
elif act_1.is_version('>=4') and ('Wrong order of backup' in line or 'invalid incremental backup' in line):
|
||||
print(f'Attempt {step}. Error message is expected.')
|
||||
else:
|
||||
print(f'Attempt {step}. UNEXPECTED {source} message: {line}')
|
||||
|
||||
get_last_bkup_guid_sttm = 'select h.rdb$guid from rdb$backup_history h order by h.rdb$backup_id desc rows 1'
|
||||
# 1. Create standby copy: make clone of source DB using nbackup -b 0:
|
||||
act_1.nbackup(switches=['-b', '0', str(act_1.db.db_path), str(nbk_level_0)])
|
||||
#nbk_level_0.chmod(16895) # Set permissions
|
||||
# Read DB-backup GUID after this 1st nbackup run:
|
||||
with act_1.db.connect() as con:
|
||||
c = con.cursor()
|
||||
db_guid = c.execute(get_last_bkup_guid_sttm).fetchone()[0]
|
||||
# Create 1st copy using just obtained DB backup GUID:
|
||||
act_1.reset()
|
||||
act_1.nbackup(switches=['-b', db_guid if act_1.is_version('>=4') else '1',
|
||||
str(act_1.db.db_path), str(nbk_level_1)])
|
||||
# Re-read DB backup GUID: it is changed after each new nbackup!
|
||||
with act_1.db.connect() as con:
|
||||
c = con.cursor()
|
||||
db_guid = c.execute(get_last_bkup_guid_sttm).fetchone()[0]
|
||||
# Create 2nd copy using LAST obtained GUID of backup:
|
||||
act_1.reset()
|
||||
act_1.nbackup(switches=['-b', db_guid if act_1.is_version('>=4') else '2',
|
||||
str(act_1.db.db_path), str(nbk_level_2)])
|
||||
# Set permissions
|
||||
nbk_level_0.chmod(16895)
|
||||
nbk_level_1.chmod(16895)
|
||||
nbk_level_2.chmod(16895)
|
||||
# Try to merge standby DB and SECOND copy, i.e. wrongly skip 1st incremental copy.
|
||||
# NB: we do this TWICE. And both time this attempt should fail with:
|
||||
# "Wrong order of backup files or invalid incremental backup file detected, file: ..."
|
||||
if act_1.is_version('>=4'):
|
||||
nbk_wrong_call = ['-inplace', '-restore', act_1.get_dsn(nbk_level_0), str(nbk_level_2)]
|
||||
else:
|
||||
nbk_wrong_call = ['-restore', str(db_3x_restore), str(nbk_level_0), str(nbk_level_2)]
|
||||
for step in [1, 2]:
|
||||
act_1.reset()
|
||||
act_1.expected_stderr = "We expect errors"
|
||||
act_1.nbackup(switches=nbk_wrong_call)
|
||||
check_stderr(step, 'nbakup')
|
||||
cleanup([db_3x_restore])
|
||||
# Try to do the same using FBSVCMGR.
|
||||
# We also do this twice and both attempts must finish the same as previous pair:
|
||||
# Wrong order of backup files or invalid incremental backup file detected, file: C:/FBTESTING/qa/fbt-repo/tmp/tmp_core_6319.nbk_02
|
||||
if act_1.is_version('>=4'):
|
||||
fbsvc_call_01 = ['action_nrest', 'nbk_inplace', 'dbname', act_1.get_dsn(nbk_level_0),
|
||||
'nbk_file', str(nbk_level_1)]
|
||||
fbsvc_call_02 = ['action_nrest', 'nbk_inplace', 'dbname', act_1.get_dsn(nbk_level_0),
|
||||
'nbk_file', str(nbk_level_2)]
|
||||
else:
|
||||
fbsvc_call_01 = ['action_nrest', 'dbname', str(db_3x_restore), 'nbk_file', str(nbk_level_0),
|
||||
'nbk_file', str(nbk_level_1), 'nbk_file', str(nbk_level_2)]
|
||||
fbsvc_call_02 = ['action_nrest', 'dbname', str(db_3x_restore), 'nbk_file', str(nbk_level_0),
|
||||
'nbk_file', str(nbk_level_2), 'nbk_file', str(nbk_level_2)]
|
||||
for step in [1, 2]:
|
||||
act_1.reset()
|
||||
act_1.expected_stderr = "We expect errors"
|
||||
act_1.svcmgr(switches=fbsvc_call_02)
|
||||
check_stderr(step, 'svcmgr')
|
||||
cleanup([db_3x_restore])
|
||||
# Try to apply incremental copies in proper order, also using FBSVCMGR.
|
||||
# No errors must occur in this case:
|
||||
act_1.reset()
|
||||
act_1.svcmgr(switches=fbsvc_call_01)
|
||||
cleanup([db_3x_restore])
|
||||
if act_1.is_version('>=4'):
|
||||
act_1.reset()
|
||||
act_1.svcmgr(switches=fbsvc_call_02)
|
||||
# Check
|
||||
act_1.reset()
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
act_1.stdout = capsys.readouterr().out
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
Loading…
Reference in New Issue
Block a user