Skip to content

Commit 6571700

Browse files
authored
Add Middleware from golibs-networking (#8)
* add middleware / mq * add sentry
1 parent 984875e commit 6571700

File tree

9 files changed

+567
-1
lines changed

9 files changed

+567
-1
lines changed

go.mod

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,17 @@ module github.com/trustwallet/golibs
33
go 1.15
44

55
require (
6-
github.com/davecgh/go-spew v1.1.1 // indirect
6+
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 // indirect
7+
github.com/evalphobia/logrus_sentry v0.8.2
8+
github.com/getsentry/raven-go v0.2.0 // indirect
9+
github.com/gin-gonic/gin v1.6.3
710
github.com/imroc/req v0.3.0
811
github.com/kr/pretty v0.1.0 // indirect
12+
github.com/patrickmn/go-cache v2.1.0+incompatible
13+
github.com/pkg/errors v0.9.1 // indirect
914
github.com/shopspring/decimal v1.2.0
15+
github.com/sirupsen/logrus v1.7.0
16+
github.com/streadway/amqp v1.0.0
1017
github.com/stretchr/testify v1.6.1
1118
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897
1219
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 // indirect

go.sum

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,87 @@
1+
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 h1:uH66TXeswKn5PW5zdZ39xEwfS9an067BirqA+P4QaLI=
2+
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
13
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
24
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
35
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
46
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
7+
github.com/evalphobia/logrus_sentry v0.8.2 h1:dotxHq+YLZsT1Bb45bB5UQbfCh3gM/nFFetyN46VoDQ=
8+
github.com/evalphobia/logrus_sentry v0.8.2/go.mod h1:pKcp+vriitUqu9KiWj/VRFbRfFNUwz95/UkgG8a6MNc=
9+
github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs=
10+
github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
11+
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
12+
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
13+
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
14+
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
15+
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
16+
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
17+
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
18+
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
19+
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
20+
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
21+
github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
22+
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
23+
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
24+
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
25+
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
526
github.com/imroc/req v0.3.0 h1:3EioagmlSG+z+KySToa+Ylo3pTFZs+jh3Brl7ngU12U=
627
github.com/imroc/req v0.3.0/go.mod h1:F+NZ+2EFSo6EFXdeIbpfE9hcC233id70kf0byW97Caw=
28+
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
29+
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
730
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
831
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
932
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
1033
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
1134
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
35+
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
36+
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
37+
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
38+
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
39+
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
40+
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
41+
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
42+
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
43+
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
44+
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
45+
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
46+
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
1247
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
1348
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
1449
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
1550
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
51+
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
52+
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
53+
github.com/streadway/amqp v1.0.0 h1:kuuDrUJFZL1QYL9hUNuCxNObNzB0bV/ZG5jV3RWAQgo=
54+
github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
1655
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
56+
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
57+
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
58+
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
1759
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
1860
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
61+
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
62+
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
63+
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
64+
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
1965
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
2066
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E=
2167
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
2268
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
2369
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
2470
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
2571
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
72+
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
73+
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
2674
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80=
2775
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
2876
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
77+
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
78+
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
2979
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
3080
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
3181
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
3282
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
83+
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
84+
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
3385
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
3486
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
3587
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=

middleware/cache.go

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
package middleware
2+
3+
import (
4+
"bytes"
5+
"crypto/sha1"
6+
"encoding/base64"
7+
"encoding/json"
8+
"errors"
9+
"fmt"
10+
"io/ioutil"
11+
"net/http"
12+
"sync"
13+
"time"
14+
15+
"github.com/gin-gonic/gin"
16+
17+
"github.com/patrickmn/go-cache"
18+
19+
log "github.com/sirupsen/logrus"
20+
)
21+
22+
var (
23+
memoryCache *memCache
24+
)
25+
26+
func init() {
27+
memoryCache = &memCache{cache: cache.New(5*time.Minute, 5*time.Minute)}
28+
}
29+
30+
type memCache struct {
31+
sync.RWMutex
32+
cache *cache.Cache
33+
}
34+
35+
type cacheResponse struct {
36+
Status int
37+
Header http.Header
38+
Data []byte
39+
}
40+
41+
type cachedWriter struct {
42+
gin.ResponseWriter
43+
status int
44+
written bool
45+
expire time.Duration
46+
key string
47+
}
48+
49+
func newCachedWriter(expire time.Duration, writer gin.ResponseWriter, key string) *cachedWriter {
50+
return &cachedWriter{writer, 0, false, expire, key}
51+
}
52+
53+
func (w *cachedWriter) WriteHeader(code int) {
54+
w.status = code
55+
w.written = true
56+
w.ResponseWriter.WriteHeader(code)
57+
}
58+
59+
func (w *cachedWriter) Status() int {
60+
return w.ResponseWriter.Status()
61+
}
62+
63+
func (w *cachedWriter) Written() bool {
64+
return w.ResponseWriter.Written()
65+
}
66+
67+
func (w *cachedWriter) Write(data []byte) (int, error) {
68+
ret, err := w.ResponseWriter.Write(data)
69+
if err != nil {
70+
return 0, nil
71+
}
72+
if w.Status() != 200 {
73+
return 0, nil
74+
}
75+
val := cacheResponse{
76+
w.Status(),
77+
w.Header(),
78+
data,
79+
}
80+
b, err := json.Marshal(val)
81+
if err != nil {
82+
return 0, errors.New("validator cache: failed to marshal cache object")
83+
}
84+
memoryCache.cache.Set(w.key, b, w.expire)
85+
return ret, nil
86+
}
87+
88+
func (w *cachedWriter) WriteString(data string) (n int, err error) {
89+
ret, err := w.ResponseWriter.WriteString(data)
90+
if err != nil {
91+
return 0, errors.New(err.Error() + " fail to cache write string")
92+
}
93+
if w.Status() != 200 {
94+
return 0, errors.New("WriteString: invalid cache status")
95+
}
96+
val := cacheResponse{
97+
w.Status(),
98+
w.Header(),
99+
[]byte(data),
100+
}
101+
b, err := json.Marshal(val)
102+
if err != nil {
103+
return 0, errors.New("validator cache: failed to marshal cache object")
104+
}
105+
memoryCache.setCache(w.key, b, w.expire)
106+
return ret, err
107+
}
108+
109+
func (mc *memCache) deleteCache(key string) {
110+
mc.RLock()
111+
defer mc.RUnlock()
112+
memoryCache.cache.Delete(key)
113+
}
114+
115+
func (mc *memCache) setCache(k string, x interface{}, d time.Duration) {
116+
b, err := json.Marshal(x)
117+
if err != nil {
118+
log.Error(errors.New(err.Error() + " client cache cannot marshal cache object"))
119+
return
120+
}
121+
mc.RLock()
122+
defer mc.RUnlock()
123+
memoryCache.cache.Set(k, b, d)
124+
}
125+
126+
func (mc *memCache) getCache(key string) (cacheResponse, error) {
127+
var result cacheResponse
128+
c, ok := mc.cache.Get(key)
129+
if !ok {
130+
return result, fmt.Errorf("gin-cache: invalid cache key %s", key)
131+
}
132+
r, ok := c.([]byte)
133+
if !ok {
134+
return result, errors.New("validator cache: failed to cast cache to bytes")
135+
}
136+
err := json.Unmarshal(r, &result)
137+
if err != nil {
138+
return result, errors.New(err.Error() + "not found")
139+
}
140+
return result, nil
141+
}
142+
143+
func generateKey(c *gin.Context) string {
144+
url := c.Request.URL.String()
145+
var b []byte
146+
if c.Request.Body != nil {
147+
b, _ = ioutil.ReadAll(c.Request.Body)
148+
// Restore the io.ReadCloser to its original state
149+
c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(b))
150+
}
151+
hash := sha1.Sum(append([]byte(url), b...))
152+
return base64.URLEncoding.EncodeToString(hash[:])
153+
}
154+
155+
// CacheMiddleware encapsulates a gin handler function and caches the model with an expiration time.
156+
func CacheMiddleware(expiration time.Duration, handle gin.HandlerFunc) gin.HandlerFunc {
157+
return func(c *gin.Context) {
158+
defer c.Next()
159+
key := generateKey(c)
160+
cacheControlValue := uint(expiration.Seconds())
161+
mc, err := memoryCache.getCache(key)
162+
if err != nil || mc.Data == nil {
163+
writer := newCachedWriter(expiration, c.Writer, key)
164+
165+
writer.Header().Set("Cache-Control", fmt.Sprintf("max-age=%d", cacheControlValue))
166+
167+
c.Writer = writer
168+
handle(c)
169+
if c.IsAborted() {
170+
memoryCache.deleteCache(key)
171+
}
172+
return
173+
}
174+
175+
c.Writer.WriteHeader(mc.Status)
176+
for k, vals := range mc.Header {
177+
for _, v := range vals {
178+
c.Writer.Header().Set(k, v)
179+
}
180+
}
181+
182+
c.Writer.Header().Set("Cache-Control", fmt.Sprintf("max-age=%d", cacheControlValue))
183+
184+
_, err = c.Writer.Write(mc.Data)
185+
if err != nil {
186+
memoryCache.deleteCache(key)
187+
log.Error(err, "cannot write data", mc)
188+
}
189+
}
190+
}

middleware/cache_control.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package middleware
2+
3+
import (
4+
"fmt"
5+
"github.com/gin-gonic/gin"
6+
"time"
7+
)
8+
9+
func CacheControl(duration time.Duration, handle gin.HandlerFunc) gin.HandlerFunc {
10+
return func(c *gin.Context) {
11+
defer c.Next()
12+
cacheControlValue := uint(duration.Seconds())
13+
c.Writer.Header().Set("Cache-Control", fmt.Sprintf("max-age=%d", cacheControlValue))
14+
handle(c)
15+
}
16+
}

middleware/cache_control_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package middleware
2+
3+
import (
4+
"fmt"
5+
"github.com/gin-gonic/gin"
6+
"github.com/stretchr/testify/assert"
7+
"net/http"
8+
"testing"
9+
"time"
10+
)
11+
12+
func init() {
13+
gin.SetMode(gin.TestMode)
14+
}
15+
16+
func TestCacheControl(t *testing.T) {
17+
router := gin.New()
18+
router.GET("/cache_ping_control", CacheControl(time.Second*30, func(c *gin.Context) {
19+
c.JSON(http.StatusOK, "pong "+fmt.Sprint(time.Now().UnixNano()))
20+
}))
21+
22+
w1 := performRequest("GET", "/cache_ping_control", router)
23+
w1CacheControl := w1.Header().Get("Cache-Control")
24+
assert.NotEqual(t, "no-cache", w1CacheControl)
25+
time.Sleep(time.Second * 1)
26+
w2 := performRequest("GET", "/cache_ping_control", router)
27+
w2CacheControl := w2.Header().Get("Cache-Control")
28+
29+
assert.Equal(t, w1CacheControl, w2CacheControl)
30+
assert.Equal(t, "max-age=30", w2CacheControl)
31+
32+
assert.Equal(t, http.StatusOK, w1.Code)
33+
assert.Equal(t, http.StatusOK, w2.Code)
34+
35+
}

0 commit comments

Comments
 (0)