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  }