funcs_misc_test.go 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. // Copyright 2022-2023 EMQ Technologies Co., Ltd.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package function
  15. import (
  16. "fmt"
  17. "reflect"
  18. "testing"
  19. "github.com/lf-edge/ekuiper/internal/conf"
  20. "github.com/lf-edge/ekuiper/internal/keyedstate"
  21. "github.com/lf-edge/ekuiper/internal/testx"
  22. kctx "github.com/lf-edge/ekuiper/internal/topo/context"
  23. "github.com/lf-edge/ekuiper/internal/topo/state"
  24. "github.com/lf-edge/ekuiper/pkg/api"
  25. "github.com/lf-edge/ekuiper/pkg/ast"
  26. )
  27. func init() {
  28. testx.InitEnv()
  29. }
  30. func TestToMap(t *testing.T) {
  31. f, ok := builtins["object_construct"]
  32. if !ok {
  33. t.Fatal("builtin not found")
  34. }
  35. contextLogger := conf.Log.WithField("rule", "testExec")
  36. ctx := kctx.WithValue(kctx.Background(), kctx.LoggerKey, contextLogger)
  37. tempStore, _ := state.CreateStore("mockRule0", api.AtMostOnce)
  38. fctx := kctx.NewDefaultFuncContext(ctx.WithMeta("mockRule0", "test", tempStore), 2)
  39. tests := []struct {
  40. args []interface{}
  41. result interface{}
  42. }{
  43. { // 0
  44. args: []interface{}{
  45. "foo",
  46. "bar",
  47. },
  48. result: map[string]interface{}{
  49. "foo": "bar",
  50. },
  51. }, { // 1
  52. args: []interface{}{
  53. true,
  54. "bar",
  55. },
  56. result: fmt.Errorf("key true is not a string"),
  57. }, { // 2
  58. args: []interface{}{
  59. "key1",
  60. "bar",
  61. "key2",
  62. "foo",
  63. },
  64. result: map[string]interface{}{
  65. "key1": "bar",
  66. "key2": "foo",
  67. },
  68. },
  69. }
  70. for i, tt := range tests {
  71. result, _ := f.exec(fctx, tt.args)
  72. if !reflect.DeepEqual(result, tt.result) {
  73. t.Errorf("%d result mismatch,\ngot:\t%v \nwant:\t%v", i, result, tt.result)
  74. }
  75. }
  76. }
  77. func TestCoalesceExec(t *testing.T) {
  78. f, ok := builtins["coalesce"]
  79. if !ok {
  80. t.Fatal("builtin not found")
  81. }
  82. contextLogger := conf.Log.WithField("rule", "testExec")
  83. ctx := kctx.WithValue(kctx.Background(), kctx.LoggerKey, contextLogger)
  84. tempStore, _ := state.CreateStore("mockRule0", api.AtMostOnce)
  85. fctx := kctx.NewDefaultFuncContext(ctx.WithMeta("mockRule0", "test", tempStore), 2)
  86. tests := []struct {
  87. args []interface{}
  88. result interface{}
  89. }{
  90. { // 1
  91. args: []interface{}{
  92. "foo",
  93. "bar",
  94. "2",
  95. },
  96. result: "foo",
  97. },
  98. { // 2
  99. args: []interface{}{
  100. nil,
  101. "dd",
  102. "1",
  103. },
  104. result: "dd",
  105. },
  106. { // 3
  107. args: []interface{}{
  108. "bar",
  109. nil,
  110. "1",
  111. },
  112. result: "bar",
  113. },
  114. { // 4
  115. args: []interface{}{
  116. nil,
  117. nil,
  118. "2",
  119. },
  120. result: "2",
  121. },
  122. { // 4
  123. args: []interface{}{
  124. nil,
  125. nil,
  126. nil,
  127. },
  128. result: nil,
  129. },
  130. }
  131. for i, tt := range tests {
  132. result, _ := f.exec(fctx, tt.args)
  133. if !reflect.DeepEqual(result, tt.result) {
  134. t.Errorf("%d result mismatch,\ngot:\t%v \nwant:\t%v", i, result, tt.result)
  135. }
  136. }
  137. }
  138. func TestToJson(t *testing.T) {
  139. f, ok := builtins["to_json"]
  140. if !ok {
  141. t.Fatal("builtin not found")
  142. }
  143. contextLogger := conf.Log.WithField("rule", "testExec")
  144. ctx := kctx.WithValue(kctx.Background(), kctx.LoggerKey, contextLogger)
  145. tempStore, _ := state.CreateStore("mockRule0", api.AtMostOnce)
  146. fctx := kctx.NewDefaultFuncContext(ctx.WithMeta("mockRule0", "test", tempStore), 2)
  147. tests := []struct {
  148. args []interface{}
  149. result interface{}
  150. }{
  151. { // 0
  152. args: []interface{}{
  153. "foo",
  154. },
  155. result: `"foo"`,
  156. }, { // 1
  157. args: []interface{}{
  158. nil,
  159. },
  160. result: "null",
  161. }, { // 2
  162. args: []interface{}{
  163. map[string]interface{}{
  164. "key1": "bar",
  165. "key2": "foo",
  166. },
  167. },
  168. result: `{"key1":"bar","key2":"foo"}`,
  169. },
  170. }
  171. for i, tt := range tests {
  172. result, _ := f.exec(fctx, tt.args)
  173. if !reflect.DeepEqual(result, tt.result) {
  174. t.Errorf("%d result mismatch,\ngot:\t%v \nwant:\t%v", i, result, tt.result)
  175. }
  176. }
  177. }
  178. func TestFromJson(t *testing.T) {
  179. f, ok := builtins["parse_json"]
  180. if !ok {
  181. t.Fatal("builtin not found")
  182. }
  183. contextLogger := conf.Log.WithField("rule", "testExec")
  184. ctx := kctx.WithValue(kctx.Background(), kctx.LoggerKey, contextLogger)
  185. tempStore, _ := state.CreateStore("mockRule0", api.AtMostOnce)
  186. fctx := kctx.NewDefaultFuncContext(ctx.WithMeta("mockRule0", "test", tempStore), 2)
  187. tests := []struct {
  188. args []interface{}
  189. result interface{}
  190. }{
  191. { // 0
  192. args: []interface{}{
  193. `"foo"`,
  194. },
  195. result: "foo",
  196. }, { // 1
  197. args: []interface{}{
  198. "null",
  199. },
  200. result: nil,
  201. }, { // 2
  202. args: []interface{}{
  203. `{"key1":"bar","key2":"foo"}`,
  204. },
  205. result: map[string]interface{}{
  206. "key1": "bar",
  207. "key2": "foo",
  208. },
  209. }, { // 3
  210. args: []interface{}{
  211. "key1",
  212. },
  213. result: fmt.Errorf("fail to parse json: invalid character 'k' looking for beginning of value"),
  214. }, { // 4
  215. args: []interface{}{
  216. `[{"key1":"bar","key2":"foo"}]`,
  217. },
  218. result: []interface{}{
  219. map[string]interface{}{
  220. "key1": "bar",
  221. "key2": "foo",
  222. },
  223. },
  224. },
  225. }
  226. for i, tt := range tests {
  227. result, _ := f.exec(fctx, tt.args)
  228. if !reflect.DeepEqual(result, tt.result) {
  229. t.Errorf("%d result mismatch,\ngot:\t%v \nwant:\t%v", i, result, tt.result)
  230. }
  231. }
  232. }
  233. func TestDelay(t *testing.T) {
  234. f, ok := builtins["delay"]
  235. if !ok {
  236. t.Fatal("builtin not found")
  237. }
  238. contextLogger := conf.Log.WithField("rule", "testExec")
  239. ctx := kctx.WithValue(kctx.Background(), kctx.LoggerKey, contextLogger)
  240. tempStore, _ := state.CreateStore("mockRule0", api.AtMostOnce)
  241. fctx := kctx.NewDefaultFuncContext(ctx.WithMeta("mockRule0", "test", tempStore), 2)
  242. err := f.val(fctx, []ast.Expr{&ast.StringLiteral{Val: "abc"}})
  243. if err == nil {
  244. t.Fatal("expect error")
  245. }
  246. err = f.val(fctx, []ast.Expr{&ast.StringLiteral{Val: "1s"}, &ast.StringLiteral{Val: "1s"}})
  247. if err == nil {
  248. t.Fatal("expect error")
  249. }
  250. err = f.val(fctx, []ast.Expr{&ast.IntegerLiteral{Val: 1000}, &ast.StringLiteral{Val: "1s"}})
  251. if err != nil {
  252. t.Fatal("expect no error")
  253. }
  254. tests := []struct {
  255. args []interface{}
  256. result interface{}
  257. }{
  258. { // 0
  259. args: []interface{}{
  260. 10,
  261. "bar",
  262. },
  263. result: "bar",
  264. }, { // 1
  265. args: []interface{}{
  266. "bar",
  267. "bar",
  268. },
  269. result: fmt.Errorf("cannot convert string(bar) to int"),
  270. },
  271. }
  272. for i, tt := range tests {
  273. result, _ := f.exec(fctx, tt.args)
  274. if !reflect.DeepEqual(result, tt.result) {
  275. t.Errorf("%d result mismatch,\ngot:\t%v \nwant:\t%v", i, result, tt.result)
  276. }
  277. }
  278. }
  279. func TestKeyedStateValidation(t *testing.T) {
  280. f, ok := builtins["get_keyed_state"]
  281. if !ok {
  282. t.Fatal("builtin not found")
  283. }
  284. tests := []struct {
  285. args []ast.Expr
  286. err error
  287. }{
  288. {
  289. args: []ast.Expr{
  290. &ast.StringLiteral{Val: "foo"},
  291. },
  292. err: fmt.Errorf("Expect 3 arguments but found 1."),
  293. }, {
  294. args: []ast.Expr{
  295. &ast.StringLiteral{Val: "foo"},
  296. &ast.StringLiteral{Val: "bar"},
  297. },
  298. err: fmt.Errorf("Expect 3 arguments but found 2."),
  299. }, {
  300. args: []ast.Expr{
  301. &ast.StringLiteral{Val: "foo"},
  302. &ast.StringLiteral{Val: "bar"},
  303. &ast.StringLiteral{Val: "barz"},
  304. },
  305. err: fmt.Errorf("expect one of following value for the 2nd parameter: bigint, float, string, boolean, datetime"),
  306. }, {
  307. args: []ast.Expr{
  308. &ast.StringLiteral{Val: "foo"},
  309. &ast.StringLiteral{Val: "bigint"},
  310. &ast.StringLiteral{Val: "barz"},
  311. },
  312. err: nil,
  313. },
  314. }
  315. for i, tt := range tests {
  316. err := f.val(nil, tt.args)
  317. if !reflect.DeepEqual(err, tt.err) {
  318. t.Errorf("%d result mismatch,\ngot:\t%v \nwant:\t%v", i, err, tt.err)
  319. }
  320. }
  321. }
  322. func TestKeyedStateExec(t *testing.T) {
  323. keyedstate.InitKeyedStateKV()
  324. f, ok := builtins["get_keyed_state"]
  325. if !ok {
  326. t.Fatal("builtin not found")
  327. }
  328. contextLogger := conf.Log.WithField("rule", "testExec")
  329. ctx := kctx.WithValue(kctx.Background(), kctx.LoggerKey, contextLogger)
  330. tempStore, _ := state.CreateStore("mockRule0", api.AtMostOnce)
  331. fctx := kctx.NewDefaultFuncContext(ctx.WithMeta("mockRule0", "test", tempStore), 1)
  332. tests := []struct {
  333. args []interface{}
  334. result interface{}
  335. }{
  336. { // 0
  337. args: []interface{}{
  338. "foo",
  339. },
  340. result: fmt.Errorf("the args must be two or three"),
  341. }, { // 1
  342. args: []interface{}{
  343. "foo",
  344. "bigint",
  345. "baz",
  346. "bar",
  347. },
  348. result: fmt.Errorf("the args must be two or three"),
  349. }, { // 2
  350. args: []interface{}{
  351. "foo",
  352. "float",
  353. 20.0,
  354. },
  355. result: 20.0,
  356. },
  357. }
  358. for i, tt := range tests {
  359. result, _ := f.exec(fctx, tt.args)
  360. if !reflect.DeepEqual(result, tt.result) {
  361. t.Errorf("%d result mismatch,\ngot:\t%v \nwant:\t%v", i, result, tt.result)
  362. }
  363. }
  364. _ = keyedstate.ClearKeyedState()
  365. }