emqx_lua_hook_SUITE.erl 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697
  1. %%--------------------------------------------------------------------
  2. %% Copyright (c) 2020 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. emqx_lua_hook:stop(),
  126. ok = file:delete(ScriptName).
  127. case12(_Config) ->
  128. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  129. Code = "function on_message_delivered(clientid, username, topic, payload, qos, retain)"
  130. "\n return topic, \"hello broker\", qos, retain"
  131. "\nend"
  132. "\n"
  133. "\nfunction register_hook()"
  134. "\n return \"on_message_delivered\""
  135. "\nend",
  136. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  137. Msg = #message{qos = 2, flags = #{retain => true}, topic = <<"a/b/c">>, payload = <<"123">>, headers = #{}},
  138. Ret = emqx_hooks:run_fold('message.delivered', [#{clientid => <<"myclient">>, username => <<"myuser">>}], Msg),
  139. ?assertEqual(Msg#message{payload = <<"hello broker">>}, Ret).
  140. case13(_Config) ->
  141. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  142. Code = "function on_message_delivered(clientid, username, topic, payload, qos, retain)"
  143. "\n return 9/0" % this code has fatal error
  144. "\nend"
  145. "\n"
  146. "\nfunction register_hook()"
  147. "\n return \"on_message_delivered\""
  148. "\nend",
  149. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  150. Msg = #message{qos = 2, flags = #{retain => true}, topic = <<"a/b/c">>, payload = <<"123">>, headers = #{}},
  151. Ret = emqx_hooks:run_fold('message.delivered', [#{clientid => <<"myclient">>, username => <<"myuser">>}], Msg),
  152. ?assertEqual(Msg, Ret).
  153. case21(_Config) ->
  154. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  155. Code = "function on_message_acked(clientid, username, topic, payload, qos, retain)"
  156. "\n return true"
  157. "\nend"
  158. "\n"
  159. "\nfunction register_hook()"
  160. "\n return \"on_message_acked\""
  161. "\nend",
  162. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  163. Msg = #message{qos = 2, flags = #{retain => true}, topic = <<"a/b/c">>, payload = <<"123">>, headers = #{}},
  164. Ret = emqx_hooks:run('message.acked', [#{clientid => <<"myclient">>, username => <<"myuser">>}, Msg]),
  165. ?assertEqual(ok, Ret).
  166. case22(_Config) ->
  167. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  168. Code = "function on_message_acked(clientid, username, topic, payload, qos, retain)"
  169. "\n return 9/0" % this code has fatal error
  170. "\nend"
  171. "\n"
  172. "\nfunction register_hook()"
  173. "\n return \"on_message_acked\""
  174. "\nend",
  175. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  176. Msg = #message{qos = 2, flags = #{retain => true}, topic = <<"a/b/c">>, payload = <<"123">>, headers = #{}},
  177. Ret = emqx_hooks:run('message.acked', [#{clientid => <<"myclient">>, username => <<"myuser">>}, Msg]),
  178. ?assertEqual(ok, Ret),
  179. emqx_lua_hook:stop(),
  180. ok = file:delete(ScriptName).
  181. case31(_Config) ->
  182. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  183. Code = "function on_client_connected(clientid, username)"
  184. "\n return 0"
  185. "\nend"
  186. "\n"
  187. "\nfunction register_hook()"
  188. "\n return \"on_client_connected\""
  189. "\nend",
  190. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  191. ?assertEqual(ok,
  192. emqx_hooks:run('client.connected',
  193. [#{clientid => <<"myclient">>, username => <<"tester">>}, #{}])).
  194. case32(_Config) ->
  195. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  196. Code = "function on_client_connected(clientid, username)"
  197. "\n return 9/0" % this code has fatal error
  198. "\nend"
  199. "\n"
  200. "\nfunction register_hook()"
  201. "\n return \"on_client_connected\""
  202. "\nend",
  203. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  204. ?assertEqual(ok,
  205. emqx_hooks:run('client.connected',
  206. [#{clientid => <<"myclient">>, username => <<"tester">>}, #{}])).
  207. case41(_Config) ->
  208. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  209. Code = "function on_client_subscribe(clientid, username, topic)"
  210. "\n if topic == \"a/b/c\" then"
  211. "\n topic = \"a1/b1/c1\";"
  212. "\n end"
  213. "\n return topic"
  214. "\nend"
  215. "\n"
  216. "\nfunction register_hook()"
  217. "\n return \"on_client_subscribe\""
  218. "\nend",
  219. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  220. TopicTable = [{<<"a/b/c">>, [qos, 1]}, {<<"d/+/e">>, [{qos, 2}]}],
  221. Ret = emqx_hooks:run_fold('client.subscribe',[#{clientid => <<"myclient">>, username => <<"myuser">>}, #{}], TopicTable),
  222. ?assertEqual([{<<"a1/b1/c1">>, [qos, 1]}, {<<"d/+/e">>, [{qos, 2}]}], Ret).
  223. case42(_Config) ->
  224. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  225. Code = "function on_client_subscribe(clientid, username, topic)"
  226. "\n return false" % return false to stop hook
  227. "\nend"
  228. "\n"
  229. "\nfunction register_hook()"
  230. "\n return \"on_client_subscribe\""
  231. "\nend",
  232. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  233. TopicTable = [{<<"a/b/c">>, [qos, 1]}, {<<"d/+/e">>, [{qos, 2}]}],
  234. Ret = emqx_hooks:run_fold('client.subscribe',[#{clientid => <<"myclient">>, username => <<"myuser">>}, #{}], TopicTable),
  235. ?assertEqual(TopicTable, Ret).
  236. case43(_Config) ->
  237. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  238. Code = "function on_client_subscribe(clientid, username, topic)"
  239. "\n return 9/0" % this code has fatal error
  240. "\nend"
  241. "\n"
  242. "\nfunction register_hook()"
  243. "\n return \"on_client_subscribe\""
  244. "\nend",
  245. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  246. TopicTable = [{<<"a/b/c">>, [qos, 1]}, {<<"d/+/e">>, [{qos, 2}]}],
  247. Ret = emqx_hooks:run_fold('client.subscribe',[#{clientid => <<"myclient">>, username => <<"myuser">>}, #{}], TopicTable),
  248. ?assertEqual(TopicTable, Ret).
  249. case51(_Config) ->
  250. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  251. Code = "function on_client_unsubscribe(clientid, username, topic)"
  252. "\n if topic == \"a/b/c\" then"
  253. "\n topic = \"a1/b1/c1\";"
  254. "\n end"
  255. "\n return topic"
  256. "\nend"
  257. "\n"
  258. "\nfunction register_hook()"
  259. "\n return \"on_client_unsubscribe\""
  260. "\nend",
  261. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  262. TopicTable = [{<<"a/b/c">>, [qos, 1]}, {<<"d/+/e">>, [{qos, 2}]}],
  263. Ret = emqx_hooks:run_fold('client.unsubscribe',[#{clientid => <<"myclient">>, username => <<"myuser">>}, #{}], TopicTable),
  264. ?assertEqual([{<<"a1/b1/c1">>, [qos, 1]}, {<<"d/+/e">>, [{qos, 2}]}], Ret).
  265. case52(_Config) ->
  266. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  267. Code = "function on_client_unsubscribe(clientid, username, topic)"
  268. "\n return false" % return false to stop hook
  269. "\nend"
  270. "\n"
  271. "\nfunction register_hook()"
  272. "\n return \"on_client_unsubscribe\""
  273. "\nend",
  274. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  275. TopicTable = [{<<"a/b/c">>, [qos, 1]}, {<<"d/+/e">>, [{qos, 2}]}],
  276. Ret = emqx_hooks:run_fold('client.unsubscribe',[#{clientid => <<"myclient">>, username => <<"myuser">>}, #{}], TopicTable),
  277. ?assertEqual(TopicTable, Ret).
  278. case53(_Config) ->
  279. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  280. Code = "function on_client_unsubscribe(clientid, username, topic)"
  281. "\n return 9/0" % this code has fatal error
  282. "\nend"
  283. "\n"
  284. "\nfunction register_hook()"
  285. "\n return \"on_client_unsubscribe\""
  286. "\nend",
  287. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  288. TopicTable = [{<<"a/b/c">>, [qos, 1]}, {<<"d/+/e">>, [{qos, 2}]}],
  289. Ret = emqx_hooks:run_fold('client.unsubscribe',[#{clientid => <<"myclient">>, username => <<"myuser">>}, #{}], TopicTable),
  290. ?assertEqual(TopicTable, Ret).
  291. case61(_Config) ->
  292. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  293. Code = "function on_client_disconnected(clientid, username, reasoncode)"
  294. "\n return 0"
  295. "\nend"
  296. "\n"
  297. "\nfunction register_hook()"
  298. "\n return \"on_client_disconnected\""
  299. "\nend",
  300. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  301. ?assertEqual(ok,
  302. emqx_hooks:run('client.disconnected',
  303. [#{clientid => <<"myclient">>, username => <<"tester">>}, 0])).
  304. case62(_Config) ->
  305. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  306. Code = "function on_client_disconnected(clientid, username, reasoncode)"
  307. "\n return 9/0" % this code has fatal error
  308. "\nend"
  309. "\n"
  310. "\nfunction register_hook()"
  311. "\n return \"on_client_disconnected\""
  312. "\nend",
  313. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  314. ?assertEqual(ok,
  315. emqx_hooks:run('client.disconnected',
  316. [#{clientid => <<"myclient">>, username => <<"tester">>}, 0])).
  317. case71(_Config) ->
  318. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  319. Code = "function on_session_subscribed(clientid, username, topic)"
  320. "\n return 0"
  321. "\nend"
  322. "\n"
  323. "\nfunction register_hook()"
  324. "\n return \"on_session_subscribed\""
  325. "\nend",
  326. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  327. Topic = <<"a/b/c">>,
  328. Ret = emqx_hooks:run('session.subscribed',[#{clientid => <<"myclient">>, username => <<"myuser">>}, Topic, #{first => false}]),
  329. ?assertEqual(ok, Ret).
  330. case72(_Config) ->
  331. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  332. Code = "function on_session_subscribed(clientid, username, topic)"
  333. "\n return false" % return false to stop hook
  334. "\nend"
  335. "\n"
  336. "\nfunction register_hook()"
  337. "\n return \"on_session_subscribed\""
  338. "\nend",
  339. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  340. Topic = <<"a/b/c">>,
  341. Ret = emqx_hooks:run('session.subscribed',[#{clientid => <<"myclient">>, username => <<"myuser">>}, Topic, #{first => false}]),
  342. ?assertEqual(ok, Ret).
  343. case73(_Config) ->
  344. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  345. Code = "function on_session_subscribed(clientid, username, topic)"
  346. "\n return 9/0" % this code has fatal error
  347. "\nend"
  348. "\n"
  349. "\nfunction register_hook()"
  350. "\n return \"on_session_subscribed\""
  351. "\nend",
  352. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  353. Topic = <<"a/b/c">>,
  354. Ret = emqx_hooks:run('session.subscribed',[#{clientid => <<"myclient">>, username => <<"myuser">>}, Topic, #{first => false}]),
  355. ?assertEqual(ok, Ret).
  356. case81(_Config) ->
  357. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  358. Code = "function on_session_unsubscribed(clientid, username, topic)"
  359. "\n return 0"
  360. "\nend"
  361. "\n"
  362. "\nfunction register_hook()"
  363. "\n return \"on_session_unsubscribed\""
  364. "\nend",
  365. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  366. Topic = <<"a/b/c">>,
  367. Ret = emqx_hooks:run('session.unsubscribed',[#{clientid => <<"myclient">>, username => <<"myuser">>}, Topic, #{first => false}]),
  368. ?assertEqual(ok, Ret).
  369. case82(_Config) ->
  370. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  371. Code = "function on_session_unsubscribed(clientid, username, topic)"
  372. "\n return false" % return false to stop hook
  373. "\nend"
  374. "\n"
  375. "\nfunction register_hook()"
  376. "\n return \"on_session_unsubscribed\""
  377. "\nend",
  378. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  379. Topic = <<"a/b/c">>,
  380. Ret = emqx_hooks:run('session.unsubscribed',[#{clientid => <<"myclient">>, username => <<"myuser">>}, Topic, #{first => false}]),
  381. ?assertEqual(ok, Ret).
  382. case83(_Config) ->
  383. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  384. Code = "function on_session_unsubscribed(clientid, username, topic)"
  385. "\n return 9/0" % this code has fatal error
  386. "\nend"
  387. "\n"
  388. "\nfunction register_hook()"
  389. "\n return \"on_session_unsubscribed\""
  390. "\nend",
  391. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  392. Topic = <<"a/b/c">>,
  393. Ret = emqx_hooks:run('session.unsubscribed',[#{clientid => <<"myclient">>, username => <<"myuser">>}, Topic, #{first => false}]),
  394. ?assertEqual(ok, Ret).
  395. case101(_Config) ->
  396. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  397. ScriptName2 = filename:join([emqx_lua_hook:lua_dir(), "mn.lua"]),
  398. Code = "function on_message_publish(clientid, username, topic, payload, qos, retain)"
  399. "\n return topic, \"hello\", qos, retain"
  400. "\nend"
  401. "\n"
  402. "\nfunction register_hook()"
  403. "\n return \"on_message_publish\""
  404. "\nend",
  405. ok = file:write_file(ScriptName, Code),
  406. Code2 = "function on_client_subscribe(clientid, username, topic)"
  407. "\n if topic == \"a/b/c\" then"
  408. "\n topic = \"a1/b1/c1\";"
  409. "\n end"
  410. "\n return topic"
  411. "\nend"
  412. "\n"
  413. "\nfunction register_hook()"
  414. "\n return \"on_client_subscribe\""
  415. "\nend",
  416. ok = file:write_file(ScriptName2, Code2), ok = emqx_lua_hook:load_scripts(),
  417. Ret = emqx_hooks:run_fold('message.publish',[], #message{qos = 2, flags = #{retain => true}, topic = <<"a/b/c">>, payload = <<"123">>, headers = #{}}),
  418. ?assertEqual(#message{qos = 2, flags = #{retain => true}, topic = <<"a/b/c">>, payload = <<"hello">>, headers = #{}}, Ret),
  419. TopicTable = [{<<"a/b/c">>, [qos, 1]}, {<<"d/+/e">>, [{qos, 2}]}],
  420. Ret2 = emqx_hooks:run_fold('client.subscribe',[#{clientid => <<"myclient">>, username => <<"myuser">>}, #{}], TopicTable),
  421. ?assertEqual([{<<"a1/b1/c1">>, [qos, 1]}, {<<"d/+/e">>, [{qos, 2}]}], Ret2).
  422. case110(_Config) ->
  423. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  424. Code = "function on_message_publish(clientid, username, topic, payload, qos, retain)"
  425. "\n return \"changed/topic\", \"hello\", qos, retain"
  426. "\nend"
  427. "\n"
  428. "\nfunction register_hook()"
  429. "\n return \"on_message_publish\""
  430. "\nend",
  431. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  432. Msg = #message{qos = 2, flags = #{retain => true}, topic = <<"a/b/c">>, payload = <<"123">>, headers = #{}},
  433. Ret = emqx_hooks:run_fold('message.publish',[], Msg),
  434. ?assertEqual(Msg#message{topic = <<"changed/topic">>, payload = <<"hello">>}, Ret).
  435. case111(_Config) ->
  436. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  437. Code = " function on_message_publish(topic, payload, qos, retain)"
  438. "\n return \"changed/topic\", \"hello\", qos, retain"
  439. "\nend"
  440. "\n"
  441. "\nfunction register_hook()"
  442. "\n return \"on_message_publish\""
  443. "\nend",
  444. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  445. emqx_ctl:run_command(["luahook", "unload", ScriptName]),
  446. Msg = #message{qos = 2, flags = #{retain => true}, topic = <<"a/b/c">>, payload = <<"123">>, headers = #{}},
  447. Ret = emqx_hooks:run_fold('message.publish',[], Msg),
  448. ?assertEqual(Msg, Ret).
  449. case112(_Config) ->
  450. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  451. Code = " function on_message_publish(clientid, username, topic, payload, qos, retain)"
  452. "\n return \"changed/topic\", \"hello\", qos, retain"
  453. "\nend"
  454. "\n"
  455. "\nfunction register_hook()"
  456. "\n return \"on_message_publish\""
  457. "\nend",
  458. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  459. emqx_ctl:run_command(["luahook", "unload", "abc.lua"]),
  460. timer:sleep(100),
  461. emqx_ctl:run_command(["luahook", "load", "abc.lua"]),
  462. Msg = #message{qos = 2, flags = #{retain => true}, topic = <<"a/b/c">>, payload = <<"123">>, headers = #{}},
  463. Ret = emqx_hooks:run_fold('message.publish',[], Msg),
  464. ?assertEqual(Msg#message{topic = <<"changed/topic">>, payload = <<"hello">>}, Ret).
  465. case113(_Config) ->
  466. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  467. ScriptDisabled = ScriptName ++ ".x",
  468. Code = "function on_message_publish(clientid, username, topic, payload, qos, retain)"
  469. "\n return \"changed/topic\", \"hello\", qos, retain"
  470. "\nend"
  471. "\n"
  472. "\nfunction register_hook()"
  473. "\n return \"on_message_publish\""
  474. "\nend",
  475. ok = file:write_file(ScriptName, Code),
  476. file:delete(ScriptDisabled),
  477. emqx_ctl:run_command(["luahook", "disable", "abc.lua"]), % this command will rename "abc.lua" to "abc.lua.x"
  478. Msg = #message{qos = 2, flags = #{retain => true}, topic = <<"a/b/c">>, payload = <<"123">>, headers = #{}},
  479. Ret = emqx_hooks:run_fold('message.publish',[], Msg),
  480. ?assertEqual(Msg, Ret),
  481. true = filelib:is_file(ScriptDisabled).
  482. case114(_Config) ->
  483. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua.x"]), % disabled script
  484. Code = "function on_message_publish(clientid, username, topic, payload, qos, retain)"
  485. "\n return \"changed/topic\", \"hello\", qos, retain"
  486. "\nend"
  487. "\n"
  488. "\nfunction register_hook()"
  489. "\n return \"on_message_publish\""
  490. "\nend",
  491. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  492. emqx_ctl:run_command(["luahook", "enable", "abc.lua"]),
  493. Msg = #message{qos = 2, flags = #{retain => true}, topic = <<"a/b/c">>, payload = <<"123">>, headers = #{}},
  494. Ret = emqx_hooks:run_fold('message.publish',[], Msg),
  495. ?assertEqual(Msg#message{topic = <<"changed/topic">>, payload = <<"hello">>}, Ret).
  496. case115(_Config) ->
  497. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  498. Code = "function on_message_publish(clientid, username, topic, payload, qos, retain)"
  499. "\n return \"changed/topic\", \"hello\", qos, retain"
  500. "\nend"
  501. "\n"
  502. "function on_client_subscribe(ClientId, Username, Topic)"
  503. "\n return \"play/football\""
  504. "\nend"
  505. "\n"
  506. "\nfunction register_hook()"
  507. "\n return \"on_message_publish\", \"on_client_subscribe\""
  508. "\nend",
  509. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  510. emqx_ctl:run_command(["luahook", "reload", "abc.lua"]),
  511. Msg = #message{qos = 2, flags = #{retain => true}, topic = <<"a/b/c">>, payload = <<"123">>, headers = #{}},
  512. Ret = emqx_hooks:run_fold('message.publish',[], Msg),
  513. ?assertEqual(Msg#message{topic = <<"changed/topic">>, payload = <<"hello">>}, Ret),
  514. TopicTable = [{<<"d/+/e">>, [{qos, 2}]}],
  515. Ret2 = emqx_hooks:run_fold('client.subscribe',[#{clientid => <<"myclient">>, username => <<"myuser">>}, #{}], TopicTable),
  516. ?assertEqual([{<<"play/football">>, [{qos, 2}]}], Ret2).
  517. case201(_Config) ->
  518. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  519. Code = "function on_session_subscribed(clientid, username, topic)"
  520. "\n return 0"
  521. "\nend"
  522. "\n"
  523. "\nfunction on_session_subscribed1()" % register_hook() is missing
  524. "\n return \"on_session_subscribed\""
  525. "\nend",
  526. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  527. Topic = <<"a/b/c">>,
  528. Ret = emqx_hooks:run('session.subscribed',[#{clientid => <<"myclient">>, username => <<"myuser">>}, Topic, #{first => false}]),
  529. ?assertEqual(ok, Ret).
  530. case202(_Config) ->
  531. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  532. Code = "function abc(clientid, username, topic)"
  533. "\n return 0"
  534. "\nend"
  535. "\n"
  536. "\n9/0", % error code
  537. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  538. Topic = <<"a/b/c">>,
  539. Ret = emqx_hooks:run('session.subscribed',[#{clientid => <<"myclient">>, username => <<"myuser">>}, Topic, #{first => false}]),
  540. ?assertEqual(ok, Ret).
  541. case203(_Config) ->
  542. file:del_dir(emqx_lua_hook:lua_dir()), % if this dir is not exist, what will happen?
  543. emqx_lua_hook:load_scripts(),
  544. Topic = <<"a/b/c">>,
  545. Ret = emqx_hooks:run('session.subscribed',[#{clientid => <<"myclient">>, username => <<"myuser">>}, Topic, #{first => false}]),
  546. ?assertEqual(ok, Ret).
  547. case204(_Config) ->
  548. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  549. Code = "function on_message_publish(clientid, username, topic, payload, qos, retain)"
  550. "\n return topic, payload .. \"_Z\", qos, retain"
  551. "\nend"
  552. "\n"
  553. "function on_client_subscribe(ClientId, Username, Topic)"
  554. "\n return \"play/football\""
  555. "\nend"
  556. "\n"
  557. "\nfunction register_hook()"
  558. "\n return \"on_message_publish\", \"on_client_subscribe\", \"on_message_publish\"" % if 2 on_message_publish() are registered, what will happend?
  559. "\nend",
  560. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  561. Msg = #message{qos = 2, flags = #{retain => true}, topic = <<"a/b/c">>, payload = <<"123">>, headers = #{}},
  562. Ret = emqx_hooks:run_fold('message.publish',[], Msg),
  563. ?assertEqual(Msg#message{payload = <<"123_Z">>}, Ret).
  564. case205(_Config) ->
  565. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  566. Code = "function on_message_publish(clientid, username, topic, payload, qos, retain)"
  567. "\n return topic, \"hello\", qos, retain"
  568. "\nend_with_error" %% syntax error
  569. "\n"
  570. "\nfunction register_hook()"
  571. "\n return \"on_message_publish\", \"on_client_subscribe\", \"on_message_publish\"" % if 2 on_message_publish() are registered, what will happend?
  572. "\nend",
  573. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  574. Msg = #message{qos = 2, flags = #{retain => true}, topic = <<"a/b/c">>, payload = <<"123">>, headers = #{}},
  575. Ret = emqx_hooks:run_fold('message.publish',[], Msg),
  576. ?assertEqual(Msg, Ret).
  577. case301(_Config) ->
  578. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  579. Code = "function on_client_authenticate(clientid, username, peerhost, password)"
  580. "\n return \"ok\""
  581. "\nend"
  582. "\n"
  583. "\nfunction register_hook()"
  584. "\n return \"on_client_authenticate\""
  585. "\nend",
  586. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  587. ClientInfo = #{clientid => undefined,
  588. username => <<"test">>,
  589. peername => undefined,
  590. password => <<"mqtt">>
  591. },
  592. Result = #{auth_result => success, anonymous => true},
  593. ?assertEqual(Result#{auth_result => success},
  594. emqx_hooks:run_fold('client.authenticate', [ClientInfo], Result)).
  595. case302(_Config) ->
  596. application:set_env(emqx, modules, [{emqx_mod_acl_internal, [{acl_file, emqx:get_env(acl_file)}]}]),
  597. emqx_modules:load_module(emqx_mod_acl_internal, false),
  598. ScriptName = filename:join([emqx_lua_hook:lua_dir(), "abc.lua"]),
  599. Code = "function on_client_check_acl(clientid, username, peerhost, password, topic, pubsub)"
  600. "\n return \"allow\""
  601. "\nend"
  602. "\n"
  603. "\nfunction register_hook()"
  604. "\n return \"on_client_check_acl\""
  605. "\nend",
  606. ok = file:write_file(ScriptName, Code), ok = emqx_lua_hook:load_scripts(),
  607. ClientInfo = #{clientid => undefined,
  608. username => <<"test">>,
  609. peername => undefined,
  610. password => <<"mqtt">>
  611. },
  612. ?assertEqual(allow, emqx_hooks:run_fold('client.check_acl',
  613. [ClientInfo, publish, <<"mytopic">>], deny)).