mirror of
https://github.com/balena-io/etcher.git
synced 2025-07-25 12:16:37 +00:00
fix(GUI): prevent flashing the drive where the source image is located
Currently Etcher will allow you to flash an image to the same drive that contains the image. As a way to protect against that case we introduce the concept of a "source drive", which means a drive that contains the source image. This commit adds the following logic around this new concept: - Don't auto-select a source drive - De-select an already selected drive if an image inside it is selected - Disable the drive in the drive selector modal - Add a "Source Drive" badge to the drive in the drive selector modal Fixes: https://github.com/resin-io/etcher/issues/830 Change-Type: minor Changelog-Entry: Prevent flashing the drive where the source image is located. Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
This commit is contained in:
parent
16340b412a
commit
95d4f2f608
@ -40,6 +40,11 @@
|
|||||||
<i class="glyphicon glyphicon-hdd"></i>
|
<i class="glyphicon glyphicon-hdd"></i>
|
||||||
System Drive</span>
|
System Drive</span>
|
||||||
|
|
||||||
|
<span class="label label-danger"
|
||||||
|
ng-show="modal.constraints.isSourceDrive(drive, modal.state.getImage())">
|
||||||
|
<i class="glyphicon glyphicon-circle-arrow-down"></i>
|
||||||
|
Source Drive</span>
|
||||||
|
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
<span class="tick tick--success"
|
<span class="tick tick--success"
|
||||||
|
@ -95,8 +95,8 @@ const storeReducer = (state, action) => {
|
|||||||
|
|
||||||
const drive = _.first(action.data);
|
const drive = _.first(action.data);
|
||||||
|
|
||||||
// Even if there's no image selectected, we need to call `isDriveValid`
|
// Even if there's no image selected, we need to call several
|
||||||
// to check if the drive is locked, and `{}` works fine with it
|
// drive/image related checks, and `{}` works fine with them
|
||||||
const image = state.getIn([ 'selection', 'image' ], Immutable.fromJS({})).toJS();
|
const image = state.getIn([ 'selection', 'image' ], Immutable.fromJS({})).toJS();
|
||||||
|
|
||||||
if (_.every([
|
if (_.every([
|
||||||
@ -268,7 +268,7 @@ const storeReducer = (state, action) => {
|
|||||||
|
|
||||||
return _.attempt(() => {
|
return _.attempt(() => {
|
||||||
if (selectedDrive && !_.every([
|
if (selectedDrive && !_.every([
|
||||||
constraints.isDriveLargeEnough(selectedDrive.toJS(), action.data),
|
constraints.isDriveValid(selectedDrive.toJS(), action.data),
|
||||||
constraints.isDriveSizeRecommended(selectedDrive.toJS(), action.data)
|
constraints.isDriveSizeRecommended(selectedDrive.toJS(), action.data)
|
||||||
])) {
|
])) {
|
||||||
return storeReducer(state, {
|
return storeReducer(state, {
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
|
const pathIsInside = require('path-is-inside');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @summary Check if a drive is locked
|
* @summary Check if a drive is locked
|
||||||
@ -65,6 +66,52 @@ exports.isSystemDrive = (drive) => {
|
|||||||
return Boolean(_.get(drive, 'system', false));
|
return Boolean(_.get(drive, 'system', false));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Check if a drive is source drive
|
||||||
|
* @function
|
||||||
|
* @public
|
||||||
|
*
|
||||||
|
* @description
|
||||||
|
* In the context of Etcher, a source drive is a drive
|
||||||
|
* containing the image.
|
||||||
|
*
|
||||||
|
* @param {Object} drive - drive
|
||||||
|
* @param {Object} image - image
|
||||||
|
* @returns {Boolean} whether the drive is a source drive
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* if (constraints.isSourceDrive({
|
||||||
|
* device: '/dev/disk2',
|
||||||
|
* name: 'My Drive',
|
||||||
|
* size: 123456789,
|
||||||
|
* protected: true,
|
||||||
|
* system: true,
|
||||||
|
* mountpoints: [
|
||||||
|
* {
|
||||||
|
* path: '/Volumes/Untitled'
|
||||||
|
* }
|
||||||
|
* ]
|
||||||
|
* }, {
|
||||||
|
* path: '/Volumes/Untitled/image.img',
|
||||||
|
* size: 1000000000
|
||||||
|
* })) {
|
||||||
|
* console.log('This drive is a source drive!');
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
exports.isSourceDrive = (drive, image) => {
|
||||||
|
const mountpoints = _.get(drive, 'mountpoints', []);
|
||||||
|
const imagePath = _.get(image, 'path');
|
||||||
|
|
||||||
|
if (!imagePath || _.isEmpty(mountpoints)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _.some(_.map(mountpoints, (mountpoint) => {
|
||||||
|
return pathIsInside(imagePath, mountpoint.path);
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @summary Check if a drive is large enough for an image
|
* @summary Check if a drive is large enough for an image
|
||||||
* @function
|
* @function
|
||||||
@ -114,7 +161,11 @@ exports.isDriveLargeEnough = (drive, image) => {
|
|||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
exports.isDriveValid = (drive, image) => {
|
exports.isDriveValid = (drive, image) => {
|
||||||
return !this.isDriveLocked(drive) && this.isDriveLargeEnough(drive, image);
|
return _.every([
|
||||||
|
!this.isDriveLocked(drive),
|
||||||
|
this.isDriveLargeEnough(drive, image),
|
||||||
|
!this.isSourceDrive(drive, image)
|
||||||
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
5
npm-shrinkwrap.json
generated
5
npm-shrinkwrap.json
generated
@ -1298,6 +1298,11 @@
|
|||||||
"from": "path-exists@>=2.0.0 <3.0.0",
|
"from": "path-exists@>=2.0.0 <3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz"
|
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz"
|
||||||
},
|
},
|
||||||
|
"path-is-inside": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"from": "path-is-inside@>=1.0.2 <2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz"
|
||||||
|
},
|
||||||
"path-key": {
|
"path-key": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"from": "path-key@>=1.0.0 <2.0.0",
|
"from": "path-key@>=1.0.0 <2.0.0",
|
||||||
|
@ -85,6 +85,7 @@
|
|||||||
"lzma-native": "^1.5.2",
|
"lzma-native": "^1.5.2",
|
||||||
"node-ipc": "^8.9.2",
|
"node-ipc": "^8.9.2",
|
||||||
"node-stream-zip": "^1.3.4",
|
"node-stream-zip": "^1.3.4",
|
||||||
|
"path-is-inside": "^1.0.2",
|
||||||
"read-chunk": "^2.0.0",
|
"read-chunk": "^2.0.0",
|
||||||
"redux": "^3.5.2",
|
"redux": "^3.5.2",
|
||||||
"redux-localstorage": "^0.4.1",
|
"redux-localstorage": "^0.4.1",
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const m = require('mochainon');
|
const m = require('mochainon');
|
||||||
|
const path = require('path');
|
||||||
const angular = require('angular');
|
const angular = require('angular');
|
||||||
require('angular-mocks');
|
require('angular-mocks');
|
||||||
|
|
||||||
@ -108,9 +109,15 @@ describe('Browser: DrivesModel', function() {
|
|||||||
describe('given a selected image and no selected drive', function() {
|
describe('given a selected image and no selected drive', function() {
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
|
if (process.platform === 'win32') {
|
||||||
|
this.imagePath = 'E:\\bar\\foo.img';
|
||||||
|
} else {
|
||||||
|
this.imagePath = '/mnt/bar/foo.img';
|
||||||
|
}
|
||||||
|
|
||||||
SelectionStateModel.removeDrive();
|
SelectionStateModel.removeDrive();
|
||||||
SelectionStateModel.setImage({
|
SelectionStateModel.setImage({
|
||||||
path: 'foo.img',
|
path: this.imagePath,
|
||||||
size: 999999999,
|
size: 999999999,
|
||||||
recommendedDriveSize: 2000000000
|
recommendedDriveSize: 2000000000
|
||||||
});
|
});
|
||||||
@ -220,6 +227,27 @@ describe('Browser: DrivesModel', function() {
|
|||||||
m.chai.expect(SelectionStateModel.hasDrive()).to.be.false;
|
m.chai.expect(SelectionStateModel.hasDrive()).to.be.false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not auto-select a source drive', function() {
|
||||||
|
m.chai.expect(SelectionStateModel.hasDrive()).to.be.false;
|
||||||
|
|
||||||
|
DrivesModel.setDrives([
|
||||||
|
{
|
||||||
|
device: '/dev/sdb',
|
||||||
|
name: 'Foo',
|
||||||
|
size: 2000000000,
|
||||||
|
mountpoints: [
|
||||||
|
{
|
||||||
|
path: path.dirname(this.imagePath)
|
||||||
|
}
|
||||||
|
],
|
||||||
|
system: false,
|
||||||
|
protected: false
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
m.chai.expect(SelectionStateModel.hasDrive()).to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const m = require('mochainon');
|
const m = require('mochainon');
|
||||||
|
const _ = require('lodash');
|
||||||
|
const path = require('path');
|
||||||
const angular = require('angular');
|
const angular = require('angular');
|
||||||
require('angular-mocks');
|
require('angular-mocks');
|
||||||
|
|
||||||
@ -485,6 +487,41 @@ describe('Browser: SelectionState', function() {
|
|||||||
SelectionStateModel.removeImage();
|
SelectionStateModel.removeImage();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should de-select a previously selected source drive', function() {
|
||||||
|
const imagePath = _.attempt(() => {
|
||||||
|
if (process.platform === 'win32') {
|
||||||
|
return 'E:\\bar\\foo.img';
|
||||||
|
}
|
||||||
|
|
||||||
|
return '/mnt/bar/foo.img';
|
||||||
|
});
|
||||||
|
|
||||||
|
DrivesModel.setDrives([
|
||||||
|
{
|
||||||
|
device: '/dev/disk1',
|
||||||
|
name: 'USB Drive',
|
||||||
|
size: 1200000000,
|
||||||
|
mountpoints: [
|
||||||
|
{
|
||||||
|
path: path.dirname(imagePath)
|
||||||
|
}
|
||||||
|
],
|
||||||
|
protected: false
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
SelectionStateModel.setDrive('/dev/disk1');
|
||||||
|
m.chai.expect(SelectionStateModel.hasDrive()).to.be.true;
|
||||||
|
|
||||||
|
SelectionStateModel.setImage({
|
||||||
|
path: imagePath,
|
||||||
|
size: 999999999
|
||||||
|
});
|
||||||
|
|
||||||
|
m.chai.expect(SelectionStateModel.hasDrive()).to.be.false;
|
||||||
|
SelectionStateModel.removeImage();
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const m = require('mochainon');
|
const m = require('mochainon');
|
||||||
|
const path = require('path');
|
||||||
const constraints = require('../../lib/shared/drive-constraints');
|
const constraints = require('../../lib/shared/drive-constraints');
|
||||||
|
|
||||||
describe('Shared: DriveConstraints', function() {
|
describe('Shared: DriveConstraints', function() {
|
||||||
@ -92,6 +93,214 @@ describe('Shared: DriveConstraints', function() {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('.isSourceDrive()', function() {
|
||||||
|
|
||||||
|
it('should return false if no image', function() {
|
||||||
|
const result = constraints.isSourceDrive({
|
||||||
|
device: '/dev/disk2',
|
||||||
|
name: 'USB Drive',
|
||||||
|
size: 999999999,
|
||||||
|
protected: true,
|
||||||
|
system: false
|
||||||
|
}, undefined);
|
||||||
|
|
||||||
|
m.chai.expect(result).to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false if no drive', function() {
|
||||||
|
const result = constraints.isSourceDrive(undefined, {
|
||||||
|
path: '/Volumes/Untitled/image.img'
|
||||||
|
});
|
||||||
|
|
||||||
|
m.chai.expect(result).to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false if there are no mount points', function() {
|
||||||
|
const result = constraints.isSourceDrive({
|
||||||
|
device: '/dev/disk2',
|
||||||
|
name: 'USB Drive',
|
||||||
|
size: 999999999,
|
||||||
|
protected: true,
|
||||||
|
system: false
|
||||||
|
}, {
|
||||||
|
path: '/Volumes/Untitled/image.img'
|
||||||
|
});
|
||||||
|
|
||||||
|
m.chai.expect(result).to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('given Windows paths', function() {
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
this.separator = path.sep;
|
||||||
|
path.sep = '\\';
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function() {
|
||||||
|
path.sep = this.separator;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return true if the image lives directly inside a mount point of the drive', function() {
|
||||||
|
const result = constraints.isSourceDrive({
|
||||||
|
mountpoints: [
|
||||||
|
{
|
||||||
|
path: 'E:'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'F:'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}, {
|
||||||
|
path: 'E:\\image.img'
|
||||||
|
});
|
||||||
|
|
||||||
|
m.chai.expect(result).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return true if the image lives inside a mount point of the drive', function() {
|
||||||
|
const result = constraints.isSourceDrive({
|
||||||
|
mountpoints: [
|
||||||
|
{
|
||||||
|
path: 'E:'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'F:'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}, {
|
||||||
|
path: 'E:\\foo\\bar\\image.img'
|
||||||
|
});
|
||||||
|
|
||||||
|
m.chai.expect(result).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false if the image does not live inside a mount point of the drive', function() {
|
||||||
|
const result = constraints.isSourceDrive({
|
||||||
|
mountpoints: [
|
||||||
|
{
|
||||||
|
path: 'E:'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'F:'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}, {
|
||||||
|
path: 'G:\\image.img'
|
||||||
|
});
|
||||||
|
|
||||||
|
m.chai.expect(result).to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false if the image is in a mount point that is a substring of the image mount point', function() {
|
||||||
|
const result = constraints.isSourceDrive({
|
||||||
|
mountpoints: [
|
||||||
|
{
|
||||||
|
path: 'E:\\fo'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}, {
|
||||||
|
path: 'E:\\foo/image.img'
|
||||||
|
});
|
||||||
|
|
||||||
|
m.chai.expect(result).to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('given UNIX paths', function() {
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
this.separator = path.sep;
|
||||||
|
path.sep = '/';
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function() {
|
||||||
|
path.sep = this.separator;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return true if the mount point is / and the image lives directly inside it', function() {
|
||||||
|
const result = constraints.isSourceDrive({
|
||||||
|
mountpoints: [
|
||||||
|
{
|
||||||
|
path: '/'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}, {
|
||||||
|
path: '/image.img'
|
||||||
|
});
|
||||||
|
|
||||||
|
m.chai.expect(result).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return true if the image lives directly inside a mount point of the drive', function() {
|
||||||
|
const result = constraints.isSourceDrive({
|
||||||
|
mountpoints: [
|
||||||
|
{
|
||||||
|
path: '/Volumes/A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/Volumes/B'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}, {
|
||||||
|
path: '/Volumes/A/image.img'
|
||||||
|
});
|
||||||
|
|
||||||
|
m.chai.expect(result).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return true if the image lives inside a mount point of the drive', function() {
|
||||||
|
const result = constraints.isSourceDrive({
|
||||||
|
mountpoints: [
|
||||||
|
{
|
||||||
|
path: '/Volumes/A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/Volumes/B'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}, {
|
||||||
|
path: '/Volumes/A/foo/bar/image.img'
|
||||||
|
});
|
||||||
|
|
||||||
|
m.chai.expect(result).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false if the image does not live inside a mount point of the drive', function() {
|
||||||
|
const result = constraints.isSourceDrive({
|
||||||
|
mountpoints: [
|
||||||
|
{
|
||||||
|
path: '/Volumes/A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/Volumes/B'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}, {
|
||||||
|
path: '/Volumes/C/image.img'
|
||||||
|
});
|
||||||
|
|
||||||
|
m.chai.expect(result).to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false if the image is in a mount point that is a substring of the image mount point', function() {
|
||||||
|
const result = constraints.isSourceDrive({
|
||||||
|
mountpoints: [
|
||||||
|
{
|
||||||
|
path: '/Volumes/fo'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}, {
|
||||||
|
path: '/Volumes/foo/image.img'
|
||||||
|
});
|
||||||
|
|
||||||
|
m.chai.expect(result).to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
describe('.isDriveLargeEnough()', function() {
|
describe('.isDriveLargeEnough()', function() {
|
||||||
|
|
||||||
it('should return true if the drive size is greater than the image size', function() {
|
it('should return true if the drive size is greater than the image size', function() {
|
||||||
@ -254,48 +463,93 @@ describe('Shared: DriveConstraints', function() {
|
|||||||
|
|
||||||
describe('.isDriveValid()', function() {
|
describe('.isDriveValid()', function() {
|
||||||
|
|
||||||
describe('given drive is large enough', function() {
|
beforeEach(function() {
|
||||||
|
if (process.platform === 'win32') {
|
||||||
|
this.mountpoint = 'E:\\foo';
|
||||||
|
} else {
|
||||||
|
this.mountpoint = '/mnt/foo';
|
||||||
|
}
|
||||||
|
|
||||||
|
this.drive = {
|
||||||
|
device: '/dev/disk2',
|
||||||
|
name: 'My Drive',
|
||||||
|
mountpoints: [
|
||||||
|
{
|
||||||
|
path: this.mountpoint
|
||||||
|
}
|
||||||
|
],
|
||||||
|
size: 4000000000
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('given the drive is locked', function() {
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
this.drive = {
|
|
||||||
device: '/dev/disk2',
|
|
||||||
name: 'My Drive',
|
|
||||||
size: 4000000000
|
|
||||||
};
|
|
||||||
this.image = {
|
|
||||||
path: 'rpi.img',
|
|
||||||
size: 2000000000
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return true if drive is not locked', function() {
|
|
||||||
this.drive.protected = false;
|
|
||||||
m.chai.expect(constraints.isDriveValid(this.drive, this.image)).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return false if drive is locked', function() {
|
|
||||||
this.drive.protected = true;
|
this.drive.protected = true;
|
||||||
m.chai.expect(constraints.isDriveValid(this.drive, this.image)).to.be.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: 5000000000
|
||||||
|
})).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: 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: 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: 2000000000
|
||||||
|
})).to.be.false;
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('given drive is not large enough', function() {
|
describe('given the drive is not locked', function() {
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
this.drive = {
|
this.drive.protected = false;
|
||||||
device: '/dev/disk2',
|
|
||||||
name: 'My Drive',
|
|
||||||
size: 1000000000
|
|
||||||
};
|
|
||||||
this.image = {
|
|
||||||
path: 'rpi.img',
|
|
||||||
size: 2000000000
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return false', function() {
|
it('should return false if the drive is not large enough and is a source drive', function() {
|
||||||
m.chai.expect(constraints.isDriveValid(this.drive, this.image)).to.be.false;
|
m.chai.expect(constraints.isDriveValid(this.drive, {
|
||||||
|
path: path.join(this.mountpoint, 'rpi.img'),
|
||||||
|
size: 5000000000
|
||||||
|
})).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: 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: 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: 2000000000
|
||||||
|
})).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user