client_server_spec.rb 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. # Copyright 2015-2016, Google Inc.
  2. # All rights reserved.
  3. #
  4. # Redistribution and use in source and binary forms, with or without
  5. # modification, are permitted provided that the following conditions are
  6. # met:
  7. #
  8. # * Redistributions of source code must retain the above copyright
  9. # notice, this list of conditions and the following disclaimer.
  10. # * Redistributions in binary form must reproduce the above
  11. # copyright notice, this list of conditions and the following disclaimer
  12. # in the documentation and/or other materials provided with the
  13. # distribution.
  14. # * Neither the name of Google Inc. nor the names of its
  15. # contributors may be used to endorse or promote products derived from
  16. # this software without specific prior written permission.
  17. #
  18. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22. # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24. # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. require 'grpc'
  30. include GRPC::Core
  31. shared_context 'setup: tags' do
  32. let(:sent_message) { 'sent message' }
  33. let(:reply_text) { 'the reply' }
  34. before(:example) do
  35. @client_tag = Object.new
  36. @server_tag = Object.new
  37. end
  38. def deadline
  39. Time.now + 5
  40. end
  41. def server_allows_client_to_proceed
  42. recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
  43. expect(recvd_rpc).to_not eq nil
  44. server_call = recvd_rpc.call
  45. ops = { CallOps::SEND_INITIAL_METADATA => {} }
  46. svr_batch = server_call.run_batch(@server_queue, @server_tag, deadline, ops)
  47. expect(svr_batch.send_metadata).to be true
  48. server_call
  49. end
  50. def new_client_call
  51. @ch.create_call(@client_queue, nil, nil, '/method', nil, deadline)
  52. end
  53. end
  54. shared_examples 'basic GRPC message delivery is OK' do
  55. include GRPC::Core
  56. include_context 'setup: tags'
  57. context 'the test channel' do
  58. it 'should have a target' do
  59. expect(@ch.target).to be_a(String)
  60. end
  61. end
  62. context 'a client call' do
  63. it 'should have a peer' do
  64. expect(new_client_call.peer).to be_a(String)
  65. end
  66. end
  67. it 'calls have peer info' do
  68. call = new_client_call
  69. expect(call.peer).to be_a(String)
  70. end
  71. it 'servers receive requests from clients and can respond' do
  72. call = new_client_call
  73. server_call = nil
  74. server_thread = Thread.new do
  75. server_call = server_allows_client_to_proceed
  76. end
  77. client_ops = {
  78. CallOps::SEND_INITIAL_METADATA => {},
  79. CallOps::SEND_MESSAGE => sent_message
  80. }
  81. batch_result = call.run_batch(@client_queue, @client_tag, deadline,
  82. client_ops)
  83. expect(batch_result.send_metadata).to be true
  84. expect(batch_result.send_message).to be true
  85. # confirm the server can read the inbound message
  86. server_thread.join
  87. server_ops = {
  88. CallOps::RECV_MESSAGE => nil
  89. }
  90. svr_batch = server_call.run_batch(@server_queue, @server_tag, deadline,
  91. server_ops)
  92. expect(svr_batch.message).to eq(sent_message)
  93. end
  94. it 'responses written by servers are received by the client' do
  95. call = new_client_call
  96. server_call = nil
  97. server_thread = Thread.new do
  98. server_call = server_allows_client_to_proceed
  99. end
  100. client_ops = {
  101. CallOps::SEND_INITIAL_METADATA => {},
  102. CallOps::SEND_MESSAGE => sent_message
  103. }
  104. batch_result = call.run_batch(@client_queue, @client_tag, deadline,
  105. client_ops)
  106. expect(batch_result.send_metadata).to be true
  107. expect(batch_result.send_message).to be true
  108. # confirm the server can read the inbound message
  109. server_thread.join
  110. server_ops = {
  111. CallOps::RECV_MESSAGE => nil,
  112. CallOps::SEND_MESSAGE => reply_text
  113. }
  114. svr_batch = server_call.run_batch(@server_queue, @server_tag, deadline,
  115. server_ops)
  116. expect(svr_batch.message).to eq(sent_message)
  117. expect(svr_batch.send_message).to be true
  118. end
  119. it 'servers can ignore a client write and send a status' do
  120. call = new_client_call
  121. server_call = nil
  122. server_thread = Thread.new do
  123. server_call = server_allows_client_to_proceed
  124. end
  125. client_ops = {
  126. CallOps::SEND_INITIAL_METADATA => {},
  127. CallOps::SEND_MESSAGE => sent_message
  128. }
  129. batch_result = call.run_batch(@client_queue, @client_tag, deadline,
  130. client_ops)
  131. expect(batch_result.send_metadata).to be true
  132. expect(batch_result.send_message).to be true
  133. # confirm the server can read the inbound message
  134. the_status = Struct::Status.new(StatusCodes::OK, 'OK')
  135. server_thread.join
  136. server_ops = {
  137. CallOps::SEND_STATUS_FROM_SERVER => the_status
  138. }
  139. svr_batch = server_call.run_batch(@server_queue, @server_tag, deadline,
  140. server_ops)
  141. expect(svr_batch.message).to eq nil
  142. expect(svr_batch.send_status).to be true
  143. end
  144. it 'completes calls by sending status to client and server' do
  145. call = new_client_call
  146. server_call = nil
  147. server_thread = Thread.new do
  148. server_call = server_allows_client_to_proceed
  149. end
  150. client_ops = {
  151. CallOps::SEND_INITIAL_METADATA => {},
  152. CallOps::SEND_MESSAGE => sent_message
  153. }
  154. batch_result = call.run_batch(@client_queue, @client_tag, deadline,
  155. client_ops)
  156. expect(batch_result.send_metadata).to be true
  157. expect(batch_result.send_message).to be true
  158. # confirm the server can read the inbound message and respond
  159. the_status = Struct::Status.new(StatusCodes::OK, 'OK', {})
  160. server_thread.join
  161. server_ops = {
  162. CallOps::RECV_MESSAGE => nil,
  163. CallOps::SEND_MESSAGE => reply_text,
  164. CallOps::SEND_STATUS_FROM_SERVER => the_status
  165. }
  166. svr_batch = server_call.run_batch(@server_queue, @server_tag, deadline,
  167. server_ops)
  168. expect(svr_batch.message).to eq sent_message
  169. expect(svr_batch.send_status).to be true
  170. expect(svr_batch.send_message).to be true
  171. # confirm the client can receive the server response and status.
  172. client_ops = {
  173. CallOps::SEND_CLOSE_FROM_CLIENT => nil,
  174. CallOps::RECV_INITIAL_METADATA => nil,
  175. CallOps::RECV_MESSAGE => nil,
  176. CallOps::RECV_STATUS_ON_CLIENT => nil
  177. }
  178. batch_result = call.run_batch(@client_queue, @client_tag, deadline,
  179. client_ops)
  180. expect(batch_result.send_close).to be true
  181. expect(batch_result.message).to eq reply_text
  182. expect(batch_result.status).to eq the_status
  183. # confirm the server can receive the client close.
  184. server_ops = {
  185. CallOps::RECV_CLOSE_ON_SERVER => nil
  186. }
  187. svr_batch = server_call.run_batch(@server_queue, @server_tag, deadline,
  188. server_ops)
  189. expect(svr_batch.send_close).to be true
  190. end
  191. end
  192. shared_examples 'GRPC metadata delivery works OK' do
  193. include_context 'setup: tags'
  194. describe 'from client => server' do
  195. before(:example) do
  196. n = 7 # arbitrary number of metadata
  197. diff_keys_fn = proc { |i| [format('k%d', i), format('v%d', i)] }
  198. diff_keys = Hash[n.times.collect { |x| diff_keys_fn.call x }]
  199. null_vals_fn = proc { |i| [format('k%d', i), format('v\0%d', i)] }
  200. null_vals = Hash[n.times.collect { |x| null_vals_fn.call x }]
  201. same_keys_fn = proc { |i| [format('k%d', i), [format('v%d', i)] * n] }
  202. same_keys = Hash[n.times.collect { |x| same_keys_fn.call x }]
  203. symbol_key = { a_key: 'a val' }
  204. @valid_metadata = [diff_keys, same_keys, null_vals, symbol_key]
  205. @bad_keys = []
  206. @bad_keys << { Object.new => 'a value' }
  207. @bad_keys << { 1 => 'a value' }
  208. end
  209. it 'raises an exception if a metadata key is invalid' do
  210. @bad_keys.each do |md|
  211. call = new_client_call
  212. client_ops = {
  213. CallOps::SEND_INITIAL_METADATA => md
  214. }
  215. blk = proc do
  216. call.run_batch(@client_queue, @client_tag, deadline,
  217. client_ops)
  218. end
  219. expect(&blk).to raise_error
  220. end
  221. end
  222. it 'sends all the metadata pairs when keys and values are valid' do
  223. @valid_metadata.each do |md|
  224. recvd_rpc = nil
  225. rcv_thread = Thread.new do
  226. recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
  227. end
  228. call = new_client_call
  229. client_ops = {
  230. CallOps::SEND_INITIAL_METADATA => md
  231. }
  232. batch_result = call.run_batch(@client_queue, @client_tag, deadline,
  233. client_ops)
  234. expect(batch_result.send_metadata).to be true
  235. # confirm the server can receive the client metadata
  236. rcv_thread.join
  237. expect(recvd_rpc).to_not eq nil
  238. recvd_md = recvd_rpc.metadata
  239. replace_symbols = Hash[md.each_pair.collect { |x, y| [x.to_s, y] }]
  240. expect(recvd_md).to eq(recvd_md.merge(replace_symbols))
  241. end
  242. end
  243. end
  244. describe 'from server => client' do
  245. before(:example) do
  246. n = 7 # arbitrary number of metadata
  247. diff_keys_fn = proc { |i| [format('k%d', i), format('v%d', i)] }
  248. diff_keys = Hash[n.times.collect { |x| diff_keys_fn.call x }]
  249. null_vals_fn = proc { |i| [format('k%d', i), format('v\0%d', i)] }
  250. null_vals = Hash[n.times.collect { |x| null_vals_fn.call x }]
  251. same_keys_fn = proc { |i| [format('k%d', i), [format('v%d', i)] * n] }
  252. same_keys = Hash[n.times.collect { |x| same_keys_fn.call x }]
  253. symbol_key = { a_key: 'a val' }
  254. @valid_metadata = [diff_keys, same_keys, null_vals, symbol_key]
  255. @bad_keys = []
  256. @bad_keys << { Object.new => 'a value' }
  257. @bad_keys << { 1 => 'a value' }
  258. end
  259. it 'raises an exception if a metadata key is invalid' do
  260. @bad_keys.each do |md|
  261. recvd_rpc = nil
  262. rcv_thread = Thread.new do
  263. recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
  264. end
  265. call = new_client_call
  266. # client signals that it's done sending metadata to allow server to
  267. # respond
  268. client_ops = {
  269. CallOps::SEND_INITIAL_METADATA => nil
  270. }
  271. call.run_batch(@client_queue, @client_tag, deadline, client_ops)
  272. # server gets the invocation
  273. rcv_thread.join
  274. expect(recvd_rpc).to_not eq nil
  275. server_ops = {
  276. CallOps::SEND_INITIAL_METADATA => md
  277. }
  278. blk = proc do
  279. recvd_rpc.call.run_batch(@server_queue, @server_tag, deadline,
  280. server_ops)
  281. end
  282. expect(&blk).to raise_error
  283. end
  284. end
  285. it 'sends an empty hash if no metadata is added' do
  286. recvd_rpc = nil
  287. rcv_thread = Thread.new do
  288. recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
  289. end
  290. call = new_client_call
  291. # client signals that it's done sending metadata to allow server to
  292. # respond
  293. client_ops = {
  294. CallOps::SEND_INITIAL_METADATA => nil
  295. }
  296. call.run_batch(@client_queue, @client_tag, deadline, client_ops)
  297. # server gets the invocation but sends no metadata back
  298. rcv_thread.join
  299. expect(recvd_rpc).to_not eq nil
  300. server_call = recvd_rpc.call
  301. server_ops = {
  302. CallOps::SEND_INITIAL_METADATA => nil
  303. }
  304. server_call.run_batch(@server_queue, @server_tag, deadline, server_ops)
  305. # client receives nothing as expected
  306. client_ops = {
  307. CallOps::RECV_INITIAL_METADATA => nil
  308. }
  309. batch_result = call.run_batch(@client_queue, @client_tag, deadline,
  310. client_ops)
  311. expect(batch_result.metadata).to eq({})
  312. end
  313. it 'sends all the pairs when keys and values are valid' do
  314. @valid_metadata.each do |md|
  315. recvd_rpc = nil
  316. rcv_thread = Thread.new do
  317. recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
  318. end
  319. call = new_client_call
  320. # client signals that it's done sending metadata to allow server to
  321. # respond
  322. client_ops = {
  323. CallOps::SEND_INITIAL_METADATA => nil
  324. }
  325. call.run_batch(@client_queue, @client_tag, deadline, client_ops)
  326. # server gets the invocation but sends no metadata back
  327. rcv_thread.join
  328. expect(recvd_rpc).to_not eq nil
  329. server_call = recvd_rpc.call
  330. server_ops = {
  331. CallOps::SEND_INITIAL_METADATA => md
  332. }
  333. server_call.run_batch(@server_queue, @server_tag, deadline, server_ops)
  334. # client receives nothing as expected
  335. client_ops = {
  336. CallOps::RECV_INITIAL_METADATA => nil
  337. }
  338. batch_result = call.run_batch(@client_queue, @client_tag, deadline,
  339. client_ops)
  340. replace_symbols = Hash[md.each_pair.collect { |x, y| [x.to_s, y] }]
  341. expect(batch_result.metadata).to eq(replace_symbols)
  342. end
  343. end
  344. end
  345. end
  346. describe 'the http client/server' do
  347. before(:example) do
  348. server_host = '0.0.0.0:0'
  349. @client_queue = GRPC::Core::CompletionQueue.new
  350. @server_queue = GRPC::Core::CompletionQueue.new
  351. @server = GRPC::Core::Server.new(@server_queue, nil)
  352. server_port = @server.add_http2_port(server_host, :this_port_is_insecure)
  353. @server.start
  354. @ch = Channel.new("0.0.0.0:#{server_port}", nil, :this_channel_is_insecure)
  355. end
  356. after(:example) do
  357. @ch.close
  358. @server.close(@server_queue, deadline)
  359. end
  360. it_behaves_like 'basic GRPC message delivery is OK' do
  361. end
  362. it_behaves_like 'GRPC metadata delivery works OK' do
  363. end
  364. end
  365. describe 'the secure http client/server' do
  366. include_context 'setup: tags'
  367. def load_test_certs
  368. test_root = File.join(File.dirname(__FILE__), 'testdata')
  369. files = ['ca.pem', 'server1.key', 'server1.pem']
  370. files.map { |f| File.open(File.join(test_root, f)).read }
  371. end
  372. before(:example) do
  373. certs = load_test_certs
  374. server_host = '0.0.0.0:0'
  375. @client_queue = GRPC::Core::CompletionQueue.new
  376. @server_queue = GRPC::Core::CompletionQueue.new
  377. server_creds = GRPC::Core::ServerCredentials.new(
  378. nil, [{ private_key: certs[1], cert_chain: certs[2] }], false)
  379. @server = GRPC::Core::Server.new(@server_queue, nil)
  380. server_port = @server.add_http2_port(server_host, server_creds)
  381. @server.start
  382. args = { Channel::SSL_TARGET => 'foo.test.google.fr' }
  383. @ch = Channel.new("0.0.0.0:#{server_port}", args,
  384. GRPC::Core::ChannelCredentials.new(certs[0], nil, nil))
  385. end
  386. after(:example) do
  387. @server.close(@server_queue, deadline)
  388. end
  389. it_behaves_like 'basic GRPC message delivery is OK' do
  390. end
  391. it_behaves_like 'GRPC metadata delivery works OK' do
  392. end
  393. it 'modifies metadata with CallCredentials' do
  394. auth_proc = proc { { 'k1' => 'updated-v1' } }
  395. call_creds = GRPC::Core::CallCredentials.new(auth_proc)
  396. md = { 'k2' => 'v2' }
  397. expected_md = { 'k1' => 'updated-v1', 'k2' => 'v2' }
  398. recvd_rpc = nil
  399. rcv_thread = Thread.new do
  400. recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
  401. end
  402. call = new_client_call
  403. call.set_credentials! call_creds
  404. client_ops = {
  405. CallOps::SEND_INITIAL_METADATA => md
  406. }
  407. batch_result = call.run_batch(@client_queue, @client_tag, deadline,
  408. client_ops)
  409. expect(batch_result.send_metadata).to be true
  410. # confirm the server can receive the client metadata
  411. rcv_thread.join
  412. expect(recvd_rpc).to_not eq nil
  413. recvd_md = recvd_rpc.metadata
  414. replace_symbols = Hash[expected_md.each_pair.collect { |x, y| [x.to_s, y] }]
  415. expect(recvd_md).to eq(recvd_md.merge(replace_symbols))
  416. end
  417. end