github.com/0chain/gosdk@v1.17.11/zboxcore/sdk/listworker_test.go (about) 1 package sdk 2 3 import ( 4 "bytes" 5 "context" 6 "encoding/json" 7 "fmt" 8 "io" 9 "io/ioutil" 10 "net/http" 11 "strconv" 12 "strings" 13 "sync" 14 "testing" 15 16 "github.com/0chain/errors" 17 "github.com/0chain/gosdk/core/zcncrypto" 18 "github.com/0chain/gosdk/zboxcore/blockchain" 19 zclient "github.com/0chain/gosdk/zboxcore/client" 20 "github.com/0chain/gosdk/zboxcore/fileref" 21 "github.com/0chain/gosdk/zboxcore/marker" 22 "github.com/0chain/gosdk/zboxcore/mocks" 23 "github.com/0chain/gosdk/zboxcore/zboxutil" 24 "github.com/stretchr/testify/mock" 25 "github.com/stretchr/testify/require" 26 ) 27 28 func TestListRequest_getListInfoFromBlobber(t *testing.T) { 29 const ( 30 mockAllocationTxId = "mock transaction id" 31 mockClientId = "mock client id" 32 mockClientKey = "mock client key" 33 mockRemoteFilePath = "mock/remote/file/path" 34 mockSignature = "mock signature" 35 mockAllocationId = "mock allocation id" 36 mockErrorMessage = "mock error message" 37 mockBlobberId = "mock blobber Id" 38 mockAllocationRoot = "mock allocation root" 39 mockType = "d" 40 ) 41 var mockClient = mocks.HttpClient{} 42 zboxutil.Client = &mockClient 43 client := zclient.GetClient() 44 client.Wallet = &zcncrypto.Wallet{ 45 ClientID: mockClientId, 46 ClientKey: mockClientKey, 47 } 48 type parameters struct { 49 listHttpResp listResponse 50 ListResult fileref.ListResult 51 respStatusCode int 52 blobberIdx int 53 requestFields map[string]string 54 } 55 tests := []struct { 56 name string 57 parameters parameters 58 setup func(t *testing.T, name string, p parameters, errMsg string) 59 wantErr bool 60 errMsg string 61 }{ 62 { 63 name: "Test_Error_New_HTTP_Failed_By_Containing_" + string([]byte{0x7f, 0, 0}), 64 parameters: parameters{ 65 blobberIdx: 41, 66 respStatusCode: 0, 67 }, 68 setup: func(t *testing.T, name string, p parameters, errMsg string) {}, 69 wantErr: true, 70 errMsg: `net/url: invalid control character in URL`, 71 }, 72 { 73 name: "Test_HTTP_Error", 74 parameters: parameters{ 75 blobberIdx: 41, 76 respStatusCode: 0, 77 }, 78 setup: func(t *testing.T, name string, p parameters, errMsg string) { 79 mockClient.On("Do", mock.MatchedBy(func(req *http.Request) bool { 80 return strings.HasPrefix(req.URL.Path, name) 81 })).Return(&http.Response{ 82 Body: ioutil.NopCloser(bytes.NewReader([]byte(""))), 83 StatusCode: p.respStatusCode, 84 }, errors.New("", mockErrorMessage)) 85 }, 86 wantErr: true, 87 errMsg: mockErrorMessage, 88 }, 89 { 90 name: "Test_HTTP_Response_Failed", 91 parameters: parameters{ 92 blobberIdx: 41, 93 respStatusCode: http.StatusInternalServerError, 94 }, 95 setup: func(t *testing.T, name string, p parameters, errMsg string) { 96 mockClient.On("Do", mock.MatchedBy(func(req *http.Request) bool { 97 return strings.HasPrefix(req.URL.Path, name) 98 })).Return(&http.Response{ 99 Body: ioutil.NopCloser(bytes.NewReader([]byte(mockErrorMessage))), 100 StatusCode: p.respStatusCode, 101 }, nil) 102 }, 103 wantErr: true, 104 errMsg: "error from server list response: " + mockErrorMessage, 105 }, 106 { 107 name: "Test_Error_HTTP_Response_Not_JSON_Format", 108 parameters: parameters{ 109 blobberIdx: 41, 110 respStatusCode: http.StatusOK, 111 }, 112 setup: func(t *testing.T, name string, p parameters, errMsg string) { 113 mockClient.On("Do", mock.MatchedBy(func(req *http.Request) bool { 114 return strings.HasPrefix(req.URL.Path, name) 115 })).Return(&http.Response{ 116 Body: ioutil.NopCloser(bytes.NewReader([]byte("this is not json format"))), 117 StatusCode: p.respStatusCode, 118 }, nil) 119 }, 120 wantErr: true, 121 errMsg: "list entities response parse error:", 122 }, 123 { 124 name: "Test_Success", 125 parameters: parameters{ 126 listHttpResp: listResponse{ 127 ref: &fileref.Ref{ 128 AllocationID: mockAllocationId, 129 Type: mockType, 130 }, 131 }, 132 ListResult: fileref.ListResult{ 133 AllocationRoot: mockAllocationRoot, 134 Meta: map[string]interface{}{ 135 "type": mockType, 136 }, 137 }, 138 blobberIdx: 41, 139 respStatusCode: http.StatusOK, 140 requestFields: map[string]string{ 141 "auth_token": func() string { 142 authBytes, err := json.Marshal(&marker.AuthTicket{ 143 Signature: mockSignature, 144 }) 145 require.NoError(t, err) 146 return string(authBytes) 147 }(), 148 "path_hash": fileref.GetReferenceLookup(mockAllocationId, mockRemoteFilePath), 149 }, 150 }, 151 setup: func(t *testing.T, testName string, p parameters, _ string) { 152 mockClient.On("Do", mock.MatchedBy(func(req *http.Request) bool { 153 query := req.URL.Query() 154 require.EqualValues(t, query.Get("auth_token"), p.requestFields["auth_token"]) 155 require.EqualValues(t, query.Get("path_hash"), p.requestFields["path_hash"]) 156 return req.URL.Path == "Test_Success"+zboxutil.LIST_ENDPOINT+mockAllocationTxId && 157 req.Method == "GET" && 158 req.Header.Get("X-App-Client-ID") == mockClientId && 159 req.Header.Get("X-App-Client-Key") == mockClientKey && 160 testName == "Test_Success" 161 })).Return(&http.Response{ 162 StatusCode: p.respStatusCode, 163 Body: func(p parameters) io.ReadCloser { 164 jsonFR, err := json.Marshal(p.ListResult) 165 require.NoError(t, err) 166 return ioutil.NopCloser(bytes.NewReader([]byte(jsonFR))) 167 }(p), 168 }, nil).Once() 169 }, 170 }, 171 } 172 for _, tt := range tests { 173 t.Run(tt.name, func(t *testing.T) { 174 require := require.New(t) 175 tt.setup(t, tt.name, tt.parameters, tt.errMsg) 176 blobber := &blockchain.StorageNode{ 177 ID: mockBlobberId, 178 Baseurl: tt.name, 179 } 180 req := &ListRequest{ 181 allocationID: mockAllocationId, 182 allocationTx: mockAllocationTxId, 183 ctx: context.TODO(), 184 remotefilepath: mockRemoteFilePath, 185 authToken: &marker.AuthTicket{ 186 Signature: mockSignature, 187 }, 188 } 189 rspCh := make(chan *listResponse, 1) 190 go req.getListInfoFromBlobber(blobber, 41, rspCh) 191 resp := <-rspCh 192 require.EqualValues(tt.wantErr, resp.err != nil) 193 if resp.err != nil { 194 require.Contains(errors.Top(resp.err), tt.errMsg) 195 return 196 } 197 require.EqualValues(tt.parameters.listHttpResp.ref, resp.ref) 198 require.EqualValues(tt.parameters.blobberIdx, resp.blobberIdx) 199 }) 200 } 201 } 202 203 func TestListRequest_GetListFromBlobbers(t *testing.T) { 204 const ( 205 mockAllocationTxId = "mock transaction id" 206 mockAllocationId = "mock allocation id" 207 mockBlobberUrl = "mockBlobberUrl" 208 mockClientId = "mock client id" 209 mockClientKey = "mock client key" 210 mockAllocationRoot = "mock allocation root" 211 mockType = "d" 212 ) 213 214 var mockClient = mocks.HttpClient{} 215 zboxutil.Client = &mockClient 216 217 client := zclient.GetClient() 218 client.Wallet = &zcncrypto.Wallet{ 219 ClientID: mockClientId, 220 ClientKey: mockClientKey, 221 } 222 223 setupHttpResponses := func(t *testing.T, name string, numBlobbers int) { 224 for i := 0; i < numBlobbers; i++ { 225 url := mockBlobberUrl + strconv.Itoa(i) 226 mockClient.On("Do", mock.MatchedBy(func(req *http.Request) bool { 227 return strings.HasPrefix(req.URL.Path, name+url) 228 })).Return(&http.Response{ 229 StatusCode: http.StatusOK, 230 Body: func() io.ReadCloser { 231 jsonFR, err := json.Marshal(&fileref.ListResult{ 232 AllocationRoot: mockAllocationRoot, 233 Meta: map[string]interface{}{ 234 "type": mockType, 235 "file_meta_hash": "mock file meta hash", 236 }, 237 }) 238 fmt.Println("returned", string(jsonFR)) 239 require.NoError(t, err) 240 return ioutil.NopCloser(bytes.NewReader([]byte(jsonFR))) 241 }(), 242 }, nil) 243 } 244 } 245 246 tests := []struct { 247 name string 248 numBlobbers int 249 consensusThresh int 250 fullconsensus int 251 252 setup func(*testing.T, string, int) 253 wantFunc func(require *require.Assertions, req *ListRequest) 254 wantErr bool 255 }{ 256 { 257 name: "Test_Failed", 258 setup: nil, 259 wantFunc: func(require *require.Assertions, req *ListRequest) { 260 require.NotNil(req) 261 require.Equal(0, req.consensus) 262 }, 263 wantErr: true, 264 }, 265 { 266 name: "Test_Success", 267 numBlobbers: 4, 268 consensusThresh: 2, 269 fullconsensus: 4, 270 setup: setupHttpResponses, 271 wantFunc: func(require *require.Assertions, req *ListRequest) { 272 require.NotNil(req) 273 require.Equal(float32(2), req.consensus) 274 }, 275 }, 276 } 277 for _, tt := range tests { 278 t.Run(tt.name, func(t *testing.T) { 279 require := require.New(t) 280 if setup := tt.setup; setup != nil { 281 tt.setup(t, tt.name, tt.numBlobbers) 282 } 283 req := &ListRequest{ 284 allocationID: mockAllocationId, 285 allocationTx: mockAllocationTxId, 286 ctx: context.TODO(), 287 blobbers: []*blockchain.StorageNode{}, 288 Consensus: Consensus{ 289 consensusThresh: tt.consensusThresh, 290 fullconsensus: tt.fullconsensus, 291 RWMutex: &sync.RWMutex{}, 292 }, 293 listOnly: true, 294 } 295 for i := 0; i < tt.numBlobbers; i++ { 296 req.blobbers = append(req.blobbers, &blockchain.StorageNode{ 297 Baseurl: tt.name + mockBlobberUrl + strconv.Itoa(i), 298 }) 299 } 300 got, _ := req.GetListFromBlobbers() 301 expectedResult := &ListResult{ 302 Type: mockType, 303 Size: 0, 304 deleteMask: zboxutil.NewUint128(1).Lsh(uint64(len(req.blobbers))).Sub64(1), 305 FileMetaHash: "mock file meta hash", 306 } 307 if !tt.wantErr { 308 require.EqualValues(expectedResult, got) 309 return 310 } 311 tt.wantFunc(require, req) 312 }) 313 } 314 }