exprlib_test.go 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  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:string and empty lines + commentaries",
  166. filename: "test_empty_line.txt",
  167. types: "string",
  168. result: 3,
  169. },
  170. {
  171. name: "file with type:re",
  172. filename: "test_data_re.txt",
  173. types: "regex",
  174. result: 2,
  175. },
  176. {
  177. name: "file without type",
  178. filename: "test_data_no_type.txt",
  179. types: "",
  180. },
  181. }
  182. for _, test := range tests {
  183. err := FileInit(TestFolder, test.filename, test.types)
  184. if err != nil {
  185. log.Fatalf(err.Error())
  186. }
  187. if test.types == "string" {
  188. if _, ok := dataFile[test.filename]; !ok {
  189. t.Fatalf("test '%s' : NOK", test.name)
  190. }
  191. if isOk := assert.Equal(t, test.result, len(dataFile[test.filename])); !isOk {
  192. t.Fatalf("test '%s' : NOK", test.name)
  193. }
  194. } else if test.types == "regex" {
  195. if _, ok := dataFileRegex[test.filename]; !ok {
  196. t.Fatalf("test '%s' : NOK", test.name)
  197. }
  198. if isOk := assert.Equal(t, test.result, len(dataFileRegex[test.filename])); !isOk {
  199. t.Fatalf("test '%s' : NOK", test.name)
  200. }
  201. } else {
  202. if _, ok := dataFileRegex[test.filename]; ok {
  203. t.Fatalf("test '%s' : NOK", test.name)
  204. }
  205. if _, ok := dataFile[test.filename]; ok {
  206. t.Fatalf("test '%s' : NOK", test.name)
  207. }
  208. }
  209. log.Printf("test '%s' : OK", test.name)
  210. }
  211. }
  212. func TestFile(t *testing.T) {
  213. if err := Init(); err != nil {
  214. log.Fatalf(err.Error())
  215. }
  216. err := FileInit(TestFolder, "test_data.txt", "string")
  217. if err != nil {
  218. log.Fatalf(err.Error())
  219. }
  220. tests := []struct {
  221. name string
  222. filter string
  223. result bool
  224. err error
  225. }{
  226. {
  227. name: "File() test: word in file",
  228. filter: "'Crowdsec' in File('test_data.txt')",
  229. result: true,
  230. err: nil,
  231. },
  232. {
  233. name: "File() test: word in file but different case",
  234. filter: "'CrowdSecurity' in File('test_data.txt')",
  235. result: false,
  236. err: nil,
  237. },
  238. {
  239. name: "File() test: word not in file",
  240. filter: "'test' in File('test_data.txt')",
  241. result: false,
  242. err: nil,
  243. },
  244. {
  245. name: "File() test: filepath provided doesn't exist",
  246. filter: "'test' in File('non_existing_data.txt')",
  247. result: false,
  248. err: nil,
  249. },
  250. }
  251. for _, test := range tests {
  252. compiledFilter, err := expr.Compile(test.filter, expr.Env(GetExprEnv(map[string]interface{}{})))
  253. if err != nil {
  254. log.Fatalf(err.Error())
  255. }
  256. result, err := expr.Run(compiledFilter, GetExprEnv(map[string]interface{}{}))
  257. if err != nil {
  258. log.Fatalf(err.Error())
  259. }
  260. if isOk := assert.Equal(t, test.result, result); !isOk {
  261. t.Fatalf("test '%s' : NOK", test.name)
  262. }
  263. log.Printf("test '%s' : OK", test.name)
  264. }
  265. }
  266. func TestIpInRange(t *testing.T) {
  267. tests := []struct {
  268. name string
  269. env map[string]interface{}
  270. code string
  271. result bool
  272. err string
  273. }{
  274. {
  275. name: "IpInRange() test: basic test",
  276. env: map[string]interface{}{
  277. "ip": "192.168.0.1",
  278. "ipRange": "192.168.0.0/24",
  279. "IpInRange": IpInRange,
  280. },
  281. code: "IpInRange(ip, ipRange)",
  282. result: true,
  283. err: "",
  284. },
  285. {
  286. name: "IpInRange() test: malformed IP",
  287. env: map[string]interface{}{
  288. "ip": "192.168.0",
  289. "ipRange": "192.168.0.0/24",
  290. "IpInRange": IpInRange,
  291. },
  292. code: "IpInRange(ip, ipRange)",
  293. result: false,
  294. err: "",
  295. },
  296. {
  297. name: "IpInRange() test: malformed IP range",
  298. env: map[string]interface{}{
  299. "ip": "192.168.0.0/255",
  300. "ipRange": "192.168.0.0/24",
  301. "IpInRange": IpInRange,
  302. },
  303. code: "IpInRange(ip, ipRange)",
  304. result: false,
  305. err: "",
  306. },
  307. }
  308. for _, test := range tests {
  309. program, err := expr.Compile(test.code, expr.Env(test.env))
  310. require.NoError(t, err)
  311. output, err := expr.Run(program, test.env)
  312. require.NoError(t, err)
  313. require.Equal(t, test.result, output)
  314. log.Printf("test '%s' : OK", test.name)
  315. }
  316. }
  317. func TestAtof(t *testing.T) {
  318. testFloat := "1.5"
  319. expectedFloat := 1.5
  320. if Atof(testFloat) != expectedFloat {
  321. t.Fatalf("Atof should returned 1.5 as a float")
  322. }
  323. log.Printf("test 'Atof()' : OK")
  324. //bad float
  325. testFloat = "1aaa.5"
  326. expectedFloat = 0.0
  327. if Atof(testFloat) != expectedFloat {
  328. t.Fatalf("Atof should returned a negative value (error) as a float got")
  329. }
  330. log.Printf("test 'Atof()' : OK")
  331. }
  332. func TestUpper(t *testing.T) {
  333. testStr := "test"
  334. expectedStr := "TEST"
  335. if Upper(testStr) != expectedStr {
  336. t.Fatalf("Upper() should returned 1.5 as a float")
  337. }
  338. log.Printf("test 'Upper()' : OK")
  339. }