mirror of
https://github.com/FirebirdSQL/firebird-qa.git
synced 2025-01-22 21:43:06 +01:00
Added/Updated functional\transactions\test_read_consist_sttm_restart_on_update_03.py. Checked on 4.0.1.2692, 5.0.0.591
This commit is contained in:
parent
22f97fae37
commit
08d4fc61e5
@ -121,15 +121,25 @@ DESCRIPTION:
|
||||
Checked on 4.0.0.2195
|
||||
26.09.2020: added for-loop in order to check different target objects: TABLE ('test') and VIEW ('v_test'), see 'checked_mode'.
|
||||
FBTEST: functional.transactions.read_consist_sttm_restart_on_update_03
|
||||
NOTES:
|
||||
[29.07.2022] pzotov
|
||||
Checked on 4.0.1.2692, 5.0.0.591
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import pytest
|
||||
from firebird.qa import *
|
||||
from pathlib import Path
|
||||
import time
|
||||
|
||||
db = db_factory()
|
||||
|
||||
act = python_act('db', substitutions=[('=', ''), ('[ \t]+', ' ')])
|
||||
|
||||
fn_worker_sql = temp_file('tmp_worker.sql')
|
||||
fn_worker_log = temp_file('tmp_worker.log')
|
||||
fn_worker_err = temp_file('tmp_worker.err')
|
||||
|
||||
expected_stdout = """
|
||||
checked_mode: table, STDLOG: Records affected: 10
|
||||
|
||||
@ -196,232 +206,160 @@ expected_stdout = """
|
||||
checked_mode: view, STDLOG: Records affected: 11
|
||||
"""
|
||||
|
||||
@pytest.mark.skip('FIXME: Not IMPLEMENTED')
|
||||
@pytest.mark.version('>=4.0')
|
||||
def test_1(act: Action):
|
||||
pytest.fail("Not IMPLEMENTED")
|
||||
def test_1(act: Action, fn_worker_sql: Path, fn_worker_log: Path, fn_worker_err: Path, capsys):
|
||||
sql_init = (act.files_dir / 'read-consist-sttm-restart-DDL.sql').read_text()
|
||||
|
||||
# Original python code for this test:
|
||||
# -----------------------------------
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# import subprocess
|
||||
# from subprocess import Popen
|
||||
# from fdb import services
|
||||
# import time
|
||||
#
|
||||
# os.environ["ISC_USER"] = user_name
|
||||
# os.environ["ISC_PASSWORD"] = user_password
|
||||
#
|
||||
# db_conn.close()
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
# def flush_and_close( file_handle ):
|
||||
# # https://docs.python.org/2/library/os.html#os.fsync
|
||||
# # If you're starting with a Python file object f,
|
||||
# # first do f.flush(), and
|
||||
# # then do os.fsync(f.fileno()), to ensure that all internal buffers associated with f are written to disk.
|
||||
# global os
|
||||
#
|
||||
# file_handle.flush()
|
||||
# if file_handle.mode not in ('r', 'rb') and file_handle.name != os.devnull:
|
||||
# # otherwise: "OSError: [Errno 9] Bad file descriptor"!
|
||||
# os.fsync(file_handle.fileno())
|
||||
# file_handle.close()
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
# def cleanup( f_names_list ):
|
||||
# global os
|
||||
# for f in f_names_list:
|
||||
# if type(f) == file:
|
||||
# del_name = f.name
|
||||
# elif type(f) == str:
|
||||
# del_name = f
|
||||
# else:
|
||||
# print('Unrecognized type of element:', f, ' - can not be treated as file.')
|
||||
# del_name = None
|
||||
#
|
||||
# if del_name and os.path.isfile( del_name ):
|
||||
# os.remove( del_name )
|
||||
#
|
||||
# #--------------------------------------------
|
||||
#
|
||||
# sql_init_ddl = os.path.join(context['files_location'],'read-consist-sttm-restart-DDL.sql')
|
||||
#
|
||||
# for checked_mode in('table', 'view'):
|
||||
#
|
||||
# target_obj = 'test' if checked_mode == 'table' else 'v_test'
|
||||
#
|
||||
# f_init_log=open( os.path.join(context['temp_directory'],'read-consist-sttm-restart-DDL.log'), 'w')
|
||||
# f_init_err=open( ''.join( ( os.path.splitext(f_init_log.name)[0], '.err') ), 'w')
|
||||
#
|
||||
# subprocess.call( [context['isql_path'], dsn, '-q', '-i', sql_init_ddl], stdout=f_init_log, stderr=f_init_err )
|
||||
# flush_and_close(f_init_log)
|
||||
# flush_and_close(f_init_err)
|
||||
#
|
||||
# # add rows with ID = 1, 2:
|
||||
# sql_addi='''
|
||||
# set term ^;
|
||||
# execute block as
|
||||
# begin
|
||||
# rdb$set_context('USER_SESSION', 'WHO', 'INIT_DATA');
|
||||
# end
|
||||
# ^
|
||||
# set term ;^
|
||||
# insert into %(target_obj)s(id, x) select row_number()over(),row_number()over() from rdb$types rows 2;
|
||||
# commit;
|
||||
# ''' % locals()
|
||||
# runProgram('isql', [ dsn, '-q' ], sql_addi)
|
||||
#
|
||||
# con_lock_1 = fdb.connect( dsn = dsn )
|
||||
# con_lock_2 = fdb.connect( dsn = dsn )
|
||||
# con_lock_1.execute_immediate( "execute block as begin rdb$set_context('USER_SESSION', 'WHO', 'LOCKER #1'); end" )
|
||||
# con_lock_2.execute_immediate( "execute block as begin rdb$set_context('USER_SESSION', 'WHO', 'LOCKER #2'); end" )
|
||||
#
|
||||
#
|
||||
# #########################
|
||||
# ### L O C K E R - 1 ###
|
||||
# #########################
|
||||
#
|
||||
# con_lock_1.execute_immediate( 'update %(target_obj)s set id=id where id = 2' % locals() )
|
||||
#
|
||||
# sql_text='''
|
||||
# connect '%(dsn)s';
|
||||
# set list on;
|
||||
# set autoddl off;
|
||||
# set term ^;
|
||||
# execute block returns (whoami varchar(30)) as
|
||||
# begin
|
||||
# whoami = 'WORKER'; -- , ATT#' || current_connection;
|
||||
# rdb$set_context('USER_SESSION','WHO', whoami);
|
||||
# -- suspend;
|
||||
# end
|
||||
# ^
|
||||
# set term ;^
|
||||
# commit;
|
||||
# --set echo on;
|
||||
# SET KEEP_TRAN_PARAMS ON;
|
||||
# set transaction read committed read consistency;
|
||||
# --select current_connection, current_transaction from rdb$database;
|
||||
# set list off;
|
||||
# set wng off;
|
||||
# --set plan on;
|
||||
# set count on;
|
||||
#
|
||||
# update %(target_obj)s set id = -id order by id; -- THIS MUST BE LOCKED
|
||||
#
|
||||
# -- check results:
|
||||
# -- ###############
|
||||
#
|
||||
# select id from %(target_obj)s order by id; -- this will produce output only after all lockers do their commit/rollback
|
||||
#
|
||||
# select v.old_id, v.op, v.snap_no_rank from v_worker_log v where v.op = 'upd';
|
||||
#
|
||||
# set width who 10;
|
||||
# -- DO NOT check this! Values can differ here from one run to another!
|
||||
# -- select id, trn, who, old_id, new_id, op, rec_vers, global_cn, snap_no from tlog_done order by id;
|
||||
#
|
||||
# rollback;
|
||||
#
|
||||
# ''' % dict(globals(), **locals())
|
||||
#
|
||||
# f_worker_sql=open( os.path.join(context['temp_directory'],'tmp_sttm_restart_on_update_03.sql'), 'w')
|
||||
# f_worker_sql.write(sql_text)
|
||||
# flush_and_close(f_worker_sql)
|
||||
#
|
||||
#
|
||||
# f_worker_log=open( ''.join( ( os.path.splitext(f_worker_sql.name)[0], '.log') ), 'w')
|
||||
# f_worker_err=open( ''.join( ( os.path.splitext(f_worker_log.name)[0], '.err') ), 'w')
|
||||
#
|
||||
# ############################################################################
|
||||
# ### L A U N C H W O R K E R U S I N G I S Q L, A S Y N C. ###
|
||||
# ############################################################################
|
||||
#
|
||||
# p_worker = Popen( [ context['isql_path'], '-pag', '999999', '-q', '-i', f_worker_sql.name ],stdout=f_worker_log, stderr=f_worker_err)
|
||||
# time.sleep(1)
|
||||
#
|
||||
# #########################
|
||||
# ### L O C K E R - 2 ###
|
||||
# #########################
|
||||
# con_lock_2.execute_immediate( 'insert into %(target_obj)s(id) values(110)' % locals() )
|
||||
# con_lock_2.execute_immediate( 'insert into %(target_obj)s(id) values(-11)' % locals() )
|
||||
# con_lock_2.commit()
|
||||
# con_lock_2.execute_immediate( 'update %(target_obj)s set id=id where id = 110' % locals() )
|
||||
# con_lock_2.execute_immediate( 'update %(target_obj)s set id=id where id = -11' % locals() )
|
||||
#
|
||||
# #########################
|
||||
# ### L O C K E R - 1 ###
|
||||
# #########################
|
||||
# con_lock_1.commit()
|
||||
# con_lock_1.execute_immediate( 'insert into %(target_obj)s(id) values(120)' % locals() )
|
||||
# con_lock_1.execute_immediate( 'insert into %(target_obj)s(id) values(-12)' % locals() )
|
||||
# con_lock_1.commit()
|
||||
# con_lock_1.execute_immediate( 'update %(target_obj)s set id=id where id = 120' % locals() )
|
||||
# con_lock_1.execute_immediate( 'update %(target_obj)s set id=id where id = -12' % locals() )
|
||||
#
|
||||
#
|
||||
# #########################
|
||||
# ### L O C K E R - 2 ###
|
||||
# #########################
|
||||
# con_lock_2.commit()
|
||||
# con_lock_2.execute_immediate( 'insert into %(target_obj)s(id) values(130)' % locals() )
|
||||
# con_lock_2.execute_immediate( 'insert into %(target_obj)s(id) values(-13)' % locals() )
|
||||
# con_lock_2.commit()
|
||||
# con_lock_2.execute_immediate( 'update %(target_obj)s set id=id where id = 130' % locals() )
|
||||
# con_lock_2.execute_immediate( 'update %(target_obj)s set id=id where id = -13' % locals() )
|
||||
#
|
||||
# #########################
|
||||
# ### L O C K E R - 1 ###
|
||||
# #########################
|
||||
# con_lock_1.commit()
|
||||
# con_lock_1.execute_immediate( 'insert into %(target_obj)s(id) values(140)' % locals() )
|
||||
# con_lock_1.execute_immediate( 'insert into %(target_obj)s(id) values(-14)' % locals() )
|
||||
# con_lock_1.commit()
|
||||
# con_lock_1.execute_immediate( 'update %(target_obj)s set id=id where id = 140' % locals() )
|
||||
# con_lock_1.execute_immediate( 'update %(target_obj)s set id=id where id = -14' % locals() )
|
||||
#
|
||||
# #########################
|
||||
# ### L O C K E R - 2 ###
|
||||
# #########################
|
||||
# con_lock_1.commit()
|
||||
#
|
||||
# #########################
|
||||
# ### L O C K E R - 1 ###
|
||||
# #########################
|
||||
# con_lock_2.commit() # WORKER will complete his job after this
|
||||
#
|
||||
#
|
||||
# # Here we wait for ISQL complete its mission:
|
||||
# p_worker.wait()
|
||||
#
|
||||
# flush_and_close(f_worker_log)
|
||||
# flush_and_close(f_worker_err)
|
||||
#
|
||||
# # Close lockers:
|
||||
# ################
|
||||
# for c in (con_lock_1, con_lock_2):
|
||||
# c.close()
|
||||
#
|
||||
# # CHECK RESULTS
|
||||
# ###############
|
||||
# with open(f_worker_log.name,'r') as f:
|
||||
# for line in f:
|
||||
# if line.strip():
|
||||
# print('checked_mode: %(checked_mode)s, STDLOG: %(line)s' % locals())
|
||||
#
|
||||
# for f in (f_init_err, f_worker_err):
|
||||
# with open(f.name,'r') as g:
|
||||
# for line in g:
|
||||
# if line.strip():
|
||||
# print( 'checked_mode: ', checked_mode, ' UNEXPECTED STDERR IN ' + g.name + ':', line)
|
||||
#
|
||||
# #<for checked mode in(...)
|
||||
#
|
||||
# # Cleanup.
|
||||
# ##########
|
||||
# time.sleep(1)
|
||||
# cleanup( (f_init_log, f_init_err, f_worker_sql, f_worker_log, f_worker_err) )
|
||||
# -----------------------------------
|
||||
for checked_mode in('table', 'view'):
|
||||
target_obj = 'test' if checked_mode == 'table' else 'v_test'
|
||||
|
||||
# add rows with ID = 1, 2:
|
||||
sql_addi = f'''
|
||||
set term ^;
|
||||
execute block as
|
||||
begin
|
||||
rdb$set_context('USER_SESSION', 'WHO', 'INIT_DATA');
|
||||
end
|
||||
^
|
||||
set term ;^
|
||||
insert into {target_obj}(id, x) select row_number()over(),row_number()over() from rdb$types rows 2;
|
||||
commit;
|
||||
'''
|
||||
|
||||
act.isql(switches=['-q'], input = ''.join( (sql_init, sql_addi) ) )
|
||||
|
||||
with act.db.connect() as con_lock_1, act.db.connect() as con_lock_2:
|
||||
for i,c in enumerate((con_lock_1,con_lock_2)):
|
||||
sttm = f"execute block as begin rdb$set_context('USER_SESSION', 'WHO', 'LOCKER #{i+1}'); end"
|
||||
c.execute_immediate(sttm)
|
||||
|
||||
#########################
|
||||
### L O C K E R - 1 ###
|
||||
#########################
|
||||
|
||||
con_lock_1.execute_immediate( f'update {target_obj} set id=id where id = 2' )
|
||||
|
||||
worker_sql = f'''
|
||||
set list on;
|
||||
set autoddl off;
|
||||
set term ^;
|
||||
execute block returns (whoami varchar(30)) as
|
||||
begin
|
||||
whoami = 'WORKER'; -- , ATT#' || current_connection;
|
||||
rdb$set_context('USER_SESSION','WHO', whoami);
|
||||
-- suspend;
|
||||
end
|
||||
^
|
||||
set term ;^
|
||||
commit;
|
||||
--set echo on;
|
||||
SET KEEP_TRAN_PARAMS ON;
|
||||
set transaction read committed read consistency;
|
||||
--select current_connection, current_transaction from rdb$database;
|
||||
set list off;
|
||||
set wng off;
|
||||
--set plan on;
|
||||
set count on;
|
||||
|
||||
update {target_obj} set id = -id order by id; -- THIS MUST BE LOCKED
|
||||
|
||||
-- check results:
|
||||
-- ###############
|
||||
|
||||
select id from {target_obj} order by id; -- this will produce output only after all lockers do their commit/rollback
|
||||
|
||||
select v.old_id, v.op, v.snap_no_rank from v_worker_log v where v.op = 'upd';
|
||||
|
||||
set width who 10;
|
||||
-- DO NOT check this! Values can differ here from one run to another!
|
||||
-- select id, trn, who, old_id, new_id, op, rec_vers, global_cn, snap_no from tlog_done order by id;
|
||||
|
||||
rollback;
|
||||
|
||||
'''
|
||||
|
||||
fn_worker_sql.write_text(worker_sql)
|
||||
|
||||
with fn_worker_log.open(mode='w') as hang_out, fn_worker_err.open(mode='w') as hang_err:
|
||||
|
||||
############################################################################
|
||||
### L A U N C H W O R K E R U S I N G I S Q L, A S Y N C. ###
|
||||
############################################################################
|
||||
p_worker = subprocess.Popen([act.vars['isql'], '-i', str(fn_worker_sql),
|
||||
'-user', act.db.user,
|
||||
'-password', act.db.password,
|
||||
'-pag', '999999',
|
||||
act.db.dsn
|
||||
],
|
||||
stdout = hang_out,
|
||||
stderr = hang_err
|
||||
)
|
||||
time.sleep(1)
|
||||
|
||||
#########################
|
||||
### L O C K E R - 2 ###
|
||||
#########################
|
||||
con_lock_2.execute_immediate( f'insert into {target_obj}(id) values(110)' )
|
||||
con_lock_2.execute_immediate( f'insert into {target_obj}(id) values(-11)' )
|
||||
con_lock_2.commit()
|
||||
con_lock_2.execute_immediate( f'update {target_obj} set id=id where id = 110' )
|
||||
con_lock_2.execute_immediate( f'update {target_obj} set id=id where id = -11' )
|
||||
|
||||
#########################
|
||||
### L O C K E R - 1 ###
|
||||
#########################
|
||||
con_lock_1.commit()
|
||||
con_lock_1.execute_immediate( f'insert into {target_obj}(id) values(120)' )
|
||||
con_lock_1.execute_immediate( f'insert into {target_obj}(id) values(-12)' )
|
||||
con_lock_1.commit()
|
||||
con_lock_1.execute_immediate( f'update {target_obj} set id=id where id = 120' )
|
||||
con_lock_1.execute_immediate( f'update {target_obj} set id=id where id = -12' )
|
||||
|
||||
|
||||
#########################
|
||||
### L O C K E R - 2 ###
|
||||
#########################
|
||||
con_lock_2.commit()
|
||||
con_lock_2.execute_immediate( f'insert into {target_obj}(id) values(130)' )
|
||||
con_lock_2.execute_immediate( f'insert into {target_obj}(id) values(-13)' )
|
||||
con_lock_2.commit()
|
||||
con_lock_2.execute_immediate( f'update {target_obj} set id=id where id = 130' )
|
||||
con_lock_2.execute_immediate( f'update {target_obj} set id=id where id = -13' )
|
||||
|
||||
#########################
|
||||
### L O C K E R - 1 ###
|
||||
#########################
|
||||
con_lock_1.commit()
|
||||
con_lock_1.execute_immediate( f'insert into {target_obj}(id) values(140)' )
|
||||
con_lock_1.execute_immediate( f'insert into {target_obj}(id) values(-14)' )
|
||||
con_lock_1.commit()
|
||||
con_lock_1.execute_immediate( f'update {target_obj} set id=id where id = 140' )
|
||||
con_lock_1.execute_immediate( f'update {target_obj} set id=id where id = -14' )
|
||||
|
||||
#########################
|
||||
### L O C K E R - 2 ###
|
||||
#########################
|
||||
con_lock_1.commit()
|
||||
|
||||
#########################
|
||||
### L O C K E R - 1 ###
|
||||
#########################
|
||||
con_lock_2.commit() # WORKER will complete his job after this
|
||||
|
||||
|
||||
# Here we wait for ISQL complete its mission:
|
||||
p_worker.wait()
|
||||
|
||||
|
||||
for g in (fn_worker_log, fn_worker_err):
|
||||
with g.open() as f:
|
||||
for line in f:
|
||||
if line.split():
|
||||
if g == fn_worker_log:
|
||||
print(f'checked_mode: {checked_mode}, STDLOG: {line}')
|
||||
else:
|
||||
print(f'UNEXPECTED STDERR {line}')
|
||||
|
||||
act.expected_stdout = expected_stdout
|
||||
act.stdout = capsys.readouterr().out
|
||||
assert act.clean_stdout == act.clean_expected_stdout
|
||||
|
Loading…
Reference in New Issue
Block a user