[#170] audit: Refactor and document package functionality

Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
Leonard Lyubich 2022-03-14 14:30:07 +03:00 committed by Alex Vanin
parent 48150852f3
commit 7d31de57ec
5 changed files with 458 additions and 362 deletions

24
audit/doc.go Normal file
View file

@ -0,0 +1,24 @@
/*
Package audit provides features to process data audit in NeoFS system.
Result type groups values which can be gathered during data audit process:
var res audit.Result
res.ForEpoch(32)
res.ForContainer(cnr)
// ...
res.Complete()
Result instances can be stored in a binary format. On reporter side:
data := res.Marshal()
// send data
On receiver side:
var res audit.Result
err := res.Unmarshal(data)
// ...
Using package types in an application is recommended to potentially work with
different protocol versions with which these types are compatible.
*/
package audit

View file

@ -2,290 +2,316 @@ package audit
import ( import (
"github.com/nspcc-dev/neofs-api-go/v2/audit" "github.com/nspcc-dev/neofs-api-go/v2/audit"
"github.com/nspcc-dev/neofs-api-go/v2/refs"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id" cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id" oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
"github.com/nspcc-dev/neofs-sdk-go/version" "github.com/nspcc-dev/neofs-sdk-go/version"
) )
// Result represents v2-compatible data audit result. // Result represents report on the results of the data audit in NeoFS system.
type Result audit.DataAuditResult
// NewFromV2 wraps v2 DataAuditResult message to Result.
// //
// Nil audit.DataAuditResult converts to nil. // Result is mutually binary-compatible with github.com/nspcc-dev/neofs-api-go/v2/audit.DataAuditResult
func NewResultFromV2(aV2 *audit.DataAuditResult) *Result { // message. See Marshal / Unmarshal methods.
return (*Result)(aV2)
}
// New creates and initializes blank Result.
// //
// Defaults: // Instances can be created using built-in var declaration.
// - version: version.Current(); type Result struct {
// - complete: false; versionEncoded bool
// - cid: nil;
// - pubKey: nil;
// - passSG, failSG: nil;
// - failNodes, passNodes: nil;
// - hit, miss, fail: 0;
// - requests, retries: 0;
// - auditEpoch: 0.
func NewResult() *Result {
r := NewResultFromV2(new(audit.DataAuditResult))
r.SetVersion(version.Current())
return r v2 audit.DataAuditResult
} }
// ToV2 converts Result to v2 DataAuditResult message. // Marshal encodes Result into a canonical NeoFS binary format (Protocol Buffers
// with direct field order).
// //
// Nil Result converts to nil. // Writes version.Current() protocol version into the resulting message if Result
func (r *Result) ToV2() *audit.DataAuditResult { // hasn't been already decoded from such a message using Unmarshal.
return (*audit.DataAuditResult)(r) //
// See also Unmarshal.
func (r *Result) Marshal() []byte {
if !r.versionEncoded {
r.v2.SetVersion(version.Current().ToV2())
r.versionEncoded = true
}
data, err := r.v2.StableMarshal(nil)
if err != nil {
panic(err)
}
return data
} }
// Marshal marshals Result into a protobuf binary form. // Unmarshal decodes Result from its canonical NeoFS binary format (Protocol Buffers
func (r *Result) Marshal() ([]byte, error) { // with direct field order). Returns an error describing a format violation.
return (*audit.DataAuditResult)(r).StableMarshal(nil) //
} // See also Marshal.
// Unmarshal unmarshals protobuf binary representation of Result.
func (r *Result) Unmarshal(data []byte) error { func (r *Result) Unmarshal(data []byte) error {
return (*audit.DataAuditResult)(r).Unmarshal(data) err := r.v2.Unmarshal(data)
} if err == nil {
r.versionEncoded = true
// MarshalJSON encodes Result to protobuf JSON format.
func (r *Result) MarshalJSON() ([]byte, error) {
return (*audit.DataAuditResult)(r).MarshalJSON()
}
// UnmarshalJSON decodes Result from protobuf JSON format.
func (r *Result) UnmarshalJSON(data []byte) error {
return (*audit.DataAuditResult)(r).UnmarshalJSON(data)
}
// Version returns Data Audit structure version.
func (r *Result) Version() *version.Version {
return version.NewFromV2(
(*audit.DataAuditResult)(r).GetVersion())
}
// SetVersion sets Data Audit structure version.
func (r *Result) SetVersion(v *version.Version) {
(*audit.DataAuditResult)(r).SetVersion(v.ToV2())
}
// AuditEpoch returns epoch number when the Data Audit was conducted.
func (r *Result) AuditEpoch() uint64 {
return (*audit.DataAuditResult)(r).GetAuditEpoch()
}
// SetAuditEpoch sets epoch number when the Data Audit was conducted.
func (r *Result) SetAuditEpoch(epoch uint64) {
(*audit.DataAuditResult)(r).SetAuditEpoch(epoch)
}
// ContainerID returns container under audit.
func (r *Result) ContainerID() *cid.ID {
return cid.NewFromV2(
(*audit.DataAuditResult)(r).GetContainerID())
}
// SetContainerID sets container under audit.
func (r *Result) SetContainerID(id *cid.ID) {
(*audit.DataAuditResult)(r).SetContainerID(id.ToV2())
}
// PublicKey returns public key of the auditing InnerRing node in a binary format.
func (r *Result) PublicKey() []byte {
return (*audit.DataAuditResult)(r).GetPublicKey()
}
// SetPublicKey sets public key of the auditing InnerRing node in a binary format.
func (r *Result) SetPublicKey(key []byte) {
(*audit.DataAuditResult)(r).SetPublicKey(key)
}
// Complete returns completion state of audit result.
func (r *Result) Complete() bool {
return (*audit.DataAuditResult)(r).GetComplete()
}
// SetComplete sets completion state of audit result.
func (r *Result) SetComplete(v bool) {
(*audit.DataAuditResult)(r).SetComplete(v)
}
// Requests returns number of requests made by PoR audit check to get
// all headers of the objects inside storage groups.
func (r *Result) Requests() uint32 {
return (*audit.DataAuditResult)(r).GetRequests()
}
// SetRequests sets number of requests made by PoR audit check to get
// all headers of the objects inside storage groups.
func (r *Result) SetRequests(v uint32) {
(*audit.DataAuditResult)(r).SetRequests(v)
}
// Retries returns number of retries made by PoR audit check to get
// all headers of the objects inside storage groups.
func (r *Result) Retries() uint32 {
return (*audit.DataAuditResult)(r).GetRetries()
}
// SetRetries sets number of retries made by PoR audit check to get
// all headers of the objects inside storage groups.
func (r *Result) SetRetries(v uint32) {
(*audit.DataAuditResult)(r).SetRetries(v)
}
// PassSG returns list of Storage Groups that passed audit PoR stage.
func (r *Result) PassSG() []oid.ID {
mV2 := (*audit.DataAuditResult)(r).
GetPassSG()
if mV2 == nil {
return nil
} }
m := make([]oid.ID, len(mV2)) return err
for i := range mV2 {
m[i] = *oid.NewIDFromV2(&mV2[i])
}
return m
} }
// SetPassSG sets list of Storage Groups that passed audit PoR stage. // Epoch returns NeoFS epoch when the data associated with the Result was audited.
func (r *Result) SetPassSG(list []oid.ID) { //
mV2 := (*audit.DataAuditResult)(r). // Zero Result has zero epoch.
GetPassSG() //
// See also ForEpoch.
func (r Result) Epoch() uint64 {
return r.v2.GetAuditEpoch()
}
if list == nil { // ForEpoch specifies NeoFS epoch when the data associated with the Result was audited.
mV2 = nil //
} else { // See also Epoch.
ln := len(list) func (r *Result) ForEpoch(epoch uint64) {
r.v2.SetAuditEpoch(epoch)
}
if cap(mV2) >= ln { // Container returns identifier of the container with which the data audit Result
mV2 = mV2[:0] // is associated.
} else { //
mV2 = make([]refs.ObjectID, ln) // Returns nil if container is not specified. Zero Result has nil container.
} // Return value MUST NOT be mutated: to do this, first make a copy.
//
// See also ForContainer.
func (r Result) Container() *cid.ID {
return cid.NewFromV2(r.v2.GetContainerID())
}
for i := 0; i < ln; i++ { // ForContainer returns identifier of the container with which the data audit Result
mV2[i] = *list[i].ToV2() // is associated.
//
// See also Container.
func (r *Result) ForContainer(cnr cid.ID) {
r.v2.SetContainerID(cnr.ToV2())
}
// AuditorKey returns public key of the auditing NeoFS Inner Ring node in
// a NeoFS binary key format.
//
// Zero Result has nil key. Return value MUST NOT be mutated: to do this,
// first make a copy.
//
// See also SetAuditorPublicKey.
func (r Result) AuditorKey() []byte {
return r.v2.GetPublicKey()
}
// SetAuditorKey specifies public key of the auditing NeoFS Inner Ring node in
// a NeoFS binary key format.
//
// Argument MUST NOT be mutated at least until the end of using the Result.
//
// See also AuditorKey.
func (r *Result) SetAuditorKey(key []byte) {
r.v2.SetPublicKey(key)
}
// Completed returns completion state of the data audit associated with the Result.
//
// Zero Result corresponds to incomplete data audit.
//
// See also Complete.
func (r Result) Completed() bool {
return r.v2.GetComplete()
}
// Complete marks the data audit associated with the Result as completed.
//
// See also Completed.
func (r *Result) Complete() {
r.v2.SetComplete(true)
}
// RequestsPoR returns number of requests made by Proof-of-Retrievability
// audit check to get all headers of the objects inside storage groups.
//
// Zero Result has zero requests.
//
// See also SetRequestsPoR.
func (r Result) RequestsPoR() uint32 {
return r.v2.GetRequests()
}
// SetRequestsPoR sets number of requests made by Proof-of-Retrievability
// audit check to get all headers of the objects inside storage groups.
//
// See also RequestsPoR.
func (r *Result) SetRequestsPoR(v uint32) {
r.v2.SetRequests(v)
}
// RetriesPoR returns number of retries made by Proof-of-Retrievability
// audit check to get all headers of the objects inside storage groups.
//
// Zero Result has zero retries.
//
// See also SetRetriesPoR.
func (r Result) RetriesPoR() uint32 {
return r.v2.GetRetries()
}
// SetRetriesPoR sets number of retries made by Proof-of-Retrievability
// audit check to get all headers of the objects inside storage groups.
//
// See also RetriesPoR.
func (r *Result) SetRetriesPoR(v uint32) {
r.v2.SetRetries(v)
}
// IteratePassedStorageGroups iterates over all storage groups that passed
// Proof-of-Retrievability audit check and passes them into f. Breaks on f's
// false return, f MUST NOT be nil.
//
// Zero Result has no passed storage groups and doesn't call f.
//
// See also SubmitPassedStorageGroup.
func (r Result) IteratePassedStorageGroups(f func(oid.ID) bool) {
r2 := r.v2.GetPassSG()
for i := range r2 {
if !f(*oid.NewIDFromV2(&r2[i])) {
return
} }
} }
(*audit.DataAuditResult)(r).SetPassSG(mV2)
} }
// FailSG returns list of Storage Groups that failed audit PoR stage. // SubmitPassedStorageGroup marks storage group as passed Proof-of-Retrievability
func (r *Result) FailSG() []oid.ID { // audit check.
mV2 := (*audit.DataAuditResult)(r). //
GetFailSG() // See also IteratePassedStorageGroups.
func (r *Result) SubmitPassedStorageGroup(sg oid.ID) {
if mV2 == nil { r.v2.SetPassSG(append(r.v2.GetPassSG(), *sg.ToV2()))
return nil
}
m := make([]oid.ID, len(mV2))
for i := range mV2 {
m[i] = *oid.NewIDFromV2(&mV2[i])
}
return m
} }
// SetFailSG sets list of Storage Groups that failed audit PoR stage. // IterateFailedStorageGroups is similar to IteratePassedStorageGroups but for failed groups.
func (r *Result) SetFailSG(list []oid.ID) { //
mV2 := (*audit.DataAuditResult)(r). // See also SubmitFailedStorageGroup.
GetFailSG() func (r Result) IterateFailedStorageGroups(f func(oid.ID) bool) {
v := r.v2.GetFailSG()
if list == nil { for i := range v {
mV2 = nil if !f(*oid.NewIDFromV2(&v[i])) {
} else { return
ln := len(list)
if cap(mV2) >= ln {
mV2 = mV2[:0]
} else {
mV2 = make([]refs.ObjectID, ln)
}
for i := 0; i < ln; i++ {
mV2[i] = *list[i].ToV2()
} }
} }
(*audit.DataAuditResult)(r).SetFailSG(mV2)
} }
// Hit returns number of sampled objects under audit placed // SubmitFailedStorageGroup is similar to SubmitPassedStorageGroup but for failed groups.
//
// See also IterateFailedStorageGroups.
func (r *Result) SubmitFailedStorageGroup(sg oid.ID) {
r.v2.SetFailSG(append(r.v2.GetFailSG(), *sg.ToV2()))
}
// Hits returns number of sampled objects under audit placed
// in an optimal way according to the container's placement policy
// when checking Proof-of-Placement.
//
// Zero result has zero hits.
//
// See also SetHits.
func (r Result) Hits() uint32 {
return r.v2.GetHit()
}
// SetHits sets number of sampled objects under audit placed
// in an optimal way according to the containers placement policy // in an optimal way according to the containers placement policy
// when checking PoP. // when checking Proof-of-Placement.
func (r *Result) Hit() uint32 { //
return (*audit.DataAuditResult)(r).GetHit() // See also Hits.
func (r *Result) SetHits(hit uint32) {
r.v2.SetHit(hit)
} }
// SetHit sets number of sampled objects under audit placed // Misses returns number of sampled objects under audit placed
// in an optimal way according to the containers placement policy // in suboptimal way according to the container's placement policy,
// when checking PoP. // but still at a satisfactory level when checking Proof-of-Placement.
func (r *Result) SetHit(hit uint32) { //
(*audit.DataAuditResult)(r).SetHit(hit) // Zero Result has zero misses.
//
// See also SetMisses.
func (r Result) Misses() uint32 {
return r.v2.GetMiss()
} }
// Miss returns number of sampled objects under audit placed // SetMisses sets number of sampled objects under audit placed
// in suboptimal way according to the containers placement policy, // in suboptimal way according to the container's placement policy,
// but still at a satisfactory level when checking PoP. // but still at a satisfactory level when checking Proof-of-Placement.
func (r *Result) Miss() uint32 { //
return (*audit.DataAuditResult)(r).GetMiss() // See also Misses.
func (r *Result) SetMisses(miss uint32) {
r.v2.SetMiss(miss)
} }
// SetMiss sets number of sampled objects under audit placed // Failures returns number of sampled objects under audit stored
// in suboptimal way according to the containers placement policy,
// but still at a satisfactory level when checking PoP.
func (r *Result) SetMiss(miss uint32) {
(*audit.DataAuditResult)(r).SetMiss(miss)
}
// Fail returns number of sampled objects under audit stored
// in a way not confirming placement policy or not found at all // in a way not confirming placement policy or not found at all
// when checking PoP. // when checking Proof-of-Placement.
func (r *Result) Fail() uint32 { //
return (*audit.DataAuditResult)(r).GetFail() // Zero result has zero failures.
//
// See also SetFailures.
func (r Result) Failures() uint32 {
return r.v2.GetFail()
} }
// SetFail sets number of sampled objects under audit stored // SetFailures sets number of sampled objects under audit stored
// in a way not confirming placement policy or not found at all // in a way not confirming placement policy or not found at all
// when checking PoP. // when checking Proof-of-Placement.
func (r *Result) SetFail(fail uint32) { //
(*audit.DataAuditResult)(r).SetFail(fail) // See also Failures.
func (r *Result) SetFailures(fail uint32) {
r.v2.SetFail(fail)
} }
// PassNodes returns list of storage node public keys that // IteratePassedStorageNodes iterates over all storage nodes that passed at least one
// passed at least one PDP. // Proof-of-Data-Possession audit check and passes their public keys into f. Breaks on
func (r *Result) PassNodes() [][]byte { // f's false return.
return (*audit.DataAuditResult)(r).GetPassNodes() //
// f MUST NOT be nil and MUST NOT mutate parameter passed into it at least until
// the end of using the Result.
//
// Zero Result has no passed storage nodes and doesn't call f.
//
// See also SubmitPassedStorageNode.
func (r Result) IteratePassedStorageNodes(f func([]byte) bool) {
v := r.v2.GetPassNodes()
for i := range v {
if !f(v[i]) {
return
}
}
} }
// SetPassNodes sets list of storage node public keys that // SubmitPassedStorageNodes marks storage node list as passed Proof-of-Data-Possession
// passed at least one PDP. // audit check. The list contains public keys.
func (r *Result) SetPassNodes(list [][]byte) { //
(*audit.DataAuditResult)(r).SetPassNodes(list) // Argument and its elements MUST NOT be mutated at least until the end of using the Result.
//
// See also IteratePassedStorageNodes.
func (r *Result) SubmitPassedStorageNodes(list [][]byte) {
r.v2.SetPassNodes(list)
} }
// FailNodes returns list of storage node public keys that // IterateFailedStorageNodes is similar to IteratePassedStorageNodes but for failed nodes.
// failed at least one PDP. //
func (r *Result) FailNodes() [][]byte { // See also SubmitPassedStorageNodes.
return (*audit.DataAuditResult)(r).GetFailNodes() func (r Result) IterateFailedStorageNodes(f func([]byte) bool) {
v := r.v2.GetFailNodes()
for i := range v {
if !f(v[i]) {
return
}
}
} }
// SetFailNodes sets list of storage node public keys that // SubmitFailedStorageNodes is similar to SubmitPassedStorageNodes but for failed nodes.
// failed at least one PDP. //
func (r *Result) SetFailNodes(list [][]byte) { // See also IterateFailedStorageNodes.
(*audit.DataAuditResult)(r).SetFailNodes(list) func (r *Result) SubmitFailedStorageNodes(list [][]byte) {
r.v2.SetFailNodes(list)
} }

View file

@ -1,154 +1,188 @@
package audit_test package audit_test
import ( import (
"bytes"
"testing" "testing"
auditv2 "github.com/nspcc-dev/neofs-api-go/v2/audit"
"github.com/nspcc-dev/neofs-sdk-go/audit" "github.com/nspcc-dev/neofs-sdk-go/audit"
audittest "github.com/nspcc-dev/neofs-sdk-go/audit/test" audittest "github.com/nspcc-dev/neofs-sdk-go/audit/test"
cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test" cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id" oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
oidtest "github.com/nspcc-dev/neofs-sdk-go/object/id/test" oidtest "github.com/nspcc-dev/neofs-sdk-go/object/id/test"
"github.com/nspcc-dev/neofs-sdk-go/version"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func TestResult(t *testing.T) { func TestResultData(t *testing.T) {
r := audit.NewResult() var r audit.Result
require.Equal(t, version.Current(), r.Version())
countSG := func(passed bool, f func(oid.ID)) int {
called := 0
ff := func(arg oid.ID) bool {
called++
if f != nil {
f(arg)
}
return true
}
if passed {
r.IteratePassedStorageGroups(ff)
} else {
r.IterateFailedStorageGroups(ff)
}
return called
}
countPassSG := func(f func(oid.ID)) int { return countSG(true, f) }
countFailSG := func(f func(oid.ID)) int { return countSG(false, f) }
countNodes := func(passed bool, f func([]byte)) int {
called := 0
ff := func(arg []byte) bool {
called++
if f != nil {
f(arg)
}
return true
}
if passed {
r.IteratePassedStorageNodes(ff)
} else {
r.IterateFailedStorageNodes(ff)
}
return called
}
countPassNodes := func(f func([]byte)) int { return countNodes(true, f) }
countFailNodes := func(f func([]byte)) int { return countNodes(false, f) }
require.Zero(t, r.Epoch())
require.Nil(t, r.Container())
require.Nil(t, r.AuditorKey())
require.False(t, r.Completed())
require.Zero(t, r.RequestsPoR())
require.Zero(t, r.RetriesPoR())
require.Zero(t, countPassSG(nil))
require.Zero(t, countFailSG(nil))
require.Zero(t, countPassNodes(nil))
require.Zero(t, countFailNodes(nil))
epoch := uint64(13) epoch := uint64(13)
r.SetAuditEpoch(epoch) r.ForEpoch(epoch)
require.Equal(t, epoch, r.AuditEpoch()) require.Equal(t, epoch, r.Epoch())
cid := cidtest.ID() cnr := cidtest.ID()
r.SetContainerID(cid) r.ForContainer(*cnr)
require.Equal(t, cid, r.ContainerID()) require.Equal(t, cnr, r.Container())
key := []byte{1, 2, 3} key := []byte{1, 2, 3}
r.SetPublicKey(key) r.SetAuditorKey(key)
require.Equal(t, key, r.PublicKey()) require.Equal(t, key, r.AuditorKey())
r.SetComplete(true) r.Complete()
require.True(t, r.Complete()) require.True(t, r.Completed())
requests := uint32(2) requests := uint32(2)
r.SetRequests(requests) r.SetRequestsPoR(requests)
require.Equal(t, requests, r.Requests()) require.Equal(t, requests, r.RequestsPoR())
retries := uint32(1) retries := uint32(1)
r.SetRetries(retries) r.SetRetriesPoR(retries)
require.Equal(t, retries, r.Retries()) require.Equal(t, retries, r.RetriesPoR())
passSG := []oid.ID{*oidtest.ID(), *oidtest.ID()} passSG1, passSG2 := *oidtest.ID(), *oidtest.ID()
r.SetPassSG(passSG) r.SubmitPassedStorageGroup(passSG1)
require.Equal(t, passSG, r.PassSG()) r.SubmitPassedStorageGroup(passSG2)
failSG := []oid.ID{*oidtest.ID(), *oidtest.ID()} called1, called2 := false, false
r.SetFailSG(failSG)
require.Equal(t, failSG, r.FailSG()) require.EqualValues(t, 2, countPassSG(func(id oid.ID) {
if id.Equal(&passSG1) {
called1 = true
} else if id.Equal(&passSG2) {
called2 = true
}
}))
require.True(t, called1)
require.True(t, called2)
failSG1, failSG2 := *oidtest.ID(), *oidtest.ID()
r.SubmitFailedStorageGroup(failSG1)
r.SubmitFailedStorageGroup(failSG2)
called1, called2 = false, false
require.EqualValues(t, 2, countFailSG(func(id oid.ID) {
if id.Equal(&failSG1) {
called1 = true
} else if id.Equal(&failSG2) {
called2 = true
}
}))
require.True(t, called1)
require.True(t, called2)
hit := uint32(1) hit := uint32(1)
r.SetHit(hit) r.SetHits(hit)
require.Equal(t, hit, r.Hit()) require.Equal(t, hit, r.Hits())
miss := uint32(2) miss := uint32(2)
r.SetMiss(miss) r.SetMisses(miss)
require.Equal(t, miss, r.Miss()) require.Equal(t, miss, r.Misses())
fail := uint32(3) fail := uint32(3)
r.SetFail(fail) r.SetFailures(fail)
require.Equal(t, fail, r.Fail()) require.Equal(t, fail, r.Failures())
passNodes := [][]byte{{1}, {2}} passNodes := [][]byte{{1}, {2}}
r.SetPassNodes(passNodes) r.SubmitPassedStorageNodes(passNodes)
require.Equal(t, passNodes, r.PassNodes())
called1, called2 = false, false
require.EqualValues(t, 2, countPassNodes(func(arg []byte) {
if bytes.Equal(arg, passNodes[0]) {
called1 = true
} else if bytes.Equal(arg, passNodes[1]) {
called2 = true
}
}))
require.True(t, called1)
require.True(t, called2)
failNodes := [][]byte{{3}, {4}} failNodes := [][]byte{{3}, {4}}
r.SetFailNodes(failNodes) r.SubmitFailedStorageNodes(failNodes)
require.Equal(t, failNodes, r.FailNodes())
called1, called2 = false, false
require.EqualValues(t, 2, countFailNodes(func(arg []byte) {
if bytes.Equal(arg, failNodes[0]) {
called1 = true
} else if bytes.Equal(arg, failNodes[1]) {
called2 = true
}
}))
require.True(t, called1)
require.True(t, called2)
} }
func TestStorageGroupEncoding(t *testing.T) { func TestResultEncoding(t *testing.T) {
r := audittest.Result() r := *audittest.Result()
t.Run("binary", func(t *testing.T) { t.Run("binary", func(t *testing.T) {
data, err := r.Marshal() data := r.Marshal()
require.NoError(t, err)
r2 := audit.NewResult() var r2 audit.Result
require.NoError(t, r2.Unmarshal(data)) require.NoError(t, r2.Unmarshal(data))
require.Equal(t, r, r2) require.Equal(t, r, r2)
}) })
t.Run("json", func(t *testing.T) {
data, err := r.MarshalJSON()
require.NoError(t, err)
r2 := audit.NewResult()
require.NoError(t, r2.UnmarshalJSON(data))
require.Equal(t, r, r2)
})
}
func TestResult_ToV2(t *testing.T) {
t.Run("nil", func(t *testing.T) {
var x *audit.Result
require.Nil(t, x.ToV2())
})
t.Run("default values", func(t *testing.T) {
result := audit.NewResult()
// check initial values
require.Equal(t, version.Current(), result.Version())
require.False(t, result.Complete())
require.Nil(t, result.ContainerID())
require.Nil(t, result.PublicKey())
require.Nil(t, result.PassSG())
require.Nil(t, result.FailSG())
require.Nil(t, result.PassNodes())
require.Nil(t, result.FailNodes())
require.Zero(t, result.Hit())
require.Zero(t, result.Miss())
require.Zero(t, result.Fail())
require.Zero(t, result.Requests())
require.Zero(t, result.Retries())
require.Zero(t, result.AuditEpoch())
// convert to v2 message
resultV2 := result.ToV2()
require.Equal(t, version.Current().ToV2(), resultV2.GetVersion())
require.False(t, resultV2.GetComplete())
require.Nil(t, resultV2.GetContainerID())
require.Nil(t, resultV2.GetPublicKey())
require.Nil(t, resultV2.GetPassSG())
require.Nil(t, resultV2.GetFailSG())
require.Nil(t, resultV2.GetPassNodes())
require.Nil(t, resultV2.GetFailNodes())
require.Zero(t, resultV2.GetHit())
require.Zero(t, resultV2.GetMiss())
require.Zero(t, resultV2.GetFail())
require.Zero(t, resultV2.GetRequests())
require.Zero(t, resultV2.GetRetries())
require.Zero(t, resultV2.GetAuditEpoch())
})
}
func TestNewResultFromV2(t *testing.T) {
t.Run("from nil", func(t *testing.T) {
var x *auditv2.DataAuditResult
require.Nil(t, audit.NewResultFromV2(x))
})
} }

13
audit/test/doc.go Normal file
View file

@ -0,0 +1,13 @@
/*
Package audittest provides functions for convenient testing of audit package API.
Note that importing the package into source files is highly discouraged.
Random instance generation functions can be useful when testing expects any value, e.g.:
import audittest "github.com/nspcc-dev/neofs-sdk-go/audit/test"
dec := audittest.Result()
// test the value
*/
package audittest

View file

@ -3,35 +3,34 @@ package audittest
import ( import (
"github.com/nspcc-dev/neofs-sdk-go/audit" "github.com/nspcc-dev/neofs-sdk-go/audit"
cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test" cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
oidtest "github.com/nspcc-dev/neofs-sdk-go/object/id/test" oidtest "github.com/nspcc-dev/neofs-sdk-go/object/id/test"
versiontest "github.com/nspcc-dev/neofs-sdk-go/version/test"
) )
// Result returns random audit.Result. // Result returns random audit.Result.
func Result() *audit.Result { func Result() *audit.Result {
x := audit.NewResult() var x audit.Result
x.SetVersion(versiontest.Version()) x.ForContainer(*cidtest.ID())
x.SetContainerID(cidtest.ID()) x.SetAuditorKey([]byte("key"))
x.SetPublicKey([]byte("key")) x.Complete()
x.SetComplete(true) x.ForEpoch(44)
x.SetAuditEpoch(44) x.SetHits(55)
x.SetHit(55) x.SetMisses(66)
x.SetMiss(66) x.SetFailures(77)
x.SetFail(77) x.SetRequestsPoR(88)
x.SetRetries(88) x.SetRequestsPoR(99)
x.SetRequests(99) x.SubmitFailedStorageNodes([][]byte{
x.SetFailNodes([][]byte{
[]byte("node1"), []byte("node1"),
[]byte("node2"), []byte("node2"),
}) })
x.SetPassNodes([][]byte{ x.SubmitPassedStorageNodes([][]byte{
[]byte("node3"), []byte("node3"),
[]byte("node4"), []byte("node4"),
}) })
x.SetPassSG([]oid.ID{*oidtest.ID(), *oidtest.ID()}) x.SubmitPassedStorageGroup(*oidtest.ID())
x.SetFailSG([]oid.ID{*oidtest.ID(), *oidtest.ID()}) x.SubmitPassedStorageGroup(*oidtest.ID())
x.SubmitFailedStorageGroup(*oidtest.ID())
x.SubmitFailedStorageGroup(*oidtest.ID())
return x return &x
} }