mongo 2.14.1 → 2.15.0.alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (230) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/README.md +4 -1
  4. data/Rakefile +8 -15
  5. data/lib/mongo/auth/aws/conversation.rb +1 -4
  6. data/lib/mongo/auth/base.rb +13 -7
  7. data/lib/mongo/auth/conversation_base.rb +32 -0
  8. data/lib/mongo/auth/cr/conversation.rb +6 -29
  9. data/lib/mongo/auth/gssapi/conversation.rb +4 -15
  10. data/lib/mongo/auth/ldap/conversation.rb +3 -14
  11. data/lib/mongo/auth/sasl_conversation_base.rb +1 -13
  12. data/lib/mongo/auth/scram_conversation_base.rb +7 -34
  13. data/lib/mongo/auth/user/view.rb +16 -9
  14. data/lib/mongo/auth/x509/conversation.rb +4 -25
  15. data/lib/mongo/bulk_write.rb +21 -18
  16. data/lib/mongo/client.rb +82 -6
  17. data/lib/mongo/cluster/reapers/cursor_reaper.rb +6 -2
  18. data/lib/mongo/cluster.rb +19 -2
  19. data/lib/mongo/collection/view/aggregation.rb +1 -1
  20. data/lib/mongo/collection/view/change_stream.rb +1 -1
  21. data/lib/mongo/collection/view/iterable.rb +7 -17
  22. data/lib/mongo/collection/view/map_reduce.rb +2 -2
  23. data/lib/mongo/collection/view/readable.rb +42 -20
  24. data/lib/mongo/collection/view/writable.rb +14 -14
  25. data/lib/mongo/collection.rb +6 -6
  26. data/lib/mongo/cursor.rb +2 -12
  27. data/lib/mongo/database/view.rb +1 -1
  28. data/lib/mongo/database.rb +8 -3
  29. data/lib/mongo/error/bulk_write_error.rb +17 -3
  30. data/lib/mongo/error/internal_driver_error.rb +22 -0
  31. data/lib/mongo/error/operation_failure.rb +21 -2
  32. data/lib/mongo/error/parser.rb +65 -12
  33. data/lib/mongo/error/server_api_conflict.rb +23 -0
  34. data/lib/mongo/error/server_api_not_supported.rb +24 -0
  35. data/lib/mongo/error/unmet_dependency.rb +21 -0
  36. data/lib/mongo/error.rb +9 -1
  37. data/lib/mongo/index/view.rb +21 -11
  38. data/lib/mongo/monitoring/event/server_heartbeat_failed.rb +27 -16
  39. data/lib/mongo/monitoring/event/server_heartbeat_succeeded.rb +26 -15
  40. data/lib/mongo/monitoring.rb +13 -4
  41. data/lib/mongo/operation/collections_info/command.rb +2 -2
  42. data/lib/mongo/operation/collections_info.rb +18 -1
  43. data/lib/mongo/operation/context.rb +99 -0
  44. data/lib/mongo/operation/indexes.rb +15 -1
  45. data/lib/mongo/operation/insert/command.rb +2 -2
  46. data/lib/mongo/operation/insert/legacy.rb +2 -2
  47. data/lib/mongo/operation/insert/op_msg.rb +2 -2
  48. data/lib/mongo/operation/list_collections/result.rb +4 -1
  49. data/lib/mongo/operation/parallel_scan/command.rb +2 -1
  50. data/lib/mongo/operation/result.rb +2 -0
  51. data/lib/mongo/operation/shared/executable.rb +24 -14
  52. data/lib/mongo/operation/shared/executable_no_validate.rb +2 -2
  53. data/lib/mongo/operation/shared/op_msg_or_command.rb +1 -7
  54. data/lib/mongo/operation/shared/op_msg_or_find_command.rb +1 -7
  55. data/lib/mongo/operation/shared/polymorphic_operation.rb +39 -0
  56. data/lib/mongo/operation/shared/read_preference_supported.rb +36 -38
  57. data/lib/mongo/operation/shared/response_handling.rb +23 -23
  58. data/lib/mongo/operation/shared/sessions_supported.rb +15 -5
  59. data/lib/mongo/operation/shared/write.rb +8 -18
  60. data/lib/mongo/operation.rb +2 -2
  61. data/lib/mongo/protocol/compressed.rb +51 -5
  62. data/lib/mongo/protocol/message.rb +20 -2
  63. data/lib/mongo/protocol/msg.rb +38 -13
  64. data/lib/mongo/protocol/query.rb +11 -11
  65. data/lib/mongo/query_cache.rb +30 -0
  66. data/lib/mongo/retryable.rb +1 -1
  67. data/lib/mongo/server/app_metadata.rb +52 -18
  68. data/lib/mongo/server/connection.rb +5 -0
  69. data/lib/mongo/server/connection_base.rb +13 -10
  70. data/lib/mongo/server/connection_pool.rb +6 -2
  71. data/lib/mongo/server/description/features.rb +9 -8
  72. data/lib/mongo/server/description.rb +4 -0
  73. data/lib/mongo/server/monitor/app_metadata.rb +1 -1
  74. data/lib/mongo/server/monitor/connection.rb +9 -10
  75. data/lib/mongo/server/monitor.rb +20 -1
  76. data/lib/mongo/server/pending_connection.rb +24 -6
  77. data/lib/mongo/server/push_monitor.rb +11 -1
  78. data/lib/mongo/server.rb +7 -1
  79. data/lib/mongo/server_selector/secondary_preferred.rb +7 -2
  80. data/lib/mongo/session/session_pool.rb +4 -2
  81. data/lib/mongo/session.rb +2 -2
  82. data/lib/mongo/socket/ssl.rb +8 -0
  83. data/lib/mongo/socket.rb +29 -4
  84. data/lib/mongo/uri/options_mapper.rb +38 -0
  85. data/lib/mongo/utils.rb +15 -0
  86. data/lib/mongo/version.rb +1 -1
  87. data/lib/mongo.rb +23 -0
  88. data/spec/README.md +24 -1
  89. data/spec/integration/auth_spec.rb +25 -15
  90. data/spec/integration/bulk_write_error_message_spec.rb +41 -0
  91. data/spec/integration/change_stream_spec.rb +4 -4
  92. data/spec/integration/command_monitoring_spec.rb +2 -2
  93. data/spec/integration/connection_spec.rb +2 -0
  94. data/spec/integration/docs_examples_spec.rb +8 -1
  95. data/spec/integration/fork_reconnect_spec.rb +4 -1
  96. data/spec/integration/ocsp_verifier_spec.rb +13 -7
  97. data/spec/integration/operation_failure_code_spec.rb +1 -1
  98. data/spec/integration/operation_failure_message_spec.rb +90 -0
  99. data/spec/integration/query_cache_spec.rb +0 -45
  100. data/spec/integration/reconnect_spec.rb +1 -1
  101. data/spec/integration/snappy_compression_spec.rb +25 -0
  102. data/spec/integration/srv_monitoring_spec.rb +1 -1
  103. data/spec/integration/transactions_examples_spec.rb +6 -0
  104. data/spec/integration/zlib_compression_spec.rb +1 -1
  105. data/spec/integration/zstd_compression_spec.rb +26 -0
  106. data/spec/lite_spec_helper.rb +7 -1
  107. data/spec/mongo/address_spec.rb +15 -11
  108. data/spec/mongo/auth/ldap/conversation_spec.rb +1 -1
  109. data/spec/mongo/auth/ldap_spec.rb +5 -1
  110. data/spec/mongo/auth/scram_negotiation_spec.rb +1 -1
  111. data/spec/mongo/auth/scram_spec.rb +1 -1
  112. data/spec/mongo/auth/x509/conversation_spec.rb +3 -3
  113. data/spec/mongo/client_construction_spec.rb +207 -33
  114. data/spec/mongo/client_spec.rb +17 -0
  115. data/spec/mongo/cluster_spec.rb +1 -0
  116. data/spec/mongo/collection/view/explainable_spec.rb +1 -1
  117. data/spec/mongo/collection/view/readable_spec.rb +33 -19
  118. data/spec/mongo/collection_crud_spec.rb +4357 -0
  119. data/spec/mongo/collection_ddl_spec.rb +534 -0
  120. data/spec/mongo/collection_spec.rb +5 -4859
  121. data/spec/mongo/database_spec.rb +66 -4
  122. data/spec/mongo/error/bulk_write_error_spec.rb +3 -3
  123. data/spec/mongo/error/parser_spec.rb +37 -6
  124. data/spec/mongo/index/view_spec.rb +4 -0
  125. data/spec/mongo/monitoring/event/server_heartbeat_failed_spec.rb +1 -1
  126. data/spec/mongo/monitoring/event/server_heartbeat_succeeded_spec.rb +1 -1
  127. data/spec/mongo/operation/aggregate_spec.rb +2 -1
  128. data/spec/mongo/operation/collections_info_spec.rb +4 -1
  129. data/spec/mongo/operation/command_spec.rb +6 -3
  130. data/spec/mongo/operation/create_index_spec.rb +6 -3
  131. data/spec/mongo/operation/create_user_spec.rb +6 -3
  132. data/spec/mongo/operation/delete/bulk_spec.rb +9 -6
  133. data/spec/mongo/operation/delete_spec.rb +11 -7
  134. data/spec/mongo/operation/drop_index_spec.rb +6 -2
  135. data/spec/mongo/operation/find/legacy_spec.rb +3 -1
  136. data/spec/mongo/operation/get_more_spec.rb +3 -1
  137. data/spec/mongo/operation/indexes_spec.rb +5 -1
  138. data/spec/mongo/operation/insert/bulk_spec.rb +10 -7
  139. data/spec/mongo/operation/insert_spec.rb +15 -12
  140. data/spec/mongo/operation/map_reduce_spec.rb +5 -2
  141. data/spec/mongo/operation/read_preference_legacy_spec.rb +19 -9
  142. data/spec/mongo/operation/read_preference_op_msg_spec.rb +3 -3
  143. data/spec/mongo/operation/remove_user_spec.rb +6 -3
  144. data/spec/mongo/operation/result_spec.rb +1 -1
  145. data/spec/mongo/operation/update/bulk_spec.rb +9 -6
  146. data/spec/mongo/operation/update_spec.rb +10 -7
  147. data/spec/mongo/operation/update_user_spec.rb +4 -1
  148. data/spec/mongo/protocol/compressed_spec.rb +26 -12
  149. data/spec/mongo/query_cache_middleware_spec.rb +55 -0
  150. data/spec/mongo/retryable_spec.rb +3 -2
  151. data/spec/mongo/server/app_metadata_shared.rb +7 -33
  152. data/spec/mongo/server/app_metadata_spec.rb +2 -0
  153. data/spec/mongo/server/connection_pool/populator_spec.rb +3 -1
  154. data/spec/mongo/server/connection_pool_spec.rb +1 -1
  155. data/spec/mongo/server/connection_spec.rb +24 -17
  156. data/spec/mongo/server/monitor/connection_spec.rb +17 -7
  157. data/spec/mongo/server/monitor_spec.rb +9 -1
  158. data/spec/mongo/server_selector/secondary_preferred_spec.rb +6 -6
  159. data/spec/mongo/server_spec.rb +15 -2
  160. data/spec/mongo/socket/ssl_spec.rb +40 -0
  161. data/spec/mongo/socket_spec.rb +2 -2
  162. data/spec/mongo/tls_context_hooks_spec.rb +37 -0
  163. data/spec/runners/connection_string.rb +0 -4
  164. data/spec/runners/crud/requirement.rb +40 -3
  165. data/spec/runners/crud/verifier.rb +8 -0
  166. data/spec/runners/transactions/operation.rb +1 -1
  167. data/spec/runners/transactions/test.rb +1 -0
  168. data/spec/runners/unified/assertions.rb +249 -0
  169. data/spec/runners/unified/change_stream_operations.rb +26 -0
  170. data/spec/runners/unified/crud_operations.rb +199 -0
  171. data/spec/runners/unified/ddl_operations.rb +96 -0
  172. data/spec/runners/unified/entity_map.rb +39 -0
  173. data/spec/runners/unified/error.rb +25 -0
  174. data/spec/runners/unified/event_subscriber.rb +91 -0
  175. data/spec/runners/unified/exceptions.rb +21 -0
  176. data/spec/runners/unified/grid_fs_operations.rb +55 -0
  177. data/spec/runners/unified/support_operations.rb +250 -0
  178. data/spec/runners/unified/test.rb +393 -0
  179. data/spec/runners/unified/test_group.rb +28 -0
  180. data/spec/runners/unified/using_hash.rb +31 -0
  181. data/spec/runners/unified.rb +96 -0
  182. data/spec/shared/lib/mrss/cluster_config.rb +0 -3
  183. data/spec/shared/lib/mrss/docker_runner.rb +0 -3
  184. data/spec/shared/lib/mrss/lite_constraints.rb +0 -16
  185. data/spec/shared/lib/mrss/server_version_registry.rb +0 -3
  186. data/spec/shared/lib/mrss/spec_organizer.rb +0 -3
  187. data/spec/shared/shlib/server.sh +1 -1
  188. data/spec/spec_helper.rb +4 -1
  189. data/spec/spec_tests/crud_unified_spec.rb +10 -0
  190. data/spec/spec_tests/data/change_streams/change-streams.yml +0 -1
  191. data/spec/spec_tests/data/crud_unified/estimatedDocumentCount.yml +267 -0
  192. data/spec/spec_tests/data/retryable_reads/estimatedDocumentCount-4.9.yml +60 -0
  193. data/spec/spec_tests/data/retryable_reads/{estimatedDocumentCount.yml → estimatedDocumentCount-pre4.9.yml} +2 -0
  194. data/spec/spec_tests/data/retryable_reads/estimatedDocumentCount-serverErrors-4.9.yml +146 -0
  195. data/spec/spec_tests/data/retryable_reads/{estimatedDocumentCount-serverErrors.yml → estimatedDocumentCount-serverErrors-pre4.9.yml} +2 -0
  196. data/spec/spec_tests/data/retryable_reads/listIndexNames.yml +1 -1
  197. data/spec/spec_tests/data/unified/valid-fail/operation-failure.yml +31 -0
  198. data/spec/spec_tests/data/unified/valid-pass/poc-change-streams.yml +220 -0
  199. data/spec/spec_tests/data/unified/valid-pass/poc-command-monitoring.yml +102 -0
  200. data/spec/spec_tests/data/unified/valid-pass/poc-crud.yml +184 -0
  201. data/spec/spec_tests/data/unified/valid-pass/poc-gridfs.yml +155 -0
  202. data/spec/spec_tests/data/unified/valid-pass/poc-retryable-reads.yml +193 -0
  203. data/spec/spec_tests/data/unified/valid-pass/poc-retryable-writes.yml +210 -0
  204. data/spec/spec_tests/data/unified/valid-pass/poc-sessions.yml +215 -0
  205. data/spec/spec_tests/data/unified/valid-pass/poc-transactions-convenient-api.yml +235 -0
  206. data/spec/spec_tests/data/unified/valid-pass/poc-transactions-mongos-pin-auto.yml +169 -0
  207. data/spec/spec_tests/data/unified/valid-pass/poc-transactions.yml +170 -0
  208. data/spec/spec_tests/data/uri_options/compression-options.yml +1 -1
  209. data/spec/spec_tests/data/versioned_api/crud-api-version-1-strict.yml +416 -0
  210. data/spec/spec_tests/data/versioned_api/crud-api-version-1.yml +409 -0
  211. data/spec/spec_tests/data/versioned_api/runcommand-helper-no-api-version-declared.yml +67 -0
  212. data/spec/spec_tests/data/versioned_api/test-commands-deprecation-errors.yml +47 -0
  213. data/spec/spec_tests/data/versioned_api/test-commands-strict-mode.yml +44 -0
  214. data/spec/spec_tests/data/versioned_api/transaction-handling.yml +180 -0
  215. data/spec/spec_tests/unified_spec.rb +15 -0
  216. data/spec/spec_tests/uri_options_spec.rb +16 -0
  217. data/spec/spec_tests/versioned_api_spec.rb +10 -0
  218. data/spec/support/client_registry.rb +4 -8
  219. data/spec/support/client_registry_macros.rb +4 -4
  220. data/spec/support/common_shortcuts.rb +15 -1
  221. data/spec/support/shared/session.rb +2 -2
  222. data/spec/support/spec_config.rb +42 -11
  223. data/spec/support/utils.rb +64 -3
  224. data.tar.gz.sig +0 -0
  225. metadata +1005 -915
  226. metadata.gz.sig +0 -0
  227. data/lib/mongo/operation/shared/collections_info_or_list_collections.rb +0 -58
  228. data/lib/mongo/operation/shared/op_msg_or_list_indexes_command.rb +0 -47
  229. data/spec/integration/secondary_reads_spec.rb +0 -102
  230. data/spec/support/cluster_config.rb +0 -207
@@ -0,0 +1,91 @@
1
+ require 'support/event_subscriber'
2
+
3
+ module Unified
4
+
5
+ class EventSubscriber < ::EventSubscriber
6
+ def ignore_commands(command_names)
7
+ @ignore_commands = command_names
8
+ end
9
+
10
+ def wanted_events
11
+ all_events.select do |event|
12
+ kind = event.class.name.sub(/.*::/, '').sub('Command', '').downcase.to_sym
13
+ @wanted_events[kind]
14
+ end.select do |event|
15
+ event.command_name != 'configureFailPoint' &&
16
+ if @ignore_commands
17
+ !@ignore_commands.include?(event.command_name)
18
+ else
19
+ true
20
+ end
21
+ end.reject do |event|
22
+ %w(authenticate getnonce saslStart saslContinue).include?(event.command_name)
23
+ end
24
+ end
25
+
26
+ def add_wanted_events(kind)
27
+ @wanted_events ||= {}
28
+ @wanted_events[kind] = true
29
+ end
30
+ end
31
+
32
+ class StoringEventSubscriber
33
+ def initialize(&block)
34
+ @handler = block
35
+ end
36
+
37
+ def started(event)
38
+ @handler.call(
39
+ 'name' => event.class.name.sub(/.*::/, '') + 'Event',
40
+ 'commandName' => event.command_name,
41
+ 'databaseName' => event.database_name,
42
+ 'observedAt' => Time.now.to_f,
43
+ 'address' => event.address.seed,
44
+ 'requestId' => event.request_id,
45
+ 'operationId' => event.operation_id,
46
+ 'connectionId' => event.connection_id,
47
+ )
48
+ end
49
+
50
+ def succeeded(event)
51
+ @handler.call(
52
+ 'name' => event.class.name.sub(/.*::/, '') + 'Event',
53
+ 'commandName' => event.command_name,
54
+ 'duration' => event.duration,
55
+ 'observedAt' => Time.now.to_f,
56
+ 'address' => event.address.seed,
57
+ 'requestId' => event.request_id,
58
+ 'operationId' => event.operation_id,
59
+ )
60
+ end
61
+
62
+ def failed(event)
63
+ @handler.call(
64
+ 'name' => event.class.name.sub(/.*::/, '') + 'Event',
65
+ 'commandName' => event.command_name,
66
+ 'duration' => event.duration,
67
+ 'failure' => event.failure,
68
+ 'observedAt' => Time.now.to_f,
69
+ 'address' => event.address.seed,
70
+ 'requestId' => event.request_id,
71
+ 'operationId' => event.operation_id,
72
+ )
73
+ end
74
+
75
+ def published(event)
76
+ payload = {
77
+ 'name' => event.class.name.sub(/.*::/, '') + 'Event',
78
+ 'observedAt' => Time.now.to_f,
79
+ 'address' => event.address.seed,
80
+ }.tap do |entry|
81
+ if event.respond_to?(:connection_id)
82
+ entry['connectionId'] = event.connection_id
83
+ end
84
+ if event.respond_to?(:reason)
85
+ entry['reason'] = event.reason
86
+ end
87
+ end
88
+ @handler.call(payload)
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,21 @@
1
+ module Unified
2
+
3
+ class Error < StandardError
4
+ end
5
+
6
+ class ResultMismatch < Error
7
+ end
8
+
9
+ class ErrorMismatch < Error
10
+ end
11
+
12
+ class EntityMapOverwriteAttempt < Error
13
+ end
14
+
15
+ class EntityMissing < Error
16
+ end
17
+
18
+ class InvalidTest < Error
19
+ end
20
+
21
+ end
@@ -0,0 +1,55 @@
1
+ module Unified
2
+
3
+ module GridFsOperations
4
+
5
+ def delete(op)
6
+ bucket = entities.get(:bucket, op.use!('object'))
7
+ use_arguments(op) do |args|
8
+ bucket.delete(args.use!('id'))
9
+ end
10
+ end
11
+
12
+ def download(op)
13
+ bucket = entities.get(:bucket, op.use!('object'))
14
+ use_arguments(op) do |args|
15
+ stream = bucket.open_download_stream(args.use!('id'))
16
+ stream.read
17
+ end
18
+ end
19
+
20
+ def upload(op)
21
+ bucket = entities.get(:bucket, op.use!('object'))
22
+ use_arguments(op) do |args|
23
+ opts = {}
24
+ if chunk_size = args.use('chunkSizeBytes')
25
+ opts[:chunk_size] = chunk_size
26
+ end
27
+ contents = transform_contents(args.use!('source'))
28
+ file_id = nil
29
+ bucket.open_upload_stream(args.use!('filename'), **opts) do |stream|
30
+ stream.write(contents)
31
+ file_id = stream.file_id
32
+ end
33
+ file_id
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def transform_contents(contents)
40
+ if Hash === contents
41
+ if contents.length != 1
42
+ raise NotImplementedError, "Wanted hash with one element"
43
+ end
44
+ if contents.keys.first != '$$hexBytes'
45
+ raise NotImplementedError, "$$hexBytes is the only key supported"
46
+ end
47
+
48
+ decode_hex_bytes(contents.values.first)
49
+ else
50
+ contents
51
+ end
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,250 @@
1
+ module Unified
2
+
3
+ module SupportOperations
4
+
5
+ def run_command(op)
6
+ database = entities.get(:database, op.use!('object'))
7
+
8
+ use_arguments(op) do |args|
9
+ args.use!('commandName')
10
+
11
+ cmd = args.use!('command')
12
+
13
+ database.command(cmd)
14
+ end
15
+ end
16
+
17
+ def fail_point(op)
18
+ consume_test_runner(op)
19
+ use_arguments(op) do |args|
20
+ client = entities.get(:client, args.use!('client'))
21
+ client.command(args.use('failPoint'))
22
+ end
23
+ end
24
+
25
+ def targeted_fail_point(op)
26
+ consume_test_runner(op)
27
+ use_arguments(op) do |args|
28
+ session = args.use!('session')
29
+ session = entities.get(:session, session)
30
+ unless session.pinned_server
31
+ raise ArgumentError, 'Targeted fail point requires session to be pinned to a server'
32
+ end
33
+
34
+ client = ClusterTools.instance.direct_client(session.pinned_server.address,
35
+ database: 'admin')
36
+ client.command(fp = args.use!('failPoint'))
37
+ args.clear
38
+
39
+ $disable_fail_points ||= []
40
+ $disable_fail_points << [
41
+ fp,
42
+ session.pinned_server.address,
43
+ ]
44
+ end
45
+ end
46
+
47
+ def end_session(op)
48
+ session = entities.get(:session, op.use!('object'))
49
+ session.end_session
50
+ end
51
+
52
+ def assert_session_dirty(op)
53
+ consume_test_runner(op)
54
+ # https://jira.mongodb.org/browse/RUBY-1813
55
+ true
56
+ end
57
+
58
+ def assert_session_not_dirty(op)
59
+ consume_test_runner(op)
60
+ use_arguments(op) do |args|
61
+ session = entities.get(:session, args.use!('session'))
62
+ # https://jira.mongodb.org/browse/RUBY-1813
63
+ true
64
+ end
65
+ end
66
+
67
+ def assert_same_lsid_on_last_two_commands(op, expected: true)
68
+ consume_test_runner(op)
69
+ use_arguments(op) do |args|
70
+ client = entities.get(:client, args.use!('client'))
71
+ subscriber = @subscribers.fetch(client)
72
+ unless subscriber.started_events.length >= 2
73
+ raise Error::ResultMismatch, "Must have at least 2 events, have #{subscriber.started_events.length}"
74
+ end
75
+ lsids = subscriber.started_events[-2...-1].map do |cmd|
76
+ cmd.command.fetch('lsid')
77
+ end
78
+ if expected
79
+ unless lsids.first == lsids.last
80
+ raise Error::ResultMismatch, "lsids differ but they were expected to be the same"
81
+ end
82
+ else
83
+ if lsids.first == lsids.last
84
+ raise Error::ResultMismatch, "lsids are the same but they were expected to be different"
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+ def assert_different_lsid_on_last_two_commands(op)
91
+ assert_same_lsid_on_last_two_commands(op, expected: false)
92
+ end
93
+
94
+ def start_transaction(op)
95
+ $klil_transactions = true
96
+ session = entities.get(:session, op.use!('object'))
97
+ assert_no_arguments(op)
98
+ session.start_transaction
99
+ end
100
+
101
+ def assert_session_transaction_state(op)
102
+ consume_test_runner(op)
103
+ use_arguments(op) do |args|
104
+ session = entities.get(:session, args.use!('session'))
105
+ state = args.use!('state')
106
+ unless session.send("#{state}_transaction?")
107
+ raise Error::ResultMismatch, "Expected session to have state #{state}"
108
+ end
109
+ end
110
+ end
111
+
112
+ def commit_transaction(op)
113
+ session = entities.get(:session, op.use!('object'))
114
+ assert_no_arguments(op)
115
+ session.commit_transaction
116
+ end
117
+
118
+ def abort_transaction(op)
119
+ session = entities.get(:session, op.use!('object'))
120
+ assert_no_arguments(op)
121
+ session.abort_transaction
122
+ end
123
+
124
+ def with_transaction(op)
125
+ $kill_transactions = true
126
+ session = entities.get(:session, op.use!('object'))
127
+ use_arguments(op) do |args|
128
+ ops = args.use!('callback')
129
+
130
+ if args.empty?
131
+ opts = {}
132
+ else
133
+ opts = ::Utils.underscore_hash(args)
134
+ if value = opts[:read_concern]&.[](:level)
135
+ opts[:read_concern][:level] = value.to_sym
136
+ end
137
+ args.clear
138
+ end
139
+
140
+ session.with_transaction(**opts) do
141
+ execute_operations(ops)
142
+ end
143
+ end
144
+ end
145
+
146
+ def assert_session_pinned(op, state = true)
147
+ consume_test_runner(op)
148
+ use_arguments(op) do |args|
149
+ session = entities.get(:session, args.use!('session'))
150
+
151
+ if state
152
+ unless session.pinned_server
153
+ raise Error::ResultMismatch, 'Expected session to be pinned but it is not'
154
+ end
155
+ else
156
+ if session.pinned_server
157
+ raise Error::ResultMismatch, 'Expected session to be not pinned but it is'
158
+ end
159
+ end
160
+ end
161
+ end
162
+
163
+ def assert_session_unpinned(op)
164
+ assert_session_pinned(op, false)
165
+ end
166
+
167
+ def _loop(op)
168
+ consume_test_runner(op)
169
+ use_arguments(op) do |args|
170
+ ops = args.use!('operations')
171
+
172
+ if store_errors = args.use('storeErrorsAsEntity')
173
+ entities.set(:error_list, store_errors, [])
174
+ end
175
+
176
+ if store_failures = args.use('storeFailuresAsEntity')
177
+ entities.set(:failure_list, store_failures, [])
178
+ end
179
+
180
+ store_iterations = args.use('storeIterationsAsEntity')
181
+ iterations = 0
182
+ store_successes = args.use('storeSuccessesAsEntity')
183
+ successes = 0
184
+
185
+ loop do
186
+ break if stop?
187
+ begin
188
+ ops.map(&:dup).each do |op|
189
+ execute_operation(op)
190
+ successes += 1
191
+ end
192
+ rescue Unified::Error::ResultMismatch => e
193
+ if store_failures
194
+ STDERR.puts "Failure: #{e.class}: #{e}"
195
+ entities.get(:failure_list, store_failures) << {
196
+ error: "#{e.class}: #{e}",
197
+ time: Time.now.to_f,
198
+ }
199
+ elsif store_errors
200
+ STDERR.puts "Failure: #{e.class}: #{e} (reporting as error)"
201
+ entities.get(:error_list, store_errors) << {
202
+ error: "#{e.class}: #{e}",
203
+ time: Time.now.to_f,
204
+ }
205
+ else
206
+ raise
207
+ end
208
+ rescue => e
209
+ if store_errors
210
+ STDERR.puts "Error: #{e.class}: #{e}"
211
+ entities.get(:error_list, store_errors) << {
212
+ error: "#{e.class}: #{e}",
213
+ observedAt: Time.now.to_f,
214
+ }
215
+ else
216
+ raise
217
+ end
218
+ end
219
+ iterations += 1
220
+ end
221
+
222
+ if store_iterations
223
+ entities.set(:iteration_count, store_iterations, iterations)
224
+ end
225
+ if store_successes
226
+ entities.set(:success_count, store_successes, successes)
227
+ end
228
+ end
229
+ end
230
+
231
+ private
232
+
233
+ def assert_no_arguments(op)
234
+ if op.key?('arguments')
235
+ raise NotimplementedError, "Arguments are not allowed"
236
+ end
237
+ end
238
+
239
+ def consume_test_runner(op)
240
+ v = op.use!('object')
241
+ unless v == 'testRunner'
242
+ raise NotImplementedError, 'Expected object to be testRunner'
243
+ end
244
+ end
245
+
246
+ def decode_hex_bytes(value)
247
+ value.scan(/../).map { |hex| hex.to_i(16).chr }.join
248
+ end
249
+ end
250
+ end