funcs_misc_test.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  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. "errors"
  17. "fmt"
  18. "reflect"
  19. "testing"
  20. "time"
  21. "github.com/stretchr/testify/assert"
  22. "github.com/stretchr/testify/require"
  23. "github.com/lf-edge/ekuiper/internal/conf"
  24. "github.com/lf-edge/ekuiper/internal/keyedstate"
  25. "github.com/lf-edge/ekuiper/internal/testx"
  26. kctx "github.com/lf-edge/ekuiper/internal/topo/context"
  27. "github.com/lf-edge/ekuiper/internal/topo/state"
  28. "github.com/lf-edge/ekuiper/pkg/api"
  29. "github.com/lf-edge/ekuiper/pkg/ast"
  30. )
  31. func init() {
  32. testx.InitEnv()
  33. }
  34. func TestCoalesceExec(t *testing.T) {
  35. f, ok := builtins["coalesce"]
  36. if !ok {
  37. t.Fatal("builtin not found")
  38. }
  39. contextLogger := conf.Log.WithField("rule", "testExec")
  40. ctx := kctx.WithValue(kctx.Background(), kctx.LoggerKey, contextLogger)
  41. tempStore, _ := state.CreateStore("mockRule0", api.AtMostOnce)
  42. fctx := kctx.NewDefaultFuncContext(ctx.WithMeta("mockRule0", "test", tempStore), 2)
  43. tests := []struct {
  44. args []interface{}
  45. result interface{}
  46. }{
  47. { // 1
  48. args: []interface{}{
  49. "foo",
  50. "bar",
  51. "2",
  52. },
  53. result: "foo",
  54. },
  55. { // 2
  56. args: []interface{}{
  57. nil,
  58. "dd",
  59. "1",
  60. },
  61. result: "dd",
  62. },
  63. { // 3
  64. args: []interface{}{
  65. "bar",
  66. nil,
  67. "1",
  68. },
  69. result: "bar",
  70. },
  71. { // 4
  72. args: []interface{}{
  73. nil,
  74. nil,
  75. "2",
  76. },
  77. result: "2",
  78. },
  79. { // 4
  80. args: []interface{}{
  81. nil,
  82. nil,
  83. nil,
  84. },
  85. result: nil,
  86. },
  87. }
  88. for i, tt := range tests {
  89. result, _ := f.exec(fctx, tt.args)
  90. if !reflect.DeepEqual(result, tt.result) {
  91. t.Errorf("%d result mismatch,\ngot:\t%v \nwant:\t%v", i, result, tt.result)
  92. }
  93. }
  94. }
  95. func TestToSeconds(t *testing.T) {
  96. f, ok := builtins["to_seconds"]
  97. if !ok {
  98. t.Fatal("builtin not found")
  99. }
  100. contextLogger := conf.Log.WithField("rule", "testExec")
  101. ctx := kctx.WithValue(kctx.Background(), kctx.LoggerKey, contextLogger)
  102. tempStore, _ := state.CreateStore("mockRule0", api.AtMostOnce)
  103. fctx := kctx.NewDefaultFuncContext(ctx.WithMeta("mockRule0", "test", tempStore), 2)
  104. tests := []struct {
  105. args []interface{}
  106. result interface{}
  107. }{
  108. { // 0
  109. args: []interface{}{
  110. time.Unix(1e9, 0),
  111. },
  112. result: int64(1e9),
  113. }, { // 1
  114. args: []interface{}{
  115. nil,
  116. },
  117. result: errors.New("unsupported type to convert to timestamp <nil>"),
  118. },
  119. }
  120. for _, tt := range tests {
  121. result, _ := f.exec(fctx, tt.args)
  122. assert.Equal(t, tt.result, result)
  123. }
  124. }
  125. func TestToJson(t *testing.T) {
  126. f, ok := builtins["to_json"]
  127. if !ok {
  128. t.Fatal("builtin not found")
  129. }
  130. contextLogger := conf.Log.WithField("rule", "testExec")
  131. ctx := kctx.WithValue(kctx.Background(), kctx.LoggerKey, contextLogger)
  132. tempStore, _ := state.CreateStore("mockRule0", api.AtMostOnce)
  133. fctx := kctx.NewDefaultFuncContext(ctx.WithMeta("mockRule0", "test", tempStore), 2)
  134. tests := []struct {
  135. args []interface{}
  136. result interface{}
  137. }{
  138. { // 0
  139. args: []interface{}{
  140. "foo",
  141. },
  142. result: `"foo"`,
  143. }, { // 1
  144. args: []interface{}{
  145. nil,
  146. },
  147. result: "null",
  148. }, { // 2
  149. args: []interface{}{
  150. map[string]interface{}{
  151. "key1": "bar",
  152. "key2": "foo",
  153. },
  154. },
  155. result: `{"key1":"bar","key2":"foo"}`,
  156. },
  157. }
  158. for i, tt := range tests {
  159. result, _ := f.exec(fctx, tt.args)
  160. if !reflect.DeepEqual(result, tt.result) {
  161. t.Errorf("%d result mismatch,\ngot:\t%v \nwant:\t%v", i, result, tt.result)
  162. }
  163. }
  164. }
  165. func TestFromJson(t *testing.T) {
  166. f, ok := builtins["parse_json"]
  167. if !ok {
  168. t.Fatal("builtin not found")
  169. }
  170. contextLogger := conf.Log.WithField("rule", "testExec")
  171. ctx := kctx.WithValue(kctx.Background(), kctx.LoggerKey, contextLogger)
  172. tempStore, _ := state.CreateStore("mockRule0", api.AtMostOnce)
  173. fctx := kctx.NewDefaultFuncContext(ctx.WithMeta("mockRule0", "test", tempStore), 2)
  174. tests := []struct {
  175. args []interface{}
  176. result interface{}
  177. }{
  178. { // 0
  179. args: []interface{}{
  180. `"foo"`,
  181. },
  182. result: "foo",
  183. }, { // 1
  184. args: []interface{}{
  185. "null",
  186. },
  187. result: nil,
  188. }, { // 2
  189. args: []interface{}{
  190. `{"key1":"bar","key2":"foo"}`,
  191. },
  192. result: map[string]interface{}{
  193. "key1": "bar",
  194. "key2": "foo",
  195. },
  196. }, { // 3
  197. args: []interface{}{
  198. "key1",
  199. },
  200. result: fmt.Errorf("fail to parse json: invalid character 'k' looking for beginning of value"),
  201. }, { // 4
  202. args: []interface{}{
  203. `[{"key1":"bar","key2":"foo"}]`,
  204. },
  205. result: []interface{}{
  206. map[string]interface{}{
  207. "key1": "bar",
  208. "key2": "foo",
  209. },
  210. },
  211. },
  212. }
  213. for i, tt := range tests {
  214. result, _ := f.exec(fctx, tt.args)
  215. if !reflect.DeepEqual(result, tt.result) {
  216. t.Errorf("%d result mismatch,\ngot:\t%v \nwant:\t%v", i, result, tt.result)
  217. }
  218. }
  219. }
  220. func TestConvertTZ(t *testing.T) {
  221. f, ok := builtins["convert_tz"]
  222. if !ok {
  223. t.Fatal("builtin not found")
  224. }
  225. contextLogger := conf.Log.WithField("rule", "testExec")
  226. ctx := kctx.WithValue(kctx.Background(), kctx.LoggerKey, contextLogger)
  227. tempStore, _ := state.CreateStore("mockRule0", api.AtMostOnce)
  228. fctx := kctx.NewDefaultFuncContext(ctx.WithMeta("mockRule0", "test", tempStore), 2)
  229. loc, _ := time.LoadLocation("Asia/Shanghai")
  230. tests := []struct {
  231. args []interface{}
  232. result interface{}
  233. }{
  234. { // 0
  235. args: []interface{}{
  236. time.Date(2022, time.April, 13, 6, 22, 32, 233000000, time.UTC),
  237. "UTC",
  238. },
  239. result: time.Date(2022, time.April, 13, 6, 22, 32, 233000000, time.UTC),
  240. }, { // 1
  241. args: []interface{}{
  242. time.Date(2022, time.April, 13, 6, 22, 32, 233000000, time.UTC),
  243. "Asia/Shanghai",
  244. },
  245. result: time.Date(2022, time.April, 13, 14, 22, 32, 233000000, loc),
  246. }, { // 2
  247. args: []interface{}{
  248. time.Date(2022, time.April, 13, 6, 22, 32, 233000000, time.UTC),
  249. "Unknown",
  250. },
  251. result: errors.New("unknown time zone Unknown"),
  252. }, { // 3
  253. args: []interface{}{
  254. true,
  255. "UTC",
  256. },
  257. result: errors.New("unsupported type to convert to timestamp true"),
  258. },
  259. }
  260. for _, tt := range tests {
  261. result, _ := f.exec(fctx, tt.args)
  262. assert.Equal(t, tt.result, result)
  263. }
  264. vtests := []struct {
  265. args []ast.Expr
  266. wantErr bool
  267. }{
  268. {
  269. []ast.Expr{&ast.TimeLiteral{Val: 0}, &ast.StringLiteral{Val: "0"}},
  270. false,
  271. },
  272. {
  273. []ast.Expr{&ast.StringLiteral{Val: "0"}},
  274. true,
  275. },
  276. {
  277. []ast.Expr{&ast.NumberLiteral{Val: 0}, &ast.NumberLiteral{Val: 0}},
  278. true,
  279. },
  280. {
  281. []ast.Expr{&ast.NumberLiteral{Val: 0}, &ast.TimeLiteral{Val: 0}},
  282. true,
  283. },
  284. {
  285. []ast.Expr{&ast.NumberLiteral{Val: 0}, &ast.BooleanLiteral{Val: true}},
  286. true,
  287. },
  288. {
  289. []ast.Expr{&ast.StringLiteral{Val: "0"}, &ast.NumberLiteral{Val: 0}},
  290. true,
  291. },
  292. {
  293. []ast.Expr{&ast.BooleanLiteral{Val: true}, &ast.NumberLiteral{Val: 0}},
  294. true,
  295. },
  296. }
  297. for _, vtt := range vtests {
  298. err := f.val(fctx, vtt.args)
  299. if vtt.wantErr {
  300. assert.Error(t, err)
  301. } else {
  302. assert.NoError(t, err)
  303. }
  304. }
  305. }
  306. func TestDelay(t *testing.T) {
  307. f, ok := builtins["delay"]
  308. if !ok {
  309. t.Fatal("builtin not found")
  310. }
  311. contextLogger := conf.Log.WithField("rule", "testExec")
  312. ctx := kctx.WithValue(kctx.Background(), kctx.LoggerKey, contextLogger)
  313. tempStore, _ := state.CreateStore("mockRule0", api.AtMostOnce)
  314. fctx := kctx.NewDefaultFuncContext(ctx.WithMeta("mockRule0", "test", tempStore), 2)
  315. err := f.val(fctx, []ast.Expr{&ast.StringLiteral{Val: "abc"}})
  316. if err == nil {
  317. t.Fatal("expect error")
  318. }
  319. err = f.val(fctx, []ast.Expr{&ast.StringLiteral{Val: "1s"}, &ast.StringLiteral{Val: "1s"}})
  320. if err == nil {
  321. t.Fatal("expect error")
  322. }
  323. err = f.val(fctx, []ast.Expr{&ast.IntegerLiteral{Val: 1000}, &ast.StringLiteral{Val: "1s"}})
  324. if err != nil {
  325. t.Fatal("expect no error")
  326. }
  327. tests := []struct {
  328. args []interface{}
  329. result interface{}
  330. }{
  331. { // 0
  332. args: []interface{}{
  333. 10,
  334. "bar",
  335. },
  336. result: "bar",
  337. }, { // 1
  338. args: []interface{}{
  339. "bar",
  340. "bar",
  341. },
  342. result: fmt.Errorf("cannot convert string(bar) to int"),
  343. },
  344. }
  345. for i, tt := range tests {
  346. result, _ := f.exec(fctx, tt.args)
  347. if !reflect.DeepEqual(result, tt.result) {
  348. t.Errorf("%d result mismatch,\ngot:\t%v \nwant:\t%v", i, result, tt.result)
  349. }
  350. }
  351. }
  352. func TestKeyedStateValidation(t *testing.T) {
  353. f, ok := builtins["get_keyed_state"]
  354. if !ok {
  355. t.Fatal("builtin not found")
  356. }
  357. tests := []struct {
  358. args []ast.Expr
  359. err error
  360. }{
  361. {
  362. args: []ast.Expr{
  363. &ast.StringLiteral{Val: "foo"},
  364. },
  365. err: fmt.Errorf("Expect 3 arguments but found 1."),
  366. }, {
  367. args: []ast.Expr{
  368. &ast.StringLiteral{Val: "foo"},
  369. &ast.StringLiteral{Val: "bar"},
  370. },
  371. err: fmt.Errorf("Expect 3 arguments but found 2."),
  372. }, {
  373. args: []ast.Expr{
  374. &ast.StringLiteral{Val: "foo"},
  375. &ast.StringLiteral{Val: "bar"},
  376. &ast.StringLiteral{Val: "barz"},
  377. },
  378. err: fmt.Errorf("expect one of following value for the 2nd parameter: bigint, float, string, boolean, datetime"),
  379. }, {
  380. args: []ast.Expr{
  381. &ast.StringLiteral{Val: "foo"},
  382. &ast.StringLiteral{Val: "bigint"},
  383. &ast.StringLiteral{Val: "barz"},
  384. },
  385. err: nil,
  386. },
  387. }
  388. for i, tt := range tests {
  389. err := f.val(nil, tt.args)
  390. if !reflect.DeepEqual(err, tt.err) {
  391. t.Errorf("%d result mismatch,\ngot:\t%v \nwant:\t%v", i, err, tt.err)
  392. }
  393. }
  394. }
  395. func TestKeyedStateExec(t *testing.T) {
  396. keyedstate.InitKeyedStateKV()
  397. f, ok := builtins["get_keyed_state"]
  398. if !ok {
  399. t.Fatal("builtin not found")
  400. }
  401. contextLogger := conf.Log.WithField("rule", "testExec")
  402. ctx := kctx.WithValue(kctx.Background(), kctx.LoggerKey, contextLogger)
  403. tempStore, _ := state.CreateStore("mockRule0", api.AtMostOnce)
  404. fctx := kctx.NewDefaultFuncContext(ctx.WithMeta("mockRule0", "test", tempStore), 1)
  405. tests := []struct {
  406. args []interface{}
  407. result interface{}
  408. }{
  409. { // 0
  410. args: []interface{}{
  411. "foo",
  412. },
  413. result: fmt.Errorf("the args must be two or three"),
  414. }, { // 1
  415. args: []interface{}{
  416. "foo",
  417. "bigint",
  418. "baz",
  419. "bar",
  420. },
  421. result: fmt.Errorf("the args must be two or three"),
  422. }, { // 2
  423. args: []interface{}{
  424. "foo",
  425. "float",
  426. 20.0,
  427. },
  428. result: 20.0,
  429. },
  430. }
  431. for i, tt := range tests {
  432. result, _ := f.exec(fctx, tt.args)
  433. if !reflect.DeepEqual(result, tt.result) {
  434. t.Errorf("%d result mismatch,\ngot:\t%v \nwant:\t%v", i, result, tt.result)
  435. }
  436. }
  437. _ = keyedstate.ClearKeyedState()
  438. }
  439. func TestHexIntFunctions(t *testing.T) {
  440. contextLogger := conf.Log.WithField("rule", "testExec")
  441. ctx := kctx.WithValue(kctx.Background(), kctx.LoggerKey, contextLogger)
  442. tempStore, _ := state.CreateStore("mockRule0", api.AtMostOnce)
  443. fctx := kctx.NewDefaultFuncContext(ctx.WithMeta("mockRule0", "test", tempStore), 2)
  444. tests := []struct {
  445. name string
  446. args []interface{}
  447. result interface{}
  448. }{
  449. {
  450. name: "hex2dec",
  451. args: []interface{}{
  452. "0x10",
  453. },
  454. result: int64(16),
  455. },
  456. {
  457. name: "dec2hex",
  458. args: []interface{}{
  459. 16,
  460. },
  461. result: "0x10",
  462. },
  463. }
  464. for i, tt := range tests {
  465. f, ok := builtins[tt.name]
  466. if !ok {
  467. t.Fatal(fmt.Sprintf("builtin %v not found", tt.name))
  468. }
  469. result, _ := f.exec(fctx, tt.args)
  470. if !reflect.DeepEqual(result, tt.result) {
  471. t.Errorf("%d result mismatch,\ngot:\t%v \nwant:\t%v", i, result, tt.result)
  472. }
  473. }
  474. }
  475. func TestMiscFuncNil(t *testing.T) {
  476. contextLogger := conf.Log.WithField("rule", "testExec")
  477. ctx := kctx.WithValue(kctx.Background(), kctx.LoggerKey, contextLogger)
  478. tempStore, _ := state.CreateStore("mockRule0", api.AtMostOnce)
  479. fctx := kctx.NewDefaultFuncContext(ctx.WithMeta("mockRule0", "test", tempStore), 2)
  480. oldBuiltins := builtins
  481. defer func() {
  482. builtins = oldBuiltins
  483. }()
  484. builtins = map[string]builtinFunc{}
  485. registerMiscFunc()
  486. for name, function := range builtins {
  487. switch name {
  488. case "compress", "decompress", "newuuid", "tstamp", "rule_id", "rule_start", "window_start", "window_end", "event_time",
  489. "json_path_query", "json_path_query_first", "coalesce", "meta", "json_path_exists":
  490. continue
  491. case "isnull":
  492. v, b := function.exec(fctx, []interface{}{nil})
  493. require.True(t, b)
  494. require.Equal(t, v, true)
  495. case "cardinality":
  496. v, b := function.check([]interface{}{nil})
  497. require.True(t, b)
  498. require.Equal(t, v, 0)
  499. case "to_json":
  500. v, b := function.exec(fctx, []interface{}{nil})
  501. require.True(t, b)
  502. require.Equal(t, v, "null")
  503. case "parse_json":
  504. v, b := function.exec(fctx, []interface{}{nil})
  505. require.True(t, b)
  506. require.Equal(t, v, nil)
  507. v, b = function.exec(fctx, []interface{}{"null"})
  508. require.True(t, b)
  509. require.Equal(t, v, nil)
  510. default:
  511. v, b := function.check([]interface{}{nil})
  512. require.True(t, b, fmt.Sprintf("%v failed", name))
  513. require.Nil(t, v, fmt.Sprintf("%v failed", name))
  514. }
  515. }
  516. }
  517. func TestCast(t *testing.T) {
  518. f, ok := builtins["cast"]
  519. if !ok {
  520. t.Fatal("builtin not found")
  521. }
  522. contextLogger := conf.Log.WithField("rule", "testExec")
  523. ctx := kctx.WithValue(kctx.Background(), kctx.LoggerKey, contextLogger)
  524. tempStore, _ := state.CreateStore("mockRule0", api.AtMostOnce)
  525. fctx := kctx.NewDefaultFuncContext(ctx.WithMeta("mockRule0", "test", tempStore), 2)
  526. tests := []struct {
  527. args []interface{}
  528. result interface{}
  529. }{
  530. { // 0
  531. args: []interface{}{
  532. "Ynl0ZWE=",
  533. "bytea",
  534. },
  535. result: []byte("bytea"),
  536. },
  537. { // 1
  538. args: []interface{}{
  539. []byte("bytea"),
  540. "bytea",
  541. },
  542. result: []byte("bytea"),
  543. },
  544. { // 2
  545. args: []interface{}{
  546. 1,
  547. "bytea",
  548. },
  549. result: fmt.Errorf("cannot convert int(1) to bytea"),
  550. },
  551. { // 3
  552. args: []interface{}{
  553. 101.5,
  554. "bigint",
  555. },
  556. result: 101,
  557. },
  558. { // 4
  559. args: []interface{}{
  560. 1,
  561. "boolean",
  562. },
  563. result: true,
  564. },
  565. { // 5
  566. args: []interface{}{
  567. 1,
  568. "float",
  569. },
  570. result: float64(1),
  571. },
  572. { // 6
  573. args: []interface{}{
  574. 1,
  575. "string",
  576. },
  577. result: "1",
  578. },
  579. }
  580. for _, tt := range tests {
  581. result, _ := f.exec(fctx, tt.args)
  582. assert.Equal(t, tt.result, result)
  583. }
  584. vtests := []struct {
  585. args []ast.Expr
  586. wantErr bool
  587. }{
  588. {
  589. []ast.Expr{&ast.FieldRef{Name: "foo"}, &ast.StringLiteral{Val: "bytea"}},
  590. false,
  591. },
  592. {
  593. []ast.Expr{&ast.FieldRef{Name: "foo"}},
  594. true,
  595. },
  596. {
  597. []ast.Expr{&ast.FieldRef{Name: "foo"}, &ast.StringLiteral{Val: "bigint"}},
  598. false,
  599. },
  600. {
  601. []ast.Expr{&ast.FieldRef{Name: "foo"}, &ast.StringLiteral{Val: "float"}},
  602. false,
  603. },
  604. {
  605. []ast.Expr{&ast.FieldRef{Name: "foo"}, &ast.StringLiteral{Val: "string"}},
  606. false,
  607. },
  608. {
  609. []ast.Expr{&ast.FieldRef{Name: "foo"}, &ast.StringLiteral{Val: "boolean"}},
  610. false,
  611. },
  612. {
  613. []ast.Expr{&ast.FieldRef{Name: "foo"}, &ast.StringLiteral{Val: "test"}},
  614. true,
  615. },
  616. }
  617. for _, vtt := range vtests {
  618. err := f.val(fctx, vtt.args)
  619. if vtt.wantErr {
  620. assert.Error(t, err)
  621. } else {
  622. assert.NoError(t, err)
  623. }
  624. }
  625. }