github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/controller/pkg/urisearch/urisearch_test.go (about) 1 // +build !windows 2 3 package urisearch 4 5 import ( 6 "testing" 7 8 . "github.com/smartystreets/goconvey/convey" 9 "go.aporeto.io/enforcerd/trireme-lib/policy" 10 ) 11 12 func initTrieRules() []*policy.HTTPRule { 13 14 return []*policy.HTTPRule{ 15 { 16 Methods: []string{"GET", "PUT"}, 17 URIs: []string{ 18 "/users/?/name", 19 "/things/?", 20 }, 21 ClaimMatchingRules: [][]string{{"policy1"}}, 22 }, 23 { 24 Methods: []string{"PATCH"}, 25 URIs: []string{ 26 "/users/?/name", 27 "/things/?", 28 }, 29 ClaimMatchingRules: [][]string{{"policy2"}}, 30 }, 31 { 32 Methods: []string{"POST"}, 33 URIs: []string{ 34 "/v1/users/?/name", 35 "/v1/things/?", 36 }, 37 Public: true, 38 ClaimMatchingRules: [][]string{{"policy3"}}, 39 }, 40 { 41 Methods: []string{"POST"}, 42 URIs: []string{"/"}, 43 ClaimMatchingRules: [][]string{{"policy4"}}, 44 }, 45 { 46 Methods: []string{"PATCH"}, 47 URIs: []string{"/?"}, 48 ClaimMatchingRules: [][]string{{"policy5"}}, 49 }, 50 { 51 Methods: []string{"HEAD"}, 52 URIs: []string{"/*"}, 53 ClaimMatchingRules: [][]string{{"policy7"}}, 54 }, 55 { 56 Methods: []string{"HEAD"}, 57 URIs: []string{"/a/?/c/d"}, 58 ClaimMatchingRules: [][]string{{"policy8"}}, 59 }, 60 { 61 Methods: []string{"HEAD"}, 62 URIs: []string{"/a/b/?/e"}, 63 ClaimMatchingRules: [][]string{{"policy9"}}, 64 }, 65 { 66 Methods: []string{"HEAD"}, 67 URIs: []string{"/a/*/c/x"}, 68 ClaimMatchingRules: [][]string{{"policy10"}}, 69 }, 70 { 71 Methods: []string{"HEAD"}, 72 URIs: []string{"/a/b/?/w"}, 73 ClaimMatchingRules: [][]string{{"policy11"}}, 74 }, 75 { 76 Methods: []string{"HEAD"}, 77 URIs: []string{"/a/b/?/y/*"}, 78 ClaimMatchingRules: [][]string{{"policy12"}, {"policy13"}, {"policy14", "policy15"}}, 79 }, 80 } 81 } 82 83 func TestNewAPICache(t *testing.T) { 84 Convey("Given a set of valid rules", t, func() { 85 rules := initTrieRules() 86 87 Convey("When I insert them in the cache, I should get a valid cache", func() { 88 c := NewAPICache(rules, "id", false) 89 So(c, ShouldNotBeNil) 90 So(c.methodRoots, ShouldNotBeNil) 91 So(len(c.methodRoots), ShouldEqual, 5) 92 So(c.methodRoots, ShouldContainKey, "GET") 93 So(c.methodRoots, ShouldContainKey, "POST") 94 So(c.methodRoots, ShouldContainKey, "PUT") 95 So(c.methodRoots, ShouldContainKey, "PATCH") 96 So(c.methodRoots, ShouldContainKey, "HEAD") 97 So(c.methodRoots["GET"], ShouldNotBeNil) 98 So(c.methodRoots["POST"], ShouldNotBeNil) 99 So(c.methodRoots["PUT"], ShouldNotBeNil) 100 So(c.methodRoots["PATCH"], ShouldNotBeNil) 101 So(c.methodRoots["POST"].data, ShouldNotBeNil) 102 So(len(c.methodRoots["GET"].children), ShouldEqual, 2) 103 }) 104 }) 105 } 106 107 func TestInsert(t *testing.T) { 108 109 Convey("When I insert a root node, it should succeed", t, func() { 110 n := &node{} 111 insert(n, "/", "data") 112 So(n.data.(string), ShouldResemble, "data") 113 So(n.leaf, ShouldBeTrue) 114 }) 115 116 Convey("When I insert a one level node, it should succeed", t, func() { 117 n := &node{} 118 insert(n, "/a", "data") 119 So(n.leaf, ShouldEqual, false) 120 So(len(n.children), ShouldEqual, 1) 121 So(n.children["/a"], ShouldNotBeNil) 122 So(n.children["/a"].leaf, ShouldBeTrue) 123 So(n.children["/a"].data.(string), ShouldResemble, "data") 124 }) 125 126 Convey("When I insert two level node, it should succeed", t, func() { 127 n := &node{} 128 insert(n, "/a/b", "data") 129 So(n.leaf, ShouldEqual, false) 130 So(len(n.children), ShouldEqual, 1) 131 So(n.children["/a"], ShouldNotBeNil) 132 So(n.children["/a"].leaf, ShouldBeFalse) 133 So(n.children["/a"].children["/b"], ShouldNotBeNil) 134 So(n.children["/a"].children["/b"].leaf, ShouldBeTrue) 135 }) 136 137 Convey("When I insert two level node with a * it should succeed", t, func() { 138 n := &node{} 139 insert(n, "/a/*", "data") 140 So(n.leaf, ShouldEqual, false) 141 So(len(n.children), ShouldEqual, 1) 142 So(n.children["/a"], ShouldNotBeNil) 143 So(n.children["/a"].leaf, ShouldBeFalse) 144 So(n.children["/a"].children["/*"], ShouldNotBeNil) 145 So(n.children["/a"].children["/*"].leaf, ShouldBeTrue) 146 }) 147 148 Convey("When I insert a two level node, where the first part is * it should succeed", t, func() { 149 n := &node{} 150 insert(n, "/*/a", "data") 151 So(n.leaf, ShouldEqual, false) 152 So(len(n.children), ShouldEqual, 1) 153 So(n.children["/*"], ShouldNotBeNil) 154 So(n.children["/*"].leaf, ShouldBeFalse) 155 So(n.children["/*"].children["/a"], ShouldNotBeNil) 156 So(n.children["/*"].children["/a"].leaf, ShouldBeTrue) 157 }) 158 159 } 160 161 func TestParse(t *testing.T) { 162 Convey("When I parse a root URI, I should get no suffix", t, func() { 163 prefix, suffix := parse("/") 164 So(prefix, ShouldEqual, "/") 165 So(suffix, ShouldEqual, "") 166 }) 167 168 Convey("When I parse non root URIs with one level", t, func() { 169 prefix, suffix := parse("/a") 170 So(prefix, ShouldEqual, "/a") 171 So(suffix, ShouldEqual, "") 172 }) 173 174 Convey("When I parse non root URIs with two levels, I should get the right suffix", t, func() { 175 prefix, suffix := parse("/a/b") 176 So(prefix, ShouldEqual, "/a") 177 So(suffix, ShouldEqual, "/b") 178 }) 179 180 Convey("When I parse non root URIs with three levels, I should get the right suffix", t, func() { 181 prefix, suffix := parse("/a/b/c") 182 So(prefix, ShouldEqual, "/a") 183 So(suffix, ShouldEqual, "/b/c") 184 }) 185 186 Convey("When I parse non root URIs with a *, I should get * as suffix", t, func() { 187 prefix, suffix := parse("/a/*") 188 So(prefix, ShouldEqual, "/a") 189 So(suffix, ShouldEqual, "/*") 190 }) 191 } 192 193 func TestAPICacheFind(t *testing.T) { 194 Convey("Given valid API cache", t, func() { 195 c := NewAPICache(initTrieRules(), "id", false) 196 Convey("When I search for correct URIs, I should get the right data", func() { 197 198 // GET and PUT combined rule 199 found, rule := c.FindRule("GET", "/users/bob/name") 200 So(found, ShouldBeTrue) 201 So(rule, ShouldNotBeNil) 202 So(rule.ClaimMatchingRules, ShouldContain, []string{"policy1"}) 203 204 found, rule = c.FindRule("BADVERB", "/users/bob/name") 205 So(found, ShouldBeFalse) 206 So(rule, ShouldBeNil) 207 208 found, rule = c.FindRule("PUT", "/users/bob/name") 209 So(found, ShouldBeTrue) 210 So(rule, ShouldNotBeNil) 211 So(rule.ClaimMatchingRules, ShouldContain, []string{"policy1"}) 212 213 found, rule = c.FindRule("GET", "/things/something") 214 So(found, ShouldBeTrue) 215 So(rule, ShouldNotBeNil) 216 So(rule.ClaimMatchingRules, ShouldContain, []string{"policy1"}) 217 218 found, rule = c.FindRule("GET", "/prefix/things/something") 219 So(found, ShouldBeFalse) 220 So(rule, ShouldBeNil) 221 222 // PATCH rule 223 found, rule = c.FindRule("PATCH", "/things/something") 224 So(found, ShouldBeTrue) 225 So(rule, ShouldNotBeNil) 226 So(rule.ClaimMatchingRules, ShouldContain, []string{"policy2"}) 227 228 found, rule = c.FindRule("PATCH", "/users/bob/name") 229 So(found, ShouldBeTrue) 230 So(rule, ShouldNotBeNil) 231 So(rule.ClaimMatchingRules, ShouldContain, []string{"policy2"}) 232 233 // POST rule 234 found, rule = c.FindRule("POST", "/v1/users/123/name") 235 So(found, ShouldBeTrue) 236 So(rule, ShouldNotBeNil) 237 So(rule.ClaimMatchingRules, ShouldContain, []string{"policy3"}) 238 239 found, rule = c.FindRule("POST", "/v1/things/123454656") 240 So(found, ShouldBeTrue) 241 So(rule, ShouldNotBeNil) 242 So(rule.ClaimMatchingRules, ShouldContain, []string{"policy3"}) 243 244 found, rule = c.FindRule("POST", "/") 245 So(found, ShouldBeTrue) 246 So(rule, ShouldNotBeNil) 247 So(rule.ClaimMatchingRules, ShouldContain, []string{"policy4"}) 248 249 // HEAD Rules 250 found, rule = c.FindRule("HEAD", "/users/123/name") 251 So(found, ShouldBeTrue) 252 So(rule, ShouldNotBeNil) 253 254 found, rule = c.FindRule("PATCH", "/users/123/name") 255 So(found, ShouldBeTrue) 256 So(rule, ShouldNotBeNil) 257 So(rule.ClaimMatchingRules, ShouldContain, []string{"policy2"}) 258 259 found, rule = c.FindRule("HEAD", "/a/b/c/d") 260 So(found, ShouldBeTrue) 261 So(rule, ShouldNotBeNil) 262 So(rule.ClaimMatchingRules, ShouldContain, []string{"policy8"}) 263 264 found, rule = c.FindRule("HEAD", "/a/x/c/d") 265 So(found, ShouldBeTrue) 266 So(rule, ShouldNotBeNil) 267 So(rule.ClaimMatchingRules, ShouldContain, []string{"policy8"}) 268 269 found, rule = c.FindRule("HEAD", "/a/b/x/e") 270 So(found, ShouldBeTrue) 271 So(rule, ShouldNotBeNil) 272 So(rule.ClaimMatchingRules, ShouldContain, []string{"policy9"}) 273 274 found, rule = c.FindRule("HEAD", "/a/b/x") 275 So(found, ShouldBeTrue) 276 So(rule, ShouldNotBeNil) 277 278 found, rule = c.FindRule("HEAD", "/a/b/c/d/e/c/x") 279 So(found, ShouldBeTrue) 280 So(rule, ShouldNotBeNil) 281 So(rule.ClaimMatchingRules, ShouldContain, []string{"policy10"}) 282 283 found, rule = c.FindRule("HEAD", "/a/b/c/w") 284 So(found, ShouldBeTrue) 285 So(rule, ShouldNotBeNil) 286 So(rule.ClaimMatchingRules, ShouldContain, []string{"policy11"}) 287 288 found, rule = c.FindRule("HEAD", "/a/b/c/z") 289 So(found, ShouldBeTrue) 290 So(rule, ShouldNotBeNil) 291 So(rule.ClaimMatchingRules, ShouldContain, []string{"policy7"}) 292 293 found, rule = c.FindRule("HEAD", "/a/b/c/d/e/f/w") 294 So(found, ShouldBeTrue) 295 So(rule, ShouldNotBeNil) 296 So(rule.ClaimMatchingRules, ShouldContain, []string{"policy7"}) 297 298 found, rule = c.FindRule("HEAD", "/a/b/c/y/d/e/f/g/g") 299 So(found, ShouldBeTrue) 300 So(rule, ShouldNotBeNil) 301 So(rule.ClaimMatchingRules, ShouldContain, []string{"policy12"}) 302 }) 303 304 Convey("When I search for bad URIs, I should get not found", func() { 305 found, _ := c.Find("GET", "/users/123/name/targets") 306 So(found, ShouldBeFalse) 307 found, _ = c.Find("PUT", "/users/name") 308 So(found, ShouldBeFalse) 309 found, _ = c.Find("GET", "/v1/things/123") 310 So(found, ShouldBeFalse) 311 found, _ = c.Find("GET", "/v1/v2/v3/v54/12312312/12321312/123123") 312 So(found, ShouldBeFalse) 313 found, _ = c.Find("GET", "/someapi") 314 So(found, ShouldBeFalse) 315 found, _ = c.Find("GET", "/") 316 So(found, ShouldBeFalse) 317 }) 318 319 Convey("Test performacen", func() { 320 for i := 0; i < 10000; i++ { 321 found, _ := c.Find("GET", "/users/123/name") 322 So(found, ShouldBeTrue) 323 } 324 }) 325 }) 326 } 327 328 func TestFindAndMachScope(t *testing.T) { 329 Convey("Given a valid API cache", t, func() { 330 c := NewAPICache(initTrieRules(), "id", false) 331 332 Convey("When I search for rules matching scopes, it should return true", func() { 333 found, _ := c.FindAndMatchScope("GET", "/users/bob/name", []string{"policy1"}) 334 So(found, ShouldBeTrue) 335 }) 336 337 Convey("When I search for an invalid URI, it should return false", func() { 338 found, _ := c.FindAndMatchScope("GET", "/this/doesnot/exist", []string{"policy1"}) 339 So(found, ShouldBeFalse) 340 }) 341 342 Convey("When I search for a valid URI and not matching scopes, it should return false", func() { 343 found, _ := c.FindAndMatchScope("GET", "/users/bob/name", []string{"policy10"}) 344 So(found, ShouldBeFalse) 345 }) 346 347 Convey("When I search for public rule and bad scopes it should always return true", func() { 348 found, _ := c.FindAndMatchScope("POST", "/v1/things/something", []string{"policy10"}) 349 So(found, ShouldBeTrue) 350 }) 351 352 Convey("When I search for public rule and good scopes it should always return true", func() { 353 found, _ := c.FindAndMatchScope("POST", "/v1/things/something", []string{"policy3"}) 354 So(found, ShouldBeTrue) 355 }) 356 357 Convey("When I search for public rule and multiple scopes in an array it should always return true", func() { 358 found, _ := c.FindAndMatchScope("HEAD", "/a/b/c/y/z", []string{"policy12", "policy13"}) 359 So(found, ShouldBeTrue) 360 }) 361 362 Convey("When I search for public rule and need to match the right and clause it should return true", func() { 363 found, _ := c.FindAndMatchScope("HEAD", "/a/b/c/y/z", []string{"policy14", "policy15"}) 364 So(found, ShouldBeTrue) 365 }) 366 367 Convey("When I search for public rule at the and clause fails, it should return false", func() { 368 found, _ := c.FindAndMatchScope("HEAD", "/a/b/c/y/z", []string{"policy1", "policy15"}) 369 So(found, ShouldBeFalse) 370 }) 371 372 Convey("When I search for public rule at the and clause fails with several labels, but it matched it should return true", func() { 373 found, _ := c.FindAndMatchScope("HEAD", "/a/b/c/y/z", []string{"x", "y", "z", "policy14", "a", "b", "c", "policy15", "k", "l", "m"}) 374 So(found, ShouldBeTrue) 375 }) 376 }) 377 }