From 5ba344516ef20ccfbdc7582ce5f2800ba98fb630 Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Sun, 31 May 2015 23:07:24 -0400 Subject: [PATCH] Update PDF tool handling in tests The test runner now downloads and caches the PDF tools for the current platform within the test data directory and only redownloads them when out of date, and it updates the download URL so that the full-text code pulls from the cache directory via a file:// URL. The installPDFTools() support function now installs the files directly instead of going through the prefs, and a new uninstallPDFTools() function removes the tools. Since the presence of the PDF tools can affect other tests, tests that need the tools should install them in a before() and uninstall them in an after(), leaving most tests to run without PDF indexing. This also adds a callback to the waitForWindow() support function. If a modal dialog is opened, it blocks the next promise handler from running, so a callback has to be used to interact with and close the dialog immediately. --- .../zotero/preferences/preferences_search.js | 16 +----- chrome/content/zotero/xpcom/fulltext.js | 50 ++++++++++++++++- resource/config.js | 3 +- test/content/runtests.js | 54 +++++++++++++++++-- test/content/support.js | 51 +++++++++--------- test/tests/fulltextTest.js | 30 +++-------- test/tests/preferences_searchTest.js | 23 ++++++++ 7 files changed, 158 insertions(+), 69 deletions(-) create mode 100644 test/tests/preferences_searchTest.js diff --git a/chrome/content/zotero/preferences/preferences_search.js b/chrome/content/zotero/preferences/preferences_search.js index 2bc54a4be..c995a5e07 100644 --- a/chrome/content/zotero/preferences/preferences_search.js +++ b/chrome/content/zotero/preferences/preferences_search.js @@ -162,21 +162,8 @@ Zotero_Preferences.Search = { * if a newer version is available */ checkPDFToolsDownloadVersion: Zotero.Promise.coroutine(function* () { - var url = Zotero.Fulltext.pdfToolsDownloadBaseURL + 'latest.json'; - - // Find latest version for this platform try { - var xmlhttp = yield Zotero.HTTP.request("GET", url, { successCodes: [200, 404] }); - - if (xmlhttp.status == 404) { - throw 404; - } - - var platform = Zotero.platform.replace(/\s/g, '-'); - var json = JSON.parse(xmlhttp.responseText); - var latestVersion = json[platform] || json['default']; - - Zotero.debug("Latest PDF tools version for " + platform + " is " + latestVersion); + var latestVersion = yield Zotero.Fulltext.getLatestPDFToolsVersion(); var converterIsRegistered = Zotero.Fulltext.pdfConverterIsRegistered(); var infoIsRegistered = Zotero.Fulltext.pdfInfoIsRegistered(); @@ -189,7 +176,6 @@ Zotero_Preferences.Search = { var infoVersionAvailable = !infoIsRegistered || Zotero.Fulltext.pdfInfoVersion != '3.02a'; var bothAvailable = converterVersionAvailable && infoVersionAvailable; - latestVersion = "3.02a"; } // Install if not installed, version unknown, outdated, or // Xpdf 3.02/3.04 (to upgrade to Poppler), diff --git a/chrome/content/zotero/xpcom/fulltext.js b/chrome/content/zotero/xpcom/fulltext.js index 84ee1c959..fab78f13b 100644 --- a/chrome/content/zotero/xpcom/fulltext.js +++ b/chrome/content/zotero/xpcom/fulltext.js @@ -30,7 +30,7 @@ Zotero.Fulltext = new function(){ this.pdfInfoIsRegistered = pdfInfoIsRegistered; this.isCachedMIMEType = isCachedMIMEType; - this.pdfToolsDownloadBaseURL = 'https://www.zotero.org/download/xpdf/'; + this.pdfToolsDownloadBaseURL = ZOTERO_CONFIG.PDF_TOOLS_URL; this.__defineGetter__("pdfToolsName", function() { return 'Xpdf'; }); this.__defineGetter__("pdfToolsURL", function() { return 'http://www.foolabs.com/xpdf/'; }); this.__defineGetter__("pdfConverterName", function() { return 'pdftotext'; }); @@ -129,6 +129,25 @@ Zotero.Fulltext = new function(){ } + this.getLatestPDFToolsVersion = Zotero.Promise.coroutine(function* () { + if (Zotero.isWin) { + return "3.02a"; + } + + // Find latest version for this platform + var url = Zotero.Fulltext.pdfToolsDownloadBaseURL + 'latest.json'; + var xmlhttp = yield Zotero.HTTP.request("GET", url, { responseType: "json" }); + var json = xmlhttp.response; + + var platform = Zotero.platform.replace(/\s/g, '-'); + var version = json[platform] || json['default']; + + Zotero.debug("Latest PDF tools version for " + platform + " is " + version); + + return version; + }); + + /* * Download and install latest PDF tool */ @@ -328,6 +347,35 @@ Zotero.Fulltext = new function(){ }); + /** + * Unregister and delete PDF tools + * + * Used only for tests + */ + this.uninstallPDFTools = Zotero.Promise.coroutine(function* () { + Zotero.debug("Uninstalling PDF tools"); + + var dataDir = Zotero.getZoteroDirectory().path; + yield Zotero.File.removeIfExists(OS.Path.join(dataDir, _pdfConverterFileName)); + yield Zotero.File.removeIfExists(OS.Path.join(dataDir, _pdfInfoFileName)); + if (_pdfConverter) { + yield Zotero.File.removeIfExists(_pdfConverter.path); + yield Zotero.File.removeIfExists(_pdfConverter.path + ".version"); + } + if (_pdfInfo) { + yield Zotero.File.removeIfExists(_pdfInfo.path); + yield Zotero.File.removeIfExists(_pdfInfo.path + ".version"); + } + if (_pdfConverterScript) yield Zotero.File.removeIfExists(_pdfConverterScript.path); + if (_pdfInfoScript) yield Zotero.File.removeIfExists(_pdfInfoScript.path); + + _pdfConverter = null; + _pdfInfo = null; + _pdfInfoScript = null; + _pdfInfoScript = null; + }); + + function pdfConverterIsRegistered() { return !!_pdfConverter; } diff --git a/resource/config.js b/resource/config.js index 15571ee94..e31d4a1b7 100644 --- a/resource/config.js +++ b/resource/config.js @@ -13,7 +13,8 @@ var ZOTERO_CONFIG = { PREF_BRANCH: 'extensions.zotero.', BOOKMARKLET_ORIGIN: 'https://www.zotero.org', HTTP_BOOKMARKLET_ORIGIN: 'http://www.zotero.org', - BOOKMARKLET_URL: 'https://www.zotero.org/bookmarklet/' + BOOKMARKLET_URL: 'https://www.zotero.org/bookmarklet/', + PDF_TOOLS_URL: "https://www.zotero.org/download/xpdf/" }; EXPORTED_SYMBOLS = ["ZOTERO_CONFIG"]; diff --git a/test/content/runtests.js b/test/content/runtests.js index fb337315b..7cdc0ac95 100644 --- a/test/content/runtests.js +++ b/test/content/runtests.js @@ -140,8 +140,56 @@ if(ZoteroUnit.tests) { if(run) { window.onload = function() { - Zotero.Schema.schemaUpdatePromise.then(function() { - mocha.run(); - }); + Zotero.spawn(function* () { + yield Zotero.Schema.schemaUpdatePromise; + + // Download and cache PDF tools for this platform + // + // To reset, delete test/tests/data/pdf/ directory + var cachePDFTools = Zotero.Promise.coroutine(function* () { + Components.utils.import("resource://zotero/config.js"); + var baseURL = ZOTERO_CONFIG.PDF_TOOLS_URL; + + var path = OS.Path.join(getTestDataDirectory().path, 'pdf'); + yield OS.File.makeDir(path, { ignoreExisting: true }); + + // Get latest tools version for the current platform + var latestPath = OS.Path.join(path, "latest.json"); + var xmlhttp = yield Zotero.HTTP.request("GET", baseURL + "latest.json"); + var json = xmlhttp.responseText; + yield Zotero.File.putContentsAsync(latestPath, json); + json = JSON.parse(json); + + var platform = Zotero.platform.replace(/\s/g, '-'); + var version = json[platform] || json['default']; + + // Create version directory (e.g., data/pdf/3.04) and download tools to it if + // they don't exist + yield OS.File.makeDir(OS.Path.join(path, version), { ignoreExisting: true }); + + var fileName = "pdfinfo-" + platform + (Zotero.isWin ? ".exe" : ""); + var execPath = OS.Path.join(path, version, fileName); + if (!(yield OS.File.exists(execPath))) { + yield Zotero.File.download(baseURL + version + "/" + fileName, execPath); + } + fileName = "pdftotext-" + platform; + execPath = OS.Path.join(path, version, fileName); + if (!(yield OS.File.exists(execPath))) { + yield Zotero.File.download(baseURL + version + "/" + fileName, execPath); + } + + // Point full-text code to the cache directory, so downloads come from there + Zotero.Fulltext.pdfToolsDownloadBaseURL = OS.Path.toFileURI(path) + "/"; + }); + + try { + yield cachePDFTools(); + } + catch (e) { + Zotero.logError(e); + } + + return mocha.run(); + }) }; } \ No newline at end of file diff --git a/test/content/support.js b/test/content/support.js index e66ba4cc5..33d3fbc23 100644 --- a/test/content/support.js +++ b/test/content/support.js @@ -55,17 +55,24 @@ var loadZoteroPane = Zotero.Promise.coroutine(function* () { }); /** - * Waits for a window with a specific URL to open. Returns a promise for the window. + * Waits for a window with a specific URL to open. Returns a promise for the window, and + * optionally passes the window to a callback immediately for use with modal dialogs, + * which prevent async code from continuing */ -function waitForWindow(uri) { +function waitForWindow(uri, callback) { var deferred = Zotero.Promise.defer(); Components.utils.import("resource://gre/modules/Services.jsm"); var loadobserver = function(ev) { ev.originalTarget.removeEventListener("load", loadobserver, false); - if(ev.target.location == uri) { + if(ev.target.location.href == uri) { Services.ww.unregisterNotification(winobserver); - deferred.resolve(ev.target.docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor). - getInterface(Components.interfaces.nsIDOMWindow)); + var win = ev.target.docShell + .QueryInterface(Components.interfaces.nsIInterfaceRequestor) + .getInterface(Components.interfaces.nsIDOMWindow); + if (callback) { + callback(win); + } + deferred.resolve(win); } }; var winobserver = {"observe":function(subject, topic, data) { @@ -190,31 +197,23 @@ function getPromiseError(promise) { /** * Ensures that the PDF tools are installed, or installs them if not. - * Returns a promise. + * + * @return {Promise} */ -function installPDFTools() { +var installPDFTools = Zotero.Promise.coroutine(function* () { if(Zotero.Fulltext.pdfConverterIsRegistered() && Zotero.Fulltext.pdfInfoIsRegistered()) { - return Zotero.Promise.resolve(true); + return; } + var version = yield Zotero.Fulltext.getLatestPDFToolsVersion(); + yield Zotero.Fulltext.downloadPDFTool('info', version); + yield Zotero.Fulltext.downloadPDFTool('converter', version); +}); - // Begin install procedure - return loadWindow("chrome://zotero/content/preferences/preferences.xul", { - pane: 'zotero-prefpane-search', - action: 'pdftools-install' - }).then(function(win) { - // Wait for confirmation dialog - return waitForWindow("chrome://global/content/commonDialog.xul").then(function(dlg) { - // Accept confirmation dialog - dlg.document.documentElement.acceptDialog(); - - // Wait for install to finish - return waitForCallback(function() { - return Zotero.Fulltext.pdfConverterIsRegistered() && Zotero.Fulltext.pdfInfoIsRegistered(); - }, 500, 30000).finally(function() { - win.close(); - }); - }); - }); +/** + * @return {Promise} + */ +function uninstallPDFTools() { + return Zotero.Fulltext.removePDFTools(); } /** diff --git a/test/tests/fulltextTest.js b/test/tests/fulltextTest.js index 23b231085..c220f636a 100644 --- a/test/tests/fulltextTest.js +++ b/test/tests/fulltextTest.js @@ -1,18 +1,9 @@ describe("Zotero.Fulltext", function () { describe("#downloadPDFTool()", function () { - var originalBaseURL; - before(function* () { - originalBaseURL = Zotero.Fulltext.pdfToolsDownloadBaseURL; - }) - after(function () { - Zotero.Fulltext.pdfToolsDownloadBaseURL = originalBaseURL; - }) - it("should install the PDF tools", function* () { var version = "3.04"; var dataDir = Zotero.getZoteroDirectory().path; var execFileName = Zotero.Fulltext.pdfInfoFileName; - var execContents = new Array(50001).join('a'); var execPath = OS.Path.join(dataDir, execFileName); var versionFileName = execFileName + '.version'; var versionPath = OS.Path.join(dataDir, versionFileName); @@ -21,6 +12,9 @@ describe("Zotero.Fulltext", function () { var scriptContents = yield Zotero.File.getContentsFromURLAsync( 'resource://zotero/redirect.' + scriptExt ); + var cacheExecPath = OS.Path.join( + getTestDataDirectory().path, "pdf", version, execFileName + ); // Delete existing files try { @@ -36,23 +30,12 @@ describe("Zotero.Fulltext", function () { } catch (e) {} - var tmpDir = Zotero.getTempDirectory(); - // Create temp version directory - var tmpVersionDir = OS.Path.join(tmpDir.path, version); - yield OS.File.makeDir(tmpVersionDir); - // Create dummy executable file to download - var tmpExecPath = OS.Path.join(tmpVersionDir, execFileName); - yield Zotero.File.putContentsAsync(tmpExecPath, execContents); - - // Override the download URL with a file URL for the temp directory - Zotero.Fulltext.pdfToolsDownloadBaseURL = OS.Path.toFileURI(tmpDir.path) + "/"; - yield Zotero.Fulltext.downloadPDFTool('info', version); assert.ok(Zotero.Fulltext.pdfInfoIsRegistered()); assert.equal( - (yield Zotero.File.getContentsAsync(execPath)), - execContents + (yield Zotero.File.getBinaryContentsAsync(cacheExecPath)), + (yield Zotero.File.getBinaryContentsAsync(execPath)) ); assert.equal((yield OS.File.stat(execPath)).unixMode, 0o755); assert.equal( @@ -65,7 +48,8 @@ describe("Zotero.Fulltext", function () { ); assert.equal((yield OS.File.stat(scriptPath)).unixMode, 0o755); - yield OS.File.removeDir(tmpVersionDir); + yield Zotero.Fulltext.uninstallPDFTools(); + assert.isFalse(Zotero.Fulltext.pdfInfoIsRegistered()); }) }) }) diff --git a/test/tests/preferences_searchTest.js b/test/tests/preferences_searchTest.js new file mode 100644 index 000000000..34e18ff41 --- /dev/null +++ b/test/tests/preferences_searchTest.js @@ -0,0 +1,23 @@ +describe("Search Preferences", function () { + describe("PDF Indexing", function () { + it("should install PDF tools if not installed", function* () { + // Begin install procedure + var win = yield loadWindow("chrome://zotero/content/preferences/preferences.xul", { + pane: 'zotero-prefpane-search', + action: 'pdftools-install' + }); + // Wait for confirmation dialog + yield waitForWindow("chrome://global/content/commonDialog.xul", function (dialog) { + // Accept confirmation dialog + dialog.document.documentElement.acceptDialog(); + }); + + // Wait for install to finish + yield waitForCallback(function() { + return Zotero.Fulltext.pdfConverterIsRegistered() + && Zotero.Fulltext.pdfInfoIsRegistered(); + }, 500) + .finally(() => win.close()); + }) + }) +})