emqx_lua_hook_SUITE.erl 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693
  1. %%--------------------------------------------------------------------
  2. %% Copyright (c) 2020-2021 EMQ Technologies Co., Ltd. All Rights Reserved.
  3. %%
  4. %% Licensed under the Apache License, Version 2.0 (the "License");
  5. %% you may not use this file except in compliance with the License.
  6. %% You may obtain a copy of the License at
  7. %%
  8. %% http://www.apache.org/licenses/LICENSE-2.0
  9. %%
  10. %% Unless required by applicable law or agreed to in writing, software
  11. %% distributed under the License is distributed on an "AS IS" BASIS,
  12. %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. %% See the License for the specific language governing permissions and
  14. %% limitations under the License.
  15. %%--------------------------------------------------------------------
  16. -module(emqx_lua_hook_SUITE).
  17. -compile(export_all).
  18. -compile(nowarn_export_all).
  19. -include_lib("emqx/include/emqx.hrl").
  20. -include_lib("emqx/include/emqx_mqtt.hrl").
  21. -include_lib("eunit/include/eunit.hrl").
  22. -include_lib("common_test/include/ct.hrl").
  23. all() ->
  24. [case01, case02, case03, case04,
  25. case11, case12, case13,
  26. case21, case22,
  27. case31, case32,
  28. case41, case42, case43,
  29. case51, case52, case53,
  30. case61, case62,
  31. case71, case72, case73,
  32. case81, case82, case83,
  33. case101,
  34. case110, case111, case112, case113, case114, case115,
  35. case201, case202, case203, case204, case205,
  36. case301, case302
  37. ].
  38. init_per_suite(Config) ->
  39. emqx_ct_helpers:start_apps([emqx_lua_hook], fun set_special_configs/1),
  40. Config.
  41. end_per_suite(Config) ->
  42. emqx_ct_helpers:stop_apps([emqx_lua_hook]),
  43. Config.
  44. set_special_configs(emqx) ->
  45. application:set_env(emqx, modules, []);
  46. set_special_configs(_App) ->
  47. ok.
  48. init_per_testcase(_, Config) ->
  49. ok = filelib:ensure_dir(filename:join([emqx_lua_hook:lua_dir(), "a"])),
  50. emqx_lua_hook:start_link(),
  51. Config.
  52. end_per_testcase(_, _Config) ->
  53. emqx_lua_hook:stop(),
  54. AllScripts = filelib:wildcard(filename:join([emqx_lua_hook:lua_dir(), "*"])),
  55. [file:delete(Filename) || Filename <- AllScripts].
  56. case01(_Config) ->
  57. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  58. Code = "function on_message_publish(ClientId, Username, topic, payload, qos, retain)"
  59. "\n return topic, \"hello\", qos, retain"
  60. "\nend"
  61. "\n"
  62. "\nfunction register_hook()"
  63. "\n return \"on_message_publish\""
  64. "\nend",
  65. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  66. Msg = #message{from = <<"myclient">>, qos = 2, flags = #{retain => true}, topic = <<"a/b/c">>, payload = <<"123">>, headers = #{username => <<"tester">>}},
  67. Ret = emqx_hooks:run_fold('message.publish',[], Msg),
  68. ?assertEqual(Msg#message{payload = <<"hello">>}, Ret).
  69. case02(_Config) ->
  70. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  71. Code = "function on_message_publish(clientid, username, topic, payload, qos, retain)"
  72. "\n return false" % return false to stop hook
  73. "\nend"
  74. "\n"
  75. "\nfunction register_hook()"
  76. "\n return \"on_message_publish\""
  77. "\nend",
  78. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  79. Msg = #message{from = <<"myclient">>, qos = 2, flags = #{retain => true}, topic = <<"a/b/c">>, payload = <<"123">>, headers = #{username => <<"tester">>}},
  80. Ret = emqx_hooks:run_fold('message.publish',[], Msg),
  81. ?assertEqual(Msg, Ret).
  82. case03(_Config) ->
  83. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  84. Code = "function on_message_publish(clientid, username, topic, payload, qos, retain)"
  85. "\n return 9/0" % this code has fatal error
  86. "\nend"
  87. "\n"
  88. "\nfunction register_hook()"
  89. "\n return \"on_message_publish\""
  90. "\nend",
  91. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  92. Msg = #message{from = <<"myclient">>, qos = 2, flags = #{retain => true}, topic = <<"a/b/c">>, payload = <<"123">>, headers = #{username => <<"tester">>}},
  93. Ret = emqx_hooks:run_fold('message.publish',[], Msg),
  94. ?assertEqual(Msg, Ret).
  95. case04(_Config) ->
  96. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  97. Code = "function on_message_publish(clientid, username, topic, payload, qos, retain)"
  98. "\n if clientid == \"broker\" then"
  99. "\n return topic, \"hello broker\", qos, retain"
  100. "\n else"
  101. "\n return false" % return false to stop hook
  102. "\n end"
  103. "\nend"
  104. "\n"
  105. "\nfunction register_hook()"
  106. "\n return \"on_message_publish\""
  107. "\nend",
  108. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  109. Msg = #message{from = <<"broker">>, qos = 2, flags = #{retain => true}, topic = <<"a/b/c">>, payload = <<"123">>, headers = #{username => <<"tester">>}},
  110. Ret = emqx_hooks:run_fold('message.publish',[], Msg),
  111. ?assertEqual(Msg#message{payload = <<"hello broker">>}, Ret).
  112. case11(_Config) ->
  113. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  114. Code = "function on_message_delivered(clientid, username, topic, payload, qos, retain)"
  115. "\n return false"
  116. "\nend"
  117. "\n"
  118. "\nfunction register_hook()"
  119. "\n return \"on_message_delivered\""
  120. "\nend",
  121. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  122. Msg = #message{qos = 2, flags = #{retain => true}, topic = <<"a/b/c">>, payload = <<"123">>, headers = #{}},
  123. Ret = emqx_hooks:run_fold('message.delivered', [#{clientid => <<"myclient">>, username => <<"myuser">>}], Msg),
  124. ?assertEqual(Msg, Ret),
  125. ok = file:delete(ScriptName).
  126. case12(_Config) ->
  127. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  128. Code = "function on_message_delivered(clientid, username, topic, payload, qos, retain)"
  129. "\n return topic, \"hello broker\", qos, retain"
  130. "\nend"
  131. "\n"
  132. "\nfunction register_hook()"
  133. "\n return \"on_message_delivered\""
  134. "\nend",
  135. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  136. Msg = #message{qos = 2, flags = #{retain => true}, topic = <<"a/b/c">>, payload = <<"123">>, headers = #{}},
  137. Ret = emqx_hooks:run_fold('message.delivered', [#{clientid => <<"myclient">>, username => <<"myuser">>}], Msg),
  138. ?assertEqual(Msg#message{payload = <<"hello broker">>}, Ret).
  139. case13(_Config) ->
  140. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  141. Code = "function on_message_delivered(clientid, username, topic, payload, qos, retain)"
  142. "\n return 9/0" % this code has fatal error
  143. "\nend"
  144. "\n"
  145. "\nfunction register_hook()"
  146. "\n return \"on_message_delivered\""
  147. "\nend",
  148. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  149. Msg = #message{qos = 2, flags = #{retain => true}, topic = <<"a/b/c">>, payload = <<"123">>, headers = #{}},
  150. Ret = emqx_hooks:run_fold('message.delivered', [#{clientid => <<"myclient">>, username => <<"myuser">>}], Msg),
  151. ?assertEqual(Msg, Ret).
  152. case21(_Config) ->
  153. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  154. Code = "function on_message_acked(clientid, username, topic, payload, qos, retain)"
  155. "\n return true"
  156. "\nend"
  157. "\n"
  158. "\nfunction register_hook()"
  159. "\n return \"on_message_acked\""
  160. "\nend",
  161. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  162. Msg = #message{qos = 2, flags = #{retain => true}, topic = <<"a/b/c">>, payload = <<"123">>, headers = #{}},
  163. Ret = emqx_hooks:run('message.acked', [#{clientid => <<"myclient">>, username => <<"myuser">>}, Msg]),
  164. ?assertEqual(ok, Ret).
  165. case22(_Config) ->
  166. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  167. Code = "function on_message_acked(clientid, username, topic, payload, qos, retain)"
  168. "\n return 9/0" % this code has fatal error
  169. "\nend"
  170. "\n"
  171. "\nfunction register_hook()"
  172. "\n return \"on_message_acked\""
  173. "\nend",
  174. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  175. Msg = #message{qos = 2, flags = #{retain => true}, topic = <<"a/b/c">>, payload = <<"123">>, headers = #{}},
  176. Ret = emqx_hooks:run('message.acked', [#{clientid => <<"myclient">>, username => <<"myuser">>}, Msg]),
  177. ?assertEqual(ok, Ret),
  178. ok = file:delete(ScriptName).
  179. case31(_Config) ->
  180. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  181. Code = "function on_client_connected(clientid, username)"
  182. "\n return 0"
  183. "\nend"
  184. "\n"
  185. "\nfunction register_hook()"
  186. "\n return \"on_client_connected\""
  187. "\nend",
  188. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  189. ?assertEqual(ok,
  190. emqx_hooks:run('client.connected',
  191. [#{clientid => <<"myclient">>, username => <<"tester">>}, #{}])).
  192. case32(_Config) ->
  193. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  194. Code = "function on_client_connected(clientid, username)"
  195. "\n return 9/0" % this code has fatal error
  196. "\nend"
  197. "\n"
  198. "\nfunction register_hook()"
  199. "\n return \"on_client_connected\""
  200. "\nend",
  201. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  202. ?assertEqual(ok,
  203. emqx_hooks:run('client.connected',
  204. [#{clientid => <<"myclient">>, username => <<"tester">>}, #{}])).
  205. case41(_Config) ->
  206. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  207. Code = "function on_client_subscribe(clientid, username, topic)"
  208. "\n if topic == \"a/b/c\" then"
  209. "\n topic = \"a1/b1/c1\";"
  210. "\n end"
  211. "\n return topic"
  212. "\nend"
  213. "\n"
  214. "\nfunction register_hook()"
  215. "\n return \"on_client_subscribe\""
  216. "\nend",
  217. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  218. TopicTable = [{<<"a/b/c">>, [qos, 1]}, {<<"d/+/e">>, [{qos, 2}]}],
  219. Ret = emqx_hooks:run_fold('client.subscribe',[#{clientid => <<"myclient">>, username => <<"myuser">>}, #{}], TopicTable),
  220. ?assertEqual([{<<"a1/b1/c1">>, [qos, 1]}, {<<"d/+/e">>, [{qos, 2}]}], Ret).
  221. case42(_Config) ->
  222. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  223. Code = "function on_client_subscribe(clientid, username, topic)"
  224. "\n return false" % return false to stop hook
  225. "\nend"
  226. "\n"
  227. "\nfunction register_hook()"
  228. "\n return \"on_client_subscribe\""
  229. "\nend",
  230. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  231. TopicTable = [{<<"a/b/c">>, [qos, 1]}, {<<"d/+/e">>, [{qos, 2}]}],
  232. Ret = emqx_hooks:run_fold('client.subscribe',[#{clientid => <<"myclient">>, username => <<"myuser">>}, #{}], TopicTable),
  233. ?assertEqual(TopicTable, Ret).
  234. case43(_Config) ->
  235. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  236. Code = "function on_client_subscribe(clientid, username, topic)"
  237. "\n return 9/0" % this code has fatal error
  238. "\nend"
  239. "\n"
  240. "\nfunction register_hook()"
  241. "\n return \"on_client_subscribe\""
  242. "\nend",
  243. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  244. TopicTable = [{<<"a/b/c">>, [qos, 1]}, {<<"d/+/e">>, [{qos, 2}]}],
  245. Ret = emqx_hooks:run_fold('client.subscribe',[#{clientid => <<"myclient">>, username => <<"myuser">>}, #{}], TopicTable),
  246. ?assertEqual(TopicTable, Ret).
  247. case51(_Config) ->
  248. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  249. Code = "function on_client_unsubscribe(clientid, username, topic)"
  250. "\n if topic == \"a/b/c\" then"
  251. "\n topic = \"a1/b1/c1\";"
  252. "\n end"
  253. "\n return topic"
  254. "\nend"
  255. "\n"
  256. "\nfunction register_hook()"
  257. "\n return \"on_client_unsubscribe\""
  258. "\nend",
  259. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  260. TopicTable = [{<<"a/b/c">>, [qos, 1]}, {<<"d/+/e">>, [{qos, 2}]}],
  261. Ret = emqx_hooks:run_fold('client.unsubscribe',[#{clientid => <<"myclient">>, username => <<"myuser">>}, #{}], TopicTable),
  262. ?assertEqual([{<<"a1/b1/c1">>, [qos, 1]}, {<<"d/+/e">>, [{qos, 2}]}], Ret).
  263. case52(_Config) ->
  264. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  265. Code = "function on_client_unsubscribe(clientid, username, topic)"
  266. "\n return false" % return false to stop hook
  267. "\nend"
  268. "\n"
  269. "\nfunction register_hook()"
  270. "\n return \"on_client_unsubscribe\""
  271. "\nend",
  272. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  273. TopicTable = [{<<"a/b/c">>, [qos, 1]}, {<<"d/+/e">>, [{qos, 2}]}],
  274. Ret = emqx_hooks:run_fold('client.unsubscribe',[#{clientid => <<"myclient">>, username => <<"myuser">>}, #{}], TopicTable),
  275. ?assertEqual(TopicTable, Ret).
  276. case53(_Config) ->
  277. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  278. Code = "function on_client_unsubscribe(clientid, username, topic)"
  279. "\n return 9/0" % this code has fatal error
  280. "\nend"
  281. "\n"
  282. "\nfunction register_hook()"
  283. "\n return \"on_client_unsubscribe\""
  284. "\nend",
  285. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  286. TopicTable = [{<<"a/b/c">>, [qos, 1]}, {<<"d/+/e">>, [{qos, 2}]}],
  287. Ret = emqx_hooks:run_fold('client.unsubscribe',[#{clientid => <<"myclient">>, username => <<"myuser">>}, #{}], TopicTable),
  288. ?assertEqual(TopicTable, Ret).
  289. case61(_Config) ->
  290. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  291. Code = "function on_client_disconnected(clientid, username, reasoncode)"
  292. "\n return 0"
  293. "\nend"
  294. "\n"
  295. "\nfunction register_hook()"
  296. "\n return \"on_client_disconnected\""
  297. "\nend",
  298. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  299. ?assertEqual(ok,
  300. emqx_hooks:run('client.disconnected',
  301. [#{clientid => <<"myclient">>, username => <<"tester">>}, 0])).
  302. case62(_Config) ->
  303. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  304. Code = "function on_client_disconnected(clientid, username, reasoncode)"
  305. "\n return 9/0" % this code has fatal error
  306. "\nend"
  307. "\n"
  308. "\nfunction register_hook()"
  309. "\n return \"on_client_disconnected\""
  310. "\nend",
  311. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  312. ?assertEqual(ok,
  313. emqx_hooks:run('client.disconnected',
  314. [#{clientid => <<"myclient">>, username => <<"tester">>}, 0])).
  315. case71(_Config) ->
  316. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  317. Code = "function on_session_subscribed(clientid, username, topic)"
  318. "\n return 0"
  319. "\nend"
  320. "\n"
  321. "\nfunction register_hook()"
  322. "\n return \"on_session_subscribed\""
  323. "\nend",
  324. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  325. Topic = <<"a/b/c">>,
  326. Ret = emqx_hooks:run('session.subscribed',[#{clientid => <<"myclient">>, username => <<"myuser">>}, Topic, #{first => false}]),
  327. ?assertEqual(ok, Ret).
  328. case72(_Config) ->
  329. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  330. Code = "function on_session_subscribed(clientid, username, topic)"
  331. "\n return false" % return false to stop hook
  332. "\nend"
  333. "\n"
  334. "\nfunction register_hook()"
  335. "\n return \"on_session_subscribed\""
  336. "\nend",
  337. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  338. Topic = <<"a/b/c">>,
  339. Ret = emqx_hooks:run('session.subscribed',[#{clientid => <<"myclient">>, username => <<"myuser">>}, Topic, #{first => false}]),
  340. ?assertEqual(ok, Ret).
  341. case73(_Config) ->
  342. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  343. Code = "function on_session_subscribed(clientid, username, topic)"
  344. "\n return 9/0" % this code has fatal error
  345. "\nend"
  346. "\n"
  347. "\nfunction register_hook()"
  348. "\n return \"on_session_subscribed\""
  349. "\nend",
  350. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  351. Topic = <<"a/b/c">>,
  352. Ret = emqx_hooks:run('session.subscribed',[#{clientid => <<"myclient">>, username => <<"myuser">>}, Topic, #{first => false}]),
  353. ?assertEqual(ok, Ret).
  354. case81(_Config) ->
  355. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  356. Code = "function on_session_unsubscribed(clientid, username, topic)"
  357. "\n return 0"
  358. "\nend"
  359. "\n"
  360. "\nfunction register_hook()"
  361. "\n return \"on_session_unsubscribed\""
  362. "\nend",
  363. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  364. Topic = <<"a/b/c">>,
  365. Ret = emqx_hooks:run('session.unsubscribed',[#{clientid => <<"myclient">>, username => <<"myuser">>}, Topic, #{first => false}]),
  366. ?assertEqual(ok, Ret).
  367. case82(_Config) ->
  368. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  369. Code = "function on_session_unsubscribed(clientid, username, topic)"
  370. "\n return false" % return false to stop hook
  371. "\nend"
  372. "\n"
  373. "\nfunction register_hook()"
  374. "\n return \"on_session_unsubscribed\""
  375. "\nend",
  376. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  377. Topic = <<"a/b/c">>,
  378. Ret = emqx_hooks:run('session.unsubscribed',[#{clientid => <<"myclient">>, username => <<"myuser">>}, Topic, #{first => false}]),
  379. ?assertEqual(ok, Ret).
  380. case83(_Config) ->
  381. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  382. Code = "function on_session_unsubscribed(clientid, username, topic)"
  383. "\n return 9/0" % this code has fatal error
  384. "\nend"
  385. "\n"
  386. "\nfunction register_hook()"
  387. "\n return \"on_session_unsubscribed\""
  388. "\nend",
  389. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  390. Topic = <<"a/b/c">>,
  391. Ret = emqx_hooks:run('session.unsubscribed',[#{clientid => <<"myclient">>, username => <<"myuser">>}, Topic, #{first => false}]),
  392. ?assertEqual(ok, Ret).
  393. case101(_Config) ->
  394. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  395. ScriptName2 = filename:join([emqx_lua_hook:lua_dir(), "mn.lua"]),
  396. Code = "function on_message_publish(clientid, username, topic, payload, qos, retain)"
  397. "\n return topic, \"hello\", qos, retain"
  398. "\nend"
  399. "\n"
  400. "\nfunction register_hook()"
  401. "\n return \"on_message_publish\""
  402. "\nend",
  403. ok = file:write_file(ScriptName, Code),
  404. Code2 = "function on_client_subscribe(clientid, username, topic)"
  405. "\n if topic == \"a/b/c\" then"
  406. "\n topic = \"a1/b1/c1\";"
  407. "\n end"
  408. "\n return topic"
  409. "\nend"
  410. "\n"
  411. "\nfunction register_hook()"
  412. "\n return \"on_client_subscribe\""
  413. "\nend",
  414. ok = file:write_file(ScriptName2, Code2), ok = emqx_lua_hook:load_scripts(),
  415. Ret = emqx_hooks:run_fold('message.publish',[], #message{qos = 2, flags = #{retain => true}, topic = <<"a/b/c">>, payload = <<"123">>, headers = #{}}),
  416. ?assertEqual(#message{qos = 2, flags = #{retain => true}, topic = <<"a/b/c">>, payload = <<"hello">>, headers = #{}}, Ret),
  417. TopicTable = [{<<"a/b/c">>, [qos, 1]}, {<<"d/+/e">>, [{qos, 2}]}],
  418. Ret2 = emqx_hooks:run_fold('client.subscribe',[#{clientid => <<"myclient">>, username => <<"myuser">>}, #{}], TopicTable),
  419. ?assertEqual([{<<"a1/b1/c1">>, [qos, 1]}, {<<"d/+/e">>, [{qos, 2}]}], Ret2).
  420. case110(_Config) ->
  421. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  422. Code = "function on_message_publish(clientid, username, topic, payload, qos, retain)"
  423. "\n return \"changed/topic\", \"hello\", qos, retain"
  424. "\nend"
  425. "\n"
  426. "\nfunction register_hook()"
  427. "\n return \"on_message_publish\""
  428. "\nend",
  429. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  430. Msg = #message{qos = 2, flags = #{retain => true}, topic = <<"a/b/c">>, payload = <<"123">>, headers = #{}},
  431. Ret = emqx_hooks:run_fold('message.publish',[], Msg),
  432. ?assertEqual(Msg#message{topic = <<"changed/topic">>, payload = <<"hello">>}, Ret).
  433. case111(_Config) ->
  434. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  435. Code = " function on_message_publish(topic, payload, qos, retain)"
  436. "\n return \"changed/topic\", \"hello\", qos, retain"
  437. "\nend"
  438. "\n"
  439. "\nfunction register_hook()"
  440. "\n return \"on_message_publish\""
  441. "\nend",
  442. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  443. emqx_ctl:run_command(["luahook", "unload", ScriptName]),
  444. Msg = #message{qos = 2, flags = #{retain => true}, topic = <<"a/b/c">>, payload = <<"123">>, headers = #{}},
  445. Ret = emqx_hooks:run_fold('message.publish',[], Msg),
  446. ?assertEqual(Msg, Ret).
  447. case112(_Config) ->
  448. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  449. Code = " function on_message_publish(clientid, username, topic, payload, qos, retain)"
  450. "\n return \"changed/topic\", \"hello\", qos, retain"
  451. "\nend"
  452. "\n"
  453. "\nfunction register_hook()"
  454. "\n return \"on_message_publish\""
  455. "\nend",
  456. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  457. emqx_ctl:run_command(["luahook", "unload", "abc.lua"]),
  458. timer:sleep(100),
  459. emqx_ctl:run_command(["luahook", "load", "abc.lua"]),
  460. Msg = #message{qos = 2, flags = #{retain => true}, topic = <<"a/b/c">>, payload = <<"123">>, headers = #{}},
  461. Ret = emqx_hooks:run_fold('message.publish',[], Msg),
  462. ?assertEqual(Msg#message{topic = <<"changed/topic">>, payload = <<"hello">>}, Ret).
  463. case113(_Config) ->
  464. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  465. ScriptDisabled = ScriptName ++ ".x",
  466. Code = "function on_message_publish(clientid, username, topic, payload, qos, retain)"
  467. "\n return \"changed/topic\", \"hello\", qos, retain"
  468. "\nend"
  469. "\n"
  470. "\nfunction register_hook()"
  471. "\n return \"on_message_publish\""
  472. "\nend",
  473. ok = file:write_file(ScriptName, Code),
  474. file:delete(ScriptDisabled),
  475. emqx_ctl:run_command(["luahook", "disable", "abc.lua"]), % this command will rename "abc.lua" to "abc.lua.x"
  476. Msg = #message{qos = 2, flags = #{retain => true}, topic = <<"a/b/c">>, payload = <<"123">>, headers = #{}},
  477. Ret = emqx_hooks:run_fold('message.publish',[], Msg),
  478. ?assertEqual(Msg, Ret),
  479. true = filelib:is_file(ScriptDisabled).
  480. case114(_Config) ->
  481. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua.x"]), % disabled script
  482. Code = "function on_message_publish(clientid, username, topic, payload, qos, retain)"
  483. "\n return \"changed/topic\", \"hello\", qos, retain"
  484. "\nend"
  485. "\n"
  486. "\nfunction register_hook()"
  487. "\n return \"on_message_publish\""
  488. "\nend",
  489. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  490. emqx_ctl:run_command(["luahook", "enable", "abc.lua"]),
  491. Msg = #message{qos = 2, flags = #{retain => true}, topic = <<"a/b/c">>, payload = <<"123">>, headers = #{}},
  492. Ret = emqx_hooks:run_fold('message.publish',[], Msg),
  493. ?assertEqual(Msg#message{topic = <<"changed/topic">>, payload = <<"hello">>}, Ret).
  494. case115(_Config) ->
  495. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  496. Code = "function on_message_publish(clientid, username, topic, payload, qos, retain)"
  497. "\n return \"changed/topic\", \"hello\", qos, retain"
  498. "\nend"
  499. "\n"
  500. "function on_client_subscribe(ClientId, Username, Topic)"
  501. "\n return \"play/football\""
  502. "\nend"
  503. "\n"
  504. "\nfunction register_hook()"
  505. "\n return \"on_message_publish\", \"on_client_subscribe\""
  506. "\nend",
  507. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  508. emqx_ctl:run_command(["luahook", "reload", "abc.lua"]),
  509. Msg = #message{qos = 2, flags = #{retain => true}, topic = <<"a/b/c">>, payload = <<"123">>, headers = #{}},
  510. Ret = emqx_hooks:run_fold('message.publish',[], Msg),
  511. ?assertEqual(Msg#message{topic = <<"changed/topic">>, payload = <<"hello">>}, Ret),
  512. TopicTable = [{<<"d/+/e">>, [{qos, 2}]}],
  513. Ret2 = emqx_hooks:run_fold('client.subscribe',[#{clientid => <<"myclient">>, username => <<"myuser">>}, #{}], TopicTable),
  514. ?assertEqual([{<<"play/football">>, [{qos, 2}]}], Ret2).
  515. case201(_Config) ->
  516. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  517. Code = "function on_session_subscribed(clientid, username, topic)"
  518. "\n return 0"
  519. "\nend"
  520. "\n"
  521. "\nfunction on_session_subscribed1()" % register_hook() is missing
  522. "\n return \"on_session_subscribed\""
  523. "\nend",
  524. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  525. Topic = <<"a/b/c">>,
  526. Ret = emqx_hooks:run('session.subscribed',[#{clientid => <<"myclient">>, username => <<"myuser">>}, Topic, #{first => false}]),
  527. ?assertEqual(ok, Ret).
  528. case202(_Config) ->
  529. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  530. Code = "function abc(clientid, username, topic)"
  531. "\n return 0"
  532. "\nend"
  533. "\n"
  534. "\n9/0", % error code
  535. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  536. Topic = <<"a/b/c">>,
  537. Ret = emqx_hooks:run('session.subscribed',[#{clientid => <<"myclient">>, username => <<"myuser">>}, Topic, #{first => false}]),
  538. ?assertEqual(ok, Ret).
  539. case203(_Config) ->
  540. file:del_dir(emqx_lua_hook:lua_dir()), % if this dir is not exist, what will happen?
  541. emqx_lua_hook:load_scripts(),
  542. Topic = <<"a/b/c">>,
  543. Ret = emqx_hooks:run('session.subscribed',[#{clientid => <<"myclient">>, username => <<"myuser">>}, Topic, #{first => false}]),
  544. ?assertEqual(ok, Ret).
  545. case204(_Config) ->
  546. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  547. Code = "function on_message_publish(clientid, username, topic, payload, qos, retain)"
  548. "\n return topic, payload .. \"_Z\", qos, retain"
  549. "\nend"
  550. "\n"
  551. "function on_client_subscribe(ClientId, Username, Topic)"
  552. "\n return \"play/football\""
  553. "\nend"
  554. "\n"
  555. "\nfunction register_hook()"
  556. "\n return \"on_message_publish\", \"on_client_subscribe\", \"on_message_publish\"" % if 2 on_message_publish() are registered, what will happend?
  557. "\nend",
  558. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  559. Msg = #message{qos = 2, flags = #{retain => true}, topic = <<"a/b/c">>, payload = <<"123">>, headers = #{}},
  560. Ret = emqx_hooks:run_fold('message.publish',[], Msg),
  561. ?assertEqual(Msg#message{payload = <<"123_Z">>}, Ret).
  562. case205(_Config) ->
  563. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  564. Code = "function on_message_publish(clientid, username, topic, payload, qos, retain)"
  565. "\n return topic, \"hello\", qos, retain"
  566. "\nend_with_error" %% syntax error
  567. "\n"
  568. "\nfunction register_hook()"
  569. "\n return \"on_message_publish\", \"on_client_subscribe\", \"on_message_publish\"" % if 2 on_message_publish() are registered, what will happend?
  570. "\nend",
  571. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  572. Msg = #message{qos = 2, flags = #{retain => true}, topic = <<"a/b/c">>, payload = <<"123">>, headers = #{}},
  573. Ret = emqx_hooks:run_fold('message.publish',[], Msg),
  574. ?assertEqual(Msg, Ret).
  575. case301(_Config) ->
  576. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  577. Code = "function on_client_authenticate(clientid, username, peerhost, password)"
  578. "\n return \"ok\""
  579. "\nend"
  580. "\n"
  581. "\nfunction register_hook()"
  582. "\n return \"on_client_authenticate\""
  583. "\nend",
  584. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  585. ClientInfo = #{clientid => undefined,
  586. username => <<"test">>,
  587. peerhost => {127, 0, 0, 1},
  588. password => <<"mqtt">>
  589. },
  590. Result = #{auth_result => success, anonymous => true},
  591. ?assertEqual(Result#{auth_result => success},
  592. emqx_hooks:run_fold('client.authenticate', [ClientInfo], Result)).
  593. case302(_Config) ->
  594. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  595. Code = "function on_client_check_acl(clientid, username, peerhost, password, topic, pubsub)"
  596. "\n return \"allow\""
  597. "\nend"
  598. "\n"
  599. "\nfunction register_hook()"
  600. "\n return \"on_client_check_acl\""
  601. "\nend",
  602. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  603. ClientInfo = #{clientid => undefined,
  604. username => <<"test">>,
  605. peerhost => {127, 0, 0, 1},
  606. password => <<"mqtt">>
  607. },
  608. ?assertEqual(allow, emqx_hooks:run_fold('client.check_acl',
  609. [ClientInfo, publish, <<"mytopic">>], deny)).