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 }