diff --git a/datamodel/low/extraction_functions_test.go b/datamodel/low/extraction_functions_test.go index 6a75386..3403f60 100644 --- a/datamodel/low/extraction_functions_test.go +++ b/datamodel/low/extraction_functions_test.go @@ -7,7 +7,9 @@ import ( "context" "crypto/sha256" "fmt" + "golang.org/x/sync/syncmap" "net/url" + "os" "strings" "testing" @@ -1889,3 +1891,72 @@ func TestLocateRefNode_NoExplode_HTTP(t *testing.T) { assert.NotNil(t, e) assert.NotNil(t, c) } + +func TestLocateRefNode_NoExplode_NoSpecPath(t *testing.T) { + + no := yaml.Node{ + Kind: yaml.MappingNode, + Content: []*yaml.Node{ + { + Kind: yaml.ScalarNode, + Value: "$ref", + }, + { + Kind: yaml.ScalarNode, + Value: "components/schemas/thing.yaml", + }, + }, + } + + cf := index.CreateClosedAPIIndexConfig() + u, _ := url.Parse("http://smilfghfhfhfhfhes.com/bikes") + cf.BaseURL = u + idx := index.NewSpecIndexWithConfig(&no, cf) + ctx := context.WithValue(context.Background(), index.CurrentPathKey, "no.yaml") + n, i, e, c := LocateRefNodeWithContext(ctx, &no, idx) + assert.Nil(t, n) + assert.NotNil(t, i) + assert.NotNil(t, e) + assert.NotNil(t, c) +} + +func TestLocateRefNode_DoARealLookup(t *testing.T) { + + no := yaml.Node{ + Kind: yaml.MappingNode, + Content: []*yaml.Node{ + { + Kind: yaml.ScalarNode, + Value: "$ref", + }, + { + Kind: yaml.ScalarNode, + Value: "/root.yaml#/components/schemas/Burger", + }, + }, + } + + b, err := os.ReadFile("../../test_specs/burgershop.openapi.yaml") + if err != nil { + t.Fatal(err) + } + var rootNode yaml.Node + _ = yaml.Unmarshal(b, &rootNode) + + cf := index.CreateClosedAPIIndexConfig() + u, _ := url.Parse("http://smilfghfhfhfhfhes.com/bikes") + cf.BaseURL = u + idx := index.NewSpecIndexWithConfig(&rootNode, cf) + + // fake cache to a lookup for a file that does not exist will work. + fakeCache := new(syncmap.Map) + fakeCache.Store("/root.yaml#/components/schemas/Burger", &index.Reference{Node: &no}) + idx.SetCache(fakeCache) + + ctx := context.WithValue(context.Background(), index.CurrentPathKey, "/root.yaml#/components/schemas/Burger") + n, i, e, c := LocateRefNodeWithContext(ctx, &no, idx) + assert.NotNil(t, n) + assert.NotNil(t, i) + assert.Nil(t, e) + assert.NotNil(t, c) +} diff --git a/index/index_model.go b/index/index_model.go index 291c33b..459a36d 100644 --- a/index/index_model.go +++ b/index/index_model.go @@ -270,7 +270,7 @@ type SpecIndex struct { componentIndexChan chan bool polyComponentIndexChan chan bool resolver *Resolver - cache syncmap.Map + cache *syncmap.Map built bool uri []string logger *slog.Logger @@ -286,6 +286,14 @@ func (index *SpecIndex) GetConfig() *SpecIndexConfig { return index.config } +func (index *SpecIndex) SetCache(sync *syncmap.Map) { + index.cache = sync +} + +func (index *SpecIndex) GetCache() *syncmap.Map { + return index.cache +} + // ExternalLookupFunction is for lookup functions that take a JSONSchema reference and tries to find that node in the // URI based document. Decides if the reference is local, remote or in a file. type ExternalLookupFunction func(id string) (foundNode *yaml.Node, rootNode *yaml.Node, lookupError error) diff --git a/index/spec_index.go b/index/spec_index.go index 021313c..730d4f0 100644 --- a/index/spec_index.go +++ b/index/spec_index.go @@ -15,6 +15,7 @@ package index import ( "context" "fmt" + "golang.org/x/sync/syncmap" "log/slog" "os" "sort" @@ -76,6 +77,8 @@ func createNewIndex(rootNode *yaml.Node, index *SpecIndex, avoidBuildOut bool) * return index } + index.cache = new(syncmap.Map) + // boot index. results := index.ExtractRefs(index.root.Content[0], index.root, []string{}, 0, false, "") diff --git a/index/spec_index_test.go b/index/spec_index_test.go index b04cd02..3d9c896 100644 --- a/index/spec_index_test.go +++ b/index/spec_index_test.go @@ -7,6 +7,7 @@ import ( "bytes" "fmt" "github.com/pb33f/libopenapi/utils" + "golang.org/x/sync/syncmap" "log" "log/slog" "net/http" @@ -22,6 +23,41 @@ import ( "gopkg.in/yaml.v3" ) +func TestSpecIndex_GetCache(t *testing.T) { + + petstore, _ := os.ReadFile("../test_specs/petstorev3.json") + var rootNode yaml.Node + _ = yaml.Unmarshal(petstore, &rootNode) + + index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) + + extCache := index.GetCache() + assert.NotNil(t, extCache) + extCache.Store("test", "test") + loaded, ok := extCache.Load("test") + assert.Equal(t, "test", loaded) + assert.True(t, ok) + + // create a new cache + newCache := new(syncmap.Map) + index.SetCache(newCache) + + // check that the cache has been set. + assert.Equal(t, newCache, index.GetCache()) + + // add an item to the new cache and check it exists + newCache.Store("test2", "test2") + loaded, ok = newCache.Load("test2") + assert.Equal(t, "test2", loaded) + assert.True(t, ok) + + // now check that the new item in the new cache does not exist in the old cache. + loaded, ok = extCache.Load("test2") + assert.Nil(t, loaded) + assert.False(t, ok) + +} + func TestSpecIndex_ExtractRefsStripe(t *testing.T) { stripe, _ := os.ReadFile("../test_specs/stripe.yaml") var rootNode yaml.Node