File: generate-error-tests.py

package info (click to toggle)
golang-mongodb-mongo-driver 1.8.4%2Bds1-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bookworm-backports
  • size: 18,520 kB
  • sloc: perl: 533; ansic: 491; python: 432; makefile: 187; sh: 72
file content (172 lines) | stat: -rw-r--r-- 5,344 bytes parent folder | download | duplicates (3)
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)