Skip to content

Commit 2afb299

Browse files
authored
Add new methods to zrouter (#110)
* Add new methods to zrouter * fix Mount * minor change * minor fix * minor fix * fix flaky tests
1 parent c1442cf commit 2afb299

File tree

5 files changed

+132
-13
lines changed

5 files changed

+132
-13
lines changed

pkg/zcache/local_cache_test.go

Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ func (suite *LocalCacheTestSuite) TestCleanupProcess() {
9393
CleanupProcess: CleanupProcess{
9494
Interval: cleanupInterval,
9595
},
96-
MetricServer: metrics.NewTaskMetrics("", "", "appname")})
96+
MetricServer: metrics.NewTaskMetrics("", "", "appname"),
97+
})
9798
suite.NoError(err)
9899

99100
ctx := context.Background()
@@ -103,12 +104,29 @@ func (suite *LocalCacheTestSuite) TestCleanupProcess() {
103104
err = cache.Set(ctx, key, value, ttl)
104105
suite.NoError(err)
105106

106-
time.Sleep(2 * cleanupInterval)
107-
108-
var result string
109-
err = cache.Get(ctx, key, &result)
107+
// Use polling to check for key expiration
108+
expired := false
109+
maxWaitTime := 10 * cleanupInterval // Maximum wait time
110+
pollingInterval := 100 * time.Millisecond // Polling interval
111+
timeout := time.After(maxWaitTime)
112+
tick := time.Tick(pollingInterval)
113+
114+
for !expired {
115+
select {
116+
case <-timeout:
117+
suite.FailNow("Timeout reached, key did not expire as expected")
118+
return
119+
case <-tick:
120+
var result string
121+
err = cache.Get(ctx, key, &result)
122+
if errors.Is(err, bigcache.ErrEntryNotFound) {
123+
expired = true
124+
}
125+
}
126+
}
110127

111-
suite.True(errors.Is(err, bigcache.ErrEntryNotFound), "Expected 'key not found' error, but got a different error")
128+
// Ensure the key has expired as expected
129+
suite.True(expired, "Key should have expired")
112130
}
113131

114132
func (suite *LocalCacheTestSuite) TestCleanupProcessBatchLogic() {
@@ -179,7 +197,7 @@ func (suite *LocalCacheTestSuite) TestCleanupProcessItemDoesNotExpire() {
179197
// after cleanup, there will be 1 key in the cache and 1 deleted expired key.
180198
func (suite *LocalCacheTestSuite) TestCleanupProcessMetrics() {
181199
cleanupInterval := 1 * time.Second
182-
ttl := 10 * time.Millisecond
200+
ttl := 25 * time.Millisecond
183201

184202
// label:count
185203
expected := map[string]int{
@@ -226,11 +244,29 @@ func (suite *LocalCacheTestSuite) TestCleanupProcessMetrics() {
226244
err = cache.Set(ctx, key+"2", value, neverExpires)
227245
suite.NoError(err)
228246

229-
time.Sleep(2 * cleanupInterval)
230-
for k, v := range expected {
231-
gotV, ok := got.Load(k)
232-
suite.Assert().True(ok)
233-
234-
suite.Assert().Equal(v, gotV)
247+
// Polling to check if metrics have been updated as expected
248+
maxWaitTime := 10 * cleanupInterval // Maximum wait time
249+
pollingInterval := 100 * time.Millisecond // Polling interval
250+
timeout := time.After(maxWaitTime)
251+
tick := time.Tick(pollingInterval)
252+
253+
for len(expected) > 0 {
254+
select {
255+
case <-timeout:
256+
suite.FailNow("Timeout reached, metrics were not updated as expected")
257+
return
258+
case <-tick:
259+
for k, v := range expected {
260+
if gotV, ok := got.Load(k); ok && v == gotV {
261+
got.Delete(k)
262+
delete(expected, k)
263+
}
264+
}
265+
if len(expected) == 0 {
266+
return
267+
}
268+
}
235269
}
270+
271+
suite.FailNow("Not all expected metrics were updated as expected")
236272
}

pkg/zrouter/domain/response.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
const (
1010
ContentTypeHeader = "Content-Type"
1111
ContentTypeApplicationJSON = "application/json; charset=utf-8"
12+
ContentTypePlainText = "text/plain; charset=utf-8"
1213
ContentTypeJSON = "json"
1314
)
1415

pkg/zrouter/handler.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,18 @@ func NotFoundHandler(_ Context) (domain.ServiceResponse, error) {
1414
return domain.NewErrorNotFound(msg), nil
1515
}
1616

17+
func ToHandlerFunc(h http.Handler) HandlerFunc {
18+
return func(ctx Context) (domain.ServiceResponse, error) {
19+
chiCtx, ok := ctx.(*chiContextAdapter)
20+
if !ok {
21+
return nil, errors.New("context provided is not a *chiContextAdapter")
22+
}
23+
24+
h.ServeHTTP(chiCtx.ctx, chiCtx.req)
25+
return nil, nil
26+
}
27+
}
28+
1729
func getChiHandler(handler HandlerFunc) http.HandlerFunc {
1830
return func(w http.ResponseWriter, r *http.Request) {
1931
adaptedContext := &chiContextAdapter{ctx: w, req: r}

pkg/zrouter/zrouter.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,19 +79,23 @@ type ZRouter interface {
7979
}
8080

8181
type Routes interface {
82+
NewSubRouter() ZRouter
8283
GET(path string, handler HandlerFunc, middlewares ...zmiddlewares.Middleware) Routes
8384
POST(path string, handler HandlerFunc, middlewares ...zmiddlewares.Middleware) Routes
8485
PUT(path string, handler HandlerFunc, middlewares ...zmiddlewares.Middleware) Routes
8586
PATCH(path string, handler HandlerFunc, middlewares ...zmiddlewares.Middleware) Routes
8687
DELETE(path string, handler HandlerFunc, middlewares ...zmiddlewares.Middleware) Routes
88+
Handle(pattern string, handler HandlerFunc)
8789
Route(method, path string, handler HandlerFunc, middlewares ...zmiddlewares.Middleware) Routes
90+
Mount(pattern string, subRouter Routes)
8891
Group(prefix string) Routes
8992
Use(middlewares ...zmiddlewares.Middleware) Routes
9093
NoRoute(handler HandlerFunc)
9194
GetRegisteredRoutes() []RegisteredRoute
9295
SetDefaultMiddlewares(loggingOptions zmiddlewares.LoggingMiddlewareOptions)
9396
GetHandler() http.Handler
9497
ServeHTTP(w http.ResponseWriter, req *http.Request)
98+
ServeFiles(routePattern string, httpHandler http.Handler)
9599
}
96100

97101
type zrouter struct {
@@ -132,6 +136,16 @@ func New(metricsServer metrics.TaskMetrics, config *Config) ZRouter {
132136
return zr
133137
}
134138

139+
func (r *zrouter) NewSubRouter() ZRouter {
140+
newRouter := &zrouter{
141+
router: chi.NewRouter(),
142+
metricsServer: r.metricsServer,
143+
config: r.config,
144+
}
145+
146+
return newRouter
147+
}
148+
135149
func (r *zrouter) SetDefaultMiddlewares(loggingOptions zmiddlewares.LoggingMiddlewareOptions) {
136150
if err := zmiddlewares.RegisterRequestMetrics(r.metricsServer); err != nil {
137151
logger.GetLoggerFromContext(context.Background()).Errorf("Error registering metrics %v", err)
@@ -262,6 +276,23 @@ func (r *zrouter) Use(middlewares ...zmiddlewares.Middleware) Routes {
262276
return r
263277
}
264278

279+
func (r *zrouter) Mount(pattern string, subRouter Routes) {
280+
sr, ok := subRouter.(*zrouter)
281+
if !ok {
282+
panic("subRouter is not of expected type *zrouter")
283+
}
284+
285+
r.router.Mount(pattern, sr.router)
286+
}
287+
288+
func (r *zrouter) Handle(pattern string, handler HandlerFunc) {
289+
if handler == nil {
290+
panic("handler is mandatory")
291+
}
292+
293+
r.router.Handle(pattern, getChiHandler(handler))
294+
}
295+
265296
func (r *zrouter) GetRegisteredRoutes() []RegisteredRoute {
266297
r.mutex.Lock()
267298
defer r.mutex.Unlock()
@@ -279,6 +310,10 @@ func (r *zrouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
279310
r.router.ServeHTTP(w, req)
280311
}
281312

313+
func (r *zrouter) ServeFiles(routePattern string, httpHandler http.Handler) {
314+
r.router.Handle(routePattern, httpHandler)
315+
}
316+
282317
func LogTopJWTPathMetrics(ctx context.Context, zCache zcache.RemoteCache, updateInterval time.Duration, topN int) {
283318
if updateInterval == 0 {
284319
updateInterval = defaultUpdateInterval

pkg/zrouter/zrouter_mock.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package zrouter
33
import (
44
"github.com/stretchr/testify/mock"
55
"github.com/zondax/golem/pkg/zrouter/zmiddlewares"
6+
"net/http"
67
)
78

89
type MockZRouter struct {
@@ -53,3 +54,37 @@ func (m *MockZRouter) Group(prefix string) Routes {
5354
args := m.Called(prefix)
5455
return args.Get(0).(Routes)
5556
}
57+
58+
func (m *MockZRouter) Handle(pattern string, handler HandlerFunc) {
59+
m.Called(pattern, handler)
60+
}
61+
62+
func (m *MockZRouter) Mount(pattern string, handler HandlerFunc) {
63+
m.Called(pattern, handler)
64+
}
65+
66+
func (m *MockZRouter) ServeFiles(routePattern string, httpHandler http.Handler) {
67+
m.Called(routePattern, httpHandler)
68+
}
69+
70+
func (m *MockZRouter) NoRoute(handler HandlerFunc) {
71+
m.Called(handler)
72+
}
73+
74+
func (m *MockZRouter) GetRegisteredRoutes() []RegisteredRoute {
75+
args := m.Called()
76+
return args.Get(0).([]RegisteredRoute)
77+
}
78+
79+
func (m *MockZRouter) SetDefaultMiddlewares(loggingOptions zmiddlewares.LoggingMiddlewareOptions) {
80+
m.Called(loggingOptions)
81+
}
82+
83+
func (m *MockZRouter) GetHandler() http.Handler {
84+
args := m.Called()
85+
return args.Get(0).(http.Handler)
86+
}
87+
88+
func (m *MockZRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
89+
m.Called(w, req)
90+
}

0 commit comments

Comments
 (0)