mongo 2.3.1 → 2.4.0.rc0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (170) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +2 -3
  4. data/lib/mongo/bulk_write.rb +8 -7
  5. data/lib/mongo/bulk_write/combineable.rb +4 -0
  6. data/lib/mongo/bulk_write/transformable.rb +17 -5
  7. data/lib/mongo/bulk_write/validatable.rb +1 -0
  8. data/lib/mongo/client.rb +3 -0
  9. data/lib/mongo/cluster.rb +8 -0
  10. data/lib/mongo/cluster/app_metadata.rb +135 -0
  11. data/lib/mongo/collection.rb +42 -10
  12. data/lib/mongo/collection/view.rb +15 -1
  13. data/lib/mongo/collection/view/aggregation.rb +5 -0
  14. data/lib/mongo/collection/view/builder/aggregation.rb +13 -3
  15. data/lib/mongo/collection/view/builder/find_command.rb +7 -21
  16. data/lib/mongo/collection/view/builder/map_reduce.rb +22 -5
  17. data/lib/mongo/collection/view/iterable.rb +1 -0
  18. data/lib/mongo/collection/view/map_reduce.rb +5 -0
  19. data/lib/mongo/collection/view/readable.rb +35 -14
  20. data/lib/mongo/collection/view/writable.rb +54 -23
  21. data/lib/mongo/cursor/builder/get_more_command.rb +2 -3
  22. data/lib/mongo/database.rb +10 -2
  23. data/lib/mongo/error.rb +2 -0
  24. data/lib/mongo/error/invalid_application_name.rb +38 -0
  25. data/lib/mongo/error/invalid_server_preference.rb +24 -3
  26. data/lib/mongo/error/unsupported_collation.rb +51 -0
  27. data/lib/mongo/index/view.rb +28 -15
  28. data/lib/mongo/operation.rb +6 -0
  29. data/lib/mongo/operation/commands.rb +3 -0
  30. data/lib/mongo/operation/commands/aggregate.rb +10 -10
  31. data/lib/mongo/operation/commands/create.rb +45 -0
  32. data/lib/mongo/operation/commands/drop.rb +45 -0
  33. data/lib/mongo/operation/commands/drop_database.rb +45 -0
  34. data/lib/mongo/operation/commands/map_reduce.rb +12 -1
  35. data/lib/mongo/operation/commands/parallel_scan.rb +1 -0
  36. data/lib/mongo/operation/read_preference.rb +9 -9
  37. data/lib/mongo/operation/specifiable.rb +34 -0
  38. data/lib/mongo/operation/takes_write_concern.rb +35 -0
  39. data/lib/mongo/operation/write/bulk/bulkable.rb +1 -1
  40. data/lib/mongo/operation/write/command/create_index.rb +6 -0
  41. data/lib/mongo/operation/write/command/drop_index.rb +6 -0
  42. data/lib/mongo/operation/write/command/insert.rb +1 -1
  43. data/lib/mongo/operation/write/command/update.rb +1 -0
  44. data/lib/mongo/operation/write/command/writable.rb +2 -2
  45. data/lib/mongo/operation/write/create_index.rb +2 -2
  46. data/lib/mongo/operation/write/create_user.rb +1 -1
  47. data/lib/mongo/operation/write/delete.rb +5 -1
  48. data/lib/mongo/operation/write/gle.rb +1 -1
  49. data/lib/mongo/operation/write/insert.rb +2 -2
  50. data/lib/mongo/operation/write/remove_user.rb +1 -1
  51. data/lib/mongo/operation/write/update.rb +5 -1
  52. data/lib/mongo/operation/write/update_user.rb +1 -1
  53. data/lib/mongo/operation/write/write_command_enabled.rb +10 -2
  54. data/lib/mongo/protocol/insert.rb +1 -2
  55. data/lib/mongo/protocol/query.rb +3 -7
  56. data/lib/mongo/server.rb +8 -3
  57. data/lib/mongo/server/connection.rb +17 -11
  58. data/lib/mongo/server/description.rb +22 -0
  59. data/lib/mongo/server/description/features.rb +2 -0
  60. data/lib/mongo/server/monitor.rb +5 -0
  61. data/lib/mongo/server/monitor/connection.rb +11 -0
  62. data/lib/mongo/server_selector/nearest.rb +9 -6
  63. data/lib/mongo/server_selector/primary.rb +4 -0
  64. data/lib/mongo/server_selector/primary_preferred.rb +7 -1
  65. data/lib/mongo/server_selector/secondary.rb +5 -0
  66. data/lib/mongo/server_selector/secondary_preferred.rb +7 -2
  67. data/lib/mongo/server_selector/selectable.rb +57 -10
  68. data/lib/mongo/socket/ssl.rb +1 -0
  69. data/lib/mongo/uri.rb +4 -0
  70. data/lib/mongo/version.rb +1 -1
  71. data/lib/mongo/write_concern.rb +1 -0
  72. data/mongo.gemspec +1 -1
  73. data/spec/mongo/auth/cr_spec.rb +7 -1
  74. data/spec/mongo/auth/ldap_spec.rb +7 -1
  75. data/spec/mongo/auth/scram_spec.rb +7 -1
  76. data/spec/mongo/auth/x509_spec.rb +7 -1
  77. data/spec/mongo/bulk_write_spec.rb +598 -5
  78. data/spec/mongo/client_spec.rb +47 -1
  79. data/spec/mongo/cluster/app_metadata_spec.rb +104 -0
  80. data/spec/mongo/cluster/topology/replica_set_spec.rb +14 -8
  81. data/spec/mongo/cluster/topology/sharded_spec.rb +9 -3
  82. data/spec/mongo/cluster/topology/single_spec.rb +10 -4
  83. data/spec/mongo/cluster_spec.rb +29 -0
  84. data/spec/mongo/collection/view/aggregation_spec.rb +139 -0
  85. data/spec/mongo/collection/view/builder/find_command_spec.rb +6 -243
  86. data/spec/mongo/collection/view/map_reduce_spec.rb +104 -0
  87. data/spec/mongo/collection/view/readable_spec.rb +83 -0
  88. data/spec/mongo/collection/view/writable_spec.rb +447 -1
  89. data/spec/mongo/collection/view_spec.rb +57 -0
  90. data/spec/mongo/collection_spec.rb +926 -101
  91. data/spec/mongo/crud_spec.rb +4 -5
  92. data/spec/mongo/database_spec.rb +99 -1
  93. data/spec/mongo/index/view_spec.rb +360 -31
  94. data/spec/mongo/max_staleness_spec.rb +108 -0
  95. data/spec/mongo/operation/read_preference_spec.rb +8 -8
  96. data/spec/mongo/operation/write/command/delete_spec.rb +1 -1
  97. data/spec/mongo/operation/write/command/insert_spec.rb +1 -1
  98. data/spec/mongo/operation/write/command/update_spec.rb +1 -1
  99. data/spec/mongo/server/connection_pool_spec.rb +3 -1
  100. data/spec/mongo/server/connection_spec.rb +17 -7
  101. data/spec/mongo/server/description/features_spec.rb +50 -0
  102. data/spec/mongo/server/description_spec.rb +9 -3
  103. data/spec/mongo/server_selection_spec.rb +5 -3
  104. data/spec/mongo/server_selector/nearest_spec.rb +73 -0
  105. data/spec/mongo/server_selector/primary_preferred_spec.rb +73 -0
  106. data/spec/mongo/server_selector/primary_spec.rb +36 -0
  107. data/spec/mongo/server_selector/secondary_preferred_spec.rb +73 -0
  108. data/spec/mongo/server_selector/secondary_spec.rb +73 -0
  109. data/spec/mongo/server_selector_spec.rb +53 -0
  110. data/spec/mongo/server_spec.rb +3 -1
  111. data/spec/mongo/uri_spec.rb +54 -0
  112. data/spec/mongo/write_concern_spec.rb +18 -0
  113. data/spec/spec_helper.rb +10 -0
  114. data/spec/support/authorization.rb +8 -1
  115. data/spec/support/crud.rb +15 -0
  116. data/spec/support/crud/read.rb +27 -19
  117. data/spec/support/crud/write.rb +28 -3
  118. data/spec/support/crud_tests/read/aggregate.yml +15 -3
  119. data/spec/support/crud_tests/read/count.yml +14 -3
  120. data/spec/support/crud_tests/read/distinct.yml +13 -1
  121. data/spec/support/crud_tests/read/find.yml +12 -2
  122. data/spec/support/crud_tests/write/deleteMany.yml +22 -1
  123. data/spec/support/crud_tests/write/deleteOne.yml +20 -1
  124. data/spec/support/crud_tests/write/findOneAndDelete.yml +27 -2
  125. data/spec/support/crud_tests/write/findOneAndReplace.yml +43 -14
  126. data/spec/support/crud_tests/write/findOneAndUpdate.yml +50 -8
  127. data/spec/support/crud_tests/write/replaceOne.yml +34 -10
  128. data/spec/support/crud_tests/write/updateMany.yml +42 -11
  129. data/spec/support/crud_tests/write/updateOne.yml +32 -7
  130. data/spec/support/max_staleness/ReplicaSetNoPrimary/DefaultNoMaxStaleness.yml +26 -0
  131. data/spec/support/max_staleness/ReplicaSetNoPrimary/Incompatible.yml +25 -0
  132. data/spec/support/max_staleness/ReplicaSetNoPrimary/LastUpdateTime.yml +33 -0
  133. data/spec/support/max_staleness/ReplicaSetNoPrimary/Nearest.yml +33 -0
  134. data/spec/support/max_staleness/ReplicaSetNoPrimary/Nearest2.yml +33 -0
  135. data/spec/support/max_staleness/ReplicaSetNoPrimary/PrimaryPreferred.yml +27 -0
  136. data/spec/support/max_staleness/ReplicaSetNoPrimary/PrimaryPreferred_tags.yml +36 -0
  137. data/spec/support/max_staleness/ReplicaSetNoPrimary/Secondary.yml +51 -0
  138. data/spec/support/max_staleness/ReplicaSetNoPrimary/SecondaryPreferred.yml +26 -0
  139. data/spec/support/max_staleness/ReplicaSetNoPrimary/SecondaryPreferred_tags.yml +51 -0
  140. data/spec/support/max_staleness/ReplicaSetWithPrimary/DefaultNoMaxStaleness.yml +26 -0
  141. data/spec/support/max_staleness/ReplicaSetWithPrimary/Incompatible.yml +25 -0
  142. data/spec/support/max_staleness/ReplicaSetWithPrimary/LastUpdateTime.yml +35 -0
  143. data/spec/support/max_staleness/ReplicaSetWithPrimary/MaxStalenessTooSmall.yml +25 -0
  144. data/spec/support/max_staleness/ReplicaSetWithPrimary/MaxStalenessWithModePrimary.yml +23 -0
  145. data/spec/support/max_staleness/ReplicaSetWithPrimary/Nearest.yml +33 -0
  146. data/spec/support/max_staleness/ReplicaSetWithPrimary/Nearest2.yml +33 -0
  147. data/spec/support/max_staleness/ReplicaSetWithPrimary/Nearest_tags.yml +36 -0
  148. data/spec/support/max_staleness/ReplicaSetWithPrimary/PrimaryPreferred.yml +27 -0
  149. data/spec/support/max_staleness/ReplicaSetWithPrimary/PrimaryPreferred_incompatible.yml +27 -0
  150. data/spec/support/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred.yml +26 -0
  151. data/spec/support/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred_tags.yml +59 -0
  152. data/spec/support/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred_tags2.yml +43 -0
  153. data/spec/support/max_staleness/ReplicaSetWithPrimary/Secondary_tags.yml +59 -0
  154. data/spec/support/max_staleness/ReplicaSetWithPrimary/Secondary_tags2.yml +43 -0
  155. data/spec/support/max_staleness/ReplicaSetWithPrimary/ShortHeartbeartShortMaxStaleness.yml +29 -0
  156. data/spec/support/max_staleness/ReplicaSetWithPrimary/ShortHeartbeartShortMaxStaleness2.yml +29 -0
  157. data/spec/support/max_staleness/ReplicaSetWithPrimary/ZeroMaxStaleness.yml +27 -0
  158. data/spec/support/max_staleness/Sharded/Incompatible.yml +25 -0
  159. data/spec/support/max_staleness/Sharded/SmallMaxStaleness.yml +20 -0
  160. data/spec/support/max_staleness/Single/Incompatible.yml +18 -0
  161. data/spec/support/max_staleness/Single/SmallMaxStaleness.yml +20 -0
  162. data/spec/support/server_selection.rb +25 -0
  163. data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/Nearest_multiple.yml +27 -0
  164. data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/Secondary_multi_tags.yml +31 -0
  165. data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/Secondary_multi_tags2.yml +31 -0
  166. data/spec/support/server_selection/selection/ReplicaSetWithPrimary/read/Nearest_multiple.yml +34 -0
  167. data/spec/support/server_selection/selection/ReplicaSetWithPrimary/read/SecondaryPreferred_tags.yml +28 -0
  168. data/spec/support/shared/server_selector.rb +4 -3
  169. metadata +91 -6
  170. metadata.gz.sig +0 -0
@@ -260,6 +260,17 @@ describe Mongo::Client do
260
260
  expect(client.cluster.logger).to_not eq(Mongo::Logger.logger)
261
261
  end
262
262
  end
263
+
264
+ context 'when providing a heartbeat_frequency' do
265
+
266
+ let(:client) do
267
+ described_class.new(['127.0.0.1:27017'], :heartbeat_frequency => 2)
268
+ end
269
+
270
+ it 'sets the heartbeat frequency' do
271
+ expect(client.cluster.options[:heartbeat_frequency]).to eq(client.options[:heartbeat_frequency])
272
+ end
273
+ end
263
274
  end
264
275
 
265
276
  context 'when providing a connection string' do
@@ -557,6 +568,41 @@ describe Mongo::Client do
557
568
  end
558
569
  end
559
570
 
571
+ context 'when the app_name is changed' do
572
+
573
+ let(:client) do
574
+ authorized_client
575
+ end
576
+
577
+ let!(:original_options) do
578
+ client.options
579
+ end
580
+
581
+ let(:new_options) do
582
+ { app_name: 'reports' }
583
+ end
584
+
585
+ let!(:new_client) do
586
+ authorized_client.with(new_options)
587
+ end
588
+
589
+ it 'returns a new client' do
590
+ expect(new_client).not_to equal(client)
591
+ end
592
+
593
+ it 'replaces the existing options' do
594
+ expect(new_client.options).to eq(client.options.merge(new_options))
595
+ end
596
+
597
+ it 'does not modify the original client' do
598
+ expect(client.options).to eq(original_options)
599
+ end
600
+
601
+ it 'does not keep the same cluster' do
602
+ expect(new_client.cluster).not_to be(client.cluster)
603
+ end
604
+ end
605
+
560
606
  context 'when the write concern is not changed' do
561
607
 
562
608
  let(:client) do
@@ -595,7 +641,7 @@ describe Mongo::Client do
595
641
  end
596
642
 
597
643
  it 'keeps the same cluster' do
598
- expect(new_client.cluster).to equal(client.cluster)
644
+ expect(new_client.cluster).to be(client.cluster)
599
645
  end
600
646
  end
601
647
 
@@ -0,0 +1,104 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mongo::Cluster::AppMetadata do
4
+
5
+ let(:app_metadata) do
6
+ described_class.new(cluster)
7
+ end
8
+
9
+ let(:cluster) do
10
+ authorized_client.cluster
11
+ end
12
+
13
+ describe '#initialize' do
14
+
15
+ context 'when the cluster has an app name option set' do
16
+
17
+ let(:cluster) do
18
+ authorized_client.with(app_name: :reports).cluster
19
+ end
20
+
21
+ it 'sets the app name' do
22
+ expect(app_metadata.send(:full_client_document)[:application][:name]).to eq(:reports)
23
+ end
24
+
25
+ context 'when the app name exceeds the max length of 128' do
26
+
27
+ let(:cluster) do
28
+ authorized_client.with(app_name: "\u3042"*43).cluster
29
+ end
30
+
31
+ it 'raises an error' do
32
+ expect {
33
+ app_metadata.send(:validate!)
34
+ }.to raise_exception(Mongo::Error::InvalidApplicationName)
35
+ end
36
+ end
37
+ end
38
+
39
+ context 'when the cluster does not have an app name option set' do
40
+
41
+ it 'does not set the app name' do
42
+ expect(app_metadata.send(:full_client_document)[:application]).to be(nil)
43
+ end
44
+ end
45
+
46
+ context 'when the client document exceeds the max of 512 bytes' do
47
+
48
+ context 'when the os.type length is too long' do
49
+
50
+ before do
51
+ allow(app_metadata).to receive(:type).and_return('x'*500)
52
+ end
53
+
54
+ it 'truncates the document' do
55
+ expect(app_metadata.send(:ismaster_bytes)).to be_a(String)
56
+ end
57
+ end
58
+
59
+ context 'when the os.name length is too long' do
60
+
61
+ before do
62
+ allow(app_metadata).to receive(:name).and_return('x'*500)
63
+ end
64
+
65
+ it 'truncates the document' do
66
+ expect(app_metadata.send(:ismaster_bytes)).to be_a(String)
67
+ end
68
+ end
69
+
70
+ context 'when the os.architecture length is too long' do
71
+
72
+ before do
73
+ allow(app_metadata).to receive(:architecture).and_return('x'*500)
74
+ end
75
+
76
+ it 'truncates the document' do
77
+ expect(app_metadata.send(:ismaster_bytes)).to be_a(String)
78
+ end
79
+ end
80
+
81
+ context 'when the platform length is too long' do
82
+
83
+ before do
84
+ allow(app_metadata).to receive(:platform).and_return('x'*500)
85
+ end
86
+
87
+ it 'truncates the document to be just an ismaster command' do
88
+ expect(app_metadata.send(:ismaster_bytes)).to be_a(String)
89
+ end
90
+ end
91
+
92
+ context 'when the driver info is too long' do
93
+
94
+ before do
95
+ allow(app_metadata).to receive(:driver_doc).and_return('x'*500)
96
+ end
97
+
98
+ it 'truncates the document to be just an ismaster command' do
99
+ expect(app_metadata.ismaster_bytes.length).to eq(Mongo::Server::Monitor::Connection::ISMASTER_BYTES.length)
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -14,22 +14,28 @@ describe Mongo::Cluster::Topology::ReplicaSet do
14
14
  Mongo::Monitoring.new
15
15
  end
16
16
 
17
+ let(:cluster) do
18
+ double('cluster').tap do |cl|
19
+ allow(cl).to receive(:app_metadata).and_return(app_metadata)
20
+ end
21
+ end
22
+
17
23
  describe '#servers' do
18
24
 
19
25
  let(:mongos) do
20
- Mongo::Server.new(address, double('cluster'), monitoring, listeners, TEST_OPTIONS)
26
+ Mongo::Server.new(address, cluster, monitoring, listeners, TEST_OPTIONS)
21
27
  end
22
28
 
23
29
  let(:standalone) do
24
- Mongo::Server.new(address, double('cluster'), monitoring, listeners, TEST_OPTIONS)
30
+ Mongo::Server.new(address, cluster, monitoring, listeners, TEST_OPTIONS)
25
31
  end
26
32
 
27
33
  let(:replica_set) do
28
- Mongo::Server.new(address, double('cluster'), monitoring, listeners, TEST_OPTIONS)
34
+ Mongo::Server.new(address, cluster, monitoring, listeners, TEST_OPTIONS)
29
35
  end
30
36
 
31
37
  let(:replica_set_two) do
32
- Mongo::Server.new(address, double('cluster'), monitoring, listeners, TEST_OPTIONS)
38
+ Mongo::Server.new(address, cluster, monitoring, listeners, TEST_OPTIONS)
33
39
  end
34
40
 
35
41
  let(:mongos_description) do
@@ -110,11 +116,11 @@ describe Mongo::Cluster::Topology::ReplicaSet do
110
116
  describe '#add_hosts?' do
111
117
 
112
118
  let(:primary) do
113
- Mongo::Server.new(address, double('cluster'), monitoring, listeners, TEST_OPTIONS)
119
+ Mongo::Server.new(address, cluster, monitoring, listeners, TEST_OPTIONS)
114
120
  end
115
121
 
116
122
  let(:secondary) do
117
- Mongo::Server.new(address, double('cluster'), monitoring, listeners, TEST_OPTIONS)
123
+ Mongo::Server.new(address, cluster, monitoring, listeners, TEST_OPTIONS)
118
124
  end
119
125
 
120
126
  let(:primary_description) do
@@ -193,7 +199,7 @@ describe Mongo::Cluster::Topology::ReplicaSet do
193
199
  describe '#remove_hosts?' do
194
200
 
195
201
  let(:primary) do
196
- Mongo::Server.new(address, double('cluster'), monitoring, listeners, TEST_OPTIONS)
202
+ Mongo::Server.new(address, cluster, monitoring, listeners, TEST_OPTIONS)
197
203
  end
198
204
 
199
205
  let(:primary_description) do
@@ -274,7 +280,7 @@ describe Mongo::Cluster::Topology::ReplicaSet do
274
280
  describe '#remove_server?' do
275
281
 
276
282
  let(:secondary) do
277
- Mongo::Server.new(address, double('cluster'), monitoring, listeners, TEST_OPTIONS)
283
+ Mongo::Server.new(address, cluster, monitoring, listeners, TEST_OPTIONS)
278
284
  end
279
285
 
280
286
  let(:secondary_description) do
@@ -18,16 +18,22 @@ describe Mongo::Cluster::Topology::Sharded do
18
18
  Mongo::Event::Listeners.new
19
19
  end
20
20
 
21
+ let(:cluster) do
22
+ double('cluster').tap do |cl|
23
+ allow(cl).to receive(:app_metadata).and_return(app_metadata)
24
+ end
25
+ end
26
+
21
27
  let(:mongos) do
22
- Mongo::Server.new(address, double('cluster'), monitoring, listeners, TEST_OPTIONS)
28
+ Mongo::Server.new(address, cluster, monitoring, listeners, TEST_OPTIONS)
23
29
  end
24
30
 
25
31
  let(:standalone) do
26
- Mongo::Server.new(address, double('cluster'), monitoring, listeners, TEST_OPTIONS)
32
+ Mongo::Server.new(address, cluster, monitoring, listeners, TEST_OPTIONS)
27
33
  end
28
34
 
29
35
  let(:replica_set) do
30
- Mongo::Server.new(address, double('cluster'), monitoring, listeners, TEST_OPTIONS)
36
+ Mongo::Server.new(address, cluster, monitoring, listeners, TEST_OPTIONS)
31
37
  end
32
38
 
33
39
  let(:mongos_description) do
@@ -18,22 +18,28 @@ describe Mongo::Cluster::Topology::Single do
18
18
  Mongo::Event::Listeners.new
19
19
  end
20
20
 
21
+ let(:cluster) do
22
+ double('cluster').tap do |cl|
23
+ allow(cl).to receive(:app_metadata).and_return(app_metadata)
24
+ end
25
+ end
26
+
21
27
  describe '.servers' do
22
28
 
23
29
  let(:mongos) do
24
- Mongo::Server.new(address, double('cluster'), monitoring, listeners, TEST_OPTIONS)
30
+ Mongo::Server.new(address, cluster, monitoring, listeners, TEST_OPTIONS)
25
31
  end
26
32
 
27
33
  let(:standalone) do
28
- Mongo::Server.new(address, double('cluster'), monitoring, listeners, TEST_OPTIONS)
34
+ Mongo::Server.new(address, cluster, monitoring, listeners, TEST_OPTIONS)
29
35
  end
30
36
 
31
37
  let(:standalone_two) do
32
- Mongo::Server.new(address, double('cluster'), monitoring, listeners, TEST_OPTIONS)
38
+ Mongo::Server.new(address, cluster, monitoring, listeners, TEST_OPTIONS)
33
39
  end
34
40
 
35
41
  let(:replica_set) do
36
- Mongo::Server.new(address, double('cluster'), monitoring, listeners, TEST_OPTIONS)
42
+ Mongo::Server.new(address, cluster, monitoring, listeners, TEST_OPTIONS)
37
43
  end
38
44
 
39
45
  let(:mongos_description) do
@@ -463,4 +463,33 @@ describe Mongo::Cluster do
463
463
  expect(primary_candidates).to include(cluster.next_primary)
464
464
  end
465
465
  end
466
+
467
+ describe '#app_metadata' do
468
+
469
+ it 'returns an AppMetadata object' do
470
+ expect(cluster.app_metadata).to be_a(Mongo::Cluster::AppMetadata)
471
+ end
472
+
473
+ context 'when the client has an app_name set' do
474
+
475
+ let(:cluster) do
476
+ authorized_client.with(app_name: 'reports').cluster
477
+ end
478
+
479
+ it 'constructs an AppMetadata object with the app_name' do
480
+ expect(cluster.app_metadata.send(:full_client_document)[:application]).to eq('name' => 'reports')
481
+ end
482
+ end
483
+
484
+ context 'when the client does not have an app_name set' do
485
+
486
+ let(:cluster) do
487
+ authorized_client.cluster
488
+ end
489
+
490
+ it 'constructs an AppMetadata object with no app_name' do
491
+ expect(cluster.app_metadata.send(:full_client_document)[:application]).to be_nil
492
+ end
493
+ end
494
+ end
466
495
  end
@@ -26,6 +26,10 @@ describe Mongo::Collection::View::Aggregation do
26
26
  described_class.new(view, pipeline, options)
27
27
  end
28
28
 
29
+ after do
30
+ authorized_collection.delete_many
31
+ end
32
+
29
33
  describe '#allow_disk_use' do
30
34
 
31
35
  let(:new_agg) do
@@ -143,6 +147,31 @@ describe Mongo::Collection::View::Aggregation do
143
147
  expect(aggregation.to_a.size).to eq(2)
144
148
  end
145
149
  end
150
+
151
+ context 'when the view has a write concern' do
152
+
153
+ let(:collection) do
154
+ authorized_collection.with(write: { w: WRITE_CONCERN[:w]+1 })
155
+ end
156
+
157
+ let(:view) do
158
+ Mongo::Collection::View.new(collection, selector, view_options)
159
+ end
160
+
161
+ context 'when the server supports write concern on the aggregate command', if: collation_enabled? do
162
+
163
+ it 'does not apply the write concern' do
164
+ expect(aggregation.to_a.size).to eq(2)
165
+ end
166
+ end
167
+
168
+ context 'when the server does not support write concern on the aggregation command', unless: collation_enabled? do
169
+
170
+ it 'does not apply the write concern' do
171
+ expect(aggregation.to_a.size).to eq(2)
172
+ end
173
+ end
174
+ end
146
175
  end
147
176
 
148
177
  describe '#initialize' do
@@ -173,6 +202,41 @@ describe Mongo::Collection::View::Aggregation do
173
202
  it 'executes an explain' do
174
203
  expect(aggregation.explain).to_not be_empty
175
204
  end
205
+
206
+ context 'when a collation is specified' do
207
+
208
+ before do
209
+ authorized_collection.insert_many([ { name: 'bang' }, { name: 'bang' }])
210
+ end
211
+
212
+ let(:pipeline) do
213
+ [{ "$match" => { "name" => "BANG" } }]
214
+ end
215
+
216
+ let(:options) do
217
+ { collation: { locale: 'en_US', strength: 2 } }
218
+ end
219
+
220
+ let(:result) do
221
+ aggregation.explain['$cursor']['queryPlanner']['collation']['locale']
222
+ end
223
+
224
+ context 'when the server selected supports collations', if: collation_enabled? do
225
+
226
+ it 'applies the collation' do
227
+ expect(result).to eq('en_US')
228
+ end
229
+ end
230
+
231
+ context 'when the server selected does not support collations', unless: collation_enabled? do
232
+
233
+ it 'raises an exception' do
234
+ expect {
235
+ result
236
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
237
+ end
238
+ end
239
+ end
176
240
  end
177
241
 
178
242
  describe '#aggregate_spec' do
@@ -323,6 +387,41 @@ describe Mongo::Collection::View::Aggregation do
323
387
  end
324
388
  end
325
389
 
390
+ context 'when the aggregation has a collation defined' do
391
+
392
+ before do
393
+ authorized_collection.insert_many([ { name: 'bang' }, { name: 'bang' }])
394
+ end
395
+
396
+ let(:pipeline) do
397
+ [{ "$match" => { "name" => "BANG" } }]
398
+ end
399
+
400
+ let(:options) do
401
+ { collation: { locale: 'en_US', strength: 2 } }
402
+ end
403
+
404
+ let(:result) do
405
+ aggregation.collect { |doc| doc['name']}
406
+ end
407
+
408
+ context 'when the server selected supports collations', if: collation_enabled? do
409
+
410
+ it 'applies the collation' do
411
+ expect(result).to eq(['bang', 'bang'])
412
+ end
413
+ end
414
+
415
+ context 'when the server selected does not support collations', unless: collation_enabled? do
416
+
417
+ it 'raises an exception' do
418
+ expect {
419
+ result
420
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
421
+ end
422
+ end
423
+ end
424
+
326
425
  context 'when $out is in the pipeline', if: write_command_enabled? do
327
426
 
328
427
  let(:pipeline) do
@@ -385,6 +484,46 @@ describe Mongo::Collection::View::Aggregation do
385
484
  expect(Mongo::Logger.logger).not_to receive(:warn?)
386
485
  aggregation.to_a
387
486
  end
487
+
488
+ context 'when the view has a write concern' do
489
+
490
+ let(:collection) do
491
+ authorized_collection.with(write: { w: WRITE_CONCERN[:w]+1 })
492
+ end
493
+
494
+ let(:view) do
495
+ Mongo::Collection::View.new(collection, selector, view_options)
496
+ end
497
+
498
+ context 'when the server supports write concern on the aggregate command', if: collation_enabled? do
499
+
500
+ it 'uses the write concern' do
501
+ expect {
502
+ aggregation.to_a
503
+ }.to raise_exception(Mongo::Error::OperationFailure)
504
+ end
505
+ end
506
+
507
+ context 'when the server does not support write concern on the aggregation command', unless: collation_enabled? do
508
+
509
+ let(:documents) do
510
+ [
511
+ { city: "Berlin", pop: 18913, neighborhood: "Kreuzberg" },
512
+ { city: "Berlin", pop: 84143, neighborhood: "Mitte" },
513
+ { city: "New York", pop: 40270, neighborhood: "Brooklyn" }
514
+ ]
515
+ end
516
+
517
+ before do
518
+ authorized_collection.insert_many(documents)
519
+ aggregation.to_a
520
+ end
521
+
522
+ it 'does not apply the write concern' do
523
+ expect(authorized_client['output_collection'].find.count).to eq(2)
524
+ end
525
+ end
526
+ end
388
527
  end
389
528
  end
390
529
  end