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: t0112 cors testing #52

Merged
merged 2 commits into from
May 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
52 changes: 52 additions & 0 deletions tests/t0112_gateway_cors_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package tests

import (
"testing"

"github.com/ipfs/gateway-conformance/tooling/test"
. "github.com/ipfs/gateway-conformance/tooling/test"
)

func TestCors(t *testing.T) {
cidHello := "bafkqabtimvwgy3yk" // hello
galargh marked this conversation as resolved.
Show resolved Hide resolved

tests := SugarTests{
{
Name: "GET Responses from Gateway should include CORS headers allowing JS from other origins to read the data cross-origin.",
Request: Request().
Path("ipfs/{{CID}}/", cidHello),
Response: Expect().
Headers(
Header("Access-Control-Allow-Origin").Equals("*"),
Header("Access-Control-Allow-Methods").Has("GET"),
Header("Access-Control-Allow-Headers").Has("Range"),
Header("Access-Control-Expose-Headers").Has(
"Content-Range",
"Content-Length",
"X-Ipfs-Path",
"X-Ipfs-Roots",
),
),
},
{
Name: "OPTIONS to Gateway succeeds",
Request: Request().
Method("OPTIONS").
Path("ipfs/{{CID}}/", cidHello),
Response: Expect().
Headers(
Header("Access-Control-Allow-Origin").Equals("*"),
Header("Access-Control-Allow-Methods").Has("GET"),
Header("Access-Control-Allow-Headers").Has("Range"),
Header("Access-Control-Expose-Headers").Has(
"Content-Range",
"Content-Length",
"X-Ipfs-Path",
"X-Ipfs-Roots",
),
),
},
}

test.Run(t, tests)
}
Copy link
Contributor Author

@laurentsenta laurentsenta May 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lidel I believe this is all we want to port from t0112, since the rest is related to the API, but please let me know if we missed something

Sharness test in kubo: https://github.com/ipfs/kubo/blob/da28fbc65a2e0f1ce59f9923823326ae2bc4f713/test/sharness/t0112-gateway-cors.sh

80 changes: 69 additions & 11 deletions tooling/check/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,27 +57,27 @@ var _ Check[string] = CheckWithHint[string]{}
type CheckIsEmpty struct {
}

func (c CheckIsEmpty) Check(v string) CheckOutput {
if v == "" {
func (c CheckIsEmpty) Check(v []string) CheckOutput {
if len(v) == 0 {
return CheckOutput{
Success: true,
}
}

return CheckOutput{
Success: false,
Reason: fmt.Sprintf("expected empty string, got '%s'", v),
Reason: fmt.Sprintf("expected empty array, got '%s'", v),
}
}

var _ Check[string] = CheckIsEmpty{}
var _ Check[[]string] = CheckIsEmpty{}

func IsEmpty(hint ...string) interface{} {
if len(hint) > 1 {
panic("hint can only be one string")
}
if len(hint) == 1 {
return WithHint[string](
return WithHint[[]string](
hint[0],
CheckIsEmpty{},
)
Expand Down Expand Up @@ -169,6 +169,64 @@ func IsEqualWithHint(hint string, value string, rest ...any) CheckWithHint[strin
return WithHint[string](hint, IsEqual(value, rest...))
}

type CheckUniqAnd struct {
check Check[string]
}

var _ Check[[]string] = &CheckUniqAnd{}

func IsUniqAnd(check Check[string]) Check[[]string] {
return &CheckUniqAnd{
check: check,
}
}

func (c *CheckUniqAnd) Check(v []string) CheckOutput {
if len(v) != 1 {
return CheckOutput{
Success: false,
Reason: "expected one element",
}
}

return c.check.Check(v[0])
}

type CheckHas struct {
values []string
}

var _ Check[[]string] = &CheckHas{}

func Has(values ...string) Check[[]string] {
return &CheckHas{
values: values,
}
}

func (c *CheckHas) Check(v []string) CheckOutput {
for _, value := range c.values {
found := false
for _, v := range v {
if v == value {
found = true
break
}
}

if !found {
return CheckOutput{
Success: false,
Reason: fmt.Sprintf("expected to find '%s' in '%s'", value, v),
}
}
}

return CheckOutput{
Success: true,
}
}

type CheckContains struct {
Value string
}
Expand Down Expand Up @@ -250,17 +308,17 @@ func (c CheckFunc[T]) Check(v T) CheckOutput {

var _ Check[string] = &CheckFunc[string]{}

type CheckNot struct {
check Check[string]
type CheckNot[T any] struct {
check Check[T]
}

func Not(check Check[string]) Check[string] {
return CheckNot{
func Not[T any](check Check[T]) Check[T] {
return CheckNot[T]{
check: check,
}
}

func (c CheckNot) Check(v string) CheckOutput {
func (c CheckNot[T]) Check(v T) CheckOutput {
result := c.check.Check(v)

if result.Success {
Expand All @@ -275,7 +333,7 @@ func (c CheckNot) Check(v string) CheckOutput {
}
}

var _ Check[string] = CheckNot{}
var _ Check[string] = CheckNot[string]{}

type CheckIsJSONEqual struct {
Value interface{}
Expand Down
27 changes: 16 additions & 11 deletions tooling/test/sugar.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,19 +160,19 @@ func (e ExpectBuilder) BodyWithHint(hint string, body interface{}) ExpectBuilder
}

type HeaderBuilder struct {
Key_ string `json:"key,omitempty"`
Value_ string `json:"value,omitempty"`
Check_ check.Check[string] `json:"check,omitempty"`
Hint_ string `json:"hint,omitempty"`
Not_ bool `json:"not,omitempty"`
Key_ string `json:"key,omitempty"`
Value_ string `json:"value,omitempty"`
Check_ check.Check[[]string] `json:"check,omitempty"`
Hint_ string `json:"hint,omitempty"`
Not_ bool `json:"not,omitempty"`
}

func Header(key string, rest ...any) HeaderBuilder {
if len(rest) > 0 {
// check if rest[0] is a string
if value, ok := rest[0].(string); ok {
value := tmpl.Fmt(value, rest[1:]...)
return HeaderBuilder{Key_: key, Value_: value, Check_: check.IsEqual(value)}
return HeaderBuilder{Key_: key, Value_: value, Check_: check.IsUniqAnd(check.IsEqual(value))}
} else {
panic("rest[0] must be a string")
}
Expand All @@ -182,12 +182,12 @@ func Header(key string, rest ...any) HeaderBuilder {
}

func (h HeaderBuilder) Contains(value string, rest ...any) HeaderBuilder {
h.Check_ = check.Contains(value, rest...)
h.Check_ = check.IsUniqAnd(check.Contains(value, rest...))
return h
}

func (h HeaderBuilder) Matches(value string, rest ...any) HeaderBuilder {
h.Check_ = check.Matches(value, rest...)
h.Check_ = check.IsUniqAnd(check.Matches(value, rest...))
return h
}

Expand All @@ -197,7 +197,12 @@ func (h HeaderBuilder) Hint(hint string) HeaderBuilder {
}

func (h HeaderBuilder) Equals(value string, args ...any) HeaderBuilder {
h.Check_ = check.IsEqual(value, args...)
h.Check_ = check.IsUniqAnd(check.IsEqual(value, args...))
return h
}

func (h HeaderBuilder) Has(values ...string) HeaderBuilder {
h.Check_ = check.Has(values...)
return h
}

Expand All @@ -207,9 +212,9 @@ func (h HeaderBuilder) IsEmpty() HeaderBuilder {
}

func (h HeaderBuilder) Checks(f func(string) bool) HeaderBuilder {
h.Check_ = check.CheckFunc[string]{
h.Check_ = check.IsUniqAnd(check.CheckFunc[string]{
Fn: f,
}
})
return h
}

Expand Down
3 changes: 2 additions & 1 deletion tooling/test/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ func Run(t *testing.T, tests SugarTests) {

for _, header := range test.Response.Headers_ {
t.Run(fmt.Sprintf("Header %s", header.Key_), func(t *testing.T) {
actual := res.Header.Get(header.Key_)
actual := res.Header.Values(header.Key_)

c := header.Check_
if header.Not_ {
c = check.Not(c)
Expand Down