mongo 2.19.1 → 2.19.3
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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/lib/mongo/collection/view/iterable.rb +15 -0
- data/lib/mongo/collection/view.rb +1 -0
- data/lib/mongo/collection.rb +23 -1
- data/lib/mongo/operation/create_search_indexes/op_msg.rb +31 -0
- data/lib/mongo/operation/create_search_indexes.rb +15 -0
- data/lib/mongo/operation/drop_search_index/op_msg.rb +33 -0
- data/lib/mongo/operation/drop_search_index.rb +15 -0
- data/lib/mongo/operation/shared/specifiable.rb +7 -0
- data/lib/mongo/operation/update_search_index/op_msg.rb +34 -0
- data/lib/mongo/operation/update_search_index.rb +15 -0
- data/lib/mongo/operation.rb +3 -0
- data/lib/mongo/search_index/view.rb +232 -0
- data/lib/mongo/version.rb +1 -1
- data/lib/mongo.rb +1 -0
- data/spec/atlas/atlas_connectivity_spec.rb +1 -5
- data/spec/atlas/operations_spec.rb +1 -5
- data/spec/integration/find_options_spec.rb +227 -0
- data/spec/integration/search_indexes_prose_spec.rb +168 -0
- data/spec/lite_spec_helper.rb +32 -10
- data/spec/runners/unified/search_index_operations.rb +63 -0
- data/spec/runners/unified/test.rb +3 -1
- data/spec/spec_helper.rb +1 -1
- data/spec/spec_tests/data/index_management/createSearchIndex.yml +62 -0
- data/spec/spec_tests/data/index_management/createSearchIndexes.yml +83 -0
- data/spec/spec_tests/data/index_management/dropSearchIndex.yml +42 -0
- data/spec/spec_tests/data/index_management/listSearchIndexes.yml +85 -0
- data/spec/spec_tests/data/index_management/updateSearchIndex.yml +45 -0
- data/spec/spec_tests/index_management_unified_spec.rb +13 -0
- data/spec/support/faas/app/aws_lambda/mongodb/Gemfile.lock +19 -0
- data/spec/support/spec_config.rb +5 -0
- data.tar.gz.sig +0 -0
- metadata +1277 -1250
- metadata.gz.sig +0 -0
@@ -0,0 +1,227 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe 'Find operation options' do
|
6
|
+
require_mri
|
7
|
+
require_no_auth
|
8
|
+
min_server_fcv '4.4'
|
9
|
+
|
10
|
+
let(:subscriber) { Mrss::EventSubscriber.new }
|
11
|
+
|
12
|
+
let(:seeds) do
|
13
|
+
[ SpecConfig.instance.addresses.first ]
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:client_options) do
|
17
|
+
{}
|
18
|
+
end
|
19
|
+
|
20
|
+
let(:collection_options) do
|
21
|
+
{}
|
22
|
+
end
|
23
|
+
|
24
|
+
let(:client) do
|
25
|
+
ClientRegistry.instance.new_local_client(
|
26
|
+
seeds,
|
27
|
+
SpecConfig.instance.test_options
|
28
|
+
.merge(database: SpecConfig.instance.test_db)
|
29
|
+
.merge(client_options)
|
30
|
+
).tap do |client|
|
31
|
+
client.subscribe(Mongo::Monitoring::COMMAND, subscriber)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
let(:collection) do
|
36
|
+
client['find_options', collection_options]
|
37
|
+
end
|
38
|
+
|
39
|
+
let(:find_command) do
|
40
|
+
subscriber.started_events.find { |cmd| cmd.command_name == 'find' }
|
41
|
+
end
|
42
|
+
|
43
|
+
let(:should_create_collection) { true }
|
44
|
+
|
45
|
+
before do
|
46
|
+
client['find_options'].drop
|
47
|
+
collection.create if should_create_collection
|
48
|
+
collection.insert_many([ { a: 1 }, { a: 2 }, { a: 3 } ])
|
49
|
+
end
|
50
|
+
|
51
|
+
describe 'collation' do
|
52
|
+
let(:client_options) do
|
53
|
+
{}
|
54
|
+
end
|
55
|
+
|
56
|
+
let(:collation) do
|
57
|
+
{ 'locale' => 'en_US' }
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'when defined on the collection' do
|
61
|
+
let(:collection_options) do
|
62
|
+
{ collation: collation }
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'uses the collation defined on the collection' do
|
66
|
+
collection.find.to_a
|
67
|
+
expect(find_command.command['collation']).to be_nil
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'when defined on the operation' do
|
72
|
+
let(:collection_options) do
|
73
|
+
{}
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'uses the collation defined on the collection' do
|
77
|
+
collection.find({}, collation: collation).to_a
|
78
|
+
expect(find_command.command['collation']).to eq(collation)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'when defined on both collection and operation' do
|
83
|
+
let(:collection_options) do
|
84
|
+
{ 'locale' => 'de_AT' }
|
85
|
+
end
|
86
|
+
|
87
|
+
let(:should_create_collection) { false }
|
88
|
+
|
89
|
+
it 'uses the collation defined on the collection' do
|
90
|
+
collection.find({}, collation: collation).to_a
|
91
|
+
expect(find_command.command['collation']).to eq(collation)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe 'read concern' do
|
97
|
+
context 'when defined on the client' do
|
98
|
+
let(:client_options) do
|
99
|
+
{ read_concern: { level: :local } }
|
100
|
+
end
|
101
|
+
|
102
|
+
let(:collection_options) do
|
103
|
+
{}
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'uses the read concern defined on the client' do
|
107
|
+
collection.find.to_a
|
108
|
+
expect(find_command.command['readConcern']).to eq('level' => 'local')
|
109
|
+
end
|
110
|
+
|
111
|
+
context 'when defined on the collection' do
|
112
|
+
let(:collection_options) do
|
113
|
+
{ read_concern: { level: :majority } }
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'uses the read concern defined on the collection' do
|
117
|
+
collection.find.to_a
|
118
|
+
expect(find_command.command['readConcern']).to eq('level' => 'majority')
|
119
|
+
end
|
120
|
+
|
121
|
+
context 'when defined on the operation' do
|
122
|
+
let(:operation_read_concern) do
|
123
|
+
{ level: :available }
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'uses the read concern defined on the operation' do
|
127
|
+
collection.find({}, read_concern: operation_read_concern).to_a
|
128
|
+
expect(find_command.command['readConcern']).to eq('level' => 'available')
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
context 'when defined on the operation' do
|
134
|
+
let(:collection_options) do
|
135
|
+
{}
|
136
|
+
end
|
137
|
+
|
138
|
+
let(:operation_read_concern) do
|
139
|
+
{ level: :available }
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'uses the read concern defined on the operation' do
|
143
|
+
collection.find({}, read_concern: operation_read_concern).to_a
|
144
|
+
expect(find_command.command['readConcern']).to eq('level' => 'available')
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
context 'when defined on the collection' do
|
150
|
+
let(:client_options) do
|
151
|
+
{}
|
152
|
+
end
|
153
|
+
|
154
|
+
let(:collection_options) do
|
155
|
+
{ read_concern: { level: :majority } }
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'uses the read concern defined on the collection' do
|
159
|
+
collection.find.to_a
|
160
|
+
expect(find_command.command['readConcern']).to eq('level' => 'majority')
|
161
|
+
end
|
162
|
+
|
163
|
+
context 'when defined on the operation' do
|
164
|
+
let(:operation_read_concern) do
|
165
|
+
{ level: :available }
|
166
|
+
end
|
167
|
+
|
168
|
+
it 'uses the read concern defined on the operation' do
|
169
|
+
collection.find({}, read_concern: operation_read_concern).to_a
|
170
|
+
expect(find_command.command['readConcern']).to eq('level' => 'available')
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
describe 'read preference' do
|
177
|
+
require_topology :replica_set
|
178
|
+
|
179
|
+
context 'when defined on the client' do
|
180
|
+
let(:client_options) do
|
181
|
+
{ read: { mode: :secondary } }
|
182
|
+
end
|
183
|
+
|
184
|
+
let(:collection_options) do
|
185
|
+
{}
|
186
|
+
end
|
187
|
+
|
188
|
+
it 'uses the read preference defined on the client' do
|
189
|
+
collection.find.to_a
|
190
|
+
expect(find_command.command['$readPreference']).to eq('mode' => 'secondary')
|
191
|
+
end
|
192
|
+
|
193
|
+
context 'when defined on the collection' do
|
194
|
+
let(:collection_options) do
|
195
|
+
{ read: { mode: :secondary_preferred } }
|
196
|
+
end
|
197
|
+
|
198
|
+
it 'uses the read concern defined on the collection' do
|
199
|
+
collection.find.to_a
|
200
|
+
expect(find_command.command['$readPreference']).to eq('mode' => 'secondaryPreferred')
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
describe 'cursor type' do
|
207
|
+
let(:collection_options) do
|
208
|
+
{ capped: true, size: 1000 }
|
209
|
+
end
|
210
|
+
|
211
|
+
context 'when cursor type is :tailable' do
|
212
|
+
it 'sets the cursor type to tailable' do
|
213
|
+
collection.find({}, cursor_type: :tailable).first
|
214
|
+
expect(find_command.command['tailable']).to be true
|
215
|
+
expect(find_command.command['awaitData']).to be_falsey
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
context 'when cursor type is :tailable_await' do
|
220
|
+
it 'sets the cursor type to tailable' do
|
221
|
+
collection.find({}, cursor_type: :tailable_await).first
|
222
|
+
expect(find_command.command['tailable']).to be true
|
223
|
+
expect(find_command.command['awaitData']).to be true
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
class SearchIndexHelper
|
6
|
+
attr_reader :client, :collection_name
|
7
|
+
|
8
|
+
def initialize(client)
|
9
|
+
@client = client
|
10
|
+
|
11
|
+
# https://github.com/mongodb/specifications/blob/master/source/index-management/tests/README.rst#id4
|
12
|
+
# "...each test uses a randomly generated collection name. Drivers may
|
13
|
+
# generate this collection name however they like, but a suggested
|
14
|
+
# implementation is a hex representation of an ObjectId..."
|
15
|
+
@collection_name = BSON::ObjectId.new.to_s
|
16
|
+
end
|
17
|
+
|
18
|
+
# `soft_create` means to create the collection object without forcing it to
|
19
|
+
# be created in the database.
|
20
|
+
def collection(soft_create: false)
|
21
|
+
@collection ||= client.database[collection_name].tap do |collection|
|
22
|
+
collection.create unless soft_create
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Wait for all of the indexes with the given names to be ready; then return
|
27
|
+
# the list of index definitions corresponding to those names.
|
28
|
+
def wait_for(*names, &condition)
|
29
|
+
timeboxed_wait do
|
30
|
+
result = collection.search_indexes
|
31
|
+
return filter_results(result, names) if names.all? { |name| ready?(result, name, &condition) }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Wait until all of the indexes with the given names are absent from the
|
36
|
+
# search index list.
|
37
|
+
def wait_for_absense_of(*names)
|
38
|
+
names.each do |name|
|
39
|
+
timeboxed_wait do
|
40
|
+
break if collection.search_indexes(name: name).empty?
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def timeboxed_wait(step: 5, max: 300)
|
48
|
+
start = Mongo::Utils.monotonic_time
|
49
|
+
|
50
|
+
loop do
|
51
|
+
yield
|
52
|
+
|
53
|
+
sleep step
|
54
|
+
raise Timeout::Error, 'wait took too long' if Mongo::Utils.monotonic_time - start > max
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Returns true if the list of search indexes includes one with the given name,
|
59
|
+
# which is ready to be queried.
|
60
|
+
def ready?(list, name, &condition)
|
61
|
+
condition ||= ->(index) { index['queryable'] }
|
62
|
+
list.any? { |index| index['name'] == name && condition[index] }
|
63
|
+
end
|
64
|
+
|
65
|
+
def filter_results(result, names)
|
66
|
+
result.select { |index| names.include?(index['name']) }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe 'Mongo::Collection#search_indexes prose tests' do
|
71
|
+
# https://github.com/mongodb/specifications/blob/master/source/index-management/tests/README.rst#id5
|
72
|
+
# "These tests must run against an Atlas cluster with a 7.0+ server."
|
73
|
+
require_atlas
|
74
|
+
|
75
|
+
let(:client) do
|
76
|
+
Mongo::Client.new(
|
77
|
+
ENV['ATLAS_URI'],
|
78
|
+
database: SpecConfig.instance.test_db,
|
79
|
+
ssl: true,
|
80
|
+
ssl_verify: true
|
81
|
+
)
|
82
|
+
end
|
83
|
+
|
84
|
+
let(:helper) { SearchIndexHelper.new(client) }
|
85
|
+
|
86
|
+
let(:name) { 'test-search-index' }
|
87
|
+
let(:definition) { { 'mappings' => { 'dynamic' => false } } }
|
88
|
+
let(:create_index) { helper.collection.search_indexes.create_one(definition, name: name) }
|
89
|
+
|
90
|
+
# Case 1: Driver can successfully create and list search indexes
|
91
|
+
context 'when creating and listing search indexes' do
|
92
|
+
let(:index) { helper.wait_for(name).first }
|
93
|
+
|
94
|
+
it 'succeeds' do
|
95
|
+
expect(create_index).to be == name
|
96
|
+
expect(index['latestDefinition']).to be == definition
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Case 2: Driver can successfully create multiple indexes in batch
|
101
|
+
context 'when creating multiple indexes in batch' do
|
102
|
+
let(:specs) do
|
103
|
+
[
|
104
|
+
{ 'name' => 'test-search-index-1', 'definition' => definition },
|
105
|
+
{ 'name' => 'test-search-index-2', 'definition' => definition }
|
106
|
+
]
|
107
|
+
end
|
108
|
+
|
109
|
+
let(:names) { specs.map { |spec| spec['name'] } }
|
110
|
+
let(:create_indexes) { helper.collection.search_indexes.create_many(specs) }
|
111
|
+
|
112
|
+
let(:indexes) { helper.wait_for(*names) }
|
113
|
+
|
114
|
+
let(:index1) { indexes[0] }
|
115
|
+
let(:index2) { indexes[1] }
|
116
|
+
|
117
|
+
it 'succeeds' do
|
118
|
+
expect(create_indexes).to be == names
|
119
|
+
expect(index1['latestDefinition']).to be == specs[0]['definition']
|
120
|
+
expect(index2['latestDefinition']).to be == specs[1]['definition']
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# Case 3: Driver can successfully drop search indexes
|
125
|
+
context 'when dropping search indexes' do
|
126
|
+
it 'succeeds' do
|
127
|
+
expect(create_index).to be == name
|
128
|
+
helper.wait_for(name)
|
129
|
+
|
130
|
+
helper.collection.search_indexes.drop_one(name: name)
|
131
|
+
|
132
|
+
expect { helper.wait_for_absense_of(name) }.not_to raise_error
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Case 4: Driver can update a search index
|
137
|
+
context 'when updating search indexes' do
|
138
|
+
let(:new_definition) { { 'mappings' => { 'dynamic' => true } } }
|
139
|
+
|
140
|
+
let(:index) do
|
141
|
+
helper
|
142
|
+
.wait_for(name) { |idx| idx['queryable'] && idx['status'] == 'READY' }
|
143
|
+
.first
|
144
|
+
end
|
145
|
+
|
146
|
+
# rubocop:disable RSpec/ExampleLength
|
147
|
+
it 'succeeds' do
|
148
|
+
expect(create_index).to be == name
|
149
|
+
helper.wait_for(name)
|
150
|
+
|
151
|
+
expect do
|
152
|
+
helper.collection.search_indexes.update_one(new_definition, name: name)
|
153
|
+
end.not_to raise_error
|
154
|
+
|
155
|
+
expect(index['latestDefinition']).to be == new_definition
|
156
|
+
end
|
157
|
+
# rubocop:enable RSpec/ExampleLength
|
158
|
+
end
|
159
|
+
|
160
|
+
# Case 5: dropSearchIndex suppresses namespace not found errors
|
161
|
+
context 'when dropping a non-existent search index' do
|
162
|
+
it 'ignores `namespace not found` errors' do
|
163
|
+
collection = helper.collection(soft_create: true)
|
164
|
+
expect { collection.search_indexes.drop_one(name: name) }
|
165
|
+
.not_to raise_error
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
data/spec/lite_spec_helper.rb
CHANGED
@@ -106,6 +106,31 @@ Mrss.patch_mongo_for_session_registry
|
|
106
106
|
|
107
107
|
class ExampleTimeout < StandardError; end
|
108
108
|
|
109
|
+
STANDARD_TIMEOUTS = {
|
110
|
+
stress: 210,
|
111
|
+
jruby: 90,
|
112
|
+
default: 45,
|
113
|
+
}.freeze
|
114
|
+
|
115
|
+
def timeout_type
|
116
|
+
if ENV['EXAMPLE_TIMEOUT'].to_i > 0
|
117
|
+
:custom
|
118
|
+
elsif %w(1 true yes).include?(ENV['STRESS']&.downcase)
|
119
|
+
:stress
|
120
|
+
elsif BSON::Environment.jruby?
|
121
|
+
:jruby
|
122
|
+
else
|
123
|
+
:default
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def example_timeout_seconds
|
128
|
+
STANDARD_TIMEOUTS.fetch(
|
129
|
+
timeout_type,
|
130
|
+
(ENV['EXAMPLE_TIMEOUT'] || STANDARD_TIMEOUTS[:default]).to_i
|
131
|
+
)
|
132
|
+
end
|
133
|
+
|
109
134
|
RSpec.configure do |config|
|
110
135
|
config.extend(CommonShortcuts::ClassMethods)
|
111
136
|
config.include(CommonShortcuts::InstanceMethods)
|
@@ -123,6 +148,12 @@ RSpec.configure do |config|
|
|
123
148
|
end
|
124
149
|
end
|
125
150
|
|
151
|
+
def require_atlas
|
152
|
+
before do
|
153
|
+
skip 'Set ATLAS_URI in environment to run atlas tests' if ENV['ATLAS_URI'].nil?
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
126
157
|
if SpecConfig.instance.ci?
|
127
158
|
SdamFormatterIntegration.subscribe
|
128
159
|
config.add_formatter(JsonExtFormatter, File.join(File.dirname(__FILE__), '../tmp/rspec.json'))
|
@@ -141,16 +172,7 @@ RSpec.configure do |config|
|
|
141
172
|
# Tests should take under 10 seconds ideally but it seems
|
142
173
|
# we have some that run for more than 10 seconds in CI.
|
143
174
|
config.around(:each) do |example|
|
144
|
-
timeout
|
145
|
-
210
|
146
|
-
else
|
147
|
-
if BSON::Environment.jruby?
|
148
|
-
90
|
149
|
-
else
|
150
|
-
45
|
151
|
-
end
|
152
|
-
end
|
153
|
-
TimeoutInterrupt.timeout(timeout, ExampleTimeout) do
|
175
|
+
TimeoutInterrupt.timeout(example_timeout_seconds, ExampleTimeout) do
|
154
176
|
example.run
|
155
177
|
end
|
156
178
|
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Unified
|
4
|
+
# The definitions of available search index operations, as used by the
|
5
|
+
# unified tests.
|
6
|
+
module SearchIndexOperations
|
7
|
+
def create_search_index(op)
|
8
|
+
collection = entities.get(:collection, op.use!('object'))
|
9
|
+
|
10
|
+
use_arguments(op) do |args|
|
11
|
+
model = args.use('model')
|
12
|
+
name = model.use('name')
|
13
|
+
definition = model.use('definition')
|
14
|
+
collection.search_indexes.create_one(definition, name: name)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_search_indexes(op)
|
19
|
+
collection = entities.get(:collection, op.use!('object'))
|
20
|
+
|
21
|
+
use_arguments(op) do |args|
|
22
|
+
models = args.use('models')
|
23
|
+
collection.search_indexes.create_many(models)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def drop_search_index(op)
|
28
|
+
collection = entities.get(:collection, op.use!('object'))
|
29
|
+
|
30
|
+
use_arguments(op) do |args|
|
31
|
+
collection.search_indexes.drop_one(
|
32
|
+
id: args.use('id'),
|
33
|
+
name: args.use('name')
|
34
|
+
)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def list_search_indexes(op)
|
39
|
+
collection = entities.get(:collection, op.use!('object'))
|
40
|
+
|
41
|
+
use_arguments(op) do |args|
|
42
|
+
agg_opts = args.use('aggregationOptions') || {}
|
43
|
+
collection.search_indexes(
|
44
|
+
id: args.use('id'),
|
45
|
+
name: args.use('name'),
|
46
|
+
aggregate: ::Utils.underscore_hash(agg_opts)
|
47
|
+
).to_a
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def update_search_index(op)
|
52
|
+
collection = entities.get(:collection, op.use!('object'))
|
53
|
+
|
54
|
+
use_arguments(op) do |args|
|
55
|
+
collection.search_indexes.update_one(
|
56
|
+
args.use('definition'),
|
57
|
+
id: args.use('id'),
|
58
|
+
name: args.use('name')
|
59
|
+
)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -9,6 +9,7 @@ require 'runners/unified/ddl_operations'
|
|
9
9
|
require 'runners/unified/change_stream_operations'
|
10
10
|
require 'runners/unified/support_operations'
|
11
11
|
require 'runners/unified/thread_operations'
|
12
|
+
require 'runners/unified/search_index_operations'
|
12
13
|
require 'runners/unified/assertions'
|
13
14
|
require 'support/utils'
|
14
15
|
require 'support/crypt'
|
@@ -23,6 +24,7 @@ module Unified
|
|
23
24
|
include ChangeStreamOperations
|
24
25
|
include SupportOperations
|
25
26
|
include ThreadOperations
|
27
|
+
include SearchIndexOperations
|
26
28
|
include Assertions
|
27
29
|
include RSpec::Core::Pending
|
28
30
|
|
@@ -120,7 +122,7 @@ module Unified
|
|
120
122
|
# the other set members, in standalone deployments because
|
121
123
|
# there is only one server, but changes behavior in
|
122
124
|
# sharded clusters compared to how the test suite is configured.
|
123
|
-
|
125
|
+
options[:single_address] = true
|
124
126
|
end
|
125
127
|
|
126
128
|
if store_events = spec.use('storeEventsAsEntities')
|
data/spec/spec_helper.rb
CHANGED
@@ -20,7 +20,7 @@ RSpec.configure do |config|
|
|
20
20
|
config.extend(Constraints)
|
21
21
|
|
22
22
|
config.before(:all) do
|
23
|
-
if
|
23
|
+
if SpecConfig.instance.kill_all_server_sessions?
|
24
24
|
kill_all_server_sessions
|
25
25
|
end
|
26
26
|
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
description: "createSearchIndex"
|
2
|
+
schemaVersion: "1.4"
|
3
|
+
createEntities:
|
4
|
+
- client:
|
5
|
+
id: &client0 client0
|
6
|
+
useMultipleMongoses: false
|
7
|
+
observeEvents:
|
8
|
+
- commandStartedEvent
|
9
|
+
- database:
|
10
|
+
id: &database0 database0
|
11
|
+
client: *client0
|
12
|
+
databaseName: *database0
|
13
|
+
- collection:
|
14
|
+
id: &collection0 collection0
|
15
|
+
database: *database0
|
16
|
+
collectionName: *collection0
|
17
|
+
|
18
|
+
runOnRequirements:
|
19
|
+
- minServerVersion: "7.0.0"
|
20
|
+
topologies: [ replicaset, load-balanced, sharded ]
|
21
|
+
serverless: forbid
|
22
|
+
|
23
|
+
tests:
|
24
|
+
- description: "no name provided for an index definition"
|
25
|
+
operations:
|
26
|
+
- name: createSearchIndex
|
27
|
+
object: *collection0
|
28
|
+
arguments:
|
29
|
+
model: { definition: &definition { mappings: { dynamic: true } } }
|
30
|
+
expectError:
|
31
|
+
# This test always errors in a non-Atlas environment. The test functions as a unit test by asserting
|
32
|
+
# that the driver constructs and sends the correct command.
|
33
|
+
isError: true
|
34
|
+
errorContains: Search index commands are only supported with Atlas
|
35
|
+
expectEvents:
|
36
|
+
- client: *client0
|
37
|
+
events:
|
38
|
+
- commandStartedEvent:
|
39
|
+
command:
|
40
|
+
createSearchIndexes: *collection0
|
41
|
+
indexes: [ { definition: *definition } ]
|
42
|
+
$db: *database0
|
43
|
+
|
44
|
+
- description: "name provided for an index definition"
|
45
|
+
operations:
|
46
|
+
- name: createSearchIndex
|
47
|
+
object: *collection0
|
48
|
+
arguments:
|
49
|
+
model: { definition: &definition { mappings: { dynamic: true } } , name: 'test index' }
|
50
|
+
expectError:
|
51
|
+
# This test always errors in a non-Atlas environment. The test functions as a unit test by asserting
|
52
|
+
# that the driver constructs and sends the correct command.
|
53
|
+
isError: true
|
54
|
+
errorContains: Search index commands are only supported with Atlas
|
55
|
+
expectEvents:
|
56
|
+
- client: *client0
|
57
|
+
events:
|
58
|
+
- commandStartedEvent:
|
59
|
+
command:
|
60
|
+
createSearchIndexes: *collection0
|
61
|
+
indexes: [ { definition: *definition, name: 'test index' } ]
|
62
|
+
$db: *database0
|
@@ -0,0 +1,83 @@
|
|
1
|
+
description: "createSearchIndexes"
|
2
|
+
schemaVersion: "1.4"
|
3
|
+
createEntities:
|
4
|
+
- client:
|
5
|
+
id: &client0 client0
|
6
|
+
useMultipleMongoses: false
|
7
|
+
observeEvents:
|
8
|
+
- commandStartedEvent
|
9
|
+
- database:
|
10
|
+
id: &database0 database0
|
11
|
+
client: *client0
|
12
|
+
databaseName: *database0
|
13
|
+
- collection:
|
14
|
+
id: &collection0 collection0
|
15
|
+
database: *database0
|
16
|
+
collectionName: *collection0
|
17
|
+
|
18
|
+
runOnRequirements:
|
19
|
+
- minServerVersion: "7.0.0"
|
20
|
+
topologies: [ replicaset, load-balanced, sharded ]
|
21
|
+
serverless: forbid
|
22
|
+
|
23
|
+
tests:
|
24
|
+
- description: "empty index definition array"
|
25
|
+
operations:
|
26
|
+
- name: createSearchIndexes
|
27
|
+
object: *collection0
|
28
|
+
arguments:
|
29
|
+
models: []
|
30
|
+
expectError:
|
31
|
+
# This test always errors in a non-Atlas environment. The test functions as a unit test by asserting
|
32
|
+
# that the driver constructs and sends the correct command.
|
33
|
+
isError: true
|
34
|
+
errorContains: Search index commands are only supported with Atlas
|
35
|
+
expectEvents:
|
36
|
+
- client: *client0
|
37
|
+
events:
|
38
|
+
- commandStartedEvent:
|
39
|
+
command:
|
40
|
+
createSearchIndexes: *collection0
|
41
|
+
indexes: []
|
42
|
+
$db: *database0
|
43
|
+
|
44
|
+
|
45
|
+
- description: "no name provided for an index definition"
|
46
|
+
operations:
|
47
|
+
- name: createSearchIndexes
|
48
|
+
object: *collection0
|
49
|
+
arguments:
|
50
|
+
models: [ { definition: &definition { mappings: { dynamic: true } } } ]
|
51
|
+
expectError:
|
52
|
+
# This test always errors in a non-Atlas environment. The test functions as a unit test by asserting
|
53
|
+
# that the driver constructs and sends the correct command.
|
54
|
+
isError: true
|
55
|
+
errorContains: Search index commands are only supported with Atlas
|
56
|
+
expectEvents:
|
57
|
+
- client: *client0
|
58
|
+
events:
|
59
|
+
- commandStartedEvent:
|
60
|
+
command:
|
61
|
+
createSearchIndexes: *collection0
|
62
|
+
indexes: [ { definition: *definition } ]
|
63
|
+
$db: *database0
|
64
|
+
|
65
|
+
- description: "name provided for an index definition"
|
66
|
+
operations:
|
67
|
+
- name: createSearchIndexes
|
68
|
+
object: *collection0
|
69
|
+
arguments:
|
70
|
+
models: [ { definition: &definition { mappings: { dynamic: true } } , name: 'test index' } ]
|
71
|
+
expectError:
|
72
|
+
# This test always errors in a non-Atlas environment. The test functions as a unit test by asserting
|
73
|
+
# that the driver constructs and sends the correct command.
|
74
|
+
isError: true
|
75
|
+
errorContains: Search index commands are only supported with Atlas
|
76
|
+
expectEvents:
|
77
|
+
- client: *client0
|
78
|
+
events:
|
79
|
+
- commandStartedEvent:
|
80
|
+
command:
|
81
|
+
createSearchIndexes: *collection0
|
82
|
+
indexes: [ { definition: *definition, name: 'test index' } ]
|
83
|
+
$db: *database0
|