diff --git a/CHANGELOG.md b/CHANGELOG.md index 3586340..cf70dba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +### 3.0 changes since 2.9 + + - NOTE: The 3.0 major version number upgrade of wchtools has a change in default behavior. + - The DEFAULT for pull, push, list and compare has been changed to only operate on "ready" items. + - wchtools is commonly used to package up ready applications, sample or otherwise, to be transferred to another WCH tenant (staging to production, or a business partner building an application for a client) and you would typically only want the final (non-draft) ready items to be pulled from the staging tenant and sent to production tenant(s). + - To obtain the prior (draft and ready, for content and assets) behavior, you may use the --draft and --ready command line arguments, to the push, pull, compare, and list commands. + ### 2.9.2 changes since 2.8.2 - New compare command for comparing source and target exports or source export with a target tenant, optionally writing a manifest of updates needed in the target, from the source, along with an optional manifest of items deleted from source that could then be deleted from the target with wchtools delete --manifest - New optional push --publish-now argument, to override a global publishing schedule, when you need to push and publish new web artifacts immediately, to address an issue. diff --git a/CLI/commands/compare.js b/CLI/commands/compare.js index 7d32500..ee73a67 100644 --- a/CLI/commands/compare.js +++ b/CLI/commands/compare.js @@ -832,6 +832,8 @@ function compareCommand (program) { .option('-R --publishing-site-revisions',i18n.__('cli_compare_opt_site_revisions')) .option('-v --verbose', i18n.__('cli_compare_opt_verbose')) .option('-A --all-authoring', i18n.__('cli_compare_opt_all')) + .option('--ready', i18n.__('cli_compare_opt_ready')) + .option('--draft', i18n.__('cli_compare_opt_draft')) .option('--manifest ', i18n.__('cli_compare_opt_use_manifest')) .option('--filter-deletions ', i18n.__('cli_compare_opt_filter_deletions')) .option('--write-manifest ', i18n.__('cli_compare_opt_write_manifest')) diff --git a/CLI/commands/list.js b/CLI/commands/list.js index 4915100..1201964 100644 --- a/CLI/commands/list.js +++ b/CLI/commands/list.js @@ -898,7 +898,7 @@ function listCommand (program) { .option('-A --all-authoring', i18n.__('cli_list_opt_all')) .option('--write-manifest ', i18n.__('cli_list_opt_write_manifest')) .option('--ready', i18n.__('cli_list_opt_ready')) - //.option('--draft', i18n.__('cli_list_opt_draft')) + .option('--draft', i18n.__('cli_list_opt_draft')) .option('--path ', i18n.__('cli_list_opt_path')) .option('--dir ', i18n.__('cli_list_opt_dir')) .option('--user ', i18n.__('cli_opt_user_name')) diff --git a/CLI/commands/pull.js b/CLI/commands/pull.js index 6f5f41b..529115e 100644 --- a/CLI/commands/pull.js +++ b/CLI/commands/pull.js @@ -1666,7 +1666,7 @@ function pullCommand (program) { .option('--write-manifest ',i18n.__('cli_pull_opt_write_manifest')) .option('--write-deletions-manifest ',i18n.__('cli_pull_opt_write_deletions_manifest')) .option('--ready', i18n.__('cli_pull_opt_ready')) - //.option('--draft', i18n.__('cli_pull_opt_draft')) + .option('--draft', i18n.__('cli_pull_opt_draft')) .option('--dir ', i18n.__('cli_pull_opt_dir')) .option('--user ', i18n.__('cli_opt_user_name')) .option('--password ', i18n.__('cli_opt_password')) diff --git a/CLI/commands/push.js b/CLI/commands/push.js index ac6239d..8704827 100644 --- a/CLI/commands/push.js +++ b/CLI/commands/push.js @@ -1071,12 +1071,11 @@ class PushCommand extends BaseCommand { deferred.reject(new Error(i18n.__('cli_push_name_and_ready'))); return deferred.promise; } -/* + if (this.getCommandLineOption("draft")) { deferred.reject(new Error(i18n.__('cli_push_name_and_draft'))); return deferred.promise; } -*/ } if (this.getOptionArtifactCount() !== 1) { @@ -1144,7 +1143,7 @@ function pushCommand (program) { .option('--publish-now', i18n.__('cli_push_opt_publish_now')) .option('--create-only', i18n.__('cli_push_opt_create_only')) .option('--ready', i18n.__('cli_push_opt_ready')) - //.option('--draft', i18n.__('cli_push_opt_draft')) + .option('--draft', i18n.__('cli_push_opt_draft')) .option('--named ', i18n.__('cli_push_opt_named')) .option('--path ', i18n.__('cli_push_opt_path')) .option('--manifest ', i18n.__('cli_push_opt_use_manifest')) diff --git a/CLI/lib/baseCommand.js b/CLI/lib/baseCommand.js index c20a025..fdd06c1 100644 --- a/CLI/lib/baseCommand.js +++ b/CLI/lib/baseCommand.js @@ -27,6 +27,8 @@ const log4js = require('log4js'); const ProductVersion = require("../package.json").version; const cliLog = "cli" + " " + ProductVersion; +const DRAFT_SITES = false; + class BaseCommand { /** * Create a BaseCommand object. @@ -63,6 +65,16 @@ class BaseCommand { this._cleanups = []; } + /** + * Determine whether draft sites (and pages) are supported. + * + * @returns {Boolean} A return value of true indicates that draft sites (and pages) are supported. A return value of + * false indicates that draft sites (and pages) are not supported. + */ + static get DRAFT_SITES() { + return DRAFT_SITES; + }; + /** * Get the Commander program object used by this command. * @@ -471,12 +483,6 @@ class BaseCommand { if (this.getCommandLineOption("renditions")) { this._optionArtifactCount++; } - if (this.getCommandLineOption("publishingSources")) { - this._optionArtifactCount++; - } - if (this.getCommandLineOption("publishingProfiles")) { - this._optionArtifactCount++; - } if (this.getCommandLineOption("publishingSiteRevisions")) { this._optionArtifactCount++; } @@ -802,32 +808,36 @@ class BaseCommand { */ handleReadyDraftOptions () { const deferred = Q.defer(); - const readyOnly = this.getCommandLineOption("ready"); - //const draftOnly = this.getCommandLineOption("draft"); + const ready = this.getCommandLineOption("ready"); + const draft = this.getCommandLineOption("draft"); const manifest = this.getCommandLineOption("manifest"); - if (readyOnly) { - /*if (draftOnly) { - // Cannot specify both the "ready" and "draft" options. - const errorMessage = i18n.__('cli_ready_and_draft_options'); - deferred.reject(new Error(errorMessage)); - } else*/ if (manifest) { + if (ready) { + if (manifest) { // Cannot specify both the "ready" and "manifest" options. const errorMessage = i18n.__('cli_ready_and_manifest_options'); deferred.reject(new Error(errorMessage)); } else { - this.setApiOption("filterReady", true); + if (!draft) { + // Ready was specified, draft was not. + this.setApiOption("filterReady", true); + } + + // Note: If both ready and draft were specified, no filtering is required. deferred.resolve(); } - } /*else if (draftOnly) { + } else if (draft) { if (manifest) { // Cannot specify both the "draft" and "manifest" options. const errorMessage = i18n.__('cli_draft_and_manifest_options'); deferred.reject(new Error(errorMessage)); } else { + // Draft was specified, ready was not. this.setApiOption("filterDraft", true); deferred.resolve(); } - }*/ else { + } else { + // If neither ready nor draft is specified, default to ready. + this.setApiOption("filterReady", true); deferred.resolve(); } @@ -857,11 +867,9 @@ class BaseCommand { deferred.resolve(); } else { // Determine what type of sites to use for this command -- draft, ready, or both. + // Note that draft sites must always be included for the delete --all command. const includeReadySites = this.getCommandLineOption("ready") || !this.getCommandLineOption("draft"); - const includeDraftSites = (this.getCommandLineOption("draft") || !this.getCommandLineOption("ready")) && this.getCommandLineOption("all"); - - // TODO Until the Sites API defects for push and pull of draft pages/sites are fixed, only allow the - // TODO draft site to be included for the delete --all command. + const includeDraftSites = (this.getCommandLineOption("draft") && BaseCommand.DRAFT_SITES) || this.getCommandLineOption("all"); // Get all sites, either local or remote. const getSites = remote ? ToolsApi.getRemoteSites : ToolsApi.getLocalSites; @@ -885,13 +893,13 @@ class BaseCommand { }); } else { // There are no local site artifacts, so just use the defaults. - //if (includeReadySites) { + if (includeReadySites) { readySiteIds.push("default"); - //} + } - //if (includeDraftSites) { - // draftSiteIds.push("default:draft"); - //} + if (includeDraftSites) { + draftSiteIds.push("default:draft"); + } // TODO Do we need a more robust solution when additional sites can be created? } diff --git a/CLI/nls/en.json b/CLI/nls/en.json index 3f69c6c..7ff00b5 100644 --- a/CLI/nls/en.json +++ b/CLI/nls/en.json @@ -12,7 +12,6 @@ "cli_save_manifest_failure": "An error occurred when trying to save the manifest: %(err)s.", "cli_invalid_url_option": "The specified API URL is not valid.", "cli_invalid_path_option": "Invalid options, path can only be used for web assets, content types, layouts, and layout mappings.", - "cli_ready_and_draft_options" : "Invalid options, cannot specifiy both ready and draft.", "cli_ready_and_manifest_options": "Invalid options, cannot specifiy both ready and manifest.", "cli_draft_and_manifest_options": "Invalid options, cannot specifiy both draft and manifest.", "cli_help_on_commands": "For help on specific commands use wchtools -h", @@ -336,7 +335,6 @@ "cli_rendering_job_started": "Starting render request.", "cli_rendering_job_created": "Render request was accepted.", "cli_rendering_opt_rebuild": "Delete content items from delivery and republish them. This implicitly triggers a re-rendering of all your content. A rebuild ignores global publish schedules and the auto publish flag.", - "cli_publishing_description": "Publish all ready artifacts that have not automatically been published.", "cli_publishing_opt_rebuild": "Delete all artifacts from delivery and republish them. A rebuild ignores global publish schedules and the auto publish flag.", "cli_publishing_opt_status": "Display the current state of the publishing site revision. Use of an optional id has been deprecated, and will be ignored if specified.", diff --git a/CLI/package.json b/CLI/package.json index 1a89301..e2f7216 100644 --- a/CLI/package.json +++ b/CLI/package.json @@ -1,7 +1,7 @@ { "name": "wchtools-cli", "description": "Command line tools for IBM Watson Content Hub", - "version": "2.9.2", + "version": "3.0.4", "keywords": [ "cli" ], diff --git a/CLI/test/unit/lib/list.unit.js b/CLI/test/unit/lib/list.unit.js index 9a44a72..1486176 100644 --- a/CLI/test/unit/lib/list.unit.js +++ b/CLI/test/unit/lib/list.unit.js @@ -23,9 +23,6 @@ const UnitTest = require("./base.cli.unit.js"); // Require the node modules used in this test file. const fs = require("fs"); -const path = require("path"); -const rimraf = require("rimraf"); -const diff = require("diff"); const prompt = require("prompt"); const Q = require("q"); const sinon = require("sinon"); @@ -33,14 +30,8 @@ const ToolsApi = require("wchtools-api"); const hashes = ToolsApi.getHashes(); const toolsCli = require("../../../wchToolsCli"); const BaseCommand = require("../../../lib/baseCommand"); -const mkdirp = require("mkdirp"); const manifests = ToolsApi.getManifests(); -const DRAFT_OPTION = false; - -// TODO When pulling draft sites is supported, the code excluded by this flag should be removed. -const DRAFT_SITES = false; - // Require the local modules that will be stubbed, mocked, and spied. const options = require("wchtools-api").getOptions(); @@ -177,15 +168,9 @@ class ListUnitTest extends UnitTest { let error; toolsCli.parseArgs(['', UnitTest.COMMAND, "list", switches, "--dir", "./", "-q", "--user", "foo", "--password", "password", "--url", "http://foo.bar/api"]) .then(function (msg) { - if (DRAFT_SITES && switches === "--pages") { - // Verify that the stub was called twice (once for each site), and the expected message was returned. - expect(stub).to.have.been.calledTwice; - expect(msg).to.contain('artifacts listed 6'); - } else { - // Verify that the stub was called once, and the expected message was returned. - expect(stub).to.have.been.calledOnce; - expect(msg).to.contain('artifacts listed 3'); - } + // Verify that the stub was called once, and the expected message was returned. + expect(stub).to.have.been.calledOnce; + expect(msg).to.contain('artifacts listed 3'); }) .catch(function (err) { // Pass the error to the "done" function to indicate a failed test. @@ -218,15 +203,9 @@ class ListUnitTest extends UnitTest { let error; toolsCli.parseArgs(['', UnitTest.COMMAND, "list", switches, "--url", "http://foo.bar/api"]) .then(function (msg) { - if (DRAFT_SITES && switches === "--pages") { - // Verify that the stub was called twice (once for each site), and the expected message was returned. - expect(stubList).to.have.been.calledTwice; - expect(msg).to.contain('artifacts listed 6'); - } else { - // Verify that the stub was called once, and the expected message was returned. - expect(stubList).to.have.been.calledOnce; - expect(msg).to.contain('artifacts listed 3'); - } + // Verify that the stub was called once, and the expected message was returned. + expect(stubList).to.have.been.calledOnce; + expect(msg).to.contain('artifacts listed 3'); }) .catch(function (err) { // Pass the error to the "done" function to indicate a failed test. @@ -392,13 +371,8 @@ class ListUnitTest extends UnitTest { let error; toolsCli.parseArgs(['', UnitTest.COMMAND, "list", switches, "--server", "--del", "--url", "http://foo.bar/api"]) .then(function (msg) { - if (DRAFT_SITES && switches === "--pages") { - // Verify that the stub was called twice (once for each site), and the expected message was returned. - expect(stubList).to.have.been.calledTwice; - } else { - // Verify that the stub was called once, and the expected message was returned. - expect(stubList).to.have.been.calledOnce; - } + // Verify that the stub was called once, and the expected message was returned. + expect(stubList).to.have.been.calledOnce; expect(msg).to.contain('artifacts listed 0'); }) .catch(function (err) { @@ -442,13 +416,8 @@ class ListUnitTest extends UnitTest { let error; toolsCli.parseArgs(['', UnitTest.COMMAND, "list", switches, "--quiet", "--server", "--url", "http://foo.bar/api"]) .then(function (msg) { - if (DRAFT_SITES && switches === "--pages") { - // Verify that the stub was called twice (once for each site), and the expected message was returned. - expect(stubList).to.have.been.calledTwice; - } else { - // Verify that the stub was called once, and the expected message was returned. - expect(stubList).to.have.been.calledOnce; - } + // Verify that the stub was called once, and the expected message was returned. + expect(stubList).to.have.been.calledOnce; expect(msg).to.contain('artifacts listed 0'); }) .catch(function (err) { @@ -488,15 +457,9 @@ class ListUnitTest extends UnitTest { let error; toolsCli.parseArgs(['', UnitTest.COMMAND, "list", switches, "--server", "-q", "--url", "http://foo.bar/api"]) .then(function (msg) { - if (DRAFT_SITES && switches === "--pages") { - // Verify that the stub was called twice (once for each site), and the expected message was returned. - expect(stubList).to.have.been.calledTwice; - expect(msg).to.contain('artifacts listed 6'); - } else { - // Verify that the stub was called once, and the expected message was returned. - expect(stubList).to.have.been.calledOnce; - expect(msg).to.contain('artifacts listed 3'); - } + // Verify that the stub was called once, and the expected message was returned. + expect(stubList).to.have.been.calledOnce; + expect(msg).to.contain('artifacts listed 3'); }) .catch(function (err) { // Pass the error to the "done" function to indicate a failed test. @@ -541,15 +504,9 @@ class ListUnitTest extends UnitTest { let error; toolsCli.parseArgs(['', UnitTest.COMMAND, "list", switches, "--server", "-q", "--write-manifest", "foo", "--url", "http://foo.bar/api"]) .then(function (msg) { - if (DRAFT_SITES && switches === "--pages") { - // Verify that the list stub was called twice (once for each site), and that the expected message was returned. - expect(stubList).to.have.been.calledTwice; - expect(msg).to.contain('artifacts listed 6'); - } else { - // Verify that the list stub was called once, and the expected message was returned. - expect(stubList).to.have.been.calledOnce; - expect(msg).to.contain('artifacts listed 3'); - } + // Verify that the list stub was called once, and the expected message was returned. + expect(stubList).to.have.been.calledOnce; + expect(msg).to.contain('artifacts listed 3'); // Verify that the manifest was only saved once, after all lists are completed. expect(stubSave).to.have.been.calledOnce; @@ -597,15 +554,10 @@ class ListUnitTest extends UnitTest { let error; toolsCli.parseArgs(['', UnitTest.COMMAND, "list", switches, "--server", "-q", "--url", "http://foo.bar/api"]) .then(function (msg) { - if (DRAFT_SITES && switches === "--pages") { - // Verify that the stub was called twice (once for each site), and the expected message was returned. - expect(stubList).to.have.been.calledTwice; - expect(msg).to.contain('artifacts listed 6'); - } else { - // Verify that the stub was called once, and the expected message was returned. - expect(stubList).to.have.been.calledOnce; - expect(msg).to.contain('artifacts listed 3'); - } + // Verify that the stub was called once, and the expected message was returned. + expect(stubList).to.have.been.calledOnce; + expect(msg).to.contain('artifacts listed 3'); + expect(stubPrompt).to.have.been.calledOnce; }) .catch(function (err) { @@ -650,15 +602,10 @@ class ListUnitTest extends UnitTest { let error; toolsCli.parseArgs(['', UnitTest.COMMAND, "list", switches, "--server", "-q", "--url", "http://foo.bar/api"]) .then(function (msg) { - if (DRAFT_SITES && switches === "--pages") { - // Verify that the stub was called twice (once for each site), and the expected message was returned. - expect(stubList).to.have.been.calledTwice; - expect(msg).to.contain('artifacts listed 6'); - } else { - // Verify that the stub was called once, and the expected message was returned. - expect(stubList).to.have.been.calledOnce; - expect(msg).to.contain('artifacts listed 3'); - } + // Verify that the stub was called once, and the expected message was returned. + expect(stubList).to.have.been.calledOnce; + expect(msg).to.contain('artifacts listed 3'); + expect(stubPrompt).to.have.been.calledOnce; }) .catch(function (err) { @@ -703,15 +650,10 @@ class ListUnitTest extends UnitTest { let error; toolsCli.parseArgs(['', UnitTest.COMMAND, "list", switches, "--server", "-q", "--url", "http://foo.bar/api"]) .then(function (msg) { - if (DRAFT_SITES && switches === "--pages") { - // Verify that the stub was called twice (once for each site), and the expected message was returned. - expect(stubList).to.have.been.calledTwice; - expect(msg).to.contain('artifacts listed 6'); - } else { - // Verify that the stub was called once, and the expected message was returned. - expect(stubList).to.have.been.calledOnce; - expect(msg).to.contain('artifacts listed 3'); - } + // Verify that the stub was called once, and the expected message was returned. + expect(stubList).to.have.been.calledOnce; + expect(msg).to.contain('artifacts listed 3'); + expect(stubPrompt).to.have.been.calledOnce; }) .catch(function (err) { @@ -760,15 +702,10 @@ class ListUnitTest extends UnitTest { let error; toolsCli.parseArgs(['', UnitTest.COMMAND, "list", switches, "--server", "-q", "--url", "http://foo.bar/api"]) .then(function (msg) { - if (DRAFT_SITES && switches === "--pages") { - // Verify that the stub was called twice (once for each site), and the expected message was returned. - expect(stubList).to.have.been.calledTwice; - expect(msg).to.contain('artifacts listed 6'); - } else { - // Verify that the stub was called once, and the expected message was returned. - expect(stubList).to.have.been.calledOnce; - expect(msg).to.contain('artifacts listed 3'); - } + // Verify that the stub was called once, and the expected message was returned. + expect(stubList).to.have.been.calledOnce; + expect(msg).to.contain('artifacts listed 3'); + expect(stubPrompt).to.have.been.calledOnce; expect(spyConsole).to.have.been.calledOnce; }) @@ -793,9 +730,14 @@ class ListUnitTest extends UnitTest { testListModified (helper, switches, itemName1, itemName2, badItem) { describe("CLI-unit-listing", function () { - it("test list local modified working (all sites)", function (done) { + it("test list local modified working (ready items only, by default)", function (done) { const stubList = sinon.stub(helper._fsApi, "listNames"); - stubList.resolves([{name: itemName1, id: "foo", path: itemName1}, {name: itemName2, id: "bar", path: itemName2}, {name: badItem, id: "ack", path: badItem}]); + stubList.resolves([{name: itemName1, id: "foo", path: itemName1, status: "ready"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "draft" + }, {name: badItem, id: "ack", path: badItem, status: "ready"}]); const stubHashes = sinon.stub(hashes, "isLocalModified"); stubHashes.returns(true); @@ -804,23 +746,60 @@ class ListUnitTest extends UnitTest { let error; toolsCli.parseArgs(['', UnitTest.COMMAND, "list", switches, "--mod", "--user", "foo", "--password", "password", "--url", "http://foo.bar/api"]) .then(function (msg) { - if (DRAFT_SITES && switches === "--pages") { - // Verify that the stub was called twice (once for each site), and the expected message was returned. + // Verify that the stubs were called as expected, and the expected message was returned. + expect(stubList).to.have.been.calledOnce; + if (switches.includes("--sites")) { + // Sites filtered to those in context.siteList. + expect(msg).to.contain('artifacts listed 1'); + } else { + expect(msg).to.contain('artifacts listed 2'); + } + }) + .catch(function (err) { + // Pass the error to the "done" function to indicate a failed test. + error = err; + }) + .finally(function () { + // Restore the stubs. + stubList.restore(); + stubHashes.restore(); + + // Call mocha's done function to indicate that the test is over. + done(error); + }); + }); + + it("test list local modified working (all items)", function (done) { + if (!BaseCommand.DRAFT_SITES && (switches.includes("--sites") || switches.includes("--pages"))) { + return done(); + } + + const stubList = sinon.stub(helper._fsApi, "listNames"); + stubList.resolves([{name: itemName1, id: "foo", path: itemName1, status: "ready"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "draft" + }, {name: badItem, id: "ack", path: badItem, status: "ready"}]); + + const stubHashes = sinon.stub(hashes, "isLocalModified"); + stubHashes.returns(true); + + // Execute the command to list the items to the download directory. + let error; + toolsCli.parseArgs(['', UnitTest.COMMAND, "list", switches, "--ready", "--draft", "--mod", "--user", "foo", "--password", "password", "--url", "http://foo.bar/api"]) + .then(function (msg) { + // Verify that the stubs were called as expected, and the expected message was returned. + if (switches.includes("--sites")) { + // Sites filtered to those in context.siteList. + expect(stubList).to.have.been.calledOnce; + expect(msg).to.contain('artifacts listed 2'); + } else if (switches.includes("--pages")) { expect(stubList).to.have.been.calledTwice; expect(msg).to.contain('artifacts listed 6'); } else { - // Verify that the stubs were called as expected, and the expected message was returned. expect(stubList).to.have.been.calledOnce; - if (switches.includes("--sites")) { - // Sites filtered to those in context.siteList. - if (DRAFT_SITES) { - expect(msg).to.contain('artifacts listed 2'); - } else { - expect(msg).to.contain('artifacts listed 1'); - } - } else { - expect(msg).to.contain('artifacts listed 3'); - } + expect(msg).to.contain('artifacts listed 3'); } }) .catch(function (err) { @@ -837,9 +816,14 @@ class ListUnitTest extends UnitTest { }); }); - it("test list local modified working (ready sites)", function (done) { + it("test list local modified working (ready items)", function (done) { const stubList = sinon.stub(helper._fsApi, "listNames"); - stubList.resolves([{name: itemName1, id: "foo", path: itemName1}, {name: itemName2, id: "bar", path: itemName2}, {name: badItem, id: "ack", path: badItem}]); + stubList.resolves([{name: itemName1, id: "foo", path: itemName1, status: "ready"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "ready" + }, {name: badItem, id: "ack", path: badItem, status: "draft"}]); const stubHashes = sinon.stub(hashes, "isLocalModified"); stubHashes.returns(true); @@ -854,7 +838,7 @@ class ListUnitTest extends UnitTest { // Sites filtered to those in context.siteList. expect(msg).to.contain('artifacts listed 1'); } else { - expect(msg).to.contain('artifacts listed 3'); + expect(msg).to.contain('artifacts listed 2'); } }) .catch(function (err) { @@ -871,14 +855,27 @@ class ListUnitTest extends UnitTest { }); }); - it("test list local modified working (draft sites)", function (done) { - // TODO Enable when --draft option is avaiable. - if (!DRAFT_OPTION) { + it("test list local modified working (draft items)", function (done) { + if (!BaseCommand.DRAFT_SITES && (switches.includes("--sites") || switches.includes("--pages"))) { return done(); } const stubList = sinon.stub(helper._fsApi, "listNames"); - stubList.resolves([{name: itemName1, id: "foo", path: itemName1}, {name: itemName2, id: "bar", path: itemName2}, {name: badItem, id: "ack", path: badItem}]); + if (switches.includes("--sites")) { + stubList.resolves([{name: itemName1, id: "foo", path: itemName1, status: "ready"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "draft" + }]); + } else { + stubList.resolves([{name: itemName1, id: "foo", path: itemName1, status: "draft"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "ready" + }, {name: badItem, id: "ack", path: badItem, status: "draft"}]); + } const stubHashes = sinon.stub(hashes, "isLocalModified"); stubHashes.returns(true); @@ -893,7 +890,7 @@ class ListUnitTest extends UnitTest { // Sites filtered to those in context.siteList. expect(msg).to.contain('artifacts listed 1'); } else { - expect(msg).to.contain('artifacts listed 3'); + expect(msg).to.contain('artifacts listed 2'); } }) .catch(function (err) { @@ -910,9 +907,14 @@ class ListUnitTest extends UnitTest { }); }); - it("test list remote modified working (all sites)", function (done) { + it("test list remote modified working (ready items only, by default)", function (done) { const stubList = sinon.stub(helper._restApi, "getModifiedItems"); - stubList.resolves([{name: itemName1, id: "foo", path: itemName1}, {name: itemName2, id: "bar", path: itemName2}, {name: badItem, id: undefined, path: badItem}]); + stubList.resolves([{name: itemName1, id: "foo", path: itemName1, status: "ready"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "draft" + }, {name: badItem, id: undefined, path: badItem, status: "ready"}]); const stubHashes = sinon.stub(hashes, "isRemoteModified"); stubHashes.returns(true); @@ -930,24 +932,74 @@ class ListUnitTest extends UnitTest { let error; toolsCli.parseArgs(['', UnitTest.COMMAND, "list", switches, "--server", "--mod", "--user", "foo", "--password", "password", "--url", "http://foo.bar/api"]) .then(function (msg) { - if (DRAFT_SITES && switches === "--pages") { - // Verify that the stub was called twice (once for each site), and the expected message was returned. + // Verify that the stubs were called as expected, and the expected message was returned. + expect(stubList).to.have.been.calledOnce; + if (switches.includes("--sites")) { + // Sites filtered to those in context.siteList. + expect(msg).to.contain('artifacts listed 1'); + expect(stubHashes).to.have.been.calledThrice; + } else { + expect(msg).to.contain('artifacts listed 2'); + } + }) + .catch(function (err) { + // Pass the error to the "done" function to indicate a failed test. + error = err; + }) + .finally(function () { + // Restore the stubs. + stubList.restore(); + stubHashes.restore(); + if (stubContentResource) { + stubContentResource.restore(); + } + + // Call mocha's done function to indicate that the test is over. + done(error); + }); + }); + + it("test list remote modified working (all items)", function (done) { + if (!BaseCommand.DRAFT_SITES && (switches.includes("--sites") || switches.includes("--pages"))) { + return done(); + } + + const stubList = sinon.stub(helper._restApi, "getModifiedItems"); + stubList.resolves([{name: itemName1, id: "foo", path: itemName1, status: "ready"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "ready" + }, {name: badItem, id: undefined, path: badItem, status: "draft"}]); + + const stubHashes = sinon.stub(hashes, "isRemoteModified"); + stubHashes.returns(true); + + let stubContentResource; + if (switches.includes("-a")) { + stubContentResource = sinon.stub(helper._fsApi, "isContentResource"); + stubContentResource.returns(true); + } else if (switches.includes("-w")) { + stubContentResource = sinon.stub(helper._fsApi, "isContentResource"); + stubContentResource.returns(false); + } + + // Execute the command to list the items to the download directory. + let error; + toolsCli.parseArgs(['', UnitTest.COMMAND, "list", switches, "--server", "--ready", "--draft", "--mod", "--user", "foo", "--password", "password", "--url", "http://foo.bar/api"]) + .then(function (msg) { + // Verify that the stubs were called as expected, and the expected message was returned. + if (switches.includes("--sites")) { + // Sites filtered to those in context.siteList. + expect(stubList).to.have.been.calledOnce; + expect(msg).to.contain('artifacts listed 2'); + expect(stubHashes).to.have.been.calledThrice; + } else if (switches.includes("--pages")) { expect(stubList).to.have.been.calledTwice; expect(msg).to.contain('artifacts listed 6'); } else { - // Verify that the stubs were called as expected, and the expected message was returned. expect(stubList).to.have.been.calledOnce; - if (switches.includes("--sites")) { - // Sites filtered to those in context.siteList. - if (DRAFT_SITES) { - expect(msg).to.contain('artifacts listed 2'); - } else { - expect(msg).to.contain('artifacts listed 1'); - } - expect(stubHashes).to.have.been.calledThrice; - } else { - expect(msg).to.contain('artifacts listed 3'); - } + expect(msg).to.contain('artifacts listed 3'); } }) .catch(function (err) { @@ -967,9 +1019,14 @@ class ListUnitTest extends UnitTest { }); }); - it("test list remote modified working (ready sites)", function (done) { + it("test list remote modified working (ready items)", function (done) { const stubList = sinon.stub(helper._restApi, "getModifiedItems"); - stubList.resolves([{name: itemName1, id: "foo", path: itemName1}, {name: itemName2, id: "bar", path: itemName2}, {name: badItem, id: undefined, path: badItem}]); + stubList.resolves([{name: itemName1, id: "foo", path: itemName1, status: "ready"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "draft" + }, {name: badItem, id: undefined, path: badItem, status: "ready"}]); const stubHashes = sinon.stub(hashes, "isRemoteModified"); stubHashes.returns(true); @@ -994,7 +1051,7 @@ class ListUnitTest extends UnitTest { expect(stubHashes).to.have.been.calledThrice; expect(msg).to.contain('artifacts listed 1'); } else { - expect(msg).to.contain('artifacts listed 3'); + expect(msg).to.contain('artifacts listed 2'); } }) .catch(function (err) { @@ -1014,14 +1071,27 @@ class ListUnitTest extends UnitTest { }); }); - it("test list remote modified working (draft sites)", function (done) { - // TODO Enable when --draft option is avaiable. - if (!DRAFT_OPTION) { + it("test list remote modified working (draft items)", function (done) { + if (!BaseCommand.DRAFT_SITES && (switches.includes("--sites") || switches.includes("--pages"))) { return done(); } const stubList = sinon.stub(helper._restApi, "getModifiedItems"); - stubList.resolves([{name: itemName1, id: "foo", path: itemName1}, {name: itemName2, id: "bar", path: itemName2}, {name: badItem, id: undefined, path: badItem}]); + if (switches.includes("--sites")) { + stubList.resolves([{name: itemName1, id: "foo", path: itemName1, status: "ready"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "draft" + }]); + } else { + stubList.resolves([{name: itemName1, id: "foo", path: itemName1, status: "draft"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "ready" + }, {name: badItem, id: "ack", path: badItem, status: "draft"}]); + } const stubHashes = sinon.stub(hashes, "isRemoteModified"); stubHashes.returns(true); @@ -1043,10 +1113,10 @@ class ListUnitTest extends UnitTest { expect(stubList).to.have.been.calledOnce; if (switches.includes("--sites")) { // Sites filtered to those in context.siteList. - expect(stubHashes).to.have.been.calledThrice; + expect(stubHashes).to.have.been.calledTwice; expect(msg).to.contain('artifacts listed 1'); } else { - expect(msg).to.contain('artifacts listed 3'); + expect(msg).to.contain('artifacts listed 2'); } }) .catch(function (err) { @@ -1070,31 +1140,70 @@ class ListUnitTest extends UnitTest { testListAll (helper, switches, itemName1, itemName2, badItem) { describe("CLI-unit-listing", function() { - it("test list local working (all sites)", function (done) { + it("test list local working (ready items only, by default)", function (done) { const stub = sinon.stub(helper._fsApi, "listNames"); - stub.resolves([{name: itemName1, id: "foo", path: itemName1}, {name: itemName2, id: "bar", path: itemName2}, {name: badItem, id: undefined, path: badItem}]); + stub.resolves([{name: itemName1, id: "foo", path: itemName1, status: "ready"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "ready" + }, {name: badItem, id: undefined, path: badItem, status: "draft"}]); // Execute the command to list the items to the download directory. let error; toolsCli.parseArgs(['', UnitTest.COMMAND, "list", switches, "--ignore-timestamps", "-q", "--user", "foo", "--password", "password", "--url", "http://foo.bar/api"]) .then(function (msg) { - if (DRAFT_SITES && switches === "--pages") { - // Verify that the stub was called twice (once for each site), and the expected message was returned. + // Verify that the stub was called once, and that the expected message was returned. + expect(stub).to.have.been.calledOnce; + if (switches.includes("--sites")) { + // Sites filtered to those in context.siteList. + expect(msg).to.contain('artifacts listed 1'); + } else { + expect(msg).to.contain('artifacts listed 2'); + } + }) + .catch(function (err) { + // Pass the error to the "done" function to indicate a failed test. + error = err; + }) + .finally(function () { + // Restore the helper's "listLocalItemNames" method. + stub.restore(); + + // Call mocha's done function to indicate that the test is over. + done(error); + }); + }); + + it("test list local working (all items)", function (done) { + if (!BaseCommand.DRAFT_SITES && (switches.includes("--sites") || switches.includes("--pages"))) { + return done(); + } + + const stub = sinon.stub(helper._fsApi, "listNames"); + stub.resolves([{name: itemName1, id: "foo", path: itemName1, status: "ready"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "draft" + }, {name: badItem, id: undefined, path: badItem, status: "ready"}]); + + // Execute the command to list the items to the download directory. + let error; + toolsCli.parseArgs(['', UnitTest.COMMAND, "list", switches, "--ignore-timestamps", "--ready", "--draft", "-q", "--user", "foo", "--password", "password", "--url", "http://foo.bar/api"]) + .then(function (msg) { + // Verify that the stub was called once, and that the expected message was returned. + if (switches.includes("--sites")) { + // Sites filtered to those in context.siteList. + expect(stub).to.have.been.calledOnce; + expect(msg).to.contain('artifacts listed 2'); + } else if (switches.includes("--pages")) { + // Sites filtered to those in context.siteList. expect(stub).to.have.been.calledTwice; expect(msg).to.contain('artifacts listed 6'); } else { - // Verify that the stub was called once, and that the expected message was returned. expect(stub).to.have.been.calledOnce; - if (switches.includes("--sites")) { - // Sites filtered to those in context.siteList. - if (DRAFT_SITES) { - expect(msg).to.contain('artifacts listed 2'); - } else { - expect(msg).to.contain('artifacts listed 1'); - } - } else { - expect(msg).to.contain('artifacts listed 3'); - } + expect(msg).to.contain('artifacts listed 3'); } }) .catch(function (err) { @@ -1110,9 +1219,14 @@ class ListUnitTest extends UnitTest { }); }); - it("test list local working (ready sites)", function (done) { + it("test list local working (ready items)", function (done) { const stub = sinon.stub(helper._fsApi, "listNames"); - stub.resolves([{name: itemName1, id: "foo", path: itemName1}, {name: itemName2, id: "bar", path: itemName2}, {name: badItem, id: undefined, path: badItem}]); + stub.resolves([{name: itemName1, id: "foo", path: itemName1, status: "ready"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "draft" + }, {name: badItem, id: undefined, path: badItem, status: "ready"}]); // Execute the command to list the items to the download directory. let error; @@ -1124,7 +1238,7 @@ class ListUnitTest extends UnitTest { // Sites filtered to those in context.siteList. expect(msg).to.contain('artifacts listed 1'); } else { - expect(msg).to.contain('artifacts listed 3'); + expect(msg).to.contain('artifacts listed 2'); } }) .catch(function (err) { @@ -1140,14 +1254,27 @@ class ListUnitTest extends UnitTest { }); }); - it("test list local working (draft sites)", function (done) { - // TODO Enable when --draft option is avaiable. - if (!DRAFT_OPTION) { + it("test list local working (draft items)", function (done) { + if (!BaseCommand.DRAFT_SITES && (switches.includes("--sites") || switches.includes("--pages"))) { return done(); } const stub = sinon.stub(helper._fsApi, "listNames"); - stub.resolves([{name: itemName1, id: "foo", path: itemName1}, {name: itemName2, id: "bar", path: itemName2}, {name: badItem, id: undefined, path: badItem}]); + if (switches.includes("--sites")) { + stub.resolves([{name: itemName1, id: "foo", path: itemName1, status: "ready"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "draft" + }]); + } else { + stub.resolves([{name: itemName1, id: "foo", path: itemName1, status: "ready"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "draft" + }, {name: badItem, id: undefined, path: badItem, status: "draft"}]); + } // Execute the command to list the items to the download directory. let error; @@ -1159,7 +1286,7 @@ class ListUnitTest extends UnitTest { // Sites filtered to those in context.siteList. expect(msg).to.contain('artifacts listed 1'); } else { - expect(msg).to.contain('artifacts listed 3'); + expect(msg).to.contain('artifacts listed 2'); } }) .catch(function (err) { @@ -1204,18 +1331,23 @@ class ListUnitTest extends UnitTest { }); }); - it("test list remote working (all sites)", function (done) { + it("test list remote working (ready items only, by default)", function (done) { let stubGet; if (switches === "--sites") { // Remove the global stub and create a local SitesREST.getItems stub that returns the standard sites - // the first time (initSites) then returns the test values the second time (the actual push). + // the first time (initSites) then returns the test values the second time (the actual list). ListUnitTest.restoreRemoteSitesStub(); stubGet = sinon.stub(helper._restApi, "getItems"); stubGet.onFirstCall().resolves([{id: "foo", siteStatus: "ready"}, {id: "bar", siteStatus: "draft"}]); stubGet.onSecondCall().resolves([{name: itemName1, id: "foo", path: itemName1}, {name: itemName2, id: "bar", path: itemName2}, {name: badItem, id: "ack", path: badItem}]); } else { stubGet = sinon.stub(helper._restApi, "getItems"); - stubGet.resolves([{name: itemName1, id: "foo", path: itemName1}, {name: itemName2, id: "bar", path: itemName2}, {name: badItem, id: "ack", path: badItem}]); + stubGet.resolves([{name: itemName1, id: "foo", path: itemName1, status: "ready"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "draft" + }, {name: badItem, id: "ack", path: badItem, status: "ready"}]); } let stubContentResource; @@ -1230,29 +1362,91 @@ class ListUnitTest extends UnitTest { // Execute the command to list the items to the download directory. let error; toolsCli.parseArgs(['', UnitTest.COMMAND, "list", switches, "--server", "--ignore-timestamps", "--user", "foo", "--password", "password", "--url", "http://foo.bar/api"]) + .then(function (msg) { + if (switches.includes("--sites")) { + // Verify that the stub was called twice, and the expected message was returned. + expect(stubGet).to.have.been.calledTwice; + + // Sites filtered to those in context.siteList. + expect(msg).to.contain('artifacts listed 1'); + } else { + // Verify that the stubs were called as expected, and the expected message was returned. + expect(stubGet).to.have.been.calledOnce; + expect(msg).to.contain('artifacts listed 2'); + } + }) + .catch(function (err) { + // Pass the error to the "done" function to indicate a failed test. + error = err; + }) + .finally(function () { + // Restore the stubs. + stubGet.restore(); + if (stubContentResource) { + stubContentResource.restore(); + } + + // Add the global stub back now if it was removed earlier. + if (switches === "--sites") { + ListUnitTest.addRemoteSitesStub(); + } + + // Call mocha's done function to indicate that the test is over. + done(error); + }); + }); + + it("test list remote working (all items)", function (done) { + if (!BaseCommand.DRAFT_SITES && (switches.includes("--sites") || switches.includes("--pages"))) { + return done(); + } + + let stubGet; + if (switches === "--sites") { + // Remove the global stub and create a local SitesREST.getItems stub that returns the standard sites + // the first time (initSites) then returns the test values the second time (the actual list). + ListUnitTest.restoreRemoteSitesStub(); + stubGet = sinon.stub(helper._restApi, "getItems"); + stubGet.onFirstCall().resolves([{id: "foo", siteStatus: "ready"}, { + id: "bar", + siteStatus: "draft" + }]); + stubGet.onSecondCall().resolves([{name: itemName1, id: "foo", path: itemName1}, { + name: itemName2, + id: "bar", + path: itemName2 + }, {name: badItem, id: "ack", path: badItem}]); + } else { + stubGet = sinon.stub(helper._restApi, "getItems"); + stubGet.resolves([{name: itemName1, id: "foo", path: itemName1, status: "ready"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "draft" + }, {name: badItem, id: "ack", path: badItem, status: "ready"}]); + } + + let stubContentResource; + if (switches.includes("-a")) { + stubContentResource = sinon.stub(helper._fsApi, "isContentResource"); + stubContentResource.returns(true); + } else if (switches.includes("-w")) { + stubContentResource = sinon.stub(helper._fsApi, "isContentResource"); + stubContentResource.returns(false); + } + + // Execute the command to list the items to the download directory. + let error; + toolsCli.parseArgs(['', UnitTest.COMMAND, "list", switches, "--server", "--ignore-timestamps", "--ready", "--draft", "--user", "foo", "--password", "password", "--url", "http://foo.bar/api"]) .then(function (msg) { if (switches === "--pages" || switches === "--sites") { - if (DRAFT_SITES) { - // Verify that the stub was called twice (once for each site), and the expected message was returned. - expect(stubGet).to.have.been.calledTwice; - if (switches.includes("--sites")) { - // Sites filtered to those in context.siteList. - expect(msg).to.contain('artifacts listed 2'); - } else { - expect(msg).to.contain('artifacts listed 6'); - } + // Verify that the stub was called twice (once for each site), and the expected message was returned. + expect(stubGet).to.have.been.calledTwice; + if (switches.includes("--sites")) { + // Sites filtered to those in context.siteList. + expect(msg).to.contain('artifacts listed 2'); } else { - if (switches.includes("--sites")) { - // Verify that the stub was called twice, and the expected message was returned. - expect(stubGet).to.have.been.calledTwice; - - // Sites filtered to those in context.siteList. - expect(msg).to.contain('artifacts listed 1'); - } else { - // Verify that the stub was called once, and the expected message was returned. - expect(stubGet).to.have.been.calledOnce; - expect(msg).to.contain('artifacts listed 3'); - } + expect(msg).to.contain('artifacts listed 6'); } } else { // Verify that the stubs were called as expected, and the expected message was returned. @@ -1281,18 +1475,23 @@ class ListUnitTest extends UnitTest { }); }); - it("test list remote working (ready sites)", function (done) { + it("test list remote working (ready items)", function (done) { let stubGet; if (switches === "--sites") { // Remove the global stub and create a local SitesREST.getItems stub that returns the standard sites - // the first time (initSites) then returns the test values the second time (the actual push). + // the first time (initSites) then returns the test values the second time (the actual list). ListUnitTest.restoreRemoteSitesStub(); stubGet = sinon.stub(helper._restApi, "getItems"); stubGet.onFirstCall().resolves([{id: "foo", siteStatus: "ready"}, {id: "bar", siteStatus: "draft"}]); stubGet.onSecondCall().resolves([{name: itemName1, id: "foo", path: itemName1}, {name: itemName2, id: "bar", path: itemName2}, {name: badItem, id: "ack", path: badItem}]); } else { stubGet = sinon.stub(helper._restApi, "getItems"); - stubGet.resolves([{name: itemName1, id: "foo", path: itemName1}, {name: itemName2, id: "bar", path: itemName2}, {name: badItem, id: "ack", path: badItem}]); + stubGet.resolves([{name: itemName1, id: "foo", path: itemName1, status: "ready"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "draft" + }, {name: badItem, id: "ack", path: badItem, status: "ready"}]); } let stubContentResource; @@ -1315,7 +1514,7 @@ class ListUnitTest extends UnitTest { expect(msg).to.contain('artifacts listed 1'); } else { expect(stubGet).to.have.been.calledOnce; - expect(msg).to.contain('artifacts listed 3'); + expect(msg).to.contain('artifacts listed 2'); } }) .catch(function (err) { @@ -1339,14 +1538,36 @@ class ListUnitTest extends UnitTest { }); }); - it("test list remote working (draft sites)", function (done) { - // TODO Enable when --draft option is avaiable. - if (!DRAFT_OPTION) { + it("test list remote working (draft items)", function (done) { + if (!BaseCommand.DRAFT_SITES && (switches.includes("--sites") || switches.includes("--pages"))) { return done(); } - const stubList = sinon.stub(helper._restApi, "getItems"); - stubList.resolves([{name: itemName1, id: "foo", path: itemName1}, {name: itemName2, id: "bar", path: itemName2}, {name: badItem, id: "ack", path: badItem}]); + let stubList; + if (switches.includes("--sites")) { + // Remove the global stub and create a local SitesREST.getItems stub that returns the standard sites + // the first time (initSites) then returns the test values the second time (the actual list). + ListUnitTest.restoreRemoteSitesStub(); + stubList = sinon.stub(helper._restApi, "getItems"); + stubList.onFirstCall().resolves([{id: "foo", siteStatus: "ready"}, { + id: "bar", + siteStatus: "draft" + }]); + stubList.onSecondCall().resolves([{ + name: itemName1, + id: "foo", + path: itemName1, + status: "ready" + }, {name: itemName2, id: "bar", path: itemName2, status: "draft"}]); + } else { + stubList = sinon.stub(helper._restApi, "getItems"); + stubList.resolves([{name: itemName1, id: "foo", path: itemName1, status: "ready"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "draft" + }, {name: badItem, id: "ack", path: badItem, status: "draft"}]); + } let stubContentResource; if (switches.includes("-a")) { @@ -1362,12 +1583,13 @@ class ListUnitTest extends UnitTest { toolsCli.parseArgs(['', UnitTest.COMMAND, "list", switches, "--draft", "--server", "--ignore-timestamps", "--user", "foo", "--password", "password", "--url", "http://foo.bar/api"]) .then(function (msg) { // Verify that the stubs were called as expected, and the expected message was returned. - expect(stubList).to.have.been.calledOnce; if (switches.includes("--sites")) { // Sites filtered to those in context.siteList. + expect(stubList).to.have.been.calledTwice; expect(msg).to.contain('artifacts listed 1'); } else { - expect(msg).to.contain('artifacts listed 3'); + expect(stubList).to.have.been.calledOnce; + expect(msg).to.contain('artifacts listed 2'); } }) .catch(function (err) { @@ -1521,31 +1743,6 @@ class ListUnitTest extends UnitTest { }); }); - it("should fail if both ready and draft specified", function (done) { - // TODO Enable when --draft option is avaiable. - if (!DRAFT_OPTION) { - return done(); - } - - let error; - toolsCli.parseArgs(['', UnitTest.COMMAND, "list", switches, '--ready', '--draft', '--user', 'foo', '--password', 'password', '--url', 'http://foo.bar/api']) - .then(function () { - // This is not expected. Pass the error to the "done" function to indicate a failed test. - error = new Error("The command should have failed."); - }) - .catch(function (err) { - expect(err.message).to.contain("cannot specifiy both ready and draft"); - }) - .catch (function (err) { - // Pass the error to the "done" function to indicate a failed test. - error = err; - }) - .finally(function () { - // Call mocha's done function to indicate that the test is over. - done(error); - }); - }); - it("should fail if the ready and draft options are not valid", function (done) { const READY_ERROR = "There was a problem with the ready option, as expected by a unit test."; const stub = sinon.stub(BaseCommand.prototype, "handleReadyDraftOptions", function () { diff --git a/CLI/test/unit/lib/pull.unit.js b/CLI/test/unit/lib/pull.unit.js index 85ff3b2..7d7adb9 100644 --- a/CLI/test/unit/lib/pull.unit.js +++ b/CLI/test/unit/lib/pull.unit.js @@ -23,25 +23,18 @@ const UnitTest = require("./base.cli.unit.js"); // Require the node modules used in this test file. const fs = require("fs"); -const path = require("path"); const rimraf = require("rimraf"); -const diff = require("diff"); const Q = require("q"); const sinon = require("sinon"); const ToolsApi = require("wchtools-api"); const hashes = ToolsApi.getHashes(); const toolsCli = require("../../../wchToolsCli"); -const events = require("events"); +const BaseCommand = require("../../../lib/baseCommand"); const mkdirp = require("mkdirp"); const options = ToolsApi.getOptions(); const manifests = ToolsApi.getManifests(); const prompt = require("prompt"); -const DRAFT_OPTION = false; - -// TODO When pulling draft sites is supported, the code excluded by this flag should be removed. -const DRAFT_SITES = false; - let stubRemoteSites; class PullUnitTest extends UnitTest { @@ -121,17 +114,10 @@ class PullUnitTest extends UnitTest { const downloadTarget = DOWNLOAD_TARGET; toolsCli.parseArgs(['', UnitTest.COMMAND, "pull", switches, "--dir", downloadTarget, '--user', 'foo', '--password', 'password', '--url', 'http://foo.bar/api', '-v']) .then(function (msg) { - if (DRAFT_SITES && switches === "--pages") { - // Verify that the stub was called twice (once for each site), and that the expected message was returned. - expect(stub).to.have.been.calledTwice; - expect(msg).to.contain('4 artifacts'); - expect(msg).to.contain('2 error'); - } else { - // Verify that the stub was called once, and that the expected message was returned. - expect(stub).to.have.been.calledOnce; - expect(msg).to.contain('2 artifacts'); - expect(msg).to.contain('1 error'); - } + // Verify that the stub was called once, and that the expected message was returned. + expect(stub).to.have.been.calledOnce; + expect(msg).to.contain('2 artifacts'); + expect(msg).to.contain('1 error'); }) .catch(function (err) { // Pass the error to the "done" function to indicate a failed test. @@ -289,15 +275,9 @@ class PullUnitTest extends UnitTest { const downloadTarget = DOWNLOAD_TARGET; toolsCli.parseArgs(['', UnitTest.COMMAND, "pull", switches, "--ignore-timestamps", "--dir", downloadTarget, '--user', 'foo', '--password', 'password', '--url', 'http://foo.bar/api', '-v']) .then(function (msg) { - if (DRAFT_SITES && switches === "--pages") { - // Verify that the stub was called twice (once for each site), and that the expected message was returned. - expect(stub).to.have.been.calledTwice; - expect(msg).to.contain('4 artifacts'); - } else { - // Verify that the stub was called once, and that the expected message was returned. - expect(stub).to.have.been.calledOnce; - expect(msg).to.contain('2 artifacts'); - } + // Verify that the stub was called once, and that the expected message was returned. + expect(stub).to.have.been.calledOnce; + expect(msg).to.contain('2 artifacts'); }) .catch(function (err) { // Pass the error to the "done" function to indicate a failed test. @@ -312,11 +292,7 @@ class PullUnitTest extends UnitTest { }); }); - it("test pull ignore-timestamps working (all sites)", function (done) { - if (switches !== "--sites" && switches !== "--pages") { - return done(); - } - + it("test pull ignore-timestamps working (ready items only, by default)", function (done) { let stubGet; if (switches === "--sites") { // Remove the global stub and create a local SitesREST.getItems stub that returns the standard sites @@ -327,12 +303,35 @@ class PullUnitTest extends UnitTest { stubGet.onSecondCall().resolves([{name: itemName1, id: "foo", path: itemName1}, {name: itemName2, id: "bar", path: itemName2}, {name: badItem, id: "ack", path: badItem}]); } else { stubGet = sinon.stub(helper._restApi, "getItems"); - stubGet.resolves([{name: itemName1, id: "foo", path: itemName1}, {name: itemName2, id: "bar", path: itemName2}, {name: badItem, id: "ack", path: badItem}]); + stubGet.resolves([{name: itemName1, id: "foo", path: itemName1, status: "ready"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "ready" + }, {name: badItem, id: "ack", path: badItem, status: "ready"}]); } const stubSave = sinon.stub(helper._fsApi, "saveItem"); stubSave.resolves(); + let stubPull; + let stubContent; + if (switches === "-a" || switches === "-w") { + stubPull = sinon.stub(helper, "_pullAsset", function (context, asset, opts) { + // When the stubbed method is called, return a promise that will be resolved asynchronously. + const stubDeferred = Q.defer(); + setTimeout(function () { + const emitter = helper.getEventEmitter(context); + emitter.emit("pulled", asset); + stubDeferred.resolve(asset); + }, 0); + return stubDeferred.promise; + }); + + stubContent = sinon.stub(helper._fsApi, "isContentResource"); + stubContent.returns(switches === "-a"); + } + const stubHashes = sinon.stub(hashes, "setLastPullTimestamp"); // Execute the command to pull the items to the download directory. @@ -341,41 +340,27 @@ class PullUnitTest extends UnitTest { toolsCli.parseArgs(['', UnitTest.COMMAND, "pull", switches, "--ignore-timestamps", "--dir", downloadTarget, '--user', 'foo', '--password', 'password', '--url', 'http://foo.bar/api', '-v']) .then(function (msg) { if (switches === "--sites") { - if (DRAFT_SITES) { - // Verify that the stub was called twice, and that the expected message was returned. - expect(stubGet).to.have.been.calledTwice; - expect(stubSave).to.have.been.calledTwice; - expect(stubSave.args[0][1].id).to.equal("foo"); - expect(stubSave.args[1][1].id).to.equal("bar"); - expect(msg).to.contain('2 artifacts'); - } else { - // Verify that the stub was called once, and that the expected message was returned. - expect(stubGet).to.have.been.calledTwice; - expect(stubSave).to.have.been.calledOnce; - expect(stubSave.args[0][1].id).to.equal("foo"); - expect(msg).to.contain('1 artifact'); - } + // Verify that the stub was called twice, and that the expected message was returned. + expect(stubGet).to.have.been.calledTwice; + expect(stubSave).to.have.been.calledOnce; + expect(stubSave.args[0][1].id).to.equal("foo"); + expect(msg).to.contain('1 artifact'); + } else if (switches === "-a" || switches === "-w") { + // Verify that the stub was called once, and that the expected message was returned. + expect(stubGet).to.have.been.calledOnce; + expect(stubPull).to.have.callCount(3); + expect(stubPull.args[0][1].id).to.equal("foo"); + expect(stubPull.args[1][1].id).to.equal("bar"); + expect(stubPull.args[2][1].id).to.equal("ack"); + expect(msg).to.contain('3 artifacts'); } else { - if (DRAFT_SITES) { - // Verify that the stub was called twice, and that the expected message was returned. - expect(stubGet).to.have.been.calledTwice; - expect(stubSave).to.have.callCount(6); - expect(stubSave.args[0][1].id).to.equal("foo"); - expect(stubSave.args[1][1].id).to.equal("bar"); - expect(stubSave.args[2][1].id).to.equal("ack"); - expect(stubSave.args[3][1].id).to.equal("foo"); - expect(stubSave.args[4][1].id).to.equal("bar"); - expect(stubSave.args[5][1].id).to.equal("ack"); - expect(msg).to.contain('6 artifacts'); - } else { - // Verify that the stub was called once, and that the expected message was returned. - expect(stubGet).to.have.been.calledOnce; - expect(stubSave).to.have.callCount(3); - expect(stubSave.args[0][1].id).to.equal("foo"); - expect(stubSave.args[1][1].id).to.equal("bar"); - expect(stubSave.args[2][1].id).to.equal("ack"); - expect(msg).to.contain('3 artifacts'); - } + // Verify that the stub was called once, and that the expected message was returned. + expect(stubGet).to.have.been.calledOnce; + expect(stubSave).to.have.callCount(3); + expect(stubSave.args[0][1].id).to.equal("foo"); + expect(stubSave.args[1][1].id).to.equal("bar"); + expect(stubSave.args[2][1].id).to.equal("ack"); + expect(msg).to.contain('3 artifacts'); } }) .catch(function (err) { @@ -387,6 +372,12 @@ class PullUnitTest extends UnitTest { stubGet.restore(); stubSave.restore(); stubHashes.restore(); + if (stubPull) { + stubPull.restore(); + } + if (stubContent) { + stubContent.restore(); + } // Add the global stub back now if it was removed earlier. if (switches === "--sites") { @@ -398,13 +389,14 @@ class PullUnitTest extends UnitTest { }); }); - it("test pull modified working (all sites)", function (done) { - if (switches !== "--sites" && switches !== "--pages") { - return done(); - } - + it("test pull modified working (ready items only, by default)", function (done) { const stubList = sinon.stub(helper._restApi, "getModifiedItems"); - stubList.resolves([{name: itemName1, id: "foo", path: itemName1}, {name: itemName2, id: "bar", path: itemName2}, {name: badItem, id: "ack", path: badItem}]); + stubList.resolves([{name: itemName1, id: "foo", path: itemName1, status: "ready"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "ready" + }, {name: badItem, id: "ack", path: badItem, status: "ready"}]); const stubModified = sinon.stub(hashes, "isRemoteModified"); stubModified.returns(true); @@ -412,6 +404,24 @@ class PullUnitTest extends UnitTest { const stubSave = sinon.stub(helper._fsApi, "saveItem"); stubSave.resolves(); + let stubPull; + let stubContent; + if (switches === "-a" || switches === "-w") { + stubPull = sinon.stub(helper, "_pullAsset", function (context, asset, opts) { + // When the stubbed method is called, return a promise that will be resolved asynchronously. + const stubDeferred = Q.defer(); + setTimeout(function () { + const emitter = helper.getEventEmitter(context); + emitter.emit("pulled", asset); + stubDeferred.resolve(asset); + }, 0); + return stubDeferred.promise; + }); + + stubContent = sinon.stub(helper._fsApi, "isContentResource"); + stubContent.returns(switches === "-a"); + } + const stubHashes = sinon.stub(hashes, "setLastPullTimestamp"); // Execute the command to pull the items to the download directory. @@ -420,41 +430,27 @@ class PullUnitTest extends UnitTest { toolsCli.parseArgs(['', UnitTest.COMMAND, "pull", switches, "--dir", downloadTarget, '--user', 'foo', '--password', 'password', '--url', 'http://foo.bar/api', '-v']) .then(function (msg) { if (switches === "--sites") { - if (DRAFT_SITES) { - // Verify that the stub was called once, and that the expected message was returned. - expect(stubList).to.have.been.calledOnce; - expect(stubSave).to.have.been.calledTwice; - expect(stubSave.args[0][1].id).to.equal("foo"); - expect(stubSave.args[1][1].id).to.equal("bar"); - expect(msg).to.contain('2 artifacts'); - } else { - // Verify that the stub was called once, and that the expected message was returned. - expect(stubList).to.have.been.calledOnce; - expect(stubSave).to.have.been.calledOnce; - expect(stubSave.args[0][1].id).to.equal("foo"); - expect(msg).to.contain('1 artifact'); - } + // Verify that the stub was called once, and that the expected message was returned. + expect(stubList).to.have.been.calledOnce; + expect(stubSave).to.have.been.calledOnce; + expect(stubSave.args[0][1].id).to.equal("foo"); + expect(msg).to.contain('1 artifact'); + } else if (switches === "-a" || switches === "-w") { + // Verify that the stub was called once, and that the expected message was returned. + expect(stubList).to.have.been.calledOnce; + expect(stubPull).to.have.callCount(3); + expect(stubPull.args[0][1].id).to.equal("foo"); + expect(stubPull.args[1][1].id).to.equal("bar"); + expect(stubPull.args[2][1].id).to.equal("ack"); + expect(msg).to.contain('3 artifacts'); } else { - if (DRAFT_SITES) { - // Verify that the stub was called twice, and that the expected message was returned. - expect(stubList).to.have.been.calledTwice; - expect(stubSave).to.have.callCount(6); - expect(stubSave.args[0][1].id).to.equal("foo"); - expect(stubSave.args[1][1].id).to.equal("bar"); - expect(stubSave.args[2][1].id).to.equal("ack"); - expect(stubSave.args[3][1].id).to.equal("foo"); - expect(stubSave.args[4][1].id).to.equal("bar"); - expect(stubSave.args[5][1].id).to.equal("ack"); - expect(msg).to.contain('6 artifacts'); - } else { - // Verify that the stub was called once, and that the expected message was returned. - expect(stubList).to.have.been.calledOnce; - expect(stubSave).to.have.callCount(3); - expect(stubSave.args[0][1].id).to.equal("foo"); - expect(stubSave.args[1][1].id).to.equal("bar"); - expect(stubSave.args[2][1].id).to.equal("ack"); - expect(msg).to.contain('3 artifacts'); - } + // Verify that the stub was called once, and that the expected message was returned. + expect(stubList).to.have.been.calledOnce; + expect(stubSave).to.have.callCount(3); + expect(stubSave.args[0][1].id).to.equal("foo"); + expect(stubSave.args[1][1].id).to.equal("bar"); + expect(stubSave.args[2][1].id).to.equal("ack"); + expect(msg).to.contain('3 artifacts'); } }) .catch(function (err) { @@ -467,17 +463,241 @@ class PullUnitTest extends UnitTest { stubModified.restore(); stubSave.restore(); stubHashes.restore(); + if (stubPull) { + stubPull.restore(); + } + if (stubContent) { + stubContent.restore(); + } // Call mocha's done function to indicate that the test is over. done(error); }); }); - it("test pull ignore-timestamps working (ready sites)", function (done) { - if (switches !== "--sites" && switches !== "--pages") { + it("test pull ignore-timestamps working (all items)", function (done) { + if (!BaseCommand.DRAFT_SITES && (switches.includes("--sites") || switches.includes("--pages"))) { return done(); } + let stubGet; + if (switches === "--sites") { + // Remove the global stub and create a local SitesREST.getItems stub that returns the standard sites + // the first time (initSites) then returns the test values the second time (the actual push). + PullUnitTest.restoreRemoteSitesStub(); + stubGet = sinon.stub(helper._restApi, "getItems"); + stubGet.onFirstCall().resolves([{id: "foo", siteStatus: "ready"}, { + id: "bar", + siteStatus: "draft" + }]); + stubGet.onSecondCall().resolves([{name: itemName1, id: "foo", path: itemName1}, { + name: itemName2, + id: "bar", + path: itemName2 + }, {name: badItem, id: "ack", path: badItem}]); + } else { + stubGet = sinon.stub(helper._restApi, "getItems"); + stubGet.resolves([{name: itemName1, id: "foo", path: itemName1, status: "ready"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "draft" + }, {name: badItem, id: "ack", path: badItem, status: "ready"}]); + } + + const stubSave = sinon.stub(helper._fsApi, "saveItem"); + stubSave.resolves(); + + let stubPull; + let stubContent; + if (switches === "-a" || switches === "-w") { + stubPull = sinon.stub(helper, "_pullAsset", function (context, asset, opts) { + // When the stubbed method is called, return a promise that will be resolved asynchronously. + const stubDeferred = Q.defer(); + setTimeout(function () { + const emitter = helper.getEventEmitter(context); + emitter.emit("pulled", asset); + stubDeferred.resolve(asset); + }, 0); + return stubDeferred.promise; + }); + + stubContent = sinon.stub(helper._fsApi, "isContentResource"); + stubContent.returns(switches === "-a"); + } + + const stubHashes = sinon.stub(hashes, "setLastPullTimestamp"); + + // Execute the command to pull the items to the download directory. + let error; + const downloadTarget = DOWNLOAD_TARGET; + toolsCli.parseArgs(['', UnitTest.COMMAND, "pull", switches, "--ignore-timestamps", "--ready", "--draft", "--dir", downloadTarget, '--user', 'foo', '--password', 'password', '--url', 'http://foo.bar/api', '-v']) + .then(function (msg) { + if (switches === "--sites") { + // Verify that the stub was called twice, and that the expected message was returned. + expect(stubGet).to.have.been.calledTwice; + expect(stubSave).to.have.been.calledTwice; + expect(stubSave.args[0][1].id).to.equal("foo"); + expect(stubSave.args[1][1].id).to.equal("bar"); + expect(msg).to.contain('2 artifacts'); + } else if (switches === "--pages") { + // Verify that the stub was called twice, and that the expected message was returned. + expect(stubGet).to.have.been.calledTwice; + expect(stubSave).to.have.callCount(6); + expect(stubSave.args[0][1].id).to.equal("foo"); + expect(stubSave.args[1][1].id).to.equal("bar"); + expect(stubSave.args[2][1].id).to.equal("ack"); + expect(stubSave.args[3][1].id).to.equal("foo"); + expect(stubSave.args[4][1].id).to.equal("bar"); + expect(stubSave.args[5][1].id).to.equal("ack"); + expect(msg).to.contain('6 artifacts'); + } else if (switches === "-a" || switches === "-w") { + // Verify that the stub was called once, and that the expected message was returned. + expect(stubGet).to.have.been.calledOnce; + expect(stubPull).to.have.callCount(3); + expect(stubPull.args[0][1].id).to.equal("foo"); + expect(stubPull.args[1][1].id).to.equal("bar"); + expect(stubPull.args[2][1].id).to.equal("ack"); + expect(msg).to.contain('3 artifacts'); + } else { + // Verify that the stub was called once, and that the expected message was returned. + expect(stubGet).to.have.been.calledOnce; + expect(stubSave).to.have.callCount(3); + expect(stubSave.args[0][1].id).to.equal("foo"); + expect(stubSave.args[1][1].id).to.equal("bar"); + expect(stubSave.args[2][1].id).to.equal("ack"); + expect(msg).to.contain('3 artifacts'); + } + }) + .catch(function (err) { + // Pass the error to the "done" function to indicate a failed test. + error = err; + }) + .finally(function () { + // Restore the stubbed methods. + stubGet.restore(); + stubSave.restore(); + stubHashes.restore(); + if (stubPull) { + stubPull.restore(); + } + if (stubContent) { + stubContent.restore(); + } + + // Add the global stub back now if it was removed earlier. + if (switches === "--sites") { + PullUnitTest.addRemoteSitesStub(); + } + + // Call mocha's done function to indicate that the test is over. + done(error); + }); + }); + + it("test pull modified working (all items)", function (done) { + if (!BaseCommand.DRAFT_SITES && (switches.includes("--sites") || switches.includes("--pages"))) { + return done(); + } + + const stubList = sinon.stub(helper._restApi, "getModifiedItems"); + stubList.resolves([{name: itemName1, id: "foo", path: itemName1, status: "ready"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "draft" + }, {name: badItem, id: "ack", path: badItem, status: "ready"}]); + + const stubModified = sinon.stub(hashes, "isRemoteModified"); + stubModified.returns(true); + + const stubSave = sinon.stub(helper._fsApi, "saveItem"); + stubSave.resolves(); + + let stubPull; + let stubContent; + if (switches === "-a" || switches === "-w") { + stubPull = sinon.stub(helper, "_pullAsset", function (context, asset, opts) { + // When the stubbed method is called, return a promise that will be resolved asynchronously. + const stubDeferred = Q.defer(); + setTimeout(function () { + const emitter = helper.getEventEmitter(context); + emitter.emit("pulled", asset); + stubDeferred.resolve(asset); + }, 0); + return stubDeferred.promise; + }); + + stubContent = sinon.stub(helper._fsApi, "isContentResource"); + stubContent.returns(switches === "-a"); + } + + const stubHashes = sinon.stub(hashes, "setLastPullTimestamp"); + + // Execute the command to pull the items to the download directory. + let error; + const downloadTarget = DOWNLOAD_TARGET; + toolsCli.parseArgs(['', UnitTest.COMMAND, "pull", switches, "--ready", "--draft", "--dir", downloadTarget, '--user', 'foo', '--password', 'password', '--url', 'http://foo.bar/api', '-v']) + .then(function (msg) { + if (switches === "--sites") { + // Verify that the stub was called once, and that the expected message was returned. + expect(stubList).to.have.been.calledOnce; + expect(stubSave).to.have.been.calledTwice; + expect(stubSave.args[0][1].id).to.equal("foo"); + expect(stubSave.args[1][1].id).to.equal("bar"); + expect(msg).to.contain('2 artifacts'); + } else if (switches === "--pages") { + // Verify that the stub was called twice, and that the expected message was returned. + expect(stubList).to.have.been.calledTwice; + expect(stubSave).to.have.callCount(6); + expect(stubSave.args[0][1].id).to.equal("foo"); + expect(stubSave.args[1][1].id).to.equal("bar"); + expect(stubSave.args[2][1].id).to.equal("ack"); + expect(stubSave.args[3][1].id).to.equal("foo"); + expect(stubSave.args[4][1].id).to.equal("bar"); + expect(stubSave.args[5][1].id).to.equal("ack"); + expect(msg).to.contain('6 artifacts'); + } else if (switches === "-a" || switches === "-w") { + // Verify that the stub was called once, and that the expected message was returned. + expect(stubList).to.have.been.calledOnce; + expect(stubPull).to.have.callCount(3); + expect(stubPull.args[0][1].id).to.equal("foo"); + expect(stubPull.args[1][1].id).to.equal("bar"); + expect(stubPull.args[2][1].id).to.equal("ack"); + expect(msg).to.contain('3 artifacts'); + } else { + // Verify that the stub was called once, and that the expected message was returned. + expect(stubList).to.have.been.calledOnce; + expect(stubSave).to.have.callCount(3); + expect(stubSave.args[0][1].id).to.equal("foo"); + expect(stubSave.args[1][1].id).to.equal("bar"); + expect(stubSave.args[2][1].id).to.equal("ack"); + expect(msg).to.contain('3 artifacts'); + } + }) + .catch(function (err) { + // Pass the error to the "done" function to indicate a failed test. + error = err; + }) + .finally(function () { + // Restore the stubbed methods. + stubList.restore(); + stubModified.restore(); + stubSave.restore(); + stubHashes.restore(); + if (stubPull) { + stubPull.restore(); + } + if (stubContent) { + stubContent.restore(); + } + + // Call mocha's done function to indicate that the test is over. + done(error); + }); + }); + + it("test pull ignore-timestamps working (ready items)", function (done) { let stubGet; if (switches === "--sites") { // Remove the global stub and create a local SitesREST.getItems stub that returns the standard sites @@ -488,12 +708,35 @@ class PullUnitTest extends UnitTest { stubGet.onSecondCall().resolves([{name: itemName1, id: "foo", path: itemName1}, {name: itemName2, id: "bar", path: itemName2}, {name: badItem, id: "ack", path: badItem}]); } else { stubGet = sinon.stub(helper._restApi, "getItems"); - stubGet.resolves([{name: itemName1, id: "foo", path: itemName1}, {name: itemName2, id: "bar", path: itemName2}, {name: badItem, id: "ack", path: badItem}]); + stubGet.resolves([{name: itemName1, id: "foo", path: itemName1, status: "ready"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "ready" + }, {name: badItem, id: "ack", path: badItem, status: "ready"}]); } const stubSave = sinon.stub(helper._fsApi, "saveItem"); stubSave.resolves(); + let stubPull; + let stubContent; + if (switches === "-a" || switches === "-w") { + stubPull = sinon.stub(helper, "_pullAsset", function (context, asset, opts) { + // When the stubbed method is called, return a promise that will be resolved asynchronously. + const stubDeferred = Q.defer(); + setTimeout(function () { + const emitter = helper.getEventEmitter(context); + emitter.emit("pulled", asset); + stubDeferred.resolve(asset); + }, 0); + return stubDeferred.promise; + }); + + stubContent = sinon.stub(helper._fsApi, "isContentResource"); + stubContent.returns(switches === "-a"); + } + const stubHashes = sinon.stub(hashes, "setLastPullTimestamp"); // Execute the command to pull the items to the download directory. @@ -507,6 +750,14 @@ class PullUnitTest extends UnitTest { expect(stubSave).to.have.been.calledOnce; expect(stubSave.args[0][1].id).to.equal("foo"); expect(msg).to.contain('1 artifact'); + } else if (switches === "-a" || switches === "-w") { + // Verify that the stub was called once, and that the expected message was returned. + expect(stubGet).to.have.been.calledOnce; + expect(stubPull).to.have.callCount(3); + expect(stubPull.args[0][1].id).to.equal("foo"); + expect(stubPull.args[1][1].id).to.equal("bar"); + expect(stubPull.args[2][1].id).to.equal("ack"); + expect(msg).to.contain('3 artifacts'); } else { // Verify that the stub was called once, and that the expected message was returned. expect(stubGet).to.have.been.calledOnce; @@ -526,6 +777,12 @@ class PullUnitTest extends UnitTest { stubGet.restore(); stubSave.restore(); stubHashes.restore(); + if (stubPull) { + stubPull.restore(); + } + if (stubContent) { + stubContent.restore(); + } // Add the global stub back now if it was removed earlier. if (switches === "--sites") { @@ -537,13 +794,14 @@ class PullUnitTest extends UnitTest { }); }); - it("test pull modified working (ready sites)", function (done) { - if (switches !== "--sites" && switches !== "--pages") { - return done(); - } - + it("test pull modified working (ready items)", function (done) { const stubList = sinon.stub(helper._restApi, "getModifiedItems"); - stubList.resolves([{name: itemName1, id: "foo", path: itemName1}, {name: itemName2, id: "bar", path: itemName2}, {name: badItem, id: "ack", path: badItem}]); + stubList.resolves([{name: itemName1, id: "foo", path: itemName1, status: "ready"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "ready" + }, {name: badItem, id: "ack", path: badItem, status: "ready"}]); const stubModified = sinon.stub(hashes, "isRemoteModified"); stubModified.returns(true); @@ -551,6 +809,24 @@ class PullUnitTest extends UnitTest { const stubSave = sinon.stub(helper._fsApi, "saveItem"); stubSave.resolves(); + let stubPull; + let stubContent; + if (switches === "-a" || switches === "-w") { + stubPull = sinon.stub(helper, "_pullAsset", function (context, asset, opts) { + // When the stubbed method is called, return a promise that will be resolved asynchronously. + const stubDeferred = Q.defer(); + setTimeout(function () { + const emitter = helper.getEventEmitter(context); + emitter.emit("pulled", asset); + stubDeferred.resolve(asset); + }, 0); + return stubDeferred.promise; + }); + + stubContent = sinon.stub(helper._fsApi, "isContentResource"); + stubContent.returns(switches === "-a"); + } + const stubHashes = sinon.stub(hashes, "setLastPullTimestamp"); // Execute the command to pull the items to the download directory. @@ -564,6 +840,14 @@ class PullUnitTest extends UnitTest { expect(stubSave).to.have.been.calledOnce; expect(stubSave.args[0][1].id).to.equal("foo"); expect(msg).to.contain('1 artifact'); + } else if (switches === "-a" || switches === "-w") { + // Verify that the stub was called once, and that the expected message was returned. + expect(stubList).to.have.been.calledOnce; + expect(stubPull).to.have.callCount(3); + expect(stubPull.args[0][1].id).to.equal("foo"); + expect(stubPull.args[1][1].id).to.equal("bar"); + expect(stubPull.args[2][1].id).to.equal("ack"); + expect(msg).to.contain('3 artifacts'); } else { // Verify that the stub was called once, and that the expected message was returned. expect(stubList).to.have.been.calledOnce; @@ -584,28 +868,70 @@ class PullUnitTest extends UnitTest { stubModified.restore(); stubSave.restore(); stubHashes.restore(); + if (stubPull) { + stubPull.restore(); + } + if (stubContent) { + stubContent.restore(); + } // Call mocha's done function to indicate that the test is over. done(error); }); }); - it("test pull ignore-timestamps working (draft sites)", function (done) { - // TODO Enable when --draft option is avaiable. - if (!DRAFT_OPTION) { + it("test pull ignore-timestamps working (draft items)", function (done) { + if (!BaseCommand.DRAFT_SITES && (switches.includes("--sites") || switches.includes("--pages"))) { return done(); } - if (switches !== "--sites" && switches !== "--pages") { - return done(); + let stubGet; + if (switches === "--sites") { + // Remove the global stub and create a local SitesREST.getItems stub that returns the standard sites + // the first time (initSites) then returns the test values the second time (the actual push). + PullUnitTest.restoreRemoteSitesStub(); + stubGet = sinon.stub(helper._restApi, "getItems"); + stubGet.onFirstCall().resolves([{id: "foo", siteStatus: "ready"}, { + id: "bar", + siteStatus: "draft" + }]); + stubGet.onSecondCall().resolves([{ + name: itemName1, + id: "foo", + path: itemName1, + siteStatus: "ready" + }, {name: itemName2, id: "bar", path: itemName2, siteStatus: "draft"}]); + } else { + stubGet = sinon.stub(helper._restApi, "getItems"); + stubGet.resolves([{name: itemName1, id: "foo", path: itemName1, status: "draft"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "draft" + }, {name: badItem, id: "ack", path: badItem, status: "draft"}]); } - const stubList = sinon.stub(helper._restApi, "getItems"); - stubList.resolves([{name: itemName1, id: "foo", path: itemName1}, {name: itemName2, id: "bar", path: itemName2}, {name: badItem, id: "ack", path: badItem}]); - const stubSave = sinon.stub(helper._fsApi, "saveItem"); stubSave.resolves(); + let stubPull; + let stubContent; + if (switches === "-a" || switches === "-w") { + stubPull = sinon.stub(helper, "_pullAsset", function (context, asset, opts) { + // When the stubbed method is called, return a promise that will be resolved asynchronously. + const stubDeferred = Q.defer(); + setTimeout(function () { + const emitter = helper.getEventEmitter(context); + emitter.emit("pulled", asset); + stubDeferred.resolve(asset); + }, 0); + return stubDeferred.promise; + }); + + stubContent = sinon.stub(helper._fsApi, "isContentResource"); + stubContent.returns(switches === "-a"); + } + const stubHashes = sinon.stub(hashes, "setLastPullTimestamp"); // Execute the command to pull the items to the download directory. @@ -615,13 +941,21 @@ class PullUnitTest extends UnitTest { .then(function (msg) { if (switches === "--sites") { // Verify that the stub was called once, and that the expected message was returned. - expect(stubList).to.have.been.calledOnce; + expect(stubGet).to.have.been.calledTwice; expect(stubSave).to.have.been.calledOnce; expect(stubSave.args[0][1].id).to.equal("bar"); expect(msg).to.contain('1 artifact'); + } else if (switches === "-a" || switches === "-w") { + // Verify that the stub was called once, and that the expected message was returned. + expect(stubGet).to.have.been.calledOnce; + expect(stubPull).to.have.callCount(3); + expect(stubPull.args[0][1].id).to.equal("foo"); + expect(stubPull.args[1][1].id).to.equal("bar"); + expect(stubPull.args[2][1].id).to.equal("ack"); + expect(msg).to.contain('3 artifacts'); } else { // Verify that the stub was called once, and that the expected message was returned. - expect(stubList).to.have.been.calledOnce; + expect(stubGet).to.have.been.calledOnce; expect(stubSave).to.have.been.calledThrice; expect(stubSave.args[0][1].id).to.equal("foo"); expect(stubSave.args[1][1].id).to.equal("bar"); @@ -635,27 +969,52 @@ class PullUnitTest extends UnitTest { }) .finally(function () { // Restore the stubbed methods. - stubList.restore(); + stubGet.restore(); stubSave.restore(); stubHashes.restore(); + if (stubPull) { + stubPull.restore(); + } + if (stubContent) { + stubContent.restore(); + } + + // Add the global stub back now if it was removed earlier. + if (switches === "--sites") { + PullUnitTest.addRemoteSitesStub(); + } // Call mocha's done function to indicate that the test is over. done(error); }); }); - it("test pull modified working (draft sites)", function (done) { - // TODO Enable when --draft option is avaiable. - if (!DRAFT_OPTION) { - return done(); - } - - if (switches !== "--sites" && switches !== "--pages") { + it("test pull modified working (draft items)", function (done) { + if (!BaseCommand.DRAFT_SITES && (switches.includes("--sites") || switches.includes("--pages"))) { return done(); } const stubList = sinon.stub(helper._restApi, "getModifiedItems"); - stubList.resolves([{name: itemName1, id: "foo", path: itemName1}, {name: itemName2, id: "bar", path: itemName2}, {name: badItem, id: "ack", path: badItem}]); + if (switches.includes("--sites")) { + stubList.resolves([{ + name: itemName1, + id: "foo", + path: itemName1, + siteStatus: "draft" + }, {name: itemName2, id: "bar", path: itemName2, siteStatus: "draft"}, { + name: badItem, + id: "ack", + path: badItem, + siteStatus: "draft" + }]); + } else { + stubList.resolves([{name: itemName1, id: "foo", path: itemName1, status: "draft"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "draft" + }, {name: badItem, id: "ack", path: badItem, status: "draft"}]); + } const stubModified = sinon.stub(hashes, "isRemoteModified"); stubModified.returns(true); @@ -663,6 +1022,24 @@ class PullUnitTest extends UnitTest { const stubSave = sinon.stub(helper._fsApi, "saveItem"); stubSave.resolves(); + let stubPull; + let stubContent; + if (switches === "-a" || switches === "-w") { + stubPull = sinon.stub(helper, "_pullAsset", function (context, asset, opts) { + // When the stubbed method is called, return a promise that will be resolved asynchronously. + const stubDeferred = Q.defer(); + setTimeout(function () { + const emitter = helper.getEventEmitter(context); + emitter.emit("pulled", asset); + stubDeferred.resolve(asset); + }, 0); + return stubDeferred.promise; + }); + + stubContent = sinon.stub(helper._fsApi, "isContentResource"); + stubContent.returns(switches === "-a"); + } + const stubHashes = sinon.stub(hashes, "setLastPullTimestamp"); // Execute the command to pull the items to the download directory. @@ -676,6 +1053,14 @@ class PullUnitTest extends UnitTest { expect(stubSave).to.have.been.calledOnce; expect(stubSave.args[0][1].id).to.equal("bar"); expect(msg).to.contain('1 artifact'); + } else if (switches === "-a" || switches === "-w") { + // Verify that the stub was called once, and that the expected message was returned. + expect(stubList).to.have.been.calledOnce; + expect(stubPull).to.have.callCount(3); + expect(stubPull.args[0][1].id).to.equal("foo"); + expect(stubPull.args[1][1].id).to.equal("bar"); + expect(stubPull.args[2][1].id).to.equal("ack"); + expect(msg).to.contain('3 artifacts'); } else { // Verify that the stub was called once, and that the expected message was returned. expect(stubList).to.have.been.calledOnce; @@ -696,6 +1081,12 @@ class PullUnitTest extends UnitTest { stubModified.restore(); stubSave.restore(); stubHashes.restore(); + if (stubPull) { + stubPull.restore(); + } + if (stubContent) { + stubContent.restore(); + } // Call mocha's done function to indicate that the test is over. done(error); @@ -782,17 +1173,11 @@ class PullUnitTest extends UnitTest { const downloadTarget = DOWNLOAD_TARGET; toolsCli.parseArgs(['', UnitTest.COMMAND, "pull", switches, "--deletions", "--quiet", "--dir", downloadTarget, '--user', 'foo', '--password', 'password', '--url', 'http://foo.bar/api', '-v']) .then(function (msg) { - if (DRAFT_SITES && switches === "--pages") { - // Verify that the stub was called twice (once for each site), and that the expected message was returned. - expect(stub).to.have.been.calledTwice; - expect(msg).to.contain('2 artifacts'); - expect(stubDelete).to.have.callCount(4); - } else { - // Verify that the stub was called once, and that the expected message was returned. - expect(stub).to.have.been.calledOnce; - expect(msg).to.contain('1 artifact'); - expect(stubDelete).to.have.been.calledTwice; - } + // Verify that the stub was called once, and that the expected message was returned. + expect(stub).to.have.been.calledOnce; + expect(msg).to.contain('1 artifact'); + expect(stubDelete).to.have.been.calledTwice; + if (stubResource) { expect(stubResource).to.have.been.calledOnce; } @@ -844,19 +1229,11 @@ class PullUnitTest extends UnitTest { const downloadTarget = DOWNLOAD_TARGET; toolsCli.parseArgs(['', UnitTest.COMMAND, "pull", switches, "--deletions", "--dir", downloadTarget, '--user', 'foo', '--password', 'password', '--url', 'http://foo.bar/api', '-v']) .then(function (msg) { - if (DRAFT_SITES && switches === "--pages") { - // Verify that the stub was called twice (once for each site), and that the expected message was returned. - expect(stub).to.have.been.calledTwice; - expect(msg).to.contain('2 artifacts'); - expect(stubPrompt).to.have.been.calledTwice; - expect(stubDelete).to.have.callCount(4); - } else { - // Verify that the stub was called once, and that the expected message was returned. - expect(stub).to.have.been.calledOnce; - expect(msg).to.contain('1 artifact'); - expect(stubPrompt).to.have.been.calledOnce; - expect(stubDelete).to.have.been.calledTwice; - } + // Verify that the stub was called once, and that the expected message was returned. + expect(stub).to.have.been.calledOnce; + expect(msg).to.contain('1 artifact'); + expect(stubPrompt).to.have.been.calledOnce; + expect(stubDelete).to.have.been.calledTwice; }) .catch(function (err) { // Pass the error to the "done" function to indicate a failed test. @@ -895,17 +1272,10 @@ class PullUnitTest extends UnitTest { const downloadTarget = DOWNLOAD_TARGET; toolsCli.parseArgs(['', UnitTest.COMMAND, "pull", switches, "--deletions", "--dir", downloadTarget, '--user', 'foo', '--password', 'password', '--url', 'http://foo.bar/api', '-v']) .then(function (msg) { - if (DRAFT_SITES && switches === "--pages") { - // Verify that the stub was called twice (once for each site), and that the expected message was returned. - expect(stub).to.have.been.calledTwice; - expect(msg).to.contain('2 artifacts'); - expect(stubPrompt).to.have.been.calledTwice; - } else { - // Verify that the stub was called once, and that the expected message was returned. - expect(stub).to.have.been.calledOnce; - expect(msg).to.contain('1 artifact'); - expect(stubPrompt).to.have.been.calledOnce; - } + // Verify that the stub was called once, and that the expected message was returned. + expect(stub).to.have.been.calledOnce; + expect(msg).to.contain('1 artifact'); + expect(stubPrompt).to.have.been.calledOnce; expect(stubDelete).to.not.have.been.called; }) .catch(function (err) { @@ -950,19 +1320,11 @@ class PullUnitTest extends UnitTest { const downloadTarget = DOWNLOAD_TARGET; toolsCli.parseArgs(['', UnitTest.COMMAND, "pull", switches, "--deletions", "--dir", downloadTarget, '--user', 'foo', '--password', 'password', '--url', 'http://foo.bar/api']) .then(function (msg) { - if (DRAFT_SITES && switches === "--pages") { - // Verify that the stub was called twice (once for each site), and that the expected message was returned. - expect(stub).to.have.been.calledTwice; - expect(msg).to.contain('2 artifacts'); - expect(stubPrompt).to.have.been.calledTwice; - expect(stubDelete).to.have.callCount(4); - } else { - // Verify that the stub was called once, and that the expected message was returned. - expect(stub).to.have.been.calledOnce; - expect(msg).to.contain('1 artifact'); - expect(stubPrompt).to.have.been.calledOnce; - expect(stubDelete).to.have.been.calledTwice; - } + // Verify that the stub was called once, and that the expected message was returned. + expect(stub).to.have.been.calledOnce; + expect(msg).to.contain('1 artifact'); + expect(stubPrompt).to.have.been.calledOnce; + expect(stubDelete).to.have.been.calledTwice; }) .catch(function (err) { // Pass the error to the "done" function to indicate a failed test. @@ -1000,17 +1362,10 @@ class PullUnitTest extends UnitTest { const downloadTarget = DOWNLOAD_TARGET; toolsCli.parseArgs(['', UnitTest.COMMAND, "pull", switches, "--deletions", "--quiet", "--dir", downloadTarget, '--user', 'foo', '--password', 'password', '--url', 'http://foo.bar/api', '-v']) .then(function (msg) { - if (DRAFT_SITES && switches === "--pages") { - // Verify that the stub was called twice (once for each site), and that the expected message was returned. - expect(stub).to.have.been.calledTwice; - expect(msg).to.contain('2 artifacts'); - expect(stubDelete).to.have.callCount(4); - } else { - // Verify that the stub was called once, and that the expected message was returned. - expect(stub).to.have.been.calledOnce; - expect(msg).to.contain('1 artifact'); - expect(stubDelete).to.have.been.calledTwice; - } + // Verify that the stub was called once, and that the expected message was returned. + expect(stub).to.have.been.calledOnce; + expect(msg).to.contain('1 artifact'); + expect(stubDelete).to.have.been.calledTwice; }) .catch(function (err) { // Pass the error to the "done" function to indicate a failed test. @@ -1048,15 +1403,9 @@ class PullUnitTest extends UnitTest { error = new Error("The command should have failed."); }) .catch(function (err) { - if (DRAFT_SITES && switches === "--pages") { - // Verify that the stub was called twice (once for each site), and that the expected message was returned. - expect(stub).to.have.been.calledTwice; - expect(err.message).to.contain('6 errors'); - } else { - // Verify that the stub was called once, and that the expected message was returned. - expect(stub).to.have.been.calledOnce; - expect(err.message).to.contain('3 errors'); - } + // Verify that the stub was called once, and that the expected message was returned. + expect(stub).to.have.been.calledOnce; + expect(err.message).to.contain('3 errors'); }) .catch(function (err) { // Pass the error to the "done" function to indicate a failed test. @@ -1086,13 +1435,9 @@ class PullUnitTest extends UnitTest { let error; toolsCli.parseArgs(['', UnitTest.COMMAND, "pull", switches, "--user", "foo", "--password", "password", "--url", "http://foo.bar/api"]) .then(function (msg) { - if (DRAFT_SITES && switches === "--pages") { - // Verify that the stub was called twice (once for each site), and that the expected message was returned. - expect(stub).to.have.been.calledTwice; - } else { - // Verify that the stub was called once, and that the expected message was returned. - expect(stub).to.have.been.calledOnce; - } + // Verify that the stub was called once, and that the expected message was returned. + expect(stub).to.have.been.calledOnce; + expect(msg).to.contain('No items pulled'); expect(msg).to.contain('Use the -I option'); }) @@ -1124,13 +1469,9 @@ class PullUnitTest extends UnitTest { let error; toolsCli.parseArgs(['', UnitTest.COMMAND, "pull", switches, "-I", "--user", "foo", "--password", "password", "--url", "http://foo.bar/api"]) .then(function (msg) { - if (DRAFT_SITES && switches === "--pages") { - // Verify that the stub was called twice (once for each site), and that the expected message was returned. - expect(stub).to.have.been.calledTwice; - } else { - // Verify that the stub was called once, and that the expected message was returned. - expect(stub).to.have.been.calledOnce; - } + // Verify that the stub was called once, and that the expected message was returned. + expect(stub).to.have.been.calledOnce; + expect(msg).to.contain('No items to be pulled'); expect(msg).to.contain('Pull complete'); }) @@ -1161,15 +1502,9 @@ class PullUnitTest extends UnitTest { error = new Error("The command should have failed."); }) .catch(function (err) { - if (DRAFT_SITES && switches === "--pages") { - // Verify that the stub was called twice (once for each site), and that the expected message was returned. - expect(stubPull).to.have.been.calledTwice; - expect(err.message).to.contain('2 errors'); - } else { - // Verify that the stub was called once, and that the expected message was returned. - expect(stubPull).to.have.been.calledOnce; - expect(err.message).to.contain('1 error'); - } + // Verify that the stub was called once, and that the expected message was returned. + expect(stubPull).to.have.been.calledOnce; + expect(err.message).to.contain('1 error'); }) .catch(function (err) { // Pass the error to the "done" function to indicate a failed test. @@ -1697,36 +2032,6 @@ class PullUnitTest extends UnitTest { }); }); - it("should fail if both ready and draft specified", function (done) { - // TODO Enable when --draft option is avaiable. - if (!DRAFT_OPTION) { - return done(); - } - - const stubInit = sinon.stub(manifests, "initializeManifests"); - stubInit.resolves(true); - - let error; - toolsCli.parseArgs(['', UnitTest.COMMAND, command, switches, "--ready", "--draft", "--user", "foo", "--password", "password", "--url", "http://foo.bar/api"]) - .then(function () { - // This is not expected. Pass the error to the "done" function to indicate a failed test. - error = new Error("The command should have failed."); - }) - .catch(function (err) { - expect(err.message).to.contain("cannot specifiy both ready and draft"); - }) - .catch(function (err) { - // Pass the error to the "done" function to indicate a failed test. - error = err; - }) - .finally(function () { - stubInit.restore(); - - // Call mocha's done function to indicate that the test is over. - done(error); - }); - }); - it("should fail if both ready and manifest specified", function (done) { const stubInit = sinon.stub(manifests, "initializeManifests"); stubInit.resolves(true); @@ -1761,11 +2066,6 @@ class PullUnitTest extends UnitTest { }); it("should fail if both draft and manifest specified", function (done) { - // TODO Enable when --draft option is avaiable. - if (!DRAFT_OPTION) { - return done(); - } - const stubInit = sinon.stub(manifests, "initializeManifests"); stubInit.resolves(true); diff --git a/CLI/test/unit/lib/push.unit.js b/CLI/test/unit/lib/push.unit.js index 54a47b1..b1a812d 100644 --- a/CLI/test/unit/lib/push.unit.js +++ b/CLI/test/unit/lib/push.unit.js @@ -23,9 +23,7 @@ const UnitTest = require("./base.cli.unit.js"); // Require the node modules used in this test file. const fs = require("fs"); -const path = require("path"); const rimraf = require("rimraf"); -const diff = require("diff"); const prompt = require("prompt"); const uuid = require("uuid"); const Q = require("q"); @@ -33,18 +31,13 @@ const sinon = require("sinon"); const ToolsApi = require("wchtools-api"); const hashes = ToolsApi.getHashes(); const toolsCli = require("../../../wchToolsCli"); +const BaseCommand = require("../../../lib/baseCommand"); const mkdirp = require("mkdirp"); -const events = require("events"); const manifests = ToolsApi.getManifests(); // Require the local modules that will be stubbed, mocked, and spied. const options = require("wchtools-api").getOptions(); -const DRAFT_OPTION = false; - -// TODO When pushing draft sites is supported, the code excluded by this flag should be removed. -const DRAFT_SITES = false; - const sitesHelper = ToolsApi.getSitesHelper(); let stubLocalSites; @@ -120,17 +113,10 @@ class PushUnitTest extends UnitTest { mkdirp.sync(downloadTarget); toolsCli.parseArgs(['', UnitTest.COMMAND, "push", switches, "--dir", downloadTarget, '--user', 'foo', '--password', 'password', '--url', 'http://foo.bar/api', '-v']) .then(function (msg) { - if (DRAFT_SITES && switches === "--pages") { - // Verify that the stub was called twice (once for each site), and that the expected message was returned. - expect(stub).to.have.been.calledTwice; - expect(msg).to.contain('4 artifacts successfully'); - expect(msg).to.contain('4 errors'); - } else { - // Verify that the stub was called once, and that the expected message was returned. - expect(stub).to.have.been.calledOnce; - expect(msg).to.contain('2 artifacts successfully'); - expect(msg).to.contain('2 errors'); - } + // Verify that the stub was called once, and that the expected message was returned. + expect(stub).to.have.been.calledOnce; + expect(msg).to.contain('2 artifacts successfully'); + expect(msg).to.contain('2 errors'); }) .catch(function (err) { // Pass the error to the "done" function to indicate a failed test. @@ -214,17 +200,11 @@ class PushUnitTest extends UnitTest { .then(function (msg) { expect(savedOpts).to.exist; expect(savedOpts["publish-now"]).to.exist; - if (DRAFT_SITES && switches === "--pages") { - // Verify that the stub was called twice (once for each site), and that the expected message was returned. - expect(stub).to.have.been.calledTwice; - expect(msg).to.contain('4 artifacts successfully'); - expect(msg).to.contain('4 errors'); - } else { - // Verify that the stub was called once, and that the expected message was returned. - expect(stub).to.have.been.calledOnce; - expect(msg).to.contain('2 artifacts'); - expect(msg).to.contain('2 errors'); - } + + // Verify that the stub was called once, and that the expected message was returned. + expect(stub).to.have.been.calledOnce; + expect(msg).to.contain('2 artifacts'); + expect(msg).to.contain('2 errors'); }) .catch(function (err) { // Pass the error to the "done" function to indicate a failed test. @@ -405,13 +385,8 @@ class PushUnitTest extends UnitTest { let error; toolsCli.parseArgs(['', UnitTest.COMMAND, "push", switches, "-I", "--user", "foo", "--password", "password", "--url", "http://foo.bar/api"]) .then(function (msg) { - if (DRAFT_SITES && switches === "--pages") { - // Verify that the stub was called twice (once for each site), and that the expected message was returned. - expect(stub).to.have.been.calledTwice; - } else { - // Verify that the expected error was specified. - expect(stub).to.have.been.calledOnce; - } + // Verify that the expected error was specified. + expect(stub).to.have.been.calledOnce; expect(msg).to.contain("No items to be pushed"); }) .catch(function (err) { @@ -447,13 +422,8 @@ class PushUnitTest extends UnitTest { let error; toolsCli.parseArgs(['', UnitTest.COMMAND, "push", switches, "--user", "foo", "--password", "password", "--url", "http://foo.bar/api"]) .then(function (msg) { - if (DRAFT_SITES && switches === "--pages") { - // Verify that the stub was called twice (once for each site), and that the expected message was returned. - expect(stub).to.have.been.calledTwice; - } else { - // Verify that the expected error was specified. - expect(stub).to.have.been.calledOnce; - } + // Verify that the expected error was specified. + expect(stub).to.have.been.calledOnce; expect(msg).to.contain("nothing has been modified locally"); }) .catch(function (err) { @@ -544,12 +514,7 @@ class PushUnitTest extends UnitTest { }); it("test successful push of named draft page", function (done) { - // TODO Enable when --draft option is avaiable. - if (!DRAFT_OPTION) { - return done(); - } - - if (switches !== "--pages") { + if (!BaseCommand.DRAFT_SITES || switches !== "--pages") { return done(); } @@ -587,12 +552,7 @@ class PushUnitTest extends UnitTest { }); it("test successful push of named ready and draft page", function (done) { - // TODO Enable when --draft option is avaiable. - if (!DRAFT_OPTION) { - return done(); - } - - if (switches !== "--pages") { + if (!BaseCommand.DRAFT_SITES || switches !== "--pages") { return done(); } @@ -767,15 +727,9 @@ class PushUnitTest extends UnitTest { const downloadTarget = DOWNLOAD_TARGET; toolsCli.parseArgs(['', UnitTest.COMMAND, "push", switches, "--ignore-timestamps", "--dir", downloadTarget, '--user', 'foo', '--password', 'password', '--url', 'http://foo.bar/api','-v']) .then(function (msg) { - if (DRAFT_SITES && switches === "--pages") { - // Verify that the stub was called twice (once for each site), and that the expected message was returned. - expect(stub).to.have.been.calledTwice; - expect(msg).to.contain('4 artifacts'); - } else { - // Verify that the stub was called once, and that the expected message was returned. - expect(stub).to.have.been.calledOnce; - expect(msg).to.contain('2 artifacts'); - } + // Verify that the stub was called once, and that the expected message was returned. + expect(stub).to.have.been.calledOnce; + expect(msg).to.contain('2 artifacts'); }) .catch(function (err) { // Pass the error to the "done" function to indicate a failed test. @@ -790,13 +744,23 @@ class PushUnitTest extends UnitTest { }); }); - it("test push ignore-timestamps working (all sites)", function (done) { - if (switches !== "--sites" && switches !== "--pages") { - return done(); - } - + it("test push ignore-timestamps working (ready items only, by default)", function (done) { const stubList = sinon.stub(helper._fsApi, "listNames"); - stubList.resolves([{name: itemName1, id: "bar", path: itemName1}, {name: itemName2, id: "foo", path: itemName2}, {name: badItem, id: undefined, path: badItem}]); + if (switches.includes("--sites")) { + stubList.resolves([{name: itemName1, id: "foo", path: itemName1, status: "ready"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "draft" + }]); + } else { + stubList.resolves([{name: itemName1, id: "foo", path: itemName1, status: "ready"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "draft" + }, {name: badItem, id: undefined, path: badItem, status: "ready"}]); + } // Stub the helper.pushAllItems method to return a promise that is resolved after emitting events. const stubPush = sinon.stub(helper, "_pushNameList", function (context) { @@ -805,15 +769,11 @@ class PushUnitTest extends UnitTest { setTimeout(function () { const emitter = helper.getEventEmitter(context); if (switches === "--sites") { - // Only the foo and bar sites are in the context site list. + // The context site list only contains the foo site, because it has a ready status. emitter.emit("pushed", {name: itemName1, id: "foo", path: itemName1}); - if (DRAFT_SITES) { - emitter.emit("pushed", {name: itemName2, id: "bar", path: itemName2}); - } } else { - // All three pages are pushed (even the page with no id). - emitter.emit("pushed", {name: itemName1, id: "bar", path: itemName1}); - emitter.emit("pushed", {name: itemName2, id: "foo", path: itemName2}); + // Both ready items are pushed (even the one with no id). + emitter.emit("pushed", {name: itemName1, id: "foo", path: itemName1}); emitter.emit("pushed", {name: badItem, id: undefined, path: badItem}); } stubDeferred.resolve(); @@ -827,49 +787,214 @@ class PushUnitTest extends UnitTest { toolsCli.parseArgs(['', UnitTest.COMMAND, "push", switches, "--ignore-timestamps", "--dir", downloadTarget, '--user', 'foo', '--password', 'password', '--url', 'http://foo.bar/api','-v']) .then(function (msg) { if (switches === "--sites") { - if (DRAFT_SITES) { - // Verify that the stubs were called once, and that the expected number of items were pushed. - expect(stubList).to.have.been.calledOnce; - expect(stubPush).to.have.been.calledOnce; + // Verify that the stubs were called once, and that the expected number of items were pushed. + expect(stubList).to.have.been.calledOnce; + expect(stubPush).to.have.been.calledOnce; + expect(stubPush.args[0][1]).to.have.lengthOf(1); + expect(stubPush.args[0][1][0].id).to.equal("foo"); + expect(msg).to.contain('1 artifact'); + } else { + // Verify that the stubs were called once, and that the expected number of items were pushed. + expect(stubList).to.have.been.calledOnce; + expect(stubPush).to.have.been.calledOnce; + expect(stubPush.args[0][1]).to.have.lengthOf(2); + if ((switches === "-a") || (switches === "-w")) { + expect(stubPush.args[0][1][0]).to.equal("type-1"); + expect(stubPush.args[0][1][1]).to.equal("type-bad-name"); + } else { + expect(stubPush.args[0][1][0].id).to.equal("foo"); + expect(stubPush.args[0][1][1].id).to.not.exist; + if (switches === "--pages") { + expect(stubPush.args[0][2].siteId).to.equal("foo"); + } + } + expect(msg).to.contain('2 artifacts'); + } + }) + .catch(function (err) { + // Pass the error to the "done" function to indicate a failed test. + error = err; + }) + .finally(function () { + // Restore the Stubbed methods. + stubList.restore(); + stubPush.restore(); + + // Call mocha's done function to indicate that the test is over. + done(error); + }); + }); + + it("test push modified working (ready items only, by default)", function (done) { + const stubList = sinon.stub(helper._fsApi, "listNames"); + if (switches.includes("--sites")) { + stubList.resolves([{name: itemName1, id: "foo", path: itemName1, status: "ready"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "draft" + }]); + } else { + stubList.resolves([{name: itemName1, id: "foo", path: itemName1, status: "ready"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "draft" + }, {name: badItem, id: undefined, path: badItem, status: "ready"}]); + } + + const stubHashes = sinon.stub(hashes, "isLocalModified"); + stubHashes.returns(true); + + // Stub the helper.pushAllItems method to return a promise that is resolved after emitting events. + const stubPush = sinon.stub(helper, "_pushNameList", function (context) { + // When the stubbed method is called, return a promise that will be resolved asynchronously. + const stubDeferred = Q.defer(); + setTimeout(function () { + const emitter = helper.getEventEmitter(context); + if (switches === "--sites") { + // The context site list only contains the foo site, because it has a ready status. + emitter.emit("pushed", {name: itemName1, id: "foo", path: itemName1}); + } else { + emitter.emit("pushed", {name: itemName1, id: "foo", path: itemName1}); + + // The item without an id is filtered in JSONItemHelper.listModifiedLocalItemNames(). + if ((switches === "-a") || (switches === "-w")) { + emitter.emit("pushed", {name: badItem, id: undefined, path: badItem}); + } + } + stubDeferred.resolve(); + }, 0); + return stubDeferred.promise; + }); + + // Execute the command to pull the items to the download directory. + let error; + const downloadTarget = DOWNLOAD_TARGET; + toolsCli.parseArgs(['', UnitTest.COMMAND, "push", switches, "--dir", downloadTarget, '--user', 'foo', '--password', 'password', '--url', 'http://foo.bar/api', '-v']) + .then(function (msg) { + if (switches === "--sites") { + // Verify that the stubs were called once, and that the expected number of items were pushed. + expect(stubList).to.have.been.calledOnce; + expect(stubPush).to.have.been.calledOnce; + expect(stubPush.args[0][1]).to.have.lengthOf(1); + expect(stubPush.args[0][1][0].id).to.equal("foo"); + } else { + // Verify that the stubs were called once, and that the expected number of items were pushed. + expect(stubList).to.have.been.calledOnce; + expect(stubPush).to.have.been.calledOnce; + if ((switches === "-a") || (switches === "-w")) { expect(stubPush.args[0][1]).to.have.lengthOf(2); - expect(stubPush.args[0][1][0].id).to.equal("bar"); - expect(stubPush.args[0][1][1].id).to.equal("foo"); + expect(stubPush.args[0][1][0]).to.equal("type-1"); + expect(stubPush.args[0][1][1]).to.equal("type-bad-name"); expect(msg).to.contain('2 artifacts'); } else { - // Verify that the stubs were called once, and that the expected number of items were pushed. - expect(stubList).to.have.been.calledOnce; - expect(stubPush).to.have.been.calledOnce; expect(stubPush.args[0][1]).to.have.lengthOf(1); expect(stubPush.args[0][1][0].id).to.equal("foo"); expect(msg).to.contain('1 artifact'); } + } + }) + .catch(function (err) { + // Pass the error to the "done" function to indicate a failed test. + error = err; + }) + .finally(function () { + // Restore the Stubbed methods. + stubList.restore(); + stubHashes.restore(); + stubPush.restore(); + + // Call mocha's done function to indicate that the test is over. + done(error); + }); + }); + + it("test push ignore-timestamps working (all items)", function (done) { + if (!BaseCommand.DRAFT_SITES && (switches.includes("--sites") || switches.includes("--pages"))) { + return done(); + } + + const stubList = sinon.stub(helper._fsApi, "listNames"); + if (switches.includes("--sites")) { + stubList.resolves([{name: itemName1, id: "foo", path: itemName1, status: "ready"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "draft" + }]); + } else { + stubList.resolves([{name: itemName1, id: "foo", path: itemName1}, { + name: itemName2, + id: "bar", + path: itemName2 + }, {name: badItem, id: undefined, path: badItem}]); + } + + // Stub the helper.pushAllItems method to return a promise that is resolved after emitting events. + const stubPush = sinon.stub(helper, "_pushNameList", function (context) { + // When the stubbed method is called, return a promise that will be resolved asynchronously. + const stubDeferred = Q.defer(); + setTimeout(function () { + const emitter = helper.getEventEmitter(context); + if (switches === "--sites") { + // Only the foo and bar sites are in the context site list. + emitter.emit("pushed", {name: itemName1, id: "foo", path: itemName1}); + emitter.emit("pushed", {name: itemName2, id: "bar", path: itemName2}); } else { - if (DRAFT_SITES) { - // Verify that the stubs were called twice, and that the expected number of items were pushed. - expect(stubList).to.have.been.calledTwice; - expect(stubPush).to.have.been.calledTwice; - expect(stubPush.args[0][1]).to.have.lengthOf(3); - expect(stubPush.args[1][1]).to.have.lengthOf(3); - expect(stubPush.args[0][1][0].id).to.equal("bar"); - expect(stubPush.args[0][1][1].id).to.equal("foo"); - expect(stubPush.args[0][1][2].id).to.not.exist; - expect(stubPush.args[0][2].siteId).to.equal("foo"); - expect(stubPush.args[1][1][0].id).to.equal("bar"); - expect(stubPush.args[1][1][1].id).to.equal("foo"); - expect(stubPush.args[1][1][2].id).to.not.exist; - expect(stubPush.args[1][2].siteId).to.equal("bar"); - expect(msg).to.contain('6 artifacts'); + // All three items are pushed (even the one with no id). + emitter.emit("pushed", {name: itemName1, id: "bar", path: itemName1}); + emitter.emit("pushed", {name: itemName2, id: "foo", path: itemName2}); + emitter.emit("pushed", {name: badItem, id: undefined, path: badItem}); + } + stubDeferred.resolve(); + }, 0); + return stubDeferred.promise; + }); + + // Execute the command to pull the items to the download directory. + let error; + const downloadTarget = DOWNLOAD_TARGET; + toolsCli.parseArgs(['', UnitTest.COMMAND, "push", switches, "--ignore-timestamps", "--ready", "--draft", "--dir", downloadTarget, '--user', 'foo', '--password', 'password', '--url', 'http://foo.bar/api', '-v']) + .then(function (msg) { + if (switches === "--sites") { + // Verify that the stubs were called once, and that the expected number of items were pushed. + expect(stubList).to.have.been.calledOnce; + expect(stubPush).to.have.been.calledOnce; + expect(stubPush.args[0][1]).to.have.lengthOf(2); + expect(stubPush.args[0][1][0].id).to.equal("foo"); + expect(stubPush.args[0][1][1].id).to.equal("bar"); + expect(msg).to.contain('2 artifacts'); + } else if (switches === "--pages") { + // Verify that the stubs were called twice, and that the expected number of items were pushed. + expect(stubList).to.have.been.calledTwice; + expect(stubPush).to.have.been.calledTwice; + expect(stubPush.args[0][1]).to.have.lengthOf(3); + expect(stubPush.args[1][1]).to.have.lengthOf(3); + expect(stubPush.args[0][1][0].id).to.equal("foo"); + expect(stubPush.args[0][1][1].id).to.equal("bar"); + expect(stubPush.args[0][1][2].id).to.not.exist; + expect(stubPush.args[0][2].siteId).to.equal("foo"); + expect(stubPush.args[1][1][0].id).to.equal("foo"); + expect(stubPush.args[1][1][1].id).to.equal("bar"); + expect(stubPush.args[1][1][2].id).to.not.exist; + expect(stubPush.args[1][2].siteId).to.equal("bar"); + expect(msg).to.contain('6 artifacts'); + } else { + // Verify that the stubs were called once, and that the expected number of items were pushed. + expect(stubList).to.have.been.calledOnce; + expect(stubPush).to.have.been.calledOnce; + expect(stubPush.args[0][1]).to.have.lengthOf(3); + if ((switches === "-a") || (switches === "-w")) { + expect(stubPush.args[0][1][0]).to.equal("type-1"); + expect(stubPush.args[0][1][1]).to.equal("type-2"); + expect(stubPush.args[0][1][2]).to.equal("type-bad-name"); } else { - // Verify that the stubs were called once, and that the expected number of items were pushed. - expect(stubList).to.have.been.calledOnce; - expect(stubPush).to.have.been.calledOnce; - expect(stubPush.args[0][1]).to.have.lengthOf(3); - expect(stubPush.args[0][1][0].id).to.equal("bar"); - expect(stubPush.args[0][1][1].id).to.equal("foo"); + expect(stubPush.args[0][1][0].id).to.equal("foo"); + expect(stubPush.args[0][1][1].id).to.equal("bar"); expect(stubPush.args[0][1][2].id).to.not.exist; - expect(stubPush.args[0][2].siteId).to.equal("foo"); - expect(msg).to.contain('3 artifacts'); } + expect(msg).to.contain('3 artifacts'); } }) .catch(function (err) { @@ -886,13 +1011,26 @@ class PushUnitTest extends UnitTest { }); }); - it("test push modified working (all sites)", function (done) { - if (switches !== "--sites" && switches !== "--pages") { + it("test push modified working (all items)", function (done) { + if (!BaseCommand.DRAFT_SITES && (switches.includes("--sites") || switches.includes("--pages"))) { return done(); } const stubList = sinon.stub(helper._fsApi, "listNames"); - stubList.resolves([{name: itemName1, id: "foo", path: itemName1}, {name: itemName2, id: "bar", path: itemName2}, {name: badItem, id: undefined, path: badItem}]); + if (switches.includes("--sites")) { + stubList.resolves([{name: itemName1, id: "foo", path: itemName1, status: "ready"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "draft" + }]); + } else { + stubList.resolves([{name: itemName1, id: "foo", path: itemName1}, { + name: itemName2, + id: "bar", + path: itemName2 + }, {name: badItem, id: undefined, path: badItem}]); + } const stubHashes = sinon.stub(hashes, "isLocalModified"); stubHashes.returns(true); @@ -903,10 +1041,15 @@ class PushUnitTest extends UnitTest { const stubDeferred = Q.defer(); setTimeout(function () { const emitter = helper.getEventEmitter(context); + // For sites, only the foo and bar sites are in the context site list. - // For pages, the page without an id is filtered in JSONItemHelper.listModifiedLocalItemNames(). emitter.emit("pushed", {name: itemName1, id: "foo", path: itemName1}); emitter.emit("pushed", {name: itemName2, id: "bar", path: itemName2}); + + // The item without an id is filtered in JSONItemHelper.listModifiedLocalItemNames(). + if ((switches === "-a") || (switches === "-w")) { + emitter.emit("pushed", {name: badItem, id: undefined, path: badItem}); + } stubDeferred.resolve(); }, 0); return stubDeferred.promise; @@ -915,40 +1058,30 @@ class PushUnitTest extends UnitTest { // Execute the command to pull the items to the download directory. let error; const downloadTarget = DOWNLOAD_TARGET; - toolsCli.parseArgs(['', UnitTest.COMMAND, "push", switches, "--dir", downloadTarget, '--user', 'foo', '--password', 'password', '--url', 'http://foo.bar/api','-v']) + toolsCli.parseArgs(['', UnitTest.COMMAND, "push", switches, "--ready", "--draft", "--dir", downloadTarget, '--user', 'foo', '--password', 'password', '--url', 'http://foo.bar/api', '-v']) .then(function (msg) { - if (switches === "--sites") { - if (DRAFT_SITES) { - // Verify that the stubs were called once, and that the expected number of items were pushed. - expect(stubList).to.have.been.calledOnce; - expect(stubPush).to.have.been.calledOnce; - expect(stubPush.args[0][1]).to.have.lengthOf(2); - expect(stubPush.args[0][1][0].id).to.equal("foo"); - expect(stubPush.args[0][1][1].id).to.equal("bar"); - expect(msg).to.contain('2 artifacts'); - } else { - // Verify that the stubs were called once, and that the expected number of items were pushed. - expect(stubList).to.have.been.calledOnce; - expect(stubPush).to.have.been.calledOnce; - expect(stubPush.args[0][1]).to.have.lengthOf(1); - expect(stubPush.args[0][1][0].id).to.equal("foo"); - } + if (switches === "--pages") { + // Verify that the stubs were called twice, and that the expected number of items were pushed. + expect(stubList).to.have.been.calledTwice; + expect(stubPush).to.have.been.calledTwice; + expect(stubPush.args[0][1]).to.have.lengthOf(2); + expect(stubPush.args[1][1]).to.have.lengthOf(2); + expect(stubPush.args[0][1][0].id).to.equal("foo"); + expect(stubPush.args[0][1][1].id).to.equal("bar"); + expect(stubPush.args[1][1][0].id).to.equal("foo"); + expect(stubPush.args[1][1][1].id).to.equal("bar"); + expect(msg).to.contain('4 artifacts'); } else { - if (DRAFT_SITES) { - // Verify that the stubs were called twice, and that the expected number of items were pushed. - expect(stubList).to.have.been.calledTwice; - expect(stubPush).to.have.been.calledTwice; - expect(stubPush.args[0][1]).to.have.lengthOf(2); - expect(stubPush.args[1][1]).to.have.lengthOf(2); - expect(stubPush.args[0][1][0].id).to.equal("foo"); - expect(stubPush.args[0][1][1].id).to.equal("bar"); - expect(stubPush.args[1][1][0].id).to.equal("foo"); - expect(stubPush.args[1][1][1].id).to.equal("bar"); - expect(msg).to.contain('4 artifacts'); + // Verify that the stubs were called once, and that the expected number of items were pushed. + expect(stubList).to.have.been.calledOnce; + expect(stubPush).to.have.been.calledOnce; + if ((switches === "-a") || (switches === "-w")) { + expect(stubPush.args[0][1]).to.have.lengthOf(3); + expect(stubPush.args[0][1][0]).to.equal("type-1"); + expect(stubPush.args[0][1][1]).to.equal("type-2"); + expect(stubPush.args[0][1][2]).to.equal("type-bad-name"); + expect(msg).to.contain('3 artifacts'); } else { - // Verify that the stubs were called once, and that the expected number of items were pushed. - expect(stubList).to.have.been.calledOnce; - expect(stubPush).to.have.been.calledOnce; expect(stubPush.args[0][1]).to.have.lengthOf(2); expect(stubPush.args[0][1][0].id).to.equal("foo"); expect(stubPush.args[0][1][1].id).to.equal("bar"); @@ -971,13 +1104,22 @@ class PushUnitTest extends UnitTest { }); }); - it("test push ignore-timestamps working (ready sites)", function (done) { - if (switches !== "--sites" && switches !== "--pages") { - return done(); - } - + it("test push ignore-timestamps working (ready items)", function (done) { const stubList = sinon.stub(helper._fsApi, "listNames"); - stubList.resolves([{name: itemName1, id: "foo", path: itemName1}, {name: itemName2, id: "bar", path: itemName2}, {name: badItem, id: undefined, path: badItem}]); + if (switches.includes("--sites")) { + stubList.resolves([{name: itemName1, id: "foo", path: itemName1, status: "ready"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "draft" + }]); + } else { + stubList.resolves([{name: itemName1, id: "foo", path: itemName1}, { + name: itemName2, + id: "bar", + path: itemName2 + }, {name: badItem, id: undefined, path: badItem}]); + } // Stub the helper.pushAllItems method to return a promise that is resolved after emitting events. const stubPush = sinon.stub(helper, "_pushNameList", function (context) { @@ -1013,9 +1155,18 @@ class PushUnitTest extends UnitTest { expect(msg).to.contain('1 artifact'); } else { expect(stubPush.args[0][1]).to.have.lengthOf(3); - expect(stubPush.args[0][1][0].id).to.equal("foo"); - expect(stubPush.args[0][1][1].id).to.equal("bar"); - expect(stubPush.args[0][1][2].id).to.not.exist; + if ((switches === "-a") || (switches === "-w")) { + expect(stubPush.args[0][1][0]).to.equal("type-1"); + expect(stubPush.args[0][1][1]).to.equal("type-2"); + expect(stubPush.args[0][1][2]).to.equal("type-bad-name"); + } else { + expect(stubPush.args[0][1][0].id).to.equal("foo"); + expect(stubPush.args[0][1][1].id).to.equal("bar"); + expect(stubPush.args[0][1][2].id).to.not.exist; + if (switches === "--pages") { + expect(stubPush.args[0][2].siteId).to.equal("foo"); + } + } expect(msg).to.contain('3 artifacts'); } }) @@ -1033,13 +1184,22 @@ class PushUnitTest extends UnitTest { }); }); - it("test push modified working (ready sites)", function (done) { - if (switches !== "--sites" && switches !== "--pages") { - return done(); - } - + it("test push modified working (ready items)", function (done) { const stubList = sinon.stub(helper._fsApi, "listNames"); - stubList.resolves([{name: itemName1, id: "foo", path: itemName1}, {name: itemName2, id: "bar", path: itemName2}, {name: badItem, id: undefined, path: badItem}]); + if (switches.includes("--sites")) { + stubList.resolves([{name: itemName1, id: "foo", path: itemName1, status: "ready"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "draft" + }]); + } else { + stubList.resolves([{name: itemName1, id: "foo", path: itemName1}, { + name: itemName2, + id: "bar", + path: itemName2 + }, {name: badItem, id: undefined, path: badItem}]); + } const stubHashes = sinon.stub(hashes, "isLocalModified"); stubHashes.returns(true); @@ -1054,10 +1214,13 @@ class PushUnitTest extends UnitTest { // Only one site (foo) is a ready site. emitter.emit("pushed", {name: itemName1, id: "foo", path: itemName1}); } else { - // Two pages will be pushed for the ready site (foo). The page with no id will be filtered - // in JSONItemHelper.listModifiedLocalItemNames(). emitter.emit("pushed", {name: itemName1, id: "foo", path: itemName1}); emitter.emit("pushed", {name: itemName2, id: "bar", path: itemName2}); + + // The item without an id is filtered in JSONItemHelper.listModifiedLocalItemNames(). + if ((switches === "-a") || (switches === "-w")) { + emitter.emit("pushed", {name: badItem, id: undefined, path: badItem}); + } } stubDeferred.resolve(); }, 0); @@ -1077,10 +1240,18 @@ class PushUnitTest extends UnitTest { expect(stubPush.args[0][1][0].id).to.equal("foo"); expect(msg).to.contain('1 artifact'); } else { - expect(stubPush.args[0][1]).to.have.lengthOf(2); - expect(stubPush.args[0][1][0].id).to.equal("foo"); - expect(stubPush.args[0][1][1].id).to.equal("bar"); - expect(msg).to.contain('2 artifacts'); + if ((switches === "-a") || (switches === "-w")) { + expect(stubPush.args[0][1]).to.have.lengthOf(3); + expect(stubPush.args[0][1][0]).to.equal("type-1"); + expect(stubPush.args[0][1][1]).to.equal("type-2"); + expect(stubPush.args[0][1][2]).to.equal("type-bad-name"); + expect(msg).to.contain('3 artifacts'); + } else { + expect(stubPush.args[0][1]).to.have.lengthOf(2); + expect(stubPush.args[0][1][0].id).to.equal("foo"); + expect(stubPush.args[0][1][1].id).to.equal("bar"); + expect(msg).to.contain('2 artifacts'); + } } }) .catch(function (err) { @@ -1098,18 +1269,27 @@ class PushUnitTest extends UnitTest { }); }); - it("test push ignore-timestamps working (draft sites)", function (done) { - // TODO Enable when --draft option is avaiable. - if (!DRAFT_OPTION) { - return done(); - } - - if (switches !== "--sites" && switches !== "--pages") { + it("test push ignore-timestamps working (draft items)", function (done) { + if (!BaseCommand.DRAFT_SITES && (switches.includes("--sites") || switches.includes("--pages"))) { return done(); } const stubList = sinon.stub(helper._fsApi, "listNames"); - stubList.resolves([{name: itemName1, id: "foo", path: itemName1}, {name: itemName2, id: "bar", path: itemName2}, {name: badItem, id: undefined, path: badItem}]); + if (switches.includes("--sites")) { + stubList.resolves([{name: itemName1, id: "foo", path: itemName1, status: "ready"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "draft" + }]); + } else { + stubList.resolves([{name: itemName1, id: "foo", path: itemName1, status: "draft"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "draft" + }, {name: badItem, id: undefined, path: badItem, status: "draft"}]); + } // Stub the helper._pushNameList method to return a promise that is resolved after emitting events. const stubPush = sinon.stub(helper, "_pushNameList", function (context) { @@ -1121,8 +1301,6 @@ class PushUnitTest extends UnitTest { // Only one site (bar) is a draft site. emitter.emit("pushed", {name: itemName2, id: "bar", path: itemName2}); } else { - // Two pages will be pushed for the draft site (bar). The page with no id will be filtered - // in JSONItemHelper.listModifiedLocalItemNames(). emitter.emit("pushed", {name: itemName1, id: "foo", path: itemName1}); emitter.emit("pushed", {name: itemName2, id: "bar", path: itemName2}); emitter.emit("pushed", {name: badItem, id: undefined, path: badItem}); @@ -1146,9 +1324,18 @@ class PushUnitTest extends UnitTest { expect(msg).to.contain('1 artifact'); } else { expect(stubPush.args[0][1]).to.have.lengthOf(3); - expect(stubPush.args[0][1][0].id).to.equal("foo"); - expect(stubPush.args[0][1][1].id).to.equal("bar"); - expect(stubPush.args[0][1][2].id).to.not.exist; + if ((switches === "-a") || (switches === "-w")) { + expect(stubPush.args[0][1][0]).to.equal("type-1"); + expect(stubPush.args[0][1][1]).to.equal("type-2"); + expect(stubPush.args[0][1][2]).to.equal("type-bad-name"); + } else { + expect(stubPush.args[0][1][0].id).to.equal("foo"); + expect(stubPush.args[0][1][1].id).to.equal("bar"); + expect(stubPush.args[0][1][2].id).to.not.exist; + if (switches === "--pages") { + expect(stubPush.args[0][2].siteId).to.equal("bar"); + } + } expect(msg).to.contain('3 artifacts'); } }) @@ -1166,18 +1353,27 @@ class PushUnitTest extends UnitTest { }); }); - it("test push modified working (draft sites)", function (done) { - // TODO Enable when --draft option is avaiable. - if (!DRAFT_OPTION) { - return done(); - } - - if (switches !== "--sites" && switches !== "--pages") { + it("test push modified working (draft items)", function (done) { + if (!BaseCommand.DRAFT_SITES && (switches.includes("--sites") || switches.includes("--pages"))) { return done(); } const stubList = sinon.stub(helper._fsApi, "listNames"); - stubList.resolves([{name: itemName1, id: "foo", path: itemName1}, {name: itemName2, id: "bar", path: itemName2}, {name: badItem, id: undefined, path: badItem}]); + if (switches.includes("--sites")) { + stubList.resolves([{name: itemName1, id: "foo", path: itemName1, status: "ready"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "draft" + }]); + } else { + stubList.resolves([{name: itemName1, id: "foo", path: itemName1, status: "draft"}, { + name: itemName2, + id: "bar", + path: itemName2, + status: "draft" + }, {name: badItem, id: undefined, path: badItem, status: "draft"}]); + } const stubHashes = sinon.stub(hashes, "isLocalModified"); stubHashes.returns(true); @@ -1192,10 +1388,13 @@ class PushUnitTest extends UnitTest { // Only one site (bar) is a draft site. emitter.emit("pushed", {name: itemName2, id: "bar", path: itemName2}); } else { - // Two pages will be pushed for the draft site (bar). The page with no id will be filtered - // in JSONItemHelper.listModifiedLocalItemNames(). emitter.emit("pushed", {name: itemName1, id: "foo", path: itemName1}); emitter.emit("pushed", {name: itemName2, id: "bar", path: itemName2}); + + // The item without an id is filtered in JSONItemHelper.listModifiedLocalItemNames(). + if ((switches === "-a") || (switches === "-w")) { + emitter.emit("pushed", {name: badItem, id: undefined, path: badItem}); + } } stubDeferred.resolve(); }, 0); @@ -1215,10 +1414,18 @@ class PushUnitTest extends UnitTest { expect(stubPush.args[0][1][0].id).to.equal("bar"); expect(msg).to.contain('1 artifact'); } else { - expect(stubPush.args[0][1]).to.have.lengthOf(2); - expect(stubPush.args[0][1][0].id).to.equal("foo"); - expect(stubPush.args[0][1][1].id).to.equal("bar"); - expect(msg).to.contain('2 artifacts'); + if ((switches === "-a") || (switches === "-w")) { + expect(stubPush.args[0][1]).to.have.lengthOf(3); + expect(stubPush.args[0][1][0]).to.equal("type-1"); + expect(stubPush.args[0][1][1]).to.equal("type-2"); + expect(stubPush.args[0][1][2]).to.equal("type-bad-name"); + expect(msg).to.contain('3 artifacts'); + } else { + expect(stubPush.args[0][1]).to.have.lengthOf(2); + expect(stubPush.args[0][1][0].id).to.equal("foo"); + expect(stubPush.args[0][1][1].id).to.equal("bar"); + expect(msg).to.contain('2 artifacts'); + } } }) .catch(function (err) { @@ -1305,15 +1512,9 @@ class PushUnitTest extends UnitTest { const downloadTarget = DOWNLOAD_TARGET; toolsCli.parseArgs(['', UnitTest.COMMAND, "push", switches, "--create-only", "--dir", downloadTarget, '--user', 'foo', '--password', 'password', '--url', 'http://foo.bar/api','-v']) .then(function (msg) { - if (DRAFT_SITES && switches === "--pages") { - // Verify that the stub was called twice (once for each site), and that the expected message was returned. - expect(stub).to.have.been.calledTwice; - expect(msg).to.contain('4 artifacts'); - } else { - // Verify that the stub was called once, and that the expected message was returned. - expect(stub).to.have.been.calledOnce; - expect(msg).to.contain('2 artifacts'); - } + // Verify that the stub was called once, and that the expected message was returned. + expect(stub).to.have.been.calledOnce; + expect(msg).to.contain('2 artifacts'); // Verify that the createOnly option was passed through. expect(stub.firstCall.args[1].createOnly).to.equal(true); @@ -1711,15 +1912,9 @@ class PushUnitTest extends UnitTest { error = new Error("The command should have failed."); }) .catch(function (err) { - if (DRAFT_SITES && switches === "--pages") { - // Verify that the stub was called twice (once for each site), and that the expected message was returned. - expect(stubPush).to.have.been.calledTwice; - expect(err.message).to.contain('2 errors'); - } else { - // Verify that the stub was called once, and that the expected message was returned. - expect(stubPush).to.have.been.calledOnce; - expect(err.message).to.contain('1 error'); - } + // Verify that the stub was called once, and that the expected message was returned. + expect(stubPush).to.have.been.calledOnce; + expect(err.message).to.contain('1 error'); }) .catch(function (err) { // Pass the error to the "done" function to indicate a failed test. @@ -1817,17 +2012,10 @@ class PushUnitTest extends UnitTest { // Verify that the prompt stub was not called. expect(stubPrompt).to.not.have.been.called; - if (DRAFT_SITES && switches === "--pages") { - // Verify that the stub was called twice (once for each site), and that the expected message was returned. - expect(stubPush).to.have.been.calledTwice; - expect(msg).to.contain('4 artifacts successfully'); - expect(msg).to.contain('4 errors'); - } else { - // Verify that the push stub was called once, and that the expected message was returned. - expect(stubPush).to.have.been.calledOnce; - expect(msg).to.contain('2 artifacts successfully'); - expect(msg).to.contain('2 errors'); - } + // Verify that the push stub was called once, and that the expected message was returned. + expect(stubPush).to.have.been.calledOnce; + expect(msg).to.contain('2 artifacts successfully'); + expect(msg).to.contain('2 errors'); }) .catch(function (err) { // Pass the error to the "done" function to indicate a failed test. @@ -1889,17 +2077,10 @@ class PushUnitTest extends UnitTest { // Verify that the prompt stub was not called. expect(stubPrompt).to.not.have.been.called; - if (DRAFT_SITES && switches === "--pages") { - // Verify that the stub was called twice (once for each site), and that the expected message was returned. - expect(stubPush).to.have.been.calledTwice; - expect(msg).to.contain('4 artifacts successfully'); - expect(msg).to.contain('4 errors'); - } else { - // Verify that the push stub was called once, and that the expected message was returned. - expect(stubPush).to.have.been.calledOnce; - expect(msg).to.contain('2 artifacts successfully'); - expect(msg).to.contain('2 errors'); - } + // Verify that the push stub was called once, and that the expected message was returned. + expect(stubPush).to.have.been.calledOnce; + expect(msg).to.contain('2 artifacts successfully'); + expect(msg).to.contain('2 errors'); }) .catch(function (err) { // Pass the error to the "done" function to indicate a failed test. @@ -2056,17 +2237,10 @@ class PushUnitTest extends UnitTest { // Verify that the prompt stub was called once. expect(stubPrompt).to.have.been.calledOnce; - if (DRAFT_SITES && switches === "--pages") { - // Verify that the stub was called twice (once for each site), and that the expected message was returned. - expect(stubPush).to.have.been.calledTwice; - expect(msg).to.contain('4 artifacts successfully'); - expect(msg).to.contain('4 errors'); - } else { - // Verify that the push stub was called once, and that the expected message was returned. - expect(stubPush).to.have.been.calledOnce; - expect(msg).to.contain('2 artifacts successfully'); - expect(msg).to.contain('2 errors'); - } + // Verify that the push stub was called once, and that the expected message was returned. + expect(stubPush).to.have.been.calledOnce; + expect(msg).to.contain('2 artifacts successfully'); + expect(msg).to.contain('2 errors'); }) .catch(function (err) { // Pass the error to the "done" function to indicate a failed test. @@ -2252,36 +2426,6 @@ class PushUnitTest extends UnitTest { }); }); - it("should fail if both ready and draft specified", function (done) { - // TODO Enable when --draft option is avaiable. - if (!DRAFT_OPTION) { - return done(); - } - - const stubInit = sinon.stub(manifests, "initializeManifests"); - stubInit.resolves(true); - - let error; - toolsCli.parseArgs(['', UnitTest.COMMAND, command, switches, "--ready", "--draft", "--user", "foo", "--password", "password", "--url", "http://foo.bar/api"]) - .then(function () { - // This is not expected. Pass the error to the "done" function to indicate a failed test. - error = new Error("The command should have failed."); - }) - .catch(function (err) { - expect(err.message).to.contain("cannot specifiy both ready and draft"); - }) - .catch (function (err) { - // Pass the error to the "done" function to indicate a failed test. - error = err; - }) - .finally(function () { - stubInit.restore(); - - // Call mocha's done function to indicate that the test is over. - done(error); - }); - }); - it("should fail if both ready and manifest specified", function (done) { const stubInit = sinon.stub(manifests, "initializeManifests"); stubInit.resolves(true); @@ -2316,11 +2460,6 @@ class PushUnitTest extends UnitTest { }); it("should fail if both draft and manifest specified", function (done) { - // TODO Enable when --draft option is avaiable. - if (!DRAFT_OPTION) { - return done(); - } - const stubInit = sinon.stub(manifests, "initializeManifests"); stubInit.resolves(true); diff --git a/CLI/test/unit/render.test.js b/CLI/test/unit/render.test.js index e8d958c..a80ad7f 100644 --- a/CLI/test/unit/render.test.js +++ b/CLI/test/unit/render.test.js @@ -68,7 +68,7 @@ describe("Test Render command", function () { let error; toolsCli.parseArgs(['', process.cwd() + '/index.js', 'render', '--user', 'uname', '--password', 'pwd', '--url', 'http://foo.bar/api']) - .then(function (msg) { + .then(function () { // The stub should only have been called once, and it should have been before the spy. expect(stubJob).to.have.been.calledOnce; expect(stubJob.firstCall.args[1].mode).to.equal("UPDATE"); @@ -92,7 +92,7 @@ describe("Test Render command", function () { let error; toolsCli.parseArgs(['', process.cwd() + '/index.js', 'render', '-rv', '--user', 'uname', '--password', 'pwd', '--url', 'http://foo.bar/api']) - .then(function (msg) { + .then(function () { // The stub should only have been called once, and it should have been before the spy. expect(stubJob).to.have.been.calledOnce; expect(stubJob.firstCall.args[1].mode).to.equal("REBUILD"); diff --git a/README.md b/README.md index bcbccd4..8399256 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ Then follow the Getting Started instructions below, to configure and start using ### Getting Started - After you successfully install the wchtools CLI, initialize the username and the API URL for your Watson Content Hub tenant. Obtain the API URL from the "Hub Information" dialog, which is available from a drop-down menu off the username on the top navigation bar of the content hub authoring UI. The API URL is of the form: https://{tenant-host}/api/{tenant-id} + After you successfully install the wchtools CLI, initialize the username and the API URL for your Watson Content Hub tenant. Obtain the API URL from the "Hub Information" dialog, which is available from the "About" flyout menu off the left navigation pane of the Watson Content Hub authoring UI. The API URL is of the form: https://{tenant-host}/api/{tenant-id} #### Initializing wchtools with a username and API URL for a non-federated IBM id @@ -288,7 +288,7 @@ The resulting my_deletions manifest would contain all of the deleted artifacts t When comparing two directories or a source directory and a target WCH tenant, any manifest files read or written by the compare command will be loaded or saved using the source directory as identified by the --source argument. When comparing two Watson Content Hub tenants, any manifest files read or written by the compare command will be loaded or saved using the current working directory where the command is executed from. -##### Limitating the scope of the comparison +##### Limiting the scope of the comparison In some scenarios, the development tenant may have more artifacts than you want to consider migrating from development to staging/production (eg, additional development-only test artifacts). To restrict a compare action to only consider a subset of files, the --manifest argument can be used, pointing to a manifest of the total set of artifacts that you want to include in the comparison. This option requires you to keep an up to date manifest of everything you want considered for migration between the tenants, and is not a default or necessarily commonly used option. @@ -571,7 +571,7 @@ The manifest created from this command will include all of the ready artifacts i #### Defaults - By default, wchtools CLI pushes only the authoring artifacts and web resources that are not modified, since the last successful push or pull. To push or pull artifacts again whether they are modified or not since the last successful push or pull, use the -I option to Ignore-timestamps. + By default, wchtools CLI pushes and pulls only the authoring artifacts and web resources that are "ready" (not draft)), and have been modified since the last successful push or pull. To push or pull artifacts again whether they are modified or not since the last successful push or pull, use the -I option to Ignore-timestamps. To push or pull "draft" authoring artifacts, use the --draft option. An initial push of a starter kit or sample package is done to populate the initial authoring artifacts. Those authoring artifacts and successive ones are typically manipulated in the Watson Content Hub web based Authoring UI and not locally on the filesystem. Web resource artifacts such as html, css, js, and handlebars templates are managed and edited externally and pushed to the Watson Content Hub with the wchtools CLI utility. Therefore, the default is to push and pull only web resource artifacts, if no options are specified to the push and pull commands. @@ -583,14 +583,22 @@ The manifest created from this command will include all of the ready artifacts i wchtools pull -act - Use the following command to pull assets, content, and types, ignoring timestamps. This allows you to pull these artifacts whether they were modified or not since the last successful pull or push, to or from this working directory. + Use the following command to pull assets, content, and types, ignoring timestamps. This allows you to pull these artifacts whether they were modified or not since the last successful pull or push, to or from this working directory. - wchtools pull -act --I + wchtools pull -act -I Use the following command to pull to a specific directory. wchtools pull --dir + Use the following command to pull draft assets and content artifacts. + + wchtools pull -ac --draft + + Use the following command to pull ready AND draft assets and content artifacts. + + wchtools pull -ac --draft --ready + Pushing and pulling assumes the / folder structure that was described earlier. You can specify a more granular folder structure when pushing or pulling web assets, content types, layouts, and layout mappings. By using the --path option, you can specify a path below the // folder. For example, consider a working directory with an assets/ subfolder, and the assets folder contains its own subfolders: simpleSpa , topNav, and sideNav. - To push only the web assets under a folder called /topNav, you would use diff --git a/authoring-api/JSONItemHelper.js b/authoring-api/JSONItemHelper.js index 3a9bea0..2628ce5 100644 --- a/authoring-api/JSONItemHelper.js +++ b/authoring-api/JSONItemHelper.js @@ -367,14 +367,14 @@ class JSONItemHelper extends BaseHelper { deferred.reject(err); }); - // After the promise has been resolved, update the last pull timestamp (but only if there were no errors.) + // After the promise has been resolved, update the last pull timestamp. return deferred.promise .then(function (items) { - const readyOnly = options.getRelevantOption(context, opts, "filterReady"); - const draftOnly = options.getRelevantOption(context, opts, "filterDraft"); const filterPath = options.getRelevantOption(context, opts, "filterPath"); - if ((context.pullErrorCount === 0) && !readyOnly && !draftOnly && !filterPath) { - hashes.setLastPullTimestamp(context, helper._fsApi.getDir(context, opts), timestamp, opts); + + // Only update the last pull timestamp if there were no errors and items are not being filtered by path. + if ((context.pullErrorCount === 0) && !filterPath) { + helper._setLastPullTimestamps(context, timestamp, opts); } const emitter = helper.getEventEmitter(context); if (deletions && emitter) { @@ -430,14 +430,14 @@ class JSONItemHelper extends BaseHelper { deferred.reject(err); }); - // After the promise has been resolved, update the last pull timestamp (but only if there were no errors.) + // After the promise has been resolved, update the last pull timestamp. return deferred.promise .then(function (items) { - const readyOnly = options.getRelevantOption(context, opts, "filterReady"); - const draftOnly = options.getRelevantOption(context, opts, "filterDraft"); const filterPath = options.getRelevantOption(context, opts, "filterPath"); - if ((context.pullErrorCount === 0) && !readyOnly && !draftOnly && !filterPath) { - hashes.setLastPullTimestamp(context, helper._fsApi.getDir(context, opts), timestamp, opts); + + // Only update the last pull timestamp if there were no errors and items are not being filtered by path. + if ((context.pullErrorCount === 0) && !filterPath) { + helper._setLastPullTimestamps(context, timestamp, opts); } return items; }) @@ -446,6 +446,82 @@ class JSONItemHelper extends BaseHelper { }); } + /** + * Get the timestamp for the last "similar" pull operation. + * + * @example "2017-01-16T22:30:05.928Z" + * + * @param {Object} context The API context to be used for this operation. + * @param {Object} opts The API options to be used for this operation. + * + * @returns {Object} The timestamp for the last "similar" pull operation, or undefined. + */ + getLastPullTimestamp(context, opts) { + const timestamps = this._getLastPullTimestamps(context, opts); + + const readyOnly = options.getRelevantOption(context, opts, "filterReady"); + const draftOnly = options.getRelevantOption(context, opts, "filterDraft"); + if (readyOnly) { + // A ready-only pull operation will use the ready timestamp. + return timestamps["ready"]; + } else if (draftOnly) { + // A draft-only pull operation will use the draft timestamp. + return timestamps["draft"]; + } else { + // A ready-and-draft pull operation will use the older timestamp to make sure all modified items are pulled. + return utils.getOldestTimestamp([timestamps["draft"], timestamps["ready"]]); + } + } + + /** + * Get the timestamp data for the last pull operation, converting to the new draft/ready format if needed. + * + * @example {"draft": "2017-01-16T22:30:05.928Z", "ready": "2017-01-16T22:30:05.928Z"} + * + * @param {Object} context The API context to be used for this operation. + * @param {Object} opts The API options to be used for this operation. + * + * @returns {Object} The last pull timestamp data. + */ + _getLastPullTimestamps(context, opts) { + const dir = this._fsApi.getDir(context, opts); + const timestamps = hashes.getLastPullTimestamp(context, dir, opts); + + if (typeof timestamps === "string") { + // Convert from a single timestamp value to the new draft/ready format. + return {"draft": timestamps, "ready": timestamps}; + } else { + // Return the existing data, or an empty object if there is no existing data. + return timestamps || {}; + } + } + + /** + * Set the timestamp data for the last pull operation. + * + * @param {Object} context The API context to be used for this operation. + * @param {Date} timestamp The current timestamp to be used. + * @param {Object} opts The API options to be used for this operation. + */ + _setLastPullTimestamps(context, timestamp, opts) { + const pullTimestamps = this._getLastPullTimestamps(context, opts); + + // Store separate pull timestamps for draft and ready. + const readyOnly = options.getRelevantOption(context, opts, "filterReady"); + const draftOnly = options.getRelevantOption(context, opts, "filterDraft"); + if (!draftOnly) { + // Store the ready timestamp if the operation is not draft only. + pullTimestamps["ready"] = timestamp; + } + if (!readyOnly) { + // Store the draft timestamp if the operation is not ready only. + pullTimestamps["draft"] = timestamp; + } + + const dir = this._fsApi.getDir(context, opts); + hashes.setLastPullTimestamp(context, dir, pullTimestamps, opts); + } + /** * Updates the manifest with results of a list operation. * @@ -728,7 +804,7 @@ class JSONItemHelper extends BaseHelper { getModifiedRemoteItems (context, flags, opts) { const helper = this; const dir = helper._fsApi.getPath(context, opts); - return helper._restApi.getModifiedItems(context, hashes.getLastPullTimestamp(context, dir, opts), opts) + return helper._restApi.getModifiedItems(context, helper.getLastPullTimestamp(context, opts), opts) .then(function (items) { const results = items.filter(function (item) { try { @@ -1355,6 +1431,25 @@ class JSONItemHelper extends BaseHelper { return deferred.promise; } + /** + * Get the status of the given item. + * + * @param {Object} context The API context to be used for this operation. + * @param {Object} item The item for which to get the status. + * @param {Object} opts The options to be used for this operations. + * + * @returns {String} "ready" or "draft". + * + * @protected + */ + getStatus(context, item, opts) { + if (item && item.status && item.status === "draft") { + return "draft"; + } else { + return "ready"; + } + } + /** * Filter the given list of items before completing the pull operation. * @@ -1372,13 +1467,15 @@ class JSONItemHelper extends BaseHelper { const draftOnly = options.getRelevantOption(context, opts, "filterDraft"); if (readyOnly) { // Filter out any items that are not ready. + const self = this; itemList = itemList.filter(function (item) { - return (!item.status || item.status === "ready"); + return (self.getStatus(context, item, opts) === "ready"); }); } else if (draftOnly) { // Filter out any items that are not draft. + const self = this; itemList = itemList.filter(function (item) { - return (item.status === "draft"); + return (self.getStatus(context, item, opts) === "draft"); }); } diff --git a/authoring-api/assetsHelper.js b/authoring-api/assetsHelper.js index fd23d75..f02318d 100644 --- a/authoring-api/assetsHelper.js +++ b/authoring-api/assetsHelper.js @@ -44,9 +44,6 @@ const WAIT_FOR_CLOSE = process.env.WCHTOOLS_WAIT_FOR_CLOSE || false; const singleton = Symbol(); const singletonEnforcer = Symbol(); -/** - * High-level functionality for managing assets on the local file system and through the Content Hub API. - */ /** * Helper class for asset artifacts. * @@ -859,10 +856,9 @@ class AssetsHelper extends BaseHelper { } }) .then(function (items) { - const readyOnly = options.getRelevantOption(context, opts, "filterReady"); - const draftOnly = options.getRelevantOption(context, opts, "filterDraft"); const filterPath = options.getRelevantOption(context, opts, "filterPath"); - if ((context.pullErrorCount === 0) && !readyOnly && !draftOnly && !filterPath) { + + if ((context.pullErrorCount === 0) && !filterPath) { // Only update the last pull timestamp if there was no filtering and no pull errors. helper._setLastPullTimestamps(context, timestamp, opts); } @@ -933,10 +929,9 @@ class AssetsHelper extends BaseHelper { } }) .then(function (items) { - const readyOnly = options.getRelevantOption(context, opts, "filterReady"); - const draftOnly = options.getRelevantOption(context, opts, "filterDraft"); const filterPath = options.getRelevantOption(context, opts, "filterPath"); - if ((context.pullErrorCount === 0) && !readyOnly && !draftOnly && !filterPath) { + + if ((context.pullErrorCount === 0) && !filterPath) { // Only update the last pull timestamp if there was no filtering and no pull errors. helper._setLastPullTimestamps(context, timestamp, opts); } @@ -985,9 +980,6 @@ class AssetsHelper extends BaseHelper { } }); - // Get the timestamp to set before we call the REST API. - const timestamp = new Date(); - let readyResults; const concurrentLimit = options.getRelevantOption(context, opts, "concurrent-limit", helper.getArtifactName()); const readyOnly = options.getRelevantOption(context, opts, "filterReady"); @@ -1046,11 +1038,6 @@ class AssetsHelper extends BaseHelper { }) .then(function (assets) { helper._updateManifest(context, assets, opts); - // Keep track of the timestamp of this operation, but only if there was no filtering and no errors. - const filterPath = options.getRelevantOption(context, opts, "filterPath"); - if ((errorCount === 0) && !readyOnly && !draftOnly && !filterPath) { - helper._setLastPushTimestamps(context, timestamp, opts); - } return assets; }) .finally(function () { @@ -1423,9 +1410,6 @@ class AssetsHelper extends BaseHelper { context.filterRetryPush = helper.filterRetryPush.bind(this); } - // Get the timestamp to set before we call the REST API. - const timestamp = new Date(); - // Throttle the number of resources to be pushed concurrently, using the currently configured limit. const concurrentLimit = options.getRelevantOption(context, opts, "concurrent-limit", helper.getArtifactName()); const results = utils.throttledAll(context, paths.map(function (path) { @@ -1451,13 +1435,6 @@ class AssetsHelper extends BaseHelper { }); return resources; }) - .then(function (resources) { - // Keep track of the timestamp of this operation, but only if there were no errors. - if (errorCount === 0) { - hashes.setLastPushTimestamp(context, helper._fsApi.getResourcesPath(context, opts), timestamp, opts); - } - return resources; - }) .finally(function () { // Once the promise has been settled, remove the retry push state from the context. delete context.retryPush; @@ -2306,8 +2283,7 @@ class AssetsHelper extends BaseHelper { // Recursively call AssetsREST.getModifiedItems() to retrieve the remote assets modified since the last pull. const helper = this; - const lastPullTimestamps = helper._getLastPullTimestamps(context, opts); - const lastPullTimestamp = helper._getTimestamp(lastPullTimestamps, opts); + const lastPullTimestamp = helper.getLastPullTimestamp(context, opts); return helper._restApi.getModifiedItems(context, lastPullTimestamp, opts) .then(function (items) { // Return a promise for the filtered list of remote modified assets. @@ -2858,100 +2834,157 @@ class AssetsHelper extends BaseHelper { } /** - * Returns the last pull timestamps, converting from a single timestamp to the new multi-value timestamp format if needed. + * Get the last pull timestamp data, converting to the new draft/ready timestamp format if needed. * * @param {Object} context The API context to be used for this operation. - * @param opts + * @param {Object} opts The API options to be used for this operation. * - * @returns {{webAssets: String | Date, contentAssets: String | Date}} + * @returns {Object} The timestamp data for the last successful pull operation. */ _getLastPullTimestamps (context, opts) { const dir = this._fsApi.getAssetsPath(context, opts); const timestamps = hashes.getLastPullTimestamp(context, dir, opts); - // create the timestamps object now - // we use the webAssets and contentAssets children of the timestamps read from .wchtoolshashes if they exist (new format) - // otherwise fall back to copying the old format (a single timestamp) into each field - return { - webAssets: (timestamps ? (timestamps.webAssets ? timestamps.webAssets : (timestamps.contentAssets ? undefined : timestamps)) : undefined), - contentAssets: (timestamps ? (timestamps.contentAssets ? timestamps.contentAssets : (timestamps.webAssets ? undefined : timestamps)) : undefined) - }; - } - /** - * Returns the last push timestamps, converting from a single timestap to the new multi-value timestamp format if needed. - * - * @param {Object} context The API context to be used for this operation. - * @param opts - * - * @returns {{webAssets: String | Date, contentAssets: String | Date}} - */ - _getLastPushTimestamps (context, opts) { - const dir = this._fsApi.getAssetsPath(context, opts); - const timestamps = hashes.getLastPushTimestamp(context, dir, opts); - // create the timestamps object now - // we use the webAssets and contentAssets children of the timestamps read from .wchtoolshashes if they exist (new format) - // otherwise fall back to copying the old format (a single timestamp) into each field - return { - webAssets: (timestamps ? (timestamps.webAssets ? timestamps.webAssets : (timestamps.contentAssets ? undefined : timestamps)) : undefined), - contentAssets: (timestamps ? (timestamps.contentAssets ? timestamps.contentAssets : (timestamps.webAssets ? undefined : timestamps)) : undefined) - }; + if (timestamps) { + if (typeof timestamps === "string") { + // Convert a single timestamp to the new format. The single timestamp is used for all of the new values. + return { + webAssets: {"draft": timestamps, "ready": timestamps}, + contentAssets: {"draft": timestamps, "ready": timestamps} + }; + } else { + const webAssetsTimestamps = timestamps["webAssets"]; + if (webAssetsTimestamps) { + if (typeof webAssetsTimestamps === "string") { + // Convert a single web assets timestamp to the new format. + timestamps["webAssets"] = {"draft": webAssetsTimestamps, "ready": webAssetsTimestamps}; + } + } else { + // Add a webAssets property to the existing timestamp data. + timestamps["webAssets"] = {}; + } + + const contentAssetsTimestamps = timestamps["contentAssets"]; + if (contentAssetsTimestamps) { + if (typeof contentAssetsTimestamps === "string") { + // Convert a single content assets timestamp to the new format. + timestamps["contentAssets"] = { + "draft": contentAssetsTimestamps, + "ready": contentAssetsTimestamps + }; + } + } else { + // Add a contentAssets property to the existing timestamp data. + timestamps["contentAssets"] = {}; + } + + return timestamps; + } + } else { + // There are no timestamps in the hashes file. + return {webAssets: {}, contentAssets: {}}; + } } /** - * Sets the last pull timestamps. + * Set the last pull timestamp data. * * @param {Object} context The API context to be used for this operation. - * @param opts + * @param {String} timestamp The API options to be used for this operation. + * @param {Object} opts The API options to be used for this operation. */ _setLastPullTimestamps (context, timestamp, opts) { - const timestamps = this._getLastPullTimestamps(context, opts); + const pullTimestamps = this._getLastPullTimestamps(context, opts); + + // Store separate pull timestamps for draft and ready. + const readyOnly = options.getRelevantOption(context, opts, "filterReady"); + const draftOnly = options.getRelevantOption(context, opts, "filterDraft"); if (opts && opts[this.ASSET_TYPES] === this.ASSET_TYPES_WEB_ASSETS) { - timestamps.webAssets = timestamp; + if (!draftOnly) { + // Store the ready timestamp if the operation is not draft only. + pullTimestamps.webAssets.ready = timestamp; + } + if (!readyOnly) { + // Store the draft timestamp if the operation is not ready only. + pullTimestamps.webAssets.draft = timestamp; + } } else if (opts && opts[this.ASSET_TYPES] === this.ASSET_TYPES_CONTENT_ASSETS) { - timestamps.contentAssets = timestamp; + if (!draftOnly) { + // Store the ready timestamp if the operation is not draft only. + pullTimestamps.contentAssets.ready = timestamp; + } + if (!readyOnly) { + // Store the draft timestamp if the operation is not ready only. + pullTimestamps.contentAssets.draft = timestamp; + } } else { - timestamps.webAssets = timestamps.contentAssets = timestamp; + if (!draftOnly) { + // Store the ready timestamp if the operation is not draft only. + pullTimestamps.webAssets.ready = timestamp; + pullTimestamps.contentAssets.ready = timestamp; + } + if (!readyOnly) { + // Store the draft timestamp if the operation is not ready only. + pullTimestamps.webAssets.draft = timestamp; + pullTimestamps.contentAssets.draft = timestamp; + } } - hashes.setLastPullTimestamp(context, this._fsApi.getAssetsPath(context, opts), timestamps, opts); + + hashes.setLastPullTimestamp(context, this._fsApi.getAssetsPath(context, opts), pullTimestamps, opts); } /** - * Sets the last push timestamps. + * Get the timestamp of the last "similar" pull operation. * * @param {Object} context The API context to be used for this operation. - * @param opts + * @param {Object} opts The API options to be used for this operation. + * + * @returns {String} The timestamp data of the last "similar" pull operation. */ - _setLastPushTimestamps (context, timestamp, opts) { - const timestamps = this._getLastPushTimestamps(context, opts); - if (opts && opts[this.ASSET_TYPES] === this.ASSET_TYPES_WEB_ASSETS) { - timestamps.webAssets = timestamp; - } else if (opts && opts[this.ASSET_TYPES] === this.ASSET_TYPES_CONTENT_ASSETS) { - timestamps.contentAssets = timestamp; - } else { - timestamps.webAssets = timestamps.contentAssets = timestamp; - } - hashes.setLastPushTimestamp(context, this._fsApi.getAssetsPath(context, opts), timestamps, opts); - } + getLastPullTimestamp(context, opts) { + const lastPullTimestamps = this._getLastPullTimestamps(context, opts) || {}; + const webAssetTimestamps = lastPullTimestamps.webAssets || {}; + const contentAssetTimestamps = lastPullTimestamps.contentAssets || {}; + const readyOnly = options.getRelevantOption(context, opts, "filterReady"); + const draftOnly = options.getRelevantOption(context, opts, "filterDraft"); - _getTimestamp (timestamps, opts) { - const webAssetTimestamp = timestamps.webAssets; - const contentAssetTimestamp = timestamps.contentAssets; - let timestamp; if (opts && opts[this.ASSET_TYPES] === this.ASSET_TYPES_WEB_ASSETS) { - timestamp = webAssetTimestamp; + // Get the appropriate web assets timestamp. + if (readyOnly) { + // A ready-only pull operation will use the ready timestamp. + return webAssetTimestamps["ready"]; + } else if (draftOnly) { + // A draft-only pull operation will use the draft timestamp. + return webAssetTimestamps["draft"]; + } else { + // A ready-and-draft pull operation will use the older timestamp to make sure all modified items are pulled. + return utils.getOldestTimestamp([webAssetTimestamps["draft"], webAssetTimestamps["ready"]]); + } } else if (opts && opts[this.ASSET_TYPES] === this.ASSET_TYPES_CONTENT_ASSETS) { - timestamp = contentAssetTimestamp; + // Get the appropriate content assets timestamp. + if (readyOnly) { + // A ready-only pull operation will use the ready timestamp. + return contentAssetTimestamps["ready"]; + } else if (draftOnly) { + // A draft-only pull operation will use the draft timestamp. + return contentAssetTimestamps["draft"]; + } else { + // A ready-and-draft pull operation will use the older timestamp to make sure all modified items are pulled. + return utils.getOldestTimestamp([contentAssetTimestamps["draft"], contentAssetTimestamps["ready"]]); + } } else { - // calculate the min of both timestamps - const webAssetDate = new Date(webAssetTimestamp); - const contentAssetDate = new Date(contentAssetTimestamp); - if (webAssetDate.valueOf() < contentAssetDate.valueOf()) { - timestamp = webAssetTimestamp; + // Get the appropriate web assets or content assets timestamp. + if (readyOnly) { + // A ready-only pull operation will use the older ready timestamp. + return utils.getOldestTimestamp([webAssetTimestamps["ready"], contentAssetTimestamps["ready"]]); + } else if (draftOnly) { + // A draft-only pull operation will use the older draft timestamp. + return utils.getOldestTimestamp([webAssetTimestamps["draft"], contentAssetTimestamps["draft"]]); } else { - timestamp = contentAssetTimestamp; + // A ready-and-draft pull operation will use the oldest timestamp to make sure all modified items are pulled. + return utils.getOldestTimestamp([webAssetTimestamps["draft"], webAssetTimestamps["ready"], contentAssetTimestamps["draft"], contentAssetTimestamps["ready"]]); } } - return timestamp; } } diff --git a/authoring-api/lib/utils/hashes.js b/authoring-api/lib/utils/hashes.js index d6d82c7..0615dfc 100644 --- a/authoring-api/lib/utils/hashes.js +++ b/authoring-api/lib/utils/hashes.js @@ -760,7 +760,7 @@ function setFilePath (context, basePath, id, filePath, opts) { /** * Get the timestamp of the last pull for the specified tenant. * - * Example: "2017-01-16T22:30:05.928Z" + * @example {"ready": "2017-01-16T22:30:05.928Z"} * * @param {Object} context The current API context. * @param {String} basePath The path where the hashes file is located. @@ -784,11 +784,11 @@ function getLastPullTimestamp (context, basePath, opts) { } /** - * Set the timestamp of the last pull for the specified tenant. + * Set the timestamp data for the last pull from the specified tenant. * * @param {Object} context The current API context. * @param {String} basePath The path where the hashes file is located. - * @param {Date | String} timestamp The timestamp of the last pull for the specified tenant. + * @param {Object} timestamp The timestamp data for the last pull from the specified tenant. * @param {Object} opts The options object that specifies which tenant is being used. * * @returns {Object} The updated tenant map for the hashes file at the given location, or an empty object. @@ -815,64 +815,6 @@ function setLastPullTimestamp (context, basePath, timestamp, opts) { } } -/** - * Get the timestamp of the last push for the specified tenant. - * - * Example: "2017-01-16T22:30:05.928Z" - * - * @param {Object} context The current API context. - * @param {String} basePath The path where the hashes file is located. - * @param {Object} opts The options object that specifies which tenant is being used. - * - * @returns {String} The timestamp of the last push for the specified tenant. - * - * @public - */ -function getLastPushTimestamp (context, basePath, opts) { - // If the context specifies that hashes should not be used, return a null timestamp. - if (!options.getRelevantOption(context, opts, "useHashes")) { - return null; - } - - // Get the tenant metadata from the hashes file at the specified location. - const hashMap = loadHashes(context, basePath, opts); - - // Return the pull timestamp for the tenant. - return hashMap.lastPushTimestamp; -} - -/** - * Set the timestamp of the last push for the specified tenant. - * - * @param {Object} context The current API context. - * @param {String} basePath The path where the hashes file is located. - * @param {Date | String} timestamp The timestamp of the last push for the specified tenant. - * @param {Object} opts The options object that specifies which tenant is being used. - * - * @returns {Object} The updated tenant map for the hashes file at the given location, or an empty object. - * - * @public - */ -function setLastPushTimestamp (context, basePath, timestamp, opts) { - // If the context specifies that hashes should not be used, return an empty tenant map. - if (!options.getRelevantOption(context, opts, "useHashes")) { - return {}; - } - - try { - // Get the tenant metadata from the hashes file at the specified location. - const hashMap = loadHashes(context, basePath, opts); - - // Update the tenant metadata with the timestamp value and save it to the hashes file in the specified location. - hashMap.lastPushTimestamp = timestamp; - return saveHashes(context, basePath, hashMap, opts); - } catch (err) { - // Log the error and return the current state of the tenant map. - utils.logErrors(context, i18n.__("error_set_last_push_timestamp"), err); - return loadTenantMap(context, basePath); - } -} - /** * Get the metadata for the given file from the hashes file at the specified location for the specified tenant. * @@ -1199,8 +1141,6 @@ const hashes = { setFilePath: setFilePath, getLastPullTimestamp: getLastPullTimestamp, setLastPullTimestamp: setLastPullTimestamp, - getLastPushTimestamp: getLastPushTimestamp, - setLastPushTimestamp: setLastPushTimestamp, getMD5ForFile: getMD5ForFile, getResourceMD5ForFile: getResourceMD5ForFile, getPathForResource: getPathForResource, diff --git a/authoring-api/lib/utils/utils.js b/authoring-api/lib/utils/utils.js index 91c7af1..2c15fad 100644 --- a/authoring-api/lib/utils/utils.js +++ b/authoring-api/lib/utils/utils.js @@ -829,6 +829,43 @@ function getRelativePath (dir, file) { return "/" + path.relative(dir, file).replace(/\\/g, '/'); } +/** + * Get the oldest timestamp from the given list. + * + * Note: If any timestamps in the list are undefined, return undefined. + * + * @param {Array} timestamps The list of timestamps to be compared. + * + * @returns {String | undefined} The oldest timestamp from the given list, or undefined if any of the timestamps are undefined. + */ +function getOldestTimestamp(timestamps) { + let oldestTimestamp; + let oldestDate; + + for (let i = 0; timestamps && i < timestamps.length; i++) { + if (!timestamps[i]) { + // The timestamp is undefined, so return undefined. + return; + } + + // Determine whether the timestamp is older than the current oldest. + if (oldestTimestamp) { + const date = new Date(timestamps[i]); + if (date < oldestDate) { + // The timestamp is the oldest for now. + oldestTimestamp = timestamps[i]; + oldestDate = date; + } + } else { + // This is the first timestamp, so it is the oldest for now. + oldestTimestamp = timestamps[i]; + oldestDate = new Date(timestamps[i]); + } + } + + return oldestTimestamp; +} + /** * Replace all of the original string's occurrences of the find string with the replace string. * @@ -895,6 +932,7 @@ const utils = { retryNetworkErrors: retryNetworkErrors, getRelativePath: getRelativePath, getHTTPLanguage: getHTTPLanguage, + getOldestTimestamp: getOldestTimestamp, replaceAll: replaceAll, reset: reset, getUserAgent: getUserAgent diff --git a/authoring-api/nls/de.json b/authoring-api/nls/de.json index dc90583..eea963f 100644 --- a/authoring-api/nls/de.json +++ b/authoring-api/nls/de.json @@ -49,7 +49,6 @@ "error_remove_hashes_by_path": "Fehler in removeHashesByPath: ", "error_remove_all_hashes": "Fehler in removeAllHashes: ", "error_set_last_pull_timestamp": "Fehler in setLastPullTimestamp: ", - "error_set_last_push_timestamp": "Fehler in setLastPushTimestamp: ", "error_get_hashes_for_file": "Fehler in getHashesForFile: ", "error_manifest_file_read": "Fehler beim Lesen der Manifestdatei %(filename)s: %(error)s", "error_manifest_file_write": "Fehler beim Schreiben der Manifestdatei %(filename)s: %(error)s", diff --git a/authoring-api/nls/en.json b/authoring-api/nls/en.json index 18b25d7..06c9ca5 100644 --- a/authoring-api/nls/en.json +++ b/authoring-api/nls/en.json @@ -49,7 +49,6 @@ "error_remove_hashes_by_path": "Error in removeHashesByPath: ", "error_remove_all_hashes": "Error in removeAllHashes: ", "error_set_last_pull_timestamp": "Error in setLastPullTimestamp: ", - "error_set_last_push_timestamp": "Error in setLastPushTimestamp: ", "error_get_hashes_for_file": "Error in getHashesForFile: ", "error_manifest_file_read": "Error reading manifest file %(filename)s: %(error)s", "error_manifest_file_write": "Error writing manifest file %(filename)s: %(error)s", diff --git a/authoring-api/nls/es.json b/authoring-api/nls/es.json index b866bc1..5f34860 100644 --- a/authoring-api/nls/es.json +++ b/authoring-api/nls/es.json @@ -49,7 +49,6 @@ "error_remove_hashes_by_path": "Error en removeHashesByPath: ", "error_remove_all_hashes": "Error en removeAllHashes: ", "error_set_last_pull_timestamp": "Error en setLastPullTimestamp: ", - "error_set_last_push_timestamp": "Error en setLastPushTimestamp: ", "error_get_hashes_for_file": "Error en getHashesForFile: ", "error_manifest_file_read": "Error al leer el archivo de manifiesto %(filename)s: %(error)s", "error_manifest_file_write": "Error al escribir el archivo de manifiesto %(filename)s: %(error)s", diff --git a/authoring-api/nls/fr.json b/authoring-api/nls/fr.json index b45c28a..254ced9 100644 --- a/authoring-api/nls/fr.json +++ b/authoring-api/nls/fr.json @@ -49,7 +49,6 @@ "error_remove_hashes_by_path": "Erreur dans removeHashesByPath : ", "error_remove_all_hashes": "Erreur dans removeAllHashes : ", "error_set_last_pull_timestamp": "Erreur dans setLastPullTimestamp : ", - "error_set_last_push_timestamp": "Erreur dans setLastPushTimestamp : ", "error_get_hashes_for_file": "Erreur dans getHashesForFile : ", "error_manifest_file_read": "Erreur lors de la lecture du fichier manifeste %(filename)s : %(error)s", "error_manifest_file_write": "Erreur lors de l'écriture du fichier manifeste %(filename)s : %(error)s", diff --git a/authoring-api/nls/it.json b/authoring-api/nls/it.json index 8024ab5..90f186a 100644 --- a/authoring-api/nls/it.json +++ b/authoring-api/nls/it.json @@ -49,7 +49,6 @@ "error_remove_hashes_by_path": "Errore in removeHashesByPath: ", "error_remove_all_hashes": "Errore in removeAllHashes: ", "error_set_last_pull_timestamp": "Errore in setLastPullTimestamp: ", - "error_set_last_push_timestamp": "Errore in setLastPushTimestamp: ", "error_get_hashes_for_file": "Errore in getHashesForFile: ", "error_manifest_file_read": "Errore durante la lettura del file manifest %(filename)s: %(error)s", "error_manifest_file_write": "Errore durante la scrittura del file manifest %(filename)s: %(error)s", diff --git a/authoring-api/nls/ja.json b/authoring-api/nls/ja.json index 5594651..7771714 100644 --- a/authoring-api/nls/ja.json +++ b/authoring-api/nls/ja.json @@ -49,7 +49,6 @@ "error_remove_hashes_by_path": "removeHashesByPath でエラーが発生しました: ", "error_remove_all_hashes": "removeAllHashes でエラーが発生しました: ", "error_set_last_pull_timestamp": "setLastPullTimestamp でエラーが発生しました: ", - "error_set_last_push_timestamp": "setLastPushTimestamp でエラーが発生しました: ", "error_get_hashes_for_file": "getHashesForFile でエラーが発生しました: ", "error_manifest_file_read": "マニフェスト・ファイル %(filename)s の読み取り中にエラーが発生しました: %(error)s", "error_manifest_file_write": "マニフェスト・ファイル %(filename)s の書き込み中にエラーが発生しました: %(error)s", diff --git a/authoring-api/nls/ko.json b/authoring-api/nls/ko.json index 6f6906a..e3d57d8 100644 --- a/authoring-api/nls/ko.json +++ b/authoring-api/nls/ko.json @@ -49,7 +49,6 @@ "error_remove_hashes_by_path": "removeHashesByPath의 오류: ", "error_remove_all_hashes": "removeAllHashes의 오류: ", "error_set_last_pull_timestamp": "setLastPullTimestamp의 오류: ", - "error_set_last_push_timestamp": "setLastPushTimestamp의 오류: ", "error_get_hashes_for_file": "getHashesForFile의 오류: ", "error_manifest_file_read": "Manifest 파일 %(filename)s 읽기 오류: %(error)s", "error_manifest_file_write": "Manifest 파일 %(filename)s 쓰기 오류: %(error)s", diff --git a/authoring-api/nls/pt_BR.json b/authoring-api/nls/pt_BR.json index 231e53e..e669f7a 100644 --- a/authoring-api/nls/pt_BR.json +++ b/authoring-api/nls/pt_BR.json @@ -49,7 +49,6 @@ "error_remove_hashes_by_path": "Erro em removeHashesByPath: ", "error_remove_all_hashes": "Erro em removeAllHashes: ", "error_set_last_pull_timestamp": "Erro em setLastPullTimestamp: ", - "error_set_last_push_timestamp": "Erro em setLastPushTimestamp: ", "error_get_hashes_for_file": "Erro em getHashesForFile: ", "error_manifest_file_read": "Erro ao ler arquivo manifest %(filename)s: %(error)s", "error_manifest_file_write": "Erro ao gravar o arquivo manifest %(filename)s: %(error)s", diff --git a/authoring-api/nls/sv.json b/authoring-api/nls/sv.json index d97f668..3ff17e4 100644 --- a/authoring-api/nls/sv.json +++ b/authoring-api/nls/sv.json @@ -49,7 +49,6 @@ "error_remove_hashes_by_path": "Fel i removeHashesByPath: ", "error_remove_all_hashes": "Fel i removeAllHashes: ", "error_set_last_pull_timestamp": "Fel i setLastPullTimestamp: ", - "error_set_last_push_timestamp": "Fel i setLastPushTimestamp: ", "error_get_hashes_for_file": "Fel i getHashesForFile: ", "error_manifest_file_read": "Fel vid läsning av manifestfilen %(filename)s: %(error)s", "error_manifest_file_write": "Fel vid skrivning av manifestfilen %(filename)s: %(error)s", diff --git a/authoring-api/nls/zh.json b/authoring-api/nls/zh.json index 9b6fc45..5639867 100644 --- a/authoring-api/nls/zh.json +++ b/authoring-api/nls/zh.json @@ -49,7 +49,6 @@ "error_remove_hashes_by_path": "removeHashesByPath 中发生错误:", "error_remove_all_hashes": "removeAllHashes 中发生错误:", "error_set_last_pull_timestamp": "setLastPullTimestamp 中发生错误:", - "error_set_last_push_timestamp": "setLastPushTimestamp 中发生错误:", "error_get_hashes_for_file": "getHashesForFile 中发生错误:", "error_manifest_file_read": "读取清单文件 %(error)s 时出错:%(error)s", "error_manifest_file_write": "写入清单文件 %(error)s 时出错:%(error)s", diff --git a/authoring-api/nls/zh_TW.json b/authoring-api/nls/zh_TW.json index 5b1bd0d..5c79b22 100644 --- a/authoring-api/nls/zh_TW.json +++ b/authoring-api/nls/zh_TW.json @@ -49,7 +49,6 @@ "error_remove_hashes_by_path": "removeHashesByPath 中的錯誤:", "error_remove_all_hashes": "removeAllHashes 中的錯誤:", "error_set_last_pull_timestamp": "setLastPullTimestamp 中的錯誤:", - "error_set_last_push_timestamp": "setLastPushTimestamp 中的錯誤:", "error_get_hashes_for_file": "getHashesForFile 中的錯誤:", "error_manifest_file_read": "讀取資訊清單檔 %(filename)s 時發生錯誤:%(error)s", "error_manifest_file_write": "寫入資訊清單檔 %(filename)s 時發生錯誤:%(error)s", diff --git a/authoring-api/package.json b/authoring-api/package.json index ea35151..3f00cf2 100644 --- a/authoring-api/package.json +++ b/authoring-api/package.json @@ -1,7 +1,7 @@ { "name": "wchtools-api", "description": "Tools API for IBM Watson Content Hub", - "version": "2.9.2", + "version": "3.0.4", "keywords": [ "api", "tools" @@ -20,7 +20,7 @@ "main": "./wchToolsApi.js", "dependencies": { "async": "^2.4.0", - "deep-extend": "^0.4.1", + "deep-extend": "^0.6.0", "i18n-2": "^0.6.3", "ignore": "^3.3.0", "log4js": "^2.5.2", diff --git a/authoring-api/sitesHelper.js b/authoring-api/sitesHelper.js index 0522905..3fc94ba 100644 --- a/authoring-api/sitesHelper.js +++ b/authoring-api/sitesHelper.js @@ -51,6 +51,27 @@ class SitesHelper extends JSONItemHelper { return this[singleton]; } + /** + * Get the status of the given item. + * + * @param {Object} context The API context to be used for this operation. + * @param {Object} item The item for which to get the status. + * @param {Object} opts The options to be used for this operations. + * + * @returns {String} "ready" or "draft". + * + * @protected + * + * @override + */ + getStatus(context, item, opts) { + if (item && item.siteStatus && item.siteStatus === "draft") { + return "draft"; + } else { + return "ready"; + } + } + /** * @param {Object} context The API context to be used for this operation. * @param {Object} opts - The options to be used for the push operation. diff --git a/authoring-api/test/unit/hashes.test.js b/authoring-api/test/unit/hashes.test.js index 32ea85d..494d057 100644 --- a/authoring-api/test/unit/hashes.test.js +++ b/authoring-api/test/unit/hashes.test.js @@ -484,83 +484,6 @@ describe("hashes", function () { }); }); - describe("setLastPushTimestamp", function () { - it("should log an error and leave the hashes file unchanged if the set fails", function (done) { - // At this point the hashes file should only contain information for the text file and the pull timestamp. - const SET_ERROR = "Set timestamp error expected by unit test."; - const stub = sinon.stub(options, "getRelevantOption"); - stub.onFirstCall().returns(true); - stub.onSecondCall().throws(new Error(SET_ERROR)); - - // Stub the logger so that the error is not written. - const stubLog = sinon.stub(context.logger, "error"); - - let error = undefined; - try { - const result = hashes.setLastPushTimestamp(context, TEST_DIRECTORY_PATH, CURRENT_DATE, TEST_OPTS); - - expect(stubLog).to.have.been.calledOnce; - expect(stubLog.firstCall.args[0]).to.contain("Error in setLastPushTimestamp"); - expect(stubLog.firstCall.args[0]).to.contain(SET_ERROR); - - // Because the timestamp could not be set, the result should be undefined. - expect(result).to.exist; - const tenantValues = result[TEST_TENANT_ID]; - expect(tenantValues).to.exist; - const lastPullTimestamp = tenantValues["lastPullTimestamp"]; - expect(lastPullTimestamp).to.exist; - const lastPushTimestamp = tenantValues["lastPushTimestamp"]; - expect(lastPushTimestamp).to.not.exist; - const fileValues = tenantValues[TEXT_FILE_ID]; - expect(fileValues).to.exist; - expect(fileValues.id).to.equal(TEXT_FILE_ID); - expect(fileValues.rev).to.equal(TEXT_FILE_REV); - expect(fileValues.md5).to.equal(TEXT_FILE_MD5); - expect(fileValues.path).to.equal(TEXT_FILE_RELATIVE_PATH); - expect(fileValues.resource).to.equal(TEXT_FILE_RESOURCE_ID_2); - expect(tenantValues[IMAGE_FILE_ID]).to.not.exist; - } catch (err) { - error = err; - } finally { - stub.restore(); - stubLog.restore(); - done(error); - } - }); - - it("should set the specified timestamp", function (done) { - let error = undefined; - try { - const result = hashes.setLastPushTimestamp(context, TEST_DIRECTORY_PATH, CURRENT_DATE, TEST_OPTS); - expect(result).to.exist; - const tenantValues = result[TEST_TENANT_ID]; - expect(tenantValues).to.exist; - const lastPushTimestamp = tenantValues["lastPushTimestamp"]; - expect(lastPushTimestamp.getTime()).to.equal(CURRENT_DATE.getTime()); - } catch (err) { - error = err; - } finally { - done(error); - } - }); - }); - - describe("getLastPushTimestamp", function () { - it("should return the timestamp that was set", function (done) { - let error = undefined; - try { - const lastPushTimestamp = hashes.getLastPushTimestamp(context, TEST_DIRECTORY_PATH, TEST_OPTS); - expect(lastPushTimestamp).to.exist; - const lastPushDate = new Date(lastPushTimestamp); - expect(lastPushDate.getTime()).to.equal(CURRENT_DATE.getTime()); - } catch (err) { - error = err; - } finally { - done(error); - } - }); - }); - describe("getMD5ForFile", function () { it("should get the exisiting metadata from the hashes file", function (done) { let error = undefined; diff --git a/authoring-api/test/unit/lib/assets.helper.unit.js b/authoring-api/test/unit/lib/assets.helper.unit.js index 1741ef2..8a52ea3 100644 --- a/authoring-api/test/unit/lib/assets.helper.unit.js +++ b/authoring-api/test/unit/lib/assets.helper.unit.js @@ -54,8 +54,6 @@ let stubGenerateMD5HashAndID; let stubGenerateMD5HashFromStream; let stubUpdateHashes; let stubUpdateResourceHashes; -let stubGetLastPush; -let stubSetLastPush; let stubGetLastPull; let stubSetLastPull; let stubGetMD5ForFile; @@ -111,13 +109,6 @@ class AssetsHelperUnitTest extends AssetsUnitTest { stubUpdateResourceHashes.returns(undefined); self.addTestDouble(stubUpdateResourceHashes); - stubGetLastPush = sinon.stub(hashes, "getLastPushTimestamp"); - stubGetLastPush.returns(undefined); - self.addTestDouble(stubGetLastPush); - - stubSetLastPush = sinon.stub(hashes, "setLastPushTimestamp"); - self.addTestDouble(stubSetLastPush); - stubGetLastPull = sinon.stub(hashes, "getLastPullTimestamp"); stubGetLastPull.returns(undefined); self.addTestDouble(stubGetLastPull); @@ -2022,7 +2013,7 @@ class AssetsHelperUnitTest extends AssetsUnitTest { expect(spyPull.args[1][0].path).to.equal(assetsFS.getAssetPath(assetMetadata3)); expect(spyError).to.not.have.been.called; - expect(stubSetLastPull).to.not.have.been.called; + expect(stubSetLastPull).to.have.been.calledOnce; // Verify that the hashes were called as expected. expect(stubUpdateHashes).to.have.callCount(2); @@ -2148,7 +2139,7 @@ class AssetsHelperUnitTest extends AssetsUnitTest { expect(spyPull.args[1][0].path).to.equal(assetsFS.getAssetPath(assetMetadata4)); expect(spyError).to.not.have.been.called; - expect(stubSetLastPull).to.not.have.been.called; + expect(stubSetLastPull).to.have.been.calledOnce; // Verify that the hashes were called as expected. expect(stubUpdateHashes).to.have.callCount(2); @@ -3699,9 +3690,6 @@ class AssetsHelperUnitTest extends AssetsUnitTest { const streamContent = stubREST.firstCall.args[7].read(65536); expect(Buffer.compare(streamContent, assetContent)).to.equal(0); - // Verify that the hashes were called as expected. - expect(stubSetLastPush).to.not.have.been.called; - expect(stubUpdateHashes).to.have.been.calledOnce; expect(stubUpdateHashes.args[0][4]).to.contain(AssetsUnitTest.ASSET_HBS_1); expect(stubUpdateHashes.args[0][3].path).to.contain(AssetsUnitTest.ASSET_HBS_1); @@ -3791,9 +3779,6 @@ class AssetsHelperUnitTest extends AssetsUnitTest { const streamContent = stubREST.thirdCall.args[7].read(65536); expect(Buffer.compare(streamContent, assetContent)).to.equal(0); - // Verify that the last push timestamp was not called, because we're only pushing one item. - expect(stubSetLastPush).to.not.have.been.called; - expect(stubUpdateHashes).to.have.been.calledOnce; expect(stubUpdateHashes.args[0][4]).to.contain(AssetsUnitTest.ASSET_HBS_1); expect(stubUpdateHashes.args[0][3].path).to.contain(AssetsUnitTest.ASSET_HBS_1); @@ -3882,9 +3867,6 @@ class AssetsHelperUnitTest extends AssetsUnitTest { const streamContent = stubREST.thirdCall.args[7].read(65536); expect(Buffer.compare(streamContent, assetContent)).to.equal(0); - // Verify that the last push timestamp was not called. - expect(stubSetLastPush).to.not.have.been.called; - expect(stubUpdateHashes).to.not.have.been.called; }) .catch(function (err) { @@ -4102,9 +4084,6 @@ class AssetsHelperUnitTest extends AssetsUnitTest { // Verify that the save stub was called once. expect(stubSave).to.have.been.calledOnce; - // Verify that the hashes were called as expected. - expect(stubSetLastPush).to.not.have.been.called; - expect(stubUpdateHashes).to.have.been.calledOnce; expect(stubUpdateHashes.args[0][2]).to.contain(AssetsUnitTest.ASSET_CONTENT_JPG_3); expect(stubUpdateHashes.args[0][3].path).to.contain(AssetsUnitTest.ASSET_CONTENT_JPG_3); @@ -4181,9 +4160,6 @@ class AssetsHelperUnitTest extends AssetsUnitTest { // Verify that the save stub was called once. expect(stubSave).to.have.been.calledOnce; - // Verify that the hashes were called as expected. - expect(stubSetLastPush).to.not.have.been.called; - expect(stubUpdateHashes).to.have.been.calledOnce; expect(stubUpdateHashes.args[0][2]).to.contain(AssetsUnitTest.ASSET_CONTENT_JPG_3); expect(stubUpdateHashes.args[0][3].path).to.contain(AssetsUnitTest.ASSET_CONTENT_JPG_3); @@ -4463,9 +4439,6 @@ class AssetsHelperUnitTest extends AssetsUnitTest { expect(spyPushed).to.not.have.been.called; expect(spyError).to.not.have.been.called; - // Verify that the hashes were called as expected. - expect(stubSetLastPush).to.not.have.been.called; - expect(stubUpdateHashes).to.have.callCount(5); expect(stubUpdateHashes.args[0][4]).to.contain(AssetsUnitTest.ASSET_HTML_1); expect(stubUpdateHashes.args[0][3].path).to.contain(AssetsUnitTest.ASSET_HTML_1); @@ -4638,9 +4611,6 @@ class AssetsHelperUnitTest extends AssetsUnitTest { expect(spyPushed.getCall(3).args[0].path).to.equal(AssetsUnitTest.ASSET_CONTENT_JPG_2_DRAFT); expect(spyError).to.not.have.been.called; - // Verify that the hashes were called as expected. - expect(stubSetLastPush).to.have.been.called; - expect(stubUpdateHashes).to.have.callCount(4); expect(stubUpdateHashes.args[0][4]).to.contain(AssetsUnitTest.ASSET_CONTENT_JPG_1); expect(stubUpdateHashes.args[0][3].path).to.contain(AssetsUnitTest.ASSET_CONTENT_JPG_1); @@ -4798,9 +4768,6 @@ class AssetsHelperUnitTest extends AssetsUnitTest { expect(spyPushed.getCall(1).args[0].path).to.equal(AssetsUnitTest.ASSET_CONTENT_JPG_2); expect(spyError).to.not.have.been.called; - // Verify that the push timestamp was not called, becuase we're filtering the results. - expect(stubSetLastPush).to.not.have.been.called; - // Verify that the hashes were called as expected. expect(stubUpdateHashes).to.have.callCount(2); expect(stubUpdateHashes.args[0][4]).to.contain(AssetsUnitTest.ASSET_CONTENT_JPG_1); @@ -4955,9 +4922,6 @@ class AssetsHelperUnitTest extends AssetsUnitTest { expect(spyPushed.getCall(1).args[0].path).to.equal(AssetsUnitTest.ASSET_CONTENT_JPG_2_DRAFT); expect(spyError).to.not.have.been.called; - // Verify that the push timestamp was not called, becuase we're filtering the results. - expect(stubSetLastPush).to.not.have.been.called; - // Verify that the hashes were called as expected. expect(stubUpdateHashes).to.have.callCount(2); expect(stubUpdateHashes.args[0][4]).to.contain(AssetsUnitTest.ASSET_CONTENT_JPG_1_DRAFT); @@ -5207,8 +5171,6 @@ class AssetsHelperUnitTest extends AssetsUnitTest { expect(stubSetLastPull).to.not.have.been.called; - expect(stubSetLastPush).to.not.have.been.called; - expect(stubUpdateHashes).to.have.been.calledTwice; expect(stubUpdateHashes.firstCall.args[4]).to.contain(AssetsUnitTest.ASSET_HTML_1); expect(stubUpdateHashes.firstCall.args[3].path).to.contain(AssetsUnitTest.ASSET_HTML_1); @@ -5373,9 +5335,6 @@ class AssetsHelperUnitTest extends AssetsUnitTest { // Verify that an MD5 hash was generated. expect(stubGenerateMD5Hash).to.have.been.calledOnce; - // Verify that the push timestamp was updated. - expect(stubSetLastPush).to.have.been.calledOnce; - // Verify that the other stubs were called once with the expected values. expect(stubStream).to.have.been.calledOnce; expect(stubStream.args[0][1]).to.equal(UnitTest.DUMMY_PATH); @@ -5425,9 +5384,6 @@ class AssetsHelperUnitTest extends AssetsUnitTest { // Verify that the push spy and the error spy to not have been called. expect(spyPushed).to.not.have.been.called; expect(spyError).to.not.have.been.called; - - // Verify that the push timestamp was not updated. - expect(stubSetLastPush).to.not.have.been.called; }) .catch(function (err) { error = err; @@ -5478,9 +5434,6 @@ class AssetsHelperUnitTest extends AssetsUnitTest { expect(spyPushed).to.not.have.been.called; expect(spyError).to.not.have.been.called; - // Verify that the push timestamp was not updated. - expect(stubSetLastPush).to.not.have.been.called; - // Verify that the other stubs were called once with the expected values. expect(stubStream).to.have.been.calledOnce; }) @@ -5581,9 +5534,6 @@ class AssetsHelperUnitTest extends AssetsUnitTest { // Verify that an MD5 hash was generated. expect(stubGenerateMD5Hash).to.have.been.calledThrice; - - // Verify that the push timestamp was updated. - expect(stubSetLastPush).to.have.been.calledOnce; }) .catch(function (err) { error = err; @@ -5680,9 +5630,6 @@ class AssetsHelperUnitTest extends AssetsUnitTest { // Verify that an MD5 hash was generated. expect(stubGenerateMD5Hash).to.have.been.calledThrice; - - // Verify that the push timestamp was not updated. - expect(stubSetLastPush).to.not.have.been.called; }) .catch(function (err) { error = err; @@ -5778,9 +5725,6 @@ class AssetsHelperUnitTest extends AssetsUnitTest { // Verify that an MD5 hash was generated. expect(stubGenerateMD5Hash).to.have.been.calledTwice; - // Verify that the push timestamp was not updated. - expect(stubSetLastPush).to.not.have.been.called; - // Verify that the other stubs were called once with the expected values. expect(stubStream).to.have.been.calledTwice; expect(stubStream.args[0][1]).to.equal(AssetsUnitTest.ASSET_HTML_1); @@ -5884,9 +5828,6 @@ class AssetsHelperUnitTest extends AssetsUnitTest { // Verify that an MD5 hash was generated. expect(stubGenerateMD5Hash).to.have.been.calledTwice; - // Verify that the push timestamp was not updated. - expect(stubSetLastPush).to.not.have.been.called; - // Verify that the other stubs were called once with the expected values. expect(stubStream).to.have.been.calledTwice; expect(stubStream.args[0][1]).to.equal(AssetsUnitTest.ASSET_HTML_1); @@ -8088,8 +8029,10 @@ class AssetsHelperUnitTest extends AssetsUnitTest { let error; try { const timestamp = assetsHelper._getLastPullTimestamps(context, UnitTest.DUMMY_OPTIONS); - expect(timestamp.contentAssets).to.equal(TIMESTAMP); - expect(timestamp.webAssets).to.equal(TIMESTAMP); + expect(timestamp.contentAssets.draft).to.equal(TIMESTAMP); + expect(timestamp.contentAssets.ready).to.equal(TIMESTAMP); + expect(timestamp.webAssets.draft).to.equal(TIMESTAMP); + expect(timestamp.webAssets.ready).to.equal(TIMESTAMP); } catch (err) { // NOTE: A failed expectation from above will be handled here. // Pass the error to the "done" function to indicate a failed test. @@ -8109,8 +8052,10 @@ class AssetsHelperUnitTest extends AssetsUnitTest { let error; try { const timestamp = assetsHelper._getLastPullTimestamps(context, UnitTest.DUMMY_OPTIONS); - expect(timestamp.contentAssets).to.equal(TIMESTAMP); - expect(timestamp.webAssets).to.equal(TIMESTAMP); + expect(timestamp.contentAssets.draft).to.equal(TIMESTAMP); + expect(timestamp.contentAssets.ready).to.equal(TIMESTAMP); + expect(timestamp.webAssets.draft).to.equal(TIMESTAMP); + expect(timestamp.webAssets.ready).to.equal(TIMESTAMP); } catch (err) { // NOTE: A failed expectation from above will be handled here. // Pass the error to the "done" function to indicate a failed test. @@ -8131,7 +8076,8 @@ class AssetsHelperUnitTest extends AssetsUnitTest { try { const timestamp = assetsHelper._getLastPullTimestamps(context, UnitTest.DUMMY_OPTIONS); expect(timestamp.contentAssets).to.be.empty; - expect(timestamp.webAssets).to.equal(TIMESTAMP); + expect(timestamp.webAssets.draft).to.equal(TIMESTAMP); + expect(timestamp.webAssets.ready).to.equal(TIMESTAMP); } catch (err) { // NOTE: A failed expectation from above will be handled here. // Pass the error to the "done" function to indicate a failed test. @@ -8152,7 +8098,8 @@ class AssetsHelperUnitTest extends AssetsUnitTest { try { const timestamp = assetsHelper._getLastPullTimestamps(context, UnitTest.DUMMY_OPTIONS); expect(timestamp.webAssets).to.be.empty; - expect(timestamp.contentAssets).to.equal(TIMESTAMP); + expect(timestamp.contentAssets.draft).to.equal(TIMESTAMP); + expect(timestamp.contentAssets.ready).to.equal(TIMESTAMP); } catch (err) { // NOTE: A failed expectation from above will be handled here. // Pass the error to the "done" function to indicate a failed test. @@ -8164,35 +8111,25 @@ class AssetsHelperUnitTest extends AssetsUnitTest { }); }); - describe("_getLastPushTimestamps", function () { - it("should succeed for no timestamp value", function (done) { - // Call the method being tested. - let error; - try { - const timestamp = assetsHelper._getLastPushTimestamps(context, UnitTest.DUMMY_OPTIONS); - expect(timestamp.contentAssets).to.be.empty; - expect(timestamp.webAssets).to.be.empty; - } catch (err) { - // NOTE: A failed expectation from above will be handled here. - // Pass the error to the "done" function to indicate a failed test. - error = err; - } finally { - // Call mocha's done function to indicate that the test is over. - done(error); - } - }); - - it("should succeed for the old timestamp format", function (done) { - // Change the hashes.getLastPushTimestamp stub to return the old format. + describe("_setLastPullTimestamps", function () { + it("should set all timestamps when both assets types are specified with no draft/ready filtering", function (done) { + // Change the hashes.getLastPullTimestamp stub to return a known value. const TIMESTAMP = "2017-05-10T04:36:49.987Z"; - stubGetLastPush.returns(TIMESTAMP); + stubGetLastPull.returns({ + webAssets: {"draft": TIMESTAMP, "ready": TIMESTAMP}, + contentAssets: {"draft": TIMESTAMP, "ready": TIMESTAMP} + }); + const NEW_TIMESTAMP = new Date(); // Call the method being tested. let error; try { - const timestamp = assetsHelper._getLastPushTimestamps(context, UnitTest.DUMMY_OPTIONS); - expect(timestamp.contentAssets).to.equal(TIMESTAMP); - expect(timestamp.webAssets).to.equal(TIMESTAMP); + assetsHelper._setLastPullTimestamps(context, NEW_TIMESTAMP, {assetTypes: assetsHelper.ASSET_TYPES_BOTH}); + expect(stubGetLastPull).to.have.been.calledOnce; + expect(stubSetLastPull.args[0][2]["webAssets"]["draft"]).to.equal(NEW_TIMESTAMP); + expect(stubSetLastPull.args[0][2]["webAssets"]["ready"]).to.equal(NEW_TIMESTAMP); + expect(stubSetLastPull.args[0][2]["contentAssets"]["draft"]).to.equal(NEW_TIMESTAMP); + expect(stubSetLastPull.args[0][2]["contentAssets"]["ready"]).to.equal(NEW_TIMESTAMP); } catch (err) { // NOTE: A failed expectation from above will be handled here. // Pass the error to the "done" function to indicate a failed test. @@ -8203,17 +8140,27 @@ class AssetsHelperUnitTest extends AssetsUnitTest { } }); - it("should succeed for the new timestamp format", function (done) { - // Change the hashes.getLastPushTimestamp stub to return the new format. + it("should set only ready timestamps when both assets types are specified with ready filtering", function (done) { + // Change the hashes.getLastPullTimestamp stub to return a known value. const TIMESTAMP = "2017-05-10T04:36:49.987Z"; - stubGetLastPush.returns({webAssets: TIMESTAMP, contentAssets: TIMESTAMP}); + stubGetLastPull.returns({ + webAssets: {"draft": TIMESTAMP, "ready": TIMESTAMP}, + contentAssets: {"draft": TIMESTAMP, "ready": TIMESTAMP} + }); + const NEW_TIMESTAMP = new Date(); // Call the method being tested. let error; try { - const timestamp = assetsHelper._getLastPushTimestamps(context, UnitTest.DUMMY_OPTIONS); - expect(timestamp.contentAssets).to.equal(TIMESTAMP); - expect(timestamp.webAssets).to.equal(TIMESTAMP); + assetsHelper._setLastPullTimestamps(context, NEW_TIMESTAMP, { + assetTypes: assetsHelper.ASSET_TYPES_BOTH, + filterReady: true + }); + expect(stubGetLastPull).to.have.been.calledOnce; + expect(stubSetLastPull.args[0][2]["webAssets"]["draft"]).to.equal(TIMESTAMP); + expect(stubSetLastPull.args[0][2]["webAssets"]["ready"]).to.equal(NEW_TIMESTAMP); + expect(stubSetLastPull.args[0][2]["contentAssets"]["draft"]).to.equal(TIMESTAMP); + expect(stubSetLastPull.args[0][2]["contentAssets"]["ready"]).to.equal(NEW_TIMESTAMP); } catch (err) { // NOTE: A failed expectation from above will be handled here. // Pass the error to the "done" function to indicate a failed test. @@ -8224,17 +8171,27 @@ class AssetsHelperUnitTest extends AssetsUnitTest { } }); - it("should succeed when only web assets value returned", function (done) { - // Change the hashes.getLastPushTimestamp stub to return only a webAssets timestamp. + it("should set only draft timestamps when both assets types are specified with draft filtering", function (done) { + // Change the hashes.getLastPullTimestamp stub to return a known value. const TIMESTAMP = "2017-05-10T04:36:49.987Z"; - stubGetLastPush.returns({webAssets: TIMESTAMP}); + stubGetLastPull.returns({ + webAssets: {"draft": TIMESTAMP, "ready": TIMESTAMP}, + contentAssets: {"draft": TIMESTAMP, "ready": TIMESTAMP} + }); + const NEW_TIMESTAMP = new Date(); // Call the method being tested. let error; try { - const timestamp = assetsHelper._getLastPushTimestamps(context, UnitTest.DUMMY_OPTIONS); - expect(timestamp.contentAssets).to.be.empty; - expect(timestamp.webAssets).to.equal(TIMESTAMP); + assetsHelper._setLastPullTimestamps(context, NEW_TIMESTAMP, { + assetTypes: assetsHelper.ASSET_TYPES_BOTH, + filterDraft: true + }); + expect(stubGetLastPull).to.have.been.calledOnce; + expect(stubSetLastPull.args[0][2]["webAssets"]["draft"]).to.equal(NEW_TIMESTAMP); + expect(stubSetLastPull.args[0][2]["webAssets"]["ready"]).to.equal(TIMESTAMP); + expect(stubSetLastPull.args[0][2]["contentAssets"]["draft"]).to.equal(NEW_TIMESTAMP); + expect(stubSetLastPull.args[0][2]["contentAssets"]["ready"]).to.equal(TIMESTAMP); } catch (err) { // NOTE: A failed expectation from above will be handled here. // Pass the error to the "done" function to indicate a failed test. @@ -8245,17 +8202,27 @@ class AssetsHelperUnitTest extends AssetsUnitTest { } }); - it("should succeed when only content assets value returned", function (done) { - // Change the hashes.getLastPushTimestamp stub to return only a contentAssets timestamp. + it("should only set the web assets ready timestamp when the web assets type is specified with ready filtering", function (done) { + // Change the hashes.getLastPullTimestamp stub to return a known value. const TIMESTAMP = "2017-05-10T04:36:49.987Z"; - stubGetLastPush.returns({contentAssets: TIMESTAMP}); + stubGetLastPull.returns({ + webAssets: {"draft": TIMESTAMP, "ready": TIMESTAMP}, + contentAssets: {"draft": TIMESTAMP, "ready": TIMESTAMP} + }); + const NEW_TIMESTAMP = new Date(); // Call the method being tested. let error; try { - const timestamp = assetsHelper._getLastPushTimestamps(context, UnitTest.DUMMY_OPTIONS); - expect(timestamp.webAssets).to.be.empty; - expect(timestamp.contentAssets).to.equal(TIMESTAMP); + assetsHelper._setLastPullTimestamps(context, NEW_TIMESTAMP, { + assetTypes: assetsHelper.ASSET_TYPES_WEB_ASSETS, + filterReady: true + }); + expect(stubGetLastPull).to.have.been.calledOnce; + expect(stubSetLastPull.args[0][2]["webAssets"]["draft"]).to.equal(TIMESTAMP); + expect(stubSetLastPull.args[0][2]["webAssets"]["ready"]).to.equal(NEW_TIMESTAMP); + expect(stubSetLastPull.args[0][2]["contentAssets"]["draft"]).to.equal(TIMESTAMP); + expect(stubSetLastPull.args[0][2]["contentAssets"]["ready"]).to.equal(TIMESTAMP); } catch (err) { // NOTE: A failed expectation from above will be handled here. // Pass the error to the "done" function to indicate a failed test. @@ -8265,26 +8232,28 @@ class AssetsHelperUnitTest extends AssetsUnitTest { done(error); } }); - }); - describe("_setLastPullTimestamps", function () { - it("should set both timestamps when both assets types are specified", function (done) { + it("should only set the web assets draft timestamp when the web assets type is specified with draft filtering", function (done) { // Change the hashes.getLastPullTimestamp stub to return a known value. const TIMESTAMP = "2017-05-10T04:36:49.987Z"; - stubGetLastPull.returns({webAssets: TIMESTAMP, contentAssets: TIMESTAMP}); + stubGetLastPull.returns({ + webAssets: {"draft": TIMESTAMP, "ready": TIMESTAMP}, + contentAssets: {"draft": TIMESTAMP, "ready": TIMESTAMP} + }); const NEW_TIMESTAMP = new Date(); // Call the method being tested. let error; try { - assetsHelper._setLastPullTimestamps(context, NEW_TIMESTAMP, {assetTypes: assetsHelper.ASSET_TYPES_BOTH}); + assetsHelper._setLastPullTimestamps(context, NEW_TIMESTAMP, { + assetTypes: assetsHelper.ASSET_TYPES_WEB_ASSETS, + filterDraft: true + }); expect(stubGetLastPull).to.have.been.calledOnce; - expect(stubSetLastPull.args[0][2]["webAssets"]).to.exist; - expect(stubSetLastPull.args[0][2]["webAssets"]).to.not.equal(TIMESTAMP); - expect(stubSetLastPull.args[0][2]["webAssets"]).to.equal(NEW_TIMESTAMP); - expect(stubSetLastPull.args[0][2]["contentAssets"]).to.exist; - expect(stubSetLastPull.args[0][2]["contentAssets"]).to.not.equal(TIMESTAMP); - expect(stubSetLastPull.args[0][2]["contentAssets"]).to.equal(NEW_TIMESTAMP); + expect(stubSetLastPull.args[0][2]["webAssets"]["draft"]).to.equal(NEW_TIMESTAMP); + expect(stubSetLastPull.args[0][2]["webAssets"]["ready"]).to.equal(TIMESTAMP); + expect(stubSetLastPull.args[0][2]["contentAssets"]["draft"]).to.equal(TIMESTAMP); + expect(stubSetLastPull.args[0][2]["contentAssets"]["ready"]).to.equal(TIMESTAMP); } catch (err) { // NOTE: A failed expectation from above will be handled here. // Pass the error to the "done" function to indicate a failed test. @@ -8295,22 +8264,27 @@ class AssetsHelperUnitTest extends AssetsUnitTest { } }); - it("should only set the web assets timestamp when the web assets type is specified", function (done) { + it("should only set the content assets ready timestamp when the content assets type is specified with ready filtering", function (done) { // Change the hashes.getLastPullTimestamp stub to return a known value. const TIMESTAMP = "2017-05-10T04:36:49.987Z"; - stubGetLastPull.returns({webAssets: TIMESTAMP, contentAssets: TIMESTAMP}); + stubGetLastPull.returns({ + webAssets: {"draft": TIMESTAMP, "ready": TIMESTAMP}, + contentAssets: {"draft": TIMESTAMP, "ready": TIMESTAMP} + }); const NEW_TIMESTAMP = new Date(); // Call the method being tested. let error; try { - assetsHelper._setLastPullTimestamps(context, NEW_TIMESTAMP, {assetTypes: assetsHelper.ASSET_TYPES_WEB_ASSETS}); + assetsHelper._setLastPullTimestamps(context, NEW_TIMESTAMP, { + assetTypes: assetsHelper.ASSET_TYPES_CONTENT_ASSETS, + filterReady: true + }); expect(stubGetLastPull).to.have.been.calledOnce; - expect(stubSetLastPull.args[0][2]["webAssets"]).to.exist; - expect(stubSetLastPull.args[0][2]["webAssets"]).to.not.equal(TIMESTAMP); - expect(stubSetLastPull.args[0][2]["webAssets"]).to.equal(NEW_TIMESTAMP); - expect(stubSetLastPull.args[0][2]["contentAssets"]).to.exist; - expect(stubSetLastPull.args[0][2]["contentAssets"]).to.equal(TIMESTAMP); + expect(stubSetLastPull.args[0][2]["webAssets"]["draft"]).to.equal(TIMESTAMP); + expect(stubSetLastPull.args[0][2]["webAssets"]["ready"]).to.equal(TIMESTAMP); + expect(stubSetLastPull.args[0][2]["contentAssets"]["draft"]).to.equal(TIMESTAMP); + expect(stubSetLastPull.args[0][2]["contentAssets"]["ready"]).to.equal(NEW_TIMESTAMP); } catch (err) { // NOTE: A failed expectation from above will be handled here. // Pass the error to the "done" function to indicate a failed test. @@ -8321,22 +8295,27 @@ class AssetsHelperUnitTest extends AssetsUnitTest { } }); - it("should only set the content assets timestamp when the content assets type is specified", function (done) { + it("should only set the content assets draft timestamp when the content assets type is specified with draft filtering", function (done) { // Change the hashes.getLastPullTimestamp stub to return a known value. const TIMESTAMP = "2017-05-10T04:36:49.987Z"; - stubGetLastPull.returns({webAssets: TIMESTAMP, contentAssets: TIMESTAMP}); + stubGetLastPull.returns({ + webAssets: {"draft": TIMESTAMP, "ready": TIMESTAMP}, + contentAssets: {"draft": TIMESTAMP, "ready": TIMESTAMP} + }); const NEW_TIMESTAMP = new Date(); // Call the method being tested. let error; try { - assetsHelper._setLastPullTimestamps(context, NEW_TIMESTAMP, {assetTypes: assetsHelper.ASSET_TYPES_CONTENT_ASSETS}); + assetsHelper._setLastPullTimestamps(context, NEW_TIMESTAMP, { + assetTypes: assetsHelper.ASSET_TYPES_CONTENT_ASSETS, + filterDraft: true + }); expect(stubGetLastPull).to.have.been.calledOnce; - expect(stubSetLastPull.args[0][2]["webAssets"]).to.exist; - expect(stubSetLastPull.args[0][2]["webAssets"]).to.equal(TIMESTAMP); - expect(stubSetLastPull.args[0][2]["contentAssets"]).to.exist; - expect(stubSetLastPull.args[0][2]["contentAssets"]).to.not.equal(TIMESTAMP); - expect(stubSetLastPull.args[0][2]["contentAssets"]).to.equal(NEW_TIMESTAMP); + expect(stubSetLastPull.args[0][2]["webAssets"]["draft"]).to.equal(TIMESTAMP); + expect(stubSetLastPull.args[0][2]["webAssets"]["ready"]).to.equal(TIMESTAMP); + expect(stubSetLastPull.args[0][2]["contentAssets"]["draft"]).to.equal(NEW_TIMESTAMP); + expect(stubSetLastPull.args[0][2]["contentAssets"]["ready"]).to.equal(TIMESTAMP); } catch (err) { // NOTE: A failed expectation from above will be handled here. // Pass the error to the "done" function to indicate a failed test. @@ -8348,159 +8327,133 @@ class AssetsHelperUnitTest extends AssetsUnitTest { }); }); - describe("_setLastPushTimestamps", function () { - it("should set both timestamps when both assets types are specified", function (done) { - // Change the hashes.getLastPushTimestamp stub to return a known value. - const TIMESTAMP = "2017-05-10T04:36:49.987Z"; - stubGetLastPush.returns({webAssets: TIMESTAMP, contentAssets: TIMESTAMP}); - const NEW_TIMESTAMP = new Date(); + describe("getLastPullTimestamp", function () { + it("should return the web assets ready timestamp when the web assets type is specified", function (done) { + const TIMESTAMP_1 = "1962-11-09T11:38:34.123Z"; + const TIMESTAMP_2 = "2017-11-28T14:31:00.456Z"; + const stub = sinon.stub(assetsHelper, "_getLastPullTimestamps"); + stub.returns({ + webAssets: {"draft": TIMESTAMP_1, "ready": TIMESTAMP_2}, + contentAssets: {"draft": TIMESTAMP_1, "ready": TIMESTAMP_1} + }); // Call the method being tested. let error; try { - assetsHelper._setLastPushTimestamps(context, NEW_TIMESTAMP, {assetTypes: assetsHelper.ASSET_TYPES_BOTH}); - expect(stubGetLastPush).to.have.been.calledOnce; - expect(stubSetLastPush.args[0][2]["webAssets"]).to.exist; - expect(stubSetLastPush.args[0][2]["webAssets"]).to.not.equal(TIMESTAMP); - expect(stubSetLastPush.args[0][2]["webAssets"]).to.equal(NEW_TIMESTAMP); - expect(stubSetLastPush.args[0][2]["contentAssets"]).to.exist; - expect(stubSetLastPush.args[0][2]["contentAssets"]).to.not.equal(TIMESTAMP); - expect(stubSetLastPush.args[0][2]["contentAssets"]).to.equal(NEW_TIMESTAMP); + const timestamp = assetsHelper.getLastPullTimestamp(context, { + assetTypes: assetsHelper.ASSET_TYPES_WEB_ASSETS, + filterReady: true + }); + expect(timestamp).to.equal(TIMESTAMP_2); } catch (err) { // NOTE: A failed expectation from above will be handled here. // Pass the error to the "done" function to indicate a failed test. error = err; } finally { + stub.restore(); + // Call mocha's done function to indicate that the test is over. done(error); } }); - it("should only set the web assets timestamp when the web assets type is specified", function (done) { - // Change the hashes.getLastPushTimestamp stub to return the old format. - const TIMESTAMP = "2017-05-10T04:36:49.987Z"; - stubGetLastPush.returns({webAssets: TIMESTAMP, contentAssets: TIMESTAMP}); - const NEW_TIMESTAMP = new Date(); + it("should return the content assets ready timestamp when the content assets type is specified", function (done) { + const TIMESTAMP_1 = "1962-11-09T11:38:34.123Z"; + const TIMESTAMP_2 = "2017-11-28T14:31:00.456Z"; + const stub = sinon.stub(assetsHelper, "_getLastPullTimestamps"); + stub.returns({ + webAssets: {"draft": TIMESTAMP_1, "ready": TIMESTAMP_1}, + contentAssets: {"draft": TIMESTAMP_1, "ready": TIMESTAMP_2} + }); // Call the method being tested. let error; try { - assetsHelper._setLastPushTimestamps(context, NEW_TIMESTAMP, {assetTypes: assetsHelper.ASSET_TYPES_WEB_ASSETS}); - expect(stubGetLastPush).to.have.been.calledOnce; - expect(stubSetLastPush.args[0][2]["webAssets"]).to.exist; - expect(stubSetLastPush.args[0][2]["webAssets"]).to.not.equal(TIMESTAMP); - expect(stubSetLastPush.args[0][2]["webAssets"]).to.equal(NEW_TIMESTAMP); - expect(stubSetLastPush.args[0][2]["contentAssets"]).to.exist; - expect(stubSetLastPush.args[0][2]["contentAssets"]).to.equal(TIMESTAMP); + const timestamp = assetsHelper.getLastPullTimestamp(context, { + assetTypes: assetsHelper.ASSET_TYPES_CONTENT_ASSETS, + filterReady: true + }); + expect(timestamp).to.equal(TIMESTAMP_2); } catch (err) { // NOTE: A failed expectation from above will be handled here. // Pass the error to the "done" function to indicate a failed test. error = err; } finally { + stub.restore(); + // Call mocha's done function to indicate that the test is over. done(error); } }); - it("should only set the content assets timestamp when the content assets type is specified", function (done) { - // Change the hashes.getLastPushTimestamp stub to return the old format. - const TIMESTAMP = "2017-05-10T04:36:49.987Z"; - stubGetLastPush.returns({webAssets: TIMESTAMP, contentAssets: TIMESTAMP}); - const NEW_TIMESTAMP = new Date(); + it("should return the web assets draft timestamp when it is before the web assets ready timestamp", function (done) { + const TIMESTAMP_1 = "1962-11-09T11:38:34.123Z"; + const TIMESTAMP_2 = "2017-11-28T14:31:00.456Z"; + const stub = sinon.stub(assetsHelper, "_getLastPullTimestamps"); + stub.returns({ + webAssets: {"draft": TIMESTAMP_1, "ready": TIMESTAMP_2}, + contentAssets: {"draft": TIMESTAMP_2, "ready": TIMESTAMP_2} + }); // Call the method being tested. let error; try { - assetsHelper._setLastPushTimestamps(context, NEW_TIMESTAMP, {assetTypes: assetsHelper.ASSET_TYPES_CONTENT_ASSETS}); - expect(stubGetLastPush).to.have.been.calledOnce; - expect(stubSetLastPush.args[0][2]["webAssets"]).to.exist; - expect(stubSetLastPush.args[0][2]["webAssets"]).to.equal(TIMESTAMP); - expect(stubSetLastPush.args[0][2]["contentAssets"]).to.exist; - expect(stubSetLastPush.args[0][2]["contentAssets"]).to.not.equal(TIMESTAMP); - expect(stubSetLastPush.args[0][2]["contentAssets"]).to.equal(NEW_TIMESTAMP); + const timestamp = assetsHelper.getLastPullTimestamp(context, {assetTypes: assetsHelper.ASSET_TYPES_WEB_ASSETS}); + expect(timestamp).to.equal(TIMESTAMP_1); } catch (err) { // NOTE: A failed expectation from above will be handled here. // Pass the error to the "done" function to indicate a failed test. error = err; } finally { - // Call mocha's done function to indicate that the test is over. - done(error); - } - }); - }); + stub.restore(); - describe("_getTimestamp", function () { - it("should return the web assets timestamp when the web assets type is specified", function (done) { - // Call the method being tested. - let error; - try { - const TIMESTAMP_BEFORE = "1962-11-09T11:38:34.123Z"; - const TIMESTAMP_AFTER = "2017-11-28T14:31:00.456Z"; - const timestamps = {webAssets: TIMESTAMP_BEFORE, contentAssets: TIMESTAMP_AFTER}; - const timestamp = assetsHelper._getTimestamp(timestamps, {assetTypes: assetsHelper.ASSET_TYPES_WEB_ASSETS}); - expect(timestamp).to.equal(TIMESTAMP_BEFORE); - } catch (err) { - // NOTE: A failed expectation from above will be handled here. - // Pass the error to the "done" function to indicate a failed test. - error = err; - } finally { // Call mocha's done function to indicate that the test is over. done(error); } }); - it("should return the content assets timestamp when the content assets type is specified", function (done) { - // Call the method being tested. - let error; - try { - const TIMESTAMP_BEFORE = "1962-11-09T11:38:34.123Z"; - const TIMESTAMP_AFTER = "2017-11-28T14:31:00.456Z"; - const timestamps = {webAssets: TIMESTAMP_BEFORE, contentAssets: TIMESTAMP_AFTER}; - const timestamp = assetsHelper._getTimestamp(timestamps, {assetTypes: assetsHelper.ASSET_TYPES_CONTENT_ASSETS}); - expect(timestamp).to.equal(TIMESTAMP_AFTER); - } catch (err) { - // NOTE: A failed expectation from above will be handled here. - // Pass the error to the "done" function to indicate a failed test. - error = err; - } finally { - // Call mocha's done function to indicate that the test is over. - done(error); - } - }); + it("should return the content assets ready timestamp when it is before the content assets draft timestamp", function (done) { + const TIMESTAMP_1 = "1962-11-09T11:38:34.123Z"; + const TIMESTAMP_2 = "2017-11-28T14:31:00.456Z"; + const stub = sinon.stub(assetsHelper, "_getLastPullTimestamps"); + stub.returns({ + webAssets: {"draft": TIMESTAMP_2, "ready": TIMESTAMP_2}, + contentAssets: {"draft": TIMESTAMP_2, "ready": TIMESTAMP_1} + }); - it("should return the web assets timestamp when it is before the content assets timestamp", function (done) { // Call the method being tested. let error; try { - const TIMESTAMP_BEFORE = "1962-11-09T11:38:34.123Z"; - const TIMESTAMP_AFTER = "2017-11-28T14:31:00.456Z"; - const timestamps = {webAssets: TIMESTAMP_BEFORE, contentAssets: TIMESTAMP_AFTER}; - const timestamp = assetsHelper._getTimestamp(timestamps, {assetTypes: assetsHelper.ASSET_TYPES_BOTH}); - expect(timestamp).to.equal(TIMESTAMP_BEFORE); + const timestamp = assetsHelper.getLastPullTimestamp(context, {assetTypes: assetsHelper.ASSET_TYPES_BOTH}); + expect(timestamp).to.equal(TIMESTAMP_1); } catch (err) { // NOTE: A failed expectation from above will be handled here. // Pass the error to the "done" function to indicate a failed test. error = err; } finally { + stub.restore(); + // Call mocha's done function to indicate that the test is over. done(error); } }); - it("should return the content assets timestamp when it is before the web assets timestamp", function (done) { + it("should return an undefined timestamp when no pull timestamps were saved", function (done) { + const stub = sinon.stub(assetsHelper, "_getLastPullTimestamps"); + stub.returns(undefined); + // Call the method being tested. let error; try { - const TIMESTAMP_BEFORE = "1962-11-09T11:38:34.123Z"; - const TIMESTAMP_AFTER = "2017-11-28T14:31:00.456Z"; - const timestamps = {webAssets: TIMESTAMP_AFTER, contentAssets: TIMESTAMP_BEFORE}; - const timestamp = assetsHelper._getTimestamp(timestamps, {assetTypes: assetsHelper.ASSET_TYPES_BOTH}); - expect(timestamp).to.equal(TIMESTAMP_BEFORE); + const timestamp = assetsHelper.getLastPullTimestamp(context, {assetTypes: assetsHelper.ASSET_TYPES_BOTH}); + expect(timestamp).to.not.exist; } catch (err) { // NOTE: A failed expectation from above will be handled here. // Pass the error to the "done" function to indicate a failed test. error = err; } finally { + stub.restore(); + // Call mocha's done function to indicate that the test is over. done(error); } diff --git a/authoring-api/test/unit/lib/base.helper.unit.js b/authoring-api/test/unit/lib/base.helper.unit.js index f44dbc7..745b954 100644 --- a/authoring-api/test/unit/lib/base.helper.unit.js +++ b/authoring-api/test/unit/lib/base.helper.unit.js @@ -1196,14 +1196,19 @@ class BaseHelperUnitTest extends UnitTest { const stubGet = sinon.stub(restApi, "getItems"); const readyMetadata1 = utils.clone(itemMetadata1); readyMetadata1.status = "ready"; + readyMetadata1.siteStatus = "ready"; const readyMetadata2 = utils.clone(itemMetadata2); readyMetadata2.status = "ready"; + readyMetadata2.siteStatus = "ready"; const readyMetadata3 = utils.clone(itemMetadata2); readyMetadata3.status = "ready"; + readyMetadata3.siteStatus = "ready"; const draftMetadata1 = utils.clone(itemMetadata1); draftMetadata1.status = "draft"; + draftMetadata1.siteStatus = "draft"; const draftMetadata2 = utils.clone(itemMetadata2); draftMetadata2.status = "draft"; + draftMetadata2.siteStatus = "draft"; stubGet.resolves([readyMetadata1, readyMetadata2, readyMetadata3, draftMetadata1, draftMetadata2]); // Create a helper.canPullItem stub that return false for some of the items. @@ -1262,14 +1267,19 @@ class BaseHelperUnitTest extends UnitTest { const stubGet = sinon.stub(restApi, "getItems"); const readyMetadata1 = utils.clone(itemMetadata1); readyMetadata1.status = "ready"; + readyMetadata1.siteStatus = "ready"; const readyMetadata2 = utils.clone(itemMetadata2); readyMetadata2.status = "ready"; + readyMetadata2.siteStatus = "ready"; const readyMetadata3 = utils.clone(itemMetadata2); readyMetadata3.status = "ready"; + readyMetadata3.siteStatus = "ready"; const draftMetadata1 = utils.clone(itemMetadata1); draftMetadata1.status = "draft"; + draftMetadata1.siteStatus = "draft"; const draftMetadata2 = utils.clone(itemMetadata2); draftMetadata2.status = "draft"; + draftMetadata2.siteStatus = "draft"; stubGet.resolves([readyMetadata1, readyMetadata2, readyMetadata3, draftMetadata1, draftMetadata2]); // Create a helper.canPullItem stub that return false for some of the items. diff --git a/package.json b/package.json index d715d42..b06d440 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prod-tools", - "version": "2.9.2", + "version": "3.0.4", "author": "IBM Corporation", "license": "Apache-2.0", "bugs": {