github.com/0chain/gosdk@v1.17.11/zboxcore/sdk/filemetaworker_test.go (about) 1 package sdk 2 3 import ( 4 "bytes" 5 "context" 6 "encoding/json" 7 "io" 8 "io/ioutil" 9 "mime" 10 "mime/multipart" 11 "net/http" 12 "strconv" 13 "strings" 14 "sync" 15 "testing" 16 "time" 17 18 "github.com/0chain/errors" 19 20 "github.com/0chain/gosdk/core/zcncrypto" 21 "github.com/0chain/gosdk/zboxcore/blockchain" 22 zclient "github.com/0chain/gosdk/zboxcore/client" 23 "github.com/0chain/gosdk/zboxcore/fileref" 24 "github.com/0chain/gosdk/zboxcore/marker" 25 "github.com/0chain/gosdk/zboxcore/mocks" 26 "github.com/0chain/gosdk/zboxcore/zboxutil" 27 "github.com/stretchr/testify/mock" 28 "github.com/stretchr/testify/require" 29 ) 30 31 func TestListRequest_getFileMetaInfoFromBlobber(t *testing.T) { 32 const mockFileRefName = "mock fileRef name" 33 const mockAllocationTxId = "mock transaction id" 34 const mockClientId = "mock client id" 35 const mockClientKey = "mock client key" 36 const mockRemoteFilePath = "mock/remote/file/path" 37 const mockSignature = "mock signature" 38 const mockAllocationId = "mock allocation id" 39 const mockErrorMessage = "mock error message" 40 41 var mockClient = mocks.HttpClient{} 42 zboxutil.Client = &mockClient 43 44 client := zclient.GetClient() 45 client.Wallet = &zcncrypto.Wallet{ 46 ClientID: mockClientId, 47 ClientKey: mockClientKey, 48 } 49 50 type parameters struct { 51 fileRefToRetrieve fileref.FileRef 52 respStatusCode int 53 requestFields map[string]string 54 blobberIdx int 55 } 56 57 tests := []struct { 58 name string 59 parameters parameters 60 setup func(*testing.T, string, parameters, string) 61 wantErr bool 62 errMsg string 63 }{ 64 { 65 name: "Test_Http_Error", 66 parameters: parameters{ 67 respStatusCode: 0, 68 }, 69 setup: func(t *testing.T, name string, p parameters, errMsg string) { 70 mockClient.On("Do", mock.MatchedBy(func(req *http.Request) bool { 71 return strings.HasPrefix(req.URL.Path, "Test_Http_Error") 72 })).Return(&http.Response{ 73 Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), 74 StatusCode: p.respStatusCode, 75 }, errors.New("", mockErrorMessage)) 76 }, 77 wantErr: true, 78 errMsg: mockErrorMessage, 79 }, 80 { 81 name: "Test_Badly_Formatted", 82 parameters: parameters{ 83 respStatusCode: 200, 84 }, 85 setup: func(t *testing.T, name string, p parameters, errMsg string) { 86 mockClient.On("Do", mock.MatchedBy(func(req *http.Request) bool { 87 return strings.HasPrefix(req.URL.Path, "Test_Badly_Formatted") 88 })).Return(&http.Response{ 89 Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), 90 StatusCode: p.respStatusCode, 91 }, nil) 92 }, 93 wantErr: true, 94 errMsg: "file meta data response parse error", 95 }, 96 { 97 name: "Test_Success", 98 parameters: parameters{ 99 fileRefToRetrieve: fileref.FileRef{ 100 Ref: fileref.Ref{ 101 Name: mockFileRefName, 102 }, 103 }, 104 requestFields: map[string]string{ 105 "auth_token": func() string { 106 authBytes, err := json.Marshal(&marker.AuthTicket{ 107 Signature: mockSignature, 108 }) 109 require.NoError(t, err) 110 return string(authBytes) 111 }(), 112 "path_hash": fileref.GetReferenceLookup(mockAllocationId, mockRemoteFilePath), 113 }, 114 respStatusCode: http.StatusOK, 115 blobberIdx: 73, 116 }, 117 setup: func(t *testing.T, testName string, p parameters, errMsg string) { 118 mockClient.On("Do", mock.MatchedBy(func(req *http.Request) bool { 119 mediaType, params, err := mime.ParseMediaType(req.Header.Get("Content-Type")) 120 require.NoError(t, err) 121 require.True(t, strings.HasPrefix(mediaType, "multipart/")) 122 reader := multipart.NewReader(req.Body, params["boundary"]) 123 124 err = nil 125 for { 126 var part *multipart.Part 127 part, err = reader.NextPart() 128 if err != nil { 129 break 130 } 131 expected, ok := p.requestFields[part.FormName()] 132 require.True(t, ok) 133 actual, err := ioutil.ReadAll(part) 134 require.NoError(t, err) 135 require.EqualValues(t, expected, string(actual)) 136 } 137 require.Error(t, err) 138 require.EqualValues(t, "EOF", errors.Top(err)) 139 140 return req.URL.Path == "Test_Success"+zboxutil.FILE_META_ENDPOINT+mockAllocationTxId && 141 req.Method == "POST" && 142 req.Header.Get("X-App-Client-ID") == mockClientId && 143 req.Header.Get("X-App-Client-Key") == mockClientKey && 144 testName == "Test_Success" 145 })).Return(&http.Response{ 146 StatusCode: p.respStatusCode, 147 Body: func(p parameters) io.ReadCloser { 148 jsonFR, err := json.Marshal(p.fileRefToRetrieve) 149 require.NoError(t, err) 150 return ioutil.NopCloser(bytes.NewReader([]byte(jsonFR))) 151 }(p), 152 }, nil) 153 }, 154 }, 155 } 156 for _, tt := range tests { 157 tt := tt 158 t.Run(tt.name, func(t *testing.T) { 159 t.Parallel() 160 tt.setup(t, tt.name, tt.parameters, tt.errMsg) 161 blobber := &blockchain.StorageNode{ 162 Baseurl: tt.name, 163 } 164 req := &ListRequest{ 165 allocationID: mockAllocationId, 166 allocationTx: mockAllocationTxId, 167 ctx: context.TODO(), 168 remotefilepath: mockRemoteFilePath, 169 authToken: &marker.AuthTicket{ 170 Signature: mockSignature, 171 }, 172 } 173 rspCh := make(chan *fileMetaResponse, 1) 174 go req.getFileMetaInfoFromBlobber(blobber, 73, rspCh) 175 176 var resp *fileMetaResponse 177 select { 178 case <-time.After(time.Second * 10): 179 t.Log("Failed after time out of 10 second") 180 case resp = <-rspCh: 181 } 182 // resp := <-rspCh 183 require.EqualValues(t, tt.wantErr, resp.err != nil) 184 if resp.err != nil { 185 require.EqualValues(t, tt.errMsg, errors.Top(resp.err)) 186 return 187 } 188 require.EqualValues(t, tt.parameters.fileRefToRetrieve, *resp.fileref) 189 require.EqualValues(t, tt.parameters.blobberIdx, resp.blobberIdx) 190 }) 191 } 192 } 193 194 func TestListRequest_getFileConsensusFromBlobbers(t *testing.T) { 195 const mockAllocationTxId = "mock transaction id" 196 const mockAllocationId = "mock allocation id" 197 const mockFileRefName = "mock file ref name" 198 const mockBlobberUrl = "mockBlobberUrl" 199 const mockActualHash = "mockActualHash" 200 201 var mockClient = mocks.HttpClient{} 202 zboxutil.Client = &mockClient 203 204 const mockClientId = "mock client id" 205 const mockClientKey = "mock client key" 206 client := zclient.GetClient() 207 client.Wallet = &zcncrypto.Wallet{ 208 ClientID: mockClientId, 209 ClientKey: mockClientKey, 210 } 211 212 setupHttpResponses := func(t *testing.T, name string, numBlobbers, numCorrect int) { 213 require.True(t, numBlobbers >= numCorrect) 214 for i := 0; i < numBlobbers; i++ { 215 var hash string 216 if i < numCorrect { 217 hash = mockActualHash 218 } 219 frName := mockFileRefName + strconv.Itoa(i) 220 url := mockBlobberUrl + strconv.Itoa(i) 221 mockClient.On("Do", mock.MatchedBy(func(req *http.Request) bool { 222 return strings.HasPrefix(req.URL.Path, name+url) 223 })).Return(&http.Response{ 224 StatusCode: http.StatusOK, 225 Body: func(fileRefName, hash string) io.ReadCloser { 226 jsonFR, err := json.Marshal(&fileref.FileRef{ 227 ActualFileHash: hash, 228 Ref: fileref.Ref{ 229 Name: fileRefName, 230 }, 231 }) 232 require.NoError(t, err) 233 return ioutil.NopCloser(bytes.NewReader([]byte(jsonFR))) 234 }(frName, hash), 235 }, nil) 236 } 237 } 238 239 tests := []struct { 240 name string 241 numBlobbers int 242 consensus Consensus 243 numCorrect int 244 245 setup func(*testing.T, string, int, int) 246 wantErr bool 247 }{ 248 { 249 name: "Fail_Consensus", 250 numBlobbers: 10, 251 consensus: Consensus{ 252 RWMutex: &sync.RWMutex{}, 253 consensusThresh: 2, 254 fullconsensus: 50, 255 }, 256 numCorrect: 5, 257 setup: setupHttpResponses, 258 wantErr: true, 259 }, 260 { 261 name: "Pass_Consensus", 262 numBlobbers: 10, 263 consensus: Consensus{ 264 RWMutex: &sync.RWMutex{}, 265 consensusThresh: 2, 266 fullconsensus: 50, 267 }, 268 numCorrect: 6, 269 setup: setupHttpResponses, 270 }, 271 } 272 for _, tt := range tests { //nolint 273 t.Run(tt.name, func(t *testing.T) { 274 tt.setup(t, tt.name, tt.numBlobbers, tt.numCorrect) 275 req := &ListRequest{ 276 allocationID: mockAllocationId, 277 allocationTx: mockAllocationTxId, 278 ctx: context.TODO(), 279 blobbers: []*blockchain.StorageNode{}, 280 Consensus: tt.consensus, //nolint 281 } 282 for i := 0; i < tt.numBlobbers; i++ { 283 req.blobbers = append(req.blobbers, &blockchain.StorageNode{ 284 Baseurl: tt.name + mockBlobberUrl + strconv.Itoa(i), 285 }) 286 } 287 288 _, _, mask, fileRefs := req.getFileConsensusFromBlobbers() 289 290 if mask == nil && fileRefs == nil { 291 require.True(t, tt.wantErr) 292 return 293 } 294 require.Len(t, fileRefs, tt.numBlobbers) 295 for i, actual := range fileRefs { 296 expected := fileref.FileRef{} 297 expected.Name = mockFileRefName + strconv.Itoa(i) 298 if i < tt.numCorrect { 299 expected.ActualFileHash = mockActualHash 300 } 301 require.EqualValues(t, expected, *actual.fileref) 302 } 303 }) 304 } 305 }