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  }