test_collection_getBatched.js (5215B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 const { Collection, WBORecord } = ChromeUtils.importESModule( 5 "resource://services-sync/record.sys.mjs" 6 ); 7 const { Service } = ChromeUtils.importESModule( 8 "resource://services-sync/service.sys.mjs" 9 ); 10 11 function recordRange(lim, offset, total) { 12 let res = []; 13 for (let i = offset; i < Math.min(lim + offset, total); ++i) { 14 res.push({ id: String(i), payload: "test:" + i }); 15 } 16 return res; 17 } 18 19 function get_test_collection_info({ 20 totalRecords, 21 batchSize, 22 lastModified, 23 throwAfter = Infinity, 24 interruptedAfter = Infinity, 25 }) { 26 let coll = new Collection("http://example.com/test/", WBORecord, Service); 27 coll.full = true; 28 let requests = []; 29 let responses = []; 30 coll.get = async function () { 31 let limit = +this.limit; 32 let offset = 0; 33 if (this.offset) { 34 equal(this.offset.slice(0, 6), "foobar"); 35 offset = +this.offset.slice(6); 36 } 37 requests.push({ 38 limit, 39 offset, 40 spec: this.spec, 41 headers: Object.assign({}, this.headers), 42 }); 43 if (--throwAfter === 0) { 44 throw new Error("Some Network Error"); 45 } 46 let body = recordRange(limit, offset, totalRecords); 47 let response = { 48 obj: body, 49 success: true, 50 status: 200, 51 headers: {}, 52 }; 53 if (--interruptedAfter === 0) { 54 response.success = false; 55 response.status = 412; 56 response.body = ""; 57 } else if (offset + limit < totalRecords) { 58 // Ensure we're treating this as an opaque string, since the docs say 59 // it might not be numeric. 60 response.headers["x-weave-next-offset"] = "foobar" + (offset + batchSize); 61 } 62 response.headers["x-last-modified"] = lastModified; 63 responses.push(response); 64 return response; 65 }; 66 return { responses, requests, coll }; 67 } 68 69 add_task(async function test_success() { 70 const totalRecords = 11; 71 const batchSize = 2; 72 const lastModified = "111111"; 73 let { responses, requests, coll } = get_test_collection_info({ 74 totalRecords, 75 batchSize, 76 lastModified, 77 }); 78 let { response, records } = await coll.getBatched(batchSize); 79 80 equal(requests.length, Math.ceil(totalRecords / batchSize)); 81 82 equal(records.length, totalRecords); 83 checkRecordsOrder(records); 84 85 // ensure we're returning the last response 86 equal(responses[responses.length - 1], response); 87 88 // check first separately since its a bit of a special case 89 ok(!requests[0].headers["x-if-unmodified-since"]); 90 ok(!requests[0].offset); 91 equal(requests[0].limit, batchSize); 92 let expectedOffset = 2; 93 for (let i = 1; i < requests.length; ++i) { 94 let req = requests[i]; 95 equal(req.headers["x-if-unmodified-since"], lastModified); 96 equal(req.limit, batchSize); 97 if (i !== requests.length - 1) { 98 equal(req.offset, expectedOffset); 99 } 100 101 expectedOffset += batchSize; 102 } 103 104 // ensure we cleaned up anything that would break further 105 // use of this collection. 106 ok(!coll._headers["x-if-unmodified-since"]); 107 ok(!coll.offset); 108 ok(!coll.limit || coll.limit == Infinity); 109 }); 110 111 add_task(async function test_total_limit() { 112 _("getBatched respects the (initial) value of the limit property"); 113 const totalRecords = 100; 114 const recordLimit = 11; 115 const batchSize = 2; 116 const lastModified = "111111"; 117 let { requests, coll } = get_test_collection_info({ 118 totalRecords, 119 batchSize, 120 lastModified, 121 }); 122 coll.limit = recordLimit; 123 let { records } = await coll.getBatched(batchSize); 124 checkRecordsOrder(records); 125 126 equal(requests.length, Math.ceil(recordLimit / batchSize)); 127 equal(records.length, recordLimit); 128 129 for (let i = 0; i < requests.length; ++i) { 130 let req = requests[i]; 131 if (i !== requests.length - 1) { 132 equal(req.limit, batchSize); 133 } else { 134 equal(req.limit, recordLimit % batchSize); 135 } 136 } 137 138 equal(coll._limit, recordLimit); 139 }); 140 141 add_task(async function test_412() { 142 _("We shouldn't record records if we get a 412 in the middle of a batch"); 143 const totalRecords = 11; 144 const batchSize = 2; 145 const lastModified = "111111"; 146 let { responses, requests, coll } = get_test_collection_info({ 147 totalRecords, 148 batchSize, 149 lastModified, 150 interruptedAfter: 3, 151 }); 152 let { response, records } = await coll.getBatched(batchSize); 153 154 equal(requests.length, 3); 155 equal(records.length, 0); // we should not get any records 156 157 // ensure we're returning the last response 158 equal(responses[responses.length - 1], response); 159 160 ok(!response.success); 161 equal(response.status, 412); 162 }); 163 164 add_task(async function test_get_throws() { 165 _("getBatched() should throw if a get() throws"); 166 const totalRecords = 11; 167 const batchSize = 2; 168 const lastModified = "111111"; 169 let { requests, coll } = get_test_collection_info({ 170 totalRecords, 171 batchSize, 172 lastModified, 173 throwAfter: 3, 174 }); 175 176 await Assert.rejects(coll.getBatched(batchSize), /Some Network Error/); 177 178 equal(requests.length, 3); 179 }); 180 181 function checkRecordsOrder(records) { 182 ok(!!records.length); 183 for (let i = 0; i < records.length; i++) { 184 equal(records[i].id, String(i)); 185 equal(records[i].payload, "test:" + i); 186 } 187 }