1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
|
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)
|