github.com/0chain/gosdk@v1.17.11/zboxcore/sdk/writemarker_mutex_test.go (about)

     1  package sdk
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"io"
     7  	"io/ioutil"
     8  	"net/http"
     9  	"strconv"
    10  	"strings"
    11  	"sync"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/0chain/gosdk/zboxcore/blockchain"
    16  	"github.com/0chain/gosdk/zboxcore/client"
    17  	"github.com/0chain/gosdk/zboxcore/mocks"
    18  	"github.com/0chain/gosdk/zboxcore/zboxutil"
    19  	"github.com/stretchr/testify/mock"
    20  	"github.com/stretchr/testify/require"
    21  )
    22  
    23  func TestWriteMarkerMutext_Should_Lock(t *testing.T) {
    24  	rawClient := zboxutil.Client
    25  	var mockClient = mocks.HttpClient{}
    26  	zboxutil.Client = &mockClient
    27  
    28  	defer func() {
    29  		zboxutil.Client = rawClient
    30  	}()
    31  
    32  	a := &Allocation{
    33  		ID:           "TestWriteMarkerMutext",
    34  		Tx:           "TestWriteMarkerMutext",
    35  		DataShards:   2,
    36  		ParityShards: 1,
    37  	}
    38  	setupMockAllocation(t, a)
    39  
    40  	setupHttpResponses := func(t *testing.T, testName string, numBlobbers int, numCorrect int) {
    41  		for i := 0; i < numBlobbers; i++ {
    42  			url := mockBlobberUrl + strconv.Itoa(i)
    43  			mockClient.On("Do", mock.MatchedBy(func(req *http.Request) bool {
    44  				return req.Method == "POST" &&
    45  					strings.Contains(req.URL.String(), testName+url)
    46  			})).Return(&http.Response{
    47  				StatusCode: func() int {
    48  					if i < numCorrect {
    49  						return http.StatusOK
    50  					}
    51  					return http.StatusBadRequest
    52  				}(),
    53  				Body: ioutil.NopCloser(bytes.NewReader([]byte(`{"status":2}`))),
    54  			}, nil)
    55  
    56  			mockClient.On("Do", mock.MatchedBy(func(req *http.Request) bool {
    57  				return req.Method == "DELETE" &&
    58  					strings.Contains(req.URL.String(), testName+url)
    59  			})).Return(&http.Response{
    60  				StatusCode: func() int {
    61  					if i < numCorrect {
    62  						return http.StatusOK
    63  					}
    64  					return http.StatusBadRequest
    65  				}(),
    66  			}, nil)
    67  		}
    68  	}
    69  
    70  	for i := 0; i < 3; i++ {
    71  		a.Blobbers = append(a.Blobbers, &blockchain.StorageNode{
    72  			ID:      "write_marker_mutex_" + strconv.Itoa(i),
    73  			Baseurl: "http://" + t.Name() + mockBlobberUrl + strconv.Itoa(i),
    74  		})
    75  	}
    76  
    77  	setupHttpResponses(t, t.Name(), len(a.Blobbers), len(a.Blobbers))
    78  
    79  	mask := zboxutil.NewUint128(1).Lsh(uint64(len(a.Blobbers))).Sub64(1)
    80  	mu := &sync.Mutex{}
    81  	mutex, _ := CreateWriteMarkerMutex(client.GetClient(), a)
    82  	consensus := &Consensus{RWMutex: &sync.RWMutex{}}
    83  	consensus.Init(a.consensusThreshold, a.fullconsensus)
    84  
    85  	err := mutex.Lock(context.TODO(), &mask, mu, a.Blobbers,
    86  		consensus, 0, time.Minute, zboxutil.NewConnectionId())
    87  	require.Nil(t, err)
    88  
    89  }
    90  
    91  func TestWriteMarkerMutext_Some_Blobbers_Down_Should_Lock(t *testing.T) {
    92  	var mockClient = mocks.HttpClient{}
    93  	rawClient := zboxutil.Client
    94  	zboxutil.Client = &mockClient
    95  
    96  	defer func() {
    97  		zboxutil.Client = rawClient
    98  	}()
    99  
   100  	a := &Allocation{
   101  		ID:           "TestWriteMarkerMutext",
   102  		Tx:           "TestWriteMarkerMutext",
   103  		DataShards:   2,
   104  		ParityShards: 2,
   105  	}
   106  	setupMockAllocation(t, a)
   107  
   108  	require := require.New(t)
   109  
   110  	setupHttpResponses := func(t *testing.T, testName string, numBlobbers int, numCorrect int) {
   111  		for i := 0; i < numBlobbers; i++ {
   112  			url := mockBlobberUrl + strconv.Itoa(i)
   113  			mockClient.On("Do", mock.MatchedBy(func(req *http.Request) bool {
   114  				return req.Method == "POST" &&
   115  					strings.Contains(req.URL.String(), testName+url)
   116  			})).Return(&http.Response{
   117  				StatusCode: func() int {
   118  					if i < numCorrect {
   119  						return http.StatusOK
   120  					}
   121  					return http.StatusBadRequest
   122  				}(),
   123  				Body: io.NopCloser(bytes.NewReader([]byte(`{"status":2}`))),
   124  			}, nil)
   125  
   126  			mockClient.On("Do", mock.MatchedBy(func(req *http.Request) bool {
   127  				return req.Method == "DELETE" &&
   128  					strings.Contains(req.URL.String(), testName+url)
   129  			})).Return(&http.Response{
   130  				StatusCode: func() int {
   131  					if i < numCorrect {
   132  						return http.StatusOK
   133  					}
   134  					return http.StatusBadRequest
   135  				}(),
   136  				Body: io.NopCloser(bytes.NewReader([]byte(""))),
   137  			}, nil)
   138  		}
   139  	}
   140  
   141  	for i := 0; i < 4; i++ {
   142  		a.Blobbers = append(a.Blobbers, &blockchain.StorageNode{
   143  			ID:      "write_marker_mutex_" + strconv.Itoa(i),
   144  			Baseurl: "http://" + t.Name() + mockBlobberUrl + strconv.Itoa(i),
   145  		})
   146  	}
   147  
   148  	setupHttpResponses(t, t.Name(), len(a.Blobbers), len(a.Blobbers)-1)
   149  	mutex, _ := CreateWriteMarkerMutex(client.GetClient(), a)
   150  	mask := zboxutil.NewUint128(1).Lsh(uint64(len(a.Blobbers))).Sub64(1)
   151  	mu := &sync.Mutex{}
   152  	consensus := &Consensus{RWMutex: &sync.RWMutex{}}
   153  	consensus.Init(a.consensusThreshold, a.fullconsensus)
   154  	err := mutex.Lock(context.TODO(), &mask, mu, a.Blobbers,
   155  		consensus, 0, time.Minute, zboxutil.NewConnectionId())
   156  	require.Nil(err)
   157  }
   158  
   159  func TestWriteMarkerMutext_Too_Less_Blobbers_Response_Should_Not_Lock(t *testing.T) {
   160  	var mockClient = mocks.HttpClient{}
   161  
   162  	rawClient := zboxutil.Client
   163  	zboxutil.Client = &mockClient
   164  
   165  	defer func() {
   166  		zboxutil.Client = rawClient
   167  	}()
   168  
   169  	a := &Allocation{
   170  		ID:           "TestWriteMarkerMutext",
   171  		Tx:           "TestWriteMarkerMutext",
   172  		DataShards:   2,
   173  		ParityShards: 1,
   174  	}
   175  	setupMockAllocation(t, a)
   176  
   177  	setupHttpResponses := func(t *testing.T, testName string, numBlobbers int, numCorrect int) {
   178  		for i := 0; i < numBlobbers; i++ {
   179  			url := mockBlobberUrl + strconv.Itoa(i)
   180  			mockClient.On("Do", mock.MatchedBy(func(req *http.Request) bool {
   181  				return req.Method == "POST" &&
   182  					strings.Contains(req.URL.String(), testName+url)
   183  			})).Return(&http.Response{
   184  				StatusCode: func() int {
   185  					if i < numCorrect {
   186  						return http.StatusOK
   187  					}
   188  					return http.StatusBadRequest
   189  				}(),
   190  				Body: ioutil.NopCloser(bytes.NewReader([]byte(""))),
   191  			}, nil)
   192  
   193  			mockClient.On("Do", mock.MatchedBy(func(req *http.Request) bool {
   194  				return req.Method == "DELETE" &&
   195  					strings.Contains(req.URL.String(), testName+url)
   196  			})).Return(&http.Response{
   197  				StatusCode: func() int {
   198  					if i < numCorrect {
   199  						return http.StatusOK
   200  					}
   201  					return http.StatusBadRequest
   202  				}(),
   203  				Body: io.NopCloser(bytes.NewReader([]byte(""))),
   204  			}, nil)
   205  		}
   206  	}
   207  
   208  	for i := 0; i < a.DataShards+a.ParityShards; i++ {
   209  		a.Blobbers = append(a.Blobbers, &blockchain.StorageNode{
   210  			ID:      "write_marker_mutex_" + strconv.Itoa(i),
   211  			Baseurl: "http://" + t.Name() + mockBlobberUrl + strconv.Itoa(i),
   212  		})
   213  	}
   214  
   215  	setupHttpResponses(t, t.Name(), len(a.Blobbers), a.consensusThreshold-1)
   216  	mutex, err := CreateWriteMarkerMutex(client.GetClient(), a)
   217  	require.NoError(t, err)
   218  	mask := zboxutil.NewUint128(1).Lsh(uint64(len(a.Blobbers))).Sub64(1)
   219  	mu := &sync.Mutex{}
   220  	consensus := &Consensus{RWMutex: &sync.RWMutex{}}
   221  	consensus.Init(a.consensusThreshold, a.fullconsensus)
   222  	err = mutex.Lock(context.TODO(), &mask, mu, a.Blobbers,
   223  		consensus, 0, time.Minute, zboxutil.NewConnectionId())
   224  	if err != nil {
   225  		require.Contains(t, err.Error(), "lock_consensus_not_met")
   226  	}
   227  }