mongoid 7.1.0 → 7.1.6

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 (131) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/CHANGELOG.md +6 -6
  5. data/README.md +1 -1
  6. data/Rakefile +14 -5
  7. data/lib/config/locales/en.yml +5 -5
  8. data/lib/mongoid/association/accessors.rb +37 -2
  9. data/lib/mongoid/association/embedded/embeds_many.rb +2 -1
  10. data/lib/mongoid/association/embedded/embeds_one.rb +2 -1
  11. data/lib/mongoid/association/proxy.rb +1 -1
  12. data/lib/mongoid/association/referenced/belongs_to/binding.rb +1 -1
  13. data/lib/mongoid/association/referenced/belongs_to/eager.rb +38 -2
  14. data/lib/mongoid/association/referenced/eager.rb +29 -9
  15. data/lib/mongoid/association/referenced/has_one/proxy.rb +6 -1
  16. data/lib/mongoid/atomic.rb +13 -3
  17. data/lib/mongoid/clients/factory.rb +2 -2
  18. data/lib/mongoid/clients/options.rb +8 -8
  19. data/lib/mongoid/clients/sessions.rb +20 -4
  20. data/lib/mongoid/clients/storage_options.rb +5 -5
  21. data/lib/mongoid/config.rb +39 -9
  22. data/lib/mongoid/criteria.rb +23 -4
  23. data/lib/mongoid/criteria/modifiable.rb +2 -1
  24. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +1 -1
  25. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +6 -6
  26. data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +12 -0
  27. data/lib/mongoid/criteria/queryable/mergeable.rb +75 -8
  28. data/lib/mongoid/criteria/queryable/pipeline.rb +3 -2
  29. data/lib/mongoid/criteria/queryable/selectable.rb +120 -13
  30. data/lib/mongoid/criteria/queryable/storable.rb +104 -99
  31. data/lib/mongoid/errors/eager_load.rb +2 -0
  32. data/lib/mongoid/errors/no_client_config.rb +2 -2
  33. data/lib/mongoid/errors/no_default_client.rb +1 -1
  34. data/lib/mongoid/extensions/hash.rb +4 -2
  35. data/lib/mongoid/extensions/regexp.rb +1 -1
  36. data/lib/mongoid/fields.rb +2 -1
  37. data/lib/mongoid/fields/validators/macro.rb +4 -1
  38. data/lib/mongoid/matchable/regexp.rb +2 -2
  39. data/lib/mongoid/persistable/pushable.rb +11 -2
  40. data/lib/mongoid/persistence_context.rb +6 -6
  41. data/lib/mongoid/query_cache.rb +61 -18
  42. data/lib/mongoid/serializable.rb +9 -3
  43. data/lib/mongoid/tasks/database.rb +38 -3
  44. data/lib/mongoid/validatable/uniqueness.rb +1 -1
  45. data/lib/mongoid/version.rb +1 -1
  46. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +32 -23
  47. data/lib/rails/generators/mongoid/model/templates/model.rb.tt +1 -1
  48. data/spec/app/models/coding.rb +4 -0
  49. data/spec/app/models/coding/pull_request.rb +12 -0
  50. data/spec/app/models/delegating_patient.rb +16 -0
  51. data/spec/app/models/passport.rb +1 -0
  52. data/spec/app/models/person.rb +2 -0
  53. data/spec/app/models/phone.rb +1 -0
  54. data/spec/app/models/publication.rb +5 -0
  55. data/spec/app/models/publication/encyclopedia.rb +12 -0
  56. data/spec/app/models/publication/review.rb +14 -0
  57. data/spec/app/models/series.rb +1 -0
  58. data/spec/app/models/wiki_page.rb +1 -0
  59. data/spec/integration/app_spec.rb +254 -0
  60. data/spec/integration/associations/embedded_spec.rb +54 -0
  61. data/spec/integration/associations/embeds_many_spec.rb +24 -0
  62. data/spec/integration/associations/embeds_one_spec.rb +24 -0
  63. data/spec/integration/associations/has_many_spec.rb +76 -0
  64. data/spec/integration/associations/has_one_spec.rb +76 -0
  65. data/spec/integration/bson_regexp_raw_spec.rb +20 -0
  66. data/spec/integration/criteria/date_field_spec.rb +41 -0
  67. data/spec/integration/criteria/logical_spec.rb +13 -0
  68. data/spec/integration/document_spec.rb +22 -0
  69. data/spec/integration/shardable_spec.rb +20 -4
  70. data/spec/lite_spec_helper.rb +12 -4
  71. data/spec/mongoid/association/accessors_spec.rb +238 -63
  72. data/spec/mongoid/association/embedded/embeds_many_models.rb +19 -0
  73. data/spec/mongoid/association/embedded/embeds_many_spec.rb +10 -0
  74. data/spec/mongoid/association/embedded/embeds_one_spec.rb +0 -2
  75. data/spec/mongoid/association/referenced/belongs_to/eager_spec.rb +193 -10
  76. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +140 -1
  77. data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +105 -0
  78. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +2 -1
  79. data/spec/mongoid/clients/factory_spec.rb +8 -8
  80. data/spec/mongoid/clients/options_spec.rb +11 -11
  81. data/spec/mongoid/clients/sessions_spec.rb +8 -4
  82. data/spec/mongoid/clients/transactions_spec.rb +20 -8
  83. data/spec/mongoid/clients_spec.rb +2 -2
  84. data/spec/mongoid/contextual/atomic_spec.rb +22 -11
  85. data/spec/mongoid/contextual/geo_near_spec.rb +11 -2
  86. data/spec/mongoid/contextual/map_reduce_spec.rb +20 -5
  87. data/spec/mongoid/contextual/mongo_spec.rb +76 -53
  88. data/spec/mongoid/criteria/queryable/extensions/regexp_raw_spec.rb +1 -1
  89. data/spec/mongoid/criteria/queryable/extensions/regexp_spec.rb +7 -7
  90. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +1 -1
  91. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +19 -7
  92. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +28 -1
  93. data/spec/mongoid/criteria/queryable/mergeable_spec.rb +45 -12
  94. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +1051 -392
  95. data/spec/mongoid/criteria/queryable/selectable_spec.rb +52 -0
  96. data/spec/mongoid/criteria/queryable/storable_spec.rb +80 -2
  97. data/spec/mongoid/criteria_spec.rb +36 -2
  98. data/spec/mongoid/document_persistence_context_spec.rb +33 -0
  99. data/spec/mongoid/errors/no_client_config_spec.rb +2 -2
  100. data/spec/mongoid/errors/no_client_database_spec.rb +3 -3
  101. data/spec/mongoid/errors/no_client_hosts_spec.rb +3 -3
  102. data/spec/mongoid/fields_spec.rb +24 -1
  103. data/spec/mongoid/indexable_spec.rb +6 -4
  104. data/spec/mongoid/matchable/default_spec.rb +1 -1
  105. data/spec/mongoid/matchable/regexp_spec.rb +2 -2
  106. data/spec/mongoid/matchable_spec.rb +2 -2
  107. data/spec/mongoid/persistable/pushable_spec.rb +55 -1
  108. data/spec/mongoid/query_cache_spec.rb +77 -9
  109. data/spec/mongoid/relations/proxy_spec.rb +1 -1
  110. data/spec/mongoid/scopable_spec.rb +2 -1
  111. data/spec/mongoid/serializable_spec.rb +129 -18
  112. data/spec/mongoid/shardable_models.rb +1 -1
  113. data/spec/mongoid/shardable_spec.rb +2 -2
  114. data/spec/mongoid/tasks/database_rake_spec.rb +13 -13
  115. data/spec/mongoid/tasks/database_spec.rb +1 -1
  116. data/spec/shared/LICENSE +20 -0
  117. data/spec/shared/lib/mrss/child_process_helper.rb +80 -0
  118. data/spec/shared/lib/mrss/cluster_config.rb +211 -0
  119. data/spec/shared/lib/mrss/constraints.rb +312 -0
  120. data/spec/shared/lib/mrss/lite_constraints.rb +175 -0
  121. data/spec/shared/lib/mrss/spec_organizer.rb +149 -0
  122. data/spec/spec_helper.rb +2 -31
  123. data/spec/support/child_process_helper.rb +76 -0
  124. data/spec/support/cluster_config.rb +3 -3
  125. data/spec/support/constraints.rb +26 -10
  126. data/spec/support/expectations.rb +3 -1
  127. data/spec/support/helpers.rb +11 -0
  128. data/spec/support/session_registry.rb +50 -0
  129. data/spec/support/spec_config.rb +12 -4
  130. metadata +520 -473
  131. metadata.gz.sig +0 -0
@@ -13,10 +13,16 @@ module Mongoid
13
13
  # We need to redefine where the JSON configuration is getting defined,
14
14
  # similar to +ActiveRecord+.
15
15
  included do
16
- extend Forwardable
17
16
 
18
- undef_method :include_root_in_json
19
- def_delegator ::Mongoid, :include_root_in_json
17
+ class << self
18
+ # Note that this intentionally only delegates :include_root_in_json
19
+ # and not :include_root_in_json? - delegating the latter produces
20
+ # wrong behavior.
21
+ # Also note that this intentionally uses the ActiveSupport delegation
22
+ # functionality and not the Ruby standard library one.
23
+ # See https://jira.mongodb.org/browse/MONGOID-4849.
24
+ delegate :include_root_in_json, to: ::Mongoid
25
+ end
20
26
  end
21
27
 
22
28
  # Gets the document as a serializable hash, used by ActiveModel's JSON
@@ -132,8 +132,32 @@ module Mongoid
132
132
  next
133
133
  end
134
134
 
135
- # Database must exist in order to run collStats
136
- model.collection.create
135
+ # Database of the collection must exist in order to run collStats.
136
+ # Depending on server version, the collection itself must also
137
+ # exist.
138
+ # MongoDB does not have a command to create the database; the best
139
+ # approximation of it is to create the collection we want.
140
+ # On older servers, creating a collection that already exists is
141
+ # an error.
142
+ # Additionally, 3.6 and potentially older servers do not provide
143
+ # the error code when they are asked to collStats a non-existent
144
+ # collection (https://jira.mongodb.org/browse/SERVER-50070).
145
+ begin
146
+ stats = model.collection.database.command(collStats: model.collection.name).first
147
+ rescue Mongo::Error::OperationFailure => exc
148
+ # Code 26 is database does not exist.
149
+ # Code 8 is collection does not exist, as of 4.0.
150
+ # On 3.6 and earlier match the text of exception message.
151
+ if exc.code == 26 || exc.code == 8 ||
152
+ exc.code.nil? && exc.message =~ /not found/
153
+ then
154
+ model.collection.create
155
+
156
+ stats = model.collection.database.command(collStats: model.collection.name).first
157
+ else
158
+ raise
159
+ end
160
+ end
137
161
 
138
162
  stats = model.collection.database.command(collStats: model.collection.name).first
139
163
  if stats[:sharded]
@@ -142,7 +166,18 @@ module Mongoid
142
166
  end
143
167
 
144
168
  admin_db = model.collection.client.use(:admin).database
145
- admin_db.command(enableSharding: model.collection.database.name)
169
+
170
+ begin
171
+ admin_db.command(enableSharding: model.collection.database.name)
172
+ rescue Mongo::Error::OperationFailure => exc
173
+ # Server 2.6 fails if sharding is already enabled
174
+ if exc.code == 23 || exc.code.nil? && exc.message =~ /already enabled/
175
+ # Nothing
176
+ else
177
+ raise
178
+ end
179
+ end
180
+
146
181
  begin
147
182
  admin_db.command(shardCollection: model.collection.namespace, **model.shard_config)
148
183
  rescue Mongo::Error::OperationFailure => e
@@ -150,7 +150,7 @@ module Mongoid
150
150
  #
151
151
  # @since 2.3.0
152
152
  def filter(value)
153
- !case_sensitive? && value ? /\A#{Regexp.escape(value.to_s)}$/i : value
153
+ !case_sensitive? && value ? /\A#{Regexp.escape(value.to_s)}\z/i : value
154
154
  end
155
155
 
156
156
  # Scope the criteria to the scope options provided.
@@ -2,5 +2,5 @@
2
2
  # encoding: utf-8
3
3
 
4
4
  module Mongoid
5
- VERSION = "7.1.0"
5
+ VERSION = "7.1.6"
6
6
  end
@@ -114,12 +114,37 @@ development:
114
114
 
115
115
  # Configure Mongoid specific options. (optional)
116
116
  options:
117
- # Includes the root model name in json serialization. (default: false)
117
+ # Application name that is printed to the mongodb logs upon establishing
118
+ # a connection in server versions >= 3.4. Note that the name cannot
119
+ # exceed 128 bytes. It is also used as the database name if the
120
+ # database name is not explicitly defined. (default: nil)
121
+ # app_name: MyApplicationName
122
+
123
+ # Create indexes in background by default. (default: false)
124
+ # background_indexing: false
125
+
126
+ # Mark belongs_to associations as required by default, so that saving a
127
+ # model with a missing belongs_to association will trigger a validation
128
+ # error. (default: true)
129
+ # belongs_to_required_by_default: true
130
+
131
+ # Raise an exception when a field is redefined. (default: false)
132
+ # duplicate_fields_exception: false
133
+
134
+ # Include the root model name in json serialization. (default: false)
118
135
  # include_root_in_json: false
119
136
 
120
137
  # Include the _type field in serialization. (default: false)
121
138
  # include_type_for_serialization: false
122
139
 
140
+ # Whether to join nested persistence contexts for atomic operations
141
+ # to parent contexts by default. (default: false)
142
+ # join_contexts: false
143
+
144
+ # Set the Mongoid and Ruby driver log levels when Mongoid is not using
145
+ # Ruby on Rails logger instance. (default: :info)
146
+ # log_level: :info
147
+
123
148
  # Preload all models in development, needed when models use
124
149
  # inheritance. (default: false)
125
150
  # preload_models: false
@@ -132,32 +157,16 @@ development:
132
157
  # existing method. (default: false)
133
158
  # scope_overwrite_exception: false
134
159
 
135
- # Raise an error when defining a field with the same name as an
136
- # existing method. (default: false)
137
- # duplicate_fields_exception: false
138
-
139
- # Use Active Support's time zone in conversions. (default: true)
160
+ # Use ActiveSupport's time zone in time operations instead of
161
+ # the Ruby default time zone. See the time zone section below for
162
+ # further information. (default: true)
140
163
  # use_activesupport_time_zone: true
141
164
 
142
- # Ensure all times are UTC in the app side. (default: false)
165
+ # Return stored times as UTC. See the time zone section below for
166
+ # further information. Most applications should not use this option.
167
+ # (default: false)
143
168
  # use_utc: false
144
169
 
145
- # Set the Mongoid and Ruby driver log levels when not in a Rails
146
- # environment. The Mongoid logger will be set to the Rails logger
147
- # otherwise.(default: :info)
148
- # log_level: :info
149
-
150
- # Control whether `belongs_to` association is required. By default
151
- # `belongs_to` will trigger a validation error if the association
152
- # is not present. (default: true)
153
- # belongs_to_required_by_default: true
154
-
155
- # Application name that is printed to the mongodb logs upon establishing a
156
- # connection in server versions >= 3.4. Note that the name cannot exceed 128 bytes.
157
- # app_name: MyApplicationName
158
-
159
- # Use background indexes by default if `background` option not specified. (default: false)
160
- # background_indexing: false
161
170
  test:
162
171
  clients:
163
172
  default:
@@ -13,7 +13,7 @@ class <%= class_name %><%= " < #{options[:parent].classify}" if options[:parent]
13
13
  field :<%= attribute.name %>, type: <%= attribute.type_class %>
14
14
  <% end -%>
15
15
  <% attributes.select{|attr| attr.reference? }.each do |attribute| -%>
16
- embedded_in :<%= attribute.name%>
16
+ belongs_to :<%= attribute.name%>
17
17
  <% end -%>
18
18
  end
19
19
  <% end -%>
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
4
+ require 'app/models/coding/pull_request'
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
4
+ module Coding
5
+ class PullRequest
6
+ include Mongoid::Document
7
+
8
+ field :title, type: String
9
+
10
+ has_many :reviews, class_name: 'Publication::Review', as: :reviewable
11
+ end
12
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
4
+ class DelegatingPatient
5
+ include Mongoid::Document
6
+
7
+ embeds_one :email
8
+
9
+ # Instance level delegation
10
+ delegate :address, to: :email
11
+
12
+ class << self
13
+ # Class level delegation
14
+ delegate :default_client, to: ::Mongoid
15
+ end
16
+ end
@@ -4,5 +4,6 @@
4
4
  class Passport
5
5
  include Mongoid::Document
6
6
  field :number, type: String
7
+ field :country, type: String
7
8
  embedded_in :person, autobuild: true
8
9
  end
@@ -80,6 +80,7 @@ class Person
80
80
  end
81
81
  embeds_one :quiz, validate: false
82
82
 
83
+ # Must have dependent: :destroy
83
84
  has_one :game, dependent: :destroy, validate: false do
84
85
  def extension
85
86
  "Testing"
@@ -105,6 +106,7 @@ class Person
105
106
  has_and_belongs_to_many :ordered_preferences, order: :value.desc, validate: false
106
107
 
107
108
  has_many :drugs, validate: false
109
+ # Must not have dependent: :destroy
108
110
  has_one :account, validate: false
109
111
  has_one :cat, dependent: :nullify, validate: false, primary_key: :username
110
112
  has_one :book, autobuild: true, validate: false
@@ -7,6 +7,7 @@ class Phone
7
7
  field :_id, type: String, overwrite: true, default: ->{ number }
8
8
 
9
9
  field :number
10
+ field :landline, type: Boolean
10
11
  embeds_one :country_code
11
12
  embedded_in :person
12
13
  end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
4
+ require 'app/models/publication/encyclopedia'
5
+ require 'app/models/publication/review'
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
4
+ module Publication
5
+ class Encyclopedia
6
+ include Mongoid::Document
7
+
8
+ field :title, type: String
9
+
10
+ has_many :reviews, class_name: 'Publication::Review', as: :reviewable
11
+ end
12
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
4
+ module Publication
5
+ class Review
6
+ include Mongoid::Document
7
+
8
+ field :summary
9
+
10
+ belongs_to :reviewable, polymorphic: true
11
+ belongs_to :reviewer, polymorphic: true
12
+ belongs_to :template
13
+ end
14
+ end
@@ -3,5 +3,6 @@
3
3
 
4
4
  class Series
5
5
  include Mongoid::Document
6
+ # Must not have dependent: :destroy
6
7
  has_many :books
7
8
  end
@@ -11,6 +11,7 @@ class WikiPage
11
11
  field :description, type: String, localize: true
12
12
 
13
13
  embeds_many :edits, validate: false
14
+ # Must have dependent: :destroy
14
15
  has_many :comments, dependent: :destroy, validate: false
15
16
  has_many :child_pages, class_name: "WikiPage", dependent: :delete_all, inverse_of: :parent_pages
16
17
  belongs_to :parent_pages, class_name: "WikiPage", inverse_of: :child_pages
@@ -0,0 +1,254 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
4
+ require 'spec_helper'
5
+
6
+ BASE = File.join(File.dirname(__FILE__), '../..')
7
+ TMP_BASE = File.join(BASE, 'tmp')
8
+
9
+ describe 'Mongoid application tests' do
10
+ before(:all) do
11
+ unless SpecConfig.instance.app_tests?
12
+ skip 'Set APP_TESTS=1 in environment to run application tests'
13
+ end
14
+
15
+ require 'fileutils'
16
+ require 'support/child_process_helper'
17
+ require 'open-uri'
18
+
19
+ FileUtils.mkdir_p(TMP_BASE)
20
+ end
21
+
22
+ context 'demo application - sinatra' do
23
+ it 'runs' do
24
+ clone_application(
25
+ 'https://github.com/mongoid/mongoid-demo',
26
+ subdir: 'sinatra-minimal',
27
+ ) do
28
+
29
+ process = ChildProcess.build(*%w(bundle exec ruby app.rb))
30
+ process.environment.update(clean_env)
31
+ process.io.inherit!
32
+ process.start
33
+
34
+ begin
35
+ # JRuby needs a long timeout
36
+ wait_for_port(4567, 20)
37
+ sleep 1
38
+
39
+ uri = URI.parse('http://localhost:4567/posts')
40
+ resp = JSON.parse(uri.open.read)
41
+ ensure
42
+ Process.kill('TERM', process.pid)
43
+ status = process.wait
44
+ end
45
+
46
+ resp.should == []
47
+
48
+ status.should == 0
49
+ end
50
+ end
51
+ end
52
+
53
+ context 'demo application - rails-api' do
54
+ ['~> 6.0.0'].each do |rails_version|
55
+ context "with rails #{rails_version}" do
56
+ it 'runs' do
57
+ clone_application(
58
+ 'https://github.com/mongoid/mongoid-demo',
59
+ subdir: 'rails-api',
60
+ rails_version: rails_version,
61
+ ) do
62
+
63
+ process = ChildProcess.build(*%w(bundle exec rails s))
64
+ process.environment.update(clean_env)
65
+ process.io.inherit!
66
+ process.start
67
+
68
+ begin
69
+ # JRuby needs a long timeout
70
+ wait_for_port(3000, 30)
71
+ sleep 1
72
+
73
+ uri = URI.parse('http://localhost:3000/posts')
74
+ resp = JSON.parse(uri.open.read)
75
+ ensure
76
+ Process.kill('TERM', process.pid)
77
+ status = process.wait
78
+ end
79
+
80
+ resp.should == []
81
+
82
+ # 143 = 128 + 15
83
+ [0, 15, 143].should include(status)
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+ context 'new application - rails' do
91
+ ['~> 5.1.0', '~> 5.2.0', '~> 6.0.0'].each do |rails_version|
92
+ context "with rails #{rails_version}" do
93
+ it 'creates' do
94
+ ChildProcessHelper.check_call(%w(gem uni rails -a))
95
+ ChildProcessHelper.check_call(%w(gem install rails --no-document -v) + [rails_version])
96
+
97
+ Dir.chdir(TMP_BASE) do
98
+ FileUtils.rm_rf('mongoid-test')
99
+ ChildProcessHelper.check_call(%w(rails new mongoid-test --skip-spring --skip-active-record), env: clean_env)
100
+
101
+ Dir.chdir('mongoid-test') do
102
+ adjust_app_gemfile
103
+ ChildProcessHelper.check_call(%w(bundle install), env: clean_env)
104
+
105
+ ChildProcessHelper.check_call(%w(rails g model post), env: clean_env)
106
+ ChildProcessHelper.check_call(%w(rails g model comment post:belongs_to), env: clean_env)
107
+
108
+ # https://jira.mongodb.org/browse/MONGOID-4885
109
+ comment_text = File.read('app/models/comment.rb')
110
+ comment_text.should =~ /belongs_to :post/
111
+ comment_text.should_not =~ /embedded_in :post/
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
118
+
119
+ context 'local test applications' do
120
+ let(:client) { Mongoid.default_client }
121
+
122
+ describe 'create_indexes rake task' do
123
+
124
+ APP_PATH = File.join(File.dirname(__FILE__), '../../test-apps/rails-api')
125
+
126
+ %w(development production).each do |rails_env|
127
+ context "in #{rails_env}" do
128
+
129
+ %w(classic zeitwerk).each do |autoloader|
130
+ context "with #{autoloader} autoloader" do
131
+
132
+ let(:env) do
133
+ clean_env.merge(RAILS_ENV: rails_env, AUTOLOADER: autoloader)
134
+ end
135
+
136
+ before do
137
+ Dir.chdir(APP_PATH) do
138
+ remove_bundler_req
139
+ ChildProcessHelper.check_call(%w(bundle install), env: env)
140
+ write_mongoid_yml
141
+ end
142
+
143
+ client['posts'].drop
144
+ client['posts'].create
145
+ end
146
+
147
+ it 'creates an index' do
148
+ index = client['posts'].indexes.detect do |index|
149
+ index['key'] == {'subject' => 1}
150
+ end
151
+ index.should be nil
152
+
153
+ ChildProcessHelper.check_call(%w(rake db:mongoid:create_indexes),
154
+ cwd: APP_PATH, env: env)
155
+
156
+ index = client['posts'].indexes.detect do |index|
157
+ index['key'] == {'subject' => 1}
158
+ end
159
+ index.should be_a(Hash)
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end
165
+ end
166
+ end
167
+
168
+ def clone_application(repo_url, subdir: nil, rails_version: nil)
169
+ Dir.chdir(TMP_BASE) do
170
+ FileUtils.rm_rf(File.basename(repo_url))
171
+ ChildProcessHelper.check_call(%w(git clone) + [repo_url])
172
+ Dir.chdir(File.join(*[File.basename(repo_url), subdir].compact)) do
173
+ adjust_app_gemfile(rails_version: rails_version)
174
+ ChildProcessHelper.check_call(%w(bundle install), env: clean_env)
175
+ puts `git diff`
176
+
177
+ write_mongoid_yml
178
+
179
+ yield
180
+ end
181
+ end
182
+ end
183
+
184
+ def write_mongoid_yml
185
+ env_config = {'clients' => {'default' => {
186
+ # TODO massive hack, will fail if uri specifies a database name or
187
+ # any uri options
188
+ 'uri' => "#{SpecConfig.instance.uri_str}/mongoid_test",
189
+ }}}
190
+ config = {'development' => env_config, 'production' => env_config}
191
+ File.open('config/mongoid.yml', 'w') do |f|
192
+ f << YAML.dump(config)
193
+ end
194
+ end
195
+
196
+ def adjust_app_gemfile(rails_version: nil)
197
+ remove_bundler_req
198
+
199
+ gemfile_lines = IO.readlines('Gemfile')
200
+ gemfile_lines.delete_if do |line|
201
+ line =~ /mongoid/
202
+ end
203
+ gemfile_lines << "gem 'mongoid', path: '#{File.expand_path(BASE)}'\n"
204
+ if rails_version
205
+ gemfile_lines.delete_if do |line|
206
+ line =~ /rails/
207
+ end
208
+ gemfile_lines << "gem 'rails', '#{rails_version}'\n"
209
+ end
210
+ File.open('Gemfile', 'w') do |f|
211
+ f << gemfile_lines.join
212
+ end
213
+ end
214
+
215
+ def remove_bundler_req
216
+ lock_lines = IO.readlines('Gemfile.lock')
217
+ # Get rid of the bundled with line so that whatever bundler is installed
218
+ # on the system is usable with the application.
219
+ if i = lock_lines.index("BUNDLED WITH\n")
220
+ lock_lines.slice!(i, 2)
221
+ File.open('Gemfile.lock', 'w') do |f|
222
+ f << lock_lines.join
223
+ end
224
+ end
225
+ end
226
+
227
+ def remove_spring
228
+ # Spring produces this error in Evergreen:
229
+ # /data/mci/280eb2ecf4fd69208e2106cd3af526f1/src/rubies/ruby-2.7.0/lib/ruby/gems/2.7.0/gems/spring-2.1.0/lib/spring/client/run.rb:26:
230
+ # in `initialize': too long unix socket path (126bytes given but 108bytes max) (ArgumentError)
231
+ # Is it trying to create unix sockets in current directory?
232
+ # https://stackoverflow.com/questions/30302021/rails-runner-without-spring
233
+ ChildProcessHelper.check_call(%w(bin/spring binstub --remove --all), env: clean_env)
234
+ end
235
+
236
+ def clean_env
237
+ @clean_env ||= Hash[ENV.keys.grep(/BUNDLE|RUBYOPT/).map { |k| [k, nil ] }]
238
+ end
239
+
240
+ def wait_for_port(port, timeout)
241
+ deadline = Time.now + timeout
242
+ loop do
243
+ begin
244
+ Socket.tcp('localhost', port, nil, nil, connect_timeout: 0.5) do |socket|
245
+ return
246
+ end
247
+ rescue IOError, SystemCallError
248
+ if Time.now > deadline
249
+ raise
250
+ end
251
+ end
252
+ end
253
+ end
254
+ end