sbTestHarness.js
Go to the documentation of this file.
1 
33 // alias some common referenced constants
34 const Ci = Components.interfaces;
35 const Cc = Components.classes;
36 const Cr = Components.results;
37 
38 // testharness constants
39 const SONGBIRD_TESTHARNESS_CONTRACTID = "@songbirdnest.com/Songbird/TestHarness;1";
40 const SONGBIRD_TESTHARNESS_CLASSNAME = "Songbird Unit Test Test-Harness";
41 const SONGBIRD_TESTHARNESS_CID = Components.ID("{fd541a71-0e71-48aa-9dd1-971df86d1e01}");
42 const SONGBIRD_TESTHARNESS_IID = Ci.sbITestHarness;
43 
44 const SONGBIRD_DEFAULT_DIR = "basetests";
45 const SONGBIRD_HEAD_FILE = "head_songbird.js";
46 const SONGBIRD_TAIL_FILE = "tail_songbird.js";
47 
48 const NS_PREFSERVICE_CONTRACTID = "@mozilla.org/preferences-service;1";
49 const NS_SCRIPT_TIMEOUT_PREF = "dom.max_chrome_script_run_time";
50 
51 const PREF_DOWNLOAD_FOLDER = "songbird.download.music.folder";
52 const PREF_DOWNLOAD_ALWAYSPROMPT = "songbird.download.music.alwaysPrompt";
53 
54 function sbTestHarness() { }
55 
56 sbTestHarness.prototype = {
57 
58  // list of directories to scan for test files
59  mTestComponents : null,
60 
61  // list of all tests that failed
62  mFailedTests: null,
63 
64  // number of tests that have been successfully completed
65  mTestCount: 0,
66 
67  // toplevel default files to always attempt to load
68  mHeadSongbird : null,
69  mTailSongbird : null,
70 
71  mOldScriptTimeout: -1,
72 
73  _disableScriptTimeout : function() {
74  var prefs = Cc[NS_PREFSERVICE_CONTRACTID].getService(Ci.nsIPrefBranch);
75 
76  mOldScriptTimeout = prefs.getIntPref(NS_SCRIPT_TIMEOUT_PREF);
77  prefs.setIntPref(NS_SCRIPT_TIMEOUT_PREF, 0);
78  },
79 
80  _enableScriptTimeout : function() {
81  if (mOldScriptTimeout > -1) {
82  var prefs = Cc[NS_PREFSERVICE_CONTRACTID].getService(Ci.nsIPrefBranch);
83  prefs.setIntPref(NS_SCRIPT_TIMEOUT_PREF, mOldScriptTimeout);
84  }
85  },
86 
87  _disableDatabaseLocaleCollation : function() {
88  var dbe = Cc["@songbirdnest.com/Songbird/DatabaseEngine;1"]
89  .getService(Ci.sbIDatabaseEngine)
90  dbe.localeCollationEnabled = false;
91  },
92 
93  _enableDatabaseLocaleCollation : function() {
94  var dbe = Cc["@songbirdnest.com/Songbird/DatabaseEngine;1"]
95  .getService(Ci.sbIDatabaseEngine)
96  dbe.localeCollationEnabled = true;
97  },
98 
99  mTempDownloadFolder: null,
100  mOldDownloadPath: "",
101  mOldDownloadPromptSetting: false,
102 
103  _setTempDownloadFolder: function() {
104  this.mTempDownloadFolder = Cc["@mozilla.org/file/directory_service;1"].
105  getService(Ci.nsIProperties).
106  get("TmpD", Ci.nsIFile);
107  this.mTempDownloadFolder.append("songbird_test_downloads");
108 
109  if (!(this.mTempDownloadFolder.exists() &&
110  this.mTempDownloadFolder.isDirectory())) {
111  this.mTempDownloadFolder.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
112  }
113 
114  var prefs = Cc[NS_PREFSERVICE_CONTRACTID].getService(Ci.nsIPrefBranch);
115  // Save old prefs
116  if (prefs.prefHasUserValue(PREF_DOWNLOAD_FOLDER)) {
117  this.mOldDownloadPath =
118  prefs.getComplexValue(PREF_DOWNLOAD_FOLDER, Ci.nsISupportsString).data;
119  }
120 
121  this.mOldDownloadPromptSetting = prefs.getBoolPref(PREF_DOWNLOAD_ALWAYSPROMPT);
122 
123  // Set new prefs
124  prefs.setBoolPref(PREF_DOWNLOAD_ALWAYSPROMPT, false);
125 
126  var str = Cc["@mozilla.org/supports-string;1"].
127  createInstance(Ci.nsISupportsString);
128  str.data = this.mTempDownloadFolder.path;
129  prefs.setComplexValue(PREF_DOWNLOAD_FOLDER, Ci.nsISupportsString, str);
130  },
131 
132  _unsetTempDownloadFolder: function() {
133  var prefs = Cc[NS_PREFSERVICE_CONTRACTID].getService(Ci.nsIPrefBranch);
134 
135  if (this.mOldDownloadPath) {
136  var str = Cc["@mozilla.org/supports-string;1"].
137  createInstance(Ci.nsISupportsString);
138  str.data = this.mOldDownloadPath;
139  prefs.setComplexValue(PREF_DOWNLOAD_FOLDER, Ci.nsISupportsString, str);
140  }
141  else {
142  prefs.clearUserPref(PREF_DOWNLOAD_FOLDER);
143  }
144 
145  if (this.mOldDownloadPromptSetting) {
146  prefs.setBoolPref(PREF_DOWNLOAD_ALWAYSPROMPT, this.mOldDownloadPromptSetting);
147  }
148 
149  if (this.mTempDownloadFolder && this.mTempDownloadFolder.exists()) {
150  this.mTempDownloadFolder.remove(true);
151  }
152  this.mTempDownloadFolder = null;
153  },
154 
155  // when using NO_EM_RESTART, on first run extension components do not get
156  // registered. Do that manually in the hopes of things working better
157  _registerExtensionComponents: function() {
158  // NO_EM_RESTART has been removed from the environment at this point, we
159  // can't check for it.
160 
161  var marker = Cc["@mozilla.org/file/directory_service;1"].
162  getService(Ci.nsIProperties).
163  get("ProfD", Components.interfaces.nsIFile);
164  marker.append(".autoreg"); // Mozilla component registration marker
165  if (!marker.exists()) {
166  // not first run, things have already registered
167  return;
168  }
169  // NOTE: we do _not_ remove the marker file, we let Mozilla deal with it
170 
171  var compReg = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
172 
173  var em = Cc["@mozilla.org/extensions/manager;1"]
174  .getService(Ci.nsIExtensionManager);
175  var appInfo = Cc["@mozilla.org/xre/runtime;1"]
176  .getService(Ci.nsIXULRuntime);
177 
178  var itemList = em.getItemList(Ci.nsIUpdateItem.TYPE_EXTENSION, {});
179  for each (var item in itemList) {
180  var installLocation = em.getInstallLocation(item.id);
181  var dir = installLocation.getItemLocation(item.id);
182  dir.append("components");
183  if (dir.exists()) {
184  compReg.autoRegister(dir);
185  }
186 
187  // also try to register in the platform-specific directory
188  dir = installLocation.getItemLocation(item.id);
189  dir.append("platform");
190  dir.append(appInfo.OS + "_" + appInfo.XPCOMABI);
191  dir.append("components");
192  if (dir.exists()) {
193  compReg.autoRegister(dir);
194  }
195  }
196  },
197 
198  init : function ( aTests ) {
199  this._registerExtensionComponents();
200 
201  // list of test components and possible test names to run.
202  // e.g. - testcomp:testname+testname,testcomp,testcomp:testname
203  if (aTests && aTests != "")
204  this.mTestComponents = aTests.split(",");
205 
206  // Get the root directory for the application
207  var dirService = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
208  var rootDir = dirService.get("resource:app" , Ci.nsIFile);
209 
210  // walk into the testharness dir
211  this.mTestDir = rootDir.clone().QueryInterface(Ci.nsILocalFile);
212  this.mTestDir.appendRelativePath("testharness");
213 
214  // set up files for the top level head and tail files
215  this.mHeadSongbird = this.mTestDir.clone().QueryInterface(Ci.nsILocalFile);
216  this.mHeadSongbird.append(SONGBIRD_DEFAULT_DIR);
217  this.mHeadSongbird.append(SONGBIRD_HEAD_FILE);
218 
219  this.mTailSongbird = this.mTestDir.clone().QueryInterface(Ci.nsILocalFile);
220  this.mTailSongbird.append(SONGBIRD_DEFAULT_DIR);
221  this.mTailSongbird.append(SONGBIRD_TAIL_FILE);
222 
223  this._disableDatabaseLocaleCollation();
224  this._disableScriptTimeout();
225  this._setTempDownloadFolder();
226  },
227 
228  run : function () {
229 
230  var consoleService = Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
231  var consoleListener = Cc["@songbirdnest.com/Songbird/TestHarness/ConsoleListener;1"].createInstance(Ci.nsIConsoleListener);
232  consoleService.registerListener(consoleListener);
233 
234  var ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
235  var jsLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader);
236 
237  var log = function (s) {
238  consoleService.logStringMessage(s);
239  }
240 
241  // If components were not specific populate the list with all of them.
242  if (!this.mTestComponents)
243  this.buildTestComponents();
244 
245  // loop over all the components and run the tests
246  for ( var index in this.mTestComponents ) {
247 
248  // create a file object pointing to each component dir in turn
249  var testDir = this.mTestDir.clone().QueryInterface(Ci.nsILocalFile);
250  var testCompTests = this.mTestComponents[index].split(":");
251  var testComp = testCompTests.shift();
252  testDir.append(testComp);
253 
254  if (testCompTests.length !=0) {
255  testCompTests = testCompTests[0].split("+");
256  }
257 
258  if ( !testDir.exists() || !testDir.isDirectory() )
259  continue;
260 
261  // put the test names into an array so we can sort them
262  var testNameArray = new Array();
263 
264  if ( testCompTests.length == 0 ) {
265  // if the user didn't specify the tests to be run, get them all
266 
267  // get an enumerator for the contents of the directory
268  let dirEnum = testDir.directoryEntries;
269 
270  while ( dirEnum.hasMoreElements() ) {
271  let testFile = dirEnum.getNext().QueryInterface(Ci.nsIFile);
272 
273  // skip over directories for now (our build system does not allow for
274  // creating hierarchical test directories
275  if (testFile.isDirectory())
276  continue;
277 
278  // check for test_*.js; the parans cause the string to get parsed into
279  // result as an array
280  var regex = /^test_(.+)\.js$/;
281  var result = testFile.leafName.match(regex);
282  if (!result)
283  continue;
284 
285  testNameArray.push(result[1]);
286  }
287 
288  // ensure all platforms do them in the same order
289  testNameArray.sort();
290  }
291  else {
292  // if the user did specify, run only them and in that order
293  testNameArray = testCompTests;
294  }
295 
296  // for each test_ file load it and the corresponding head & tail files
297  for ( let index = 0; index < testNameArray.length; index++ ) {
298  let testBase = testNameArray[index];
299 
300  // clone the nsIFile object so we can point to 3 files
301  var testFile = testDir.clone().QueryInterface(Ci.nsILocalFile);
302  var testHeadFile = testDir.clone().QueryInterface(Ci.nsILocalFile);
303  var compHeadFile = testDir.clone().QueryInterface(Ci.nsILocalFile);
304  var testTailFile = testDir.clone().QueryInterface(Ci.nsILocalFile);
305  var compTailFile = testDir.clone().QueryInterface(Ci.nsILocalFile);
306 
307  // append the file names
308  testFile.append("test_" + testBase + ".js");
309  testHeadFile.append("head_" + testBase + ".js");
310  compHeadFile.append("head_" + testComp + ".js");
311  testTailFile.append("tail_" + testBase + ".js");
312  compTailFile.append("tail_" + testComp + ".js");
313 
314  // script loader takes a nsIURI object
315  var scriptUri = null;
316 
317  // the scope to load the test into
318  var scope = { __proto__ : (function()this)(),
319  _test_name: "sbTestHarness",
320  _test_comp: "testharness"};
321  scope.wrappedJSObject = scope;
322 
323  // top level head file to always load
324  if (this.mHeadSongbird.exists()) {
325  scriptUri = ioService.newFileURI(this.mHeadSongbird);
326  jsLoader.loadSubScript( scriptUri.spec, scope );
327  }
328 
329  // load the component head script
330  if (compHeadFile.exists()) {
331  scriptUri = ioService.newFileURI(compHeadFile);
332  jsLoader.loadSubScript( scriptUri.spec, scope );
333  }
334 
335  // load the test head script
336  if (testHeadFile.exists()) {
337  scriptUri = ioService.newFileURI(testHeadFile);
338  jsLoader.loadSubScript( scriptUri.spec, scope );
339  }
340 
341  // _test_name defined in the head_songbird.js file and is used in tail_songbird.js
342  scope._test_name = testComp + " - " + testBase;
343 
344  // _test_comp defined in head_songbird.js
345  scope._test_comp = testComp;
346 
347  // load the test script
348  if (testFile.exists()) {
349  log("*** [" + scope._test_name + "] - Testing...");
350  scriptUri = ioService.newFileURI(testFile);
351  jsLoader.loadSubScript( scriptUri.spec, scope );
352  }
353 
354  // top level tail file to always load - calls run_test()
355  if (this.mTailSongbird.exists()) {
356  // load the cleanup script
357  scriptUri = ioService.newFileURI(this.mTailSongbird);
358  jsLoader.loadSubScript( scriptUri.spec, scope );
359  }
360 
361  // load the test tail script
362  if (testTailFile.exists()) {
363  // load the cleanup script
364  scriptUri = ioService.newFileURI(testTailFile);
365  jsLoader.loadSubScript( scriptUri.spec, scope );
366  }
367 
368  // load the component tail script
369  if (compTailFile.exists()) {
370  // load the cleanup script
371  scriptUri = ioService.newFileURI(compTailFile);
372  jsLoader.loadSubScript( scriptUri.spec, scope );
373  }
374 
375  this.mTestCount++;
376  scope = null;
377  Components.utils.forceGC();
378  }
379  }
380 
381  if ( this.mFailedTests ) {
382  log("\n\n");
383  log("[Test Harness] *** The following tests failed:");
384  for ( var index = 0; index < this.mFailedTests.length ; index++ )
385  log("[Test Harness] - " + this.mFailedTests[index]);
386  log("\n\n");
387  }
388  else if (this.mTestCount > 0) {
389  log("\n\n");
390  log("[Test Harness] *** ALL TESTS PASSED\n\n");
391  }
392  else {
393  log("\n\n");
394  log("[Test Harness] *** NO TESTS FOUND\n\n");
395  }
396 
397  consoleService.unregisterListener(consoleListener);
398  this._unsetTempDownloadFolder();
399  this._enableScriptTimeout();
400  this._enableDatabaseLocaleCollation();
401 
402  if (this.mFailedTests) {
403  throw Cr.NS_ERROR_ABORT;
404  }
405  },
406 
407  // called only if there are NO components passed in, builds a list
408  // of ALL subdirectories.
409  buildTestComponents : function() {
410  // iterate over all directories in testharness and add ALL directories
411  // found to the list of dirs to recurse through.
412  if (!this.mTestDir.exists()) {
413  // No test dir so no tests to run.
414  return;
415  }
416 
417  let dirEnum = this.mTestDir.directoryEntries;
418  this.mTestComponents = new Array();
419  while ( dirEnum.hasMoreElements() ) {
420  var entry = dirEnum.getNext().QueryInterface(Ci.nsIFile);
421  if (entry.isDirectory()) {
422  this.mTestComponents.push(entry.leafName);
423  }
424  }
425  this.mTestComponents.sort();
426  },
427 
428  logFailure: function (aComponentName) {
429  if (! this.mFailedTests)
430  this.mFailedTests = new Array();
431  this.mFailedTests.push(aComponentName);
432  },
433 
434  QueryInterface : function(iid) {
435  if (!iid.equals(SONGBIRD_TESTHARNESS_IID) &&
436  !iid.equals(Ci.nsISupports))
437  throw Cr.NS_ERROR_NO_INTERFACE;
438  return this;
439  }
440 }; // sbTestHarness
441 
448  registerSelf: function(compMgr, fileSpec, location, type) {
449  compMgr = compMgr.QueryInterface(Ci.nsIComponentRegistrar);
450  compMgr.registerFactoryLocation( SONGBIRD_TESTHARNESS_CID,
453  fileSpec,
454  location,
455  type );
456  },
457 
458  getClassObject: function(compMgr, cid, iid) {
459  if (!cid.equals(SONGBIRD_TESTHARNESS_CID))
460  throw Cr.NS_ERROR_NO_INTERFACE;
461 
462  if (!iid.equals(Ci.nsIFactory))
463  throw Cr.NS_ERROR_NOT_IMPLEMENTED;
464 
465  return this.mFactory;
466  },
467 
468  mFactory: {
469  createInstance : function (outer, iid) {
470  if (outer != null)
471  throw Cr.NS_ERROR_NO_AGGREGATION;
472  return (new sbTestHarness()).QueryInterface(iid);
473  }
474  },
475 
476  canUnload: function(compMgr) {
477  return true;
478  },
479 
480  QueryInterface : function (iid) {
481  if ( !iid.equals(Ci.nsIModule) &&
482  !iid.equals(Ci.nsISupports) )
483  throw Cr.NS_ERROR_NO_INTERFACE;
484 
485  return this;
486  }
487 
488 }; // sbTestHarnessModule
489 
490 function NSGetModule(compMgr, fileSpec) {
491  return sbTestHarnessModule;
492 } // NSGetModule
classDescription entry
Definition: FeedWriter.js:1427
function NSGetModule(compMgr, fileSpec)
const PREF_DOWNLOAD_ALWAYSPROMPT
const SONGBIRD_TESTHARNESS_CONTRACTID
SafebrowsingApplicationMod prototype registerSelf
var _test_comp
const NS_PREFSERVICE_CONTRACTID
const SONGBIRD_TAIL_FILE
function sbTestHarness()
function log(s)
var _test_name
var scope
sidebarFactory createInstance
Definition: nsSidebar.js:351
sbOSDControlService prototype QueryInterface
const Cr
var ioService
const sbTestHarnessModule
getService(Ci.sbIFaceplateManager)
const SONGBIRD_TESTHARNESS_IID
_window init
Definition: FeedWriter.js:1144
SafebrowsingApplicationMod prototype getClassObject
const Cc
return null
Definition: FeedWriter.js:1143
const SONGBIRD_HEAD_FILE
var prefs
Definition: FeedWriter.js:1169
const NS_SCRIPT_TIMEOUT_PREF
var consoleListener
if(DEBUG_DATAREMOTES)
const Ci
const PREF_DOWNLOAD_FOLDER
const SONGBIRD_TESTHARNESS_CLASSNAME
const SONGBIRD_TESTHARNESS_CID
const SONGBIRD_DEFAULT_DIR