summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/service-workers/cache-storage/cache-add.https.any.js
blob: eca516abd5f3933510d299859bf44bb0a2f56052 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
// META: title=Cache.add and Cache.addAll
// META: global=window,worker
// META: script=/common/get-host-info.sub.js
// META: script=./resources/test-helpers.js
// META: timeout=long

const { REMOTE_HOST } = get_host_info();

cache_test(function(cache, test) {
    return promise_rejects_js(
      test,
      TypeError,
      cache.add(),
      'Cache.add should throw a TypeError when no arguments are given.');
  }, 'Cache.add called with no arguments');

cache_test(function(cache) {
    return cache.add('./resources/simple.txt')
      .then(function(result) {
          assert_equals(result, undefined,
                        'Cache.add should resolve with undefined on success.');
          return cache.match('./resources/simple.txt');
        })
        .then(function(response) {
          assert_class_string(response, 'Response',
                              'Cache.add should put a resource in the cache.');
          return response.text();
        })
        .then(function(body) {
          assert_equals(body, 'a simple text file\n',
                        'Cache.add should retrieve the correct body.');
        });
  }, 'Cache.add called with relative URL specified as a string');

cache_test(function(cache, test) {
    return promise_rejects_js(
      test,
      TypeError,
      cache.add('javascript://this-is-not-http-mmkay'),
      'Cache.add should throw a TypeError for non-HTTP/HTTPS URLs.');
  }, 'Cache.add called with non-HTTP/HTTPS URL');

cache_test(function(cache) {
    var request = new Request('./resources/simple.txt');
    return cache.add(request)
      .then(function(result) {
          assert_equals(result, undefined,
                        'Cache.add should resolve with undefined on success.');
        });
  }, 'Cache.add called with Request object');

cache_test(function(cache, test) {
    var request = new Request('./resources/simple.txt',
                              {method: 'POST', body: 'This is a body.'});
    return promise_rejects_js(
      test,
      TypeError,
      cache.add(request),
      'Cache.add should throw a TypeError for non-GET requests.');
  }, 'Cache.add called with POST request');

cache_test(function(cache) {
    var request = new Request('./resources/simple.txt');
    return cache.add(request)
      .then(function(result) {
          assert_equals(result, undefined,
                        'Cache.add should resolve with undefined on success.');
        })
      .then(function() {
          return cache.add(request);
        })
      .then(function(result) {
          assert_equals(result, undefined,
                        'Cache.add should resolve with undefined on success.');
        });
  }, 'Cache.add called twice with the same Request object');

cache_test(function(cache) {
    var request = new Request('./resources/simple.txt');
    return request.text()
      .then(function() {
          assert_false(request.bodyUsed);
        })
      .then(function() {
          return cache.add(request);
        });
  }, 'Cache.add with request with null body (not consumed)');

cache_test(function(cache, test) {
    return promise_rejects_js(
      test,
      TypeError,
      cache.add('./resources/fetch-status.py?status=206'),
      'Cache.add should reject on partial response');
  }, 'Cache.add with 206 response');

cache_test(function(cache, test) {
    var urls = ['./resources/fetch-status.py?status=206',
                './resources/fetch-status.py?status=200'];
    var requests = urls.map(function(url) {
        return new Request(url);
      });
    return promise_rejects_js(
      test,
      TypeError,
      cache.addAll(requests),
      'Cache.addAll should reject with TypeError if any request fails');
  }, 'Cache.addAll with 206 response');

cache_test(function(cache, test) {
    var urls = ['./resources/fetch-status.py?status=206',
                './resources/fetch-status.py?status=200'];
    var requests = urls.map(function(url) {
        var cross_origin_url = new URL(url, location.href);
        cross_origin_url.hostname = REMOTE_HOST;
        return new Request(cross_origin_url.href, { mode: 'no-cors' });
      });
    return promise_rejects_js(
      test,
      TypeError,
      cache.addAll(requests),
      'Cache.addAll should reject with TypeError if any request fails');
  }, 'Cache.addAll with opaque-filtered 206 response');

cache_test(function(cache, test) {
    return promise_rejects_js(
      test,
      TypeError,
      cache.add('this-does-not-exist-please-dont-create-it'),
      'Cache.add should reject if response is !ok');
  }, 'Cache.add with request that results in a status of 404');


cache_test(function(cache, test) {
    return promise_rejects_js(
      test,
      TypeError,
      cache.add('./resources/fetch-status.py?status=500'),
      'Cache.add should reject if response is !ok');
  }, 'Cache.add with request that results in a status of 500');

cache_test(function(cache, test) {
    return promise_rejects_js(
      test,
      TypeError,
      cache.addAll(),
      'Cache.addAll with no arguments should throw TypeError.');
  }, 'Cache.addAll with no arguments');

cache_test(function(cache, test) {
    // Assumes the existence of ../resources/simple.txt and ../resources/blank.html
    var urls = ['./resources/simple.txt', undefined, './resources/blank.html'];
    return promise_rejects_js(
      test,
      TypeError,
      cache.addAll(urls),
      'Cache.addAll should throw TypeError for an undefined argument.');
  }, 'Cache.addAll with a mix of valid and undefined arguments');

cache_test(function(cache) {
    return cache.addAll([])
      .then(function(result) {
          assert_equals(result, undefined,
                        'Cache.addAll should resolve with undefined on ' +
                        'success.');
          return cache.keys();
        })
      .then(function(result) {
          assert_equals(result.length, 0,
                        'There should be no entry in the cache.');
        });
  }, 'Cache.addAll with an empty array');

cache_test(function(cache) {
    // Assumes the existence of ../resources/simple.txt and
    // ../resources/blank.html
    var urls = ['./resources/simple.txt',
                self.location.href,
                './resources/blank.html'];
    return cache.addAll(urls)
      .then(function(result) {
          assert_equals(result, undefined,
                        'Cache.addAll should resolve with undefined on ' +
                        'success.');
          return Promise.all(
            urls.map(function(url) { return cache.match(url); }));
        })
      .then(function(responses) {
          assert_class_string(
            responses[0], 'Response',
            'Cache.addAll should put a resource in the cache.');
          assert_class_string(
            responses[1], 'Response',
            'Cache.addAll should put a resource in the cache.');
          assert_class_string(
            responses[2], 'Response',
            'Cache.addAll should put a resource in the cache.');
          return Promise.all(
            responses.map(function(response) { return response.text(); }));
        })
      .then(function(bodies) {
          assert_equals(
            bodies[0], 'a simple text file\n',
            'Cache.add should retrieve the correct body.');
          assert_equals(
            bodies[2], '<!DOCTYPE html>\n<title>Empty doc</title>\n',
            'Cache.add should retrieve the correct body.');
        });
  }, 'Cache.addAll with string URL arguments');

cache_test(function(cache) {
    // Assumes the existence of ../resources/simple.txt and
    // ../resources/blank.html
    var urls = ['./resources/simple.txt',
                self.location.href,
                './resources/blank.html'];
    var requests = urls.map(function(url) {
        return new Request(url);
      });
    return cache.addAll(requests)
      .then(function(result) {
          assert_equals(result, undefined,
                        'Cache.addAll should resolve with undefined on ' +
                        'success.');
          return Promise.all(
            urls.map(function(url) { return cache.match(url); }));
        })
      .then(function(responses) {
          assert_class_string(
            responses[0], 'Response',
            'Cache.addAll should put a resource in the cache.');
          assert_class_string(
            responses[1], 'Response',
            'Cache.addAll should put a resource in the cache.');
          assert_class_string(
            responses[2], 'Response',
            'Cache.addAll should put a resource in the cache.');
          return Promise.all(
            responses.map(function(response) { return response.text(); }));
        })
      .then(function(bodies) {
          assert_equals(
            bodies[0], 'a simple text file\n',
            'Cache.add should retrieve the correct body.');
          assert_equals(
            bodies[2], '<!DOCTYPE html>\n<title>Empty doc</title>\n',
            'Cache.add should retrieve the correct body.');
        });
  }, 'Cache.addAll with Request arguments');

cache_test(function(cache, test) {
    // Assumes that ../resources/simple.txt and ../resources/blank.html exist.
    // The second resource does not.
    var urls = ['./resources/simple.txt',
                'this-resource-should-not-exist',
                './resources/blank.html'];
    var requests = urls.map(function(url) {
        return new Request(url);
      });
    return promise_rejects_js(
      test,
      TypeError,
      cache.addAll(requests),
      'Cache.addAll should reject with TypeError if any request fails')
      .then(function() {
          return Promise.all(urls.map(function(url) {
              return cache.match(url);
            }));
      })
      .then(function(matches) {
          assert_array_equals(
            matches,
            [undefined, undefined, undefined],
            'If any response fails, no response should be added to cache');
      });
  }, 'Cache.addAll with a mix of succeeding and failing requests');

cache_test(function(cache, test) {
    var request = new Request('../resources/simple.txt');
    return promise_rejects_dom(
      test,
      'InvalidStateError',
      cache.addAll([request, request]),
      'Cache.addAll should throw InvalidStateError if the same request is added ' +
      'twice.');
  }, 'Cache.addAll called with the same Request object specified twice');

cache_test(async function(cache, test) {
    const url = './resources/vary.py?vary=x-shape';
    let requests = [
      new Request(url, { headers: { 'x-shape': 'circle' }}),
      new Request(url, { headers: { 'x-shape': 'square' }}),
    ];
    let result = await cache.addAll(requests);
    assert_equals(result, undefined, 'Cache.addAll() should succeed');
  }, 'Cache.addAll should succeed when entries differ by vary header');

cache_test(async function(cache, test) {
    const url = './resources/vary.py?vary=x-shape';
    let requests = [
      new Request(url, { headers: { 'x-shape': 'circle' }}),
      new Request(url, { headers: { 'x-shape': 'circle' }}),
    ];
    await promise_rejects_dom(
      test,
      'InvalidStateError',
      cache.addAll(requests),
      'Cache.addAll() should reject when entries are duplicate by vary header');
  }, 'Cache.addAll should reject when entries are duplicate by vary header');

// VARY header matching is asymmetric.  Determining if two entries are duplicate
// depends on which entry's response is used in the comparison.  The target
// response's VARY header determines what request headers are examined.  This
// test verifies that Cache.addAll() duplicate checking handles this asymmetric
// behavior correctly.
cache_test(async function(cache, test) {
    const base_url = './resources/vary.py';

    // Define a request URL that sets a VARY header in the
    // query string to be echoed back by the server.
    const url = base_url + '?vary=x-size';

    // Set a cookie to override the VARY header of the response
    // when the request is made with credentials.  This will
    // take precedence over the query string vary param.  This
    // is a bit confusing, but it's necessary to construct a test
    // where the URL is the same, but the VARY headers differ.
    //
    // Note, the test could also pass this information in additional
    // request headers.  If the cookie approach becomes too unwieldy
    // this test could be rewritten to use that technique.
    await fetch(base_url + '?set-vary-value-override-cookie=x-shape');
    test.add_cleanup(_ => fetch(base_url + '?clear-vary-value-override-cookie'));

    let requests = [
      // This request will result in a Response with a "Vary: x-shape"
      // header.  This *will not* result in a duplicate match with the
      // other entry.
      new Request(url, { headers: { 'x-shape': 'circle',
                                    'x-size': 'big' },
                         credentials: 'same-origin' }),

      // This request will result in a Response with a "Vary: x-size"
      // header.  This *will* result in a duplicate match with the other
      // entry.
      new Request(url, { headers: { 'x-shape': 'square',
                                    'x-size': 'big' },
                         credentials: 'omit' }),
    ];
    await promise_rejects_dom(
      test,
      'InvalidStateError',
      cache.addAll(requests),
      'Cache.addAll() should reject when one entry has a vary header ' +
      'matching an earlier entry.');

    // Test the reverse order now.
    await promise_rejects_dom(
      test,
      'InvalidStateError',
      cache.addAll(requests.reverse()),
      'Cache.addAll() should reject when one entry has a vary header ' +
      'matching a later entry.');

  }, 'Cache.addAll should reject when one entry has a vary header ' +
     'matching another entry');

done();