|
| 1 | +from collections import namedtuple |
| 2 | +from jinja2 import Template |
| 3 | +import os |
| 4 | +import sys |
| 5 | + |
| 6 | +Operation = namedtuple( |
| 7 | + 'Operation', ['operation_name', 'command_name', 'object', 'arguments']) |
| 8 | + |
| 9 | +CLIENT_OPERATIONS = [ |
| 10 | + Operation('listDatabases', 'listDatabases', 'client', ['filter: {}']), |
| 11 | + Operation('listDatabaseNames', 'listDatabases', 'client', []), |
| 12 | + Operation('createChangeStream', 'aggregate', 'client', ['pipeline: []']) |
| 13 | +] |
| 14 | + |
| 15 | +RUN_COMMAND_ARGUMENTS = '''command: { ping: 1 } |
| 16 | + commandName: ping''' |
| 17 | + |
| 18 | +DB_OPERATIONS = [ |
| 19 | + Operation('aggregate', 'aggregate', 'database', [ |
| 20 | + 'pipeline: [ { $listLocalSessions: {} }, { $limit: 1 } ]']), |
| 21 | + Operation('listCollections', 'listCollections', |
| 22 | + 'database', ['filter: {}']), |
| 23 | + Operation('listCollectionNames', 'listCollections', |
| 24 | + 'database', ['filter: {}']), # Optional. |
| 25 | + Operation('runCommand', 'ping', 'database', [RUN_COMMAND_ARGUMENTS]), |
| 26 | + Operation('createChangeStream', 'aggregate', 'database', ['pipeline: []']) |
| 27 | +] |
| 28 | + |
| 29 | +INSERT_MANY_ARGUMENTS = '''documents: |
| 30 | + - { _id: 2, x: 22 }''' |
| 31 | + |
| 32 | +BULK_WRITE_ARGUMENTS = '''requests: |
| 33 | + - insertOne: |
| 34 | + document: { _id: 2, x: 22 }''' |
| 35 | + |
| 36 | +COLLECTION_READ_OPERATIONS = [ |
| 37 | + Operation('aggregate', 'aggregate', 'collection', ['pipeline: []']), |
| 38 | + # Operation('count', 'count', 'collection', ['filter: {}']), # Deprecated. |
| 39 | + Operation('countDocuments', 'aggregate', 'collection', ['filter: {}']), |
| 40 | + Operation('estimatedDocumentCount', 'count', 'collection', []), |
| 41 | + Operation('distinct', 'distinct', 'collection', |
| 42 | + ['fieldName: x', 'filter: {}']), |
| 43 | + Operation('find', 'find', 'collection', ['filter: {}']), |
| 44 | + Operation('findOne', 'find', 'collection', ['filter: {}']), # Optional. |
| 45 | + Operation('listIndexes', 'listIndexes', 'collection', []), |
| 46 | + Operation('listIndexNames', 'listIndexes', 'collection', []), # Optional. |
| 47 | + Operation('createChangeStream', 'aggregate', |
| 48 | + 'collection', ['pipeline: []']), |
| 49 | +] |
| 50 | + |
| 51 | +COLLECTION_WRITE_OPERATIONS = [ |
| 52 | + Operation('insertOne', 'insert', 'collection', |
| 53 | + ['document: { _id: 2, x: 22 }']), |
| 54 | + Operation('insertMany', 'insert', 'collection', [INSERT_MANY_ARGUMENTS]), |
| 55 | + Operation('deleteOne', 'delete', 'collection', ['filter: {}']), |
| 56 | + Operation('deleteMany', 'delete', 'collection', ['filter: {}']), |
| 57 | + Operation('replaceOne', 'update', 'collection', [ |
| 58 | + 'filter: {}', 'replacement: { x: 22 }']), |
| 59 | + Operation('updateOne', 'update', 'collection', [ |
| 60 | + 'filter: {}', 'update: { $set: { x: 22 } }']), |
| 61 | + Operation('updateMany', 'update', 'collection', [ |
| 62 | + 'filter: {}', 'update: { $set: { x: 22 } }']), |
| 63 | + Operation('findOneAndDelete', 'findAndModify', |
| 64 | + 'collection', ['filter: {}']), |
| 65 | + Operation('findOneAndReplace', 'findAndModify', 'collection', |
| 66 | + ['filter: {}', 'replacement: { x: 22 }']), |
| 67 | + Operation('findOneAndUpdate', 'findAndModify', 'collection', |
| 68 | + ['filter: {}', 'update: { $set: { x: 22 } }']), |
| 69 | + Operation('bulkWrite', 'insert', 'collection', [BULK_WRITE_ARGUMENTS]), |
| 70 | + Operation('createIndex', 'createIndexes', 'collection', |
| 71 | + ['keys: { x: 11 }', 'name: "x_11"']), |
| 72 | + Operation('dropIndex', 'dropIndexes', 'collection', ['name: "x_11"']), |
| 73 | + Operation('dropIndexes', 'dropIndexes', 'collection', []), |
| 74 | +] |
| 75 | + |
| 76 | +COLLECTION_OPERATIONS = COLLECTION_READ_OPERATIONS + COLLECTION_WRITE_OPERATIONS |
| 77 | + |
| 78 | +# Session and GridFS operations are generally tested in other files, so they're not included in the list of all |
| 79 | +# operations. Individual generation functions can choose to include them if needed. |
| 80 | +OPERATIONS = CLIENT_OPERATIONS + DB_OPERATIONS + COLLECTION_OPERATIONS |
| 81 | + |
| 82 | +RETRYABLE_READ_OPERATIONS = [op for op in OPERATIONS if op.operation_name in |
| 83 | + ['find', |
| 84 | + 'findOne', |
| 85 | + 'aggregate', |
| 86 | + 'distinct', |
| 87 | + 'count', |
| 88 | + 'estimatedDocumentCount', |
| 89 | + 'countDocuments', |
| 90 | + 'createChangeStream', |
| 91 | + 'listDatabases', |
| 92 | + 'listDatabaseNames', |
| 93 | + 'listCollections', |
| 94 | + 'listCollectionNames', |
| 95 | + 'listIndexes', |
| 96 | + 'listIndexNames', |
| 97 | + ] |
| 98 | + ] |
| 99 | + |
| 100 | +RETRYABLE_WRITE_OPERATIONS = [op for op in OPERATIONS if op.operation_name in |
| 101 | + ['insertOne', |
| 102 | + 'updateOne', |
| 103 | + 'deleteOne', |
| 104 | + 'replaceOne', |
| 105 | + 'findOneAndDelete', |
| 106 | + 'findOneAndUpdate', |
| 107 | + 'findOneAndReplace', |
| 108 | + 'insertMany', |
| 109 | + 'bulkWrite', |
| 110 | + ] |
| 111 | + ] |
| 112 | + |
| 113 | + |
| 114 | +# ./source/etc |
| 115 | +DIR = os.path.dirname(os.path.realpath(__file__)) |
| 116 | + |
| 117 | + |
| 118 | +def get_template(file, templates_dir): |
| 119 | + path = f'{templates_dir}/{file}.yml.template' |
| 120 | + return Template(open(path, 'r').read()) |
| 121 | + |
| 122 | + |
| 123 | +def write_yaml(file, template, tests_dir, injections): |
| 124 | + rendered = template.render(**injections) |
| 125 | + path = f'{tests_dir}/{file}.yml' |
| 126 | + open(path, 'w').write(rendered) |
| 127 | + |
| 128 | + |
| 129 | +def generate(name, templates_dir, tests_dir, operations): |
| 130 | + template = get_template(name, templates_dir) |
| 131 | + injections = { |
| 132 | + 'operations': operations, |
| 133 | + } |
| 134 | + write_yaml(name, template, tests_dir, injections) |
| 135 | + |
| 136 | + |
| 137 | +def generate_retryable_reads_handshake_error_tests(): |
| 138 | + # ./source/retryable-reads/tests/etc/templates |
| 139 | + templates_dir = f'{os.path.dirname(DIR)}/retryable-reads/tests/etc/templates' |
| 140 | + # ./source/retryable-reads/tests/unified |
| 141 | + tests_dir = f'{os.path.dirname(DIR)}/retryable-reads/tests/unified' |
| 142 | + generate('handshakeError', templates_dir, |
| 143 | + tests_dir, RETRYABLE_READ_OPERATIONS) |
| 144 | + |
| 145 | + |
| 146 | +def generate_retryable_writes_handshake_error_tests(): |
| 147 | + # ./source/retryable-writes/tests/etc/templates |
| 148 | + templates_dir = f'{os.path.dirname(DIR)}/retryable-writes/tests/etc/templates' |
| 149 | + # ./source/retryable-writes/tests/unified |
| 150 | + tests_dir = f'{os.path.dirname(DIR)}/retryable-writes/tests/unified' |
| 151 | + generate('handshakeError', templates_dir, |
| 152 | + tests_dir, RETRYABLE_WRITE_OPERATIONS) |
| 153 | + |
| 154 | + |
| 155 | +generate_retryable_reads_handshake_error_tests() |
| 156 | +generate_retryable_writes_handshake_error_tests() |
0 commit comments