Wrote a better IPFS daemon mock for testing. Adapted tests.
License: MIT Signed-off-by: Hector Sanjuan <hector@protocol.ai>
This commit is contained in:
parent
0422ceed16
commit
8c458d0650
|
@ -97,7 +97,7 @@ func testingConsensus(t *testing.T) *Consensus {
|
|||
t.Fatal("cannot create Consensus:", err)
|
||||
}
|
||||
// Oxygen for Raft to declare leader
|
||||
time.Sleep(2 * time.Second)
|
||||
time.Sleep(3 * time.Second)
|
||||
return cc
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ var (
|
|||
testCid = "QmP63DkAFEnDYNjDYBpyNDfttu1fvUw99x1brscPzpqmmq"
|
||||
testCid2 = "QmP63DkAFEnDYNjDYBpyNDfttu1fvUw99x1brscPzpqmma"
|
||||
testCid3 = "QmP63DkAFEnDYNjDYBpyNDfttu1fvUw99x1brscPzpqmmb"
|
||||
errorCid = "QmP63DkAFEnDYNjDYBpyNDfttu1fvUw99x1brscPzpqmmc"
|
||||
testPeerID, _ = peer.IDB58Decode("QmXZrtE5jQwXNqCJMfHUTQkvhQ4ZAnqMnmzFMJfLewuabc")
|
||||
)
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ package ipfscluster
|
|||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -12,39 +11,8 @@ import (
|
|||
cid "github.com/ipfs/go-cid"
|
||||
)
|
||||
|
||||
func testServer(t *testing.T) *httptest.Server {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
//t.Log(r.URL.String())
|
||||
switch r.URL.Path {
|
||||
case "/api/v0/pin/add":
|
||||
if r.URL.RawQuery == fmt.Sprintf("arg=%s", testCid) {
|
||||
fmt.Fprintln(w, `{ "pinned": "`+testCid+`" }`)
|
||||
} else {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
case "/api/v0/pin/rm":
|
||||
if r.URL.RawQuery == fmt.Sprintf("arg=%s", testCid) {
|
||||
fmt.Fprintln(w, `{ "unpinned": "`+testCid+`" }`)
|
||||
} else {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
case "/api/v0/pin/ls":
|
||||
if r.URL.RawQuery == fmt.Sprintf("arg=%s", testCid) {
|
||||
fmt.Fprintln(w,
|
||||
`{"Keys":{"`+testCid+`":{"Type":"recursive"}}}`)
|
||||
} else {
|
||||
fmt.Fprintln(w,
|
||||
`{"Keys":{"`+testCid2+`":{"Type":"indirect"}}}`)
|
||||
}
|
||||
default:
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
}
|
||||
}))
|
||||
return ts
|
||||
}
|
||||
|
||||
func testIPFSConnectorConfig(ts *httptest.Server) *Config {
|
||||
url, _ := url.Parse(ts.URL)
|
||||
func testIPFSConnectorConfig(mock *ipfsMock) *Config {
|
||||
url, _ := url.Parse(mock.server.URL)
|
||||
h := strings.Split(url.Host, ":")
|
||||
i, _ := strconv.Atoi(h[1])
|
||||
|
||||
|
@ -54,20 +22,20 @@ func testIPFSConnectorConfig(ts *httptest.Server) *Config {
|
|||
return cfg
|
||||
}
|
||||
|
||||
func ipfsConnector(t *testing.T) (*IPFSHTTPConnector, *httptest.Server) {
|
||||
ts := testServer(t)
|
||||
cfg := testIPFSConnectorConfig(ts)
|
||||
func ipfsConnector(t *testing.T) (*IPFSHTTPConnector, *ipfsMock) {
|
||||
mock := newIpfsMock()
|
||||
cfg := testIPFSConnectorConfig(mock)
|
||||
|
||||
ipfs, err := NewIPFSHTTPConnector(cfg)
|
||||
if err != nil {
|
||||
t.Fatal("creating an IPFSConnector should work: ", err)
|
||||
}
|
||||
return ipfs, ts
|
||||
return ipfs, mock
|
||||
}
|
||||
|
||||
func TestNewIPFSHTTPConnector(t *testing.T) {
|
||||
ipfs, ts := ipfsConnector(t)
|
||||
defer ts.Close()
|
||||
ipfs, mock := ipfsConnector(t)
|
||||
defer mock.Close()
|
||||
defer ipfs.Shutdown()
|
||||
|
||||
ch := ipfs.RpcChan()
|
||||
|
@ -77,15 +45,23 @@ func TestNewIPFSHTTPConnector(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestIPFSPin(t *testing.T) {
|
||||
ipfs, ts := ipfsConnector(t)
|
||||
defer ts.Close()
|
||||
ipfs, mock := ipfsConnector(t)
|
||||
defer mock.Close()
|
||||
defer ipfs.Shutdown()
|
||||
c, _ := cid.Decode(testCid)
|
||||
c2, _ := cid.Decode(testCid2)
|
||||
err := ipfs.Pin(c)
|
||||
if err != nil {
|
||||
t.Error("expected success pinning cid")
|
||||
}
|
||||
yes, err := ipfs.IsPinned(c)
|
||||
if err != nil {
|
||||
t.Fatal("expected success doing ls")
|
||||
}
|
||||
if !yes {
|
||||
t.Error("cid should have been pinned")
|
||||
}
|
||||
|
||||
c2, _ := cid.Decode(errorCid)
|
||||
err = ipfs.Pin(c2)
|
||||
if err == nil {
|
||||
t.Error("expected error pinning cid")
|
||||
|
@ -93,35 +69,29 @@ func TestIPFSPin(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestIPFSUnpin(t *testing.T) {
|
||||
ipfs, ts := ipfsConnector(t)
|
||||
defer ts.Close()
|
||||
ipfs, mock := ipfsConnector(t)
|
||||
defer mock.Close()
|
||||
defer ipfs.Shutdown()
|
||||
c, _ := cid.Decode(testCid)
|
||||
c2, _ := cid.Decode(testCid2)
|
||||
c3, _ := cid.Decode(testCid3)
|
||||
err := ipfs.Unpin(c)
|
||||
if err != nil {
|
||||
t.Error("expected success unpinning cid")
|
||||
t.Error("expected success unpinning non-pinned cid")
|
||||
}
|
||||
|
||||
err = ipfs.Unpin(c2)
|
||||
ipfs.Pin(c)
|
||||
err = ipfs.Unpin(c)
|
||||
if err != nil {
|
||||
t.Error("expected error unpinning cid")
|
||||
}
|
||||
|
||||
err = ipfs.Unpin(c3)
|
||||
if err == nil {
|
||||
t.Error("expected error unpinning cid")
|
||||
t.Error("expected success unpinning pinned cid")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsPinned(t *testing.T) {
|
||||
ipfs, ts := ipfsConnector(t)
|
||||
defer ts.Close()
|
||||
func TestIPFSIsPinned(t *testing.T) {
|
||||
ipfs, mock := ipfsConnector(t)
|
||||
defer mock.Close()
|
||||
defer ipfs.Shutdown()
|
||||
c, _ := cid.Decode(testCid)
|
||||
c2, _ := cid.Decode(testCid2)
|
||||
|
||||
ipfs.Pin(c)
|
||||
isp, err := ipfs.IsPinned(c)
|
||||
if err != nil || !isp {
|
||||
t.Error("c should appear pinned")
|
||||
|
@ -133,13 +103,16 @@ func TestIsPinned(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestProxy(t *testing.T) {
|
||||
ipfs, ts := ipfsConnector(t)
|
||||
defer ts.Close()
|
||||
func TestIPFSProxy(t *testing.T) {
|
||||
ipfs, mock := ipfsConnector(t)
|
||||
defer mock.Close()
|
||||
defer ipfs.Shutdown()
|
||||
|
||||
// Address comes from testingConfig()
|
||||
res, err := http.Get("http://127.0.0.1:10001/api/v0/add?arg=" + testCid)
|
||||
cfg := testingConfig()
|
||||
res, err := http.Get(fmt.Sprintf("http://%s:%d/api/v0/add?arg=%s",
|
||||
cfg.IPFSAPIListenAddr,
|
||||
cfg.IPFSAPIListenPort,
|
||||
testCid))
|
||||
if err != nil {
|
||||
t.Fatal("should forward requests to ipfs host: ", err)
|
||||
}
|
||||
|
@ -149,10 +122,12 @@ func TestProxy(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestIPFSShutdown(t *testing.T) {
|
||||
ipfs, ts := ipfsConnector(t)
|
||||
defer ts.Close()
|
||||
ipfs, mock := ipfsConnector(t)
|
||||
defer mock.Close()
|
||||
if err := ipfs.Shutdown(); err != nil {
|
||||
t.Error("expected a clean shutdown")
|
||||
}
|
||||
ipfs.Shutdown()
|
||||
if err := ipfs.Shutdown(); err != nil {
|
||||
t.Error("expected a second clean shutdown")
|
||||
}
|
||||
}
|
||||
|
|
136
ipfsmock_test.go
Normal file
136
ipfsmock_test.go
Normal file
|
@ -0,0 +1,136 @@
|
|||
package ipfscluster
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
|
||||
cid "github.com/ipfs/go-cid"
|
||||
)
|
||||
|
||||
// This is an ipfs daemon mock which should sustain the functionality used by
|
||||
// used by ipfscluster.
|
||||
|
||||
type ipfsMock struct {
|
||||
server *httptest.Server
|
||||
pinMap *MapState
|
||||
}
|
||||
|
||||
type mockPinResp struct {
|
||||
Pins []string
|
||||
}
|
||||
|
||||
type mockPinType struct {
|
||||
Type string
|
||||
}
|
||||
|
||||
type mockPinLsResp struct {
|
||||
Keys map[string]mockPinType
|
||||
}
|
||||
|
||||
type ipfsErr struct {
|
||||
Code int
|
||||
Message string
|
||||
}
|
||||
|
||||
func newIpfsMock() *ipfsMock {
|
||||
st := NewMapState()
|
||||
m := &ipfsMock{
|
||||
pinMap: st,
|
||||
}
|
||||
ts := httptest.NewServer(http.HandlerFunc(m.handler))
|
||||
m.server = ts
|
||||
return m
|
||||
|
||||
}
|
||||
|
||||
// FIXME: what if IPFS API changes?
|
||||
func (m *ipfsMock) handler(w http.ResponseWriter, r *http.Request) {
|
||||
p := r.URL.Path
|
||||
endp := strings.TrimPrefix(p, "/api/v0/")
|
||||
var cidStr string
|
||||
switch endp {
|
||||
case "pin/add":
|
||||
query := r.URL.Query()
|
||||
arg, ok := query["arg"]
|
||||
if !ok || len(arg) != 1 {
|
||||
goto ERROR
|
||||
}
|
||||
cidStr = arg[0]
|
||||
if cidStr == errorCid {
|
||||
goto ERROR
|
||||
}
|
||||
c, err := cid.Decode(cidStr)
|
||||
if err != nil {
|
||||
goto ERROR
|
||||
}
|
||||
m.pinMap.AddPin(c)
|
||||
resp := mockPinResp{
|
||||
Pins: []string{cidStr},
|
||||
}
|
||||
j, _ := json.Marshal(resp)
|
||||
w.Write(j)
|
||||
case "pin/rm":
|
||||
query := r.URL.Query()
|
||||
arg, ok := query["arg"]
|
||||
if !ok || len(arg) != 1 {
|
||||
goto ERROR
|
||||
}
|
||||
cidStr = arg[0]
|
||||
c, err := cid.Decode(cidStr)
|
||||
if err != nil {
|
||||
goto ERROR
|
||||
}
|
||||
m.pinMap.RmPin(c)
|
||||
resp := mockPinResp{
|
||||
Pins: []string{cidStr},
|
||||
}
|
||||
j, _ := json.Marshal(resp)
|
||||
w.Write(j)
|
||||
case "pin/ls":
|
||||
query := r.URL.Query()
|
||||
arg, ok := query["arg"]
|
||||
if !ok {
|
||||
rMap := make(map[string]mockPinType)
|
||||
pins := m.pinMap.ListPins()
|
||||
for _, p := range pins {
|
||||
rMap[p.String()] = mockPinType{"recursive"}
|
||||
}
|
||||
j, _ := json.Marshal(mockPinLsResp{rMap})
|
||||
w.Write(j)
|
||||
break
|
||||
}
|
||||
if len(arg) != 1 {
|
||||
goto ERROR
|
||||
}
|
||||
cidStr = arg[0]
|
||||
|
||||
c, err := cid.Decode(cidStr)
|
||||
if err != nil {
|
||||
goto ERROR
|
||||
}
|
||||
ok = m.pinMap.HasPin(c)
|
||||
if ok {
|
||||
rMap := make(map[string]mockPinType)
|
||||
rMap[cidStr] = mockPinType{"recursive"}
|
||||
j, _ := json.Marshal(mockPinLsResp{rMap})
|
||||
w.Write(j)
|
||||
} else {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
resp := ipfsErr{0, fmt.Sprintf("Path '%s' is not pinned", cidStr)}
|
||||
j, _ := json.Marshal(resp)
|
||||
w.Write(j)
|
||||
}
|
||||
default:
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
}
|
||||
return
|
||||
ERROR:
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
func (m *ipfsMock) Close() {
|
||||
m.server.Close()
|
||||
}
|
7
state.go
7
state.go
|
@ -37,6 +37,13 @@ func (st *MapState) RmPin(c *cid.Cid) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (st *MapState) HasPin(c *cid.Cid) bool {
|
||||
st.mux.RLock()
|
||||
defer st.mux.RUnlock()
|
||||
_, ok := st.PinMap[c.String()]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (st *MapState) ListPins() []*cid.Cid {
|
||||
st.mux.RLock()
|
||||
defer st.mux.RUnlock()
|
||||
|
|
Loading…
Reference in New Issue
Block a user