test_http.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  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.node_entities import UserFrom
  7. from core.workflow.entities.variable_pool import VariablePool
  8. from core.workflow.enums import SystemVariableKey
  9. from core.workflow.graph_engine.entities.graph import Graph
  10. from core.workflow.graph_engine.entities.graph_init_params import GraphInitParams
  11. from core.workflow.graph_engine.entities.graph_runtime_state import GraphRuntimeState
  12. from core.workflow.nodes.http_request.http_request_node import HttpRequestNode
  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": {"type": "json", "data": '{"a": "{{#a.b123.args1#}}"}'},
  189. },
  190. }
  191. )
  192. result = node._run()
  193. assert result.process_data is not None
  194. data = result.process_data.get("request", "")
  195. assert '{"a": "1"}' in data
  196. assert "X-Header: 123" in data
  197. def test_x_www_form_urlencoded(setup_http_mock):
  198. node = init_http_node(
  199. config={
  200. "id": "1",
  201. "data": {
  202. "title": "http",
  203. "desc": "",
  204. "method": "post",
  205. "url": "http://example.com",
  206. "authorization": {
  207. "type": "api-key",
  208. "config": {
  209. "type": "basic",
  210. "api_key": "ak-xxx",
  211. "header": "api-key",
  212. },
  213. },
  214. "headers": "X-Header:123",
  215. "params": "A:b",
  216. "body": {"type": "x-www-form-urlencoded", "data": "a:{{#a.b123.args1#}}\nb:{{#a.b123.args2#}}"},
  217. },
  218. }
  219. )
  220. result = node._run()
  221. assert result.process_data is not None
  222. data = result.process_data.get("request", "")
  223. assert "a=1&b=2" in data
  224. assert "X-Header: 123" in data
  225. def test_form_data(setup_http_mock):
  226. node = init_http_node(
  227. config={
  228. "id": "1",
  229. "data": {
  230. "title": "http",
  231. "desc": "",
  232. "method": "post",
  233. "url": "http://example.com",
  234. "authorization": {
  235. "type": "api-key",
  236. "config": {
  237. "type": "basic",
  238. "api_key": "ak-xxx",
  239. "header": "api-key",
  240. },
  241. },
  242. "headers": "X-Header:123",
  243. "params": "A:b",
  244. "body": {"type": "form-data", "data": "a:{{#a.b123.args1#}}\nb:{{#a.b123.args2#}}"},
  245. },
  246. }
  247. )
  248. result = node._run()
  249. assert result.process_data is not None
  250. data = result.process_data.get("request", "")
  251. assert 'form-data; name="a"' in data
  252. assert "1" in data
  253. assert 'form-data; name="b"' in data
  254. assert "2" in data
  255. assert "X-Header: 123" in data
  256. def test_none_data(setup_http_mock):
  257. node = init_http_node(
  258. config={
  259. "id": "1",
  260. "data": {
  261. "title": "http",
  262. "desc": "",
  263. "method": "post",
  264. "url": "http://example.com",
  265. "authorization": {
  266. "type": "api-key",
  267. "config": {
  268. "type": "basic",
  269. "api_key": "ak-xxx",
  270. "header": "api-key",
  271. },
  272. },
  273. "headers": "X-Header:123",
  274. "params": "A:b",
  275. "body": {"type": "none", "data": "123123123"},
  276. },
  277. }
  278. )
  279. result = node._run()
  280. assert result.process_data is not None
  281. data = result.process_data.get("request", "")
  282. assert "X-Header: 123" in data
  283. assert "123123123" not in data
  284. def test_mock_404(setup_http_mock):
  285. node = init_http_node(
  286. config={
  287. "id": "1",
  288. "data": {
  289. "title": "http",
  290. "desc": "",
  291. "method": "get",
  292. "url": "http://404.com",
  293. "authorization": {
  294. "type": "no-auth",
  295. "config": None,
  296. },
  297. "body": None,
  298. "params": "",
  299. "headers": "X-Header:123",
  300. },
  301. }
  302. )
  303. result = node._run()
  304. assert result.outputs is not None
  305. resp = result.outputs
  306. assert 404 == resp.get("status_code")
  307. assert "Not Found" in resp.get("body", "")
  308. def test_multi_colons_parse(setup_http_mock):
  309. node = init_http_node(
  310. config={
  311. "id": "1",
  312. "data": {
  313. "title": "http",
  314. "desc": "",
  315. "method": "get",
  316. "url": "http://example.com",
  317. "authorization": {
  318. "type": "no-auth",
  319. "config": None,
  320. },
  321. "params": "Referer:http://example1.com\nRedirect:http://example2.com",
  322. "headers": "Referer:http://example3.com\nRedirect:http://example4.com",
  323. "body": {"type": "form-data", "data": "Referer:http://example5.com\nRedirect:http://example6.com"},
  324. },
  325. }
  326. )
  327. result = node._run()
  328. assert result.process_data is not None
  329. assert result.outputs is not None
  330. resp = result.outputs
  331. assert urlencode({"Redirect": "http://example2.com"}) in result.process_data.get("request", "")
  332. assert 'form-data; name="Redirect"\n\nhttp://example6.com' in result.process_data.get("request", "")
  333. assert "http://example3.com" == resp.get("headers", {}).get("referer")