github.com/ethersphere/bee/v2@v2.2.0/pkg/api/soc_test.go (about) 1 // Copyright 2021 The Swarm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package api_test 6 7 import ( 8 "bytes" 9 "encoding/hex" 10 "fmt" 11 "io" 12 "net/http" 13 "testing" 14 "time" 15 16 "github.com/ethersphere/bee/v2/pkg/api" 17 "github.com/ethersphere/bee/v2/pkg/crypto" 18 "github.com/ethersphere/bee/v2/pkg/jsonhttp" 19 "github.com/ethersphere/bee/v2/pkg/jsonhttp/jsonhttptest" 20 "github.com/ethersphere/bee/v2/pkg/postage" 21 mockbatchstore "github.com/ethersphere/bee/v2/pkg/postage/batchstore/mock" 22 testingpostage "github.com/ethersphere/bee/v2/pkg/postage/testing" 23 testingsoc "github.com/ethersphere/bee/v2/pkg/soc/testing" 24 "github.com/ethersphere/bee/v2/pkg/spinlock" 25 mockstorer "github.com/ethersphere/bee/v2/pkg/storer/mock" 26 "github.com/ethersphere/bee/v2/pkg/swarm" 27 ) 28 29 // nolint:paralleltest 30 func TestSOC(t *testing.T) { 31 var ( 32 testData = []byte("foo") 33 socResource = func(owner, id, sig string) string { return fmt.Sprintf("/soc/%s/%s?sig=%s", owner, id, sig) } 34 mockStorer = mockstorer.New() 35 ) 36 t.Run("empty data", func(t *testing.T) { 37 client, _, _, _ := newTestServer(t, testServerOptions{ 38 Storer: mockStorer, 39 Post: newTestPostService(), 40 DirectUpload: true, 41 }) 42 jsonhttptest.Request(t, client, http.MethodPost, socResource("8d3766440f0d7b949a5e32995d09619a7f86e632", "bb", "cc"), http.StatusBadRequest, 43 jsonhttptest.WithRequestHeader(api.SwarmPostageBatchIdHeader, batchOkStr), 44 jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{ 45 Message: "short chunk data", 46 Code: http.StatusBadRequest, 47 }), 48 ) 49 }) 50 51 t.Run("signature invalid", func(t *testing.T) { 52 s := testingsoc.GenerateMockSOC(t, testData) 53 54 // modify the sign 55 sig := make([]byte, swarm.SocSignatureSize) 56 copy(sig, s.Signature) 57 sig[12] = 0x98 58 sig[10] = 0x12 59 60 client, _, _, _ := newTestServer(t, testServerOptions{ 61 Storer: mockStorer, 62 Post: newTestPostService(), 63 DirectUpload: true, 64 }) 65 jsonhttptest.Request(t, client, http.MethodPost, socResource(hex.EncodeToString(s.Owner), hex.EncodeToString(s.ID), hex.EncodeToString(sig)), http.StatusUnauthorized, 66 jsonhttptest.WithRequestBody(bytes.NewReader(s.WrappedChunk.Data())), 67 jsonhttptest.WithRequestHeader(api.SwarmPostageBatchIdHeader, batchOkStr), 68 jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{ 69 Message: "invalid chunk", 70 Code: http.StatusUnauthorized, 71 }), 72 ) 73 }) 74 75 t.Run("ok", func(t *testing.T) { 76 s := testingsoc.GenerateMockSOC(t, testData) 77 client, _, _, _ := newTestServer(t, testServerOptions{ 78 Storer: mockStorer, 79 Post: newTestPostService(), 80 DirectUpload: true, 81 }) 82 jsonhttptest.Request(t, client, http.MethodPost, socResource(hex.EncodeToString(s.Owner), hex.EncodeToString(s.ID), hex.EncodeToString(s.Signature)), http.StatusCreated, 83 jsonhttptest.WithRequestHeader(api.SwarmPinHeader, "true"), 84 jsonhttptest.WithRequestHeader(api.SwarmPostageBatchIdHeader, batchOkStr), 85 jsonhttptest.WithRequestBody(bytes.NewReader(s.WrappedChunk.Data())), 86 jsonhttptest.WithExpectedJSONResponse(api.SocPostResponse{ 87 Reference: s.Address(), 88 }), 89 ) 90 91 // try to fetch the same chunk 92 rsrc := fmt.Sprintf("/chunks/" + s.Address().String()) 93 resp := request(t, client, http.MethodGet, rsrc, nil, http.StatusOK) 94 data, err := io.ReadAll(resp.Body) 95 if err != nil { 96 t.Fatal(err) 97 } 98 99 if !bytes.Equal(s.Chunk().Data(), data) { 100 t.Fatal("data retrieved doesn't match uploaded content") 101 } 102 }) 103 104 t.Run("postage", func(t *testing.T) { 105 s := testingsoc.GenerateMockSOC(t, testData) 106 t.Run("err - bad batch", func(t *testing.T) { 107 hexbatch := "abcdefgg" 108 client, _, _, _ := newTestServer(t, testServerOptions{ 109 Storer: mockStorer, 110 Post: newTestPostService(), 111 DirectUpload: true, 112 }) 113 jsonhttptest.Request(t, client, http.MethodPost, socResource(hex.EncodeToString(s.Owner), hex.EncodeToString(s.ID), hex.EncodeToString(s.Signature)), http.StatusBadRequest, 114 jsonhttptest.WithRequestHeader(api.SwarmPostageBatchIdHeader, hexbatch), 115 jsonhttptest.WithRequestBody(bytes.NewReader(s.WrappedChunk.Data())), 116 jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{ 117 Code: http.StatusBadRequest, 118 Message: "invalid header params", 119 Reasons: []jsonhttp.Reason{ 120 { 121 Field: api.SwarmPostageBatchIdHeader, 122 Error: api.HexInvalidByteError('g').Error(), 123 }, 124 }, 125 })) 126 }) 127 128 t.Run("ok batch", func(t *testing.T) { 129 130 s := testingsoc.GenerateMockSOC(t, testData) 131 hexbatch := hex.EncodeToString(batchOk) 132 client, _, _, chanStorer := newTestServer(t, testServerOptions{ 133 Storer: mockStorer, 134 Post: newTestPostService(), 135 DirectUpload: true, 136 }) 137 jsonhttptest.Request(t, client, http.MethodPost, socResource(hex.EncodeToString(s.Owner), hex.EncodeToString(s.ID), hex.EncodeToString(s.Signature)), http.StatusCreated, 138 jsonhttptest.WithRequestHeader(api.SwarmDeferredUploadHeader, "true"), 139 jsonhttptest.WithRequestHeader(api.SwarmPostageBatchIdHeader, hexbatch), 140 jsonhttptest.WithRequestBody(bytes.NewReader(s.WrappedChunk.Data())), 141 ) 142 err := spinlock.Wait(time.Second, func() bool { return chanStorer.Has(s.Address()) }) 143 if err != nil { 144 t.Fatal(err) 145 } 146 }) 147 148 // TestPreSignedUpload tests that chunk can be uploaded with pre-signed postage stamp 149 t.Run("pre-signed upload", func(t *testing.T) { 150 t.Parallel() 151 152 var ( 153 s = testingsoc.GenerateMockSOC(t, testData) 154 storerMock = mockstorer.New() 155 batchStore = mockbatchstore.New() 156 client, _, _, _ = newTestServer(t, testServerOptions{ 157 Storer: storerMock, 158 BatchStore: batchStore, 159 }) 160 ) 161 162 // generate random postage batch and stamp 163 key, _ := crypto.GenerateSecp256k1Key() 164 signer := crypto.NewDefaultSigner(key) 165 owner, _ := signer.EthereumAddress() 166 stamp := testingpostage.MustNewValidStamp(signer, s.Address()) 167 _ = batchStore.Save(&postage.Batch{ 168 ID: stamp.BatchID(), 169 Owner: owner.Bytes(), 170 }) 171 stampBytes, _ := stamp.MarshalBinary() 172 173 // read off inserted chunk 174 go func() { <-storerMock.PusherFeed() }() 175 176 jsonhttptest.Request(t, client, http.MethodPost, socResource(hex.EncodeToString(s.Owner), hex.EncodeToString(s.ID), hex.EncodeToString(s.Signature)), http.StatusCreated, 177 jsonhttptest.WithRequestHeader(api.SwarmPostageStampHeader, hex.EncodeToString(stampBytes)), 178 jsonhttptest.WithRequestBody(bytes.NewReader(s.WrappedChunk.Data())), 179 ) 180 }) 181 182 t.Run("err - batch empty", func(t *testing.T) { 183 s := testingsoc.GenerateMockSOC(t, testData) 184 hexbatch := hex.EncodeToString(batchEmpty) 185 client, _, _, _ := newTestServer(t, testServerOptions{ 186 Storer: mockStorer, 187 Post: newTestPostService(), 188 DirectUpload: true, 189 }) 190 jsonhttptest.Request(t, client, http.MethodPost, socResource(hex.EncodeToString(s.Owner), hex.EncodeToString(s.ID), hex.EncodeToString(s.Signature)), http.StatusBadRequest, 191 jsonhttptest.WithRequestHeader(api.SwarmPostageBatchIdHeader, hexbatch), 192 jsonhttptest.WithRequestBody(bytes.NewReader(s.WrappedChunk.Data())), 193 ) 194 }) 195 }) 196 }