|
@@ -1,4 +1,4 @@
|
|
|
-// Copyright 2022 EMQ Technologies Co., Ltd.
|
|
|
+// Copyright 2022-2023 EMQ Technologies Co., Ltd.
|
|
|
//
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
// you may not use this file except in compliance with the License.
|
|
@@ -21,6 +21,10 @@ import (
|
|
|
"path"
|
|
|
"reflect"
|
|
|
"testing"
|
|
|
+
|
|
|
+ "github.com/stretchr/testify/require"
|
|
|
+
|
|
|
+ "github.com/lf-edge/ekuiper/pkg/ast"
|
|
|
)
|
|
|
|
|
|
func TestMessageDecode(t *testing.T) {
|
|
@@ -73,3 +77,333 @@ func TestMessageDecode(t *testing.T) {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+func TestFastJsonConverterWithSchema(t *testing.T) {
|
|
|
+ testcases := []struct {
|
|
|
+ schema map[string]*ast.JsonStreamField
|
|
|
+ payload []byte
|
|
|
+ require map[string]interface{}
|
|
|
+ }{
|
|
|
+ {
|
|
|
+ payload: []byte(`{"a":1}`),
|
|
|
+ schema: map[string]*ast.JsonStreamField{
|
|
|
+ "a": {
|
|
|
+ Type: "bigint",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ require: map[string]interface{}{
|
|
|
+ "a": float64(1),
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ payload: []byte(`{"a":1}`),
|
|
|
+ schema: map[string]*ast.JsonStreamField{
|
|
|
+ "a": {
|
|
|
+ Type: "float",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ require: map[string]interface{}{
|
|
|
+ "a": float64(1),
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ payload: []byte(`{"a":"a"}`),
|
|
|
+ schema: map[string]*ast.JsonStreamField{
|
|
|
+ "a": {
|
|
|
+ Type: "string",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ require: map[string]interface{}{
|
|
|
+ "a": "a",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ payload: []byte(`{"a":"a"}`),
|
|
|
+ schema: map[string]*ast.JsonStreamField{
|
|
|
+ "a": {
|
|
|
+ Type: "bytea",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ require: map[string]interface{}{
|
|
|
+ "a": "a",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ payload: []byte(`{"a":true}`),
|
|
|
+ schema: map[string]*ast.JsonStreamField{
|
|
|
+ "a": {
|
|
|
+ Type: "boolean",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ require: map[string]interface{}{
|
|
|
+ "a": true,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ payload: []byte(`{"a":123}`),
|
|
|
+ schema: map[string]*ast.JsonStreamField{
|
|
|
+ "a": {
|
|
|
+ Type: "datetime",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ require: map[string]interface{}{
|
|
|
+ "a": float64(123),
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ payload: []byte(`{"a":"123"}`),
|
|
|
+ schema: map[string]*ast.JsonStreamField{
|
|
|
+ "a": {
|
|
|
+ Type: "datetime",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ require: map[string]interface{}{
|
|
|
+ "a": "123",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ payload: []byte(`{"a":{"b":1}}`),
|
|
|
+ schema: map[string]*ast.JsonStreamField{
|
|
|
+ "a": {
|
|
|
+ Type: "struct",
|
|
|
+ Properties: map[string]*ast.JsonStreamField{
|
|
|
+ "b": {
|
|
|
+ Type: "bigint",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ require: map[string]interface{}{
|
|
|
+ "a": map[string]interface{}{
|
|
|
+ "b": float64(1),
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ }
|
|
|
+ for _, tc := range testcases {
|
|
|
+ f := NewFastJsonConverter(tc.schema)
|
|
|
+ v, err := f.Decode(tc.payload)
|
|
|
+ require.NoError(t, err)
|
|
|
+ require.Equal(t, v, tc.require)
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, tc := range testcases {
|
|
|
+ arrayPayload := []byte(fmt.Sprintf("[%s]", string(tc.payload)))
|
|
|
+ arrayRequire := []map[string]interface{}{
|
|
|
+ tc.require,
|
|
|
+ }
|
|
|
+ f := NewFastJsonConverter(tc.schema)
|
|
|
+ v, err := f.Decode(arrayPayload)
|
|
|
+ require.NoError(t, err)
|
|
|
+ require.Equal(t, v, arrayRequire)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestFastJsonConverterWithSchemaError(t *testing.T) {
|
|
|
+ testcases := []struct {
|
|
|
+ schema map[string]*ast.JsonStreamField
|
|
|
+ payload []byte
|
|
|
+ err error
|
|
|
+ }{
|
|
|
+ {
|
|
|
+ payload: []byte(`{123}`),
|
|
|
+ schema: map[string]*ast.JsonStreamField{
|
|
|
+ "a": {
|
|
|
+ Type: "bigint",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ err: fmt.Errorf(`cannot parse JSON: cannot parse object: cannot find opening '"" for object key; unparsed tail: "123}"`),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ payload: []byte(`123`),
|
|
|
+ schema: map[string]*ast.JsonStreamField{
|
|
|
+ "a": {
|
|
|
+ Type: "bigint",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ err: fmt.Errorf("only map[string]interface{} and []map[string]interface{} is supported"),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ payload: []byte(`{"a":"123"}`),
|
|
|
+ schema: map[string]*ast.JsonStreamField{
|
|
|
+ "a": {
|
|
|
+ Type: "bigint",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ err: fmt.Errorf("a has wrong type:string, expect:bigint"),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ payload: []byte(`{"a":true}`),
|
|
|
+ schema: map[string]*ast.JsonStreamField{
|
|
|
+ "a": {
|
|
|
+ Type: "string",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ err: fmt.Errorf("a has wrong type:true, expect:string"),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ payload: []byte(`{"a":123}`),
|
|
|
+ schema: map[string]*ast.JsonStreamField{
|
|
|
+ "a": {
|
|
|
+ Type: "array",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ err: fmt.Errorf("a has wrong type:number, expect:array"),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ payload: []byte(`{"a":123}`),
|
|
|
+ schema: map[string]*ast.JsonStreamField{
|
|
|
+ "a": {
|
|
|
+ Type: "struct",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ err: fmt.Errorf("a has wrong type:number, expect:struct"),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ payload: []byte(`{"a":123}`),
|
|
|
+ schema: map[string]*ast.JsonStreamField{
|
|
|
+ "a": {
|
|
|
+ Type: "boolean",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ err: fmt.Errorf("a has wrong type:number, expect:boolean"),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ payload: []byte(`{"a":true}`),
|
|
|
+ schema: map[string]*ast.JsonStreamField{
|
|
|
+ "a": {
|
|
|
+ Type: "datetime",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ err: fmt.Errorf("a has wrong type:true, expect:datetime"),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ payload: []byte(`{"a":["123"]}`),
|
|
|
+ schema: map[string]*ast.JsonStreamField{
|
|
|
+ "a": {
|
|
|
+ Type: "array",
|
|
|
+ Items: &ast.JsonStreamField{
|
|
|
+ Type: "bigint",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ err: fmt.Errorf("array has wrong type:string, expect:bigint"),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ payload: []byte(`{"a":[true]}`),
|
|
|
+ schema: map[string]*ast.JsonStreamField{
|
|
|
+ "a": {
|
|
|
+ Type: "array",
|
|
|
+ Items: &ast.JsonStreamField{
|
|
|
+ Type: "string",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ err: fmt.Errorf("array has wrong type:true, expect:string"),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ payload: []byte(`{"a":[123]}`),
|
|
|
+ schema: map[string]*ast.JsonStreamField{
|
|
|
+ "a": {
|
|
|
+ Type: "array",
|
|
|
+ Items: &ast.JsonStreamField{
|
|
|
+ Type: "array",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ err: fmt.Errorf("array has wrong type:number, expect:array"),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ payload: []byte(`{"a":[123]}`),
|
|
|
+ schema: map[string]*ast.JsonStreamField{
|
|
|
+ "a": {
|
|
|
+ Type: "array",
|
|
|
+ Items: &ast.JsonStreamField{
|
|
|
+ Type: "struct",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ err: fmt.Errorf("array has wrong type:number, expect:struct"),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ payload: []byte(`{"a":[123]}`),
|
|
|
+ schema: map[string]*ast.JsonStreamField{
|
|
|
+ "a": {
|
|
|
+ Type: "array",
|
|
|
+ Items: &ast.JsonStreamField{
|
|
|
+ Type: "boolean",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ err: fmt.Errorf("array has wrong type:number, expect:boolean"),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ payload: []byte(`{"a":[true]}`),
|
|
|
+ schema: map[string]*ast.JsonStreamField{
|
|
|
+ "a": {
|
|
|
+ Type: "array",
|
|
|
+ Items: &ast.JsonStreamField{
|
|
|
+ Type: "datetime",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ err: fmt.Errorf("array has wrong type:true, expect:datetime"),
|
|
|
+ },
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, tc := range testcases {
|
|
|
+ f := NewFastJsonConverter(tc.schema)
|
|
|
+ _, err := f.Decode(tc.payload)
|
|
|
+ require.Error(t, err)
|
|
|
+ require.Equal(t, err, tc.err)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestFastJsonEncode(t *testing.T) {
|
|
|
+ a := make(map[string]int)
|
|
|
+ a["a"] = 1
|
|
|
+ f := NewFastJsonConverter(nil)
|
|
|
+ v, err := f.Encode(a)
|
|
|
+ require.NoError(t, err)
|
|
|
+ require.Equal(t, v, []byte(`{"a":1}`))
|
|
|
+}
|
|
|
+
|
|
|
+func TestArrayWithArray(t *testing.T) {
|
|
|
+ payload := []byte(`{
|
|
|
+ "a":[
|
|
|
+ [
|
|
|
+ {
|
|
|
+ "c":1
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ ]
|
|
|
+}`)
|
|
|
+ schema := map[string]*ast.JsonStreamField{
|
|
|
+ "a": {
|
|
|
+ Type: "array",
|
|
|
+ Items: &ast.JsonStreamField{
|
|
|
+ Type: "array",
|
|
|
+ Items: &ast.JsonStreamField{
|
|
|
+ Type: "struct",
|
|
|
+ Properties: map[string]*ast.JsonStreamField{
|
|
|
+ "c": {
|
|
|
+ Type: "bigint",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ }
|
|
|
+ f := NewFastJsonConverter(schema)
|
|
|
+ v, err := f.Decode(payload)
|
|
|
+ require.NoError(t, err)
|
|
|
+ require.Equal(t, v, map[string]interface{}{
|
|
|
+ "a": []interface{}{
|
|
|
+ []interface{}{
|
|
|
+ map[string]interface{}{
|
|
|
+ "c": float64(1),
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ })
|
|
|
+}
|