Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Fixes ref rebasing when following nested $ref in Paths section

Signed-off-by: Frederic BIDON <fredbi@yahoo.com>
  • Loading branch information
fredbi committed Nov 21, 2019
1 parent 7447963 commit 40ac585
Show file tree
Hide file tree
Showing 9 changed files with 108 additions and 60 deletions.
5 changes: 5 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,8 @@ linters:
- lll
- gochecknoinits
- gochecknoglobals
- funlen
- godox
- gocognit
- whitespace
- wsl
7 changes: 4 additions & 3 deletions expander.go
Original file line number Diff line number Diff line change
Expand Up @@ -452,11 +452,12 @@ func expandPathItem(pathItem *PathItem, resolver *schemaLoader, basePath string)
return err
}
if pathItem.Ref.String() != "" {
var err error
resolver, err = resolver.transitiveResolver(basePath, pathItem.Ref)
if resolver.shouldStopOnError(err) {
transitiveResolver, err := resolver.transitiveResolver(basePath, pathItem.Ref)
if transitiveResolver.shouldStopOnError(err) {
return err
}
basePath = transitiveResolver.updateBasePath(resolver, basePath)
resolver = transitiveResolver
}
pathItem.Ref = Ref{}

Expand Down
9 changes: 9 additions & 0 deletions fixtures/bugs/2113/base.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
swagger: "2.0"
info:
version: "1"
title: "nested $ref fixture"
paths:
/dummy:
$ref: ./schemas/api/api.yaml#/paths/~1dummy
/example:
$ref: ./schemas/api/api.yaml#/paths/~1example
19 changes: 19 additions & 0 deletions fixtures/bugs/2113/schemas/api/api.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
swagger: "2.0"
info:
version: "1"
title: "sub api"
paths:
/dummy:
get:
responses:
200:
description: OK
schema:
$ref: ../dummy/dummy.yaml
/example:
get:
responses:
200:
description: OK
schema:
$ref: ../example/example.yaml
5 changes: 5 additions & 0 deletions fixtures/bugs/2113/schemas/dummy/dummy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
required:
- dummyPayload
properties:
dummyPayload:
type: string
6 changes: 6 additions & 0 deletions fixtures/bugs/2113/schemas/example/example.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
$schema: http://json-schema.org/draft-07/schema#
required:
- payload
properties:
payload:
type: string
1 change: 1 addition & 0 deletions ref.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ func (r *Ref) IsValidURI(basepaths ...string) bool {
}

if r.HasFullURL {
//#nosec
rr, err := http.Get(v)
if err != nil {
return false
Expand Down
7 changes: 1 addition & 6 deletions schema_loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,7 @@ func (r *schemaLoader) transitiveResolver(basePath string, ref Ref) (*schemaLoad
newOptions := r.options
newOptions.RelativeBase = rootURL.String()
debugLog("setting new root: %s", newOptions.RelativeBase)
resolver, err := defaultSchemaLoader(root, newOptions, r.cache, r.context)
if err != nil {
return nil, err
}

return resolver, nil
return defaultSchemaLoader(root, newOptions, r.cache, r.context)
}

func (r *schemaLoader) updateBasePath(transitive *schemaLoader, basePath string) string {
Expand Down
109 changes: 58 additions & 51 deletions spec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,26 +25,33 @@ import (
"github.com/go-openapi/spec"
"github.com/go-openapi/swag"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

// mimics what the go-openapi/load does
var (
yamlLoader = swag.YAMLDoc
rex = regexp.MustCompile(`"\$ref":\s*"(.+)"`)
testLoader func(string) (json.RawMessage, error)
)

func loadOrFail(t *testing.T, path string) *spec.Swagger {
raw, erl := yamlLoader(path)
if erl != nil {
t.Logf("can't load fixture %s: %v", path, erl)
t.FailNow()
return nil
func init() {
testLoader = func(path string) (json.RawMessage, error) {
if swag.YAMLMatcher(path) {
return swag.YAMLDoc(path)
}
data, err := swag.LoadFromFileOrHTTP(path)
if err != nil {
return nil, err
}
return json.RawMessage(data), nil
}
}
func loadOrFail(t *testing.T, path string) *spec.Swagger {
raw, err := testLoader(path)
require.NoErrorf(t, err, "can't load fixture %s: %v", path, err)
swspec := new(spec.Swagger)
if err := json.Unmarshal(raw, swspec); err != nil {
t.FailNow()
return nil
}
err = json.Unmarshal(raw, swspec)
require.NoError(t, err)
return swspec
}

Expand All @@ -54,22 +61,17 @@ func Test_Issue1429(t *testing.T) {
defer func() {
spec.PathLoader = prevPathLoader
}()
spec.PathLoader = yamlLoader
spec.PathLoader = testLoader
path := filepath.Join("fixtures", "bugs", "1429", "swagger.yaml")

// load and full expand
sp := loadOrFail(t, path)
err := spec.ExpandSpec(sp, &spec.ExpandOptions{RelativeBase: path, SkipSchemas: false})
if !assert.NoError(t, err) {
t.FailNow()
return
}
require.NoError(t, err)

// assert well expanded
if !assert.Truef(t, (sp.Paths != nil && sp.Paths.Paths != nil), "expected paths to be available in fixture") {
t.FailNow()
return
}
require.Truef(t, (sp.Paths != nil && sp.Paths.Paths != nil), "expected paths to be available in fixture")

for _, pi := range sp.Paths.Paths {
for _, param := range pi.Get.Parameters {
if assert.NotNilf(t, param.Schema, "expected param schema not to be nil") {
Expand All @@ -96,16 +98,11 @@ func Test_Issue1429(t *testing.T) {
// reload and SkipSchemas: true
sp = loadOrFail(t, path)
err = spec.ExpandSpec(sp, &spec.ExpandOptions{RelativeBase: path, SkipSchemas: true})
if !assert.NoError(t, err) {
t.FailNow()
return
}
require.NoError(t, err)

// assert well resolved
if !assert.Truef(t, (sp.Paths != nil && sp.Paths.Paths != nil), "expected paths to be available in fixture") {
t.FailNow()
return
}
require.Truef(t, (sp.Paths != nil && sp.Paths.Paths != nil), "expected paths to be available in fixture")

for _, pi := range sp.Paths.Paths {
for _, param := range pi.Get.Parameters {
if assert.NotNilf(t, param.Schema, "expected param schema not to be nil") {
Expand Down Expand Up @@ -154,20 +151,17 @@ func Test_MoreLocalExpansion(t *testing.T) {
defer func() {
spec.PathLoader = prevPathLoader
}()
spec.PathLoader = yamlLoader
spec.PathLoader = testLoader
path := filepath.Join("fixtures", "local_expansion", "spec2.yaml")

// load and full expand
sp := loadOrFail(t, path)
err := spec.ExpandSpec(sp, &spec.ExpandOptions{RelativeBase: path, SkipSchemas: false})
if !assert.NoError(t, err) {
t.FailNow()
return
}
require.NoError(t, err)

// asserts all $ref expanded
jazon, _ := json.MarshalIndent(sp, "", " ")
assert.NotContains(t, jazon, `"$ref"`)
//t.Log(string(jazon))
}

func Test_Issue69(t *testing.T) {
Expand All @@ -179,10 +173,8 @@ func Test_Issue69(t *testing.T) {
// load and expand
sp := loadOrFail(t, path)
err := spec.ExpandSpec(sp, &spec.ExpandOptions{RelativeBase: path, SkipSchemas: false})
if !assert.NoError(t, err) {
t.FailNow()
return
}
require.NoError(t, err)

// asserts all $ref expanded
jazon, _ := json.MarshalIndent(sp, "", " ")

Expand All @@ -202,18 +194,16 @@ func Test_Issue1621(t *testing.T) {
defer func() {
spec.PathLoader = prevPathLoader
}()
spec.PathLoader = yamlLoader
spec.PathLoader = testLoader
path := filepath.Join("fixtures", "bugs", "1621", "fixture-1621.yaml")

// expand with relative path
// load and expand
sp := loadOrFail(t, path)

err := spec.ExpandSpec(sp, &spec.ExpandOptions{RelativeBase: path, SkipSchemas: false})
if !assert.NoError(t, err) {
t.FailNow()
return
}
require.NoError(t, err)

// asserts all $ref expanded
jazon, _ := json.MarshalIndent(sp, "", " ")
m := rex.FindAllStringSubmatch(string(jazon), -1)
Expand All @@ -228,10 +218,8 @@ func Test_Issue1614(t *testing.T) {
// load and expand
sp := loadOrFail(t, path)
err := spec.ExpandSpec(sp, &spec.ExpandOptions{RelativeBase: path, SkipSchemas: false})
if !assert.NoError(t, err) {
t.FailNow()
return
}
require.NoError(t, err)

// asserts all $ref expanded
jazon, _ := json.MarshalIndent(sp, "", " ")

Expand All @@ -248,10 +236,8 @@ func Test_Issue1614(t *testing.T) {
// now with option CircularRefAbsolute
sp = loadOrFail(t, path)
err = spec.ExpandSpec(sp, &spec.ExpandOptions{RelativeBase: path, SkipSchemas: false, AbsoluteCircularRef: true})
if !assert.NoError(t, err) {
t.FailNow()
return
}
require.NoError(t, err)

// asserts all $ref expanded
jazon, _ = json.MarshalIndent(sp, "", " ")

Expand All @@ -267,3 +253,24 @@ func Test_Issue1614(t *testing.T) {
}
}
}

func Test_Issue2113(t *testing.T) {
prevPathLoader := spec.PathLoader
defer func() {
spec.PathLoader = prevPathLoader
}()
spec.PathLoader = testLoader
// this checks expansion with nested specs
path := filepath.Join("fixtures", "bugs", "2113", "base.yaml")

// load and expand
sp := loadOrFail(t, path)
err := spec.ExpandSpec(sp, &spec.ExpandOptions{RelativeBase: path, SkipSchemas: false})
require.NoError(t, err)
// asserts all $ref expanded
jazon, _ := json.MarshalIndent(sp, "", " ")

// assert all $ref match have been expanded
m := rex.FindAllStringSubmatch(string(jazon), -1)
assert.Emptyf(t, m, "expected all $ref to be expanded")
}

0 comments on commit 40ac585

Please sign in to comment.