Skip to content

Commit 73ddb9b

Browse files
committed
accept view unit-test
Signed-off-by: Angelo De Caro <adc@zurich.ibm.com>
1 parent 8d97041 commit 73ddb9b

File tree

3 files changed

+263
-17
lines changed

3 files changed

+263
-17
lines changed

token/services/ttx/accept.go

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,8 @@ package ttx
88

99
import (
1010
"github.com/hyperledger-labs/fabric-smart-client/pkg/utils/errors"
11-
"github.com/hyperledger-labs/fabric-smart-client/platform/view/services/id"
12-
"github.com/hyperledger-labs/fabric-smart-client/platform/view/services/sig"
1311
"github.com/hyperledger-labs/fabric-smart-client/platform/view/view"
14-
"github.com/hyperledger-labs/fabric-token-sdk/token/services/tokens"
12+
"github.com/hyperledger-labs/fabric-token-sdk/token/services/ttx/dep"
1513
"github.com/hyperledger-labs/fabric-token-sdk/token/services/utils"
1614
)
1715

@@ -67,18 +65,14 @@ func (s *AcceptView) Call(context view.Context) (interface{}, error) {
6765
// with the identity of the FSC node running this stack.
6866
func (s *AcceptView) ack(context view.Context) error {
6967
txRaw := s.tx.FromRaw
70-
idProvider, err := id.GetProvider(context)
68+
idProvider, err := dep.GetNetworkIdentityProvider(context)
7169
if err != nil {
72-
return errors.Wrapf(err, "failed to get identity provider")
70+
return errors.Wrapf(errors.Join(err, ErrDepNotAvailableInContext), "failed to get identity provider")
7371
}
7472
defaultIdentity := idProvider.DefaultIdentity()
7573

7674
logger.DebugfContext(context.Context(), "signing ack response [%s] with identity [%s]", utils.Hashable(txRaw), defaultIdentity)
77-
sigService, err := sig.GetService(context)
78-
if err != nil {
79-
return errors.Wrapf(err, "failed to get sig service")
80-
}
81-
signer, err := sigService.GetSigner(defaultIdentity)
75+
signer, err := idProvider.GetSigner(defaultIdentity)
8276
if err != nil {
8377
return errors.WithMessagef(err, "failed to get signer for default identity")
8478
}
@@ -101,12 +95,12 @@ func (s *AcceptView) ack(context view.Context) error {
10195

10296
func (s *AcceptView) cacheRequest(context view.Context) error {
10397
// cache the token request into the tokens db
104-
t, err := tokens.GetService(context, s.tx.TMSID())
98+
sp, err := GetStorageProvider(context)
10599
if err != nil {
106-
return errors.Wrapf(err, "failed to get tokens db for [%s]", s.tx.TMSID())
100+
return errors.Wrapf(errors.Join(err, ErrDepNotAvailableInContext), "failed to get storage provider")
107101
}
108102

109-
if err := t.CacheRequest(context.Context(), s.tx.TMSID(), s.tx.TokenRequest); err != nil {
103+
if err := sp.CacheRequest(context.Context(), s.tx.TMSID(), s.tx.TokenRequest); err != nil {
110104
logger.WarnfContext(context.Context(), "failed to cache token request [%s], this might cause delay, investigate when possible: [%s]", s.tx.TokenRequest.Anchor, err)
111105
}
112106

token/services/ttx/accept_test.go

Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package ttx_test
8+
9+
import (
10+
"math/rand"
11+
"strconv"
12+
"testing"
13+
14+
"github.com/hyperledger-labs/fabric-smart-client/pkg/utils/errors"
15+
"github.com/hyperledger-labs/fabric-smart-client/platform/view/services/endpoint"
16+
"github.com/hyperledger-labs/fabric-smart-client/platform/view/services/metrics"
17+
"github.com/hyperledger-labs/fabric-smart-client/platform/view/view"
18+
"github.com/hyperledger-labs/fabric-token-sdk/token"
19+
"github.com/hyperledger-labs/fabric-token-sdk/token/driver"
20+
"github.com/hyperledger-labs/fabric-token-sdk/token/driver/mock"
21+
"github.com/hyperledger-labs/fabric-token-sdk/token/services/ttx"
22+
mock2 "github.com/hyperledger-labs/fabric-token-sdk/token/services/ttx/dep/mock"
23+
"github.com/hyperledger-labs/fabric-token-sdk/token/services/ttx/dep/tokenapi"
24+
"github.com/stretchr/testify/assert"
25+
"github.com/stretchr/testify/require"
26+
)
27+
28+
type mockCounter struct {
29+
addCallCount int
30+
}
31+
32+
func (m *mockCounter) With(labelValues ...string) metrics.Counter {
33+
return m
34+
}
35+
36+
func (m *mockCounter) Add(delta float64) {
37+
m.addCallCount++
38+
}
39+
40+
type TestAcceptViewContext struct {
41+
ctx *mock2.Context
42+
tx *ttx.Transaction
43+
storageProvider *mock2.StorageProvider
44+
storage *mock2.Storage
45+
session *mock2.Session
46+
networkIdentityProvider *mock2.NetworkIdentityProvider
47+
networkIdentitySigner *mock2.NetworkIdentitySigner
48+
metrics *ttx.Metrics
49+
acceptedCounter *mockCounter
50+
}
51+
52+
func newTestAcceptViewContext(t *testing.T) *TestAcceptViewContext {
53+
t.Helper()
54+
55+
session := &mock2.Session{}
56+
ch := make(chan *view.Message, 2)
57+
session.ReceiveReturns(ch)
58+
59+
seed := strconv.Itoa(rand.Int())
60+
61+
tms := &mock2.TokenManagementServiceWithExtensions{}
62+
tms.NetworkReturns("a_network" + seed)
63+
tms.ChannelReturns("a_channel" + seed)
64+
tmsID := token.TMSID{
65+
Network: "a_network" + seed,
66+
Channel: "a_channel" + seed,
67+
Namespace: "a_namespace" + seed,
68+
}
69+
tms.IDReturns(tmsID)
70+
tokenDes := &mock.Deserializer{}
71+
tokenIP := &mock.IdentityProvider{}
72+
tokenIP.IsMeReturns(true)
73+
tokenSigner := &mock.Signer{}
74+
tokenSigner.SignReturns([]byte("a_token_sigma"+seed), nil)
75+
tokenIP.GetSignerReturns(tokenSigner, nil)
76+
tms.SigServiceReturns(token.NewSignatureService(tokenDes, tokenIP))
77+
tokenAPITMS := tokenapi.NewMockedManagementService(t, tmsID)
78+
tms.SetTokenManagementServiceStub = func(arg1 *token.Request) error {
79+
arg1.SetTokenService(tokenAPITMS)
80+
return nil
81+
}
82+
tmsp := &mock2.TokenManagementServiceProvider{}
83+
tmsp.TokenManagementServiceReturns(tms, nil)
84+
network := &mock2.Network{}
85+
network.ComputeTxIDReturns("an_anchor" + seed)
86+
np := &mock2.NetworkProvider{}
87+
np.GetNetworkReturns(network, nil)
88+
89+
req := token.NewRequest(nil, token.RequestAnchor("an_anchor"+seed))
90+
req.Metadata.Issues = []*driver.IssueMetadata{
91+
{
92+
Issuer: driver.AuditableIdentity{
93+
Identity: []byte("an_issuer" + seed),
94+
},
95+
},
96+
}
97+
tms.NewRequestReturns(req, nil)
98+
99+
ctx := &mock2.Context{}
100+
ctx.SessionReturns(session)
101+
ctx.ContextReturns(t.Context())
102+
ctx.GetServiceReturnsOnCall(0, tmsp, nil)
103+
ctx.GetServiceReturnsOnCall(1, np, nil)
104+
ctx.GetServiceReturnsOnCall(2, &endpoint.Service{}, nil)
105+
ctx.GetServiceReturnsOnCall(3, np, nil)
106+
ctx.GetServiceReturnsOnCall(4, tmsp, nil)
107+
tx, err := ttx.NewTransaction(ctx, []byte("a_signer"))
108+
require.NoError(t, err)
109+
110+
storage := &mock2.Storage{}
111+
storage.AppendReturns(nil)
112+
storageProvider := &mock2.StorageProvider{}
113+
storageProvider.GetStorageReturns(storage, nil)
114+
115+
networkIdentityProvider := &mock2.NetworkIdentityProvider{}
116+
nis := &mock2.NetworkIdentitySigner{}
117+
nis.SignReturns([]byte("an_ack_signature"+seed), nil)
118+
networkIdentityProvider.GetSignerReturns(nis, nil)
119+
networkIdentityProvider.DefaultIdentityReturns([]byte("default_identity" + seed))
120+
121+
acceptedCounter := &mockCounter{}
122+
metrics := &ttx.Metrics{
123+
AcceptedTransactions: acceptedCounter,
124+
}
125+
126+
ctx = &mock2.Context{}
127+
ctx.SessionReturns(session)
128+
ctx.ContextReturns(t.Context())
129+
ctx.GetServiceReturnsOnCall(0, storageProvider, nil)
130+
ctx.GetServiceReturnsOnCall(1, networkIdentityProvider, nil)
131+
ctx.GetServiceReturnsOnCall(2, metrics, nil)
132+
ctx.GetServiceReturnsOnCall(3, storageProvider, nil)
133+
134+
return &TestAcceptViewContext{
135+
ctx: ctx,
136+
tx: tx,
137+
storage: storage,
138+
storageProvider: storageProvider,
139+
session: session,
140+
networkIdentityProvider: networkIdentityProvider,
141+
networkIdentitySigner: nis,
142+
metrics: metrics,
143+
acceptedCounter: acceptedCounter,
144+
}
145+
}
146+
147+
func TestAcceptView(t *testing.T) {
148+
testCases := []struct {
149+
name string
150+
prepare func(*TestAcceptViewContext)
151+
expectError bool
152+
errorContains string
153+
expectErr error
154+
verify func(*TestAcceptViewContext, any)
155+
}{
156+
{
157+
name: "transaction is nil",
158+
prepare: func(c *TestAcceptViewContext) {
159+
c.tx = nil
160+
},
161+
expectError: true,
162+
errorContains: "transaction is nil",
163+
expectErr: ttx.ErrInvalidInput,
164+
},
165+
{
166+
name: "success",
167+
prepare: func(c *TestAcceptViewContext) {
168+
},
169+
expectError: false,
170+
verify: func(c *TestAcceptViewContext, res any) {
171+
assert.Equal(t, 1, c.session.SendWithContextCallCount())
172+
_, sigma := c.session.SendWithContextArgsForCall(0)
173+
assert.Contains(t, string(sigma), "an_ack_signature")
174+
175+
assert.Equal(t, 1, c.storage.AppendCallCount())
176+
assert.Equal(t, 1, c.storageProvider.CacheRequestCallCount())
177+
assert.Equal(t, 1, c.acceptedCounter.addCallCount)
178+
},
179+
},
180+
{
181+
name: "failed storing transaction records",
182+
prepare: func(c *TestAcceptViewContext) {
183+
c.storage.AppendReturns(errors.New("storage error"))
184+
},
185+
expectError: true,
186+
errorContains: "failed storing transaction records",
187+
},
188+
{
189+
name: "failed acknowledgement (identity provider)",
190+
prepare: func(c *TestAcceptViewContext) {
191+
c.ctx.GetServiceReturnsOnCall(1, nil, errors.New("id provider error"))
192+
},
193+
expectError: true,
194+
errorContains: "failed to get identity provider",
195+
},
196+
{
197+
name: "failed acknowledgement (signer)",
198+
prepare: func(c *TestAcceptViewContext) {
199+
c.networkIdentityProvider.GetSignerReturns(nil, errors.New("signer error"))
200+
},
201+
expectError: true,
202+
errorContains: "failed to get signer for default identity",
203+
},
204+
{
205+
name: "failed acknowledgement (sign)",
206+
prepare: func(c *TestAcceptViewContext) {
207+
c.networkIdentitySigner.SignReturns(nil, errors.New("sign error"))
208+
},
209+
expectError: true,
210+
errorContains: "failed to sign ack response",
211+
},
212+
{
213+
name: "failed acknowledgement (send)",
214+
prepare: func(c *TestAcceptViewContext) {
215+
c.session.SendWithContextReturns(errors.New("send error"))
216+
},
217+
expectError: true,
218+
errorContains: "failed sending ack",
219+
},
220+
{
221+
name: "failed caching request (storage provider)",
222+
prepare: func(c *TestAcceptViewContext) {
223+
c.ctx.GetServiceReturnsOnCall(3, nil, errors.New("storage provider error"))
224+
},
225+
expectError: true,
226+
errorContains: "failed to get storage provider",
227+
},
228+
}
229+
230+
for _, tc := range testCases {
231+
t.Run(tc.name, func(t *testing.T) {
232+
c := newTestAcceptViewContext(t)
233+
tc.prepare(c)
234+
v := ttx.NewAcceptView(c.tx)
235+
res, err := v.Call(c.ctx)
236+
if tc.expectError {
237+
require.Error(t, err)
238+
if len(tc.errorContains) > 0 {
239+
assert.Contains(t, err.Error(), tc.errorContains)
240+
}
241+
if tc.expectErr != nil {
242+
assert.ErrorIs(t, err, tc.expectErr)
243+
}
244+
} else {
245+
require.NoError(t, err)
246+
if tc.verify != nil {
247+
tc.verify(c, res)
248+
}
249+
}
250+
})
251+
}
252+
}

token/services/ttx/views.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ import (
1010
"github.com/hyperledger-labs/fabric-smart-client/platform/view/view"
1111
)
1212

13-
//go:generate counterfeiter -o deps/mock/context.go -fake-name Context . Context
14-
1513
// Context is an alias of view.Context
14+
//
15+
//go:generate counterfeiter -o deps/mock/context.go -fake-name Context . Context
1616
type Context = view.Context
1717

18-
//go:generate counterfeiter -o deps/mock/session.go -fake-name Session . Session
19-
2018
// Session is an alias of view.Session
19+
//
20+
//go:generate counterfeiter -o deps/mock/session.go -fake-name Session . Session
2121
type Session = view.Session

0 commit comments

Comments
 (0)