diff --git a/lib/shared/drive-constraints.js b/lib/shared/drive-constraints.js index f667ff64..e32dacc2 100644 --- a/lib/shared/drive-constraints.js +++ b/lib/shared/drive-constraints.js @@ -168,7 +168,29 @@ exports.isDriveLargeEnough = (drive, image) => { } /** - * @summary Check if a drive is is valid, i.e. not locked and large enough for an image + * @summary Check if a drive is pending (i.e. not ready for selection) + * @function + * @public + * + * @param {Object} drive - drive + * @returns {Boolean} whether the drive is pending + * + * @example + * if (constraints.isDrivePending({ + * device: '/dev/disk2', + * name: 'My Drive', + * size: 1000000000, + * pending: true + * })) { + * console.log('The drive is pending'); + * } + */ +exports.isDrivePending = (drive) => { + return _.get(drive, [ 'pending' ], false) +} + +/** + * @summary Check if a drive is valid, i.e. not locked and large enough for an image * @function * @public * @@ -194,7 +216,8 @@ exports.isDriveValid = (drive, image) => { return _.every([ !this.isDriveLocked(drive), this.isDriveLargeEnough(drive, image), - !this.isSourceDrive(drive, image) + !this.isSourceDrive(drive, image), + !this.isDrivePending(drive) ]) } @@ -278,6 +301,15 @@ exports.COMPATIBILITY_STATUS_MESSAGES = { */ SYSTEM: 'System Drive', + /** + * @property {String} PENDING + * @memberof COMPATIBILITY_STATUS_MESSAGES + * + * @description + * The drive is not fully loaded. + */ + PENDING: 'Pending', + /** * @property {String} CONTAINS_IMAGE * @memberof COMPATIBILITY_STATUS_MESSAGES @@ -342,7 +374,12 @@ exports.getDriveImageCompatibilityStatuses = (drive, image) => { const statusList = [] // Mind the order of the if-statements if you modify. - if (exports.isSourceDrive(drive, image)) { + if (exports.isDrivePending(drive)) { + statusList.push({ + type: exports.COMPATIBILITY_STATUS_TYPES.ERROR, + message: exports.COMPATIBILITY_STATUS_MESSAGES.PENDING + }) + } else if (exports.isSourceDrive(drive, image)) { statusList.push({ type: exports.COMPATIBILITY_STATUS_TYPES.ERROR, message: exports.COMPATIBILITY_STATUS_MESSAGES.CONTAINS_IMAGE diff --git a/tests/shared/drive-constraints.spec.js b/tests/shared/drive-constraints.spec.js index 0059f593..6deeb884 100644 --- a/tests/shared/drive-constraints.spec.js +++ b/tests/shared/drive-constraints.spec.js @@ -527,6 +527,43 @@ describe('Shared: DriveConstraints', function () { }) }) + describe('.isDrivePending()', function () { + it('should return true if the drive is pending', function () { + const result = constraints.isDrivePending({ + device: '/dev/disk1', + name: 'USB Drive', + size: 1000000000, + protected: false, + pending: true + }) + + m.chai.expect(result).to.be.true + }) + + it('should return false if the drive is not pending', function () { + const result = constraints.isDrivePending({ + device: '/dev/disk1', + name: 'USB Drive', + size: 1000000000, + protected: false, + pending: false + }) + + m.chai.expect(result).to.be.false + }) + + it('should return false if "pending" is undefined', function () { + const result = constraints.isDrivePending({ + device: '/dev/disk1', + name: 'USB Drive', + size: 1000000000, + protected: false + }) + + m.chai.expect(result).to.be.false + }) + }) + describe('.isDriveSizeRecommended()', function () { it('should return true if the drive size is greater than the recommended size ', function () { const result = constraints.isDriveSizeRecommended({ @@ -639,56 +676,120 @@ describe('Shared: DriveConstraints', function () { this.drive.protected = true }) - it('should return false if the drive is not large enough and is a source drive', function () { - m.chai.expect(constraints.isDriveValid(this.drive, { - path: path.join(this.mountpoint, 'rpi.img'), - size: { - original: 5000000000, - final: { - estimation: false, - value: 5000000000 + describe('given the drive is pending', function () { + beforeEach(function () { + this.drive.pending = true + }) + + it('should return false if the drive is not large enough and is a source drive', function () { + m.chai.expect(constraints.isDriveValid(this.drive, { + path: path.join(this.mountpoint, 'rpi.img'), + size: { + original: 5000000000, + final: { + estimation: false, + value: 5000000000 + } } - } - })).to.be.false + })).to.be.false + }) + + it('should return false if the drive is not large enough and is not a source drive', function () { + m.chai.expect(constraints.isDriveValid(this.drive, { + path: path.resolve(this.mountpoint, '../bar/rpi.img'), + size: { + original: 5000000000, + final: { + estimation: false, + value: 5000000000 + } + } + })).to.be.false + }) + + it('should return false if the drive is large enough and is a source drive', function () { + m.chai.expect(constraints.isDriveValid(this.drive, { + path: path.join(this.mountpoint, 'rpi.img'), + size: { + original: 2000000000, + final: { + estimation: false, + value: 2000000000 + } + } + })).to.be.false + }) + + it('should return false if the drive is large enough and is not a source drive', function () { + m.chai.expect(constraints.isDriveValid(this.drive, { + path: path.resolve(this.mountpoint, '../bar/rpi.img'), + size: { + original: 2000000000, + final: { + estimation: false, + value: 2000000000 + } + } + })).to.be.false + }) }) - it('should return false if the drive is not large enough and is not a source drive', function () { - m.chai.expect(constraints.isDriveValid(this.drive, { - path: path.resolve(this.mountpoint, '../bar/rpi.img'), - size: { - original: 5000000000, - final: { - estimation: false, - value: 5000000000 - } - } - })).to.be.false - }) + describe('given the drive is not pending', function () { + beforeEach(function () { + this.drive.pending = false + }) - it('should return false if the drive is large enough and is a source drive', function () { - m.chai.expect(constraints.isDriveValid(this.drive, { - path: path.join(this.mountpoint, 'rpi.img'), - size: { - original: 2000000000, - final: { - estimation: false, - value: 2000000000 + it('should return false if the drive is not large enough and is a source drive', function () { + m.chai.expect(constraints.isDriveValid(this.drive, { + path: path.join(this.mountpoint, 'rpi.img'), + size: { + original: 5000000000, + final: { + estimation: false, + value: 5000000000 + } } - } - })).to.be.false - }) + })).to.be.false + }) - it('should return false if the drive is large enough and is not a source drive', function () { - m.chai.expect(constraints.isDriveValid(this.drive, { - path: path.resolve(this.mountpoint, '../bar/rpi.img'), - size: { - original: 2000000000, - final: { - estimation: false, - value: 2000000000 + it('should return false if the drive is not large enough and is not a source drive', function () { + m.chai.expect(constraints.isDriveValid(this.drive, { + path: path.resolve(this.mountpoint, '../bar/rpi.img'), + size: { + original: 5000000000, + final: { + estimation: false, + value: 5000000000 + } } - } - })).to.be.false + })).to.be.false + }) + + it('should return false if the drive is large enough and is a source drive', function () { + m.chai.expect(constraints.isDriveValid(this.drive, { + path: path.join(this.mountpoint, 'rpi.img'), + size: { + original: 2000000000, + final: { + estimation: false, + value: 2000000000 + } + } + })).to.be.false + }) + + it('should return false if the drive is large enough and is not a source drive', function () { + m.chai.expect(constraints.isDriveValid(this.drive, { + path: path.resolve(this.mountpoint, '../bar/rpi.img'), + size: { + original: 2000000000, + final: { + estimation: false, + value: 2000000000 + } + } + })).to.be.false + }) }) }) @@ -697,56 +798,120 @@ describe('Shared: DriveConstraints', function () { this.drive.protected = false }) - it('should return false if the drive is not large enough and is a source drive', function () { - m.chai.expect(constraints.isDriveValid(this.drive, { - path: path.join(this.mountpoint, 'rpi.img'), - size: { - original: 5000000000, - final: { - estimation: false, - value: 5000000000 + describe('given the drive is pending', function () { + beforeEach(function () { + this.drive.pending = true + }) + + it('should return false if the drive is not large enough and is a source drive', function () { + m.chai.expect(constraints.isDriveValid(this.drive, { + path: path.join(this.mountpoint, 'rpi.img'), + size: { + original: 5000000000, + final: { + estimation: false, + value: 5000000000 + } } - } - })).to.be.false + })).to.be.false + }) + + it('should return false if the drive is not large enough and is not a source drive', function () { + m.chai.expect(constraints.isDriveValid(this.drive, { + path: path.resolve(this.mountpoint, '../bar/rpi.img'), + size: { + original: 5000000000, + final: { + estimation: false, + value: 5000000000 + } + } + })).to.be.false + }) + + it('should return false if the drive is large enough and is a source drive', function () { + m.chai.expect(constraints.isDriveValid(this.drive, { + path: path.join(this.mountpoint, 'rpi.img'), + size: { + original: 2000000000, + final: { + estimation: false, + value: 2000000000 + } + } + })).to.be.false + }) + + it('should return false if the drive is large enough and is not a source drive', function () { + m.chai.expect(constraints.isDriveValid(this.drive, { + path: path.resolve(this.mountpoint, '../bar/rpi.img'), + size: { + original: 2000000000, + final: { + estimation: false, + value: 2000000000 + } + } + })).to.be.false + }) }) - it('should return false if the drive is not large enough and is not a source drive', function () { - m.chai.expect(constraints.isDriveValid(this.drive, { - path: path.resolve(this.mountpoint, '../bar/rpi.img'), - size: { - original: 5000000000, - final: { - estimation: false, - value: 5000000000 - } - } - })).to.be.false - }) + describe('given the drive is not pending', function () { + beforeEach(function () { + this.drive.pending = false + }) - it('should return false if the drive is large enough and is a source drive', function () { - m.chai.expect(constraints.isDriveValid(this.drive, { - path: path.join(this.mountpoint, 'rpi.img'), - size: { - original: 2000000000, - final: { - estimation: false, - value: 2000000000 + it('should return false if the drive is not large enough and is a source drive', function () { + m.chai.expect(constraints.isDriveValid(this.drive, { + path: path.join(this.mountpoint, 'rpi.img'), + size: { + original: 5000000000, + final: { + estimation: false, + value: 5000000000 + } } - } - })).to.be.false - }) + })).to.be.false + }) - it('should return true if the drive is large enough and is not a source drive', function () { - m.chai.expect(constraints.isDriveValid(this.drive, { - path: path.resolve(this.mountpoint, '../bar/rpi.img'), - size: { - original: 2000000000, - final: { - estimation: false, - value: 2000000000 + it('should return false if the drive is not large enough and is not a source drive', function () { + m.chai.expect(constraints.isDriveValid(this.drive, { + path: path.resolve(this.mountpoint, '../bar/rpi.img'), + size: { + original: 5000000000, + final: { + estimation: false, + value: 5000000000 + } } - } - })).to.be.true + })).to.be.false + }) + + it('should return false if the drive is large enough and is a source drive', function () { + m.chai.expect(constraints.isDriveValid(this.drive, { + path: path.join(this.mountpoint, 'rpi.img'), + size: { + original: 2000000000, + final: { + estimation: false, + value: 2000000000 + } + } + })).to.be.false + }) + + it('should return true if the drive is large enough and is not a source drive', function () { + m.chai.expect(constraints.isDriveValid(this.drive, { + path: path.resolve(this.mountpoint, '../bar/rpi.img'), + size: { + original: 2000000000, + final: { + estimation: false, + value: 2000000000 + } + } + })).to.be.true + }) }) }) }) @@ -766,6 +931,7 @@ describe('Shared: DriveConstraints', function () { name: 'My Drive', protected: false, system: false, + pending: false, mountpoints: [ { path: this.mountpoint @@ -809,6 +975,19 @@ describe('Shared: DriveConstraints', function () { }) }) + describe('given the drive is pending', () => { + it('should return an empty list', function () { + this.drive.pending = true + const result = constraints.getDriveImageCompatibilityStatuses(this.drive, { + path: '/mnt/disk2/rpi.img', + size: 1000000000 + }) + + const expectedTuples = [ [ 'ERROR', 'PENDING' ] ] + expectStatusTypesAndMessagesToBe(result, expectedTuples) + }) + }) + describe('given the drive contains the image', () => { it('should return the contains-image error', function () { this.image.path = path.join(this.mountpoint, 'rpi.img')