[#11] Trim the old functionality

Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
Leonard Lyubich 2020-08-21 14:32:03 +03:00 committed by Alex Vanin
parent 783ec72d56
commit a87fdab324
235 changed files with 39 additions and 36211 deletions

View file

View file

@ -1,24 +0,0 @@
package basic
const (
// OpGetRangeHash is an index of GetRangeHash operation in basic ACL bitmask order.
OpGetRangeHash uint8 = iota
// OpGetRange is an index of GetRange operation in basic ACL bitmask order.
OpGetRange
// OpSearch is an index of Search operation in basic ACL bitmask order.
OpSearch
// OpDelete is an index of Delete operation in basic ACL bitmask order.
OpDelete
// OpPut is an index of Put operation in basic ACL bitmask order.
OpPut
// OpHead is an index of Head operation in basic ACL bitmask order.
OpHead
// OpGet is an index of Get operation in basic ACL bitmask order.
OpGet
)

View file

@ -1,159 +0,0 @@
package basic
// ACL represents a container's
// basic permission bits.
type ACL uint32
const (
reservedBitNumber = 2 // first left bits are reserved
stickyBitPos = reservedBitNumber // X-bit after reserved bits
finalBitPos = stickyBitPos + 1 // F-bit after X-bit
)
const (
opOffset = finalBitPos + 1 // offset of operation bits
bitsPerOp = 4 // number of bits per operation
opNumber = 7 // number of operation bit sections
)
const (
bitUser uint8 = iota
bitSystem
bitOthers
bitBearer
)
const leftACLBitPos = opOffset + bitsPerOp*opNumber - 1
// returns true if n-th left bit is set (starting at 0).
func isLeftBitSet(value ACL, n uint8) bool {
bitMask := ACL(1 << (leftACLBitPos - n))
return bitMask != 0 && value&bitMask == bitMask
}
// sets n-th left bit (starting at 0).
func setLeftBit(value *ACL, n uint8) {
*value |= ACL(1 << (leftACLBitPos - n))
}
// resets n-th left bit (starting at 0).
func resetLeftBit(value *ACL, n uint8) {
*value &= ^ACL(1 << (leftACLBitPos - n))
}
// Reserved returns true if n-th reserved option is enabled in basic ACL.
func (a ACL) Reserved(n uint8) bool {
return n < reservedBitNumber && isLeftBitSet(a, n)
}
// SetReserved enables the n-th reserved option in basic ACL.
func (a *ACL) SetReserved(bit uint8) {
if bit < reservedBitNumber {
setLeftBit(a, bit)
}
}
// ResetReserved disables the n-th reserved option in basic ACL.
func (a *ACL) ResetReserved(bit uint8) {
if bit < reservedBitNumber {
resetLeftBit(a, bit)
}
}
// Final returns true if final option is enabled in basic ACL.
func (a ACL) Final() bool {
return isLeftBitSet(a, finalBitPos)
}
// SetFinal enables final option in basic ACL.
func (a *ACL) SetFinal() {
setLeftBit(a, finalBitPos)
}
// ResetFinal disables final option in basic ACL.
func (a *ACL) ResetFinal() {
resetLeftBit(a, finalBitPos)
}
// Sticky returns true if sticky option is enabled in basic ACL.
func (a ACL) Sticky() bool {
return isLeftBitSet(a, stickyBitPos)
}
// SetSticky enables the sticky option in basic ACL.
func (a *ACL) SetSticky() {
setLeftBit(a, stickyBitPos)
}
// ResetSticky disables the sticky option in basic ACL.
func (a *ACL) ResetSticky() {
resetLeftBit(a, stickyBitPos)
}
// UserAllowed returns true if user allowed the n-th operation in basic ACL.
func (a ACL) UserAllowed(n uint8) bool {
return isLeftBitSet(a, opOffset+n*bitsPerOp+bitUser)
}
// AllowUser allows user the n-th operation in basic ACL.
func (a *ACL) AllowUser(n uint8) {
setLeftBit(a, opOffset+n*bitsPerOp+bitUser)
}
// ForbidUser forbids user the n-th operation in basic ACL.
func (a *ACL) ForbidUser(n uint8) {
resetLeftBit(a, opOffset+n*bitsPerOp+bitUser)
}
// SystemAllowed returns true if System group allowed the n-th operation is set in basic ACL.
func (a ACL) SystemAllowed(n uint8) bool {
if n != OpDelete && n != OpGetRange {
return true
}
return isLeftBitSet(a, opOffset+n*bitsPerOp+bitSystem)
}
// AllowSystem allows System group the n-th operation in basic ACL.
func (a *ACL) AllowSystem(op uint8) {
setLeftBit(a, opOffset+op*bitsPerOp+bitSystem)
}
// ForbidSystem forbids System group the n-th operation in basic ACL.
func (a *ACL) ForbidSystem(op uint8) {
resetLeftBit(a, opOffset+op*bitsPerOp+bitSystem)
}
// OthersAllowed returns true if Others group allowed the n-th operation is set in basic ACL.
func (a ACL) OthersAllowed(op uint8) bool {
return isLeftBitSet(a, opOffset+op*bitsPerOp+bitOthers)
}
// AllowOthers allows Others group the n-th operation in basic ACL.
func (a *ACL) AllowOthers(op uint8) {
setLeftBit(a, opOffset+op*bitsPerOp+bitOthers)
}
// ForbidOthers forbids Others group the n-th operation in basic ACL.
func (a *ACL) ForbidOthers(op uint8) {
resetLeftBit(a, opOffset+op*bitsPerOp+bitOthers)
}
// BearerAllowed returns true if Bearer token usage is allowed for n-th operation in basic ACL.
func (a ACL) BearerAllowed(op uint8) bool {
return isLeftBitSet(a, opOffset+op*bitsPerOp+bitBearer)
}
// AllowBearer allows Bearer token usage for n-th operation in basic ACL.
func (a *ACL) AllowBearer(op uint8) {
setLeftBit(a, opOffset+op*bitsPerOp+bitBearer)
}
// ForbidBearer forbids Bearer token usage for n-th operation in basic ACL.
func (a *ACL) ForbidBearer(op uint8) {
resetLeftBit(a, opOffset+op*bitsPerOp+bitBearer)
}

View file

@ -1,189 +0,0 @@
package basic
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestACLValues(t *testing.T) {
t.Run("private", func(t *testing.T) {
acl := FromUint32(0x1C8C8CCC)
require.False(t, acl.Reserved(0))
require.False(t, acl.Reserved(1))
require.False(t, acl.Sticky())
require.True(t, acl.Final())
require.True(t, acl.UserAllowed(OpGetRangeHash))
require.True(t, acl.SystemAllowed(OpGetRangeHash))
require.False(t, acl.OthersAllowed(OpGetRangeHash))
require.False(t, acl.BearerAllowed(OpGetRangeHash))
require.True(t, acl.UserAllowed(OpGetRange))
require.False(t, acl.SystemAllowed(OpGetRange))
require.False(t, acl.OthersAllowed(OpGetRange))
require.False(t, acl.BearerAllowed(OpGetRange))
require.True(t, acl.UserAllowed(OpSearch))
require.True(t, acl.SystemAllowed(OpSearch))
require.False(t, acl.OthersAllowed(OpSearch))
require.False(t, acl.BearerAllowed(OpSearch))
require.True(t, acl.UserAllowed(OpDelete))
require.False(t, acl.SystemAllowed(OpDelete))
require.False(t, acl.OthersAllowed(OpDelete))
require.False(t, acl.BearerAllowed(OpDelete))
require.True(t, acl.UserAllowed(OpPut))
require.True(t, acl.SystemAllowed(OpPut))
require.False(t, acl.OthersAllowed(OpPut))
require.False(t, acl.BearerAllowed(OpPut))
require.True(t, acl.UserAllowed(OpHead))
require.True(t, acl.SystemAllowed(OpHead))
require.False(t, acl.OthersAllowed(OpHead))
require.False(t, acl.BearerAllowed(OpHead))
require.True(t, acl.UserAllowed(OpGet))
require.True(t, acl.SystemAllowed(OpGet))
require.False(t, acl.OthersAllowed(OpGet))
require.False(t, acl.BearerAllowed(OpGet))
})
t.Run("public with X-bit", func(t *testing.T) {
acl := FromUint32(0x3FFFFFFF)
require.False(t, acl.Reserved(0))
require.False(t, acl.Reserved(1))
require.True(t, acl.Sticky())
require.True(t, acl.Final())
require.True(t, acl.UserAllowed(OpGetRangeHash))
require.True(t, acl.SystemAllowed(OpGetRangeHash))
require.True(t, acl.OthersAllowed(OpGetRangeHash))
require.True(t, acl.BearerAllowed(OpGetRangeHash))
require.True(t, acl.UserAllowed(OpGetRange))
require.True(t, acl.SystemAllowed(OpGetRange))
require.True(t, acl.OthersAllowed(OpGetRange))
require.True(t, acl.BearerAllowed(OpGetRange))
require.True(t, acl.UserAllowed(OpSearch))
require.True(t, acl.SystemAllowed(OpSearch))
require.True(t, acl.OthersAllowed(OpSearch))
require.True(t, acl.BearerAllowed(OpSearch))
require.True(t, acl.UserAllowed(OpDelete))
require.True(t, acl.SystemAllowed(OpDelete))
require.True(t, acl.OthersAllowed(OpDelete))
require.True(t, acl.BearerAllowed(OpDelete))
require.True(t, acl.UserAllowed(OpPut))
require.True(t, acl.SystemAllowed(OpPut))
require.True(t, acl.OthersAllowed(OpPut))
require.True(t, acl.BearerAllowed(OpPut))
require.True(t, acl.UserAllowed(OpHead))
require.True(t, acl.SystemAllowed(OpHead))
require.True(t, acl.OthersAllowed(OpHead))
require.True(t, acl.BearerAllowed(OpHead))
require.True(t, acl.UserAllowed(OpGet))
require.True(t, acl.SystemAllowed(OpGet))
require.True(t, acl.OthersAllowed(OpGet))
require.True(t, acl.BearerAllowed(OpGet))
})
t.Run("read only", func(t *testing.T) {
acl := FromUint32(0x1FFFCCFF)
require.False(t, acl.Reserved(0))
require.False(t, acl.Reserved(1))
require.False(t, acl.Sticky())
require.True(t, acl.Final())
require.True(t, acl.UserAllowed(OpGetRangeHash))
require.True(t, acl.SystemAllowed(OpGetRangeHash))
require.True(t, acl.OthersAllowed(OpGetRangeHash))
require.True(t, acl.BearerAllowed(OpGetRangeHash))
require.True(t, acl.UserAllowed(OpGetRange))
require.True(t, acl.SystemAllowed(OpGetRange))
require.True(t, acl.OthersAllowed(OpGetRange))
require.True(t, acl.BearerAllowed(OpGetRange))
require.True(t, acl.UserAllowed(OpSearch))
require.True(t, acl.SystemAllowed(OpSearch))
require.True(t, acl.OthersAllowed(OpSearch))
require.True(t, acl.BearerAllowed(OpSearch))
require.True(t, acl.UserAllowed(OpDelete))
require.True(t, acl.SystemAllowed(OpDelete))
require.False(t, acl.OthersAllowed(OpDelete))
require.False(t, acl.BearerAllowed(OpDelete))
require.True(t, acl.UserAllowed(OpPut))
require.True(t, acl.SystemAllowed(OpPut))
require.False(t, acl.OthersAllowed(OpPut))
require.False(t, acl.BearerAllowed(OpPut))
require.True(t, acl.UserAllowed(OpHead))
require.True(t, acl.SystemAllowed(OpHead))
require.True(t, acl.OthersAllowed(OpHead))
require.True(t, acl.BearerAllowed(OpHead))
require.True(t, acl.UserAllowed(OpGet))
require.True(t, acl.SystemAllowed(OpGet))
require.True(t, acl.OthersAllowed(OpGet))
require.True(t, acl.BearerAllowed(OpGet))
})
}
func TestACLMethods(t *testing.T) {
acl := new(ACL)
for i := uint8(0); i < reservedBitNumber; i++ {
acl.SetReserved(i)
require.True(t, acl.Reserved(i))
acl.ResetReserved(i)
require.False(t, acl.Reserved(i))
}
acl.SetSticky()
require.True(t, acl.Sticky())
acl.ResetSticky()
require.False(t, acl.Sticky())
acl.SetFinal()
require.True(t, acl.Final())
acl.ResetFinal()
require.False(t, acl.Final())
for i := OpGetRangeHash; i <= OpGet; i++ {
acl.AllowUser(i)
require.True(t, acl.UserAllowed(i))
acl.ForbidUser(i)
require.False(t, acl.UserAllowed(i))
acl.AllowOthers(i)
require.True(t, acl.OthersAllowed(i))
acl.ForbidOthers(i)
require.False(t, acl.OthersAllowed(i))
acl.AllowBearer(i)
require.True(t, acl.BearerAllowed(i))
acl.ForbidBearer(i)
require.False(t, acl.BearerAllowed(i))
acl.AllowSystem(i)
require.True(t, acl.SystemAllowed(i))
acl.ForbidSystem(i)
if i == OpDelete || i == OpGetRange {
require.False(t, acl.SystemAllowed(i))
} else {
require.True(t, acl.SystemAllowed(i))
}
}
}

View file

@ -1,64 +0,0 @@
package basic
import (
"encoding/binary"
"io"
)
// Size is a size of ACL
// in a binary form.
const Size = 4
// FromUint32 converts builtin
// uint32 value to ACL.
//
// Try to avoid direct cast for
// better portability.
func FromUint32(v uint32) ACL {
return ACL(v)
}
// ToUint32 converts ACL value
// to builtin uint32.
//
// Try to avoid direct cast for
// better portability.
func ToUint32(v ACL) uint32 {
return uint32(v)
}
// Equal reports whether e and e2 are the same ACL.
//
// Function defines the relation of equality
// between two ACL. Try to avoid comparison through
// "==" operator for better portability.
func Equal(a, b ACL) bool {
return ToUint32(a) == ToUint32(b)
}
// Marshal encodes ACL into a
// binary form and returns the result.
//
// Result slice has Size length.
func Marshal(a ACL) []byte {
d := make([]byte, Size)
binary.BigEndian.PutUint32(d, ToUint32(a))
return d
}
// UnmarshalBinary unmarshals ACL from
// a binary representation.
//
// If buffer size is insufficient,
// io.ErrUnexpectedEOF is returned.
func (a *ACL) UnmarshalBinary(data []byte) error {
if len(data) < Size {
return io.ErrUnexpectedEOF
}
*a = FromUint32(binary.BigEndian.Uint32(data))
return nil
}

View file

@ -1,36 +0,0 @@
package basic
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestEqual(t *testing.T) {
require.True(t,
Equal(
FromUint32(1),
FromUint32(1),
),
)
require.False(t,
Equal(
FromUint32(1),
FromUint32(2),
),
)
}
func TestMarshal(t *testing.T) {
a := FromUint32(1)
a2 := new(ACL)
require.NoError(t,
a2.UnmarshalBinary(
Marshal(a),
),
)
require.True(t, Equal(a, *a2))
}

View file

@ -1,53 +0,0 @@
package storage
import (
"errors"
eacl "github.com/nspcc-dev/neofs-api-go/acl/extended"
"github.com/nspcc-dev/neofs-node/pkg/core/container"
)
// CID represents the container identifier.
//
// It is a type alias of
// github.com/nspcc-dev/neofs-node/pkg/core/container.ID.
type CID = container.ID
// Table represents extended ACL rule table.
//
// It is a type alias of
// github.com/nspcc-dev/neofs-node/pkg/core/container/eacl/extended.Table.
type Table = eacl.Table
// Storage is the interface that wraps
// basic methods of extended ACL table storage.
type Storage interface {
// GetEACL reads the table from the storage by identifier.
// It returns any error encountered.
//
// GetEACL must return exactly one non-nil value.
// GetEACL must return ErrNotFound if the table is not in storage.
//
// Implementations must not retain or modify the table
// (even temporarily).
GetEACL(CID) (Table, error)
// PutEACL saves the table to the underlying storage.
// It returns any error encountered that caused the saving to interrupt.
//
// PutEACL must return extended.ErrNilTable on nil table.
//
// Implementations must not retain or modify the table (even temporarily).
//
// Table rewriting behavior is dictated by implementation.
PutEACL(CID, Table, []byte) error
}
// ErrNotFound is the error returned when eACL table
// was not found in storage.
var ErrNotFound = errors.New("container not found")
// ErrNilStorage is the error returned by functions that
// expect a non-nil eACL table storage implementation,
// but received nil.
var ErrNilStorage = errors.New("eACL storage is nil")

View file

@ -1,48 +0,0 @@
package test
import (
"sync"
"github.com/nspcc-dev/neofs-node/pkg/core/container"
"github.com/nspcc-dev/neofs-node/pkg/core/container/acl/extended"
"github.com/nspcc-dev/neofs-node/pkg/core/container/acl/extended/storage"
)
type testStorage struct {
*sync.RWMutex
items map[container.ID]storage.Table
}
func (s *testStorage) GetEACL(cid storage.CID) (storage.Table, error) {
s.RLock()
table, ok := s.items[cid]
s.RUnlock()
if !ok {
return nil, storage.ErrNotFound
}
return table, nil
}
func (s *testStorage) PutEACL(cid storage.CID, table storage.Table, _ []byte) error {
if table == nil {
return extended.ErrNilTable
}
s.Lock()
s.items[cid] = table
s.Unlock()
return nil
}
// New creates new eACL table storage
// that stores table in go-builtin map.
func New() storage.Storage {
return &testStorage{
RWMutex: new(sync.RWMutex),
items: make(map[container.ID]storage.Table),
}
}

View file

@ -1,102 +0,0 @@
package extended
import (
"errors"
eacl "github.com/nspcc-dev/neofs-api-go/acl/extended"
"github.com/nspcc-dev/neofs-node/pkg/core/container"
)
// FIXME: do not duplicate constants
// OperationType represents the enumeration
// of different destination types of request.
//
// It is a type alias of
// github.com/nspcc-dev/neofs-api-go/eacl.OperationType.
// FIXME: operation type should be defined in core lib.
type OperationType = eacl.OperationType
// Group represents the enumeration
// of different authorization groups.
//
// It is a type alias of
// github.com/nspcc-dev/neofs-api-go/acl/extended.Group.
// FIXME: target should be defined in core lib.
type Group = eacl.Group
// HeaderType represents the enumeration
// of different types of header.
//
// It is a type alias of
// github.com/nspcc-dev/neofs-api-go/eacl.HeaderType.
// FIXME: header type enum should be defined in core lib.
type HeaderType = eacl.HeaderType
// CID represents the container identifier.
//
// It is a type alias of
// github.com/nspcc-dev/neofs-node/pkg/core/container.ID.
type CID = container.ID
// Header is an interface that wraps
// methods of string key-value header.
//
// It is a type alias of
// github.com/nspcc-dev/neofs-api-go/eacl.Header.
// FIXME: header should be defined in core lib.
type Header = eacl.Header
// Table represents extended ACL rule table.
//
// It is a type alias of
// github.com/nspcc-dev/neofs-api-go/eacl.ExtendedACLTable.
// FIXME: eacl table should be defined in core package.
// type Table = eacl.ExtendedACLTable
// TypedHeaderSource is the interface that wraps
// method for selecting typed headers by type.
type TypedHeaderSource interface {
// HeadersOfType returns the list of key-value headers
// of particular type.
//
// It returns any problem encountered through the boolean
// false value.
HeadersOfType(HeaderType) ([]Header, bool)
}
// RequestInfo is an interface that wraps
// request with authority methods.
type RequestInfo interface {
TypedHeaderSource
// CID returns container identifier from request context.
CID() CID
// Key returns the binary representation of
// author's public key.
//
// Any problem encountered can be reflected
// through an empty slice.
//
// Binary key format is dictated by implementation.
Key() []byte
// OperationType returns the type of request destination.
//
// Any problem encountered can be reflected
// through OpTypeUnknown value. Caller should handle
// OpTypeUnknown value according to its internal logic.
OperationType() OperationType
// Group returns the authority group type.
//
// Any problem encountered can be reflected
// through GroupUnknown value. Caller should handle
// TargetUnknown value according to its internal logic.
Group() Group
}
// ErrNilTable is the error returned by functions that
// expect a non-nil eACL table, but received nil.
var ErrNilTable = errors.New("eACL table is nil")

View file

@ -1,82 +0,0 @@
package container
import (
"errors"
"github.com/nspcc-dev/neofs-node/pkg/core/container/acl/basic"
"github.com/nspcc-dev/netmap"
)
// BasicACL represents the basic
// ACL rules.
//
// It is a type alias of
// github.com/nspcc-dev/neofs-node/pkg/core/container/basic.ACL.
type BasicACL = basic.ACL
// PlacementRule represents placement
// rules of the container.
//
// It is a type alias of
// github.com/nspcc-dev/netmap.PlacementRule.
// FIXME: container placement rules should be defined in core lib.
type PlacementRule = netmap.PlacementRule
// Container represents NeoFS container.
type Container struct {
basicACL BasicACL // basic ACL mask
ownerID OwnerID // the identifier of container's owner
salt []byte // unique container bytes
placementRule PlacementRule // placement rules
}
// ErrNilContainer is the error returned by functions that
// expect a non-nil container pointer, but received nil.
var ErrNilContainer = errors.New("container is nil")
// OwnerID returns an ID of the container's owner.
func (c *Container) OwnerID() OwnerID {
return c.ownerID
}
// SetOwnerID sets the ID of the container's owner.
func (c *Container) SetOwnerID(v OwnerID) {
c.ownerID = v
}
// Salt returns the container salt.
//
// Slice is returned by reference without copying.
func (c *Container) Salt() []byte {
return c.salt
}
// SetSalt sets the container salt.
//
// Slice is assigned by reference without copying.
func (c *Container) SetSalt(v []byte) {
c.salt = v
}
// BasicACL returns the mask of basic container permissions.
func (c *Container) BasicACL() BasicACL {
return c.basicACL
}
// SetBasicACL sets the mask of basic container permissions.
func (c *Container) SetBasicACL(v BasicACL) {
c.basicACL = v
}
// PlacementRule returns placement rule of the container.
func (c *Container) PlacementRule() PlacementRule {
return c.placementRule
}
// SetPlacementRule sets placement rule of the container.
func (c *Container) SetPlacementRule(v PlacementRule) {
c.placementRule = v
}

View file

@ -1,30 +0,0 @@
package container
import (
"testing"
"github.com/nspcc-dev/neofs-node/pkg/core/container/acl/basic"
"github.com/stretchr/testify/require"
)
func TestContainerMethods(t *testing.T) {
c := new(Container)
acl := basic.FromUint32(1)
c.SetBasicACL(acl)
require.True(t, basic.Equal(acl, c.BasicACL()))
ownerID := OwnerID{1, 2, 3}
c.SetOwnerID(ownerID)
require.Equal(t, ownerID, c.OwnerID())
salt := []byte{4, 5, 6}
c.SetSalt(salt)
require.Equal(t, salt, c.Salt())
rule := PlacementRule{
ReplFactor: 1,
}
c.SetPlacementRule(rule)
require.Equal(t, rule, c.PlacementRule())
}

View file

@ -1,49 +0,0 @@
package container
import (
"crypto/sha256"
"github.com/nspcc-dev/neofs-api-go/refs"
)
// ID represents the
// container identifier.
//
// It is a type alias of
// github.com/nspcc-dev/neofs-api-go/refs.CID.
// FIXME: container id should be defined in core package.
type ID = refs.CID
// OwnerID represents the
// container owner identifier.
//
// It is a type alias of
// github.com/nspcc-dev/neofs-api-go/refs.OwnerID.
// FIXME: owner ID should be defined in core lib.
type OwnerID = refs.OwnerID
// OwnerIDSize is a size of OwnerID
// in a binary form.
const OwnerIDSize = refs.OwnerIDSize
// CalculateID calculates container identifier
// as SHA256 checksum of the binary form.
//
// If container is nil, ErrNilContainer is returned.
func CalculateID(cnr *Container) (*ID, error) {
if cnr == nil {
return nil, ErrNilContainer
}
data, err := cnr.MarshalBinary()
if err != nil {
return nil, err
}
res := new(ID)
sh := sha256.Sum256(data)
copy(res[:], sh[:])
return res, nil
}

View file

@ -1,38 +0,0 @@
package container
import (
"crypto/sha256"
"testing"
"github.com/nspcc-dev/neofs-node/pkg/core/container/acl/basic"
"github.com/pkg/errors"
"github.com/stretchr/testify/require"
)
func TestCalculateID(t *testing.T) {
_, err := CalculateID(nil)
require.True(t, errors.Is(err, ErrNilContainer))
cnr := new(Container)
cnr.SetBasicACL(basic.FromUint32(1))
cnr.SetOwnerID(OwnerID{1, 2, 3})
cnr.SetSalt([]byte{4, 5, 6})
id1, err := CalculateID(cnr)
require.NoError(t, err)
data, err := cnr.MarshalBinary()
require.NoError(t, err)
sh := sha256.Sum256(data)
require.Equal(t, id1.Bytes(), sh[:])
// change the container
cnr.SetSalt(append(cnr.Salt(), 1))
id2, err := CalculateID(cnr)
require.NoError(t, err)
require.NotEqual(t, id1, id2)
}

View file

@ -1,75 +0,0 @@
package container
import (
"encoding/binary"
"io"
"github.com/nspcc-dev/neofs-node/pkg/core/container/acl/basic"
)
const (
saltLenSize = 2
fixedSize = 0 +
basic.Size +
OwnerIDSize +
saltLenSize
)
// MarshalBinary encodes the container into a binary form
// and returns the result.
func (c *Container) MarshalBinary() ([]byte, error) {
data := make([]byte, binaryContainerSize(c))
off := copy(data, basic.Marshal(c.basicACL))
off += copy(data[off:], c.ownerID.Bytes())
binary.BigEndian.PutUint16(data[off:], uint16(len(c.salt)))
off += saltLenSize
off += copy(data[off:], c.salt)
if _, err := c.placementRule.MarshalTo(data[off:]); err != nil {
return nil, err
}
return data, nil
}
// UnmarshalBinary unmarshals container from a binary
// representation.
//
// If buffer size is insufficient, io.ErrUnexpectedEOF is returned.
func (c *Container) UnmarshalBinary(data []byte) error {
if len(data) < binaryContainerSize(c) {
return io.ErrUnexpectedEOF
}
if err := c.basicACL.UnmarshalBinary(data); err != nil {
return err
}
off := basic.Size
off += copy(c.ownerID[:], data[off:])
saltLen := binary.BigEndian.Uint16(data[off:])
off += saltLenSize
c.salt = make([]byte, saltLen)
off += copy(c.salt, data[off:])
if err := c.placementRule.Unmarshal(data[off:]); err != nil {
return err
}
return nil
}
// returns the length of the container in binary form.
func binaryContainerSize(cnr *Container) int {
return fixedSize +
len(cnr.salt) +
cnr.placementRule.Size()
}

View file

@ -1,26 +0,0 @@
package container
import (
"testing"
"github.com/nspcc-dev/neofs-node/pkg/core/container/acl/basic"
"github.com/stretchr/testify/require"
)
func TestContainerMarshal(t *testing.T) {
srcCnr := new(Container)
srcCnr.SetBasicACL(basic.FromUint32(1))
srcCnr.SetOwnerID(OwnerID{1, 2, 3})
srcCnr.SetSalt([]byte{4, 5, 6})
srcCnr.SetPlacementRule(PlacementRule{
ReplFactor: 3,
})
data, err := srcCnr.MarshalBinary()
require.NoError(t, err)
dstCnr := new(Container)
require.NoError(t, dstCnr.UnmarshalBinary(data))
require.Equal(t, srcCnr, dstCnr)
}

View file

@ -1,79 +0,0 @@
package storage
import (
"errors"
"github.com/nspcc-dev/neofs-node/pkg/core/container"
)
// Container represents the NeoFS container.
//
// It is a type alias of
// github.com/nspcc-dev/neofs-node/pkg/core/container.Container.
type Container = container.Container
// OwnerID represents the container
// owner identifier.
//
// It is a type alias of
// github.com/nspcc-dev/neofs-node/pkg/core/container.OwnerID.
type OwnerID = container.OwnerID
// CID represents the container identifier.
//
// It is a type alias of
// github.com/nspcc-dev/neofs-node/pkg/core/container.ID.
type CID = container.ID
// Storage is an interface that wraps
// basic container storage methods.
type Storage interface {
// Put saves pointed container to the underlying storage.
// It returns calculated container identifier and any error
// encountered that caused the saving to interrupt.
//
// Put must return container.ErrNilContainer on nil-pointer.
//
// Implementations must not modify the container through the pointer (even temporarily).
// Implementations must not retain the container pointer.
//
// Container rewriting behavior is dictated by implementation.
Put(*Container) (*CID, error)
// Get reads the container from the storage by identifier.
// It returns the pointer to requested container and any error encountered.
//
// Get must return exactly one non-nil value.
// Get must return ErrNotFound if the container is not in storage.
//
// Implementations must not retain the container pointer and modify
// the container through it.
Get(CID) (*Container, error)
// Delete removes the container from the storage.
// It returns any error encountered that caused the deletion to interrupt.
//
// Delete must return nil if container was successfully deleted.
//
// Behavior when deleting a nonexistent container is dictated by implementation.
Delete(CID) error
// List returns a list of container identifiers belonging to the specified owner.
// It returns any error encountered that caused the listing to interrupt.
//
// List must return the identifiers of all stored containers if owner pointer is nil.
// List must return the empty list and no error in the absence of containers in storage.
//
// Result slice can be either empty slice or nil, so empty list should be checked
// by comparing with zero length (not nil).
//
// Callers should carefully handle the incomplete list in case of interrupt error.
List(*OwnerID) ([]CID, error)
}
// ErrNotFound is the error returned when container was not found in storage.
var ErrNotFound = errors.New("container not found")
// ErrNilStorage is the error returned by functions that
// expect a non-nil container storage implementation, but received nil.
var ErrNilStorage = errors.New("container storage is nil")

View file

@ -1,127 +0,0 @@
package test
import (
"sync"
"testing"
"github.com/nspcc-dev/neofs-node/pkg/core/container"
"github.com/nspcc-dev/neofs-node/pkg/core/container/storage"
"github.com/stretchr/testify/require"
)
type testStorage struct {
*sync.RWMutex
items map[container.ID]*container.Container
}
func (s *testStorage) Put(cnr *storage.Container) (*storage.CID, error) {
if cnr == nil {
return nil, container.ErrNilContainer
}
cid, err := container.CalculateID(cnr)
if err != nil {
return nil, err
}
s.Lock()
s.items[*cid] = cnr
s.Unlock()
return cid, nil
}
func (s *testStorage) Get(cid storage.CID) (*storage.Container, error) {
s.RLock()
cnr, ok := s.items[cid]
s.RUnlock()
if !ok {
return nil, storage.ErrNotFound
}
return cnr, nil
}
func (s *testStorage) Delete(cid storage.CID) error {
s.Lock()
delete(s.items, cid)
s.Unlock()
return nil
}
func (s *testStorage) List(ownerID *storage.OwnerID) ([]storage.CID, error) {
s.RLock()
defer s.RUnlock()
res := make([]storage.CID, 0)
for cid, cnr := range s.items {
if ownerID == nil || ownerID.Equal(cnr.OwnerID()) {
res = append(res, cid)
}
}
return res, nil
}
// New creates new container storage
// that stores containers in go-builtin map.
func New() storage.Storage {
return &testStorage{
RWMutex: new(sync.RWMutex),
items: make(map[container.ID]*container.Container),
}
}
// Storage conducts testing of container
// storage for interface specification.
//
// Storage must be empty.
func Storage(t *testing.T, s storage.Storage) {
list, err := s.List(nil)
require.NoError(t, err)
require.Empty(t, list)
cnr1 := new(container.Container)
cnr1.SetOwnerID(container.OwnerID{1, 2, 3})
id1, err := s.Put(cnr1)
require.NoError(t, err)
res, err := s.Get(*id1)
require.NoError(t, err)
require.Equal(t, cnr1, res)
cnr2 := new(container.Container)
owner1 := cnr1.OwnerID()
owner1[0]++
cnr2.SetOwnerID(owner1)
id2, err := s.Put(cnr2)
require.NoError(t, err)
res, err = s.Get(*id2)
require.NoError(t, err)
require.Equal(t, cnr2, res)
list, err = s.List(nil)
require.NoError(t, err)
require.Len(t, list, 2)
require.Contains(t, list, *id1)
require.Contains(t, list, *id2)
owner1 = cnr1.OwnerID()
list, err = s.List(&owner1)
require.NoError(t, err)
require.Len(t, list, 1)
require.Equal(t, *id1, list[0])
owner2 := cnr2.OwnerID()
list, err = s.List(&owner2)
require.NoError(t, err)
require.Len(t, list, 1)
require.Equal(t, *id2, list[0])
}

View file

@ -1,11 +0,0 @@
package test
import (
"testing"
)
func TestNewStorage(t *testing.T) {
s := New()
Storage(t, s)
}