sourceMeta_test.go 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. package plugins
  2. import (
  3. //"net/http"
  4. //"net/http/httptest"
  5. "encoding/json"
  6. "testing"
  7. // "encoding/json"
  8. "fmt"
  9. "reflect"
  10. )
  11. var (
  12. g_file string = `httppull.json`
  13. g_plugin string = `httppull`
  14. g_cf string = `{"default":{"url":"http://localhost","method":"post","interval":10000,"timeout":5000,"body":"{}","bodyType":"json","headers":{"Accept":"application/json"}},"ck1":{"url":"127.0.0.1:9527","method":"get","interval":1000,"headers":{"Accept":"application/json"}},"ck2":{"method":"delete","interval":100,"url":"http://localhost:9090/pull"}}`
  15. g_template string = `{"author":{"name":"Jiyong Huang","email":"huangjy@emqx.io","company":"EMQ Technologies Co., Ltd","website":"https://www.emqx.io"},"libs":[],"helpUrl":{"en_US":"https://github.com/emqx/kuiper/blob/master/docs/en_US/rules/sources/http_pull.md","zh_CN":"https://github.com/emqx/kuiper/blob/master/docs/zh_CN/rules/sources/http_pull.md"},"properties":{"default":[{"name":"url","default":"127.0.0.1:5536","optional":false,"control":"text","type":"string","hint":{"en_US":"The URL where to get the result.","zh_CN":"获取结果的 URL"},"label":{"en_US":"URL","zh_CN":"路径"}},{"name":"method","default":"","optional":false,"control":"text","type":"string","hint":{"en_US":"HTTP method, it could be post, get, put & delete.","zh_CN":"HTTP 方法,它可以是 post、get、put 和 delete。"},"label":{"en_US":"HTTP method","zh_CN":"HTTP 方法"}},{"name":"interval","default":1000,"optional":false,"control":"text","type":"int","hint":{"en_US":"The interval between the requests, time unit is ms.","zh_CN":"请求之间的间隔时间,单位为 ms"},"label":{"en_US":"Interval","zh_CN":"间隔时间"}},{"name":"timeout","default":5000,"optional":false,"control":"text","type":"int","hint":{"en_US":"The timeout for http request, time unit is ms.","zh_CN":"http 请求的超时时间,单位为 ms"},"label":{"en_US":"Timeout","zh_CN":"超时时间"}},{"name":"incremental","default":false,"optional":false,"control":"text","type":"bool","hint":{"en_US":"If it's set to true, then will compare with last result; If response of two requests are the same, then will skip sending out the result.","zh_CN":"如果将其设置为 true,则将与最后的结果进行比较; 如果两个请求的响应相同,则将跳过发送结果。"},"label":{"en_US":"Incremental","zh_CN":"递增"}},{"name":"body","default":"{}","optional":false,"control":"text","type":"string","hint":{"en_US":"The body of request","zh_CN":"请求的正文"},"label":{"en_US":"Body","zh_CN":"正文"}},{"name":"bodyType","default":"json","optional":false,"control":"text","type":"string","hint":{"en_US":"Body type, it could be none|text|json|html|xml|javascript|format.","zh_CN":"正文类型,可以是 none|text|json|html|xml|javascript| 格式"},"label":{"en_US":"Body type","zh_CN":"正文类型"}},{"name":"headers","default":[{"name":"Accept","default":"application/json","optional":false,"control":"text","type":"string","hint":{"en_US":"HTTP headers","zh_CN":"HTTP标头"},"label":{"en_US":"HTTP headers","zh_CN":"HTTP标头"}}],"optional":false,"control":"text","type":"string","hint":{"en_US":"The HTTP request headers that you want to send along with the HTTP request.","zh_CN":"需要与 HTTP 请求一起发送的 HTTP 请求标头。"},"label":{"en_US":"HTTP headers","zh_CN":"HTTP标头"}}]}}`
  16. )
  17. func TestGetSourceMeta(t *testing.T) {
  18. source := new(sourceProperty)
  19. var cf map[string]map[string]interface{}
  20. if err := json.Unmarshal([]byte(g_cf), &cf); nil != err {
  21. t.Error(err)
  22. }
  23. var fileMeta = new(fileSource)
  24. if err := json.Unmarshal([]byte(g_template), fileMeta); nil != err {
  25. t.Error(err)
  26. }
  27. meta, err := newUiSource(fileMeta)
  28. if nil != err {
  29. t.Error(err)
  30. }
  31. source.cf = cf
  32. source.meta = meta
  33. g_sourceProperty = make(map[string]*sourceProperty)
  34. g_sourceProperty[g_file] = source
  35. showMeta, err := GetSourceMeta(g_plugin, "zh_CN")
  36. if nil != err {
  37. t.Error(err)
  38. }
  39. if err := compare(source, showMeta); nil != err {
  40. t.Error(err)
  41. }
  42. addData := `{"url":"127.0.0.1","method":"post","headers":{"Accept":"json"}}`
  43. delData := `{"method":"","headers":{"Accept":""}}`
  44. if err := AddSourceConfKey(g_plugin, "new", "zh_CN", []byte(addData)); nil != err {
  45. t.Error(err)
  46. }
  47. if err := isAddData(addData, cf[`new`]); nil != err {
  48. t.Error(err)
  49. }
  50. if err := DelSourceConfKeyField(g_plugin, "new", "zh_CN", []byte(delData)); nil != err {
  51. t.Error(err)
  52. }
  53. if err := isDelData(delData, cf[`new`]); nil != err {
  54. t.Error(err)
  55. }
  56. }
  57. func isDelData(js string, cf map[string]interface{}) error {
  58. var delNode map[string]interface{}
  59. if err := json.Unmarshal([]byte(js), &delNode); nil != err {
  60. return err
  61. }
  62. for delk, delv := range delNode {
  63. if nil == delv {
  64. if _, ok := cf[delk]; ok {
  65. return fmt.Errorf("%s still exists", delk)
  66. }
  67. }
  68. switch t := delv.(type) {
  69. case string:
  70. if 0 == len(t) {
  71. if _, ok := cf[delk]; ok {
  72. return fmt.Errorf("%s still exists", delk)
  73. }
  74. }
  75. case map[string]interface{}:
  76. if b, err := json.Marshal(t); nil != err {
  77. return fmt.Errorf("request format error")
  78. } else {
  79. var auxCf map[string]interface{}
  80. if err := marshalUn(cf[delk], &auxCf); nil == err {
  81. if err := isDelData(string(b), auxCf); nil != err {
  82. return err
  83. }
  84. }
  85. }
  86. }
  87. }
  88. return nil
  89. }
  90. func isAddData(js string, cf map[string]interface{}) error {
  91. var addNode map[string]interface{}
  92. if err := json.Unmarshal([]byte(js), &addNode); nil != err {
  93. return err
  94. }
  95. for addk, _ := range addNode {
  96. if _, ok := cf[addk]; !ok {
  97. return fmt.Errorf("not found key:%s", addk)
  98. }
  99. }
  100. return nil
  101. }
  102. func marshalUn(input, output interface{}) error {
  103. jsonString, err := json.Marshal(input)
  104. if err != nil {
  105. return err
  106. }
  107. return json.Unmarshal(jsonString, output)
  108. }
  109. func compareUiCf(ui []*field, cf map[string]interface{}) (err error) {
  110. for i := 0; i < len(ui); i++ {
  111. if !ui[i].Exist {
  112. continue
  113. }
  114. if v, ok := cf[ui[i].Name]; ok {
  115. if v == ui[i].Default {
  116. continue
  117. }
  118. if nil == v || nil == ui[i].Default {
  119. return fmt.Errorf("default of %s is nil", ui[i].Name)
  120. }
  121. if reflect.Map == reflect.TypeOf(v).Kind() {
  122. var auxUi []*field
  123. if err = marshalUn(ui[i].Default, &auxUi); nil != err {
  124. return err
  125. }
  126. var auxCf map[string]interface{}
  127. if err = marshalUn(v, &auxCf); nil != err {
  128. return err
  129. }
  130. if err = compareUiCf(auxUi, auxCf); nil != err {
  131. return err
  132. }
  133. } else if ui[i].Default != v {
  134. return fmt.Errorf("not equal->%s:{cf:%v,ui:%v}", ui[i].Name, v, ui[i])
  135. }
  136. } else {
  137. return fmt.Errorf("%s is not in the configuration file", ui[i].Name)
  138. }
  139. }
  140. return nil
  141. }
  142. func compareUiTp(ui, tp []*field) (err error) {
  143. for i := 0; i < len(ui); i++ {
  144. j := 0
  145. for ; j < len(tp); j++ {
  146. if ui[i].Name != tp[j].Name {
  147. continue
  148. }
  149. if ui[i].Type != tp[j].Type {
  150. return fmt.Errorf("not equal->%s type:{tp:%v,ui:%v}", ui[i].Name, tp[j].Type, ui[i].Type)
  151. }
  152. if ui[i].Control != tp[j].Control {
  153. return fmt.Errorf("not equal->%s control:{tp:%v,ui:%v}", ui[i].Name, tp[j].Control, ui[i].Control)
  154. }
  155. if ui[i].Optional != tp[j].Optional {
  156. return fmt.Errorf("not equal->%s optional:{tp:%v,ui:%v}", ui[i].Name, tp[j].Optional, ui[i].Optional)
  157. }
  158. if ui[i].Values != tp[j].Values {
  159. return fmt.Errorf("not equal->%s values:{tp:%v,ui:%v}", ui[i].Name, tp[j].Values, ui[i].Values)
  160. }
  161. if ui[i].Hint != tp[j].Hint {
  162. if nil == ui[i].Hint || nil == tp[j].Hint {
  163. return fmt.Errorf("hint of %s is nil", ui[i].Name)
  164. }
  165. if ui[i].Hint.English != tp[j].Hint.English {
  166. return fmt.Errorf("not equal->%s hint.en_US:{tp:%v,ui:%v}", ui[i].Name, tp[j].Hint.English, ui[i].Hint.English)
  167. }
  168. if ui[i].Hint.Chinese != tp[j].Hint.Chinese {
  169. return fmt.Errorf("not equal->%s hint.zh_CN:{tp:%v,ui:%v}", ui[i].Name, tp[j].Hint.Chinese, ui[i].Hint.Chinese)
  170. }
  171. }
  172. if ui[i].Label != tp[j].Label {
  173. if nil == ui[i].Label || nil == tp[j].Label {
  174. return fmt.Errorf("label of %s is nil", ui[i].Name)
  175. }
  176. if ui[i].Label.English != tp[j].Label.English {
  177. return fmt.Errorf("not equal->%s label.en_US:{tp:%v,ui:%v}", ui[i].Name, tp[j].Label.English, ui[i].Label.English)
  178. }
  179. if ui[i].Label.Chinese != tp[j].Label.Chinese {
  180. return fmt.Errorf("not equal->%s label.zh_CN:{tp:%v,ui:%v}", ui[i].Name, tp[j].Label.Chinese, ui[i].Label.Chinese)
  181. }
  182. }
  183. if !ui[i].Exist {
  184. if nil == ui[i].Default || nil == tp[j].Default {
  185. return fmt.Errorf("The default of %s is nil", ui[i].Name)
  186. if reflect.Slice == reflect.TypeOf(ui[i].Default).Kind() {
  187. var auxUi, auxTp []*field
  188. if err = marshalUn(ui[i].Default, &auxUi); nil != err {
  189. return err
  190. }
  191. if err = marshalUn(tp[j].Default, &auxTp); nil != err {
  192. return err
  193. }
  194. if err = compareUiTp(auxUi, auxTp); nil != err {
  195. return err
  196. }
  197. } else if ui[i].Default != tp[j].Default {
  198. return fmt.Errorf("not equal->%s default:{tp:%v,ui:%v}", ui[i].Name, tp[j].Default, ui[i].Default)
  199. }
  200. }
  201. }
  202. break
  203. }
  204. if len(tp) == j {
  205. return fmt.Errorf("%s is not in the template file", ui[i].Name)
  206. }
  207. }
  208. return nil
  209. }
  210. func compare(source *sourceProperty, uiMeta *uiSource) (err error) {
  211. tp := source.meta.ConfKeys["default"]
  212. for k, v := range source.cf {
  213. ui := uiMeta.ConfKeys[k]
  214. if err = compareUiCf(ui, v); nil != err {
  215. return err
  216. }
  217. if err = compareUiTp(ui, tp); nil != err {
  218. return err
  219. }
  220. }
  221. return nil
  222. }