test_http.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. import time
  2. import uuid
  3. from urllib.parse import urlencode
  4. import pytest
  5. from core.app.entities.app_invoke_entities import InvokeFrom
  6. from core.workflow.entities.variable_pool import VariablePool
  7. from core.workflow.enums import SystemVariableKey
  8. from core.workflow.graph_engine.entities.graph import Graph
  9. from core.workflow.graph_engine.entities.graph_init_params import GraphInitParams
  10. from core.workflow.graph_engine.entities.graph_runtime_state import GraphRuntimeState
  11. from core.workflow.nodes.http_request.node import HttpRequestNode
  12. from models.enums import UserFrom
  13. from models.workflow import WorkflowType
  14. from tests.integration_tests.workflow.nodes.__mock.http import setup_http_mock
  15. def init_http_node(config: dict):
  16. graph_config = {
  17. "edges": [
  18. {
  19. "id": "start-source-next-target",
  20. "source": "start",
  21. "target": "1",
  22. },
  23. ],
  24. "nodes": [{"data": {"type": "start"}, "id": "start"}, config],
  25. }
  26. graph = Graph.init(graph_config=graph_config)
  27. init_params = GraphInitParams(
  28. tenant_id="1",
  29. app_id="1",
  30. workflow_type=WorkflowType.WORKFLOW,
  31. workflow_id="1",
  32. graph_config=graph_config,
  33. user_id="1",
  34. user_from=UserFrom.ACCOUNT,
  35. invoke_from=InvokeFrom.DEBUGGER,
  36. call_depth=0,
  37. )
  38. # construct variable pool
  39. variable_pool = VariablePool(
  40. system_variables={SystemVariableKey.FILES: [], SystemVariableKey.USER_ID: "aaa"},
  41. user_inputs={},
  42. environment_variables=[],
  43. conversation_variables=[],
  44. )
  45. variable_pool.add(["a", "b123", "args1"], 1)
  46. variable_pool.add(["a", "b123", "args2"], 2)
  47. return HttpRequestNode(
  48. id=str(uuid.uuid4()),
  49. graph_init_params=init_params,
  50. graph=graph,
  51. graph_runtime_state=GraphRuntimeState(variable_pool=variable_pool, start_at=time.perf_counter()),
  52. config=config,
  53. )
  54. @pytest.mark.parametrize("setup_http_mock", [["none"]], indirect=True)
  55. def test_get(setup_http_mock):
  56. node = init_http_node(
  57. config={
  58. "id": "1",
  59. "data": {
  60. "title": "http",
  61. "desc": "",
  62. "method": "get",
  63. "url": "http://example.com",
  64. "authorization": {
  65. "type": "api-key",
  66. "config": {
  67. "type": "basic",
  68. "api_key": "ak-xxx",
  69. "header": "api-key",
  70. },
  71. },
  72. "headers": "X-Header:123",
  73. "params": "A:b",
  74. "body": None,
  75. },
  76. }
  77. )
  78. result = node._run()
  79. assert result.process_data is not None
  80. data = result.process_data.get("request", "")
  81. assert "?A=b" in data
  82. assert "X-Header: 123" in data
  83. @pytest.mark.parametrize("setup_http_mock", [["none"]], indirect=True)
  84. def test_no_auth(setup_http_mock):
  85. node = init_http_node(
  86. config={
  87. "id": "1",
  88. "data": {
  89. "title": "http",
  90. "desc": "",
  91. "method": "get",
  92. "url": "http://example.com",
  93. "authorization": {
  94. "type": "no-auth",
  95. "config": None,
  96. },
  97. "headers": "X-Header:123",
  98. "params": "A:b",
  99. "body": None,
  100. },
  101. }
  102. )
  103. result = node._run()
  104. assert result.process_data is not None
  105. data = result.process_data.get("request", "")
  106. assert "?A=b" in data
  107. assert "X-Header: 123" in data
  108. @pytest.mark.parametrize("setup_http_mock", [["none"]], indirect=True)
  109. def test_custom_authorization_header(setup_http_mock):
  110. node = init_http_node(
  111. config={
  112. "id": "1",
  113. "data": {
  114. "title": "http",
  115. "desc": "",
  116. "method": "get",
  117. "url": "http://example.com",
  118. "authorization": {
  119. "type": "api-key",
  120. "config": {
  121. "type": "custom",
  122. "api_key": "Auth",
  123. "header": "X-Auth",
  124. },
  125. },
  126. "headers": "X-Header:123",
  127. "params": "A:b",
  128. "body": None,
  129. },
  130. }
  131. )
  132. result = node._run()
  133. assert result.process_data is not None
  134. data = result.process_data.get("request", "")
  135. assert "?A=b" in data
  136. assert "X-Header: 123" in data
  137. @pytest.mark.parametrize("setup_http_mock", [["none"]], indirect=True)
  138. def test_template(setup_http_mock):
  139. node = init_http_node(
  140. config={
  141. "id": "1",
  142. "data": {
  143. "title": "http",
  144. "desc": "",
  145. "method": "get",
  146. "url": "http://example.com/{{#a.b123.args2#}}",
  147. "authorization": {
  148. "type": "api-key",
  149. "config": {
  150. "type": "basic",
  151. "api_key": "ak-xxx",
  152. "header": "api-key",
  153. },
  154. },
  155. "headers": "X-Header:123\nX-Header2:{{#a.b123.args2#}}",
  156. "params": "A:b\nTemplate:{{#a.b123.args2#}}",
  157. "body": None,
  158. },
  159. }
  160. )
  161. result = node._run()
  162. assert result.process_data is not None
  163. data = result.process_data.get("request", "")
  164. assert "?A=b" in data
  165. assert "Template=2" in data
  166. assert "X-Header: 123" in data
  167. assert "X-Header2: 2" in data
  168. @pytest.mark.parametrize("setup_http_mock", [["none"]], indirect=True)
  169. def test_json(setup_http_mock):
  170. node = init_http_node(
  171. config={
  172. "id": "1",
  173. "data": {
  174. "title": "http",
  175. "desc": "",
  176. "method": "post",
  177. "url": "http://example.com",
  178. "authorization": {
  179. "type": "api-key",
  180. "config": {
  181. "type": "basic",
  182. "api_key": "ak-xxx",
  183. "header": "api-key",
  184. },
  185. },
  186. "headers": "X-Header:123",
  187. "params": "A:b",
  188. "body": {
  189. "type": "json",
  190. "data": [
  191. {
  192. "key": "",
  193. "type": "text",
  194. "value": '{"a": "{{#a.b123.args1#}}"}',
  195. },
  196. ],
  197. },
  198. },
  199. }
  200. )
  201. result = node._run()
  202. assert result.process_data is not None
  203. data = result.process_data.get("request", "")
  204. assert '{"a": "1"}' in data
  205. assert "X-Header: 123" in data
  206. def test_x_www_form_urlencoded(setup_http_mock):
  207. node = init_http_node(
  208. config={
  209. "id": "1",
  210. "data": {
  211. "title": "http",
  212. "desc": "",
  213. "method": "post",
  214. "url": "http://example.com",
  215. "authorization": {
  216. "type": "api-key",
  217. "config": {
  218. "type": "basic",
  219. "api_key": "ak-xxx",
  220. "header": "api-key",
  221. },
  222. },
  223. "headers": "X-Header:123",
  224. "params": "A:b",
  225. "body": {
  226. "type": "x-www-form-urlencoded",
  227. "data": [
  228. {
  229. "key": "a",
  230. "type": "text",
  231. "value": "{{#a.b123.args1#}}",
  232. },
  233. {
  234. "key": "b",
  235. "type": "text",
  236. "value": "{{#a.b123.args2#}}",
  237. },
  238. ],
  239. },
  240. },
  241. }
  242. )
  243. result = node._run()
  244. assert result.process_data is not None
  245. data = result.process_data.get("request", "")
  246. assert "a=1&b=2" in data
  247. assert "X-Header: 123" in data
  248. def test_form_data(setup_http_mock):
  249. node = init_http_node(
  250. config={
  251. "id": "1",
  252. "data": {
  253. "title": "http",
  254. "desc": "",
  255. "method": "post",
  256. "url": "http://example.com",
  257. "authorization": {
  258. "type": "api-key",
  259. "config": {
  260. "type": "basic",
  261. "api_key": "ak-xxx",
  262. "header": "api-key",
  263. },
  264. },
  265. "headers": "X-Header:123",
  266. "params": "A:b",
  267. "body": {
  268. "type": "form-data",
  269. "data": [
  270. {
  271. "key": "a",
  272. "type": "text",
  273. "value": "{{#a.b123.args1#}}",
  274. },
  275. {
  276. "key": "b",
  277. "type": "text",
  278. "value": "{{#a.b123.args2#}}",
  279. },
  280. ],
  281. },
  282. },
  283. }
  284. )
  285. result = node._run()
  286. assert result.process_data is not None
  287. data = result.process_data.get("request", "")
  288. assert 'form-data; name="a"' in data
  289. assert "1" in data
  290. assert 'form-data; name="b"' in data
  291. assert "2" in data
  292. assert "X-Header: 123" in data
  293. def test_none_data(setup_http_mock):
  294. node = init_http_node(
  295. config={
  296. "id": "1",
  297. "data": {
  298. "title": "http",
  299. "desc": "",
  300. "method": "post",
  301. "url": "http://example.com",
  302. "authorization": {
  303. "type": "api-key",
  304. "config": {
  305. "type": "basic",
  306. "api_key": "ak-xxx",
  307. "header": "api-key",
  308. },
  309. },
  310. "headers": "X-Header:123",
  311. "params": "A:b",
  312. "body": {"type": "none", "data": []},
  313. },
  314. }
  315. )
  316. result = node._run()
  317. assert result.process_data is not None
  318. data = result.process_data.get("request", "")
  319. assert "X-Header: 123" in data
  320. assert "123123123" not in data
  321. def test_mock_404(setup_http_mock):
  322. node = init_http_node(
  323. config={
  324. "id": "1",
  325. "data": {
  326. "title": "http",
  327. "desc": "",
  328. "method": "get",
  329. "url": "http://404.com",
  330. "authorization": {
  331. "type": "no-auth",
  332. "config": None,
  333. },
  334. "body": None,
  335. "params": "",
  336. "headers": "X-Header:123",
  337. },
  338. }
  339. )
  340. result = node._run()
  341. assert result.outputs is not None
  342. resp = result.outputs
  343. assert resp.get("status_code") == 404
  344. assert "Not Found" in resp.get("body", "")
  345. def test_multi_colons_parse(setup_http_mock):
  346. node = init_http_node(
  347. config={
  348. "id": "1",
  349. "data": {
  350. "title": "http",
  351. "desc": "",
  352. "method": "get",
  353. "url": "http://example.com",
  354. "authorization": {
  355. "type": "no-auth",
  356. "config": None,
  357. },
  358. "params": "Referer:http://example1.com\nRedirect:http://example2.com",
  359. "headers": "Referer:http://example3.com\nRedirect:http://example4.com",
  360. "body": {
  361. "type": "form-data",
  362. "data": [
  363. {
  364. "key": "Referer",
  365. "type": "text",
  366. "value": "http://example5.com",
  367. },
  368. {
  369. "key": "Redirect",
  370. "type": "text",
  371. "value": "http://example6.com",
  372. },
  373. ],
  374. },
  375. },
  376. }
  377. )
  378. result = node._run()
  379. assert result.process_data is not None
  380. assert result.outputs is not None
  381. resp = result.outputs
  382. assert urlencode({"Redirect": "http://example2.com"}) in result.process_data.get("request", "")
  383. assert 'form-data; name="Redirect"\r\n\r\nhttp://example6.com' in result.process_data.get("request", "")
  384. # assert "http://example3.com" == resp.get("headers", {}).get("referer")