From ec471d37661ed3c098710bf735c3447e99a45ffb Mon Sep 17 00:00:00 2001 From: Sparsh Agarwal Date: Sat, 18 Sep 2021 14:37:48 +0530 Subject: [PATCH 01/14] added support for npm package caching --- bin/commands/runs.js | 181 +++++++++++++++++--------------- bin/helpers/capabilityHelper.js | 5 + bin/helpers/checkUploaded.js | 37 ++++--- bin/helpers/config.js | 2 + bin/helpers/constants.js | 4 + bin/helpers/fileHelpers.js | 12 +++ bin/helpers/packageInstaller.js | 115 ++++++++++++++++++++ bin/helpers/utils.js | 77 ++++++++++++++ bin/helpers/zipUpload.js | 66 +++++++----- package.json | 3 +- 10 files changed, 377 insertions(+), 125 deletions(-) create mode 100644 bin/helpers/packageInstaller.js diff --git a/bin/commands/runs.js b/bin/commands/runs.js index 2fb7fe45..9c05c8f8 100644 --- a/bin/commands/runs.js +++ b/bin/commands/runs.js @@ -10,6 +10,7 @@ const archiver = require("../helpers/archiver"), fileHelpers = require("../helpers/fileHelpers"), syncRunner = require("../helpers/syncRunner"), checkUploaded = require("../helpers/checkUploaded"), + packageInstaller = require("../helpers/packageInstaller"), reportGenerator = require('../helpers/reporterHTML').reportGenerator, {initTimeComponents, markBlockStart, markBlockEnd, getTimeComponents} = require('../helpers/timeComponents'); @@ -87,109 +88,119 @@ module.exports = function run(args) { return checkUploaded.checkUploadedMd5(bsConfig, args).then(function (md5data) { markBlockEnd('checkAlreadyUploaded'); - // Archive the spec files - markBlockStart('zip'); - markBlockStart('zip.archive'); - return archiver.archive(bsConfig.run_settings, config.fileName, args.exclude, md5data).then(function (data) { - markBlockEnd('zip.archive'); - - // Uploaded zip file - markBlockStart('zip.zipUpload'); - return zipUploader.zipUpload(bsConfig, config.fileName, md5data).then(async function (zip) { - markBlockEnd('zip.zipUpload'); - markBlockEnd('zip'); - // Create build - - //setup Local Testing - markBlockStart('localSetup'); - let bs_local = await utils.setupLocalTesting(bsConfig, args); - markBlockEnd('localSetup'); - markBlockStart('createBuild'); - return build.createBuild(bsConfig, zip).then(function (data) { - markBlockEnd('createBuild'); - markBlockEnd('total'); - let message = `${data.message}! ${Constants.userMessages.BUILD_CREATED} with build id: ${data.build_id}`; - let dashboardLink = `${Constants.userMessages.VISIT_DASHBOARD} ${data.dashboard_url}`; - utils.exportResults(data.build_id, `${config.dashboardUrl}${data.build_id}`); - if ((utils.isUndefined(bsConfig.run_settings.parallels) && utils.isUndefined(args.parallels)) || (!utils.isUndefined(bsConfig.run_settings.parallels) && bsConfig.run_settings.parallels == Constants.cliMessages.RUN.DEFAULT_PARALLEL_MESSAGE)) { - logger.warn(Constants.userMessages.NO_PARALLELS); - } + markBlockStart('packageInstaller'); + return packageInstaller.packageWrappper(bsConfig, config.packageDirName, config.packageFileName, md5data, args).then(function (packageData) { + markBlockEnd('packageInstaller'); + + // Archive the spec files + markBlockStart('zip'); + markBlockStart('zip.archive'); + return archiver.archive(bsConfig.run_settings, config.fileName, args.exclude, md5data).then(function (data) { + markBlockEnd('zip.archive'); + + // Uploaded zip file + markBlockStart('zip.zipUpload'); + return zipUploader.zipUpload(bsConfig, md5data, packageData).then(async function (zip) { + markBlockEnd('zip.zipUpload'); + markBlockEnd('zip'); + + // Create build + //setup Local Testing + markBlockStart('localSetup'); + let bs_local = await utils.setupLocalTesting(bsConfig, args); + markBlockEnd('localSetup'); + markBlockStart('createBuild'); + return build.createBuild(bsConfig, zip).then(function (data) { + markBlockEnd('createBuild'); + markBlockEnd('total'); + let message = `${data.message}! ${Constants.userMessages.BUILD_CREATED} with build id: ${data.build_id}`; + let dashboardLink = `${Constants.userMessages.VISIT_DASHBOARD} ${data.dashboard_url}`; + utils.exportResults(data.build_id, `${config.dashboardUrl}${data.build_id}`); + if ((utils.isUndefined(bsConfig.run_settings.parallels) && utils.isUndefined(args.parallels)) || (!utils.isUndefined(bsConfig.run_settings.parallels) && bsConfig.run_settings.parallels == Constants.cliMessages.RUN.DEFAULT_PARALLEL_MESSAGE)) { + logger.warn(Constants.userMessages.NO_PARALLELS); + } - if (bsConfig.run_settings.cypress_version && bsConfig.run_settings.cypress_version !== data.cypress_version) { - if (bsConfig.run_settings.cypress_version.match(Constants.LATEST_VERSION_SYNTAX_REGEX)) { - let versionMessage = utils.latestSyntaxToActualVersionMessage(bsConfig.run_settings.cypress_version, data.cypress_version); - logger.info(versionMessage); - } else { - let versionMessage = utils.versionChangedMessage(bsConfig.run_settings.cypress_version, data.cypress_version); - logger.warn(versionMessage); + if (bsConfig.run_settings.cypress_version && bsConfig.run_settings.cypress_version !== data.cypress_version) { + if (bsConfig.run_settings.cypress_version.match(Constants.LATEST_VERSION_SYNTAX_REGEX)) { + let versionMessage = utils.latestSyntaxToActualVersionMessage(bsConfig.run_settings.cypress_version, data.cypress_version); + logger.info(versionMessage); + } else { + let versionMessage = utils.versionChangedMessage(bsConfig.run_settings.cypress_version, data.cypress_version); + logger.warn(versionMessage); + } } - } - if (!args.disableNpmWarning && bsConfig.run_settings.npm_dependencies && Object.keys(bsConfig.run_settings.npm_dependencies).length <= 0) { - logger.warn(Constants.userMessages.NO_NPM_DEPENDENCIES); - logger.warn(Constants.userMessages.NO_NPM_DEPENDENCIES_READ_MORE); - } + if (!args.disableNpmWarning && bsConfig.run_settings.npm_dependencies && Object.keys(bsConfig.run_settings.npm_dependencies).length <= 0) { + logger.warn(Constants.userMessages.NO_NPM_DEPENDENCIES); + logger.warn(Constants.userMessages.NO_NPM_DEPENDENCIES_READ_MORE); + } - if (args.sync) { - syncRunner.pollBuildStatus(bsConfig, data).then(async (exitCode) => { + if (args.sync) { + syncRunner.pollBuildStatus(bsConfig, data).then(async (exitCode) => { - // stop the Local instance - await utils.stopLocalBinary(bsConfig, bs_local, args); + // stop the Local instance + await utils.stopLocalBinary(bsConfig, bs_local, args); - // Generate custom report! - reportGenerator(bsConfig, data.build_id, args, function(){ - utils.sendUsageReport(bsConfig, args, `${message}\n${dashboardLink}`, Constants.messageTypes.SUCCESS, null); - utils.handleSyncExit(exitCode, data.dashboard_url); + // Generate custom report! + reportGenerator(bsConfig, data.build_id, args, function(){ + utils.sendUsageReport(bsConfig, args, `${message}\n${dashboardLink}`, Constants.messageTypes.SUCCESS, null); + utils.handleSyncExit(exitCode, data.dashboard_url); + }); }); - }); - } - - logger.info(message); - logger.info(dashboardLink); - if(!args.sync) logger.info(Constants.userMessages.EXIT_SYNC_CLI_MESSAGE.replace("",data.build_id)); - let dataToSend = { - time_components: getTimeComponents(), - build_id: data.build_id, - }; - if (bsConfig && bsConfig.connection_settings) { - if (bsConfig.connection_settings.local_mode) { - dataToSend.local_mode = bsConfig.connection_settings.local_mode; } - if (bsConfig.connection_settings.usedAutoLocal) { - dataToSend.used_auto_local = bsConfig.connection_settings.usedAutoLocal; + + logger.info(message); + logger.info(dashboardLink); + if(!args.sync) logger.info(Constants.userMessages.EXIT_SYNC_CLI_MESSAGE.replace("",data.build_id)); + let dataToSend = { + time_components: getTimeComponents(), + build_id: data.build_id, + }; + if (bsConfig && bsConfig.connection_settings) { + if (bsConfig.connection_settings.local_mode) { + dataToSend.local_mode = bsConfig.connection_settings.local_mode; + } + if (bsConfig.connection_settings.usedAutoLocal) { + dataToSend.used_auto_local = bsConfig.connection_settings.usedAutoLocal; + } } - } - utils.sendUsageReport(bsConfig, args, `${message}\n${dashboardLink}`, Constants.messageTypes.SUCCESS, null, dataToSend); - return; - }).catch(async function (err) { - // Build creation failed + utils.sendUsageReport(bsConfig, args, `${message}\n${dashboardLink}`, Constants.messageTypes.SUCCESS, null, dataToSend); + return; + }).catch(async function (err) { + // Build creation failed + logger.error(err); + // stop the Local instance + await utils.stopLocalBinary(bsConfig, bs_local, args); + + utils.sendUsageReport(bsConfig, args, err, Constants.messageTypes.ERROR, 'build_failed'); + }); + }).catch(function (err) { + // Zip Upload failed | Local Start failed logger.error(err); - // stop the Local instance - await utils.stopLocalBinary(bsConfig, bs_local, args); - - utils.sendUsageReport(bsConfig, args, err, Constants.messageTypes.ERROR, 'build_failed'); + if(err === Constants.userMessages.LOCAL_START_FAILED){ + utils.sendUsageReport(bsConfig, args, `${err}\n${Constants.userMessages.LOCAL_START_FAILED}`, Constants.messageTypes.ERROR, 'local_start_failed'); + } else { + logger.error(Constants.userMessages.ZIP_UPLOAD_FAILED); + fileHelpers.deleteZip(); + utils.sendUsageReport(bsConfig, args, `${err}\n${Constants.userMessages.ZIP_UPLOAD_FAILED}`, Constants.messageTypes.ERROR, 'zip_upload_failed'); + } }); }).catch(function (err) { - // Zip Upload failed | Local Start failed + // Zipping failed logger.error(err); - if(err === Constants.userMessages.LOCAL_START_FAILED){ - utils.sendUsageReport(bsConfig, args, `${err}\n${Constants.userMessages.LOCAL_START_FAILED}`, Constants.messageTypes.ERROR, 'local_start_failed'); - } else { - logger.error(Constants.userMessages.ZIP_UPLOAD_FAILED); + logger.error(Constants.userMessages.FAILED_TO_ZIP); + utils.sendUsageReport(bsConfig, args, `${err}\n${Constants.userMessages.FAILED_TO_ZIP}`, Constants.messageTypes.ERROR, 'zip_creation_failed'); + try { fileHelpers.deleteZip(); - utils.sendUsageReport(bsConfig, args, `${err}\n${Constants.userMessages.ZIP_UPLOAD_FAILED}`, Constants.messageTypes.ERROR, 'zip_upload_failed'); + } catch (err) { + utils.sendUsageReport(bsConfig, args, Constants.userMessages.ZIP_DELETE_FAILED, Constants.messageTypes.ERROR, 'zip_deletion_failed'); } }); }).catch(function (err) { - // Zipping failed + // package installer failed logger.error(err); - logger.error(Constants.userMessages.FAILED_TO_ZIP); - utils.sendUsageReport(bsConfig, args, `${err}\n${Constants.userMessages.FAILED_TO_ZIP}`, Constants.messageTypes.ERROR, 'zip_creation_failed'); - try { - fileHelpers.deleteZip(); - } catch (err) { - utils.sendUsageReport(bsConfig, args, Constants.userMessages.ZIP_DELETE_FAILED, Constants.messageTypes.ERROR, 'zip_deletion_failed'); - } + logger.error(Constants.userMessages.FAILED_CREATE_NPM_ARCHIVE); + utils.sendUsageReport(bsConfig, args, Constants.userMessages.FAILED_CREATE_NPM_ARCHIVE, Constants.messageTypes.ERROR, 'npm_package_archive_failed'); }); }).catch(function (err) { // md5 check failed diff --git a/bin/helpers/capabilityHelper.js b/bin/helpers/capabilityHelper.js index b432f6fc..3a46d052 100644 --- a/bin/helpers/capabilityHelper.js +++ b/bin/helpers/capabilityHelper.js @@ -42,6 +42,11 @@ const caps = (bsConfig, zip) => { reject("Test suite is empty"); } + // Npm package + if (zip.npm_package_url && zip.npm_package_url.split("://")[1].length !== 0) { + obj.npm_package_suite = zip.npm_package_url.split("://")[1]; + } + // Inferred settings if(bsConfig.connection_settings){ if (bsConfig.connection_settings.local_mode_inferred) { diff --git a/bin/helpers/checkUploaded.js b/bin/helpers/checkUploaded.js index beaa77fa..1c8c109f 100644 --- a/bin/helpers/checkUploaded.js +++ b/bin/helpers/checkUploaded.js @@ -45,12 +45,12 @@ const checkPackageMd5 = (runSettings) => { const outputHash = crypto.createHash(Constants.hashingOptions.algo); let packageJSON = {}; if (typeof runSettings.package_config_options === 'object') { - Object.assign(packageJSON, runSettings.package_config_options); + Object.assign(packageJSON, utils.sortJsonKeys(runSettings.package_config_options)); } if (typeof runSettings.npm_dependencies === 'object') { Object.assign(packageJSON, { - devDependencies: runSettings.npm_dependencies, + devDependencies: utils.sortJsonKeys(runSettings.npm_dependencies), }); } @@ -66,14 +66,22 @@ const checkUploadedMd5 = (bsConfig, args) => { return new Promise(function (resolve) { let obj = { zipUrlPresent: false, + packageUrlPresent: false, }; - if (args["force-upload"]) { + if (args["force-upload"] && !utils.isTrueString(bsConfig.run_settings.local_npm_install)) { return resolve(obj); } - checkSpecsMd5(bsConfig.run_settings, args.exclude).then(function (md5data) { - Object.assign(obj, {md5sum: md5data}); - let package_md5sum = checkPackageMd5(bsConfig.run_settings); - let data = JSON.stringify({ zip_md5sum: md5data, instrument_package_md5sum: package_md5sum}); + checkSpecsMd5(bsConfig.run_settings, args.exclude).then(function (zip_md5sum) { + let npm_package_md5sum = checkPackageMd5(bsConfig.run_settings); + let data = {}; + if (!args["force-upload"]) { + Object.assign(data, { zip_md5sum:"sad" }); + Object.assign(obj, { zip_md5sum }); + } + if (utils.isTrueString(bsConfig.run_settings.local_npm_install)) { + Object.assign(data, { npm_package_md5sum:"as" }); + Object.assign(obj, { npm_package_md5sum }); + } let options = { url: config.checkMd5sum, @@ -85,7 +93,7 @@ const checkUploadedMd5 = (bsConfig, args) => { 'Content-Type': 'application/json', "User-Agent": utils.getUserAgent(), }, - body: data + body: JSON.stringify(data) }; request.post(options, function (err, resp, body) { @@ -98,14 +106,19 @@ const checkUploadedMd5 = (bsConfig, args) => { } catch (error) { zipData = {}; } - if (resp.statusCode === 200 && !utils.isUndefined(zipData.zipUrl)) { - Object.assign(obj, zipData, {zipUrlPresent: true}); + if (resp.statusCode === 200) { + if (!utils.isUndefined(zipData.zipUrl)) { + Object.assign(obj, zipData, {zipUrlPresent: true}); + } + if (!utils.isUndefined(zipData.npmPackageUrl)) { + Object.assign(obj, zipData, {packageUrlPresent: true}); + } } resolve(obj); } }); - }).catch((error) => { - resolve({zipUrlPresent: false}); + }).catch((_error) => { + resolve({zipUrlPresent: false, packageUrlPresent: false}); }); }); }; diff --git a/bin/helpers/config.js b/bin/helpers/config.js index a17f0c43..530ca530 100644 --- a/bin/helpers/config.js +++ b/bin/helpers/config.js @@ -17,6 +17,8 @@ config.buildUrl = `${config.cypress_v1}/builds/`; config.buildStopUrl = `${config.cypress_v1}/builds/stop/`; config.checkMd5sum = `${config.cypress_v1}/md5sumcheck/`; config.fileName = "tests.zip"; +config.packageFileName = "bstackPackages.tar.gz"; +config.packageDirName = "tmpBstackPackages"; config.retries = 5; config.networkErrorExitCode = 2; diff --git a/bin/helpers/constants.js b/bin/helpers/constants.js index 884687c4..d280cf1d 100644 --- a/bin/helpers/constants.js +++ b/bin/helpers/constants.js @@ -24,8 +24,11 @@ const userMessages = { MD5_CHECK_FAILED: "There was some issue while checking if zip is already uploaded.", ZIP_DELETE_FAILED: "Could not delete tests.zip successfully.", ZIP_DELETED: "Deleted tests.zip successfully.", + NPM_DELETE_FAILED: "Could not delete browserstack-cli npm packages successfully.", + NPM_DELETED: "Deleted browserstack-cli npm packages successfully.", API_DEPRECATED: "This version of API is deprecated, please use latest version of API.", FAILED_TO_ZIP: "Failed to zip files.", + FAILED_CREATE_NPM_ARCHIVE: "Something went wrong while crreating npm archieve.", FAILED_MD5_CHECK: "Something went wrong - you can retry running browserstack-cypress with ‘--force-upload’ parameter, or contact BrowserStack Support.", VISIT_DASHBOARD: "Visit the Automate dashboard for real-time test reporting:", CONFLICTING_INIT_ARGUMENTS: "Conflicting arguments given. You can use --path only with a file name, and not with a file path.", @@ -34,6 +37,7 @@ const userMessages = { NO_NPM_DEPENDENCIES_READ_MORE: "Read more about npm dependencies here: https://www.browserstack.com/docs/automate/cypress/npm-packages. You can suppress this warning by using --disable-npm-warning flag.", VALIDATING_CONFIG: "Validating the config", UPLOADING_TESTS: "Uploading the tests to BrowserStack", + UPLOADING_NPM_PACKAGES: "Uploading npm packages to BrowserStack", LOCAL_TRUE: "you will now be able to test localhost / private URLs", LOCAL_FALSE: "you won't be able to test localhost / private URLs", EXIT_SYNC_CLI_MESSAGE: "Exiting the CLI, but your build is still running. You can use the --sync option to keep getting test updates. You can also use the build-info command now.", diff --git a/bin/helpers/fileHelpers.js b/bin/helpers/fileHelpers.js index dd8f0383..2e973f1c 100644 --- a/bin/helpers/fileHelpers.js +++ b/bin/helpers/fileHelpers.js @@ -35,6 +35,18 @@ exports.deleteZip = () => { } }; +exports.deletePackageArchieve = () => { + try { + fs.removeSync(config.packageFileName); + fs.removeSync(config.packageDirName); + logger.info(Constants.userMessages.NPM_DELETED); + return 0; + } catch (err) { + logger.info(Constants.userMessages.NPM_DELETE_FAILED); + return 1; + } +}; + exports.dirExists = function (filePath, cb) { let exists = false; if (fs.existsSync(path.dirname(filePath), cb)) { diff --git a/bin/helpers/packageInstaller.js b/bin/helpers/packageInstaller.js new file mode 100644 index 00000000..b3f0aa37 --- /dev/null +++ b/bin/helpers/packageInstaller.js @@ -0,0 +1,115 @@ +'use strict'; +const npm = require('global-npm'), + archiver = require("archiver"), + path = require('path'), + fs = require("fs-extra"), + fileHelpers = require("./fileHelpers"), + utils = require('./utils'); + +const setupPackageFolder = (runSettings, directoryPath) => { + return new Promise(function (resolve, reject) { + fileHelpers.deletePackageArchieve(); + fs.mkdir(directoryPath, (err) => { + if (err) { + return reject(err); + } + let packageJSON = {}; + if (typeof runSettings.package_config_options === 'object') { + Object.assign(packageJSON, runSettings.package_config_options); + } + + if (typeof runSettings.npm_dependencies === 'object') { + Object.assign(packageJSON, { + devDependencies: runSettings.npm_dependencies, + }); + } + + if (Object.keys(packageJSON).length > 0) { + let packageJSONString = JSON.stringify(packageJSON); + let packagePath = path.join(directoryPath, "package.json"); + fs.writeFileSync(packagePath, packageJSONString); + return resolve("package file created"); + } + return reject("Nothing in package file"); + }) + }) +}; + +const packageInstall = (packageDir) => { + return new Promise(function (resolve, reject) { + let savedPrefix = null; + let npmLoad = { loglevel: 'silent' }; + const installCallback = (err, result) => { + npm.prefix = savedPrefix; + if (err) { + return reject(err); + } + resolve(result); + }; + const loadCallback = (err) => { + if (err) { + return reject(err); + } + savedPrefix = npm.prefix; + npm.prefix = packageDir; + npm.commands.install(packageDir, [], installCallback); + }; + npm.load(npmLoad, loadCallback); + }); +}; + +const packageArchiver = (packageDir, packageFile) => { + return new Promise(function (resolve, reject) { + let output = fs.createWriteStream(packageFile); + let archive = archiver('tar', { + gzip: true + }); + archive.on('warning', function (err) { + if (err.code === 'ENOENT') { + logger.info(err); + } else { + reject(err); + } + }); + + output.on('close', function () { + resolve('Zipping completed'); + }); + + output.on('end', function () { + logger.info('Data has been drained'); + }); + + archive.on('error', function (err) { + reject(err); + }); + + archive.pipe(output); + archive.directory(packageDir, false); + archive.finalize(); + }) +} + +const packageWrappper = (bsConfig, packageDir, packageFile, md5data, args) => { + return new Promise(function (resolve) { + let obj = { + packageArchieveCreated: false + }; + if (md5data.packageUrlPresent || !utils.isTrueString(bsConfig.run_settings.local_npm_install)) { + return resolve(obj); + } + return setupPackageFolder(bsConfig.run_settings, packageDir).then((_result) => { + return packageInstall(packageDir); + }).then((_result) => { + return packageArchiver(packageDir, packageFile); + }).then((_result) => { + Object.assign(obj, { packageArchieveCreated: true }); + return resolve(obj); + }).catch((_error) => { + fileHelpers.deletePackageArchieve(); + return resolve(obj); + }) + }) +} + +exports.packageWrappper = packageWrappper; diff --git a/bin/helpers/utils.js b/bin/helpers/utils.js index 345e18ff..e2430cf8 100644 --- a/bin/helpers/utils.js +++ b/bin/helpers/utils.js @@ -12,6 +12,7 @@ const usageReporting = require("./usageReporting"), Constants = require("./constants"), chalk = require('chalk'), syncCliLogger = require("../helpers/logger").syncCliLogger, + fileHelpers = require("./fileHelpers"), config = require("../helpers/config"); const request = require('request'); @@ -331,6 +332,8 @@ exports.fixCommaSeparatedString = (string) => { exports.isUndefined = value => (value === undefined || value === null); +exports.isTrueString = value => (!this.isUndefined(value) && value.toString().toLowerCase() === 'true'); + exports.isFloat = (value) => Number(value) && Number(value) % 1 !== 0; exports.isParallelValid = (value) => { @@ -394,6 +397,80 @@ exports.isCypressProjDirValid = (cypressProjDir, integrationFoldDir) => { return parentTokens.every((t, i) => childTokens[i] === t); }; +exports.generateUploadParams = (bsConfig, filePath, md5data, fileDetails) => { + let options = { + url: config.uploadUrl, + auth: { + user: bsConfig.auth.username, + password: bsConfig.auth.access_key + }, + formData: { + file: fs.createReadStream(filePath), + filetype: fileDetails.filetype, + filename: fileDetails.filename, + zipMd5sum: md5data ? md5data : '', + }, + headers: { + "User-Agent": exports.getUserAgent(), + } + } + return options +} + +exports.sortJsonKeys = (unordered) => { + const ordered = Object.keys(unordered).sort().reduce( + (obj, key) => { + obj[key] = unordered[key]; + return obj; + }, + {} + ); + return ordered +} + +exports.generateUploadOptions = (type, md5data, packageData) => { + let options = {} + switch (type) { + case 'zip': + options = { + archivePresent: true, + md5ReturnKey: "zip_url", + urlPresent: md5data.zipUrlPresent, + md5Data: md5data.zip_md5sum, + url: md5data.zipUrl, + propogateError: true, + fileDetails: { + filetype: "zip", + filename: "tests" + }, + messages: { + uploading: Constants.userMessages.UPLOADING_TESTS + }, + cleanupMethod: fileHelpers.deleteZip, + } + break; + case 'npm': + options = { + archivePresent: packageData.packageArchieveCreated, + md5ReturnKey: "npm_package_url", + urlPresent: md5data.packageUrlPresent, + md5Data: md5data.npm_package_md5sum, + url: md5data.npmPackageUrl, + propogateError: false, + fileDetails: { + filetype: "tar.gz", + filename: "bstackPackages" + }, + messages: { + uploading: Constants.userMessages.UPLOADING_NPM_PACKAGES + }, + cleanupMethod: fileHelpers.deletePackageArchieve, + } + break; + } + return options +} + exports.getLocalFlag = (connectionSettings) => { return ( !this.isUndefined(connectionSettings) && diff --git a/bin/helpers/zipUpload.js b/bin/helpers/zipUpload.js index 1c604206..7a0158aa 100644 --- a/bin/helpers/zipUpload.js +++ b/bin/helpers/zipUpload.js @@ -1,35 +1,22 @@ 'use strict'; const config = require("./config"), request = require("request"), - fs = require("fs"), logger = require("./logger").winstonLogger, Constants = require("./constants"), - utils = require("./utils"), - fileHelpers = require("./fileHelpers"); + utils = require("./utils"); -const uploadCypressZip = (bsConfig, filePath, md5data) => { +const uploadSuits = (bsConfig, filePath, opts) => { return new Promise(function (resolve, reject) { - if (md5data.zipUrlPresent) { - return resolve({ zip_url: md5data.zipUrl }); + if (opts.urlPresent) { + return resolve({ [opts.md5ReturnKey]: opts.url }); } - logger.info(Constants.userMessages.UPLOADING_TESTS); - let options = { - url: config.uploadUrl, - auth: { - user: bsConfig.auth.username, - password: bsConfig.auth.access_key - }, - formData: { - file: fs.createReadStream(filePath), - filetype: 'zip', - filename: 'tests', - zipMd5sum: md5data.md5sum ? md5data.md5sum : '', - }, - headers: { - "User-Agent": utils.getUserAgent(), - } + if (!opts.archivePresent) { + return resolve({}); } + logger.info(opts.messages.uploading); + + let options = utils.generateUploadParams(bsConfig, filePath, opts.md5Data, opts.fileDetails) let responseData = null; request.post(options, function (err, resp, body) { if (err) { @@ -41,20 +28,28 @@ const uploadCypressZip = (bsConfig, filePath, md5data) => { responseData = null } if (resp.statusCode != 200) { + if (resp.statusCode == 401) { + if (responseData && responseData["error"]) { + return reject(responseData["error"]); + } else { + return reject(Constants.validationMessages.INVALID_DEFAULT_AUTH_PARAMS); + } + } + if (!opts.propogateError){ + return resolve({}); + } if(responseData && responseData["error"]){ reject(responseData["error"]); } else { - if(resp.statusCode == 401){ - reject(Constants.validationMessages.INVALID_DEFAULT_AUTH_PARAMS); - } else if (resp.statusCode == 413) { + if (resp.statusCode == 413) { reject(Constants.userMessages.ZIP_UPLOAD_LIMIT_EXCEEDED); } else { reject(Constants.userMessages.ZIP_UPLOADER_NOT_REACHABLE); } } } else { - logger.info(`Uploaded tests successfully (${responseData.zip_url})`); - fileHelpers.deleteZip(); + logger.info(`Uploaded tests successfully (${responseData[opts.md5ReturnKey]})`); + opts.cleanupMethod(); resolve(responseData); } } @@ -62,4 +57,21 @@ const uploadCypressZip = (bsConfig, filePath, md5data) => { }); } + +const uploadCypressZip = (bsConfig, md5data, packageData) => { + return new Promise(function (resolve, reject) { + let obj = {} + const zipOptions = utils.generateUploadOptions('zip', md5data, packageData); + const npmOptions = utils.generateUploadOptions('npm', md5data, packageData); + let zipUpload = uploadSuits(bsConfig, config.fileName, zipOptions); + let npmPackageUpload = uploadSuits(bsConfig, config.packageFileName, npmOptions); + Promise.all([zipUpload, npmPackageUpload]).then(function (uploads) { + uploads.forEach(upload => Object.assign(obj, upload)) + return resolve(obj); + }).catch((error) => { + return reject(error); + }) + }) +} + exports.zipUpload = uploadCypressZip diff --git a/package.json b/package.json index aed0c50a..e15b3903 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,8 @@ "table": "^5.4.6", "uuid": "^8.3.2", "winston": "^2.3.1", - "yargs": "^14.2.3" + "yargs": "^14.2.3", + "global-npm": "^0.4.1" }, "repository": { "type": "git", From 7eb40da441ea557b0cfcb6126d6cdef0b544209e Mon Sep 17 00:00:00 2001 From: Sparsh Agarwal Date: Wed, 22 Sep 2021 12:51:59 +0530 Subject: [PATCH 02/14] added CYPRESS_INSTALL_BINARY to control cypress package install --- bin/helpers/fileHelpers.js | 2 ++ bin/helpers/packageInstaller.js | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/bin/helpers/fileHelpers.js b/bin/helpers/fileHelpers.js index 2e973f1c..14e4bba0 100644 --- a/bin/helpers/fileHelpers.js +++ b/bin/helpers/fileHelpers.js @@ -4,6 +4,7 @@ const fs = require('fs-extra'), const logger = require('./logger').winstonLogger, Constants = require('../helpers/constants'), + process = require('process'), config = require('../helpers/config'); exports.write = function (f, message, args, cb) { @@ -37,6 +38,7 @@ exports.deleteZip = () => { exports.deletePackageArchieve = () => { try { + delete process.env.CYPRESS_INSTALL_BINARY; fs.removeSync(config.packageFileName); fs.removeSync(config.packageDirName); logger.info(Constants.userMessages.NPM_DELETED); diff --git a/bin/helpers/packageInstaller.js b/bin/helpers/packageInstaller.js index b3f0aa37..6297a501 100644 --- a/bin/helpers/packageInstaller.js +++ b/bin/helpers/packageInstaller.js @@ -2,8 +2,9 @@ const npm = require('global-npm'), archiver = require("archiver"), path = require('path'), - fs = require("fs-extra"), - fileHelpers = require("./fileHelpers"), + fs = require('fs-extra'), + fileHelpers = require('./fileHelpers'), + process = require('process'), utils = require('./utils'); const setupPackageFolder = (runSettings, directoryPath) => { @@ -99,6 +100,7 @@ const packageWrappper = (bsConfig, packageDir, packageFile, md5data, args) => { return resolve(obj); } return setupPackageFolder(bsConfig.run_settings, packageDir).then((_result) => { + process.env.CYPRESS_INSTALL_BINARY = 0 return packageInstall(packageDir); }).then((_result) => { return packageArchiver(packageDir, packageFile); From 4c300ef79b79f34038a8cf40f7f940a1eab4dfd5 Mon Sep 17 00:00:00 2001 From: Sparsh Agarwal Date: Tue, 5 Oct 2021 11:14:55 +0530 Subject: [PATCH 03/14] add npmrc --- bin/helpers/checkUploaded.js | 4 ++-- bin/helpers/packageInstaller.js | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/bin/helpers/checkUploaded.js b/bin/helpers/checkUploaded.js index a8445b9a..db5817e3 100644 --- a/bin/helpers/checkUploaded.js +++ b/bin/helpers/checkUploaded.js @@ -80,11 +80,11 @@ const checkUploadedMd5 = (bsConfig, args, instrumentBlocks) => { instrumentBlocks.markBlockEnd("checkAlreadyUploaded.md5Total"); let data = {}; if (!args["force-upload"]) { - Object.assign(data, { zip_md5sum:"sad" }); + Object.assign(data, { zip_md5sum }); Object.assign(obj, { zip_md5sum }); } if (utils.isTrueString(bsConfig.run_settings.local_npm_install)) { - Object.assign(data, { npm_package_md5sum:"as" }); + Object.assign(data, { npm_package_md5sum }); Object.assign(obj, { npm_package_md5sum }); } diff --git a/bin/helpers/packageInstaller.js b/bin/helpers/packageInstaller.js index 6297a501..19910bd7 100644 --- a/bin/helpers/packageInstaller.js +++ b/bin/helpers/packageInstaller.js @@ -29,6 +29,12 @@ const setupPackageFolder = (runSettings, directoryPath) => { let packageJSONString = JSON.stringify(packageJSON); let packagePath = path.join(directoryPath, "package.json"); fs.writeFileSync(packagePath, packageJSONString); + let cypressFolderPath = path.dirname(runSettings.cypressConfigFilePath); + let sourceNpmrc = path.join(cypressFolderPath, ".npmrc"); + let destNpmrc = path.join(directoryPath, ".npmrc"); + if (fs.existsSync(sourceNpmrc)) { + fs.copyFileSync(sourceNpmrc, destNpmrc); + } return resolve("package file created"); } return reject("Nothing in package file"); From b4c9e81b0549ee97268ad494dc82d53841fc4dc0 Mon Sep 17 00:00:00 2001 From: Sparsh Agarwal Date: Tue, 5 Oct 2021 20:43:37 +0530 Subject: [PATCH 04/14] add npmrc to md5 check --- bin/commands/runs.js | 3 ++- bin/helpers/checkUploaded.js | 8 ++++++++ bin/helpers/constants.js | 10 ++++++++++ bin/helpers/packageInstaller.js | 11 +++++++++-- 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/bin/commands/runs.js b/bin/commands/runs.js index 045da792..4a8e9acb 100644 --- a/bin/commands/runs.js +++ b/bin/commands/runs.js @@ -99,7 +99,7 @@ module.exports = function run(args) { markBlockEnd('checkAlreadyUploaded'); markBlockStart('packageInstaller'); - return packageInstaller.packageWrappper(bsConfig, config.packageDirName, config.packageFileName, md5data, args).then(function (packageData) { + return packageInstaller.packageWrappper(bsConfig, config.packageDirName, config.packageFileName, md5data, {markBlockStart, markBlockEnd}).then(function (packageData) { markBlockEnd('packageInstaller'); // Archive the spec files @@ -174,6 +174,7 @@ module.exports = function run(args) { if(!args.sync) logger.info(Constants.userMessages.EXIT_SYNC_CLI_MESSAGE.replace("",data.build_id)); let dataToSend = { time_components: getTimeComponents(), + unique_id: utils.generateUniqueHash(), build_id: data.build_id, }; if (bsConfig && bsConfig.connection_settings) { diff --git a/bin/helpers/checkUploaded.js b/bin/helpers/checkUploaded.js index db5817e3..a238fff6 100644 --- a/bin/helpers/checkUploaded.js +++ b/bin/helpers/checkUploaded.js @@ -58,6 +58,12 @@ const checkPackageMd5 = (runSettings) => { let packageJSONString = JSON.stringify(packageJSON); outputHash.update(packageJSONString); } + let cypressFolderPath = path.dirname(runSettings.cypressConfigFilePath); + let sourceNpmrc = path.join(cypressFolderPath, ".npmrc"); + if (fs.existsSync(sourceNpmrc)) { + const npmrc = fs.readFileSync(sourceNpmrc, {encoding:'utf8', flag:'r'}); + outputHash.update(npmrc); + } return outputHash.digest(Constants.hashingOptions.encoding) }; @@ -78,6 +84,7 @@ const checkUploadedMd5 = (bsConfig, args, instrumentBlocks) => { let npm_package_md5sum = checkPackageMd5(bsConfig.run_settings); instrumentBlocks.markBlockEnd("checkAlreadyUploaded.md5Package"); instrumentBlocks.markBlockEnd("checkAlreadyUploaded.md5Total"); + console.log(npm_package_md5sum) let data = {}; if (!args["force-upload"]) { Object.assign(data, { zip_md5sum }); @@ -126,6 +133,7 @@ const checkUploadedMd5 = (bsConfig, args, instrumentBlocks) => { } }); }).catch((_error) => { + console.log(_error) resolve({zipUrlPresent: false, packageUrlPresent: false}); }); }); diff --git a/bin/helpers/constants.js b/bin/helpers/constants.js index 698f0405..a7900530 100644 --- a/bin/helpers/constants.js +++ b/bin/helpers/constants.js @@ -179,6 +179,15 @@ const hashingOptions = { encoding: 'hex', }; +const packageInstallerOptions = { + npmLoad: { + loglevel: 'silent', + only: 'dev', + 'save-dev': true, + 'only-dev': true, + } +} + const specFileTypes = ['js', 'ts', 'feature', 'jsx', 'coffee', 'cjsx']; const DEFAULT_CYPRESS_SPEC_PATH = "cypress/integration" @@ -202,6 +211,7 @@ module.exports = Object.freeze({ filesToIgnoreWhileUploading, readDirOptions, hashingOptions, + packageInstallerOptions, specFileTypes, DEFAULT_CYPRESS_SPEC_PATH, SPEC_TOTAL_CHAR_LIMIT, diff --git a/bin/helpers/packageInstaller.js b/bin/helpers/packageInstaller.js index 19910bd7..8a549288 100644 --- a/bin/helpers/packageInstaller.js +++ b/bin/helpers/packageInstaller.js @@ -4,6 +4,7 @@ const npm = require('global-npm'), path = require('path'), fs = require('fs-extra'), fileHelpers = require('./fileHelpers'), + Constants = require('./constants'), process = require('process'), utils = require('./utils'); @@ -45,7 +46,7 @@ const setupPackageFolder = (runSettings, directoryPath) => { const packageInstall = (packageDir) => { return new Promise(function (resolve, reject) { let savedPrefix = null; - let npmLoad = { loglevel: 'silent' }; + let npmLoad = Constants.packageInstallerOptions.npmLoad const installCallback = (err, result) => { npm.prefix = savedPrefix; if (err) { @@ -97,7 +98,7 @@ const packageArchiver = (packageDir, packageFile) => { }) } -const packageWrappper = (bsConfig, packageDir, packageFile, md5data, args) => { +const packageWrappper = (bsConfig, packageDir, packageFile, md5data, instrumentBlocks) => { return new Promise(function (resolve) { let obj = { packageArchieveCreated: false @@ -105,12 +106,18 @@ const packageWrappper = (bsConfig, packageDir, packageFile, md5data, args) => { if (md5data.packageUrlPresent || !utils.isTrueString(bsConfig.run_settings.local_npm_install)) { return resolve(obj); } + instrumentBlocks.markBlockStart("packageInstaller.folderSetup"); return setupPackageFolder(bsConfig.run_settings, packageDir).then((_result) => { process.env.CYPRESS_INSTALL_BINARY = 0 + instrumentBlocks.markBlockEnd("packageInstaller.folderSetup"); + instrumentBlocks.markBlockStart("packageInstaller.packageInstall"); return packageInstall(packageDir); }).then((_result) => { + instrumentBlocks.markBlockEnd("packageInstaller.packageInstall"); + instrumentBlocks.markBlockStart("packageInstaller.packageArchive"); return packageArchiver(packageDir, packageFile); }).then((_result) => { + instrumentBlocks.markBlockEnd("packageInstaller.packageArchive"); Object.assign(obj, { packageArchieveCreated: true }); return resolve(obj); }).catch((_error) => { From cbb9fb30ba8d9b12cf5fb9f99509e41cc6e9725d Mon Sep 17 00:00:00 2001 From: Sparsh Agarwal Date: Tue, 5 Oct 2021 21:20:01 +0530 Subject: [PATCH 05/14] remove debug logs --- bin/helpers/checkUploaded.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/bin/helpers/checkUploaded.js b/bin/helpers/checkUploaded.js index a238fff6..14fb312b 100644 --- a/bin/helpers/checkUploaded.js +++ b/bin/helpers/checkUploaded.js @@ -84,7 +84,6 @@ const checkUploadedMd5 = (bsConfig, args, instrumentBlocks) => { let npm_package_md5sum = checkPackageMd5(bsConfig.run_settings); instrumentBlocks.markBlockEnd("checkAlreadyUploaded.md5Package"); instrumentBlocks.markBlockEnd("checkAlreadyUploaded.md5Total"); - console.log(npm_package_md5sum) let data = {}; if (!args["force-upload"]) { Object.assign(data, { zip_md5sum }); @@ -133,7 +132,6 @@ const checkUploadedMd5 = (bsConfig, args, instrumentBlocks) => { } }); }).catch((_error) => { - console.log(_error) resolve({zipUrlPresent: false, packageUrlPresent: false}); }); }); From 3de6e8006810e6e07fbc62a46082516d93ecd637 Mon Sep 17 00:00:00 2001 From: Sparsh Agarwal Date: Wed, 6 Oct 2021 10:47:48 +0530 Subject: [PATCH 06/14] log error to UsageReport --- bin/commands/runs.js | 2 ++ bin/helpers/checkUploaded.js | 4 ++-- bin/helpers/packageInstaller.js | 4 ++-- bin/helpers/utils.js | 6 ++++++ 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/bin/commands/runs.js b/bin/commands/runs.js index 4a8e9acb..ba54e771 100644 --- a/bin/commands/runs.js +++ b/bin/commands/runs.js @@ -175,6 +175,8 @@ module.exports = function run(args) { let dataToSend = { time_components: getTimeComponents(), unique_id: utils.generateUniqueHash(), + package_error: utils.checkError(packageData), + checkmd5_error: utils.checkError(md5data), build_id: data.build_id, }; if (bsConfig && bsConfig.connection_settings) { diff --git a/bin/helpers/checkUploaded.js b/bin/helpers/checkUploaded.js index 14fb312b..8466ee76 100644 --- a/bin/helpers/checkUploaded.js +++ b/bin/helpers/checkUploaded.js @@ -131,8 +131,8 @@ const checkUploadedMd5 = (bsConfig, args, instrumentBlocks) => { resolve(obj); } }); - }).catch((_error) => { - resolve({zipUrlPresent: false, packageUrlPresent: false}); + }).catch((err) => { + resolve({zipUrlPresent: false, packageUrlPresent: false, error: err.stack.substring(0,100)}); }); }); }; diff --git a/bin/helpers/packageInstaller.js b/bin/helpers/packageInstaller.js index 8a549288..696de870 100644 --- a/bin/helpers/packageInstaller.js +++ b/bin/helpers/packageInstaller.js @@ -120,8 +120,8 @@ const packageWrappper = (bsConfig, packageDir, packageFile, md5data, instrumentB instrumentBlocks.markBlockEnd("packageInstaller.packageArchive"); Object.assign(obj, { packageArchieveCreated: true }); return resolve(obj); - }).catch((_error) => { - fileHelpers.deletePackageArchieve(); + }).catch((err) => { + obj.error = err.stack.substring(0,100) return resolve(obj); }) }) diff --git a/bin/helpers/utils.js b/bin/helpers/utils.js index 2716da02..1937fe30 100644 --- a/bin/helpers/utils.js +++ b/bin/helpers/utils.js @@ -822,6 +822,12 @@ exports.latestSyntaxToActualVersionMessage = (latestSyntaxVersion, actualVersion return message } +exports.checkError = (data) => { + if (!this.isUndefined(data.error)) { + return data.error + } +} + exports.isJSONInvalid = (err, args) => { let invalid = true From 60e403bef630729e9719e58f29dfa36ae744618b Mon Sep 17 00:00:00 2001 From: Sparsh Agarwal Date: Wed, 6 Oct 2021 17:22:42 +0530 Subject: [PATCH 07/14] skip test md5 calculation --- bin/helpers/checkUploaded.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/bin/helpers/checkUploaded.js b/bin/helpers/checkUploaded.js index 8466ee76..a0457a85 100644 --- a/bin/helpers/checkUploaded.js +++ b/bin/helpers/checkUploaded.js @@ -10,10 +10,13 @@ const crypto = require('crypto'), utils = require('./utils'); -const checkSpecsMd5 = (runSettings, excludeFiles, instrumentBlocks) => { +const checkSpecsMd5 = (runSettings, args, instrumentBlocks) => { return new Promise(function (resolve, reject) { + if (args["force-upload"]) { + return resolve("force-upload"); + } let cypressFolderPath = path.dirname(runSettings.cypressConfigFilePath); - let ignoreFiles = utils.getFilesToIgnore(runSettings, excludeFiles, false); + let ignoreFiles = utils.getFilesToIgnore(runSettings, args.exclude, false); let options = { cwd: cypressFolderPath, ignore: ignoreFiles, @@ -79,7 +82,7 @@ const checkUploadedMd5 = (bsConfig, args, instrumentBlocks) => { } instrumentBlocks.markBlockStart("checkAlreadyUploaded.md5Total"); - checkSpecsMd5(bsConfig.run_settings, args.exclude, instrumentBlocks).then(function (zip_md5sum) { + checkSpecsMd5(bsConfig.run_settings, args, instrumentBlocks).then(function (zip_md5sum) { instrumentBlocks.markBlockStart("checkAlreadyUploaded.md5Package"); let npm_package_md5sum = checkPackageMd5(bsConfig.run_settings); instrumentBlocks.markBlockEnd("checkAlreadyUploaded.md5Package"); From a2afcca91f48d1944f4ab69a97499f74e8dda90a Mon Sep 17 00:00:00 2001 From: Sparsh Agarwal Date: Wed, 6 Oct 2021 18:18:49 +0530 Subject: [PATCH 08/14] use npm 6.14.15 and error handling --- bin/helpers/packageInstaller.js | 54 ++++++++++++++++++--------------- package.json | 2 +- 2 files changed, 30 insertions(+), 26 deletions(-) diff --git a/bin/helpers/packageInstaller.js b/bin/helpers/packageInstaller.js index 696de870..640c6e80 100644 --- a/bin/helpers/packageInstaller.js +++ b/bin/helpers/packageInstaller.js @@ -1,5 +1,5 @@ 'use strict'; -const npm = require('global-npm'), +const npm = require('npm'), archiver = require("archiver"), path = require('path'), fs = require('fs-extra'), @@ -11,34 +11,38 @@ const npm = require('global-npm'), const setupPackageFolder = (runSettings, directoryPath) => { return new Promise(function (resolve, reject) { fileHelpers.deletePackageArchieve(); - fs.mkdir(directoryPath, (err) => { - if (err) { - return reject(err); - } - let packageJSON = {}; - if (typeof runSettings.package_config_options === 'object') { - Object.assign(packageJSON, runSettings.package_config_options); - } + fs.mkdir(directoryPath, function (err) { + try { + if (err) { + return reject(err); + } + let packageJSON = {}; + if (typeof runSettings.package_config_options === 'object') { + Object.assign(packageJSON, runSettings.package_config_options); + } - if (typeof runSettings.npm_dependencies === 'object') { - Object.assign(packageJSON, { - devDependencies: runSettings.npm_dependencies, - }); - } + if (typeof runSettings.npm_dependencies === 'object') { + Object.assign(packageJSON, { + devDependencies: runSettings.npm_dependencies, + }); + } - if (Object.keys(packageJSON).length > 0) { - let packageJSONString = JSON.stringify(packageJSON); - let packagePath = path.join(directoryPath, "package.json"); - fs.writeFileSync(packagePath, packageJSONString); - let cypressFolderPath = path.dirname(runSettings.cypressConfigFilePath); - let sourceNpmrc = path.join(cypressFolderPath, ".npmrc"); - let destNpmrc = path.join(directoryPath, ".npmrc"); - if (fs.existsSync(sourceNpmrc)) { - fs.copyFileSync(sourceNpmrc, destNpmrc); + if (Object.keys(packageJSON).length > 0) { + let packageJSONString = JSON.stringify(packageJSON); + let packagePath = path.join(directoryPath, "package.json"); + fs.writeFileSync(packagePath, packageJSONString); + let cypressFolderPath = path.dirname(runSettings.cypressConfigFilePath); + let sourceNpmrc = path.join(cypressFolderPath, ".npmrc"); + let destNpmrc = path.join(directoryPath, ".npmrc"); + if (fs.existsSync(sourceNpmrc)) { + fs.copyFileSync(sourceNpmrc, destNpmrc); + } + return resolve("package file created"); } - return resolve("package file created"); + return reject("Nothing in package file"); + } catch(error) { + return reject(error); } - return reject("Nothing in package file"); }) }) }; diff --git a/package.json b/package.json index dc83d27e..d82f2337 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "uuid": "^8.3.2", "winston": "^2.3.1", "yargs": "^14.2.3", - "global-npm": "^0.4.1", + "npm": "^6.14.15", "axios": "^0.21.1", "unzipper": "^0.10.11" }, From e05069c917e783e05a90e0509056b3fefb33ab3a Mon Sep 17 00:00:00 2001 From: Sparsh Agarwal Date: Thu, 7 Oct 2021 16:56:10 +0530 Subject: [PATCH 09/14] change flag name --- bin/helpers/capabilityHelper.js | 1 + bin/helpers/checkUploaded.js | 4 ++-- bin/helpers/packageInstaller.js | 2 +- bin/helpers/utils.js | 5 +++++ 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/bin/helpers/capabilityHelper.js b/bin/helpers/capabilityHelper.js index 78a8275e..5ecde658 100644 --- a/bin/helpers/capabilityHelper.js +++ b/bin/helpers/capabilityHelper.js @@ -45,6 +45,7 @@ const caps = (bsConfig, zip) => { if (zip.npm_package_url && zip.npm_package_url.split("://")[1].length !== 0) { obj.npm_package_suite = zip.npm_package_url.split("://")[1]; } + obj.cache_dependencies = bsConfig.run_settings.cache_dependencies; // Inferred settings if(bsConfig.connection_settings){ diff --git a/bin/helpers/checkUploaded.js b/bin/helpers/checkUploaded.js index a0457a85..ca32e161 100644 --- a/bin/helpers/checkUploaded.js +++ b/bin/helpers/checkUploaded.js @@ -77,7 +77,7 @@ const checkUploadedMd5 = (bsConfig, args, instrumentBlocks) => { zipUrlPresent: false, packageUrlPresent: false, }; - if (args["force-upload"] && !utils.isTrueString(bsConfig.run_settings.local_npm_install)) { + if (args["force-upload"] && !utils.isTrueString(bsConfig.run_settings.cache_dependencies)) { return resolve(obj); } @@ -92,7 +92,7 @@ const checkUploadedMd5 = (bsConfig, args, instrumentBlocks) => { Object.assign(data, { zip_md5sum }); Object.assign(obj, { zip_md5sum }); } - if (utils.isTrueString(bsConfig.run_settings.local_npm_install)) { + if (utils.isTrueString(bsConfig.run_settings.cache_dependencies)) { Object.assign(data, { npm_package_md5sum }); Object.assign(obj, { npm_package_md5sum }); } diff --git a/bin/helpers/packageInstaller.js b/bin/helpers/packageInstaller.js index 640c6e80..ad8f1b35 100644 --- a/bin/helpers/packageInstaller.js +++ b/bin/helpers/packageInstaller.js @@ -107,7 +107,7 @@ const packageWrappper = (bsConfig, packageDir, packageFile, md5data, instrumentB let obj = { packageArchieveCreated: false }; - if (md5data.packageUrlPresent || !utils.isTrueString(bsConfig.run_settings.local_npm_install)) { + if (md5data.packageUrlPresent || !utils.isTrueString(bsConfig.run_settings.cache_dependencies)) { return resolve(obj); } instrumentBlocks.markBlockStart("packageInstaller.folderSetup"); diff --git a/bin/helpers/utils.js b/bin/helpers/utils.js index 1937fe30..35bfe541 100644 --- a/bin/helpers/utils.js +++ b/bin/helpers/utils.js @@ -188,6 +188,11 @@ exports.setDefaults = (bsConfig, args) => { bsConfig.connection_settings = {}; } + // setting cache_dependencies to true if not present + if (this.isUndefined(bsConfig.run_settings.cache_dependencies)) { + bsConfig.run_settings.cache_dependencies = true; + } + } exports.setUsername = (bsConfig, args) => { From 9463861e9e354cb9e9234517c17e1d58ebe33611 Mon Sep 17 00:00:00 2001 From: Sparsh Agarwal Date: Thu, 7 Oct 2021 20:54:05 +0530 Subject: [PATCH 10/14] npm install cache and messaging --- bin/helpers/constants.js | 2 +- bin/helpers/fileHelpers.js | 6 +++--- bin/helpers/packageInstaller.js | 6 +++++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/bin/helpers/constants.js b/bin/helpers/constants.js index a7900530..36b6a220 100644 --- a/bin/helpers/constants.js +++ b/bin/helpers/constants.js @@ -38,7 +38,7 @@ const userMessages = { NO_NPM_DEPENDENCIES_READ_MORE: "Read more about npm dependencies here: https://www.browserstack.com/docs/automate/cypress/npm-packages. You can suppress this warning by using --disable-npm-warning flag.", VALIDATING_CONFIG: "Validating the config", UPLOADING_TESTS: "Uploading the tests to BrowserStack", - UPLOADING_NPM_PACKAGES: "Uploading npm packages to BrowserStack", + UPLOADING_NPM_PACKAGES: "Uploading required node_modules to BrowserStack", LOCAL_TRUE: "you will now be able to test localhost / private URLs", LOCAL_FALSE: "you won't be able to test localhost / private URLs", EXIT_SYNC_CLI_MESSAGE: "Exiting the CLI, but your build is still running. You can use the --sync option to keep getting test updates. You can also use the build-info command now.", diff --git a/bin/helpers/fileHelpers.js b/bin/helpers/fileHelpers.js index 14e4bba0..743ab85c 100644 --- a/bin/helpers/fileHelpers.js +++ b/bin/helpers/fileHelpers.js @@ -36,15 +36,15 @@ exports.deleteZip = () => { } }; -exports.deletePackageArchieve = () => { +exports.deletePackageArchieve = (logging = true) => { try { delete process.env.CYPRESS_INSTALL_BINARY; fs.removeSync(config.packageFileName); fs.removeSync(config.packageDirName); - logger.info(Constants.userMessages.NPM_DELETED); + if (logging) logger.info(Constants.userMessages.NPM_DELETED); return 0; } catch (err) { - logger.info(Constants.userMessages.NPM_DELETE_FAILED); + if (logging) logger.info(Constants.userMessages.NPM_DELETE_FAILED); return 1; } }; diff --git a/bin/helpers/packageInstaller.js b/bin/helpers/packageInstaller.js index ad8f1b35..d189f6de 100644 --- a/bin/helpers/packageInstaller.js +++ b/bin/helpers/packageInstaller.js @@ -2,15 +2,17 @@ const npm = require('npm'), archiver = require("archiver"), path = require('path'), + os = require('os'), fs = require('fs-extra'), fileHelpers = require('./fileHelpers'), + logger = require("./logger").winstonLogger, Constants = require('./constants'), process = require('process'), utils = require('./utils'); const setupPackageFolder = (runSettings, directoryPath) => { return new Promise(function (resolve, reject) { - fileHelpers.deletePackageArchieve(); + fileHelpers.deletePackageArchieve(false); fs.mkdir(directoryPath, function (err) { try { if (err) { @@ -51,6 +53,7 @@ const packageInstall = (packageDir) => { return new Promise(function (resolve, reject) { let savedPrefix = null; let npmLoad = Constants.packageInstallerOptions.npmLoad + npmLoad["cache"] = fs.mkdtempSync(`${os.tmpdir()}${path.sep}`); const installCallback = (err, result) => { npm.prefix = savedPrefix; if (err) { @@ -110,6 +113,7 @@ const packageWrappper = (bsConfig, packageDir, packageFile, md5data, instrumentB if (md5data.packageUrlPresent || !utils.isTrueString(bsConfig.run_settings.cache_dependencies)) { return resolve(obj); } + logger.info(`Installing required dependencies and building the package to upload to BrowserStack`); instrumentBlocks.markBlockStart("packageInstaller.folderSetup"); return setupPackageFolder(bsConfig.run_settings, packageDir).then((_result) => { process.env.CYPRESS_INSTALL_BINARY = 0 From 8006beb5535f03acb92696b3559c22eeec2bd63e Mon Sep 17 00:00:00 2001 From: Sparsh Agarwal Date: Tue, 12 Oct 2021 21:28:20 +0530 Subject: [PATCH 11/14] disable cache flag and cleanup --- bin/commands/runs.js | 17 ++++++++++++++++- bin/helpers/checkUploaded.js | 8 ++++++++ bin/helpers/constants.js | 4 ++++ bin/helpers/packageInstaller.js | 6 +++--- bin/helpers/utils.js | 6 ++++-- bin/helpers/zipUpload.js | 2 +- 6 files changed, 36 insertions(+), 7 deletions(-) diff --git a/bin/commands/runs.js b/bin/commands/runs.js index ba54e771..248dc644 100644 --- a/bin/commands/runs.js +++ b/bin/commands/runs.js @@ -99,7 +99,7 @@ module.exports = function run(args) { markBlockEnd('checkAlreadyUploaded'); markBlockStart('packageInstaller'); - return packageInstaller.packageWrappper(bsConfig, config.packageDirName, config.packageFileName, md5data, {markBlockStart, markBlockEnd}).then(function (packageData) { + return packageInstaller.packageWrapper(bsConfig, config.packageDirName, config.packageFileName, md5data, {markBlockStart, markBlockEnd}).then(function (packageData) { markBlockEnd('packageInstaller'); // Archive the spec files @@ -206,6 +206,11 @@ module.exports = function run(args) { logger.error(Constants.userMessages.ZIP_UPLOAD_FAILED); fileHelpers.deleteZip(); utils.sendUsageReport(bsConfig, args, `${err}\n${Constants.userMessages.ZIP_UPLOAD_FAILED}`, Constants.messageTypes.ERROR, 'zip_upload_failed'); + try { + fileHelpers.deletePackageArchieve(); + } catch (err) { + utils.sendUsageReport(bsConfig, args, Constants.userMessages.NPM_DELETE_FAILED, Constants.messageTypes.ERROR, 'npm_deletion_failed'); + } } }); }).catch(function (err) { @@ -218,12 +223,22 @@ module.exports = function run(args) { } catch (err) { utils.sendUsageReport(bsConfig, args, Constants.userMessages.ZIP_DELETE_FAILED, Constants.messageTypes.ERROR, 'zip_deletion_failed'); } + try { + fileHelpers.deletePackageArchieve(); + } catch (err) { + utils.sendUsageReport(bsConfig, args, Constants.userMessages.NPM_DELETE_FAILED, Constants.messageTypes.ERROR, 'npm_deletion_failed'); + } }); }).catch(function (err) { // package installer failed logger.error(err); logger.error(Constants.userMessages.FAILED_CREATE_NPM_ARCHIVE); utils.sendUsageReport(bsConfig, args, Constants.userMessages.FAILED_CREATE_NPM_ARCHIVE, Constants.messageTypes.ERROR, 'npm_package_archive_failed'); + try { + fileHelpers.deletePackageArchieve(); + } catch (err) { + utils.sendUsageReport(bsConfig, args, Constants.userMessages.NPM_DELETE_FAILED, Constants.messageTypes.ERROR, 'npm_deletion_failed'); + } }); }).catch(function (err) { // md5 check failed diff --git a/bin/helpers/checkUploaded.js b/bin/helpers/checkUploaded.js index ca32e161..32d83f19 100644 --- a/bin/helpers/checkUploaded.js +++ b/bin/helpers/checkUploaded.js @@ -130,6 +130,14 @@ const checkUploadedMd5 = (bsConfig, args, instrumentBlocks) => { Object.assign(obj, zipData, {packageUrlPresent: true}); } } + if (utils.isTrueString(zipData.disableNpmSuiteCache)) { + bsConfig.run_settings.cache_dependencies = false; + Object.assign(obj, {packageUrlPresent: false}); + } + if (utils.isTrueString(zipData.disableTestSuiteCache)) { + args["force-upload"] = true; + Object.assign(obj, {zipUrlPresent: false}); + } instrumentBlocks.markBlockEnd("checkAlreadyUploaded.railsCheck"); resolve(obj); } diff --git a/bin/helpers/constants.js b/bin/helpers/constants.js index 36b6a220..c5b41ad9 100644 --- a/bin/helpers/constants.js +++ b/bin/helpers/constants.js @@ -38,7 +38,9 @@ const userMessages = { NO_NPM_DEPENDENCIES_READ_MORE: "Read more about npm dependencies here: https://www.browserstack.com/docs/automate/cypress/npm-packages. You can suppress this warning by using --disable-npm-warning flag.", VALIDATING_CONFIG: "Validating the config", UPLOADING_TESTS: "Uploading the tests to BrowserStack", + UPLOADING_TESTS_SUCCESS: "Uploaded tests successfully", UPLOADING_NPM_PACKAGES: "Uploading required node_modules to BrowserStack", + UPLOADING_NPM_PACKAGES_SUCCESS: "Uploaded node_modules successfully", LOCAL_TRUE: "you will now be able to test localhost / private URLs", LOCAL_FALSE: "you won't be able to test localhost / private URLs", EXIT_SYNC_CLI_MESSAGE: "Exiting the CLI, but your build is still running. You can use the --sync option to keep getting test updates. You can also use the build-info command now.", @@ -160,6 +162,8 @@ const filesToIgnoreWhileUploading = [ '.idea/**', '.vscode/**', '.npm/**', + 'bstackPackages.tar.gz', + 'tmpBstackPackages/**', '.yarn/**', 'build_artifacts/**' ]; diff --git a/bin/helpers/packageInstaller.js b/bin/helpers/packageInstaller.js index d189f6de..d9746237 100644 --- a/bin/helpers/packageInstaller.js +++ b/bin/helpers/packageInstaller.js @@ -105,7 +105,7 @@ const packageArchiver = (packageDir, packageFile) => { }) } -const packageWrappper = (bsConfig, packageDir, packageFile, md5data, instrumentBlocks) => { +const packageWrapper = (bsConfig, packageDir, packageFile, md5data, instrumentBlocks) => { return new Promise(function (resolve) { let obj = { packageArchieveCreated: false @@ -129,10 +129,10 @@ const packageWrappper = (bsConfig, packageDir, packageFile, md5data, instrumentB Object.assign(obj, { packageArchieveCreated: true }); return resolve(obj); }).catch((err) => { - obj.error = err.stack.substring(0,100) + obj.error = err.stack.substring(0,100); return resolve(obj); }) }) } -exports.packageWrappper = packageWrappper; +exports.packageWrapper = packageWrapper; diff --git a/bin/helpers/utils.js b/bin/helpers/utils.js index 35bfe541..a8b3dc33 100644 --- a/bin/helpers/utils.js +++ b/bin/helpers/utils.js @@ -459,7 +459,8 @@ exports.generateUploadOptions = (type, md5data, packageData) => { filename: "tests" }, messages: { - uploading: Constants.userMessages.UPLOADING_TESTS + uploading: Constants.userMessages.UPLOADING_TESTS, + uploadingSuccess: Constants.userMessages.UPLOADING_TESTS_SUCCESS }, cleanupMethod: fileHelpers.deleteZip, } @@ -477,7 +478,8 @@ exports.generateUploadOptions = (type, md5data, packageData) => { filename: "bstackPackages" }, messages: { - uploading: Constants.userMessages.UPLOADING_NPM_PACKAGES + uploading: Constants.userMessages.UPLOADING_NPM_PACKAGES, + uploadingSuccess: Constants.userMessages.UPLOADING_NPM_PACKAGES_SUCCESS }, cleanupMethod: fileHelpers.deletePackageArchieve, } diff --git a/bin/helpers/zipUpload.js b/bin/helpers/zipUpload.js index 7a0158aa..19241fda 100644 --- a/bin/helpers/zipUpload.js +++ b/bin/helpers/zipUpload.js @@ -48,7 +48,7 @@ const uploadSuits = (bsConfig, filePath, opts) => { } } } else { - logger.info(`Uploaded tests successfully (${responseData[opts.md5ReturnKey]})`); + logger.info(`${opts.messages.uploadingSuccess} (${responseData[opts.md5ReturnKey]})`); opts.cleanupMethod(); resolve(responseData); } From 2d180d5f0e4d62efb95d1d1cccf334da9605fb17 Mon Sep 17 00:00:00 2001 From: Sparsh Agarwal Date: Wed, 13 Oct 2021 12:25:30 +0530 Subject: [PATCH 12/14] improve messaging --- bin/helpers/constants.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/helpers/constants.js b/bin/helpers/constants.js index c5b41ad9..06a48a6e 100644 --- a/bin/helpers/constants.js +++ b/bin/helpers/constants.js @@ -25,11 +25,11 @@ const userMessages = { MD5_CHECK_FAILED: "There was some issue while checking if zip is already uploaded.", ZIP_DELETE_FAILED: "Could not delete tests.zip successfully.", ZIP_DELETED: "Deleted tests.zip successfully.", - NPM_DELETE_FAILED: "Could not delete browserstack-cli npm packages successfully.", - NPM_DELETED: "Deleted browserstack-cli npm packages successfully.", + NPM_DELETE_FAILED: "Could not delete the dependency packages.", + NPM_DELETED: "Deleted dependency packages successfully.", API_DEPRECATED: "This version of API is deprecated, please use latest version of API.", FAILED_TO_ZIP: "Failed to zip files.", - FAILED_CREATE_NPM_ARCHIVE: "Something went wrong while crreating npm archieve.", + FAILED_CREATE_NPM_ARCHIVE: "CLI execution failed due to some issue in npm setup. Please retry.", FAILED_MD5_CHECK: "Something went wrong - you can retry running browserstack-cypress with ‘--force-upload’ parameter, or contact BrowserStack Support.", VISIT_DASHBOARD: "Visit the Automate dashboard for real-time test reporting:", CONFLICTING_INIT_ARGUMENTS: "Conflicting arguments given. You can use --path only with a file name, and not with a file path.", From c50065e0c6a7e13e5a2a2dec5c67921675faf351 Mon Sep 17 00:00:00 2001 From: Sparsh Agarwal Date: Thu, 28 Oct 2021 20:34:12 +0530 Subject: [PATCH 13/14] test coverage for npm install --- bin/helpers/checkUploaded.js | 2 + bin/helpers/utils.js | 6 +- bin/helpers/zipUpload.js | 2 +- test/unit/bin/commands/runs.js | 37 +- test/unit/bin/helpers/capabilityHelper.js | 8 + test/unit/bin/helpers/checkUploaded.js | 311 +++++++++++--- test/unit/bin/helpers/packageInstaller.js | 478 ++++++++++++++++++++++ test/unit/bin/helpers/utils.js | 121 ++++++ test/unit/bin/helpers/zipUpload.js | 474 ++++++++++++--------- 9 files changed, 1202 insertions(+), 237 deletions(-) create mode 100644 test/unit/bin/helpers/packageInstaller.js diff --git a/bin/helpers/checkUploaded.js b/bin/helpers/checkUploaded.js index 32d83f19..7ff3f68c 100644 --- a/bin/helpers/checkUploaded.js +++ b/bin/helpers/checkUploaded.js @@ -133,10 +133,12 @@ const checkUploadedMd5 = (bsConfig, args, instrumentBlocks) => { if (utils.isTrueString(zipData.disableNpmSuiteCache)) { bsConfig.run_settings.cache_dependencies = false; Object.assign(obj, {packageUrlPresent: false}); + delete obj.npm_package_md5sum; } if (utils.isTrueString(zipData.disableTestSuiteCache)) { args["force-upload"] = true; Object.assign(obj, {zipUrlPresent: false}); + delete obj.zip_md5sum; } instrumentBlocks.markBlockEnd("checkAlreadyUploaded.railsCheck"); resolve(obj); diff --git a/bin/helpers/utils.js b/bin/helpers/utils.js index a8b3dc33..1644a210 100644 --- a/bin/helpers/utils.js +++ b/bin/helpers/utils.js @@ -444,7 +444,7 @@ exports.sortJsonKeys = (unordered) => { } exports.generateUploadOptions = (type, md5data, packageData) => { - let options = {} + let options = {}; switch (type) { case 'zip': options = { @@ -485,8 +485,8 @@ exports.generateUploadOptions = (type, md5data, packageData) => { } break; } - return options -} + return options; +}; exports.getLocalFlag = (connectionSettings) => { return ( diff --git a/bin/helpers/zipUpload.js b/bin/helpers/zipUpload.js index 19241fda..7ae26da4 100644 --- a/bin/helpers/zipUpload.js +++ b/bin/helpers/zipUpload.js @@ -25,7 +25,7 @@ const uploadSuits = (bsConfig, filePath, opts) => { try { responseData = JSON.parse(body); } catch (e) { - responseData = null + responseData = {}; } if (resp.statusCode != 200) { if (resp.statusCode == 401) { diff --git a/test/unit/bin/commands/runs.js b/test/unit/bin/commands/runs.js index ffca3fef..bb463271 100644 --- a/test/unit/bin/commands/runs.js +++ b/test/unit/bin/commands/runs.js @@ -216,12 +216,14 @@ describe("runs", () => { validateBstackJsonStub = sandbox.stub(); setUsageReportingFlagStub = sandbox.stub().returns(undefined); checkUploadedStub = sandbox.stub(); + packageInstallerStub = sandbox.stub(); sendUsageReportStub = sandbox.stub().callsFake(function () { return "end"; }); capabilityValidatorStub = sandbox.stub(); archiverStub = sandbox.stub(); deleteZipStub = sandbox.stub(); + deletePackageArchieveStub = sandbox.stub(); setLocalStub = sandbox.stub(); setLocalModeStub = sandbox.stub(); setupLocalTestingStub = sandbox.stub(); @@ -284,16 +286,21 @@ describe("runs", () => { }, '../helpers/fileHelpers': { deleteZip: deleteZipStub, + deletePackageArchieve: deletePackageArchieveStub }, '../helpers/checkUploaded': { checkUploadedMd5: checkUploadedStub, }, + '../helpers/packageInstaller': { + packageWrapper: packageInstallerStub, + }, }); validateBstackJsonStub.returns(Promise.resolve(bsConfig)); setupLocalTestingStub.returns(Promise.resolve("nothing")); capabilityValidatorStub.returns(Promise.resolve(Constants.validationMessages.VALIDATED)); checkUploadedStub.returns(Promise.resolve({ zipUrlPresent: false })); + packageInstallerStub.returns(Promise.resolve({ packageArchieveCreated: false })); archiverStub.returns(Promise.reject("random-error")); return runs(args) @@ -355,6 +362,7 @@ describe("runs", () => { getConfigPathStub = sandbox.stub(); setUsageReportingFlagStub = sandbox.stub().returns(undefined); checkUploadedStub = sandbox.stub(); + packageInstallerStub = sandbox.stub(); sendUsageReportStub = sandbox.stub().callsFake(function () { return "end"; }); @@ -362,6 +370,7 @@ describe("runs", () => { archiverStub = sandbox.stub(); zipUploadStub = sandbox.stub(); deleteZipStub = sandbox.stub(); + deletePackageArchieveStub = sandbox.stub(); setLocalStub = sandbox.stub(); setLocalModeStub = sandbox.stub(); setupLocalTestingStub = sandbox.stub(); @@ -424,6 +433,7 @@ describe("runs", () => { }, '../helpers/fileHelpers': { deleteZip: deleteZipStub, + deletePackageArchieve: deletePackageArchieveStub }, '../helpers/zipUpload': { zipUpload: zipUploadStub, @@ -431,12 +441,16 @@ describe("runs", () => { '../helpers/checkUploaded': { checkUploadedMd5: checkUploadedStub, }, + '../helpers/packageInstaller': { + packageWrapper: packageInstallerStub, + }, }); validateBstackJsonStub.returns(Promise.resolve(bsConfig)); capabilityValidatorStub.returns(Promise.resolve(Constants.validationMessages.VALIDATED)); setupLocalTestingStub.returns(Promise.resolve("nothing")); - checkUploadedStub.returns(Promise.resolve({ zipUrlPresent: false })) + checkUploadedStub.returns(Promise.resolve({ zipUrlPresent: false })); + packageInstallerStub.returns(Promise.resolve({ packageArchieveCreated: false })); archiverStub.returns(Promise.resolve("Zipping completed")); zipUploadStub.returns(Promise.reject("random-error")); @@ -498,6 +512,7 @@ describe("runs", () => { getConfigPathStub = sandbox.stub(); setUsageReportingFlagStub = sandbox.stub().returns(undefined); checkUploadedStub = sandbox.stub(); + packageInstallerStub = sandbox.stub(); sendUsageReportStub = sandbox.stub().callsFake(function () { return "end"; }); @@ -506,6 +521,7 @@ describe("runs", () => { zipUploadStub = sandbox.stub(); createBuildStub = sandbox.stub(); deleteZipStub = sandbox.stub(); + deletePackageArchieveStub = sandbox.stub(); setLocalStub = sandbox.stub(); setLocalModeStub = sandbox.stub(); setupLocalTestingStub = sandbox.stub(); @@ -570,6 +586,7 @@ describe("runs", () => { }, '../helpers/fileHelpers': { deleteZip: deleteZipStub, + deletePackageArchieve: deletePackageArchieveStub }, '../helpers/zipUpload': { zipUpload: zipUploadStub, @@ -580,6 +597,9 @@ describe("runs", () => { '../helpers/checkUploaded': { checkUploadedMd5: checkUploadedStub, }, + '../helpers/packageInstaller': { + packageWrapper: packageInstallerStub, + }, }); validateBstackJsonStub.returns(Promise.resolve(bsConfig)); @@ -589,6 +609,7 @@ describe("runs", () => { ); archiverStub.returns(Promise.resolve("Zipping completed")); checkUploadedStub.returns(Promise.resolve({ zipUrlPresent: false })); + packageInstallerStub.returns(Promise.resolve({ packageArchieveCreated: false })); zipUploadStub.returns(Promise.resolve("zip uploaded")); stopLocalBinaryStub.returns(Promise.resolve("nothing")); createBuildStub.returns(Promise.reject("random-error")); @@ -652,9 +673,11 @@ describe("runs", () => { setUserSpecsStub = sandbox.stub(); setTestEnvsStub = sandbox.stub(); setSystemEnvsStub = sandbox.stub(); + checkErrorStub = sandbox.stub(); getConfigPathStub = sandbox.stub(); setUsageReportingFlagStub = sandbox.stub().returns(undefined); checkUploadedStub = sandbox.stub(); + packageInstallerStub = sandbox.stub(); sendUsageReportStub = sandbox.stub().callsFake(function () { return "end"; }); @@ -664,6 +687,7 @@ describe("runs", () => { zipUploadStub = sandbox.stub(); createBuildStub = sandbox.stub(); deleteZipStub = sandbox.stub(); + deletePackageArchieveStub = sandbox.stub(); exportResultsStub = sandbox.stub(); deleteResultsStub = sandbox.stub(); setDefaultsStub = sandbox.stub(); @@ -698,7 +722,7 @@ describe("runs", () => { let errorCode = null; let message = `Success! ${Constants.userMessages.BUILD_CREATED} with build id: random_build_id`; let dashboardLink = `${Constants.userMessages.VISIT_DASHBOARD} ${dashboardUrl}`; - let data = {time_components: {}, unique_id: 'random_hash', build_id: 'random_build_id'} + let data = {time_components: {}, unique_id: 'random_hash', package_error: 'test', checkmd5_error: 'test', build_id: 'random_build_id'} const runs = proxyquire('../../../../bin/commands/runs', { '../helpers/utils': { @@ -733,6 +757,7 @@ describe("runs", () => { setConfig: setConfigStub, stopLocalBinary: stopLocalBinaryStub, nonEmptyArray: nonEmptyArrayStub, + checkError: checkErrorStub }, '../helpers/capabilityHelper': { validate: capabilityValidatorStub, @@ -742,6 +767,7 @@ describe("runs", () => { }, '../helpers/fileHelpers': { deleteZip: deleteZipStub, + deletePackageArchieve: deletePackageArchieveStub }, '../helpers/zipUpload': { zipUpload: zipUploadStub, @@ -755,6 +781,9 @@ describe("runs", () => { '../helpers/checkUploaded': { checkUploadedMd5: checkUploadedStub, }, + '../helpers/packageInstaller': { + packageWrapper: packageInstallerStub, + }, '../helpers/timeComponents': { initTimeComponents: initTimeComponentsStub, instrumentEventTime: instrumentEventTimeStub, @@ -770,10 +799,12 @@ describe("runs", () => { Promise.resolve(Constants.validationMessages.VALIDATED) ); archiverStub.returns(Promise.resolve("Zipping completed")); - checkUploadedStub.returns(Promise.resolve({ zipUrlPresent: false })) + checkUploadedStub.returns(Promise.resolve({ zipUrlPresent: false })); + packageInstallerStub.returns(Promise.resolve({ packageArchieveCreated: false })); zipUploadStub.returns(Promise.resolve("zip uploaded")); stopLocalBinaryStub.returns(Promise.resolve("nothing")); nonEmptyArrayStub.returns(false); + checkErrorStub.returns('test'); createBuildStub.returns(Promise.resolve({ message: 'Success', build_id: 'random_build_id', dashboard_url: dashboardUrl })); return runs(args) diff --git a/test/unit/bin/helpers/capabilityHelper.js b/test/unit/bin/helpers/capabilityHelper.js index b640fa5b..c7cdd3aa 100644 --- a/test/unit/bin/helpers/capabilityHelper.js +++ b/test/unit/bin/helpers/capabilityHelper.js @@ -149,6 +149,8 @@ describe("capabilityHelper.js", () => { connection_settings: { local: false, }, + run_settings: { + } }; return capabilityHelper .caps(bsConfig, { zip_url: zip_url }) @@ -178,6 +180,8 @@ describe("capabilityHelper.js", () => { local: true, local_identifier: "abc" }, + run_settings: { + } }; return capabilityHelper .caps(bsConfig, { zip_url: zip_url }) @@ -208,6 +212,8 @@ describe("capabilityHelper.js", () => { connection_settings: { local: true, }, + run_settings: { + } }; return capabilityHelper .caps(bsConfig, { zip_url: zip_url }) @@ -235,6 +241,8 @@ describe("capabilityHelper.js", () => { versions: ["78", "77"], }, ], + run_settings: { + } }; return capabilityHelper .caps(bsConfig, { zip_url: zip_url }) diff --git a/test/unit/bin/helpers/checkUploaded.js b/test/unit/bin/helpers/checkUploaded.js index 891f5c74..f683b7dc 100644 --- a/test/unit/bin/helpers/checkUploaded.js +++ b/test/unit/bin/helpers/checkUploaded.js @@ -27,9 +27,14 @@ describe("checkUploaded", () => { }); context("checkUploadedMd5", () => { - let checkSpecsMd5Stub; + let checkSpecsMd5Stub, checkPackageMd5Stub, instrumentBlocks; beforeEach(() => { checkSpecsMd5Stub = sandbox.stub().returns(Promise.resolve("random_md5sum")); + checkPackageMd5Stub = sandbox.stub().returns("random_md5sum"); + instrumentBlocks = { + markBlockStart: sinon.stub(), + markBlockEnd: sinon.stub() + } }); it("resolves with zipUrlPresent false due to request error", () => { @@ -43,18 +48,64 @@ describe("checkUploaded", () => { checkSpecsMd5: checkSpecsMd5Stub }); let checkUploadedMd5rewire = checkUploaded.__get__('checkUploadedMd5'); - let instrumentBlocks = { - markBlockStart: sinon.stub(), - markBlockEnd: sinon.stub() - } return checkUploadedMd5rewire(bsConfig, {}, instrumentBlocks) - .then(function (data) { - chai.assert.equal(data.md5sum, 'random_md5sum'); + .then((data) => { + chai.assert.equal(data.zip_md5sum, 'random_md5sum'); chai.assert.equal(data.zipUrlPresent, false); + chai.assert.equal(data.packageUrlPresent, false); sinon.assert.calledOnce(requestStub); sinon.assert.calledOnce(checkSpecsMd5Stub); }) - .catch((error) => { + .catch((_error) => { + chai.assert.fail("Promise error"); + }); + }); + + it("resolves with zipUrlPresent false and packageUrlPresent false due to checkSpecsMd5 error", () => { + let requestStub = sandbox + .stub(request, "post") + .yields(new Error("random error"), null, null); + let checkSpecsMd5ErrorStub = sandbox.stub().returns(Promise.reject({message: "test error", stack: "test error stack"})); + + const checkUploaded = rewire("../../../../bin/helpers/checkUploaded"); + checkUploaded.__set__({ + request: { post: requestStub }, + checkSpecsMd5: checkSpecsMd5ErrorStub + }); + let checkUploadedMd5rewire = checkUploaded.__get__('checkUploadedMd5'); + return checkUploadedMd5rewire(bsConfig, {}, instrumentBlocks) + .then((data) => { + chai.assert.equal(data.zipUrlPresent, false); + chai.assert.equal(data.packageUrlPresent, false); + chai.assert.equal(data.error, "test error stack"); + sinon.assert.notCalled(requestStub); + sinon.assert.calledOnce(checkSpecsMd5ErrorStub); + }) + .catch((_error) => { + chai.assert.fail("Promise error"); + }); + }); + + it("resolves with zipUrlPresent false and packageUrlPresent false due to parsing error", () => { + let requestStub = sandbox + .stub(request, "post") + .yields(null, { statusCode: 200 }, '{"zipUrl":"bs://random_hashid}'); + + const checkUploaded = rewire("../../../../bin/helpers/checkUploaded"); + checkUploaded.__set__({ + request: { post: requestStub }, + checkSpecsMd5: checkSpecsMd5Stub + }); + let checkUploadedMd5rewire = checkUploaded.__get__('checkUploadedMd5'); + return checkUploadedMd5rewire(bsConfig, {}, instrumentBlocks) + .then((data) => { + chai.assert.equal(data.zipUrlPresent, false); + chai.assert.equal(data.packageUrlPresent, false); + chai.assert.equal(data.zip_md5sum, "random_md5sum"); + sinon.assert.calledOnce(requestStub); + sinon.assert.calledOnce(checkSpecsMd5Stub); + }) + .catch((_error) => { chai.assert.fail("Promise error"); }); }); @@ -70,17 +121,37 @@ describe("checkUploaded", () => { checkSpecsMd5: checkSpecsMd5Stub }); let checkUploadedMd5rewire = checkUploaded.__get__('checkUploadedMd5'); - let instrumentBlocks = { - markBlockStart: sinon.stub(), - markBlockEnd: sinon.stub() - } return checkUploadedMd5rewire(bsConfig, {}, instrumentBlocks) - .then(function (data) { - chai.assert.deepEqual(data, { md5sum: 'random_md5sum', zipUrlPresent: true, zipUrl: 'bs://random_hashid' }) + .then((data) => { + chai.assert.deepEqual(data, { zip_md5sum: 'random_md5sum', zipUrlPresent: true, packageUrlPresent: false, zipUrl: 'bs://random_hashid' }) sinon.assert.calledOnce(requestStub); sinon.assert.calledOnce(checkSpecsMd5Stub); }) - .catch((error) => { + .catch((_error) => { + chai.assert.fail("Promise error"); + }); + }); + + it("resolves with zipUrlPresent true, packageUrlPresent true, zip url, and packge url", () => { + let requestStub = sandbox + .stub(request, "post") + .yields(null, { statusCode: 200 }, '{"zipUrl":"bs://random_hashid", "npmPackageUrl":"bs://random_hashid2"}'); + + const checkUploaded = rewire("../../../../bin/helpers/checkUploaded"); + checkUploaded.__set__({ + request: { post: requestStub }, + checkSpecsMd5: checkSpecsMd5Stub, + checkPackageMd5: checkPackageMd5Stub + }); + let checkUploadedMd5rewire = checkUploaded.__get__('checkUploadedMd5'); + bsConfig.run_settings.cache_dependencies = true + return checkUploadedMd5rewire(bsConfig, {}, instrumentBlocks) + .then((data) => { + chai.assert.deepEqual(data, { zip_md5sum: 'random_md5sum', npm_package_md5sum: 'random_md5sum', zipUrlPresent: true, packageUrlPresent: true, zipUrl: 'bs://random_hashid', npmPackageUrl: 'bs://random_hashid2' }) + sinon.assert.calledOnce(requestStub); + sinon.assert.calledOnce(checkSpecsMd5Stub); + }) + .catch((_error) => { chai.assert.fail("Promise error"); }); }); @@ -93,25 +164,23 @@ describe("checkUploaded", () => { const checkUploaded = rewire("../../../../bin/helpers/checkUploaded"); checkUploaded.__set__({ request: { post: requestStub }, - checkSpecsMd5: checkSpecsMd5Stub + checkSpecsMd5: checkSpecsMd5Stub, + checkPackageMd5: checkPackageMd5Stub }); let checkUploadedMd5rewire = checkUploaded.__get__('checkUploadedMd5'); - let instrumentBlocks = { - markBlockStart: sinon.stub(), - markBlockEnd: sinon.stub() - } + bsConfig.run_settings.cache_dependencies = false return checkUploadedMd5rewire(bsConfig, {}, instrumentBlocks) - .then(function (data) { - chai.assert.deepEqual(data, { md5sum: 'random_md5sum', zipUrlPresent: false }) + .then((data) => { + chai.assert.deepEqual(data, { zip_md5sum: 'random_md5sum', zipUrlPresent: false, packageUrlPresent: false, }) sinon.assert.calledOnce(requestStub); sinon.assert.calledOnce(checkSpecsMd5Stub); }) - .catch((error) => { + .catch((_error) => { chai.assert.fail("Promise error"); }); }); - it("resolves with zipUrlPresent false if force-upload enabled", () => { + it("resolves with zipUrlPresent and packageUrlPresent false if force-upload enabled and cache_dependencies disabled", () => { let requestStub = sandbox .stub(request, "post") .yields(null, { statusCode: 404 }, '{"message":"zip_url for md5sum random_md5sum not found."}'); @@ -119,25 +188,75 @@ describe("checkUploaded", () => { const checkUploaded = rewire("../../../../bin/helpers/checkUploaded"); checkUploaded.__set__({ request: { post: requestStub }, - checkSpecsMd5: checkSpecsMd5Stub + checkSpecsMd5: checkSpecsMd5Stub, + checkPackageMd5: checkPackageMd5Stub }); let checkUploadedMd5rewire = checkUploaded.__get__('checkUploadedMd5'); - - return checkUploadedMd5rewire(bsConfig, {"force-upload": true}) - .then(function (data) { - chai.assert.deepEqual(data, { zipUrlPresent: false }) + bsConfig.run_settings.cache_dependencies = false + return checkUploadedMd5rewire(bsConfig, {"force-upload": true}, instrumentBlocks) + .then((data) => { + chai.assert.deepEqual(data, { zipUrlPresent: false, packageUrlPresent: false }) sinon.assert.notCalled(requestStub); sinon.assert.notCalled(checkSpecsMd5Stub); }) - .catch((error) => { + .catch((_error) => { + chai.assert.fail("Promise error"); + }); + }); + + it("resolves with zipUrlPresent false and packageUrlPresent true if force-upload enabled and cache_dependencies enabled", () => { + let requestStub = sandbox + .stub(request, "post") + .yields(null, { statusCode: 200 }, '{"npmPackageUrl":"bs://random_hashid2"}'); + + const checkUploaded = rewire("../../../../bin/helpers/checkUploaded"); + checkUploaded.__set__({ + request: { post: requestStub }, + checkSpecsMd5: checkSpecsMd5Stub, + checkPackageMd5: checkPackageMd5Stub + }); + let checkUploadedMd5rewire = checkUploaded.__get__('checkUploadedMd5'); + bsConfig.run_settings.cache_dependencies = true + return checkUploadedMd5rewire(bsConfig, {"force-upload": true}, instrumentBlocks) + .then((data) => { + chai.assert.deepEqual(data, { zipUrlPresent: false, packageUrlPresent: true, npm_package_md5sum: 'random_md5sum', npmPackageUrl: 'bs://random_hashid2' }) + sinon.assert.calledOnce(requestStub); + sinon.assert.calledOnce(checkSpecsMd5Stub); + }) + .catch((_error) => { + chai.assert.fail("Promise error"); + }); + }); + + it("resolves with zipUrlPresent false and packageUrlPresent false if diabled from rails", () => { + let requestStub = sandbox + .stub(request, "post") + .yields(null, { statusCode: 200 }, '{"disableNpmSuiteCache": true, "disableTestSuiteCache": true }'); + + const checkUploaded = rewire("../../../../bin/helpers/checkUploaded"); + checkUploaded.__set__({ + request: { post: requestStub }, + checkSpecsMd5: checkSpecsMd5Stub, + checkPackageMd5: checkPackageMd5Stub + }); + let checkUploadedMd5rewire = checkUploaded.__get__('checkUploadedMd5'); + bsConfig.run_settings.cache_dependencies = true + return checkUploadedMd5rewire(bsConfig, {}, instrumentBlocks) + .then((data) => { + chai.assert.deepEqual(data, { zipUrlPresent: false, packageUrlPresent: false }) + sinon.assert.calledOnce(requestStub); + sinon.assert.calledOnce(checkSpecsMd5Stub); + }) + .catch((_error) => { chai.assert.fail("Promise error"); }); }); }); context("checkSpecsMd5", () => { - let cryptoStub, digestStub, updateStub, pathStub, fsStub; + let cryptoStub, checkPackageMd5Stub, digestStub, updateStub, pathStub, fsStub; beforeEach(() => { + checkPackageMd5Stub = sandbox.stub().returns("random_md5sum") digestStub = sandbox.stub().returns("random_md5sum"); updateStub = sandbox.stub().returns(null); pathStub = { @@ -156,53 +275,151 @@ describe("checkUploaded", () => { }; }); - it("resolves with md5 value without adding config_file and package.json", () => { + it("resolves early due to force upload", () => { let hashElementstub = sandbox.stub().returns(Promise.resolve("random_md5sum")); const checkUploaded = rewire("../../../../bin/helpers/checkUploaded"); checkUploaded.__set__({ hashHelper: { hashWrapper: hashElementstub }, crypto: cryptoStub, - path: pathStub + path: pathStub, + checkPackageMd5: checkPackageMd5Stub }); let checkSpecsMd5Rewire = checkUploaded.__get__('checkSpecsMd5'); + let args = { + exclude: "random_files", + "force-upload": true + } + return checkSpecsMd5Rewire(bsConfig.run_settings, args) + .then((data) => { + chai.assert.equal(data, 'force-upload') + }) + .catch((_error) => { + chai.assert.fail("Promise error"); + }); + }); + + it("reject due to error in hashing", () => { + let hashElementErrorstub = sandbox.stub().returns(Promise.reject({message: "test error", stack: "test error stack"})); + const checkUploaded = rewire("../../../../bin/helpers/checkUploaded"); + checkUploaded.__set__({ + hashHelper: { hashWrapper: hashElementErrorstub }, + crypto: cryptoStub, + path: pathStub, + checkPackageMd5: checkPackageMd5Stub + }); + let checkSpecsMd5Rewire = checkUploaded.__get__('checkSpecsMd5'); + let args = { + exclude: "random_files", + } + return checkSpecsMd5Rewire(bsConfig.run_settings, args) + .then((_data) => { + chai.assert.fail("Promise error"); + }) + .catch((error) => { + chai.assert.equal(error.message, 'test error') + }); + }); - return checkSpecsMd5Rewire(bsConfig.run_settings, "random_files") - .then(function (data) { + it("resolves with md5 value", () => { + let hashElementstub = sandbox.stub().returns(Promise.resolve("random_md5sum")); + const checkUploaded = rewire("../../../../bin/helpers/checkUploaded"); + checkUploaded.__set__({ + hashHelper: { hashWrapper: hashElementstub }, + crypto: cryptoStub, + path: pathStub, + checkPackageMd5: checkPackageMd5Stub, + fs: fsStub + }); + let checkSpecsMd5Rewire = checkUploaded.__get__('checkSpecsMd5'); + let args = { + exclude: "random_files" + } + return checkSpecsMd5Rewire(bsConfig.run_settings, args) + .then((data) => { chai.assert.equal(data, 'random_md5sum') sinon.assert.calledOnce(hashElementstub); - sinon.assert.calledTwice(digestStub); + sinon.assert.calledOnce(digestStub); sinon.assert.calledTwice(updateStub); }) - .catch((error) => { + .catch((_error) => { chai.assert.fail("Promise error"); }); }); - it("resolves with md5 value adding config_file and package.json", () => { + it("resolves with md5 value including config file", () => { let hashElementstub = sandbox.stub().returns(Promise.resolve("random_md5sum")); const checkUploaded = rewire("../../../../bin/helpers/checkUploaded"); checkUploaded.__set__({ hashHelper: { hashWrapper: hashElementstub }, crypto: cryptoStub, path: pathStub, + checkPackageMd5: checkPackageMd5Stub, fs: fsStub }); let checkSpecsMd5Rewire = checkUploaded.__get__('checkSpecsMd5'); - let run_settings = { - package_config_options: {random: "value"}, - cypress_config_file: "random/path" + let args = { + exclude: "random_files" } - - return checkSpecsMd5Rewire(run_settings, "random_files") - .then(function (data) { + bsConfig.run_settings.cypress_config_file = "random/path" + return checkSpecsMd5Rewire(bsConfig.run_settings, args) + .then((data) => { chai.assert.equal(data, 'random_md5sum') sinon.assert.calledOnce(hashElementstub); - sinon.assert.called(digestStub); - sinon.assert.callCount(updateStub, 4); + sinon.assert.calledOnce(digestStub); + sinon.assert.calledThrice(updateStub); }) - .catch((error) => { + .catch((_error) => { chai.assert.fail("Promise error"); }); }); }); + + context("checkPackageMd5", () => { + let cryptoStub, checkPackageMd5Stub, digestStub, updateStub, pathStub, fsStub, utilStub; + beforeEach(() => { + checkPackageMd5Stub = sandbox.stub().returns("random_md5sum") + digestStub = sandbox.stub().returns("random_md5sum"); + updateStub = sandbox.stub().returns(null); + utilStub = { + sortJsonKeys : sandbox.stub().returns('{}') + } + pathStub = { + dirname: sandbox.stub().returns(null), + join: sandbox.stub().returns(null) + }; + fsStub = { + readFileSync: sandbox.stub().returns('{}'), + existsSync: sandbox.stub().returns(true) + } + cryptoStub = { + createHash: () => { + return { + update: updateStub, + digest: digestStub + } + } + }; + }); + + it("resolves early due to force upload", () => { + const checkUploaded = rewire("../../../../bin/helpers/checkUploaded"); + checkUploaded.__set__({ + crypto: cryptoStub, + path: pathStub, + fs: fsStub, + utils: utilStub + }); + let checkPackageMd5Rewire = checkUploaded.__get__('checkPackageMd5'); + let run_settings = { + package_config_options: { + "name": "test" + }, + npm_dependencies: { + "random-package-1": "1.2.3", + "random-package-2": "1.2.4" + } + }; + return chai.assert.equal(checkPackageMd5Rewire(run_settings), 'random_md5sum'); + }); + }); }); diff --git a/test/unit/bin/helpers/packageInstaller.js b/test/unit/bin/helpers/packageInstaller.js new file mode 100644 index 00000000..087eb817 --- /dev/null +++ b/test/unit/bin/helpers/packageInstaller.js @@ -0,0 +1,478 @@ +'use strict'; +const chai = require("chai"), + chaiAsPromised = require("chai-as-promised"), + sinon = require("sinon"), + fs = require('fs-extra'), + path = require('path'), + npm = require('npm'); + +const logger = require("../../../../bin/helpers/logger").winstonLogger, +fileHelpers = require("../../../../bin/helpers/fileHelpers"); + +const rewire = require("rewire"); + +chai.use(chaiAsPromised); +logger.transports["console.info"].silent = true; + + +describe("packageInstaller", () => { + let sandbox; + + beforeEach(() => { + sandbox = sinon.createSandbox(); + }); + + afterEach(() => { + sandbox.restore(); + sinon.restore(); + }); + + context("setupPackageFolder", () => { + let fileHelpersStub, fsmkdirStub, fsmkdirErrorStub, fswriteFileSyncStub, fsexistsSyncStub, fscopyFileSyncStub, pathdirnameStub, pathjoinStub, pathJoinErrorStub; + const packageInstaller = rewire("../../../../bin/helpers/packageInstaller"); + beforeEach(() => { + fileHelpersStub = sandbox.stub(fileHelpers, "deletePackageArchieve").returns(null); + fsmkdirStub = sandbox.stub(fs, "mkdir").yields(null); + fswriteFileSyncStub = sandbox.stub(fs, "writeFileSync").returns(null); + fsexistsSyncStub = sandbox.stub(fs, "existsSync").returns(true); + fscopyFileSyncStub = sandbox.stub(fs, "copyFileSync").returns(null); + pathdirnameStub = sandbox.stub(path, "dirname").returns(null); + pathjoinStub = sandbox.stub(path, "join").returns(null); + }); + + it("should reject if nothing in package.json", () => { + packageInstaller.__set__({ + fileHelpers: {deletePackageArchieve: fileHelpersStub}, + fs: {mkdir: fsmkdirStub} + }); + let setupPackageFolderrewire = packageInstaller.__get__('setupPackageFolder'); + let runSettings = {}; + let directoryPath = "/random/path"; + return setupPackageFolderrewire(runSettings, directoryPath) + .then((_data) => { + chai.assert.fail("Promise error"); + }) + .catch((error) => { + sinon.assert.calledOnce(fsmkdirStub); + sinon.assert.calledOnce(fileHelpersStub); + chai.assert.equal(error, "Nothing in package file"); + }); + }); + + it("should reject if error in any step", () => { + pathjoinStub.restore(); + let error = new Error("test error"); + pathJoinErrorStub = sandbox.stub(path, "join").throws(error); + packageInstaller.__set__({ + fileHelpers: {deletePackageArchieve: fileHelpersStub}, + fs: {mkdir: fsmkdirStub}, + path: {join: pathJoinErrorStub} + }); + let setupPackageFolderrewire = packageInstaller.__get__('setupPackageFolder'); + let runSettings = { + package_config_options: { + "name": "test" + }, + npm_dependencies: { + "random-package-1": "1.2.3", + "random-package-2": "1.2.4" + } + }; + let directoryPath = "/random/path"; + return setupPackageFolderrewire(runSettings, directoryPath) + .then((_data) => { + chai.assert.fail("Promise error"); + }) + .catch((error) => { + chai.assert.equal(error.message, "test error"); + }); + }); + + it("should reject if directory creation fails", () => { + fsmkdirStub.restore(); + fsmkdirErrorStub = sandbox.stub(fs, "mkdir").yields("test error"); + packageInstaller.__set__({ + fileHelpers: {deletePackageArchieve: fileHelpersStub}, + fs: {mkdir: fsmkdirErrorStub} + }); + let setupPackageFolderrewire = packageInstaller.__get__('setupPackageFolder'); + let runSettings = {}; + let directoryPath = "/random/path"; + return setupPackageFolderrewire(runSettings, directoryPath) + .then((_data) => { + chai.assert.fail("Promise error"); + }) + .catch((error) => { + sinon.assert.calledOnce(fileHelpersStub); + chai.assert.equal(error, "test error"); + }); + }); + + it("should create folder with required files if npmrc exists", () => { + packageInstaller.__set__({ + fileHelpers: {deletePackageArchieve: fileHelpersStub}, + fs: { + mkdir: fsmkdirStub, + writeFileSync: fswriteFileSyncStub, + existsSync: fsexistsSyncStub, + copyFileSync: fscopyFileSyncStub + }, + path: { + dirname: pathdirnameStub, + join: pathjoinStub + } + }); + let setupPackageFolderrewire = packageInstaller.__get__('setupPackageFolder'); + let runSettings = { + package_config_options: { + "name": "test" + }, + npm_dependencies: { + "random-package-1": "1.2.3", + "random-package-2": "1.2.4" + } + }; + let packageCreated = JSON.stringify({ + "name": "test", + "devDependencies": { + "random-package-1": "1.2.3", + "random-package-2": "1.2.4" + } + }) + let directoryPath = "/random/path"; + return setupPackageFolderrewire(runSettings, directoryPath) + .then((data) => { + sinon.assert.calledOnce(fsmkdirStub); + sinon.assert.calledOnce(fileHelpersStub); + sinon.assert.calledOnce(fswriteFileSyncStub); + sinon.assert.calledOnce(fsexistsSyncStub); + sinon.assert.calledOnce(fscopyFileSyncStub); + sinon.assert.calledOnce(pathdirnameStub); + sinon.assert.calledThrice(pathjoinStub); + sinon.assert.calledWith(fswriteFileSyncStub, null, packageCreated); + chai.assert.equal(data, "package file created"); + }) + .catch((_error) => { + console.log(_error) + chai.assert.fail("Promise error"); + }); + }); + + it("should create folder with required files if npmrc doesn't exists", () => { + fsexistsSyncStub.restore(); + let fsexistsSyncFAlseStub = sandbox.stub(fs, "existsSync").returns(false); + packageInstaller.__set__({ + fileHelpers: {deletePackageArchieve: fileHelpersStub}, + fs: { + mkdir: fsmkdirStub, + writeFileSync: fswriteFileSyncStub, + existsSync: fsexistsSyncFAlseStub, + copyFileSync: fscopyFileSyncStub + }, + path: { + dirname: pathdirnameStub, + join: pathjoinStub + } + }); + let setupPackageFolderrewire = packageInstaller.__get__('setupPackageFolder'); + let runSettings = { + package_config_options: { + "name": "test" + }, + npm_dependencies: { + "random-package-1": "1.2.3", + "random-package-2": "1.2.4" + } + }; + let packageCreated = JSON.stringify({ + "name": "test", + "devDependencies": { + "random-package-1": "1.2.3", + "random-package-2": "1.2.4" + } + }) + let directoryPath = "/random/path"; + return setupPackageFolderrewire(runSettings, directoryPath) + .then((data) => { + sinon.assert.calledOnce(fsmkdirStub); + sinon.assert.calledOnce(fileHelpersStub); + sinon.assert.calledOnce(fswriteFileSyncStub); + sinon.assert.calledOnce(fsexistsSyncFAlseStub); + sinon.assert.notCalled(fscopyFileSyncStub); + sinon.assert.calledOnce(pathdirnameStub); + sinon.assert.calledThrice(pathjoinStub); + sinon.assert.calledWith(fswriteFileSyncStub, null, packageCreated); + chai.assert.equal(data, "package file created"); + }) + .catch((_error) => { + console.log(_error) + chai.assert.fail("Promise error"); + }); + }); + }); + + context("packageInstall", () => { + let npmInstallStub; + const packageInstaller = rewire("../../../../bin/helpers/packageInstaller"); + beforeEach(() => { + npmInstallStub = sandbox.stub(npm.commands, "install").returns(null); + }); + + it("should reject if error in npm load", () => { + packageInstaller.__set__({ + npm: { + commands: { + install: npmInstallStub + }, + load: (_npmLoad, loadCallback) => { + loadCallback("test error"); + } + }, + }); + let packageInstallrewire = packageInstaller.__get__('packageInstall'); + let directoryPath = "/random/path"; + return packageInstallrewire(directoryPath) + .then((_data) => { + chai.assert.fail("Promise error"); + }) + .catch((error) => { + chai.assert.equal(error, "test error") + }); + }); + + it("should call npm install on directory", () => { + packageInstaller.__set__({ + npm: { + commands: { + install: (_packageDir, [], installCallback) => { + installCallback(null, "npm install done"); + } + }, + load: (_npmLoad, loadCallback) => { + loadCallback(null); + } + }, + }); + let packageInstallrewire = packageInstaller.__get__('packageInstall'); + let directoryPath = "/random/path"; + return packageInstallrewire(directoryPath) + .then((data) => { + chai.assert.equal(data, "npm install done") + }) + .catch((_error) => { + chai.assert.fail("Promise error"); + }); + }); + + it("should reject if error in npm install", () => { + packageInstaller.__set__({ + npm: { + commands: { + install: (_packageDir, [], installCallback) => { + installCallback("test error", "npm install failed"); + } + }, + load: (_npmLoad, loadCallback) => { + loadCallback(null); + } + }, + }); + let packageInstallrewire = packageInstaller.__get__('packageInstall'); + let directoryPath = "/random/path"; + return packageInstallrewire(directoryPath) + .then((_data) => { + chai.assert.fail("Promise error"); + }) + .catch((error) => { + chai.assert.equal(error, "test error") + }); + }); + }); + + context("packageArchiver", () => { + let fsStub, archiverStub, winstonLoggerInfoStub; + let directoryPath = "/random/path"; + let packageFile = "/random/path/to/file"; + const packageInstaller = rewire("../../../../bin/helpers/packageInstaller"); + beforeEach(() => { + fsStub = { + events: {}, + on: (event, func) => { + fsStub.events[event] = func + }, + createWriteStream: () => { + return fsStub + }, + pipe: () => { + return fsStub + }, + emit: (event, data) => { + fsStub.events[event](data) + } + }; + archiverStub = { + events: {}, + on: (event, func) => { + fsStub.events[event] = func + }, + pipe: () => { + return fsStub + }, + directory: () => { + return fsStub + }, + finalize: () => { + archiverStub.emit("warning", {code: "ENOENT"}); + fsStub.emit("end"); + fsStub.emit("close"); + }, + emit: (event, data) => { + fsStub.events[event](data) + } + }; + winstonLoggerInfoStub = sinon.stub().returns(null); + }); + + it("should retun if zipping complete with ENOENT warning", () => { + packageInstaller.__set__({ + fs: fsStub, + archiver: () => { + return archiverStub; + }, + logger: { + info: winstonLoggerInfoStub + } + }); + let packageArchiverrewire = packageInstaller.__get__('packageArchiver'); + return packageArchiverrewire(directoryPath, packageFile) + .then((data) => { + chai.assert.equal(data, "Zipping completed") + }) + .catch((_error) => { + chai.assert.fail("Promise error"); + }); + }); + + it("should reject if error in archiver", () => { + archiverStub.finalize = () => {archiverStub.emit("error", "test error")} + packageInstaller.__set__({ + fs: fsStub, + archiver: () => { + return archiverStub; + } + }); + let packageArchiverrewire = packageInstaller.__get__('packageArchiver'); + return packageArchiverrewire(directoryPath, packageFile) + .then((_data) => { + chai.assert.fail("Promise error"); + }) + .catch((error) => { + chai.assert.equal(error, "test error") + }); + }); + + it("should reject if archiver warning other then ENOENT", () => { + archiverStub.finalize = () => {archiverStub.emit("warning", {message: "test error"})} + packageInstaller.__set__({ + fs: fsStub, + archiver: () => { + return archiverStub; + } + }); + let packageArchiverrewire = packageInstaller.__get__('packageArchiver'); + return packageArchiverrewire(directoryPath, packageFile) + .then((_data) => { + chai.assert.fail("Promise error"); + }) + .catch((error) => { + chai.assert.equal(error.message, "test error") + }); + }); + }); + + context("packageWrapper", () => { + let setupPackageFolderStub, setupPackageFolderErrorStub, setupPackageInstallStub, setupPackageArchiverStub; + let packageDir = "/random/path"; + let packageFile = "/random/path/to/file"; + const packageInstaller = rewire("../../../../bin/helpers/packageInstaller"); + beforeEach(() => { + setupPackageFolderStub = sandbox.stub().returns(Promise.resolve("random")); + setupPackageInstallStub = sandbox.stub().returns(Promise.resolve("random")); + setupPackageArchiverStub = sandbox.stub().returns(Promise.resolve("random")); + }); + + it("should return if feature not enabled", () => { + let packageWrapperrewire = packageInstaller.__get__('packageWrapper'); + let bsConfig = { + run_settings: { + cache_dependencies: false + } + }; + let md5data = {}; + let instrumentBlocks = { + markBlockStart: sinon.stub(), + markBlockEnd: sinon.stub() + } + return packageWrapperrewire(bsConfig, packageDir, packageFile, md5data, instrumentBlocks) + .then((data) => { + chai.assert.deepEqual(data, {packageArchieveCreated: false}); + }) + .catch((_error) => { + chai.assert.fail("Promise error"); + }); + }); + + it("should resolve with package exist if all step are successful", () => { + packageInstaller.__set__({ + setupPackageFolder: setupPackageFolderStub, + packageInstall:setupPackageInstallStub, + packageArchiver: setupPackageArchiverStub + }); + let packageWrapperrewire = packageInstaller.__get__('packageWrapper'); + let bsConfig = { + run_settings: { + cache_dependencies: true + } + }; + let md5data = {}; + let instrumentBlocks = { + markBlockStart: sinon.stub(), + markBlockEnd: sinon.stub() + } + return packageWrapperrewire(bsConfig, packageDir, packageFile, md5data, instrumentBlocks) + .then((data) => { + chai.assert.deepEqual(data, {packageArchieveCreated: true}); + }) + .catch((_error) => { + chai.assert.fail("Promise error"); + }); + }); + + it("should reject with error if issue in any step", () => { + setupPackageFolderErrorStub = sandbox.stub().returns(Promise.reject({message: "test error", stack: "test error stack"})); + packageInstaller.__set__({ + setupPackageFolder: setupPackageFolderErrorStub, + packageInstall:setupPackageInstallStub, + packageArchiver: setupPackageArchiverStub + }); + let packageWrapperrewire = packageInstaller.__get__('packageWrapper'); + let bsConfig = { + run_settings: { + cache_dependencies: true + } + }; + let md5data = {}; + let instrumentBlocks = { + markBlockStart: sinon.stub(), + markBlockEnd: sinon.stub() + } + return packageWrapperrewire(bsConfig, packageDir, packageFile, md5data, instrumentBlocks) + .then((data) => { + chai.assert.deepEqual(data, { packageArchieveCreated: false, error: 'test error stack' }); + }) + .catch((_error) => { + chai.assert.fail("Promise error"); + }); + }); + }); +}); diff --git a/test/unit/bin/helpers/utils.js b/test/unit/bin/helpers/utils.js index a75b8c9e..50872011 100644 --- a/test/unit/bin/helpers/utils.js +++ b/test/unit/bin/helpers/utils.js @@ -17,6 +17,8 @@ const usageReporting = require('../../../../bin/helpers/usageReporting'); const utils = require('../../../../bin/helpers/utils'), constant = require('../../../../bin/helpers/constants'), logger = require('../../../../bin/helpers/logger').winstonLogger, + config = require('../../../../bin/helpers/config'), + fileHelpers = require('../../../../bin/helpers/fileHelpers'), testObjects = require('../../support/fixtures/testObjects'), syncLogger = require('../../../../bin/helpers/logger').syncCliLogger; const browserstack = require('browserstack-local'); @@ -231,6 +233,125 @@ describe('utils', () => { }); }); + describe('checkError', () => { + it('should return error if exists', () => { + expect(utils.checkError({error: "test error"})).to.be.eq("test error"); + expect(utils.checkError({})).to.be.eq(undefined); + }) + }) + + describe('isTrueString', () => { + it('should return true if true string', () => { + expect(utils.isTrueString("true")).to.be.eq(true); + expect(utils.isTrueString(true)).to.be.eq(true); + expect(utils.isTrueString(false)).to.be.eq(false); + expect(utils.isTrueString("atrue")).to.be.eq(false); + expect(utils.isTrueString("false")).to.be.eq(false); + }) + }) + + describe('generateUploadParams', () => { + it('should generate upload params based on data', () => { + let bsConfig = { + auth: { + username: "user", + access_key: "key" + } + }; + let filePath = "random/path"; + let md5data = "md5data"; + let fileDetails = { + filetype: "type", + filename: "name" + }; + let options = { + url: config.uploadUrl, + auth: { + user: "user", + password: "key" + }, + formData: { + file: "random_fs", + filetype: "type", + filename: "name", + zipMd5sum: "md5data", + }, + headers: { + "User-Agent": "random_agent", + } + }; + let getUserAgentStub = sinon.stub(utils, 'getUserAgent').returns("random_agent"); + let fsStub = sinon.stub(fs, 'createReadStream').returns("random_fs"); + expect(utils.generateUploadParams(bsConfig, filePath, md5data, fileDetails)).to.deep.equal(options); + getUserAgentStub.restore(); + fsStub.restore(); + }); + }); + + describe('sortJsonKeys', () => { + it('should return josn sorted by keys', () => { + expect(utils.sortJsonKeys({b:1, a:2})).to.deep.equal({a:2, b:1}) + }); + }); + + describe('generateUploadOptions', () => { + it('should generate zip upload options based on data', () => { + let md5data = { + zipUrlPresent: true, + zip_md5sum: "randum_md5", + zipUrl: "bs://random_hash" + }; + let packageData = {}; + let options = { + archivePresent: true, + md5ReturnKey: "zip_url", + urlPresent: true, + md5Data: "randum_md5", + url: "bs://random_hash", + propogateError: true, + fileDetails: { + filetype: "zip", + filename: "tests" + }, + messages: { + uploading: constant.userMessages.UPLOADING_TESTS, + uploadingSuccess: constant.userMessages.UPLOADING_TESTS_SUCCESS + }, + cleanupMethod: fileHelpers.deleteZip, + }; + expect(utils.generateUploadOptions('zip', md5data, packageData)).to.deep.equal(options); + }); + + it('should generate npm upload options based on data', () => { + let md5data = { + packageUrlPresent: true, + npm_package_md5sum: "randum_md5", + npmPackageUrl: "bs://random_hash" + }; + let packageData = { + packageArchieveCreated: true + }; + let options = { + archivePresent: true, + md5ReturnKey: "npm_package_url", + urlPresent: true, + md5Data: "randum_md5", + url: "bs://random_hash", + propogateError: false, + fileDetails: { + filetype: "tar.gz", + filename: "bstackPackages" + }, + messages: { + uploading: constant.userMessages.UPLOADING_NPM_PACKAGES, + uploadingSuccess: constant.userMessages.UPLOADING_NPM_PACKAGES_SUCCESS + }, + cleanupMethod: fileHelpers.deletePackageArchieve, + }; + expect(utils.generateUploadOptions('npm', md5data, packageData)).to.deep.equal(options); + }); + }); + describe('getErrorCodeFromErr', () => { it('should return bstack_json_invalid_unknown if err.Code is not present in the list', () => { expect(utils.getErrorCodeFromErr('random_value')).to.be.eq( diff --git a/test/unit/bin/helpers/zipUpload.js b/test/unit/bin/helpers/zipUpload.js index 3a2de658..b6c75acf 100644 --- a/test/unit/bin/helpers/zipUpload.js +++ b/test/unit/bin/helpers/zipUpload.js @@ -1,28 +1,22 @@ +'use strict'; const chai = require("chai"), chaiAsPromised = require("chai-as-promised"), sinon = require("sinon"), - request = require("request"), - fs = require("fs"); + request = require("request"); -const Constants = require("../../../../bin/helpers/constants"), - logger = require("../../../../bin/helpers/logger").winstonLogger, - testObjects = require("../../support/fixtures/testObjects"); +const logger = require("../../../../bin/helpers/logger").winstonLogger, + constant = require('../../../../bin/helpers/constants'); -const proxyquire = require("proxyquire").noCallThru(); +const rewire = require("rewire"); chai.use(chaiAsPromised); logger.transports["console.info"].silent = true; describe("zipUpload", () => { - let bsConfig = testObjects.sampleBsConfig; - - var sandbox; + let sandbox; beforeEach(() => { sandbox = sinon.createSandbox(); - getUserAgentStub = sandbox.stub().returns("random user-agent"); - createReadStreamStub = sandbox.stub(fs, "createReadStream"); - deleteZipStub = sandbox.stub().returns(true); }); afterEach(() => { @@ -30,206 +24,320 @@ describe("zipUpload", () => { sinon.restore(); }); - it("reject with error", () => { - let requestStub = sandbox - .stub(request, "post") - .yields(new Error("random error"), null, null); - - const zipUploader = proxyquire("../../../../bin/helpers/zipUpload", { - "./utils": { - getUserAgent: getUserAgentStub, - }, - request: { post: requestStub }, + context("uploadSuits", () => { + let utilsStub, loggerStub; + let bsConfig = {} + let filePath = "random/path"; + const zipUploader = rewire("../../../../bin/helpers/zipUpload"); + beforeEach(() => { + utilsStub = { + generateUploadParams: sinon.stub().returns({}) + }; + loggerStub = { + info: sandbox.stub().returns(null) + }; }); - return zipUploader - .zipUpload(bsConfig, "./random_file_path",{}) - .then(function (data) { - chai.assert.fail("Promise error"); - }) - .catch((error) => { - sinon.assert.calledOnce(requestStub); - sinon.assert.calledOnce(getUserAgentStub); - sinon.assert.calledOnce(createReadStreamStub); - chai.assert.equal(error.message, "random error"); - }); - }); + it("reject with error", () => { + let requestStub = sandbox + .stub(request, "post") + .yields(new Error("test error"), null, null); - it("reject with error (if error present in response) if statusCode == 401", () => { - let error = "non 200 code"; + zipUploader.__set__({ + request: { post: requestStub }, + utils: utilsStub, + logger: loggerStub + }); + let uploadSuitsrewire = zipUploader.__get__('uploadSuits'); + let opts = { + archivePresent: true, + messages: {} + } + return uploadSuitsrewire(bsConfig, filePath, opts) + .then((_data) => { + chai.assert.fail("Promise error"); + }) + .catch((error) => { + chai.assert.equal(error.message, "test error"); + }); + }); - let requestStub = sandbox - .stub(request, "post") - .yields(null, { statusCode: 401 }, JSON.stringify({ error: error })); + it("resolve with url if already present", () => { + let uploadSuitsrewire = zipUploader.__get__('uploadSuits'); + let opts = { + urlPresent: true, + md5ReturnKey: 'returnKey', + url: 'bs://random_hash' + } + return uploadSuitsrewire(bsConfig, filePath, opts) + .then((data) => { + chai.assert.deepEqual(data, {returnKey: 'bs://random_hash'}); + }) + .catch((_error) => { + chai.assert.fail("Promise error"); + }); + }); - const zipUploader = proxyquire("../../../../bin/helpers/zipUpload", { - "./utils": { - getUserAgent: getUserAgentStub, - }, - request: { post: requestStub }, + it("resolve with url if archive not present", () => { + let uploadSuitsrewire = zipUploader.__get__('uploadSuits'); + let opts = { + archivePresent: false, + } + return uploadSuitsrewire(bsConfig, filePath, opts) + .then((data) => { + chai.assert.deepEqual(data, {}); + }) + .catch((_error) => { + chai.assert.fail("Promise error"); + }); }); - return zipUploader - .zipUpload(bsConfig, "./random_file_path", {}) - .then(function (data) { - chai.assert.fail("Promise error"); - }) - .catch((error) => { - sinon.assert.calledOnce(requestStub); - sinon.assert.calledOnce(getUserAgentStub); - sinon.assert.calledOnce(createReadStreamStub); - chai.assert.equal(error, "non 200 code"); + it("resolve with nothing if parsing error", () => { + let requestStub = sandbox + .stub(request, "post") + .yields(null, { statusCode: 200 }, '{ random: "test }'); + + zipUploader.__set__({ + request: { post: requestStub }, + utils: utilsStub, + logger: loggerStub }); - }); + let uploadSuitsrewire = zipUploader.__get__('uploadSuits'); + let opts = { + cleanupMethod: sinon.stub().returns(null), + archivePresent: true, + messages: {} + } + return uploadSuitsrewire(bsConfig, filePath, opts) + .then((data) => { + chai.assert.deepEqual(data, {}); + }) + .catch((_error) => { + chai.assert.fail("Promise error"); + }); + }); - it("reject with message if statusCode == 401 and error not in response", () => { - let requestStub = sandbox - .stub(request, "post") - .yields( - null, - { statusCode: 401 }, - JSON.stringify({ message: "random message" }) - ); - - const zipUploader = proxyquire("../../../../bin/helpers/zipUpload", { - "./utils": { - getUserAgent: getUserAgentStub, - }, - request: { post: requestStub }, + it("resolve with message if statusCode = 200", () => { + let requestStub = sandbox + .stub(request, "post") + .yields(null, { statusCode: 200 }, JSON.stringify({ zip_url: "zip_url" })); + + zipUploader.__set__({ + request: { post: requestStub }, + utils: utilsStub, + logger: loggerStub + }); + let uploadSuitsrewire = zipUploader.__get__('uploadSuits'); + let opts = { + cleanupMethod: sinon.stub().returns(null), + archivePresent: true, + messages: {} + } + return uploadSuitsrewire(bsConfig, filePath, opts) + .then((data) => { + chai.assert.deepEqual(data, {zip_url: 'zip_url'}); + }) + .catch((_error) => { + chai.assert.fail("Promise error"); + }); }); - return zipUploader - .zipUpload(bsConfig, "./random_file_path", {}) - .then(function (data) { - chai.assert.fail("Promise error"); - }) - .catch((error) => { - sinon.assert.calledOnce(requestStub); - sinon.assert.calledOnce(getUserAgentStub); - sinon.assert.calledOnce(createReadStreamStub); - chai.assert.equal( - error, - Constants.validationMessages.INVALID_DEFAULT_AUTH_PARAMS - ); + it("reject with returned message if auth failed with message", () => { + let requestStub = sandbox + .stub(request, "post") + .yields(null, { statusCode: 401 }, JSON.stringify({ error: "auth failed" })); + + zipUploader.__set__({ + request: { post: requestStub }, + utils: utilsStub, + logger: loggerStub }); - }); + let uploadSuitsrewire = zipUploader.__get__('uploadSuits'); + let opts = { + archivePresent: true, + messages: {} + } + return uploadSuitsrewire(bsConfig, filePath, opts) + .then((_data) => { + chai.assert.fail("Promise error"); + }) + .catch((error) => { + chai.assert.equal(error, "auth failed"); + }); + }); - it("reject with error (if error present in response) if statusCode != 200 and statusCode != 401", () => { - let error = "non 200 and non 401 code"; + it("reject with predefined message if auth failed without message", () => { + let requestStub = sandbox + .stub(request, "post") + .yields(null, { statusCode: 401 }, JSON.stringify({ })); - let requestStub = sandbox - .stub(request, "post") - .yields(null, { statusCode: 404 }, JSON.stringify({ error: error })); + zipUploader.__set__({ + request: { post: requestStub }, + utils: utilsStub, + logger: loggerStub + }); + let uploadSuitsrewire = zipUploader.__get__('uploadSuits'); + let opts = { + archivePresent: true, + messages: {} + } + return uploadSuitsrewire(bsConfig, filePath, opts) + .then((_data) => { + chai.assert.fail("Promise error"); + }) + .catch((error) => { + chai.assert.equal(error, constant.validationMessages.INVALID_DEFAULT_AUTH_PARAMS); + }); + }); + + it("resolve with nothing if request error but no propogation", () => { + let requestStub = sandbox + .stub(request, "post") + .yields(null, { statusCode: 402 }, JSON.stringify({ })); - const zipUploader = proxyquire("../../../../bin/helpers/zipUpload", { - "./utils": { - getUserAgent: getUserAgentStub, - }, - request: { post: requestStub }, + zipUploader.__set__({ + request: { post: requestStub }, + utils: utilsStub, + logger: loggerStub + }); + let uploadSuitsrewire = zipUploader.__get__('uploadSuits'); + let opts = { + archivePresent: true, + messages: {}, + propogateError: false + } + return uploadSuitsrewire(bsConfig, filePath, opts) + .then((data) => { + chai.assert.deepEqual(data, {}); + }) + .catch((_error) => { + chai.assert.fail("Promise error"); + }); }); - return zipUploader - .zipUpload(bsConfig, "./random_file_path", {}) - .then(function (data) { - chai.assert.fail("Promise error"); - }) - .catch((error) => { - sinon.assert.calledOnce(requestStub); - sinon.assert.calledOnce(getUserAgentStub); - sinon.assert.calledOnce(createReadStreamStub); - chai.assert.equal(error, "non 200 and non 401 code"); + it("reject with error if request error", () => { + let requestStub = sandbox + .stub(request, "post") + .yields(null, { statusCode: 402 }, JSON.stringify({ error: "test error" })); + + zipUploader.__set__({ + request: { post: requestStub }, + utils: utilsStub, + logger: loggerStub }); - }); + let uploadSuitsrewire = zipUploader.__get__('uploadSuits'); + let opts = { + archivePresent: true, + messages: {}, + propogateError: true + } + return uploadSuitsrewire(bsConfig, filePath, opts) + .then((_data) => { + chai.assert.fail("Promise error"); + }) + .catch((error) => { + chai.assert.deepEqual(error, "test error"); + }); + }); - it("reject with message if statusCode != 200 and statusCode != 401 and error not in response", () => { - let requestStub = sandbox - .stub(request, "post") - .yields( - null, - { statusCode: 404 }, - JSON.stringify({ message: "random message" }) - ); - - const zipUploader = proxyquire("../../../../bin/helpers/zipUpload", { - "./utils": { - getUserAgent: getUserAgentStub, - }, - request: { post: requestStub }, + it("reject with limit exceeded error", () => { + let requestStub = sandbox + .stub(request, "post") + .yields(null, { statusCode: 413 }, JSON.stringify({ })); + + zipUploader.__set__({ + request: { post: requestStub }, + utils: utilsStub, + logger: loggerStub + }); + let uploadSuitsrewire = zipUploader.__get__('uploadSuits'); + let opts = { + archivePresent: true, + messages: {}, + propogateError: true + } + return uploadSuitsrewire(bsConfig, filePath, opts) + .then((_data) => { + chai.assert.fail("Promise error"); + }) + .catch((error) => { + chai.assert.deepEqual(error, constant.userMessages.ZIP_UPLOAD_LIMIT_EXCEEDED); + }); }); - return zipUploader - .zipUpload(bsConfig, "./random_file_path", {}) - .then(function (data) { - chai.assert.fail("Promise error"); - }) - .catch((error) => { - sinon.assert.calledOnce(requestStub); - sinon.assert.calledOnce(getUserAgentStub); - sinon.assert.calledOnce(createReadStreamStub); - chai.assert.equal( - error, - Constants.userMessages.ZIP_UPLOADER_NOT_REACHABLE - ); + it("reject with not reachable error", () => { + let requestStub = sandbox + .stub(request, "post") + .yields(null, { statusCode: 414 }, JSON.stringify({ })); + + zipUploader.__set__({ + request: { post: requestStub }, + utils: utilsStub, + logger: loggerStub }); + let uploadSuitsrewire = zipUploader.__get__('uploadSuits'); + let opts = { + archivePresent: true, + messages: {}, + propogateError: true + } + return uploadSuitsrewire(bsConfig, filePath, opts) + .then((_data) => { + chai.assert.fail("Promise error"); + }) + .catch((error) => { + chai.assert.deepEqual(error, constant.userMessages.ZIP_UPLOADER_NOT_REACHABLE); + }); + }); }); - it("resolve with message if statusCode = 200", () => { - let zip_url = "uploaded zip url"; - let requestStub = sandbox - .stub(request, "post") - .yields(null, { statusCode: 200 }, JSON.stringify({ zip_url: zip_url })); - - const zipUploader = proxyquire('../../../../bin/helpers/zipUpload', { - './utils': { - getUserAgent: getUserAgentStub, - }, - request: {post: requestStub}, - './fileHelpers': { - deleteZip: deleteZipStub, - }, + context("uploadCypressZip", () => { + let utilsStub, uploadSuitsStub, uploadSuitsErrorStub; + const zipUploader = rewire("../../../../bin/helpers/zipUpload"); + beforeEach(() => { + utilsStub = { + generateUploadOptions: sinon.stub().returns({}) + }; + uploadSuitsStub = sandbox.stub().returns(Promise.resolve({zip_url: 'zip_url'})); }); - return zipUploader - .zipUpload(bsConfig, "./random_file_path", {}) - .then(function (data) { - sinon.assert.calledOnce(requestStub); - sinon.assert.calledOnce(getUserAgentStub); - sinon.assert.calledOnce(createReadStreamStub); - sinon.assert.calledOnce(deleteZipStub); - chai.assert.equal(data.zip_url, zip_url); - }) - .catch((error) => { - chai.assert.isNotOk(error, "Promise error"); + it("resolve with test suit", () => { + zipUploader.__set__({ + utils: utilsStub, + uploadSuits: uploadSuitsStub + }); + let uploadCypressZiprewire = zipUploader.__get__('uploadCypressZip'); + let bsConfig = {} + let md5data = {}; + let packageData = { + } + return uploadCypressZiprewire(bsConfig, md5data, packageData) + .then((data) => { + chai.assert.deepEqual(data, {zip_url: 'zip_url'}); + }) + .catch((_error) => { + chai.assert.fail("Promise error"); }); - }); - - it("resolve early if zip url already present", () => { - let zip_url = "uploaded zip url"; - let requestStub = sandbox - .stub(request, "post") - .yields(null, { statusCode: 200 }, JSON.stringify({ zip_url: zip_url })); - - const zipUploader = proxyquire('../../../../bin/helpers/zipUpload', { - './utils': { - getUserAgent: getUserAgentStub, - }, - request: {post: requestStub}, - './fileHelpers': { - deleteZip: deleteZipStub, - }, }); - return zipUploader - .zipUpload(bsConfig, "./random_file_path", { zipUrlPresent: true, zipUrl: zip_url }) - .then(function (data) { - sinon.assert.notCalled(requestStub); - sinon.assert.notCalled(getUserAgentStub); - sinon.assert.notCalled(createReadStreamStub); - sinon.assert.notCalled(deleteZipStub); - chai.assert.equal(data.zip_url, zip_url); - }) - .catch((error) => { - chai.assert.isNotOk(error, "Promise error"); + it("reject with error while uploading suit", () => { + let uploadSuitsErrorStub = sandbox.stub().returns(Promise.reject("test error")); + zipUploader.__set__({ + utils: utilsStub, + uploadSuits: uploadSuitsErrorStub + }); + let uploadCypressZiprewire = zipUploader.__get__('uploadCypressZip'); + let bsConfig = {} + let md5data = {}; + let packageData = { + } + return uploadCypressZiprewire(bsConfig, md5data, packageData) + .then((_data) => { + chai.assert.fail("Promise error"); + }) + .catch((error) => { + chai.assert.equal(error, "test error"); }); + }); }); }); From 68979800b44bf78faf8b7e0a7211b7f723abbf53 Mon Sep 17 00:00:00 2001 From: Sparsh Agarwal Date: Tue, 9 Nov 2021 19:00:09 +0530 Subject: [PATCH 14/14] merge issue --- bin/commands/runs.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/commands/runs.js b/bin/commands/runs.js index 534a442e..a4ee13c4 100644 --- a/bin/commands/runs.js +++ b/bin/commands/runs.js @@ -139,10 +139,10 @@ module.exports = function run(args) { if (bsConfig.run_settings.cypress_version && bsConfig.run_settings.cypress_version !== data.cypress_version) { if (bsConfig.run_settings.cypress_version.toString().match(Constants.LATEST_VERSION_SYNTAX_REGEX)) { - let versionMessage = utils.latestSyntaxToActualVersionMessage(bsConfig.run_settings.cypress_version, data.cypress_version); + let versionMessage = utils.latestSyntaxToActualVersionMessage(bsConfig.run_settings.cypress_version, data.cypress_version, data.framework_upgrade_message); logger.info(versionMessage); } else { - let versionMessage = utils.versionChangedMessage(bsConfig.run_settings.cypress_version, data.cypress_version); + let versionMessage = utils.versionChangedMessage(bsConfig.run_settings.cypress_version, data.cypress_version, data.framework_upgrade_message); logger.warn(versionMessage); } }