Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: range request helpers #162

Merged
merged 20 commits into from
Oct 2, 2023
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
fd64058
feat: add AnyOf response type
aschmahmann Aug 30, 2023
96ff093
feat: add AllOf response type and range request helpers
aschmahmann Sep 6, 2023
d1d1c9a
run per-check Go tests during AllOf validation
aschmahmann Sep 18, 2023
0a8d398
run per-check Go testes during AnyOf validation
aschmahmann Sep 18, 2023
c4c667b
sugar: add Clone to ExpectValidator
aschmahmann Sep 18, 2023
f780f20
readd spec logging
aschmahmann Sep 19, 2023
a7978a1
helpers: add helper combining single and multirange tests
aschmahmann Sep 18, 2023
ecc439b
switch tests that were using both the single and multirange helper to…
aschmahmann Sep 18, 2023
54b0386
switch tests that were testing fetching of full data and ranges to us…
aschmahmann Sep 19, 2023
74d7b32
remove data from ByteRange helper
aschmahmann Sep 19, 2023
245795b
allow tests to delegate choosing which ranges to query to the helpers
aschmahmann Sep 19, 2023
ed808db
switch Response and HeaderBuilder Clones from doing shallow clones wh…
aschmahmann Sep 19, 2023
be3f9e7
Revert "switch Response and HeaderBuilder Clones from doing shallow c…
aschmahmann Sep 19, 2023
55874e3
rename testWithoutRangeRequestHeader to baseTest
aschmahmann Sep 19, 2023
63df4e1
correctly do Content-Type checks for multi-range request helpers
aschmahmann Sep 19, 2023
08f2f1e
chore: apply some feedback from @lidel
hacdias Sep 25, 2023
d8c1f49
refactor: apply @lidel suggestion A
hacdias Sep 25, 2023
2b085ee
refactor: use value for append
hacdias Oct 2, 2023
8504a15
docs: changelog
hacdias Oct 2, 2023
ecc00fb
fix: Changelog
laurentsenta Oct 2, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

### Added

- Added tests for HTTP Range requests, as well as some basic helpers for `AnyOf` and `AllOf`. [PR](https://github.com/ipfs/gateway-conformance/pull/162)
## [0.3.1] - 2023-09-15
laurentsenta marked this conversation as resolved.
Show resolved Hide resolved
### Added
- Specs Dashboard Output. [PR](https://github.com/ipfs/gateway-conformance/pull/163)
Expand Down
284 changes: 218 additions & 66 deletions tests/path_gateway_dag_test.go
hacdias marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/ipfs/gateway-conformance/tooling"
"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 @@ -231,86 +232,121 @@ func TestPlainCodec(t *testing.T) {
plainCID := plain.Cid()
plainOrDagCID := plainOrDag.Cid()

tests := SugarTests{
{
Name: Fmt(`GET {{name}} without Accept or format= has expected "{{format}}" Content-Type and body as-is`, row.Name, row.Format),
Hint: `
var dagFormattedResponse []byte

tests := SugarTests{}.
Append(
helpers.IncludeRandomRangeTests(t,
SugarTest{
Name: Fmt(`GET {{name}} without Accept or format= has expected "{{format}}" Content-Type and body as-is`, row.Name, row.Format),
Hint: `
No explicit format, just codec in CID
`,
Request: Request().
Path("/ipfs/{{cid}}", plainCID),
Response: Expect().
Status(200).
Headers(
Header("Content-Disposition").
Contains(Fmt(`{{disposition}}; filename="{{cid}}.{{format}}"`, row.Disposition, plainCID, row.Format)),
Header("Content-Type").
Contains(Fmt("application/{{format}}", row.Format)),
).Body(
Request: Request().
Path("/ipfs/{{cid}}", plainCID),
Response: Expect().
Headers(
Header("Content-Disposition").
Contains(Fmt(`{{disposition}}; filename="{{cid}}.{{format}}"`, row.Disposition, plainCID, row.Format)),
),
},
plain.RawData(),
),
},
{
Name: Fmt("GET {{name}} with ?format= has expected {{format}} Content-Type and body as-is", row.Name, row.Format),
Hint: `
Fmt("application/{{format}}", row.Format),
)...).
Append(
helpers.IncludeRandomRangeTests(t,
SugarTest{
Name: Fmt("GET {{name}} with ?format= has expected {{format}} Content-Type and body as-is", row.Name, row.Format),
Hint: `
Explicit format still gives correct output, just codec in CID
`,
Request: Request().
Path("/ipfs/{{cid}}", plainCID).
Query("format", row.Format),
Response: Expect().
Status(200).
Headers(
Header("Content-Disposition").
Contains(`{{disposition}}; filename="{{cid}}.{{format}}"`, row.Disposition, plainCID, row.Format),
Header("Content-Type").
Contains("application/{{format}}", row.Format),
).Body(
Request: Request().
Path("/ipfs/{{cid}}", plainCID).
Query("format", row.Format),
Response: Expect().
Headers(
Header("Content-Disposition").
Contains(`{{disposition}}; filename="{{cid}}.{{format}}"`, row.Disposition, plainCID, row.Format),
),
},
plain.RawData(),
),
},
{
Name: Fmt("GET {{name}} with Accept has expected {{format}} Content-Type and body as-is", row.Name, row.Format),
Hint: `
Fmt("application/{{format}}", row.Format),
)...).
Append(
helpers.IncludeRandomRangeTests(t,
SugarTest{
Name: Fmt("GET {{name}} with Accept has expected {{format}} Content-Type and body as-is, with single range request", row.Name, row.Format),
Hint: `
Explicit format still gives correct output, just codec in CID
`,
Request: Request().
Path("/ipfs/{{cid}}", plainCID).
Header("Accept", Fmt("application/{{format}}", row.Format)),
Response: Expect().
Status(200).
Headers(
Header("Content-Disposition").
Contains(`{{disposition}}; filename="{{cid}}.{{format}}"`, row.Disposition, plainCID, row.Format),
Header("Content-Type").
Contains("application/{{format}}", row.Format),
).Body(
Request: Request().
Path("/ipfs/{{cid}}", plainCID).
Headers(
Header("Accept", Fmt("application/{{format}}", row.Format)),
),
Response: Expect().
Headers(
Header("Content-Disposition").
Contains(`{{disposition}}; filename="{{cid}}.{{format}}"`, row.Disposition, plainCID, row.Format),
),
},
plain.RawData(),
),
},
{
Name: Fmt("GET {{name}} with format=dag-{{format}} interprets {{format}} as dag-* variant and produces expected Content-Type and body", row.Name, row.Format),
Hint: `
Fmt("application/{{format}}", row.Format),
)...).
Append(
SugarTest{
Name: Fmt("GET {{name}} with format=dag-{{format}} interprets {{format}} as dag-* variant and produces expected Content-Type and body", row.Name, row.Format),
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).
Query("format", Fmt("dag-{{format}}", row.Format)),
Response: Expect().
Status(200).
Headers(
Header("Content-Disposition").
Contains(`{{disposition}}; filename="{{cid}}.{{format}}"`, row.Disposition, plainOrDagCID, row.Format),
Header("Content-Type").
Contains("application/vnd.ipld.dag-{{format}}", row.Format),
).Body(
row.Checker(formatted),
),
},
}
Request: Request().
Path("/ipfs/{{cid}}", plainOrDagCID).
Query("format", Fmt("dag-{{format}}", row.Format)),
Response: Expect().
Status(200).
Headers(
Header("Content-Disposition").
Contains(`{{disposition}}; filename="{{cid}}.{{format}}"`, row.Disposition, plainOrDagCID, row.Format),
Header("Content-Type").
Contains("application/vnd.ipld.dag-{{format}}", row.Format),
).Body(
Checks("", func(t []byte) bool {
innerCheck := row.Checker(formatted).Check(t)
if innerCheck.Success {
dagFormattedResponse = t
return true
}
return false
}),
),
},
)

RunWithSpecs(t, tests, specs.PathGatewayDAG)

if dagFormattedResponse != nil {
rangeTests := helpers.OnlyRandomRangeTests(t,
SugarTest{
Name: Fmt("GET {{name}} with format=dag-{{format}} interprets {{format}} as dag-* variant and produces expected Content-Type and body, with single range request", row.Name, row.Format),
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).
Query("format", Fmt("dag-{{format}}", row.Format)),
Response: Expect().
Headers(
Header("Content-Disposition").
Contains(`{{disposition}}; filename="{{cid}}.{{format}}"`, row.Disposition, plainOrDagCID, row.Format),
),
},
dagFormattedResponse,
Fmt("application/vnd.ipld.dag-{{format}}", row.Format),
)
RunWithSpecs(t, rangeTests, specs.PathGatewayDAG)
}
}
}

Expand Down Expand Up @@ -577,9 +613,125 @@ func TestNativeDag(t *testing.T) {
),
},
}
tests.Append(helpers.OnlyRandomRangeTests(t,
SugarTest{
Name: Fmt("GET {{name}} on /ipfs with no explicit header", row.Name),
Request: Request().
Path("/ipfs/{{cid}}/", dagTraversalCID),
Response: Expect(),
},
dagTraversal.RawData(), Fmt("application/vnd.ipld.dag-{{format}}", row.Format),
)...).Append(
helpers.OnlyRandomRangeTests(t,
SugarTest{
Name: Fmt("GET {{name}} on /ipfs with dag content headers", row.Name),
Request: Request().
Path("/ipfs/{{cid}}/", dagTraversalCID).
Headers(
Header("Accept", "application/vnd.ipld.dag-{{format}}", row.Format),
),
Response: Expect(),
},
dagTraversal.RawData(),
Fmt("application/vnd.ipld.dag-{{format}}", row.Format),
)...).Append(
helpers.OnlyRandomRangeTests(t,
SugarTest{
Name: Fmt("GET {{name}} on /ipfs with non-dag content headers", row.Name),
Request: Request().
Path("/ipfs/{{cid}}/", dagTraversalCID).
Headers(
Header("Accept", "application/{{format}}", row.Format),
),
Response: Expect(),
},
dagTraversal.RawData(),
Fmt("application/{{format}}", row.Format),
)...)

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 {
hacdias marked this conversation as resolved.
Show resolved Hide resolved
rangeTests := helpers.OnlyRandomRangeTests(
t,
SugarTest{
Name: "Convert application/vnd.ipld.dag-cbor to application/vnd.ipld.dag-json with range request includes correct bytes",
Hint: "",
Request: Request().
Path("/ipfs/{{cid}}/", dagCborCID).
Headers(
Header("Accept", "application/vnd.ipld.dag-json"),
),
Response: Expect(),
},
dagJsonConvertedData,
"application/vnd.ipld.dag-json")

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 := helpers.OnlyRandomRangeTests(t,
SugarTest{
Name: "Convert application/vnd.ipld.dag-cbor to text/html with range request includes correct bytes",
Hint: "",
Request: Request().
Path("/ipfs/{{cid}}/", dagCborCID).
Headers(
Header("Accept", "text/html"),
),
Response: Expect(),
},
dagCborHTMLRendering,
"text/html")

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

func TestGatewayJSONCborAndIPNS(t *testing.T) {
Expand Down
Loading
Loading