3
0

More tests

This commit is contained in:
Tomaž Jerman 2024-11-29 11:59:56 +01:00
parent 69dbfa9f66
commit 1e79cd1d46
2 changed files with 39 additions and 188 deletions

View File

@ -34,6 +34,7 @@ func buildRuleIndex(rules []*Rule) (index *ruleIndex) {
return index
}
// add adds a new Rule to the index
func (index *ruleIndex) add(rules ...*Rule) {
if index.children == nil {
index.children = make(map[uint64]*ruleIndexNode, len(rules)/2)
@ -71,62 +72,12 @@ func (index *ruleIndex) add(rules ...*Rule) {
}
}
func (index *ruleIndex) remove(role uint64, resource string, ops ...string) {
if _, ok := index.children[role]; !ok {
return
}
auxOps := ops
if len(auxOps) == 0 {
for op := range index.children[role].children {
auxOps = append(auxOps, op)
}
}
for _, op := range auxOps {
bits := append([]string{op}, strings.Split(resource, "/")...)
index.removeRec(index.children[role], bits)
// Finishing touch cleanup
if len(index.children[role].children[op].children) == 0 {
delete(index.children[role].children, op)
}
if len(index.children[role].children) == 0 {
delete(index.children, role)
}
}
}
func (index *ruleIndex) removeRec(n *ruleIndexNode, bits []string) {
// Recursive in; decrement counters
n.count--
if len(bits) == 0 {
return
}
n = n.children[bits[0]]
index.removeRec(n, bits[1:])
// Recursive out; yoink out obsolete štuff
if len(bits) == 1 {
if len(n.children) > 0 {
n.children[bits[0]].isLeaf = false
n.children[bits[0]].rule = nil
}
return
}
if n.children[bits[1]].count == 0 {
delete(n.children, bits[1])
}
}
// has checks if the rule is already in there
func (t *ruleIndex) has(r *Rule) bool {
return len(t.collect(true, r.RoleID, r.Operation, r.Resource)) > 0
}
// get returns the matching rules
func (t *ruleIndex) get(role uint64, op, res string) (out []*Rule) {
return t.collect(false, role, op, res)
}

View File

@ -9,11 +9,10 @@ import (
func TestIndexBuild(t *testing.T) {
tcc := []struct {
name string
in []*Rule
remove []*Rule
add []*Rule
out []int
name string
in []*Rule
add []*Rule
out []int
role uint64
op string
@ -120,126 +119,6 @@ func TestIndexBuild(t *testing.T) {
role: 1,
op: "read",
res: "a:b/c/d",
}, {
name: "removing the only element",
in: []*Rule{{
RoleID: 1,
Resource: "a:b/c/d",
Operation: "write",
Access: Allow,
}},
remove: []*Rule{{
RoleID: 1,
Resource: "a:b/c/d",
Operation: "write",
Access: Allow,
}},
out: nil,
role: 1,
op: "write",
res: "a:b/c/d",
},
{
name: "removing twice added thing",
in: []*Rule{{
RoleID: 1,
Resource: "a:b/c/d",
Operation: "write",
Access: Allow,
}, {
RoleID: 1,
Resource: "a:b/c/d",
Operation: "write",
Access: Allow,
}},
remove: []*Rule{{
RoleID: 1,
Resource: "a:b/c/d",
Operation: "write",
Access: Allow,
}},
out: nil,
role: 1,
op: "write",
res: "a:b/c/d",
},
{
name: "two elements with no common root",
in: []*Rule{{
RoleID: 1,
Resource: "a:b/c/d",
Operation: "write",
Access: Allow,
}, {
RoleID: 2,
Resource: "a:b/c/d",
Operation: "write",
Access: Allow,
}},
remove: []*Rule{{
RoleID: 1,
Resource: "a:b/c/d",
Operation: "write",
Access: Allow,
}},
out: nil,
role: 1,
op: "write",
res: "a:b/c/d",
},
{
name: "two elements with common root (get removed)",
in: []*Rule{{
RoleID: 1,
Resource: "a:b/c/d",
Operation: "write",
Access: Allow,
}, {
RoleID: 1,
Resource: "a:b/c/e",
Operation: "write",
Access: Allow,
}},
remove: []*Rule{{
RoleID: 1,
Resource: "a:b/c/d",
Operation: "write",
Access: Allow,
}},
out: nil,
role: 1,
op: "write",
res: "a:b/c/d",
},
{
name: "two elements with common root (get not removed)",
in: []*Rule{{
RoleID: 1,
Resource: "a:b/c/d",
Operation: "write",
Access: Allow,
}, {
RoleID: 1,
Resource: "a:b/c/e",
Operation: "write",
Access: Allow,
}},
remove: []*Rule{{
RoleID: 1,
Resource: "a:b/c/d",
Operation: "write",
Access: Allow,
}},
out: []int{1},
role: 1,
op: "write",
res: "a:b/c/e",
},
{
name: "add new element",
@ -266,13 +145,12 @@ func TestIndexBuild(t *testing.T) {
for _, tc := range tcc {
t.Run(tc.name, func(t *testing.T) {
ix := buildRuleIndex(tc.in)
ix.remove(tc.remove...)
ix.add(tc.add...)
out := RuleSet(ix.get(tc.role, tc.op, tc.res))
sort.Sort(out)
want := RuleSet(graby(append(tc.in, tc.add...), tc.out))
want := RuleSet(grabIndexMatches(append(tc.in, tc.add...), tc.out))
sort.Sort(want)
require.Len(t, out, len(want))
@ -281,10 +159,32 @@ func TestIndexBuild(t *testing.T) {
}
})
}
}
func graby(rr []*Rule, want []int) (out []*Rule) {
func TestIndexHas(t *testing.T) {
ix := buildRuleIndex([]*Rule{{
RoleID: 1,
Resource: "a:b/c/x",
Operation: "write",
Access: Allow,
}})
require.True(t, ix.has(&Rule{
RoleID: 1,
Resource: "a:b/c/x",
Operation: "write",
Access: Allow,
}))
require.False(t, ix.has(&Rule{
RoleID: 2,
Resource: "a:b/c/x",
Operation: "write",
Access: Allow,
}))
}
func grabIndexMatches(rr []*Rule, want []int) (out []*Rule) {
out = make([]*Rule, 0, len(want))
for _, w := range want {
@ -294,14 +194,14 @@ func graby(rr []*Rule, want []int) (out []*Rule) {
return
}
// goos: linux
// goarch: amd64
// goos: darwin
// goarch: arm64
// pkg: github.com/cortezaproject/corteza/server/pkg/rbac
// cpu: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
// BenchmarkIndexBuild_100-12 10000 102361 ns/op 88064 B/op 1271 allocs/op
// BenchmarkIndexBuild_1000-12 1149 1024872 ns/op 755375 B/op 11183 allocs/op
// BenchmarkIndexBuild_10000-12 128 8986248 ns/op 4406477 B/op 82453 allocs/op
// BenchmarkIndexBuild_100000-12 14 81871407 ns/op 20627785 B/op 543568 allocs/op
// cpu: Apple M3 Pro
// BenchmarkIndexBuild_100-12 26077 43467 ns/op 94785 B/op 1119 allocs/op
// BenchmarkIndexBuild_1000-12 2316 505664 ns/op 939447 B/op 10219 allocs/op
// BenchmarkIndexBuild_10000-12 228 5301265 ns/op 9008425 B/op 98033 allocs/op
// BenchmarkIndexBuild_100000-12 19 68454059 ns/op 70832448 B/op 843270 allocs/op
func benchmarkIndexBuild(b *testing.B, rules []*Rule) {
b.ResetTimer()