github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/internal/pkg/gateway/commit/finder_test.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package commit 8 9 import ( 10 "context" 11 "testing" 12 "time" 13 14 "github.com/hechain20/hechain/core/ledger" 15 "github.com/hechain20/hechain/internal/pkg/gateway/commit/mocks" 16 "github.com/hyperledger/fabric-protos-go/peer" 17 "github.com/pkg/errors" 18 "github.com/stretchr/testify/require" 19 ) 20 21 //go:generate counterfeiter -o mocks/queryprovider.go --fake-name QueryProvider . queryProvider 22 type queryProvider interface { // Mimic QueryProvider to avoid circular import with generated mock 23 QueryProvider 24 } 25 26 func TestFinder(t *testing.T) { 27 sendUntilDone := func(commitSend chan<- *ledger.CommitNotification, msg *ledger.CommitNotification) chan struct{} { 28 done := make(chan struct{}) 29 30 go func() { 31 for ; ; time.Sleep(10 * time.Millisecond) { 32 select { 33 case commitSend <- msg: 34 case <-done: 35 return 36 } 37 } 38 }() 39 40 return done 41 } 42 43 t.Run("passes channel name to query provider", func(t *testing.T) { 44 provider := &mocks.QueryProvider{} 45 provider.TransactionStatusReturns(peer.TxValidationCode_MVCC_READ_CONFLICT, 101, nil) 46 finder := NewFinder(provider, newTestNotifier(nil)) 47 48 finder.TransactionStatus(context.Background(), "CHANNEL", "TX_ID") 49 50 require.Equal(t, 1, provider.TransactionStatusCallCount()) 51 52 actual, _ := provider.TransactionStatusArgsForCall(0) 53 require.Equal(t, "CHANNEL", actual) 54 }) 55 56 t.Run("passes transaction ID to query provider", func(t *testing.T) { 57 provider := &mocks.QueryProvider{} 58 provider.TransactionStatusReturns(peer.TxValidationCode_MVCC_READ_CONFLICT, 101, nil) 59 finder := NewFinder(provider, newTestNotifier(nil)) 60 61 finder.TransactionStatus(context.Background(), "CHANNEL", "TX_ID") 62 63 require.Equal(t, 1, provider.TransactionStatusCallCount()) 64 65 _, actual := provider.TransactionStatusArgsForCall(0) 66 require.Equal(t, "TX_ID", actual) 67 }) 68 69 t.Run("returns previously committed transaction status", func(t *testing.T) { 70 provider := &mocks.QueryProvider{} 71 provider.TransactionStatusReturns(peer.TxValidationCode_MVCC_READ_CONFLICT, 101, nil) 72 finder := NewFinder(provider, newTestNotifier(nil)) 73 74 actual, err := finder.TransactionStatus(context.Background(), "CHANNEL", "TX_ID") 75 require.NoError(t, err) 76 77 expected := &Status{ 78 Code: peer.TxValidationCode_MVCC_READ_CONFLICT, 79 BlockNumber: 101, 80 TransactionID: "TX_ID", 81 } 82 require.Equal(t, expected, actual) 83 }) 84 85 t.Run("returns notified transaction status when no previous commit", func(t *testing.T) { 86 provider := &mocks.QueryProvider{} 87 provider.TransactionStatusReturns(0, 0, errors.New("NOT_FOUND")) 88 commitSend := make(chan *ledger.CommitNotification) 89 finder := NewFinder(provider, newTestNotifier(commitSend)) 90 91 msg := &ledger.CommitNotification{ 92 BlockNumber: 101, 93 TxsInfo: []*ledger.CommitNotificationTxInfo{ 94 { 95 TxID: "TX_ID", 96 ValidationCode: peer.TxValidationCode_MVCC_READ_CONFLICT, 97 }, 98 }, 99 } 100 defer close(sendUntilDone(commitSend, msg)) 101 102 actual, err := finder.TransactionStatus(context.Background(), "CHANNEL", "TX_ID") 103 require.NoError(t, err) 104 105 expected := &Status{ 106 Code: peer.TxValidationCode_MVCC_READ_CONFLICT, 107 BlockNumber: 101, 108 TransactionID: "TX_ID", 109 } 110 require.Equal(t, expected, actual) 111 }) 112 113 t.Run("returns error from notifier", func(t *testing.T) { 114 provider := &mocks.QueryProvider{} 115 provider.TransactionStatusReturns(0, 0, errors.New("NOT_FOUND")) 116 supplier := &mocks.NotificationSupplier{} 117 supplier.CommitNotificationsReturns(nil, errors.New("MY_ERROR")) 118 finder := NewFinder(provider, NewNotifier(supplier)) 119 120 _, err := finder.TransactionStatus(context.Background(), "CHANNEL", "TX_ID") 121 require.ErrorContains(t, err, "MY_ERROR") 122 }) 123 124 t.Run("passes channel name to supplier", func(t *testing.T) { 125 provider := &mocks.QueryProvider{} 126 provider.TransactionStatusReturns(0, 0, errors.New("NOT_FOUND")) 127 supplier := &mocks.NotificationSupplier{} 128 supplier.CommitNotificationsReturns(nil, errors.New("MY_ERROR")) 129 finder := NewFinder(provider, NewNotifier(supplier)) 130 131 finder.TransactionStatus(context.Background(), "CHANNEL", "TX_ID") 132 133 require.Equal(t, 1, supplier.CommitNotificationsCallCount()) 134 135 _, actual := supplier.CommitNotificationsArgsForCall(0) 136 require.Equal(t, "CHANNEL", actual) 137 }) 138 139 t.Run("returns context error when context cancelled", func(t *testing.T) { 140 provider := &mocks.QueryProvider{} 141 provider.TransactionStatusReturns(0, 0, errors.New("NOT_FOUND")) 142 finder := NewFinder(provider, newTestNotifier(nil)) 143 144 ctx, cancel := context.WithCancel(context.Background()) 145 cancel() 146 _, err := finder.TransactionStatus(ctx, "CHANNEL", "TX_ID") 147 148 require.Equal(t, context.Canceled, err) 149 }) 150 151 t.Run("returns error when notification supplier fails", func(t *testing.T) { 152 provider := &mocks.QueryProvider{} 153 provider.TransactionStatusReturns(0, 0, errors.New("NOT_FOUND")) 154 commitSend := make(chan *ledger.CommitNotification) 155 close(commitSend) 156 finder := NewFinder(provider, newTestNotifier(commitSend)) 157 158 _, err := finder.TransactionStatus(context.Background(), "CHANNEL", "TX_ID") 159 160 require.ErrorContains(t, err, "unexpected close of commit notification channel") 161 }) 162 }