1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/contacts/tests/test_migration_chrome.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,336 @@ 1.4 +/* global 1.5 + sendAsyncMessage, 1.6 + addMessageListener, 1.7 + indexedDB 1.8 + */ 1.9 +"use strict"; 1.10 + 1.11 +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; 1.12 + 1.13 +let imports = {}; 1.14 + 1.15 +Cu.import("resource://gre/modules/ContactDB.jsm", imports); 1.16 +Cu.import("resource://gre/modules/ContactService.jsm", imports); 1.17 +Cu.import("resource://gre/modules/Promise.jsm", imports); 1.18 +Cu.importGlobalProperties(["indexedDB"]); 1.19 + 1.20 +const { 1.21 + STORE_NAME, 1.22 + SAVED_GETALL_STORE_NAME, 1.23 + REVISION_STORE, 1.24 + DB_NAME, 1.25 + ContactService, 1.26 +} = imports; 1.27 +// |const| will not work because 1.28 +// it will make the Promise object immutable before assigning. 1.29 +// Using Object.defineProperty() instead. 1.30 +Object.defineProperty(this, "Promise", { 1.31 + value: imports.Promise, writable: false, configurable: false 1.32 +}); 1.33 + 1.34 +let DEBUG = false; 1.35 +function debug(str) { 1.36 + if (DEBUG){ 1.37 + dump("-*- TestMigrationChromeScript: " + str + "\n"); 1.38 + } 1.39 +} 1.40 + 1.41 +const DATA = { 1.42 + 12: { 1.43 + SCHEMA: function createSchema12(db, transaction) { 1.44 + let objectStore = db.createObjectStore(STORE_NAME, {keyPath: "id"}); 1.45 + objectStore.createIndex("familyName", "properties.familyName", { multiEntry: true }); 1.46 + objectStore.createIndex("givenName", "properties.givenName", { multiEntry: true }); 1.47 + objectStore.createIndex("familyNameLowerCase", "search.familyName", { multiEntry: true }); 1.48 + objectStore.createIndex("givenNameLowerCase", "search.givenName", { multiEntry: true }); 1.49 + objectStore.createIndex("telLowerCase", "search.tel", { multiEntry: true }); 1.50 + objectStore.createIndex("emailLowerCase", "search.email", { multiEntry: true }); 1.51 + objectStore.createIndex("tel", "search.exactTel", { multiEntry: true }); 1.52 + objectStore.createIndex("category", "properties.category", { multiEntry: true }); 1.53 + objectStore.createIndex("email", "search.email", { multiEntry: true }); 1.54 + objectStore.createIndex("telMatch", "search.parsedTel", {multiEntry: true}); 1.55 + db.createObjectStore(SAVED_GETALL_STORE_NAME); 1.56 + db.createObjectStore(REVISION_STORE).put(0, "revision"); 1.57 + }, 1.58 + BAD: [ 1.59 + { 1.60 + // this contact is bad because its "name" property is not an array and 1.61 + // is the empty string (upgrade 16 to 17) 1.62 + "properties": { 1.63 + "name": "", 1.64 + "email": [], 1.65 + "url": [{ 1.66 + "type": ["source"], 1.67 + "value": "urn:service:gmail:uid:http://www.google.com/m8/feeds/contacts/XXX/base/4567894654" 1.68 + }], 1.69 + "category": ["gmail"], 1.70 + "adr": [], 1.71 + "tel": [{ 1.72 + "type": ["mobile"], 1.73 + "value": "+7 123 456-78-90" 1.74 + }], 1.75 + "sex": "undefined", 1.76 + "genderIdentity": "undefined" 1.77 + }, 1.78 + "search": { 1.79 + "givenName": [], 1.80 + "familyName": [], 1.81 + "email": [], 1.82 + "category": ["gmail"], 1.83 + "tel": ["+71234567890","71234567890","1234567890","234567890","34567890", 1.84 + "4567890","567890","67890","7890","890","90","0","81234567890"], 1.85 + "exactTel": ["+71234567890"], 1.86 + "parsedTel": ["+71234567890","1234567890","81234567890","34567890"] 1.87 + }, 1.88 + "updated": new Date("2013-07-27T16:47:40.974Z"), 1.89 + "published": new Date("2013-07-27T16:47:40.974Z"), 1.90 + "id": "bad-1" 1.91 + }, 1.92 + { 1.93 + // This contact is bad because its "name" property is not an array 1.94 + // (upgrade 14 to 15) 1.95 + "properties": { 1.96 + "name": "name-bad-2", 1.97 + "email": [], 1.98 + "url": [{ 1.99 + "type": ["source"], 1.100 + "value": "urn:service:gmail:uid:http://www.google.com/m8/feeds/contacts/XXX/base/4567894654" 1.101 + }], 1.102 + "category": ["gmail"], 1.103 + "adr": [], 1.104 + "tel": [{ 1.105 + "type": ["mobile"], 1.106 + "value": "+7 123 456-78-90" 1.107 + }], 1.108 + "sex": "undefined", 1.109 + "genderIdentity": "undefined" 1.110 + }, 1.111 + "search": { 1.112 + "givenName": [], 1.113 + "familyName": [], 1.114 + "email": [], 1.115 + "category": ["gmail"], 1.116 + "tel": ["+71234567890","71234567890","1234567890","234567890","34567890", 1.117 + "4567890","567890","67890","7890","890","90","0","81234567890"], 1.118 + "exactTel": ["+71234567890"], 1.119 + "parsedTel": ["+71234567890","1234567890","81234567890","34567890"] 1.120 + }, 1.121 + "updated": new Date("2013-07-27T16:47:40.974Z"), 1.122 + "published": new Date("2013-07-27T16:47:40.974Z"), 1.123 + "id": "bad-2" 1.124 + }, 1.125 + { 1.126 + // This contact is bad because its bday property is a String (upgrade 15 1.127 + // to 16), and its anniversary property is an empty string (upgrade 16 1.128 + // to 17) 1.129 + "properties": { 1.130 + "name": ["name-bad-3"], 1.131 + "email": [], 1.132 + "url": [{ 1.133 + "type": ["source"], 1.134 + "value": "urn:service:gmail:uid:http://www.google.com/m8/feeds/contacts/XXX/base/4567894654" 1.135 + }], 1.136 + "category": ["gmail"], 1.137 + "adr": [], 1.138 + "tel": [{ 1.139 + "type": ["mobile"], 1.140 + "value": "+7 123 456-78-90" 1.141 + }], 1.142 + "sex": "undefined", 1.143 + "genderIdentity": "undefined", 1.144 + "bday": "2013-07-27T16:47:40.974Z", 1.145 + "anniversary": "" 1.146 + }, 1.147 + "search": { 1.148 + "givenName": [], 1.149 + "familyName": [], 1.150 + "email": [], 1.151 + "category": ["gmail"], 1.152 + "tel": ["+71234567890","71234567890","1234567890","234567890","34567890", 1.153 + "4567890","567890","67890","7890","890","90","0","81234567890"], 1.154 + "exactTel": ["+71234567890"], 1.155 + "parsedTel": ["+71234567890","1234567890","81234567890","34567890"] 1.156 + }, 1.157 + "updated": new Date("2013-07-27T16:47:40.974Z"), 1.158 + "published": new Date("2013-07-27T16:47:40.974Z"), 1.159 + "id": "bad-3" 1.160 + }, 1.161 + { 1.162 + // This contact is bad because its tel property has a tel.type null 1.163 + // value (upgrade 16 to 17), and email.type not array value (upgrade 14 1.164 + // to 15) 1.165 + "properties": { 1.166 + "name": ["name-bad-4"], 1.167 + "email": [{ 1.168 + "value": "toto@toto.com", 1.169 + "type": "home" 1.170 + }], 1.171 + "url": [{ 1.172 + "type": ["source"], 1.173 + "value": "urn:service:gmail:uid:http://www.google.com/m8/feeds/contacts/XXX/base/4567894654" 1.174 + }], 1.175 + "category": ["gmail"], 1.176 + "adr": [], 1.177 + "tel": [{ 1.178 + "type": null, 1.179 + "value": "+7 123 456-78-90" 1.180 + }], 1.181 + "sex": "undefined", 1.182 + "genderIdentity": "undefined" 1.183 + }, 1.184 + "search": { 1.185 + "givenName": [], 1.186 + "familyName": [], 1.187 + "email": [], 1.188 + "category": ["gmail"], 1.189 + "tel": ["+71234567890","71234567890","1234567890","234567890","34567890", 1.190 + "4567890","567890","67890","7890","890","90","0","81234567890"], 1.191 + "exactTel": ["+71234567890"], 1.192 + "parsedTel": ["+71234567890","1234567890","81234567890","34567890"] 1.193 + }, 1.194 + "updated": new Date("2013-07-27T16:47:40.974Z"), 1.195 + "published": new Date("2013-07-27T16:47:40.974Z"), 1.196 + "id": "bad-4" 1.197 + } 1.198 + ], 1.199 + GOOD: [ 1.200 + { 1.201 + "properties": { 1.202 + "name": ["name-good-1"], 1.203 + "email": [], 1.204 + "url": [{ 1.205 + "type": ["source"], 1.206 + "value": "urn:service:gmail:uid:http://www.google.com/m8/feeds/contacts/XXX/base/4567894654" 1.207 + }], 1.208 + "category": ["gmail"], 1.209 + "adr": [], 1.210 + "tel": [{ 1.211 + "type": ["mobile"], 1.212 + "value": "+7 123 456-78-90" 1.213 + }], 1.214 + "sex": "undefined", 1.215 + "genderIdentity": "undefined" 1.216 + }, 1.217 + "search": { 1.218 + "givenName": [], 1.219 + "familyName": [], 1.220 + "email": [], 1.221 + "category": ["gmail"], 1.222 + "tel": ["+71234567890","71234567890","1234567890","234567890","34567890", 1.223 + "4567890","567890","67890","7890","890","90","0","81234567890"], 1.224 + "exactTel": ["+71234567890"], 1.225 + "parsedTel": ["+71234567890","1234567890","81234567890","34567890"] 1.226 + }, 1.227 + "updated": new Date("2013-07-27T16:47:40.974Z"), 1.228 + "published": new Date("2013-07-27T16:47:40.974Z"), 1.229 + "id": "good-1" 1.230 + } 1.231 + ] 1.232 + } 1.233 +}; 1.234 + 1.235 +function DataManager(version) { 1.236 + if (!(version in DATA)) { 1.237 + throw new Error("Version " + version + " can't be found in our test datas."); 1.238 + } 1.239 + 1.240 + this.version = version; 1.241 + this.data = DATA[version]; 1.242 +} 1.243 + 1.244 +DataManager.prototype = { 1.245 + open: function() { 1.246 + debug("opening for version " + this.version); 1.247 + var deferred = Promise.defer(); 1.248 + 1.249 + let req = indexedDB.open(DB_NAME, this.version); 1.250 + req.onupgradeneeded = function() { 1.251 + let db = req.result; 1.252 + let transaction = req.transaction; 1.253 + this.createSchema(db, transaction); 1.254 + this.addContacts(db, transaction); 1.255 + }.bind(this); 1.256 + 1.257 + req.onsuccess = function() { 1.258 + debug("succeeded opening the db, let's close it now"); 1.259 + req.result.close(); 1.260 + deferred.resolve(this.contactsCount()); 1.261 + }.bind(this); 1.262 + 1.263 + req.onerror = function() { 1.264 + deferred.reject(this.error); 1.265 + }; 1.266 + 1.267 + return deferred.promise; 1.268 + }, 1.269 + 1.270 + createSchema: function(db, transaction) { 1.271 + debug("createSchema for version " + this.version); 1.272 + this.data.SCHEMA(db, transaction); 1.273 + }, 1.274 + 1.275 + addContacts: function(db, transaction) { 1.276 + debug("adding contacts for version " + this.version); 1.277 + var os = transaction.objectStore(STORE_NAME); 1.278 + 1.279 + this.data.GOOD.forEach(function(contact) { 1.280 + os.put(contact); 1.281 + }); 1.282 + this.data.BAD.forEach(function(contact) { 1.283 + os.put(contact); 1.284 + }); 1.285 + }, 1.286 + 1.287 + contactsCount: function() { 1.288 + return this.data.BAD.length + this.data.GOOD.length; 1.289 + } 1.290 +}; 1.291 + 1.292 +DataManager.delete = function() { 1.293 + debug("Deleting the database"); 1.294 + var deferred = Promise.defer(); 1.295 + 1.296 + /* forcibly close the db before deleting it */ 1.297 + ContactService._db.close(); 1.298 + 1.299 + var req = indexedDB.deleteDatabase(DB_NAME); 1.300 + req.onsuccess = function() { 1.301 + debug("Successfully deleted!"); 1.302 + deferred.resolve(); 1.303 + }; 1.304 + 1.305 + req.onerror = function() { 1.306 + debug("Not deleted, error is " + this.error.name); 1.307 + deferred.reject(this.error); 1.308 + }; 1.309 + 1.310 + req.onblocked = function() { 1.311 + debug("Waiting for the current users"); 1.312 + }; 1.313 + 1.314 + return deferred.promise; 1.315 +}; 1.316 + 1.317 +addMessageListener("createDB", function(version) { 1.318 + // Promises help handling gracefully exceptions 1.319 + Promise.resolve().then(function() { 1.320 + return new DataManager(version); 1.321 + }).then(function(manager) { 1.322 + return manager.open(); 1.323 + }).then(function onSuccess(count) { 1.324 + sendAsyncMessage("createDB.success", count); 1.325 + }, function onError(err) { 1.326 + sendAsyncMessage("createDB.error", "Failed to create the DB: " + 1.327 + "(" + err.name + ") " + err.message); 1.328 + }); 1.329 +}); 1.330 + 1.331 +addMessageListener("deleteDB", function() { 1.332 + Promise.resolve().then( 1.333 + DataManager.delete 1.334 + ).then(function onSuccess() { 1.335 + sendAsyncMessage("deleteDB.success"); 1.336 + }, function onError(err) { 1.337 + sendAsyncMessage("deleteDB.error", "Failed to delete the DB:" + err.name); 1.338 + }); 1.339 +});