mongoid 7.1.7 → 7.1.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -245,6 +245,97 @@ describe Mongoid::Attributes do
245
245
  end
246
246
  end
247
247
 
248
+ context "when the field was not explicitly defined" do
249
+
250
+ context "when excluding with only and the field was not excluded" do
251
+
252
+ let(:from_db) do
253
+ Person.only(:_id).first
254
+ end
255
+
256
+ it "raises an error" do
257
+ expect {
258
+ from_db[:undefined_field]
259
+ }.to raise_error(ActiveModel::MissingAttributeError)
260
+ end
261
+ end
262
+
263
+ context "when excluding with without and the field was excluded" do
264
+
265
+ let(:from_db) do
266
+ Person.without(:title).first
267
+ end
268
+
269
+ it "raises an error" do
270
+ expect {
271
+ from_db[:title]
272
+ }.to raise_error(ActiveModel::MissingAttributeError)
273
+ end
274
+ end
275
+
276
+ context "when excluding with without and the field was not excluded" do
277
+
278
+ let(:from_db) do
279
+ Person.without(:title).first
280
+ end
281
+
282
+ it "returns nil" do
283
+ from_db[:undefined_field].should be nil
284
+ end
285
+ end
286
+ end
287
+
288
+ context 'when projecting with #only' do
289
+ let!(:person) do
290
+ Person.create(title: 'sir', name: { first_name: 'Jose', language: { name: 'es' } })
291
+ end
292
+
293
+ context 'when projecting an embedded association' do
294
+ let(:from_db) do
295
+ Person.only(:name).first
296
+ end
297
+
298
+ context 'when retrieving a field of the association using the dot notation' do
299
+
300
+ it 'retrieves the field' do
301
+ pending 'MONGOID-5032, fixed in 7.3'
302
+
303
+ expect(from_db['name.first_name']).to eq 'Jose'
304
+ end
305
+ end
306
+
307
+ context 'when retrieving a field of a nested association using the dot notation' do
308
+ it 'retrieves the field' do
309
+ pending 'MONGOID-5032, fixed in 7.3'
310
+
311
+ expect(from_db['name.language.name']).to eq 'es'
312
+ end
313
+ end
314
+ end
315
+
316
+ context 'when projecting a sub-association of an embedded association' do
317
+ let(:from_db) do
318
+ Person.only('name.language').first
319
+ end
320
+
321
+ context 'when retrieving a field under the projected sub-association' do
322
+ it 'retrieves the field' do
323
+ pending 'MONGOID-5032, fixed in 7.3'
324
+
325
+ expect(from_db['name.language.name']).to eq 'es'
326
+ end
327
+ end
328
+
329
+ context 'when retrieving a non-projected field' do
330
+ it 'raises MissingAttributeError' do
331
+ expect do
332
+ from_db['name.first_name']
333
+ end.to raise_error(ActiveModel::MissingAttributeError)
334
+ end
335
+ end
336
+ end
337
+ end
338
+
248
339
  context "when the attribute does not exist" do
249
340
 
250
341
  before do
@@ -329,6 +420,67 @@ describe Mongoid::Attributes do
329
420
  expect(terms).to eq(true)
330
421
  end
331
422
  end
423
+
424
+ context 'when the field is not explicitly defined' do
425
+ let(:bar) { Bar.new }
426
+
427
+ before do
428
+ bar['missing_field'] = 42
429
+ end
430
+
431
+ it 'writes the value into attributes' do
432
+ bar.attributes.should == {'_id' => bar.id, 'missing_field' => 42}
433
+ end
434
+
435
+ it 'makes the attribute accessible via []' do
436
+ bar['missing_field'].should == 42
437
+ end
438
+
439
+ context 'when writing fields on a document with projection' do
440
+
441
+ let!(:person) do
442
+ Person.create(title: "sir")
443
+ end
444
+
445
+ context "when excluding with only and the field was not excluded" do
446
+
447
+ let(:from_db) do
448
+ Person.only(:_id).first
449
+ end
450
+
451
+ it "raises an error" do
452
+ expect {
453
+ from_db[:undefined_field] = 'x'
454
+ }.to raise_error(ActiveModel::MissingAttributeError)
455
+ end
456
+ end
457
+
458
+ context "when excluding with without and the field was excluded" do
459
+
460
+ let(:from_db) do
461
+ Person.without(:title).first
462
+ end
463
+
464
+ it "raises an error" do
465
+ expect {
466
+ from_db[:title] = 'x'
467
+ }.to raise_error(ActiveModel::MissingAttributeError)
468
+ end
469
+ end
470
+
471
+ context "when excluding with without and the field was not excluded" do
472
+
473
+ let(:from_db) do
474
+ Person.without(:title).first
475
+ end
476
+
477
+ it "writes the value" do
478
+ from_db[:undefined_field] = 'x'
479
+ from_db[:undefined_field].should == 'x'
480
+ end
481
+ end
482
+ end
483
+ end
332
484
  end
333
485
 
334
486
  describe "#_id" do
@@ -893,6 +1045,50 @@ describe Mongoid::Attributes do
893
1045
  expect(person.age_before_type_cast).to eq("old")
894
1046
  end
895
1047
  end
1048
+
1049
+ context 'when reading fields on a document with projection' do
1050
+
1051
+ let!(:person) do
1052
+ Person.create(title: "sir")
1053
+ end
1054
+
1055
+ context "when excluding with only and the field was not excluded" do
1056
+
1057
+ let(:from_db) do
1058
+ Person.only(:_id).first
1059
+ end
1060
+
1061
+ it "raises an error" do
1062
+ expect {
1063
+ from_db.read_attribute(:undefined_field)
1064
+ }.to raise_error(ActiveModel::MissingAttributeError)
1065
+ end
1066
+ end
1067
+
1068
+ context "when excluding with without and the field was excluded" do
1069
+
1070
+ let(:from_db) do
1071
+ Person.without(:title).first
1072
+ end
1073
+
1074
+ it "raises an error" do
1075
+ expect {
1076
+ from_db.read_attribute(:title)
1077
+ }.to raise_error(ActiveModel::MissingAttributeError)
1078
+ end
1079
+ end
1080
+
1081
+ context "when excluding with without and the field was not excluded" do
1082
+
1083
+ let(:from_db) do
1084
+ Person.without(:title).first
1085
+ end
1086
+
1087
+ it "returns nil" do
1088
+ from_db.read_attribute(:undefined_field).should be nil
1089
+ end
1090
+ end
1091
+ end
896
1092
  end
897
1093
 
898
1094
  describe "#attribute_present?" do
@@ -1398,6 +1594,51 @@ describe Mongoid::Attributes do
1398
1594
  expect(dictionary.description).to eq('foo')
1399
1595
  end
1400
1596
  end
1597
+
1598
+ context 'when writing fields on a document with projection' do
1599
+
1600
+ let!(:person) do
1601
+ Person.create(title: "sir")
1602
+ end
1603
+
1604
+ context "when excluding with only and the field was not excluded" do
1605
+
1606
+ let(:from_db) do
1607
+ Person.only(:_id).first
1608
+ end
1609
+
1610
+ it "raises an error" do
1611
+ expect {
1612
+ from_db.write_attribute(:undefined_field, 'x')
1613
+ }.to raise_error(ActiveModel::MissingAttributeError)
1614
+ end
1615
+ end
1616
+
1617
+ context "when excluding with without and the field was excluded" do
1618
+
1619
+ let(:from_db) do
1620
+ Person.without(:title).first
1621
+ end
1622
+
1623
+ it "raises an error" do
1624
+ expect {
1625
+ from_db.write_attribute(:title, 'x')
1626
+ }.to raise_error(ActiveModel::MissingAttributeError)
1627
+ end
1628
+ end
1629
+
1630
+ context "when excluding with without and the field was not excluded" do
1631
+
1632
+ let(:from_db) do
1633
+ Person.without(:title).first
1634
+ end
1635
+
1636
+ it "writes the value" do
1637
+ from_db.write_attribute(:undefined_field, 'x')
1638
+ from_db.read_attribute(:undefined_field).should == 'x'
1639
+ end
1640
+ end
1641
+ end
1401
1642
  end
1402
1643
 
1403
1644
  describe "#typed_value_for" do
@@ -753,12 +753,25 @@ describe Mongoid::Contextual::Atomic do
753
753
  context.set(name: "Recoil")
754
754
  end
755
755
 
756
- it "sets existing fields" do
757
- expect(depeche_mode.reload.name).to eq("Recoil")
756
+ shared_examples 'writes as expected' do
757
+ it "sets existing fields" do
758
+ expect(depeche_mode.reload.name).to eq("Recoil")
759
+ end
760
+
761
+ it "sets non existent fields" do
762
+ expect(smiths.reload.name).to eq("Recoil")
763
+ end
758
764
  end
759
765
 
760
- it "sets non existent fields" do
761
- expect(smiths.reload.name).to eq("Recoil")
766
+ include_examples 'writes as expected'
767
+
768
+ context 'when fields being set have been projected out' do
769
+
770
+ let(:criteria) do
771
+ Band.only(:genres)
772
+ end
773
+
774
+ include_examples 'writes as expected'
762
775
  end
763
776
  end
764
777
 
@@ -109,11 +109,11 @@ describe Mongoid::Factory do
109
109
  context "when the attributes are nil" do
110
110
 
111
111
  let(:document) do
112
- described_class.from_db(Address, nil)
112
+ described_class.from_db(Animal, nil)
113
113
  end
114
114
 
115
115
  it "generates based on the provided class" do
116
- expect(document).to be_a(Address)
116
+ expect(document).to be_a(Animal)
117
117
  end
118
118
 
119
119
  it "sets the attributes to empty" do
@@ -169,8 +169,8 @@ describe Mongoid::Persistable::Savable do
169
169
  Person.create(title: "Blah")
170
170
  end
171
171
 
172
- let!(:address) do
173
- person.addresses.build(street: "Bond St")
172
+ let!(:symptom) do
173
+ person.symptoms.build(name: "Headache")
174
174
  end
175
175
 
176
176
  let!(:name) do
@@ -193,7 +193,7 @@ describe Mongoid::Persistable::Savable do
193
193
  "name.first_name" => "Ryan"
194
194
  },
195
195
  "$push"=> {
196
- "addresses" => { '$each' => [ { "_id" => address.id, "street" => "Bond St" } ] }
196
+ "symptoms" => { '$each' => [ { "_id" => symptom.id, "name" => "Headache" } ] }
197
197
  }
198
198
  })
199
199
  end
@@ -205,7 +205,7 @@ describe Mongoid::Persistable::Savable do
205
205
  end
206
206
 
207
207
  it "saves embedded many relations" do
208
- expect(person.addresses.first.street).to eq("Bond St")
208
+ expect(person.symptoms.first.name).to eq("Headache")
209
209
  end
210
210
 
211
211
  it "saves embedded one relations" do
@@ -512,4 +512,34 @@ describe Mongoid::Persistable::Settable do
512
512
  end
513
513
  end
514
514
  end
515
+
516
+ context "when the field being set was projected out" do
517
+ let(:full_agent) do
518
+ Agent.create!(title: "Double-Oh Eight")
519
+ end
520
+
521
+ let(:agent) do
522
+ Agent.where(_id: full_agent.id).only(:dob).first
523
+ end
524
+
525
+ context 'field exists in database' do
526
+ it "raises MissingAttributeError" do
527
+ lambda do
528
+ agent.set(title: '008')
529
+ end.should raise_error(ActiveModel::MissingAttributeError)
530
+
531
+ expect(agent.reload.title).to eq 'Double-Oh Eight'
532
+ end
533
+ end
534
+
535
+ context 'field does not exist in database' do
536
+ it "raises MissingAttributeError" do
537
+ lambda do
538
+ agent.set(number: '008')
539
+ end.should raise_error(ActiveModel::MissingAttributeError)
540
+
541
+ expect(agent.reload.read_attribute(:number)).to be nil
542
+ end
543
+ end
544
+ end
515
545
  end
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ desired_version, arch = ARGV
4
+ if arch.nil?
5
+ STDERR.puts "Usage: get-mongodb-download-url desired-version arch"
6
+ exit 1
7
+ end
8
+
9
+ $: << File.join(File.dirname(__FILE__), '../lib')
10
+ require 'mrss/server_version_registry'
11
+
12
+ begin
13
+ puts Mrss::ServerVersionRegistry.new(desired_version, arch).download_url
14
+ rescue Mrss::ServerVersionRegistry::Error => exc
15
+ STDERR.puts "Error: #{exc}"
16
+ exit 2
17
+ end
@@ -1,3 +1,6 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
1
4
  # ClusterConfig requires ClientRegistry class provided by the host project.
2
5
 
3
6
  require 'singleton'
@@ -82,6 +85,11 @@ module Mrss
82
85
  @primary_description
83
86
  end
84
87
 
88
+ def server_parameters
89
+ determine_cluster_config
90
+ @server_parameters
91
+ end
92
+
85
93
  # Try running a command on the admin database to see if the mongod was
86
94
  # started with auth.
87
95
  def auth_enabled?
@@ -196,8 +204,10 @@ module Mrss
196
204
  @server_version = build_info['version']
197
205
  @enterprise = build_info['modules'] && build_info['modules'].include?('enterprise')
198
206
 
207
+ @server_parameters = client.use(:admin).command(getParameter: '*').first
208
+
199
209
  if @topology != :sharded && short_server_version >= '3.4'
200
- rv = client.use(:admin).command(getParameter: 1, featureCompatibilityVersion: 1).first['featureCompatibilityVersion']
210
+ rv = @server_parameters['featureCompatibilityVersion']
201
211
  @fcv = rv['version'] || rv
202
212
  end
203
213
  end
@@ -113,6 +113,14 @@ module Mrss
113
113
  end
114
114
  end
115
115
 
116
+ def require_retry_writes
117
+ before(:all) do
118
+ unless SpecConfig.instance.retry_writes?
119
+ skip "Retry writes is disabled"
120
+ end
121
+ end
122
+ end
123
+
116
124
  def require_no_retry_writes
117
125
  before(:all) do
118
126
  if SpecConfig.instance.retry_writes?
@@ -172,8 +180,8 @@ module Mrss
172
180
  skip "Zstd compression is enabled"
173
181
  end
174
182
  end
175
- end
176
-
183
+ end
184
+
177
185
  def require_no_compression
178
186
  before(:all) do
179
187
  if SpecConfig.instance.compressors
@@ -326,5 +334,21 @@ module Mrss
326
334
  end
327
335
  end
328
336
  end
337
+
338
+ def require_required_api_version
339
+ before(:all) do
340
+ unless ENV['API_VERSION_REQUIRED'] == '1'
341
+ skip 'Set API_VERSION_REQUIRED=1 to run this test'
342
+ end
343
+ end
344
+ end
345
+
346
+ def require_no_required_api_version
347
+ before(:all) do
348
+ if ENV['API_VERSION_REQUIRED'] == '1'
349
+ skip 'Cannot have API_VERSION_REQUIRED=1 to run this test'
350
+ end
351
+ end
352
+ end
329
353
  end
330
354
  end
@@ -1,3 +1,6 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
1
4
  require 'optparse'
2
5
  require 'erb'
3
6
  autoload :Dotenv, 'dotenv'
@@ -171,5 +171,21 @@ module Mrss
171
171
  end
172
172
  end
173
173
  end
174
+
175
+ def require_active_support
176
+ before(:all) do
177
+ if !SpecConfig.instance.active_support?
178
+ skip 'This test requires ActiveSupport; set WITH_ACTIVE_SUPPORT=1 in environment'
179
+ end
180
+ end
181
+ end
182
+
183
+ def no_active_support
184
+ before(:all) do
185
+ if SpecConfig.instance.active_support?
186
+ skip 'This test requires no ActiveSupport; unset WITH_ACTIVE_SUPPORT in environment'
187
+ end
188
+ end
189
+ end
174
190
  end
175
191
  end
@@ -1,8 +1,23 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
1
4
  autoload :JSON, 'json'
2
5
  require 'open-uri'
3
6
 
4
7
  module Mrss
5
8
  class ServerVersionRegistry
9
+ class Error < StandardError
10
+ end
11
+
12
+ class UnknownVersion < Error
13
+ end
14
+
15
+ class MissingDownloadUrl < Error
16
+ end
17
+
18
+ class BrokenDownloadUrl < Error
19
+ end
20
+
6
21
  def initialize(desired_version, arch)
7
22
  @desired_version, @arch = desired_version, arch
8
23
  end
@@ -11,39 +26,16 @@ module Mrss
11
26
 
12
27
  def download_url
13
28
  @download_url ||= begin
14
- info = JSON.load(uri_open('http://downloads.mongodb.org/current.json').read)
15
- version = info['versions'].detect do |version|
16
- version['version'].start_with?(desired_version) &&
17
- !version['version'].include?('-') &&
18
- # Sometimes the download situation is borked and there is a release
19
- # with no downloads... skip those.
20
- !version['downloads'].empty?
21
- end
22
- # Allow RC releases if there isn't a GA release.
23
- version ||= info['versions'].detect do |version|
24
- version['version'].start_with?(desired_version) &&
25
- # Sometimes the download situation is borked and there is a release
26
- # with no downloads... skip those.
27
- !version['downloads'].empty?
29
+ version, version_ok = detect_version(current_catalog)
30
+ if version.nil?
31
+ version, full_version_ok = detect_version(full_catalog)
32
+ version_ok ||= full_version_ok
28
33
  end
29
34
  if version.nil?
30
- info = JSON.load(URI.parse('http://downloads.mongodb.org/full.json').open.read)
31
- versions = info['versions'].select do |version|
32
- version['version'].start_with?(desired_version) &&
33
- !version['downloads'].empty?
34
- end
35
- # Get rid of rc, beta etc. versions if there is a GA release.
36
- if versions.any? { |version| !version.include?('-') }
37
- versions.delete_if do |version|
38
- version['version'].include?('-')
39
- end
40
- end
41
- # Versions are ordered with newest first, take the first one i.e. the most
42
- # recent one.
43
- version = versions.first
44
- if version.nil?
45
- STDERR.puts "Error: no version #{desired_version}"
46
- exit 2
35
+ if version_ok
36
+ raise MissingDownloadUrl, "No downloads for version #{desired_version}"
37
+ else
38
+ raise UnknownVersion, "No version #{desired_version}"
47
39
  end
48
40
  end
49
41
  dl = version['downloads'].detect do |dl|
@@ -51,13 +43,31 @@ module Mrss
51
43
  dl['arch'] == 'x86_64'
52
44
  end
53
45
  unless dl
54
- STDERR.puts "Error: no download for #{arch} for #{version['version']}"
55
- exit 2
46
+ raise MissingDownloadUrl, "No download for #{arch} for #{version['version']}"
56
47
  end
57
48
  url = dl['archive']['url']
58
49
  end
50
+ rescue MissingDownloadUrl
51
+ if %w(4.7 4.7.0).include?(desired_version)
52
+ # 4.7.0 has no advertised downloads but it is downloadable and
53
+ # we do need it. Dirty hack below.
54
+ registry = self.class.new('4.4.3', arch)
55
+ registry.download_url.sub('4.4.3', '4.7.0').tap do |url|
56
+ # Sanity check - ensure the URL we hacked up is a valid one
57
+ io = uri_open(url)
58
+ begin
59
+ io.read(1)
60
+ ensure
61
+ io.close
62
+ end
63
+ end
64
+ else
65
+ raise
66
+ end
59
67
  end
60
68
 
69
+ private
70
+
61
71
  def uri_open(*args)
62
72
  if RUBY_VERSION < '2.5'
63
73
  open(*args)
@@ -65,5 +75,41 @@ module Mrss
65
75
  URI.open(*args)
66
76
  end
67
77
  end
78
+
79
+ def detect_version(catalog)
80
+ candidate_versions = catalog['versions'].select do |version|
81
+ version['version'].start_with?(desired_version) &&
82
+ !version['version'].include?('-')
83
+ end
84
+ version_ok = !candidate_versions.empty?
85
+ # Sometimes the download situation is borked and there is a release
86
+ # with no downloads... skip those.
87
+ version = candidate_versions.detect do |version|
88
+ !version['downloads'].empty?
89
+ end
90
+ # Allow RC releases if there isn't a GA release.
91
+ if version.nil?
92
+ candidate_versions = catalog['versions'].select do |version|
93
+ version['version'].start_with?(desired_version)
94
+ end
95
+ version_ok ||= !candidate_versions.empty?
96
+ version = candidate_versions.detect do |version|
97
+ !version['downloads'].empty?
98
+ end
99
+ end
100
+ [version, version_ok]
101
+ end
102
+
103
+ def current_catalog
104
+ @current_catalog ||= begin
105
+ JSON.load(uri_open('http://downloads.mongodb.org/current.json').read)
106
+ end
107
+ end
108
+
109
+ def full_catalog
110
+ @full_catalog ||= begin
111
+ JSON.load(uri_open('http://downloads.mongodb.org/full.json').read)
112
+ end
113
+ end
68
114
  end
69
115
  end
@@ -1,3 +1,6 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
1
4
  autoload :JSON, 'json'
2
5
  autoload :FileUtils, 'fileutils'
3
6
  autoload :Find, 'find'
@@ -78,10 +81,20 @@ module Mrss
78
81
  end
79
82
 
80
83
  def run
84
+ run_buckets(*buckets.keys)
85
+ end
86
+
87
+ def run_buckets(*buckets)
81
88
  FileUtils.rm_f(rspec_all_json_path)
82
89
 
90
+ buckets.each do |bucket|
91
+ if bucket && !self.buckets[bucket]
92
+ raise "Unknown bucket #{bucket}"
93
+ end
94
+ end
95
+ buckets = Hash[self.buckets.select { |k, v| buckets.include?(k) }]
96
+
83
97
  failed = []
84
- buckets = self.buckets.dup
85
98
 
86
99
  priority_order.each do |category|
87
100
  if files = buckets.delete(category)
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
4
+ module Mrss
5
+ module Utils
6
+
7
+ module_function def print_backtrace(dest=STDERR)
8
+ begin
9
+ hello world
10
+ rescue => e
11
+ dest.puts e.backtrace.join("\n")
12
+ end
13
+ end
14
+ end
15
+ end