6
0
mirror of https://github.com/FirebirdSQL/firebird-qa.git synced 2025-01-22 21:43:06 +01:00
firebird-qa/tests/bugs/gh_6785_test.py

133 lines
5.0 KiB
Python

#coding:utf-8
"""
ID: issue-6785
ISSUE: 6785
TITLE: Problem when restoring the database on FB 4.0 RC1 (gbak regression)
DESCRIPTION:
Test used database backup that was provided in the ticket.
Maximal allowed time is set here for restoring process and gbak will be
forcedly killed if it can not complete during this time.
Currently this time is 300 seconds (see 'MAX_THRESHOLD' variable).
Database is validated (using 'gfix -v -full') after successful restore finish.
Test checks that returned codes for both gbak and validation are zero.
Also, it checks that firebird.log contains message with 'all-zeroes' values
for validation outcome ("Validation finished: 0 errors, 0 warnings, 0 fixed").
Restore issues warnings:
gbak: WARNING:function F_DATETOSTR is not defined
gbak: WARNING: module name or entrypoint could not be found
gbak: WARNING:function F_DATETOSTR is not defined
gbak: WARNING: module name or entrypoint could not be found
All of them are ignored by this test when gbak output is parsed.
Confirmed bug on 4.0.0.2452 SS: gbak infinitely hanged.
Checked on 4.0.0.2453 SS/CS (Linux and Windows): all OK, restore lasts near 200s.
FBTEST: bugs.gh_6785
NOTES:
[30.06.2022] pzotov
Checked again on 4.0.1.2692, 5.0.0.509. Confirmed reproducing of problem on 4.0.0.2452.
[20.07.2022] pzotov
firebird.log may contain messages encoded in different code pages (say, in cp1251 and in utf8).
Because of this, one need to IGNORE any decoding errors when obtain content of log.
In this case call of act.get_firebird_log() will raise:
UnicodeDecodeError: 'ascii' codec can't decode byte 0x** ... ordinal not in range(128)
We have either to specify this using somewhat like "act.connect_server(encoding_errors = 'ignore')",
or to change firebid-driver.conf - and this will be more proper way.
This file (firebid-driver.conf) must have section with name [DEFAULT] with encoding_errors = ignore.
Test assumes exactly THIS, i.e. we do NOT specify "encoding_errors = 'ignore'" in acty.connect_server()
"""
import locale
import zipfile
import subprocess
import re
import pytest
from firebird.qa import *
from firebird.driver import SrvRepairFlag
from pathlib import Path
from difflib import unified_diff
import time
db = db_factory()
act = python_act('db')
tmp_log = temp_file('gh_6785.tmp.log')
tmp_fbk = temp_file('gh_6785.tmp.fbk')
tmp_fdb = temp_file('gh_6785.tmp.fdb')
###################
MAX_THRESHOLD = 300
###################
expected_stdout = """
Restore retcode: 0
Validation retcode: 0
"""
restore_completed_msg = 'Restore COMPLETED.'
@pytest.mark.version('>=4.0')
def test_1(act: Action, tmp_fbk: Path, tmp_fdb: Path, tmp_log: Path, capsys):
zipped_fbk_file = zipfile.Path(act.files_dir / 'gh_6785.zip', at = 'gh_6785.fbk')
tmp_fbk.write_bytes(zipped_fbk_file.read_bytes())
restore_code = -1
# If the timeout expires, the child process will be killed and waited for.
# The TimeoutExpired exception will be re-raised after the child process has terminated.
try:
p = subprocess.run([ act.vars['gbak'],
'-user', act.db.user, '-password', act.db.password,
'-rep', tmp_fbk, tmp_fdb,
'-st', 'tdrw',
'-v', '-y', str(tmp_log)
]
,stderr = subprocess.STDOUT
,timeout = MAX_THRESHOLD
)
print( restore_completed_msg )
restore_code = p.returncode
except Exception as e:
print(e.__str__())
tmp_fdb.unlink()
act.expected_stdout = restore_completed_msg
act.stdout = capsys.readouterr().out
assert act.clean_stdout == act.clean_expected_stdout
act.reset()
if restore_code == 0:
# Get FB log before validation, run validation and get FB log after it:
with act.connect_server() as srv:
fblog_1 = act.get_firebird_log()
#with act.connect_server(encoding=locale.getpreferredencoding()) as srv:
# srv.info.get_log()
# fblog_1 = srv.readlines()
srv.database.repair(database = str(tmp_fdb), flags=SrvRepairFlag.CORRUPTION_CHECK)
fblog_2 = act.get_firebird_log()
#with act.connect_server(encoding=locale.getpreferredencoding()) as srv:
# srv.info.get_log()
# fblog_2 = srv.readlines()
p_diff = re.compile('Validation finished: \\d+ errors, \\d+ warnings, \\d+ fixed')
validation_result = ''
for line in unified_diff(fblog_1, fblog_2):
if line.startswith('+') and p_diff.search(line):
validation_result =line.strip().replace('\t', ' ')
break
assert validation_result == '+ Validation finished: 0 errors, 0 warnings, 0 fixed'
act.reset()