Skip to content

Commit

Permalink
add context adapters (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
JunNishimura committed Mar 31, 2024
1 parent e65352f commit 90ca3e2
Show file tree
Hide file tree
Showing 2 changed files with 190 additions and 0 deletions.
81 changes: 81 additions & 0 deletions context_adapter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// this implementation refers to the following link:
// https://github.com/casbin/gorm-adapter/blob/master/context_adapter.go

package casbinbunadapter

import (
"context"

"github.com/casbin/casbin/v2/model"
"github.com/casbin/casbin/v2/persist"
)

var (
// check if the ctxBunAdapter implements the ContextAdapter interface
_ persist.ContextAdapter = (*ctxBunAdapter)(nil) // Ensure ctxBunAdapter
)

type ctxBunAdapter struct {
*bunAdapter
}

func NewCtxAdapter(driverName string, dataSourceName string, opts ...adapterOption) (*ctxBunAdapter, error) {
adapter, err := NewAdapter(driverName, dataSourceName, opts...)
if err != nil {
return nil, err
}
return &ctxBunAdapter{adapter}, nil
}

// executeWithContext is a helper function to execute a function with context and return the result or error.
func executeWithContext(ctx context.Context, fn func() error) error {
done := make(chan error)
go func() {
done <- fn()
}()

select {
case <-ctx.Done():
return ctx.Err()
case err := <-done:
return err
}
}

// LoadPolicyCtx loads all policy rules from the storage with context.
func (a *ctxBunAdapter) LoadPolicyCtx(ctx context.Context, model model.Model) error {
return executeWithContext(ctx, func() error {
return a.LoadPolicy(model)
})
}

// SavePolicyCtx saves all policy rules to the storage with context.
func (a *ctxBunAdapter) SavePolicyCtx(ctx context.Context, model model.Model) error {
return executeWithContext(ctx, func() error {
return a.SavePolicy(model)
})
}

// AddPolicyCtx adds a policy rule to the storage with context.
// This is part of the Auto-Save feature.
func (a *ctxBunAdapter) AddPolicyCtx(ctx context.Context, sec string, ptype string, rule []string) error {
return executeWithContext(ctx, func() error {
return a.AddPolicy(sec, ptype, rule)
})
}

// RemovePolicyCtx removes a policy rule from the storage with context.
// This is part of the Auto-Save feature.
func (a *ctxBunAdapter) RemovePolicyCtx(ctx context.Context, sec string, ptype string, rule []string) error {
return executeWithContext(ctx, func() error {
return a.RemovePolicy(sec, ptype, rule)
})
}

// RemoveFilteredPolicyCtx removes policy rules that match the filter from the storage with context.
// This is part of the Auto-Save feature.
func (a *ctxBunAdapter) RemoveFilteredPolicyCtx(ctx context.Context, sec string, ptype string, fieldIndex int, fieldValues ...string) error {
return executeWithContext(ctx, func() error {
return a.RemoveFilteredPolicy(sec, ptype, fieldIndex, fieldValues...)
})
}
109 changes: 109 additions & 0 deletions context_adapter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package casbinbunadapter

import (
"context"
"testing"
"time"

"github.com/agiledragon/gomonkey/v2"
"github.com/casbin/casbin/v2"
"github.com/stretchr/testify/assert"
)

func mockExecuteWithContextTimeOut(ctx context.Context, fn func() error) error {
done := make(chan error)
go func() {
time.Sleep(500 * time.Microsecond)
done <- fn()
}()

select {
case <-ctx.Done():
return ctx.Err()
case err := <-done:
return err
}
}

func clearDBPolicy() (*casbin.Enforcer, *ctxBunAdapter) {
ca, err := NewCtxAdapter("mysql", "root:root@tcp(127.0.0.1:3306)/test", WithDebugMode())
if err != nil {
panic(err)
}
e, err := casbin.NewEnforcer("examples/rbac_model.conf", ca)
if err != nil {
panic(err)
}
e.ClearPolicy()
if err := e.SavePolicy(); err != nil {
panic(err)
}
return e, ca
}

func TestCtxBunAdapter_AddPolicyCtx(t *testing.T) {
e, ca := clearDBPolicy()

if err := ca.AddPolicyCtx(context.Background(), "p", "p", []string{"alice", "data1", "read"}); err != nil {
t.Fatalf("failed to add policy: %v", err)
}
_ = e.LoadPolicy()
testGetPolicy(
t,
e,
[][]string{
{"alice", "data1", "read"},
},
)

var p = gomonkey.ApplyFunc(executeWithContext, mockExecuteWithContextTimeOut)
defer p.Reset()
ctx, cancel := context.WithTimeout(context.Background(), 300*time.Microsecond)
defer cancel()
assert.EqualError(t, ca.AddPolicyCtx(ctx, "p", "p", []string{"alice", "data2", "read"}), "context deadline exceeded")
}

func TestCtxBunAdapter_RemovePolicyCtx(t *testing.T) {
e, ca := clearDBPolicy()

_ = ca.AddPolicyCtx(context.Background(), "p", "p", []string{"alice", "data1", "read"})
_ = ca.AddPolicyCtx(context.Background(), "p", "p", []string{"alice", "data2", "read"})
_ = ca.RemovePolicyCtx(context.Background(), "p", "p", []string{"alice", "data1", "read"})
_ = e.LoadPolicy()
testGetPolicy(
t,
e,
[][]string{
{"alice", "data2", "read"},
},
)

var p = gomonkey.ApplyFunc(executeWithContext, mockExecuteWithContextTimeOut)
defer p.Reset()
ctx, cancel := context.WithTimeout(context.Background(), 300*time.Microsecond)
defer cancel()
assert.EqualError(t, ca.RemovePolicyCtx(ctx, "p", "p", []string{"alice", "data2", "read"}), "context deadline exceeded")
}

func TestCtxBunAdapter_RemoveFilteredPolicyCtx(t *testing.T) {
e, ca := clearDBPolicy()

_ = ca.AddPolicyCtx(context.Background(), "p", "p", []string{"alice", "data1", "read"})
_ = ca.AddPolicyCtx(context.Background(), "p", "p", []string{"alice", "data2", "read"})
_ = ca.AddPolicyCtx(context.Background(), "p", "p", []string{"bob", "data1", "read"})
_ = ca.RemoveFilteredPolicyCtx(context.Background(), "p", "p", 0, "alice")
_ = e.LoadPolicy()
testGetPolicy(
t,
e,
[][]string{
{"bob", "data1", "read"},
},
)

var p = gomonkey.ApplyFunc(executeWithContext, mockExecuteWithContextTimeOut)
defer p.Reset()
ctx, cancel := context.WithTimeout(context.Background(), 300*time.Microsecond)
defer cancel()
assert.EqualError(t, ca.RemoveFilteredPolicyCtx(ctx, "p", "p", 0, "alice"), "context deadline exceeded")
}

0 comments on commit 90ca3e2

Please sign in to comment.