package container import ( "crypto/ecdsa" "encoding/hex" "testing" "time" containercore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/container" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client" cntClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/container" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/frostfsid" containerEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/container" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger/test" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" containerSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/acl" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto" frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/version" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/network/payload" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/stretchr/testify/require" ) func TestPutEvent(t *testing.T) { t.Parallel() nst := &testNetworkState{ homHashDisabled: true, epoch: 100, } cc := &testContainerClient{ get: make(map[string]*containercore.Container), } proc, err := New(&Params{ Log: test.NewLogger(t, true), PoolSize: 2, AlphabetState: &testAlphabetState{isAlphabet: true}, FrostFSIDClient: &testIDClient{}, NotaryDisabled: true, NetworkState: nst, ContainerClient: cc, }) require.NoError(t, err, "failed to create processor") p, err := keys.NewPrivateKey() require.NoError(t, err) var usr user.ID user.IDFromKey(&usr, (ecdsa.PublicKey)(*p.PublicKey())) var pp netmap.PlacementPolicy pp.AddReplicas(netmap.ReplicaDescriptor{}) var cnr containerSDK.Container cnr.Init() cnr.SetOwner(usr) cnr.SetPlacementPolicy(pp) cnr.SetBasicACL(acl.Private) containerSDK.DisableHomomorphicHashing(&cnr) event := &testPutEvent{ cnr: &cnr, pk: p, st: nil, } proc.handlePut(event) for proc.pool.Running() > 0 { time.Sleep(10 * time.Millisecond) } var expectedPut cntClient.PutPrm expectedPut.SetContainer(cnr.Marshal()) expectedPut.SetKey(p.PublicKey().Bytes()) expectedPut.SetSignature(p.Sign(cnr.Marshal())) expectedPut.SetZone("container") require.EqualValues(t, []cntClient.PutPrm{expectedPut}, cc.put, "invalid put requests") } func TestDeleteEvent(t *testing.T) { t.Parallel() nst := &testNetworkState{ homHashDisabled: true, epoch: 100, } cc := &testContainerClient{ get: make(map[string]*containercore.Container), } p, err := keys.NewPrivateKey() require.NoError(t, err) idc := &testIDClient{ publicKeys: []*keys.PublicKey{ p.PublicKey(), }, } proc, err := New(&Params{ Log: test.NewLogger(t, true), PoolSize: 2, AlphabetState: &testAlphabetState{isAlphabet: true}, FrostFSIDClient: idc, NotaryDisabled: true, NetworkState: nst, ContainerClient: cc, }) require.NoError(t, err, "failed to create processor") var usr user.ID user.IDFromKey(&usr, (ecdsa.PublicKey)(*p.PublicKey())) var pp netmap.PlacementPolicy pp.AddReplicas(netmap.ReplicaDescriptor{}) var cnr containerSDK.Container cnr.Init() cnr.SetOwner(usr) cnr.SetPlacementPolicy(pp) cnr.SetBasicACL(acl.Private) containerSDK.DisableHomomorphicHashing(&cnr) var cid cid.ID containerSDK.CalculateID(&cid, cnr) cidBin := make([]byte, 32) cid.Encode(cidBin) ev := containerEvent.Delete{ ContainerIDValue: cidBin, SignatureValue: p.Sign(cidBin), } var signature frostfscrypto.Signature signer := frostfsecdsa.Signer(p.PrivateKey) require.NoError(t, signature.Calculate(signer, ev.ContainerID()), "failed to calculate signature") cc.get[hex.EncodeToString(ev.ContainerID())] = &containercore.Container{ Value: cnr, Signature: signature, } proc.handleDelete(ev) for proc.pool.Running() > 0 { time.Sleep(10 * time.Millisecond) } var expectedDelete cntClient.DeletePrm expectedDelete.SetCID(ev.ContainerID()) expectedDelete.SetSignature(ev.Signature()) require.EqualValues(t, []cntClient.DeletePrm{expectedDelete}, cc.delete, "invalid delete requests") } func TestSetEACLEvent(t *testing.T) { t.Parallel() nst := &testNetworkState{ homHashDisabled: true, epoch: 100, } cc := &testContainerClient{ get: make(map[string]*containercore.Container), } proc, err := New(&Params{ Log: test.NewLogger(t, true), PoolSize: 2, AlphabetState: &testAlphabetState{isAlphabet: true}, FrostFSIDClient: &testIDClient{}, NotaryDisabled: true, NetworkState: nst, ContainerClient: cc, }) require.NoError(t, err, "failed to create processor") p, err := keys.NewPrivateKey() require.NoError(t, err) var usr user.ID user.IDFromKey(&usr, (ecdsa.PublicKey)(*p.PublicKey())) var pp netmap.PlacementPolicy pp.AddReplicas(netmap.ReplicaDescriptor{}) var cnr containerSDK.Container cnr.Init() cnr.SetOwner(usr) cnr.SetPlacementPolicy(pp) cnr.SetBasicACL(acl.PrivateExtended) containerSDK.DisableHomomorphicHashing(&cnr) var cid cid.ID containerSDK.CalculateID(&cid, cnr) cidBytes := make([]byte, 32) cid.Encode(cidBytes) var signature frostfscrypto.Signature signer := frostfsecdsa.Signer(p.PrivateKey) require.NoError(t, signature.Calculate(signer, cidBytes), "failed to calculate signature") cc.get[hex.EncodeToString(cidBytes)] = &containercore.Container{ Value: cnr, Signature: signature, } table := eacl.NewTable() table.SetCID(cid) table.SetVersion(version.Current()) r := &eacl.Record{} r.AddObjectContainerIDFilter(eacl.MatchStringEqual, cid) table.AddRecord(r) event := containerEvent.SetEACL{ TableValue: table.ToV2().StableMarshal(nil), PublicKeyValue: p.PublicKey().Bytes(), SignatureValue: p.Sign(table.ToV2().StableMarshal(nil)), } proc.handleSetEACL(event) for proc.pool.Running() > 0 { time.Sleep(10 * time.Millisecond) } var expectedPutEACL cntClient.PutEACLPrm expectedPutEACL.SetTable(table.ToV2().StableMarshal(nil)) expectedPutEACL.SetKey(p.PublicKey().Bytes()) expectedPutEACL.SetSignature(p.Sign(table.ToV2().StableMarshal(nil))) require.EqualValues(t, []cntClient.PutEACLPrm{expectedPutEACL}, cc.putEACL, "invalid set EACL requests") } type testAlphabetState struct { isAlphabet bool } func (s *testAlphabetState) IsAlphabet() bool { return s.isAlphabet } type testNetworkState struct { homHashDisabled bool epoch uint64 } func (s *testNetworkState) HomomorphicHashDisabled() (bool, error) { return s.homHashDisabled, nil } func (s *testNetworkState) Epoch() (uint64, error) { return s.epoch, nil } type testContainerClient struct { contractAddress util.Uint160 put []cntClient.PutPrm get map[string]*containercore.Container delete []cntClient.DeletePrm putEACL []cntClient.PutEACLPrm } func (c *testContainerClient) ContractAddress() util.Uint160 { return c.contractAddress } func (c *testContainerClient) Morph() *client.Client { return nil } func (c *testContainerClient) Put(p cntClient.PutPrm) error { c.put = append(c.put, p) return nil } func (c *testContainerClient) Get(cid []byte) (*containercore.Container, error) { key := hex.EncodeToString(cid) if cont, found := c.get[key]; found { return cont, nil } return nil, apistatus.ContainerNotFound{} } func (c *testContainerClient) Delete(p cntClient.DeletePrm) error { c.delete = append(c.delete, p) return nil } func (c *testContainerClient) PutEACL(p cntClient.PutEACLPrm) error { c.putEACL = append(c.putEACL, p) return nil } type testIDClient struct { publicKeys keys.PublicKeys } func (c *testIDClient) AccountKeys(p frostfsid.AccountKeysPrm) (keys.PublicKeys, error) { return c.publicKeys, nil } var _ putEvent = &testPutEvent{} type testPutEvent struct { cnr *containerSDK.Container pk *keys.PrivateKey st []byte } func (e *testPutEvent) MorphEvent() {} func (e *testPutEvent) Container() []byte { return e.cnr.Marshal() } func (e *testPutEvent) PublicKey() []byte { return e.pk.PublicKey().Bytes() } func (e *testPutEvent) Signature() []byte { return e.pk.Sign(e.cnr.Marshal()) } func (e *testPutEvent) SessionToken() []byte { return e.st } func (e *testPutEvent) NotaryRequest() *payload.P2PNotaryRequest { return nil }