|
1 | 1 | package fastcache_test
|
2 | 2 |
|
3 | 3 | import (
|
4 |
| - "io/ioutil" |
| 4 | + "fmt" |
| 5 | + "io" |
5 | 6 | "log"
|
6 | 7 | "net/http"
|
7 | 8 | "os"
|
@@ -50,6 +51,49 @@ func init() {
|
50 | 51 | Logger: log.New(os.Stdout, "", log.Ldate|log.Ltime|log.Lshortfile),
|
51 | 52 | }
|
52 | 53 |
|
| 54 | + includeQS = &fastcache.Options{ |
| 55 | + NamespaceKey: namespaceKey, |
| 56 | + ETag: true, |
| 57 | + TTL: time.Second * 5, |
| 58 | + Logger: log.New(os.Stdout, "", log.Ldate|log.Ltime|log.Lshortfile), |
| 59 | + IncludeQueryString: true, |
| 60 | + } |
| 61 | + |
| 62 | + includeQSNoEtag = &fastcache.Options{ |
| 63 | + NamespaceKey: namespaceKey, |
| 64 | + ETag: false, |
| 65 | + TTL: time.Second * 5, |
| 66 | + Logger: log.New(os.Stdout, "", log.Ldate|log.Ltime|log.Lshortfile), |
| 67 | + IncludeQueryString: true, |
| 68 | + } |
| 69 | + |
| 70 | + includeQSSpecific = &fastcache.Options{ |
| 71 | + NamespaceKey: namespaceKey, |
| 72 | + ETag: true, |
| 73 | + TTL: time.Second * 5, |
| 74 | + Logger: log.New(os.Stdout, "", log.Ldate|log.Ltime|log.Lshortfile), |
| 75 | + IncludeQueryString: true, |
| 76 | + QueryArgsTransformerHook: func(args *fasthttp.Args) { |
| 77 | + // Copy the keys to delete, and delete them later. This is to |
| 78 | + // avoid borking the VisitAll() iterator. |
| 79 | + mp := map[string]struct{}{ |
| 80 | + "foo": {}, |
| 81 | + } |
| 82 | + |
| 83 | + delKeys := [][]byte{} |
| 84 | + args.VisitAll(func(k, v []byte) { |
| 85 | + if _, ok := mp[string(k)]; !ok { |
| 86 | + delKeys = append(delKeys, k) |
| 87 | + } |
| 88 | + }) |
| 89 | + |
| 90 | + // Delete the keys. |
| 91 | + for _, k := range delKeys { |
| 92 | + args.DelBytes(k) |
| 93 | + } |
| 94 | + }, |
| 95 | + } |
| 96 | + |
53 | 97 | fc = fastcache.New(cachestore.New("CACHE:", redis.NewClient(&redis.Options{
|
54 | 98 | Addr: rd.Addr(),
|
55 | 99 | })))
|
@@ -78,6 +122,19 @@ func init() {
|
78 | 122 | return r.SendBytes(200, "text/plain", []byte("ok"))
|
79 | 123 | }, ttlShort, group))
|
80 | 124 |
|
| 125 | + srv.GET("/include-qs", fc.Cached(func(r *fastglue.Request) error { |
| 126 | + return r.SendBytes(200, "text/plain", []byte("ok")) |
| 127 | + }, includeQS, group)) |
| 128 | + |
| 129 | + srv.GET("/include-qs-no-etag", fc.Cached(func(r *fastglue.Request) error { |
| 130 | + out := time.Now() |
| 131 | + return r.SendBytes(200, "text/plain", []byte(fmt.Sprintf("%v", out))) |
| 132 | + }, includeQSNoEtag, group)) |
| 133 | + |
| 134 | + srv.GET("/include-qs-specific", fc.Cached(func(r *fastglue.Request) error { |
| 135 | + return r.SendBytes(200, "text/plain", []byte("ok")) |
| 136 | + }, includeQSSpecific, group)) |
| 137 | + |
81 | 138 | // Start the server
|
82 | 139 | go func() {
|
83 | 140 | s := &fasthttp.Server{
|
@@ -111,7 +168,7 @@ func getReq(url, etag string, t *testing.T) (*http.Response, string) {
|
111 | 168 | t.Fatal(err)
|
112 | 169 | }
|
113 | 170 |
|
114 |
| - b, err := ioutil.ReadAll(resp.Body) |
| 171 | + b, err := io.ReadAll(resp.Body) |
115 | 172 | if err != nil {
|
116 | 173 | t.Fatal(b)
|
117 | 174 | }
|
@@ -139,22 +196,119 @@ func TestCache(t *testing.T) {
|
139 | 196 | }
|
140 | 197 |
|
141 | 198 | // Wrong etag.
|
142 |
| - r, b = getReq(srvRoot+"/cached", "wrong", t) |
| 199 | + r, _ = getReq(srvRoot+"/cached", "wrong", t) |
143 | 200 | if r.StatusCode != 200 {
|
144 | 201 | t.Fatalf("expected 200 but got '%v'", r.StatusCode)
|
145 | 202 | }
|
146 | 203 |
|
147 | 204 | // Clear cache.
|
148 |
| - r, b = getReq(srvRoot+"/clear-group", "", t) |
| 205 | + r, _ = getReq(srvRoot+"/clear-group", "", t) |
149 | 206 | if r.StatusCode != 200 {
|
150 | 207 | t.Fatalf("expected 200 but got %v", r.StatusCode)
|
151 | 208 | }
|
152 |
| - r, b = getReq(srvRoot+"/cached", r.Header.Get("Etag"), t) |
| 209 | + r, _ = getReq(srvRoot+"/cached", r.Header.Get("Etag"), t) |
153 | 210 | if r.StatusCode != 200 {
|
154 | 211 | t.Fatalf("expected 200 but got '%v'", r.StatusCode)
|
155 | 212 | }
|
156 | 213 | }
|
157 | 214 |
|
| 215 | +func TestQueryString(t *testing.T) { |
| 216 | + // First request should be 200. |
| 217 | + r, b := getReq(srvRoot+"/include-qs?foo=bar", "", t) |
| 218 | + if r.StatusCode != 200 { |
| 219 | + t.Fatalf("expected 200 but got %v", r.StatusCode) |
| 220 | + } |
| 221 | + |
| 222 | + if b != "ok" { |
| 223 | + t.Fatalf("expected 'ok' in body but got %v", b) |
| 224 | + } |
| 225 | + |
| 226 | + // Second should be 304. |
| 227 | + r, _ = getReq(srvRoot+"/include-qs?foo=bar", r.Header.Get("Etag"), t) |
| 228 | + if r.StatusCode != 304 { |
| 229 | + t.Fatalf("expected 304 but got '%v'", r.StatusCode) |
| 230 | + } |
| 231 | +} |
| 232 | + |
| 233 | +func TestQueryStringLexicographical(t *testing.T) { |
| 234 | + // First request should be 200. |
| 235 | + r, b := getReq(srvRoot+"/include-qs?foo=bar&baz=qux", "", t) |
| 236 | + if r.StatusCode != 200 { |
| 237 | + t.Fatalf("expected 200 but got %v", r.StatusCode) |
| 238 | + } |
| 239 | + |
| 240 | + if b != "ok" { |
| 241 | + t.Fatalf("expected 'ok' in body but got %v", b) |
| 242 | + } |
| 243 | + |
| 244 | + // Second should be 304. |
| 245 | + r, _ = getReq(srvRoot+"/include-qs?baz=qux&foo=bar", r.Header.Get("Etag"), t) |
| 246 | + if r.StatusCode != 304 { |
| 247 | + t.Fatalf("expected 304 but got '%v'", r.StatusCode) |
| 248 | + } |
| 249 | +} |
| 250 | + |
| 251 | +func TestQueryStringWithoutEtag(t *testing.T) { |
| 252 | + // First request should be 200. |
| 253 | + r, b := getReq(srvRoot+"/include-qs-no-etag?foo=bar", "", t) |
| 254 | + if r.StatusCode != 200 { |
| 255 | + t.Fatalf("expected 200 but got %v", r.StatusCode) |
| 256 | + } |
| 257 | + |
| 258 | + // Second should be 200 but with same response. |
| 259 | + r2, b2 := getReq(srvRoot+"/include-qs-no-etag?foo=bar", "", t) |
| 260 | + if r2.StatusCode != 200 { |
| 261 | + t.Fatalf("expected 200 but got '%v'", r2.StatusCode) |
| 262 | + } |
| 263 | + |
| 264 | + if b2 != b { |
| 265 | + t.Fatalf("expected '%v' in body but got %v", b, b2) |
| 266 | + } |
| 267 | + |
| 268 | + // Third should be 200 but with different response. |
| 269 | + r3, b3 := getReq(srvRoot+"/include-qs-no-etag?foo=baz", "", t) |
| 270 | + if r3.StatusCode != 200 { |
| 271 | + t.Fatalf("expected 200 but got '%v'", r3.StatusCode) |
| 272 | + } |
| 273 | + |
| 274 | + // time should be different |
| 275 | + if b3 == b { |
| 276 | + t.Fatalf("expected both to be different (should not be %v), but got %v", b, b3) |
| 277 | + } |
| 278 | +} |
| 279 | + |
| 280 | +func TestQueryStringSpecific(t *testing.T) { |
| 281 | + // First request should be 200. |
| 282 | + r1, b := getReq(srvRoot+"/include-qs-specific?foo=bar&baz=qux", "", t) |
| 283 | + if r1.StatusCode != 200 { |
| 284 | + t.Fatalf("expected 200 but got %v", r1.StatusCode) |
| 285 | + } |
| 286 | + if b != "ok" { |
| 287 | + t.Fatalf("expected 'ok' in body but got %v", b) |
| 288 | + } |
| 289 | + |
| 290 | + // Second should be 304. |
| 291 | + r, _ := getReq(srvRoot+"/include-qs-specific?foo=bar&baz=qux", r1.Header.Get("Etag"), t) |
| 292 | + if r.StatusCode != 304 { |
| 293 | + t.Fatalf("expected 304 but got '%v'", r.StatusCode) |
| 294 | + } |
| 295 | + |
| 296 | + // Third should be 304 as foo=bar |
| 297 | + r, _ = getReq(srvRoot+"/include-qs-specific?loo=mar&foo=bar&baz=qux&quux=quuz", r1.Header.Get("Etag"), t) |
| 298 | + if r.StatusCode != 304 { |
| 299 | + t.Fatalf("expected 304 but got '%v'", r.StatusCode) |
| 300 | + } |
| 301 | + |
| 302 | + // Fourth should be 200 as foo=rab |
| 303 | + r, b = getReq(srvRoot+"/include-qs-specific?foo=rab&baz=qux&quux=quuz", r1.Header.Get("Etag"), t) |
| 304 | + if r.StatusCode != 200 { |
| 305 | + t.Fatalf("expected 200 but got '%v'", r.StatusCode) |
| 306 | + } |
| 307 | + if b != "ok" { |
| 308 | + t.Fatalf("expected 'ok' in body but got %v", b) |
| 309 | + } |
| 310 | +} |
| 311 | + |
158 | 312 | func TestNoCache(t *testing.T) {
|
159 | 313 | // All requests should return 200.
|
160 | 314 | for n := 0; n < 3; n++ {
|
|
0 commit comments