2023-11-07 18:29:51 +00:00
|
|
|
package inmemory
|
|
|
|
|
|
|
|
import (
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
|
|
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2023-12-01 13:08:52 +00:00
|
|
|
container = "native:::object/ExYw/*"
|
2023-11-07 18:29:51 +00:00
|
|
|
chainID = "ingress:ExYw"
|
|
|
|
nonExistChainId = "ingress:LxGyWyL"
|
|
|
|
)
|
|
|
|
|
2024-01-18 08:01:39 +00:00
|
|
|
var resrc = engine.ContainerTarget(container)
|
2023-12-01 13:08:52 +00:00
|
|
|
|
2023-11-07 18:29:51 +00:00
|
|
|
func testInmemLocalStorage() *inmemoryLocalStorage {
|
|
|
|
return NewInmemoryLocalStorage().(*inmemoryLocalStorage)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAddOverride(t *testing.T) {
|
|
|
|
inmem := testInmemLocalStorage()
|
|
|
|
|
|
|
|
inmem.AddOverride(chain.Ingress, resrc, &chain.Chain{
|
|
|
|
Rules: []chain.Rule{
|
|
|
|
{
|
|
|
|
Status: chain.AccessDenied,
|
|
|
|
Actions: chain.Actions{Names: []string{"native::object::delete"}},
|
|
|
|
Resources: chain.Resources{Names: []string{"native::object::*"}},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
ingressChains, ok := inmem.nameToResourceChains[chain.Ingress]
|
|
|
|
require.True(t, ok)
|
|
|
|
resourceChains, ok := ingressChains[resrc]
|
|
|
|
require.True(t, ok)
|
|
|
|
require.Len(t, resourceChains, 1)
|
|
|
|
require.Len(t, resourceChains[0].Rules, 1)
|
|
|
|
|
|
|
|
inmem.AddOverride(chain.Ingress, resrc, &chain.Chain{
|
|
|
|
Rules: []chain.Rule{
|
|
|
|
{
|
|
|
|
Status: chain.QuotaLimitReached,
|
|
|
|
Actions: chain.Actions{Names: []string{"native::object::put"}},
|
|
|
|
Resources: chain.Resources{Names: []string{"native::object::*"}},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Status: chain.AccessDenied,
|
|
|
|
Actions: chain.Actions{Names: []string{"native::object::get"}},
|
|
|
|
Resources: chain.Resources{Names: []string{"native::object::*"}},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
ingressChains, ok = inmem.nameToResourceChains[chain.Ingress]
|
|
|
|
require.True(t, ok)
|
|
|
|
resourceChains, ok = ingressChains[resrc]
|
|
|
|
require.True(t, ok)
|
|
|
|
require.Len(t, resourceChains, 2)
|
|
|
|
require.Len(t, resourceChains[1].Rules, 2)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestRemoveOverride(t *testing.T) {
|
|
|
|
t.Run("remove from empty storage", func(t *testing.T) {
|
|
|
|
inmem := testInmemLocalStorage()
|
|
|
|
err := inmem.RemoveOverride(chain.Ingress, resrc, chain.ID(chainID))
|
|
|
|
require.ErrorIs(t, err, engine.ErrChainNameNotFound)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("remove not added chain id", func(t *testing.T) {
|
|
|
|
inmem := testInmemLocalStorage()
|
|
|
|
inmem.AddOverride(chain.Ingress, resrc, &chain.Chain{
|
|
|
|
ID: chain.ID(chainID),
|
|
|
|
Rules: []chain.Rule{
|
|
|
|
{ // Restrict to remove ANY object from the namespace.
|
|
|
|
Status: chain.AccessDenied,
|
|
|
|
Actions: chain.Actions{Names: []string{"native::object::delete"}},
|
|
|
|
Resources: chain.Resources{Names: []string{"native::object::*"}},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
err := inmem.RemoveOverride(chain.Ingress, resrc, chain.ID(nonExistChainId))
|
|
|
|
require.ErrorIs(t, err, engine.ErrChainNotFound)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("remove existing chain id", func(t *testing.T) {
|
|
|
|
inmem := testInmemLocalStorage()
|
|
|
|
inmem.AddOverride(chain.Ingress, resrc, &chain.Chain{
|
|
|
|
ID: chain.ID(chainID),
|
|
|
|
Rules: []chain.Rule{
|
|
|
|
{ // Restrict to remove ANY object from the namespace.
|
|
|
|
Status: chain.AccessDenied,
|
|
|
|
Actions: chain.Actions{Names: []string{"native::object::delete"}},
|
|
|
|
Resources: chain.Resources{Names: []string{"native::object::*"}},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
err := inmem.RemoveOverride(chain.Ingress, resrc, chain.ID(chainID))
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
ingressChains, ok := inmem.nameToResourceChains[chain.Ingress]
|
|
|
|
require.True(t, ok)
|
|
|
|
require.Len(t, ingressChains, 1)
|
|
|
|
resourceChains, ok := ingressChains[resrc]
|
|
|
|
require.True(t, ok)
|
|
|
|
require.Len(t, resourceChains, 0)
|
|
|
|
})
|
2024-03-07 10:55:41 +00:00
|
|
|
|
|
|
|
t.Run("remove by target", func(t *testing.T) {
|
|
|
|
inmem := testInmemLocalStorage()
|
|
|
|
t0 := engine.ContainerTarget("name0")
|
|
|
|
t1 := engine.ContainerTarget("name1")
|
|
|
|
inmem.AddOverride(chain.Ingress, t0, &chain.Chain{
|
|
|
|
ID: chain.ID(chainID),
|
|
|
|
Rules: []chain.Rule{
|
|
|
|
{
|
|
|
|
Status: chain.AccessDenied,
|
|
|
|
Actions: chain.Actions{Names: []string{"native::object::delete"}},
|
|
|
|
Resources: chain.Resources{Names: []string{"native::object::*"}},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
inmem.AddOverride(chain.Ingress, t0, &chain.Chain{
|
|
|
|
ID: chain.ID(chainID),
|
|
|
|
Rules: []chain.Rule{
|
|
|
|
{
|
|
|
|
Status: chain.Allow,
|
|
|
|
Actions: chain.Actions{Names: []string{"native::object::delete"}},
|
|
|
|
Resources: chain.Resources{Names: []string{"native::object::*"}},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
inmem.AddOverride(chain.Ingress, t1, &chain.Chain{
|
|
|
|
ID: chain.ID(chainID),
|
|
|
|
Rules: []chain.Rule{
|
|
|
|
{
|
|
|
|
Status: chain.Allow,
|
|
|
|
Actions: chain.Actions{Names: []string{"native::object::delete"}},
|
|
|
|
Resources: chain.Resources{Names: []string{"native::object::*"}},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
err := inmem.RemoveOverridesByTarget(chain.Ingress, t0)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
ingressChains, ok := inmem.nameToResourceChains[chain.Ingress]
|
|
|
|
require.True(t, ok)
|
|
|
|
require.Len(t, ingressChains, 1)
|
|
|
|
resourceChains, ok := ingressChains[t1]
|
|
|
|
require.True(t, ok)
|
|
|
|
require.Len(t, resourceChains, 1)
|
|
|
|
})
|
2023-11-07 18:29:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestGetOverride(t *testing.T) {
|
|
|
|
addChain := &chain.Chain{
|
|
|
|
ID: chain.ID(chainID),
|
|
|
|
Rules: []chain.Rule{
|
|
|
|
{ // Restrict to remove ANY object from the namespace.
|
|
|
|
Status: chain.AccessDenied,
|
|
|
|
Actions: chain.Actions{Names: []string{"native::object::delete"}},
|
|
|
|
Resources: chain.Resources{Names: []string{"native::object::*"}},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Run("get from empty storage", func(t *testing.T) {
|
|
|
|
inmem := testInmemLocalStorage()
|
|
|
|
_, err := inmem.GetOverride(chain.Ingress, resrc, chain.ID(chainID))
|
|
|
|
require.ErrorIs(t, err, engine.ErrChainNameNotFound)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("get not added chain id", func(t *testing.T) {
|
|
|
|
inmem := testInmemLocalStorage()
|
|
|
|
inmem.AddOverride(chain.Ingress, resrc, addChain)
|
|
|
|
|
|
|
|
const nonExistingChainID = "ingress:LxGyWyL"
|
|
|
|
|
|
|
|
_, err := inmem.GetOverride(chain.Ingress, resrc, chain.ID(nonExistingChainID))
|
|
|
|
require.ErrorIs(t, err, engine.ErrChainNotFound)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("get existing chain id", func(t *testing.T) {
|
|
|
|
inmem := testInmemLocalStorage()
|
|
|
|
inmem.AddOverride(chain.Ingress, resrc, addChain)
|
|
|
|
|
|
|
|
c, err := inmem.GetOverride(chain.Ingress, resrc, chain.ID(chainID))
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.EqualValues(t, *addChain, *c)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("get removed chain id", func(t *testing.T) {
|
|
|
|
inmem := testInmemLocalStorage()
|
|
|
|
inmem.AddOverride(chain.Ingress, resrc, addChain)
|
|
|
|
|
|
|
|
err := inmem.RemoveOverride(chain.Ingress, resrc, chain.ID(chainID))
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
_, err = inmem.GetOverride(chain.Ingress, resrc, chain.ID(chainID))
|
|
|
|
require.ErrorIs(t, err, engine.ErrChainNotFound)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestListOverrides(t *testing.T) {
|
|
|
|
addChain := &chain.Chain{
|
|
|
|
ID: chain.ID(chainID),
|
|
|
|
Rules: []chain.Rule{
|
|
|
|
{ // Restrict to remove ANY object from the namespace.
|
|
|
|
Status: chain.AccessDenied,
|
|
|
|
Actions: chain.Actions{Names: []string{"native::object::delete"}},
|
|
|
|
Resources: chain.Resources{Names: []string{"native::object::*"}},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Run("list empty storage", func(t *testing.T) {
|
|
|
|
inmem := testInmemLocalStorage()
|
|
|
|
l, _ := inmem.ListOverrides(chain.Ingress, resrc)
|
|
|
|
require.Len(t, l, 0)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("list with one added resource", func(t *testing.T) {
|
|
|
|
inmem := testInmemLocalStorage()
|
|
|
|
inmem.AddOverride(chain.Ingress, resrc, addChain)
|
|
|
|
l, _ := inmem.ListOverrides(chain.Ingress, resrc)
|
|
|
|
require.Len(t, l, 1)
|
2024-01-26 14:25:59 +00:00
|
|
|
targets, err := inmem.ListOverrideDefinedTargets(chain.Ingress)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, []engine.Target{resrc}, targets)
|
2023-11-07 18:29:51 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("list after drop", func(t *testing.T) {
|
|
|
|
inmem := testInmemLocalStorage()
|
|
|
|
inmem.AddOverride(chain.Ingress, resrc, addChain)
|
|
|
|
l, _ := inmem.ListOverrides(chain.Ingress, resrc)
|
|
|
|
require.Len(t, l, 1)
|
|
|
|
|
|
|
|
_ = inmem.DropAllOverrides(chain.Ingress)
|
|
|
|
l, _ = inmem.ListOverrides(chain.Ingress, resrc)
|
|
|
|
require.Len(t, l, 0)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestGenerateID(t *testing.T) {
|
|
|
|
inmem := testInmemLocalStorage()
|
|
|
|
ids := make([]chain.ID, 0, 100)
|
|
|
|
for i := 0; i < 100; i++ {
|
|
|
|
ids = append(ids, inmem.generateChainID(chain.Ingress, resrc))
|
|
|
|
}
|
|
|
|
require.False(t, hasDuplicates(ids))
|
|
|
|
}
|
|
|
|
|
|
|
|
func hasDuplicates(ids []chain.ID) bool {
|
2024-01-18 08:01:39 +00:00
|
|
|
seen := make(map[string]bool)
|
2023-11-07 18:29:51 +00:00
|
|
|
for _, id := range ids {
|
2024-01-18 08:01:39 +00:00
|
|
|
if seen[string(id)] {
|
2023-11-07 18:29:51 +00:00
|
|
|
return true
|
|
|
|
}
|
2024-01-18 08:01:39 +00:00
|
|
|
seen[string(id)] = true
|
2023-11-07 18:29:51 +00:00
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|