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

Added/Updated bugs\gh_6860_test.py. Re-implemented. Checked on 5.0.0.623, 4.0.1.2692 - both on Windows and Linux.

This commit is contained in:
zotov 2022-08-18 15:45:30 +03:00
parent b366eff138
commit bf5fb4e20d

View File

@ -2,260 +2,107 @@
"""
ID: issue-6860
ISSUE: 6860
ISSUE: https://github.com/FirebirdSQL/firebird/issues/6860
TITLE: Create user statement fails with SQLSTATE = HY000 when using DataTypeCompatibility
DESCRIPTION:
Test makes back-copies of firebnird.conf + databases.conf and changes firebird.conf by adding DataTypeCompatibility = N.M;
also, databases.conf is changed by adding alias for new database which will be self-security and has alias = 'self_gh_6860'.
Such database (self-security) allows us to create new DBA (SYSDBA/masterkey) without any affect on common security.db data.
Then we make file-level copy of security.db to database defined by alias 'self_gh_6860', do connect and apply SQL script that
creates and drops user. Repeat this for DataTypeCompatibility = 2.5 and 3.0.
No errors must raise during this work.
Finally, test restored back-copies of .conf files.
NOTE-1.
Perhaps, test can be significantly simplified (may be implemented without self-security database ?), but this will be done later.
NOTE-2.
One need to change temporary DB state to 'full shutdown' before drop it otherwise we get 'Windows 32' error because DB file remains
opened by engine. In order to do this, we have to call fbsvcmgr and pass "expected_db" command switch to it with specifying name
of tempoprary DB which is self-security. Otherwise fbsvcmgr will try to connect to common security.db.
Confirmed on 5.0.0.82, 4.0.1.2519: statement 'CREATE USER SYSDBA ...' fails with "SQLSTATE = HY000/.../-Incompatible data type"
Checked on 5.0.0.131 SS/CS, 4.0.1.2563 SS/CS -- all fine.
Test creates two self-security databases, each of them allows to create new SYSDBA.
Alias for first of these DB contains 'DataTypeCompatibility = 2.5', second - 'DataTypeCompatibility = 3.0'
(NB: parameter 'DataTypeCompatibility' is defined as per-database).
Creation of SYSDBA in each of these databases must no raise any error.
FBTEST: bugs.gh_6860
NOTES:
[18.08.2022] pzotov
1. One need to be sure that firebird.conf does NOT contain DatabaseAccess = None.
2. Test uses pre-created databases.conf which has TWO aliases ('tmp_gh_6860_fb25_alias', 'tmp_gh_6860_fb30_alias')
for each DataTypeCompatibility value (2.5 and 3.0).
Both these aliases must defined SecurityDatabase which points to that alias, thus making such DB be self-security.
Database file for that alias must NOT exist in the QA_root/files/qa/ subdirectory: it will be created here.
Content of databases.conf must be taken from $QA_ROOT/files/qa-databases.conf (one need to replace
it before every test session).
Discussed with pcisar, letters since 30-may-2022 13:48, subject:
"new qa, core_4964_test.py: strange outcome when use... shutil.copy() // comparing to shutil.copy2()"
3. Each value of req_alias must be EXACTLY the same as alias specified in the pre-created databases.conf
(for LINUX this equality is case-sensitive, even when aliases are compared!)
Confirmed again problem: 5.0.0.82, 4.0.1.2519 (got SQLSTATE = HY000 / add record error / -Incompatible data type).
Checked on 5.0.0.623, 4.0.1.2692 - both on Windows and Linux.
"""
import re
import locale
from pathlib import Path
import pytest
from firebird.qa import *
# Name of alias for self-security DB in the QA_root/files/qa-databases.conf.
# This file must be copied manually to each testing FB homw folder, with replacing
# databases.conf there:
#
db = db_factory()
act_ = python_act('db_1')
act = python_act('db')
expected_stdout = """
SEC$USER_NAME TMP$GH_6860_25
SEC$USER_NAME TMP$GH_6860_25_X
@pytest.mark.version('>=4.0')
def test_1(act: Action, capsys):
SEC$USER_NAME TMP$GH_6860_30
SEC$USER_NAME TMP$GH_6860_30_X
"""
for req_alias in ('tmp_gh_6860_fb25_alias', 'tmp_gh_6860_fb30_alias'):
@pytest.mark.skip('FIXME: databases.conf / firebird.conf')
@pytest.mark.version('>=4.0.1')
def test_1(act_: Action):
pytest.fail("Not IMPLEMENTED")
# Scan line-by-line through databases.conf, find line starting with REQUIRED_ALIAS and extract name of file that
# must be created in the $(dir_sampleDb)/qa/ folder. This name will be used further as target database (tmp_fdb).
# NOTE: we have to SKIP lines which are commented out, i.e. if they starts with '#':
p_required_alias_ptn = re.compile( '^(?!#)((^|\\s+)' + req_alias + ')\\s*=\\s*\\$\\(dir_sampleDb\\)/qa/', re.IGNORECASE )
fname_in_dbconf = None
# test_script_1
#---
# import os
# import sys
# import subprocess
# from subprocess import Popen
# import datetime
# import time
# import shutil
# from fdb import services
# from datetime import datetime as dt
# from datetime import timedelta
#
# os.environ["ISC_USER"] = user_name
# os.environ["ISC_PASSWORD"] = user_password
#
# db_conn.close()
#
# #-----------------------------------
# def showtime():
# global dt
# return ''.join( (dt.now().strftime("%H:%M:%S.%f")[:11],'.') )
#
# #--------------------------------------------
#
# 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 )
#
# #--------------------------------------------
#
#
# FB_HOME = services.connect(host='localhost', user= user_name, password= user_password).get_home_directory()
# # Resut: FB_HOME is full path to FB instance home (with trailing slash).
#
# if os.name == 'nt':
# # For Windows we assume that client library is always in FB_HOME dir:
# FB_CLNT=os.path.join(FB_HOME, 'fbclient.dll')
# else:
# # For Linux client library will be searched in 'lib' subdirectory of FB_HOME:
# FB_CLNT=os.path.join(FB_HOME, 'lib', 'libfbclient.so' )
#
#
# dts = datetime.datetime.now().strftime("%y%m%d_%H%M%S")
#
# fbconf_cur = os.path.join( FB_HOME, 'firebird.conf')
# fbconf_bak = os.path.join( context['temp_directory'], 'firebird'+dts+'.bak')
#
# dbconf_cur = os.path.join(FB_HOME, 'databases.conf')
# dbconf_bak = os.path.join(context['temp_directory'], 'databases_'+dts+'.bak')
#
# shutil.copy2( fbconf_cur, fbconf_bak )
# shutil.copy2( dbconf_cur, dbconf_bak )
#
# sec_db = context['isc4_path']
# tmp_alias = 'self_gh_6860'
#
# ##############################################################
#
# for iter in (1,2):
#
# DCOMPAT_VAL = '2.5' if iter == 1 else '3.0'
# DCOMPAT_SUF = DCOMPAT_VAL.replace('.', '')
# DBA_PSWD = 'pw6860_' + DCOMPAT_SUF
# DBA_PSWD = 'masterkey'
#
# tmp_fdb = os.path.join(context['temp_directory'],'tmp_gh_6860_'+DCOMPAT_SUF+'.fdb')
# alias_data= '''
# # Temporary added for executing test gh_6860.fbt
# #
# %(tmp_alias)s = %(tmp_fdb)s {
# RemoteAccess = true
# SecurityDatabase = %(tmp_alias)s
# }
# ''' % locals()
#
# cleanup( (tmp_fdb,) )
# shutil.copy2( sec_db, tmp_fdb )
#
#
# # Restore original content of .conf files:
# ##################
# shutil.copy2( fbconf_bak, fbconf_cur )
# shutil.copy2( dbconf_bak, dbconf_cur )
#
# f_fbconf=open( fbconf_cur, 'r')
# fbconf_content=f_fbconf.readlines()
# f_fbconf.close()
# for i,s in enumerate( fbconf_content ):
# line = s.lower().lstrip()
# if line.startswith( 'DataTypeCompatibility'.lower() ):
# fbconf_content[i] = '# [temply commented by fbtest for gh_6860.fbt] ' + s
#
# text2app= '''
# ### TEMPORARY CHANGED FOR gh-6860.fbt ###
# DataTypeCompatibility = %(DCOMPAT_VAL)s
# #########################################
# ''' % locals()
#
# fbconf_content += [ os.linesep + x for x in text2app.split( os.linesep ) ]
#
# f_fbconf=open( fbconf_cur, 'w')
# f_fbconf.writelines( fbconf_content )
# flush_and_close( f_fbconf )
#
#
# f_dbconf=open( dbconf_cur, 'a')
# f_dbconf.seek(0, 2)
# f_dbconf.write( alias_data )
# flush_and_close( f_dbconf )
#
#
# sql_txt = '''
# set bail on;
# set list on;
#
# create or alter user %(user_name)s password '%(DBA_PSWD)s';
# create or alter user tmp$gh_6860_%(DCOMPAT_SUF)s password '123' grant admin role;
# commit;
#
# connect 'localhost:%(tmp_alias)s' user tmp$gh_6860_%(DCOMPAT_SUF)s password '123';
#
# create or alter user tmp$gh_6860_%(DCOMPAT_SUF)s_x password '456';
# commit;
#
# connect 'localhost:%(tmp_alias)s' user %(user_name)s password '%(DBA_PSWD)s';
#
# select sec$user_name from sec$users where sec$user_name starting with upper('tmp$gh_6860_') order by sec$user_name;
# commit;
#
# drop user tmp$gh_6860_%(DCOMPAT_SUF)s;
# drop user tmp$gh_6860_%(DCOMPAT_SUF)s_x;
# commit;
# ''' % dict(globals(), **locals())
#
# f_isql_cmd=open( os.path.join(context['temp_directory'],'tmp_6860.dtc_' + DCOMPAT_SUF + '.sql'), 'w')
# f_isql_cmd.write(sql_txt)
# flush_and_close( f_isql_cmd )
#
# f_isql_log = open( os.path.splitext(f_isql_cmd.name)[0] + '.log', 'w' )
# f_isql_err = open( os.path.splitext(f_isql_cmd.name)[0] + '.err', 'w' )
# subprocess.call( [ context['isql_path'], 'localhost:' + tmp_alias, '-q', '-user', user_name, '-i', f_isql_cmd.name], stdout=f_isql_log, stderr=f_isql_err )
# flush_and_close( f_isql_log )
# flush_and_close( f_isql_err )
#
# with open( f_isql_err.name, 'r' ) as f:
# for line in f:
# if line:
# print("Unexpected STDERR when create/drop users: "+line)
#
# # Output list of users created on this iteration of test:
# with open( f_isql_log.name, 'r' ) as f:
# for line in f:
# if line:
# print(line)
#
# f_shutdown_log=open( os.path.join(context['temp_directory'],'tmp_6860_shutdown_'+DCOMPAT_SUF+'.log'), 'w')
# subprocess.call( [context['fbsvcmgr_path'],
# "localhost:service_mgr",
# "user", user_name, "password", DBA_PSWD,
# "expected_db", tmp_fdb,
# "action_properties", "prp_shutdown_mode", "prp_sm_full", "prp_shutdown_db", "0", "dbname", tmp_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:
# print("Unexpected STDERR when try to make full shutdown: "+line)
#
#
# cleanup( (tmp_fdb,) )
# cleanup( (f_isql_err,f_isql_log,f_isql_cmd, f_shutdown_log) )
#
#
# # Restore original content of firebird.conf:
# ##################
# shutil.move( fbconf_bak, fbconf_cur )
# shutil.move( dbconf_bak, dbconf_cur )
#
#---
with open(act.home_dir/'databases.conf', 'r') as f:
for line in f:
if p_required_alias_ptn.search(line):
# If databases.conf contains line like this:
# tmp_6147_alias = $(dir_sampleDb)/qa/tmp_core_6147.fdb
# - then we extract filename: 'tmp_core_6147.fdb' (see below):
fname_in_dbconf = Path(line.split('=')[1].strip()).name
break
# if 'fname_in_dbconf' remains undefined here then propably REQUIRED_ALIAS not equals to specified in the databases.conf!
#
assert fname_in_dbconf
# Full path + filename of database to which we will try to connect:
#
tmp_fdb = Path( act.vars['sample_dir'], 'qa', fname_in_dbconf )
tmp_dba_pswd = 'p@$$w6860'
init_sql = f'''
set bail on;
set list on;
create database '{req_alias}' user {act.db.user};
select '{req_alias}' as req_alias, 'DB creation completed OK.' as msg from rdb$database;
alter database set linger to 0;
create user {act.db.user} password '{tmp_dba_pswd}' using plugin Srp;
commit;
'''
try:
act.expected_stdout = f"""
REQ_ALIAS {req_alias}
MSG DB creation completed OK.
"""
act.isql(switches = ['-q'], input = init_sql, connect_db=False, credentials = False, combine_output = True, io_enc = locale.getpreferredencoding())
assert act.clean_stdout == act.clean_expected_stdout
act.reset()
# Change DB state to full shutdown in order to have ability to drop database file.
# This is needed because when DB is self-security then it will be kept opened for 10s
# (as it always occurs for common security.db). Set linger to 0 does not help.
act.gfix(switches=['-shut', 'full', '-force', '0', f'localhost:{req_alias}', '-user', act.db.user, '-pas', tmp_dba_pswd], io_enc = locale.getpreferredencoding(), credentials = False, combine_output = True)
act.stdout = capsys.readouterr().out
assert act.clean_stdout == act.clean_expected_stdout
act.reset()
finally:
tmp_fdb.unlink()