Skip to content
File

Blob: src/workerd/api/tests/cache-operations-test.js

javascript307 lines
1// Copyright (c) 2017-2023 Cloudflare, Inc.
2// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3// https://opensource.org/licenses/Apache-2.0
4//
5// Cache API operations for generating instrumentation telemetry.
6// The actual validation of telemetry spans happens in cache-instrumentation-test.js
7 
8import * as assert from 'node:assert';
9 
10// Note that these aren't really tests of the cache API. We run through a bunch
11// of the cache API operations to emit telemetry for the tests in cache-instrumentation-test.js
12 
13export const matchOperations = {
14 async test(ctrl, env, ctx) {
15 const cache = caches.default;
16 
17 // Test cache.match() - HIT case
18 const matchRequest1 = new Request('https://example.com/cached-resource', {
19 method: 'GET',
20 });
21 let matchResult = await cache.match(matchRequest1);
22 assert.ok(matchResult !== undefined, 'Should have a cache HIT');
23 assert.strictEqual(await matchResult.text(), 'Cached content');
24 
25 // Test cache.match() - MISS case
26 const matchRequest2 = new Request('https://example.com/not-cached', {
27 method: 'GET',
28 });
29 matchResult = await cache.match(matchRequest2);
30 assert.strictEqual(matchResult, undefined, 'Should be cache MISS');
31 
32 // Test cache.match() with options
33 const matchRequest3 = new Request(
34 'https://example.com/cached-with-options',
35 {
36 method: 'GET',
37 }
38 );
39 matchResult = await cache.match(matchRequest3, { ignoreMethod: false });
40 assert.strictEqual(
41 matchResult,
42 undefined,
43 'Should be cache MISS with options'
44 );
45 },
46};
47 
48export const putOperations = {
49 async test(ctrl, env, ctx) {
50 const cache = caches.default;
51 
52 // Test cache.put() with max-age
53 const putRequest1 = new Request('https://example.com/put-resource', {
54 method: 'GET',
55 });
56 const putResponse1 = new Response('Test content', {
57 status: 200,
58 headers: {
59 'Content-Type': 'text/plain',
60 'Cache-Control': 'public, max-age=3600',
61 },
62 });
63 await cache.put(putRequest1, putResponse1);
64 
65 // Test cache.put() with no-store
66 const putRequest2 = new Request('https://example.com/put-no-store', {
67 method: 'GET',
68 });
69 const putResponse2 = new Response('No store content', {
70 status: 200,
71 headers: {
72 'Content-Type': 'text/plain',
73 'Cache-Control': 'no-store',
74 },
75 });
76 await cache.put(putRequest2, putResponse2);
77 
78 // Test cache.put() with s-maxage
79 const putRequest3 = new Request('https://example.com/put-s-maxage', {
80 method: 'GET',
81 });
82 const putResponse3 = new Response('S-maxage content', {
83 status: 200,
84 headers: {
85 'Content-Type': 'text/plain',
86 'Cache-Control': 's-maxage=7200, public',
87 },
88 });
89 await cache.put(putRequest3, putResponse3);
90 },
91};
92 
93export const deleteOperations = {
94 async test(ctrl, env, ctx) {
95 const cache = caches.default;
96 
97 // Test cache.delete() - exists
98 const deleteRequest1 = new Request('https://example.com/delete-exists', {
99 method: 'GET',
100 });
101 let deleteResult = await cache.delete(deleteRequest1);
102 assert.strictEqual(
103 deleteResult,
104 true,
105 'Should return true for successful delete'
106 );
107 
108 // Test cache.delete() - doesn't exist
109 const deleteRequest2 = new Request(
110 'https://example.com/delete-not-exists',
111 {
112 method: 'GET',
113 }
114 );
115 deleteResult = await cache.delete(deleteRequest2);
116 assert.strictEqual(
117 deleteResult,
118 false,
119 'Should return false when not found'
120 );
121 
122 // Test cache.delete() with options
123 const deleteRequest3 = new Request(
124 'https://example.com/delete-with-options',
125 {
126 method: 'POST',
127 }
128 );
129 deleteResult = await cache.delete(deleteRequest3, { ignoreMethod: true });
130 assert.strictEqual(deleteResult, false, 'Should handle options');
131 },
132};
133 
134export const headersOperations = {
135 async test(ctrl, env, ctx) {
136 const cache = caches.default;
137 
138 // Test cache.put() with Cache-Tag header
139 const putRequest1 = new Request('https://example.com/put-cache-tag', {
140 method: 'GET',
141 });
142 const putResponse1 = new Response('Tagged content', {
143 status: 200,
144 headers: {
145 'Content-Type': 'text/plain',
146 'Cache-Control': 'public, max-age=3600',
147 'Cache-Tag': 'tag1,tag2,tag3',
148 },
149 });
150 await cache.put(putRequest1, putResponse1);
151 
152 // Test cache.put() with ETag header
153 const putRequest2 = new Request('https://example.com/put-etag', {
154 method: 'GET',
155 });
156 const putResponse2 = new Response('ETag content', {
157 status: 200,
158 headers: {
159 'Content-Type': 'text/plain',
160 'Cache-Control': 'public, max-age=3600',
161 ETag: '"abc123"',
162 },
163 });
164 await cache.put(putRequest2, putResponse2);
165 
166 // Test cache.put() with Expires header
167 const putRequest3 = new Request('https://example.com/put-expires', {
168 method: 'GET',
169 });
170 const putResponse3 = new Response('Expires content', {
171 status: 200,
172 headers: {
173 'Content-Type': 'text/plain',
174 Expires: 'Wed, 21 Oct 2025 07:28:00 GMT',
175 },
176 });
177 await cache.put(putRequest3, putResponse3);
178 
179 // Test cache.put() with Last-Modified header
180 const putRequest4 = new Request('https://example.com/put-last-modified', {
181 method: 'GET',
182 });
183 const putResponse4 = new Response('Last-Modified content', {
184 status: 200,
185 headers: {
186 'Content-Type': 'text/plain',
187 'Cache-Control': 'public, max-age=3600',
188 'Last-Modified': 'Wed, 21 Oct 2020 07:28:00 GMT',
189 },
190 });
191 await cache.put(putRequest4, putResponse4);
192 
193 // Test cache.put() with Set-Cookie header (should not cache or require special handling)
194 const putRequest5 = new Request('https://example.com/put-set-cookie', {
195 method: 'GET',
196 });
197 const putResponse5 = new Response('Cookie content', {
198 status: 200,
199 headers: {
200 'Content-Type': 'text/plain',
201 'Cache-Control': 'public, max-age=3600',
202 'Set-Cookie': 'sessionid=abc123; Path=/; HttpOnly',
203 },
204 });
205 await cache.put(putRequest5, putResponse5);
206 
207 // Test cache.put() with Set-Cookie and Cache-Control: private=Set-Cookie
208 const putRequest6 = new Request(
209 'https://example.com/put-set-cookie-private',
210 {
211 method: 'GET',
212 }
213 );
214 const putResponse6 = new Response('Cookie content with private', {
215 status: 200,
216 headers: {
217 'Content-Type': 'text/plain',
218 'Cache-Control': 'public, max-age=3600, private=Set-Cookie',
219 'Set-Cookie': 'sessionid=xyz789; Path=/; HttpOnly',
220 },
221 });
222 await cache.put(putRequest6, putResponse6);
223 
224 // Test cache.put() with must-revalidate
225 const putRequest7 = new Request('https://example.com/put-must-revalidate', {
226 method: 'GET',
227 });
228 const putResponse7 = new Response('Must revalidate content', {
229 status: 200,
230 headers: {
231 'Content-Type': 'text/plain',
232 'Cache-Control': 'public, max-age=3600, must-revalidate',
233 },
234 });
235 await cache.put(putRequest7, putResponse7);
236 
237 // Test cache.put() with proxy-revalidate
238 const putRequest8 = new Request(
239 'https://example.com/put-proxy-revalidate',
240 {
241 method: 'GET',
242 }
243 );
244 const putResponse8 = new Response('Proxy revalidate content', {
245 status: 200,
246 headers: {
247 'Content-Type': 'text/plain',
248 'Cache-Control': 'public, max-age=3600, proxy-revalidate',
249 },
250 });
251 await cache.put(putRequest8, putResponse8);
252 
253 // Test cache.put() with private cache control
254 const putRequest9 = new Request('https://example.com/put-private', {
255 method: 'GET',
256 });
257 const putResponse9 = new Response('Private content', {
258 status: 200,
259 headers: {
260 'Content-Type': 'text/plain',
261 'Cache-Control': 'private, max-age=3600',
262 },
263 });
264 await cache.put(putRequest9, putResponse9);
265 
266 // Test cache.put() with no-cache
267 const putRequest10 = new Request('https://example.com/put-no-cache', {
268 method: 'GET',
269 });
270 const putResponse10 = new Response('No-cache content', {
271 status: 200,
272 headers: {
273 'Content-Type': 'text/plain',
274 'Cache-Control': 'no-cache, max-age=3600',
275 },
276 });
277 await cache.put(putRequest10, putResponse10);
278 },
279};
280 
281export const conditionalRequestOperations = {
282 async test(ctrl, env, ctx) {
283 const cache = caches.default;
284 
285 // Test cache.match() with If-None-Match (should work with ETag)
286 const matchRequest1 = new Request('https://example.com/conditional-etag', {
287 method: 'GET',
288 headers: {
289 'If-None-Match': 'abc123',
290 },
291 });
292 let _matchResult = await cache.match(matchRequest1);
293 
294 // Test cache.match() with If-Modified-Since (should work with Last-Modified)
295 const matchRequest2 = new Request(
296 'https://example.com/conditional-last-modified',
297 {
298 method: 'GET',
299 headers: {
300 'If-Modified-Since': 'Wed, 21 Oct 2020 07:28:00 GMT',
301 },
302 }
303 );
304 _matchResult = await cache.match(matchRequest2);
305 },
306};