6
0
mirror of https://github.com/FirebirdSQL/firebird-qa.git synced 2025-01-22 13:33:07 +01:00

More pytyhon tests

This commit is contained in:
Pavel Císař 2021-11-17 19:43:06 +01:00
parent 7822a79624
commit ea95f54d07
21 changed files with 1198 additions and 733 deletions

View File

@ -40,7 +40,7 @@
# qmid: None
import pytest
from threading import Thread
from threading import Thread, Barrier
from firebird.qa import db_factory, python_act, Action
# version: 2.5
@ -264,7 +264,7 @@ test_script_1 = """
set term ;^
"""
def trace_session(act: Action):
def trace_session(act: Action, b: Barrier):
cfg30 = ['# Trace config, format for 3.0. Generated auto, do not edit!',
f'database=%[\\\\/]{act.db.db_path.name}',
'{',
@ -280,13 +280,16 @@ def trace_session(act: Action):
'}']
with act.connect_server() as srv:
srv.trace.start(config='\n'.join(cfg30))
b.wait()
for line in srv:
print(line)
@pytest.mark.version('>=3.0')
def test_1(act_1: Action, capsys):
trace_thread = Thread(target=trace_session, args=[act_1])
b = Barrier(2)
trace_thread = Thread(target=trace_session, args=[act_1, b])
trace_thread.start()
b.wait()
act_1.isql(switches=['-n'], input=test_script_1)
with act_1.connect_server() as srv:
for session in list(srv.trace.sessions.keys()):

View File

@ -16,7 +16,7 @@
# qmid: None
import pytest
from threading import Thread
from threading import Thread, Barrier
from difflib import unified_diff
from firebird.qa import db_factory, python_act, Action
@ -482,7 +482,7 @@ select '*Лев Николаевич Толстой *
' from rdb$database;
"""
def trace_session(act: Action):
def trace_session(act: Action, b: Barrier):
cfg30 = ['# Trace config, format for 3.0. Generated auto, do not edit!',
f'database=%[\\\\/]{act.db.db_path.name}',
'{',
@ -515,17 +515,20 @@ def trace_session(act: Action):
with act.connect_server() as srv:
srv.encoding = 'utf8'
srv.trace.start(config='\n'.join(cfg30))
b.wait()
for line in srv:
pass # we are not interested in trace output
@pytest.mark.version('>=2.5.1')
def test_1(act_1: Action):
b = Barrier(2)
# Get content of firebird.log BEFORE test
with act_1.connect_server() as srv:
srv.info.get_log()
log_before = srv.readlines()
trace_thread = Thread(target=trace_session, args=[act_1])
trace_thread = Thread(target=trace_session, args=[act_1, b])
trace_thread.start()
b.wait()
# RUN QUERY WITH NON-ASCII CHARACTERS
act_1.isql(switches=['-n', '-q'], input=test_script_1)
with act_1.connect_server() as srv:

View File

@ -20,7 +20,7 @@
# qmid: None
import pytest
from threading import Thread
from threading import Thread, Barrier
from firebird.qa import db_factory, python_act, Action
# version: 2.5
@ -188,7 +188,7 @@ expected_stdout_1 = """
SYSDBA:NONE, ISO88591, TCP
"""
def trace_session(act: Action):
def trace_session(act: Action, b: Barrier):
cfg30 = ['# Trace config, format for 3.0. Generated auto, do not edit!',
f'database=%[\\\\/]{act.db.db_path.name}',
'{',
@ -198,13 +198,16 @@ def trace_session(act: Action):
'}']
with act.connect_server() as srv:
srv.trace.start(config='\n'.join(cfg30))
b.wait()
for line in srv:
print(line.upper())
@pytest.mark.version('>=3.0')
def test_1(act_1: Action, capsys):
trace_thread = Thread(target=trace_session, args=[act_1])
b = Barrier(2)
trace_thread = Thread(target=trace_session, args=[act_1, b])
trace_thread.start()
b.wait()
# make two connections with different charset
with act_1.db.connect(charset='utf8'):
pass

View File

@ -9,7 +9,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.1.5
# resources: None
@ -48,12 +48,16 @@ db_1 = db_factory(page_size=4096, sql_dialect=3, init=init_script_1)
# else:
# pass
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
@pytest.mark.version('>=2.1.5')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
act_1 = python_act('db_1', substitutions=substitutions_1)
@pytest.mark.version('>=3.0')
def test_1(act_1: Action):
with act_1.db.connect() as con:
c = con.cursor()
# Test non multi-bytes
c.execute("with q(s) as (select cast('abcdefghijklmno' as blob sub_type 1 character set utf8) from rdb$database) select overlay (s placing cast('0123456789' as blob sub_type 1 character set utf8) from 5) from q")
# Test UTF8
c.execute("with q(s) as (select cast('abcdefghijklmno' as blob sub_type 1 character set utf8) from rdb$database) select overlay (s placing cast(_iso8859_1 'áé' as blob sub_type 1 character set utf8) from 5) from q")
# Test ISO8859_1
c.execute("with q(s) as (select cast('abcdefghijklmno' as blob sub_type 1 character set utf8) from rdb$database) select overlay (s placing cast(_iso8859_1 'áé' as blob sub_type 1 character set iso8859_1) from 5) from q")

View File

@ -36,6 +36,9 @@
# 2.5.9.27152 CS: 1.333s.
#
#
# [pcisar] 17.11.2021
# This test is too complicated and fragile (can screw the test environment)
# It should be reimplemnted in more robust way, or removed from suite
#
# tracker_id: CORE-3323
# min_versions: ['2.5.1']

View File

@ -20,30 +20,10 @@
#
# Samples of call with '-c <path_to_fbclient_dll>':
#
# fbt_run -b C:\\MIX
# irebird
# b25in bugs.core_3328 -o localhost/3255 -c C:\\MIX
# irebird
# b25in
# bclient.dll
# fbt_run -b C:\\MIX
# irebird
# b25Csin bugs.core_3328 -o localhost/3249 -c C:\\MIX
# irebird
# b25csin
# bclient.dll
# fbt_run -b C:\\MIX
# irebird
# b40Cs bugs.core_3328 -o localhost/3439 -c C:\\MIX
# irebird
# b40cs
# bclient.dll
# fbt_run -b C:\\MIX
# irebird
# b40sc bugs.core_3328 -o localhost/3430 -c C:\\MIX
# irebird
# b40sc
# bclient.dll & fbt_view -d results.trf
# fbt_run -b C:\\MIX\\firebird\\fb25\\bin bugs.core_3328 -o localhost/3255 -c C:\\MIX\\firebird\\fb25\\fbinbclient.dll
# fbt_run -b C:\\MIX\\firebird\\fb25Cs\\bin bugs.core_3328 -o localhost/3249 -c C:\\MIX\\firebird\\fb25cs\\bin\\fbclient.dll
# fbt_run -b C:\\MIX\\firebird\\fb40Cs bugs.core_3328 -o localhost/3439 -c C:\\MIX\\firebird\\fb40cs\\fbclient.dll
# fbt_run -b C:\\MIX\\firebird\\fb40sc bugs.core_3328 -o localhost/3430 -c C:\\MIX\\firebird\\fb40sc\\fbclient.dll & fbt_view -d results.trf
#
# tracker_id: CORE-3328
# min_versions: ['2.5.1']
@ -51,17 +31,22 @@
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
import time
from difflib import unified_diff
from threading import Thread
from firebird.qa import db_factory, python_act, Action
from firebird.driver import ShutdownMethod, ShutdownMode
# version: 2.5.1
# resources: None
substitutions_1 = [('attachments: [1-9]+', 'attachments: 1'), ('[\\s]+', ' ')]
# substitutions_1 = [('attachments: [1-9]+', 'attachments: 1'), ('[\\s]+', ' ')]
substitutions_1 = [('database.*shutdown', 'database shutdown')]
init_script_1 = """
create table test(s varchar(36) unique);
commit;
"""
"""
db_1 = db_factory(sql_dialect=3, init=init_script_1)
@ -285,16 +270,55 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
#
#
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
expected_stdout_1 = """
Attributes force write, full shutdown
Attributes force write
act_1 = python_act('db_1', substitutions=substitutions_1)
expected_stderr_1 = """
Statement failed, SQLSTATE = HY000
database /tmp/pytest-of-pcisar/pytest-528/test_10/test.fdb shutdown
Statement failed, SQLSTATE = HY000
database /tmp/pytest-of-pcisar/pytest-528/test_10/test.fdb shutdown
"""
def run_work(act: Action):
test_script = """
show version;
set term ^;
execute block as
declare v_role varchar(31);
begin
v_role = left(replace( uuid_to_char(gen_uuid()), '-', ''), 31);
while (1=1) do
begin
insert into test(s) values( uuid_to_char( gen_uuid() ) );
end
end
^
set term ;^
"""
act.expected_stderr = expected_stderr_1
act.isql(switches=['-n'], input=test_script)
@pytest.mark.version('>=2.5.1')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
@pytest.mark.version('>=3.0')
def test_1(act_1: Action):
with act_1.connect_server() as srv:
srv.info.get_log()
log_before = srv.readlines()
#
work_thread = Thread(target=run_work, args=[act_1])
work_thread.start()
time.sleep(2)
#
srv.database.shutdown(database=str(act_1.db.db_path), mode=ShutdownMode.FULL,
method=ShutdownMethod.FORCED, timeout=0)
srv.database.bring_online(database=str(act_1.db.db_path))
#
srv.info.get_log()
log_after = srv.readlines()
#
work_thread.join(2)
if work_thread.is_alive():
pytest.fail('Work thread is still alive')
#
assert list(unified_diff(log_before, log_after)) == []
assert act_1.clean_stderr == act_1.clean_expected_stderr

View File

@ -18,7 +18,9 @@
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
from io import BytesIO
from firebird.qa import db_factory, python_act, Action
from firebird.driver import SrvRestoreFlag
# version: 3.0
# resources: None
@ -29,7 +31,7 @@ init_script_1 = """
recreate sequence g1 start with 9223372036854775807 increment by -2147483647;
recreate sequence g2 start with -9223372036854775808 increment by 2147483647;
commit;
"""
"""
db_1 = db_factory(sql_dialect=3, init=init_script_1)
@ -48,17 +50,25 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# if os.path.isfile(fbk):
# os.remove(fbk)
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
act_1 = python_act('db_1', substitutions=substitutions_1)
expected_stdout_1 = """
Generator G1, current value: 9223372036854775807, initial value: 9223372036854775807, increment: -2147483647
Generator G2, current value: -9223372036854775808, initial value: -9223372036854775808, increment: 2147483647
"""
"""
@pytest.mark.version('>=3.0')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
@pytest.mark.version('>=3.0,<4')
def test_1(act_1: Action):
with act_1.connect_server() as srv:
backup = BytesIO()
srv.database.local_backup(database=str(act_1.db.db_path), backup_stream=backup)
backup.seek(0)
srv.database.local_restore(backup_stream=backup, database=str(act_1.db.db_path),
flags=SrvRestoreFlag.REPLACE)
act_1.expected_stdout = expected_stdout_1
act_1.isql(switches=[], input="show sequ g1; show sequ g2;")
assert act_1.clean_stdout == act_1.clean_expected_stdout
# version: 4.0
@ -70,7 +80,7 @@ init_script_2 = """
recreate sequence g1 start with 9223372036854775807 increment by -2147483647;
recreate sequence g2 start with -9223372036854775808 increment by 2147483647;
commit;
"""
"""
db_2 = db_factory(sql_dialect=3, init=init_script_2)
@ -89,7 +99,8 @@ db_2 = db_factory(sql_dialect=3, init=init_script_2)
# if os.path.isfile(fbk):
# os.remove(fbk)
#---
#act_2 = python_act('db_2', test_script_2, substitutions=substitutions_2)
act_2 = python_act('db_2', substitutions=substitutions_2)
expected_stdout_2 = """
Generator G1, current value: -9223372034707292162, initial value: 9223372036854775807, increment: -2147483647
@ -97,8 +108,15 @@ expected_stdout_2 = """
"""
@pytest.mark.version('>=4.0')
@pytest.mark.xfail
def test_2(db_2):
pytest.fail("Test not IMPLEMENTED")
def test_2(act_2: Action):
with act_2.connect_server() as srv:
backup = BytesIO()
srv.database.local_backup(database=str(act_2.db.db_path), backup_stream=backup)
backup.seek(0)
srv.database.local_restore(backup_stream=backup, database=str(act_2.db.db_path),
flags=SrvRestoreFlag.REPLACE)
act_2.expected_stdout = expected_stdout_2
act_2.isql(switches=[], input="show sequ g1; show sequ g2;")
assert act_2.clean_stdout == act_2.clean_expected_stdout

View File

@ -20,12 +20,15 @@
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
from threading import Thread, Barrier
from firebird.qa import db_factory, python_act, Action
# version: 2.5.1
# resources: None
substitutions_1 = [('^((?!ERROR|ELEMENT).)*$', ''), ('ERROR CREATING TRACE SESSION.*', 'ERROR CREATING TRACE SESSION'), ('.*"FOO" IS NOT A VALID.*', '"FOO" IS NOT A VALID')]
substitutions_1 = [('^((?!ERROR|ELEMENT).)*$', ''),
('ERROR CREATING TRACE SESSION.*', 'ERROR CREATING TRACE SESSION'),
('.*"FOO" IS NOT A VALID.*', '"FOO" IS NOT A VALID')]
init_script_1 = """"""
@ -184,17 +187,43 @@ 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 = """
ERROR CREATING TRACE SESSION FOR DATABASE
ERROR WHILE PARSING TRACE CONFIGURATION
ELEMENT "LOG_STATEMENT_FINISH": "FOO" IS NOT A VALID
"""
"""
@pytest.mark.version('>=2.5.1')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def trace_session(act: Action, b: Barrier):
cfg30 = ['# Trace config, format for 3.0. Generated auto, do not edit!',
f'database=%[\\\\/]{act.db.db_path.name}',
'{',
' enabled = true',
' time_threshold = 0',
' log_statement_finish = foo',
'}']
with act.connect_server() as srv:
srv.trace.start(config='\n'.join(cfg30))
b.wait()
for line in srv:
print(line.upper())
@pytest.mark.version('>=3.0')
def test_1(act_1: Action, capsys):
b = Barrier(2)
trace_thread = Thread(target=trace_session, args=[act_1, b])
trace_thread.start()
b.wait()
act_1.isql(switches=['-n'], input='select 1 as c from rdb$database;')
with act_1.connect_server() as srv:
for session in list(srv.trace.sessions.keys()):
srv.trace.stop(session_id=session)
trace_thread.join(1.0)
if trace_thread.is_alive():
pytest.fail('Trace thread still alive')
act_1.expected_stdout = expected_stdout_1
act_1.stdout = capsys.readouterr().out
assert act_1.clean_stdout == act_1.clean_expected_stdout

View File

@ -4,7 +4,7 @@
# title: Inserting Käse into a CHARACTER SET ASCII column succeeds
# decription:
# 02-mar-2021. Re-implemented in order to have ability to run this test on Linux.
# Ttest creates table and fills it with non-ascii characters in init_script, using charset = UTF8.
# Test creates table and fills it with non-ascii characters in init_script, using charset = UTF8.
# Then it generates .sql script for running it in separae ISQL process.
# This script makes connection to test DB using charset = WIN1252 and perform needed DML.
# Result will be redirected to .log which will be opened via codecs.open(...encoding='cp1252').
@ -20,7 +20,8 @@
# 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: 2.5
# resources: None
@ -31,7 +32,7 @@ init_script_1 = """
create table tascii(s_ascii varchar(10) character set ascii);
create table tlatin(s_latin varchar(10) character set latin1);
commit;
"""
"""
db_1 = db_factory(sql_dialect=3, init=init_script_1)
@ -114,15 +115,12 @@ 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 = """
insert into tascii values ('Käse');
Statement failed, SQLSTATE = 22018
arithmetic exception, numeric overflow, or string truncation
-Cannot transliterate character between character sets
Records affected: 0
select s_ascii from tascii;
@ -136,9 +134,31 @@ expected_stdout_1 = """
Records affected: 1
"""
expected_stderr_1 = """
Statement failed, SQLSTATE = 22018
arithmetic exception, numeric overflow, or string truncation
-Cannot transliterate character between character sets
After line 4 in file /tmp/pytest-of-pcisar/pytest-559/test_10/test_script.sql
"""
test_script_1 = 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_1: Path):
test_script_1.write_text("""
set list on;
set count on;
set echo on;
insert into tascii values ('Käse');
select s_ascii from tascii;
insert into tlatin values ('Käse');
select s_latin from tlatin;
""", encoding='cp1252')
act_1.expected_stdout = expected_stdout_1
act_1.expected_stderr = expected_stderr_1
act_1.isql(switches=[], input_file=test_script_1, charset='WIN1252')
assert act_1.clean_stderr == act_1.clean_expected_stderr
assert act_1.clean_stdout == act_1.clean_expected_stdout

View File

@ -4,7 +4,7 @@
# title: Blob transliteration may not happen inside the union
# decription:
# 02-mar-2021. Re-implemented in order to have ability to run this test on Linux.
# Ttest creates table and fills it with non-ascii characters in init_script, using charset = UTF8.
# Test creates table and fills it with non-ascii characters in init_script, using charset = UTF8.
# Then it generates .sql script for running it in separae ISQL process.
# This script makes connection to test DB using charset = WIN1251 and perform needed DML.
# Result will be redirected to .log which will be opened via codecs.open(...encoding='cp1251').
@ -19,7 +19,8 @@
# 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: 2.5.1
# resources: None
@ -125,17 +126,33 @@ db_1 = db_factory(charset='WIN1251', 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 = """
Это проверка на вывод строки "Йцукёнг"
Это проверка на вывод строки "Йцукёнг"
Records affected: 2
"""
"""
test_script_1 = temp_file('test_script.sql')
@pytest.mark.version('>=2.5.1')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action, test_script_1: Path):
test_script_1.write_text("""
set list on;
set blob all;
set count on;
set list on;
select msg_blob_id
from sp_test
union
select msg_blob_id
from sp_test;
""", encoding='cp1251')
act_1.expected_stdout = expected_stdout_1
act_1.isql(switches=[], input_file=test_script_1, charset='WIN1251')
assert act_1.clean_stdout == act_1.clean_expected_stdout

View File

@ -41,7 +41,10 @@
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
import time
from threading import Thread, Barrier
from firebird.qa import db_factory, python_act, Action
from firebird.driver import DbWriteMode
# version: 2.5.2
# resources: None
@ -49,8 +52,8 @@ from firebird.qa import db_factory, isql_act, Action
substitutions_1 = []
init_script_1 = """
set bail on;
set echo on;
set bail on;
set echo on;
create or alter procedure sp_fill_fix_tab as begin end;
create or alter procedure sp_fill_gtt_del_rows as begin end;
create or alter procedure sp_fill_gtt_sav_rows as begin end;
@ -128,7 +131,7 @@ set echo on;
^
set term ;^
commit;
"""
"""
db_1 = db_factory(page_size=4096, sql_dialect=3, init=init_script_1)
@ -434,7 +437,8 @@ db_1 = db_factory(page_size=4096, 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 = """
Check ratio_fetches_to_datapages_for_GTT_DELETE_ROWS: OK
@ -445,11 +449,126 @@ expected_stdout_1 = """
Check ratio_marks_to_datapages_for_GTT_PRESERVE_ROWS: OK
Check ratio_marks_to_row_count_for_GTT_DELETE_ROWS: OK
Check ratio_marks_to_row_count_for_GTT_PRESERVE_ROWS: OK
"""
"""
def trace_session(act: Action, b: Barrier):
cfg30 = ['# Trace config, format for 3.0. Generated auto, do not edit!',
f'database=%[\\\\/]{act.db.db_path.name}',
'{',
' enabled = true',
' log_transactions = true',
' print_perf = true',
#' log_connections = true',
#' log_procedure_start = true',
#' log_procedure_finish = true',
' log_initfini = false',
'}']
with act.connect_server() as srv:
srv.trace.start(config='\n'.join(cfg30))
b.wait()
for line in srv:
print(line)
@pytest.mark.version('>=2.5.2')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action, capsys):
NUM_ROWS_TO_BE_ADDED = 45000
# Change FW to OFF in order to speed up initial data filling
with act_1.connect_server() as srv:
srv.database.set_write_mode(database=str(act_1.db.db_path), mode=DbWriteMode.ASYNC)
# Make initial data filling into PERMANENT table for retrieving later number of data pages
# (it should be the same for any kind of tables, including GTTs):
with act_1.db.connect() as con:
c = con.cursor()
c.call_procedure('sp_fill_fix_tab', [NUM_ROWS_TO_BE_ADDED])
con.commit()
#
b = Barrier(2)
trace_thread = Thread(target=trace_session, args=[act_1, b])
trace_thread.start()
b.wait()
#
with act_1.db.connect() as con1:
c = con1.cursor()
c.call_procedure('sp_fill_gtt_sav_rows', [NUM_ROWS_TO_BE_ADDED])
con1.rollback()
with act_1.db.connect() as con2:
c = con2.cursor()
c.call_procedure('sp_fill_gtt_del_rows', [NUM_ROWS_TO_BE_ADDED])
con2.rollback()
# Somehow sleep is necessary otherwise "sp_fill_gtt_del_rows" will not show up in trace log
time.sleep(3)
with act_1.connect_server() as srv:
for session in list(srv.trace.sessions.keys()):
srv.trace.stop(session_id=session)
trace_thread.join(3.0)
if trace_thread.is_alive():
pytest.fail('Trace thread still alive')
trace_output = capsys.readouterr().out
# Obtain statistics for table T_FIX_TAB in order to estimate numberof data pages
dp_cnt = 0
act_1.gstat(switches=['-a','-t', 'T_FIX_TAB', '-u', act_1.db.user, '-p', act_1.db.password])
for line in act_1.stdout.splitlines():
if 'data pages' in line.lower():
# Data pages: 1098, data page slots: 1098, average fill: 74% ==> 1098
dp_cnt = int(line.replace(',', ' ').split()[2])
#
gtt_sav_fetches = -1
gtt_sav_marks = -1
gtt_del_fetches = -1
gtt_del_marks = -1
gtt_del_trace = ''
gtt_sav_trace = ''
for line in trace_output.splitlines():
if 'fetch' in line:
# 2.5.7:
# ['370', 'ms,', '1100', 'read(s),', '1358', 'write(s),', '410489', 'fetch(es),', '93294', 'mark(s)']
# ['2', 'ms,', '1', 'read(s),', '257', 'write(s),', '1105', 'fetch(es),', '1102', 'mark(s)']
# 3.0.2:
# 618 ms, 1 read(s), 2210 write(s), 231593 fetch(es), 92334 mark(s)
# 14 ms, 1109 write(s), 7 fetch(es), 4 mark(s)
words = line.split()
for k in range(len(words)):
if words[k].startswith('fetch'):
if gtt_sav_fetches == -1:
gtt_sav_fetches = int(words[k-1])
gtt_sav_trace = line.strip()
else:
gtt_del_fetches = int(words[k-1])
gtt_del_trace = line.strip()
if words[k].startswith('mark'):
if gtt_sav_marks==-1:
gtt_sav_marks = int(words[k-1])
else:
gtt_del_marks = int(words[k-1])
#
check_data = {
'ratio_fetches_to_row_count_for_GTT_PRESERVE_ROWS' : (1.00 * gtt_sav_fetches / NUM_ROWS_TO_BE_ADDED, 9.1219, 5.1465),
'ratio_fetches_to_row_count_for_GTT_DELETE_ROWS' : (1.00 * gtt_del_fetches / NUM_ROWS_TO_BE_ADDED, 0.0245, 0.00015),
'ratio_marks_to_row_count_for_GTT_PRESERVE_ROWS' : (1.00 * gtt_sav_marks / NUM_ROWS_TO_BE_ADDED, 2.0732, 2.05186),
'ratio_marks_to_row_count_for_GTT_DELETE_ROWS' : (1.00 * gtt_del_marks / NUM_ROWS_TO_BE_ADDED, 0.0245, 0.000089),
'ratio_fetches_to_datapages_for_GTT_PRESERVE_ROWS' : (1.00 * gtt_sav_fetches / dp_cnt, 373.85, 209.776),
'ratio_fetches_to_datapages_for_GTT_DELETE_ROWS' : (1.00 * gtt_del_fetches / dp_cnt, 1.0063, 0.00634),
'ratio_marks_to_datapages_for_GTT_PRESERVE_ROWS' : (1.00 * gtt_sav_marks / dp_cnt, 84.9672, 83.6358),
'ratio_marks_to_datapages_for_GTT_DELETE_ROWS' : (1.00 * gtt_del_marks / dp_cnt, 1.0036, 0.00362),
}
i = 2 # FB 3+
MAX_DIFF_PERCENT = 5.0
# THRESHOLD
failed_flag = False
for k, v in sorted(check_data.items()):
msg = ('Check ' + k + ': ' +
('OK' if v[i] * ((100 - MAX_DIFF_PERCENT)/100) <= v[0] <= v[i] * (100+MAX_DIFF_PERCENT) / 100
else 'value '+str(v[0])+' not in range '+str( v[i] ) + ' +/-' + str(MAX_DIFF_PERCENT) + '%')
)
print(msg)
failed_flag = 'not in range' in msg
if failed_flag:
print('Trace for GTT PRESERVE rows: ' + gtt_sav_trace)
print('Trace for GTT DELETE rows: ' + gtt_del_trace)
#
act_1.expected_stdout = expected_stdout_1
act_1.stdout = capsys.readouterr().out
assert act_1.clean_stdout == act_1.clean_expected_stdout

View File

@ -9,7 +9,8 @@
# 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 SrvStatFlag
# version: 2.5.5
# resources: None
@ -27,15 +28,23 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# runProgram('gstat',['$(DATABASE_LOCATION)bugs.core_3548.fdb','-h','-user',user_name,'-password',user_password])
# runProgram('gfix',['$(DATABASE_LOCATION)bugs.core_3548.fdb','-online','-user',user_name,'-password',user_password])
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
act_1 = python_act('db_1', substitutions=substitutions_1)
expected_stdout_1 = """
Attributes force write, full shutdown
"""
"""
@pytest.mark.version('>=2.5.5')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action):
act_1.gfix(switches=['-user', act_1.db.user, '-password', act_1.db.password,
'-shut', 'full', '-force', '0', str(act_1.db.db_path)])
with act_1.connect_server() as srv:
srv.database.get_statistics(database=str(act_1.db.db_path), flags=SrvStatFlag.HDR_PAGES)
stats = srv.readlines()
act_1.gfix(switches=['-user', act_1.db.user, '-password', act_1.db.password,
'-online', str(act_1.db.db_path)])
act_1.stdout = '\n'.join(stats)
act_1.expected_stdout = expected_stdout_1
assert act_1.clean_stdout == act_1.clean_expected_stdout

View File

@ -28,7 +28,9 @@
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
import time
from threading import Thread, Barrier
from firebird.qa import db_factory, python_act, Action
# version: 3.0
# resources: None
@ -39,7 +41,7 @@ init_script_1 = """
recreate table tfix(id int);
recreate global temporary table gtt_ssn(id int) on commit preserve rows;
recreate global temporary table gtt_tra(id int) on commit delete rows;
"""
"""
db_1 = db_factory(sql_dialect=3, init=init_script_1)
@ -206,7 +208,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
#
# # Output log of trace session, with filtering only interested info:
#
# # Pwerformance header text (all excessive spaces will be removed before comparison - see below):
# # Performance header text (all excessive spaces will be removed before comparison - see below):
# perf_header='Table Natural Index Update Insert Delete Backout Purge Expunge'
#
# checked_events= {
@ -239,9 +241,30 @@ 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)
test_script_1 = """
set autoddl off;
set echo on;
set count on;
set bail on;
insert into tfix(id) values(1);
commit;
insert into tfix(id) values(2);
rollback;
insert into gtt_ssn(id) values(1);
commit;
insert into gtt_ssn(id) values(2);
rollback;
insert into gtt_tra(id) values(1);
commit;
insert into gtt_tra(id) values(2);
rollback;
"""
expected_stdout_1 = """
Statement statistics detected for COMMIT
Statement statistics detected for COMMIT
Statement statistics detected for ROLLBACK
Found performance block header
@ -252,11 +275,67 @@ expected_stdout_1 = """
Found table statistics for GTT_SSN
Statement statistics detected for COMMIT
Statement statistics detected for ROLLBACK
"""
"""
def trace_session(act: Action, b: Barrier):
cfg30 = ['# Trace config, format for 3.0. Generated auto, do not edit!',
f'database=%[\\\\/]{act.db.db_path.name}',
'{',
' enabled = true',
' log_transactions = true',
' print_perf = true',
#' log_connections = true',
#' log_procedure_start = true',
#' log_procedure_finish = true',
' log_initfini = false',
'}']
with act.connect_server() as srv:
srv.trace.start(config='\n'.join(cfg30))
b.wait()
for line in srv:
print(line)
@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):
b = Barrier(2)
trace_thread = Thread(target=trace_session, args=[act_1, b])
trace_thread.start()
b.wait()
#
act_1.isql(switches=[], input=test_script_1)
# do NOT remove this otherwise trace log can contain only message about its start before being closed!
time.sleep(3)
with act_1.connect_server() as srv:
for session in list(srv.trace.sessions.keys()):
srv.trace.stop(session_id=session)
trace_thread.join(3.0)
if trace_thread.is_alive():
pytest.fail('Trace thread still alive')
trace_output = capsys.readouterr().out
# Output log of trace session, with filtering only interested info:
# Performance header text (all excessive spaces will be removed before comparison - see below):
perf_header='Table Natural Index Update Insert Delete Backout Purge Expunge'
checked_events= {') COMMIT_TRANSACTION': 'commit',
') ROLLBACK_TRANSACTION': 'rollback',
') EXECUTE_STATEMENT': 'execute_statement',
') START_TRANSACTION': 'start_transaction'
}
i, k = 0, 0
watched_event = ''
for line in trace_output.splitlines():
k += 1
e = ''.join([v.upper() for x, v in checked_events.items() if x in line])
watched_event = e if e else watched_event
if ' ms,' in line and ('fetch' in line or 'mark' in line): # One of these *always* must be in trace statistics.
print(f'Statement statistics detected for {watched_event}')
i += 1
if ' '.join(line.split()).upper() == ' '.join(perf_header.split()).upper():
print('Found performance block header')
if line.startswith('TFIX') or line.startswith('GTT_SSN') or line.startswith('GTT_TRA'):
print(f'Found table statistics for {line.split()[0]}')
act_1.expected_stdout = expected_stdout_1
act_1.stdout = capsys.readouterr().out
assert act_1.clean_stdout == act_1.clean_expected_stdout

View File

@ -34,7 +34,7 @@ init_script_1 = """
insert into test_tree values ('5', '4');
insert into test_tree values ('6', '2');
commit;
"""
"""
db_1 = db_factory(sql_dialect=3, init=init_script_1)
@ -116,12 +116,31 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# cleanup( [i.name for i in (f_isql_cmd, f_isql_log)] )
#
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
test_script_1 = """
set planonly;
with recursive
r_tree as
(
select tt.id as a, cast(tt.id as varchar(100)) as asum
from test_tree tt
where tt.id_header is null
union all
select tt.id as a, rt.asum || '_' || tt.id
from test_tree tt join r_tree rt on rt.a = tt.id_header
)
select * from r_tree rt2 join test_tree tt2 on tt2.id=rt2.a ;
"""
act_1 = isql_act('db_1', test_script_1, substitutions=substitutions_1)
@pytest.mark.version('>=3.0')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action):
act_1.execute()
for line in act_1.stdout.splitlines():
if 'PLAN' in line and (line.count('(') - line.count(')') != 0):
pytest.fail(f"Difference in opening vs close parenthesis: {line.count('(') - line.count(')')}")

View File

@ -35,14 +35,28 @@
# 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 DbInfoCode
# version: 2.5.2
# resources: None
substitutions_1 = [('[ ]+', ' ')]
init_script_1 = """"""
init_script_1 = """
recreate view v_check as
select i.mon$page_writes as iostat_pg_writes
from mon$attachments a
left join mon$io_stats i on a.mon$stat_id = i.mon$stat_id
where
a.mon$attachment_id <> current_connection
and a.mon$remote_protocol is not null
and i.mon$stat_group = 1 -- <<< ATTACHMENTS level
;
recreate table test(x int) ;
insert into test(x) values(1) ;
"""
db_1 = db_factory(sql_dialect=3, init=init_script_1)
@ -165,15 +179,57 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
#
#
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
expected_stdout_1 = """
PAGE_WRITES DIFFERENCE SIGN: 1
"""
act_1 = python_act('db_1', substitutions=substitutions_1)
@pytest.mark.version('>=2.5.2')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action):
with act_1.db.connect() as worker_con, act_1.db.connect() as watcher_con:
worker = worker_con.cursor()
watcher = watcher_con.cursor()
sql_mon_query = f'''
select count(distinct a.mon$server_pid), min(a.mon$remote_protocol), max(iif(a.mon$remote_protocol is null,1,0))
from mon$attachments a
where a.mon$attachment_id in ({worker_con.info.id}, {watcher_con.info.id}) or upper(a.mon$user) = upper('cache writer')
'''
worker.execute(sql_mon_query)
server_cnt, server_pro, cache_wrtr = worker.fetchone()
if server_pro is None:
fba = 'Embedded'
elif cache_wrtr == 1:
fba = 'SS'
elif server_cnt == 2:
fba = 'CS'
else:
f1 = worker_con.info.get_info(DbInfoCode.FETCHES)
watcher.execute('select 1 from rdb$database')
watcher.fetchall()
f1 = worker_con.info.get_info(DbInfoCode.FETCHES)
fba = 'SC' if f1 ==f2 else 'SS'
#
if fba == 'SS':
# SUPERSERVER SHOULD *NOT* BE PROCESSED BY THIS TEST
# COUNTER MON$PAGE_WRITES IS NOT CHANGED DURING RUN,
# SO WE CAN ONLY "SIMULATE" PROPER OUTCOME FOR THIS!
page_writes_at_point_2, page_writes_at_point_1 = 0, 1
else:
# Do following in connection-WATCHER:
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
worker_con.execute_immediate('update test set x = 2 rows 1')
watcher.execute('select * from v_check') # get FIRST value of mon$page_writes
page_writes_at_point_1 = watcher.fetchone()[0]
# Again do in connection-worker: add small change to the data,
# otherwise watcher will not get any difference in mon$page_writes:
worker_con.execute_immediate('update test set x = 3 rows 1')
watcher.execute('select * from test')
watcher.fetchall()
watcher_con.commit()
watcher.execute('select * from v_check') # get SECOND value of mon$page_writes
page_writes_at_point_2 = watcher.fetchone()[0]
# PAGE_WRITES DIFFERENCE SIGN: 1
assert abs(page_writes_at_point_2 - page_writes_at_point_1) == 1

View File

@ -19,6 +19,8 @@
# 3.0.8.33420 CS: 6.649s.
# 2.5.9.27152 SC: 4.410s.
#
# [pcisar] 17.11.2021
# Implementation is complicated, and IMHO not worth of realization
# tracker_id: CORE-3658
# min_versions: ['2.5.2']
# versions: 2.5.2

View File

@ -19,12 +19,15 @@
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
from difflib import unified_diff
from firebird.qa import db_factory, python_act, Action
# version: 2.5.2
# resources: None
substitutions_1 = [('STATEMENT FAILED, SQLSTATE = HY000', ''), ('RECORD NOT FOUND FOR USER: TMP\\$C3732', ''), ('AFTER LINE.*', '')]
substitutions_1 = [('STATEMENT FAILED, SQLSTATE = HY000', ''),
('RECORD NOT FOUND FOR USER: TMP\\$C3732', ''),
('AFTER LINE.*', '')]
init_script_1 = """"""
@ -158,12 +161,27 @@ 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)
test_script_1 = """
create role REPL_ADMIN;
create user tmp$c3732 password '12345';
grant repl_admin to tmp$c3732;
revoke all on all from tmp$c3732;
drop user tmp$c3732;
drop role REPL_ADMIN;
exit;
"""
@pytest.mark.version('>=2.5.2')
@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:
srv.info.get_log()
log_before = srv.readlines()
act_1.isql(switches=['-q'], input=test_script_1)
with act_1.connect_server() as srv:
srv.info.get_log()
log_after = srv.readlines()
assert list(unified_diff(log_before, log_after)) == []

View File

@ -12,7 +12,9 @@
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
import socket
import getpass
from firebird.qa import db_factory, python_act, Action
# version: 3.0
# resources: None
@ -46,16 +48,16 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
# cur.close()
#
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
expected_stdout_1 = """
Check of remote_host: passed
Check of remote_os_user: passed
"""
act_1 = python_act('db_1', substitutions=substitutions_1)
@pytest.mark.version('>=3.0')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action):
with act_1.db.connect() as con:
c = con.cursor()
c.execute('select mon$remote_host, mon$remote_os_user from mon$attachments where mon$attachment_id=current_connection')
r = c.fetchone()
if r[0].upper() != socket.gethostname().upper():
pytest.fail(f'FAILED check remote_host: got "{r[0]}" instead of "{socket.gethostname()}"')
if r[1].upper() != getpass.getuser().upper():
pytest.fail(f'FAILED check remote_os_user: got "{r[1]}" instead of "{getpass.getuser()}"')

View File

@ -38,7 +38,7 @@ 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)
# test_script_1
#---
@ -47,10 +47,9 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
@pytest.mark.version('>=3.0')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1():
# This test should PASS, as there is nothing to check because of changed trace config format
pass

View File

@ -11,7 +11,9 @@
# qmid: None
import pytest
from firebird.qa import db_factory, isql_act, Action
from threading import Thread, Barrier
from firebird.qa import db_factory, python_act, Action
from firebird.driver import DatabaseError
# version: 2.5
# resources: None
@ -188,17 +190,42 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
#
#
#---
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
expected_stdout_1 = """
error text: Error while preparing SQL statement:
error text: - SQLCODE: -104
error text: - Unexpected end of command - line 1, column 1
"""
act_1 = python_act('db_1', substitutions=substitutions_1)
def trace_session(act: Action, b: Barrier):
cfg30 = ['# Trace config, format for 3.0. Generated auto, do not edit!',
f'database=%[\\\\/]{act.db.db_path.name}',
'{',
' enabled = true',
' time_threshold = 0',
' log_statement_finish = true',
'}']
with act.connect_server() as srv:
srv.trace.start(config='\n'.join(cfg30))
b.wait()
for line in srv:
pass # We are not interested in trace output
@pytest.mark.version('>=2.5')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action, capsys):
b = Barrier(2)
trace_thread = Thread(target=trace_session, args=[act_1, b])
trace_thread.start()
b.wait()
# empty query
with act_1.db.connect() as con:
c = con.cursor()
try:
c.execute('') # This may crash the server
except Exception as exc:
pass
#
with act_1.connect_server() as srv:
for session in list(srv.trace.sessions.keys()):
srv.trace.stop(session_id=session)
trace_thread.join(1.0)
if trace_thread.is_alive():
pytest.fail('Trace thread still alive')
# If we got here, the server lives so test passed

View File

@ -21,7 +21,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.3
# resources: None
@ -61,7 +61,7 @@ init_script_1 = """
commit
^
set term ;^
"""
"""
db_1 = db_factory(sql_dialect=3, init=init_script_1)
@ -103,12 +103,23 @@ 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)
@pytest.mark.version('>=2.5.3')
@pytest.mark.xfail
def test_1(db_1):
pytest.fail("Test not IMPLEMENTED")
def test_1(act_1: Action):
run_cnt = 20
with act_1.db.connect() as con:
c = con.cursor()
mem_usage = []
for i in range(0, run_cnt):
c.execute('select id from sp_main')
c.fetchall()
mem_usage.append(con.info.current_memory)
max_mem_leak = 16384 # FB 3+
print(mem_usage)
for i in range(2, run_cnt):
m0 = mem_usage[i-1]
m1 = mem_usage[i]
if m1 - m0 >= max_mem_leak:
pytest.fail(f'Unexpected memory leak: {m1-m0} bytes, exceeds threshold = {max_mem_leak}')