forked from TrueCloudLab/frostfs-sdk-go
[#170] audit: Refactor and document package functionality
Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
parent
48150852f3
commit
7d31de57ec
5 changed files with 458 additions and 362 deletions
24
audit/doc.go
Normal file
24
audit/doc.go
Normal 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
|
512
audit/result.go
512
audit/result.go
|
@ -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.
|
||||||
if list == nil {
|
func (r Result) Epoch() uint64 {
|
||||||
mV2 = nil
|
return r.v2.GetAuditEpoch()
|
||||||
} else {
|
|
||||||
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).SetPassSG(mV2)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FailSG returns list of Storage Groups that failed audit PoR stage.
|
// ForEpoch specifies NeoFS epoch when the data associated with the Result was audited.
|
||||||
func (r *Result) FailSG() []oid.ID {
|
//
|
||||||
mV2 := (*audit.DataAuditResult)(r).
|
// See also Epoch.
|
||||||
GetFailSG()
|
func (r *Result) ForEpoch(epoch uint64) {
|
||||||
|
r.v2.SetAuditEpoch(epoch)
|
||||||
if mV2 == nil {
|
|
||||||
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.
|
// Container returns identifier of the container with which the data audit Result
|
||||||
func (r *Result) SetFailSG(list []oid.ID) {
|
// is associated.
|
||||||
mV2 := (*audit.DataAuditResult)(r).
|
//
|
||||||
GetFailSG()
|
// 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.
|
||||||
if list == nil {
|
//
|
||||||
mV2 = nil
|
// See also ForContainer.
|
||||||
} else {
|
func (r Result) Container() *cid.ID {
|
||||||
ln := len(list)
|
return cid.NewFromV2(r.v2.GetContainerID())
|
||||||
|
|
||||||
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
|
// ForContainer returns identifier of the container with which the data audit Result
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubmitPassedStorageGroup marks storage group as passed Proof-of-Retrievability
|
||||||
|
// audit check.
|
||||||
|
//
|
||||||
|
// See also IteratePassedStorageGroups.
|
||||||
|
func (r *Result) SubmitPassedStorageGroup(sg oid.ID) {
|
||||||
|
r.v2.SetPassSG(append(r.v2.GetPassSG(), *sg.ToV2()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IterateFailedStorageGroups is similar to IteratePassedStorageGroups but for failed groups.
|
||||||
|
//
|
||||||
|
// See also SubmitFailedStorageGroup.
|
||||||
|
func (r Result) IterateFailedStorageGroups(f func(oid.ID) bool) {
|
||||||
|
v := r.v2.GetFailSG()
|
||||||
|
|
||||||
|
for i := range v {
|
||||||
|
if !f(*oid.NewIDFromV2(&v[i])) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
13
audit/test/doc.go
Normal 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
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue