user_agent_spec.rb 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. require 'rails_helper'
  3. require 'rack/handler/puma'
  4. # this cop is disabled to speed up testing by avoiding the overhead of multiple requests
  5. RSpec.describe UserAgent, :aggregate_failures, integration: true do
  6. include ZammadSpecSupportRequest
  7. def host_with_port
  8. host = 'http://localhost:3000'
  9. if ENV['CI'].present?
  10. host = 'http://build:3000'
  11. end
  12. host
  13. end
  14. puma_thread = nil
  15. # we need a running web server, otherwise the requests will fail
  16. before :all do # rubocop:disable RSpec/BeforeAfterAll
  17. ENV['CI_BASIC_AUTH_USER'] = 'basic_auth_user'
  18. ENV['CI_BASIC_AUTH_PASSWORD'] = 'test123'
  19. ENV['CI_BEARER_TOKEN'] = 'test_bearer_123'
  20. puma_thread = Thread.new do
  21. app = Rack::Builder.new do
  22. map '/' do
  23. run Rails.application
  24. end
  25. end.to_app
  26. Rack::Handler::Puma.run app, Port: 3000
  27. end
  28. sleep 0.25
  29. # wait for server to start
  30. server_started = false
  31. 10.times do
  32. next if server_started
  33. server_started = system("curl -sSf #{host_with_port} > /dev/null")
  34. sleep 0.2 if !server_started
  35. end
  36. end
  37. after :all do # rubocop:disable RSpec/BeforeAfterAll
  38. puma_thread.kill
  39. end
  40. shared_context 'when doing user agent tests' do
  41. let(:host) { host_with_port }
  42. shared_examples 'successful request' do
  43. it 'returns a response' do
  44. expect(response).to be_success
  45. expect(response.code).to eq(code)
  46. end
  47. end
  48. shared_examples 'successful request with json body' do
  49. it 'returns a response' do
  50. expect(response).to be_success
  51. expect(response.code).to eq(code)
  52. expect(json_response).to include(expected_body)
  53. end
  54. end
  55. shared_examples 'successful get request' do
  56. it 'returns a response' do
  57. expect(response).to be_success
  58. expect(response.code).to eq(code)
  59. expect(response.header).to include('content-type' => content_type)
  60. expect(json_response).to include(expected_body)
  61. end
  62. end
  63. shared_examples 'successful post/put request' do
  64. include_examples 'successful request with json body'
  65. end
  66. shared_examples 'successful delete request' do
  67. include_examples 'successful request with json body'
  68. end
  69. shared_examples 'successful redirect request' do
  70. include_examples 'successful request with json body'
  71. end
  72. shared_examples 'unsuccessful request' do
  73. it 'returns a response' do
  74. expect(response).not_to be_success
  75. expect(response.code).to eq(code)
  76. end
  77. end
  78. shared_examples 'unsuccessful request without body' do
  79. it 'returns a response' do
  80. expect(response).not_to be_success
  81. expect(response.code).to eq(code)
  82. expect(response.body).to be_nil
  83. end
  84. end
  85. shared_examples 'unsuccessful get/post/put/delete request' do
  86. it 'returns a response' do
  87. expect(response).not_to be_success
  88. expect(response.code).to eq(code)
  89. expect(response.body).to eq(expected_body)
  90. end
  91. end
  92. shared_examples 'ftp requests' do
  93. it 'returns a response' do
  94. expect(response).to be_success
  95. expect(response.code).to eq(code)
  96. expect(response.body).to match(expected_body)
  97. end
  98. end
  99. describe '#get' do
  100. context 'without http basic auth' do
  101. subject(:response) { described_class.get(request_url) }
  102. context 'with code 200' do
  103. let(:code) { '200' }
  104. let(:content_type) { 'application/json; charset=utf-8' }
  105. let(:request_url) { "#{host}/test/get/1?submitted=123" }
  106. let(:expected_body) do
  107. {
  108. 'method' => 'get',
  109. 'submitted' => '123',
  110. 'content_type_requested' => nil,
  111. }
  112. end
  113. include_examples 'successful get request'
  114. end
  115. context 'with code 202' do
  116. let(:code) { '202' }
  117. let(:content_type) { 'application/json; charset=utf-8' }
  118. let(:request_url) { "#{host}/test/get_accepted/1?submitted=123" }
  119. let(:expected_body) do
  120. {
  121. 'method' => 'get',
  122. 'submitted' => '123',
  123. 'content_type_requested' => nil,
  124. }
  125. end
  126. include_examples 'successful get request'
  127. end
  128. context 'with code 404' do
  129. let(:code) { '404' }
  130. let(:request_url) { "#{host}/test/not_existing" }
  131. include_examples 'unsuccessful request'
  132. end
  133. end
  134. context 'with http basic auth' do
  135. subject(:response) do
  136. described_class.get(request_url, {}, {
  137. user: 'basic_auth_user',
  138. password: password,
  139. })
  140. end
  141. context 'with code 200' do
  142. let(:code) { '200' }
  143. let(:content_type) { 'application/json; charset=utf-8' }
  144. let(:request_url) { "#{host}/test_basic_auth/get/1?submitted=123" }
  145. let(:password) { 'test123' }
  146. let(:expected_body) do
  147. {
  148. 'method' => 'get',
  149. 'submitted' => '123',
  150. 'content_type_requested' => nil,
  151. }
  152. end
  153. include_examples 'successful get request'
  154. end
  155. context 'with code 401' do
  156. let(:code) { '401' }
  157. let(:request_url) { "#{host}/test_basic_auth/get/1?submitted=123" }
  158. let(:password) { 'test<>123' }
  159. let(:expected_body) { "HTTP Basic: Access denied.\n" }
  160. include_examples 'unsuccessful get/post/put/delete request'
  161. end
  162. end
  163. context 'with bearer token auth' do
  164. subject(:response) do
  165. described_class.get(request_url, {}, {
  166. bearer_token: bearer_token,
  167. })
  168. end
  169. context 'with code 200' do
  170. let(:code) { '200' }
  171. let(:content_type) { 'application/json; charset=utf-8' }
  172. let(:request_url) { "#{host}/test_bearer_auth/get/1?submitted=123" }
  173. let(:bearer_token) { 'test_bearer_123' }
  174. let(:expected_body) do
  175. {
  176. 'method' => 'get',
  177. 'submitted' => '123',
  178. 'content_type_requested' => nil,
  179. }
  180. end
  181. include_examples 'successful get request'
  182. end
  183. context 'with code 401' do
  184. let(:code) { '401' }
  185. let(:request_url) { "#{host}/test_bearer_auth/get/1?submitted=123" }
  186. let(:bearer_token) { 'wrong_test_bearer' }
  187. let(:expected_body) { "HTTP Token: Access denied.\n" }
  188. include_examples 'unsuccessful get/post/put/delete request'
  189. end
  190. end
  191. context 'when timeouts are raised' do
  192. subject(:response) do
  193. described_class.get(request_url, {}, {
  194. open_timeout: 0,
  195. read_timeout: 0,
  196. })
  197. end
  198. let(:request_url) { "#{host}/test/get/1?submitted=123" }
  199. let(:code) { 0 }
  200. include_examples 'unsuccessful request without body'
  201. end
  202. context 'with content type set to json' do
  203. subject(:response) { described_class.get(request_url, request_params, request_options) }
  204. context 'with code 200' do
  205. let(:code) { '200' }
  206. let(:content_type) { 'application/json; charset=utf-8' }
  207. let(:request_url) { "#{host}/test/get/1" }
  208. let(:request_params) { { submitted: 'some value' } }
  209. let(:request_options) { { json: true } }
  210. let(:expected_body) do
  211. {
  212. 'method' => 'get',
  213. 'content_type_requested' => nil,
  214. 'submitted' => 'some value',
  215. }
  216. end
  217. include_examples 'successful get request'
  218. end
  219. context 'with code 404' do
  220. let(:code) { '404' }
  221. let(:request_url) { "#{host}/test/not_existing" }
  222. let(:request_params) { { submitted: { key: 'some value' } } }
  223. let(:request_options) { { json: true } }
  224. include_examples 'unsuccessful request'
  225. end
  226. end
  227. end
  228. describe '#post' do
  229. context 'without http basic auth' do
  230. subject(:response) { described_class.post(request_url, request_params) }
  231. context 'with code 201' do
  232. let(:code) { '201' }
  233. let(:request_url) { "#{host}/test/post/1" }
  234. let(:request_params) { { submitted: 'some value' } }
  235. let(:expected_body) do
  236. {
  237. 'method' => 'post',
  238. 'submitted' => 'some value',
  239. 'content_type_requested' => 'application/x-www-form-urlencoded',
  240. }
  241. end
  242. include_examples 'successful post/put request'
  243. end
  244. context 'with code 404' do
  245. let(:code) { '404' }
  246. let(:request_url) { "#{host}/test/not_existing" }
  247. let(:request_params) { { submitted: 'some value' } }
  248. include_examples 'unsuccessful request without body'
  249. end
  250. end
  251. context 'with http basic auth' do
  252. subject(:response) do
  253. described_class.post(request_url, request_params, {
  254. user: 'basic_auth_user',
  255. password: password,
  256. })
  257. end
  258. context 'with code 201' do
  259. let(:code) { '201' }
  260. let(:request_url) { "#{host}/test_basic_auth/post/1" }
  261. let(:request_params) { { submitted: 'some value' } }
  262. let(:password) { 'test123' }
  263. let(:expected_body) do
  264. {
  265. 'method' => 'post',
  266. 'submitted' => 'some value',
  267. 'content_type_requested' => 'application/x-www-form-urlencoded',
  268. }
  269. end
  270. include_examples 'successful post/put request'
  271. end
  272. context 'with code 401' do
  273. let(:code) { '401' }
  274. let(:request_url) { "#{host}/test_basic_auth/post/1" }
  275. let(:request_params) { { submitted: 'some value' } }
  276. let(:password) { 'test<>123' }
  277. let(:expected_body) { "HTTP Basic: Access denied.\n" }
  278. include_examples 'unsuccessful get/post/put/delete request'
  279. end
  280. end
  281. context 'with bearer token auth' do
  282. subject(:response) do
  283. described_class.post(request_url, request_params, {
  284. bearer_token: bearer_token,
  285. })
  286. end
  287. context 'with code 201' do
  288. let(:code) { '201' }
  289. let(:request_url) { "#{host}/test_bearer_auth/post/1" }
  290. let(:request_params) { { submitted: 'some value' } }
  291. let(:bearer_token) { 'test_bearer_123' }
  292. let(:expected_body) do
  293. {
  294. 'method' => 'post',
  295. 'submitted' => 'some value',
  296. 'content_type_requested' => 'application/x-www-form-urlencoded',
  297. }
  298. end
  299. include_examples 'successful post/put request'
  300. end
  301. context 'with code 401' do
  302. let(:code) { '401' }
  303. let(:request_url) { "#{host}/test_bearer_auth/post/1" }
  304. let(:request_params) { { submitted: 'some value' } }
  305. let(:bearer_token) { 'wrong_test_bearer' }
  306. let(:expected_body) { "HTTP Token: Access denied.\n" }
  307. include_examples 'unsuccessful get/post/put/delete request'
  308. end
  309. end
  310. context 'when timeouts are raised' do
  311. subject(:response) do
  312. described_class.post(request_url, request_params, {
  313. open_timeout: 0,
  314. read_timeout: 0,
  315. })
  316. end
  317. let(:request_url) { "#{host}/test/post/1" }
  318. let(:request_params) { { submitted: 'timeout' } }
  319. let(:code) { 0 }
  320. include_examples 'unsuccessful request without body'
  321. end
  322. context 'with content type set to json' do
  323. subject(:response) { described_class.post(request_url, request_params, request_options) }
  324. context 'with code 201' do
  325. let(:code) { '201' }
  326. let(:content_type) { 'application/json; charset=utf-8' }
  327. let(:request_url) { "#{host}/test/post/1" }
  328. let(:request_params) { { submitted: { key: 'some value' } } }
  329. let(:request_options) { { json: true } }
  330. let(:expected_body) do
  331. {
  332. 'method' => 'post',
  333. 'content_type_requested' => 'application/json',
  334. 'submitted' => {
  335. 'key' => 'some value',
  336. },
  337. }
  338. end
  339. include_examples 'successful post/put request'
  340. end
  341. end
  342. end
  343. describe '#put' do
  344. subject(:response) { described_class.put(request_url, request_params) }
  345. context 'without http basic auth' do
  346. context 'with code 200' do
  347. let(:code) { '200' }
  348. let(:request_url) { "#{host}/test/put/1" }
  349. let(:request_params) { { submitted: 'some value' } }
  350. let(:expected_body) do
  351. {
  352. 'method' => 'put',
  353. 'submitted' => 'some value',
  354. 'content_type_requested' => 'application/x-www-form-urlencoded',
  355. }
  356. end
  357. include_examples 'successful post/put request'
  358. end
  359. context 'with code 404' do
  360. let(:code) { '404' }
  361. let(:request_url) { "#{host}/test/not_existing" }
  362. let(:request_params) { { submitted: 'some value' } }
  363. include_examples 'unsuccessful request without body'
  364. end
  365. end
  366. context 'with http basic auth' do
  367. subject(:response) do
  368. described_class.put(request_url, request_params, {
  369. user: 'basic_auth_user',
  370. password: password,
  371. })
  372. end
  373. let(:password) { 'test123' }
  374. let(:submit_value) { 'some value' }
  375. context 'with code 200' do
  376. let(:code) { '200' }
  377. let(:request_url) { "#{host}/test_basic_auth/put/1" }
  378. let(:request_params) { { submitted: 'some value' } }
  379. let(:expected_body) do
  380. {
  381. 'method' => 'put',
  382. 'submitted' => 'some value',
  383. 'content_type_requested' => 'application/x-www-form-urlencoded',
  384. }
  385. end
  386. include_examples 'successful post/put request'
  387. end
  388. context 'with code 401' do
  389. let(:code) { '401' }
  390. let(:request_url) { "#{host}/test_basic_auth/put/1" }
  391. let(:request_params) { { submitted: 'some value' } }
  392. let(:password) { 'test<>123' }
  393. let(:expected_body) { "HTTP Basic: Access denied.\n" }
  394. include_examples 'unsuccessful get/post/put/delete request'
  395. end
  396. end
  397. context 'with bearer token auth' do
  398. subject(:response) do
  399. described_class.put(request_url, request_params, {
  400. bearer_token: bearer_token,
  401. })
  402. end
  403. context 'with code 200' do
  404. let(:code) { '200' }
  405. let(:request_url) { "#{host}/test_bearer_auth/put/1" }
  406. let(:request_params) { { submitted: 'some value' } }
  407. let(:bearer_token) { 'test_bearer_123' }
  408. let(:expected_body) do
  409. {
  410. 'method' => 'put',
  411. 'submitted' => 'some value',
  412. 'content_type_requested' => 'application/x-www-form-urlencoded',
  413. }
  414. end
  415. include_examples 'successful post/put request'
  416. end
  417. context 'with code 401' do
  418. let(:code) { '401' }
  419. let(:request_url) { "#{host}/test_bearer_auth/put/1" }
  420. let(:request_params) { { submitted: 'some value' } }
  421. let(:bearer_token) { 'wrong_test_bearer' }
  422. let(:expected_body) { "HTTP Token: Access denied.\n" }
  423. include_examples 'unsuccessful get/post/put/delete request'
  424. end
  425. end
  426. end
  427. describe '#delete' do
  428. context 'without http basic auth' do
  429. subject(:response) { described_class.delete(request_url) }
  430. context 'with code 200' do
  431. let(:code) { '200' }
  432. let(:request_url) { "#{host}/test/delete/1" }
  433. let(:expected_body) do
  434. {
  435. 'method' => 'delete',
  436. 'content_type_requested' => nil,
  437. }
  438. end
  439. include_examples 'successful delete request'
  440. end
  441. context 'with code 404' do
  442. let(:code) { '404' }
  443. let(:request_url) { "#{host}/test/not_existing" }
  444. include_examples 'unsuccessful request without body'
  445. end
  446. end
  447. context 'with http basic auth' do
  448. subject(:response) do
  449. described_class.delete(request_url, {}, {
  450. user: 'basic_auth_user',
  451. password: password,
  452. })
  453. end
  454. context 'with code 200' do
  455. let(:code) { '200' }
  456. let(:content_type) { 'application/json; charset=utf-8' }
  457. let(:request_url) { "#{host}/test_basic_auth/delete/1" }
  458. let(:password) { 'test123' }
  459. let(:expected_body) do
  460. {
  461. 'method' => 'delete',
  462. 'content_type_requested' => nil,
  463. }
  464. end
  465. include_examples 'successful delete request'
  466. end
  467. context 'with code 401' do
  468. let(:code) { '401' }
  469. let(:request_url) { "#{host}/test_basic_auth/delete/1" }
  470. let(:password) { 'test<>123' }
  471. let(:expected_body) { "HTTP Basic: Access denied.\n" }
  472. include_examples 'unsuccessful get/post/put/delete request'
  473. end
  474. end
  475. context 'with bearer token auth' do
  476. subject(:response) do
  477. described_class.delete(request_url, {}, {
  478. bearer_token: bearer_token,
  479. })
  480. end
  481. context 'with code 200' do
  482. let(:code) { '200' }
  483. let(:content_type) { 'application/json; charset=utf-8' }
  484. let(:request_url) { "#{host}/test_bearer_auth/delete/1" }
  485. let(:request_params) { { submitted: 'some value' } }
  486. let(:bearer_token) { 'test_bearer_123' }
  487. let(:expected_body) do
  488. {
  489. 'method' => 'delete',
  490. 'content_type_requested' => nil,
  491. }
  492. end
  493. include_examples 'successful delete request'
  494. end
  495. context 'with code 401' do
  496. let(:code) { '401' }
  497. let(:request_url) { "#{host}/test_bearer_auth/delete/1" }
  498. let(:request_params) { { submitted: 'some value' } }
  499. let(:bearer_token) { 'wrong_test_bearer' }
  500. let(:expected_body) { "HTTP Token: Access denied.\n" }
  501. include_examples 'unsuccessful get/post/put/delete request'
  502. end
  503. end
  504. end
  505. describe '#request' do
  506. context 'without http basic auth' do
  507. subject(:response) { described_class.request(request_url) }
  508. context 'with code 200' do
  509. let(:code) { '200' }
  510. let(:content_type) { 'application/json; charset=utf-8' }
  511. let(:request_url) { "#{host}/test/redirect" }
  512. let(:expected_body) do
  513. {
  514. 'method' => 'get',
  515. 'submitted' => 'abc',
  516. 'content_type_requested' => nil,
  517. }
  518. end
  519. include_examples 'successful redirect request'
  520. end
  521. end
  522. context 'with http basic auth' do
  523. subject(:response) do
  524. described_class.request(request_url, {
  525. user: 'basic_auth_user',
  526. password: password,
  527. })
  528. end
  529. context 'with code 200' do
  530. let(:code) { '200' }
  531. let(:request_url) { "#{host}/test_basic_auth/redirect" }
  532. let(:password) { 'test123' }
  533. let(:expected_body) do
  534. {
  535. 'method' => 'get',
  536. 'submitted' => 'abc',
  537. 'content_type_requested' => nil,
  538. }
  539. end
  540. include_examples 'successful redirect request'
  541. end
  542. context 'with code 401' do
  543. let(:code) { '401' }
  544. let(:request_url) { "#{host}/test_basic_auth/redirect" }
  545. let(:password) { 'test<>123' }
  546. let(:expected_body) { "HTTP Basic: Access denied.\n" }
  547. include_examples 'unsuccessful get/post/put/delete request'
  548. end
  549. end
  550. context 'when ftp', integration: true, required_envs: ['FTP_URL'] do
  551. subject(:response) do
  552. described_class.request(request_url)
  553. end
  554. context 'with code 200' do
  555. let(:code) { '200' }
  556. let(:request_url) { "#{ENV['FTP_URL']}/zammad.txt" }
  557. let(:expected_body) { %r{zammad}i }
  558. include_examples 'ftp requests'
  559. end
  560. context 'with code 550' do
  561. let(:code) { '550' }
  562. let(:request_url) { "#{ENV['FTP_URL']}/nonexisting.txt" }
  563. include_examples 'unsuccessful request without body'
  564. end
  565. context 'with a not existing URL' do
  566. let(:code) { 0 }
  567. let(:request_url) { 'http://not.existing.host.tld/test.php' }
  568. include_examples 'unsuccessful request without body'
  569. end
  570. end
  571. end
  572. end
  573. describe 'testing without proxy' do
  574. include_context 'when doing user agent tests'
  575. end
  576. describe 'testing with proxy', required_envs: %w[CI_PROXY_URL CI_PROXY_USER CI_PROXY_PASSWORD] do
  577. before do
  578. Setting.set('proxy', ENV['CI_PROXY_URL'])
  579. Setting.set('proxy_username', ENV['CI_PROXY_USER'])
  580. Setting.set('proxy_password', ENV['CI_PROXY_PASSWORD'])
  581. end
  582. include_context 'when doing user agent tests'
  583. end
  584. end