diff --git a/go.mod b/go.mod index 4b13a1853..4dde3e0ba 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,8 @@ require ( go.uber.org/zap v1.26.0 ) +replace github.com/nspcc-dev/neofs-api-go/v2 v2.14.0 => ../neofs-api-go + require ( dario.cat/mergo v1.0.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect @@ -60,12 +62,12 @@ require ( golang.org/x/crypto v0.14.0 // indirect golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect golang.org/x/mod v0.13.0 // indirect - golang.org/x/net v0.16.0 // indirect + golang.org/x/net v0.17.0 // indirect golang.org/x/sys v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect golang.org/x/tools v0.14.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5 // indirect - google.golang.org/grpc v1.57.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect + google.golang.org/grpc v1.59.0 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index a6abce8d5..4f32d118a 100644 --- a/go.sum +++ b/go.sum @@ -71,8 +71,6 @@ github.com/nspcc-dev/hrw/v2 v2.0.0-20231115095647-bf62f4ad0a43 h1:zXkCRGTHqhkBRJ github.com/nspcc-dev/hrw/v2 v2.0.0-20231115095647-bf62f4ad0a43/go.mod h1:BGU4YsuoFXjQddsCfUXpq5uNr2A8W4PrWbiljdD/TpU= github.com/nspcc-dev/neo-go v0.102.0 h1:O2Gt4JPOWmp0c+PnPWwd2wPI74BKSwkaNCEyvyQTWJw= github.com/nspcc-dev/neo-go v0.102.0/go.mod h1:QXxpZxJT2KedwM0Nlj8UO0/fZN2WIe4h/i03uBHKbnc= -github.com/nspcc-dev/neofs-api-go/v2 v2.14.0 h1:jhuN8Ldqz7WApvUJRFY0bjRXE1R3iCkboMX5QVZhHVk= -github.com/nspcc-dev/neofs-api-go/v2 v2.14.0/go.mod h1:DRIr0Ic1s+6QgdqmNFNLIqMqd7lNMJfYwkczlm1hDtM= github.com/nspcc-dev/neofs-crypto v0.4.0 h1:5LlrUAM5O0k1+sH/sktBtrgfWtq1pgpDs09fZo+KYi4= github.com/nspcc-dev/neofs-crypto v0.4.0/go.mod h1:6XJ8kbXgOfevbI2WMruOtI+qUJXNwSGM/E9eClXxPHs= github.com/nspcc-dev/rfc6979 v0.2.0 h1:3e1WNxrN60/6N0DW7+UYisLeZJyfqZTNOjeV/toYvOE= @@ -91,7 +89,7 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/shirou/gopsutil/v3 v3.23.7 h1:C+fHO8hfIppoJ1WdsVm1RoI0RwXoNdfTK7yWXV0wVj4= github.com/shirou/gopsutil/v3 v3.23.7/go.mod h1:c4gnmoRC0hQuaLqvxnx1//VXQ0Ms/X9UnJF8pddY5z4= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= @@ -140,8 +138,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.16.0 h1:7eBu7KsSvFDtSXUIDbh3aqlK4DPsZ1rByC8PFfBThos= -golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -172,10 +170,10 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5 h1:eSaPbMR4T7WfH9FvABk36NBMacoTUKdWCvV0dx+KfOg= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5/go.mod h1:zBEcrKX2ZOcEkHWxBPAIvYUWOKKMIhYcmNiUIu2ji3I= -google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= -google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= +google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= diff --git a/object/object.go b/object/object.go index 9a3b8eeb7..f54360b4d 100644 --- a/object/object.go +++ b/object/object.go @@ -490,6 +490,29 @@ func (o *Object) SetChildren(v ...oid.ID) { }) } +// todo +func (o *Object) SetInitID(id oid.ID) { + var v2 refs.ObjectID + id.WriteToV2(&v2) + + o.setSplitFields(func(split *object.SplitHeader) { + split.SetInit(&v2) + }) +} + +// todo +func (o *Object) InitID() (v oid.ID, isSet bool) { + v2 := (*object.Object)(o) + + v2Init := v2.GetHeader().GetSplit().GetInit() + if v2Init != nil { + err := v.ReadFromV2(*v2Init) + isSet = (err == nil) + } + + return +} + // NotificationInfo groups information about object notification // that can be written to object. // diff --git a/object/object_copy.go b/object/object_copy.go index 7833af5d8..e5cbca2aa 100644 --- a/object/object_copy.go +++ b/object/object_copy.go @@ -90,6 +90,7 @@ func copySplitHeader(spl *object.SplitHeader) *object.SplitHeader { newSpl.SetParent(copyObjectID(spl.GetParent())) newSpl.SetPrevious(copyObjectID(spl.GetPrevious())) + newSpl.SetInit(copyObjectID(spl.GetInit())) newSpl.SetParentSignature(copySignature(spl.GetParentSignature())) newSpl.SetParentHeader(copyHeader(spl.GetParentHeader())) diff --git a/object/slicer/slicer.go b/object/slicer/slicer.go index a3a9e0a4e..60cdaf5c4 100644 --- a/object/slicer/slicer.go +++ b/object/slicer/slicer.go @@ -261,6 +261,7 @@ func initPayloadStream(ctx context.Context, ow ObjectWriter, header object.Objec owner: owner, currentEpoch: opts.currentNeoFSEpoch, sessionToken: opts.sessionToken, + withHomo: opts.withHomoChecksum, rootMeta: newDynamicObjectMetadata(opts.withHomoChecksum), childMeta: newDynamicObjectMetadata(opts.withHomoChecksum), prmObjectPutInit: prm, @@ -289,6 +290,7 @@ type PayloadWriter struct { owner user.ID currentEpoch uint64 sessionToken *session.Object + withHomo bool buf bytes.Buffer @@ -303,6 +305,7 @@ type PayloadWriter struct { writtenChildren []oid.ID prmObjectPutInit client.PrmObjectPutInit stubObject *object.Object + initObjID oid.ID } // Write writes next chunk of the object data. Concatenation of all chunks forms @@ -325,6 +328,11 @@ func (x *PayloadWriter) Write(chunk []byte) (int, error) { // to fill splitInfo in all child objects. x.withSplit = true + err = x.writeInitObject(x.ctx) + if err != nil { + return n, fmt.Errorf("write initial object: %w", err) + } + err = x.writeIntermediateChild(x.ctx, x.rootMeta) if err != nil { return n, fmt.Errorf("write 1st child: %w", err) @@ -369,6 +377,48 @@ func (x *PayloadWriter) ID() oid.ID { return x.rootID } +var emptyPayloadTZHash = tz.Sum([]byte{}) + +func (x *PayloadWriter) writeInitObject(ctx context.Context) error { + var initObj object.Object + + initObj.SetVersion(x.headerObject.Version()) + initObj.SetParent(&x.headerObject) + initObj.SetContainerID(x.container) + initObj.SetCreationEpoch(x.currentEpoch) + initObj.SetType(object.TypeInit) + initObj.SetOwnerID(&x.owner) + initObj.SetSessionToken(x.sessionToken) + initObj.SetSplitID(x.splitID) + initObj.SetPayload(nil) + initObj.SetPayloadSize(0) + if x.withHomo { + var cs checksum.Checksum + + cs.SetTillichZemor(emptyPayloadTZHash) + initObj.SetPayloadHomomorphicHash(cs) + } + + err := initObj.SetVerificationFields(x.signer) + if err != nil { + return fmt.Errorf("verification fields processing: %w", err) + } + + stream, err := x.stream.ObjectPutInit(ctx, initObj, x.signer, x.prmObjectPutInit) + if err != nil { + return fmt.Errorf("init data stream for the initial object: %w", err) + } + + err = stream.Close() + if err != nil { + return fmt.Errorf("finish initial object stream: %w", err) + } + + x.initObjID, _ = initObj.ID() + + return nil +} + // writeIntermediateChild writes intermediate split-chain element with specified // dynamicObjectMetadata to the configured ObjectWriter. func (x *PayloadWriter) writeIntermediateChild(ctx context.Context, meta dynamicObjectMetadata) error { @@ -390,9 +440,11 @@ func (x *PayloadWriter) _writeChild(ctx context.Context, meta dynamicObjectMetad obj.ResetParentID() obj.SetSignature(nil) obj.ResetID() + obj.ResetRelations() if x.withSplit { obj.SetSplitID(x.splitID) + obj.SetInitID(x.initObjID) } if len(x.writtenChildren) > 0 { obj.SetPreviousID(x.writtenChildren[len(x.writtenChildren)-1]) diff --git a/object/slicer/slicer_test.go b/object/slicer/slicer_test.go index 2d247aa88..6b032cb59 100644 --- a/object/slicer/slicer_test.go +++ b/object/slicer/slicer_test.go @@ -458,7 +458,10 @@ func (x *slicedObjectChecker) NetworkInfo(_ context.Context, _ client.PrmNetwork } func (x *slicedObjectChecker) ObjectPutInit(_ context.Context, hdr object.Object, _ user.Signer, _ client.PrmObjectPutInit) (client.ObjectWriter, error) { - checkStaticMetadata(x.tb, hdr, x.input) + checkStaticMetadata(x.tb, hdr, x.input, !x.chainCollector.firstObjectHandled) + if !x.chainCollector.firstObjectHandled { + x.chainCollector.firstObjectHandled = true + } buf := bytes.NewBuffer(nil) @@ -535,6 +538,10 @@ type chainCollector struct { first oid.ID firstHeader object.Object + firstObjectHandled bool + init oid.ID + initHeader object.Object + mNext map[oid.ID]oid.ID mPayloads map[oid.ID]payloadWithChecksum @@ -551,7 +558,7 @@ func newChainCollector(tb testing.TB) *chainCollector { } } -func checkStaticMetadata(tb testing.TB, header object.Object, in input) { +func checkStaticMetadata(tb testing.TB, header object.Object, in input, firstObject bool) { cnr, ok := header.ContainerID() require.True(tb, ok, "all objects must be bound to some container") require.True(tb, cnr.Equals(in.container), "the container must be set to the configured one") @@ -568,7 +575,11 @@ func checkStaticMetadata(tb testing.TB, header object.Object, in input) { require.NotNil(tb, ver, "version must be set in all objects") require.Equal(tb, version.Current(), *ver, "the version must be set to current SDK one") - require.Equal(tb, object.TypeRegular, header.Type(), "only regular objects must be produced") + if header.SplitID() != nil && firstObject { + require.Equal(tb, object.TypeInit, header.Type(), "first objects must be of init type") + } else { + require.Equal(tb, object.TypeRegular, header.Type(), "non-first objects must be regular") + } require.EqualValues(tb, in.currentEpoch, header.CreationEpoch(), "configured current epoch must be set as creation epoch") require.Equal(tb, in.sessionToken, header.SessionToken(), "configured session token must be written into objects") @@ -600,7 +611,7 @@ func (x *chainCollector) handleOutgoingObject(header object.Object, payload io.R } parent := header.Parent() - if parent != nil { + if parent != nil && header.Type() == object.TypeRegular { // check only link and last object, not the init one require.Nil(x.tb, parent.Parent(), "multi-level genealogy is not supported") if x.parentHeaderSet { @@ -621,6 +632,11 @@ func (x *chainCollector) handleOutgoingObject(header object.Object, payload io.R } x.mNext[prev] = id + } else if header.Type() == object.TypeInit { + require.Empty(x.tb, header.Children(), "initial part must know nothing about child objects") + + x.init, _ = header.ID() + x.initHeader = header } else if len(header.Children()) == 0 { // 1st split-chain or linking object require.False(x.tb, x.firstSet, "there must not be multiple split-chains") x.firstSet = true @@ -704,7 +720,7 @@ func (x *chainCollector) verify(in input, rootID oid.ID) { require.True(x.tb, ok, "root object must have an ID") require.True(x.tb, id.Equals(rootID), "root ID in root object must be returned in the result") - checkStaticMetadata(x.tb, rootObj, in) + checkStaticMetadata(x.tb, rootObj, in, false) attrs := rootObj.Attributes() require.Len(x.tb, attrs, len(in.attributes)) @@ -789,7 +805,7 @@ func TestSlicedObjectsHaveSplitID(t *testing.T) { _, err = sl.Put(ctx, bytes.NewBuffer(payload), nil) require.NoError(t, err) - require.Equal(t, overheadAmount+1, uint64(len(writer.headers))) + require.Equal(t, overheadAmount+2, uint64(len(writer.headers))) for _, h := range writer.headers { splitID := h.SplitID() @@ -820,7 +836,7 @@ func TestSlicedObjectsHaveSplitID(t *testing.T) { } require.NoError(t, payloadWriter.Close()) - require.Equal(t, overheadAmount+1, uint64(len(writer.headers))) + require.Equal(t, overheadAmount+2, uint64(len(writer.headers))) for _, h := range writer.headers { splitID := h.SplitID() diff --git a/object/splitinfo.go b/object/splitinfo.go index f4c83deef..b97fadebe 100644 --- a/object/splitinfo.go +++ b/object/splitinfo.go @@ -109,6 +109,27 @@ func (s *SplitInfo) SetLink(v oid.ID) { (*object.SplitInfo)(s).SetLink(&idV2) } +// todo +func (s SplitInfo) InitPart() (v oid.ID, isSet bool) { + v2 := (object.SplitInfo)(s) + + initV2 := v2.GetInitPart() + if initV2 != nil { + _ = v.ReadFromV2(*initV2) + isSet = true + } + + return +} + +// todo +func (s *SplitInfo) SetInitPart(v oid.ID) { + var idV2 refs.ObjectID + v.WriteToV2(&idV2) + + (*object.SplitInfo)(s).SetInitPart(&idV2) +} + // Marshal marshals [SplitInfo] into a protobuf binary form. // // See also [SplitInfo.Unmarshal]. @@ -147,12 +168,13 @@ func (s *SplitInfo) UnmarshalJSON(data []byte) error { return formatCheckSI((*object.SplitInfo)(s)) } -var errSplitInfoMissingFields = errors.New("neither link object ID nor last part object ID is set") +var errSplitInfoMissingFields = errors.New("neither link object ID nor last part object ID not init part object ID is set") func formatCheckSI(v2 *object.SplitInfo) error { link := v2.GetLink() lastPart := v2.GetLastPart() - if link == nil && lastPart == nil { + initPart := v2.GetInitPart() + if link == nil && lastPart == nil && initPart == nil { return errSplitInfoMissingFields } @@ -172,5 +194,12 @@ func formatCheckSI(v2 *object.SplitInfo) error { } } + if initPart != nil { + err := oID.ReadFromV2(*initPart) + if err != nil { + return fmt.Errorf("could not convert last part object ID: %w", err) + } + } + return nil } diff --git a/object/splitinfo_test.go b/object/splitinfo_test.go index 7c13f2cab..9502076da 100644 --- a/object/splitinfo_test.go +++ b/object/splitinfo_test.go @@ -16,6 +16,7 @@ func TestSplitInfo(t *testing.T) { splitID := object.NewSplitID() lastPart := generateID() link := generateID() + initPart := generateID() s.SetSplitID(splitID) require.Equal(t, splitID, s.SplitID()) @@ -29,6 +30,11 @@ func TestSplitInfo(t *testing.T) { l, set := s.Link() require.True(t, set) require.Equal(t, link, l) + + s.SetInitPart(initPart) + ip, set := s.InitPart() + require.True(t, set) + require.Equal(t, initPart, ip) } func TestSplitInfoMarshal(t *testing.T) { @@ -49,11 +55,12 @@ func TestSplitInfoMarshal(t *testing.T) { require.Equal(t, s, newS) } - t.Run("good, both fields are set", func(t *testing.T) { + t.Run("good, all fields are set", func(t *testing.T) { s := object.NewSplitInfo() s.SetSplitID(object.NewSplitID()) s.SetLink(generateID()) s.SetLastPart(generateID()) + s.SetInitPart(generateID()) testToV2(t, s) testMarshal(t, s) @@ -74,6 +81,14 @@ func TestSplitInfoMarshal(t *testing.T) { testToV2(t, s) testMarshal(t, s) }) + t.Run("good, only init part is set", func(t *testing.T) { + s := object.NewSplitInfo() + s.SetSplitID(object.NewSplitID()) + s.SetInitPart(generateID()) + + testToV2(t, s) + testMarshal(t, s) + }) t.Run("bad, no fields are set", func(t *testing.T) { s := object.NewSplitInfo() s.SetSplitID(object.NewSplitID()) @@ -120,6 +135,8 @@ func TestNewSplitInfo(t *testing.T) { require.False(t, set) _, set = si.Link() require.False(t, set) + _, set = si.InitPart() + require.False(t, set) // convert to v2 message siV2 := si.ToV2() @@ -127,6 +144,7 @@ func TestNewSplitInfo(t *testing.T) { require.Nil(t, siV2.GetSplitID()) require.Nil(t, siV2.GetLastPart()) require.Nil(t, siV2.GetLink()) + require.Nil(t, siV2.GetInitPart()) }) } @@ -136,6 +154,7 @@ func TestSplitInfoMarshalJSON(t *testing.T) { s.SetSplitID(object.NewSplitID()) s.SetLastPart(generateID()) s.SetLink(generateID()) + s.SetInitPart(generateID()) data, err := s.MarshalJSON() require.NoError(t, err) @@ -152,4 +171,8 @@ func TestSplitInfoMarshalJSON(t *testing.T) { data := `{"splitId":"Sn707289RrqDyJOrZMbMoQ==","lastPart":{"value":"bad"},"link":{"value":"eRyPNCNNxHfxPcjijlv05HEcdoep/b7eHNLRSmDlnts="}}` require.Error(t, json.Unmarshal([]byte(data), object.NewSplitInfo())) }) + t.Run("bad init part", func(t *testing.T) { + data := `{"splitId":"Sn707289RrqDyJOrZMbMoQ==","initPart":{"value":"bad"},"link":{"value":"eRyPNCNNxHfxPcjijlv05HEcdoep/b7eHNLRSmDlnts="}}` + require.Error(t, json.Unmarshal([]byte(data), object.NewSplitInfo())) + }) } diff --git a/object/type.go b/object/type.go index 58ea41174..0ef6caaf6 100644 --- a/object/type.go +++ b/object/type.go @@ -12,6 +12,7 @@ const ( TypeTombstone TypeStorageGroup TypeLock + TypeInit ) // ToV2 converts [Type] to v2 [object.Type]. @@ -31,6 +32,7 @@ func TypeFromV2(t object.Type) Type { // - [TypeStorageGroup]: STORAGE_GROUP; // - [TypeLock]: LOCK; // - [TypeRegular], default: REGULAR. +// - [TypeInit], default: INIT. func (t Type) EncodeToString() string { return t.ToV2().String() } diff --git a/object/type_test.go b/object/type_test.go index e83cef714..99a251b76 100644 --- a/object/type_test.go +++ b/object/type_test.go @@ -29,6 +29,10 @@ func TestType_ToV2(t *testing.T) { t: object.TypeLock, t2: v2object.TypeLock, }, + { + t: object.TypeInit, + t2: v2object.TypeInit, + }, } for _, item := range typs { @@ -50,6 +54,7 @@ func TestType_String(t *testing.T) { {val: toPtr(object.TypeStorageGroup), str: "STORAGE_GROUP"}, {val: toPtr(object.TypeRegular), str: "REGULAR"}, {val: toPtr(object.TypeLock), str: "LOCK"}, + {val: toPtr(object.TypeInit), str: "INIT"}, }) }