chunk_test.go 5.51 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
// Copyright 2020 The Swarm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package api_test

import (
	"bytes"
	"io"
	"io/ioutil"
	"net/http"
	"testing"

14 15 16
	"github.com/ethersphere/bee/pkg/logging"
	statestore "github.com/ethersphere/bee/pkg/statestore/mock"

Zahoor Mohamed's avatar
Zahoor Mohamed committed
17 18
	"github.com/ethersphere/bee/pkg/tags"

19
	"github.com/ethersphere/bee/pkg/api"
20 21
	"github.com/ethersphere/bee/pkg/jsonhttp"
	"github.com/ethersphere/bee/pkg/jsonhttp/jsonhttptest"
22
	"github.com/ethersphere/bee/pkg/storage"
23
	"github.com/ethersphere/bee/pkg/storage/mock"
acud's avatar
acud committed
24
	testingc "github.com/ethersphere/bee/pkg/storage/testing"
25 26 27
	"github.com/ethersphere/bee/pkg/swarm"
)

acud's avatar
acud committed
28
// TestChunkUploadDownload uploads a chunk to an API that verifies the chunk according
29 30
// to a given validator, then tries to download the uploaded data.
func TestChunkUploadDownload(t *testing.T) {
31

acud's avatar
acud committed
32
	var (
acud's avatar
acud committed
33 34 35 36 37 38 39 40 41 42 43
		targets         = "0x222"
		resource        = func(addr swarm.Address) string { return "/chunks/" + addr.String() }
		resourceTargets = func(addr swarm.Address) string { return "/chunks/" + addr.String() + "?targets=" + targets }
		someHash        = swarm.MustParseHexAddress("aabbcc")
		chunk           = testingc.GenerateTestRandomChunk()
		mockStatestore  = statestore.NewStateStore()
		logger          = logging.New(ioutil.Discard, 0)
		tag             = tags.NewTags(mockStatestore, logger)
		mockStorer      = mock.NewStorer()
		client, _, _    = newTestServer(t, testServerOptions{
			Storer: mockStorer,
Zahoor Mohamed's avatar
Zahoor Mohamed committed
44
			Tags:   tag,
acud's avatar
acud committed
45 46
		})
	)
47

acud's avatar
acud committed
48 49 50
	t.Run("invalid chunk", func(t *testing.T) {
		jsonhttptest.Request(t, client, http.MethodPost, resource(someHash), http.StatusBadRequest,
			jsonhttptest.WithRequestBody(bytes.NewReader(chunk.Data())),
51
			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
acud's avatar
acud committed
52
				Message: http.StatusText(http.StatusBadRequest),
53 54 55
				Code:    http.StatusBadRequest,
			}),
		)
56 57

		// make sure chunk is not retrievable
acud's avatar
acud committed
58
		_ = request(t, client, http.MethodGet, resource(someHash), nil, http.StatusNotFound)
59 60
	})

acud's avatar
acud committed
61 62
	t.Run("empty chunk", func(t *testing.T) {
		jsonhttptest.Request(t, client, http.MethodPost, resource(someHash), http.StatusBadRequest,
63
			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
acud's avatar
acud committed
64
				Message: http.StatusText(http.StatusBadRequest),
65 66 67
				Code:    http.StatusBadRequest,
			}),
		)
68

acud's avatar
acud committed
69 70
		// make sure chunk is not retrievable
		_ = request(t, client, http.MethodGet, resource(someHash), nil, http.StatusNotFound)
71 72 73
	})

	t.Run("ok", func(t *testing.T) {
acud's avatar
acud committed
74 75
		jsonhttptest.Request(t, client, http.MethodPost, resource(chunk.Address()), http.StatusOK,
			jsonhttptest.WithRequestBody(bytes.NewReader(chunk.Data())),
76 77 78 79 80
			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
				Message: http.StatusText(http.StatusOK),
				Code:    http.StatusOK,
			}),
		)
81 82

		// try to fetch the same chunk
acud's avatar
acud committed
83
		resp := request(t, client, http.MethodGet, resource(chunk.Address()), nil, http.StatusOK)
84 85 86 87 88
		data, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			t.Fatal(err)
		}

acud's avatar
acud committed
89
		if !bytes.Equal(chunk.Data(), data) {
90 91 92
			t.Fatal("data retrieved doesnt match uploaded content")
		}
	})
Zahoor Mohamed's avatar
Zahoor Mohamed committed
93

94
	t.Run("pin-invalid-value", func(t *testing.T) {
acud's avatar
acud committed
95 96
		jsonhttptest.Request(t, client, http.MethodPost, resource(chunk.Address()), http.StatusOK,
			jsonhttptest.WithRequestBody(bytes.NewReader(chunk.Data())),
97 98 99 100 101 102
			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
				Message: http.StatusText(http.StatusOK),
				Code:    http.StatusOK,
			}),
			jsonhttptest.WithRequestHeader(api.SwarmPinHeader, "invalid-pin"),
		)
103 104

		// Also check if the chunk is NOT pinned
acud's avatar
acud committed
105
		if mockStorer.GetModeSet(chunk.Address()) == storage.ModeSetPin {
106 107 108 109
			t.Fatal("chunk should not be pinned")
		}
	})
	t.Run("pin-header-missing", func(t *testing.T) {
acud's avatar
acud committed
110 111
		jsonhttptest.Request(t, client, http.MethodPost, resource(chunk.Address()), http.StatusOK,
			jsonhttptest.WithRequestBody(bytes.NewReader(chunk.Data())),
112 113 114 115 116
			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
				Message: http.StatusText(http.StatusOK),
				Code:    http.StatusOK,
			}),
		)
117 118

		// Also check if the chunk is NOT pinned
acud's avatar
acud committed
119
		if mockStorer.GetModeSet(chunk.Address()) == storage.ModeSetPin {
120 121 122 123
			t.Fatal("chunk should not be pinned")
		}
	})
	t.Run("pin-ok", func(t *testing.T) {
acud's avatar
acud committed
124 125
		jsonhttptest.Request(t, client, http.MethodPost, resource(chunk.Address()), http.StatusOK,
			jsonhttptest.WithRequestBody(bytes.NewReader(chunk.Data())),
126 127 128 129 130 131
			jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
				Message: http.StatusText(http.StatusOK),
				Code:    http.StatusOK,
			}),
			jsonhttptest.WithRequestHeader(api.SwarmPinHeader, "True"),
		)
132 133

		// Also check if the chunk is pinned
acud's avatar
acud committed
134
		if mockStorer.GetModePut(chunk.Address()) != storage.ModePutUploadPin {
135 136 137 138
			t.Fatal("chunk is not pinned")
		}

	})
139
	t.Run("retrieve-targets", func(t *testing.T) {
acud's avatar
acud committed
140
		resp := request(t, client, http.MethodGet, resourceTargets(chunk.Address()), nil, http.StatusOK)
141 142 143 144 145 146

		// Check if the target is obtained correctly
		if resp.Header.Get(api.TargetsRecoveryHeader) != targets {
			t.Fatalf("targets mismatch. got %s, want %s", resp.Header.Get(api.TargetsRecoveryHeader), targets)
		}
	})
147 148
}

149
func request(t *testing.T, client *http.Client, method, resource string, body io.Reader, responseCode int) *http.Response {
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
	t.Helper()

	req, err := http.NewRequest(method, resource, body)
	if err != nil {
		t.Fatal(err)
	}
	resp, err := client.Do(req)
	if err != nil {
		t.Fatal(err)
	}
	if resp.StatusCode != responseCode {
		t.Fatalf("got response status %s, want %v %s", resp.Status, responseCode, http.StatusText(responseCode))
	}
	return resp
}