user_agent_spec.rb 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. # Copyright (C) 2012-2022 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. ip_address = Socket.ip_address_list.detect(&:ipv4_private?).ip_address
  11. host = "http://#{ip_address}:3000"
  12. end
  13. host
  14. end
  15. puma_thread = nil
  16. # we need a running web server, otherwise the requests will fail
  17. before :all do # rubocop:disable RSpec/BeforeAfterAll
  18. ENV['CI_BASIC_AUTH_USER'] = 'basic_auth_user'
  19. ENV['CI_BASIC_AUTH_PASSWORD'] = 'test123'
  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 'when timeouts are raised' do
  164. subject(:response) do
  165. described_class.get(request_url, {}, {
  166. open_timeout: 0,
  167. read_timeout: 0,
  168. })
  169. end
  170. let(:request_url) { "#{host}/test/get/1?submitted=123" }
  171. let(:code) { 0 }
  172. include_examples 'unsuccessful request without body'
  173. end
  174. context 'with content type set to json' do
  175. subject(:response) { described_class.get(request_url, request_params, request_options) }
  176. context 'with code 200' do
  177. let(:code) { '200' }
  178. let(:content_type) { 'application/json; charset=utf-8' }
  179. let(:request_url) { "#{host}/test/get/1" }
  180. let(:request_params) { { submitted: 'some value' } }
  181. let(:request_options) { { json: true } }
  182. let(:expected_body) do
  183. {
  184. 'method' => 'get',
  185. 'content_type_requested' => nil,
  186. 'submitted' => 'some value',
  187. }
  188. end
  189. include_examples 'successful get request'
  190. end
  191. context 'with code 404' do
  192. let(:code) { '404' }
  193. let(:request_url) { "#{host}/test/not_existing" }
  194. let(:request_params) { { submitted: { key: 'some value' } } }
  195. let(:request_options) { { json: true } }
  196. include_examples 'unsuccessful request'
  197. end
  198. end
  199. end
  200. describe '#post' do
  201. context 'without http basic auth' do
  202. subject(:response) { described_class.post(request_url, request_params) }
  203. context 'with code 201' do
  204. let(:code) { '201' }
  205. let(:request_url) { "#{host}/test/post/1" }
  206. let(:request_params) { { submitted: 'some value' } }
  207. let(:expected_body) do
  208. {
  209. 'method' => 'post',
  210. 'submitted' => 'some value',
  211. 'content_type_requested' => 'application/x-www-form-urlencoded',
  212. }
  213. end
  214. include_examples 'successful post/put request'
  215. end
  216. context 'with code 404' do
  217. let(:code) { '404' }
  218. let(:request_url) { "#{host}/test/not_existing" }
  219. let(:request_params) { { submitted: 'some value' } }
  220. include_examples 'unsuccessful request without body'
  221. end
  222. end
  223. context 'with http basic auth' do
  224. subject(:response) do
  225. described_class.post(request_url, request_params, {
  226. user: 'basic_auth_user',
  227. password: password,
  228. })
  229. end
  230. context 'with code 201' do
  231. let(:code) { '201' }
  232. let(:request_url) { "#{host}/test_basic_auth/post/1" }
  233. let(:request_params) { { submitted: 'some value' } }
  234. let(:password) { 'test123' }
  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 401' do
  245. let(:code) { '401' }
  246. let(:request_url) { "#{host}/test_basic_auth/post/1" }
  247. let(:request_params) { { submitted: 'some value' } }
  248. let(:password) { 'test<>123' }
  249. let(:expected_body) { "HTTP Basic: Access denied.\n" }
  250. include_examples 'unsuccessful get/post/put/delete request'
  251. end
  252. end
  253. context 'when timeouts are raised' do
  254. subject(:response) do
  255. described_class.post(request_url, request_params, {
  256. open_timeout: 0,
  257. read_timeout: 0,
  258. })
  259. end
  260. let(:request_url) { "#{host}/test/post/1" }
  261. let(:request_params) { { submitted: 'timeout' } }
  262. let(:code) { 0 }
  263. include_examples 'unsuccessful request without body'
  264. end
  265. context 'with content type set to json' do
  266. subject(:response) { described_class.post(request_url, request_params, request_options) }
  267. context 'with code 201' do
  268. let(:code) { '201' }
  269. let(:content_type) { 'application/json; charset=utf-8' }
  270. let(:request_url) { "#{host}/test/post/1" }
  271. let(:request_params) { { submitted: { key: 'some value' } } }
  272. let(:request_options) { { json: true } }
  273. let(:expected_body) do
  274. {
  275. 'method' => 'post',
  276. 'content_type_requested' => 'application/json',
  277. 'submitted' => {
  278. 'key' => 'some value',
  279. },
  280. }
  281. end
  282. include_examples 'successful post/put request'
  283. end
  284. end
  285. end
  286. describe '#put' do
  287. subject(:response) { described_class.put(request_url, request_params) }
  288. context 'without http basic auth' do
  289. context 'with code 200' do
  290. let(:code) { '200' }
  291. let(:request_url) { "#{host}/test/put/1" }
  292. let(:request_params) { { submitted: 'some value' } }
  293. let(:expected_body) do
  294. {
  295. 'method' => 'put',
  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 404' do
  303. let(:code) { '404' }
  304. let(:request_url) { "#{host}/test/not_existing" }
  305. let(:request_params) { { submitted: 'some value' } }
  306. include_examples 'unsuccessful request without body'
  307. end
  308. end
  309. context 'with http basic auth' do
  310. subject(:response) do
  311. described_class.put(request_url, request_params, {
  312. user: 'basic_auth_user',
  313. password: password,
  314. })
  315. end
  316. let(:password) { 'test123' }
  317. let(:submit_value) { 'some value' }
  318. context 'with code 200' do
  319. let(:code) { '200' }
  320. let(:request_url) { "#{host}/test_basic_auth/put/1" }
  321. let(:request_params) { { submitted: 'some value' } }
  322. let(:expected_body) do
  323. {
  324. 'method' => 'put',
  325. 'submitted' => 'some value',
  326. 'content_type_requested' => 'application/x-www-form-urlencoded',
  327. }
  328. end
  329. include_examples 'successful post/put request'
  330. end
  331. context 'with code 401' do
  332. let(:code) { '401' }
  333. let(:request_url) { "#{host}/test_basic_auth/put/1" }
  334. let(:request_params) { { submitted: 'some value' } }
  335. let(:password) { 'test<>123' }
  336. let(:expected_body) { "HTTP Basic: Access denied.\n" }
  337. include_examples 'unsuccessful get/post/put/delete request'
  338. end
  339. end
  340. end
  341. describe '#delete' do
  342. context 'without http basic auth' do
  343. subject(:response) { described_class.delete(request_url) }
  344. context 'with code 200' do
  345. let(:code) { '200' }
  346. let(:request_url) { "#{host}/test/delete/1" }
  347. let(:expected_body) do
  348. {
  349. 'method' => 'delete',
  350. 'content_type_requested' => nil,
  351. }
  352. end
  353. include_examples 'successful delete request'
  354. end
  355. context 'with code 404' do
  356. let(:code) { '404' }
  357. let(:request_url) { "#{host}/test/not_existing" }
  358. include_examples 'unsuccessful request without body'
  359. end
  360. end
  361. context 'with http basic auth' do
  362. subject(:response) do
  363. described_class.delete(request_url, {}, {
  364. user: 'basic_auth_user',
  365. password: password,
  366. })
  367. end
  368. context 'with code 200' do
  369. let(:code) { '200' }
  370. let(:content_type) { 'application/json; charset=utf-8' }
  371. let(:request_url) { "#{host}/test_basic_auth/delete/1" }
  372. let(:password) { 'test123' }
  373. let(:expected_body) do
  374. {
  375. 'method' => 'delete',
  376. 'content_type_requested' => nil,
  377. }
  378. end
  379. include_examples 'successful delete request'
  380. end
  381. context 'with code 401' do
  382. let(:code) { '401' }
  383. let(:request_url) { "#{host}/test_basic_auth/delete/1" }
  384. let(:password) { 'test<>123' }
  385. let(:expected_body) { "HTTP Basic: Access denied.\n" }
  386. include_examples 'unsuccessful get/post/put/delete request'
  387. end
  388. end
  389. end
  390. describe '#request' do
  391. context 'without http basic auth' do
  392. subject(:response) { described_class.request(request_url) }
  393. context 'with code 200' do
  394. let(:code) { '200' }
  395. let(:content_type) { 'application/json; charset=utf-8' }
  396. let(:request_url) { "#{host}/test/redirect" }
  397. let(:expected_body) do
  398. {
  399. 'method' => 'get',
  400. 'submitted' => 'abc',
  401. 'content_type_requested' => nil,
  402. }
  403. end
  404. include_examples 'successful redirect request'
  405. end
  406. end
  407. context 'with http basic auth' do
  408. subject(:response) do
  409. described_class.request(request_url, {
  410. user: 'basic_auth_user',
  411. password: password,
  412. })
  413. end
  414. context 'with code 200' do
  415. let(:code) { '200' }
  416. let(:request_url) { "#{host}/test_basic_auth/redirect" }
  417. let(:password) { 'test123' }
  418. let(:expected_body) do
  419. {
  420. 'method' => 'get',
  421. 'submitted' => 'abc',
  422. 'content_type_requested' => nil,
  423. }
  424. end
  425. include_examples 'successful redirect request'
  426. end
  427. context 'with code 401' do
  428. let(:code) { '401' }
  429. let(:request_url) { "#{host}/test_basic_auth/redirect" }
  430. let(:password) { 'test<>123' }
  431. let(:expected_body) { "HTTP Basic: Access denied.\n" }
  432. include_examples 'unsuccessful get/post/put/delete request'
  433. end
  434. end
  435. context 'when ftp' do
  436. subject(:response) do
  437. described_class.request(request_url)
  438. end
  439. context 'with code 200' do
  440. let(:code) { '200' }
  441. let(:request_url) { 'ftp://ftp.gwdg.de/pub/rfc/rfc-index.txt' }
  442. let(:expected_body) { %r{instructions}i }
  443. include_examples 'ftp requests'
  444. end
  445. context 'with code 550' do
  446. let(:code) { '550' }
  447. let(:request_url) { 'ftp://ftp.gwdg.de/pub/rfc/not_existing.txt' }
  448. include_examples 'unsuccessful request without body'
  449. end
  450. context 'with a not existing URL' do
  451. let(:code) { 0 }
  452. let(:request_url) { 'http://not.existing.host.tld/test.php' }
  453. include_examples 'unsuccessful request without body'
  454. end
  455. end
  456. end
  457. end
  458. describe 'testing without proxy' do
  459. include_context 'when doing user agent tests'
  460. end
  461. describe 'testing with proxy', required_envs: %w[CI_PROXY_URL CI_PROXY_USER CI_PROXY_PASSWORD] do
  462. before do
  463. Setting.set('proxy', ENV['CI_PROXY_URL'])
  464. Setting.set('proxy_username', ENV['CI_PROXY_USER'])
  465. Setting.set('proxy_password', ENV['CI_PROXY_PASSWORD'])
  466. end
  467. include_context 'when doing user agent tests'
  468. end
  469. end