3
0

Update role importer, add tests

This commit is contained in:
Denis Arh
2019-09-25 15:07:03 +02:00
parent 9c37d6d4e2
commit d8a8e311f0
6 changed files with 138 additions and 126 deletions
+16 -6
View File
@@ -6,12 +6,14 @@ import (
"os"
"github.com/spf13/cobra"
"gopkg.in/yaml.v2"
"github.com/cortezaproject/corteza-server/internal/auth"
"github.com/cortezaproject/corteza-server/internal/permissions"
"github.com/cortezaproject/corteza-server/pkg/cli"
"github.com/cortezaproject/corteza-server/system/importer"
"github.com/cortezaproject/corteza-server/system/service"
"github.com/cortezaproject/corteza-server/system/types"
)
func Importer(ctx context.Context, c *cli.Config) *cobra.Command {
@@ -24,6 +26,7 @@ func Importer(ctx context.Context, c *cli.Config) *cobra.Command {
c.InitServices(ctx, c)
var (
aux interface{}
ff []io.Reader
err error
)
@@ -41,18 +44,25 @@ func Importer(ctx context.Context, c *cli.Config) *cobra.Command {
ff = []io.Reader{os.Stdin}
}
roles := service.DefaultRole.With(ctx)
roles, err := service.DefaultRole.With(ctx).Find(&types.RoleFilter{})
cli.HandleError(err)
for i, f := range ff {
cmd.Printf("Importing from %s\n", args[i])
imp := importer.NewImporter(
roles,
permissions.NewImporter(service.DefaultAccessControl.Whitelist()),
cli.HandleError(yaml.NewDecoder(f).Decode(&aux))
perm := permissions.NewImporter(service.DefaultAccessControl.Whitelist())
imp := importer.NewImporter(perm,
importer.NewRoleImport(perm, roles),
)
cli.HandleError(imp.YAML(f))
cli.HandleError(imp.Store(ctx, roles, service.DefaultAccessControl))
cli.HandleError(imp.Store(
ctx,
service.DefaultRole.With(ctx),
service.DefaultAccessControl,
))
}
},
}
+3 -20
View File
@@ -3,9 +3,6 @@ package importer
import (
"context"
"fmt"
"io"
"gopkg.in/yaml.v2"
"github.com/cortezaproject/corteza-server/internal/permissions"
"github.com/cortezaproject/corteza-server/pkg/deinterfacer"
@@ -14,32 +11,18 @@ import (
type (
Importer struct {
roleFinder roleFinder
roles *RoleImport
roles *Role
permissions importer.PermissionImporter
}
)
func NewImporter(rf roleFinder, p importer.PermissionImporter) *Importer {
func NewImporter(p importer.PermissionImporter, ri *Role) *Importer {
return &Importer{
roleFinder: rf,
roles: NewRoleImporter(rf, p),
roles: ri,
permissions: p,
}
}
func (imp *Importer) YAML(r io.Reader) (err error) {
var aux interface{}
if err = yaml.NewDecoder(r).Decode(&aux); err != nil {
return
}
return imp.Cast(aux)
}
func (imp *Importer) Cast(in interface{}) (err error) {
return deinterfacer.Each(in, func(index int, key string, val interface{}) (err error) {
switch key {
+65
View File
@@ -0,0 +1,65 @@
package importer
import (
"fmt"
"os"
"testing"
"github.com/stretchr/testify/require"
"gopkg.in/yaml.v2"
"github.com/cortezaproject/corteza-server/internal/permissions"
"github.com/cortezaproject/corteza-server/system/service"
)
var (
pi *permissions.Importer
imp *Importer
)
func TestMain(m *testing.M) {
resetMocks()
os.Exit(m.Run())
}
func resetMocks() {
// whitelist = nil, anything can be added
pi = permissions.NewImporter(service.AccessControl(nil).Whitelist())
imp = NewImporter(
pi,
NewRoleImport(pi, nil),
)
}
func impFixTester(t *testing.T, name string, tester interface{}) {
t.Run(name, func(t *testing.T) {
// We're not calling reset mocks BEFORE calling tester()
// because we want to have an option to set it up as we want
defer resetMocks()
var aux interface{}
req := require.New(t)
f, err := os.Open(fmt.Sprintf("testdata/%s.yaml", name))
req.NoError(err)
req.NoError(yaml.NewDecoder(f).Decode(&aux))
req.NotNil(aux)
if reqError, ok := tester.(error); ok {
req.EqualError(imp.Cast(aux), reqError.Error())
return
} else {
req.NoError(imp.Cast(aux))
}
switch tester := tester.(type) {
case func(*testing.T, *Role):
tester(t, imp.roles)
case func(*testing.T, *Importer):
tester(t, imp)
default:
panic("unsupported tester function signature")
}
})
}
+37 -65
View File
@@ -12,17 +12,10 @@ import (
)
type (
RoleImport struct {
set types.RoleSet
dirty map[string]bool
Role struct {
set types.RoleSet
dirty map[uint64]bool
permissions importer.PermissionImporter
finder roleFinder
}
roleFinder interface {
FindByHandle(string) (*types.Role, error)
}
roleKeeper interface {
@@ -31,31 +24,32 @@ type (
}
)
func NewRoleImporter(finder roleFinder, permissions importer.PermissionImporter) *RoleImport {
return &RoleImport{
set: types.RoleSet{},
dirty: map[string]bool{},
permissions: permissions,
finder: finder,
func NewRoleImport(permissions importer.PermissionImporter, set types.RoleSet) *Role {
if set == nil {
set = types.RoleSet{}
}
out := &Role{
set: set,
dirty: make(map[uint64]bool),
permissions: permissions,
}
return out
}
// Resolves permission rules:
// { <role-handle>: { role } } or [ { role }, ... ]
func (imp *RoleImport) CastSet(set interface{}) error {
func (rImp *Role) CastSet(set interface{}) error {
return deinterfacer.Each(set, func(index int, handle string, def interface{}) error {
if index > -1 {
// Roles defined as collection
deinterfacer.KVsetString(&handle, "handle", def)
}
return imp.Cast(handle, def)
return rImp.Cast(handle, def)
})
}
// Resolves permission rules:
// { <role-handle>: { role } } or [ { role }, ... ]
func (imp *RoleImport) Cast(handle string, def interface{}) (err error) {
func (rImp *Role) Cast(handle string, def interface{}) (err error) {
var role *types.Role
if !importer.IsValidHandle(handle) {
@@ -63,12 +57,21 @@ func (imp *RoleImport) Cast(handle string, def interface{}) (err error) {
}
handle = importer.NormalizeHandle(handle)
if role, err = imp.Get(handle); err != nil {
if role, err = rImp.Get(handle); err != nil {
return err
} else if role == nil {
role = &types.Role{
Handle: handle,
}
rImp.set = append(rImp.set, role)
} else if role.ID == 0 {
return errors.Errorf("role handle %q already defined in this import session", role.Handle)
} else {
rImp.dirty[role.ID] = true
}
if name, ok := def.(string); ok && name != "" {
imp.dirty[handle] = role.Name != name
role.Name = name
return nil
}
@@ -79,11 +82,10 @@ func (imp *RoleImport) Cast(handle string, def interface{}) (err error) {
// already handled
case "name":
name := deinterfacer.ToString(val)
imp.dirty[handle] = role.Name != name
role.Name = name
case "allow", "deny":
return imp.permissions.CastSet(types.RolePermissionResource.String()+role.Handle, key, val)
return rImp.permissions.CastSet(types.RolePermissionResource.String()+role.Handle, key, val)
default:
return fmt.Errorf("unexpected key %q for role %q", key, role.Handle)
@@ -93,62 +95,32 @@ func (imp *RoleImport) Cast(handle string, def interface{}) (err error) {
})
}
// Exists returns true if role exists in the buffer or
// can be loaded from the storage
func (imp *RoleImport) Exists(handle string) bool {
handle = importer.NormalizeHandle(handle)
role := imp.set.FindByHandle(handle)
if role != nil {
return true
}
if imp.finder != nil {
role, err := imp.finder.FindByHandle(handle)
if err == nil && role != nil {
imp.set = append(imp.set, role)
return true
}
}
return false
}
// finds or makes new role
func (imp *RoleImport) Get(handle string) (*types.Role, error) {
func (rImp *Role) Get(handle string) (*types.Role, error) {
handle = importer.NormalizeHandle(handle)
if !importer.IsValidHandle(handle) {
return nil, errors.New("invalid role handle")
}
if !imp.Exists(handle) {
imp.set = append(imp.set, &types.Role{
Handle: handle,
Name: handle,
})
}
return imp.set.FindByHandle(handle), nil
return rImp.set.FindByHandle(handle), nil
}
func (imp *RoleImport) Store(ctx context.Context, k roleKeeper) error {
return imp.set.Walk(func(role *types.Role) (err error) {
func (rImp *Role) Store(ctx context.Context, k roleKeeper) error {
return rImp.set.Walk(func(role *types.Role) (err error) {
var handle = role.Handle
if role.ID == 0 {
role, err = k.Create(role)
} else {
if imp.dirty[handle] {
role, err = k.Update(role)
}
} else if rImp.dirty[role.ID] {
role, err = k.Update(role)
}
if err != nil {
return
}
imp.permissions.UpdateResources(types.RolePermissionResource.String(), handle, role.ID)
imp.permissions.UpdateRoles(role.Handle, role.ID)
rImp.permissions.UpdateResources(types.RolePermissionResource.String(), handle, role.ID)
rImp.permissions.UpdateRoles(role.Handle, role.ID)
return
})
+13 -35
View File
@@ -2,42 +2,20 @@ package importer
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestRoleImport_CastSet(t *testing.T) {
t.Skip()
// tests := []struct {
// name string
// resource string
// yaml string
// set types.RoleSet
// }{
// {name: "empty", yaml: ``},
// {name: "empty map", yaml: `{}`},
// {name: "empty slice", yaml: `[]`},
// {
// name: "full",
// yaml: `
// admins: Admins
// foo:
// name: Foo
// bar:
// `,
// set: []*types.Role{
// {Handle: "admins", Name: "Admins"},
// {Handle: "foo", Name: "Foo"},
// {Handle: "bar", Name: "bar"},
// },
// },
// }
// for _, tt := range tests {
// t.Run(tt.name, func(t *testing.T) {
// imp := &RoleImport{}
//
// aux, err := importer.ParseYAML([]byte(tt.yaml))
// require.NoError(t, err)
// require.NoError(t, imp.CastSet(aux))
// require.Equal(t, tt.set, imp.set)
// })
// }
impFixTester(t, "roles", func(t *testing.T, ri *Role) {
req := require.New(t)
req.NotNil(ri.set)
req.Len(ri.set, 2)
req.NotNil(ri.set.FindByHandle("r1"))
req.Equal("Role1", ri.set.FindByHandle("r1").Name)
req.NotNil(ri.set.FindByHandle("r2"))
req.Equal("Role2", ri.set.FindByHandle("r2").Name)
})
}
+4
View File
@@ -0,0 +1,4 @@
roles:
r1: Role1
r2:
name: Role2