exprlib_test.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. package exprhelpers
  2. import (
  3. "fmt"
  4. log "github.com/sirupsen/logrus"
  5. "testing"
  6. "github.com/antonmedv/expr"
  7. "github.com/stretchr/testify/assert"
  8. "github.com/stretchr/testify/require"
  9. )
  10. var (
  11. TestFolder = "tests"
  12. )
  13. func TestVisitor(t *testing.T) {
  14. if err := Init(); err != nil {
  15. log.Fatalf(err.Error())
  16. }
  17. tests := []struct {
  18. name string
  19. filter string
  20. result bool
  21. env map[string]interface{}
  22. err error
  23. }{
  24. {
  25. name: "debug : no variable",
  26. filter: "'crowdsec' startsWith 'crowdse'",
  27. result: true,
  28. err: nil,
  29. env: map[string]interface{}{},
  30. },
  31. {
  32. name: "debug : simple variable",
  33. filter: "'crowdsec' startsWith static_one && 1 == 1",
  34. result: true,
  35. err: nil,
  36. env: map[string]interface{}{"static_one": string("crowdse")},
  37. },
  38. {
  39. name: "debug : simple variable re-used",
  40. filter: "static_one.foo == 'bar' && static_one.foo != 'toto'",
  41. result: true,
  42. err: nil,
  43. env: map[string]interface{}{"static_one": map[string]string{"foo": "bar"}},
  44. },
  45. {
  46. name: "debug : can't compile",
  47. filter: "static_one.foo.toto == 'lol'",
  48. result: false,
  49. err: fmt.Errorf("bad syntax"),
  50. env: map[string]interface{}{"static_one": map[string]string{"foo": "bar"}},
  51. },
  52. {
  53. name: "debug : can't compile #2",
  54. filter: "static_one.f!oo.to/to == 'lol'",
  55. result: false,
  56. err: fmt.Errorf("bad syntax"),
  57. env: map[string]interface{}{"static_one": map[string]string{"foo": "bar"}},
  58. },
  59. {
  60. name: "debug : can't compile #3",
  61. filter: "",
  62. result: false,
  63. err: fmt.Errorf("bad syntax"),
  64. env: map[string]interface{}{"static_one": map[string]string{"foo": "bar"}},
  65. },
  66. }
  67. log.SetLevel(log.DebugLevel)
  68. clog := log.WithFields(log.Fields{
  69. "type": "test",
  70. })
  71. for _, test := range tests {
  72. compiledFilter, err := expr.Compile(test.filter, expr.Env(GetExprEnv(test.env)))
  73. if err != nil && test.err == nil {
  74. log.Fatalf("compile: %s", err.Error())
  75. }
  76. debugFilter, err := NewDebugger(test.filter, expr.Env(GetExprEnv(test.env)))
  77. if err != nil && test.err == nil {
  78. log.Fatalf("debug: %s", err.Error())
  79. }
  80. if compiledFilter != nil {
  81. result, err := expr.Run(compiledFilter, GetExprEnv(test.env))
  82. if err != nil && test.err == nil {
  83. log.Fatalf("run : %s", err.Error())
  84. }
  85. if isOk := assert.Equal(t, test.result, result); !isOk {
  86. t.Fatalf("test '%s' : NOK", test.filter)
  87. }
  88. }
  89. if debugFilter != nil {
  90. debugFilter.Run(clog, test.result, GetExprEnv(test.env))
  91. }
  92. }
  93. }
  94. func TestRegexpInFile(t *testing.T) {
  95. if err := Init(); err != nil {
  96. log.Fatalf(err.Error())
  97. }
  98. err := FileInit(TestFolder, "test_data_re.txt", "regex")
  99. if err != nil {
  100. log.Fatalf(err.Error())
  101. }
  102. tests := []struct {
  103. name string
  104. filter string
  105. result bool
  106. err error
  107. }{
  108. {
  109. name: "RegexpInFile() test: lower case word in data file",
  110. filter: "RegexpInFile('crowdsec', 'test_data_re.txt')",
  111. result: false,
  112. err: nil,
  113. },
  114. {
  115. name: "RegexpInFile() test: Match exactly",
  116. filter: "RegexpInFile('Crowdsec', 'test_data_re.txt')",
  117. result: true,
  118. err: nil,
  119. },
  120. {
  121. name: "RegexpInFile() test: match with word before",
  122. filter: "RegexpInFile('test Crowdsec', 'test_data_re.txt')",
  123. result: true,
  124. err: nil,
  125. },
  126. {
  127. name: "RegexpInFile() test: match with word before and other case",
  128. filter: "RegexpInFile('test CrowdSec', 'test_data_re.txt')",
  129. result: true,
  130. err: nil,
  131. },
  132. }
  133. for _, test := range tests {
  134. compiledFilter, err := expr.Compile(test.filter, expr.Env(GetExprEnv(map[string]interface{}{})))
  135. if err != nil {
  136. log.Fatalf(err.Error())
  137. }
  138. result, err := expr.Run(compiledFilter, GetExprEnv(map[string]interface{}{}))
  139. if err != nil {
  140. log.Fatalf(err.Error())
  141. }
  142. if isOk := assert.Equal(t, test.result, result); !isOk {
  143. t.Fatalf("test '%s' : NOK", test.name)
  144. }
  145. }
  146. }
  147. func TestFileInit(t *testing.T) {
  148. if err := Init(); err != nil {
  149. log.Fatalf(err.Error())
  150. }
  151. tests := []struct {
  152. name string
  153. filename string
  154. types string
  155. result int
  156. err error
  157. }{
  158. {
  159. name: "file with type:string",
  160. filename: "test_data.txt",
  161. types: "string",
  162. result: 3,
  163. },
  164. {
  165. name: "file with type:re",
  166. filename: "test_data_re.txt",
  167. types: "regex",
  168. result: 2,
  169. },
  170. {
  171. name: "file without type",
  172. filename: "test_data_no_type.txt",
  173. types: "",
  174. },
  175. }
  176. for _, test := range tests {
  177. err := FileInit(TestFolder, test.filename, test.types)
  178. if err != nil {
  179. log.Fatalf(err.Error())
  180. }
  181. if test.types == "string" {
  182. if _, ok := dataFile[test.filename]; !ok {
  183. t.Fatalf("test '%s' : NOK", test.name)
  184. }
  185. if isOk := assert.Equal(t, test.result, len(dataFile[test.filename])); !isOk {
  186. t.Fatalf("test '%s' : NOK", test.name)
  187. }
  188. } else if test.types == "regex" {
  189. if _, ok := dataFileRegex[test.filename]; !ok {
  190. t.Fatalf("test '%s' : NOK", test.name)
  191. }
  192. if isOk := assert.Equal(t, test.result, len(dataFileRegex[test.filename])); !isOk {
  193. t.Fatalf("test '%s' : NOK", test.name)
  194. }
  195. } else {
  196. if _, ok := dataFileRegex[test.filename]; ok {
  197. t.Fatalf("test '%s' : NOK", test.name)
  198. }
  199. if _, ok := dataFile[test.filename]; ok {
  200. t.Fatalf("test '%s' : NOK", test.name)
  201. }
  202. }
  203. log.Printf("test '%s' : OK", test.name)
  204. }
  205. }
  206. func TestFile(t *testing.T) {
  207. if err := Init(); err != nil {
  208. log.Fatalf(err.Error())
  209. }
  210. err := FileInit(TestFolder, "test_data.txt", "string")
  211. if err != nil {
  212. log.Fatalf(err.Error())
  213. }
  214. tests := []struct {
  215. name string
  216. filter string
  217. result bool
  218. err error
  219. }{
  220. {
  221. name: "File() test: word in file",
  222. filter: "'Crowdsec' in File('test_data.txt')",
  223. result: true,
  224. err: nil,
  225. },
  226. {
  227. name: "File() test: word in file but different case",
  228. filter: "'CrowdSecurity' in File('test_data.txt')",
  229. result: false,
  230. err: nil,
  231. },
  232. {
  233. name: "File() test: word not in file",
  234. filter: "'test' in File('test_data.txt')",
  235. result: false,
  236. err: nil,
  237. },
  238. {
  239. name: "File() test: filepath provided doesn't exist",
  240. filter: "'test' in File('non_existing_data.txt')",
  241. result: false,
  242. err: nil,
  243. },
  244. }
  245. for _, test := range tests {
  246. compiledFilter, err := expr.Compile(test.filter, expr.Env(GetExprEnv(map[string]interface{}{})))
  247. if err != nil {
  248. log.Fatalf(err.Error())
  249. }
  250. result, err := expr.Run(compiledFilter, GetExprEnv(map[string]interface{}{}))
  251. if err != nil {
  252. log.Fatalf(err.Error())
  253. }
  254. if isOk := assert.Equal(t, test.result, result); !isOk {
  255. t.Fatalf("test '%s' : NOK", test.name)
  256. }
  257. log.Printf("test '%s' : OK", test.name)
  258. }
  259. }
  260. func TestIpInRange(t *testing.T) {
  261. tests := []struct {
  262. name string
  263. env map[string]interface{}
  264. code string
  265. result bool
  266. err string
  267. }{
  268. {
  269. name: "IpInRange() test: basic test",
  270. env: map[string]interface{}{
  271. "ip": "192.168.0.1",
  272. "ipRange": "192.168.0.0/24",
  273. "IpInRange": IpInRange,
  274. },
  275. code: "IpInRange(ip, ipRange)",
  276. result: true,
  277. err: "",
  278. },
  279. {
  280. name: "IpInRange() test: malformed IP",
  281. env: map[string]interface{}{
  282. "ip": "192.168.0",
  283. "ipRange": "192.168.0.0/24",
  284. "IpInRange": IpInRange,
  285. },
  286. code: "IpInRange(ip, ipRange)",
  287. result: false,
  288. err: "",
  289. },
  290. {
  291. name: "IpInRange() test: malformed IP range",
  292. env: map[string]interface{}{
  293. "ip": "192.168.0.0/255",
  294. "ipRange": "192.168.0.0/24",
  295. "IpInRange": IpInRange,
  296. },
  297. code: "IpInRange(ip, ipRange)",
  298. result: false,
  299. err: "",
  300. },
  301. }
  302. for _, test := range tests {
  303. program, err := expr.Compile(test.code, expr.Env(test.env))
  304. require.NoError(t, err)
  305. output, err := expr.Run(program, test.env)
  306. require.NoError(t, err)
  307. require.Equal(t, test.result, output)
  308. log.Printf("test '%s' : OK", test.name)
  309. }
  310. }
  311. func TestAtof(t *testing.T) {
  312. testFloat := "1.5"
  313. expectedFloat := 1.5
  314. if Atof(testFloat) != expectedFloat {
  315. t.Fatalf("Atof should returned 1.5 as a float")
  316. }
  317. log.Printf("test 'Atof()' : OK")
  318. //bad float
  319. testFloat = "1aaa.5"
  320. expectedFloat = 0.0
  321. if Atof(testFloat) != expectedFloat {
  322. t.Fatalf("Atof should returned a negative value (error) as a float got")
  323. }
  324. log.Printf("test 'Atof()' : OK")
  325. }
  326. func TestUpper(t *testing.T) {
  327. testStr := "test"
  328. expectedStr := "TEST"
  329. if Upper(testStr) != expectedStr {
  330. t.Fatalf("Upper() should returned 1.5 as a float")
  331. }
  332. log.Printf("test 'Upper()' : OK")
  333. }