mirror of
https://github.com/balena-io/etcher.git
synced 2025-04-24 07:17:18 +00:00
refactor: unify image objects across GUI and image-stream (#1229)
`image-stream` returns image objects that look like this: ```js { stream: <readable stream>, transform: <transform stream>, size: { original: <number>, final: { value: <number>, estimation: <boolean> } }, ... } ``` While the GUI handles image objects that look like this: ```sh { path: <string>, size: <number>, ... } ``` It looks like we should share a common structure between both, so we can use `image-stream` images in `drive-constraints`, for example. Turns out that we actually transform `image-stream` image objects to GUI image objects when the user selects an image using the image selector dialog, which is another indicator that we should normalise this situation. As a solution, this commit does the following: - Add `path` to `image-stream` image object - Reuse `image-stream` image objects in the GUI, given they are a superset of GUI image objects See: https://github.com/resin-io/etcher/pull/1223#discussion_r108165110 Fixes: https://github.com/resin-io/etcher/issues/1232 Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
This commit is contained in:
parent
63901ccf77
commit
802d9abb1d
@ -69,9 +69,7 @@ exports.writeImage = (imagePath, drive, options, onProgress) => {
|
||||
return fs.openAsync(drive.raw, 'rs+');
|
||||
}).then((driveFileDescriptor) => {
|
||||
return imageStream.getFromFilePath(imagePath).then((image) => {
|
||||
if (!image.size.final.estimation && !constraints.isDriveLargeEnough(drive, {
|
||||
size: image.size.final.value
|
||||
})) {
|
||||
if (!constraints.isDriveLargeEnough(drive, image)) {
|
||||
throw errors.createUserError(
|
||||
'The image you selected is too big for this drive',
|
||||
'Please connect a bigger drive and try again'
|
||||
|
@ -146,7 +146,9 @@ SelectionStateModel.service('SelectionStateModel', function(DrivesModel) {
|
||||
return _.get(Store.getState().toJS(), [
|
||||
'selection',
|
||||
'image',
|
||||
'size'
|
||||
'size',
|
||||
'final',
|
||||
'value'
|
||||
]);
|
||||
};
|
||||
|
||||
|
@ -287,10 +287,24 @@ const storeReducer = (state = DEFAULT_STATE, action) => {
|
||||
throw errors.createError('Missing image size');
|
||||
}
|
||||
|
||||
if (!_.isNumber(action.data.size)) {
|
||||
if (!_.isPlainObject(action.data.size)) {
|
||||
throw errors.createError(`Invalid image size: ${action.data.size}`);
|
||||
}
|
||||
|
||||
const MINIMUM_IMAGE_SIZE = 0;
|
||||
|
||||
if (!_.isInteger(action.data.size.original) || action.data.size.original < MINIMUM_IMAGE_SIZE) {
|
||||
throw errors.createError(`Invalid original image size: ${action.data.size.original}`);
|
||||
}
|
||||
|
||||
if (!_.isInteger(action.data.size.final.value) || action.data.size.final.value < MINIMUM_IMAGE_SIZE) {
|
||||
throw errors.createError(`Invalid final image size: ${action.data.size.final.value}`);
|
||||
}
|
||||
|
||||
if (!_.isBoolean(action.data.size.final.estimation)) {
|
||||
throw errors.createError(`Invalid final image size estimation flag: ${action.data.size.final.estimation}`);
|
||||
}
|
||||
|
||||
if (action.data.url && !_.isString(action.data.url)) {
|
||||
throw errors.createError(`Invalid image url: ${action.data.url}`);
|
||||
}
|
||||
|
@ -18,7 +18,6 @@
|
||||
|
||||
const _ = require('lodash');
|
||||
const electron = require('electron');
|
||||
const imageStream = require('../../../../image-stream');
|
||||
const errors = require('../../../../shared/errors');
|
||||
|
||||
module.exports = function($q, SupportedFormatsModel) {
|
||||
@ -47,7 +46,7 @@ module.exports = function($q, SupportedFormatsModel) {
|
||||
* });
|
||||
*/
|
||||
this.selectImage = () => {
|
||||
return $q((resolve, reject) => {
|
||||
return $q((resolve) => {
|
||||
electron.remote.dialog.showOpenDialog(currentWindow, {
|
||||
|
||||
// This variable is set when running in GNU/Linux from
|
||||
@ -73,17 +72,8 @@ module.exports = function($q, SupportedFormatsModel) {
|
||||
// `_.first` is smart enough to not throw and return `undefined`
|
||||
// if we pass it an `undefined` value (e.g: when the selection
|
||||
// dialog was cancelled).
|
||||
const imagePath = _.first(files);
|
||||
return resolve(_.first(files));
|
||||
|
||||
if (!imagePath) {
|
||||
return resolve();
|
||||
}
|
||||
|
||||
return imageStream.getImageMetadata(imagePath).then((metadata) => {
|
||||
metadata.path = imagePath;
|
||||
metadata.size = metadata.size.final.value;
|
||||
return resolve(metadata);
|
||||
}).catch(reject);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
@ -17,7 +17,6 @@
|
||||
'use strict';
|
||||
|
||||
const _ = require('lodash');
|
||||
const fs = require('fs');
|
||||
|
||||
/**
|
||||
* @summary Dropzone directive
|
||||
@ -60,10 +59,7 @@ module.exports = ($timeout) => {
|
||||
|
||||
// Pass the filename as a named
|
||||
// parameter called `$file`
|
||||
$file: {
|
||||
path: filename,
|
||||
size: fs.statSync(filename).size
|
||||
}
|
||||
$file: filename
|
||||
|
||||
});
|
||||
});
|
||||
|
@ -21,6 +21,7 @@ const Bluebird = require('bluebird');
|
||||
const path = require('path');
|
||||
const messages = require('../../../../shared/messages');
|
||||
const errors = require('../../../../shared/errors');
|
||||
const imageStream = require('../../../../image-stream');
|
||||
|
||||
module.exports = function(
|
||||
SupportedFormatsModel,
|
||||
@ -107,6 +108,22 @@ module.exports = function(
|
||||
}).catch(ErrorService.reportException);
|
||||
};
|
||||
|
||||
/**
|
||||
* @summary Select an image by path
|
||||
* @function
|
||||
* @public
|
||||
*
|
||||
* @param {String} imagePath - image path
|
||||
*
|
||||
* @example
|
||||
* ImageSelectionController.selectImageByPath('path/to/image.img');
|
||||
*/
|
||||
this.selectImageByPath = (imagePath) => {
|
||||
imageStream.getImageMetadata(imagePath)
|
||||
.then(this.selectImage)
|
||||
.catch(ErrorService.reportException);
|
||||
};
|
||||
|
||||
/**
|
||||
* @summary Open image selector
|
||||
* @function
|
||||
@ -118,16 +135,16 @@ module.exports = function(
|
||||
this.openImageSelector = () => {
|
||||
AnalyticsService.logEvent('Open image selector');
|
||||
|
||||
OSDialogService.selectImage().then((image) => {
|
||||
OSDialogService.selectImage().then((imagePath) => {
|
||||
|
||||
// Avoid analytics and selection state changes
|
||||
// if no file was resolved from the dialog.
|
||||
if (!image) {
|
||||
if (!imagePath) {
|
||||
AnalyticsService.logEvent('Image selector closed');
|
||||
return;
|
||||
}
|
||||
|
||||
this.selectImage(image);
|
||||
this.selectImageByPath(imagePath);
|
||||
}).catch(ErrorService.reportException);
|
||||
};
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<div class="page-main row around-xs">
|
||||
<div class="col-xs" ng-controller="ImageSelectionController as image">
|
||||
<div class="box text-center relative" os-dropzone="image.selectImage($file)">
|
||||
<div class="box text-center relative" os-dropzone="image.selectImageByPath($file)">
|
||||
|
||||
<svg-icon
|
||||
class="center-block"
|
||||
|
@ -195,6 +195,7 @@ exports.extractImage = (archive, hooks) => {
|
||||
}).then((results) => {
|
||||
results.metadata.stream = results.imageStream;
|
||||
results.metadata.transform = new PassThroughStream();
|
||||
results.metadata.path = archive;
|
||||
|
||||
results.metadata.size = {
|
||||
original: imageEntry.size,
|
||||
|
@ -48,6 +48,7 @@ module.exports = {
|
||||
*/
|
||||
'application/x-bzip2': (file, options) => {
|
||||
return Bluebird.props({
|
||||
path: file,
|
||||
stream: fs.createReadStream(file),
|
||||
size: {
|
||||
original: options.size,
|
||||
@ -76,6 +77,7 @@ module.exports = {
|
||||
'application/gzip': (file, options) => {
|
||||
return gzip.getUncompressedSize(file).then((uncompressedSize) => {
|
||||
return Bluebird.props({
|
||||
path: file,
|
||||
stream: fs.createReadStream(file),
|
||||
size: {
|
||||
original: options.size,
|
||||
@ -109,6 +111,7 @@ module.exports = {
|
||||
});
|
||||
}).then((metadata) => {
|
||||
return {
|
||||
path: file,
|
||||
stream: fs.createReadStream(file),
|
||||
size: {
|
||||
original: options.size,
|
||||
@ -151,6 +154,7 @@ module.exports = {
|
||||
*/
|
||||
'application/octet-stream': (file, options) => {
|
||||
return Bluebird.props({
|
||||
path: file,
|
||||
stream: fs.createReadStream(file),
|
||||
size: {
|
||||
original: options.size,
|
||||
|
@ -142,7 +142,31 @@ exports.isSourceDrive = (drive, image) => {
|
||||
* }
|
||||
*/
|
||||
exports.isDriveLargeEnough = (drive, image) => {
|
||||
return _.get(drive, [ 'size' ], UNKNOWN_SIZE) >= _.get(image, [ 'size' ], UNKNOWN_SIZE);
|
||||
const driveSize = _.get(drive, [ 'size' ], UNKNOWN_SIZE);
|
||||
|
||||
if (_.get(image, [ 'size', 'final', 'estimation' ])) {
|
||||
|
||||
// If the drive size is smaller than the original image size, and
|
||||
// the final image size is just an estimation, then we stop right
|
||||
// here, based on the assumption that the final size will never
|
||||
// be less than the original size.
|
||||
if (driveSize < _.get(image, [ 'size', 'original' ], UNKNOWN_SIZE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the final image size is just an estimation then consider it
|
||||
// large enough. In the worst case, the user gets an error saying
|
||||
// the drive has ran out of space, instead of prohibiting the flash
|
||||
// at all, when the estimation may be wrong.
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
return driveSize >= _.get(image, [
|
||||
'size',
|
||||
'final',
|
||||
'value'
|
||||
], UNKNOWN_SIZE);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -118,7 +118,13 @@ describe('Browser: DrivesModel', function() {
|
||||
SelectionStateModel.removeDrive();
|
||||
SelectionStateModel.setImage({
|
||||
path: this.imagePath,
|
||||
size: 999999999,
|
||||
size: {
|
||||
original: 999999999,
|
||||
final: {
|
||||
estimation: false,
|
||||
value: 999999999
|
||||
}
|
||||
},
|
||||
recommendedDriveSize: 2000000000
|
||||
});
|
||||
});
|
||||
|
@ -221,7 +221,13 @@ describe('Browser: SelectionState', function() {
|
||||
beforeEach(function() {
|
||||
this.image = {
|
||||
path: 'foo.img',
|
||||
size: 999999999,
|
||||
size: {
|
||||
original: 999999999,
|
||||
final: {
|
||||
estimation: false,
|
||||
value: 999999999
|
||||
}
|
||||
},
|
||||
recommendedDriveSize: 1000000000,
|
||||
url: 'https://www.raspbian.org',
|
||||
supportUrl: 'https://www.raspbian.org/forums/',
|
||||
@ -336,7 +342,13 @@ describe('Browser: SelectionState', function() {
|
||||
it('should override the image', function() {
|
||||
SelectionStateModel.setImage({
|
||||
path: 'bar.img',
|
||||
size: 999999999
|
||||
size: {
|
||||
original: 999999999,
|
||||
final: {
|
||||
estimation: false,
|
||||
value: 999999999
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const imagePath = SelectionStateModel.getImagePath();
|
||||
@ -369,7 +381,13 @@ describe('Browser: SelectionState', function() {
|
||||
it('should be able to set an image', function() {
|
||||
SelectionStateModel.setImage({
|
||||
path: 'foo.img',
|
||||
size: 999999999
|
||||
size: {
|
||||
original: 999999999,
|
||||
final: {
|
||||
estimation: false,
|
||||
value: 999999999
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const imagePath = SelectionStateModel.getImagePath();
|
||||
@ -381,7 +399,13 @@ describe('Browser: SelectionState', function() {
|
||||
it('should throw if no path', function() {
|
||||
m.chai.expect(function() {
|
||||
SelectionStateModel.setImage({
|
||||
size: 999999999
|
||||
size: {
|
||||
original: 999999999,
|
||||
final: {
|
||||
estimation: false,
|
||||
value: 999999999
|
||||
}
|
||||
}
|
||||
});
|
||||
}).to.throw('Missing image path');
|
||||
});
|
||||
@ -390,7 +414,13 @@ describe('Browser: SelectionState', function() {
|
||||
m.chai.expect(function() {
|
||||
SelectionStateModel.setImage({
|
||||
path: 123,
|
||||
size: 999999999
|
||||
size: {
|
||||
original: 999999999,
|
||||
final: {
|
||||
estimation: false,
|
||||
value: 999999999
|
||||
}
|
||||
}
|
||||
});
|
||||
}).to.throw('Invalid image path: 123');
|
||||
});
|
||||
@ -403,40 +433,163 @@ describe('Browser: SelectionState', function() {
|
||||
}).to.throw('Missing image size');
|
||||
});
|
||||
|
||||
it('should throw if size is not a number', function() {
|
||||
it('should throw if size is not a plain object', function() {
|
||||
m.chai.expect(function() {
|
||||
SelectionStateModel.setImage({
|
||||
path: 'foo.img',
|
||||
size: '999999999'
|
||||
size: 999999999
|
||||
});
|
||||
}).to.throw('Invalid image size: 999999999');
|
||||
});
|
||||
|
||||
it('should throw if url is defined but its not a string', function() {
|
||||
it('should throw if the original size is not a number', function() {
|
||||
m.chai.expect(function() {
|
||||
SelectionStateModel.setImage({
|
||||
path: 'foo.img',
|
||||
size: 999999999,
|
||||
size: {
|
||||
original: '999999999',
|
||||
final: {
|
||||
estimation: false,
|
||||
value: 999999999
|
||||
}
|
||||
}
|
||||
});
|
||||
}).to.throw('Invalid original image size: 999999999');
|
||||
});
|
||||
|
||||
it('should throw if the original size is a float number', function() {
|
||||
m.chai.expect(function() {
|
||||
SelectionStateModel.setImage({
|
||||
path: 'foo.img',
|
||||
size: {
|
||||
original: 999999999.999,
|
||||
final: {
|
||||
estimation: false,
|
||||
value: 999999999
|
||||
}
|
||||
}
|
||||
});
|
||||
}).to.throw('Invalid original image size: 999999999.999');
|
||||
});
|
||||
|
||||
it('should throw if the original size is negative', function() {
|
||||
m.chai.expect(function() {
|
||||
SelectionStateModel.setImage({
|
||||
path: 'foo.img',
|
||||
size: {
|
||||
original: -1,
|
||||
final: {
|
||||
estimation: false,
|
||||
value: 999999999
|
||||
}
|
||||
}
|
||||
});
|
||||
}).to.throw('Invalid original image size: -1');
|
||||
});
|
||||
|
||||
it('should throw if the final size is not a number', function() {
|
||||
m.chai.expect(function() {
|
||||
SelectionStateModel.setImage({
|
||||
path: 'foo.img',
|
||||
size: {
|
||||
original: 999999999,
|
||||
final: {
|
||||
estimation: false,
|
||||
value: '999999999'
|
||||
}
|
||||
}
|
||||
});
|
||||
}).to.throw('Invalid final image size: 999999999');
|
||||
});
|
||||
|
||||
it('should throw if the final size is a float number', function() {
|
||||
m.chai.expect(function() {
|
||||
SelectionStateModel.setImage({
|
||||
path: 'foo.img',
|
||||
size: {
|
||||
original: 999999999,
|
||||
final: {
|
||||
estimation: false,
|
||||
value: 999999999.999
|
||||
}
|
||||
}
|
||||
});
|
||||
}).to.throw('Invalid final image size: 999999999.999');
|
||||
});
|
||||
|
||||
it('should throw if the final size is negative', function() {
|
||||
m.chai.expect(function() {
|
||||
SelectionStateModel.setImage({
|
||||
path: 'foo.img',
|
||||
size: {
|
||||
original: 999999999,
|
||||
final: {
|
||||
estimation: false,
|
||||
value: -1
|
||||
}
|
||||
}
|
||||
});
|
||||
}).to.throw('Invalid final image size: -1');
|
||||
});
|
||||
|
||||
it('should throw if the final size estimation flag is not a boolean', function() {
|
||||
m.chai.expect(function() {
|
||||
SelectionStateModel.setImage({
|
||||
path: 'foo.img',
|
||||
size: {
|
||||
original: 999999999,
|
||||
final: {
|
||||
estimation: 'false',
|
||||
value: 999999999
|
||||
}
|
||||
}
|
||||
});
|
||||
}).to.throw('Invalid final image size estimation flag: false');
|
||||
});
|
||||
|
||||
it('should throw if url is defined but it\'s not a string', function() {
|
||||
m.chai.expect(function() {
|
||||
SelectionStateModel.setImage({
|
||||
path: 'foo.img',
|
||||
size: {
|
||||
original: 999999999,
|
||||
final: {
|
||||
estimation: false,
|
||||
value: 999999999
|
||||
}
|
||||
},
|
||||
url: 1234
|
||||
});
|
||||
}).to.throw('Invalid image url: 1234');
|
||||
});
|
||||
|
||||
it('should throw if name is defined but its not a string', function() {
|
||||
it('should throw if name is defined but it\'s not a string', function() {
|
||||
m.chai.expect(function() {
|
||||
SelectionStateModel.setImage({
|
||||
path: 'foo.img',
|
||||
size: 999999999,
|
||||
size: {
|
||||
original: 999999999,
|
||||
final: {
|
||||
estimation: false,
|
||||
value: 999999999
|
||||
}
|
||||
},
|
||||
name: 1234
|
||||
});
|
||||
}).to.throw('Invalid image name: 1234');
|
||||
});
|
||||
|
||||
it('should throw if logo is defined but its not a string', function() {
|
||||
it('should throw if logo is defined but it\'s not a string', function() {
|
||||
m.chai.expect(function() {
|
||||
SelectionStateModel.setImage({
|
||||
path: 'foo.img',
|
||||
size: 999999999,
|
||||
size: {
|
||||
original: 999999999,
|
||||
final: {
|
||||
estimation: false,
|
||||
value: 999999999
|
||||
}
|
||||
},
|
||||
logo: 1234
|
||||
});
|
||||
}).to.throw('Invalid image logo: 1234');
|
||||
@ -457,7 +610,13 @@ describe('Browser: SelectionState', function() {
|
||||
|
||||
SelectionStateModel.setImage({
|
||||
path: 'foo.img',
|
||||
size: 9999999999
|
||||
size: {
|
||||
original: 9999999999,
|
||||
final: {
|
||||
estimation: false,
|
||||
value: 9999999999
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
m.chai.expect(SelectionStateModel.hasDrive()).to.be.false;
|
||||
@ -479,7 +638,13 @@ describe('Browser: SelectionState', function() {
|
||||
|
||||
SelectionStateModel.setImage({
|
||||
path: 'foo.img',
|
||||
size: 999999999,
|
||||
size: {
|
||||
original: 999999999,
|
||||
final: {
|
||||
estimation: false,
|
||||
value: 999999999
|
||||
}
|
||||
},
|
||||
recommendedDriveSize: 1500000000
|
||||
});
|
||||
|
||||
@ -515,7 +680,13 @@ describe('Browser: SelectionState', function() {
|
||||
|
||||
SelectionStateModel.setImage({
|
||||
path: imagePath,
|
||||
size: 999999999
|
||||
size: {
|
||||
original: 999999999,
|
||||
final: {
|
||||
estimation: false,
|
||||
value: 999999999
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
m.chai.expect(SelectionStateModel.hasDrive()).to.be.false;
|
||||
@ -542,7 +713,13 @@ describe('Browser: SelectionState', function() {
|
||||
|
||||
SelectionStateModel.setImage({
|
||||
path: 'foo.img',
|
||||
size: 999999999
|
||||
size: {
|
||||
original: 999999999,
|
||||
final: {
|
||||
estimation: false,
|
||||
value: 999999999
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -17,7 +17,6 @@
|
||||
'use strict';
|
||||
|
||||
const m = require('mochainon');
|
||||
const fs = require('fs');
|
||||
const angular = require('angular');
|
||||
require('angular-mocks');
|
||||
|
||||
@ -40,20 +39,11 @@ describe('Browser: OSDropzone', function() {
|
||||
}));
|
||||
|
||||
it('should pass the file back to the callback as $file', function(done) {
|
||||
const statStub = m.sinon.stub(fs, 'statSync');
|
||||
$rootScope.onDropZone = function(file) {
|
||||
statStub.restore();
|
||||
m.chai.expect(file).to.deep.equal({
|
||||
path: '/foo/bar',
|
||||
size: 999999999
|
||||
});
|
||||
m.chai.expect(file).to.deep.equal('/foo/bar');
|
||||
done();
|
||||
};
|
||||
|
||||
statStub.returns({
|
||||
size: 999999999
|
||||
});
|
||||
|
||||
const element = $compile('<div os-dropzone="onDropZone($file)">Drop a file here</div>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
|
||||
@ -73,17 +63,11 @@ describe('Browser: OSDropzone', function() {
|
||||
});
|
||||
|
||||
it('should pass undefined to the callback if not passing $file', function(done) {
|
||||
const statStub = m.sinon.stub(fs, 'statSync');
|
||||
$rootScope.onDropZone = function(file) {
|
||||
statStub.restore();
|
||||
m.chai.expect(file).to.be.undefined;
|
||||
done();
|
||||
};
|
||||
|
||||
statStub.returns({
|
||||
size: 999999999
|
||||
});
|
||||
|
||||
const element = $compile('<div os-dropzone="onDropZone()">Drop a file here</div>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
|
||||
|
@ -43,7 +43,13 @@ describe('Browser: MainPage', function() {
|
||||
|
||||
SelectionStateModel.setImage({
|
||||
path: 'rpi.img',
|
||||
size: 99999
|
||||
size: {
|
||||
original: 99999,
|
||||
final: {
|
||||
estimation: false,
|
||||
value: 99999
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
m.chai.expect(controller.shouldDriveStepBeDisabled()).to.be.false;
|
||||
@ -71,7 +77,13 @@ describe('Browser: MainPage', function() {
|
||||
SelectionStateModel.clear();
|
||||
SelectionStateModel.setImage({
|
||||
path: 'rpi.img',
|
||||
size: 99999
|
||||
size: {
|
||||
original: 99999,
|
||||
final: {
|
||||
estimation: false,
|
||||
value: 99999
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
m.chai.expect(controller.shouldFlashStepBeDisabled()).to.be.true;
|
||||
@ -118,7 +130,13 @@ describe('Browser: MainPage', function() {
|
||||
|
||||
SelectionStateModel.setImage({
|
||||
path: 'rpi.img',
|
||||
size: 99999
|
||||
size: {
|
||||
original: 99999,
|
||||
final: {
|
||||
estimation: false,
|
||||
value: 99999
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
m.chai.expect(controller.shouldFlashStepBeDisabled()).to.be.false;
|
||||
@ -159,7 +177,13 @@ describe('Browser: MainPage', function() {
|
||||
|
||||
SelectionStateModel.setImage({
|
||||
path: path.join(__dirname, 'foo', 'bar.img'),
|
||||
size: 999999999
|
||||
size: {
|
||||
original: 999999999,
|
||||
final: {
|
||||
estimation: false,
|
||||
value: 999999999
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
m.chai.expect(controller.getImageBasename()).to.equal('bar.img');
|
||||
|
@ -47,6 +47,7 @@ describe('ImageStream: BZ2', function() {
|
||||
|
||||
imageStream.getImageMetadata(image).then((metadata) => {
|
||||
m.chai.expect(metadata).to.deep.equal({
|
||||
path: image,
|
||||
size: {
|
||||
original: expectedSize,
|
||||
final: {
|
||||
|
@ -48,6 +48,7 @@ describe('ImageStream: GZ', function() {
|
||||
|
||||
imageStream.getImageMetadata(image).then((metadata) => {
|
||||
m.chai.expect(metadata).to.deep.equal({
|
||||
path: image,
|
||||
size: {
|
||||
original: compressedSize,
|
||||
final: {
|
||||
|
@ -46,6 +46,7 @@ describe('ImageStream: IMG', function() {
|
||||
|
||||
imageStream.getImageMetadata(image).then((metadata) => {
|
||||
m.chai.expect(metadata).to.deep.equal({
|
||||
path: image,
|
||||
size: {
|
||||
original: expectedSize,
|
||||
final: {
|
||||
|
@ -48,6 +48,7 @@ describe('ImageStream: XZ', function() {
|
||||
|
||||
imageStream.getImageMetadata(image).then((metadata) => {
|
||||
m.chai.expect(metadata).to.deep.equal({
|
||||
path: image,
|
||||
size: {
|
||||
original: compressedSize,
|
||||
final: {
|
||||
|
@ -71,6 +71,7 @@ describe('ImageStream: ZIP', function() {
|
||||
|
||||
imageStream.getImageMetadata(image).then((metadata) => {
|
||||
m.chai.expect(metadata).to.deep.equal({
|
||||
path: image,
|
||||
size: {
|
||||
original: expectedSize,
|
||||
final: {
|
||||
|
@ -303,52 +303,219 @@ describe('Shared: DriveConstraints', function() {
|
||||
|
||||
describe('.isDriveLargeEnough()', function() {
|
||||
|
||||
it('should return true if the drive size is greater than the image size', function() {
|
||||
const result = constraints.isDriveLargeEnough({
|
||||
device: '/dev/disk1',
|
||||
name: 'USB Drive',
|
||||
size: 1000000001,
|
||||
protected: false
|
||||
}, {
|
||||
path: 'rpi.img',
|
||||
size: 1000000000
|
||||
});
|
||||
|
||||
m.chai.expect(result).to.be.true;
|
||||
});
|
||||
|
||||
it('should return true if the drive size is equal to the image size', function() {
|
||||
const result = constraints.isDriveLargeEnough({
|
||||
beforeEach(function() {
|
||||
this.drive = {
|
||||
device: '/dev/disk1',
|
||||
name: 'USB Drive',
|
||||
size: 1000000000,
|
||||
protected: false
|
||||
}, {
|
||||
path: 'rpi.img',
|
||||
size: 1000000000
|
||||
});
|
||||
|
||||
m.chai.expect(result).to.be.true;
|
||||
};
|
||||
});
|
||||
|
||||
it('should return false if the drive size is less than the image size', function() {
|
||||
const result = constraints.isDriveLargeEnough({
|
||||
device: '/dev/disk1',
|
||||
name: 'USB Drive',
|
||||
size: 1000000000,
|
||||
protected: false
|
||||
}, {
|
||||
path: 'rpi.img',
|
||||
size: 1000000001
|
||||
describe('given the final image size estimation flag is false', function() {
|
||||
|
||||
describe('given the original size is less than the drive size', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
this.image = {
|
||||
path: path.join(__dirname, 'rpi.img'),
|
||||
size: {
|
||||
original: this.drive.size - 1,
|
||||
final: {
|
||||
estimation: false
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
it('should return true if the final size is less than the drive size', function() {
|
||||
this.image.size.final.value = this.drive.size - 1;
|
||||
m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.true;
|
||||
});
|
||||
|
||||
it('should return true if the final size is equal to the drive size', function() {
|
||||
this.image.size.final.value = this.drive.size;
|
||||
m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.true;
|
||||
});
|
||||
|
||||
it('should return false if the final size is greater than the drive size', function() {
|
||||
this.image.size.final.value = this.drive.size + 1;
|
||||
m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.false;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('given the original size is equal to the drive size', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
this.image = {
|
||||
path: path.join(__dirname, 'rpi.img'),
|
||||
size: {
|
||||
original: this.drive.size,
|
||||
final: {
|
||||
estimation: false
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
it('should return true if the final size is less than the drive size', function() {
|
||||
this.image.size.final.value = this.drive.size - 1;
|
||||
m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.true;
|
||||
});
|
||||
|
||||
it('should return true if the final size is equal to the drive size', function() {
|
||||
this.image.size.final.value = this.drive.size;
|
||||
m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.true;
|
||||
});
|
||||
|
||||
it('should return false if the final size is greater than the drive size', function() {
|
||||
this.image.size.final.value = this.drive.size + 1;
|
||||
m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.false;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('given the original size is greater than the drive size', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
this.image = {
|
||||
path: path.join(__dirname, 'rpi.img'),
|
||||
size: {
|
||||
original: this.drive.size + 1,
|
||||
final: {
|
||||
estimation: false
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
it('should return true if the final size is less than the drive size', function() {
|
||||
this.image.size.final.value = this.drive.size - 1;
|
||||
m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.true;
|
||||
});
|
||||
|
||||
it('should return true if the final size is equal to the drive size', function() {
|
||||
this.image.size.final.value = this.drive.size;
|
||||
m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.true;
|
||||
});
|
||||
|
||||
it('should return false if the final size is greater than the drive size', function() {
|
||||
this.image.size.final.value = this.drive.size + 1;
|
||||
m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.false;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('given the final image size estimation flag is true', function() {
|
||||
|
||||
describe('given the original size is less than the drive size', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
this.image = {
|
||||
path: path.join(__dirname, 'rpi.img'),
|
||||
size: {
|
||||
original: this.drive.size - 1,
|
||||
final: {
|
||||
estimation: true
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
it('should return true if the final size is less than the drive size', function() {
|
||||
this.image.size.final.value = this.drive.size - 1;
|
||||
m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.true;
|
||||
});
|
||||
|
||||
it('should return true if the final size is equal to the drive size', function() {
|
||||
this.image.size.final.value = this.drive.size;
|
||||
m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.true;
|
||||
});
|
||||
|
||||
it('should return true if the final size is greater than the drive size', function() {
|
||||
this.image.size.final.value = this.drive.size + 1;
|
||||
m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.true;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('given the original size is equal to the drive size', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
this.image = {
|
||||
path: path.join(__dirname, 'rpi.img'),
|
||||
size: {
|
||||
original: this.drive.size,
|
||||
final: {
|
||||
estimation: true
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
it('should return true if the final size is less than the drive size', function() {
|
||||
this.image.size.final.value = this.drive.size - 1;
|
||||
m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.true;
|
||||
});
|
||||
|
||||
it('should return true if the final size is equal to the drive size', function() {
|
||||
this.image.size.final.value = this.drive.size;
|
||||
m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.true;
|
||||
});
|
||||
|
||||
it('should return true if the final size is greater than the drive size', function() {
|
||||
this.image.size.final.value = this.drive.size + 1;
|
||||
m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.true;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('given the original size is greater than the drive size', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
this.image = {
|
||||
path: path.join(__dirname, 'rpi.img'),
|
||||
size: {
|
||||
original: this.drive.size + 1,
|
||||
final: {
|
||||
estimation: true
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
it('should return false if the final size is less than the drive size', function() {
|
||||
this.image.size.final.value = this.drive.size - 1;
|
||||
m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.false;
|
||||
});
|
||||
|
||||
it('should return false if the final size is equal to the drive size', function() {
|
||||
this.image.size.final.value = this.drive.size;
|
||||
m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.false;
|
||||
});
|
||||
|
||||
it('should return false if the final size is greater than the drive size', function() {
|
||||
this.image.size.final.value = this.drive.size + 1;
|
||||
m.chai.expect(constraints.isDriveLargeEnough(this.drive, this.image)).to.be.false;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
m.chai.expect(result).to.be.false;
|
||||
});
|
||||
|
||||
it('should return false if the drive is undefined', function() {
|
||||
const result = constraints.isDriveLargeEnough(undefined, {
|
||||
path: 'rpi.img',
|
||||
size: 1000000000
|
||||
path: path.join(__dirname, 'rpi.img'),
|
||||
size: {
|
||||
original: 1000000000,
|
||||
final: {
|
||||
estimation: false,
|
||||
value: 1000000000
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
m.chai.expect(result).to.be.false;
|
||||
@ -381,7 +548,7 @@ describe('Shared: DriveConstraints', function() {
|
||||
size: 2000000001,
|
||||
protected: false
|
||||
}, {
|
||||
path: 'rpi.img',
|
||||
path: path.join(__dirname, 'rpi.img'),
|
||||
size: 1000000000,
|
||||
recommendedDriveSize: 2000000000
|
||||
});
|
||||
@ -396,7 +563,7 @@ describe('Shared: DriveConstraints', function() {
|
||||
size: 2000000000,
|
||||
protected: false
|
||||
}, {
|
||||
path: 'rpi.img',
|
||||
path: path.join(__dirname, 'rpi.img'),
|
||||
size: 1000000000,
|
||||
recommendedDriveSize: 2000000000
|
||||
});
|
||||
@ -411,7 +578,7 @@ describe('Shared: DriveConstraints', function() {
|
||||
size: 2000000000,
|
||||
protected: false
|
||||
}, {
|
||||
path: 'rpi.img',
|
||||
path: path.join(__dirname, 'rpi.img'),
|
||||
size: 1000000000,
|
||||
recommendedDriveSize: 2000000001
|
||||
});
|
||||
@ -426,7 +593,7 @@ describe('Shared: DriveConstraints', function() {
|
||||
size: 2000000000,
|
||||
protected: false
|
||||
}, {
|
||||
path: 'rpi.img',
|
||||
path: path.join(__dirname, 'rpi.img'),
|
||||
size: 1000000000
|
||||
});
|
||||
|
||||
@ -435,7 +602,7 @@ describe('Shared: DriveConstraints', function() {
|
||||
|
||||
it('should return false if the drive is undefined', function() {
|
||||
const result = constraints.isDriveSizeRecommended(undefined, {
|
||||
path: 'rpi.img',
|
||||
path: path.join(__dirname, 'rpi.img'),
|
||||
size: 1000000000,
|
||||
recommendedDriveSize: 1000000000
|
||||
});
|
||||
@ -491,28 +658,52 @@ describe('Shared: DriveConstraints', 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, {
|
||||
path: path.join(this.mountpoint, 'rpi.img'),
|
||||
size: 5000000000
|
||||
size: {
|
||||
original: 5000000000,
|
||||
final: {
|
||||
estimation: false,
|
||||
value: 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
|
||||
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: 2000000000
|
||||
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: 2000000000
|
||||
size: {
|
||||
original: 2000000000,
|
||||
final: {
|
||||
estimation: false,
|
||||
value: 2000000000
|
||||
}
|
||||
}
|
||||
})).to.be.false;
|
||||
});
|
||||
|
||||
@ -527,28 +718,52 @@ describe('Shared: DriveConstraints', 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, {
|
||||
path: path.join(this.mountpoint, 'rpi.img'),
|
||||
size: 5000000000
|
||||
size: {
|
||||
original: 5000000000,
|
||||
final: {
|
||||
estimation: false,
|
||||
value: 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
|
||||
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: 2000000000
|
||||
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: 2000000000
|
||||
size: {
|
||||
original: 2000000000,
|
||||
final: {
|
||||
estimation: false,
|
||||
value: 2000000000
|
||||
}
|
||||
}
|
||||
})).to.be.true;
|
||||
});
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user