mirror of
https://github.com/FirebirdSQL/firebird-qa.git
synced 2025-01-22 13:33:07 +01:00
More python tests
This commit is contained in:
parent
8858dfd25b
commit
7822a79624
@ -2,14 +2,14 @@
|
||||
#
|
||||
# id: bugs.core_2341
|
||||
# title: Hidden variables conflict with output parameters, causing assertions, unexpected errors or possibly incorrect results
|
||||
# decription:
|
||||
# decription:
|
||||
# tracker_id: CORE-2341
|
||||
# min_versions: []
|
||||
# versions: 2.5
|
||||
# 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
|
||||
@ -23,7 +23,7 @@ db_1 = db_factory(page_size=4096, sql_dialect=3, init=init_script_1)
|
||||
# test_script_1
|
||||
#---
|
||||
# c = db_conn.cursor()
|
||||
#
|
||||
#
|
||||
# cmd = c.prep("""execute block (i varchar(10) = ?) returns (o varchar(10))
|
||||
# as
|
||||
# begin
|
||||
@ -34,7 +34,8 @@ db_1 = db_factory(page_size=4096, sql_dialect=3, init=init_script_1)
|
||||
# c.execute(cmd,['asd'])
|
||||
# printData(c)
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """O
|
||||
----------
|
||||
@ -42,8 +43,21 @@ asd
|
||||
"""
|
||||
|
||||
@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):
|
||||
with act_1.db.connect() as con:
|
||||
c = con.cursor()
|
||||
cmd = c.prepare("""execute block (i varchar(10) = ?) returns (o varchar(10))
|
||||
as
|
||||
begin
|
||||
o = coalesce(cast(o as date), current_date);
|
||||
o = i;
|
||||
suspend;
|
||||
end""")
|
||||
c.execute(cmd, ['asd'])
|
||||
act_1.print_data(c)
|
||||
#
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
act_1.stdout = capsys.readouterr().out
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
||||
|
||||
|
@ -2,25 +2,26 @@
|
||||
#
|
||||
# id: bugs.core_2408
|
||||
# title: isql -ex puts default values of sp parameters before the NOT NULL and COLLATE flags
|
||||
# decription:
|
||||
# decription:
|
||||
# Quote from ticket: "make a procedure with NOT NULL and/or COLLATE flags *and* a default value on any parameter".
|
||||
# Test enchances this by checking not only procedure but also function and package.
|
||||
# Also, check is performed for table (I've encountered the same for TABLES definition in some old databases).
|
||||
#
|
||||
#
|
||||
# Algorithm is similar to test for core-5089: we create several DB objects which do have properties from ticket.
|
||||
# Then we extract metadata and save it into file as 'initial' text.
|
||||
# After this we drop all objects and make attempt to APPLY just extracted metadata script. It should perform without errors.
|
||||
# Finally, we extract metadata again and do COMPARISON of their current content and those which are stored 'initial' file.
|
||||
#
|
||||
#
|
||||
# Checked on: WI-V3.0.0.32328 (SS/CS/SC).
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-2408
|
||||
# min_versions: ['3.0']
|
||||
# versions: 3.0
|
||||
# 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: 3.0
|
||||
# resources: None
|
||||
@ -61,7 +62,7 @@ init_script_1 = """
|
||||
suspend;
|
||||
end
|
||||
^
|
||||
|
||||
|
||||
create or alter function fn_test(
|
||||
p1 varchar(20) character set utf8 not null collate nums_coll default 'foo'
|
||||
,p2 dm_test default 'qwe'
|
||||
@ -134,23 +135,23 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
|
||||
# import subprocess
|
||||
# import time
|
||||
# import difflib
|
||||
#
|
||||
#
|
||||
# #-----------------------------------
|
||||
#
|
||||
#
|
||||
# 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()
|
||||
# os.fsync(file_handle.fileno())
|
||||
#
|
||||
#
|
||||
# file_handle.close()
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def cleanup( f_names_list ):
|
||||
# global os
|
||||
# for i in range(len( f_names_list )):
|
||||
@ -158,22 +159,22 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
|
||||
# os.remove( f_names_list[i] )
|
||||
# if os.path.isfile( f_names_list[i]):
|
||||
# print('ERROR: can not remove file ' + f_names_list[i])
|
||||
#
|
||||
#
|
||||
# #-------------------------------------------
|
||||
#
|
||||
#
|
||||
# db_file=db_conn.database_name
|
||||
# db_conn.close()
|
||||
#
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
#
|
||||
#
|
||||
# f_extract_initial_meta_sql = open( os.path.join(context['temp_directory'],'tmp_meta_2408_init.sql'), 'w')
|
||||
# subprocess.call( [ context['isql_path'], dsn, "-x", "-ch", "utf8" ],
|
||||
# stdout = f_extract_initial_meta_sql,
|
||||
# stderr = subprocess.STDOUT
|
||||
# )
|
||||
# flush_and_close( f_extract_initial_meta_sql )
|
||||
#
|
||||
#
|
||||
# ddl_clear_all='''
|
||||
# drop package pg_test;
|
||||
# drop function fn_test;
|
||||
@ -184,85 +185,108 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
|
||||
# drop collation nums_coll;
|
||||
# commit;
|
||||
# '''
|
||||
#
|
||||
#
|
||||
# f_meta_drop_all_sql = open( os.path.join(context['temp_directory'],'tmp_meta_2408_drop_all.sql'), 'w')
|
||||
# f_meta_drop_all_sql.write(ddl_clear_all)
|
||||
# flush_and_close( f_meta_drop_all_sql )
|
||||
#
|
||||
#
|
||||
# f_meta_drop_all_log = open( os.path.join(context['temp_directory'],'tmp_meta_2408_drop_all.log'), 'w')
|
||||
# subprocess.call( [ context['isql_path'], dsn, "-i", f_meta_drop_all_sql.name, "-ch", "utf8" ],
|
||||
# stdout = f_meta_drop_all_log,
|
||||
# stderr = subprocess.STDOUT
|
||||
# )
|
||||
# flush_and_close( f_meta_drop_all_log )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# f_apply_extracted_meta_log = open( os.path.join(context['temp_directory'],'tmp_meta_2408_apply.log'), 'w')
|
||||
# subprocess.call( [ context['isql_path'], dsn, "-i", f_extract_initial_meta_sql.name, "-ch", "utf8" ],
|
||||
# stdout = f_apply_extracted_meta_log,
|
||||
# stderr = subprocess.STDOUT
|
||||
# )
|
||||
# flush_and_close( f_apply_extracted_meta_log )
|
||||
#
|
||||
#
|
||||
# f_extract_current_meta_sql = open( os.path.join(context['temp_directory'],'tmp_meta_2408_last.sql'), 'w')
|
||||
# subprocess.call( [ context['isql_path'], dsn, "-x", "-ch", "utf8"],
|
||||
# stdout = f_extract_current_meta_sql,
|
||||
# stderr = subprocess.STDOUT
|
||||
# )
|
||||
# flush_and_close( f_extract_current_meta_sql )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# f_diff_txt=open( os.path.join(context['temp_directory'],'tmp_2408_meta_diff.txt'), 'w')
|
||||
#
|
||||
#
|
||||
# f_old=[]
|
||||
# f_new=[]
|
||||
#
|
||||
#
|
||||
# f_old.append(f_extract_initial_meta_sql) # tmp_meta_2408_init.sql -- extracted metadata just after 'init_script' was done
|
||||
# f_new.append(f_extract_current_meta_sql) # tmp_meta_2408_last.sql -- extracted metadata after drop all object and applying 'tmp_meta_2408_init.sql'
|
||||
#
|
||||
#
|
||||
# for i in range(len(f_old)):
|
||||
# old_file=open(f_old[i].name,'r')
|
||||
# new_file=open(f_new[i].name,'r')
|
||||
#
|
||||
#
|
||||
# f_diff_txt.write( ''.join( difflib.unified_diff( old_file.readlines(), new_file.readlines() ) ) )
|
||||
#
|
||||
#
|
||||
# old_file.close()
|
||||
# new_file.close()
|
||||
#
|
||||
#
|
||||
# flush_and_close( f_diff_txt )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# # Should be EMPTY:
|
||||
# ##################
|
||||
# with open( f_meta_drop_all_log.name, 'r') as f:
|
||||
# for line in f:
|
||||
# print( 'Error log of dropping existing objects: ' + f.line() )
|
||||
#
|
||||
#
|
||||
# # Should be EMPTY:
|
||||
# ##################
|
||||
# with open( f_apply_extracted_meta_log.name, 'r') as f:
|
||||
# for line in f:
|
||||
# print( 'Error log of applying extracted metadata: ' + f.line() )
|
||||
#
|
||||
#
|
||||
# # Should be EMPTY:
|
||||
# ##################
|
||||
# with open( f_diff_txt.name,'r') as f:
|
||||
# for line in f:
|
||||
# print( ' '.join(line.split()).upper() )
|
||||
#
|
||||
#
|
||||
# ###############################
|
||||
# # Cleanup.
|
||||
# time.sleep(1)
|
||||
# cleanup( [ i.name for i in (f_extract_initial_meta_sql,f_extract_current_meta_sql,f_meta_drop_all_sql,f_meta_drop_all_log,f_apply_extracted_meta_log,f_diff_txt) ] )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#---
|
||||
#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')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
|
||||
|
||||
def test_1(act_1: Action):
|
||||
# Extract metadata
|
||||
act_1.isql(switches=['-x'])
|
||||
initial_meta = act_1.stdout
|
||||
# Clear all
|
||||
ddl_clear_all = '''
|
||||
drop package pg_test;
|
||||
drop function fn_test;
|
||||
drop procedure sp_test;
|
||||
drop table test;
|
||||
drop domain dm_test;
|
||||
drop collation name_coll;
|
||||
drop collation nums_coll;
|
||||
commit;
|
||||
'''
|
||||
act_1.reset()
|
||||
act_1.isql(switches=[], input=ddl_clear_all)
|
||||
# Recreate metadata
|
||||
act_1.reset()
|
||||
act_1.isql(switches=[], input=initial_meta)
|
||||
# Extract metadata again
|
||||
act_1.reset()
|
||||
act_1.isql(switches=['-x'])
|
||||
current_meta = act_1.stdout
|
||||
# Compare metadata
|
||||
meta_diff = '\n'.join(unified_diff(initial_meta.splitlines(), current_meta.splitlines()))
|
||||
assert meta_diff == ''
|
||||
|
@ -2,14 +2,15 @@
|
||||
#
|
||||
# id: bugs.core_2420
|
||||
# title: Parsing error in EXECUTE STATEMENT with named parameters
|
||||
# decription:
|
||||
# decription:
|
||||
# tracker_id: CORE-2420
|
||||
# min_versions: []
|
||||
# versions: 2.5
|
||||
# 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: 2.5
|
||||
# resources: None
|
||||
@ -50,16 +51,35 @@ db_1 = db_factory(page_size=4096, sql_dialect=3, init=init_script_1)
|
||||
# do exit;
|
||||
# end""")
|
||||
# print ('Execution OK')
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """Execution OK
|
||||
"""
|
||||
act_1 = python_act('db_1', substitutions=substitutions_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):
|
||||
with act_1.db.connect() as con:
|
||||
c = con.cursor()
|
||||
# Test fails if next raises an exception
|
||||
try:
|
||||
c.execute("""execute block as
|
||||
declare datedoc date;
|
||||
declare cod int;
|
||||
declare num int;
|
||||
declare name int;
|
||||
declare summa int;
|
||||
begin
|
||||
for execute statement (
|
||||
' select s.cod,s.num, s.name,sum(g.summa) from sch s
|
||||
left join getschdet(s.cod,:datedoc ,:datedoc,0,0,0,0,0,0,0,0,0,0,0,1,3) g on 1=1
|
||||
where s.num in (''50'',''51'') and s.udl<>''У'' and s.root=1
|
||||
and not exists (select s2.cod from sch s2 where s2.prevcod=s.cod)
|
||||
group by 1,2,3') (datedoc := :datedoc)
|
||||
into :cod, :num, :name, :summa
|
||||
do exit;
|
||||
end""")
|
||||
except DatabaseError as exc:
|
||||
pytest.fail(f"SQL execution failed with: {str(exc)}")
|
||||
|
||||
|
||||
|
||||
|
@ -2,14 +2,16 @@
|
||||
#
|
||||
# id: bugs.core_2441
|
||||
# title: Server crashes on UPDATE OR INSERT statement
|
||||
# decription:
|
||||
# decription:
|
||||
# tracker_id: CORE-2441
|
||||
# min_versions: []
|
||||
# versions: 2.1.3
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
import datetime
|
||||
from firebird.qa import db_factory, python_act, Action
|
||||
from firebird.driver import DatabaseError
|
||||
|
||||
# version: 2.1.3
|
||||
# resources: None
|
||||
@ -31,14 +33,17 @@ db_1 = db_factory(page_size=4096, sql_dialect=3, init=init_script_1)
|
||||
# c.execute("""UPDATE OR INSERT INTO TABLE_TXT (FIELD1)
|
||||
# VALUES (CAST(? AS TIMESTAMP))
|
||||
# MATCHING(FIELD1)""",[datetime.datetime(2011,5,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.1.3')
|
||||
@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("""UPDATE OR INSERT INTO TABLE_TXT (FIELD1)
|
||||
VALUES (CAST(? AS TIMESTAMP))
|
||||
MATCHING(FIELD1)""", [datetime.datetime(2011,5,1)])
|
||||
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
# title: External table data not visible to other sessions in Classic
|
||||
# decription: In 2.1.2 SuperServer, any data written to external tables are visible to other sessions.
|
||||
# However in Classic, this data is not visible. It seems to be cached and written to file eventually, when this happens it becomes visible.
|
||||
#
|
||||
#
|
||||
# THIS TEST WILL END WITH ERROR IF EXTERNAL TABLE ACCESS IS NOT ALLOWED, WHICH IS BY DEFAULT. It's necessary to adjust firebird.conf.
|
||||
# tracker_id: CORE-2475
|
||||
# min_versions: ['2.1.3']
|
||||
@ -12,16 +12,15 @@
|
||||
# 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.1.3
|
||||
# resources: None
|
||||
|
||||
substitutions_1 = []
|
||||
|
||||
init_script_1 = """create table EXT1 external file '$(DATABASE_LOCATION)EXT1.TBL'
|
||||
(PK INTEGER);
|
||||
"""
|
||||
init_script_1 = """"""
|
||||
|
||||
db_1 = db_factory(page_size=4096, sql_dialect=3, init=init_script_1)
|
||||
|
||||
@ -30,37 +29,45 @@ db_1 = db_factory(page_size=4096, sql_dialect=3, init=init_script_1)
|
||||
# # init
|
||||
# import os
|
||||
# ext_filename = '%sEXT1.TBL' % context[db_path_property]
|
||||
#
|
||||
#
|
||||
# # session A
|
||||
# c1 = db_conn.cursor()
|
||||
# c1.execute("insert into EXT1 (PK) values (1)")
|
||||
#
|
||||
#
|
||||
# db_conn.commit()
|
||||
#
|
||||
#
|
||||
# # session B
|
||||
# con2 = kdb.connect(dsn=dsn,user=user_name,password=user_password)
|
||||
# c2 = con2.cursor()
|
||||
# c2.execute('select * from EXT1')
|
||||
# printData(c2)
|
||||
#
|
||||
#
|
||||
# # cleanup
|
||||
# con2.close()
|
||||
# try:
|
||||
# os.remove(ext_filename)
|
||||
# except:
|
||||
# print("Error while removing external table file")
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """PK
|
||||
-----------
|
||||
1
|
||||
"""
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
external_table = temp_file('EXT1.TBL')
|
||||
|
||||
@pytest.mark.version('>=2.1.3')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
|
||||
|
||||
def test_1(act_1: Action, external_table: Path):
|
||||
# Create external table
|
||||
act_1.isql(switches=[],
|
||||
input=f"create table EXT1 external file '{str(external_table)}' (PK INTEGER); exit;")
|
||||
# session A
|
||||
with act_1.db.connect() as con:
|
||||
c = con.cursor()
|
||||
c.execute("insert into EXT1 (PK) values (1)")
|
||||
con.commit()
|
||||
# session B
|
||||
with act_1.db.connect() as con:
|
||||
c = con.cursor()
|
||||
c.execute('select * from EXT1')
|
||||
result = c.fetchall()
|
||||
assert result == [(1, )]
|
||||
|
@ -2,32 +2,32 @@
|
||||
#
|
||||
# id: bugs.core_2477
|
||||
# title: mon$memory_usage: Sorting memory should be reported as owned by the statement
|
||||
# decription:
|
||||
# decription:
|
||||
# We create view that gathers monitoring info related to all needed levels of statistics (DB, attachment, transaction, call).
|
||||
# Then this view is "customized" in order to leave only interested info about activity that will be started by separate isql process.
|
||||
# Then we start ascynchronously ISQL and make it stay in some (small) pause. At this moment we make first "photo" of mon$ info and store
|
||||
# it in dict object 'map_beg'.
|
||||
# NB: we should NOT wait too long because when SORT starts it can very fast to fill whole space of TempCacheLimit and mon$memory* counters
|
||||
# will not change since this poitn at all (===> one mey to get zero difference between mon$ countyers in this case).
|
||||
#
|
||||
#
|
||||
# After small pause (in ISQL connect) will gone, ISQL starts to do "huge sort" by invoking query with 'SELECT DISTINCT FROM <huge data source>'.
|
||||
# We wait about 1..2 second after this sort start and then make 2nd "photo" of monitoring counters and also store their values in another
|
||||
# We wait about 1..2 second after this sort start and then make 2nd "photo" of monitoring counters and also store their values in another
|
||||
# dict object ('map_end').
|
||||
#
|
||||
#
|
||||
# Finally, we force ISQL to finish (by moving DB in full shutdown state) and compare differences between corresp. values of map_end and map_beg.
|
||||
# Values for DATABASE level (mon$stat_group = 0) change only in SuperServer but never change in CS/SC and remain zero. We do not compare them.
|
||||
# Values for TRANSACTION level never increase; moreover, mon$memory_allocated counter at the "end-point" (when sorting is running) even is reduced
|
||||
# (and the reason still remain unknown for me; see letter to dimitr 04-may-2018 20:07).
|
||||
# So, we compare only difference of mon$memory* counters for ATTACHMENT and STATEMENT level (mon$stat_group = 1 and 3).
|
||||
#
|
||||
#
|
||||
# This difference must be not less than some threshold that depends on FB arch, for __BOTH__ levels (and this is main idea of this test)
|
||||
# ###################
|
||||
#
|
||||
#
|
||||
# Runs this test on firebird.conf with default TempCacheLimit show following values of differences:
|
||||
# 1) for SuperServer: ~68.1 Mb;
|
||||
# 1) for SuperServer: ~68.1 Mb;
|
||||
# 2) for Classic: ~9.4 Mb
|
||||
# For this reason minimal threshold for consider difference Ok is about 1 Mb (see MIN_DIFF_THRESHOLD).
|
||||
#
|
||||
#
|
||||
# Checked on (Windows 32 bit):
|
||||
# 25SC, build 2.5.9.27107: OK, 10.328s.
|
||||
# 25sS, build 2.5.8.27056: OK, 14.656s.
|
||||
@ -35,7 +35,10 @@
|
||||
# 30SS, build 3.0.4.32963: OK, 17.234s.
|
||||
# 40CS, build 4.0.0.955: OK, 11.219s.
|
||||
# 40SS, build 4.0.0.967: OK, 12.718s.
|
||||
#
|
||||
#
|
||||
# [pcisar] 16.11.2021
|
||||
# This test is too complicated and fragile, and it's IMHO not worth to be implemented
|
||||
#
|
||||
# tracker_id: CORE-2477
|
||||
# min_versions: ['2.5.0']
|
||||
# versions: 2.5
|
||||
@ -53,7 +56,7 @@ init_script_1 = """
|
||||
create or alter view v_mon as
|
||||
select *
|
||||
from (
|
||||
select
|
||||
select
|
||||
m.mon$stat_group as stat_gr
|
||||
,rpad( decode(m.mon$stat_group, 0,'0:database', 1,'1:attachment', 2,'2:transaction', 3,'3:statement', 4,'4:call'), 15,' ') as stat_type
|
||||
,m.mon$memory_used as memo_used
|
||||
@ -67,24 +70,24 @@ init_script_1 = """
|
||||
,coalesce( decode( s.mon$state, 0,'finished', 1,'running', 2,'suspended' ), 'n/a') as stm_state
|
||||
,lower(right( coalesce(trim(coalesce(a.mon$remote_process, a.mon$user)), ''), 20 )) as att_process -- isql.exe or Garbace Collector or Cache Writer
|
||||
,lower(left( coalesce(cast(s.mon$sql_text as varchar(2000)),''), 50 )) as sql_text
|
||||
from mon$memory_usage m
|
||||
from mon$memory_usage m
|
||||
left join mon$statements s on m.mon$stat_group = 3 and m.mon$stat_id = s.mon$stat_id
|
||||
left join mon$transactions t on
|
||||
left join mon$transactions t on
|
||||
m.mon$stat_group = 2 and m.mon$stat_id = t.mon$stat_id
|
||||
or m.mon$stat_group = 3 and m.mon$stat_id = s.mon$stat_id and t.mon$transaction_id = s.mon$transaction_id
|
||||
left join mon$attachments a on
|
||||
m.mon$stat_group = 1 and m.mon$stat_id = a.mon$stat_id
|
||||
left join mon$attachments a on
|
||||
m.mon$stat_group = 1 and m.mon$stat_id = a.mon$stat_id
|
||||
or m.mon$stat_group=2 and m.mon$stat_id = t.mon$stat_id and a.mon$attachment_id = t.mon$attachment_id
|
||||
or m.mon$stat_group=3 and m.mon$stat_id = s.mon$stat_id and a.mon$attachment_id = s.mon$attachment_id
|
||||
where
|
||||
s.mon$sql_text is null
|
||||
or
|
||||
where
|
||||
s.mon$sql_text is null
|
||||
or
|
||||
-- NB: There is additional statement like "SELECT RDB$MAP_USING, RDB$MAP_PLUGIN ..." in 4.0!
|
||||
-- We have to filter it out and leave here only "our" statement that does SORT job:
|
||||
s.mon$sql_text containing 'distinct'
|
||||
) t
|
||||
where
|
||||
t.stat_gr = 0
|
||||
where
|
||||
t.stat_gr = 0
|
||||
or
|
||||
t.att_process similar to '%[\\/]isql(.exe){0,1}'
|
||||
order by stat_type, stat_id;
|
||||
@ -98,55 +101,55 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
|
||||
# test_script_1
|
||||
#---
|
||||
#
|
||||
#
|
||||
# import os
|
||||
# import subprocess
|
||||
# from subprocess import Popen
|
||||
# import time
|
||||
# from fdb import services
|
||||
#
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
#
|
||||
#
|
||||
# db_file=db_conn.database_name
|
||||
#
|
||||
#
|
||||
# db_conn.close()
|
||||
#
|
||||
#
|
||||
# ISQL_USER=user_name
|
||||
# ISQL_PSWD=user_password
|
||||
#
|
||||
#
|
||||
# MIN_DIFF_THRESHOLD=1000000
|
||||
#
|
||||
#
|
||||
# # change on True if one need to look at intermediate results of gathering mon$ info
|
||||
# # (before ISQL async launch; after launch but before starting sort; while sorting)
|
||||
# RUN_DBG=False
|
||||
#
|
||||
#
|
||||
# DELAY_IN_ISQL_BEFORE_IT_STARTS_SORT = 3
|
||||
# DELAY_FOR_ISQL_ESTABLISH_ITS_CONNECT = 1
|
||||
# DELAY_BEFORE_MON_WHILE_SORT_IS_RUNNING = DELAY_IN_ISQL_BEFORE_IT_STARTS_SORT + DELAY_FOR_ISQL_ESTABLISH_ITS_CONNECT + 1
|
||||
#
|
||||
#
|
||||
# SQL_GATHER_SORT_INFO='''
|
||||
# select
|
||||
# v.att_process,
|
||||
# replace(replace(replace(replace(v.sql_text, ascii_char(10),' '), ascii_char(13),' '),' ',' '),' ',' ') as sql_text,
|
||||
# v.stat_type,
|
||||
# v.stm_state,
|
||||
# v.att_id,
|
||||
# v.trn_id,
|
||||
# v.sttm_id,
|
||||
# v.memo_used,
|
||||
# v.memo_allo,
|
||||
# v.max_memo_used,
|
||||
# v.max_memo_allo
|
||||
# from v_mon v
|
||||
# select
|
||||
# v.att_process,
|
||||
# replace(replace(replace(replace(v.sql_text, ascii_char(10),' '), ascii_char(13),' '),' ',' '),' ',' ') as sql_text,
|
||||
# v.stat_type,
|
||||
# v.stm_state,
|
||||
# v.att_id,
|
||||
# v.trn_id,
|
||||
# v.sttm_id,
|
||||
# v.memo_used,
|
||||
# v.memo_allo,
|
||||
# v.max_memo_used,
|
||||
# v.max_memo_allo
|
||||
# from v_mon v
|
||||
# where v.att_id is distinct from current_connection
|
||||
# '''
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------------------------
|
||||
#
|
||||
#
|
||||
# def result_msg(a_diff_value, a_min_threshold):
|
||||
# return ( ('OK, expected: increased significantly.') if a_diff_value > a_min_threshold else ('BAD! Did not increased as expected. Difference: ' + "{:d}".format(a_diff_value)+'.') )
|
||||
#
|
||||
#
|
||||
# def debug_store_mon_view(dsn, SQL_GATHER_SORT_INFO, file_name_suffix):
|
||||
# global os
|
||||
# global subprocess
|
||||
@ -157,14 +160,14 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# subprocess.call( [ context['isql_path'], dsn, '-q', '-n', '-i', f_sql_dbg.name ], stdout=f_log_dbg, stderr = subprocess.STDOUT)
|
||||
# f_log_dbg.close()
|
||||
# os.remove(f_sql_dbg.name)
|
||||
#
|
||||
#
|
||||
# def forcely_clean_attachments_by_shutdown_online( db_file ):
|
||||
#
|
||||
#
|
||||
# global RUN_DBG
|
||||
# global os
|
||||
#
|
||||
#
|
||||
# f_shutdown_log = open( os.path.join(context['temp_directory'],'tmp_shutdown_and_online_2477.log'), 'w')
|
||||
#
|
||||
#
|
||||
# subprocess.call( [context['fbsvcmgr_path'], "localhost:service_mgr",
|
||||
# "action_properties", "prp_shutdown_mode", "prp_sm_full", "prp_shutdown_db", "0",
|
||||
# "dbname", db_file,
|
||||
@ -172,7 +175,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# stdout = f_shutdown_log,
|
||||
# stderr = subprocess.STDOUT
|
||||
# )
|
||||
#
|
||||
#
|
||||
# subprocess.call( [context['fbsvcmgr_path'],"localhost:service_mgr",
|
||||
# "action_db_stats",
|
||||
# "dbname", db_file, "sts_hdr_pages"
|
||||
@ -180,7 +183,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# stdout = f_shutdown_log,
|
||||
# stderr=subprocess.STDOUT
|
||||
# )
|
||||
#
|
||||
#
|
||||
# subprocess.call( [context['fbsvcmgr_path'], "localhost:service_mgr",
|
||||
# "action_properties", "prp_db_online",
|
||||
# "dbname", db_file,
|
||||
@ -195,16 +198,16 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# stdout = f_shutdown_log,
|
||||
# stderr=subprocess.STDOUT
|
||||
# )
|
||||
#
|
||||
#
|
||||
# f_shutdown_log.close()
|
||||
#
|
||||
#
|
||||
# if not RUN_DBG:
|
||||
# os.remove(f_shutdown_log.name)
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------------------
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# sql_text='''
|
||||
# commit;
|
||||
# set transaction lock timeout %(DELAY_IN_ISQL_BEFORE_IT_STARTS_SORT)s;
|
||||
@ -218,15 +221,15 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# on external 'localhost:' || rdb$get_context('SYSTEM','DB_NAME')
|
||||
# as user '%(ISQL_USER)s' password '%(ISQL_PSWD)s'
|
||||
# ;
|
||||
# when any do
|
||||
# begin
|
||||
# when any do
|
||||
# begin
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# select count(*)
|
||||
# from (
|
||||
#
|
||||
# select count(*)
|
||||
# from (
|
||||
# -- this force to use "PLAN SORT":
|
||||
# select distinct lpad('', 500, uuid_to_char(gen_uuid())) s from rdb$types a,rdb$types b, rdb$types c
|
||||
# select distinct lpad('', 500, uuid_to_char(gen_uuid())) s from rdb$types a,rdb$types b, rdb$types c
|
||||
# )
|
||||
# into c;
|
||||
# suspend;
|
||||
@ -234,73 +237,73 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# ^
|
||||
# set term ;^
|
||||
# ''' %locals()
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# f_isql_cmd=open( os.path.join(context['temp_directory'],'tmp_2477_sort.sql'), 'w')
|
||||
# f_isql_cmd.write(sql_text)
|
||||
# f_isql_cmd.close()
|
||||
#
|
||||
#
|
||||
# if RUN_DBG:
|
||||
# debug_store_mon_view(dsn, SQL_GATHER_SORT_INFO, '0')
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# # Launch async-ly ISQL which must establish connect and:
|
||||
# # 1) stay in small delay
|
||||
# # 2) start "big sorting" job (for at least 20-30 seconds):
|
||||
#
|
||||
#
|
||||
# f_log_sort=open( os.path.join(context['temp_directory'], 'tmp_2477_sort.log'), 'w')
|
||||
# p_sql = subprocess.Popen( [ context['isql_path'], dsn, '-q', '-n', '-i', f_isql_cmd.name ], stdout=f_log_sort, stderr = subprocess.STDOUT)
|
||||
#
|
||||
#
|
||||
# # do NOT remove this delay: we have to wait while ISQL for sure will establish connection.
|
||||
# ##########################
|
||||
# time.sleep( DELAY_FOR_ISQL_ESTABLISH_ITS_CONNECT )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# if RUN_DBG:
|
||||
# # NOTE: assign RUN_DBG to True and look in debug snapshot file tmp_c2477_dbg1.log
|
||||
# # with results of 1st gathering of mon$ info. If it will contain only one record (of DB level)
|
||||
# # than it means that we have to increase DELAY_FOR_ISQL_ESTABLISH_ITS_CONNECT value):
|
||||
# debug_store_mon_view(dsn, SQL_GATHER_SORT_INFO, '1')
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# # Start separate connect for gather monio
|
||||
# con_mon=fdb.connect(dsn=dsn)
|
||||
# cur_mon=con_mon.cursor()
|
||||
#
|
||||
#
|
||||
# # Gather info from mon$memory_usage before SORT start (ISQL stays in pause now):
|
||||
# ###################################
|
||||
# cur_mon.execute(SQL_GATHER_SORT_INFO)
|
||||
#
|
||||
#
|
||||
# map_beg={}
|
||||
#
|
||||
#
|
||||
# # Take at once all the records that cursor can return (actually it can return only 5 records in 3.0+ SS):
|
||||
# for x in cur_mon.fetchmanymap(99):
|
||||
# # we need only several for storing as KEY-VALUE pairs from the whole set of columns of view v_mon:
|
||||
# (stat_type, att_id, trn_id, sttm_id) = ( v for k,v in x.items() if k in ( 'STAT_TYPE', 'ATT_ID', 'TRN_ID', 'STTM_ID') )
|
||||
# val = [ v for k,v in x.items() if k in ('MEMO_USED', 'MEMO_ALLO') ]
|
||||
#
|
||||
#
|
||||
# map_beg[ stat_type, att_id, trn_id, sttm_id ] = val
|
||||
#
|
||||
#
|
||||
# #for k,v in sorted(map_beg.items()):
|
||||
# # print('::: beg ::: k=',k,'; v=',v)
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# cur_mon.close()
|
||||
#
|
||||
#
|
||||
# # This is mandatory before any subsequent gathering mon$ info:
|
||||
# con_mon.commit()
|
||||
#
|
||||
#
|
||||
# # This *seems* not necessary but one need to test this again in SC/CS:
|
||||
# con_mon.close()
|
||||
# con_mon=fdb.connect(dsn=dsn)
|
||||
#
|
||||
#
|
||||
# # this delay is mandatory and must be greater than delay in ISQL
|
||||
# # (see 'set tran lock timeout N' in its sql script).
|
||||
# # We have to give ISQL to actually start SORT job:
|
||||
# time.sleep( DELAY_BEFORE_MON_WHILE_SORT_IS_RUNNING )
|
||||
#
|
||||
#
|
||||
# cur_mon=con_mon.cursor()
|
||||
#
|
||||
#
|
||||
# # Gather info from mon$memory_usage when SORT is running:
|
||||
# ###################################
|
||||
# cur_mon.execute(SQL_GATHER_SORT_INFO)
|
||||
@ -308,66 +311,66 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# for x in cur_mon.fetchmanymap(99):
|
||||
# (stat_type, att_id, trn_id, sttm_id) = ( v for k,v in x.items() if k in ( 'STAT_TYPE', 'ATT_ID', 'TRN_ID', 'STTM_ID') )
|
||||
# val = [ v for k,v in x.items() if k in ('MEMO_USED', 'MEMO_ALLO') ]
|
||||
#
|
||||
#
|
||||
# map_end[ stat_type, att_id, trn_id, sttm_id ] = val
|
||||
#
|
||||
#
|
||||
# cur_mon.close()
|
||||
#
|
||||
#
|
||||
# if RUN_DBG:
|
||||
# # NOTE: assign RUN_DBG to True and look in debug snapshot file tmp_c2477_dbg1.log
|
||||
# # with results of 1st gathering of mon$ info.
|
||||
# debug_store_mon_view(dsn, SQL_GATHER_SORT_INFO, '2')
|
||||
#
|
||||
#
|
||||
# con_mon.close()
|
||||
#
|
||||
#
|
||||
# # We have to be sure that NO ANY activity remains in the database before finish this test.
|
||||
# # Unfortunately, it seems that just killing process of ISQL (that was launched async-ly) not enough,
|
||||
# # so we turn database offline and bring back online:
|
||||
# forcely_clean_attachments_by_shutdown_online( db_file )
|
||||
#
|
||||
#
|
||||
# # ::: !! :::
|
||||
# ########################################
|
||||
# # TERMINATE ISQL THAT DOES HUGE SORT JOB
|
||||
# ########################################
|
||||
# p_sql.terminate()
|
||||
# f_log_sort.close()
|
||||
#
|
||||
#
|
||||
# #time.sleep(1)
|
||||
#
|
||||
#
|
||||
# for k,v in sorted(map_beg.items()):
|
||||
#
|
||||
#
|
||||
# if 'database' in k[0]:
|
||||
# # mon$memory_* counters always ZERO in CS/SC for database level
|
||||
# pass
|
||||
#
|
||||
#
|
||||
# if 'transaction' in k[0]:
|
||||
# # mon$memory_* counters never change for transaction level (reason currently is unknown).
|
||||
# pass
|
||||
#
|
||||
#
|
||||
# if 'attachment' in k[0] or 'statement' in k[0]:
|
||||
#
|
||||
#
|
||||
# (beg_memo_used, beg_memo_allo) = v
|
||||
#
|
||||
#
|
||||
# (end_memo_used, end_memo_allo) = map_end.get(k)
|
||||
# (dif_memo_used, dif_memo_allo) = (end_memo_used - beg_memo_used, end_memo_allo - beg_memo_allo)
|
||||
#
|
||||
#
|
||||
# #print( k[0].rstrip()+':' )
|
||||
# # 4debug: output value of mon$memory* counters difference:
|
||||
# #print( ' '.join( (' * DELTA of mon$memory_used:', "{:9d}".format(dif_memo_used), result_msg(dif_memo_used, MIN_DIFF_THRESHOLD) ) ) )
|
||||
# #print( ' '.join( (' * DELTA of mon$memory_allo:', "{:9d}".format(dif_memo_allo), result_msg(dif_memo_allo, MIN_DIFF_THRESHOLD) ) ) )
|
||||
#
|
||||
#
|
||||
# print( ' '.join( k[0].split(':') ).rstrip() )
|
||||
# print( ' * DELTA of mon$memory_used: ' + result_msg(dif_memo_used, MIN_DIFF_THRESHOLD) )
|
||||
# print( ' * DELTA of mon$memory_allo: ' + result_msg(dif_memo_allo, MIN_DIFF_THRESHOLD) )
|
||||
#
|
||||
#
|
||||
# # cleanup:
|
||||
# ##########
|
||||
# time.sleep(1)
|
||||
# f_list = (f_isql_cmd, f_log_sort)
|
||||
# for f in f_list:
|
||||
# os.remove(f.name)
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
|
@ -2,61 +2,66 @@
|
||||
#
|
||||
# id: bugs.core_2484
|
||||
# title: Success message when connecting to tiny trash database file
|
||||
# decription:
|
||||
# decription:
|
||||
# We make invalid FDB file by creating binary file and write small data piece to it.
|
||||
# Then we try to connect to such "database" using ISQL with passing trivial command
|
||||
# like 'select current_timestamp' for execution.
|
||||
# ISQL must raise error and quit (obviously without any result to STDOUT).
|
||||
#
|
||||
#
|
||||
# ::: NB :::
|
||||
# If Windows with non-ascii language is used then message about overlapped IO
|
||||
# ("-Overlapped I/O operation is in progress") will be translated by OS to localized
|
||||
# text and it will be displayed in STDERR. This message must be suppressed or ignored.
|
||||
#
|
||||
#
|
||||
# Because of this, it was decided to redirect output of ISQL to logs and open
|
||||
# them using codecs.open() with errors='ignore' option.
|
||||
# We check presense of error message in STDERR file created by ISQL.
|
||||
# It is ennough to verify that STDERR log contains pattern 'SQLSTATE = '.
|
||||
# Checked on 4.0.0.2164; 3.0.7.33356
|
||||
#
|
||||
#
|
||||
# 02-mar-2021. Re-implemented in order to have ability to run this test on Linux.
|
||||
#
|
||||
#
|
||||
# NOTE: message that clearly points to the reason of failed connection is shown
|
||||
# only on Linux FB 3.x:
|
||||
# =====
|
||||
# Statement failed, SQLSTATE = 08004
|
||||
# file <...>/tmp_2484_fake.fdb is not a valid database
|
||||
# =====
|
||||
#
|
||||
#
|
||||
# All other cases produce SQLSTATE = 08001 and somewhat strange after it (from my POV):
|
||||
# =====
|
||||
# Windows:
|
||||
# I/O error during "ReadFile" operation for file "<...>\\TMP_2484_FAKE.FDB"
|
||||
# -Error while trying to read from file
|
||||
#
|
||||
#
|
||||
# Linux:
|
||||
# I/O error during "read_retry" operation for file "<...>/tmp_2484_fake.fdb"
|
||||
# -Error while trying to read from file
|
||||
# -Success <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< :-)
|
||||
# =====
|
||||
#
|
||||
#
|
||||
# Checked on:
|
||||
# * Windows: 4.0.0.2377, 3.0.8.33420 -- both on SS/CS
|
||||
# * Linux: 4.0.0.2377, 3.0.8.33415
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-2484
|
||||
# min_versions: ['3.0']
|
||||
# versions: 3.0
|
||||
# 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
|
||||
# resources: None
|
||||
|
||||
substitutions_1 = [('SQLSTATE = 08004', 'SQLSTATE = 08001')]
|
||||
substitutions_1 = [('SQLSTATE = 08004', 'SQLSTATE = 08001'),
|
||||
('I/O error during.*', ''),
|
||||
('-File size is less than expected', ''),
|
||||
('-Error while.*', ''),
|
||||
('Use CONNECT or CREATE DATABASE to specify a database', '')]
|
||||
|
||||
init_script_1 = """"""
|
||||
|
||||
@ -64,34 +69,34 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
|
||||
|
||||
# test_script_1
|
||||
#---
|
||||
#
|
||||
#
|
||||
# import os
|
||||
# import subprocess
|
||||
# import codecs
|
||||
# import re
|
||||
# import time
|
||||
#
|
||||
#
|
||||
# db_conn.close()
|
||||
# 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
|
||||
# # 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 )):
|
||||
@ -102,20 +107,20 @@ db_1 = db_factory(charset='UTF8', 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 )
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# f_fake_fdb = open( os.path.join(context['temp_directory'],'tmp_2484_fake.fdb'), 'wb')
|
||||
# f_fake_fdb.write('ŒåŁä')
|
||||
# flush_and_close( f_fake_fdb )
|
||||
#
|
||||
#
|
||||
# f_fake_sql = open( os.path.splitext(f_fake_fdb.name)[0]+'.sql', 'w')
|
||||
# f_fake_sql.write('set heading off; select current_timestamp from rdb$database; quit;')
|
||||
# flush_and_close( f_fake_sql )
|
||||
#
|
||||
#
|
||||
# f_fake_log = open( os.path.splitext(f_fake_fdb.name)[0]+'.log', 'w')
|
||||
# f_fake_err = open( os.path.splitext(f_fake_fdb.name)[0]+'.err', 'w')
|
||||
# subprocess.call( [ context['isql_path'], 'localhost:' + f_fake_fdb.name, "-i", f_fake_sql.name ],
|
||||
@ -124,7 +129,7 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
|
||||
# )
|
||||
# flush_and_close( f_fake_log )
|
||||
# flush_and_close( f_fake_err )
|
||||
#
|
||||
#
|
||||
# ###########################################################################
|
||||
# # Linux, FB 3.x:
|
||||
# # Statement failed, SQLSTATE = 08004
|
||||
@ -133,7 +138,7 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
|
||||
# # Statement failed, SQLSTATE = 08001
|
||||
# # I/O error during "ReadFile" operation for file "<...>\\TMP_2484_FAKE.FDB"
|
||||
# # -Error while trying to read from file
|
||||
#
|
||||
#
|
||||
# # Linux, FB 4.x:
|
||||
# # Statement failed, SQLSTATE = 08001
|
||||
# # I/O error during "read_retry" operation for file "<...>/tmp_2484_fake.fdb"
|
||||
@ -145,34 +150,43 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
|
||||
# # -Error while trying to read from file
|
||||
# # Overlapped I/O operation is in progress << WILL BE IN LOCALIZED FORM!
|
||||
# ###########################################################################
|
||||
#
|
||||
#
|
||||
# p = re.compile('SQLSTATE\\s+=\\s+',re.IGNORECASE)
|
||||
# with codecs.open( filename = f_fake_err.name, mode = 'r', errors = 'ignore') as f:
|
||||
# for line in f:
|
||||
# if p.search(line):
|
||||
# print(line)
|
||||
#
|
||||
#
|
||||
# with codecs.open( filename = f_fake_log.name, mode = 'r', errors = 'ignore') as f:
|
||||
# for line in f:
|
||||
# if p.search(line):
|
||||
# print('UNEXPECTED STDOUT: ' + line)
|
||||
#
|
||||
#
|
||||
# # cleanup:
|
||||
# ##########
|
||||
# time.sleep(1)
|
||||
# cleanup( ( f_fake_fdb, f_fake_sql, f_fake_log, f_fake_err ) )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
Statement failed, SQLSTATE = 08001
|
||||
"""
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
expected_stderr_1 = """
|
||||
Statement failed, SQLSTATE = 08001
|
||||
"""
|
||||
|
||||
fake_db = temp_file('tmp_2484_fake.fdb')
|
||||
|
||||
@pytest.mark.version('>=3.0')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
def test_1(act_1: Action, fake_db: Path):
|
||||
fake_db.write_bytes(bytes([1, 2, 3, 4, 5, 6, 0]))
|
||||
act_1.expected_stdout = ''
|
||||
act_1.expected_stderr = expected_stderr_1
|
||||
act_1.isql(switches=['-user', act_1.db.user, '-password', act_1.db.password, str(fake_db)],
|
||||
connect_db=False,
|
||||
input='set heading off; select current_timestamp from rdb$database; quit;')
|
||||
assert act_1.clean_stderr == act_1.clean_expected_stderr
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
||||
|
||||
|
@ -2,59 +2,61 @@
|
||||
#
|
||||
# id: bugs.core_2531
|
||||
# title: The famous "cannot transliterate" error may be thrown when selecting data from the monitoring tables
|
||||
# decription:
|
||||
# decription:
|
||||
# In order to check issues of ticket we have to create Python script which is encoded in non-ascii codepage and also
|
||||
# its codepage should be NON utf8 (choosed: Windows 1252). This is because all .fbt files have to be encoded only in UTF8,
|
||||
# so we can not put inside .fbt a statement which contains non-ascii SINGLE-BYTE characters.
|
||||
#
|
||||
#
|
||||
# Character |å|, "LATIN SMALL LETTER A WITH RING ABOVE", was selected in order to verify ticket issue, see:
|
||||
# http://www.fileformat.info/info/unicode/char/00e5/index.htm
|
||||
#
|
||||
#
|
||||
# Temporary Python file ("tmp_2531_run.py") will contain encoding statement ('# coding: latin-1') followed by commands for:
|
||||
# 1) make first attachment to database, by Python itself, with charset = Win1252, with preparing: "select 'gång' from rdb$database";
|
||||
# also, this attachments SAVES string of this query into table (NOTE: it works with charset = win1252);
|
||||
# 2) make second attachment by ISQL, with charset = utf8, which will query mon$statements.mon$sql_text - this should return query
|
||||
# which has been prepared by first attachment. This query is compared to that which was stored into table by attachment-1,
|
||||
# and these rows should be equal: |select 'gång' from rdb$database|
|
||||
#
|
||||
#
|
||||
# Confirmed wrong (incompleted) output of mon$sql_text on 2.1.0.17798 (but there is no "cannot transliterate" error):
|
||||
# ===
|
||||
# select 'gång: ' || current_timestamp from rdb$database
|
||||
# select 'g
|
||||
# select 'gång: ' || current_timestamp from rdb$database
|
||||
# select 'g
|
||||
# ^^^
|
||||
# |
|
||||
# +--- three white-spaces here (after 'g')
|
||||
# ===
|
||||
# ===
|
||||
# No such effect on builds >= 2.1.3.18185.
|
||||
#
|
||||
#
|
||||
# Refactored 08-may-2017: replaced buggy "folder.replace()" with bulk of backslashes ("") with locals() usage.
|
||||
# Checked again on Classic for: WI-V3.0.2.32708, WI-T4.0.0.633
|
||||
# Checked again on Classic for: WI-V3.0.2.32708, WI-T4.0.0.633
|
||||
# (added expression to WHERE-block to filter out record from mon$statements with RDB$AUTH_MAPPING data).
|
||||
#
|
||||
#
|
||||
# 02-MAR-2021:
|
||||
# Changed code in order to remove dependency on PATH-list (CLI utilities must be invoked using context['..._path'])
|
||||
# Full path+name of FB client library file is passed to generated Python code.
|
||||
# Removed unneeded variables.
|
||||
#
|
||||
#
|
||||
# Checked on Windows: 4.0.0.2377 (SS/CS), 3.0.8.33420 (SS/CS), 2.5.9.27152 (SC)
|
||||
# Checked on Linux: 4.0.0.2377, 3.0.8.33415.
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-2531
|
||||
# min_versions: ['2.5.0']
|
||||
# versions: 2.5
|
||||
# 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
|
||||
|
||||
substitutions_1 = [('SQL_TEXT_BLOB_ID .*', ''), ('[\t ]+', ' ')]
|
||||
|
||||
init_script_1 = """"""
|
||||
init_script_1 = """
|
||||
recreate table non_ascii(stored_sql_expr varchar(255) character set win1252);
|
||||
"""
|
||||
|
||||
db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
db_1 = db_factory(sql_dialect=3, init=init_script_1, charset='WIN1252')
|
||||
|
||||
# test_script_1
|
||||
#---
|
||||
@ -64,18 +66,16 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# import time
|
||||
# import codecs
|
||||
# from fdb import services
|
||||
#
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
# engine = db_conn.engine_version
|
||||
# db_conn.close()
|
||||
#
|
||||
#
|
||||
# svc = services.connect()
|
||||
# FB_HOME = os.path.normpath( svc.get_home_directory() ) # 'c:
|
||||
# irebird' --> 'c:
|
||||
# irebird' (i.e. remove trailing backslash if needed)
|
||||
# FB_HOME = os.path.normpath( svc.get_home_directory() ) # 'c:\\firebird\\' --> 'c:\\firebird' (i.e. remove trailing backslash if needed)
|
||||
# svc.close()
|
||||
#
|
||||
#
|
||||
# FB_CLNT = '<UNKNOWN>'
|
||||
# if os.name == 'nt':
|
||||
# # For Windows we assume that client library is always in FB_HOME dir:
|
||||
@ -87,24 +87,24 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# # For Linux client library will be searched in 'lib' subdirectory of FB_HOME:
|
||||
# # con=fdb.connect( dsn='localhost:employee', fb_library_name='/var/tmp/fb40tmp/lib/libfbclient.so', ...)
|
||||
# FB_CLNT=os.path.join(FB_HOME, 'lib', 'libfbclient.so' )
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# 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'):
|
||||
# # 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 )):
|
||||
@ -115,19 +115,19 @@ db_1 = db_factory(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 )
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# #non_ascii_query="select 'gång' from rdb$database"
|
||||
# non_ascii_query=u"select 'gång' as non_ascii_literal from rdb$database"
|
||||
#
|
||||
#
|
||||
# f_sql_txt='''
|
||||
# set count on;
|
||||
# set blob all;
|
||||
# set list on;
|
||||
# set list on;
|
||||
# select stored_sql_expr from non_ascii;
|
||||
# select
|
||||
# c.rdb$character_set_name as connection_charset
|
||||
@ -140,14 +140,14 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# and s.mon$sql_text containing 'non_ascii_literal'
|
||||
# ;
|
||||
# '''
|
||||
#
|
||||
#
|
||||
# f_mon_sql = open( os.path.join(context['temp_directory'], 'tmp_2531_w1252.sql'), 'w' )
|
||||
# f_mon_sql.write(f_sql_txt)
|
||||
# flush_and_close( f_mon_sql )
|
||||
#
|
||||
#
|
||||
# isql_path = context['isql_path']
|
||||
# isql_file = f_mon_sql.name
|
||||
#
|
||||
#
|
||||
# ######################################################################
|
||||
# ### t e m p o r a r y P y t h o n s c r i p t s t ar t ###
|
||||
# ######################################################################
|
||||
@ -157,57 +157,58 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# import subprocess
|
||||
# os.environ["ISC_USER"] = '%(user_name)s'
|
||||
# os.environ["ISC_PASSWORD"] = '%(user_password)s'
|
||||
#
|
||||
#
|
||||
# att1 = fdb.connect(dsn = r'%(dsn)s', fb_library_name = r'%(FB_CLNT)s', charset = 'win1252')
|
||||
# att1.execute_immediate("recreate table non_ascii(stored_sql_expr varchar(255) character set win1252)")
|
||||
# att1.commit()
|
||||
#
|
||||
#
|
||||
# txt = "%(non_ascii_query)s"
|
||||
#
|
||||
#
|
||||
# cur1=att1.cursor()
|
||||
# cur1.execute( "insert into non_ascii(stored_sql_expr) values('%%s')" %% txt.replace("'","''") )
|
||||
# att1.commit()
|
||||
#
|
||||
#
|
||||
# # The will cause SQL expression with non-ascii character
|
||||
# # appear in mon$statements.mon$sql_text column.
|
||||
# # NOTE: charset of current connection is >>> win1252 <<<
|
||||
# cur1.prep(txt)
|
||||
#
|
||||
#
|
||||
# subprocess.call([ r'%(isql_path)s', r'%(dsn)s', '-ch', 'utf8', '-i', r'%(isql_file)s' ])
|
||||
#
|
||||
#
|
||||
# cur1.close()
|
||||
# att1.commit()
|
||||
# att1.close()
|
||||
# ''' % dict(globals(), **locals())
|
||||
# ############## temporary Python script finish ###################
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# #####################################################################
|
||||
# ### Create temporary Python script with code page = Windows-1252, ###
|
||||
# ### so |select 'gång' from rdb$database| will be written there in ###
|
||||
# ### single-byte encoding rather than in utf8. ###
|
||||
# ### single-byte encoding rather than in utf8. ###
|
||||
# ####################################################################
|
||||
# f_python_run=codecs.open( os.path.join(context['temp_directory'],'tmp_2531_w1252.py'), encoding='cp1252', mode='w')
|
||||
# f_python_run.write(f_python_txt)
|
||||
#
|
||||
#
|
||||
# flush_and_close( f_python_run )
|
||||
# time.sleep(1)
|
||||
#
|
||||
#
|
||||
# runProgram( sys.executable, [f_python_run.name] )
|
||||
#
|
||||
#
|
||||
# # 02.03.2021 DO NOT! subprocess.call( [sys.executable, f_python_run.name] ) -- for unknown reason this will NOT issu anything to STDOUT!
|
||||
#
|
||||
#
|
||||
# time.sleep(1)
|
||||
#
|
||||
#
|
||||
# # 02.03.2021: do NOT pass to cleanup() files!
|
||||
# # It will fail with 'uknown type' for executed script ('f_python_run')
|
||||
# # because it will consider its type as 'instance' rather than common 'file'!
|
||||
# # We have to pass only NAMES list of used files here:
|
||||
# cleanup( [i.name for i in (f_python_run,f_mon_sql)] )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
STORED_SQL_EXPR select 'gång' as non_ascii_literal from rdb$database
|
||||
@ -218,8 +219,32 @@ 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):
|
||||
non_ascii_query = "select 'gång' as non_ascii_literal from rdb$database"
|
||||
non_ascii_query_inline = non_ascii_query.replace("'","''")
|
||||
script = '''
|
||||
set count on;
|
||||
set blob all;
|
||||
set list on;
|
||||
select stored_sql_expr from non_ascii;
|
||||
select
|
||||
c.rdb$character_set_name as connection_charset
|
||||
,s.mon$sql_text as sql_text_blob_id
|
||||
from mon$attachments a
|
||||
left join rdb$character_sets c on a.mon$character_set_id = c.rdb$character_set_id
|
||||
left join mon$statements s on a.mon$attachment_id = s.mon$attachment_id
|
||||
where
|
||||
s.mon$attachment_id <> current_connection
|
||||
and s.mon$sql_text containing 'non_ascii_literal'
|
||||
;
|
||||
'''
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
with act_1.db.connect(charset='WIN1252') as con:
|
||||
c = con.cursor()
|
||||
c.execute(f"insert into non_ascii(stored_sql_expr) values('{non_ascii_query_inline}')")
|
||||
con.commit()
|
||||
x = c.prepare(non_ascii_query)
|
||||
act_1.isql(switches=[], input=script, charset='WIN1252')
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
||||
|
||||
|
@ -2,14 +2,14 @@
|
||||
#
|
||||
# id: bugs.core_2573
|
||||
# title: The server crashes when selecting from the MON$ tables in the ON DISCONNECT trigger
|
||||
# decription:
|
||||
# decription:
|
||||
# tracker_id: CORE-2573
|
||||
# min_versions: []
|
||||
# versions: 2.5
|
||||
# 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
|
||||
@ -30,24 +30,39 @@ db_1 = db_factory(page_size=4096, sql_dialect=3, init=init_script_1)
|
||||
# select mon$stat_id from mon$attachments rows 1 into :i;
|
||||
# end
|
||||
# """
|
||||
#
|
||||
#
|
||||
# c = db_conn.cursor()
|
||||
# c.execute(sql)
|
||||
# db_conn.commit()
|
||||
# db_conn.close()
|
||||
#
|
||||
#
|
||||
# db_conn = kdb.connect(dsn=dsn,user=user_name,password=user_password)
|
||||
# c = db_conn.cursor()
|
||||
# c.execute("DROP TRIGGER DIST")
|
||||
# db_conn.commit()
|
||||
# db_conn.close()
|
||||
#---
|
||||
#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')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
def test_1(act_1: Action):
|
||||
sql = """CREATE OR ALTER TRIGGER DIST
|
||||
ON DISCONNECT POSITION 0
|
||||
AS
|
||||
declare variable i integer;
|
||||
begin
|
||||
select mon$stat_id from mon$attachments rows 1 into :i;
|
||||
end
|
||||
"""
|
||||
with act_1.db.connect() as con:
|
||||
c = con.cursor()
|
||||
c.execute(sql)
|
||||
con.commit()
|
||||
# The server should could be crashed at this point
|
||||
with act_1.db.connect() as con:
|
||||
c = con.cursor()
|
||||
c.execute('DROP TRIGGER DIST')
|
||||
con.commit()
|
||||
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
#
|
||||
# id: bugs.core_2602
|
||||
# title: Attachments using NONE charset may cause reads from MON$ tables to fail
|
||||
# decription:
|
||||
# decription:
|
||||
# Fully refactored 05-feb-2018. Apply HASH() functions to unicode mon$sql_text in order to returnonly numeric value
|
||||
# rather than non-translatable unicode representation which can differ on machines with different codepage / OS.
|
||||
# For example, instead of (on Win XP with codepage 1251):
|
||||
@ -16,7 +16,7 @@
|
||||
# - lock conflict on no wait transaction', -901, 335544345)
|
||||
# - just after issued 1st cursor result.
|
||||
# No error since 2.5.0.26074.
|
||||
#
|
||||
#
|
||||
# 25.12.2019: added filtering expr to WHERE clause in order to prevent from passing through records related to RDB$AUTH table (4.x).
|
||||
# Last tested 25.12.2019 on:
|
||||
# 4.0.0.1707 SS: 1.448s.
|
||||
@ -27,14 +27,14 @@
|
||||
# 3.0.5.33212 CS: 1.755s.
|
||||
# 2.5.9.27149 SC: 0.218s.
|
||||
# 2.5.9.27119 SS: 2.411s.
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-2602
|
||||
# min_versions: ['2.5']
|
||||
# versions: 2.5
|
||||
# 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
|
||||
@ -47,34 +47,34 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
|
||||
|
||||
# test_script_1
|
||||
#---
|
||||
#
|
||||
#
|
||||
# import os
|
||||
# import fdb
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
#
|
||||
#
|
||||
# db_conn.close()
|
||||
#
|
||||
#
|
||||
# c1none=fdb.connect(dsn=dsn,charset='none')
|
||||
# c1utf8=fdb.connect(dsn=dsn,charset='utf8')
|
||||
#
|
||||
#
|
||||
# c2none=fdb.connect(dsn=dsn,charset='none')
|
||||
# c2utf8=fdb.connect(dsn=dsn,charset='utf8')
|
||||
#
|
||||
#
|
||||
# r1none = c1none.cursor()
|
||||
# r1utf8 = c1utf8.cursor()
|
||||
#
|
||||
#
|
||||
# r2none = c2none.cursor()
|
||||
# r2utf8 = c2utf8.cursor()
|
||||
#
|
||||
#
|
||||
# # In attachment with charset = NONE we start query to mon$database which includes two non-ascii characters:
|
||||
# # 1) Unicode Character 'LATIN SMALL LETTER A WITH ACUTE' (U+00E1)
|
||||
# # 1) Unicode Character 'LATIN SMALL LETTER A WITH ACUTE' (U+00E1)
|
||||
# # 2) Unicode Character 'LATIN SMALL LETTER E WITH ACUTE' (U+00E9)
|
||||
# r1none.execute("select '123áé456' from mon$database")
|
||||
#
|
||||
#
|
||||
# sql='''
|
||||
# select
|
||||
# iif(s.mon$attachment_id = current_connection, 'this', 'othr') as attach
|
||||
# select
|
||||
# iif(s.mon$attachment_id = current_connection, 'this', 'othr') as attach
|
||||
# -- do NOT return SQL text of query with non-ascii characters: it can be displayed differently
|
||||
# -- depending on machine codepage (or OS?):
|
||||
# -- >>> disabled 05-feb-2018 >>> , iif(s.mon$sql_text like '%123%456%', s.mon$sql_text, '') as sql_text
|
||||
@ -85,49 +85,50 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
|
||||
# join mon$attachments a on s.mon$attachment_id = a.mon$attachment_id
|
||||
# join rdb$character_sets c on a.mon$character_set_id = c.rdb$character_set_id
|
||||
# where
|
||||
# s.mon$attachment_id != current_connection
|
||||
# s.mon$attachment_id != current_connection
|
||||
# and s.mon$sql_text NOT containing 'mon$statements'
|
||||
# and s.mon$sql_text NOT containing 'rdb$auth'
|
||||
# and a.mon$remote_protocol is not null
|
||||
# '''
|
||||
#
|
||||
#
|
||||
# r2none.execute(sql)
|
||||
# for r in r2none:
|
||||
# #print( ' '.join( 'THIS connect with charset NONE. OTHER connect tiwh charset UTF8.', 'WE see other sqltest hash as: ', r[0], '; sql_text_hash: ', str( r[1] ), '; charset_name', r[2] ) )
|
||||
# #print('r2none',r)
|
||||
# print( ' '.join( ( 'Attach: r2none.', r[0], '; sql_text_hash: ', str( r[1] ), '; charset_name', r[2] ) ) )
|
||||
#
|
||||
#
|
||||
# r2utf8.execute(sql)
|
||||
# for r in r2utf8:
|
||||
# print( ' '.join( ( 'Attach: r2utf8.', r[0], '; sql_text_hash: ', str( r[1] ), '; charset_name', r[2] ) ) )
|
||||
# #print('r2utf8',r)
|
||||
#
|
||||
#
|
||||
# c1none.close()
|
||||
# #----------------------------
|
||||
#
|
||||
#
|
||||
# r1utf8.execute("select '123áé456' from mon$database")
|
||||
#
|
||||
#
|
||||
# c2none.commit()
|
||||
# c2utf8.commit()
|
||||
#
|
||||
#
|
||||
# r2none.execute(sql)
|
||||
# for r in r2none:
|
||||
# #print('r2none', r)
|
||||
# print( ' '.join( ( 'Attach: r2none.', r[0], '; sql_text_hash: ', str( r[1] ), '; charset_name', r[2] ) ) )
|
||||
#
|
||||
#
|
||||
# r2utf8.execute(sql)
|
||||
# for r in r2utf8:
|
||||
# #print('r2utf8', r)
|
||||
# print( ' '.join( ( 'Attach: r2utf8.', r[0], '; sql_text_hash: ', str( r[1] ), '; charset_name', r[2] ) ) )
|
||||
#
|
||||
#
|
||||
# c1utf8.close()
|
||||
# #---------------------------
|
||||
#
|
||||
#
|
||||
# c2none.close()
|
||||
# c2utf8.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 = """
|
||||
Attach: r2none. othr ; sql_text_hash: 98490476833044645 ; charset_name NONE
|
||||
@ -137,8 +138,57 @@ 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, capsys):
|
||||
with act_1.db.connect(charset='UTF8') as con1_utf8, \
|
||||
act_1.db.connect(charset='NONE') as con2_none, \
|
||||
act_1.db.connect(charset='UTF8') as con2_utf8:
|
||||
with act_1.db.connect(charset='NONE') as con1_none:
|
||||
r1none = con1_none.cursor()
|
||||
r1utf8 = con1_utf8.cursor()
|
||||
|
||||
r2none = con2_none.cursor()
|
||||
r2utf8 = con2_utf8.cursor()
|
||||
# In attachment with charset = NONE we start query to mon$database which includes two non-ascii characters:
|
||||
# 1) Unicode Character 'LATIN SMALL LETTER A WITH ACUTE' (U+00E1)
|
||||
# 2) Unicode Character 'LATIN SMALL LETTER E WITH ACUTE' (U+00E9)
|
||||
r1none.execute("select '123áé456' from mon$database")
|
||||
sql = '''
|
||||
select
|
||||
iif(s.mon$attachment_id = current_connection, 'this', 'othr') as attach
|
||||
-- do NOT return SQL text of query with non-ascii characters: it can be displayed differently
|
||||
-- depending on machine codepage (or OS?):
|
||||
-- >>> disabled 05-feb-2018 >>> , iif(s.mon$sql_text like '%123%456%', s.mon$sql_text, '') as sql_text
|
||||
-- Use HASH(sql_text) instead. Bug (in 2.1.3) still can be reproduces with hash() also:
|
||||
,hash(s.mon$sql_text) as sql_text_hash
|
||||
,trim(c.rdb$character_set_name) as charset_name
|
||||
from mon$statements s
|
||||
join mon$attachments a on s.mon$attachment_id = a.mon$attachment_id
|
||||
join rdb$character_sets c on a.mon$character_set_id = c.rdb$character_set_id
|
||||
where
|
||||
s.mon$attachment_id != current_connection
|
||||
and s.mon$sql_text NOT containing 'mon$statements'
|
||||
and s.mon$sql_text NOT containing 'rdb$auth'
|
||||
and a.mon$remote_protocol is not null
|
||||
'''
|
||||
r2none.execute(sql)
|
||||
for r in r2none:
|
||||
print(' '.join(('Attach: r2none.', r[0], '; sql_text_hash: ', str(r[1]), '; charset_name', r[2])))
|
||||
|
||||
r2utf8.execute(sql)
|
||||
for r in r2utf8:
|
||||
print(' '.join(('Attach: r2utf8.', r[0], '; sql_text_hash: ', str(r[1]), '; charset_name', r[2])))
|
||||
|
||||
r1utf8.execute("select '123áé456' from mon$database")
|
||||
con2_none.commit()
|
||||
con2_utf8.commit()
|
||||
r2none.execute(sql)
|
||||
for r in r2none:
|
||||
print(' '.join(('Attach: r2none.', r[0], '; sql_text_hash: ', str(r[1]), '; charset_name', r[2])))
|
||||
|
||||
r2utf8.execute(sql)
|
||||
for r in r2utf8:
|
||||
print(' '.join(('Attach: r2utf8.', r[0], '; sql_text_hash: ', str(r[1]), '; charset_name', r[2])))
|
||||
#
|
||||
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_2606
|
||||
# title: Multibyte CHAR value requested as VARCHAR is returned with padded spaces
|
||||
# decription:
|
||||
# decription:
|
||||
# tracker_id: CORE-2606
|
||||
# min_versions: ['3.0']
|
||||
# versions: 3.0
|
||||
# qmid:
|
||||
# qmid:
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
from firebird.qa import db_factory, python_act, Action
|
||||
|
||||
# version: 3.0
|
||||
# resources: None
|
||||
@ -22,57 +22,89 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
|
||||
# test_script_1
|
||||
#---
|
||||
#
|
||||
#
|
||||
# import os
|
||||
#
|
||||
#
|
||||
# db_conn.close()
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
#
|
||||
#
|
||||
# sql_cmd='''
|
||||
# set list on;
|
||||
#
|
||||
#
|
||||
# select s.rdb$character_set_name as client_charset
|
||||
# from mon$attachments a
|
||||
# join rdb$character_sets s on a.mon$character_set_id = s.rdb$character_set_id
|
||||
# from mon$attachments a
|
||||
# join rdb$character_sets s on a.mon$character_set_id = s.rdb$character_set_id
|
||||
# where a.mon$attachment_id=current_connection;
|
||||
#
|
||||
#
|
||||
# --set sqlda_display on;
|
||||
# --set planonly;
|
||||
# --set echo on;
|
||||
#
|
||||
#
|
||||
# select cast('A' as char character set utf8) || '.' as char1_utf8 from rdb$database;
|
||||
# select cast('A' as varchar(1) character set utf8) || '.' as varc1_utf8 from rdb$database;
|
||||
# select cast('A' as char character set ascii) || '.' char1_ascii from rdb$database;
|
||||
# select cast('A' as varchar(1) character set ascii) || '.' varc1_ascii from rdb$database;
|
||||
# '''
|
||||
#
|
||||
#
|
||||
# # Wrong result was encountered only in FB 1.5.6, for cast('A' as Char charset utf8 / ascii), on any client charset.
|
||||
# # Varchar always returns expected output.
|
||||
#
|
||||
#
|
||||
# runProgram('isql',['-q', '-ch', 'UTF8', dsn], sql_cmd)
|
||||
# runProgram('isql',['-q', '-ch', 'SJIS_0208', dsn], sql_cmd)
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
test_script_1 = """
|
||||
set list on;
|
||||
|
||||
select s.rdb$character_set_name as client_charset
|
||||
from mon$attachments a
|
||||
join rdb$character_sets s on a.mon$character_set_id = s.rdb$character_set_id
|
||||
where a.mon$attachment_id=current_connection;
|
||||
|
||||
--set sqlda_display on;
|
||||
--set planonly;
|
||||
--set echo on;
|
||||
|
||||
select cast('A' as char character set utf8) || '.' as char1_utf8 from rdb$database;
|
||||
select cast('A' as varchar(1) character set utf8) || '.' as varc1_utf8 from rdb$database;
|
||||
select cast('A' as char character set ascii) || '.' char1_ascii from rdb$database;
|
||||
select cast('A' as varchar(1) character set ascii) || '.' varc1_ascii from rdb$database;
|
||||
"""
|
||||
|
||||
expected_stdout_1_a = """
|
||||
CLIENT_CHARSET UTF8
|
||||
CHAR1_UTF8 A.
|
||||
VARC1_UTF8 A.
|
||||
CHAR1_ASCII A.
|
||||
VARC1_ASCII A.
|
||||
"""
|
||||
|
||||
expected_stdout_1_b = """
|
||||
CLIENT_CHARSET SJIS_0208
|
||||
CHAR1_UTF8 A.
|
||||
VARC1_UTF8 A.
|
||||
CHAR1_ASCII A.
|
||||
VARC1_ASCII A.
|
||||
"""
|
||||
"""
|
||||
|
||||
@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.expected_stdout = expected_stdout_1_a
|
||||
act_1.script = test_script_1
|
||||
act_1.charset = 'UTF8'
|
||||
act_1.execute()
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
act_1.reset()
|
||||
act_1.expected_stdout = expected_stdout_1_b
|
||||
act_1.script = test_script_1
|
||||
act_1.charset = 'SJIS_0208'
|
||||
act_1.execute()
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
||||
|
||||
|
||||
|
@ -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.5
|
||||
# resources: None
|
||||
@ -25,26 +25,37 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
|
||||
# c = db_conn.cursor()
|
||||
# con2 = kdb.connect(dsn=dsn,user=user_name,password=user_password)
|
||||
# c2 = con2.cursor()
|
||||
#
|
||||
#
|
||||
# c.execute("select _dos850 '123áé456' from rdb$database")
|
||||
# c2.execute("select mon$sql_text from mon$statements s where s.mon$sql_text containing '_dos850'")
|
||||
# #printData(c2)
|
||||
# for r in c2:
|
||||
# print(r[0])
|
||||
#
|
||||
#
|
||||
# con2.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 = """
|
||||
select mon$sql_text from mon$statements s where s.mon$sql_text containing '_dos850'
|
||||
select _dos850 X'313233C3A1C3A9343536' from rdb$database
|
||||
"""
|
||||
"""
|
||||
|
||||
@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):
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
with act_1.db.connect() as con1:
|
||||
c1 = con.cursor()
|
||||
with act_1.db.connect() as con2:
|
||||
c2 = con.cursor()
|
||||
c1.execute("select _dos850 '123áé456' from rdb$database")
|
||||
c2.execute("select mon$sql_text from mon$statements s where s.mon$sql_text containing '_dos850'")
|
||||
for r in c2:
|
||||
print(r[0])
|
||||
act_1.stdout = capsys.readouterr().out
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
||||
|
||||
|
||||
|
@ -2,19 +2,20 @@
|
||||
#
|
||||
# id: bugs.core_2635
|
||||
# title: Unique index with a lot of NULL keys can be corrupted at level 1
|
||||
# decription:
|
||||
# decription:
|
||||
# tracker_id: CORE-2635
|
||||
# min_versions: ['2.1.4', '2.0.6', '2.5']
|
||||
# versions: 2.5
|
||||
# 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
|
||||
|
||||
substitutions_1 = []
|
||||
substitutions_1 = [('[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9]', ''),
|
||||
('Relation [0-9]{3,4}', 'Relation')]
|
||||
|
||||
init_script_1 = """set term ^;
|
||||
recreate table t (id int, sss varchar(255)) ^
|
||||
@ -61,12 +62,25 @@ db_1 = db_factory(page_size=4096, sql_dialect=3, init=init_script_1)
|
||||
# db_conn.close()
|
||||
# runProgram('gfix',['-validate','-full','-no_update','-user',user_name,'-password',user_password,dsn])
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
Validation started
|
||||
Relation (T)
|
||||
process pointer page 0 of 1
|
||||
Index 1 (T_ID_DESC)
|
||||
Index 2 (T_ID_ASC)
|
||||
Index 3 (T_ID_SSS_DESC)
|
||||
Index 4 (T_ID_SSS_ASC)
|
||||
Relation (T) is ok
|
||||
Validation finished
|
||||
"""
|
||||
|
||||
@pytest.mark.version('>=2.5')
|
||||
@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
|
||||
with act_1.connect_server() as srv:
|
||||
srv.database.validate(database=str(act_1.db.db_path))
|
||||
act_1.stdout = '\n'.join(srv.readlines())
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
@ -2,14 +2,14 @@
|
||||
#
|
||||
# id: bugs.core_2651
|
||||
# title: Incorrect "string right truncation" error with NONE column and multibyte connection charset
|
||||
# decription:
|
||||
# decription:
|
||||
# tracker_id: CORE-2651
|
||||
# min_versions: []
|
||||
# versions: 2.5
|
||||
# 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
|
||||
@ -35,12 +35,16 @@ db_1 = db_factory(page_size=4096, sql_dialect=3, init=init_script_1)
|
||||
# finally:
|
||||
# con.close()
|
||||
#---
|
||||
#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')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
def test_1(act_1: Action):
|
||||
with act_1.db.connect(charset='CP943C') as con:
|
||||
c = con.cursor()
|
||||
try:
|
||||
c.execute("select * from TEST_NONE")
|
||||
except:
|
||||
pytest.fail("Test FAILED")
|
||||
|
||||
|
||||
|
@ -2,18 +2,18 @@
|
||||
#
|
||||
# id: bugs.core_2668
|
||||
# title: Write note into log when automatic sweep is started
|
||||
# decription:
|
||||
# decription:
|
||||
# In order to make database be 'ready' for sweep auto-start we:
|
||||
# 1. Launch ISQL in async. process (using Python subprocess.Popen() unit) which does:
|
||||
# 1.1. Change DB sweep interval to small value (100 selected).
|
||||
# 1.2. Create table and add one row in it (marked as 'LOCKED_FOR_PAUSE') + COMMIT.
|
||||
# 1.3. Start EXECUTE BLOCK with adding 150 of rows in autonomous transactions
|
||||
# 1.3. Start EXECUTE BLOCK with adding 150 of rows in autonomous transactions
|
||||
# (this lead eventually to difference Next - OIT =~ 150).
|
||||
# 1.4. Run execute block with ES/EDS which will establish new attachment (we specify
|
||||
# there connection ROLE as some non-existent string, see ":v_role" usage below).
|
||||
# This EB will try to UPDATE record which is LOCKED now by 1st ("main") attachment.
|
||||
# ISQL will infinitelly hang since this moment.
|
||||
#
|
||||
#
|
||||
# 2. Run (in main Python thread) FBSVCMGR with:
|
||||
# 2.1. Moving database to SHUTDOWN state;
|
||||
# 2.2. Returning database back to ONLINE.
|
||||
@ -22,20 +22,26 @@
|
||||
# 2.5. Take small delay (~2..3 seconds) in order to allow OS to finish writing new messages
|
||||
# about SWEEP auto-start in firebird.log.
|
||||
# 2.6. Obtaining content of firebird.log and storing it in separate file ('f_fblog_after').
|
||||
#
|
||||
#
|
||||
# 3. Compare two files: f_fblog_before and f_fblog_after (using Python package "diff").
|
||||
# Checked on:
|
||||
# 4.0.0.2173 SS/SC/CS
|
||||
# 3.0.7.33357 SS/SC/CS
|
||||
# 2.5.9.27152 SS/SC/CS
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-2668
|
||||
# min_versions: ['2.5.2']
|
||||
# versions: 2.5.2
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
import time
|
||||
import subprocess
|
||||
import re
|
||||
from pathlib import Path
|
||||
from difflib import unified_diff
|
||||
from firebird.qa import db_factory, python_act, Action, temp_file
|
||||
from firebird.driver import DbWriteMode, ShutdownMode, ShutdownMethod
|
||||
|
||||
# version: 2.5.2
|
||||
# resources: None
|
||||
@ -56,16 +62,16 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# import difflib
|
||||
# import shutil
|
||||
# import re
|
||||
#
|
||||
#
|
||||
# def svc_get_fb_log( engine, f_fb_log ):
|
||||
#
|
||||
#
|
||||
# import subprocess
|
||||
#
|
||||
#
|
||||
# if engine.startswith('2.5'):
|
||||
# get_firebird_log_key='action_get_ib_log'
|
||||
# else:
|
||||
# get_firebird_log_key='action_get_fb_log'
|
||||
#
|
||||
#
|
||||
# subprocess.call([ context['fbsvcmgr_path'],
|
||||
# "localhost:service_mgr",
|
||||
# get_firebird_log_key
|
||||
@ -73,32 +79,32 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# stdout=f_fb_log, stderr=subprocess.STDOUT
|
||||
# )
|
||||
# return
|
||||
#
|
||||
#
|
||||
# engine = str(db_conn.engine_version)
|
||||
# db_file=db_conn.database_name
|
||||
#
|
||||
#
|
||||
# db_conn.close()
|
||||
#
|
||||
#
|
||||
# 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'):
|
||||
# # 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 )):
|
||||
@ -106,11 +112,11 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# os.remove( f_names_list[i] )
|
||||
# if os.path.isfile( f_names_list[i]):
|
||||
# print('ERROR: can not remove file ' + f_names_list[i])
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# f_init_log = open( os.path.join(context['temp_directory'],'tmp_init_2668.log'), 'w')
|
||||
#
|
||||
#
|
||||
# subprocess.call( [context['fbsvcmgr_path'], "localhost:service_mgr",
|
||||
# "action_properties", "prp_sweep_interval", "100",
|
||||
# "dbname", db_file,
|
||||
@ -118,40 +124,40 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# stdout = f_init_log,
|
||||
# stderr = subprocess.STDOUT
|
||||
# )
|
||||
#
|
||||
#
|
||||
# subprocess.call([ context['fbsvcmgr_path'], "localhost:service_mgr",
|
||||
# "action_properties", "prp_write_mode", "prp_wm_async",
|
||||
# "dbname", db_file ],
|
||||
# stdout = f_init_log,
|
||||
# stderr = subprocess.STDOUT
|
||||
# )
|
||||
#
|
||||
#
|
||||
# f_work_sql=open( os.path.join(context['temp_directory'],'tmp_work_2668.sql'), 'w')
|
||||
#
|
||||
#
|
||||
# sql_dml='''
|
||||
# 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 = 150;
|
||||
# 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()) ) )
|
||||
# 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 test set s = s where s = ?') ('LOCKED_FOR_PAUSE')
|
||||
# on external
|
||||
# on external
|
||||
# 'localhost:' || rdb$get_context('SYSTEM', 'DB_NAME')
|
||||
# as user 'SYSDBA' password 'masterkey' role v_role
|
||||
# with autonomous transaction;
|
||||
@ -159,7 +165,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# begin
|
||||
# end
|
||||
# end
|
||||
#
|
||||
#
|
||||
# end
|
||||
# ^
|
||||
# set term ;^
|
||||
@ -168,12 +174,12 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# '''
|
||||
# f_work_sql.write(sql_dml)
|
||||
# flush_and_close( f_work_sql )
|
||||
#
|
||||
#
|
||||
# f_work_log=open( os.path.join(context['temp_directory'],'tmp_work_2668.log'), 'w')
|
||||
#
|
||||
#
|
||||
# p_work_sql=Popen( [context['isql_path'], dsn, "-i", f_work_sql.name], stdout = f_work_log, stderr = subprocess.STDOUT )
|
||||
# time.sleep(3)
|
||||
#
|
||||
#
|
||||
# subprocess.call( [context['fbsvcmgr_path'], "localhost:service_mgr",
|
||||
# "action_properties", "prp_shutdown_mode", "prp_sm_full", "prp_shutdown_db", "0",
|
||||
# "dbname", db_file,
|
||||
@ -181,11 +187,11 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# stdout = f_init_log,
|
||||
# stderr = subprocess.STDOUT
|
||||
# )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# p_work_sql.terminate()
|
||||
# flush_and_close( f_work_log )
|
||||
#
|
||||
#
|
||||
# subprocess.call( [context['fbsvcmgr_path'], "localhost:service_mgr",
|
||||
# "action_properties", "prp_db_online",
|
||||
# "dbname", db_file,
|
||||
@ -193,75 +199,137 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# stdout = f_init_log,
|
||||
# stderr = subprocess.STDOUT
|
||||
# )
|
||||
#
|
||||
#
|
||||
# flush_and_close( f_init_log )
|
||||
#
|
||||
#
|
||||
# # 4 debug only -- shutil.copy2(db_file, os.path.splitext(db_file)[0]+'.copy.fdb')
|
||||
#
|
||||
#
|
||||
# f_fblog_before=open( os.path.join(context['temp_directory'],'tmp_2668_fblog_before.txt'), 'w')
|
||||
# svc_get_fb_log( engine, f_fblog_before )
|
||||
# flush_and_close( f_fblog_before )
|
||||
#
|
||||
#
|
||||
# ###########################################
|
||||
# # Make connection to database.
|
||||
# # SWEEP should be auto started at this point:
|
||||
# ###########################################
|
||||
#
|
||||
#
|
||||
# con_for_sweep_start=fdb.connect(dsn = dsn)
|
||||
#
|
||||
#
|
||||
# # NOTE: it is mandatory to start transaction for auto-sweep:
|
||||
# con_for_sweep_start.begin()
|
||||
#
|
||||
#
|
||||
# # _!_!_!_!_!_!_!_!_!_! do NOT reduce this delay: firebird.log get new messages NOT instantly !_!_!_!_!_!_!_!_
|
||||
# # Currently firebird.log can stay with OLD content if heavy concurrent workload exists on the same host!
|
||||
# time.sleep(2)
|
||||
#
|
||||
#
|
||||
# con_for_sweep_start.close()
|
||||
#
|
||||
#
|
||||
# f_fblog_after=open( os.path.join(context['temp_directory'],'tmp_2668_fblog_after.txt'), 'w')
|
||||
# svc_get_fb_log( engine, f_fblog_after )
|
||||
# flush_and_close( f_fblog_after )
|
||||
#
|
||||
#
|
||||
# oldfb=open(f_fblog_before.name, 'r')
|
||||
# newfb=open(f_fblog_after.name, 'r')
|
||||
#
|
||||
#
|
||||
# difftext = ''.join(difflib.unified_diff(
|
||||
# oldfb.readlines(),
|
||||
# oldfb.readlines(),
|
||||
# newfb.readlines()
|
||||
# ))
|
||||
# oldfb.close()
|
||||
# newfb.close()
|
||||
#
|
||||
#
|
||||
# f_diff_txt=open( os.path.join(context['temp_directory'],'tmp_2668_diff.txt'), 'w')
|
||||
# f_diff_txt.write(difftext)
|
||||
# flush_and_close( f_diff_txt )
|
||||
#
|
||||
#
|
||||
# pattern = re.compile('Sweep\\s+.*SWEEPER', re.IGNORECASE)
|
||||
#
|
||||
# # NB: difflib.unified_diff() can show line(s) that present in both files, without marking that line(s) with "+".
|
||||
#
|
||||
# # NB: difflib.unified_diff() can show line(s) that present in both files, without marking that line(s) with "+".
|
||||
# # Usually these are 1-2 lines that placed just BEFORE difference starts.
|
||||
# # So we have to check output before display diff content: lines that are really differ must start with "+".
|
||||
#
|
||||
#
|
||||
# with open( f_diff_txt.name,'r') as f:
|
||||
# for line in f:
|
||||
# if line.startswith('+') and pattern.search(line):
|
||||
# print('Expected line FOUND.')
|
||||
#
|
||||
#
|
||||
# ###############################
|
||||
# # Cleanup.
|
||||
# time.sleep(1)
|
||||
# cleanup( [x.name for x in (f_init_log,f_work_sql,f_work_log,f_fblog_before,f_fblog_after,f_diff_txt) ] )
|
||||
#
|
||||
#
|
||||
#---
|
||||
#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 line FOUND.
|
||||
"""
|
||||
"""
|
||||
|
||||
work_script_1 = temp_file('work_script.sql')
|
||||
|
||||
@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, work_script_1: Path):
|
||||
work_script_1.write_text('''
|
||||
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 = 150;
|
||||
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 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;
|
||||
''')
|
||||
with act_1.connect_server() as srv:
|
||||
srv.database.set_sweep_interval(database=str(act_1.db.db_path), interval=100)
|
||||
srv.database.set_write_mode(database=str(act_1.db.db_path), mode=DbWriteMode.ASYNC)
|
||||
p_work_sql = subprocess.Popen([act_1.vars['isql'], '-i', str(work_script_1),
|
||||
'-user', act_1.db.user,
|
||||
'-password', act_1.db.password, act_1.db.dsn],
|
||||
stderr = subprocess.STDOUT)
|
||||
time.sleep(3)
|
||||
srv.database.shutdown(database=str(act_1.db.db_path), mode=ShutdownMode.FULL,
|
||||
method=ShutdownMethod.FORCED, timeout=0)
|
||||
p_work_sql.terminate()
|
||||
srv.database.bring_online(database=str(act_1.db.db_path))
|
||||
srv.info.get_log()
|
||||
fblog_before = srv.readlines()
|
||||
with act_1.db.connect() as con_for_sweep_start:
|
||||
con_for_sweep_start.begin()
|
||||
time.sleep(2)
|
||||
srv.info.get_log()
|
||||
fblog_after = srv.readlines()
|
||||
pattern = re.compile('Sweep\\s+.*SWEEPER', re.IGNORECASE)
|
||||
success = False
|
||||
for line in unified_diff(fblog_before, fblog_after):
|
||||
if line.startswith('+') and pattern.search(line):
|
||||
success = True
|
||||
assert success
|
||||
|
@ -2,15 +2,16 @@
|
||||
#
|
||||
# id: bugs.core_2712
|
||||
# title: Do not print "invalid request BLR" for par.cpp errors with valid BLR
|
||||
# decription:
|
||||
#
|
||||
# decription:
|
||||
#
|
||||
# tracker_id: CORE-2712
|
||||
# min_versions: ['3.0.0']
|
||||
# versions: 3.0
|
||||
# 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
|
||||
# resources: None
|
||||
@ -23,26 +24,26 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
|
||||
# test_script_1
|
||||
#---
|
||||
#
|
||||
#
|
||||
# import os
|
||||
#
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
#
|
||||
#
|
||||
# db_conn.close()
|
||||
# msg=''
|
||||
#
|
||||
#
|
||||
# att1 = kdb.connect(dsn=dsn)
|
||||
# cur1 = att1.cursor()
|
||||
# cur1.execute("recreate table test(x int)")
|
||||
# att1.commit()
|
||||
# cur1.execute("insert into test values(1)")
|
||||
# att1.commit()
|
||||
#
|
||||
#
|
||||
# att2 = kdb.connect(dsn=dsn)
|
||||
# cur2 = att2.cursor()
|
||||
# cur2.execute("select 1 from rdb$database")
|
||||
#
|
||||
#
|
||||
# cur1.execute("drop table test")
|
||||
# try:
|
||||
# cur2.prep("update test set x=-x")
|
||||
@ -50,22 +51,27 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# except Exception as e:
|
||||
# msg = e[0]
|
||||
# print(msg)
|
||||
#
|
||||
#
|
||||
# att1.close()
|
||||
# att2.close()
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
Error while preparing SQL statement:
|
||||
- SQLCODE: -219
|
||||
- table id 128 is not defined
|
||||
"""
|
||||
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, capsys):
|
||||
with act_1.db.connect() as att1:
|
||||
cur1 = att1.cursor()
|
||||
cur1.execute("recreate table test(x int)")
|
||||
att1.commit()
|
||||
cur1.execute("insert into test values(1)")
|
||||
att1.commit()
|
||||
with act_1.db.connect() as att2:
|
||||
cur2 = att2.cursor()
|
||||
cur2.execute("select 1 from rdb$database")
|
||||
|
||||
cur1.execute("drop table test")
|
||||
with pytest.raises(DatabaseError, match='.*table id [0-9]+ is not defined.*'):
|
||||
cur2.prepare("update test set x=-x")
|
||||
att2.commit()
|
||||
|
@ -2,21 +2,21 @@
|
||||
#
|
||||
# id: bugs.core_2724
|
||||
# title: Validate or transform string of DML queries so that engine internals doesn't receive malformed strings
|
||||
# decription:
|
||||
# decription:
|
||||
# Code from doc/sql.extensions/README.ddl_triggers.txt was taken as basis for this test
|
||||
# (see ticket issue: "This situation happened with DDL triggers ...").
|
||||
# Several DB objects are created here and their DDL contain unicode (Greek) text.
|
||||
# Attachment these issues these DDL intentionally is run with charset = NONE.
|
||||
# Attachment these issues these DDL intentionally is run with charset = NONE.
|
||||
# This charset (NONE) should result in question marks after we finish DDL and want to query log table
|
||||
# that was filled by DDL trigger and contains issued DDL statements.
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-2724
|
||||
# min_versions: ['3.0']
|
||||
# versions: 3.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
|
||||
# resources: None
|
||||
@ -41,7 +41,7 @@ init_script_1 = """
|
||||
result_info blob sub_type text
|
||||
);
|
||||
commit;
|
||||
|
||||
|
||||
set term ^;
|
||||
create trigger trig_ddl_log_before before any ddl statement
|
||||
as
|
||||
@ -52,18 +52,18 @@ init_script_1 = """
|
||||
-- didn't run, the log will survive.
|
||||
in autonomous transaction do
|
||||
begin
|
||||
|
||||
|
||||
select coalesce(c.rdb$character_set_name, '??? NULL ???')
|
||||
from mon$attachments a
|
||||
left join rdb$character_sets c on a.mon$character_set_id = c.rdb$character_set_id
|
||||
where a.mon$attachment_id = current_connection
|
||||
into v_current_connection_cset;
|
||||
|
||||
insert into ddl_log (id, moment, current_connection_cset,
|
||||
|
||||
insert into ddl_log (id, moment, current_connection_cset,
|
||||
event_type, object_type, ddl_event, object_name,
|
||||
old_object_name, new_object_name, sql_text, ok, result_info)
|
||||
values (next value for ddl_seq,
|
||||
'now',
|
||||
values (next value for ddl_seq,
|
||||
'now',
|
||||
:v_current_connection_cset,
|
||||
rdb$get_context('DDL_TRIGGER', 'EVENT_TYPE'),
|
||||
rdb$get_context('DDL_TRIGGER', 'OBJECT_TYPE'),
|
||||
@ -79,7 +79,7 @@ init_script_1 = """
|
||||
end
|
||||
end
|
||||
^
|
||||
|
||||
|
||||
-- Note: the above trigger will fire for this DDL command. It's good idea to use -nodbtriggers
|
||||
-- when working with them!
|
||||
create trigger trig_ddl_log_after after any ddl statement
|
||||
@ -89,14 +89,14 @@ init_script_1 = """
|
||||
-- record inserted on the BEFORE trigger autonomous transaction if user transaction is not
|
||||
-- READ COMMITTED.
|
||||
in autonomous transaction do
|
||||
update ddl_log set ok = 'Y',
|
||||
update ddl_log set ok = 'Y',
|
||||
result_info = 'Τα πάντα ήταν επιτυχής' -- Everything has completed successfully
|
||||
where id = rdb$get_context('USER_SESSION', 'trig_ddl_log_id');
|
||||
end
|
||||
^
|
||||
set term ;^
|
||||
commit;
|
||||
|
||||
|
||||
-- So lets delete the record about trig_ddl_log_after creation.
|
||||
delete from ddl_log;
|
||||
commit;
|
||||
@ -106,33 +106,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
|
||||
# # 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'):
|
||||
# # 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 )):
|
||||
@ -140,13 +140,13 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
|
||||
# os.remove( f_names_list[i] )
|
||||
# if os.path.isfile( f_names_list[i]):
|
||||
# print('ERROR: can not remove file ' + f_names_list[i])
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# sql_check=''' delete from ddl_log;
|
||||
# commit;
|
||||
#
|
||||
#
|
||||
# create domain dm_name varchar(50) check (value in ('αμορτισέρ', 'κόμβο', 'σωλήνα', 'φέροντα', 'βραχίονα'));
|
||||
# recreate table t1 (
|
||||
# saller_id integer -- αναγνωριστικό εμπόρου // ID of saler
|
||||
@ -155,39 +155,39 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
|
||||
# );
|
||||
# commit;
|
||||
# set list on;
|
||||
#
|
||||
#
|
||||
# select id, current_connection_cset, sql_text, result_info, ddl_event, object_name
|
||||
# from ddl_log order by id;
|
||||
#
|
||||
#
|
||||
# commit;
|
||||
# drop table t1;
|
||||
# drop domain dm_name;
|
||||
# exit;
|
||||
# '''
|
||||
#
|
||||
#
|
||||
# f_check_sql = open( os.path.join(context['temp_directory'],'tmp_check_2724.sql'), 'w')
|
||||
# f_check_sql.write(sql_check)
|
||||
# flush_and_close( f_check_sql )
|
||||
#
|
||||
#
|
||||
# ##########################################################################################
|
||||
#
|
||||
#
|
||||
# f_ch_none_log = open( os.path.join(context['temp_directory'],'tmp_ch_none_2724.log'), 'w')
|
||||
# f_ch_none_err = open( os.path.join(context['temp_directory'],'tmp_ch_none_2724.err'), 'w')
|
||||
#
|
||||
#
|
||||
# subprocess.call( [context['isql_path'], dsn, "-i", f_check_sql.name,
|
||||
# "-ch", "none"],
|
||||
# stdout = f_ch_none_log,
|
||||
# stderr = f_ch_none_err
|
||||
# )
|
||||
#
|
||||
#
|
||||
# flush_and_close( f_ch_none_log )
|
||||
# flush_and_close( f_ch_none_err )
|
||||
#
|
||||
#
|
||||
# ##########################################################################################
|
||||
#
|
||||
#
|
||||
# f_ch_utf8_log = open( os.path.join(context['temp_directory'],'tmp_ch_utf8_2724.log'), 'w')
|
||||
# f_ch_utf8_err = open( os.path.join(context['temp_directory'],'tmp_ch_utf8_2724.err'), 'w')
|
||||
#
|
||||
#
|
||||
# subprocess.call( [context['isql_path'], dsn, "-user", user_name, "-password", user_password, "-i", f_check_sql.name,
|
||||
# "-ch", "utf8"],
|
||||
# stdout = f_ch_utf8_log,
|
||||
@ -195,50 +195,53 @@ db_1 = db_factory(charset='UTF8', sql_dialect=3, init=init_script_1)
|
||||
# )
|
||||
# flush_and_close( f_ch_utf8_log )
|
||||
# flush_and_close( f_ch_utf8_err )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# f_list = [f_ch_none_log, f_ch_none_err, f_ch_utf8_log, f_ch_utf8_err]
|
||||
# for f in f_list:
|
||||
# with open( f.name,'r') as f:
|
||||
# print(f.read())
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# # Cleanup
|
||||
# #########
|
||||
# time.sleep(1)
|
||||
#
|
||||
#
|
||||
# f_list.append(f_check_sql)
|
||||
# cleanup( [i.name for i in f_list] )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1_a = """
|
||||
ID 2
|
||||
CURRENT_CONNECTION_CSET NONE
|
||||
SQL_TEXT
|
||||
CURRENT_CONNECTION_CSET NONE
|
||||
SQL_TEXT
|
||||
create domain dm_name varchar(50) check (value in ('??????????????????', '??????????', '????????????', '??????????????', '????????????????'))
|
||||
RESULT_INFO
|
||||
RESULT_INFO
|
||||
Τα πάντα ήταν επιτυχής
|
||||
DDL_EVENT CREATE DOMAIN
|
||||
OBJECT_NAME DM_NAME
|
||||
|
||||
ID 3
|
||||
CURRENT_CONNECTION_CSET NONE
|
||||
SQL_TEXT
|
||||
CURRENT_CONNECTION_CSET NONE
|
||||
SQL_TEXT
|
||||
recreate table t1 (
|
||||
saller_id integer -- ?????????????????????????? ?????????????? // ID of saler
|
||||
,customer_id integer -- ?????????????????????????? ???????????? // ID of customer
|
||||
,product_name dm_name
|
||||
)
|
||||
RESULT_INFO
|
||||
RESULT_INFO
|
||||
Τα πάντα ήταν επιτυχής
|
||||
DDL_EVENT CREATE TABLE
|
||||
OBJECT_NAME T1
|
||||
|
||||
OBJECT_NAME T1
|
||||
"""
|
||||
|
||||
expected_stdout_1_b = """
|
||||
ID 6
|
||||
CURRENT_CONNECTION_CSET UTF8
|
||||
CURRENT_CONNECTION_CSET UTF8
|
||||
SQL_TEXT 80:0
|
||||
create domain dm_name varchar(50) check (value in ('αμορτισέρ', 'κόμβο', 'σωλήνα', 'φέροντα', 'βραχίονα'))
|
||||
RESULT_INFO 80:2
|
||||
@ -247,22 +250,48 @@ expected_stdout_1 = """
|
||||
OBJECT_NAME DM_NAME
|
||||
|
||||
ID 7
|
||||
CURRENT_CONNECTION_CSET UTF8
|
||||
SQL_TEXT
|
||||
CURRENT_CONNECTION_CSET UTF8
|
||||
SQL_TEXT
|
||||
recreate table t1 (
|
||||
saller_id integer -- αναγνωριστικό εμπόρου // ID of saler
|
||||
,customer_id integer -- αναγνωριστικό πελάτη // ID of customer
|
||||
,product_name dm_name
|
||||
)
|
||||
RESULT_INFO
|
||||
RESULT_INFO
|
||||
Τα πάντα ήταν επιτυχής
|
||||
DDL_EVENT CREATE TABLE
|
||||
OBJECT_NAME T1
|
||||
OBJECT_NAME T1
|
||||
"""
|
||||
|
||||
@pytest.mark.version('>=3.0')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
def test_1(act_1: Action):
|
||||
sql_check = '''
|
||||
delete from ddl_log;
|
||||
commit;
|
||||
|
||||
create domain dm_name varchar(50) check (value in ('αμορτισέρ', 'κόμβο', 'σωλήνα', 'φέροντα', 'βραχίονα'));
|
||||
recreate table t1 (
|
||||
saller_id integer -- αναγνωριστικό εμπόρου // ID of saler
|
||||
,customer_id integer -- αναγνωριστικό πελάτη // ID of customer
|
||||
,product_name dm_name
|
||||
);
|
||||
commit;
|
||||
set list on;
|
||||
|
||||
select id, current_connection_cset, sql_text, result_info, ddl_event, object_name
|
||||
from ddl_log order by id;
|
||||
|
||||
commit;
|
||||
drop table t1;
|
||||
drop domain dm_name;
|
||||
exit;
|
||||
'''
|
||||
#
|
||||
act_1.expected_stdout = expected_stdout_1_a
|
||||
act_1.isql(switches=[], charset='NONE', input=sql_check)
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
#
|
||||
act_1.reset()
|
||||
act_1.expected_stdout = expected_stdout_1_b
|
||||
act_1.isql(switches=[], charset='UTF8', input=sql_check)
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
@ -2,15 +2,15 @@
|
||||
#
|
||||
# id: bugs.core_2788
|
||||
# title: isql extracts the array dimensions after the character set name
|
||||
# decription:
|
||||
#
|
||||
# decription:
|
||||
#
|
||||
# tracker_id: CORE-2788
|
||||
# min_versions: ['3.0']
|
||||
# versions: 3.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
|
||||
# resources: None
|
||||
@ -27,29 +27,29 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# import time
|
||||
# import subprocess
|
||||
# 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'):
|
||||
# # 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 )):
|
||||
@ -57,20 +57,20 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# os.remove( f_names_list[i] )
|
||||
# if os.path.isfile( f_names_list[i]):
|
||||
# print('ERROR: can not remove file ' + f_names_list[i])
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# sql_ddl=''' create domain dm_test as char(1) character set iso8859_1[1:2];
|
||||
# create domain dm_test as char(1)[1:2] character set iso8859_1;
|
||||
# commit;
|
||||
# show domain dm_test;
|
||||
# '''
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# f_init_sql = open( os.path.join(context['temp_directory'],'tmp_init_2788.sql'), 'w')
|
||||
# f_init_sql.write(sql_ddl)
|
||||
# flush_and_close( f_init_sql )
|
||||
#
|
||||
#
|
||||
# f_init_log = open( os.path.join(context['temp_directory'],'tmp_init_2788.log'), 'w')
|
||||
# f_init_err = open( os.path.join(context['temp_directory'],'tmp_init_2788.err'), 'w')
|
||||
# subprocess.call( [context['isql_path'], dsn, "-i", f_init_sql.name],
|
||||
@ -79,35 +79,35 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# )
|
||||
# # This file should be empty:
|
||||
# flush_and_close( f_init_log )
|
||||
#
|
||||
#
|
||||
# # This file should contain error messages about 1st 'CREATE DOMAIN' statement that has syntax trouble:
|
||||
# flush_and_close( f_init_err )
|
||||
#
|
||||
#
|
||||
# # This file should contain error messages about 1st 'CREATE DOMAIN' statement that has syntax trouble:
|
||||
# with open( f_init_err.name,'r') as f:
|
||||
# print(f.read())
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# f_xmeta_log = open( os.path.join(context['temp_directory'],'tmp_xmeta_2788.log'), 'w')
|
||||
# f_xmeta_err = open( os.path.join(context['temp_directory'],'tmp_xmeta_2788.err'), 'w')
|
||||
# subprocess.call( [context['isql_path'], dsn, "-x"], stdout = f_xmeta_log, stderr = f_xmeta_err)
|
||||
#
|
||||
#
|
||||
# # This file should contain metadata - domain definition:
|
||||
# flush_and_close( f_xmeta_log )
|
||||
#
|
||||
#
|
||||
# # This file should be empty:
|
||||
# flush_and_close( f_xmeta_err )
|
||||
#
|
||||
#
|
||||
# att1 = fdb.connect(dsn=dsn.encode())
|
||||
# cur1=att1.cursor()
|
||||
# cur1.execute("drop domain dm_test")
|
||||
# att1.commit()
|
||||
#
|
||||
#
|
||||
# att1.close()
|
||||
#
|
||||
#
|
||||
# # This shoudl issue "There is no domain DM_TEST in this database":
|
||||
# runProgram('isql',[dsn, '-q'],'show domain dm_test;')
|
||||
#
|
||||
#
|
||||
# f_apply_log = open( os.path.join(context['temp_directory'],'tmp_apply_2788.log'), 'w')
|
||||
# f_apply_err = open( os.path.join(context['temp_directory'],'tmp_apply_2788.err'), 'w')
|
||||
# subprocess.call( [context['isql_path'], dsn, "-i", f_xmeta_log.name],
|
||||
@ -117,49 +117,82 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# # Both of these files should be empty:
|
||||
# flush_and_close( f_apply_log )
|
||||
# flush_and_close( f_apply_err )
|
||||
#
|
||||
#
|
||||
# # This shoudl issue DDL of just created domain:
|
||||
# runProgram('isql',[dsn, '-q'],'show domain dm_test;')
|
||||
#
|
||||
#
|
||||
# # No output should be here:
|
||||
# with open( f_xmeta_err.name,'r') as f:
|
||||
# print(f.read())
|
||||
#
|
||||
#
|
||||
# # No output should be here:
|
||||
# with open( f_apply_log.name,'r') as f:
|
||||
# print(f.read())
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# # No output should be here:
|
||||
# with open( f_apply_err.name,'r') as f:
|
||||
# print(f.read())
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# ################################################
|
||||
# # Cleanup
|
||||
# time.sleep(1)
|
||||
# cleanup( [i.name for i in (f_init_sql,f_init_log,f_init_err,f_xmeta_log,f_xmeta_err,f_apply_log,f_apply_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 = """
|
||||
Statement failed, SQLSTATE = 42000
|
||||
Dynamic SQL Error
|
||||
-SQL error code = -104
|
||||
-Token unknown - line 1, column 57
|
||||
-[
|
||||
DM_TEST ARRAY OF [2]
|
||||
CHAR(1) CHARACTER SET ISO8859_1 Nullable
|
||||
"""
|
||||
expected_stderr_1 = """
|
||||
There is no domain DM_TEST in this database
|
||||
"""
|
||||
DM_TEST ARRAY OF [2]
|
||||
CHAR(1) CHARACTER SET ISO8859_1 Nullable
|
||||
"""
|
||||
|
||||
expected_stderr_1_a = """
|
||||
Statement failed, SQLSTATE = 42000
|
||||
Dynamic SQL Error
|
||||
-SQL error code = -104
|
||||
-Token unknown - line 1, column 57
|
||||
-[
|
||||
"""
|
||||
|
||||
expected_stderr_1_b = """
|
||||
There is no domain DM_TEST in this database
|
||||
"""
|
||||
|
||||
@pytest.mark.version('>=3.0')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
|
||||
|
||||
def test_1(act_1: Action):
|
||||
sql_ddl = ''' create domain dm_test as char(1) character set iso8859_1[1:2];
|
||||
create domain dm_test as char(1)[1:2] character set iso8859_1;
|
||||
commit;
|
||||
show domain dm_test;
|
||||
'''
|
||||
act_1.expected_stderr = expected_stderr_1_a
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
act_1.isql(switches=[], input=sql_ddl)
|
||||
assert act_1.clean_stderr == act_1.clean_expected_stderr
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
#
|
||||
act_1.reset()
|
||||
act_1.isql(switches=['-x'])
|
||||
xmeta = act_1.stdout
|
||||
#
|
||||
with act_1.db.connect() as con:
|
||||
c = con.cursor()
|
||||
c.execute('drop domain dm_test')
|
||||
con.commit()
|
||||
#
|
||||
act_1.reset()
|
||||
act_1.expected_stderr = expected_stderr_1_b
|
||||
act_1.isql(switches=['-q'], input='show domain dm_test;')
|
||||
assert act_1.clean_stderr == act_1.clean_expected_stderr
|
||||
#
|
||||
act_1.reset()
|
||||
act_1.isql(switches=[], input=xmeta)
|
||||
#
|
||||
act_1.reset()
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
act_1.isql(switches=['-q'], input='show domain dm_test;')
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
@ -2,15 +2,15 @@
|
||||
#
|
||||
# id: bugs.core_2817
|
||||
# title: If stored procedure or trigger contains query with PLAN ORDER it could fail after disconnect of attachment where procedure rigger executed first time
|
||||
# decription:
|
||||
#
|
||||
# decription:
|
||||
#
|
||||
# tracker_id: CORE-2817
|
||||
# min_versions: ['2.5.0']
|
||||
# versions: 2.5
|
||||
# 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
|
||||
@ -39,9 +39,9 @@ init_script_1 = """
|
||||
set term ^;
|
||||
create or alter procedure sp_test(a_odd smallint) as
|
||||
declare c_ord cursor for (
|
||||
select s
|
||||
from test
|
||||
where mod(x, 2) = :a_odd
|
||||
select s
|
||||
from test
|
||||
where mod(x, 2) = :a_odd
|
||||
order by x
|
||||
);
|
||||
declare v_s type of column test.s;
|
||||
@ -57,7 +57,7 @@ init_script_1 = """
|
||||
end
|
||||
^ -- sp_test
|
||||
set term ;^
|
||||
commit;
|
||||
commit;
|
||||
"""
|
||||
|
||||
db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
@ -65,32 +65,36 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# test_script_1
|
||||
#---
|
||||
# import fdb
|
||||
#
|
||||
#
|
||||
# db_conn.close()
|
||||
# att1 = kdb.connect(dsn=dsn.encode(),user='SYSDBA',password='masterkey')
|
||||
# att2 = kdb.connect(dsn=dsn.encode(),user='SYSDBA',password='masterkey')
|
||||
#
|
||||
#
|
||||
# cur1 = att1.cursor()
|
||||
# cur2 = att2.cursor()
|
||||
#
|
||||
#
|
||||
# sp_run='execute procedure sp_test'
|
||||
#
|
||||
#
|
||||
# cur1.execute('execute procedure sp_test(0)')
|
||||
# cur2.execute('execute procedure sp_test(1)')
|
||||
#
|
||||
#
|
||||
# att1.commit()
|
||||
# att1.close()
|
||||
#
|
||||
#
|
||||
# cur2.execute('execute procedure sp_test(1)')
|
||||
# att2.close()
|
||||
#
|
||||
#
|
||||
#---
|
||||
#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')
|
||||
@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 att2:
|
||||
with act_1.db.connect() as att1:
|
||||
cur1 = att1.cursor()
|
||||
cur2 = att2.cursor()
|
||||
cur1.execute('execute procedure sp_test(0)')
|
||||
cur2.execute('execute procedure sp_test(1)')
|
||||
att1.commit()
|
||||
cur2.execute('execute procedure sp_test(1)')
|
||||
|
@ -2,14 +2,14 @@
|
||||
#
|
||||
# id: bugs.core_2831
|
||||
# title: isql shouldn't display db and user name when extracting a script
|
||||
# decription:
|
||||
# decription:
|
||||
# tracker_id: CORE-2831
|
||||
# min_versions: ['2.0.6', '2.1.4', '2.5']
|
||||
# versions: 3.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
|
||||
# resources: None
|
||||
@ -25,12 +25,12 @@ db_1 = db_factory(page_size=4096, sql_dialect=3, init=init_script_1)
|
||||
# #
|
||||
# runProgram('isql',['-x',dsn,'-user',user_name,'-pass',user_password])
|
||||
#---
|
||||
#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')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
|
||||
def test_1(act_1: Action):
|
||||
act_1.isql(switches=['-x'])
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
||||
|
@ -2,32 +2,30 @@
|
||||
#
|
||||
# id: bugs.core_2861
|
||||
# title: Cannot remove user with dot in login
|
||||
# decription:
|
||||
# Since 10.01.2016 this test (for 3.0) is based on totally new algorithm with checking ability of
|
||||
# normal work with randomly generated logins. These logins consists only of punctuation chars and
|
||||
# decription:
|
||||
# Since 10.01.2016 this test (for 3.0) is based on totally new algorithm with checking ability of
|
||||
# normal work with randomly generated logins. These logins consists only of punctuation chars and
|
||||
# for sure will have at least one dot.
|
||||
# The reason of this replacement was failed results on Classic 3.0 when 'gsec' utility is invoked.
|
||||
# Code for 2.5 was not changed and is preserved (though it was missed for 2.5 before, but it works OK).
|
||||
#
|
||||
#
|
||||
# See http://web.firebirdsql.org/download/prerelease/results/archive/ for builds: 3.0.0.32266 3.0.0.32268
|
||||
#
|
||||
#
|
||||
# Correctness of current code was verified by batch scenario, totally about ~1500 iterations was done.
|
||||
# Several samples of logins that were be checked:
|
||||
# ,(/;.>_:%$^`.&<|#?=[~\\*}-{@)
|
||||
# >=[{+%\\.&|~$`(;#._,])}?*@:^!
|
||||
# }^\\*@.)#>|/;&!=~`]<[,?.-:(%.
|
||||
#
|
||||
#
|
||||
# NOTE: currently we EXCLUDE single and double quotes from random login because of CORE-5072.
|
||||
#
|
||||
#
|
||||
# This login is handled then by both FBSVCMGR and ISQL utilities:
|
||||
# 1) run FBSVCMGR and:
|
||||
# 1.1) add user
|
||||
# 1.1) add user
|
||||
# 1.2) modifying some of its attributes (password, firstname etc).
|
||||
# NOTE! We do *not* run 'fbsvcmgr action_delete_user' because it does not work (at least on build 32268)
|
||||
# ######################################################################################################
|
||||
# COMMAND: fbsvcmgr localhost/3333:service_mgr user sysdba password masterkey action_delete_user dbname C:\\MIX
|
||||
# irebird
|
||||
# b30\\security3.fdb sec_username john
|
||||
# COMMAND: fbsvcmgr localhost/3333:service_mgr user sysdba password masterkey action_delete_user dbname C:\\MIX\\firebird\\fb30\\security3.fdb sec_username john
|
||||
# STDERR: unexpected item in service parameter block, expected isc_spb_sec_username
|
||||
# (sent letter to Alex, 09-jan-2016 22:34; after getting reply about this issue test can be further changed).
|
||||
# 2) run ISQL and:
|
||||
@ -35,23 +33,27 @@
|
||||
# 2.2) create this login again;
|
||||
# 2.3) modifying some of this login attributes;
|
||||
# 2.4) drop it finally.
|
||||
#
|
||||
#
|
||||
# See also:
|
||||
# CORE-1810 ("Usernames with '.' character"; login 'JOHN.SMITH' is used there).
|
||||
# CORE-3000 (use of unquoted reserved word ADMIN as user name in SQL command).
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-2861
|
||||
# min_versions: ['2.5.0']
|
||||
# versions: 3.0
|
||||
# qmid:
|
||||
# qmid:
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
import string
|
||||
from random import sample, choice
|
||||
from firebird.qa import db_factory, python_act, Action
|
||||
from firebird.driver.types import UserInfo
|
||||
|
||||
# version: 3.0
|
||||
# resources: None
|
||||
|
||||
substitutions_1 = [('[ ]+', ' '), ('[\t]*', ' '), ('.* Name: .*', ' Name: <name.with.puncts>')]
|
||||
substitutions_1 = [('.* name: .*', 'Name: <name.with.puncts>'),
|
||||
('.*USER_NAME.*', 'USER_NAME <name.with.puncts>')]
|
||||
|
||||
init_script_1 = """"""
|
||||
|
||||
@ -66,60 +68,60 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# import string
|
||||
# from random import sample, choice
|
||||
# from fdb import services
|
||||
#
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
#
|
||||
#
|
||||
# db_name=db_conn.database_name
|
||||
# db_conn.close()
|
||||
#
|
||||
#
|
||||
# svc = services.connect(host='localhost')
|
||||
# security_db_name = svc.get_security_database_path() # path+name of security DB
|
||||
# svc.close()
|
||||
#
|
||||
#
|
||||
# # Useful links related to this .fbt:
|
||||
# # https://docs.python.org/2/library/string.html
|
||||
# # http://stackoverflow.com/questions/3854692/generate-password-in-python
|
||||
# # http://stackoverflow.com/questions/2257441/random-string-generation-with-upper-case-letters-and-digits-in-python
|
||||
# # http://stackoverflow.com/questions/1024049/is-it-pythonic-to-import-inside-functions
|
||||
# # http://stackoverflow.com/questions/3095071/in-python-what-happens-when-you-import-inside-of-a-function
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# 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'):
|
||||
# # 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 )):
|
||||
# if os.path.isfile( f_names_list[i]):
|
||||
# os.remove( f_names_list[i] )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def svc_show_user( f_svc_log, f_svc_err, title_msg, security_db_name, sec_user ):
|
||||
#
|
||||
#
|
||||
# global subprocess
|
||||
#
|
||||
#
|
||||
# f_svc_log.seek(0,2)
|
||||
# f_svc_log.write("\\n")
|
||||
# f_svc_log.write(title_msg)
|
||||
# f_svc_log.write("\\n")
|
||||
# f_svc_log.seek(0,2)
|
||||
#
|
||||
#
|
||||
# subprocess.call( [ context['fbsvcmgr_path'],
|
||||
# "localhost:service_mgr",
|
||||
# "action_display_user_adm",
|
||||
@ -129,38 +131,38 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# stdout=f_svc_log, stderr=f_svc_err
|
||||
# )
|
||||
# return
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# f_svc_log=open( os.path.join(context['temp_directory'],'tmp_2861_fbsvc.log'), 'w')
|
||||
# f_svc_err=open( os.path.join(context['temp_directory'],'tmp_2861_fbsvc.err'), 'w')
|
||||
#
|
||||
# chars = string.punctuation
|
||||
#
|
||||
# # + string.digits
|
||||
#
|
||||
# chars = string.punctuation
|
||||
#
|
||||
# # + string.digits
|
||||
# #string.letters + string.digits
|
||||
# # do NOT: chars = string.printable -- it includes whitespaces, i.e. LF etc!
|
||||
#
|
||||
#
|
||||
# # NB: maximal part of user name that is displayed in fbsvcmgr action_display_user is only 28 chars.
|
||||
# # We build user name as two parts delimited by dot, so max. length of these parts is bound to 13,
|
||||
# # otherwise total length of user name will be 14+1+14 = 29 and we'll get mismatch on expected stdout.
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# '''
|
||||
# length = 13
|
||||
# dotted_user=''.join(sample(chars,length)).replace('"','.').replace("'",'.')
|
||||
# dotted_user=dotted_user+'.'+''.join(sample(chars,length))
|
||||
# dotted_user=dotted_user.replace('"','""').replace("'","''")
|
||||
# '''
|
||||
#
|
||||
#
|
||||
# length = 28
|
||||
# dotted_user=''.join(sample(chars,length)).replace('"','.').replace("'",'.')
|
||||
# quoted_user='"'+dotted_user+'"'
|
||||
#
|
||||
#
|
||||
# f_svc_log.write("Try to add user with name: "+quoted_user)
|
||||
# f_svc_log.write("\\n")
|
||||
# f_svc_log.seek(0,2)
|
||||
#
|
||||
#
|
||||
# subprocess.call( [ context['fbsvcmgr_path'],
|
||||
# "localhost:service_mgr",
|
||||
# "action_add_user",
|
||||
@ -171,15 +173,15 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# ],
|
||||
# stdout=f_svc_log, stderr=f_svc_err
|
||||
# )
|
||||
#
|
||||
#
|
||||
# svc_show_user( f_svc_log, f_svc_err, "Try to display user after adding.", security_db_name, quoted_user )
|
||||
#
|
||||
#
|
||||
# f_svc_log.seek(0,2)
|
||||
# f_svc_log.write("\\n")
|
||||
# f_svc_log.write("Try to modify user: change password and some attributes.")
|
||||
# f_svc_log.write("\\n")
|
||||
# f_svc_log.seek(0,2)
|
||||
#
|
||||
#
|
||||
# subprocess.call( [ context['fbsvcmgr_path'],
|
||||
# "localhost:service_mgr",
|
||||
# "action_modify_user",
|
||||
@ -193,23 +195,23 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# ],
|
||||
# stdout=f_svc_log, stderr=f_svc_err
|
||||
# )
|
||||
#
|
||||
#
|
||||
# svc_show_user( f_svc_log, f_svc_err, "Try to display user after modifying.", security_db_name, quoted_user )
|
||||
#
|
||||
#
|
||||
# f_svc_log.seek(0,2)
|
||||
# f_svc_log.write("\\n")
|
||||
# f_svc_log.write("All done.")
|
||||
# f_svc_log.write("\\n")
|
||||
#
|
||||
#
|
||||
# flush_and_close( f_svc_log )
|
||||
# flush_and_close( f_svc_err )
|
||||
#
|
||||
#
|
||||
# #####################################
|
||||
#
|
||||
#
|
||||
# # Now we drop user (using ISQL - fbsvcmgr currently does not work)
|
||||
# # and then create + modify + drop him again by ISQL.
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# isql_txt='''---- %s
|
||||
# set list on;
|
||||
# --set echo on;
|
||||
@ -217,24 +219,24 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# from sec$users
|
||||
# where upper(sec$user_name)=upper('%s');
|
||||
# commit;
|
||||
#
|
||||
#
|
||||
# -- select * from v_sec; commit; -- ==> FOO.RIO.BAR, in UPPER case (left after fbsvcmgr add_user)
|
||||
#
|
||||
#
|
||||
# drop user %s;
|
||||
# commit;
|
||||
#
|
||||
#
|
||||
# select 'Try to add user with name: ' || '%s' as isql_msg from rdb$database;
|
||||
#
|
||||
#
|
||||
# create or alter user %s password '123' grant admin role;
|
||||
# commit;
|
||||
#
|
||||
#
|
||||
# select 'Try to display user after adding.' as isql_msg from rdb$database;
|
||||
#
|
||||
#
|
||||
# select * from v_sec;
|
||||
# commit;
|
||||
#
|
||||
#
|
||||
# select 'Try to modify user: change password and some attributes.' as isql_msg from rdb$database;
|
||||
#
|
||||
#
|
||||
# alter user %s
|
||||
# password 'Zeppelin'
|
||||
# firstname 'John'
|
||||
@ -243,97 +245,147 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# revoke admin role
|
||||
# ;
|
||||
# commit;
|
||||
#
|
||||
#
|
||||
# select 'Try to display user after modifying.' as isql_msg from rdb$database;
|
||||
# select * from v_sec;
|
||||
# commit;
|
||||
#
|
||||
#
|
||||
# select 'Try to drop user.' as isql_msg from rdb$database;
|
||||
# drop user %s;
|
||||
# commit;
|
||||
# select 'All done.' as isql_msg from rdb$database;
|
||||
# ''' % (dotted_user, dotted_user, quoted_user.upper(), dotted_user, quoted_user, quoted_user, quoted_user )
|
||||
#
|
||||
#
|
||||
# f_sql_txt=open( os.path.join(context['temp_directory'],'tmp_2861_isql.sql'), 'w')
|
||||
# f_sql_txt.write(isql_txt)
|
||||
# flush_and_close( f_sql_txt )
|
||||
#
|
||||
#
|
||||
# f_sql_log=open( os.path.join(context['temp_directory'],'tmp_2861_isql.log'), 'w')
|
||||
# f_sql_err=open( os.path.join(context['temp_directory'],'tmp_2861_isql.err'), 'w')
|
||||
#
|
||||
#
|
||||
# subprocess.call( [ context['isql_path'], dsn, "-i", f_sql_txt.name ],
|
||||
# stdout=f_sql_log, stderr=f_sql_err
|
||||
# )
|
||||
#
|
||||
#
|
||||
# flush_and_close( f_sql_log )
|
||||
# flush_and_close( f_sql_err )
|
||||
#
|
||||
#
|
||||
# with open( f_svc_log.name,'r') as f:
|
||||
# l = [l for l in f.readlines() if l.strip()]
|
||||
#
|
||||
#
|
||||
# for line in l:
|
||||
# print("SVC STDOUT: "+line.replace(dotted_user.upper(),"<name.with.puncts>") )
|
||||
#
|
||||
#
|
||||
# with open( f_svc_err.name,'r') as f:
|
||||
# l = [l for l in f.readlines() if l.strip()]
|
||||
#
|
||||
#
|
||||
# for line in l:
|
||||
# print("SVC STDERR: "+line+", user: "+dotted_user)
|
||||
#
|
||||
#
|
||||
# with open( f_sql_log.name,'r') as f:
|
||||
# l = [l for l in f.readlines() if l.strip()]
|
||||
#
|
||||
#
|
||||
# for line in l:
|
||||
# print("SQL STDOUT: "+line.replace(dotted_user,"<name.with.puncts>"))
|
||||
#
|
||||
#
|
||||
# with open( f_sql_err.name,'r') as f:
|
||||
# l = [l for l in f.readlines() if l.strip()]
|
||||
#
|
||||
#
|
||||
# for line in l:
|
||||
# print("SQL STDERR: "+line+", user: "+dotted_user)
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# # Cleanup.
|
||||
# ##########
|
||||
#
|
||||
#
|
||||
# time.sleep(1)
|
||||
# cleanup( [i.name for i in (f_svc_log,f_svc_err,f_sql_log,f_sql_err,f_sql_txt)] )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
SVC STDOUT: Try to add user with name: "<name.with.puncts>"
|
||||
SVC STDOUT: Try to display user after adding.
|
||||
SVC STDOUT: Login Full name uid gid adm
|
||||
SVC STDOUT: <name.with.puncts> 0 0 yes
|
||||
SVC STDOUT: Try to modify user: change password and some attributes.
|
||||
SVC STDOUT: Try to display user after modifying.
|
||||
SVC STDOUT: Login Full name uid gid adm
|
||||
SVC STDOUT: <name.with.puncts> Ozzy The Terrible Osbourne 0 0 no
|
||||
SVC STDOUT: All done.
|
||||
SQL STDOUT: ISQL_MSG Try to add user with name: <name.with.puncts>
|
||||
SQL STDOUT: ISQL_MSG Try to display user after adding.
|
||||
SQL STDOUT: SEC$USER_NAME <name.with.puncts>
|
||||
SQL STDOUT: SEC$FIRST_NAME <null>
|
||||
SQL STDOUT: SEC$MIDDLE_NAME <null>
|
||||
SQL STDOUT: SEC$LAST_NAME <null>
|
||||
SQL STDOUT: SEC$ADMIN <true>
|
||||
SQL STDOUT: ISQL_MSG Try to modify user: change password and some attributes.
|
||||
SQL STDOUT: ISQL_MSG Try to display user after modifying.
|
||||
SQL STDOUT: SEC$USER_NAME <name.with.puncts>
|
||||
SQL STDOUT: SEC$FIRST_NAME John
|
||||
SQL STDOUT: SEC$MIDDLE_NAME Bonzo The Beast
|
||||
SQL STDOUT: SEC$LAST_NAME Bonham
|
||||
SQL STDOUT: SEC$ADMIN <false>
|
||||
SQL STDOUT: ISQL_MSG Try to drop user.
|
||||
SQL STDOUT: ISQL_MSG All done.
|
||||
"""
|
||||
ISQL_MSG Try to add user with name: <name.with.puncts>
|
||||
ISQL_MSG Try to display user after adding.
|
||||
SEC$USER_NAME <name.with.puncts>
|
||||
SEC$FIRST_NAME <null>
|
||||
SEC$MIDDLE_NAME <null>
|
||||
SEC$LAST_NAME <null>
|
||||
SEC$ADMIN <true>
|
||||
ISQL_MSG Try to modify user: change password and some attributes.
|
||||
ISQL_MSG Try to display user after modifying.
|
||||
SEC$USER_NAME <name.with.puncts>
|
||||
SEC$FIRST_NAME John
|
||||
SEC$MIDDLE_NAME Bonzo The Beast
|
||||
SEC$LAST_NAME Bonham
|
||||
SEC$ADMIN <false>
|
||||
ISQL_MSG Try to drop user.
|
||||
ISQL_MSG All done.
|
||||
"""
|
||||
|
||||
@pytest.mark.version('>=3.0')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
def test_1(act_1: Action):
|
||||
chars = string.punctuation
|
||||
length = 28
|
||||
dotted_user = ''.join(sample(chars, length)).replace('"', '.').replace("'", '.')
|
||||
quoted_user = '"' + dotted_user + '"'
|
||||
# Via services
|
||||
with act_1.connect_server() as srv:
|
||||
srv.user.add(user_name=quoted_user, password='foobarkey', admin=True)
|
||||
user = srv.user.get(user_name=quoted_user)
|
||||
assert user == UserInfo(user_name=dotted_user, password=None, admin=True,
|
||||
first_name='', middle_name='', last_name='', user_id=0,
|
||||
group_id=0)
|
||||
srv.user.update(user_name=quoted_user, password='BSabbath', first_name='Ozzy',
|
||||
middle_name='The Terrible', last_name='Osbourne', admin=False)
|
||||
user = srv.user.get(user_name=quoted_user)
|
||||
assert user == UserInfo(user_name=dotted_user, password=None, admin=False,
|
||||
first_name='Ozzy', middle_name='The Terrible', last_name='Osbourne',
|
||||
user_id=0, group_id=0)
|
||||
srv.user.delete(user_name=quoted_user)
|
||||
assert srv.user.get(user_name=quoted_user) is None
|
||||
# Via ISQL
|
||||
isql_txt = f'''---- {dotted_user}
|
||||
set list on;
|
||||
--set echo on;
|
||||
create or alter view v_sec as select sec$user_name, sec$first_name, sec$middle_name, sec$last_name, sec$admin
|
||||
from sec$users
|
||||
where upper(sec$user_name)=upper('{dotted_user}');
|
||||
commit;
|
||||
|
||||
select 'Try to add user with name: ' || '{dotted_user}' as isql_msg from rdb$database;
|
||||
|
||||
create or alter user {quoted_user} password '123' grant admin role;
|
||||
commit;
|
||||
|
||||
select 'Try to display user after adding.' as isql_msg from rdb$database;
|
||||
|
||||
select * from v_sec;
|
||||
commit;
|
||||
|
||||
select 'Try to modify user: change password and some attributes.' as isql_msg from rdb$database;
|
||||
|
||||
alter user {quoted_user}
|
||||
password 'Zeppelin'
|
||||
firstname 'John'
|
||||
middlename 'Bonzo The Beast'
|
||||
lastname 'Bonham'
|
||||
revoke admin role
|
||||
;
|
||||
commit;
|
||||
|
||||
select 'Try to display user after modifying.' as isql_msg from rdb$database;
|
||||
select * from v_sec;
|
||||
commit;
|
||||
|
||||
select 'Try to drop user.' as isql_msg from rdb$database;
|
||||
drop user {quoted_user};
|
||||
commit;
|
||||
select 'All done.' as isql_msg from rdb$database;
|
||||
'''
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
act_1.isql(switches=[], input=isql_txt)
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
||||
|
@ -2,29 +2,33 @@
|
||||
#
|
||||
# id: bugs.core_2879
|
||||
# title: Sweep could raise error : page 0 is of wrong type (expected 6, found 1)
|
||||
# decription:
|
||||
# decription:
|
||||
# Test receives content of firebird.log _before_ and _after_ running query that is show in the ticket.
|
||||
# Then we compare these two files.
|
||||
# Difference between them should relate ONLY to sweep start and finish details, and NOT about page wrong type.
|
||||
#
|
||||
#
|
||||
# Checked on: WI-V2.5.7.27024, WI-V3.0.1.32570, WI-T4.0.0.316 -- all works OK.
|
||||
# Refactored 01.02.2020, checked on:
|
||||
# 4.0.0.1759 SS: 4.754s.
|
||||
# 3.0.6.33240 SS: 3.704s.
|
||||
# 2.5.9.27119 SS: 6.607s.
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-2879
|
||||
# min_versions: ['2.5.1']
|
||||
# versions: 2.5.1
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
import time
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from difflib import unified_diff
|
||||
from firebird.qa import db_factory, python_act, Action, temp_file
|
||||
|
||||
# version: 2.5.1
|
||||
# resources: None
|
||||
|
||||
substitutions_1 = [('\t+', ' '), ('^((?!start|finish|expected|page|wrong).)*$', '')]
|
||||
substitutions_1 = [('^((?!start|finish|expected|page|wrong).)*$', '')] # ('\t+', ' '),
|
||||
|
||||
init_script_1 = """"""
|
||||
|
||||
@ -32,7 +36,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
|
||||
# test_script_1
|
||||
#---
|
||||
#
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# import subprocess
|
||||
@ -41,61 +45,61 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# import time
|
||||
# import datetime
|
||||
# from datetime import datetime
|
||||
#
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
#
|
||||
#
|
||||
# engine = str(db_conn.engine_version)
|
||||
# db_file = db_conn.database_name # "$(DATABASE_LOCATION)bugs.core_2879.fdb"
|
||||
#
|
||||
#
|
||||
# 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'):
|
||||
# # 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 )):
|
||||
# if os.path.isfile( f_names_list[i]):
|
||||
# os.remove( f_names_list[i] )
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def svc_get_fb_log( engine, f_fb_log ):
|
||||
#
|
||||
#
|
||||
# global subprocess
|
||||
#
|
||||
#
|
||||
# if engine.startswith('2.5'):
|
||||
# get_firebird_log_key='action_get_ib_log'
|
||||
# else:
|
||||
# get_firebird_log_key='action_get_fb_log'
|
||||
#
|
||||
#
|
||||
# subprocess.call([ context['fbsvcmgr_path'],
|
||||
# "localhost:service_mgr",
|
||||
# get_firebird_log_key
|
||||
# ],
|
||||
# stdout=f_fb_log,
|
||||
# stdout=f_fb_log,
|
||||
# stderr=subprocess.STDOUT
|
||||
# )
|
||||
#
|
||||
#
|
||||
# return
|
||||
#
|
||||
#
|
||||
# #-----------------------------------------------------
|
||||
#
|
||||
#
|
||||
# sql_ddl=''' set list on;
|
||||
# set term ^;
|
||||
# execute block returns (dts timestamp, sql varchar(80)) as
|
||||
@ -110,110 +114,155 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# sql = 'create global temporary table ' || :s || ' (id int);';
|
||||
# execute statement sql with autonomous transaction;
|
||||
# suspend;
|
||||
#
|
||||
#
|
||||
# dts = 'now';
|
||||
# sql = 'drop table ' || :s || ';';
|
||||
# execute statement sql with autonomous transaction;
|
||||
# suspend;
|
||||
#
|
||||
#
|
||||
# i = i + 1;
|
||||
# end
|
||||
# end ^
|
||||
# set term ;^
|
||||
# '''
|
||||
#
|
||||
#
|
||||
# f_isql_cmd=open( os.path.join(context['temp_directory'],'tmp_make_lot_GTT_2879.sql'), 'w', buffering = 0)
|
||||
# f_isql_cmd.write(sql_ddl)
|
||||
# f_isql_cmd.close()
|
||||
#
|
||||
#
|
||||
# # Get content of firebird.log BEFORE test:
|
||||
# ##########################################
|
||||
#
|
||||
#
|
||||
# f_fblog_before=open( os.path.join(context['temp_directory'],'tmp_2879_fblog_before.txt'), 'w', buffering = 0)
|
||||
# svc_get_fb_log( engine, f_fblog_before )
|
||||
# flush_and_close( f_fblog_before )
|
||||
#
|
||||
#
|
||||
# # LAUNCH ISQL ASYNCHRONOUSLY
|
||||
# ############################
|
||||
#
|
||||
#
|
||||
# f_isql_log=open( os.path.join(context['temp_directory'],'tmp_make_lot_GTT_2879.log'), 'w', buffering = 0)
|
||||
# p_isql=subprocess.Popen( [context['isql_path'], dsn, "-i", f_isql_cmd.name],
|
||||
# stdout=f_isql_log,
|
||||
# stdout=f_isql_log,
|
||||
# stderr=subprocess.STDOUT
|
||||
# )
|
||||
# #------------
|
||||
# time.sleep(2)
|
||||
# #------------
|
||||
#
|
||||
#
|
||||
# # LAUNCH SWEEP while ISQL is working:
|
||||
# # ############
|
||||
# fbsvc_log=open( os.path.join(context['temp_directory'],'tmp_svc_2879.log'), 'w', buffering = 0)
|
||||
# subprocess.call( [ context['fbsvcmgr_path'],"localhost:service_mgr", "action_repair", "dbname", db_file, "rpr_sweep_db"], stdout=fbsvc_log, stderr=subprocess.STDOUT )
|
||||
# flush_and_close( fbsvc_log )
|
||||
#
|
||||
#
|
||||
# p_isql.terminate()
|
||||
# f_isql_log.close()
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# # Get content of firebird.log AFTER test:
|
||||
# #########################################
|
||||
#
|
||||
#
|
||||
# f_fblog_after=open( os.path.join(context['temp_directory'],'tmp_2879_fblog_after.txt'), 'w', buffering = 0)
|
||||
# svc_get_fb_log( engine, f_fblog_after )
|
||||
# flush_and_close( f_fblog_after )
|
||||
#
|
||||
#
|
||||
# # 07.08.2016
|
||||
# # DIFFERENCE in the content of firebird.log should be EMPTY:
|
||||
# ####################
|
||||
#
|
||||
#
|
||||
# oldfb=open(f_fblog_before.name, 'r')
|
||||
# newfb=open(f_fblog_after.name, 'r')
|
||||
#
|
||||
#
|
||||
# difftext = ''.join(difflib.unified_diff(
|
||||
# oldfb.readlines(),
|
||||
# oldfb.readlines(),
|
||||
# newfb.readlines()
|
||||
# ))
|
||||
# oldfb.close()
|
||||
# newfb.close()
|
||||
#
|
||||
#
|
||||
# f_diff_txt=open( os.path.join(context['temp_directory'],'tmp_2879_diff.txt'), 'w', buffering = 0)
|
||||
# f_diff_txt.write(difftext)
|
||||
# flush_and_close( f_diff_txt )
|
||||
#
|
||||
# # NB: difflib.unified_diff() can show line(s) that present in both files, without marking that line(s) with "+".
|
||||
#
|
||||
# # NB: difflib.unified_diff() can show line(s) that present in both files, without marking that line(s) with "+".
|
||||
# # Usually these are 1-2 lines that placed just BEFORE difference starts.
|
||||
# # So we have to check output before display diff content: lines that are really differ must start with "+".
|
||||
#
|
||||
#
|
||||
# with open( f_diff_txt.name,'r') as f:
|
||||
# for line in f:
|
||||
# if line.startswith('+') and line.split('+'):
|
||||
# print(line.replace('+',' '))
|
||||
#
|
||||
#
|
||||
# # 01.02.2020. We have to change DB state to full shutdown and bring it back online
|
||||
# # in order to prevent "Object in use" while fbtest will try to drop this DB
|
||||
# #####################################
|
||||
# runProgram('gfix',[dsn,'-shut','full','-force','0'])
|
||||
# runProgram('gfix',[dsn,'-online'])
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# # Cleanup:
|
||||
# ##########
|
||||
# time.sleep(1)
|
||||
# cleanup( [i.name for i in (f_isql_cmd, f_isql_log, fbsvc_log, f_fblog_before,f_fblog_after, f_diff_txt)] )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
Sweep is started by SYSDBA
|
||||
Sweep is finished
|
||||
"""
|
||||
"""
|
||||
|
||||
isql_script = 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, isql_script: Path, capsys):
|
||||
isql_script.write_text(''' set list on;
|
||||
set term ^;
|
||||
execute block returns (dts timestamp, sql varchar(80)) as
|
||||
declare i int;
|
||||
declare s varchar(256);
|
||||
begin
|
||||
i = 1;
|
||||
while (i < 32767) do
|
||||
begin
|
||||
s = 'tmp' || :i;
|
||||
dts = 'now';
|
||||
sql = 'create global temporary table ' || :s || ' (id int);';
|
||||
execute statement sql with autonomous transaction;
|
||||
suspend;
|
||||
|
||||
dts = 'now';
|
||||
sql = 'drop table ' || :s || ';';
|
||||
execute statement sql with autonomous transaction;
|
||||
suspend;
|
||||
|
||||
i = i + 1;
|
||||
end
|
||||
end ^
|
||||
set term ;^
|
||||
''')
|
||||
with act_1.connect_server() as srv:
|
||||
# Get content of firebird.log BEFORE test
|
||||
srv.info.get_log()
|
||||
log_before = srv.readlines()
|
||||
p_isql = subprocess.Popen([act_1.vars['isql'], act_1.db.dsn, '-i', str(isql_script)],
|
||||
stderr=subprocess.STDOUT)
|
||||
time.sleep(2)
|
||||
# LAUNCH SWEEP while ISQL is working
|
||||
srv.database.sweep(database=str(act_1.db.db_path))
|
||||
p_isql.terminate()
|
||||
# Get content of firebird.log AFTER test
|
||||
srv.info.get_log()
|
||||
log_after = srv.readlines()
|
||||
for line in unified_diff(log_before, log_after):
|
||||
if line.startswith('+') and line.split('+'):
|
||||
print(line.replace('+', ' '))
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
act_1.stdout = capsys.readouterr().out
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
||||
|
||||
|
@ -2,25 +2,28 @@
|
||||
#
|
||||
# id: bugs.core_2912
|
||||
# title: Exception when upper casing string with lowercase y trema (code 0xFF in ISO8859_1 )
|
||||
# decription:
|
||||
# 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 = ISO8859_1 and perform several queries.
|
||||
# Result will be redirected to .log and .err files (they will be encoded, of course, also in ISO8859_1).
|
||||
# Finally, we open .log file (using codecs package), convert its content to UTF8 and show in expected_stdout.
|
||||
#
|
||||
#
|
||||
# Checked on:
|
||||
# * Windows: 4.0.0.2377, 3.0.8.33420, 2.5.9.27152
|
||||
# * Windows: 4.0.0.2377, 3.0.8.33420, 2.5.9.27152
|
||||
# * Linux: 4.0.0.2377, 3.0.8.33415
|
||||
#
|
||||
#
|
||||
# [pcisar] 16.11.2021
|
||||
# This test fails as UPPER('ÿ') does not work properly
|
||||
#
|
||||
# tracker_id: CORE-2912
|
||||
# min_versions: ['2.5.3']
|
||||
# versions: 2.5.3
|
||||
# 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
|
||||
@ -33,39 +36,39 @@ init_script_1 = """
|
||||
insert into test(c) values('ÿ');
|
||||
insert into test(c) values('Faÿ');
|
||||
commit;
|
||||
create index test_cu on test computed by (upper (c collate iso8859_1));
|
||||
commit;
|
||||
create index test_cu on test computed by (upper (c collate iso8859_1));
|
||||
commit;
|
||||
"""
|
||||
|
||||
db_1 = db_factory(charset='ISO8859_1', sql_dialect=3, init=init_script_1)
|
||||
|
||||
# test_script_1
|
||||
#---
|
||||
#
|
||||
#
|
||||
# import os
|
||||
# import codecs
|
||||
# import subprocess
|
||||
# import time
|
||||
#
|
||||
#
|
||||
# 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 )):
|
||||
@ -76,13 +79,13 @@ db_1 = db_factory(charset='ISO8859_1', 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 )
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
# sql_txt=''' set names ISO8859_1;
|
||||
#
|
||||
# sql_txt=''' set names ISO8859_1;
|
||||
# connect '%(dsn)s' user '%(user_name)s' password '%(user_password)s';
|
||||
# set list on;
|
||||
# select upper('aÿb') au from rdb$database;
|
||||
@ -95,15 +98,15 @@ db_1 = db_factory(charset='ISO8859_1', sql_dialect=3, init=init_script_1)
|
||||
# -- will be specified not in UPPER case (see note in CORE-4740 08/Apr/15 05:48 PM):
|
||||
# select c, upper(c) cu from test where c similar to '[[:ALPHA:]]{1,}ÿ%%';
|
||||
# set plan on;
|
||||
# select c from test where upper (c collate iso8859_1) = upper('ÿ');
|
||||
# select c, upper(c) cu from test where upper (c collate iso8859_1) starting with upper('Faÿ');
|
||||
# select c from test where upper (c collate iso8859_1) = upper('ÿ');
|
||||
# select c, upper(c) cu from test where upper (c collate iso8859_1) starting with upper('Faÿ');
|
||||
# ''' % dict(globals(), **locals())
|
||||
#
|
||||
#
|
||||
# f_run_sql = open( os.path.join(context['temp_directory'], 'tmp_2912_iso8859_1.sql'), 'w' )
|
||||
# f_run_sql.write( sql_txt.decode('utf8').encode('iso-8859-1') )
|
||||
# flush_and_close( f_run_sql )
|
||||
# # result: file tmp_2912_iso8859_1.sql is encoded in iso8859_1 (aka 'latin-1')
|
||||
#
|
||||
#
|
||||
# f_run_log = open( os.path.splitext(f_run_sql.name)[0]+'.log', 'w')
|
||||
# f_run_err = open( os.path.splitext(f_run_sql.name)[0]+'.err', 'w')
|
||||
# subprocess.call( [ context['isql_path'], '-q', '-i', f_run_sql.name ],
|
||||
@ -112,52 +115,67 @@ db_1 = db_factory(charset='ISO8859_1', sql_dialect=3, init=init_script_1)
|
||||
# )
|
||||
# flush_and_close( f_run_log )
|
||||
# flush_and_close( f_run_err )
|
||||
#
|
||||
#
|
||||
# # result: output will be encoded in iso9959_1, error log must be empty.
|
||||
# with codecs.open(f_run_log.name, 'r', encoding='iso-8859-1' ) as f:
|
||||
# stdout_encoded_in_latin_1 = f.readlines()
|
||||
#
|
||||
#
|
||||
# with codecs.open(f_run_err.name, 'r', encoding='iso-8859-1' ) as f:
|
||||
# stderr_encoded_in_latin_1 = f.readlines()
|
||||
#
|
||||
#
|
||||
# for i in stdout_encoded_in_latin_1:
|
||||
# print( i.encode('utf8') )
|
||||
#
|
||||
#
|
||||
# # NO error must occur:
|
||||
# ######################
|
||||
# for i in stderr_encoded_in_latin_1:
|
||||
# print( 'UNEXPECTED STDERR: ', i.encode('utf8') )
|
||||
#
|
||||
#
|
||||
# # cleanup:
|
||||
# ###########
|
||||
# ###########
|
||||
# cleanup( (f_run_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 = """
|
||||
AU AÿB
|
||||
C ÿ
|
||||
CU ÿ
|
||||
C Faÿ
|
||||
CU FAÿ
|
||||
C Faÿ
|
||||
CU FAÿ
|
||||
C Faÿ
|
||||
CU FAÿ
|
||||
C Faÿ
|
||||
CU FAÿ
|
||||
PLAN (TEST INDEX (TEST_CU))
|
||||
C ÿ
|
||||
PLAN (TEST INDEX (TEST_CU))
|
||||
C Faÿ
|
||||
CU FAÿ
|
||||
"""
|
||||
AU AÿB
|
||||
C ÿ
|
||||
CU ÿ
|
||||
C Faÿ
|
||||
CU FAÿ
|
||||
C Faÿ
|
||||
CU FAÿ
|
||||
C Faÿ
|
||||
CU FAÿ
|
||||
C Faÿ
|
||||
CU FAÿ
|
||||
PLAN (TEST INDEX (TEST_CU))
|
||||
C ÿ
|
||||
PLAN (TEST INDEX (TEST_CU))
|
||||
C Faÿ
|
||||
CU FAÿ
|
||||
"""
|
||||
|
||||
@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):
|
||||
sql_txt = '''set names ISO8859_1;
|
||||
set list on;
|
||||
select upper('aÿb') au from rdb$database;
|
||||
select c, upper(c) cu from test where c starting with upper('ÿ');
|
||||
select c, upper(c) cu from test where c containing 'Faÿ';
|
||||
select c, upper(c) cu from test where c starting with 'Faÿ';
|
||||
select c, upper(c) cu from test where c like 'Faÿ%';
|
||||
-- ### ACHTUNG ###
|
||||
-- As of WI-V2.5.4.26857, following will FAILS if character class "alpha"
|
||||
-- will be specified not in UPPER case (see note in CORE-4740 08/Apr/15 05:48 PM):
|
||||
select c, upper(c) cu from test where c similar to '[[:ALPHA:]]{1,}ÿ%';
|
||||
set plan on;
|
||||
select c from test where upper (c collate iso8859_1) = upper('ÿ');
|
||||
select c, upper(c) cu from test where upper (c collate iso8859_1) starting with upper('Faÿ');
|
||||
'''
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
act_1.isql(switches=['-q'], charset='ISO8859_1', input=sql_txt)
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
@ -2,45 +2,46 @@
|
||||
#
|
||||
# id: bugs.core_2940
|
||||
# title: Trace output could contain garbage data left from filtered out statements
|
||||
# decription:
|
||||
# decription:
|
||||
# 1. Obtain engine_version from built-in context variable.
|
||||
# 2. Make config for trace in proper format according to FB engine version, with 'exclude_filter' parameter from ticket.
|
||||
# 3. Launch trace session in separate child process using 'FBSVCMGR action_trace_start'
|
||||
# 4. Run ISQL with test commands. Only one of these command does not contain token that is specified in 'exclude_filter'
|
||||
# 5. Stop trace session. Output its log with filtering only statistics info.
|
||||
#
|
||||
#
|
||||
# Checked on: WI-V2.5.5.26916 (SS, SC, CS); WI-V3.0.0.32008 (SS, SC, CS). Result: OK.
|
||||
# Checked on: 3.0.1.32525, 4.0.0.238 // 07-jun-2016
|
||||
# ::: NB :::
|
||||
# Several delays (time.sleep) added in main thread because of OS buffering. Couldn't switch this buffering off.
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# ::: NB ::: 07-jun-2016.
|
||||
#
|
||||
#
|
||||
# WI-T4.0.0.238 will issue in trace log following statement with its statistics ("1 records fetched"):
|
||||
# ===
|
||||
# with recursive role_tree as (
|
||||
# select rdb$relation_name as nm, 0 as ur from rdb$user_privileges
|
||||
# where
|
||||
# rdb$privilege = 'M' and rdb$field_name = 'D'
|
||||
# and rdb$user = ? and rdb$user_type = 8
|
||||
# union all
|
||||
# select rdb$role_name as nm, 1 as ur from rdb$roles
|
||||
# with recursive role_tree as (
|
||||
# select rdb$relation_name as nm, 0 as ur from rdb$user_privileges
|
||||
# where
|
||||
# rdb$privilege = 'M' and rdb$field_name = 'D'
|
||||
# and rdb$user = ? and rdb$user_type = 8
|
||||
# union all
|
||||
# select rdb$role_name as nm, 1 as ur from rdb$roles
|
||||
# where rdb$role_name =...
|
||||
#
|
||||
#
|
||||
# param0 = varchar(93), "SYSDBA"
|
||||
# param1 = varchar(93), "NONE"
|
||||
# ===
|
||||
# We have to SKIP this statement statistics and start to check only "our" selects from rdb$database
|
||||
# see usage of first_sttm_pattern and trace_stat_pattern.
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-2940
|
||||
# min_versions: ['2.5.0']
|
||||
# versions: 2.5
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
from threading import Thread
|
||||
from firebird.qa import db_factory, python_act, Action
|
||||
|
||||
# version: 2.5
|
||||
# resources: None
|
||||
@ -58,40 +59,40 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# from subprocess import Popen
|
||||
# import time
|
||||
# import re
|
||||
#
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
#
|
||||
#
|
||||
# engine=str(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
|
||||
# # 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'):
|
||||
# # 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 )):
|
||||
# if os.path.isfile( f_names_list[i]):
|
||||
# os.remove( f_names_list[i] )
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# txt25 = '''# Trace config, format for 2.5. Generated auto, do not edit!
|
||||
# <database %[\\\\\\\\/]bugs.core_2940.fdb>
|
||||
# enabled true
|
||||
@ -102,15 +103,15 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# log_statement_finish true
|
||||
# print_plan true
|
||||
# print_perf true
|
||||
# time_threshold 0
|
||||
# time_threshold 0
|
||||
# </database>
|
||||
# '''
|
||||
#
|
||||
#
|
||||
# # NOTES ABOUT TRACE CONFIG FOR 3.0:
|
||||
# # 1) Header contains `database` clause in different format vs FB 2.5: its data must be enclosed with '{' '}'
|
||||
# # 2) Name and value must be separated by EQUALITY sign ('=') in FB-3 trace.conf, otherwise we get runtime error:
|
||||
# # element "<. . .>" have no attribute value set
|
||||
#
|
||||
#
|
||||
# txt30 = '''# Trace config, format for 3.0. Generated auto, do not edit!
|
||||
# database=%[\\\\\\\\/]bugs.core_2940.fdb
|
||||
# {
|
||||
@ -122,7 +123,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# log_statement_finish = true
|
||||
# print_plan = true
|
||||
# print_perf = true
|
||||
# time_threshold = 0
|
||||
# time_threshold = 0
|
||||
# }
|
||||
# '''
|
||||
# trccfg=open( os.path.join(context['temp_directory'],'tmp_trace_2940.cfg'), 'w')
|
||||
@ -131,40 +132,40 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# else:
|
||||
# trccfg.write(txt30)
|
||||
# trccfg.close()
|
||||
#
|
||||
#
|
||||
# trclog=open( os.path.join(context['temp_directory'],'tmp_trace_2940.log'), 'w')
|
||||
# trclog.close()
|
||||
# trclst=open( os.path.join(context['temp_directory'],'tmp_trace_2940.lst'), 'w')
|
||||
# trclst.close()
|
||||
#
|
||||
#
|
||||
# #####################################################
|
||||
# # Starting trace session in new child process (async.):
|
||||
#
|
||||
#
|
||||
# f_trclog=open(trclog.name,'w')
|
||||
# # Execute a child program in a new process, redirecting STDERR to the same target as of STDOUT:
|
||||
# p_trace=Popen([context['fbsvcmgr_path'], "localhost:service_mgr",
|
||||
# "action_trace_start",
|
||||
# "trc_cfg", trccfg.name],
|
||||
# stdout=f_trclog, stderr=subprocess.STDOUT)
|
||||
#
|
||||
#
|
||||
# # Wait! Trace session is initialized not instantly!
|
||||
# time.sleep(1)
|
||||
#
|
||||
#
|
||||
# #####################################################
|
||||
# # Running ISQL with test commands:
|
||||
#
|
||||
#
|
||||
# sqltxt='''
|
||||
# set list on;
|
||||
# -- statistics for this statement SHOULD appear in trace log:
|
||||
# select 1 k1 from rdb$database;
|
||||
# select 1 k1 from rdb$database;
|
||||
# commit;
|
||||
#
|
||||
#
|
||||
# -- statistics for this statement should NOT appear in trace log:
|
||||
# select 2 k2 from rdb$types rows 2 /* no_trace*/;
|
||||
#
|
||||
# select 2 k2 from rdb$types rows 2 /* no_trace*/;
|
||||
#
|
||||
# -- statistics for this statement should NOT appear in trace log:
|
||||
# select 3 no_trace from rdb$types rows 3;
|
||||
#
|
||||
# select 3 no_trace from rdb$types rows 3;
|
||||
#
|
||||
# -- statistics for this statement should NOT appear in trace log:
|
||||
# set term ^;
|
||||
# execute block returns(k4 int) as
|
||||
@ -174,15 +175,15 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# ^
|
||||
# set term ;^
|
||||
# '''
|
||||
#
|
||||
#
|
||||
# runProgram('isql',[dsn,'-n'],sqltxt)
|
||||
#
|
||||
#
|
||||
# # do NOT remove this otherwise trace log can contain only message about its start before being closed!
|
||||
# time.sleep(3)
|
||||
#
|
||||
#
|
||||
# #####################################################
|
||||
# # Getting ID of launched trace session and STOP it:
|
||||
#
|
||||
#
|
||||
# # Save active trace session info into file for further parsing it and obtain session_id back (for stop):
|
||||
# f_trclst=open(trclst.name,'w')
|
||||
# subprocess.call([context['fbsvcmgr_path'], "localhost:service_mgr",
|
||||
@ -190,7 +191,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# stdout=f_trclst, stderr=subprocess.STDOUT
|
||||
# )
|
||||
# flush_and_close( f_trclst )
|
||||
#
|
||||
#
|
||||
# trcssn=0
|
||||
# with open( trclst.name,'r') as f:
|
||||
# for line in f:
|
||||
@ -201,7 +202,7 @@ 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:
|
||||
# f_trclst=open(trclst.name,'a')
|
||||
# f_trclst.seek(0,2)
|
||||
@ -211,14 +212,14 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# stdout=f_trclst, stderr=subprocess.STDOUT
|
||||
# )
|
||||
# flush_and_close( f_trclst )
|
||||
#
|
||||
#
|
||||
# # Terminate child process of launched trace session (though it should already be killed):
|
||||
# p_trace.terminate()
|
||||
# flush_and_close( f_trclog )
|
||||
#
|
||||
#
|
||||
# #####################################################
|
||||
# # Output log of trace session, with filtering only info about statistics ('fetches'):
|
||||
#
|
||||
#
|
||||
# first_sttm_pattern=re.compile("select 1 k1")
|
||||
# trace_stat_pattern=re.compile("1 records fetched")
|
||||
# flag=0
|
||||
@ -228,24 +229,74 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# flag=1
|
||||
# if flag==1 and trace_stat_pattern.match(line):
|
||||
# print(line)
|
||||
#
|
||||
#
|
||||
# # Cleanup:
|
||||
# ##########
|
||||
# time.sleep(1)
|
||||
#
|
||||
#
|
||||
# cleanup([i.name for i in (trccfg,trclst,trclog)])
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#---
|
||||
#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 records fetched
|
||||
"""
|
||||
"""
|
||||
|
||||
test_script_1 = """
|
||||
set list on;
|
||||
-- statistics for this statement SHOULD appear in trace log:
|
||||
select 1 k1 from rdb$database;
|
||||
commit;
|
||||
-- statistics for this statement should NOT appear in trace log:
|
||||
select 2 k2 from rdb$types rows 2 /* no_trace*/;
|
||||
-- statistics for this statement should NOT appear in trace log:
|
||||
select 3 no_trace from rdb$types rows 3;
|
||||
-- statistics for this statement should NOT appear in trace log:
|
||||
set term ^;
|
||||
execute block returns(k4 int) as
|
||||
begin
|
||||
for select 4 from rdb$types rows 4 into k4 do suspend;
|
||||
end -- no_trace
|
||||
^
|
||||
set term ;^
|
||||
"""
|
||||
|
||||
def trace_session(act: Action):
|
||||
cfg30 = ['# Trace config, format for 3.0. Generated auto, do not edit!',
|
||||
f'database=%[\\\\/]{act.db.db_path.name}',
|
||||
'{',
|
||||
' enabled = true',
|
||||
' #include_filter',
|
||||
' exclude_filter = %no_trace%',
|
||||
' log_connections = true',
|
||||
' log_transactions = true',
|
||||
' log_statement_finish = true',
|
||||
' print_plan = true',
|
||||
' print_perf = true',
|
||||
' time_threshold = 0',
|
||||
'}']
|
||||
with act.connect_server() as srv:
|
||||
srv.trace.start(config='\n'.join(cfg30))
|
||||
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])
|
||||
trace_thread.start()
|
||||
act_1.isql(switches=['-n'], input=test_script_1)
|
||||
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
|
||||
|
||||
@pytest.mark.version('>=2.5')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
|
||||
|
||||
|
@ -2,21 +2,23 @@
|
||||
#
|
||||
# id: bugs.core_2981
|
||||
# title: Error in Trace plugin (use local symbols in query)
|
||||
# decription:
|
||||
# decription:
|
||||
# Test prepares trace config as it was mentioned in the ticket, then creates .sql with russian text in UTF8 encoding
|
||||
# and run trace and ISQL.
|
||||
# Finally, we compare content of firebird.log before and after running this query (it should be empty) and check that
|
||||
# size of error log of trace session is zero.
|
||||
#
|
||||
#
|
||||
# Checked on: WI-V2.5.7.27024, WI-V3.0.1.32570, WI-T4.0.0.316 -- all works OK.
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-2981
|
||||
# min_versions: ['2.5.1']
|
||||
# versions: 2.5.1
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
from threading import Thread
|
||||
from difflib import unified_diff
|
||||
from firebird.qa import db_factory, python_act, Action
|
||||
|
||||
# version: 2.5.1
|
||||
# resources: None
|
||||
@ -34,60 +36,60 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# import subprocess
|
||||
# import difflib
|
||||
# from subprocess import Popen
|
||||
#
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
#
|
||||
#
|
||||
# engine = str(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
|
||||
# # 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'):
|
||||
# # 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 )):
|
||||
# if os.path.isfile( f_names_list[i]):
|
||||
# os.remove( f_names_list[i] )
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def svc_get_fb_log( engine, f_fb_log ):
|
||||
#
|
||||
#
|
||||
# global subprocess
|
||||
#
|
||||
#
|
||||
# if engine.startswith('2.5'):
|
||||
# get_firebird_log_key='action_get_ib_log'
|
||||
# else:
|
||||
# get_firebird_log_key='action_get_fb_log'
|
||||
#
|
||||
#
|
||||
# subprocess.call([ context['fbsvcmgr_path'],
|
||||
# "localhost:service_mgr",
|
||||
# get_firebird_log_key
|
||||
# ],
|
||||
# stdout=f_fb_log,
|
||||
# stdout=f_fb_log,
|
||||
# stderr=subprocess.STDOUT
|
||||
# )
|
||||
#
|
||||
#
|
||||
# return
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# txt25 = '''# Trace config, format for 2.5. Generated auto, do not edit!
|
||||
# <database %[\\\\\\\\/]bugs.core_2981.fdb>
|
||||
# enabled true
|
||||
@ -115,20 +117,20 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# max_blr_length 500
|
||||
# max_dyn_length 500
|
||||
# max_arg_length 80
|
||||
# max_arg_count 30
|
||||
# max_arg_count 30
|
||||
# </database>
|
||||
# <services>
|
||||
# enabled false
|
||||
# log_services false
|
||||
# log_service_query false
|
||||
# </services>
|
||||
# </services>
|
||||
# '''
|
||||
#
|
||||
#
|
||||
# # NOTES ABOUT TRACE CONFIG FOR 3.0:
|
||||
# # 1) Header contains `database` clause in different format vs FB 2.5: its data must be enclosed with '{' '}'
|
||||
# # 2) Name and value must be separated by EQUALITY sign ('=') in FB-3 trace.conf, otherwise we get runtime error:
|
||||
# # element "<. . .>" have no attribute value set
|
||||
#
|
||||
#
|
||||
# txt30 = '''# Trace config, format for 3.0. Generated auto, do not edit!
|
||||
# database=%[\\\\\\\\/]bugs.core_2981.fdb
|
||||
# {
|
||||
@ -156,7 +158,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# max_blr_length = 500
|
||||
# max_dyn_length = 500
|
||||
# max_arg_length = 80
|
||||
# max_arg_count = 30
|
||||
# max_arg_count = 30
|
||||
# }
|
||||
# services {
|
||||
# enabled = false
|
||||
@ -164,52 +166,52 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# log_service_query = false
|
||||
# }
|
||||
# '''
|
||||
#
|
||||
#
|
||||
# f_trccfg=open( os.path.join(context['temp_directory'],'tmp_trace_2981.cfg'), 'w')
|
||||
# if engine.startswith('2.5'):
|
||||
# f_trccfg.write(txt25)
|
||||
# else:
|
||||
# f_trccfg.write(txt30)
|
||||
# flush_and_close( f_trccfg )
|
||||
#
|
||||
#
|
||||
# # Get content of firebird.log BEFORE test:
|
||||
# ##########################################
|
||||
#
|
||||
#
|
||||
# f_fblog_before=open( os.path.join(context['temp_directory'],'tmp_2981_fblog_before.txt'), 'w')
|
||||
# svc_get_fb_log( engine, f_fblog_before )
|
||||
# flush_and_close( f_fblog_before )
|
||||
#
|
||||
#
|
||||
# # Starting trace session in new child process (async.):
|
||||
# #######################################################
|
||||
#
|
||||
#
|
||||
# f_trclog=open( os.path.join(context['temp_directory'],'tmp_trace_2981.log'), 'w')
|
||||
# f_trcerr=open( os.path.join(context['temp_directory'],'tmp_trace_2981.err'), 'w')
|
||||
#
|
||||
#
|
||||
# # Execute a child program in a new process, redirecting STDERR to the same target as of STDOUT:
|
||||
# p_trace=Popen([context['fbsvcmgr_path'], "localhost:service_mgr",
|
||||
# "action_trace_start",
|
||||
# "trc_cfg", f_trccfg.name],
|
||||
# stdout=f_trclog,
|
||||
# stdout=f_trclog,
|
||||
# stderr=f_trcerr
|
||||
# )
|
||||
#
|
||||
#
|
||||
# # Wait! Trace session is initialized not instantly!
|
||||
# time.sleep(2)
|
||||
#
|
||||
#
|
||||
# localized_query='''
|
||||
# set list on;
|
||||
# select '*Лев Николаевич Толстой *
|
||||
#
|
||||
#
|
||||
# *Анна Каренина *
|
||||
#
|
||||
#
|
||||
# /Мне отмщение, и аз воздам/
|
||||
#
|
||||
#
|
||||
# *ЧАСТЬ ПЕРВАЯ*
|
||||
#
|
||||
#
|
||||
# *I *
|
||||
#
|
||||
#
|
||||
# Все счастливые семьи похожи друг на друга, каждая несчастливая
|
||||
# семья несчастлива по-своему.
|
||||
# семья несчастлива по-своему.
|
||||
# Все смешалось в доме Облонских. Жена узнала, что муж был в связи
|
||||
# с бывшею в их доме француженкою-гувернанткой, и объявила мужу, что
|
||||
# не может жить с ним в одном доме. Положение это продолжалось уже
|
||||
@ -221,20 +223,20 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# своих комнат, мужа третий день не было дома. Дети бегали по всему
|
||||
# дому, как потерянные; англичанка поссорилась с экономкой и написала
|
||||
# записку приятельнице, прося приискать ей новое место; повар ушел еще
|
||||
# вчера со двора, во время обеда; черная кухарка и кучер просили расчета.
|
||||
# вчера со двора, во время обеда; черная кухарка и кучер просили расчета.
|
||||
# На третий день после ссоры князь Степан Аркадьич Облонский --
|
||||
# Стива, как его звали в свете, -- в обычный час, то есть в восемь
|
||||
# часов утра, проснулся не в спальне жены, а в своем кабинете, на
|
||||
# сафьянном диване... Он повернул свое полное, выхоленное тело на
|
||||
# пружинах дивана, как бы желая опять заснуть надолго, с другой
|
||||
# стороны крепко обнял подушку и прижался к ней щекой; но вдруг
|
||||
# вскочил, сел на диван и открыл глаза.
|
||||
# вскочил, сел на диван и открыл глаза.
|
||||
# "Да, да, как это было? -- думал он, вспоминая сон. -- Да, как это
|
||||
# было? Да! Алабин давал обед в Дармштадте; нет, не в Дармштадте, а
|
||||
# что-то американское. Да, но там Дармштадт был в Америке. Да, Алабин
|
||||
# давал обед на стеклянных столах, да, -- и столы пели: Il mio tesoro,
|
||||
# и не Il mio tesoro, а что-то лучше, и какие-то маленькие графинчики,
|
||||
# и они же женщины", -- вспоминал он.
|
||||
# и они же женщины", -- вспоминал он.
|
||||
# Глаза Степана Аркадьича весело заблестели, и он задумался,
|
||||
# улыбаясь. "Да, хорошо было, очень хорошо. Много еще там было
|
||||
# отличного, да не скажешь словами и мыслями даже наяву не выразишь".
|
||||
@ -244,27 +246,27 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# по старой, девятилетней привычке, не вставая, потянулся рукой к тому
|
||||
# месту, где в спальне у него висел халат. И тут он вспомнил вдруг,
|
||||
# как и почему он спит не в спальне жены, а в кабинете; улыбка исчезла
|
||||
# с его лица, он сморщил лоб.
|
||||
# с его лица, он сморщил лоб.
|
||||
# "Ах, ах, ах! Ааа!.." -- замычал он, вспоминая все, что было. И
|
||||
# его воображению представились опять все подробности ссоры с женою,
|
||||
# вся безвыходность его положения и мучительнее всего собственная вина
|
||||
# его.
|
||||
# его.
|
||||
# "Да! она не простит и не может простить. И всего ужаснее то, что
|
||||
# виной всему я, виной я, а не виноват. В этом-то вся драма, -- думал
|
||||
# он. -- Ах, ах, ах!" -- приговаривал он с отчаянием, вспоминая самые
|
||||
# тяжелые для себя впечатления из этой ссоры.
|
||||
# тяжелые для себя впечатления из этой ссоры.
|
||||
# Неприятнее всего была та первая минута, когда он, вернувшись из
|
||||
# театра, веселый и довольный, с огромною грушей для жены в руке, не
|
||||
# нашел жены в гостиной; к удивлению, не нашел ее и в кабинете и,
|
||||
# наконец, увидал ее в спальне с несчастною, открывшею все, запиской в
|
||||
# руке.
|
||||
# руке.
|
||||
# Она, эта вечно озабоченная, и хлопотливая, и недалекая, какою он
|
||||
# считал ее, Долли, неподвижно сидела с запиской в руке и с выражением
|
||||
# ужаса, отчаяния и гнева смотрела на него.
|
||||
# -- Что это? это? -- спрашивала она, указывая на записку.
|
||||
# ужаса, отчаяния и гнева смотрела на него.
|
||||
# -- Что это? это? -- спрашивала она, указывая на записку.
|
||||
# И при этом воспоминании, как это часто бывает, мучала Степана
|
||||
# Аркадьича не столько самое событие, сколько то, как он ответил на
|
||||
# эти слова жены.
|
||||
# эти слова жены.
|
||||
# С ним случилось в эту минуту то, что случается с людьми, когда
|
||||
# они неожиданно уличены в чем-нибудь слишком постыдном. Он не сумел
|
||||
# приготовить свое лицо к тому положению, в которое он становился
|
||||
@ -273,45 +275,45 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# равнодушным -- все было бы лучше того, что он сделал! -- его лицо
|
||||
# совершенно невольно ("рефлексы головного мозга", -- подумал Степан
|
||||
# Аркадьич, который любил физиологию), совершенно невольно вдруг
|
||||
# улыбнулось привычною, доброю и потому глупою улыбкой.
|
||||
# улыбнулось привычною, доброю и потому глупою улыбкой.
|
||||
# Эту глупую улыбку он не мог простить себе. Увидав эту улыбку,
|
||||
# Долли вздрогнула, как от физической боли, разразилась, со
|
||||
# свойственною ей горячностью, потоком жестоких слов и выбежала из
|
||||
# комнаты. С тех пор она не хотела видеть мужа.
|
||||
# "Всему виной эта глупая улыбка", -- думал Степан Аркадьич.
|
||||
# комнаты. С тех пор она не хотела видеть мужа.
|
||||
# "Всему виной эта глупая улыбка", -- думал Степан Аркадьич.
|
||||
# "Но что же делать? что делать?" -- с отчаянием говорил он себе и
|
||||
# не находил ответа.
|
||||
# не находил ответа.
|
||||
# ' from rdb$database;
|
||||
# '''
|
||||
# f_utf8 = open( os.path.join(context['temp_directory'],'tmp_2981_run.sql'), 'w')
|
||||
# f_utf8.write(localized_query)
|
||||
# flush_and_close( f_utf8 )
|
||||
#
|
||||
#
|
||||
# # RUN QUERY WITH NON-ASCII CHARACTERS
|
||||
# #####################################
|
||||
#
|
||||
#
|
||||
# f_run_log = open( os.path.join(context['temp_directory'],'tmp_2981_run.log'), 'w')
|
||||
# f_run_err = open( os.path.join(context['temp_directory'],'tmp_2981_run.err'), 'w')
|
||||
# subprocess.call( [context['isql_path'], dsn, "-q", "-i", f_utf8.name, '-ch', 'utf8' ],
|
||||
# stdout = f_run_log,
|
||||
# stderr = f_run_err
|
||||
# )
|
||||
#
|
||||
#
|
||||
# flush_and_close( f_run_log )
|
||||
# flush_and_close( f_run_err )
|
||||
#
|
||||
#
|
||||
# #####################################################
|
||||
# # Getting ID of launched trace session and STOP it:
|
||||
#
|
||||
#
|
||||
# # Save active trace session info into file for further parsing it and obtain session_id back (for stop):
|
||||
# f_trclst=open( os.path.join(context['temp_directory'],'tmp_trace_2981.lst'), 'w')
|
||||
# subprocess.call([context['fbsvcmgr_path'], "localhost:service_mgr",
|
||||
# "action_trace_list"],
|
||||
# stdout=f_trclst,
|
||||
# stdout=f_trclst,
|
||||
# stderr=subprocess.STDOUT
|
||||
# )
|
||||
# flush_and_close( f_trclst )
|
||||
#
|
||||
#
|
||||
# trcssn=0
|
||||
# with open( f_trclst.name,'r') as f:
|
||||
# for line in f:
|
||||
@ -322,7 +324,7 @@ 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:
|
||||
# f_trclst=open(f_trclst.name,'a')
|
||||
# f_trclst.seek(0,2)
|
||||
@ -332,23 +334,23 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# stdout=f_trclst, stderr=subprocess.STDOUT
|
||||
# )
|
||||
# flush_and_close( f_trclst )
|
||||
#
|
||||
#
|
||||
# # do NOT remove this delay: trase session can not be stopped immediatelly:
|
||||
# time.sleep(2)
|
||||
#
|
||||
#
|
||||
# # Terminate child process of launched trace session (though it should already be killed):
|
||||
# p_trace.terminate()
|
||||
# flush_and_close( f_trclog )
|
||||
# flush_and_close( f_trcerr )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# # Get content of firebird.log AFTER test:
|
||||
# #########################################
|
||||
#
|
||||
#
|
||||
# f_fblog_after=open( os.path.join(context['temp_directory'],'tmp_2981_fblog_after.txt'), 'w')
|
||||
# svc_get_fb_log( engine, f_fblog_after )
|
||||
# flush_and_close( f_fblog_after )
|
||||
#
|
||||
#
|
||||
# # STDERR for ISQL (that created DB) and trace session - they both must be EMPTY:
|
||||
# #################
|
||||
# f_list=[f_run_err, f_trcerr]
|
||||
@ -358,43 +360,184 @@ 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)
|
||||
#
|
||||
#
|
||||
# # DIFFERENCE in the content of firebird.log should be EMPTY:
|
||||
# ####################
|
||||
#
|
||||
#
|
||||
# oldfb=open(f_fblog_before.name, 'r')
|
||||
# newfb=open(f_fblog_after.name, 'r')
|
||||
#
|
||||
#
|
||||
# difftext = ''.join(difflib.unified_diff(
|
||||
# oldfb.readlines(),
|
||||
# oldfb.readlines(),
|
||||
# newfb.readlines()
|
||||
# ))
|
||||
# oldfb.close()
|
||||
# newfb.close()
|
||||
#
|
||||
#
|
||||
# f_diff_txt=open( os.path.join(context['temp_directory'],'tmp_2981_diff.txt'), 'w')
|
||||
# f_diff_txt.write(difftext)
|
||||
# flush_and_close( f_diff_txt )
|
||||
#
|
||||
#
|
||||
# with open( f_diff_txt.name,'r') as f:
|
||||
# for line in f:
|
||||
# print("Unexpected DIFF in firebird.log: "+line)
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# # Cleanup:
|
||||
# ###########
|
||||
# time.sleep(1)
|
||||
# cleanup( [i.name for i in (f_run_log, f_run_err, f_trccfg, f_trclst, f_trcerr, f_fblog_before,f_fblog_after, f_diff_txt, f_trclog, f_utf8)] )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#---
|
||||
#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;
|
||||
select '*Лев Николаевич Толстой *
|
||||
|
||||
*Анна Каренина *
|
||||
|
||||
/Мне отмщение, и аз воздам/
|
||||
|
||||
*ЧАСТЬ ПЕРВАЯ*
|
||||
|
||||
*I *
|
||||
|
||||
Все счастливые семьи похожи друг на друга, каждая несчастливая
|
||||
семья несчастлива по-своему.
|
||||
Все смешалось в доме Облонских. Жена узнала, что муж был в связи
|
||||
с бывшею в их доме француженкою-гувернанткой, и объявила мужу, что
|
||||
не может жить с ним в одном доме. Положение это продолжалось уже
|
||||
третий день и мучительно чувствовалось и самими супругами, и всеми
|
||||
членами семьи, и домочадцами. Все члены семьи и домочадцы
|
||||
чувствовали, что нет смысла в их сожительстве и что на каждом
|
||||
постоялом дворе случайно сошедшиеся люди более связаны между собой,
|
||||
чем они, члены семьи и домочадцы Облонских. Жена не выходила из
|
||||
своих комнат, мужа третий день не было дома. Дети бегали по всему
|
||||
дому, как потерянные; англичанка поссорилась с экономкой и написала
|
||||
записку приятельнице, прося приискать ей новое место; повар ушел еще
|
||||
вчера со двора, во время обеда; черная кухарка и кучер просили расчета.
|
||||
На третий день после ссоры князь Степан Аркадьич Облонский --
|
||||
Стива, как его звали в свете, -- в обычный час, то есть в восемь
|
||||
часов утра, проснулся не в спальне жены, а в своем кабинете, на
|
||||
сафьянном диване... Он повернул свое полное, выхоленное тело на
|
||||
пружинах дивана, как бы желая опять заснуть надолго, с другой
|
||||
стороны крепко обнял подушку и прижался к ней щекой; но вдруг
|
||||
вскочил, сел на диван и открыл глаза.
|
||||
"Да, да, как это было? -- думал он, вспоминая сон. -- Да, как это
|
||||
было? Да! Алабин давал обед в Дармштадте; нет, не в Дармштадте, а
|
||||
что-то американское. Да, но там Дармштадт был в Америке. Да, Алабин
|
||||
давал обед на стеклянных столах, да, -- и столы пели: Il mio tesoro,
|
||||
и не Il mio tesoro, а что-то лучше, и какие-то маленькие графинчики,
|
||||
и они же женщины", -- вспоминал он.
|
||||
Глаза Степана Аркадьича весело заблестели, и он задумался,
|
||||
улыбаясь. "Да, хорошо было, очень хорошо. Много еще там было
|
||||
отличного, да не скажешь словами и мыслями даже наяву не выразишь".
|
||||
И, заметив полосу света, пробившуюся сбоку одной из суконных стор,
|
||||
он весело скинул ноги с дивана, отыскал ими шитые женой (подарок ко
|
||||
дню рождения в прошлом году), обделанные в золотистый сафьян туфли и
|
||||
по старой, девятилетней привычке, не вставая, потянулся рукой к тому
|
||||
месту, где в спальне у него висел халат. И тут он вспомнил вдруг,
|
||||
как и почему он спит не в спальне жены, а в кабинете; улыбка исчезла
|
||||
с его лица, он сморщил лоб.
|
||||
"Ах, ах, ах! Ааа!.." -- замычал он, вспоминая все, что было. И
|
||||
его воображению представились опять все подробности ссоры с женою,
|
||||
вся безвыходность его положения и мучительнее всего собственная вина
|
||||
его.
|
||||
"Да! она не простит и не может простить. И всего ужаснее то, что
|
||||
виной всему я, виной я, а не виноват. В этом-то вся драма, -- думал
|
||||
он. -- Ах, ах, ах!" -- приговаривал он с отчаянием, вспоминая самые
|
||||
тяжелые для себя впечатления из этой ссоры.
|
||||
Неприятнее всего была та первая минута, когда он, вернувшись из
|
||||
театра, веселый и довольный, с огромною грушей для жены в руке, не
|
||||
нашел жены в гостиной; к удивлению, не нашел ее и в кабинете и,
|
||||
наконец, увидал ее в спальне с несчастною, открывшею все, запиской в
|
||||
руке.
|
||||
Она, эта вечно озабоченная, и хлопотливая, и недалекая, какою он
|
||||
считал ее, Долли, неподвижно сидела с запиской в руке и с выражением
|
||||
ужаса, отчаяния и гнева смотрела на него.
|
||||
-- Что это? это? -- спрашивала она, указывая на записку.
|
||||
И при этом воспоминании, как это часто бывает, мучала Степана
|
||||
Аркадьича не столько самое событие, сколько то, как он ответил на
|
||||
эти слова жены.
|
||||
С ним случилось в эту минуту то, что случается с людьми, когда
|
||||
они неожиданно уличены в чем-нибудь слишком постыдном. Он не сумел
|
||||
приготовить свое лицо к тому положению, в которое он становился
|
||||
перед женой после открытия его вины. Вместо того чтоб оскорбиться,
|
||||
отрекаться, оправдываться, просить прощения, оставаться даже
|
||||
равнодушным -- все было бы лучше того, что он сделал! -- его лицо
|
||||
совершенно невольно ("рефлексы головного мозга", -- подумал Степан
|
||||
Аркадьич, который любил физиологию), совершенно невольно вдруг
|
||||
улыбнулось привычною, доброю и потому глупою улыбкой.
|
||||
Эту глупую улыбку он не мог простить себе. Увидав эту улыбку,
|
||||
Долли вздрогнула, как от физической боли, разразилась, со
|
||||
свойственною ей горячностью, потоком жестоких слов и выбежала из
|
||||
комнаты. С тех пор она не хотела видеть мужа.
|
||||
"Всему виной эта глупая улыбка", -- думал Степан Аркадьич.
|
||||
"Но что же делать? что делать?" -- с отчаянием говорил он себе и
|
||||
не находил ответа.
|
||||
' from rdb$database;
|
||||
"""
|
||||
|
||||
def trace_session(act: Action):
|
||||
cfg30 = ['# Trace config, format for 3.0. Generated auto, do not edit!',
|
||||
f'database=%[\\\\/]{act.db.db_path.name}',
|
||||
'{',
|
||||
' enabled = true',
|
||||
' include_filter = %(SELECT|INSERT|UPDATE|DELETE)%',
|
||||
' exclude_filter = %no_trace%',
|
||||
' log_connections = true',
|
||||
' log_transactions = true',
|
||||
' log_statement_prepare = true',
|
||||
' log_statement_free = true',
|
||||
' log_statement_start = true',
|
||||
' log_statement_finish = true',
|
||||
' log_trigger_start = true',
|
||||
' log_trigger_finish = true',
|
||||
' log_context = true',
|
||||
' print_plan = true',
|
||||
' print_perf = true',
|
||||
' time_threshold = 0',
|
||||
' max_sql_length = 5000',
|
||||
' max_blr_length = 500',
|
||||
' max_dyn_length = 500',
|
||||
' max_arg_length = 80',
|
||||
' max_arg_count = 30',
|
||||
'}',
|
||||
'services {',
|
||||
' enabled = false',
|
||||
' log_services = false',
|
||||
' log_service_query = false',
|
||||
'}']
|
||||
with act.connect_server() as srv:
|
||||
srv.encoding = 'utf8'
|
||||
srv.trace.start(config='\n'.join(cfg30))
|
||||
for line in srv:
|
||||
pass # we are not interested in trace output
|
||||
|
||||
@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):
|
||||
# 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.start()
|
||||
# RUN QUERY WITH NON-ASCII CHARACTERS
|
||||
act_1.isql(switches=['-n', '-q'], input=test_script_1)
|
||||
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')
|
||||
# Get content of firebird.log AFTER test
|
||||
with act_1.connect_server() as srv:
|
||||
srv.info.get_log()
|
||||
log_after = srv.readlines()
|
||||
assert '\n'.join(unified_diff(log_before, log_after)) == ''
|
||||
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
#
|
||||
# id: bugs.core_2988
|
||||
# title: Concurrent transaction number not reported if lock timeout occurs
|
||||
# decription:
|
||||
# decription:
|
||||
# 08-aug-2018.
|
||||
# ::: ACHTUNG :::
|
||||
# Important change has been added in FB 4.0.
|
||||
@ -16,29 +16,32 @@
|
||||
# as ticket says in its case-1:
|
||||
# ===
|
||||
# set transaction read committed no record_version lock timeout 10;
|
||||
# select * from test;
|
||||
# select * from test;
|
||||
# ===
|
||||
# For this reason it was decided to create separate section for major version 4.0
|
||||
# and use UPDATE statement instead of 'select * from test' (UPDATE also must READ
|
||||
# and use UPDATE statement instead of 'select * from test' (UPDATE also must READ
|
||||
# data before changing).
|
||||
#
|
||||
#
|
||||
# Checked on:
|
||||
# FB25SC, build 2.5.9.27115: OK, 3.750s.
|
||||
# FB30SS, build 3.0.4.33022: OK, 4.343s.
|
||||
# FB40SS, build 4.0.0.1154: OK, 4.875s.
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-2988
|
||||
# min_versions: ['2.5.4']
|
||||
# versions: 3.0, 4.0
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
from firebird.qa import db_factory, isql_act, Action, python_act
|
||||
from firebird.driver import TPB, TraAccessMode, Isolation
|
||||
|
||||
# version: 3.0
|
||||
# resources: None
|
||||
|
||||
substitutions_1 = [('record not found for user:.*', ''), ('-concurrent transaction number is.*', '-concurrent transaction number is'), ('-At block line: [\\d]+, col: [\\d]+', '-At block line')]
|
||||
substitutions_1 = [('record not found for user:.*', ''),
|
||||
('-concurrent transaction number is.*', '-concurrent transaction number is'),
|
||||
('-At block line: [\\d]+, col: [\\d]+', '-At block line')]
|
||||
|
||||
init_script_1 = """"""
|
||||
|
||||
@ -49,7 +52,7 @@ test_script_1 = """
|
||||
commit;
|
||||
create user tmp$2988 password 'tmp$2988';
|
||||
commit;
|
||||
|
||||
|
||||
recreate table test (id integer);
|
||||
insert into test values(1);
|
||||
commit;
|
||||
@ -60,7 +63,7 @@ test_script_1 = """
|
||||
|
||||
set transaction lock timeout 1;
|
||||
update test set id = id;
|
||||
|
||||
|
||||
set term ^;
|
||||
execute block as
|
||||
declare v_usr char(31) = 'tmp$2988';
|
||||
@ -76,10 +79,10 @@ test_script_1 = """
|
||||
^
|
||||
set term ;^
|
||||
rollback;
|
||||
|
||||
|
||||
set transaction read committed no record_version lock timeout 1;
|
||||
update test set id = id;
|
||||
|
||||
|
||||
set term ^;
|
||||
execute block as
|
||||
declare v_usr char(31) = 'tmp$2988';
|
||||
@ -95,11 +98,11 @@ test_script_1 = """
|
||||
^
|
||||
set term ;^
|
||||
rollback;
|
||||
|
||||
|
||||
set list on;
|
||||
set transaction read committed no record_version lock timeout 1;
|
||||
select id from test with lock;
|
||||
|
||||
|
||||
set term ^;
|
||||
execute block as
|
||||
declare v_usr char(31) = 'tmp$2988';
|
||||
@ -114,7 +117,7 @@ test_script_1 = """
|
||||
begin
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
execute statement ('select id from test with lock')
|
||||
with autonomous transaction
|
||||
as user v_usr password v_pwd
|
||||
@ -155,7 +158,8 @@ act_1 = isql_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
ID 1
|
||||
"""
|
||||
"""
|
||||
|
||||
expected_stderr_1 = """
|
||||
Statement failed, SQLSTATE = HY000
|
||||
record not found for user: TMP$2988
|
||||
@ -177,7 +181,7 @@ expected_stderr_1 = """
|
||||
-read conflicts with concurrent update
|
||||
-concurrent transaction number is 24
|
||||
-At block line: 7, col: 9
|
||||
"""
|
||||
"""
|
||||
|
||||
@pytest.mark.version('>=3.0,<4.0')
|
||||
def test_1(act_1: Action):
|
||||
@ -190,7 +194,8 @@ def test_1(act_1: Action):
|
||||
# version: 4.0
|
||||
# resources: None
|
||||
|
||||
substitutions_2 = [('^((?!concurrent transaction number is).)*$', ''), ('[\\-]{0,1}concurrent transaction number is [0-9]+', 'concurrent transaction number is')]
|
||||
substitutions_2 = [('^((?!concurrent transaction number is).)*$', ''),
|
||||
('[\\-]{0,1}concurrent transaction number is [0-9]+', 'concurrent transaction number is')]
|
||||
|
||||
init_script_2 = """
|
||||
create table test(id int, x int, constraint test_pk primary key(id) using index test_pk);
|
||||
@ -203,42 +208,42 @@ db_2 = db_factory(sql_dialect=3, init=init_script_2)
|
||||
|
||||
# test_script_2
|
||||
#---
|
||||
#
|
||||
#
|
||||
# import os
|
||||
# db_conn.close()
|
||||
#
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
#
|
||||
#
|
||||
# con = fdb.connect(dsn = dsn)
|
||||
#
|
||||
# tx1 = con.trans()
|
||||
#
|
||||
# tx1 = con.trans()
|
||||
# tx1.begin()
|
||||
# cur1=tx1.cursor()
|
||||
# cur1.execute( 'update test set x = ? where id = ?', (222, 1) )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# # **INSTEAD** of ticket case-1:
|
||||
# # set transaction read committed no record_version lock timeout N;
|
||||
# # -- we start Tx with lock_timeout using custom TPB and try just to **update** record which is locked now
|
||||
# # (but NOT 'SELECT ...'! It is useless with default value of confign parameter ReadConsistency = 1).
|
||||
# # Message about concurrent transaction (which holds lock) in any case must appear in exception text.
|
||||
# # NB: NO_rec_version is USELESS in default FB 4.0 config!
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# # Linsk to doc for creating instance of custom TPB and start transaction which using it:
|
||||
# # 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) # ::: NB ::: NO_rec_version is USELESS in default FB 4.0 config!
|
||||
# custom_tpb.lock_timeout = 1
|
||||
#
|
||||
# tx2 = con.trans( default_tpb = custom_tpb )
|
||||
#
|
||||
# tx2 = con.trans( default_tpb = custom_tpb )
|
||||
# tx2.begin()
|
||||
# cur2=tx2.cursor()
|
||||
#
|
||||
#
|
||||
# try:
|
||||
# cur2.execute( 'update test set x = ? where id = ?', (333, 1) )
|
||||
# except Exception,e:
|
||||
@ -249,21 +254,21 @@ db_2 = db_factory(sql_dialect=3, init=init_script_2)
|
||||
# print( '-'*30 )
|
||||
# finally:
|
||||
# tx2.commit()
|
||||
#
|
||||
#
|
||||
# #----------------------------------------------------------
|
||||
#
|
||||
#
|
||||
# # This is for ticket case-2:
|
||||
# # set transaction read committed lock timeout N;
|
||||
# # select * from test with lock;
|
||||
#
|
||||
# # select * from test with lock;
|
||||
#
|
||||
# custom_tpb.access_mode = fdb.isc_tpb_write
|
||||
# custom_tpb.isolation_level = fdb.isc_tpb_concurrency
|
||||
# custom_tpb.lock_timeout = 1
|
||||
#
|
||||
# tx3 = con.trans( default_tpb = custom_tpb )
|
||||
#
|
||||
# tx3 = con.trans( default_tpb = custom_tpb )
|
||||
# tx3.begin()
|
||||
# cur3=tx3.cursor()
|
||||
#
|
||||
#
|
||||
# try:
|
||||
# cur3.execute( 'select x from test where id = ? with lock', (1,) )
|
||||
# for r in cur3:
|
||||
@ -276,22 +281,69 @@ db_2 = db_factory(sql_dialect=3, init=init_script_2)
|
||||
# print( '-'*30 )
|
||||
# finally:
|
||||
# tx3.commit()
|
||||
#
|
||||
#
|
||||
# tx1.commit()
|
||||
# con.close()
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_2 = python_act('db_2', test_script_2, substitutions=substitutions_2)
|
||||
|
||||
act_2 = python_act('db_2', substitutions=substitutions_2)
|
||||
|
||||
expected_stdout_2 = """
|
||||
- concurrent transaction number is 13
|
||||
- concurrent transaction number is 13
|
||||
"""
|
||||
concurrent transaction number is 13
|
||||
concurrent transaction number is 13
|
||||
"""
|
||||
|
||||
@pytest.mark.version('>=4.0')
|
||||
@pytest.mark.xfail
|
||||
def test_2(db_2):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
|
||||
|
||||
def test_2(act_2: Action, capsys):
|
||||
with act_2.db.connect() as con:
|
||||
tx1 = con.transaction_manager()
|
||||
tx1.begin()
|
||||
cur1 = tx1.cursor()
|
||||
cur1.execute('update test set x = ? where id = ?', (222, 1))
|
||||
# **INSTEAD** of ticket case-1:
|
||||
# set transaction read committed no record_version lock timeout N;
|
||||
# -- we start Tx with lock_timeout using custom TPB and try just to **update** record which is locked now
|
||||
# (but NOT 'SELECT ...'! It is useless with default value of confign parameter ReadConsistency = 1).
|
||||
# Message about concurrent transaction (which holds lock) in any case must appear in exception text.
|
||||
# NB: NO_rec_version is USELESS in default FB 4.0 config!
|
||||
custom_tpb = TPB(access_mode=TraAccessMode.WRITE,
|
||||
isolation=Isolation.READ_COMMITTED_RECORD_VERSION,
|
||||
lock_timeout=1)
|
||||
tx2 = con.transaction_manager(default_tpb=custom_tpb.get_buffer())
|
||||
tx2.begin()
|
||||
cur2 = tx2.cursor()
|
||||
try:
|
||||
cur2.execute('update test set x = ? where id = ?', (333, 1))
|
||||
except Exception as e:
|
||||
print('Exception in cur2:')
|
||||
print('-' * 30)
|
||||
for x in e.args:
|
||||
print(x)
|
||||
print('-' * 30)
|
||||
finally:
|
||||
tx2.commit()
|
||||
# This is for ticket case-2:
|
||||
# set transaction read committed lock timeout N;
|
||||
# select * from test with lock;
|
||||
custom_tpb.isolation = Isolation.CONCURRENCY
|
||||
tx3 = con.transaction_manager(default_tpb=custom_tpb.get_buffer())
|
||||
tx3.begin()
|
||||
cur3 = tx3.cursor()
|
||||
try:
|
||||
cur3.execute('select x from test where id = ? with lock', (1,))
|
||||
for r in cur3:
|
||||
print(r[0])
|
||||
except Exception as e:
|
||||
print('Exception in cur3:')
|
||||
print('-' * 30)
|
||||
for x in e.args:
|
||||
print(x)
|
||||
print('-' * 30)
|
||||
finally:
|
||||
tx3.commit()
|
||||
tx1.commit()
|
||||
act_2.expected_stdout = expected_stdout_2
|
||||
act_2.stdout = capsys.readouterr().out
|
||||
assert act_2.clean_stdout == act_2.clean_expected_stdout
|
||||
|
@ -2,30 +2,32 @@
|
||||
#
|
||||
# id: bugs.core_3008
|
||||
# title: Add attachment's CHARACTER SET name into corresponding trace records
|
||||
# decription:
|
||||
# decription:
|
||||
# 1. Obtain engine_version from built-in context variable.
|
||||
# 2. Make config for trace in proper format according to FB engine version,
|
||||
# with adding invalid element 'foo' instead on boolean ('true' or 'false')
|
||||
# 3. Launch trace session in separate child process using 'FBSVCMGR action_trace_start'
|
||||
# 4. Run ISQL single 'QUIT;' command in order trace session will register connection.
|
||||
# 5. Stop trace session. Output its log with filtering only messages related to connect/disconnect event.
|
||||
#
|
||||
#
|
||||
# Checked on: WI-V2.5.5.26916 (SS, SC, CS); WI-V3.0.0.32008 (SS, SC, CS). Result: OK.
|
||||
# ::: NB :::
|
||||
# Several delays (time.sleep) added in main thread because of OS buffering. Couldn't switch this buffering off.
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-3008
|
||||
# min_versions: ['2.5.0']
|
||||
# versions: 2.5
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
from threading import Thread
|
||||
from firebird.qa import db_factory, python_act, Action
|
||||
|
||||
# version: 2.5
|
||||
# resources: None
|
||||
|
||||
substitutions_1 = [('^((?!ERROR|ELEMENT|SYSDBA:NONE).)*$', ''), ('.*SYSDBA:NONE', 'SYSDBA:NONE'), ('TCPV.*', 'TCP')]
|
||||
substitutions_1 = [('^((?!ERROR|ELEMENT|SYSDBA:NONE).)*$', ''),
|
||||
('.*SYSDBA:NONE', 'SYSDBA:NONE'), ('TCPV.*', 'TCP')]
|
||||
|
||||
init_script_1 = """"""
|
||||
|
||||
@ -37,32 +39,32 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# import subprocess
|
||||
# from subprocess import Popen
|
||||
# import time
|
||||
#
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# # Obtain engine version, 2.5 or 3.0, for make trace config in appropriate format:
|
||||
# engine=str(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
|
||||
# # 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'):
|
||||
# # 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,9 +72,9 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# os.remove( f_names_list[i] )
|
||||
# if os.path.isfile( f_names_list[i]):
|
||||
# print('ERROR: can not remove file ' + f_names_list[i])
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# txt25 = '''# Trace config, format for 2.5. Generated auto, do not edit!
|
||||
# <database %[\\\\\\\\/]bugs.core_3008.fdb>
|
||||
# enabled true
|
||||
@ -80,12 +82,12 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# log_connections true
|
||||
# </database>
|
||||
# '''
|
||||
#
|
||||
#
|
||||
# # NOTES ABOUT TRACE CONFIG FOR 3.0:
|
||||
# # 1) Header contains `database` clause in different format vs FB 2.5: its data must be enclosed with '{' '}'
|
||||
# # 2) Name and value must be separated by EQUALITY sign ('=') in FB-3 trace.conf, otherwise we get runtime error:
|
||||
# # element "<. . .>" have no attribute value set
|
||||
#
|
||||
#
|
||||
# txt30 = '''# Trace config, format for 3.0. Generated auto, do not edit!
|
||||
# database=%[\\\\\\\\/]bugs.core_3008.fdb
|
||||
# {
|
||||
@ -94,38 +96,38 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# log_connections = true
|
||||
# }
|
||||
# '''
|
||||
#
|
||||
#
|
||||
# f_trccfg=open( os.path.join(context['temp_directory'],'tmp_trace_3008.cfg'), 'w')
|
||||
# if engine.startswith('2.5'):
|
||||
# f_trccfg.write(txt25)
|
||||
# else:
|
||||
# f_trccfg.write(txt30)
|
||||
# f_trccfg.close()
|
||||
#
|
||||
#
|
||||
# #####################################################
|
||||
# # Starting trace session in new child process (async.):
|
||||
#
|
||||
#
|
||||
# f_trclog = open( os.path.join(context['temp_directory'],'tmp_trace_3008.log'), 'w')
|
||||
# # Execute a child program in a new process, redirecting STDERR to the same target as of STDOUT:
|
||||
# p_trace=Popen([context['fbsvcmgr_path'], "localhost:service_mgr",
|
||||
# "action_trace_start",
|
||||
# "trc_cfg", f_trccfg.name],
|
||||
# stdout=f_trclog, stderr=subprocess.STDOUT)
|
||||
#
|
||||
#
|
||||
# # Wait! Trace session is initialized not instantly!
|
||||
# time.sleep(1)
|
||||
#
|
||||
#
|
||||
# sqltxt='''quit;'''
|
||||
#
|
||||
#
|
||||
# runProgram('isql',[dsn,'-ch','utf8'],sqltxt)
|
||||
# runProgram('isql',[dsn,'-ch','iso8859_1'],sqltxt)
|
||||
#
|
||||
#
|
||||
# # do NOT remove this otherwise trace log can contain only message about its start before being closed!
|
||||
# time.sleep(3)
|
||||
#
|
||||
#
|
||||
# #####################################################
|
||||
# # Getting ID of launched trace session and STOP it:
|
||||
#
|
||||
#
|
||||
# # Save active trace session info into file for further parsing it and obtain session_id back (for stop):
|
||||
# f_trclst = open( os.path.join(context['temp_directory'],'tmp_trace_3008.lst'), 'w')
|
||||
# subprocess.call([context['fbsvcmgr_path'], "localhost:service_mgr",
|
||||
@ -133,7 +135,7 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# stdout=f_trclst, stderr=subprocess.STDOUT
|
||||
# )
|
||||
# flush_and_close( f_trclst )
|
||||
#
|
||||
#
|
||||
# trcssn=0
|
||||
# with open( f_trclst.name,'r') as f:
|
||||
# for line in f:
|
||||
@ -144,7 +146,7 @@ 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:
|
||||
# f_trclst=open(f_trclst.name,'a')
|
||||
# f_trclst.seek(0,2)
|
||||
@ -154,40 +156,66 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# stdout=f_trclst, stderr=subprocess.STDOUT
|
||||
# )
|
||||
# flush_and_close( f_trclst )
|
||||
#
|
||||
#
|
||||
# # Terminate child process of launched trace session (though it should already be killed):
|
||||
# p_trace.terminate()
|
||||
#
|
||||
#
|
||||
# flush_and_close( f_trclog )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# # Output log of trace for comparing it with expected: it must contain only TWO events: TRACE_INIT and TRACE_FINI
|
||||
# # ::: NB ::: Content if trace log is converted to UPPER case in order to reduce change of mismatching with
|
||||
# # updated trace output in some future versions:
|
||||
# with open( f_trclog.name,'r') as f:
|
||||
# print(f.read().upper())
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# # do NOT remove this delay otherwise get access error 'Windows 32'
|
||||
# # (The process cannot access the file because it is being used by another process):
|
||||
# time.sleep(1)
|
||||
#
|
||||
#
|
||||
# cleanup( [i.name for i in (f_trccfg, f_trclst, f_trclog ) ] )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
SYSDBA:NONE, UTF8, TCP
|
||||
SYSDBA:NONE, UTF8, TCP
|
||||
SYSDBA:NONE, ISO88591, TCP
|
||||
SYSDBA:NONE, ISO88591, TCP
|
||||
"""
|
||||
|
||||
@pytest.mark.version('>=2.5')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
"""
|
||||
|
||||
def trace_session(act: Action):
|
||||
cfg30 = ['# Trace config, format for 3.0. Generated auto, do not edit!',
|
||||
f'database=%[\\\\/]{act.db.db_path.name}',
|
||||
'{',
|
||||
' enabled = true',
|
||||
' log_connections = true',
|
||||
' time_threshold = 0',
|
||||
'}']
|
||||
with act.connect_server() as srv:
|
||||
srv.trace.start(config='\n'.join(cfg30))
|
||||
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])
|
||||
trace_thread.start()
|
||||
# make two connections with different charset
|
||||
with act_1.db.connect(charset='utf8'):
|
||||
pass
|
||||
with act_1.db.connect(charset='iso8859_1'):
|
||||
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')
|
||||
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_3024
|
||||
# title: Error "no current record for fetch operation" after ALTER VIEW
|
||||
# decription:
|
||||
# decription:
|
||||
# Confirmed error on: WI-V2.5.6.26962 (SC), fixed on: WI-V2.5.6.26963.
|
||||
# Checked on WI-V3.0.0.32268 (SS, SC, CS).
|
||||
# Checked on fdb version 1.5.
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-3024
|
||||
# min_versions: ['2.5.6']
|
||||
# versions: 2.5.6
|
||||
# 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.6
|
||||
# resources: None
|
||||
@ -27,44 +27,61 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# test_script_1
|
||||
#---
|
||||
# db_conn.close()
|
||||
#
|
||||
#
|
||||
# att1=kdb.connect(dsn=dsn.encode(),user='SYSDBA',password='masterkey')
|
||||
# att2=kdb.connect(dsn=dsn.encode(),user='SYSDBA',password='masterkey')
|
||||
#
|
||||
#
|
||||
# trn1=att1.trans()
|
||||
#
|
||||
#
|
||||
# cur1=trn1.cursor()
|
||||
#
|
||||
#
|
||||
# cur1.execute("create table t(a int, b int, c int)") # att_12, tra_4
|
||||
# cur1.execute("create view v as select a,b from t")
|
||||
# trn1.commit()
|
||||
#
|
||||
#
|
||||
# cur1.execute("insert into t values(1,2,3)") # att_12, tra_5
|
||||
# cur1.execute("select * from v")
|
||||
# trn1.commit()
|
||||
#
|
||||
#
|
||||
# trn2=att2.trans()
|
||||
# cur2=trn2.cursor()
|
||||
# cur2.execute("select * from v") # att_13, tra_7
|
||||
# trn2.commit()
|
||||
#
|
||||
#
|
||||
# cur1.execute("alter view v as select a, b, c from t") # att-12, tra_8
|
||||
# trn1.commit()
|
||||
#
|
||||
#
|
||||
# cur2.execute("select * from v") # att_13, tra_9
|
||||
# printData(cur2)
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
A B C
|
||||
1 2 3
|
||||
"""
|
||||
"""
|
||||
|
||||
@pytest.mark.version('>=2.5.6')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
|
||||
|
||||
def test_1(act_1: Action, capsys):
|
||||
with act_1.db.connect() as att1, act_1.db.connect() as att2:
|
||||
trn1 = att1.transaction_manager()
|
||||
cur1 = trn1.cursor()
|
||||
cur1.execute("create table t(a int, b int, c int)") # att_12, tra_4
|
||||
cur1.execute("create view v as select a,b from t")
|
||||
trn1.commit()
|
||||
cur1.execute("insert into t values(1,2,3)") # att_12, tra_5
|
||||
cur1.execute("select * from v")
|
||||
trn1.commit()
|
||||
trn2 = att2.transaction_manager()
|
||||
cur2 = trn2.cursor()
|
||||
cur2.execute("select * from v") # att_13, tra_7
|
||||
trn2.commit()
|
||||
cur1.execute("alter view v as select a, b, c from t") # att-12, tra_8
|
||||
trn1.commit()
|
||||
cur2.execute("select * from v") # att_13, tra_9
|
||||
act_1.print_data(cur2)
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
act_1.stdout = capsys.readouterr().out
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
@ -2,23 +2,23 @@
|
||||
#
|
||||
# id: bugs.core_3095
|
||||
# title: Client receive event's with count equal to 1 despite of how many times EVENT was POSTed in same transaction
|
||||
# decription:
|
||||
# decription:
|
||||
# We create stored procedure as it was specified in the ticket, and call it with input arg = 3.
|
||||
# This mean that we have to receive THREE events after code which calls this SP will issue COMMIT.
|
||||
#
|
||||
#
|
||||
# Confirmed on 2.5.0.26074 - only one event was delivered instead of three.
|
||||
# Works OK since 2.5.1.26351.
|
||||
#
|
||||
# PS. Event handling code in this text was adapted from fdb manual:
|
||||
#
|
||||
# PS. Event handling code in this text was adapted from fdb manual:
|
||||
# http://pythonhosted.org/fdb/usage-guide.html#database-events
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-3095
|
||||
# min_versions: ['2.5.1']
|
||||
# versions: 2.5.1
|
||||
# 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.1
|
||||
# resources: None
|
||||
@ -38,7 +38,7 @@ init_script_1 = """
|
||||
^
|
||||
set term ;^
|
||||
commit;
|
||||
"""
|
||||
"""
|
||||
|
||||
db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
|
||||
@ -46,55 +46,61 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
#---
|
||||
# import os
|
||||
# import threading
|
||||
#
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
#
|
||||
#
|
||||
# # Utility function
|
||||
# def send_events(command_list):
|
||||
# cur = db_conn.cursor()
|
||||
# for cmd in command_list:
|
||||
# cur.execute(cmd)
|
||||
# db_conn.commit()
|
||||
#
|
||||
#
|
||||
# timed_event = threading.Timer(3.0, send_events, args=[["execute procedure sp_test(3)",]])
|
||||
#
|
||||
# # Connection.event_conduit() takes a sequence of string event names as parameter, and returns
|
||||
#
|
||||
# # Connection.event_conduit() takes a sequence of string event names as parameter, and returns
|
||||
# # EventConduit instance.
|
||||
# events = db_conn.event_conduit(['loop'])
|
||||
#
|
||||
# # To start listening for events it's necessary (starting from FDB version 1.4.2)
|
||||
#
|
||||
# # To start listening for events it's necessary (starting from FDB version 1.4.2)
|
||||
# # to call EventConduit.begin() method or use EventConduit's context manager interface
|
||||
# # Immediately when begin() method is called, EventConduit starts to accumulate notifications
|
||||
# # of any events that occur within the conduit's internal queue until the conduit is closed
|
||||
# # Immediately when begin() method is called, EventConduit starts to accumulate notifications
|
||||
# # of any events that occur within the conduit's internal queue until the conduit is closed
|
||||
# # (via the close() method)
|
||||
#
|
||||
#
|
||||
# events.begin()
|
||||
#
|
||||
#
|
||||
# timed_event.start()
|
||||
#
|
||||
# # Notifications about events are aquired through call to wait() method, that blocks the calling
|
||||
# # thread until at least one of the events occurs, or the specified timeout (if any) expires,
|
||||
#
|
||||
# # Notifications about events are aquired through call to wait() method, that blocks the calling
|
||||
# # thread until at least one of the events occurs, or the specified timeout (if any) expires,
|
||||
# # and returns None if the wait timed out, or a dictionary that maps event_name -> event_occurrence_count.
|
||||
#
|
||||
#
|
||||
# e = events.wait(10)
|
||||
#
|
||||
#
|
||||
# events.close()
|
||||
#
|
||||
#
|
||||
# print(e)
|
||||
# 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 = """
|
||||
{'loop': 3}
|
||||
"""
|
||||
|
||||
@pytest.mark.version('>=2.5.1')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
|
||||
{'loop': 3}
|
||||
"""
|
||||
|
||||
@pytest.mark.version('>=3.0')
|
||||
def test_1(act_1: Action, capsys):
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
with act_1.db.connect() as con:
|
||||
c = con.cursor()
|
||||
with con.event_collector(['loop']) as events:
|
||||
c.execute('execute procedure sp_test(3)')
|
||||
con.commit()
|
||||
print(events.wait(10))
|
||||
act_1.stdout = capsys.readouterr().out
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
@ -2,7 +2,7 @@
|
||||
#
|
||||
# id: bugs.core_3131
|
||||
# title: WIN1257_LV (Latvian) collation is wrong for 4 letters: A E I U.
|
||||
# decription:
|
||||
# decription:
|
||||
# ::: NOTE :::
|
||||
# In order to check correctness of following statements under ISQL itself (NOT under fbt_run), do following:
|
||||
# 1) open some text editor that supports charset = win1257 and set encoding for new document = WIN1257
|
||||
@ -19,27 +19,28 @@
|
||||
# 4) save .fbt and ensure that it was saved in UTF8 encoding, otherwise exeption like
|
||||
# "UnicodeDecodeError: 'utf8' codec can't decode byte 0xc3 in position 621: invalid continuation byte"
|
||||
# will raise.
|
||||
#
|
||||
#
|
||||
# 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 (WIN1257 in this test).
|
||||
# Then ISQL is launched in separate (child) process which performs all necessary actions (using required charset).
|
||||
# Result will be redirected to log(s) which will be opened further via codecs.open(...encoding='cp1257').
|
||||
# Finally, its content will be converted to UTF8 for showing in expected_stdout.
|
||||
#
|
||||
#
|
||||
# Confirmed bug on 2.5.0.26074. Fixed on 2.5.1.26351 and up to 2.5.9.27152
|
||||
#
|
||||
#
|
||||
# Checked on:
|
||||
# * Windows: 4.0.0.2377, 3.0.8.33423
|
||||
# * Linux: 4.0.0.2379, 3.0.8.33415
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-3131
|
||||
# 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
|
||||
@ -52,31 +53,31 @@ db_1 = db_factory(charset='WIN1257', 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 )):
|
||||
@ -87,43 +88,43 @@ db_1 = db_factory(charset='WIN1257', 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 )
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# sql_txt=''' set bail on;
|
||||
# set names win1257;
|
||||
# connect '%(dsn)s' user '%(user_name)s' password '%(user_password)s';
|
||||
#
|
||||
#
|
||||
# create collation coll_1257_ci_ai
|
||||
# for win1257 from win1257_lv
|
||||
# no pad case insensitive accent sensitive;
|
||||
# commit;
|
||||
#
|
||||
#
|
||||
# create table test1257 (
|
||||
# letter varchar(2) collate coll_1257_ci_ai,
|
||||
# sort_index smallint
|
||||
# );
|
||||
#
|
||||
#
|
||||
# -- ### ONCE AGAIN ###
|
||||
# -- 1) for checking this under ISQL following must be encoded in WIN1257
|
||||
# -- 2) for running under fbt_run utility following must be encoded in UTF8.
|
||||
# insert into test1257 values ('Iz', 18);
|
||||
# insert into test1257 values ('Īb', 19);
|
||||
# insert into test1257 values ('Īz', 20);
|
||||
#
|
||||
#
|
||||
# insert into test1257 values ('Ķz', 24);
|
||||
# insert into test1257 values ('Ēz', 12);
|
||||
# insert into test1257 values ('Gb', 13);
|
||||
#
|
||||
#
|
||||
# insert into test1257 values ('Ģz', 16);
|
||||
# insert into test1257 values ('Ib', 17);
|
||||
#
|
||||
#
|
||||
# insert into test1257 values ('Gz', 14);
|
||||
# insert into test1257 values ('Ģb', 15);
|
||||
#
|
||||
#
|
||||
# insert into test1257 values ('Ņb', 31);
|
||||
# insert into test1257 values ('Ņz', 32);
|
||||
# insert into test1257 values ('Cb', 5);
|
||||
@ -133,10 +134,10 @@ db_1 = db_factory(charset='WIN1257', sql_dialect=3, init=init_script_1)
|
||||
# insert into test1257 values ('Eb', 9);
|
||||
# insert into test1257 values ('Ez', 10);
|
||||
# insert into test1257 values ('Ēb', 11);
|
||||
#
|
||||
#
|
||||
# insert into test1257 values ('Ub', 37);
|
||||
# insert into test1257 values ('Uz', 38);
|
||||
#
|
||||
#
|
||||
# insert into test1257 values ('Lz', 26);
|
||||
# insert into test1257 values ('Ļb', 27);
|
||||
# insert into test1257 values ('Ļz', 28);
|
||||
@ -147,108 +148,195 @@ db_1 = db_factory(charset='WIN1257', sql_dialect=3, init=init_script_1)
|
||||
# insert into test1257 values ('Cz', 6);
|
||||
# insert into test1257 values ('Čb', 7);
|
||||
# insert into test1257 values ('Čz', 8);
|
||||
#
|
||||
#
|
||||
# insert into test1257 values ('Sb', 33);
|
||||
# insert into test1257 values ('Sz', 34);
|
||||
# insert into test1257 values ('Šb', 35);
|
||||
#
|
||||
#
|
||||
# insert into test1257 values ('Nb', 29);
|
||||
# insert into test1257 values ('Nz', 30);
|
||||
# insert into test1257 values ('Ķb', 23);
|
||||
# insert into test1257 values ('Zz', 42);
|
||||
# insert into test1257 values ('Žb', 43);
|
||||
# insert into test1257 values ('Žz', 44);
|
||||
#
|
||||
#
|
||||
# insert into test1257 values ('Ab', 1);
|
||||
# insert into test1257 values ('Az', 2);
|
||||
# insert into test1257 values ('Āb', 3);
|
||||
# insert into test1257 values ('Āz', 4);
|
||||
# insert into test1257 values ('Āz', 4);
|
||||
# commit;
|
||||
#
|
||||
#
|
||||
# set heading off;
|
||||
# select *
|
||||
# from test1257 tls
|
||||
# order by tls.letter collate coll_1257_ci_ai;
|
||||
#
|
||||
#
|
||||
# ''' % dict(globals(), **locals())
|
||||
#
|
||||
#
|
||||
# f_run_sql = open( os.path.join(context['temp_directory'], 'tmp_3131_win1257.sql'), 'w' )
|
||||
# f_run_sql.write( sql_txt.decode('utf8').encode('cp1257') )
|
||||
# flush_and_close( f_run_sql )
|
||||
#
|
||||
#
|
||||
# # result: file tmp_3131_win1257.sql is encoded in win1257
|
||||
#
|
||||
#
|
||||
# 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 win1257
|
||||
#
|
||||
#
|
||||
# with codecs.open(f_run_log.name, 'r', encoding='cp1257' ) as f:
|
||||
# result_in_win1257 = f.readlines()
|
||||
#
|
||||
#
|
||||
# for i in result_in_win1257:
|
||||
# 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)
|
||||
|
||||
test_script_1 = """
|
||||
set bail on;
|
||||
set names win1257;
|
||||
|
||||
create collation coll_1257_ci_ai
|
||||
for win1257 from win1257_lv
|
||||
no pad case insensitive accent sensitive;
|
||||
|
||||
commit;
|
||||
|
||||
create table test1257 (
|
||||
letter varchar(2) collate coll_1257_ci_ai,
|
||||
sort_index smallint
|
||||
);
|
||||
|
||||
commit;
|
||||
|
||||
-- ### ONCE AGAIN ###
|
||||
-- 1) for checking this under ISQL following must be encoded in WIN1257
|
||||
-- 2) for running under fbt_run utility following must be encoded in UTF8.
|
||||
|
||||
insert into test1257 values ('Iz', 18);
|
||||
insert into test1257 values ('Īb', 19);
|
||||
insert into test1257 values ('Īz', 20);
|
||||
|
||||
insert into test1257 values ('Ķz', 24);
|
||||
insert into test1257 values ('Ēz', 12);
|
||||
insert into test1257 values ('Gb', 13);
|
||||
|
||||
insert into test1257 values ('Ģz', 16);
|
||||
insert into test1257 values ('Ib', 17);
|
||||
|
||||
insert into test1257 values ('Gz', 14);
|
||||
insert into test1257 values ('Ģb', 15);
|
||||
|
||||
insert into test1257 values ('Ņb', 31);
|
||||
insert into test1257 values ('Ņz', 32);
|
||||
insert into test1257 values ('Cb', 5);
|
||||
insert into test1257 values ('Ūb', 39);
|
||||
insert into test1257 values ('Ūz', 40);
|
||||
insert into test1257 values ('Zb', 41);
|
||||
insert into test1257 values ('Eb', 9);
|
||||
insert into test1257 values ('Ez', 10);
|
||||
insert into test1257 values ('Ēb', 11);
|
||||
|
||||
insert into test1257 values ('Ub', 37);
|
||||
insert into test1257 values ('Uz', 38);
|
||||
|
||||
insert into test1257 values ('Lz', 26);
|
||||
insert into test1257 values ('Ļb', 27);
|
||||
insert into test1257 values ('Ļz', 28);
|
||||
insert into test1257 values ('Kb', 21);
|
||||
insert into test1257 values ('Kz', 22);
|
||||
insert into test1257 values ('Šz', 36);
|
||||
insert into test1257 values ('Lb', 25);
|
||||
insert into test1257 values ('Cz', 6);
|
||||
insert into test1257 values ('Čb', 7);
|
||||
insert into test1257 values ('Čz', 8);
|
||||
|
||||
insert into test1257 values ('Sb', 33);
|
||||
insert into test1257 values ('Sz', 34);
|
||||
insert into test1257 values ('Šb', 35);
|
||||
|
||||
insert into test1257 values ('Nb', 29);
|
||||
insert into test1257 values ('Nz', 30);
|
||||
insert into test1257 values ('Ķb', 23);
|
||||
insert into test1257 values ('Zz', 42);
|
||||
insert into test1257 values ('Žb', 43);
|
||||
insert into test1257 values ('Žz', 44);
|
||||
|
||||
insert into test1257 values ('Ab', 1);
|
||||
insert into test1257 values ('Az', 2);
|
||||
insert into test1257 values ('Āb', 3);
|
||||
insert into test1257 values ('Āz', 4);
|
||||
commit;
|
||||
|
||||
set heading off;
|
||||
select *
|
||||
from test1257 tls
|
||||
order by tls.letter collate coll_1257_ci_ai;
|
||||
"""
|
||||
|
||||
expected_stdout_1 = """
|
||||
Ab 1
|
||||
Az 2
|
||||
Āb 3
|
||||
Āz 4
|
||||
Cb 5
|
||||
Cz 6
|
||||
Čb 7
|
||||
Čz 8
|
||||
Eb 9
|
||||
Ez 10
|
||||
Ēb 11
|
||||
Ēz 12
|
||||
Gb 13
|
||||
Gz 14
|
||||
Ģb 15
|
||||
Ģz 16
|
||||
Ib 17
|
||||
Iz 18
|
||||
Īb 19
|
||||
Īz 20
|
||||
Kb 21
|
||||
Kz 22
|
||||
Ķb 23
|
||||
Ķz 24
|
||||
Lb 25
|
||||
Lz 26
|
||||
Ļb 27
|
||||
Ļz 28
|
||||
Nb 29
|
||||
Nz 30
|
||||
Ņb 31
|
||||
Ņz 32
|
||||
Sb 33
|
||||
Sz 34
|
||||
Šb 35
|
||||
Šz 36
|
||||
Ub 37
|
||||
Uz 38
|
||||
Ūb 39
|
||||
Ūz 40
|
||||
Zb 41
|
||||
Zz 42
|
||||
Žb 43
|
||||
Žz 44
|
||||
Ab 1
|
||||
Az 2
|
||||
Āb 3
|
||||
Āz 4
|
||||
Cb 5
|
||||
Cz 6
|
||||
Čb 7
|
||||
Čz 8
|
||||
Eb 9
|
||||
Ez 10
|
||||
Ēb 11
|
||||
Ēz 12
|
||||
Gb 13
|
||||
Gz 14
|
||||
Ģb 15
|
||||
Ģz 16
|
||||
Ib 17
|
||||
Iz 18
|
||||
Īb 19
|
||||
Īz 20
|
||||
Kb 21
|
||||
Kz 22
|
||||
Ķb 23
|
||||
Ķz 24
|
||||
Lb 25
|
||||
Lz 26
|
||||
Ļb 27
|
||||
Ļz 28
|
||||
Nb 29
|
||||
Nz 30
|
||||
Ņb 31
|
||||
Ņz 32
|
||||
Sb 33
|
||||
Sz 34
|
||||
Šb 35
|
||||
Šz 36
|
||||
Ub 37
|
||||
Uz 38
|
||||
Ūb 39
|
||||
Ūz 40
|
||||
Zb 41
|
||||
Zz 42
|
||||
Žb 43
|
||||
Žz 44
|
||||
"""
|
||||
|
||||
|
||||
script_file = 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, script_file: Path):
|
||||
script_file.write_text(test_script_1, encoding='cp1257')
|
||||
act_1.expected_stdout = expected_stdout_1
|
||||
act_1.isql(switches=[], input_file=script_file, charset='WIN1257')
|
||||
assert act_1.clean_stdout == act_1.clean_expected_stdout
|
||||
|
||||
|
@ -2,38 +2,41 @@
|
||||
#
|
||||
# id: bugs.core_3168
|
||||
# title: exclude_filter doesn't work for <services></section> section of the Trace facility
|
||||
# decription:
|
||||
# decription:
|
||||
# Note. It was encountered that FBSVCMGR does NOT wait for OS completes writing of its output on disk,
|
||||
# (see CORE-4896), so we use delays - see calls of time.sleep().
|
||||
#
|
||||
#
|
||||
# Correct work was checked on: WI-V2.5.5.26916 (SS, SC) and WI-V3.0.0.31948 (SS, SC, CS)
|
||||
# Refactored 17.12.2016 after encountering CORE-5424 ("restore process is impossible when trace ..."):
|
||||
# added checking of STDERR logs for all fbsvcmgr actions.
|
||||
#
|
||||
#
|
||||
# -----------------------------------------
|
||||
# Updated 27.03.2017: moved artificial delay (1 sec) at proper place.
|
||||
# It should be just after
|
||||
# subprocess.call('fbsvcmgr', 'localhost:service_mgr', 'action_trace_stop', ...)
|
||||
# and BEFORE 'p_trace.terminate()' command.
|
||||
# -----------------------------------------
|
||||
#
|
||||
#
|
||||
# Test time (approx):
|
||||
# 2.5.7.27030: SC = 3"
|
||||
# 2.5.7.27030: SC = 3"
|
||||
# 3.0.232644 and 4.0.0.463: SS = SC = 6"; CS = 15"
|
||||
# Checked on 2.5.8.27056, CLASSIC server: 3.6" (27-03-2017)
|
||||
#
|
||||
#
|
||||
# 13.04.2021. Adapted for run both on Windows and Linux. Checked on:
|
||||
# Windows: 3.0.8.33445, 4.0.0.2416
|
||||
# Linux: 3.0.8.33426, 4.0.0.2416
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-3168
|
||||
# min_versions: ['2.5.0']
|
||||
# versions: 2.5
|
||||
# qmid: None
|
||||
|
||||
import pytest
|
||||
from firebird.qa import db_factory, isql_act, Action
|
||||
from threading import Thread, Barrier
|
||||
from io import BytesIO
|
||||
from firebird.qa import db_factory, python_act, Action, temp_file
|
||||
from firebird.driver import SrvStatFlag
|
||||
|
||||
# version: 2.5
|
||||
# resources: None
|
||||
@ -46,37 +49,37 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
|
||||
# test_script_1
|
||||
#---
|
||||
#
|
||||
#
|
||||
# import os
|
||||
# import subprocess
|
||||
# import time
|
||||
# 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
|
||||
# # 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 )):
|
||||
@ -88,13 +91,13 @@ db_1 = db_factory(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 )
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# # ::: NB ::: Trace config file format in 3.0 differs from 2.5 one:
|
||||
# # 1) header section must be enclosed in "[" and "]",
|
||||
# # 2) parameter-value pairs must be separated with '=' sign:
|
||||
@ -102,16 +105,16 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# # {
|
||||
# # parameter = value
|
||||
# # }
|
||||
#
|
||||
#
|
||||
# if engine.startswith('2.5'):
|
||||
# txt = '''# Generated auto, do not edit!
|
||||
# <services>
|
||||
# enabled true
|
||||
# log_services true
|
||||
#
|
||||
#
|
||||
# # This should prevent appearance of messages like "List Trace Session(s)" or "Start Trace Session(s)":
|
||||
# exclude_filter "%(List|LIST|list|Start|START|start)[[:WHITESPACE:]]+(Trace|TRACE|trace)[[:WHITESPACE:]]+(Session|SESSION|session)%"
|
||||
#
|
||||
#
|
||||
# # This should work even if we filter out messages about list/start trace session(s)
|
||||
# # (and test also check corret work of THIS filter beside previous `exclude`):
|
||||
# # include_filter "Database Stats"
|
||||
@ -123,68 +126,68 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# {
|
||||
# enabled = true
|
||||
# log_services = true
|
||||
#
|
||||
#
|
||||
# # This should prevent appearance of messages like "List Trace Session(s)" or "Start Trace Session(s)":
|
||||
# exclude_filter = "%(List|LIST|list|Start|START|start)[[:WHITESPACE:]]+(Trace|TRACE|trace)[[:WHITESPACE:]]+(Session|SESSION|session)%"
|
||||
#
|
||||
#
|
||||
# # This should work even if we filter out messages about list/start trace session(s)
|
||||
# # (and test also check corret work of THIS filter beside previous `exclude`):
|
||||
# # include_filter = "Database Stats"
|
||||
# }
|
||||
# '''
|
||||
#
|
||||
#
|
||||
# f_trc_cfg=open( os.path.join(context['temp_directory'],'tmp_trace_3168.cfg'), 'w')
|
||||
# f_trc_cfg.write(txt)
|
||||
# f_trc_cfg.close()
|
||||
#
|
||||
#
|
||||
# # Instead of using 'start /min cmd /c fbsvcmgr ... 1>%2 2>&1' deciced to exploite Popen in order to run asynchronous process
|
||||
# # without opening separate window. Output is catched into `trclog` file, which will be closed after call fbsvcmgr with argument
|
||||
# # 'action_trace_stop' (see below):
|
||||
# # See also:
|
||||
# # https://docs.python.org/2/library/subprocess.html
|
||||
# # http://stackoverflow.com/questions/11801098/calling-app-from-subprocess-call-with-arguments
|
||||
#
|
||||
#
|
||||
# # ##############################################################
|
||||
# # 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_3168.log'), "w")
|
||||
# f_trc_err=open( os.path.join(context['temp_directory'],'tmp_trace_3168.err'), "w")
|
||||
#
|
||||
#
|
||||
# p_trace = Popen([ context['fbsvcmgr_path'], 'localhost:service_mgr', 'action_trace_start' , 'trc_cfg', f_trc_cfg.name],stdout=f_trc_log,stderr=f_trc_err)
|
||||
#
|
||||
#
|
||||
# thisdb='$(DATABASE_LOCATION)bugs.core_3168.fdb'
|
||||
# tmpbkp='$(DATABASE_LOCATION)bugs.core_3168_fbk.tmp'
|
||||
# tmpres='$(DATABASE_LOCATION)bugs.core_3168_new.tmp'
|
||||
#
|
||||
#
|
||||
# f_run_log=open( os.path.join(context['temp_directory'],'tmp_action_3168.log'), 'w')
|
||||
# f_run_err=open( os.path.join(context['temp_directory'],'tmp_action_3168.err'), 'w')
|
||||
#
|
||||
#
|
||||
# subprocess.call( [ context['fbsvcmgr_path'], 'localhost:service_mgr','action_properties','dbname', thisdb,'prp_sweep_interval', '1234321'], stdout=f_run_log,stderr=f_run_err)
|
||||
# subprocess.call( [ context['fbsvcmgr_path'], 'localhost:service_mgr','action_db_stats', 'dbname', thisdb, 'sts_hdr_pages'], stdout=f_run_log,stderr=f_run_err)
|
||||
# subprocess.call( [ context['fbsvcmgr_path'], 'localhost:service_mgr','action_backup', 'dbname', thisdb, 'bkp_file', tmpbkp], stdout=f_run_log,stderr=f_run_err)
|
||||
# subprocess.call( [ context['fbsvcmgr_path'], 'localhost:service_mgr','action_restore', 'bkp_file', tmpbkp, 'dbname', tmpres, 'res_replace'], stdout=f_run_log,stderr=f_run_err)
|
||||
#
|
||||
#
|
||||
# flush_and_close( f_run_log )
|
||||
# flush_and_close( f_run_err )
|
||||
#
|
||||
#
|
||||
# # do NOT try to get FB log! It can contain non-ascii messages which lead to runtime fault of fbtest!
|
||||
# # (see CORE-5418):
|
||||
# # runProgram(context['fbsvcmgr_path'],['localhost:service_mgr','action_get_fb_log'])
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# # ####################################################
|
||||
# # 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_3168.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:
|
||||
@ -196,76 +199,109 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# i=i+1
|
||||
# break
|
||||
# # Result: `trcssn` is ID of active trace session. Now we have to terminate it:
|
||||
#
|
||||
#
|
||||
# # ####################################################
|
||||
# # S E N D R E Q U E S T T R A C E T O S T O P
|
||||
# # ####################################################
|
||||
#
|
||||
#
|
||||
# fn_nul = open(os.devnull, 'w')
|
||||
# subprocess.call([context['fbsvcmgr_path'], 'localhost:service_mgr', 'action_trace_stop','trc_id', trcssn], stdout=fn_nul)
|
||||
# fn_nul.close()
|
||||
#
|
||||
#
|
||||
# # ::: NB ::: Artificial delay, Added 27.03.2017.
|
||||
# # Do NOT remove this line otherwise record with 'database restore' may not appear
|
||||
# # Do NOT remove this line otherwise record with 'database restore' may not appear
|
||||
# # in the final trace log (file buffer is flushed not instantly).
|
||||
# time.sleep(1)
|
||||
#
|
||||
#
|
||||
# time.sleep(1)
|
||||
#
|
||||
#
|
||||
# # Doc about Popen.terminate():
|
||||
# # https://docs.python.org/2/library/subprocess.html
|
||||
# # Stop the child. On Posix OSs the method sends SIGTERM to the child.
|
||||
# # On Windows the Win32 API function TerminateProcess() is called to stop the child.
|
||||
#
|
||||
#
|
||||
# # Doc about Win API TerminateProcess() function:
|
||||
# # https://msdn.microsoft.com/en-us/library/windows/desktop/ms686714%28v=vs.85%29.aspx
|
||||
# # The terminated process cannot exit until all pending I/O has been completed or canceled.
|
||||
# # TerminateProcess is ____asynchronous____; it initiates termination and returns immediately.
|
||||
# # ^^^^^^^^^^^^
|
||||
#
|
||||
#
|
||||
# p_trace.terminate()
|
||||
# flush_and_close(f_trc_log)
|
||||
# flush_and_close(f_trc_err)
|
||||
#
|
||||
#
|
||||
# # Should be EMPTY:
|
||||
# with open( f_trc_err.name,'r') as f:
|
||||
# for line in f:
|
||||
# if line.split():
|
||||
# print('fbsvcmgr(1) unexpected STDERR: '+line.upper() )
|
||||
#
|
||||
#
|
||||
# # Should be EMPTY:
|
||||
# with open( f_run_err.name,'r') as f:
|
||||
# for line in f:
|
||||
# if line.split():
|
||||
# print('fbsvcmgr(2) unexpected STDERR: '+line.upper() )
|
||||
#
|
||||
#
|
||||
# # Output log of trace for comparing it with expected.
|
||||
# # ::: NB ::: Content if trace log is converted to UPPER case in order to reduce change of mismatching with
|
||||
# # updated trace output in some future versions:
|
||||
#
|
||||
#
|
||||
# with open( f_trc_log.name,'r') as f:
|
||||
# for line in f:
|
||||
# if line.split():
|
||||
# print(line.upper())
|
||||
#
|
||||
#
|
||||
# # CLEANUP
|
||||
# #########
|
||||
# time.sleep(1)
|
||||
# cleanup( (f_trc_cfg, f_trc_lst, f_trc_log, f_trc_err, f_run_log, f_run_err, tmpbkp, tmpres) )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#---
|
||||
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
||||
|
||||
act_1 = python_act('db_1', substitutions=substitutions_1)
|
||||
|
||||
expected_stdout_1 = """
|
||||
"DATABASE PROPERTIES"
|
||||
"DATABASE STATS"
|
||||
"BACKUP DATABASE"
|
||||
"RESTORE DATABASE"
|
||||
"""
|
||||
EXCLUDE_FILTER = "DATABASE STATS"
|
||||
"DATABASE PROPERTIES"
|
||||
"BACKUP DATABASE"
|
||||
"""
|
||||
|
||||
@pytest.mark.version('>=2.5')
|
||||
@pytest.mark.xfail
|
||||
def test_1(db_1):
|
||||
pytest.fail("Test not IMPLEMENTED")
|
||||
def trace_session(act: Action, barrier: Barrier):
|
||||
cfg30 = ['services',
|
||||
'{',
|
||||
' enabled = true',
|
||||
' log_services = true',
|
||||
' exclude_filter = "Database Stats"',
|
||||
'}']
|
||||
with act.connect_server() as srv:
|
||||
srv.trace.start(config='\n'.join(cfg30))
|
||||
barrier.wait()
|
||||
for line in srv:
|
||||
print(line.upper())
|
||||
|
||||
temp_file_1 = temp_file('test-file')
|
||||
|
||||
@pytest.mark.version('>=3.0')
|
||||
def test_1(act_1: Action, capsys, temp_file_1):
|
||||
b = Barrier(2)
|
||||
trace_thread = Thread(target=trace_session, args=[act_1, b])
|
||||
trace_thread.start()
|
||||
with act_1.connect_server() as srv:
|
||||
# Make some service requests
|
||||
b.wait()
|
||||
srv.database.set_sweep_interval(database=str(act_1.db.db_path), interval=1234321)
|
||||
srv.database.get_statistics(database=str(act_1.db.db_path), flags=SrvStatFlag.HDR_PAGES)
|
||||
srv.wait()
|
||||
srv.database.backup(database=str(act_1.db.db_path), backup=str(temp_file_1))
|
||||
srv.wait()
|
||||
#
|
||||
for session in list(srv.trace.sessions.keys()):
|
||||
srv.trace.stop(session_id=session)
|
||||
trace_thread.join(2.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
|
||||
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
#
|
||||
# id: bugs.core_3188
|
||||
# title: page 0 is of wrong type (expected 6, found 1)
|
||||
# decription:
|
||||
# decription:
|
||||
# Confirmed on WI-V2.5.0.26074
|
||||
# exception:
|
||||
# DatabaseError:
|
||||
@ -13,21 +13,22 @@
|
||||
# - page 0 is of wrong type (expected 6, found 1)
|
||||
# -902
|
||||
# 335544335
|
||||
#
|
||||
#
|
||||
# New messages in firebird.log in 2.5.0 after running ticket statements:
|
||||
#
|
||||
#
|
||||
# CSPROG (Client) Mon Feb 15 07:28:05 2016
|
||||
# INET/inet_error: connect errno = 10061
|
||||
# CSPROG Mon Feb 15 07:41:02 2016
|
||||
# Shutting down the server with 0 active connection(s) to 0 database(s), 1 active service(s)
|
||||
#
|
||||
#
|
||||
# tracker_id: CORE-3188
|
||||
# min_versions: ['2.5.1']
|
||||
# versions: 2.5.1
|
||||
# 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.1
|
||||
# resources: None
|
||||
@ -40,34 +41,34 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
|
||||
# test_script_1
|
||||
#---
|
||||
#
|
||||
#
|
||||
# import os
|
||||
# import difflib
|
||||
#
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
#
|
||||
#
|
||||
# engine = str(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
|
||||
# # 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'):
|
||||
# # 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 )):
|
||||
@ -75,20 +76,20 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# os.remove( f_names_list[i] )
|
||||
# if os.path.isfile( f_names_list[i]):
|
||||
# print('ERROR: can not remove file ' + f_names_list[i])
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
# def svc_get_fb_log( engine, f_fb_log ):
|
||||
#
|
||||
#
|
||||
# import subprocess
|
||||
#
|
||||
#
|
||||
# # ::: NB ::: Service call for receive firebird.log works properly only since FB 2.5.2!
|
||||
#
|
||||
#
|
||||
# if engine.startswith('2.5'):
|
||||
# get_firebird_log_key='action_get_ib_log'
|
||||
# else:
|
||||
# get_firebird_log_key='action_get_fb_log'
|
||||
#
|
||||
#
|
||||
# subprocess.call([ context['fbsvcmgr_path'],
|
||||
# "localhost:service_mgr",
|
||||
# get_firebird_log_key
|
||||
@ -96,73 +97,83 @@ db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
||||
# stdout=f_fb_log, stderr=subprocess.STDOUT
|
||||
# )
|
||||
# return
|
||||
#
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# # Start two attachments:
|
||||
# con1 = kdb.connect(dsn=dsn)
|
||||
# con2 = kdb.connect(dsn=dsn)
|
||||
#
|
||||
#
|
||||
# # Session-1:
|
||||
# c1 = con1.cursor()
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# f_fblog_before=open( os.path.join(context['temp_directory'],'tmp_3188_fblog_before.txt'), 'w')
|
||||
# svc_get_fb_log( engine, f_fblog_before )
|
||||
# flush_and_close( f_fblog_before )
|
||||
#
|
||||
#
|
||||
# c1.execute("create table test(id int primary key)")
|
||||
# con1.commit()
|
||||
#
|
||||
#
|
||||
# # Session-2:
|
||||
#
|
||||
#
|
||||
# c2 = con2.cursor()
|
||||
# c2.execute('drop table test')
|
||||
# con2.commit()
|
||||
#
|
||||
#
|
||||
# # cleanup
|
||||
# con1.close()
|
||||
# con2.close()
|
||||
#
|
||||
#
|
||||
# f_fblog_after=open( os.path.join(context['temp_directory'],'tmp_3188_fblog_after.txt'), 'w')
|
||||
# svc_get_fb_log( engine, f_fblog_after )
|
||||
# flush_and_close( f_fblog_after )
|
||||
#
|
||||
#
|
||||
# # Now we can compare two versions of firebird.log and check their difference.
|
||||
#
|
||||
#
|
||||
# oldfb=open(f_fblog_before.name, 'r')
|
||||
# newfb=open(f_fblog_after.name, 'r')
|
||||
#
|
||||
#
|
||||
# difftext = ''.join(difflib.unified_diff(
|
||||
# oldfb.readlines(),
|
||||
# oldfb.readlines(),
|
||||
# newfb.readlines()
|
||||
# ))
|
||||
# oldfb.close()
|
||||
# newfb.close()
|
||||
#
|
||||
#
|
||||
# f_diff_txt=open( os.path.join(context['temp_directory'],'tmp_3188_diff.txt'), 'w')
|
||||
# f_diff_txt.write(difftext)
|
||||
# flush_and_close( f_diff_txt )
|
||||
#
|
||||
#
|
||||
# # Difference of firebird.log should be EMPTY:
|
||||
#
|
||||
#
|
||||
# with open( f_diff_txt.name,'r') as f:
|
||||
# print( f.read() )
|
||||
# f.close()
|
||||
#
|
||||
#
|
||||
# ###############################
|
||||
# # Cleanup.
|
||||
# cleanup( [i.name for i in (f_fblog_before, f_fblog_after, f_diff_txt)] )
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#---
|
||||
#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.1')
|
||||
@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()
|
||||
with act_1.db.connect() as con1, act_1.db.connect() as con2:
|
||||
c1 = con1.cursor()
|
||||
c1.execute("create table test(id int primary key)")
|
||||
con1.commit()
|
||||
#
|
||||
c2 = con2.cursor()
|
||||
c2.execute('drop table test')
|
||||
con2.commit()
|
||||
srv.info.get_log()
|
||||
log_after = srv.readlines()
|
||||
assert list(unified_diff(log_before, log_after)) == []
|
||||
|
Loading…
Reference in New Issue
Block a user