bb8e8725e8
These changes fix a few bugs in the PinSVC API and have been discovered by running the compliance tool at https://github.com/ipfs-shipyard/pinning-service-compliance. In particular, the error objects did not respect the spec, filters and counts were not done right. An additional PR will follow with fixes to the pintracker because some pin status information was not correctly set.
254 lines
6.8 KiB
Go
254 lines
6.8 KiB
Go
package pinsvcapi
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/ipfs-cluster/ipfs-cluster/api"
|
|
"github.com/ipfs-cluster/ipfs-cluster/api/common/test"
|
|
"github.com/ipfs-cluster/ipfs-cluster/api/pinsvcapi/pinsvc"
|
|
clustertest "github.com/ipfs-cluster/ipfs-cluster/test"
|
|
|
|
libp2p "github.com/libp2p/go-libp2p"
|
|
ma "github.com/multiformats/go-multiaddr"
|
|
)
|
|
|
|
func testAPIwithConfig(t *testing.T, cfg *Config, name string) *API {
|
|
ctx := context.Background()
|
|
apiMAddr, _ := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/0")
|
|
h, err := libp2p.New(libp2p.ListenAddrs(apiMAddr))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
cfg.HTTPListenAddr = []ma.Multiaddr{apiMAddr}
|
|
|
|
svcapi, err := NewAPIWithHost(ctx, cfg, h)
|
|
if err != nil {
|
|
t.Fatalf("should be able to create a new %s API: %s", name, err)
|
|
}
|
|
|
|
// No keep alive for tests
|
|
svcapi.SetKeepAlivesEnabled(false)
|
|
svcapi.SetClient(clustertest.NewMockRPCClient(t))
|
|
|
|
return svcapi
|
|
}
|
|
|
|
func testAPI(t *testing.T) *API {
|
|
cfg := NewConfig()
|
|
cfg.Default()
|
|
cfg.CORSAllowedOrigins = []string{"myorigin"}
|
|
cfg.CORSAllowedMethods = []string{"GET", "POST", "DELETE"}
|
|
//cfg.CORSAllowedHeaders = []string{"Content-Type"}
|
|
cfg.CORSMaxAge = 10 * time.Minute
|
|
|
|
return testAPIwithConfig(t, cfg, "basic")
|
|
}
|
|
|
|
func TestAPIListEndpoint(t *testing.T) {
|
|
ctx := context.Background()
|
|
svcapi := testAPI(t)
|
|
defer svcapi.Shutdown(ctx)
|
|
|
|
tf := func(t *testing.T, url test.URLFunc) {
|
|
var resp pinsvc.PinList
|
|
test.MakeGet(t, svcapi, url(svcapi)+"/pins", &resp)
|
|
|
|
// mockPinTracker returns 3 items for Cluster.StatusAll
|
|
if resp.Count != 3 {
|
|
t.Fatal("Count should be 3")
|
|
}
|
|
|
|
if len(resp.Results) != 3 {
|
|
t.Fatal("There should be 3 results")
|
|
}
|
|
|
|
results := resp.Results
|
|
if !results[0].Pin.Cid.Equals(clustertest.Cid1) ||
|
|
results[1].Status != pinsvc.StatusPinning {
|
|
t.Errorf("unexpected statusAll resp: %+v", results)
|
|
}
|
|
|
|
// Test status filters
|
|
var resp2 pinsvc.PinList
|
|
test.MakeGet(t, svcapi, url(svcapi)+"/pins?status=pinning", &resp2)
|
|
// mockPinTracker calls pintracker.StatusAll which returns 2
|
|
// items.
|
|
if resp2.Count != 1 {
|
|
t.Errorf("unexpected statusAll+status=pinning resp:\n %+v", resp2)
|
|
}
|
|
|
|
var resp3 pinsvc.PinList
|
|
test.MakeGet(t, svcapi, url(svcapi)+"/pins?status=queued", &resp3)
|
|
if resp3.Count != 0 {
|
|
t.Errorf("unexpected statusAll+status=queued resp:\n %+v", resp3)
|
|
}
|
|
|
|
var resp4 pinsvc.PinList
|
|
test.MakeGet(t, svcapi, url(svcapi)+"/pins?status=pinned", &resp4)
|
|
if resp4.Count != 1 {
|
|
t.Errorf("unexpected statusAll+status=queued resp:\n %+v", resp4)
|
|
}
|
|
|
|
var resp5 pinsvc.PinList
|
|
test.MakeGet(t, svcapi, url(svcapi)+"/pins?status=failed", &resp5)
|
|
if resp5.Count != 1 {
|
|
t.Errorf("unexpected statusAll+status=queued resp:\n %+v", resp5)
|
|
}
|
|
|
|
var resp6 pinsvc.PinList
|
|
test.MakeGet(t, svcapi, url(svcapi)+"/pins?status=failed,pinned", &resp6)
|
|
if resp6.Count != 2 {
|
|
t.Errorf("unexpected statusAll+status=failed,pinned resp:\n %+v", resp6)
|
|
}
|
|
|
|
// Test with cids
|
|
var resp7 pinsvc.PinList
|
|
test.MakeGet(t, svcapi, url(svcapi)+"/pins?cid=QmP63DkAFEnDYNjDYBpyNDfttu1fvUw99x1brscPzpqmmq,QmP63DkAFEnDYNjDYBpyNDfttu1fvUw99x1brscPzpqmmb", &resp7)
|
|
if resp7.Count != 2 {
|
|
t.Errorf("unexpected statusAll+cids resp:\n %+v", resp7)
|
|
}
|
|
|
|
// Test with cids+limit
|
|
var resp8 pinsvc.PinList
|
|
test.MakeGet(t, svcapi, url(svcapi)+"/pins?cid=QmP63DkAFEnDYNjDYBpyNDfttu1fvUw99x1brscPzpqmmq,QmP63DkAFEnDYNjDYBpyNDfttu1fvUw99x1brscPzpqmmb&limit=1", &resp8)
|
|
if resp8.Count != 2 || len(resp8.Results) != 1 {
|
|
t.Errorf("unexpected statusAll+cids+limit resp:\n %+v", resp8)
|
|
}
|
|
|
|
// Test with limit
|
|
var resp9 pinsvc.PinList
|
|
test.MakeGet(t, svcapi, url(svcapi)+"/pins?limit=1", &resp9)
|
|
if resp9.Count != 3 || len(resp9.Results) != 1 {
|
|
t.Errorf("unexpected statusAll+limit=1 resp:\n %+v", resp9)
|
|
}
|
|
|
|
// Test with name-match
|
|
var resp10 pinsvc.PinList
|
|
test.MakeGet(t, svcapi, url(svcapi)+"/pins?name=C&match=ipartial", &resp10)
|
|
if resp10.Count != 1 {
|
|
t.Errorf("unexpected statusAll+name resp:\n %+v", resp10)
|
|
}
|
|
|
|
// Test with meta-match
|
|
var resp11 pinsvc.PinList
|
|
test.MakeGet(t, svcapi, url(svcapi)+`/pins?meta={"ccc":"3c"}`, &resp11)
|
|
if resp11.Count != 1 {
|
|
t.Errorf("unexpected statusAll+meta resp:\n %+v", resp11)
|
|
}
|
|
|
|
var errorResp pinsvc.APIError
|
|
test.MakeGet(t, svcapi, url(svcapi)+"/pins?status=invalid", &errorResp)
|
|
if errorResp.Details.Reason == "" {
|
|
t.Errorf("expected an error: %s", errorResp.Details.Reason)
|
|
}
|
|
}
|
|
|
|
test.BothEndpoints(t, tf)
|
|
}
|
|
|
|
func TestAPIPinEndpoint(t *testing.T) {
|
|
ctx := context.Background()
|
|
svcapi := testAPI(t)
|
|
defer svcapi.Shutdown(ctx)
|
|
|
|
ma, _ := api.NewMultiaddr("/ip4/1.2.3.4/ipfs/" + clustertest.PeerID1.String())
|
|
|
|
tf := func(t *testing.T, url test.URLFunc) {
|
|
// test normal pin
|
|
pin := pinsvc.Pin{
|
|
Cid: clustertest.Cid3,
|
|
Name: "testname",
|
|
Origins: []api.Multiaddr{
|
|
ma,
|
|
},
|
|
Meta: map[string]string{
|
|
"meta": "data",
|
|
},
|
|
}
|
|
var status pinsvc.PinStatus
|
|
pinJSON, err := json.Marshal(pin)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
test.MakePost(t, svcapi, url(svcapi)+"/pins", pinJSON, &status)
|
|
|
|
if status.Pin.Cid != pin.Cid {
|
|
t.Error("cids should match")
|
|
}
|
|
if status.Pin.Meta["meta"] != "data" {
|
|
t.Errorf("metadata should match: %+v", status.Pin)
|
|
}
|
|
if len(status.Pin.Origins) != 1 {
|
|
t.Errorf("expected origins: %+v", status.Pin)
|
|
}
|
|
if len(status.Delegates) != 3 {
|
|
t.Errorf("expected 3 delegates: %+v", status)
|
|
}
|
|
|
|
var errName pinsvc.APIError
|
|
pin2 := pinsvc.Pin{
|
|
Cid: clustertest.Cid1,
|
|
Name: pinsvc.PinName(make([]byte, 256)),
|
|
}
|
|
pinJSON, err = json.Marshal(pin2)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
test.MakePost(t, svcapi, url(svcapi)+"/pins", pinJSON, &errName)
|
|
if !strings.Contains(errName.Details.Reason, "255") {
|
|
t.Error("expected name error")
|
|
}
|
|
}
|
|
|
|
test.BothEndpoints(t, tf)
|
|
}
|
|
|
|
func TestAPIGetPinEndpoint(t *testing.T) {
|
|
ctx := context.Background()
|
|
svcapi := testAPI(t)
|
|
defer svcapi.Shutdown(ctx)
|
|
|
|
tf := func(t *testing.T, url test.URLFunc) {
|
|
// test existing pin
|
|
var status pinsvc.PinStatus
|
|
test.MakeGet(t, svcapi, url(svcapi)+"/pins/"+clustertest.Cid1.String(), &status)
|
|
|
|
if !status.Pin.Cid.Equals(clustertest.Cid1) {
|
|
t.Error("Cid should be set")
|
|
}
|
|
|
|
if status.Pin.Meta["meta"] != "data" {
|
|
t.Errorf("metadata should match: %+v", status.Pin)
|
|
}
|
|
if len(status.Delegates) != 1 {
|
|
t.Errorf("expected 1 delegates: %+v", status)
|
|
}
|
|
|
|
var err pinsvc.APIError
|
|
test.MakeGet(t, svcapi, url(svcapi)+"/pins/"+clustertest.ErrorCid.String(), &err)
|
|
if err.Details.Reason == "" {
|
|
t.Error("expected an error")
|
|
}
|
|
}
|
|
|
|
test.BothEndpoints(t, tf)
|
|
}
|
|
|
|
func TestAPIRemovePinEndpoint(t *testing.T) {
|
|
ctx := context.Background()
|
|
svcapi := testAPI(t)
|
|
defer svcapi.Shutdown(ctx)
|
|
|
|
tf := func(t *testing.T, url test.URLFunc) {
|
|
// test existing pin
|
|
test.MakeDelete(t, svcapi, url(svcapi)+"/pins/"+clustertest.Cid1.String(), nil)
|
|
}
|
|
|
|
test.BothEndpoints(t, tf)
|
|
}
|