173 lines
5.2 KiB
Python
173 lines
5.2 KiB
Python
import itertools
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
|
|
# Require Python 3.7+ for ordered dictionaries so that the order of the
|
|
# generated tests remain the same.
|
|
if sys.version_info[:2] < (3, 7):
|
|
print('ERROR: This script requires Python >= 3.7, not:')
|
|
print(sys.version)
|
|
print('Usage: python3 %s' % (sys.argv[0]))
|
|
exit(1)
|
|
|
|
|
|
dirname = os.path.dirname
|
|
DIR = dirname(os.path.realpath(__file__))
|
|
SOURCE = dirname(dirname(dirname(DIR)))
|
|
|
|
|
|
def template(filename):
|
|
fullpath = os.path.join(DIR, filename)
|
|
with open(fullpath, 'r') as f:
|
|
return f.read()
|
|
|
|
|
|
def write_test(filename, data):
|
|
fullpath = os.path.join(DIR, filename + '.yml')
|
|
with open(fullpath, 'w') as f:
|
|
f.write(data)
|
|
|
|
print(f"Generated {fullpath}")
|
|
|
|
|
|
# Maps from error_name to (error_code,)
|
|
ERR_CODES = {
|
|
'InterruptedAtShutdown': (11600,),
|
|
'InterruptedDueToReplStateChange': (11602,),
|
|
'NotPrimaryOrSecondary': (13436,),
|
|
'PrimarySteppedDown': (189,),
|
|
'ShutdownInProgress': (91,),
|
|
'NotWritablePrimary': (10107,),
|
|
'NotPrimaryNoSecondaryOk': (13435,),
|
|
'LegacyNotPrimary': (10058,),
|
|
}
|
|
|
|
|
|
def create_stale_tests():
|
|
tmp = template('stale-topologyVersion.yml.template')
|
|
for error_name in ERR_CODES:
|
|
test_name = f'stale-topologyVersion-{error_name}'
|
|
error_code, = ERR_CODES[error_name]
|
|
data = tmp.format(**locals())
|
|
write_test(test_name, data)
|
|
|
|
TV_GREATER = '''
|
|
topologyVersion:
|
|
processId:
|
|
"$oid": '000000000000000000000001'
|
|
counter:
|
|
"$numberLong": "2"'''
|
|
TV_GREATER_FINAL = '''
|
|
processId:
|
|
"$oid": '000000000000000000000001'
|
|
counter:
|
|
"$numberLong": "2"'''
|
|
TV_CHANGED = '''
|
|
topologyVersion:
|
|
processId:
|
|
"$oid": '000000000000000000000002'
|
|
counter:
|
|
"$numberLong": "1"'''
|
|
TV_CHANGED_FINAL = '''
|
|
processId:
|
|
"$oid": '000000000000000000000002'
|
|
counter:
|
|
"$numberLong": "1"'''
|
|
|
|
# Maps non-stale error description to:
|
|
# (error_topology_version, final_topology_version)
|
|
NON_STALE_CASES = {
|
|
'topologyVersion missing': ('', ' null'),
|
|
'topologyVersion greater': (TV_GREATER, TV_GREATER_FINAL),
|
|
'topologyVersion proccessId changed': (TV_CHANGED, TV_CHANGED_FINAL),
|
|
}
|
|
|
|
|
|
def create_non_stale_tests():
|
|
tmp = template('non-stale-topologyVersion.yml.template')
|
|
for error_name, description in itertools.product(
|
|
ERR_CODES, NON_STALE_CASES):
|
|
test_name = f'non-stale-{description.replace(" ", "-")}-{error_name}'
|
|
error_code, = ERR_CODES[error_name]
|
|
error_topology_version, final_topology_version = NON_STALE_CASES[description]
|
|
# On 4.2+, only ShutdownInProgress and InterruptedAtShutdown will
|
|
# clear the pool.
|
|
if error_name in ("ShutdownInProgress", "InterruptedAtShutdown"):
|
|
final_pool_generation = 1
|
|
else:
|
|
final_pool_generation = 0
|
|
|
|
data = tmp.format(**locals())
|
|
write_test(test_name, data)
|
|
|
|
|
|
WHEN = ['beforeHandshakeCompletes', 'afterHandshakeCompletes']
|
|
STALE_GENERATION_COMMAND_ERROR = '''
|
|
type: command
|
|
response:
|
|
ok: 0
|
|
errmsg: {error_name}
|
|
code: {error_code}
|
|
topologyVersion:
|
|
processId:
|
|
"$oid": '000000000000000000000001'
|
|
counter:
|
|
"$numberLong": "2"'''
|
|
STALE_GENERATION_NETWORK_ERROR = '''
|
|
type: {network_error_type}'''
|
|
|
|
|
|
def create_stale_generation_tests():
|
|
tmp = template('stale-generation.yml.template')
|
|
# Stale command errors
|
|
for error_name, when in itertools.product(ERR_CODES, WHEN):
|
|
test_name = f'stale-generation-{when}-{error_name}'
|
|
error_code, = ERR_CODES[error_name]
|
|
stale_error = STALE_GENERATION_COMMAND_ERROR.format(**locals())
|
|
data = tmp.format(**locals())
|
|
write_test(test_name, data)
|
|
# Stale network errors
|
|
for network_error_type, when in itertools.product(
|
|
['network', 'timeout'], WHEN):
|
|
error_name = network_error_type
|
|
test_name = f'stale-generation-{when}-{network_error_type}'
|
|
stale_error = STALE_GENERATION_NETWORK_ERROR.format(**locals())
|
|
data = tmp.format(**locals())
|
|
write_test(test_name, data)
|
|
|
|
|
|
def create_pre_42_tests():
|
|
tmp = template('pre-42.yml.template')
|
|
# All "not writable primary"/"node is recovering" clear the pool on <4.2
|
|
for error_name in ERR_CODES:
|
|
test_name = f'pre-42-{error_name}'
|
|
error_code, = ERR_CODES[error_name]
|
|
data = tmp.format(**locals())
|
|
write_test(test_name, data)
|
|
|
|
|
|
def create_post_42_tests():
|
|
tmp = template('post-42.yml.template')
|
|
for error_name in ERR_CODES:
|
|
test_name = f'post-42-{error_name}'
|
|
error_code, = ERR_CODES[error_name]
|
|
# On 4.2+, only ShutdownInProgress and InterruptedAtShutdown will
|
|
# clear the pool.
|
|
if error_name in ("ShutdownInProgress", "InterruptedAtShutdown"):
|
|
final_pool_generation = 1
|
|
else:
|
|
final_pool_generation = 0
|
|
data = tmp.format(**locals())
|
|
write_test(test_name, data)
|
|
|
|
|
|
create_stale_tests()
|
|
create_non_stale_tests()
|
|
create_stale_generation_tests()
|
|
create_pre_42_tests()
|
|
create_post_42_tests()
|
|
|
|
print('Running make')
|
|
subprocess.run(f'cd {SOURCE} && make', shell=True, check=True)
|