2021-04-26 20:07:00 +02:00
|
|
|
#coding:utf-8
|
|
|
|
#
|
|
|
|
# id: bugs.core_4298
|
|
|
|
# title: fbsvcmgr doesn't recognise sts_record_versions and other sts switches
|
|
|
|
# decription:
|
|
|
|
# Test creates table and add 5 rows to it. Than we run in child async. process ISQL with EB which has ES/EDS
|
|
|
|
# and will stay in pause due to update conflict in lock-timeout transaction (Python currently can not operate
|
|
|
|
# with several attachments which open cursors with DML - this will crash).
|
|
|
|
# When EB will be paused, we start another ISQL which will add one row to the same table and finish.
|
|
|
|
# At this point table will have 5 versions and this should be shown in the output of fbsvcmgr when it is run
|
|
|
|
# with 'action_db_stats sts_record_versions' keys.
|
|
|
|
# Finally, we terminate hanged ISQL process and proceed with logs (STDOUR and STDERR) of fbsvcmgr.
|
|
|
|
# Log of errors should be empty, log of STDOUT should contain text with non-zero number of versions.
|
|
|
|
# Checked on:
|
|
|
|
# WI-V2.5.5.26942 (SS), WI-V2.5.5.26952 (sC);
|
|
|
|
# WI-V3.0.0.32239 (SS), WI-V3.0.0.32208 (Cs, sC).
|
|
|
|
# ### NOTE ###
|
|
|
|
# Classic keeps database file opened when hanged ISQL is killed by teminate(), thus leading to access error
|
|
|
|
# when fbtest tries to remove database by dropping it (get "Windows error (32)"). For that reason we have
|
|
|
|
# to allow ISQL that stays in pause to finish by Tx timeout expiration and close itself his own process.
|
|
|
|
#
|
|
|
|
# Checked on (28.10.2019):
|
|
|
|
# 4.0.0.1635 SS: 7.720s.
|
|
|
|
# 4.0.0.1633 CS: 7.378s.
|
|
|
|
# 3.0.5.33180 SS: 7.313s.
|
|
|
|
# 3.0.5.33178 CS: 6.720s.
|
|
|
|
# 2.5.9.27119 SS: 6.506s.
|
|
|
|
# 2.5.9.27146 SC: 5.388s.
|
|
|
|
#
|
|
|
|
# 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-4298
|
|
|
|
# min_versions: ['2.5.2']
|
|
|
|
# versions: 2.5.2
|
|
|
|
# qmid: None
|
|
|
|
|
|
|
|
import pytest
|
|
|
|
from firebird.qa import db_factory, isql_act, Action
|
|
|
|
|
|
|
|
# version: 2.5.2
|
|
|
|
# resources: None
|
|
|
|
|
|
|
|
substitutions_1 = [('Average version length: [\\d]+.[\\d]+, total versions: 5, max versions: 1', 'total versions: 5, max versions: 1')]
|
|
|
|
|
|
|
|
init_script_1 = """
|
|
|
|
recreate table test(id int, x int);
|
|
|
|
commit;
|
|
|
|
insert into test values(1, 100);
|
|
|
|
insert into test values(2, 200);
|
|
|
|
insert into test values(3, 300);
|
|
|
|
insert into test values(4, 400);
|
|
|
|
insert into test values(5, 500);
|
|
|
|
commit;
|
|
|
|
"""
|
|
|
|
|
|
|
|
db_1 = db_factory(sql_dialect=3, init=init_script_1)
|
|
|
|
|
|
|
|
# test_script_1
|
|
|
|
#---
|
|
|
|
# import os
|
|
|
|
# import time
|
|
|
|
# import subprocess
|
|
|
|
# from subprocess import Popen
|
|
|
|
# from fdb import services
|
|
|
|
#
|
|
|
|
# os.environ["ISC_USER"] = user_name
|
|
|
|
# os.environ["ISC_PASSWORD"] = user_password
|
|
|
|
#
|
|
|
|
# # Obtain engine version:
|
|
|
|
# engine = str(db_conn.engine_version) # convert to text because 'float' object has no attribute 'startswith'
|
|
|
|
#
|
|
|
|
# #--------------------------------------------
|
|
|
|
#
|
|
|
|
# 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 )):
|
|
|
|
# if type(f_names_list[i]) == file:
|
|
|
|
# del_name = f_names_list[i].name
|
|
|
|
# elif type(f_names_list[i]) == str:
|
|
|
|
# del_name = f_names_list[i]
|
|
|
|
# else:
|
|
|
|
# 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 )
|
|
|
|
#
|
|
|
|
# #--------------------------------------------
|
|
|
|
#
|
|
|
|
# sqltxt='''
|
|
|
|
# set term ^;
|
|
|
|
# execute block as
|
|
|
|
# begin
|
|
|
|
# execute statement 'drop role TMP$R4298';
|
|
|
|
# when any do begin end
|
|
|
|
# end ^
|
|
|
|
# set term ;^
|
|
|
|
# commit;
|
|
|
|
#
|
|
|
|
#
|
|
|
|
# commit;
|
|
|
|
# set transaction lock timeout 15;
|
|
|
|
# update test set x = -x;
|
|
|
|
# set term ^;
|
|
|
|
# execute block as
|
|
|
|
# begin
|
|
|
|
# execute statement 'update test set x = -x'
|
|
|
|
# on external 'localhost:' || rdb$get_context('SYSTEM','DB_NAME')
|
|
|
|
# as user '%s' password '%s' role 'TMP$R4298';
|
|
|
|
# when any do
|
|
|
|
# begin
|
|
|
|
# end
|
|
|
|
# end
|
|
|
|
# ^
|
|
|
|
# set term ;^
|
|
|
|
# rollback;
|
|
|
|
#
|
|
|
|
# ''' % (user_name, user_password)
|
|
|
|
#
|
|
|
|
#
|
|
|
|
# f_hanged_sql=open( os.path.join(context['temp_directory'],'tmp_4298_hang.sql'), 'w')
|
|
|
|
# f_hanged_sql.write(sqltxt)
|
|
|
|
# flush_and_close( f_hanged_sql )
|
|
|
|
#
|
|
|
|
# f_hanged_log=open( os.path.join(context['temp_directory'],'tmp_4298_hang.log'), 'w')
|
|
|
|
#
|
|
|
|
# # Execute a child program in a new process, redirecting STDERR to the same target as of STDOUT:
|
|
|
|
# p_hang = Popen([context['isql_path'], dsn, "-i" , f_hanged_sql.name], stdout=f_hanged_log, stderr=subprocess.STDOUT)
|
|
|
|
#
|
|
|
|
# time.sleep(1)
|
|
|
|
#
|
|
|
|
# runProgram('isql',[dsn],'insert into test(id, x) values(-1, -100); commit;')
|
|
|
|
#
|
|
|
|
# this_fdb='$(DATABASE_LOCATION)bugs.core_4298.fdb'
|
|
|
|
#
|
|
|
|
# f_stat_log=open( os.path.join(context['temp_directory'],'tmp_4298_dbstat.log'), 'w')
|
|
|
|
# f_stat_err=open( os.path.join(context['temp_directory'],'tmp_4298_dbstat.err'), 'w')
|
|
|
|
#
|
|
|
|
# subprocess.call( [ context['fbsvcmgr_path'],"localhost:service_mgr",
|
|
|
|
# "action_db_stats", "dbname", this_fdb,
|
|
|
|
# "sts_record_versions"
|
|
|
|
# ],
|
|
|
|
# stdout=f_stat_log,
|
|
|
|
# stderr=f_stat_err
|
|
|
|
# )
|
|
|
|
#
|
|
|
|
# flush_and_close( f_stat_log )
|
|
|
|
# flush_and_close( f_stat_err )
|
|
|
|
#
|
|
|
|
# # do NOT remove this pause: Classic 3.0 keeps database opened even after we kill hanged ISQL by p_hang.terminate().
|
|
|
|
# # So we have to wait enough for 1st ISQL process that currently will hangs about 4 seconds to be CORRECTLY closed
|
|
|
|
# # by itself:
|
|
|
|
#
|
|
|
|
# time.sleep(3)
|
|
|
|
#
|
|
|
|
# # These kill and close commands are also needed here, despite that corresponding ISQL has been already closed itself.
|
|
|
|
# # It is so at least for Cs 3.0:
|
|
|
|
# p_hang.terminate()
|
|
|
|
# flush_and_close( f_hanged_log )
|
|
|
|
#
|
|
|
|
# # ERRORS log of obtaining DB statistics should be EMPTY:
|
|
|
|
# with open( f_stat_err.name,'r') as f:
|
|
|
|
# for line in f:
|
|
|
|
# if line.split():
|
|
|
|
# print("UNEXPECTED STDERR for 'action_db_stats': " + line)
|
|
|
|
#
|
|
|
|
# # STDOUT of obtaining DB statistics should NOT be EMPTY:
|
|
|
|
# with open(f_stat_log.name,'r') as f:
|
|
|
|
# for line in f:
|
|
|
|
# if 'versions:' in line.lower():
|
|
|
|
# print(line)
|
|
|
|
#
|
|
|
|
# #####################################################################
|
|
|
|
# # 28.10.2019: add full shutdown to forcedly drop all attachments.
|
|
|
|
# ## ||||||||||||||||||||||||||||
|
|
|
|
# ## ###################################||| FB 4.0+, SS and SC |||##############################
|
|
|
|
# ## ||||||||||||||||||||||||||||
|
|
|
|
# ## If we check SS or SC and ExtConnPoolLifeTime > 0 (config parameter FB 4.0+) then current
|
|
|
|
# ## DB (bugs.core_NNNN.fdb) will be 'captured' by firebird.exe process and fbt_run utility
|
|
|
|
# ## will not able to drop this database at the final point of test.
|
|
|
|
# ## Moreover, DB file will be hold until all activity in firebird.exe completed and AFTER this
|
|
|
|
# ## we have to wait for <ExtConnPoolLifeTime> seconds after it (discussion and small test see
|
|
|
|
# ## in the letter to hvlad and dimitr 13.10.2019 11:10).
|
|
|
|
# ## This means that one need to kill all connections to prevent from exception on cleanup phase:
|
|
|
|
# ## SQLCODE: -901 / lock time-out on wait transaction / object <this_test_DB> is in use
|
|
|
|
# ## #############################################################################################
|
|
|
|
#
|
|
|
|
# f_shutdown_log=open( os.path.join(context['temp_directory'],'tmp_4298_shutdown.log'), 'w')
|
|
|
|
#
|
|
|
|
# subprocess.call( [context['fbsvcmgr_path'], "localhost:service_mgr",
|
|
|
|
# "action_properties", "prp_shutdown_mode", "prp_sm_full", "prp_shutdown_db", "0", "dbname", this_fdb,
|
|
|
|
# ],
|
|
|
|
# stdout = f_shutdown_log,
|
|
|
|
# stderr = subprocess.STDOUT
|
|
|
|
# )
|
|
|
|
# subprocess.call( [context['fbsvcmgr_path'], "localhost:service_mgr",
|
|
|
|
# "action_properties", "prp_db_online", "dbname", this_fdb,
|
|
|
|
# ],
|
|
|
|
# stdout = f_shutdown_log,
|
|
|
|
# stderr = subprocess.STDOUT
|
|
|
|
# )
|
|
|
|
#
|
|
|
|
# flush_and_close( f_shutdown_log )
|
|
|
|
#
|
|
|
|
# with open( f_shutdown_log.name,'r') as f:
|
|
|
|
# for line in f:
|
|
|
|
# if line.split():
|
|
|
|
# print( 'UNEXPECTED OUTPUT IN DB SHUTDOWN LOG: ' + (' '.join(line.split()).upper()) )
|
|
|
|
#
|
|
|
|
#
|
|
|
|
# # Cleanup:
|
|
|
|
# ##########
|
|
|
|
# # do NOT remove this pause otherwise some of logs will not be enable for deletion and test will finish with
|
|
|
|
# # Exception raised while executing Python test script. exception: WindowsError: 32
|
|
|
|
# time.sleep(1)
|
|
|
|
#
|
|
|
|
# cleanup( (f_hanged_sql, f_hanged_log, f_stat_log, f_stat_err, f_shutdown_log) )
|
|
|
|
#
|
|
|
|
#
|
|
|
|
#---
|
|
|
|
#act_1 = python_act('db_1', test_script_1, substitutions=substitutions_1)
|
|
|
|
|
|
|
|
expected_stdout_1 = """
|
|
|
|
Average version length: 9.00, total versions: 5, max versions: 1
|
|
|
|
"""
|
|
|
|
|
|
|
|
@pytest.mark.version('>=2.5.2')
|
|
|
|
@pytest.mark.xfail
|
2021-04-28 12:42:11 +02:00
|
|
|
def test_1(db_1):
|
2021-04-26 20:07:00 +02:00
|
|
|
pytest.fail("Test not IMPLEMENTED")
|
|
|
|
|
|
|
|
|