| 1 | package cli |
| 2 | |
| 3 | import ( |
| 4 | "fmt" |
| 5 | "net/http" |
| 6 | "os" |
| 7 | "testing" |
| 8 | |
| 9 | "github.com/ipfs/kubo/test/cli/harness" |
| 10 | "github.com/stretchr/testify/assert" |
| 11 | ) |
| 12 | |
| 13 | func TestGatewayHAMTDirectory(t *testing.T) { |
| 14 | t.Parallel() |
| 15 | |
| 16 | const ( |
| 17 | // The CID of the HAMT-sharded directory that has 10k items |
| 18 | hamtCid = "bafybeiggvykl7skb2ndlmacg2k5modvudocffxjesexlod2pfvg5yhwrqm" |
| 19 | |
| 20 | // fixtureCid is the CID of root of the DAG that is a subset of hamtCid DAG |
| 21 | // representing the minimal set of blocks necessary for directory listing. |
| 22 | // It also includes a "files_refs" file with the list of the references |
| 23 | // we do NOT needs to fetch (files inside the directory) |
| 24 | fixtureCid = "bafybeig3yoibxe56aolixqa4zk55gp5sug3qgaztkakpndzk2b2ynobd4i" |
| 25 | ) |
| 26 | |
| 27 | // Start node |
| 28 | h := harness.NewT(t) |
| 29 | node := h.NewNode().Init("--empty-repo", "--profile=test").StartDaemon("--offline") |
| 30 | defer node.StopDaemon() |
| 31 | client := node.GatewayClient() |
| 32 | |
| 33 | // Import fixtures |
| 34 | r, err := os.Open("./fixtures/TestGatewayHAMTDirectory.car") |
| 35 | assert.NoError(t, err) |
| 36 | defer r.Close() |
| 37 | err = node.IPFSDagImport(r, fixtureCid) |
| 38 | assert.NoError(t, err) |
| 39 | |
| 40 | // Fetch HAMT directory succeeds with minimal refs |
| 41 | resp := client.Get(fmt.Sprintf("/ipfs/%s/", hamtCid)) |
| 42 | assert.Equal(t, http.StatusOK, resp.StatusCode) |
| 43 | } |
| 44 | |
| 45 | func TestGatewayHAMTRanges(t *testing.T) { |
| 46 | t.Parallel() |
| 47 | |
| 48 | const ( |
| 49 | // fileCid is the CID of the large HAMT-sharded file. |
| 50 | fileCid = "bafybeiae5abzv6j3ucqbzlpnx3pcqbr2otbnpot7d2k5pckmpymin4guau" |
| 51 | |
| 52 | // fixtureCid is the CID of root of the DAG that is a subset of fileCid DAG |
| 53 | // representing the minimal set of blocks necessary for a simple byte range request. |
| 54 | fixtureCid = "bafybeicgsg3lwyn3yl75lw7sn4zhyj5dxtb7wfxwscpq6yzippetmr2w3y" |
| 55 | ) |
| 56 | |
| 57 | // Start node |
| 58 | h := harness.NewT(t) |
| 59 | node := h.NewNode().Init("--empty-repo", "--profile=test").StartDaemon("--offline") |
| 60 | t.Cleanup(func() { node.StopDaemon() }) |
| 61 | client := node.GatewayClient() |
| 62 | |
| 63 | // Import fixtures |
| 64 | r, err := os.Open("./fixtures/TestGatewayMultiRange.car") |
| 65 | assert.NoError(t, err) |
| 66 | defer r.Close() |
| 67 | err = node.IPFSDagImport(r, fixtureCid) |
| 68 | assert.NoError(t, err) |
| 69 | |
| 70 | t.Run("Succeeds Fetching Range", func(t *testing.T) { |
| 71 | t.Parallel() |
| 72 | |
| 73 | resp := client.Get(fmt.Sprintf("/ipfs/%s", fileCid), func(r *http.Request) { |
| 74 | r.Header.Set("Range", "bytes=1276-1279") |
| 75 | }) |
| 76 | assert.Equal(t, http.StatusPartialContent, resp.StatusCode) |
| 77 | assert.Equal(t, "bytes 1276-1279/109266405", resp.Headers.Get("Content-Range")) |
| 78 | assert.Equal(t, "iana", resp.Body) |
| 79 | }) |
| 80 | |
| 81 | t.Run("Succeeds Fetching Second Range", func(t *testing.T) { |
| 82 | t.Parallel() |
| 83 | |
| 84 | resp := client.Get(fmt.Sprintf("/ipfs/%s", fileCid), func(r *http.Request) { |
| 85 | r.Header.Set("Range", "bytes=29839070-29839080") |
| 86 | }) |
| 87 | assert.Equal(t, http.StatusPartialContent, resp.StatusCode) |
| 88 | assert.Equal(t, "bytes 29839070-29839080/109266405", resp.Headers.Get("Content-Range")) |
| 89 | assert.Equal(t, "EXAMPLE.COM", resp.Body) |
| 90 | }) |
| 91 | |
| 92 | t.Run("Succeeds Fetching First Range of Multi-range Request", func(t *testing.T) { |
| 93 | t.Parallel() |
| 94 | |
| 95 | resp := client.Get(fmt.Sprintf("/ipfs/%s", fileCid), func(r *http.Request) { |
| 96 | r.Header.Set("Range", "bytes=1276-1279, 29839070-29839080") |
| 97 | }) |
| 98 | assert.Equal(t, http.StatusPartialContent, resp.StatusCode) |
| 99 | assert.Equal(t, "bytes 1276-1279/109266405", resp.Headers.Get("Content-Range")) |
| 100 | assert.Equal(t, "iana", resp.Body) |
| 101 | }) |
| 102 | } |