mirror of
https://github.com/FirebirdSQL/firebird-qa.git
synced 2025-01-22 13:33:07 +01:00
Set '@pytest.mark.es_eds' to tests which relate to ES/EDS mechanism.
This commit is contained in:
parent
71b430dcd5
commit
188f82dba7
@ -100,7 +100,7 @@ expected_stderr = """
|
||||
-At block line: 3, col: 7
|
||||
"""
|
||||
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=3')
|
||||
def test_1(act: Action, cvc_user: User, for_role: Role, for_cvc_role: Role):
|
||||
act.expected_stdout = expected_stdout
|
||||
|
@ -146,6 +146,7 @@ expected_stdout = """
|
||||
USING_INDEX 1
|
||||
"""
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=3.0')
|
||||
def test_1(act: Action):
|
||||
act.expected_stdout = expected_stdout
|
||||
|
@ -120,6 +120,7 @@ expected_stdout = """
|
||||
PID 1
|
||||
"""
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=3')
|
||||
def test_1(act: Action):
|
||||
act.expected_stdout = expected_stdout
|
||||
|
@ -209,6 +209,7 @@ expected_stderr_2 = """
|
||||
-At block line
|
||||
"""
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=4.0')
|
||||
def test_2(act_2: Action):
|
||||
act_2.expected_stderr = expected_stderr_2
|
||||
|
@ -119,6 +119,7 @@ expected_stdout = """
|
||||
ATTACHES_I_CAN_SEE 11
|
||||
"""
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=3')
|
||||
def test_1(act: Action):
|
||||
act.expected_stdout = expected_stdout
|
||||
|
@ -77,6 +77,7 @@ expected_stderr = """
|
||||
-At block line: 11, col: 9
|
||||
"""
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=3.0')
|
||||
def test_1(act: Action):
|
||||
act.expected_stdout = expected_stdout
|
||||
|
@ -110,6 +110,7 @@ expected_stdout = """
|
||||
DISTINCT_STATEMENT_ID_THEY_SAW 1
|
||||
"""
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=3')
|
||||
def test_1(act: Action):
|
||||
act.expected_stdout = expected_stdout
|
||||
|
@ -63,6 +63,7 @@ select '-- shutdown me now --' from rdb$database;
|
||||
|
||||
tmp_script = temp_file('work_script.sql')
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=3')
|
||||
def test_1(act: Action, tmp_script: Path):
|
||||
tmp_script.write_text(test_script)
|
||||
|
@ -85,6 +85,7 @@ expected_stderr = """
|
||||
-At block line: 5, col: 5
|
||||
"""
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=3')
|
||||
def test_1(act: Action):
|
||||
act.expected_stderr = expected_stderr
|
||||
|
@ -152,6 +152,7 @@ expected_stdout = """
|
||||
MEASURE_RESULT WINS >= 3.8x
|
||||
"""
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=3.0')
|
||||
def test_1(act: Action):
|
||||
act.expected_stdout = expected_stdout
|
||||
|
@ -252,6 +252,7 @@ Statement failed, SQLSTATE = HY000
|
||||
record not found for user: TMP$C3100B
|
||||
"""
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=3.0')
|
||||
def test_1(act: Action):
|
||||
act.expected_stdout = expected_stdout
|
||||
|
@ -99,6 +99,7 @@ expected_stderr = """
|
||||
-At block line: 4, col: 7
|
||||
"""
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=3.0')
|
||||
def test_1(act: Action):
|
||||
act.expected_stdout = expected_stdout
|
||||
|
@ -80,6 +80,7 @@ expected_stderr = """
|
||||
-At block line: 3, col: 9
|
||||
"""
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=3')
|
||||
def test_1(act: Action):
|
||||
act.expected_stdout = expected_stdout
|
||||
|
@ -143,6 +143,7 @@ expected_stderr = """
|
||||
335544878 : concurrent transaction number is 806
|
||||
"""
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=3.0')
|
||||
def test_1(act: Action, user_1_ro: User, user_1_ud: User):
|
||||
act.expected_stdout = expected_stdout
|
||||
|
@ -117,6 +117,7 @@ expected_stdout = """
|
||||
WHAT_I_SEE 789654123
|
||||
"""
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=3')
|
||||
def test_1(act: Action):
|
||||
act.expected_stdout = expected_stdout
|
||||
|
@ -142,6 +142,7 @@ expected_stdout = """
|
||||
MINE_F01 300
|
||||
"""
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=3.0')
|
||||
def test_1(act: Action, tmp_user: User):
|
||||
act.expected_stdout = expected_stdout
|
||||
|
@ -91,6 +91,7 @@ expected_stdout = """
|
||||
LNAME Zeppelin
|
||||
"""
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=3.0')
|
||||
def test_1(act: Action, tmp_user: User):
|
||||
act.expected_stdout = expected_stdout
|
||||
|
@ -73,6 +73,7 @@ expected_stdout = """
|
||||
CNT 0
|
||||
"""
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=3.0')
|
||||
def test_1(act: Action):
|
||||
act.expected_stdout = expected_stdout
|
||||
|
@ -91,6 +91,7 @@ expected_stdout = """
|
||||
STR_SIZE 36
|
||||
"""
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=3')
|
||||
def test_1(act: Action):
|
||||
act.expected_stdout = expected_stdout
|
||||
|
@ -68,6 +68,7 @@ expected_stdout = """
|
||||
hang_script_file = temp_file('hang_script.sql')
|
||||
hang_output = temp_file('hang_script.out')
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=2.5.5')
|
||||
def test_1(act: Action, hang_script_file: Path, hang_output: Path, capsys, request):
|
||||
# Fializer for FB4
|
||||
|
@ -35,6 +35,7 @@ substitutions=[ ('RUNNING_STT_ID[ ]+[0-9]+', 'RUNNING_STT_ID'),
|
||||
|
||||
act = python_act('db', substitutions = substitutions)
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=3')
|
||||
def test_1(act: Action):
|
||||
|
||||
|
@ -73,6 +73,7 @@ expected_stdout = """
|
||||
WHOAMI_SRP TMP$C5225
|
||||
"""
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=3.0.1')
|
||||
def test_1(act: Action, user_srp: User, user_leg: User):
|
||||
act.expected_stdout = expected_stdout
|
||||
|
@ -30,6 +30,7 @@ expected_stdout = """
|
||||
"""
|
||||
|
||||
@pytest.mark.skip("FIXME: see notes")
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=3.0.1')
|
||||
def test_1(act: Action):
|
||||
sql_chk = f"""
|
||||
|
@ -185,6 +185,7 @@ expected_stderr = """
|
||||
-Attachment level timeout expired.
|
||||
"""
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=4.0')
|
||||
def test_1(act: Action):
|
||||
act.expected_stdout = expected_stdout
|
||||
|
@ -87,6 +87,7 @@ expected_stdout = """
|
||||
GDS_ON_SELECT_WITH_LOCK 335544336
|
||||
"""
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=3.0.3')
|
||||
def test_1(act: Action):
|
||||
act.expected_stdout = expected_stdout
|
||||
|
@ -40,6 +40,7 @@ expected_stdout = """
|
||||
|
||||
eds_script = temp_file('eds_script.sql')
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=3.0.3')
|
||||
def test_1(act: Action, eds_script: Path):
|
||||
eds_sql = f"""
|
||||
|
@ -152,6 +152,7 @@ hang_stdout = temp_file('hang_script.out')
|
||||
hang_stderr = temp_file('hang_script.err')
|
||||
|
||||
@pytest.mark.skipif(platform.system() != 'Windows', reason='FIXME: see notes')
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=3.0.3')
|
||||
def test_1(act: Action, hang_script: Path, hang_stdout: Path, hang_stderr: Path,
|
||||
capsys):
|
||||
|
@ -44,6 +44,7 @@ eds_output = temp_file('eds_script.out')
|
||||
new_diff_file = temp_file('_new_diff_5704.tmp')
|
||||
new_main_file = temp_file('new_main_5704.tmp')
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=3.0.3')
|
||||
def test_1(act: Action, eds_script: Path, eds_output: Path, new_diff_file: Path,
|
||||
new_main_file: Path):
|
||||
|
@ -99,6 +99,7 @@ expected_stdout = """
|
||||
WHAT_PROTOCOL_IM_USING <null>
|
||||
"""
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=3.0.4')
|
||||
def test_1(act: Action, tmp_user, tmp_role):
|
||||
act.expected_stdout = expected_stdout
|
||||
|
@ -85,6 +85,7 @@ expected_stdout = """
|
||||
WHATS_MY_ROLE WORKER
|
||||
"""
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=3.0')
|
||||
def test_1(act: Action, user_foo, user_bar):
|
||||
act.expected_stdout = expected_stdout
|
||||
|
@ -165,6 +165,7 @@ expected_stdout = """
|
||||
DUP_CNT 5
|
||||
"""
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=4.0')
|
||||
def test_1(act: Action):
|
||||
if int(act.get_config('ExtConnPoolSize')) < 6 or int(act.get_config('ExtConnPoolLifeTime')) < 10:
|
||||
|
@ -105,7 +105,7 @@ def init_main_db(act: Action, eds_user: User):
|
||||
"""
|
||||
act.isql(switches=[], input=ddl_script)
|
||||
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=4.0')
|
||||
def test_1(act: Action, db_a: Database, db_b: Database, db_c: Database,
|
||||
db_d: Database, eds_user: User, capsys):
|
||||
|
@ -78,6 +78,7 @@ expected_stdout = """
|
||||
Records affected: 0
|
||||
"""
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=4.0.1')
|
||||
def test_1(act: Action):
|
||||
act.expected_stdout = expected_stdout
|
||||
|
@ -448,6 +448,7 @@ expected_stdout = f"""
|
||||
ID=10
|
||||
"""
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=5.0')
|
||||
def test_1(act: Action, capsys):
|
||||
|
||||
|
419
tests/bugs/gh_7917_test-obj-in-use-on-drop-db.py
Normal file
419
tests/bugs/gh_7917_test-obj-in-use-on-drop-db.py
Normal file
@ -0,0 +1,419 @@
|
||||
#coding:utf-8
|
||||
|
||||
"""
|
||||
ID: issue-7917
|
||||
ISSUE: https://github.com/FirebirdSQL/firebird/issues/7917
|
||||
TITLE: Hang in a case of error when sweep thread is attaching to database
|
||||
DESCRIPTION:
|
||||
Test uses preliminary created alias with KeyHolderPlugin that points to special configuration with name 'KH2'.
|
||||
This configuration makes crypt plugin accept key ONLY from client app (in contrary to some other encryption-related tests).
|
||||
DB-level triggers (ON CONNECT, ON DISCONNECT) are created for logging appropriate events (see table 'att_log').
|
||||
Then we run special SQL that uses autonomous transactions and ES/EDS.
|
||||
This script will hang because of update-conflict after some number of transactions (see TX_NUMBER_BEFORE_HANG).
|
||||
We run this script asynchronously, then reduce sweep interval to value SWP_INTERVAL_TO_CHECK that is less than TX_NUMBER_BEFORE_HANG,
|
||||
change DB state to full shutdown and return it online.
|
||||
At this point any connection to DB will fire AUTO SWEEP (normally this can be seen in firebird.log as 'Sweep is started by SWEEPER').
|
||||
We run ISQL that queries 'att_log' table and causes AUTO SWEEP. That ISQL has to normally detach from DB and we must see its results.
|
||||
NOTES:
|
||||
[28.12.2023] pzotov
|
||||
1. To make crypt plugin accept key only from client app, $FB_HOME/plugins.conf must contain following lines:
|
||||
==================
|
||||
Plugin = KH2 {
|
||||
Module = $(dir_plugins)/fbSampleKeyHolder
|
||||
RegisterName = fbSampleKeyHolder
|
||||
Config = KH2
|
||||
}
|
||||
Config = KH2 {
|
||||
Auto = false
|
||||
}
|
||||
==================
|
||||
QA-scenario (.bat and .sh) must add in advance content of $QA_ROOT/files/qa-plugins-supplement.conf to $FB_HOME/plugins.conf.
|
||||
|
||||
2. Demo-plugin (fbSampleKeyHolder) can transfer key over network only for default key which has no-name.
|
||||
Because of this, command 'alter database encrypt with <plugin>' has no '... key <key>' tail.
|
||||
See letter from Alex, 15.12.2023 16:16
|
||||
|
||||
3. In case of regression caused by that bug, we have to be ready that FB will hang on this test!
|
||||
|
||||
Great thanks to Alex for suggestions (discussion started 13.12.2023 13:18).
|
||||
|
||||
Confirmed bug on 6.0.0.173.
|
||||
Checked on 6.0.0.175, 5.0.0.1305, 4.0.5.3049 - but currenlyt only SuperServer works fine.
|
||||
Classic has the same problem. Sent report to Alex, 28.12.2023 13:10.
|
||||
|
||||
On 3.0.12.33726 error raises:
|
||||
unsuccessful metadata update / -ALTER DATABASE failed / -Missing correct crypt key / -Plugin fbSampleDbCrypt: / -Crypt key not set
|
||||
This problem not [yet] investogated.
|
||||
"""
|
||||
import os
|
||||
import time
|
||||
import datetime as py_dt
|
||||
import subprocess
|
||||
import locale
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from firebird.qa import *
|
||||
from firebird.driver import DatabaseError
|
||||
|
||||
REQUIRED_ALIAS = 'tmp_gh_7917_alias'
|
||||
|
||||
###########################
|
||||
### S E T T I N G S ###
|
||||
###########################
|
||||
|
||||
# QA_GLOBALS -- dict, is defined in qa/plugin.py, obtain settings
|
||||
# from act.files_dir/'test_config.ini':
|
||||
enc_settings = QA_GLOBALS['encryption']
|
||||
|
||||
# ACHTUNG: this must be carefully tuned on every new host:
|
||||
#
|
||||
MAX_WAITING_ENCR_FINISH = int(enc_settings['MAX_WAIT_FOR_ENCR_FINISH_WIN' if os.name == 'nt' else 'MAX_WAIT_FOR_ENCR_FINISH_NIX'])
|
||||
assert MAX_WAITING_ENCR_FINISH > 0
|
||||
|
||||
ENCRYPTION_PLUGIN = enc_settings['encryption_plugin'] # fbSampleDbCrypt
|
||||
ENCRYPTION_KEY = enc_settings['encryption_key'] # Red
|
||||
|
||||
SWP_INTERVAL_TO_CHECK = 100
|
||||
TX_NUMBER_BEFORE_HANG = SWP_INTERVAL_TO_CHECK + 10
|
||||
|
||||
MAX_WAIT_FOR_ISQL_TERMINATE=11
|
||||
|
||||
db = db_factory(filename = '#' + REQUIRED_ALIAS, do_not_drop = True)
|
||||
|
||||
act = python_act('db', substitutions = [('^((?!(ISQL|Attributes)).)*$', ''), ('[ \t]+', ' '), ('TCPv(4|6)$', 'TCP')])
|
||||
#act = python_act('db')
|
||||
|
||||
tmp_sql_file = temp_file('tmp_7917.sql')
|
||||
tmp_log_file = temp_file('tmp_7917.log')
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
def run_encr_decr(act: Action, mode, max_wait_encr_thread_finish, capsys):
|
||||
if mode == 'encrypt':
|
||||
# See letter from Alex, 15.12.2023 16:16 demo-plugin can not transfer named key over network.
|
||||
# Because of that, we have to use following command WITHOUT adding 'key "{ENCRYPTION_KEY}"':
|
||||
# ::: NB ::: One need to be sure that $FB_HOME/plugins.conf contains following lines:
|
||||
# Plugin = KH2 {
|
||||
# Module = $(dir_plugins)/fbSampleKeyHolder
|
||||
# RegisterName = fbSampleKeyHolder
|
||||
# Config = KH2
|
||||
# }
|
||||
# Config = KH2 {
|
||||
# Auto = false
|
||||
# }
|
||||
# Otherwise error will raise:
|
||||
# unsuccessful metadata update
|
||||
# -ALTER DATABASE failed
|
||||
# -Missing database encryption key for your attachment
|
||||
# -Plugin fbSampleDbCrypt:
|
||||
# -Crypt key not set
|
||||
#
|
||||
alter_db_sttm = f'alter database encrypt with "{ENCRYPTION_PLUGIN}"'
|
||||
wait_for_state = 'Database encrypted'
|
||||
elif mode == 'decrypt':
|
||||
alter_db_sttm = 'alter database decrypt'
|
||||
wait_for_state = 'Database not encrypted'
|
||||
|
||||
|
||||
e_thread_started = False
|
||||
e_thread_finished = False
|
||||
with act.db.connect() as con:
|
||||
|
||||
t1=py_dt.datetime.now()
|
||||
d1 = t1-t1
|
||||
try:
|
||||
con.execute_immediate(alter_db_sttm)
|
||||
con.commit()
|
||||
e_thread_started = True
|
||||
except DatabaseError as e:
|
||||
print( e.__str__() )
|
||||
|
||||
while e_thread_started:
|
||||
t2=py_dt.datetime.now()
|
||||
d1=t2-t1
|
||||
if d1.seconds*1000 + d1.microseconds//1000 > max_wait_encr_thread_finish:
|
||||
print(f'TIMEOUT EXPIRATION. Mode="{mode}" took {d1.seconds*1000 + d1.microseconds//1000} ms which exceeds limit = {max_wait_encr_thread_finish} ms.')
|
||||
break
|
||||
|
||||
# Possible output:
|
||||
# Database [not] encrypted
|
||||
# Database encrypted, crypt thread not complete
|
||||
act.isql(switches=['-q'], input = 'show database;', combine_output = True)
|
||||
if wait_for_state in act.stdout:
|
||||
if 'not complete' in act.stdout:
|
||||
pass
|
||||
else:
|
||||
e_thread_finished = True
|
||||
break
|
||||
act.reset()
|
||||
|
||||
act.expected_stdout = ''
|
||||
act.stdout = capsys.readouterr().out
|
||||
assert act.clean_stdout == act.clean_expected_stdout
|
||||
act.reset()
|
||||
|
||||
assert e_thread_finished
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.encryption
|
||||
@pytest.mark.version('>=4.0.5')
|
||||
@pytest.mark.platform('Windows')
|
||||
def test_1(act: Action, tmp_sql_file: Path, tmp_log_file: Path, capsys):
|
||||
|
||||
'''
|
||||
with act.db.connect() as con:
|
||||
if act.vars['server-arch'] == 'SuperServer':
|
||||
pass
|
||||
else:
|
||||
pytest.skip("Currently fixed only for SuperServer. Temporary SKIPPED.")
|
||||
'''
|
||||
|
||||
# Scan line-by-line through databases.conf, find line starting with REQUIRED_ALIAS and extract name of file that
|
||||
# must be created in the $(dir_sampleDb)/qa/ folder. This name will be used further as target database (tmp_fdb).
|
||||
# NOTE: we have to SKIP lines which are commented out, i.e. if they starts with '#':
|
||||
p_required_alias_ptn = re.compile( '^(?!#)((^|\\s+)' + REQUIRED_ALIAS + ')\\s*=\\s*\\$\\(dir_sampleDb\\)/qa/', re.IGNORECASE )
|
||||
fname_in_dbconf = None
|
||||
|
||||
with open(act.home_dir/'databases.conf', 'r') as f:
|
||||
for line in f:
|
||||
if p_required_alias_ptn.search(line):
|
||||
# If databases.conf contains line like this:
|
||||
# tmp_7598_alias = $(dir_sampleDb)/qa/tmp_gh_7598.fdb
|
||||
# - then we extract filename: 'tmp_gh_7598.fdb' (see below):
|
||||
fname_in_dbconf = Path(line.split('=')[1].strip()).name
|
||||
break
|
||||
|
||||
# if 'fname_in_dbconf' remains undefined here then propably REQUIRED_ALIAS not equals to specified in the databases.conf!
|
||||
#
|
||||
assert fname_in_dbconf
|
||||
|
||||
#----------------------------------------------------------------
|
||||
|
||||
run_encr_decr(act, 'encrypt', MAX_WAITING_ENCR_FINISH, capsys)
|
||||
|
||||
test_script = f"""
|
||||
set bail on;
|
||||
create table att_log(
|
||||
att_prot varchar(15)
|
||||
,who_ami varchar(31) default current_user
|
||||
,att_id bigint default current_connection
|
||||
,trn_id bigint default current_transaction
|
||||
,evt_time time default 'now'
|
||||
,evt_name varchar(20)
|
||||
,swp_interval int
|
||||
);
|
||||
set term ^;
|
||||
create procedure sp_fill_dblevel_log(a_evt_name type of column att_log.evt_name) as
|
||||
declare v_swp_interval int;
|
||||
declare v_protocol type of column att_log.att_prot;
|
||||
begin
|
||||
insert into att_log(
|
||||
att_prot
|
||||
,evt_name
|
||||
) values (
|
||||
rdb$get_context('SYSTEM', 'NETWORK_PROTOCOL')
|
||||
,:a_evt_name
|
||||
);
|
||||
|
||||
end
|
||||
^
|
||||
create or alter trigger trg_detach on disconnect as
|
||||
begin
|
||||
execute procedure sp_fill_dblevel_log('detach');
|
||||
end
|
||||
^
|
||||
create or alter trigger trg_attach on connect as
|
||||
begin
|
||||
execute procedure sp_fill_dblevel_log('attach');
|
||||
end
|
||||
^
|
||||
set term ;^
|
||||
commit;
|
||||
|
||||
recreate table test(s varchar(36) unique);
|
||||
insert into test(s) values('LOCKED_FOR_PAUSE');
|
||||
commit;
|
||||
|
||||
set transaction read committed WAIT;
|
||||
|
||||
update test set s = s where s = 'LOCKED_FOR_PAUSE';
|
||||
|
||||
set term ^;
|
||||
execute block as
|
||||
declare n int = {TX_NUMBER_BEFORE_HANG};
|
||||
declare v_role varchar(31);
|
||||
begin
|
||||
while (n > 0) do
|
||||
in autonomous transaction do
|
||||
insert into test(s) values( rpad('', 36, uuid_to_char(gen_uuid()) ) )
|
||||
returning :n-1 into n;
|
||||
|
||||
v_role = left(replace( uuid_to_char(gen_uuid()), '-', ''), 31);
|
||||
|
||||
begin
|
||||
execute statement ('update /* ES/EDS */ test set s = s where s = ?') ('LOCKED_FOR_PAUSE')
|
||||
on external
|
||||
'localhost:' || rdb$get_context('SYSTEM', 'DB_NAME')
|
||||
as user 'SYSDBA' password 'masterkey' role v_role
|
||||
with autonomous transaction;
|
||||
when any do
|
||||
begin
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
^
|
||||
set term ;^
|
||||
set heading off;
|
||||
select '-- shutdown me now --' from rdb$database;
|
||||
"""
|
||||
|
||||
tmp_sql_file.write_text(test_script)
|
||||
|
||||
#----------------------------------------------------------------
|
||||
|
||||
# Reduce sweep interval to small value (that must be less than SQL_HANG_AFTER_TX_CNT):
|
||||
#
|
||||
act.gfix(switches=['-h', f'{SWP_INTERVAL_TO_CHECK}', act.db.dsn], combine_output = True, io_enc = locale.getpreferredencoding())
|
||||
|
||||
with open(tmp_log_file, 'w') as f:
|
||||
# Launch ISQL which will hang because update conflict.
|
||||
# This ISQl will be 'self-terminated' further because we will change DB state to full shutdown:
|
||||
#
|
||||
p_handed_isql = subprocess.Popen([act.vars['isql'], '-nod', '-i', str(tmp_sql_file),
|
||||
'-user', act.db.user,
|
||||
'-password', act.db.password, act.db.dsn],
|
||||
stdout = f,
|
||||
stderr = subprocess.STDOUT)
|
||||
|
||||
# Let ISQL time to establish connection and fall in hanging state:
|
||||
time.sleep(3)
|
||||
|
||||
try:
|
||||
act.gfix(switches=['-shut', 'full', '-force', '0', act.db.dsn], combine_output = True, io_enc = locale.getpreferredencoding())
|
||||
finally:
|
||||
p_handed_isql.terminate()
|
||||
|
||||
p_handed_isql.wait(MAX_WAIT_FOR_ISQL_TERMINATE)
|
||||
if p_handed_isql.poll() is None:
|
||||
print(f'Hanged ISQL process WAS NOT terminated in {MAX_WAIT_FOR_ISQL_TERMINATE} second(s).!')
|
||||
else:
|
||||
print(f'Hanged ISQL process terminated with retcode = {p_handed_isql.poll()}')
|
||||
|
||||
# Result: log of hanged ISQL must contain now:
|
||||
# Statement failed, SQLSTATE = 08003
|
||||
# connection shutdown
|
||||
# -Database is shutdown.
|
||||
|
||||
act.gfix(switches=['-online', act.db.dsn], combine_output = True, io_enc = locale.getpreferredencoding())
|
||||
assert act.clean_stdout == ''
|
||||
act.reset()
|
||||
|
||||
# Must show: Attributes encrypted, plugin {ENCRYPTION_PLUGIN} - without 'shutdown'!
|
||||
act.gstat(switches=['-h'])
|
||||
print(act.stdout)
|
||||
|
||||
#act.stdout = capsys.readouterr().out
|
||||
#assert act.clean_stdout == act.clean_expected_stdout
|
||||
#act.reset()
|
||||
|
||||
|
||||
#----------------------------------------------------------------
|
||||
|
||||
TEST_QUERY = 'select att_prot,who_ami,evt_name from att_log order by trn_id'
|
||||
final_sql = f"""
|
||||
set count on;
|
||||
set list on;
|
||||
set echo on;
|
||||
{TEST_QUERY};
|
||||
commit;
|
||||
connect '{act.db.dsn}';
|
||||
drop database;
|
||||
quit;
|
||||
"""
|
||||
tmp_sql_file.write_text(final_sql)
|
||||
|
||||
with open(tmp_log_file, 'w') as f:
|
||||
# Explained by Alex, letter 13-dec-2023 13:18.
|
||||
# Following ISQL will create attach that provokes AUTO SWEEP (because Next - OST now greater than SWP_INTERVAL_TO_CHECK).
|
||||
# Problem raised when other attachments were prohibited to use encryption key (and this is default behaviour).
|
||||
# Before fix, SWEEEP was not allowed to use key from this ISQL-attachment.
|
||||
# Following message was added in firebird.log: "Automatic sweep error /Missing database encryption key for your attachment"
|
||||
# But despite problem with establishing connection by SWEEP, its thread already created appropriate lock at that point.
|
||||
# As result, engine remained in wrong state after this: existied attachments could not be closed.
|
||||
# Also, FB process could not be normally stopped.
|
||||
|
||||
MAX_WAIT_AUTO_SWEEP_FINISH = 3
|
||||
p_chk_sql = subprocess.Popen( [ act.vars['isql'],
|
||||
'-nod', '-i', str(tmp_sql_file),
|
||||
'-user', act.db.user,
|
||||
'-password', act.db.password,
|
||||
act.db.dsn
|
||||
],
|
||||
stdout = f,
|
||||
stderr = subprocess.STDOUT,
|
||||
)
|
||||
|
||||
# If the process does not terminate after timeout seconds, raise a TimeoutExpired exception.
|
||||
# It is safe to catch this exception and retry the wait.
|
||||
try:
|
||||
p_chk_sql.wait(timeout = MAX_WAIT_AUTO_SWEEP_FINISH)
|
||||
except subprocess.TimeoutExpired as e:
|
||||
print(f'Could not obtain result for {MAX_WAIT_AUTO_SWEEP_FINISH} seconds:')
|
||||
print(e.__str__())
|
||||
|
||||
p_chk_sql.terminate()
|
||||
p_chk_sql.wait(MAX_WAIT_FOR_ISQL_TERMINATE)
|
||||
|
||||
# Check if child process has terminated. Set and return returncode attribute. Otherwise, returns None.
|
||||
if p_chk_sql.poll() is None:
|
||||
print(f'Final ISQL process WAS NOT terminated in {MAX_WAIT_FOR_ISQL_TERMINATE} second(s).!')
|
||||
else:
|
||||
print(f'Final ISQL process terminated')
|
||||
#print(f'Final ISQL process terminated with retcode = {p_chk_sql.poll()}')
|
||||
|
||||
|
||||
# do NOT put here this:
|
||||
#run_encr_decr(act, 'decrypt', MAX_WAITING_ENCR_FINISH, capsys)
|
||||
# - otherwise pytest will not return control
|
||||
|
||||
with open(tmp_log_file, 'r') as f:
|
||||
for line in f:
|
||||
if line.strip():
|
||||
print('final ISQL log:',line)
|
||||
|
||||
act.expected_stdout = f"""
|
||||
Hanged ISQL process terminated with retcode = 1
|
||||
Attributes encrypted, plugin {ENCRYPTION_PLUGIN}
|
||||
|
||||
Final ISQL process terminated
|
||||
final ISQL log: {TEST_QUERY};
|
||||
final ISQL log: ATT_PROT TCP
|
||||
final ISQL log: WHO_AMI {act.db.user.upper()}
|
||||
final ISQL log: EVT_NAME attach
|
||||
|
||||
final ISQL log: ATT_PROT TCP
|
||||
final ISQL log: WHO_AMI {act.db.user.upper()}
|
||||
final ISQL log: EVT_NAME detach
|
||||
|
||||
final ISQL log: Records affected: 2
|
||||
|
||||
final ISQL log: commit;
|
||||
final ISQL log: drop database;
|
||||
final ISQL log: quit;
|
||||
"""
|
||||
|
||||
act.stdout = capsys.readouterr().out
|
||||
assert act.clean_stdout == act.clean_expected_stdout
|
||||
act.reset()
|
||||
|
||||
# NB! We have to decrypt database now. Otherwise teardown will fail with:
|
||||
# firebird.driver.types.DatabaseError: Missing database encryption key for your attachment
|
||||
# -Plugin fbSampleDbCrypt:
|
||||
# -Crypt key not set
|
||||
#run_encr_decr(act, 'decrypt', MAX_WAITING_ENCR_FINISH, capsys)
|
@ -166,6 +166,7 @@ def run_encr_decr(act: Action, mode, max_wait_encr_thread_finish, capsys):
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.encryption
|
||||
@pytest.mark.version('>=4.0.5')
|
||||
def test_1(act: Action, tmp_sql_file: Path, tmp_log_file: Path, tmp_gstat_log: Path, capsys):
|
||||
|
@ -70,6 +70,7 @@ STOP_RECURSIVE_ES_AFTER_ITER = 101
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=4.0.5')
|
||||
def test_1(act: Action, tmp_sql: Path, tmp_log: Path, capsys):
|
||||
|
||||
|
@ -73,6 +73,7 @@ ADD_DELAY_FOR_RARE = 2
|
||||
#
|
||||
ITER_LOOP_CNT = 3
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=4.0')
|
||||
def test_1(act: Action, tmp_user_freq: User, tmp_user_rare: User, tmp_cleaner_role: Role, capsys):
|
||||
|
||||
@ -244,14 +245,6 @@ def test_1(act: Action, tmp_user_freq: User, tmp_user_rare: User, tmp_cleaner_ro
|
||||
commit;
|
||||
'''
|
||||
|
||||
'''
|
||||
print(sql_init)
|
||||
act.expected_stdout = ''
|
||||
act.stdout = capsys.readouterr().out
|
||||
assert act.clean_stdout == act.clean_expected_stdout
|
||||
act.reset()
|
||||
'''
|
||||
|
||||
act.expected_stdout = ''
|
||||
act.isql(switches = ['-q'], input = sql_init, combine_output = True, io_enc = locale.getpreferredencoding())
|
||||
assert act.clean_stdout == act.clean_expected_stdout
|
||||
|
@ -62,6 +62,7 @@ expected_stdout_isql = """
|
||||
-At block line
|
||||
"""
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=4.0')
|
||||
def test_1(act: Action, tmp_user: User, tmp_role:Role, capsys):
|
||||
|
||||
|
@ -139,6 +139,7 @@ expected_stdout = """
|
||||
Records affected: 1
|
||||
"""
|
||||
|
||||
@pytest.mark.es_eds
|
||||
@pytest.mark.version('>=4.0')
|
||||
def test_1(act: Action, test_user, test_role):
|
||||
act.expected_stdout = expected_stdout
|
||||
|
Loading…
Reference in New Issue
Block a user