Skip to content

Commit

Permalink
refactor: multirange and single range path unixfs tests
Browse files Browse the repository at this point in the history
  • Loading branch information
hacdias committed Jul 31, 2023
1 parent 0623113 commit 517e9e3
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 113 deletions.
27 changes: 27 additions & 0 deletions fixtures/path_gateway_unixfs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,30 @@ ln -s foo testfiles/bar &&
ROOT_DIR_CID=$(ipfs add -Qr testfiles) &&
ipfs dag export $ROOT_DIR_CID > symlink.car
```

### [dir-with-files.car](./dir-with-files.car)

```sh
ipfs version
# ipfs version 0.21.0
TEXT=$(cat <<-EOF
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non imperdiet nunc. Proin ac quam ut nibh eleifend aliquet. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Sed ligula dolor, imperdiet sagittis arcu et, semper tincidunt urna. Donec et tempor augue, quis sollicitudin metus. Curabitur semper ullamcorper aliquet. Mauris hendrerit sodales lectus eget fermentum. Proin sollicitudin vestibulum commodo. Vivamus nec lectus eu augue aliquet dignissim nec condimentum justo. In hac habitasse platea dictumst. Mauris vel sem neque.
Vivamus finibus, enim at lacinia semper, arcu erat gravida lacus, sit amet gravida magna orci sit amet est. Sed non leo lacus. Nullam viverra ipsum a tincidunt dapibus. Nulla pulvinar ligula sit amet ante ultrices tempus. Proin purus urna, semper sed lobortis quis, gravida vitae ipsum. Aliquam mi urna, pulvinar eu bibendum quis, convallis ac dolor. In gravida justo sed risus ullamcorper, vitae luctus massa hendrerit. Pellentesque habitant amet.
EOF
)

ASCII_CID=$(echo "hello application/vnd.ipld.car" | ipfs add --cid-version=1 -q)
HELLO_CID=$(echo "hello world" | ipfs add --cid-version=1 -q)
MULTIBLOCK_CID=$(echo -n $TEXT | ipfs add --cid-version=1 --chunker=size-256 -q)
# Print the Multiblock CIDs (required for some tests)
ipfs dag get $MULTIBLOCK_CID | jq .Links | jq -r '.[].Hash."/"'
ipfs files mkdir -p --cid-version 1 /dir-with-files
ipfs files cp /ipfs/$ASCII_CID /dir-with-files/ascii-copy.txt
ipfs files cp /ipfs/$ASCII_CID /dir-with-files/ascii.txt
ipfs files cp /ipfs/$HELLO_CID /dir-with-files/hello.txt
ipfs files cp /ipfs/$MULTIBLOCK_CID /dir-with-files/multiblock.txt
ipfs files ls -l
# Manually CID of "dir-with-files" and then...
ipfs dag export $CID
```
Binary file added fixtures/path_gateway_unixfs/dir-with-files.car
Binary file not shown.
113 changes: 0 additions & 113 deletions tests/path_gateway_raw_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"testing"

"github.com/ipfs/gateway-conformance/tooling/car"
. "github.com/ipfs/gateway-conformance/tooling/check"
"github.com/ipfs/gateway-conformance/tooling/specs"
. "github.com/ipfs/gateway-conformance/tooling/test"
)
Expand Down Expand Up @@ -143,115 +142,3 @@ func TestGatewayBlock(t *testing.T) {

RunWithSpecs(t, tests, specs.PathGatewayRaw)
}

func TestGatewayBlockMultiRangeRequest(t *testing.T) {
// Multi-range requests MUST conform to the HTTP semantics. The server does not
// need to be able to support returning multiple ranges. However, it must respond
// correctly.
fixture := car.MustOpenUnixfsCar("gateway-raw-block.car")

var (
contentType string
contentRange string
)

RunWithSpecs(t, SugarTests{
{
Name: "GET with application/vnd.ipld.raw with multiple range request includes correct bytes",
Request: Request().
Path("/ipfs/{{cid}}/dir/ascii.txt", fixture.MustGetCid()).
Headers(
Header("Accept", "application/vnd.ipld.raw"),
Header("Range", "bytes=6-16,0-4"),
),
Response: Expect().
Status(206).
Headers(
Header("Content-Type").
Checks(func(v string) bool {
contentType = v
return v != ""
}),
Header("Content-Range").
ChecksAll(func(v []string) bool {
if len(v) == 1 {
contentRange = v[0]
}
return true
}),
),
},
}, specs.PathGatewayRaw)

tests := SugarTests{}

if contentType == "application/vnd.ipld.raw" {
// The server is not able to respond to a multi-range request. Therefore,
// there might be only one range or... just the whole file, depending on the headers.

if contentRange == "" {
// Server does not support range requests and must send back the complete file.
tests = append(tests, SugarTest{
Name: "GET with application/vnd.ipld.raw with multiple range request includes correct bytes",
Request: Request().
Path("/ipfs/{{cid}}/dir/ascii.txt", fixture.MustGetCid()).
Headers(
Header("Accept", "application/vnd.ipld.raw"),
Header("Range", "bytes=6-16,0-4"),
),
Response: Expect().
Status(206).
Headers(
Header("Content-Type", "application/vnd.ipld.raw"),
Header("Content-Range").IsEmpty(),
).
Body(fixture.MustGetRawData("dir", "ascii.txt")),
})
} else {
// Server supports range requests but only the first range.
tests = append(tests, SugarTest{
Name: "GET with application/vnd.ipld.raw with multiple range request includes correct bytes",
Request: Request().
Path("/ipfs/{{cid}}/dir/ascii.txt", fixture.MustGetCid()).
Headers(
Header("Accept", "application/vnd.ipld.raw"),
Header("Range", "bytes=6-16,0-4"),
),
Response: Expect().
Status(206).
Headers(
Header("Content-Type", "application/vnd.ipld.raw"),
Header("Content-Range", "bytes 6-16/31"),
).
Body(fixture.MustGetRawData("dir", "ascii.txt")[6:17]),
})
}
} else if strings.Contains(contentType, "multipart/byteranges") {
// The server supports responding with multi-range requests.
tests = append(tests, SugarTest{
Name: "GET with application/vnd.ipld.raw with multiple range request includes correct bytes",
Request: Request().
Path("/ipfs/{{cid}}/dir/ascii.txt", fixture.MustGetCid()).
Headers(
Header("Accept", "application/vnd.ipld.raw"),
Header("Range", "bytes=6-16,0-4"),
),
Response: Expect().
Status(206).
Headers(
Header("Content-Type").Contains("multipart/byteranges"),
).
Body(And(
Contains("Content-Range: bytes 6-16/31"),
Contains("Content-Type: application/vnd.ipld.raw"),
Contains(string(fixture.MustGetRawData("dir", "ascii.txt")[6:17])),
Contains("Content-Range: bytes 0-4/31"),
Contains(string(fixture.MustGetRawData("dir", "ascii.txt")[0:5])),
)),
})
} else {
t.Error("Content-Type header did not match any of the accepted options")
}

RunWithSpecs(t, tests, specs.PathGatewayRaw)
}
123 changes: 123 additions & 0 deletions tests/path_gateway_unixfs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -434,3 +434,126 @@ func TestGatewaySymlink(t *testing.T) {

RunWithSpecs(t, tests, specs.PathGatewayUnixFS)
}

func TestGatewayUnixFSFileRanges(t *testing.T) {
// Multi-range requests MUST conform to the HTTP semantics. The server does not
// need to be able to support returning multiple ranges. However, it must respond
// correctly.
fixture := car.MustOpenUnixfsCar("path_gateway_unixfs/dir-with-files.car")

var (
contentType string
contentRange string
)

RunWithSpecs(t, SugarTests{
{
Name: "GET for /ipfs/ file with single range request includes correct bytes",
Request: Request().
Path("/ipfs/{{cid}}/ascii.txt", fixture.MustGetCid()).
Headers(
Header("Range", "bytes=6-16"),
),
Response: Expect().
Status(206).
Headers(
Header("Content-Type").Contains("text/plain"),
Header("Content-Range").Equals("bytes 6-16/31"),
).
Body(fixture.MustGetRawData("ascii.txt")[6:17]),
},
{
Name: "GET for /ipfs/ file with multiple range request includes correct bytes",
Request: Request().
Path("/ipfs/{{cid}}/ascii.txt", fixture.MustGetCid()).
Headers(
Header("Range", "bytes=6-16,0-4"),
),
Response: Expect().
Status(206).
Headers(
Header("Content-Type").
Checks(func(v string) bool {
contentType = v
return v != ""
}),
Header("Content-Range").
ChecksAll(func(v []string) bool {
if len(v) == 1 {
contentRange = v[0]
}
return true
}),
),
},
}, specs.PathGatewayRaw)

tests := SugarTests{}

if strings.Contains(contentType, "text/plain") {
// The server is not able to respond to a multi-range request. Therefore,
// there might be only one range or... just the whole file, depending on the headers.

if contentRange == "" {
// Server does not support range requests and must send back the complete file.
tests = append(tests, SugarTest{
Name: "GET for /ipfs/ file with multiple range request includes correct bytes",
Request: Request().
Path("/ipfs/{{cid}}/ascii.txt", fixture.MustGetCid()).
Headers(
Header("Range", "bytes=6-16,0-4"),
),
Response: Expect().
Status(206).
Headers(
Header("Content-Type").Contains("text/plain"),
Header("Content-Range").IsEmpty(),
).
Body(fixture.MustGetRawData("ascii.txt")),
})
} else {
// Server supports range requests but only the first range.
tests = append(tests, SugarTest{
Name: "GET for /ipfs/ file with multiple range request includes correct bytes",
Request: Request().
Path("/ipfs/{{cid}}/ascii.txt", fixture.MustGetCid()).
Headers(
Header("Range", "bytes=6-16,0-4"),
),
Response: Expect().
Status(206).
Headers(
Header("Content-Type").Contains("text/plain"),
Header("Content-Range", "bytes 6-16/31"),
).
Body(fixture.MustGetRawData("ascii.txt")[6:17]),
})
}
} else if strings.Contains(contentType, "multipart/byteranges") {
// The server supports responding with multi-range requests.
tests = append(tests, SugarTest{
Name: "GET for /ipfs/ file with multiple range request includes correct bytes",
Request: Request().
Path("/ipfs/{{cid}}/ascii.txt", fixture.MustGetCid()).
Headers(
Header("Range", "bytes=6-16,0-4"),
),
Response: Expect().
Status(206).
Headers(
Header("Content-Type").Contains("multipart/byteranges"),
).
Body(And(
Contains("Content-Range: bytes 6-16/31"),
Contains("Content-Type: text/plain"),
Contains(string(fixture.MustGetRawData("ascii.txt")[6:17])),
Contains("Content-Range: bytes 0-4/31"),
Contains(string(fixture.MustGetRawData("ascii.txt")[0:5])),
)),
})
} else {
t.Error("Content-Type header did not match any of the accepted options")
}

RunWithSpecs(t, tests, specs.PathGatewayUnixFS)
}

0 comments on commit 517e9e3

Please sign in to comment.