[#1255] node/session: Add persistent tests
Signed-off-by: Pavel Karpy <carpawell@nspcc.ru>
This commit is contained in:
parent
455b9fb325
commit
a884ad56d9
2 changed files with 252 additions and 0 deletions
226
pkg/services/session/storage/persistent/executor_test.go
Normal file
226
pkg/services/session/storage/persistent/executor_test.go
Normal file
|
@ -0,0 +1,226 @@
|
||||||
|
package persistent
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"crypto/elliptic"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/v2/session"
|
||||||
|
ownerSDK "github.com/nspcc-dev/neofs-sdk-go/owner"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"go.etcd.io/bbolt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTokenStore(t *testing.T) {
|
||||||
|
ts, err := NewTokenStore(filepath.Join(t.TempDir(), ".storage"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
owner := new(refs.OwnerID)
|
||||||
|
owner.SetValue([]byte{0, 1, 2, 3, 4, 5})
|
||||||
|
|
||||||
|
req := new(session.CreateRequestBody)
|
||||||
|
req.SetOwnerID(owner)
|
||||||
|
|
||||||
|
const tokenNumber = 5
|
||||||
|
|
||||||
|
type tok struct {
|
||||||
|
id []byte
|
||||||
|
key []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
tokens := make([]tok, 0, tokenNumber)
|
||||||
|
|
||||||
|
for i := 0; i < tokenNumber; i++ {
|
||||||
|
req.SetExpiration(uint64(i))
|
||||||
|
|
||||||
|
res, err := ts.Create(context.Background(), req)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
tokens = append(tokens, tok{
|
||||||
|
id: res.GetID(),
|
||||||
|
key: res.GetSessionKey(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, token := range tokens {
|
||||||
|
savedToken := ts.Get(ownerSDK.NewIDFromV2(owner), token.id)
|
||||||
|
|
||||||
|
require.Equal(t, uint64(i), savedToken.ExpiredAt())
|
||||||
|
|
||||||
|
equalKeys(t, token.key, savedToken.SessionKey())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTokenStore_Persistent(t *testing.T) {
|
||||||
|
path := filepath.Join(t.TempDir(), ".storage")
|
||||||
|
|
||||||
|
ts, err := NewTokenStore(path)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
owner := new(refs.OwnerID)
|
||||||
|
owner.SetValue([]byte{0, 1, 2, 3, 4, 5})
|
||||||
|
|
||||||
|
const exp = 12345
|
||||||
|
|
||||||
|
req := new(session.CreateRequestBody)
|
||||||
|
req.SetOwnerID(owner)
|
||||||
|
req.SetExpiration(exp)
|
||||||
|
|
||||||
|
res, err := ts.Create(context.Background(), req)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
id := res.GetID()
|
||||||
|
pubKey := res.GetSessionKey()
|
||||||
|
|
||||||
|
// close db (stop the node)
|
||||||
|
require.NoError(t, ts.Close())
|
||||||
|
|
||||||
|
// open persistent storage again
|
||||||
|
ts, err = NewTokenStore(path)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
savedToken := ts.Get(ownerSDK.NewIDFromV2(owner), id)
|
||||||
|
|
||||||
|
equalKeys(t, pubKey, savedToken.SessionKey())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTokenStore_RemoveOld(t *testing.T) {
|
||||||
|
tests := []*struct {
|
||||||
|
epoch uint64
|
||||||
|
id, key []byte
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
epoch: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
epoch: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
epoch: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
epoch: 4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
epoch: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
epoch: 6,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ts, err := NewTokenStore(filepath.Join(t.TempDir(), ".storage"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
owner := new(refs.OwnerID)
|
||||||
|
owner.SetValue([]byte{0, 1, 2, 3, 4, 5})
|
||||||
|
|
||||||
|
req := new(session.CreateRequestBody)
|
||||||
|
req.SetOwnerID(owner)
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
req.SetExpiration(test.epoch)
|
||||||
|
|
||||||
|
res, err := ts.Create(context.Background(), req)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
test.id = res.GetID()
|
||||||
|
test.key = res.GetSessionKey()
|
||||||
|
}
|
||||||
|
|
||||||
|
const currEpoch = 3
|
||||||
|
|
||||||
|
ts.RemoveOld(currEpoch)
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
token := ts.Get(ownerSDK.NewIDFromV2(owner), test.id)
|
||||||
|
|
||||||
|
if test.epoch <= currEpoch {
|
||||||
|
require.Nil(t, token)
|
||||||
|
} else {
|
||||||
|
equalKeys(t, test.key, token.SessionKey())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This test was added to fix bolt's behaviour since the persistent
|
||||||
|
// storage uses cursor and there is an issue about `cursor.Delete`
|
||||||
|
// method: https://github.com/etcd-io/bbolt/issues/146.
|
||||||
|
//
|
||||||
|
// If this test is passing, TokenStore works correctly.
|
||||||
|
func TestBolt_Cursor(t *testing.T) {
|
||||||
|
db, err := bbolt.Open(filepath.Join(t.TempDir(), ".storage"), 0666, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
cursorKeys := make(map[string]struct{})
|
||||||
|
|
||||||
|
var bucketName = []byte("bucket")
|
||||||
|
|
||||||
|
err = db.Update(func(tx *bbolt.Tx) (err error) {
|
||||||
|
b, err := tx.CreateBucket(bucketName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
put := func(s []byte) {
|
||||||
|
if err == nil {
|
||||||
|
err = b.Put(s, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
put([]byte("1"))
|
||||||
|
put([]byte("2"))
|
||||||
|
put([]byte("3"))
|
||||||
|
put([]byte("4"))
|
||||||
|
|
||||||
|
return
|
||||||
|
})
|
||||||
|
|
||||||
|
err = db.Update(func(tx *bbolt.Tx) error {
|
||||||
|
b := tx.Bucket(bucketName)
|
||||||
|
c := b.Cursor()
|
||||||
|
|
||||||
|
for k, _ := c.First(); k != nil; k, _ = c.Next() {
|
||||||
|
// fill key that was viewed
|
||||||
|
cursorKeys[string(k)] = struct{}{}
|
||||||
|
|
||||||
|
if bytes.Equal(k, []byte("1")) {
|
||||||
|
// delete the first one
|
||||||
|
err = c.Delete()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, ok := cursorKeys["2"]
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("unexpectedly skipped '2' value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func equalKeys(t *testing.T, sessionKey []byte, savedPrivateKey *ecdsa.PrivateKey) {
|
||||||
|
returnedPubKey, err := keys.NewPublicKeyFromBytes(sessionKey, elliptic.P256())
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
savedPubKey := (keys.PublicKey)(savedPrivateKey.PublicKey)
|
||||||
|
|
||||||
|
require.Equal(t, true, returnedPubKey.Equal(&savedPubKey))
|
||||||
|
}
|
26
pkg/services/session/storage/persistent/util_test.go
Normal file
26
pkg/services/session/storage/persistent/util_test.go
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
package persistent
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPack(t *testing.T) {
|
||||||
|
key, err := keys.NewPrivateKey()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
const exp = 12345
|
||||||
|
|
||||||
|
raw, err := packToken(exp, &key.PrivateKey)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, uint64(exp), epochFromToken(raw))
|
||||||
|
|
||||||
|
unpacked, err := unpackToken(raw)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, uint64(exp), unpacked.ExpiredAt())
|
||||||
|
require.Equal(t, true, key.Equal(unpacked.SessionKey()))
|
||||||
|
}
|
Loading…
Reference in a new issue