PageRenderTime 54ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/spec/mongo/uri_spec.rb

http://github.com/mongodb/mongo-ruby-driver
Ruby | 1256 lines | 940 code | 316 blank | 0 comment | 1 complexity | 31d79a2fe31433e12fde19aeacb9b439 MD5 | raw file
Possible License(s): Apache-2.0
  1. require 'lite_spec_helper'
  2. describe Mongo::URI do
  3. describe '.get' do
  4. let(:uri) { described_class.get(string) }
  5. describe 'invalid uris' do
  6. context 'string is not uri' do
  7. let(:string) { 'tyler' }
  8. it 'raises an error' do
  9. expect { uri }.to raise_error(Mongo::Error::InvalidURI)
  10. end
  11. end
  12. context 'nil' do
  13. let(:string) { nil }
  14. it 'raises an error' do
  15. expect do
  16. uri
  17. end.to raise_error(Mongo::Error::InvalidURI, /URI must be a string, not nil/)
  18. end
  19. end
  20. context 'empty string' do
  21. let(:string) { '' }
  22. it 'raises an error' do
  23. expect do
  24. uri
  25. end.to raise_error(Mongo::Error::InvalidURI, /Cannot parse an empty URI/)
  26. end
  27. end
  28. end
  29. context 'when the scheme is mongodb://' do
  30. let(:string) do
  31. 'mongodb://localhost:27017'
  32. end
  33. it 'returns a Mongo::URI object' do
  34. expect(uri).to be_a(Mongo::URI)
  35. end
  36. end
  37. context 'when the scheme is mongodb+srv://' do
  38. require_external_connectivity
  39. let(:string) do
  40. 'mongodb+srv://test5.test.build.10gen.cc'
  41. end
  42. it 'returns a Mongo::URI::SRVProtocol object' do
  43. expect(uri).to be_a(Mongo::URI::SRVProtocol)
  44. end
  45. end
  46. context 'when the scheme is invalid' do
  47. let(:string) do
  48. 'mongo://localhost:27017'
  49. end
  50. it 'raises an exception' do
  51. expect { uri }.to raise_error(Mongo::Error::InvalidURI)
  52. end
  53. end
  54. end
  55. let(:scheme) { 'mongodb://' }
  56. let(:uri) { described_class.new(string) }
  57. describe 'invalid uris' do
  58. context 'string is not uri' do
  59. let(:string) { 'tyler' }
  60. it 'raises an error' do
  61. expect { uri }.to raise_error(Mongo::Error::InvalidURI)
  62. end
  63. end
  64. context 'nil' do
  65. let(:string) { nil }
  66. it 'raises an error' do
  67. expect do
  68. uri
  69. end.to raise_error(Mongo::Error::InvalidURI, /URI must be a string, not nil/)
  70. end
  71. end
  72. context 'empty string' do
  73. let(:string) { '' }
  74. it 'raises an error' do
  75. expect do
  76. uri
  77. end.to raise_error(Mongo::Error::InvalidURI, /Cannot parse an empty URI/)
  78. end
  79. end
  80. context 'mongo://localhost:27017' do
  81. let(:string) { 'mongo://localhost:27017' }
  82. it 'raises an error' do
  83. expect { uri }.to raise_error(Mongo::Error::InvalidURI)
  84. end
  85. end
  86. context 'mongodb://' do
  87. let(:string) { 'mongodb://' }
  88. it 'raises an error' do
  89. expect { uri }.to raise_error(Mongo::Error::InvalidURI)
  90. end
  91. end
  92. context 'mongodb://localhost::27017' do
  93. let(:string) { 'mongodb://localhost::27017' }
  94. it 'raises an error' do
  95. expect { uri }.to raise_error(Mongo::Error::InvalidURI)
  96. end
  97. end
  98. context 'mongodb://localhost::27017/' do
  99. let(:string) { 'mongodb://localhost::27017/' }
  100. it 'raises an error' do
  101. expect { uri }.to raise_error(Mongo::Error::InvalidURI)
  102. end
  103. end
  104. context 'mongodb://::' do
  105. let(:string) { 'mongodb://::' }
  106. it 'raises an error' do
  107. expect { uri }.to raise_error(Mongo::Error::InvalidURI)
  108. end
  109. end
  110. context 'mongodb://localhost,localhost::' do
  111. let(:string) { 'mongodb://localhost,localhost::' }
  112. it 'raises an error' do
  113. expect { uri }.to raise_error(Mongo::Error::InvalidURI)
  114. end
  115. end
  116. context 'mongodb://localhost::27017,abc' do
  117. let(:string) { 'mongodb://localhost::27017,abc' }
  118. it 'raises an error' do
  119. expect { uri }.to raise_error(Mongo::Error::InvalidURI)
  120. end
  121. end
  122. context 'mongodb://localhost:-1' do
  123. let(:string) { 'mongodb://localhost:-1' }
  124. it 'raises an error' do
  125. expect { uri }.to raise_error(Mongo::Error::InvalidURI)
  126. end
  127. end
  128. context 'mongodb://localhost:0/' do
  129. let(:string) { 'mongodb://localhost:0/' }
  130. it 'raises an error' do
  131. expect { uri }.to raise_error(Mongo::Error::InvalidURI)
  132. end
  133. end
  134. context 'mongodb://localhost:65536' do
  135. let(:string) { 'mongodb://localhost:65536' }
  136. it 'raises an error' do
  137. expect { uri }.to raise_error(Mongo::Error::InvalidURI)
  138. end
  139. end
  140. context 'mongodb://localhost:foo' do
  141. let(:string) { 'mongodb://localhost:foo' }
  142. it 'raises an error' do
  143. expect { uri }.to raise_error(Mongo::Error::InvalidURI)
  144. end
  145. end
  146. context 'mongodb://[::1]:-1' do
  147. let(:string) { 'mongodb://[::1]:-1' }
  148. it 'raises an error' do
  149. expect { uri }.to raise_error(Mongo::Error::InvalidURI)
  150. end
  151. end
  152. context 'mongodb://[::1]:0/' do
  153. let(:string) { 'mongodb://[::1]:0/' }
  154. it 'raises an error' do
  155. expect { uri }.to raise_error(Mongo::Error::InvalidURI)
  156. end
  157. end
  158. context 'mongodb://[::1]:65536' do
  159. let(:string) { 'mongodb://[::1]:65536' }
  160. it 'raises an error' do
  161. expect { uri }.to raise_error(Mongo::Error::InvalidURI)
  162. end
  163. end
  164. context 'mongodb://[::1]:65536/' do
  165. let(:string) { 'mongodb://[::1]:65536/' }
  166. it 'raises an error' do
  167. expect { uri }.to raise_error(Mongo::Error::InvalidURI)
  168. end
  169. end
  170. context 'mongodb://[::1]:foo' do
  171. let(:string) { 'mongodb://[::1]:foo' }
  172. it 'raises an error' do
  173. expect { uri }.to raise_error(Mongo::Error::InvalidURI)
  174. end
  175. end
  176. context 'no slash after hosts, and options' do
  177. let(:string) { 'mongodb://example.com?tls=true' }
  178. it 'raises an error' do
  179. expect { uri }.to raise_error(Mongo::Error::InvalidURI, %r,MongoDB URI must have a slash \(/\) after the hosts if options are given,)
  180. end
  181. end
  182. context 'mongodb://example.com/?w' do
  183. let(:string) { 'mongodb://example.com/?w' }
  184. it 'raises an error' do
  185. expect { uri }.to raise_error(Mongo::Error::InvalidURI, /Option w has no value/)
  186. end
  187. end
  188. context 'equal sign in option value' do
  189. let(:string) { 'mongodb://example.com/?authmechanismproperties=foo:a=b&appname=test' }
  190. it 'is allowed' do
  191. expect(uri.uri_options[:auth_mech_properties]).to eq('foo' => 'a=b')
  192. end
  193. end
  194. context 'slash in option value' do
  195. let(:string) { 'mongodb://example.com/?tlsCAFile=a/b' }
  196. it 'returns a Mongo::URI object' do
  197. expect(uri).to be_a(Mongo::URI)
  198. end
  199. it 'parses correctly' do
  200. expect(uri.servers).to eq(['example.com'])
  201. expect(uri.uri_options[:ssl_ca_cert]).to eq('a/b')
  202. end
  203. end
  204. context 'numeric value in a string option' do
  205. let(:string) { 'mongodb://example.com/?appName=1' }
  206. it 'returns a Mongo::URI object' do
  207. expect(uri).to be_a(Mongo::URI)
  208. end
  209. it 'sets option to the string value' do
  210. expect(uri.uri_options[:app_name]).to eq('1')
  211. end
  212. end
  213. context 'options start with ampersand' do
  214. let(:string) { 'mongodb://example.com/?&appName=foo' }
  215. it 'returns a Mongo::URI object' do
  216. expect(uri).to be_a(Mongo::URI)
  217. end
  218. it 'parses the options' do
  219. expect(uri.uri_options[:app_name]).to eq('foo')
  220. end
  221. end
  222. context 'mongodb://alice:foo:bar@127.0.0.1' do
  223. let(:string) { 'mongodb://alice:foo:bar@127.0.0.1' }
  224. it 'raises an error' do
  225. expect { uri }.to raise_error(Mongo::Error::InvalidURI)
  226. end
  227. end
  228. context 'mongodb://alice@@127.0.0.1' do
  229. let(:string) { 'mongodb://alice@@127.0.0.1' }
  230. it 'raises an error' do
  231. expect { uri }.to raise_error(Mongo::Error::InvalidURI)
  232. end
  233. end
  234. context 'mongodb://alice@foo:bar@127.0.0.1' do
  235. let(:string) { 'mongodb://alice@foo:bar@127.0.0.1' }
  236. it 'raises an error' do
  237. expect { uri }.to raise_error(Mongo::Error::InvalidURI)
  238. end
  239. end
  240. end
  241. describe '#initialize' do
  242. context 'string is not uri' do
  243. let(:string) { 'tyler' }
  244. it 'raises an error' do
  245. expect { uri }.to raise_error(Mongo::Error::InvalidURI)
  246. end
  247. end
  248. end
  249. describe '#servers' do
  250. let(:string) { "#{scheme}#{servers}" }
  251. context 'single server' do
  252. let(:servers) { 'localhost' }
  253. it 'returns an array with the parsed server' do
  254. expect(uri.servers).to eq([servers])
  255. end
  256. end
  257. context 'single server with port' do
  258. let(:servers) { 'localhost:27017' }
  259. it 'returns an array with the parsed server' do
  260. expect(uri.servers).to eq([servers])
  261. end
  262. end
  263. context 'numerical ipv4 server' do
  264. let(:servers) { '127.0.0.1' }
  265. it 'returns an array with the parsed server' do
  266. expect(uri.servers).to eq([servers])
  267. end
  268. end
  269. context 'numerical ipv6 server' do
  270. let(:servers) { '[::1]:27107' }
  271. it 'returns an array with the parsed server' do
  272. expect(uri.servers).to eq([servers])
  273. end
  274. end
  275. context 'unix socket server' do
  276. let(:servers) { '%2Ftmp%2Fmongodb-27017.sock' }
  277. it 'returns an array with the parsed server' do
  278. expect(uri.servers).to eq([URI::DEFAULT_PARSER.unescape(servers)])
  279. end
  280. end
  281. context 'multiple servers' do
  282. let(:servers) { 'localhost,127.0.0.1' }
  283. it 'returns an array with the parsed servers' do
  284. expect(uri.servers).to eq(servers.split(','))
  285. end
  286. end
  287. context 'multiple servers with ports' do
  288. let(:servers) { '127.0.0.1:27107,localhost:27018' }
  289. it 'returns an array with the parsed servers' do
  290. expect(uri.servers).to eq(servers.split(','))
  291. end
  292. end
  293. end
  294. describe '#client_options' do
  295. let(:db) { 'dummy_db' }
  296. let(:servers) { 'localhost' }
  297. let(:string) { "#{scheme}#{credentials}@#{servers}/#{db}" }
  298. let(:user) { 'tyler' }
  299. let(:password) { 's3kr4t' }
  300. let(:credentials) { "#{user}:#{password}" }
  301. let(:options) do
  302. uri.client_options
  303. end
  304. it 'includes the database in the options' do
  305. expect(options[:database]).to eq('dummy_db')
  306. end
  307. it 'includes the user in the options' do
  308. expect(options[:user]).to eq(user)
  309. end
  310. it 'includes the password in the options' do
  311. expect(options[:password]).to eq(password)
  312. end
  313. end
  314. describe '#credentials' do
  315. let(:servers) { 'localhost' }
  316. let(:string) { "#{scheme}#{credentials}@#{servers}" }
  317. let(:user) { 'tyler' }
  318. context 'username provided' do
  319. let(:credentials) { "#{user}:" }
  320. it 'returns the username' do
  321. expect(uri.credentials[:user]).to eq(user)
  322. end
  323. end
  324. context 'username and password provided' do
  325. let(:password) { 's3kr4t' }
  326. let(:credentials) { "#{user}:#{password}" }
  327. it 'returns the username' do
  328. expect(uri.credentials[:user]).to eq(user)
  329. end
  330. it 'returns the password' do
  331. expect(uri.credentials[:password]).to eq(password)
  332. end
  333. end
  334. end
  335. describe '#database' do
  336. let(:servers) { 'localhost' }
  337. let(:string) { "#{scheme}#{servers}/#{db}" }
  338. let(:db) { 'auth-db' }
  339. context 'database provided' do
  340. it 'returns the database name' do
  341. expect(uri.database).to eq(db)
  342. end
  343. end
  344. end
  345. describe '#uri_options' do
  346. let(:servers) { 'localhost' }
  347. let(:string) { "#{scheme}#{servers}/?#{options}" }
  348. context 'when no options were provided' do
  349. let(:string) { "#{scheme}#{servers}" }
  350. it 'returns an empty hash' do
  351. expect(uri.uri_options).to be_empty
  352. end
  353. end
  354. context 'write concern options provided' do
  355. context 'numerical w value' do
  356. let(:options) { 'w=1' }
  357. let(:concern) { Mongo::Options::Redacted.new(:w => 1)}
  358. it 'sets the write concern options' do
  359. expect(uri.uri_options[:write_concern]).to eq(concern)
  360. end
  361. it 'sets the options on a client created with the uri' do
  362. client = new_local_client_nmio(string)
  363. expect(client.options[:write_concern]).to eq(concern)
  364. end
  365. end
  366. context 'w=majority' do
  367. let(:options) { 'w=majority' }
  368. let(:concern) { Mongo::Options::Redacted.new(:w => :majority) }
  369. it 'sets the write concern options' do
  370. expect(uri.uri_options[:write_concern]).to eq(concern)
  371. end
  372. it 'sets the options on a client created with the uri' do
  373. client = new_local_client_nmio(string)
  374. expect(client.options[:write_concern]).to eq(concern)
  375. end
  376. end
  377. context 'journal' do
  378. let(:options) { 'journal=true' }
  379. let(:concern) { Mongo::Options::Redacted.new(:j => true) }
  380. it 'sets the write concern options' do
  381. expect(uri.uri_options[:write_concern]).to eq(concern)
  382. end
  383. it 'sets the options on a client created with the uri' do
  384. client = new_local_client_nmio(string)
  385. expect(client.options[:write_concern]).to eq(concern)
  386. end
  387. end
  388. context 'fsync' do
  389. let(:options) { 'fsync=true' }
  390. let(:concern) { Mongo::Options::Redacted.new(:fsync => true) }
  391. it 'sets the write concern options' do
  392. expect(uri.uri_options[:write_concern]).to eq(concern)
  393. end
  394. it 'sets the options on a client created with the uri' do
  395. client = new_local_client_nmio(string)
  396. expect(client.options[:write_concern]).to eq(concern)
  397. end
  398. end
  399. context 'wtimeoutMS' do
  400. let(:timeout) { 1234 }
  401. let(:options) { "w=2&wtimeoutMS=#{timeout}" }
  402. let(:concern) { Mongo::Options::Redacted.new(:w => 2, :wtimeout => timeout) }
  403. it 'sets the write concern options' do
  404. expect(uri.uri_options[:write_concern]).to eq(concern)
  405. end
  406. it 'sets the options on a client created with the uri' do
  407. client = new_local_client_nmio(string)
  408. expect(client.options[:write_concern]).to eq(concern)
  409. end
  410. end
  411. end
  412. context 'read preference option provided' do
  413. let(:options) { "readPreference=#{mode}" }
  414. context 'primary' do
  415. let(:mode) { 'primary' }
  416. let(:read) { Mongo::Options::Redacted.new(:mode => :primary) }
  417. it 'sets the read preference' do
  418. expect(uri.uri_options[:read]).to eq(read)
  419. end
  420. it 'sets the options on a client created with the uri' do
  421. client = new_local_client_nmio(string)
  422. expect(client.options[:read]).to eq(read)
  423. end
  424. end
  425. context 'primaryPreferred' do
  426. let(:mode) { 'primaryPreferred' }
  427. let(:read) { Mongo::Options::Redacted.new(:mode => :primary_preferred) }
  428. it 'sets the read preference' do
  429. expect(uri.uri_options[:read]).to eq(read)
  430. end
  431. it 'sets the options on a client created with the uri' do
  432. client = new_local_client_nmio(string)
  433. expect(client.options[:read]).to eq(read)
  434. end
  435. end
  436. context 'secondary' do
  437. let(:mode) { 'secondary' }
  438. let(:read) { Mongo::Options::Redacted.new(:mode => :secondary) }
  439. it 'sets the read preference' do
  440. expect(uri.uri_options[:read]).to eq(read)
  441. end
  442. it 'sets the options on a client created with the uri' do
  443. client = new_local_client_nmio(string)
  444. expect(client.options[:read]).to eq(read)
  445. end
  446. end
  447. context 'secondaryPreferred' do
  448. let(:mode) { 'secondaryPreferred' }
  449. let(:read) { Mongo::Options::Redacted.new(:mode => :secondary_preferred) }
  450. it 'sets the read preference' do
  451. expect(uri.uri_options[:read]).to eq(read)
  452. end
  453. it 'sets the options on a client created with the uri' do
  454. client = new_local_client_nmio(string)
  455. expect(client.options[:read]).to eq(read)
  456. end
  457. end
  458. context 'nearest' do
  459. let(:mode) { 'nearest' }
  460. let(:read) { Mongo::Options::Redacted.new(:mode => :nearest) }
  461. it 'sets the read preference' do
  462. expect(uri.uri_options[:read]).to eq(read)
  463. end
  464. it 'sets the options on a client created with the uri' do
  465. client = new_local_client_nmio(string)
  466. expect(client.options[:read]).to eq(read)
  467. end
  468. end
  469. end
  470. context 'read preference tags provided' do
  471. context 'single read preference tag set' do
  472. let(:options) do
  473. 'readPreferenceTags=dc:ny,rack:1'
  474. end
  475. let(:read) do
  476. Mongo::Options::Redacted.new(:tag_sets => [{ 'dc' => 'ny', 'rack' => '1' }])
  477. end
  478. it 'sets the read preference tag set' do
  479. expect(uri.uri_options[:read]).to eq(read)
  480. end
  481. it 'sets the options on a client created with the uri' do
  482. client = new_local_client_nmio(string)
  483. expect(client.options[:read]).to eq(read)
  484. end
  485. end
  486. context 'multiple read preference tag sets' do
  487. let(:options) do
  488. 'readPreferenceTags=dc:ny&readPreferenceTags=dc:bos'
  489. end
  490. let(:read) do
  491. Mongo::Options::Redacted.new(:tag_sets => [{ 'dc' => 'ny' }, { 'dc' => 'bos' }])
  492. end
  493. it 'sets the read preference tag sets' do
  494. expect(uri.uri_options[:read]).to eq(read)
  495. end
  496. it 'sets the options on a client created with the uri' do
  497. client = new_local_client_nmio(string)
  498. expect(client.options[:read]).to eq(read)
  499. end
  500. end
  501. end
  502. context 'read preference max staleness option provided' do
  503. let(:options) do
  504. 'readPreference=Secondary&maxStalenessSeconds=120'
  505. end
  506. let(:read) do
  507. Mongo::Options::Redacted.new(mode: :secondary, :max_staleness => 120)
  508. end
  509. it 'sets the read preference max staleness in seconds' do
  510. expect(uri.uri_options[:read]).to eq(read)
  511. end
  512. it 'sets the options on a client created with the uri' do
  513. client = new_local_client_nmio(string)
  514. expect(client.options[:read]).to eq(read)
  515. end
  516. context 'when the read preference and max staleness combination is invalid' do
  517. context 'when max staleness is combined with read preference mode primary' do
  518. let(:options) do
  519. 'readPreference=primary&maxStalenessSeconds=120'
  520. end
  521. it 'raises an exception when read preference is accessed on the client' do
  522. client = new_local_client_nmio(string)
  523. expect {
  524. client.server_selector
  525. }.to raise_exception(Mongo::Error::InvalidServerPreference)
  526. end
  527. end
  528. context 'when the max staleness value is too small' do
  529. let(:options) do
  530. 'readPreference=secondary&maxStalenessSeconds=89'
  531. end
  532. it 'does not raise an exception until the read preference is used' do
  533. client = new_local_client_nmio(string)
  534. expect(client.read_preference).to eq(BSON::Document.new(mode: :secondary, max_staleness: 89))
  535. end
  536. end
  537. end
  538. end
  539. context 'replica set option provided' do
  540. let(:rs_name) { 'dummy_rs' }
  541. let(:options) { "replicaSet=#{rs_name}" }
  542. it 'sets the replica set option' do
  543. expect(uri.uri_options[:replica_set]).to eq(rs_name)
  544. end
  545. it 'sets the options on a client created with the uri' do
  546. client = new_local_client_nmio(string)
  547. expect(client.options[:replica_set]).to eq(rs_name)
  548. end
  549. end
  550. context 'auth mechanism provided' do
  551. let(:string) { "#{scheme}#{credentials}@#{servers}/?#{options}" }
  552. let(:user) { 'tyler' }
  553. let(:password) { 's3kr4t' }
  554. let(:credentials) { "#{user}:#{password}" }
  555. let(:options) { "authMechanism=#{mechanism}" }
  556. context 'plain' do
  557. let(:mechanism) { 'PLAIN' }
  558. let(:expected) { :plain }
  559. it 'sets the auth mechanism to :plain' do
  560. expect(uri.uri_options[:auth_mech]).to eq(expected)
  561. end
  562. it 'sets the options on a client created with the uri' do
  563. client = new_local_client_nmio(string)
  564. expect(client.options[:auth_mech]).to eq(expected)
  565. end
  566. it 'is case-insensitive' do
  567. client = new_local_client_nmio(string.downcase)
  568. expect(client.options[:auth_mech]).to eq(expected)
  569. end
  570. context 'when mechanism_properties are provided' do
  571. let(:options) { "authMechanism=#{mechanism}&authMechanismProperties=CANONICALIZE_HOST_NAME:true" }
  572. it 'does not allow a client to be created' do
  573. expect {
  574. new_local_client_nmio(string)
  575. }.to raise_error(Mongo::Auth::InvalidConfiguration, /mechanism_properties are not supported/)
  576. end
  577. end
  578. end
  579. context 'mongodb-cr' do
  580. let(:mechanism) { 'MONGODB-CR' }
  581. let(:expected) { :mongodb_cr }
  582. it 'sets the auth mechanism to :mongodb_cr' do
  583. expect(uri.uri_options[:auth_mech]).to eq(expected)
  584. end
  585. it 'sets the options on a client created with the uri' do
  586. client = new_local_client_nmio(string)
  587. expect(client.options[:auth_mech]).to eq(expected)
  588. end
  589. it 'is case-insensitive' do
  590. client = new_local_client_nmio(string.downcase)
  591. expect(client.options[:auth_mech]).to eq(expected)
  592. end
  593. context 'when mechanism_properties are provided' do
  594. let(:options) { "authMechanism=#{mechanism}&authMechanismProperties=CANONICALIZE_HOST_NAME:true" }
  595. it 'does not allow a client to be created' do
  596. expect {
  597. new_local_client_nmio(string)
  598. }.to raise_error(Mongo::Auth::InvalidConfiguration, /mechanism_properties are not supported/)
  599. end
  600. end
  601. end
  602. context 'gssapi' do
  603. require_mongo_kerberos
  604. let(:mechanism) { 'GSSAPI' }
  605. let(:expected) { :gssapi }
  606. let(:client) { new_local_client_nmio(string) }
  607. it 'sets the auth mechanism to :gssapi' do
  608. expect(uri.uri_options[:auth_mech]).to eq(expected)
  609. end
  610. it 'sets the options on a client created with the uri' do
  611. expect(client.options[:auth_mech]).to eq(expected)
  612. end
  613. it 'is case-insensitive' do
  614. client = new_local_client_nmio(string.downcase)
  615. expect(client.options[:auth_mech]).to eq(expected)
  616. end
  617. context 'when auth source is invalid' do
  618. let(:options) { "authMechanism=#{mechanism}&authSource=foo" }
  619. it 'does not allow a client to be created' do
  620. expect {
  621. client
  622. }.to raise_error(Mongo::Auth::InvalidConfiguration, /invalid auth source/)
  623. end
  624. end
  625. context 'when mechanism_properties are provided' do
  626. let(:options) { "authMechanism=#{mechanism}&authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:true" }
  627. it 'sets the options on a client created with the uri' do
  628. expect(client.options[:auth_mech_properties]).to eq({ 'canonicalize_host_name' => true, 'service_name' => 'other' })
  629. end
  630. context 'when a mapping value is missing' do
  631. let(:options) { "authMechanism=#{mechanism}&authMechanismProperties=SERVICE_NAME:,CANONICALIZE_HOST_NAME:" }
  632. it 'sets the options on a client created with the uri' do
  633. expect(client.options[:auth_mech_properties]).to eq({ 'canonicalize_host_name' => nil, 'service_name' => nil })
  634. end
  635. end
  636. context 'when a mapping value is missing but another is present' do
  637. let(:options) { "authMechanism=#{mechanism}&authMechanismProperties=SERVICE_NAME:foo,CANONICALIZE_HOST_NAME:" }
  638. it 'sets the options on a client created with the uri' do
  639. expect(client.options[:auth_mech_properties]).to eq({ 'canonicalize_host_name' => nil, 'service_name' => 'foo' })
  640. end
  641. end
  642. end
  643. end
  644. context 'scram-sha-1' do
  645. let(:mechanism) { 'SCRAM-SHA-1' }
  646. let(:expected) { :scram }
  647. it 'sets the auth mechanism to :scram' do
  648. expect(uri.uri_options[:auth_mech]).to eq(expected)
  649. end
  650. it 'sets the options on a client created with the uri' do
  651. client = new_local_client_nmio(string)
  652. expect(client.options[:auth_mech]).to eq(expected)
  653. end
  654. it 'is case-insensitive' do
  655. client = new_local_client_nmio(string.downcase)
  656. expect(client.options[:auth_mech]).to eq(expected)
  657. end
  658. context 'when mechanism_properties are provided' do
  659. let(:options) { "authMechanism=#{mechanism}&authMechanismProperties=CANONICALIZE_HOST_NAME:true" }
  660. it 'does not allow a client to be created' do
  661. expect {
  662. new_local_client_nmio(string)
  663. }.to raise_error(Mongo::Auth::InvalidConfiguration, /mechanism_properties are not supported/)
  664. end
  665. end
  666. end
  667. context 'mongodb-x509' do
  668. let(:mechanism) { 'MONGODB-X509' }
  669. let(:expected) { :mongodb_x509 }
  670. let(:credentials) { user }
  671. it 'sets the auth mechanism to :mongodb_x509' do
  672. expect(uri.uri_options[:auth_mech]).to eq(expected)
  673. end
  674. it 'sets the options on a client created with the uri' do
  675. client = new_local_client_nmio(string)
  676. expect(client.options[:auth_mech]).to eq(expected)
  677. end
  678. it 'is case-insensitive' do
  679. client = new_local_client_nmio(string.downcase)
  680. expect(client.options[:auth_mech]).to eq(expected)
  681. end
  682. context 'when auth source is invalid' do
  683. let(:options) { "authMechanism=#{mechanism}&authSource=foo" }
  684. it 'does not allow a client to be created' do
  685. expect {
  686. new_local_client_nmio(string)
  687. }.to raise_error(Mongo::Auth::InvalidConfiguration, /invalid auth source/)
  688. end
  689. end
  690. context 'when a username is not provided' do
  691. let(:string) { "#{scheme}#{servers}/?#{options}" }
  692. it 'recognizes the mechanism with no username' do
  693. client = new_local_client_nmio(string.downcase)
  694. expect(client.options[:auth_mech]).to eq(expected)
  695. expect(client.options[:user]).to be_nil
  696. end
  697. end
  698. context 'when a password is provided' do
  699. let(:credentials) { "#{user}:#{password}"}
  700. let(:password) { 's3kr4t' }
  701. it 'does not allow a client to be created' do
  702. expect do
  703. new_local_client_nmio(string)
  704. end.to raise_error(Mongo::Auth::InvalidConfiguration, /Password is not supported/)
  705. end
  706. end
  707. context 'when mechanism_properties are provided' do
  708. let(:options) { "authMechanism=#{mechanism}&authMechanismProperties=CANONICALIZE_HOST_NAME:true" }
  709. it 'does not allow a client to be created' do
  710. expect {
  711. new_local_client_nmio(string)
  712. }.to raise_error(Mongo::Auth::InvalidConfiguration, /mechanism_properties are not supported/)
  713. end
  714. end
  715. end
  716. end
  717. context 'auth mechanism is not provided' do
  718. let(:string) { "#{scheme}#{credentials}@#{servers}/" }
  719. context 'with no credentials' do
  720. let(:string) { "#{scheme}#{servers}/" }
  721. it 'sets user and password as nil' do
  722. expect(uri.credentials[:user]).to be_nil
  723. expect(uri.credentials[:password]).to be_nil
  724. end
  725. it 'sets the options on a client created with the uri' do
  726. client = new_local_client_nmio(string)
  727. expect(client.options[:user]).to be_nil
  728. expect(client.options[:password]).to be_nil
  729. end
  730. end
  731. context 'with empty credentials' do
  732. let(:credentials) { '' }
  733. it 'sets user as an empty string and password as nil' do
  734. expect(uri.credentials[:user]).to eq('')
  735. expect(uri.credentials[:password]).to be_nil
  736. end
  737. it 'does not allow a client to be created with default auth mechanism' do
  738. expect do
  739. new_local_client_nmio(string)
  740. end.to raise_error(Mongo::Auth::InvalidConfiguration, /Empty username is not supported/)
  741. end
  742. end
  743. end
  744. context 'auth source provided' do
  745. let(:options) { "authSource=#{source}" }
  746. context 'regular db' do
  747. let(:source) { 'foo' }
  748. it 'sets the auth source to the database' do
  749. expect(uri.uri_options[:auth_source]).to eq(source)
  750. end
  751. it 'sets the options on a client created with the uri' do
  752. client = new_local_client_nmio(string)
  753. expect(client.options[:auth_source]).to eq(source)
  754. end
  755. end
  756. end
  757. context 'auth mechanism properties provided' do
  758. context 'service_name' do
  759. let(:options) do
  760. "authMechanismProperties=SERVICE_NAME:#{service_name}"
  761. end
  762. let(:service_name) { 'foo' }
  763. let(:expected) { Mongo::Options::Redacted.new({ service_name: service_name }) }
  764. it 'sets the auth mechanism properties' do
  765. expect(uri.uri_options[:auth_mech_properties]).to eq(expected)
  766. end
  767. it 'sets the options on a client created with the uri' do
  768. client = new_local_client_nmio(string)
  769. expect(client.options[:auth_mech_properties]).to eq(expected)
  770. end
  771. end
  772. context 'canonicalize_host_name' do
  773. let(:options) do
  774. "authMechanismProperties=CANONICALIZE_HOST_NAME:#{canonicalize_host_name}"
  775. end
  776. let(:canonicalize_host_name) { 'true' }
  777. let(:expected) { Mongo::Options::Redacted.new({ canonicalize_host_name: true }) }
  778. it 'sets the auth mechanism properties' do
  779. expect(uri.uri_options[:auth_mech_properties]).to eq(expected)
  780. end
  781. it 'sets the options on a client created with the uri' do
  782. client = new_local_client_nmio(string)
  783. expect(client.options[:auth_mech_properties]).to eq(expected)
  784. end
  785. end
  786. context 'service_realm' do
  787. let(:options) do
  788. "authMechanismProperties=SERVICE_REALM:#{service_realm}"
  789. end
  790. let(:service_realm) { 'dumdum' }
  791. let(:expected) { Mongo::Options::Redacted.new({ service_realm: service_realm }) }
  792. it 'sets the auth mechanism properties' do
  793. expect(uri.uri_options[:auth_mech_properties]).to eq(expected)
  794. end
  795. it 'sets the options on a client created with the uri' do
  796. client = new_local_client_nmio(string)
  797. expect(client.options[:auth_mech_properties]).to eq(expected)
  798. end
  799. end
  800. context 'multiple properties' do
  801. let(:options) do
  802. "authMechanismProperties=SERVICE_REALM:#{service_realm}," +
  803. "CANONICALIZE_HOST_NAME:#{canonicalize_host_name}," +
  804. "SERVICE_NAME:#{service_name}"
  805. end
  806. let(:service_name) { 'foo' }
  807. let(:canonicalize_host_name) { 'true' }
  808. let(:service_realm) { 'dumdum' }
  809. let(:expected) do
  810. Mongo::Options::Redacted.new({ service_name: service_name,
  811. canonicalize_host_name: true,
  812. service_realm: service_realm })
  813. end
  814. it 'sets the auth mechanism properties' do
  815. expect(uri.uri_options[:auth_mech_properties]).to eq(expected)
  816. end
  817. it 'sets the options on a client created with the uri' do
  818. client = new_local_client_nmio(string)
  819. expect(client.options[:auth_mech_properties]).to eq(expected)
  820. end
  821. end
  822. end
  823. context 'connectTimeoutMS' do
  824. let(:options) { "connectTimeoutMS=4567" }
  825. it 'sets the the connect timeout' do
  826. expect(uri.uri_options[:connect_timeout]).to eq(4.567)
  827. end
  828. end
  829. context 'socketTimeoutMS' do
  830. let(:options) { "socketTimeoutMS=8910" }
  831. it 'sets the socket timeout' do
  832. expect(uri.uri_options[:socket_timeout]).to eq(8.910)
  833. end
  834. end
  835. context 'when providing serverSelectionTimeoutMS' do
  836. let(:options) { "serverSelectionTimeoutMS=3561" }
  837. it 'sets the the connect timeout' do
  838. expect(uri.uri_options[:server_selection_timeout]).to eq(3.561)
  839. end
  840. end
  841. context 'when providing localThresholdMS' do
  842. let(:options) { "localThresholdMS=3561" }
  843. it 'sets the the connect timeout' do
  844. expect(uri.uri_options[:local_threshold]).to eq(3.561)
  845. end
  846. end
  847. context 'when providing maxPoolSize' do
  848. let(:max_pool_size) { 10 }
  849. let(:options) { "maxPoolSize=#{max_pool_size}" }
  850. it 'sets the max pool size option' do
  851. expect(uri.uri_options[:max_pool_size]).to eq(max_pool_size)
  852. end
  853. end
  854. context 'when providing minPoolSize' do
  855. let(:min_pool_size) { 5 }
  856. let(:options) { "minPoolSize=#{min_pool_size}" }
  857. it 'sets the min pool size option' do
  858. expect(uri.uri_options[:min_pool_size]).to eq(min_pool_size)
  859. end
  860. end
  861. context 'when providing waitQueueTimeoutMS' do
  862. let(:wait_queue_timeout) { 500 }
  863. let(:options) { "waitQueueTimeoutMS=#{wait_queue_timeout}" }
  864. it 'sets the wait queue timeout option' do
  865. expect(uri.uri_options[:wait_queue_timeout]).to eq(0.5)
  866. end
  867. end
  868. context 'ssl' do
  869. let(:options) { "ssl=#{ssl}" }
  870. context 'true' do
  871. let(:ssl) { true }
  872. it 'sets the ssl option to true' do
  873. expect(uri.uri_options[:ssl]).to be true
  874. end
  875. end
  876. context 'false' do
  877. let(:ssl) { false }
  878. it 'sets the ssl option to false' do
  879. expect(uri.uri_options[:ssl]).to be false
  880. end
  881. end
  882. end
  883. context 'grouped and non-grouped options provided' do
  884. let(:options) { 'w=1&ssl=true' }
  885. it 'do not overshadow top level options' do
  886. expect(uri.uri_options).not_to be_empty
  887. end
  888. end
  889. context 'when an invalid option is provided' do
  890. let(:options) { 'invalidOption=10' }
  891. let(:uri_options) do
  892. uri.uri_options
  893. end
  894. it 'does not raise an exception' do
  895. expect(uri_options).to be_empty
  896. end
  897. context 'when an invalid option is combined with valid options' do
  898. let(:options) { 'invalidOption=10&waitQueueTimeoutMS=500&ssl=true' }
  899. it 'does not raise an exception' do
  900. expect(uri_options).not_to be_empty
  901. end
  902. it 'sets the valid options' do
  903. expect(uri_options[:wait_queue_timeout]).to eq(0.5)
  904. expect(uri_options[:ssl]).to be true
  905. end
  906. end
  907. end
  908. context 'when an app name option is provided' do
  909. let(:options) { "appname=uri_test" }
  910. it 'sets the app name on the client' do
  911. client = new_local_client_nmio(string)
  912. expect(client.options[:app_name]).to eq('uri_test')
  913. end
  914. end
  915. context 'when a supported compressors option is provided' do
  916. let(:options) { "compressors=zlib" }
  917. it 'sets the compressors as an array on the client' do
  918. client = new_local_client_nmio(string)
  919. expect(client.options[:compressors]).to eq(['zlib'])
  920. end
  921. end
  922. context 'when a non-supported compressors option is provided' do
  923. let(:options) { "compressors=snoopy" }
  924. let(:client) do
  925. client = new_local_client_nmio(string)
  926. end
  927. it 'sets no compressors on the client and warns' do
  928. expect(Mongo::Logger.logger).to receive(:warn)
  929. expect(client.options[:compressors]).to be_nil
  930. end
  931. end
  932. context 'when a zlibCompressionLevel option is provided' do
  933. let(:options) { "zlibCompressionLevel=6" }
  934. it 'sets the zlib compression level on the client' do
  935. client = new_local_client_nmio(string)
  936. expect(client.options[:zlib_compression_level]).to eq(6)
  937. end
  938. end
  939. end
  940. end