forked from TrueCloudLab/frostfs-sdk-go
[#128] session: Add ObjectContext
Signed-off-by: Pavel Karpy <carpawell@nspcc.ru>
This commit is contained in:
parent
e8eac3997c
commit
fb5b56fdc9
5 changed files with 322 additions and 1 deletions
|
@ -57,7 +57,7 @@ func TestContainerContext_ApplyTo(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFilter_ToV2(t *testing.T) {
|
func TestContextFilter_ToV2(t *testing.T) {
|
||||||
t.Run("nil", func(t *testing.T) {
|
t.Run("nil", func(t *testing.T) {
|
||||||
var x *session.ContainerContext
|
var x *session.ContainerContext
|
||||||
|
|
||||||
|
|
166
session/object.go
Normal file
166
session/object.go
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
package session
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/v2/session"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/object/address"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ObjectContext represents NeoFS API v2-compatible
|
||||||
|
// context of the object session.
|
||||||
|
//
|
||||||
|
// It is a wrapper over session.ObjectSessionContext
|
||||||
|
// which allows abstracting from details of the message
|
||||||
|
// structure.
|
||||||
|
type ObjectContext session.ObjectSessionContext
|
||||||
|
|
||||||
|
// NewObjectContext creates and returns blank ObjectContext.
|
||||||
|
//
|
||||||
|
// Defaults:
|
||||||
|
// - not bound to any operation;
|
||||||
|
// - nil object address.
|
||||||
|
func NewObjectContext() *ObjectContext {
|
||||||
|
v2 := new(session.ObjectSessionContext)
|
||||||
|
|
||||||
|
return ObjectContextFromV2(v2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ObjectContextFromV2 wraps session.ObjectSessionContext
|
||||||
|
// into ObjectContext.
|
||||||
|
func ObjectContextFromV2(v *session.ObjectSessionContext) *ObjectContext {
|
||||||
|
return (*ObjectContext)(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToV2 converts ObjectContext to session.ObjectSessionContext
|
||||||
|
// message structure.
|
||||||
|
func (x *ObjectContext) ToV2() *session.ObjectSessionContext {
|
||||||
|
return (*session.ObjectSessionContext)(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplyTo specifies which object the ObjectContext applies to.
|
||||||
|
func (x *ObjectContext) ApplyTo(id *address.Address) {
|
||||||
|
v2 := (*session.ObjectSessionContext)(x)
|
||||||
|
|
||||||
|
v2.SetAddress(id.ToV2())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Address returns identifier of the object
|
||||||
|
// to which the ObjectContext applies.
|
||||||
|
func (x *ObjectContext) Address() *address.Address {
|
||||||
|
v2 := (*session.ObjectSessionContext)(x)
|
||||||
|
|
||||||
|
return address.NewAddressFromV2(v2.GetAddress())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ObjectContext) forVerb(v session.ObjectSessionVerb) {
|
||||||
|
(*session.ObjectSessionContext)(x).
|
||||||
|
SetVerb(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ObjectContext) isForVerb(v session.ObjectSessionVerb) bool {
|
||||||
|
return (*session.ObjectSessionContext)(x).
|
||||||
|
GetVerb() == v
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForPut binds the ObjectContext to
|
||||||
|
// PUT operation.
|
||||||
|
func (x *ObjectContext) ForPut() {
|
||||||
|
x.forVerb(session.ObjectVerbPut)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsForPut checks if ObjectContext is bound to
|
||||||
|
// PUT operation.
|
||||||
|
func (x *ObjectContext) IsForPut() bool {
|
||||||
|
return x.isForVerb(session.ObjectVerbPut)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForDelete binds the ObjectContext to
|
||||||
|
// DELETE operation.
|
||||||
|
func (x *ObjectContext) ForDelete() {
|
||||||
|
x.forVerb(session.ObjectVerbDelete)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsForDelete checks if ObjectContext is bound to
|
||||||
|
// DELETE operation.
|
||||||
|
func (x *ObjectContext) IsForDelete() bool {
|
||||||
|
return x.isForVerb(session.ObjectVerbDelete)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForGet binds the ObjectContext to
|
||||||
|
// GET operation.
|
||||||
|
func (x *ObjectContext) ForGet() {
|
||||||
|
x.forVerb(session.ObjectVerbGet)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsForGet checks if ObjectContext is bound to
|
||||||
|
// GET operation.
|
||||||
|
func (x *ObjectContext) IsForGet() bool {
|
||||||
|
return x.isForVerb(session.ObjectVerbGet)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForHead binds the ObjectContext to
|
||||||
|
// HEAD operation.
|
||||||
|
func (x *ObjectContext) ForHead() {
|
||||||
|
x.forVerb(session.ObjectVerbHead)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsForHead checks if ObjectContext is bound to
|
||||||
|
// HEAD operation.
|
||||||
|
func (x *ObjectContext) IsForHead() bool {
|
||||||
|
return x.isForVerb(session.ObjectVerbHead)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForSearch binds the ObjectContext to
|
||||||
|
// SEARCH operation.
|
||||||
|
func (x *ObjectContext) ForSearch() {
|
||||||
|
x.forVerb(session.ObjectVerbSearch)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsForSearch checks if ObjectContext is bound to
|
||||||
|
// SEARCH operation.
|
||||||
|
func (x *ObjectContext) IsForSearch() bool {
|
||||||
|
return x.isForVerb(session.ObjectVerbSearch)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForRange binds the ObjectContext to
|
||||||
|
// RANGE operation.
|
||||||
|
func (x *ObjectContext) ForRange() {
|
||||||
|
x.forVerb(session.ObjectVerbRange)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsForRange checks if ObjectContext is bound to
|
||||||
|
// RANGE operation.
|
||||||
|
func (x *ObjectContext) IsForRange() bool {
|
||||||
|
return x.isForVerb(session.ObjectVerbRange)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForRangeHash binds the ObjectContext to
|
||||||
|
// RANGEHASH operation.
|
||||||
|
func (x *ObjectContext) ForRangeHash() {
|
||||||
|
x.forVerb(session.ObjectVerbRangeHash)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsForRangeHash checks if ObjectContext is bound to
|
||||||
|
// RANGEHASH operation.
|
||||||
|
func (x *ObjectContext) IsForRangeHash() bool {
|
||||||
|
return x.isForVerb(session.ObjectVerbRangeHash)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal marshals ObjectContext into a protobuf binary form.
|
||||||
|
func (x *ObjectContext) Marshal() ([]byte, error) {
|
||||||
|
return x.ToV2().StableMarshal(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal unmarshals protobuf binary representation of ObjectContext.
|
||||||
|
func (x *ObjectContext) Unmarshal(data []byte) error {
|
||||||
|
return x.ToV2().Unmarshal(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON encodes ObjectContext to protobuf JSON format.
|
||||||
|
func (x *ObjectContext) MarshalJSON() ([]byte, error) {
|
||||||
|
return x.ToV2().MarshalJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON decodes ObjectContext from protobuf JSON format.
|
||||||
|
func (x *ObjectContext) UnmarshalJSON(data []byte) error {
|
||||||
|
return x.ToV2().UnmarshalJSON(data)
|
||||||
|
}
|
123
session/object_test.go
Normal file
123
session/object_test.go
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
package session_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
v2session "github.com/nspcc-dev/neofs-api-go/v2/session"
|
||||||
|
objecttest "github.com/nspcc-dev/neofs-sdk-go/object/address/test"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/session"
|
||||||
|
sessiontest "github.com/nspcc-dev/neofs-sdk-go/session/test"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestObjectContextVerbs(t *testing.T) {
|
||||||
|
c := session.NewObjectContext()
|
||||||
|
|
||||||
|
assert := func(setter func(), getter func() bool, verb v2session.ObjectSessionVerb) {
|
||||||
|
setter()
|
||||||
|
|
||||||
|
require.True(t, getter())
|
||||||
|
|
||||||
|
require.Equal(t, verb, c.ToV2().GetVerb())
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("PUT", func(t *testing.T) {
|
||||||
|
assert(c.ForPut, c.IsForPut, v2session.ObjectVerbPut)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("DELETE", func(t *testing.T) {
|
||||||
|
assert(c.ForDelete, c.IsForDelete, v2session.ObjectVerbDelete)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("GET", func(t *testing.T) {
|
||||||
|
assert(c.ForGet, c.IsForGet, v2session.ObjectVerbGet)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("SEARCH", func(t *testing.T) {
|
||||||
|
assert(c.ForSearch, c.IsForSearch, v2session.ObjectVerbSearch)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("RANGE", func(t *testing.T) {
|
||||||
|
assert(c.ForRange, c.IsForRange, v2session.ObjectVerbRange)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("RANGEHASH", func(t *testing.T) {
|
||||||
|
assert(c.ForRangeHash, c.IsForRangeHash, v2session.ObjectVerbRangeHash)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("HEAD", func(t *testing.T) {
|
||||||
|
assert(c.ForHead, c.IsForHead, v2session.ObjectVerbHead)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestObjectContext_ApplyTo(t *testing.T) {
|
||||||
|
c := session.NewObjectContext()
|
||||||
|
id := objecttest.Address()
|
||||||
|
|
||||||
|
t.Run("method", func(t *testing.T) {
|
||||||
|
c.ApplyTo(id)
|
||||||
|
|
||||||
|
require.Equal(t, id, c.Address())
|
||||||
|
|
||||||
|
c.ApplyTo(nil)
|
||||||
|
|
||||||
|
require.Nil(t, c.Address())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestObjectFilter_ToV2(t *testing.T) {
|
||||||
|
t.Run("nil", func(t *testing.T) {
|
||||||
|
var x *session.ObjectContext
|
||||||
|
|
||||||
|
require.Nil(t, x.ToV2())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("default values", func(t *testing.T) {
|
||||||
|
c := session.NewObjectContext()
|
||||||
|
|
||||||
|
// check initial values
|
||||||
|
require.Nil(t, c.Address())
|
||||||
|
|
||||||
|
for _, op := range []func() bool{
|
||||||
|
c.IsForPut,
|
||||||
|
c.IsForDelete,
|
||||||
|
c.IsForGet,
|
||||||
|
c.IsForHead,
|
||||||
|
c.IsForRange,
|
||||||
|
c.IsForRangeHash,
|
||||||
|
c.IsForSearch,
|
||||||
|
} {
|
||||||
|
require.False(t, op())
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert to v2 message
|
||||||
|
cV2 := c.ToV2()
|
||||||
|
|
||||||
|
require.Equal(t, v2session.ObjectVerbUnknown, cV2.GetVerb())
|
||||||
|
require.Nil(t, cV2.GetAddress())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestObjectContextEncoding(t *testing.T) {
|
||||||
|
c := sessiontest.ObjectContext()
|
||||||
|
|
||||||
|
t.Run("binary", func(t *testing.T) {
|
||||||
|
data, err := c.Marshal()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
c2 := session.NewObjectContext()
|
||||||
|
require.NoError(t, c2.Unmarshal(data))
|
||||||
|
|
||||||
|
require.Equal(t, c, c2)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("json", func(t *testing.T) {
|
||||||
|
data, err := c.MarshalJSON()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
c2 := session.NewObjectContext()
|
||||||
|
require.NoError(t, c2.UnmarshalJSON(data))
|
||||||
|
|
||||||
|
require.Equal(t, c, c2)
|
||||||
|
})
|
||||||
|
}
|
|
@ -237,6 +237,8 @@ func (t *Token) Context() interface{} {
|
||||||
return nil
|
return nil
|
||||||
case *session.ContainerSessionContext:
|
case *session.ContainerSessionContext:
|
||||||
return ContainerContextFromV2(c)
|
return ContainerContextFromV2(c)
|
||||||
|
case *session.ObjectSessionContext:
|
||||||
|
return ObjectContextFromV2(c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
30
session/test/object.go
Normal file
30
session/test/object.go
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
package sessiontest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
|
||||||
|
oidtest "github.com/nspcc-dev/neofs-sdk-go/object/address/test"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/session"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ObjectContext returns session.ObjectContext
|
||||||
|
// which applies to random operation on a random object.
|
||||||
|
func ObjectContext() *session.ObjectContext {
|
||||||
|
c := session.NewObjectContext()
|
||||||
|
|
||||||
|
setters := []func(){
|
||||||
|
c.ForPut,
|
||||||
|
c.ForDelete,
|
||||||
|
c.ForHead,
|
||||||
|
c.ForRange,
|
||||||
|
c.ForRangeHash,
|
||||||
|
c.ForSearch,
|
||||||
|
c.ForGet,
|
||||||
|
}
|
||||||
|
|
||||||
|
setters[rand.Uint32()%uint32(len(setters))]()
|
||||||
|
|
||||||
|
c.ApplyTo(oidtest.Address())
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
Loading…
Reference in a new issue