@@ -15,6 +15,7 @@ import (
1515 "github.com/stretchr/testify/require"
1616
1717 "github.com/pb33f/libopenapi-validator/config"
18+ "github.com/pb33f/libopenapi-validator/helpers"
1819 "github.com/pb33f/libopenapi-validator/paths"
1920)
2021
@@ -2247,18 +2248,25 @@ paths:
22472248 assert .NotEmpty (t , errors )
22482249}
22492250
2250- type RegexCacheWatcher struct {
2251+ type regexCacheWatcher struct {
22512252 inner * sync.Map
2252- loadCount int64
2253+ missCount int64
2254+ hitCount int64
22532255 storeCount int64
22542256}
22552257
2256- func (c * RegexCacheWatcher ) Load (key any ) (value any , ok bool ) {
2257- atomic .AddInt64 (& c .loadCount , 1 )
2258- return c .inner .Load (key )
2258+ func (c * regexCacheWatcher ) Load (key any ) (value any , ok bool ) {
2259+ data , found := c .inner .Load (key )
2260+ if found {
2261+ atomic .AddInt64 (& c .hitCount , 1 )
2262+ } else {
2263+ atomic .AddInt64 (& c .missCount , 1 )
2264+ }
2265+
2266+ return data , found
22592267}
22602268
2261- func (c * RegexCacheWatcher ) Store (key , value any ) {
2269+ func (c * regexCacheWatcher ) Store (key , value any ) {
22622270 atomic .AddInt64 (& c .storeCount , 1 )
22632271 c .inner .Store (key , value )
22642272}
@@ -2274,20 +2282,21 @@ paths:
22742282
22752283 m , _ := doc .BuildV3Model ()
22762284
2277- cache := & RegexCacheWatcher {inner : & sync.Map {}}
2285+ cache := & regexCacheWatcher {inner : & sync.Map {}}
22782286 v := NewParameterValidator (& m .Model , config .WithRegexCache (cache ))
22792287
22802288 compiledPizza := regexp .MustCompile ("^pizza$" )
2281- cache .Store ("pizza" , compiledPizza )
2289+ cache .inner . Store ("pizza" , compiledPizza )
22822290
2283- assert .Equal (t , int64 ( 1 ) , cache .storeCount )
2284- assert .Equal (t , int64 ( 0 ) , cache .loadCount )
2291+ assert .EqualValues (t , 0 , cache .storeCount )
2292+ assert .EqualValues (t , 0 , cache .hitCount + cache . missCount )
22852293
22862294 request , _ := http .NewRequest (http .MethodGet , "https://things.com/pizza" , nil )
2287- valid , errors := v .ValidatePathParams (request )
2295+ v .ValidatePathParams (request )
22882296
2289- assert .Equal (t , int64 (1 ), cache .storeCount )
2290- assert .Equal (t , int64 (1 ), cache .loadCount )
2297+ assert .EqualValues (t , 0 , cache .storeCount )
2298+ assert .EqualValues (t , 0 , cache .missCount )
2299+ assert .EqualValues (t , 1 , cache .hitCount )
22912300
22922301 mapLength := 0
22932302
@@ -2296,14 +2305,78 @@ paths:
22962305 return true
22972306 })
22982307
2299- assert .True (t , valid )
2300- assert .Len (t , errors , 0 )
23012308 assert .Equal (t , 1 , mapLength )
23022309
23032310 cache .inner .Clear ()
23042311
23052312 v .ValidatePathParams (request )
23062313
2307- assert .Equal (t , int64 (2 ), cache .storeCount )
2308- assert .Equal (t , int64 (2 ), cache .loadCount )
2314+ assert .EqualValues (t , 1 , cache .storeCount )
2315+ assert .EqualValues (t , 1 , cache .missCount )
2316+ assert .EqualValues (t , 1 , cache .hitCount )
2317+ }
2318+
2319+ func TestValidatePathParamsWithPathItem_RegexCache_WithOneCached (t * testing.T ) {
2320+ spec := `openapi: 3.1.0
2321+ paths:
2322+ /burgers/{burgerId}/locate:
2323+ parameters:
2324+ - in: path
2325+ name: burgerId
2326+ schema:
2327+ type: integer
2328+ get:
2329+ operationId: locateBurgers`
2330+ doc , _ := libopenapi .NewDocument ([]byte (spec ))
2331+ m , _ := doc .BuildV3Model ()
2332+
2333+ cache := & regexCacheWatcher {inner : & sync.Map {}}
2334+
2335+ segment := "{burgerId}"
2336+ r , err := helpers .GetRegexForPath (segment )
2337+ require .NoError (t , err )
2338+ cache .inner .Store (segment , r )
2339+
2340+ v := NewParameterValidator (& m .Model , config .WithRegexCache (cache ))
2341+
2342+ request , _ := http .NewRequest (http .MethodGet , "https://things.com/burgers/123/locate" , nil )
2343+
2344+ pathItem , _ , foundPath := paths .FindPath (request , & m .Model , nil )
2345+ v .ValidatePathParamsWithPathItem (request , pathItem , foundPath )
2346+
2347+ // Only "{burgerId}" regex was cached
2348+ assert .EqualValues (t , 2 , cache .storeCount ) // Stores "burgers" and "locate" regex
2349+ assert .EqualValues (t , 2 , cache .missCount )
2350+ assert .EqualValues (t , 1 , cache .hitCount )
2351+ }
2352+
2353+ func TestValidatePathParamsWithPathItem_RegexCache_MissOnceThenHit (t * testing.T ) {
2354+ spec := `openapi: 3.1.0
2355+ paths:
2356+ /burgers/{burgerId}/locate:
2357+ parameters:
2358+ - in: path
2359+ name: burgerId
2360+ schema:
2361+ type: integer
2362+ get:
2363+ operationId: locateBurgers`
2364+ doc , _ := libopenapi .NewDocument ([]byte (spec ))
2365+ m , _ := doc .BuildV3Model ()
2366+
2367+ cache := & regexCacheWatcher {inner : & sync.Map {}}
2368+
2369+ v := NewParameterValidator (& m .Model , config .WithRegexCache (cache ))
2370+
2371+ request , _ := http .NewRequest (http .MethodGet , "https://things.com/burgers/123/locate" , nil )
2372+ pathItem , _ , foundPath := paths .FindPath (request , & m .Model , cache )
2373+
2374+ v .ValidatePathParamsWithPathItem (request , pathItem , foundPath )
2375+
2376+ assert .EqualValues (t , 3 , cache .storeCount )
2377+ assert .EqualValues (t , 3 , cache .missCount )
2378+ assert .EqualValues (t , 3 , cache .hitCount )
2379+
2380+ _ , found := cache .inner .Load ("{burgerId}" )
2381+ assert .True (t , found )
23092382}
0 commit comments