diff --git a/pkg/innerring/indexer_test.go b/pkg/innerring/indexer_test.go new file mode 100644 index 00000000..493ae92d --- /dev/null +++ b/pkg/innerring/indexer_test.go @@ -0,0 +1,225 @@ +package innerring + +import ( + "fmt" + "testing" + "time" + + "github.com/nspcc-dev/neo-go/pkg/crypto/keys" + "github.com/stretchr/testify/require" + "go.uber.org/atomic" +) + +func TestIndexerReturnsIndexes(t *testing.T) { + t.Parallel() + commiteeKeys, err := keys.NewPublicKeysFromStrings([]string{ + "03ff65b6ae79134a4dce9d0d39d3851e9bab4ee97abf86e81e1c5bbc50cd2826ae", + "022bb4041c50d607ff871dec7e4cd7778388e0ea6849d84ccbd9aa8f32e16a8131", + }) + require.NoError(t, err, "convert string to commitee public keys failed") + cf := &testCommiteeFetcher{ + keys: commiteeKeys, + } + + irKeys, err := keys.NewPublicKeysFromStrings([]string{ + "038c862959e56b43e20f79187c4fe9e0bc7c8c66c1603e6cf0ec7f87ab6b08dc35", + "02ac920cd7df0b61b289072e6b946e2da4e1a31b9ab1c621bb475e30fa4ab102c3", + "022bb4041c50d607ff871dec7e4cd7778388e0ea6849d84ccbd9aa8f32e16a8131", + }) + require.NoError(t, err, "convert string to IR public keys failed") + irf := &testIRFetcher{ + keys: irKeys, + } + + t.Run("success", func(t *testing.T) { + t.Parallel() + key := irKeys[2] + + indexer := newInnerRingIndexer(cf, irf, key, time.Second) + + idx, err := indexer.AlphabetIndex() + require.NoError(t, err, "failed to get alphabet index") + require.Equal(t, int32(1), idx, "invalid alphabet index") + + idx, err = indexer.InnerRingIndex() + require.NoError(t, err, "failed to get IR index") + require.Equal(t, int32(2), idx, "invalid IR index") + + size, err := indexer.InnerRingSize() + require.NoError(t, err, "failed to get IR size") + require.Equal(t, int32(3), size, "invalid IR size") + }) + + t.Run("not found alphabet", func(t *testing.T) { + t.Parallel() + key := irKeys[0] + + indexer := newInnerRingIndexer(cf, irf, key, time.Second) + + idx, err := indexer.AlphabetIndex() + require.NoError(t, err, "failed to get alphabet index") + require.Equal(t, int32(-1), idx, "invalid alphabet index") + + idx, err = indexer.InnerRingIndex() + require.NoError(t, err, "failed to get IR index") + require.Equal(t, int32(0), idx, "invalid IR index") + }) + + t.Run("not found IR", func(t *testing.T) { + t.Parallel() + key := commiteeKeys[0] + + indexer := newInnerRingIndexer(cf, irf, key, time.Second) + + idx, err := indexer.AlphabetIndex() + require.NoError(t, err, "failed to get alphabet index") + require.Equal(t, int32(0), idx, "invalid alphabet index") + + idx, err = indexer.InnerRingIndex() + require.NoError(t, err, "failed to get IR index") + require.Equal(t, int32(-1), idx, "invalid IR index") + }) +} + +func TestIndexerCachesIndexes(t *testing.T) { + t.Parallel() + commiteeKeys, err := keys.NewPublicKeysFromStrings([]string{}) + require.NoError(t, err, "convert string to commitee public keys failed") + cf := &testCommiteeFetcher{ + keys: commiteeKeys, + } + + irKeys, err := keys.NewPublicKeysFromStrings([]string{}) + require.NoError(t, err, "convert string to IR public keys failed") + irf := &testIRFetcher{ + keys: irKeys, + } + + key, err := keys.NewPublicKeyFromString("022bb4041c50d607ff871dec7e4cd7778388e0ea6849d84ccbd9aa8f32e16a8131") + require.NoError(t, err, "convert string to public key failed") + + indexer := newInnerRingIndexer(cf, irf, key, time.Second) + + idx, err := indexer.AlphabetIndex() + require.NoError(t, err, "failed to get alphabet index") + require.Equal(t, int32(-1), idx, "invalid alphabet index") + + idx, err = indexer.InnerRingIndex() + require.NoError(t, err, "failed to get IR index") + require.Equal(t, int32(-1), idx, "invalid IR index") + + size, err := indexer.InnerRingSize() + require.NoError(t, err, "failed to get IR size") + require.Equal(t, int32(0), size, "invalid IR size") + + require.Equal(t, int32(1), cf.calls.Load(), "invalid commitee calls count") + require.Equal(t, int32(1), irf.calls.Load(), "invalid IR calls count") + + idx, err = indexer.AlphabetIndex() + require.NoError(t, err, "failed to get alphabet index") + require.Equal(t, int32(-1), idx, "invalid alphabet index") + + idx, err = indexer.InnerRingIndex() + require.NoError(t, err, "failed to get IR index") + require.Equal(t, int32(-1), idx, "invalid IR index") + + size, err = indexer.InnerRingSize() + require.NoError(t, err, "failed to get IR size") + require.Equal(t, int32(0), size, "invalid IR size") + + require.Equal(t, int32(1), cf.calls.Load(), "invalid commitee calls count") + require.Equal(t, int32(1), irf.calls.Load(), "invalid IR calls count") + + time.Sleep(2 * time.Second) + + idx, err = indexer.AlphabetIndex() + require.NoError(t, err, "failed to get alphabet index") + require.Equal(t, int32(-1), idx, "invalid alphabet index") + + idx, err = indexer.InnerRingIndex() + require.NoError(t, err, "failed to get IR index") + require.Equal(t, int32(-1), idx, "invalid IR index") + + size, err = indexer.InnerRingSize() + require.NoError(t, err, "failed to get IR size") + require.Equal(t, int32(0), size, "invalid IR size") + + require.Equal(t, int32(2), cf.calls.Load(), "invalid commitee calls count") + require.Equal(t, int32(2), irf.calls.Load(), "invalid IR calls count") +} + +func TestIndexerThrowsErrors(t *testing.T) { + t.Parallel() + cf := &testCommiteeFetcher{ + err: fmt.Errorf("test commitee error"), + } + + irKeys, err := keys.NewPublicKeysFromStrings([]string{}) + require.NoError(t, err, "convert string to IR public keys failed") + irf := &testIRFetcher{ + keys: irKeys, + } + + key, err := keys.NewPublicKeyFromString("022bb4041c50d607ff871dec7e4cd7778388e0ea6849d84ccbd9aa8f32e16a8131") + require.NoError(t, err, "convert string to public key failed") + + indexer := newInnerRingIndexer(cf, irf, key, time.Second) + + idx, err := indexer.AlphabetIndex() + require.ErrorContains(t, err, "test commitee error", "error from commitee not throwed") + require.Equal(t, int32(0), idx, "invalid alphabet index") + + idx, err = indexer.InnerRingIndex() + require.ErrorContains(t, err, "test commitee error", "error from IR not throwed") + require.Equal(t, int32(0), idx, "invalid IR index") + + size, err := indexer.InnerRingSize() + require.ErrorContains(t, err, "test commitee error", "error from IR not throwed") + require.Equal(t, int32(0), size, "invalid IR size") + + commiteeKeys, err := keys.NewPublicKeysFromStrings([]string{}) + require.NoError(t, err, "convert string to commitee public keys failed") + cf = &testCommiteeFetcher{ + keys: commiteeKeys, + } + + irf = &testIRFetcher{ + err: fmt.Errorf("test IR error"), + } + + indexer = newInnerRingIndexer(cf, irf, key, time.Second) + + idx, err = indexer.AlphabetIndex() + require.ErrorContains(t, err, "test IR error", "error from commitee not throwed") + require.Equal(t, int32(0), idx, "invalid alphabet index") + + idx, err = indexer.InnerRingIndex() + require.ErrorContains(t, err, "test IR error", "error from IR not throwed") + require.Equal(t, int32(0), idx, "invalid IR index") + + size, err = indexer.InnerRingSize() + require.ErrorContains(t, err, "test IR error", "error from IR not throwed") + require.Equal(t, int32(0), size, "invalid IR size") +} + +type testCommiteeFetcher struct { + keys keys.PublicKeys + err error + calls atomic.Int32 +} + +func (f *testCommiteeFetcher) Committee() (keys.PublicKeys, error) { + f.calls.Inc() + return f.keys, f.err +} + +type testIRFetcher struct { + keys keys.PublicKeys + err error + calls atomic.Int32 +} + +func (f *testIRFetcher) InnerRingKeys() (keys.PublicKeys, error) { + f.calls.Inc() + return f.keys, f.err +}