parser_test.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. // Copyright 2019 Yunion
  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 conditionparser
  15. import (
  16. "go/parser"
  17. "testing"
  18. "yunion.io/x/jsonutils"
  19. )
  20. func TestAst(t *testing.T) {
  21. input := jsonutils.NewDict()
  22. input.Add(jsonutils.NewString("windows"), "server", "os_type")
  23. disk := jsonutils.NewDict()
  24. disk.Add(jsonutils.NewString("ssd"), "medium_type")
  25. disks := jsonutils.NewArray(disk)
  26. input.Add(disks, "server", "disks")
  27. input.Add(disk, "server", "disk.0")
  28. cases := []struct {
  29. in string
  30. want bool
  31. }{
  32. {`server.os_type == "windows"`, true},
  33. {`server.os_type.startswith("window")`, true},
  34. {`server.disks[0].medium_type == "ssd"`, true},
  35. {`server.disks[0].medium_type == "hdd"`, false},
  36. {`server.os_type == "windows" && server.disks[0].medium_type == "ssd"`, true},
  37. {`server.contains("os_type")`, true},
  38. {`server.disks[0].contains("medium_type")`, true},
  39. {`server.disk[0].contains("medium_type")`, true},
  40. {`server.disks[0].contains("backend")`, false},
  41. {`server.keys().contains("os_type", "disks")`, true},
  42. {`server.keys() == "os_type"`, true},
  43. {`server.keys() == "os_type1"`, false},
  44. }
  45. for _, c := range cases {
  46. result, err := EvalBool(c.in, input)
  47. if err != nil {
  48. t.Errorf("eval expr %s error %s", c.in, err)
  49. return
  50. }
  51. if result != c.want {
  52. t.Errorf("expect %v got %v", c.want, result)
  53. return
  54. }
  55. }
  56. }
  57. func TestIsValid(t *testing.T) {
  58. cases := []struct {
  59. in string
  60. want bool
  61. }{
  62. {`server.os_type == "windows"`, true},
  63. {`server.os_type ==`, false},
  64. {`dfadsfsdf ==`, false},
  65. {`dfadsfsdf +`, false},
  66. }
  67. for _, c := range cases {
  68. got := IsValid(c.in)
  69. if got != c.want {
  70. t.Errorf("%s is valid %v got %v", c.in, c.want, got)
  71. }
  72. }
  73. }
  74. func TestEval2(t *testing.T) {
  75. inputStr := `{"server": {"disable_delete":false,
  76. "disk.0":{"backend":"local","format":"qcow2","image_id":"4b9fa54c-858c-4c2b-8719-27aee120b3cb","image_properties":{"os_arch":"x86_64","os_distribution":"CentOS","os_type":"Linux","os_version":"7.5.1804"},"medium":"hybrid","size":40960},
  77. "hypervisor":"kvm","keypair_id":"None","name":"testsched","os_type":"Linux","owner_tenant_id":"5d65667d112e47249ae66dbd7bc07030",
  78. "sched_tag.0":"ssd","secgrp_id":"default","vcpu_count":1,"vmem_size":1024}}`
  79. input, err := jsonutils.ParseString(inputStr)
  80. if err != nil {
  81. t.Errorf("fail to parse server json")
  82. return
  83. }
  84. cases := []struct {
  85. in string
  86. want bool
  87. }{
  88. {`server.os_type == "Linux"`, true},
  89. {`server["os_type"] == "Linux"`, true},
  90. {`server.vmem_size > 2048`, false},
  91. {`server.hypervisor.in("kvm", "aliyun")`, true},
  92. {`server.disable_delete`, false},
  93. {`server.disk[0].backend == "local"`, true},
  94. {`server.sched_tag[0] != "ssd"`, false},
  95. {`server.sched_tag[0] == "ssd"`, true},
  96. // {`server.os_type == "windows" && server.disks[0].medium_type == "ssd"`, true},
  97. }
  98. for _, c := range cases {
  99. result, err := EvalBool(c.in, input)
  100. if err != nil {
  101. t.Errorf("eval expr %s error %s", c.in, err)
  102. return
  103. }
  104. if result != c.want {
  105. t.Errorf("expect %v got %v", c.want, result)
  106. return
  107. }
  108. }
  109. }
  110. func TestEval3(t *testing.T) {
  111. exprStr := `server.disk.backend == "local"`
  112. expr, err := parser.ParseExpr(exprStr)
  113. if err != nil {
  114. t.Errorf("parse exprStr fail %s %s", exprStr, err)
  115. return
  116. }
  117. t.Logf("%s", jsonutils.Marshal(expr))
  118. inputStr := `{"server":{
  119. "disk.0":{"backend": "local", "medium": "hdd"},
  120. "disk.1":{"backend": "local", "medium": "hdd"},
  121. "disk.2":{"backend": "rbd", "medium": "ssd"},
  122. "disk.3":{"backend": "rbd", "medium": "ssd"}}
  123. }`
  124. input, err := jsonutils.ParseString(inputStr)
  125. if err != nil {
  126. t.Errorf("fail to parse server json %s", err)
  127. return
  128. }
  129. cases := []struct {
  130. in string
  131. want bool
  132. }{
  133. {`server.disk.backend == "local"`, true},
  134. {`server.disk.medium == "ssd"`, true},
  135. {`server.disk.medium == "hdd"`, true},
  136. {`server.disk.medium == "hybrid"`, false},
  137. {`server.disk.medium.contains("ssd")`, true},
  138. {`server.disk[0]["medium"] == "hdd"`, true},
  139. {`server["disk"][0]["medium"] == "hdd"`, true},
  140. {`server.disk[0].medium.in(server.disk.medium)`, true},
  141. {`server.disk.len() == 4`, true},
  142. {`server.disk[0].len() == 2`, true},
  143. {`server.disk[0].backend.len() == 5`, true},
  144. {`server.disk[0].backend.substr(1) == "l"`, true},
  145. {`server.disk[0].backend.substr(0, 1) == "l"`, true},
  146. {`server.disk[0].backend.substr(1, 2) == "o"`, true},
  147. {`server.disk[0].backend.substr(1, -2) == "oc"`, true},
  148. }
  149. for _, c := range cases {
  150. result, err := EvalBool(c.in, input)
  151. if err != nil {
  152. t.Errorf("eval expr %s error %s", c.in, err)
  153. return
  154. }
  155. if result != c.want {
  156. t.Errorf("%s expect %v got %v", c.in, c.want, result)
  157. return
  158. }
  159. }
  160. }
  161. func TestEvalString(t *testing.T) {
  162. input := jsonutils.NewDict()
  163. input.Add(jsonutils.NewString("myname"), "name")
  164. input.Add(jsonutils.NewString("myhostname"), "host", "name")
  165. input.Add(jsonutils.NewString("myproject"), "project", "name")
  166. input.Add(jsonutils.NewString("myprojectId"), "project", "id")
  167. cases := []struct {
  168. input string
  169. want string
  170. }{
  171. {
  172. input: "host.name",
  173. want: "myhostname",
  174. },
  175. {
  176. input: "project.id",
  177. want: "myprojectId",
  178. },
  179. {
  180. input: "project.name",
  181. want: "myproject",
  182. },
  183. {
  184. input: "name",
  185. want: "myname",
  186. },
  187. {
  188. input: `name+"/"+project.name`,
  189. want: "myname/myproject",
  190. },
  191. }
  192. for _, c := range cases {
  193. got, err := EvalString(c.input, input)
  194. if err != nil {
  195. t.Errorf("Eval %s fail: %s", c.input, err)
  196. } else if got != c.want {
  197. t.Errorf("Eval %s want %s got %s", c.input, c.want, got)
  198. }
  199. }
  200. }