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  }