mongoid 7.0.4 → 7.0.10
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.tar.gz.sig +0 -0
- data/LICENSE +1 -0
- data/README.md +3 -2
- data/Rakefile +26 -0
- data/lib/mongoid.rb +2 -1
- data/lib/mongoid/association/embedded/embeds_many.rb +2 -1
- data/lib/mongoid/association/embedded/embeds_one.rb +2 -1
- data/lib/mongoid/association/proxy.rb +1 -1
- data/lib/mongoid/atomic.rb +13 -3
- data/lib/mongoid/atomic/paths/embedded.rb +1 -1
- data/lib/mongoid/attributes.rb +28 -20
- data/lib/mongoid/attributes/dynamic.rb +15 -14
- data/lib/mongoid/clients/sessions.rb +20 -4
- data/lib/mongoid/config/environment.rb +21 -8
- data/lib/mongoid/criteria.rb +7 -1
- data/lib/mongoid/criteria/modifiable.rb +13 -2
- data/lib/mongoid/criteria/queryable/extensions/numeric.rb +1 -1
- data/lib/mongoid/criteria/queryable/extensions/regexp.rb +3 -3
- data/lib/mongoid/criteria/queryable/extensions/time.rb +1 -1
- data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +12 -0
- data/lib/mongoid/criteria/queryable/key.rb +67 -8
- data/lib/mongoid/criteria/queryable/mergeable.rb +5 -4
- data/lib/mongoid/criteria/queryable/selectable.rb +3 -4
- data/lib/mongoid/criteria/queryable/selector.rb +9 -31
- data/lib/mongoid/extensions/hash.rb +4 -2
- data/lib/mongoid/extensions/regexp.rb +1 -1
- data/lib/mongoid/extensions/string.rb +2 -2
- data/lib/mongoid/fields.rb +2 -1
- data/lib/mongoid/matchable.rb +14 -15
- data/lib/mongoid/matchable/all.rb +4 -3
- data/lib/mongoid/matchable/default.rb +71 -24
- data/lib/mongoid/matchable/regexp.rb +2 -2
- data/lib/mongoid/persistable/pushable.rb +11 -2
- data/lib/mongoid/persistence_context.rb +6 -6
- data/lib/mongoid/positional.rb +1 -1
- data/lib/mongoid/query_cache.rb +24 -11
- data/lib/mongoid/validatable/macros.rb +1 -1
- data/lib/mongoid/validatable/uniqueness.rb +1 -1
- data/lib/mongoid/version.rb +2 -1
- data/lib/rails/generators/mongoid/model/templates/model.rb.tt +1 -1
- data/spec/README.md +18 -0
- data/spec/app/models/delegating_patient.rb +16 -0
- data/spec/integration/app_spec.rb +192 -0
- data/spec/integration/associations/embedded_spec.rb +62 -0
- data/spec/integration/criteria/date_field_spec.rb +41 -0
- data/spec/integration/criteria/time_with_zone_spec.rb +32 -0
- data/spec/integration/document_spec.rb +22 -0
- data/spec/integration/matchable_spec.rb +680 -0
- data/spec/lite_spec_helper.rb +15 -5
- data/spec/mongoid/association/embedded/embeds_many_models.rb +53 -0
- data/spec/mongoid/association/embedded/embeds_many_spec.rb +10 -0
- data/spec/mongoid/association/embedded/embeds_one_spec.rb +0 -2
- data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +140 -1
- data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +105 -0
- data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +2 -1
- data/spec/mongoid/attributes/dynamic_spec.rb +153 -0
- data/spec/mongoid/attributes_spec.rb +19 -7
- data/spec/mongoid/clients/factory_spec.rb +2 -2
- data/spec/mongoid/clients/options_spec.rb +4 -4
- data/spec/mongoid/clients/sessions_spec.rb +20 -7
- data/spec/mongoid/clients/transactions_spec.rb +36 -15
- data/spec/mongoid/clients_spec.rb +2 -2
- data/spec/mongoid/contextual/atomic_spec.rb +20 -10
- data/spec/mongoid/contextual/geo_near_spec.rb +12 -2
- data/spec/mongoid/contextual/map_reduce_spec.rb +20 -5
- data/spec/mongoid/contextual/mongo_spec.rb +76 -53
- data/spec/mongoid/criteria/modifiable_spec.rb +59 -10
- data/spec/mongoid/criteria/queryable/extensions/numeric_spec.rb +54 -0
- data/spec/mongoid/criteria/queryable/extensions/regexp_spec.rb +7 -7
- data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +1 -1
- data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +19 -7
- data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +28 -1
- data/spec/mongoid/criteria/queryable/key_spec.rb +48 -6
- data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +762 -0
- data/spec/mongoid/criteria/queryable/selectable_spec.rb +5 -224
- data/spec/mongoid/criteria/queryable/selector_spec.rb +37 -0
- data/spec/mongoid/criteria_spec.rb +7 -2
- data/spec/mongoid/document_fields_spec.rb +88 -0
- data/spec/mongoid/document_persistence_context_spec.rb +33 -0
- data/spec/mongoid/indexable_spec.rb +6 -4
- data/spec/mongoid/matchable/default_spec.rb +10 -3
- data/spec/mongoid/matchable/regexp_spec.rb +2 -2
- data/spec/mongoid/matchable_spec.rb +2 -2
- data/spec/mongoid/persistable/pushable_spec.rb +55 -1
- data/spec/mongoid/query_cache_spec.rb +62 -8
- data/spec/mongoid/relations/proxy_spec.rb +1 -1
- data/spec/mongoid/scopable_spec.rb +2 -1
- data/spec/mongoid/tasks/database_rake_spec.rb +13 -13
- data/spec/mongoid/tasks/database_spec.rb +1 -1
- data/spec/mongoid/validatable/uniqueness_spec.rb +33 -6
- data/spec/spec_helper.rb +4 -37
- data/spec/support/child_process_helper.rb +76 -0
- data/spec/support/cluster_config.rb +158 -0
- data/spec/support/constraints.rb +201 -30
- data/spec/support/expectations.rb +17 -3
- data/spec/support/spec_config.rb +12 -4
- metadata +490 -454
- metadata.gz.sig +0 -0
|
@@ -20,52 +20,99 @@ module Mongoid
|
|
|
20
20
|
@attribute, @document = attribute, document
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
#
|
|
24
|
-
#
|
|
23
|
+
# Checks whether the attribute matches the value, using the default
|
|
24
|
+
# MongoDB matching logic (i.e., when no operator is specified in the
|
|
25
|
+
# criteria).
|
|
25
26
|
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
27
|
+
# If attribute and value are both of basic types like string or number,
|
|
28
|
+
# this method returns true if and only if the attribute equals the value.
|
|
28
29
|
#
|
|
29
|
-
#
|
|
30
|
+
# Value can also be of a type like Regexp or Range which defines
|
|
31
|
+
# more complex matching/inclusion behavior via the === operator.
|
|
32
|
+
# If so, and attribute is still of a basic type like string or number,
|
|
33
|
+
# this method returns true if and only if the value's === operator
|
|
34
|
+
# returns true for the attribute. For example, this method returns true
|
|
35
|
+
# if attribute is a string and value is a Regexp and attribute matches
|
|
36
|
+
# the value, of if attribute is a number and value is a Range and
|
|
37
|
+
# the value includes the attribute.
|
|
30
38
|
#
|
|
31
|
-
#
|
|
39
|
+
# If attribute is an array and value is not an array, the checks just
|
|
40
|
+
# described (i.e. the === operator invocation) are performed on each item
|
|
41
|
+
# of the attribute array. If any of the items in the attribute match
|
|
42
|
+
# the value according to the value type's === operator, this method
|
|
43
|
+
# returns true.
|
|
44
|
+
#
|
|
45
|
+
# If attribute and value are both arrays, this method returns true if and
|
|
46
|
+
# only if the arrays are equal (including the order of the elements).
|
|
47
|
+
#
|
|
48
|
+
# @param [ Object ] value The value to check.
|
|
49
|
+
#
|
|
50
|
+
# @return [ true, false ] True if attribute matches the value, false if not.
|
|
32
51
|
#
|
|
33
52
|
# @since 1.0.0
|
|
34
53
|
def _matches?(value)
|
|
35
|
-
attribute.is_a?(Array) && !value.is_a?(Array)
|
|
54
|
+
if attribute.is_a?(Array) && !value.is_a?(Array)
|
|
55
|
+
attribute.any? { |_attribute| value === _attribute }
|
|
56
|
+
else
|
|
57
|
+
value === attribute
|
|
58
|
+
end
|
|
36
59
|
end
|
|
37
60
|
|
|
38
61
|
protected
|
|
39
62
|
|
|
40
|
-
#
|
|
63
|
+
# Given a condition, which is a one-element hash consisting of an
|
|
64
|
+
# operator and a value like {'$gt' => 1}, return the value.
|
|
41
65
|
#
|
|
42
|
-
# @example Get the
|
|
43
|
-
# matcher.
|
|
66
|
+
# @example Get the condition value.
|
|
67
|
+
# matcher.condition_value({'$gt' => 1})
|
|
68
|
+
# # => 1
|
|
44
69
|
#
|
|
45
|
-
# @param [ Hash ]
|
|
70
|
+
# @param [ Hash ] condition The condition.
|
|
46
71
|
#
|
|
47
|
-
# @return [ Object ] The
|
|
72
|
+
# @return [ Object ] The value of the condition.
|
|
48
73
|
#
|
|
49
74
|
# @since 1.0.0
|
|
50
|
-
def
|
|
51
|
-
|
|
75
|
+
def condition_value(condition)
|
|
76
|
+
unless condition.is_a?(Hash)
|
|
77
|
+
raise ArgumentError, 'Condition must be a hash'
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
unless condition.length == 1
|
|
81
|
+
raise ArgumentError, 'Condition must have one element'
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
condition.values.first
|
|
52
85
|
end
|
|
53
86
|
|
|
54
|
-
#
|
|
87
|
+
# Determines whether the attribute value stored in this matcher
|
|
88
|
+
# satisfies the provided condition using the provided operator.
|
|
89
|
+
#
|
|
90
|
+
# For example, given an instance of Gt matcher with the @attribute of
|
|
91
|
+
# 2, the matcher is set up to answer whether the attribute is
|
|
92
|
+
# greater than some input value. This input value is provided in
|
|
93
|
+
# the condition, which could be {"$gt" => 1}, and the operator is
|
|
94
|
+
# provided (somewhat in a duplicate fashion) in the operator argument,
|
|
95
|
+
# in this case :>.
|
|
55
96
|
#
|
|
56
|
-
# @example
|
|
57
|
-
# matcher.
|
|
97
|
+
# @example
|
|
98
|
+
# matcher = Matchable::Gt.new(2)
|
|
99
|
+
# matcher.determine({'$gt' => 1}, :>)
|
|
100
|
+
# # => true
|
|
58
101
|
#
|
|
59
|
-
# @param [
|
|
60
|
-
#
|
|
102
|
+
# @param [ Hash ] condition The condition to evaluate. This must be
|
|
103
|
+
# a one-element hash; the key is ignored, and the value is passed
|
|
104
|
+
# as the argument to the operator.
|
|
105
|
+
# @param [ Symbol, String ] operator The comparison operator or method.
|
|
106
|
+
# The operator is invoked on the attribute stored in the matcher
|
|
107
|
+
# instance.
|
|
61
108
|
#
|
|
62
|
-
# @return [ true, false ]
|
|
109
|
+
# @return [ true, false ] Result of condition evaluation.
|
|
63
110
|
#
|
|
64
111
|
# @since 1.0.0
|
|
65
|
-
def determine(
|
|
66
|
-
attribute.__array__.any?
|
|
67
|
-
attr
|
|
68
|
-
|
|
112
|
+
def determine(condition, operator)
|
|
113
|
+
attribute.__array__.any? do |attr|
|
|
114
|
+
attr && attr.send(operator, condition_value(condition))
|
|
115
|
+
end
|
|
69
116
|
end
|
|
70
117
|
end
|
|
71
118
|
end
|
|
@@ -7,8 +7,8 @@ module Mongoid
|
|
|
7
7
|
# Does the supplied query match the attribute?
|
|
8
8
|
#
|
|
9
9
|
# @example Does this match?
|
|
10
|
-
# matcher._matches?(
|
|
11
|
-
# matcher._matches?(BSON::Regex::Raw.new("
|
|
10
|
+
# matcher._matches?(/\AEm/)
|
|
11
|
+
# matcher._matches?(BSON::Regex::Raw.new("\\AEm"))
|
|
12
12
|
#
|
|
13
13
|
# @param [ BSON::Regexp::Raw, Regexp ] regexp The regular expression object.
|
|
14
14
|
#
|
|
@@ -22,7 +22,13 @@ module Mongoid
|
|
|
22
22
|
def add_to_set(adds)
|
|
23
23
|
prepare_atomic_operation do |ops|
|
|
24
24
|
process_atomic_operations(adds) do |field, value|
|
|
25
|
-
existing = send(field) ||
|
|
25
|
+
existing = send(field) || attributes[field]
|
|
26
|
+
if existing.nil?
|
|
27
|
+
attributes[field] = []
|
|
28
|
+
# Read the value out of attributes:
|
|
29
|
+
# https://jira.mongodb.org/browse/MONGOID-4874
|
|
30
|
+
existing = attributes[field]
|
|
31
|
+
end
|
|
26
32
|
values = [ value ].flatten(1)
|
|
27
33
|
values.each do |val|
|
|
28
34
|
existing.push(val) unless existing.include?(val)
|
|
@@ -49,7 +55,10 @@ module Mongoid
|
|
|
49
55
|
def push(pushes)
|
|
50
56
|
prepare_atomic_operation do |ops|
|
|
51
57
|
process_atomic_operations(pushes) do |field, value|
|
|
52
|
-
existing = send(field) ||
|
|
58
|
+
existing = send(field) || begin
|
|
59
|
+
attributes[field] ||= []
|
|
60
|
+
attributes[field]
|
|
61
|
+
end
|
|
53
62
|
values = [ value ].flatten(1)
|
|
54
63
|
values.each{ |val| existing.push(val) }
|
|
55
64
|
ops[atomic_attribute_name(field)] = { "$each" => values }
|
|
@@ -116,6 +116,12 @@ module Mongoid
|
|
|
116
116
|
client.with(client_options))
|
|
117
117
|
end
|
|
118
118
|
|
|
119
|
+
def client_name
|
|
120
|
+
@client_name ||= options[:client] ||
|
|
121
|
+
Threaded.client_override ||
|
|
122
|
+
storage_options && __evaluate__(storage_options[:client])
|
|
123
|
+
end
|
|
124
|
+
|
|
119
125
|
# Determine if this persistence context is equal to another.
|
|
120
126
|
#
|
|
121
127
|
# @example Compare two persistence contexts.
|
|
@@ -133,12 +139,6 @@ module Mongoid
|
|
|
133
139
|
|
|
134
140
|
private
|
|
135
141
|
|
|
136
|
-
def client_name
|
|
137
|
-
@client_name ||= options[:client] ||
|
|
138
|
-
Threaded.client_override ||
|
|
139
|
-
storage_options && __evaluate__(storage_options[:client])
|
|
140
|
-
end
|
|
141
|
-
|
|
142
142
|
def set_options!(opts)
|
|
143
143
|
@options ||= opts.each.reduce({}) do |_options, (key, value)|
|
|
144
144
|
unless VALID_OPTIONS.include?(key.to_sym)
|
data/lib/mongoid/positional.rb
CHANGED
data/lib/mongoid/query_cache.rb
CHANGED
|
@@ -166,7 +166,8 @@ module Mongoid
|
|
|
166
166
|
@coll_name ||= result.namespace.sub("#{database.name}.", '') if result.namespace
|
|
167
167
|
documents = result.documents
|
|
168
168
|
if @cursor_id.zero? && !@after_first_batch
|
|
169
|
-
|
|
169
|
+
@cached_documents ||= []
|
|
170
|
+
@cached_documents.concat(documents)
|
|
170
171
|
end
|
|
171
172
|
@after_first_batch = true
|
|
172
173
|
documents
|
|
@@ -229,14 +230,29 @@ module Mongoid
|
|
|
229
230
|
unless cursor = cached_cursor
|
|
230
231
|
read_with_retry do
|
|
231
232
|
server = server_selector.select_server(cluster)
|
|
232
|
-
|
|
233
|
-
|
|
233
|
+
result = send_initial_query(server)
|
|
234
|
+
if result.cursor_id == 0 || result.cursor_id.nil?
|
|
235
|
+
cursor = CachedCursor.new(view, result, server)
|
|
236
|
+
QueryCache.cache_table[cache_key] = cursor
|
|
237
|
+
else
|
|
238
|
+
cursor = Mongo::Cursor.new(view, result, server)
|
|
239
|
+
end
|
|
234
240
|
end
|
|
235
241
|
end
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
242
|
+
|
|
243
|
+
if block_given?
|
|
244
|
+
if limit && limit != -1
|
|
245
|
+
cursor.to_a[0...limit].each do |doc|
|
|
246
|
+
yield doc
|
|
247
|
+
end
|
|
248
|
+
else
|
|
249
|
+
cursor.each do |doc|
|
|
250
|
+
yield doc
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
else
|
|
254
|
+
cursor
|
|
255
|
+
end
|
|
240
256
|
end
|
|
241
257
|
end
|
|
242
258
|
|
|
@@ -246,9 +262,6 @@ module Mongoid
|
|
|
246
262
|
if limit
|
|
247
263
|
key = [ collection.namespace, selector, nil, skip, sort, projection, collation ]
|
|
248
264
|
cursor = QueryCache.cache_table[key]
|
|
249
|
-
if cursor
|
|
250
|
-
cursor.to_a[0...limit.abs]
|
|
251
|
-
end
|
|
252
265
|
end
|
|
253
266
|
cursor || QueryCache.cache_table[cache_key]
|
|
254
267
|
end
|
|
@@ -258,7 +271,7 @@ module Mongoid
|
|
|
258
271
|
end
|
|
259
272
|
|
|
260
273
|
def system_collection?
|
|
261
|
-
collection.namespace =~
|
|
274
|
+
collection.namespace =~ /\Asystem./
|
|
262
275
|
end
|
|
263
276
|
end
|
|
264
277
|
|
|
@@ -48,7 +48,7 @@ module Mongoid
|
|
|
48
48
|
# include Mongoid::Document
|
|
49
49
|
# field :title
|
|
50
50
|
#
|
|
51
|
-
# validates_format_of :title, with:
|
|
51
|
+
# validates_format_of :title, with: /\A[a-z0-9 \-_]*\z/i
|
|
52
52
|
# end
|
|
53
53
|
#
|
|
54
54
|
# @param [ Array ] args The names of the fields to validate.
|
|
@@ -148,7 +148,7 @@ module Mongoid
|
|
|
148
148
|
#
|
|
149
149
|
# @since 2.3.0
|
|
150
150
|
def filter(value)
|
|
151
|
-
!case_sensitive? && value ? /\A#{Regexp.escape(value.to_s)}
|
|
151
|
+
!case_sensitive? && value ? /\A#{Regexp.escape(value.to_s)}\z/i : value
|
|
152
152
|
end
|
|
153
153
|
|
|
154
154
|
# Scope the criteria to the scope options provided.
|
data/lib/mongoid/version.rb
CHANGED
|
@@ -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
|
-
|
|
16
|
+
belongs_to :<%= attribute.name%>
|
|
17
17
|
<% end -%>
|
|
18
18
|
end
|
|
19
19
|
<% end -%>
|
data/spec/README.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Running Mongoid Tests
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
### Quick Start
|
|
5
|
+
Spin up a MongoDB deployment against which to run the Mongoid specs. Mongoid specs support a variety of MongoDB topologies, but the simplest is a single MongoDB instance:
|
|
6
|
+
|
|
7
|
+
# Launch mongod in one terminal
|
|
8
|
+
mkdir /tmp/mdb
|
|
9
|
+
mongod --dbpath /tmp/mdb
|
|
10
|
+
|
|
11
|
+
Run the test suite in a separate terminal:
|
|
12
|
+
|
|
13
|
+
rake
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
## Caveats
|
|
17
|
+
### "Too many open files" error
|
|
18
|
+
On MacOS, you may encounter a "Too many open files" error on the MongoDB server when running the tests. If this happens, stop the server, run the command `ulimit -n 10000` in the same terminal session as the server, and restart the server. This will increase the number of files that can be opened. Then, re-run the tests.
|
|
@@ -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
|
|
@@ -0,0 +1,192 @@
|
|
|
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), 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
|
+
def clone_application(repo_url, subdir: nil, rails_version: nil)
|
|
120
|
+
Dir.chdir(TMP_BASE) do
|
|
121
|
+
FileUtils.rm_rf(File.basename(repo_url))
|
|
122
|
+
ChildProcessHelper.check_call(%w(git clone) + [repo_url])
|
|
123
|
+
Dir.chdir(File.join(*[File.basename(repo_url), subdir].compact)) do
|
|
124
|
+
adjust_app_gemfile(rails_version: rails_version)
|
|
125
|
+
ChildProcessHelper.check_call(%w(bundle install), env: clean_env)
|
|
126
|
+
puts `git diff`
|
|
127
|
+
|
|
128
|
+
config = {'development' => {'clients' => {'default' => {'uri' => SpecConfig.instance.uri_str}}}}
|
|
129
|
+
File.open('config/mongoid.yml', 'w') do |f|
|
|
130
|
+
f << YAML.dump(config)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
yield
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def adjust_app_gemfile(rails_version: nil)
|
|
139
|
+
lock_lines = IO.readlines('Gemfile.lock')
|
|
140
|
+
# Get rid of the bundled with line so that whatever bundler is installed
|
|
141
|
+
# on the system is usable with the application.
|
|
142
|
+
if i = lock_lines.index("BUNDLED WITH\n")
|
|
143
|
+
lock_lines.slice!(i, 2)
|
|
144
|
+
File.open('Gemfile.lock', 'w') do |f|
|
|
145
|
+
f << lock_lines.join
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
gemfile_lines = IO.readlines('Gemfile')
|
|
150
|
+
gemfile_lines.delete_if do |line|
|
|
151
|
+
line =~ /mongoid/
|
|
152
|
+
end
|
|
153
|
+
gemfile_lines << "gem 'mongoid', path: '#{File.expand_path(BASE)}'\n"
|
|
154
|
+
if rails_version
|
|
155
|
+
gemfile_lines.delete_if do |line|
|
|
156
|
+
line =~ /rails/
|
|
157
|
+
end
|
|
158
|
+
gemfile_lines << "gem 'rails', '#{rails_version}'\n"
|
|
159
|
+
end
|
|
160
|
+
File.open('Gemfile', 'w') do |f|
|
|
161
|
+
f << gemfile_lines.join
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def remove_spring
|
|
166
|
+
# Spring produces this error in Evergreen:
|
|
167
|
+
# /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:
|
|
168
|
+
# in `initialize': too long unix socket path (126bytes given but 108bytes max) (ArgumentError)
|
|
169
|
+
# Is it trying to create unix sockets in current directory?
|
|
170
|
+
# https://stackoverflow.com/questions/30302021/rails-runner-without-spring
|
|
171
|
+
ChildProcessHelper.check_call(%w(bin/spring binstub --remove --all), env: clean_env)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def clean_env
|
|
175
|
+
@clean_env ||= Hash[ENV.keys.grep(/BUNDLE|RUBYOPT/).map { |k| [k, nil ] }]
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def wait_for_port(port, timeout)
|
|
179
|
+
deadline = Time.now + timeout
|
|
180
|
+
loop do
|
|
181
|
+
begin
|
|
182
|
+
Socket.tcp('localhost', port, nil, nil, connect_timeout: 0.5) do |socket|
|
|
183
|
+
return
|
|
184
|
+
end
|
|
185
|
+
rescue IOError, SystemCallError
|
|
186
|
+
if Time.now > deadline
|
|
187
|
+
raise
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|