Skip to content

Commit

Permalink
feat: add AllOf response type and range request helpers
Browse files Browse the repository at this point in the history
switch tests to use range request helpers
  • Loading branch information
aschmahmann committed Sep 11, 2023
1 parent a4562c9 commit d6a4caa
Show file tree
Hide file tree
Showing 5 changed files with 431 additions and 99 deletions.
210 changes: 210 additions & 0 deletions tests/path_gateway_dag_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/ipfs/gateway-conformance/tooling/car"
. "github.com/ipfs/gateway-conformance/tooling/check"
"github.com/ipfs/gateway-conformance/tooling/helpers"
"github.com/ipfs/gateway-conformance/tooling/ipns"
"github.com/ipfs/gateway-conformance/tooling/specs"
. "github.com/ipfs/gateway-conformance/tooling/test"
Expand Down Expand Up @@ -300,6 +301,57 @@ func TestPlainCodec(t *testing.T) {
row.Checker(formatted),
),
},
{
Name: Fmt("GET {{name}} on /ipfs with no explicit header and range returns range", row.Name),
Request: Request().
Path("/ipfs/{{cid}}/", plainOrDagCID).
Headers(
Header("Range", "bytes=6-16"),
),
Response: Expect().
Status(206).
Headers(
Header("Content-Type", "application/vnd.ipld.dag-{{format}}", row.Format),
Header("Content-Range", "bytes 6-16/57"),
).
Body(row.Checker(plainOrDag.RawData()[6:17])),
},
{
Name: Fmt("GET {{name}} on /ipfs with non-dag content headers and range returns range", row.Name),
Request: Request().
Path("/ipfs/{{cid}}/", plainOrDagCID).
Headers(
Header("Accept", "application/{{format}}", row.Format),
Header("Range", "bytes=6-16"),
),
Response: Expect().
Status(206).
Headers(
Header("Content-Type", "application/{{format}}", row.Format),
Header("Content-Range", "bytes 6-16/57"),
).
Body(row.Checker(plainOrDag.RawData()[6:17])),
},
{
Name: Fmt("GET {{name}} on /ipfs with dag content headers and range returns range", row.Name),
Hint: `
Explicit dag-* format passed, attempt to parse as dag* variant
Note: this works only for simple JSON that can be upgraded to DAG-JSON.
`,
Request: Request().
Path("/ipfs/{{cid}}/", plainOrDagCID).
Headers(
Header("Accept", "application/vnd.ipld.dag-{{format}}", row.Format),
Header("Range", "bytes=6-16"),
),
Response: Expect().
Status(206).
Headers(
Header("Content-Type", "application/vnd.ipld.dag-{{format}}", row.Format),
Header("Content-Range", "bytes 6-16/57"),
).
Body(row.Checker(plainOrDag.RawData()[6:17])),
},
}

RunWithSpecs(t, tests, specs.PathGatewayDAG)
Expand Down Expand Up @@ -563,10 +615,168 @@ func TestNativeDag(t *testing.T) {
Contains("</html>"),
),
},
helpers.SingleRangeTestTransform(t,
SugarTest{
Name: Fmt("GET {{name}} on /ipfs with no explicit header and single range", row.Name),
Request: Request().
Path("/ipfs/{{cid}}/", dagTraversalCID).
Headers(
Header("Range", "bytes=6-16"),
),
Response: Expect().
Headers(
Header("Content-Type", "application/vnd.ipld.dag-{{format}}", row.Format),
),
},
helpers.SimpleByteRange(6, 16, dagTraversal.RawData()[6:17]),
dagTraversal.RawData(),
),
helpers.SingleRangeTestTransform(t,
SugarTest{
Name: Fmt("GET {{name}} on /ipfs with dag content headers and single range", row.Name),
Request: Request().
Path("/ipfs/{{cid}}/", dagTraversalCID).
Headers(
Header("Accept", "application/vnd.ipld.dag-{{format}}", row.Format),
Header("Range", "bytes=6-16"),
),
Response: Expect().
Headers(
Header("Content-Type", "application/vnd.ipld.dag-{{format}}", row.Format),
),
},
helpers.SimpleByteRange(6, 16, dagTraversal.RawData()[6:17]),
dagTraversal.RawData(),
),
helpers.SingleRangeTestTransform(t,
SugarTest{
Name: Fmt("GET {{name}} on /ipfs with non-dag content headers and single range", row.Name),
Request: Request().
Path("/ipfs/{{cid}}/", dagTraversalCID).
Headers(
Header("Accept", "application/{{format}}", row.Format),
Header("Range", "bytes=6-16"),
),
Response: Expect().
Headers(
Header("Content-Type", "application/{{format}}", row.Format),
),
},
helpers.SimpleByteRange(6, 16, dagTraversal.RawData()[6:17]),
dagTraversal.RawData(),
),
}

RunWithSpecs(t, tests, specs.PathGatewayDAG)
}

dagCborFixture := car.MustOpenUnixfsCar("path_gateway_dag/dag-cbor-traversal.car").MustGetRoot()
dagCborCID := dagCborFixture.Cid()
var dagJsonConvertedData []byte
RunWithSpecs(t, SugarTests{
SugarTest{
Name: "Convert application/vnd.ipld.dag-cbor to application/vnd.ipld.dag-json",
Hint: "",
Request: Request().
Path("/ipfs/{{cid}}/", dagCborCID).
Headers(
Header("Accept", "application/vnd.ipld.dag-json"),
),
Response: Expect().Body(Checks("", func(t []byte) bool {
innerCheck := IsJSONEqual(dagCborFixture.Formatted("dag-json")).Check(t)
if innerCheck.Success {
dagJsonConvertedData = t
return true
}
return false
})),
},
}, specs.PathGatewayDAG)

if dagJsonConvertedData != nil {
rangeTests := SugarTests{
helpers.SingleRangeTestTransform(t, SugarTest{
Name: "Convert application/vnd.ipld.dag-cbor to application/vnd.ipld.dag-json with single range request includes correct bytes",
Hint: "",
Request: Request().
Path("/ipfs/{{cid}}/", dagCborCID).
Headers(
Header("Accept", "application/vnd.ipld.dag-json"),
Header("Range", "bytes=1-5"),
),
Response: Expect(),
}, helpers.SimpleByteRange(1, 5, dagJsonConvertedData[1:6]), dagJsonConvertedData),
helpers.MultiRangeTestTransform(t, SugarTest{
Name: "Convert application/vnd.ipld.dag-cbor to application/vnd.ipld.dag-json with multiple range request includes correct bytes",
Hint: "",
Request: Request().
Path("/ipfs/{{cid}}/", dagCborCID).
Headers(
Header("Accept", "application/vnd.ipld.dag-json"),
Header("Range", "bytes=1-5,93-104"),
),
Response: Expect(),
}, helpers.ByteRanges{
helpers.SimpleByteRange(1, 5, dagJsonConvertedData[1:6]),
helpers.SimpleByteRange(93, 104, dagJsonConvertedData[93:105])},
dagJsonConvertedData),
}

RunWithSpecs(t, rangeTests, specs.PathGatewayDAG)
}

var dagCborHTMLRendering []byte
RunWithSpecs(t, SugarTests{
SugarTest{
Name: "Convert application/vnd.ipld.dag-cbor to text/html",
Hint: "",
Request: Request().
Path("/ipfs/{{cid}}/", dagCborCID).
Headers(
Header("Accept", "text/html"),
),
Response: Expect().Body(Checks("", func(t []byte) bool {
innerCheck := Contains("</html>").Check(string(t))
if innerCheck.Success {
dagCborHTMLRendering = t
return true
}
return false
})),
},
}, specs.PathGatewayDAG)

if dagCborHTMLRendering != nil {
rangeTests := SugarTests{
helpers.SingleRangeTestTransform(t, SugarTest{
Name: "Convert application/vnd.ipld.dag-cbor to text/html with single range request includes correct bytes",
Hint: "",
Request: Request().
Path("/ipfs/{{cid}}/", dagCborCID).
Headers(
Header("Accept", "text/html"),
Header("Range", "bytes=1-5"),
),
Response: Expect(),
}, helpers.SimpleByteRange(1, 5, dagCborHTMLRendering[1:6]), dagCborHTMLRendering),
helpers.MultiRangeTestTransform(t, SugarTest{
Name: "Convert application/vnd.ipld.dag-cbor to text/html with multiple range request includes correct bytes",
Hint: "",
Request: Request().
Path("/ipfs/{{cid}}/", dagCborCID).
Headers(
Header("Accept", "text/html"),
Header("Range", "bytes=1-5,93-104"),
),
Response: Expect(),
}, helpers.ByteRanges{
helpers.SimpleByteRange(1, 5, dagCborHTMLRendering[1:6]),
helpers.SimpleByteRange(93, 104, dagCborHTMLRendering[93:105])},
dagCborHTMLRendering),
}

RunWithSpecs(t, rangeTests, specs.PathGatewayDAG)
}
}

func TestGatewayJSONCborAndIPNS(t *testing.T) {
Expand Down
120 changes: 21 additions & 99 deletions tests/trustless_gateway_raw_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package tests

import (
"github.com/ipfs/gateway-conformance/tooling/helpers"
"strconv"
"strings"
"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 @@ -133,123 +133,45 @@ func TestTrustlessRawRanges(t *testing.T) {
// correctly.
fixture := car.MustOpenUnixfsCar("gateway-raw-block.car")

var (
contentType string
contentRange string
)

RunWithSpecs(t, SugarTests{
{
Name: "GETaa with application/vnd.ipld.raw with single range request includes correct bytes",
singleRangeTest := helpers.SingleRangeTestTransform(t,
SugarTest{
Name: "GET with application/vnd.ipld.raw with single range request includes correct bytes",
Request: Request().
Path("/ipfs/{{cid}}", fixture.MustGetCid("dir", "ascii.txt")).
Headers(
Header("Accept", "application/vnd.ipld.raw"),
Header("Range", "bytes=6-16"),
),
Response: Expect().
Status(206).
Headers(
Header("Content-Type").Contains("application/vnd.ipld.raw"),
Header("Content-Range").Equals("bytes 6-16/31"),
).
Body(fixture.MustGetRawData("dir", "ascii.txt")[6:17]),
},
{
Name: "GET with application/vnd.ipld.raw with multiple range request includes correct bytes",
Request: Request().
Path("/ipfs/{{cid}}", fixture.MustGetCid("dir", "ascii.txt")).
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 strings.Contains(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.
helpers.SimpleByteRange(6, 16, fixture.MustGetRawData("dir", "ascii.txt")[6:17]),
fixture.MustGetRawData("dir", "ascii.txt"),
)

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}}", fixture.MustGetCid("dir", "ascii.txt")).
Headers(
Header("Accept", "application/vnd.ipld.raw"),
Header("Range", "bytes=6-16,0-4"),
),
Response: Expect().
Status(206).
Headers(
Header("Content-Type").Contains("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}}", fixture.MustGetCid("dir", "ascii.txt")).
Headers(
Header("Accept", "application/vnd.ipld.raw"),
Header("Range", "bytes=6-16,0-4"),
),
Response: Expect().
Status(206).
Headers(
Header("Content-Type").Contains("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{
multiRangeTest := helpers.MultiRangeTestTransform(t,
SugarTest{
Name: "GET with application/vnd.ipld.raw with multiple range request includes correct bytes",
Request: Request().
Path("/ipfs/{{cid}}", fixture.MustGetCid("dir", "ascii.txt")).
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")
Response: Expect(),
},
helpers.ByteRanges{
helpers.SimpleByteRange(6, 16, fixture.MustGetRawData("dir", "ascii.txt")[6:17]),
helpers.SimpleByteRange(0, 4, fixture.MustGetRawData("dir", "ascii.txt")[0:5]),
},
fixture.MustGetRawData("dir", "ascii.txt"),
)

tests := SugarTests{
singleRangeTest,
multiRangeTest,
}

RunWithSpecs(t, tests, specs.TrustlessGatewayRaw)
Expand Down
Loading

0 comments on commit d6a4caa

Please sign in to comment.