user_agent_spec.rb 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  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 with body' do
  73. it 'returns a response' do
  74. expect(response).not_to be_success
  75. expect(response.code).to eq(code)
  76. expect(response.body).to be_present
  77. end
  78. end
  79. shared_examples 'unsuccessful request without body' do
  80. it 'returns a response' do
  81. expect(response).not_to be_success
  82. expect(response.code).to eq(code)
  83. expect(response.body).to be_nil
  84. end
  85. end
  86. shared_examples 'unsuccessful get/post/put/delete request' do
  87. it 'returns a response' do
  88. expect(response).not_to be_success
  89. expect(response.code).to eq(code)
  90. expect(response.body).to eq(expected_body)
  91. end
  92. end
  93. shared_examples 'ftp requests' do
  94. it 'returns a response' do
  95. expect(response).to be_success
  96. expect(response.code).to eq(code)
  97. expect(response.body).to match(expected_body)
  98. end
  99. end
  100. describe '#get' do
  101. context 'without http basic auth' do
  102. subject(:response) { described_class.get(request_url) }
  103. context 'with code 200' do
  104. let(:code) { '200' }
  105. let(:content_type) { 'application/json; charset=utf-8' }
  106. let(:request_url) { "#{host}/test/get/1?submitted=123" }
  107. let(:expected_body) do
  108. {
  109. 'method' => 'get',
  110. 'submitted' => '123',
  111. 'content_type_requested' => nil,
  112. }
  113. end
  114. include_examples 'successful get request'
  115. end
  116. context 'with code 202' do
  117. let(:code) { '202' }
  118. let(:content_type) { 'application/json; charset=utf-8' }
  119. let(:request_url) { "#{host}/test/get_accepted/1?submitted=123" }
  120. let(:expected_body) do
  121. {
  122. 'method' => 'get',
  123. 'submitted' => '123',
  124. 'content_type_requested' => nil,
  125. }
  126. end
  127. include_examples 'successful get request'
  128. end
  129. context 'with code 404' do
  130. let(:code) { '404' }
  131. let(:request_url) { "#{host}/test/not_existing" }
  132. include_examples 'unsuccessful request with body'
  133. end
  134. end
  135. context 'with http basic auth' do
  136. subject(:response) do
  137. described_class.get(request_url, {}, {
  138. user: 'basic_auth_user',
  139. password: password,
  140. })
  141. end
  142. context 'with code 200' do
  143. let(:code) { '200' }
  144. let(:content_type) { 'application/json; charset=utf-8' }
  145. let(:request_url) { "#{host}/test_basic_auth/get/1?submitted=123" }
  146. let(:password) { 'test123' }
  147. let(:expected_body) do
  148. {
  149. 'method' => 'get',
  150. 'submitted' => '123',
  151. 'content_type_requested' => nil,
  152. }
  153. end
  154. include_examples 'successful get request'
  155. end
  156. context 'with code 401' do
  157. let(:code) { '401' }
  158. let(:request_url) { "#{host}/test_basic_auth/get/1?submitted=123" }
  159. let(:password) { 'test<>123' }
  160. let(:expected_body) { "HTTP Basic: Access denied.\n" }
  161. include_examples 'unsuccessful get/post/put/delete request'
  162. end
  163. end
  164. context 'with bearer token auth' do
  165. subject(:response) do
  166. described_class.get(request_url, {}, {
  167. bearer_token: bearer_token,
  168. })
  169. end
  170. context 'with code 200' do
  171. let(:code) { '200' }
  172. let(:content_type) { 'application/json; charset=utf-8' }
  173. let(:request_url) { "#{host}/test_bearer_auth/get/1?submitted=123" }
  174. let(:bearer_token) { 'test_bearer_123' }
  175. let(:expected_body) do
  176. {
  177. 'method' => 'get',
  178. 'submitted' => '123',
  179. 'content_type_requested' => nil,
  180. }
  181. end
  182. include_examples 'successful get request'
  183. end
  184. context 'with code 401' do
  185. let(:code) { '401' }
  186. let(:request_url) { "#{host}/test_bearer_auth/get/1?submitted=123" }
  187. let(:bearer_token) { 'wrong_test_bearer' }
  188. let(:expected_body) { "HTTP Token: Access denied.\n" }
  189. include_examples 'unsuccessful get/post/put/delete request'
  190. end
  191. end
  192. context 'when timeouts are raised' do
  193. subject(:response) do
  194. described_class.get(request_url, {}, {
  195. open_timeout: 0,
  196. read_timeout: 0,
  197. })
  198. end
  199. let(:request_url) { "#{host}/test/get/1?submitted=123" }
  200. let(:code) { 0 }
  201. include_examples 'unsuccessful request without body'
  202. end
  203. context 'with content type set to json' do
  204. subject(:response) { described_class.get(request_url, request_params, request_options) }
  205. context 'with code 200' do
  206. let(:code) { '200' }
  207. let(:content_type) { 'application/json; charset=utf-8' }
  208. let(:request_url) { "#{host}/test/get/1" }
  209. let(:request_params) { { submitted: 'some value' } }
  210. let(:request_options) { { json: true } }
  211. let(:expected_body) do
  212. {
  213. 'method' => 'get',
  214. 'content_type_requested' => nil,
  215. 'submitted' => 'some value',
  216. }
  217. end
  218. include_examples 'successful get request'
  219. end
  220. context 'with code 404' do
  221. let(:code) { '404' }
  222. let(:request_url) { "#{host}/test/not_existing" }
  223. let(:request_params) { { submitted: { key: 'some value' } } }
  224. let(:request_options) { { json: true } }
  225. include_examples 'unsuccessful request with body'
  226. end
  227. end
  228. end
  229. describe '#post' do
  230. context 'without http basic auth' do
  231. subject(:response) { described_class.post(request_url, request_params) }
  232. context 'with code 201' do
  233. let(:code) { '201' }
  234. let(:request_url) { "#{host}/test/post/1" }
  235. let(:request_params) { { submitted: 'some value' } }
  236. let(:expected_body) do
  237. {
  238. 'method' => 'post',
  239. 'submitted' => 'some value',
  240. 'content_type_requested' => 'application/x-www-form-urlencoded',
  241. }
  242. end
  243. include_examples 'successful post/put request'
  244. end
  245. context 'with code 404' do
  246. let(:code) { '404' }
  247. let(:request_url) { "#{host}/test/not_existing" }
  248. let(:request_params) { { submitted: 'some value' } }
  249. include_examples 'unsuccessful request with body'
  250. end
  251. end
  252. context 'with http basic auth' do
  253. subject(:response) do
  254. described_class.post(request_url, request_params, {
  255. user: 'basic_auth_user',
  256. password: password,
  257. })
  258. end
  259. context 'with code 201' do
  260. let(:code) { '201' }
  261. let(:request_url) { "#{host}/test_basic_auth/post/1" }
  262. let(:request_params) { { submitted: 'some value' } }
  263. let(:password) { 'test123' }
  264. let(:expected_body) do
  265. {
  266. 'method' => 'post',
  267. 'submitted' => 'some value',
  268. 'content_type_requested' => 'application/x-www-form-urlencoded',
  269. }
  270. end
  271. include_examples 'successful post/put request'
  272. end
  273. context 'with code 401' do
  274. let(:code) { '401' }
  275. let(:request_url) { "#{host}/test_basic_auth/post/1" }
  276. let(:request_params) { { submitted: 'some value' } }
  277. let(:password) { 'test<>123' }
  278. let(:expected_body) { "HTTP Basic: Access denied.\n" }
  279. include_examples 'unsuccessful get/post/put/delete request'
  280. end
  281. end
  282. context 'with bearer token auth' do
  283. subject(:response) do
  284. described_class.post(request_url, request_params, {
  285. bearer_token: bearer_token,
  286. })
  287. end
  288. context 'with code 201' do
  289. let(:code) { '201' }
  290. let(:request_url) { "#{host}/test_bearer_auth/post/1" }
  291. let(:request_params) { { submitted: 'some value' } }
  292. let(:bearer_token) { 'test_bearer_123' }
  293. let(:expected_body) do
  294. {
  295. 'method' => 'post',
  296. 'submitted' => 'some value',
  297. 'content_type_requested' => 'application/x-www-form-urlencoded',
  298. }
  299. end
  300. include_examples 'successful post/put request'
  301. end
  302. context 'with code 401' do
  303. let(:code) { '401' }
  304. let(:request_url) { "#{host}/test_bearer_auth/post/1" }
  305. let(:request_params) { { submitted: 'some value' } }
  306. let(:bearer_token) { 'wrong_test_bearer' }
  307. let(:expected_body) { "HTTP Token: Access denied.\n" }
  308. include_examples 'unsuccessful get/post/put/delete request'
  309. end
  310. end
  311. context 'when timeouts are raised' do
  312. subject(:response) do
  313. described_class.post(request_url, request_params, {
  314. open_timeout: 0,
  315. read_timeout: 0,
  316. })
  317. end
  318. let(:request_url) { "#{host}/test/post/1" }
  319. let(:request_params) { { submitted: 'timeout' } }
  320. let(:code) { 0 }
  321. include_examples 'unsuccessful request without body'
  322. end
  323. context 'with content type set to json' do
  324. subject(:response) { described_class.post(request_url, request_params, request_options) }
  325. context 'with code 201' do
  326. let(:code) { '201' }
  327. let(:content_type) { 'application/json; charset=utf-8' }
  328. let(:request_url) { "#{host}/test/post/1" }
  329. let(:request_params) { { submitted: { key: 'some value' } } }
  330. let(:request_options) { { json: true } }
  331. let(:expected_body) do
  332. {
  333. 'method' => 'post',
  334. 'content_type_requested' => 'application/json',
  335. 'submitted' => {
  336. 'key' => 'some value',
  337. },
  338. }
  339. end
  340. include_examples 'successful post/put request'
  341. end
  342. end
  343. end
  344. describe '#put' do
  345. subject(:response) { described_class.put(request_url, request_params) }
  346. context 'without http basic auth' do
  347. context 'with code 200' do
  348. let(:code) { '200' }
  349. let(:request_url) { "#{host}/test/put/1" }
  350. let(:request_params) { { submitted: 'some value' } }
  351. let(:expected_body) do
  352. {
  353. 'method' => 'put',
  354. 'submitted' => 'some value',
  355. 'content_type_requested' => 'application/x-www-form-urlencoded',
  356. }
  357. end
  358. include_examples 'successful post/put request'
  359. end
  360. context 'with code 404' do
  361. let(:code) { '404' }
  362. let(:request_url) { "#{host}/test/not_existing" }
  363. let(:request_params) { { submitted: 'some value' } }
  364. include_examples 'unsuccessful request with body'
  365. end
  366. end
  367. context 'with http basic auth' do
  368. subject(:response) do
  369. described_class.put(request_url, request_params, {
  370. user: 'basic_auth_user',
  371. password: password,
  372. })
  373. end
  374. let(:password) { 'test123' }
  375. let(:submit_value) { 'some value' }
  376. context 'with code 200' do
  377. let(:code) { '200' }
  378. let(:request_url) { "#{host}/test_basic_auth/put/1" }
  379. let(:request_params) { { submitted: 'some value' } }
  380. let(:expected_body) do
  381. {
  382. 'method' => 'put',
  383. 'submitted' => 'some value',
  384. 'content_type_requested' => 'application/x-www-form-urlencoded',
  385. }
  386. end
  387. include_examples 'successful post/put request'
  388. end
  389. context 'with code 401' do
  390. let(:code) { '401' }
  391. let(:request_url) { "#{host}/test_basic_auth/put/1" }
  392. let(:request_params) { { submitted: 'some value' } }
  393. let(:password) { 'test<>123' }
  394. let(:expected_body) { "HTTP Basic: Access denied.\n" }
  395. include_examples 'unsuccessful get/post/put/delete request'
  396. end
  397. end
  398. context 'with bearer token auth' do
  399. subject(:response) do
  400. described_class.put(request_url, request_params, {
  401. bearer_token: bearer_token,
  402. })
  403. end
  404. context 'with code 200' do
  405. let(:code) { '200' }
  406. let(:request_url) { "#{host}/test_bearer_auth/put/1" }
  407. let(:request_params) { { submitted: 'some value' } }
  408. let(:bearer_token) { 'test_bearer_123' }
  409. let(:expected_body) do
  410. {
  411. 'method' => 'put',
  412. 'submitted' => 'some value',
  413. 'content_type_requested' => 'application/x-www-form-urlencoded',
  414. }
  415. end
  416. include_examples 'successful post/put request'
  417. end
  418. context 'with code 401' do
  419. let(:code) { '401' }
  420. let(:request_url) { "#{host}/test_bearer_auth/put/1" }
  421. let(:request_params) { { submitted: 'some value' } }
  422. let(:bearer_token) { 'wrong_test_bearer' }
  423. let(:expected_body) { "HTTP Token: Access denied.\n" }
  424. include_examples 'unsuccessful get/post/put/delete request'
  425. end
  426. end
  427. end
  428. describe '#delete' do
  429. context 'without http basic auth' do
  430. subject(:response) { described_class.delete(request_url) }
  431. context 'with code 200' do
  432. let(:code) { '200' }
  433. let(:request_url) { "#{host}/test/delete/1" }
  434. let(:expected_body) do
  435. {
  436. 'method' => 'delete',
  437. 'content_type_requested' => nil,
  438. }
  439. end
  440. include_examples 'successful delete request'
  441. end
  442. context 'with code 404' do
  443. let(:code) { '404' }
  444. let(:request_url) { "#{host}/test/not_existing" }
  445. include_examples 'unsuccessful request with body'
  446. end
  447. end
  448. context 'with http basic auth' do
  449. subject(:response) do
  450. described_class.delete(request_url, {}, {
  451. user: 'basic_auth_user',
  452. password: password,
  453. })
  454. end
  455. context 'with code 200' do
  456. let(:code) { '200' }
  457. let(:content_type) { 'application/json; charset=utf-8' }
  458. let(:request_url) { "#{host}/test_basic_auth/delete/1" }
  459. let(:password) { 'test123' }
  460. let(:expected_body) do
  461. {
  462. 'method' => 'delete',
  463. 'content_type_requested' => nil,
  464. }
  465. end
  466. include_examples 'successful delete request'
  467. end
  468. context 'with code 401' do
  469. let(:code) { '401' }
  470. let(:request_url) { "#{host}/test_basic_auth/delete/1" }
  471. let(:password) { 'test<>123' }
  472. let(:expected_body) { "HTTP Basic: Access denied.\n" }
  473. include_examples 'unsuccessful get/post/put/delete request'
  474. end
  475. end
  476. context 'with bearer token auth' do
  477. subject(:response) do
  478. described_class.delete(request_url, {}, {
  479. bearer_token: bearer_token,
  480. })
  481. end
  482. context 'with code 200' do
  483. let(:code) { '200' }
  484. let(:content_type) { 'application/json; charset=utf-8' }
  485. let(:request_url) { "#{host}/test_bearer_auth/delete/1" }
  486. let(:request_params) { { submitted: 'some value' } }
  487. let(:bearer_token) { 'test_bearer_123' }
  488. let(:expected_body) do
  489. {
  490. 'method' => 'delete',
  491. 'content_type_requested' => nil,
  492. }
  493. end
  494. include_examples 'successful delete request'
  495. end
  496. context 'with code 401' do
  497. let(:code) { '401' }
  498. let(:request_url) { "#{host}/test_bearer_auth/delete/1" }
  499. let(:request_params) { { submitted: 'some value' } }
  500. let(:bearer_token) { 'wrong_test_bearer' }
  501. let(:expected_body) { "HTTP Token: Access denied.\n" }
  502. include_examples 'unsuccessful get/post/put/delete request'
  503. end
  504. end
  505. end
  506. describe '#request' do
  507. context 'without http basic auth' do
  508. subject(:response) { described_class.request(request_url) }
  509. context 'with code 200' do
  510. let(:code) { '200' }
  511. let(:content_type) { 'application/json; charset=utf-8' }
  512. let(:request_url) { "#{host}/test/redirect" }
  513. let(:expected_body) do
  514. {
  515. 'method' => 'get',
  516. 'submitted' => 'abc',
  517. 'content_type_requested' => nil,
  518. }
  519. end
  520. include_examples 'successful redirect request'
  521. end
  522. end
  523. context 'with http basic auth' do
  524. subject(:response) do
  525. described_class.request(request_url, {
  526. user: 'basic_auth_user',
  527. password: password,
  528. })
  529. end
  530. context 'with code 200' do
  531. let(:code) { '200' }
  532. let(:request_url) { "#{host}/test_basic_auth/redirect" }
  533. let(:password) { 'test123' }
  534. let(:expected_body) do
  535. {
  536. 'method' => 'get',
  537. 'submitted' => 'abc',
  538. 'content_type_requested' => nil,
  539. }
  540. end
  541. include_examples 'successful redirect request'
  542. end
  543. context 'with code 401' do
  544. let(:code) { '401' }
  545. let(:request_url) { "#{host}/test_basic_auth/redirect" }
  546. let(:password) { 'test<>123' }
  547. let(:expected_body) { "HTTP Basic: Access denied.\n" }
  548. include_examples 'unsuccessful get/post/put/delete request'
  549. end
  550. end
  551. context 'when ftp', integration: true, required_envs: ['FTP_URL'] do
  552. subject(:response) do
  553. described_class.request(request_url)
  554. end
  555. context 'with code 200' do
  556. let(:code) { '200' }
  557. let(:request_url) { "#{ENV['FTP_URL']}/zammad.txt" }
  558. let(:expected_body) { %r{zammad}i }
  559. include_examples 'ftp requests'
  560. end
  561. context 'with code 550' do
  562. let(:code) { '550' }
  563. let(:request_url) { "#{ENV['FTP_URL']}/nonexisting.txt" }
  564. include_examples 'unsuccessful request without body'
  565. end
  566. context 'with a not existing URL' do
  567. let(:code) { 0 }
  568. let(:request_url) { 'http://not.existing.host.tld/test.php' }
  569. include_examples 'unsuccessful request without body'
  570. end
  571. end
  572. end
  573. end
  574. describe 'testing without proxy' do
  575. include_context 'when doing user agent tests'
  576. end
  577. describe 'testing with proxy', required_envs: %w[CI_PROXY_URL CI_PROXY_USER CI_PROXY_PASSWORD] do
  578. before do
  579. Setting.set('proxy', ENV['CI_PROXY_URL'])
  580. Setting.set('proxy_username', ENV['CI_PROXY_USER'])
  581. Setting.set('proxy_password', ENV['CI_PROXY_PASSWORD'])
  582. end
  583. include_context 'when doing user agent tests'
  584. end
  585. end