diff --git a/lib/tools/apk-utils.js b/lib/tools/apk-utils.js index 4beef95e..e40d2a39 100644 --- a/lib/tools/apk-utils.js +++ b/lib/tools/apk-utils.js @@ -471,11 +471,12 @@ apkUtilsMethods.install = async function install (appPath, options = {}) { return await this.installApks(appPath, options); } - options = Object.assign({ + options = _.cloneDeep(options); + _.defaults(options, { replace: true, timeout: this.adbExecTimeout === DEFAULT_ADB_EXEC_TIMEOUT ? APK_INSTALL_TIMEOUT : this.adbExecTimeout, timeoutCapName: 'androidInstallTimeout', - }, options); + }); const installArgs = buildInstallArgs(await this.getApiLevel(), options); const installOpts = { @@ -613,10 +614,6 @@ apkUtilsMethods.getApplicationInstallState = async function getApplicationInstal * @throws {Error} If an unexpected error happens during install. */ apkUtilsMethods.installOrUpgrade = async function installOrUpgrade (appPath, pkg = null, options = {}) { - if (!util.hasValue(options.timeout)) { - options.timeout = APK_INSTALL_TIMEOUT; - } - if (!pkg) { const apkInfo = await this.getApkInfo(appPath); pkg = apkInfo.name; diff --git a/lib/tools/apks-utils.js b/lib/tools/apks-utils.js index c184ad58..c7d287de 100644 --- a/lib/tools/apks-utils.js +++ b/lib/tools/apks-utils.js @@ -139,10 +139,12 @@ apksUtilsMethods.getDeviceSpec = async function getDeviceSpec (specLocation) { * @throws {Error} If the .apks bundle cannot be installed */ apksUtilsMethods.installApks = async function installApks (apks, options = {}) { - options = Object.assign({ + options = _.cloneDeep(options); + _.defaults(options, { timeout: this.adbExecTimeout === DEFAULT_ADB_EXEC_TIMEOUT ? APKS_INSTALL_TIMEOUT : this.adbExecTimeout, timeoutCapName: 'androidInstallTimeout', - }, options, {replace: true}); + }); + Object.assign(options, {replace: true}); const tmpRoot = await tempDir.openDir(); try { diff --git a/lib/tools/system-calls.js b/lib/tools/system-calls.js index d9f63c06..8af6794b 100644 --- a/lib/tools/system-calls.js +++ b/lib/tools/system-calls.js @@ -295,6 +295,7 @@ systemCallMethods.adbExec = async function adbExec (cmd, opts = {}) { throw new Error('You need to pass in a command to adbExec()'); } + opts = _.cloneDeep(opts); // setting default timeout for each command to prevent infinite wait. opts.timeout = opts.timeout || this.adbExecTimeout || DEFAULT_ADB_EXEC_TIMEOUT; opts.timeoutCapName = opts.timeoutCapName || 'adbExecTimeout'; // For error message @@ -348,6 +349,9 @@ systemCallMethods.adbExec = async function adbExec (cmd, opts = {}) { /** * @typedef {Object} ShellExecOptions + * @property {?string} timeoutCapName [adbExecTimeout] - the name of the corresponding Appium's timeout capability + * (used in the error messages). + * @property {?number} timeout [adbExecTimeout] - command execution timeout. * @property {?boolean} privileged [falsy] - Whether to run the given command as root. * @property {?boolean} keepPrivileged [falsy] - Whether to keep root mode after command execution is completed. * diff --git a/test/unit/apk-utils-specs.js b/test/unit/apk-utils-specs.js index c9a38183..26dde7e8 100644 --- a/test/unit/apk-utils-specs.js +++ b/test/unit/apk-utils-specs.js @@ -1009,7 +1009,7 @@ describe('Apk-utils', withMocks({adb, fs, teen_process}, function (mocks) { versionCode: 1 }); mocks.adb.expects('isAppInstalled').withExactArgs(pkgId).once().returns(true); - mocks.adb.expects('install').withArgs(apkPath, {replace: true, timeout: 60000}).once().returns(true); + mocks.adb.expects('install').withArgs(apkPath, {replace: true}).once().returns(true); await adb.installOrUpgrade(apkPath); }); it('should perform upgrade if older package version is installed, but version codes are not maintained', async function () { @@ -1023,7 +1023,7 @@ describe('Apk-utils', withMocks({adb, fs, teen_process}, function (mocks) { versionName: '1.0.0', }); mocks.adb.expects('isAppInstalled').withExactArgs(pkgId).once().returns(true); - mocks.adb.expects('install').withArgs(apkPath, {replace: true, timeout: 60000}).once().returns(true); + mocks.adb.expects('install').withArgs(apkPath, {replace: true}).once().returns(true); await adb.installOrUpgrade(apkPath); }); it('should perform upgrade if the same version is installed, but version codes are different', async function () { @@ -1037,7 +1037,7 @@ describe('Apk-utils', withMocks({adb, fs, teen_process}, function (mocks) { versionName: '2.0.0', }); mocks.adb.expects('isAppInstalled').withExactArgs(pkgId).once().returns(true); - mocks.adb.expects('install').withArgs(apkPath, {replace: true, timeout: 60000}).once().returns(true); + mocks.adb.expects('install').withArgs(apkPath, {replace: true}).once().returns(true); await adb.installOrUpgrade(apkPath); }); it('should uninstall and re-install if older package version is installed and upgrade fails', async function () { @@ -1049,9 +1049,9 @@ describe('Apk-utils', withMocks({adb, fs, teen_process}, function (mocks) { versionCode: 1 }); mocks.adb.expects('isAppInstalled').withExactArgs(pkgId).once().returns(true); - mocks.adb.expects('install').withArgs(apkPath, {replace: true, timeout: 60000}).once().throws(); + mocks.adb.expects('install').withArgs(apkPath, {replace: true}).once().throws(); mocks.adb.expects('uninstallApk').withExactArgs(pkgId).once().returns(true); - mocks.adb.expects('install').withArgs(apkPath, {replace: false, timeout: 60000}).once().returns(true); + mocks.adb.expects('install').withArgs(apkPath, {replace: false}).once().returns(true); await adb.installOrUpgrade(apkPath); }); it('should throw an exception if upgrade and reinstall fail', async function () {