git.frostfs.info/TrueCloudLab/frostfs-sdk-go@v0.0.0-20241022124111-5361f0ecebd3/ns/nns_test.go (about)

     1  package ns
     2  
     3  import (
     4  	"crypto/rand"
     5  	"errors"
     6  	"fmt"
     7  	"math/big"
     8  	"strings"
     9  	"testing"
    10  
    11  	"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
    12  	cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
    13  	"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
    14  	"github.com/nspcc-dev/neo-go/pkg/util"
    15  	"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
    16  	"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
    17  	"github.com/stretchr/testify/require"
    18  )
    19  
    20  // testNeoClient represents test Neo client which checks invocation arguments
    21  // and returns predefined result.
    22  type testNeoClient struct {
    23  	t *testing.T
    24  
    25  	expectedContract util.Uint160
    26  
    27  	res result.Invoke
    28  
    29  	err error
    30  }
    31  
    32  func (x *testNeoClient) Call(contract util.Uint160, operation string, params ...any) (*result.Invoke, error) {
    33  	var domain string
    34  
    35  	require.Equal(x.t, x.expectedContract, contract)
    36  	require.Equal(x.t, "resolve", operation)
    37  	require.Len(x.t, params, 2)
    38  	require.NotPanics(x.t, func() { domain = params[0].(string) })
    39  	require.NotPanics(x.t, func() { _ = params[1].(int64) })
    40  	require.True(x.t, strings.HasSuffix(domain, ".container"))
    41  	require.NotEmpty(x.t, strings.TrimSuffix(domain, ".container"))
    42  
    43  	return &x.res, x.err
    44  }
    45  
    46  // implements test stackitem.Item which is obviously incorrect:
    47  // it returns itself on Convert(stackitem.ArrayT), but returns integer from Value.
    48  type brokenArrayStackItem struct {
    49  	stackitem.Item
    50  }
    51  
    52  func (x brokenArrayStackItem) Value() any {
    53  	return 1
    54  }
    55  
    56  func (x brokenArrayStackItem) Convert(t stackitem.Type) (stackitem.Item, error) {
    57  	if t != stackitem.ArrayT {
    58  		panic(fmt.Sprintf("unexpected stack item type %s", t))
    59  	}
    60  
    61  	return x, nil
    62  }
    63  
    64  func TestNNS_ResolveContainerDomain(t *testing.T) {
    65  	var testContainerDomain container.Domain
    66  	testContainerDomain.SetName("some_container")
    67  
    68  	var nnsContract util.Uint160
    69  
    70  	rand.Read(nnsContract[:])
    71  
    72  	testC := &testNeoClient{
    73  		t:                t,
    74  		expectedContract: nnsContract,
    75  	}
    76  
    77  	n := NNS{
    78  		nnsContract: nnsContract,
    79  		invoker:     testC,
    80  	}
    81  
    82  	t.Run("invocation failure", func(t *testing.T) {
    83  		err1 := errors.New("invoke err")
    84  		testC.err = err1
    85  
    86  		_, err2 := n.ResolveContainerDomain(testContainerDomain)
    87  		require.ErrorIs(t, err2, err1)
    88  	})
    89  
    90  	testC.err = nil
    91  
    92  	t.Run("fault exception", func(t *testing.T) {
    93  		_, err := n.ResolveContainerDomain(testContainerDomain)
    94  		require.Error(t, err)
    95  	})
    96  
    97  	testC.res.State = vmstate.Halt.String()
    98  
    99  	t.Run("empty stack", func(t *testing.T) {
   100  		_, err := n.ResolveContainerDomain(testContainerDomain)
   101  		require.Error(t, err)
   102  	})
   103  
   104  	testC.res.Stack = make([]stackitem.Item, 1)
   105  
   106  	t.Run("non-array last stack item", func(t *testing.T) {
   107  		testC.res.Stack[0] = stackitem.NewBigInteger(big.NewInt(11))
   108  
   109  		_, err := n.ResolveContainerDomain(testContainerDomain)
   110  		require.Error(t, err)
   111  	})
   112  
   113  	t.Run("null array", func(t *testing.T) {
   114  		testC.res.Stack[0] = stackitem.Null{}
   115  
   116  		_, err := n.ResolveContainerDomain(testContainerDomain)
   117  		require.ErrorIs(t, err, errNotFound)
   118  	})
   119  
   120  	t.Run("array stack item with non-slice value", func(t *testing.T) {
   121  		testC.res.Stack[0] = brokenArrayStackItem{}
   122  
   123  		_, err := n.ResolveContainerDomain(testContainerDomain)
   124  		require.Error(t, err)
   125  	})
   126  
   127  	arr := make([]stackitem.Item, 2)
   128  	testC.res.Stack[0] = stackitem.NewArray(arr)
   129  
   130  	t.Run("non-bytes array element", func(t *testing.T) {
   131  		arr[0] = stackitem.NewArray(nil)
   132  
   133  		_, err := n.ResolveContainerDomain(testContainerDomain)
   134  		require.Error(t, err)
   135  	})
   136  
   137  	arr[0] = stackitem.NewByteArray([]byte("some byte array 1"))
   138  
   139  	t.Run("non-container array elements", func(t *testing.T) {
   140  		arr[1] = stackitem.NewByteArray([]byte("some byte array 2"))
   141  
   142  		_, err := n.ResolveContainerDomain(testContainerDomain)
   143  		require.Error(t, err)
   144  	})
   145  
   146  	t.Run("with container array element", func(t *testing.T) {
   147  		id := cidtest.ID()
   148  
   149  		arr[1] = stackitem.NewByteArray([]byte(id.EncodeToString()))
   150  
   151  		res, err := n.ResolveContainerDomain(testContainerDomain)
   152  		require.NoError(t, err)
   153  
   154  		require.Equal(t, id, res)
   155  	})
   156  }
   157  
   158  func TestNNS_ResolveContractHash(t *testing.T) {
   159  	var testContainerDomain container.Domain
   160  	testContainerDomain.SetName("some_container")
   161  
   162  	var nnsContract util.Uint160
   163  
   164  	rand.Read(nnsContract[:])
   165  
   166  	testC := &testNeoClient{
   167  		t:                t,
   168  		expectedContract: nnsContract,
   169  	}
   170  
   171  	n := NNS{
   172  		nnsContract: nnsContract,
   173  		invoker:     testC,
   174  	}
   175  
   176  	t.Run("invocation failure", func(t *testing.T) {
   177  		err1 := errors.New("invoke err")
   178  		testC.err = err1
   179  
   180  		_, err2 := n.ResolveContractHash(testContainerDomain)
   181  		require.ErrorIs(t, err2, err1)
   182  	})
   183  
   184  	testC.err = nil
   185  
   186  	t.Run("fault exception", func(t *testing.T) {
   187  		_, err := n.ResolveContractHash(testContainerDomain)
   188  		require.Error(t, err)
   189  	})
   190  
   191  	testC.res.State = vmstate.Halt.String()
   192  
   193  	t.Run("empty stack", func(t *testing.T) {
   194  		_, err := n.ResolveContractHash(testContainerDomain)
   195  		require.Error(t, err)
   196  	})
   197  
   198  	testC.res.Stack = make([]stackitem.Item, 1)
   199  
   200  	t.Run("non-array last stack item", func(t *testing.T) {
   201  		testC.res.Stack[0] = stackitem.NewBigInteger(big.NewInt(11))
   202  
   203  		_, err := n.ResolveContractHash(testContainerDomain)
   204  		require.Error(t, err)
   205  	})
   206  
   207  	t.Run("null array", func(t *testing.T) {
   208  		testC.res.Stack[0] = stackitem.Null{}
   209  
   210  		_, err := n.ResolveContractHash(testContainerDomain)
   211  		require.ErrorIs(t, err, errNotFound)
   212  	})
   213  
   214  	t.Run("array stack item with non-slice value", func(t *testing.T) {
   215  		testC.res.Stack[0] = brokenArrayStackItem{}
   216  
   217  		_, err := n.ResolveContractHash(testContainerDomain)
   218  		require.Error(t, err)
   219  	})
   220  
   221  	arr := make([]stackitem.Item, 2)
   222  	testC.res.Stack[0] = stackitem.NewArray(arr)
   223  
   224  	t.Run("non-bytes array element", func(t *testing.T) {
   225  		arr[0] = stackitem.NewArray(nil)
   226  
   227  		_, err := n.ResolveContractHash(testContainerDomain)
   228  		require.Error(t, err)
   229  	})
   230  
   231  	arr[0] = stackitem.NewByteArray([]byte("some byte array 1"))
   232  
   233  	t.Run("non-container array elements", func(t *testing.T) {
   234  		arr[1] = stackitem.NewByteArray([]byte("some byte array 2"))
   235  
   236  		_, err := n.ResolveContractHash(testContainerDomain)
   237  		require.Error(t, err)
   238  	})
   239  }