Compare commits

...
Sign in to create a new pull request.

1 commit

Author SHA1 Message Date
700d091061 Add covertest and change tests
Signed-off-by: Ekaterina Lebedeva <ekaterina.lebedeva@yadro.com>
2023-08-15 16:27:26 +03:00
11 changed files with 451 additions and 69 deletions

1
.gitignore vendored
View file

@ -5,6 +5,7 @@ config.json
/vendor/
.idea
/bin/
*.out
# debhelpers
**/.debhelper

133
covertest/client.go Normal file
View file

@ -0,0 +1,133 @@
package covertest
import (
"testing"
"github.com/nspcc-dev/neo-go/pkg/core"
"github.com/nspcc-dev/neo-go/pkg/core/block"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/neotest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/stretchr/testify/require"
)
// ContractInvoker is a client for a specific contract.
type ContractInvoker struct {
*neotest.ContractInvoker
Methods []Method
}
type Method struct {
Name string
Instructions []InstrHash
}
// CommitteeInvoker creates a new ContractInvoker for the contract with hash h and a committee multisignature signer.
func CommitteeInvoker(e *neotest.Executor, h util.Uint160) *ContractInvoker {
return &ContractInvoker{
ContractInvoker: &neotest.ContractInvoker{
Executor: e,
Hash: h,
Signers: []neotest.Signer{e.Committee},
},
Methods: nil,
}
}
// Invoke invokes the method with the args, persists the transaction and checks the result.
// Returns transaction hash.
func (c *ContractInvoker) Invoke(t testing.TB, result interface{}, method string, args ...interface{}) util.Uint256 {
c.Methods = append(c.Methods, Method{
Name: method,
Instructions: nil,
})
tx := c.PrepareInvoke(t, method, args...)
c.AddNewBlock(t, tx)
c.CheckHalt(t, tx.Hash(), stackitem.Make(result))
return tx.Hash()
}
// InvokeFail invokes the method with the args, persists the transaction and checks the error message.
// It returns the transaction hash.
func (c *ContractInvoker) InvokeFail(t testing.TB, message string, method string, args ...interface{}) util.Uint256 {
c.Methods = append(c.Methods, Method{
Name: method,
Instructions: nil,
})
tx := c.PrepareInvoke(t, method, args...)
c.AddNewBlock(t, tx)
c.CheckFault(t, tx.Hash(), message)
return tx.Hash()
}
// PrepareInvoke creates a new invocation transaction.
func (c *ContractInvoker) PrepareInvoke(t testing.TB, method string, args ...interface{}) *transaction.Transaction {
return c.NewTx(t, c.Signers, c.Hash, method, args...)
}
// NewTx creates a new transaction which invokes the contract method.
// The transaction is signed by the signers.
func (c *ContractInvoker) NewTx(t testing.TB, signers []neotest.Signer,
hash util.Uint160, method string, args ...interface{}) *transaction.Transaction {
tx := c.NewUnsignedTx(t, hash, method, args...)
return c.SignTx(t, tx, -1, signers...)
}
// SignTx signs a transaction using the provided signers.
func (c *ContractInvoker) SignTx(t testing.TB, tx *transaction.Transaction, sysFee int64, signers ...neotest.Signer) *transaction.Transaction {
for _, acc := range signers {
tx.Signers = append(tx.Signers, transaction.Signer{
Account: acc.ScriptHash(),
Scopes: transaction.Global,
})
}
neotest.AddNetworkFee(c.Chain, tx, signers...)
c.AddSystemFee(c.Chain, tx, sysFee)
for _, acc := range signers {
require.NoError(t, acc.SignTx(c.Chain.GetConfig().Magic, tx))
}
return tx
}
// AddSystemFee adds system fee to the transaction. If negative value specified,
// then system fee is defined by test invocation.
func (c *ContractInvoker) AddSystemFee(bc *core.Blockchain, tx *transaction.Transaction, sysFee int64) {
if sysFee >= 0 {
tx.SystemFee = sysFee
return
}
ops, v, _ := TestInvoke(bc, tx) // ignore error to support failing transactions
tx.SystemFee = v.GasConsumed()
c.Methods[len(c.Methods)-1].Instructions = make([]InstrHash, len(ops))
copy(c.Methods[len(c.Methods)-1].Instructions, ops)
}
// TestInvoke creates a test VM with a dummy block and executes a transaction in it.
func TestInvoke(bc *core.Blockchain, tx *transaction.Transaction) ([]InstrHash, *vm.VM, error) {
lastBlock, err := bc.GetBlock(bc.GetHeaderHash(bc.BlockHeight()))
if err != nil {
return nil, nil, err
}
b := &block.Block{
Header: block.Header{
Index: bc.BlockHeight() + 1,
Timestamp: lastBlock.Timestamp + 1,
},
}
// `GetTestVM` as well as `Run` can use a transaction hash which will set a cached value.
// This is unwanted behavior, so we explicitly copy the transaction to perform execution.
ttx := *tx
ic, _ := bc.GetTestVM(trigger.Application, &ttx, b)
defer ic.Finalize()
ic.VM.LoadWithFlags(tx.Script, callflag.All)
ops, err := Run(ic.VM)
return ops, ic.VM, err
}

56
covertest/compile.go Normal file
View file

@ -0,0 +1,56 @@
package covertest
import (
"testing"
"github.com/nspcc-dev/neo-go/cli/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/compiler"
"github.com/nspcc-dev/neo-go/pkg/config"
"github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/neotest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/stretchr/testify/require"
)
// ContractWithDebugInfo contains contract info for deployment and debug information for coverage.
type ContractWithDebugInfo struct {
Contract *neotest.Contract
DebugInfo *compiler.DebugInfo
}
// CompileFile compiles a contract from the file and returns its NEF, manifest, hash and debug information.
func CompileFile(t testing.TB, sender util.Uint160, srcPath string, configPath string) *ContractWithDebugInfo {
// nef.NewFile() cares about version a lot.
config.Version = "neotest"
ne, di, err := compiler.CompileWithOptions(srcPath, nil, nil)
require.NoError(t, err)
conf, err := smartcontract.ParseContractConfig(configPath)
require.NoError(t, err)
o := &compiler.Options{}
o.Name = conf.Name
o.ContractEvents = conf.Events
o.ContractSupportedStandards = conf.SupportedStandards
o.Permissions = make([]manifest.Permission, len(conf.Permissions))
for i := range conf.Permissions {
o.Permissions[i] = manifest.Permission(conf.Permissions[i])
}
o.SafeMethods = conf.SafeMethods
o.Overloads = conf.Overloads
o.SourceURL = conf.SourceURL
m, err := compiler.CreateManifest(di, o)
require.NoError(t, err)
c := &neotest.Contract{
Hash: state.CreateContractHash(sender, ne.Checksum, m.Name),
NEF: ne,
Manifest: m,
}
return &ContractWithDebugInfo{
Contract: c,
DebugInfo: di,
}
}

124
covertest/cover.go Normal file
View file

@ -0,0 +1,124 @@
package covertest
import (
"fmt"
"os"
"strings"
"sync"
"testing"
"github.com/nspcc-dev/neo-go/pkg/compiler"
"github.com/stretchr/testify/require"
)
var mu sync.Mutex
type coverline struct {
Doc string
Opcode int
StartLine int
StartCol int
EndLine int
EndCol int
WTFnumber int
IsCovered bool
}
// MakeCoverage generates an output file with coverage info in correct format
func (c *ContractInvoker) MakeCoverage(t testing.TB, ctrdi *ContractWithDebugInfo, ctrPath string, fileName string) {
docs := getDocuments(t, ctrdi.DebugInfo.Documents, ctrPath)
cov := getSeqPoints(t, ctrdi.DebugInfo, docs)
for _, iMethod := range c.Methods {
countInstructions(cov, iMethod.Instructions)
}
printToFile(t, cov, fileName)
}
func getDocuments(t testing.TB, docs []string, substr string) []int {
res := make([]int, 0, len(docs))
for i, cDoc := range docs {
if strings.Contains(cDoc, substr) {
res = append(res, i)
}
}
if len(res) == 0 {
t.Log("Cannot get document\n")
t.FailNow()
}
return res
}
func getSeqPoints(t testing.TB, di *compiler.DebugInfo, docs []int) []coverline {
res := make([]coverline, 0, 10)
for _, method := range di.Methods {
maxLine := method.Range.End
for _, seqPoint := range method.SeqPoints {
if isValidDocument(seqPoint.Document, docs) && seqPoint.Opcode < int(maxLine) {
res = append(res, coverline{
Doc: di.Documents[seqPoint.Document],
Opcode: seqPoint.Opcode,
StartLine: seqPoint.StartLine,
StartCol: seqPoint.StartCol,
EndLine: seqPoint.EndLine,
EndCol: seqPoint.EndCol,
WTFnumber: 1,
IsCovered: false,
})
}
}
}
return res
}
func isValidDocument(iDocToCheck int, docs []int) bool {
for _, iDoc := range docs {
if iDoc == iDocToCheck {
return true
}
}
return false
}
func countInstructions(cov []coverline, codes []InstrHash) {
for i := 0; i < len(cov); i++ {
for _, code := range codes {
if code.Offset == cov[i].Opcode {
cov[i].IsCovered = true
//cov[i].WTFnumber++
//break
}
}
}
}
func printToFile(t testing.TB, cov []coverline, name string) {
mu.Lock()
defer mu.Unlock()
f, err := os.OpenFile(name, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
require.NoError(t, err)
defer f.Close()
fi, err := os.Stat(name)
require.NoError(t, err)
firstToWrite := ""
if fi.Size() == 0 {
firstToWrite = "mode: set\n"
}
_, err = f.WriteString(firstToWrite)
require.NoError(t, err)
for _, info := range cov {
covered := 0
if info.IsCovered {
covered++
}
line := fmt.Sprintf("%s:%d.%d,%d.%d %d %d\n", info.Doc, info.StartLine, info.StartCol, info.EndLine, info.EndCol, info.WTFnumber, covered)
_, err = f.WriteString(line)
require.NoError(t, err)
}
}

58
covertest/run.go Normal file
View file

@ -0,0 +1,58 @@
package covertest
import (
"errors"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
)
// InstrHash maps instruction with scripthash of a contract it belongs to.
type InstrHash struct {
Offset int
Instruction opcode.Opcode
ScriptHash util.Uint160
}
// Run starts execution of the loaded program and accumulates all seen opcodes
// together with the scripthash of a contract they belong to.
// Original vm.Run(): https://github.com/nspcc-dev/neo-go/blob/v0.101.3/pkg/vm/vm.go#L418
func Run(v *vm.VM) ([]InstrHash, error) {
if !v.Ready() {
return nil, errors.New("no program loaded")
}
if v.HasFailed() {
// VM already ran something and failed, in general its state is
// undefined in this case so we can't run anything.
return nil, errors.New("VM has failed")
}
// vmstate.Halt (the default) or vmstate.Break are safe to continue.
var ops []InstrHash
for {
switch {
case v.HasFailed():
// Should be caught and reported already by the v.Step(),
// but we're checking here anyway just in case.
return ops, errors.New("VM has failed")
case v.HasHalted(), v.AtBreakpoint():
// Normal exit from this loop.
return ops, nil
case v.State() == vmstate.None:
nStr, curInstr := v.Context().NextInstr()
ops = append(ops, InstrHash{
Offset: nStr,
Instruction: curInstr,
ScriptHash: v.Context().ScriptHash(),
})
if err := v.Step(); err != nil {
return ops, err
}
default:
return ops, errors.New("unknown state")
}
}
}

4
go.mod
View file

@ -4,7 +4,7 @@ go 1.14
require (
github.com/mr-tron/base58 v1.2.0
github.com/nspcc-dev/neo-go v0.101.5-0.20230808195420-5fc61be5f6c5
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20230808195420-5fc61be5f6c5
github.com/nspcc-dev/neo-go v0.101.5-0.20230811211719-9fb154a376fc
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20230810094130-11bb733f1a2c
github.com/stretchr/testify v1.8.1
)

10
go.sum
View file

@ -698,14 +698,12 @@ github.com/nspcc-dev/neo-go v0.73.1-pre.0.20200303142215-f5a1b928ce09/go.mod h1:
github.com/nspcc-dev/neo-go v0.98.0/go.mod h1:E3cc1x6RXSXrJb2nDWXTXjnXk3rIqVN8YdFyWv+FrqM=
github.com/nspcc-dev/neo-go v0.99.2/go.mod h1:9P0yWqhZX7i/ChJ+zjtiStO1uPTolPFUM+L5oNznU8E=
github.com/nspcc-dev/neo-go v0.100.1/go.mod h1:Nnp7F4e9IBccsgtCeLtUWV+0T6gk1PtP5HRtA13hUfc=
github.com/nspcc-dev/neo-go v0.101.5-0.20230808195420-5fc61be5f6c5 h1:AXI2upTPeTqX+n4xrBEzPATgEviOM/Prg6UQ6KDm+DU=
github.com/nspcc-dev/neo-go v0.101.5-0.20230808195420-5fc61be5f6c5/go.mod h1:Z0kpjwnTJj/ik/X6z18xjCL0X2+RNbqlnhKrl+MYgP8=
github.com/nspcc-dev/neo-go v0.101.5-0.20230811211719-9fb154a376fc h1:U4x1uOG3JXy9TWgcH2B/ZOWfxZmerkymkZibBrxSA1Q=
github.com/nspcc-dev/neo-go v0.101.5-0.20230811211719-9fb154a376fc/go.mod h1:QXxpZxJT2KedwM0Nlj8UO0/fZN2WIe4h/i03uBHKbnc=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20220809123759-3094d3e0c14b/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20221202075445-cb5c18dc73eb/go.mod h1:23bBw0v6pBYcrWs8CBEEDIEDJNbcFoIh8pGGcf2Vv8s=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20230420112658-c50ab951645a h1:63sh46kfKF/g2IE1z/EV8CBEKCVmGJXSSH0ZHqTDGCY=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20230420112658-c50ab951645a/go.mod h1:ZUuXOkdtHZgaC13za/zMgXfQFncZ0jLzfQTe+OsDOtg=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20230808195420-5fc61be5f6c5 h1:/d7mY5hYlNhmEXexKcyqSR0b1Hdl5hf/c5o8Vi/1vt4=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20230808195420-5fc61be5f6c5/go.mod h1:ZUuXOkdtHZgaC13za/zMgXfQFncZ0jLzfQTe+OsDOtg=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20230810094130-11bb733f1a2c h1:upj+XyoI0dS7CYnZOTAeyuznhvDIJurQXL4FvHNKyl4=
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20230810094130-11bb733f1a2c/go.mod h1:ZUuXOkdtHZgaC13za/zMgXfQFncZ0jLzfQTe+OsDOtg=
github.com/nspcc-dev/neofs-api-go/v2 v2.11.0-pre.0.20211201134523-3604d96f3fe1/go.mod h1:oS8dycEh8PPf2Jjp6+8dlwWyEv2Dy77h/XhhcdxYEFs=
github.com/nspcc-dev/neofs-api-go/v2 v2.11.1/go.mod h1:oS8dycEh8PPf2Jjp6+8dlwWyEv2Dy77h/XhhcdxYEFs=
github.com/nspcc-dev/neofs-api-go/v2 v2.14.0 h1:jhuN8Ldqz7WApvUJRFY0bjRXE1R3iCkboMX5QVZhHVk=

View file

@ -4,6 +4,7 @@ import (
"path"
"testing"
"git.frostfs.info/TrueCloudLab/frostfs-contract/covertest"
"github.com/nspcc-dev/neo-go/pkg/neotest"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
@ -12,17 +13,17 @@ import (
const balancePath = "../balance"
func deployBalanceContract(t *testing.T, e *neotest.Executor, addrNetmap, addrContainer util.Uint160) util.Uint160 {
c := neotest.CompileFile(t, e.CommitteeHash, balancePath, path.Join(balancePath, "config.yml"))
c := covertest.CompileFile(t, e.CommitteeHash, balancePath, path.Join(balancePath, "config.yml"))
args := make([]interface{}, 3)
args[0] = false
args[1] = addrNetmap
args[2] = addrContainer
e.DeployContract(t, c, args)
return c.Hash
e.DeployContract(t, c.Contract, args)
return c.Contract.Hash
}
func balanceMint(t *testing.T, c *neotest.ContractInvoker, acc neotest.Signer, amount int64, details []byte) {
func balanceMint(t *testing.T, c *covertest.ContractInvoker, acc neotest.Signer, amount int64, details []byte) {
c.Invoke(t, stackitem.Null{}, "mint", acc.ScriptHash(), amount, details)
}

View file

@ -9,6 +9,7 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-contract/common"
"git.frostfs.info/TrueCloudLab/frostfs-contract/container"
"git.frostfs.info/TrueCloudLab/frostfs-contract/covertest"
"git.frostfs.info/TrueCloudLab/frostfs-contract/nns"
"github.com/mr-tron/base58"
"github.com/nspcc-dev/neo-go/pkg/core/interop/storage"
@ -35,26 +36,26 @@ func deployContainerContract(t *testing.T, e *neotest.Executor, addrNetmap, addr
args[4] = addrNNS
args[5] = "frostfs"
c := neotest.CompileFile(t, e.CommitteeHash, containerPath, path.Join(containerPath, "config.yml"))
e.DeployContract(t, c, args)
return c.Hash
c := covertest.CompileFile(t, e.CommitteeHash, containerPath, path.Join(containerPath, "config.yml"))
e.DeployContract(t, c.Contract, args)
return c.Contract.Hash
}
func newContainerInvoker(t *testing.T) (*neotest.ContractInvoker, *neotest.ContractInvoker, *neotest.ContractInvoker) {
func newContainerInvoker(t *testing.T) (*covertest.ContractWithDebugInfo, *covertest.ContractInvoker, *covertest.ContractInvoker, *covertest.ContractInvoker) {
e := newExecutor(t)
ctrNNS := neotest.CompileFile(t, e.CommitteeHash, nnsPath, path.Join(nnsPath, "config.yml"))
ctrNetmap := neotest.CompileFile(t, e.CommitteeHash, netmapPath, path.Join(netmapPath, "config.yml"))
ctrBalance := neotest.CompileFile(t, e.CommitteeHash, balancePath, path.Join(balancePath, "config.yml"))
ctrContainer := neotest.CompileFile(t, e.CommitteeHash, containerPath, path.Join(containerPath, "config.yml"))
ctrNNS := covertest.CompileFile(t, e.CommitteeHash, nnsPath, path.Join(nnsPath, "config.yml"))
ctrNetmap := covertest.CompileFile(t, e.CommitteeHash, netmapPath, path.Join(netmapPath, "config.yml"))
ctrBalance := covertest.CompileFile(t, e.CommitteeHash, balancePath, path.Join(balancePath, "config.yml"))
ctrContainer := covertest.CompileFile(t, e.CommitteeHash, containerPath, path.Join(containerPath, "config.yml"))
e.DeployContract(t, ctrNNS, nil)
deployNetmapContract(t, e, ctrBalance.Hash, ctrContainer.Hash,
e.DeployContract(t, ctrNNS.Contract, nil)
deployNetmapContract(t, e, ctrBalance.Contract.Hash, ctrContainer.Contract.Hash,
container.RegistrationFeeKey, int64(containerFee),
container.AliasFeeKey, int64(containerAliasFee))
deployBalanceContract(t, e, ctrNetmap.Hash, ctrContainer.Hash)
deployContainerContract(t, e, ctrNetmap.Hash, ctrBalance.Hash, ctrNNS.Hash)
return e.CommitteeInvoker(ctrContainer.Hash), e.CommitteeInvoker(ctrBalance.Hash), e.CommitteeInvoker(ctrNetmap.Hash)
deployBalanceContract(t, e, ctrNetmap.Contract.Hash, ctrContainer.Contract.Hash)
deployContainerContract(t, e, ctrNetmap.Contract.Hash, ctrBalance.Contract.Hash, ctrNNS.Contract.Hash)
return ctrContainer, covertest.CommitteeInvoker(e, ctrContainer.Contract.Hash), covertest.CommitteeInvoker(e, ctrBalance.Contract.Hash), covertest.CommitteeInvoker(e, ctrNetmap.Contract.Hash)
}
func setContainerOwner(c []byte, acc neotest.Signer) {
@ -86,7 +87,7 @@ func dummyContainer(owner neotest.Signer) testContainer {
}
func TestContainerCount(t *testing.T) {
c, cBal, _ := newContainerInvoker(t)
ctrdi, c, cBal, _ := newContainerInvoker(t)
checkCount := func(t *testing.T, expected int64) {
s, err := c.TestInvoke(t, "count")
@ -120,9 +121,10 @@ func TestContainerCount(t *testing.T) {
c.Invoke(t, stackitem.Null{}, "delete", cnt3.id[:], cnt3.sig, cnt3.pub, cnt3.token)
checkCount(t, 0)
checkContainerList(t, c, [][]byte{})
c.MakeCoverage(t, ctrdi, "container", "c.out")
}
func checkContainerList(t *testing.T, c *neotest.ContractInvoker, expected [][]byte) {
func checkContainerList(t *testing.T, c *covertest.ContractInvoker, expected [][]byte) {
t.Run("check with `list`", func(t *testing.T) {
s, err := c.TestInvoke(t, "list", nil)
require.NoError(t, err)
@ -166,7 +168,7 @@ func checkContainerList(t *testing.T, c *neotest.ContractInvoker, expected [][]b
}
func TestContainerPut(t *testing.T) {
c, cBal, _ := newContainerInvoker(t)
ctrdi, c, cBal, _ := newContainerInvoker(t)
acc := c.NewAccount(t)
cnt := dummyContainer(acc)
@ -182,8 +184,8 @@ func TestContainerPut(t *testing.T) {
c.Invoke(t, stackitem.Null{}, "put", putArgs...)
t.Run("with nice names", func(t *testing.T) {
ctrNNS := neotest.CompileFile(t, c.CommitteeHash, nnsPath, path.Join(nnsPath, "config.yml"))
nnsHash := ctrNNS.Hash
ctrNNS := covertest.CompileFile(t, c.CommitteeHash, nnsPath, path.Join(nnsPath, "config.yml"))
nnsHash := ctrNNS.Contract.Hash
balanceMint(t, cBal, acc, containerFee*1, []byte{})
@ -231,9 +233,10 @@ func TestContainerPut(t *testing.T) {
cNNS.Invoke(t, expected, "resolve", "domain.cdn", int64(nns.TXT))
})
})
c.MakeCoverage(t, ctrdi, "container", "c.out")
}
func addContainer(t *testing.T, c, cBal *neotest.ContractInvoker) (neotest.Signer, testContainer) {
func addContainer(t *testing.T, c, cBal *covertest.ContractInvoker) (neotest.Signer, testContainer) {
acc := c.NewAccount(t)
cnt := dummyContainer(acc)
@ -243,7 +246,7 @@ func addContainer(t *testing.T, c, cBal *neotest.ContractInvoker) (neotest.Signe
}
func TestContainerDelete(t *testing.T) {
c, cBal, cNm := newContainerInvoker(t)
ctrdi, c, cBal, cNm := newContainerInvoker(t)
acc, cnt := addContainer(t, c, cBal)
cAcc := c.WithSigners(acc)
@ -283,10 +286,11 @@ func TestContainerDelete(t *testing.T) {
})
c.InvokeFail(t, container.NotFoundError, "get", cnt.id[:])
c.MakeCoverage(t, ctrdi, "container", "c.out")
}
func TestContainerOwner(t *testing.T) {
c, cBal, _ := newContainerInvoker(t)
ctrdi, c, cBal, _ := newContainerInvoker(t)
acc, cnt := addContainer(t, c, cBal)
@ -298,10 +302,11 @@ func TestContainerOwner(t *testing.T) {
owner := signerToOwner(acc)
c.Invoke(t, stackitem.NewBuffer(owner), "owner", cnt.id[:])
c.MakeCoverage(t, ctrdi, "container", "c.out")
}
func TestContainerGet(t *testing.T) {
c, cBal, _ := newContainerInvoker(t)
ctrdi, c, cBal, _ := newContainerInvoker(t)
_, cnt := addContainer(t, c, cBal)
@ -318,6 +323,7 @@ func TestContainerGet(t *testing.T) {
stackitem.NewByteArray(cnt.token),
})
c.Invoke(t, expected, "get", cnt.id[:])
c.MakeCoverage(t, ctrdi, "container", "c.out")
}
type eacl struct {
@ -339,7 +345,7 @@ func dummyEACL(containerID [32]byte) eacl {
}
func TestContainerSetEACL(t *testing.T) {
c, cBal, _ := newContainerInvoker(t)
ctrdi, c, cBal, _ := newContainerInvoker(t)
acc, cnt := addContainer(t, c, cBal)
@ -364,10 +370,11 @@ func TestContainerSetEACL(t *testing.T) {
stackitem.NewByteArray(e.token),
})
c.Invoke(t, expected, "eACL", cnt.id[:])
c.MakeCoverage(t, ctrdi, "container", "c.out")
}
func TestContainerSizeEstimation(t *testing.T) {
c, cBal, cNm := newContainerInvoker(t)
ctrdi, c, cBal, cNm := newContainerInvoker(t)
_, cnt := addContainer(t, c, cBal)
nodes := []testNodeInfo{
@ -435,6 +442,7 @@ func TestContainerSizeEstimation(t *testing.T) {
}
checkEstimations(t, c, 2, cnt)
checkEstimations(t, c, epoch, cnt, estimation{nodes[1].pub, int64(999)})
c.MakeCoverage(t, ctrdi, "container", "c.out")
}
type estimation struct {
@ -442,7 +450,7 @@ type estimation struct {
size int64
}
func checkEstimations(t *testing.T, c *neotest.ContractInvoker, epoch int64, cnt testContainer, estimations ...estimation) {
func checkEstimations(t *testing.T, c *covertest.ContractInvoker, epoch int64, cnt testContainer, estimations ...estimation) {
// Check that listed estimations match expected
listEstimations := getListEstimations(t, c, epoch, cnt)
requireEstimationsMatch(t, estimations, listEstimations)
@ -452,7 +460,7 @@ func checkEstimations(t *testing.T, c *neotest.ContractInvoker, epoch int64, cnt
requireEstimationsMatch(t, estimations, iterEstimations)
}
func getListEstimations(t *testing.T, c *neotest.ContractInvoker, epoch int64, cnt testContainer) []estimation {
func getListEstimations(t *testing.T, c *covertest.ContractInvoker, epoch int64, cnt testContainer) []estimation {
s, err := c.TestInvoke(t, "listContainerSizes", epoch)
require.NoError(t, err)
@ -481,7 +489,7 @@ func getListEstimations(t *testing.T, c *neotest.ContractInvoker, epoch int64, c
return convertStackToEstimations(sizes[1].Value().([]stackitem.Item))
}
func getIterEstimations(t *testing.T, c *neotest.ContractInvoker, epoch int64) []estimation {
func getIterEstimations(t *testing.T, c *covertest.ContractInvoker, epoch int64) []estimation {
iterStack, err := c.TestInvoke(t, "iterateContainerSizes", epoch)
require.NoError(t, err)
iter := iterStack.Pop().Value().(*storage.Iterator)

View file

@ -7,6 +7,7 @@ import (
"testing"
"git.frostfs.info/TrueCloudLab/frostfs-contract/container"
"git.frostfs.info/TrueCloudLab/frostfs-contract/covertest"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/neotest"
"github.com/nspcc-dev/neo-go/pkg/util"
@ -16,37 +17,37 @@ import (
const frostfsidPath = "../frostfsid"
func deployFrostFSIDContract(t *testing.T, e *neotest.Executor, addrNetmap, addrContainer util.Uint160) util.Uint160 {
func deployFrostFSIDContract(t *testing.T, e *neotest.Executor, addrNetmap, addrContainer util.Uint160) (util.Uint160, *covertest.ContractWithDebugInfo) {
args := make([]interface{}, 5)
args[0] = false
args[1] = addrNetmap
args[2] = addrContainer
c := neotest.CompileFile(t, e.CommitteeHash, frostfsidPath, path.Join(frostfsidPath, "config.yml"))
e.DeployContract(t, c, args)
return c.Hash
c := covertest.CompileFile(t, e.CommitteeHash, frostfsidPath, path.Join(frostfsidPath, "config.yml"))
e.DeployContract(t, c.Contract, args)
return c.Contract.Hash, c
}
func newFrostFSIDInvoker(t *testing.T) *neotest.ContractInvoker {
func newFrostFSIDInvoker(t *testing.T) (*covertest.ContractInvoker, *covertest.ContractWithDebugInfo) {
e := newExecutor(t)
ctrNNS := neotest.CompileFile(t, e.CommitteeHash, nnsPath, path.Join(nnsPath, "config.yml"))
ctrNetmap := neotest.CompileFile(t, e.CommitteeHash, netmapPath, path.Join(netmapPath, "config.yml"))
ctrBalance := neotest.CompileFile(t, e.CommitteeHash, balancePath, path.Join(balancePath, "config.yml"))
ctrContainer := neotest.CompileFile(t, e.CommitteeHash, containerPath, path.Join(containerPath, "config.yml"))
ctrNNS := covertest.CompileFile(t, e.CommitteeHash, nnsPath, path.Join(nnsPath, "config.yml"))
ctrNetmap := covertest.CompileFile(t, e.CommitteeHash, netmapPath, path.Join(netmapPath, "config.yml"))
ctrBalance := covertest.CompileFile(t, e.CommitteeHash, balancePath, path.Join(balancePath, "config.yml"))
ctrContainer := covertest.CompileFile(t, e.CommitteeHash, containerPath, path.Join(containerPath, "config.yml"))
e.DeployContract(t, ctrNNS, nil)
deployNetmapContract(t, e, ctrBalance.Hash, ctrContainer.Hash,
e.DeployContract(t, ctrNNS.Contract, nil)
deployNetmapContract(t, e, ctrBalance.Contract.Hash, ctrContainer.Contract.Hash,
container.RegistrationFeeKey, int64(containerFee),
container.AliasFeeKey, int64(containerAliasFee))
deployBalanceContract(t, e, ctrNetmap.Hash, ctrContainer.Hash)
deployContainerContract(t, e, ctrNetmap.Hash, ctrBalance.Hash, ctrNNS.Hash)
h := deployFrostFSIDContract(t, e, ctrNetmap.Hash, ctrContainer.Hash)
return e.CommitteeInvoker(h)
deployBalanceContract(t, e, ctrNetmap.Contract.Hash, ctrContainer.Contract.Hash)
deployContainerContract(t, e, ctrNetmap.Contract.Hash, ctrBalance.Contract.Hash, ctrNNS.Contract.Hash)
h, c := deployFrostFSIDContract(t, e, ctrNetmap.Contract.Hash, ctrContainer.Contract.Hash)
return covertest.CommitteeInvoker(e, h), c
}
func TestFrostFSID_AddKey(t *testing.T) {
e := newFrostFSIDInvoker(t)
e, c := newFrostFSIDInvoker(t)
pubs := make([][]byte, 6)
for i := range pubs {
@ -108,4 +109,5 @@ func TestFrostFSID_AddKey(t *testing.T) {
arr = []stackitem.Item{stackitem.NewBuffer(pubs[3])}
e.Invoke(t, stackitem.NewArray(arr), "key", owner)
})
e.MakeCoverage(t, c, "frostfsid", "c.out")
}

View file

@ -9,6 +9,7 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-contract/common"
"git.frostfs.info/TrueCloudLab/frostfs-contract/container"
"git.frostfs.info/TrueCloudLab/frostfs-contract/covertest"
"git.frostfs.info/TrueCloudLab/frostfs-contract/netmap"
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
"github.com/nspcc-dev/neo-go/pkg/neotest"
@ -36,19 +37,19 @@ func deployNetmapContract(t *testing.T, e *neotest.Executor, addrBalance, addrCo
return c.Hash
}
func newNetmapInvoker(t *testing.T, config ...interface{}) *neotest.ContractInvoker {
func newNetmapInvoker(t *testing.T, config ...interface{}) *covertest.ContractInvoker {
e := newExecutor(t)
ctrNNS := neotest.CompileFile(t, e.CommitteeHash, nnsPath, path.Join(nnsPath, "config.yml"))
ctrNetmap := neotest.CompileFile(t, e.CommitteeHash, netmapPath, path.Join(netmapPath, "config.yml"))
ctrBalance := neotest.CompileFile(t, e.CommitteeHash, balancePath, path.Join(balancePath, "config.yml"))
ctrContainer := neotest.CompileFile(t, e.CommitteeHash, containerPath, path.Join(containerPath, "config.yml"))
ctrNNS := covertest.CompileFile(t, e.CommitteeHash, nnsPath, path.Join(nnsPath, "config.yml"))
ctrNetmap := covertest.CompileFile(t, e.CommitteeHash, netmapPath, path.Join(netmapPath, "config.yml"))
ctrBalance := covertest.CompileFile(t, e.CommitteeHash, balancePath, path.Join(balancePath, "config.yml"))
ctrContainer := covertest.CompileFile(t, e.CommitteeHash, containerPath, path.Join(containerPath, "config.yml"))
e.DeployContract(t, ctrNNS, nil)
deployContainerContract(t, e, ctrNetmap.Hash, ctrBalance.Hash, ctrNNS.Hash)
deployBalanceContract(t, e, ctrNetmap.Hash, ctrContainer.Hash)
deployNetmapContract(t, e, ctrBalance.Hash, ctrContainer.Hash, config...)
return e.CommitteeInvoker(ctrNetmap.Hash)
e.DeployContract(t, ctrNNS.Contract, nil)
deployContainerContract(t, e, ctrNetmap.Contract.Hash, ctrBalance.Contract.Hash, ctrNNS.Contract.Hash)
deployBalanceContract(t, e, ctrNetmap.Contract.Hash, ctrContainer.Contract.Hash)
deployNetmapContract(t, e, ctrBalance.Contract.Hash, ctrContainer.Contract.Hash, config...)
return covertest.CommitteeInvoker(e, ctrNetmap.Contract.Hash)
}
func TestDeploySetConfig(t *testing.T) {
@ -80,7 +81,7 @@ func dummyNodeInfo(acc neotest.Signer) testNodeInfo {
}
}
func newStorageNode(t *testing.T, c *neotest.ContractInvoker) testNodeInfo {
func newStorageNode(t *testing.T, c *covertest.ContractInvoker) testNodeInfo {
return dummyNodeInfo(c.NewAccount(t))
}
@ -173,7 +174,7 @@ func TestUpdateSnapshotCount(t *testing.T) {
require.True(t, netmap.DefaultSnapshotCount > 5) // sanity check, adjust tests if false.
prepare := func(t *testing.T, cNm *neotest.ContractInvoker, epochCount int) [][]testNodeInfo {
prepare := func(t *testing.T, cNm *covertest.ContractInvoker, epochCount int) [][]testNodeInfo {
nodes := make([][]testNodeInfo, epochCount)
nodes[0] = []testNodeInfo{newStorageNode(t, cNm)}
cNm.Invoke(t, stackitem.Null{}, "addPeerIR", nodes[0][0].raw)
@ -279,7 +280,7 @@ func TestUpdateSnapshotCount(t *testing.T) {
})
}
func checkSnapshotAt(t *testing.T, epoch int, cNm *neotest.ContractInvoker, nodes []testNodeInfo) {
func checkSnapshotAt(t *testing.T, epoch int, cNm *covertest.ContractInvoker, nodes []testNodeInfo) {
s, err := cNm.TestInvoke(t, "snapshot", int64(epoch))
require.NoError(t, err)
require.Equal(t, 1, s.Len())
@ -402,7 +403,7 @@ func TestUpdateState(t *testing.T) {
checkNetmapCandidates(t, cNm, 0)
}
func checkNetmapCandidates(t *testing.T, c *neotest.ContractInvoker, size int) []stackitem.Item {
func checkNetmapCandidates(t *testing.T, c *covertest.ContractInvoker, size int) []stackitem.Item {
s, err := c.TestInvoke(t, "netmapCandidates")
require.NoError(t, err)
require.Equal(t, 1, s.Len())