Comparar commits

..

14 Commits

Autor SHA1 Mensagem Data
Brian Broll 4da87b5806 v0.22.0 2016-12-20 12:21:54 -06:00
Brian Broll f73d9d6958 Updated to webgme v2.8.0. Fixes #936 (#941)
* WIP #936 Added webgme-executor-worker

* WIP #936 Updated start-worker.js

* WIP #936 Fixed bug in class generation
2016-12-20 12:14:26 -06:00
Brian Broll fd96d41698 Fixed ValidateArch tests and cleaned up npm scripts. Fixes #939 (#940)
* WIP #939 improved the validate arch plugin

* WIP #939 cleaned up npm scripts
2016-12-20 11:47:13 -06:00
Brian Broll 7ccf8dafc4 Removed tmp dir used for arch validation. Fixes #929 (#930)
* WIP #929 Removed tmp dir after arch validation

* WIP #929 Added test for mkdir/rmdir of tmp dir

* WIP #929 Fixed tests

* WIP #929 Refactored cli tests

* WIP #929 Increased timeout to 3000

* WIP #929 Added logs to help debug travis

* WIP #929 Added more logs

* WIP typo in console log

* WIP #929 Trying webgme-simple-nodes patch

* WIP added assertion to only execute callback once

* WIP removed old logs and updated the dependency

* WIP #929 Removed debug logs and set torch installation to true

* WIP #929 removed extra debug logs
2016-12-19 22:35:03 -06:00
Brian Broll 2ea4f71a1a Updated input/ptr delete action to deselect. Fixes #937 (#938)
* Updated input/ptr delete action to deselect. Fixes #937

* WIP #937 Fixed test

No idea why it broke here... This change should have had nothing to
do with this test...
2016-12-19 19:49:36 -06:00
Brian Broll e702f5cef0 Fixed child process group management and termination. Fixes #934 (#935)
* WIP #934 Added cleanup fn

* WIP #934 Fixed group termination

* WIP #934 Fixed exit code when canceled (SIGINT)

* WIP #934 Added SIGINT exit code
2016-12-19 19:00:08 -06:00
Brian Broll 24d8a02fff Fixed getUniqueName to filter null children. Fixes #932 (#933) 2016-12-11 22:42:53 -06:00
Brian Broll 1917f71856 Added support for validating custom layers. Fixes #928 (#931)
* Added support for validating custom layers. Fixes #928

* WIP #928 Added test for validating custom layers

* WIP #928 Updated torch mock for custom layer
2016-12-10 13:27:53 -06:00
Brian Broll 81e1622621 Added starter kit link to the additional resources 2016-12-10 11:58:00 -06:00
Brian Broll 2e9e5e7889 Updated gitter for the new channel 2016-12-08 16:05:16 -06:00
Brian Broll 017223945f Removed lineOffset from operation attrs in exec. Fixes #924 (#925)
* Removed lineOffset from operation attrs in exec. Fixes #924

* WIP #924 replaced hard coded string with constant
2016-12-07 20:18:57 -06:00
Brian Broll 735cbd4e73 added additional resource links 2016-12-06 21:50:09 -06:00
Brian Broll eef307476d Updated badges urls for the organization transfer (#921) 2016-12-06 15:37:54 -06:00
Brian Broll ae37e17cae Added layer validation and visual cues on error. Fixes #915 (#920)
* WIP #915 Added layer validation plugin

* WIP #915 Validate plugin on territory update (1.5s delay)

* WIP #915 Added validation plugin

* WIP #915 Fixed multiple layer check at once and cleaned msg

* WIP #915 Changed from 'warn' to 'error'

* WIP #915 Fixed flickering issue

* WIP #915 decreased validation delay

* WIP #915 graceful failing if th not installed

* WIP #915 updated for unsupported server side

* WIP #915 Added validation plugin test

* WIP can't seem to push to github...

* WIP removed stupid tmp file
2016-12-06 14:43:59 -06:00
18 arquivos alterados com 578 adições e 95 exclusões
+11 -3
Ver Arquivo
@@ -1,8 +1,8 @@
[![Release State](https://img.shields.io/badge/state-beta-yellow.svg)](https://img.shields.io/badge/state-beta-yellow.svg)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](./LICENSE)
[![Build Status](https://travis-ci.org/dfst/deepforge.svg?branch=master)](https://travis-ci.org/dfst/deepforge)
[![Join the chat at https://gitter.im/dfst/deepforge](https://badges.gitter.im/dfst/deepforge.svg)](https://gitter.im/dfst/deepforge?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Stories in Ready](https://badge.waffle.io/dfst/deepforge.png?label=ready&title=Ready)](https://waffle.io/dfst/deepforge)
[![Build Status](https://travis-ci.org/deepforge-dev/deepforge.svg?branch=master)](https://travis-ci.org/deepforge-dev/deepforge)
[![Join the chat at https://gitter.im/deepforge-dev/deepforge](https://badges.gitter.im/deepforge-dev/deepforge.svg)](https://gitter.im/deepforge-dev/deepforge?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Stories in Ready](https://badge.waffle.io/deepforge-dev/deepforge.png?label=ready&title=Ready)](https://waffle.io/deepforge-dev/deepforge)
**Notice**: DeepForge is still a work in progress and in beta! That being said, any contributions and/or feedback is greatly appreciated. If you have any questions, check out the [wiki](https://github.com/dfst/deepforge/wiki/) or drop me a line on the gitter!
@@ -40,6 +40,14 @@ Finally, start deepforge with `deepforge start`and navigate to [http://localhost
Also, be sure to check out the other available features of the `deepforge` cli; it can be used to update, manage your torch installation, uninstall deepforge and run individual components!
## Additional Resources
- [Intro to DeepForge Slides](https://docs.google.com/presentation/d/10_y5O3gHXSATfjHVLJg7dOdrz-tAXNWjlxhJ5SlA0ic/edit?usp=sharing)
- [wiki](https://github.com/deepforge-dev/deepforge/wiki) containing overview, installation, configuration and developer information
- [Starter Kit](https://github.com/deepforge-dev/examples/tree/master/starterkit) containing example pipelines demonstrating various deepforge features
- [Examples](https://github.com/deepforge-dev/examples)
- [Datamodel Developer Slides](https://docs.google.com/presentation/d/1hd3IyUlzW_TIPnzCnE-1pdz00Pw8WaIxYiOW_Hyog-M/edit#slide=id.p)
## Interested in contributing?
Contributions are welcome! Either fork the project and submit some PR's or shoot me an email about getting more involved!
+3 -14
Ver Arquivo
@@ -6,8 +6,7 @@ var path = require('path'),
spawn = childProcess.spawn,
rm_rf = require('rimraf'),
projectConfig = require(__dirname + '/../config'),
executorSrc = path.join(__dirname, '..', 'node_modules', 'webgme', 'src',
'server', 'middleware', 'executor', 'worker'),
executorSrc = path.join(__dirname, '..', 'node_modules', '.bin', 'webgme-executor-worker'),
id = Date.now(),
workerRootPath = process.env.DEEPFORGE_WORKER_DIR || path.join(__dirname, '..', 'src', 'worker'),
workerPath = path.join(workerRootPath, `worker_${id}`),
@@ -60,7 +59,7 @@ var startExecutor = function() {
// Start the executor
var execJob = spawn('node', [
'node_worker.js',
executorSrc,
workerConfigPath,
workerTmp
]);
@@ -80,14 +79,4 @@ var createConfigJson = function() {
fs.writeFile(workerConfigPath, JSON.stringify(config), startExecutor);
};
process.chdir(executorSrc);
fs.mkdir(workerTmp, function() {
// npm install in this directory
var npmInstall = spawn('npm', ['install']);
npmInstall.stdout.pipe(process.stdout);
npmInstall.stderr.pipe(process.stderr);
npmInstall.on('close', function() {
createConfigJson();
});
});
fs.mkdir(workerTmp, createConfigJson);
+5 -4
Ver Arquivo
@@ -8,18 +8,18 @@
"start-dev": "NODE_ENV=dev node app.js",
"local": "node ./bin/start-local.js",
"worker": "node ./bin/start-worker.js",
"test": "mkdir ./test-tmp; node ./node_modules/mocha/bin/mocha --recursive test",
"watch-test": "./node_modules/nodemon/bin/nodemon.js --exec 'node ./node_modules/mocha/bin/mocha --recursive test'",
"test": "mkdir ./test-tmp; mocha --recursive test",
"watch-test": "nodemon --exec 'mocha --recursive test'",
"build-nn": "node ./utils/nn-parser.js"
},
"version": "0.21.0",
"version": "0.22.0",
"dependencies": {
"commander": "^2.9.0",
"dotenv": "^2.0.0",
"exists-file": "^2.1.0",
"express": "^4.14.0",
"lodash.difference": "^4.1.2",
"graceful-fs": "^4.1.10",
"lodash.difference": "^4.1.2",
"lodash.merge": "^4.5.1",
"mongodb": "^2.2.10",
"nodemon": "^1.9.2",
@@ -30,6 +30,7 @@
"webgme-breadcrumbheader": "^2.1.1",
"webgme-chflayout": "^2.0.0",
"webgme-easydag": "dfst/webgme-easydag",
"webgme-executor-worker": "^1.0.1",
"webgme-fab": "dfst/webgme-fab",
"webgme-simple-nodes": "^2.1.0"
},
+3 -1
Ver Arquivo
@@ -83,7 +83,9 @@ define([
exists = {},
i = 2;
children.forEach(child => exists[child.getAttribute('name')] = true);
children
.filter(child => child !== null)
.forEach(child => exists[child.getAttribute('name')] = true);
while (exists[name]) {
name = basename + '_' + i;
+3 -3
Ver Arquivo
@@ -73,17 +73,17 @@ define([
classNodes = metanodes.filter(node => {
var base = this.core.getBase(node),
baseId = this.core.getPath(base),
baseId,
count = 1;
// Count the sets back to a class node
while (base) {
baseId = this.core.getPath(base);
if (isClass[baseId]) {
inheritanceLvl[this.core.getPath(node)] = count;
return true;
}
base = this.core.getBase(base);
baseId = this.core.getPath(base);
count++;
}
@@ -285,7 +285,7 @@ define([
};
ExecuteJob.prototype.createAttributeFile = function (node, files) {
var skip = ['code', 'stdout', 'execFiles', 'jobId', 'secret'],
var skip = ['code', 'stdout', 'execFiles', 'jobId', 'secret', CONSTANTS.LINE_OFFSET],
numOrBool = /^(-?\d+\.?\d*((e|e-)\d+)?|(true|false))$/,
table;
+34 -3
Ver Arquivo
@@ -74,7 +74,7 @@ requirejs([
var checkFinished = () => {
if (exitCode !== null && remainingImageCount === 0) {
log('finished!');
process.exit(exitCode);
cleanup();
}
};
@@ -201,14 +201,45 @@ requirejs([
// Download the large files
var inputData = JSON.parse(fs.readFileSync('./input-data.json')),
inputPaths = Object.keys(inputData);
inputPaths = Object.keys(inputData),
pid,
job,
cleanup;
// Make sure to kill the spawned process group on exit
cleanup = function() {
if (job) {
pid = job.pid;
job = null;
log(`killing process group: ${pid}`);
process.kill(-pid, 'SIGTERM');
if (exitCode !== null) {
log(`exiting w/ code ${exitCode}`);
process.exit(exitCode);
}
}
};
process.on('exit', () => {
log('received "exit" event')
cleanup();
});
process.on('SIGINT', function() {
log('received "SIGINT" event')
cleanup();
process.exit(130);
});
process.on('uncaughtException', () => {
log('received "uncaughtException" event')
cleanup();
});
// Request the data from the blob
prepareCache()
.then(() => Q.all(inputPaths.map(ipath => getData(ipath, inputData[ipath]))))
.then(() => {
// Run 'th init.lua' and merge the stdout, stderr
var job = spawn('th', ['init.lua']);
job = spawn('th', ['init.lua'], {detached: true});
job.stdout.on('data', onStdout);
job.stderr.on('data', onStderr);
job.on('close', code => {
@@ -49,6 +49,11 @@ define([
this.LayerDict = createLayerDict(this.core, this.META);
this.uniqueId = 2;
this.varnames = {net: true};
this.definitions = [
'require \'nn\'',
'require \'rnn\''
];
return PluginBase.prototype.main.apply(this, arguments);
};
@@ -71,11 +76,6 @@ define([
result = {},
code = '';
this.definitions = [
'require \'nn\'',
'require \'rnn\''
];
// Add an index to each layer
layers.forEach((l, index) => l[INDEX] = index);
@@ -460,7 +460,7 @@ define([
classNodes = metanodes.filter(node => {
var base = this.core.getBase(node),
baseId = this.core.getPath(base),
baseId,
deps = [],
name,
count = 1;
@@ -468,6 +468,7 @@ define([
// Count the sets back to a class node
while (base) {
deps.push(this.core.getAttribute(base, 'name'));
baseId = this.core.getPath(base);
if (isClass[baseId]) {
inheritanceLvl[this.core.getPath(node)] = count;
name = this.core.getAttribute(node, 'name');
@@ -475,7 +476,6 @@ define([
return true;
}
base = this.core.getBase(base);
baseId = this.core.getPath(base);
count++;
}
@@ -0,0 +1,194 @@
/*globals define*/
/*jshint node:true, browser:true*/
define([
'plugin/GenerateArchitecture/GenerateArchitecture/GenerateArchitecture',
'SimpleNodes/Constants',
'text!./metadata.json',
'q',
'fs',
'path',
'child_process',
'rimraf'
], function (
PluginBase,
SimpleNodeConstants,
pluginMetadata,
Q,
fs,
path,
childProcess,
rm_rf
) {
'use strict';
pluginMetadata = JSON.parse(pluginMetadata);
/**
* Initializes a new instance of ValidateArchitecture.
* @class
* @augments {PluginBase}
* @classdesc This class represents the plugin ValidateArchitecture.
* @constructor
*/
var TMP_DIR = '/tmp',
spawn = childProcess.spawn,
GET_ARG_INDEX = /argument #([0-9]+) to/,
TORCH_INSTALLED = true;
var ValidateArchitecture = function () {
// Call base class' constructor.
PluginBase.call(this);
this.pluginMetadata = pluginMetadata;
};
/**
* Metadata associated with the plugin. Contains id, name, version, description, icon, configStructue etc.
* This is also available at the instance at this.pluginMetadata.
* @type {object}
*/
ValidateArchitecture.metadata = pluginMetadata;
// Prototypical inheritance from PluginBase.
ValidateArchitecture.prototype = Object.create(PluginBase.prototype);
ValidateArchitecture.prototype.constructor = ValidateArchitecture;
ValidateArchitecture.prototype.main = function (callback) {
var name = this.core.getAttribute(this.activeNode, 'name');
this._callback = callback;
// make the tmp dir
this._tmpFileId = path.join(TMP_DIR, `${name}_${Date.now()}`);
fs.mkdir(this._tmpFileId, err => {
if (err) throw err;
return PluginBase.prototype.main.call(this, callback);
});
};
ValidateArchitecture.prototype.createOutputFiles = function (tree) {
var layers = tree[SimpleNodeConstants.CHILDREN],
tests = [],
id;
if (!TORCH_INSTALLED) {
return this.validationFinished();
}
// Generate code for each layer
this.layerName = {};
for (var i = layers.length; i--;) {
id = layers[i][SimpleNodeConstants.NODE_PATH];
this.layerName[id] = layers[i].name;
tests.push([id, this.createLayerTestCode(layers[i])]);
}
// Run each code snippet
this.validateLayers(tests)
.then(errors => this.validationFinished(errors))
.fail(err => this.logger.error(`validation failed: ${err}`));
};
ValidateArchitecture.prototype.validationFinished = function (errors) {
if (!TORCH_INSTALLED) {
this.logger.warn('Torch is not installed. Architecture validation is not supported.');
} else {
this.logger.info(`found ${errors.length} validation errors`);
}
this.createMessage(null, {
errors: TORCH_INSTALLED ? errors : null
});
this.result.setSuccess(true);
this._callback(null, this.result);
};
ValidateArchitecture.prototype.createLayerTestCode = function (layer) {
var customLayerDefs = this.genLayerDefinitions([layer]);
return this.definitions.concat([
customLayerDefs,
this.createLayer(layer)
]).join('\n');
};
ValidateArchitecture.prototype.validateLayers = function (layerTests) {
return Q.all(layerTests.map(layer => this.validateLayer(layer[0], layer[1])))
.then(results => Q.nfcall(rm_rf, this._tmpFileId)
.then(() => results.filter(result => !!result))
);
};
ValidateArchitecture.prototype.validateLayer = function (id, code) {
var deferred = Q.defer(),
tmpPath = path.join(this._tmpFileId, id.replace(/[^a-zA-Z\d]+/g, '_'));
if (!TORCH_INSTALLED) {
deferred.resolve(null);
} else {
// Write to a temp file
fs.writeFile(tmpPath, code, err => {
var job,
stderr = '',
stdout = '';
if (err) {
return deferred.reject(`Could not create tmp file at ${tmpPath}: ${err}`);
}
// Run the file
job = spawn('th', [tmpPath]);
job.stderr.on('data', data => stderr += data.toString());
job.stdout.on('data', data => stdout += data.toString());
job.on('error', err => {
if (err.code === 'ENOENT') {
TORCH_INSTALLED = false;
}
});
job.on('close', code => {
if (code === 0) {
deferred.resolve(null);
} else {
// If it errored, clean the error and return it
deferred.resolve(this.parseError(id, stderr));
}
});
});
}
return deferred.promise;
};
ValidateArchitecture.prototype.parseError = function (id, stderr) {
var msg = stderr
.split('\n').shift() // first line
.replace(/^[^:]*: /, '') // remove the file path
.replace(/ at [^ ]*\)/, ')') // remove last line number
.replace(/ to '\?'/, ''); // remove unknown symbol
// convert 'bad argument #[num]' to the argument name
if (msg.indexOf('bad argument') === 0) {
var layerName = this.layerName[id],
args = this.LayerDict[layerName].args,
argIndex = +(stderr.match(GET_ARG_INDEX)[1]),
argName = args[argIndex-1].name;
// FIXME: This is not the correct index...
// This is the index for the incorrect argument passed to the
// tensor...
msg = msg.replace(`#${argIndex}`, `"${argName}"`);
}
return {
id: id,
msg: msg
};
};
ValidateArchitecture.prototype._saveOutput = function () {};
// for testing
ValidateArchitecture.prototype.setTorchInstalled = function (value) {
TORCH_INSTALLED = !!value;
};
return ValidateArchitecture;
});
@@ -0,0 +1,14 @@
{
"id": "ValidateArchitecture",
"name": "ValidateArchitecture",
"version": "0.1.0",
"description": "",
"icon": {
"class": "glyphicon glyphicon-cog",
"src": ""
},
"disableServerSideExecution": false,
"disableBrowserSideExecution": true,
"writeAccessRequired": false,
"configStructure": []
}
Arquivo binário não exibido.
@@ -7,14 +7,16 @@ define([
'deepforge/viz/panels/ThumbnailControl',
'js/NodePropertyNames',
'js/Utils/ComponentSettings',
'underscore'
'underscore',
'q'
], function (
Constants,
DeepForge,
ThumbnailControl,
nodePropertyNames,
ComponentSettings,
_
_,
Q
) {
'use strict';
@@ -36,6 +38,7 @@ define([
ThumbnailControl.call(this, options);
this._config = DEFAULT_CONFIG;
ComponentSettings.resolveWithWebGMEGlobal(this._config, this.getComponentId());
this.validateLayers = _.debounce(() => this.validateArchitecture(), 500);
};
_.extend(ArchEditorControl.prototype, ThumbnailControl.prototype);
@@ -248,5 +251,28 @@ define([
this._client.completeTransaction();
};
ArchEditorControl.prototype._eventCallback = function() {
ThumbnailControl.prototype._eventCallback.apply(this, arguments);
this.validateLayers();
};
ArchEditorControl.prototype.validateArchitecture = function() {
var pluginId = 'ValidateArchitecture',
context = this._client.getCurrentPluginContext(pluginId);
this._logger.info('about to validate arch');
// Run the plugin in the browser (set namespace)
context.managerConfig.namespace = 'nn';
context.pluginConfig = {};
Q.ninvoke(this._client, 'runServerPlugin', pluginId, context)
.then(res => {
var results = res.messages[0].message;
if (results.errors !== null) {
this._widget.displayErrors(results.errors);
}
})
.fail(err => this._logger.warn(`Validation failed: ${err}`));
};
return ArchEditorControl;
});
@@ -42,6 +42,7 @@ define([
}
ThumbnailWidget.apply(this, arguments);
this._emptyMsg = 'Click to add a new layer';
this.hasError = {};
};
_.extend(ArchEditorWidget.prototype, ThumbnailWidget.prototype);
@@ -223,5 +224,28 @@ define([
.then(selected => this.insertLayer(selected.node.id, item.id));
};
ArchEditorWidget.prototype.displayErrors = function(errors) {
// For each of the errors, highlight the given nodes
var oldErrored = Object.keys(this.hasError),
currentErrored = errors.map(err => err.id),
newErrored = _.difference(currentErrored, oldErrored),
fixedLayers = _.difference(oldErrored, currentErrored);
this._logger.info('updating displayed errors to', currentErrored);
this.hasError = {};
newErrored.forEach(id => {
if (this.items[id]) {
this.items[id].decorator.highlight('red');
this.hasError[id] = true;
}
});
fixedLayers.forEach(id => {
if (this.items[id]) {
this.items[id].clear();
}
});
};
return ArchEditorWidget;
});
@@ -86,6 +86,7 @@ define([
} else {
this.deleteNode(item.id);
}
this.selectionManager.deselect();
};
return {
+49 -48
Ver Arquivo
@@ -1,58 +1,59 @@
var mockery = require('mockery'),
assert = require('assert'),
path = require('path'),
nop = () => {},
cli;
describe('cli', function() {
var mockery = require('mockery'),
assert = require('assert'),
path = require('path'),
nop = () => {},
cli;
var callRegister = {
childProcess: {
execSync: []
}
};
var mocks = {
childProcess: {},
rimraf: {}
};
var childProcess = {
execSync: function(cmd) {
callRegister.childProcess.execSync.push(cmd);
if (mocks.childProcess.execSync) {
return mocks.childProcess.execSync.apply(this, arguments);
var callRegister = {
childProcess: {
execSync: []
}
},
spawnSync: function(cmd) {
if (cmd === 'luarocks') {
};
var mocks = {
childProcess: {},
rimraf: {}
};
var childProcess = {
execSync: function(cmd) {
callRegister.childProcess.execSync.push(cmd);
if (mocks.childProcess.execSync) {
return mocks.childProcess.execSync.apply(this, arguments);
}
},
spawnSync: function(cmd) {
if (cmd === 'luarocks') {
return {
stdout: 'rnn'
};
}
return {};
},
spawn: function() {
if (mocks.childProcess.spawn) {
mocks.childProcess.spawn.apply(this, arguments);
}
return {
stdout: 'rnn'
on: () => {},
stdout: {
on: () => {}
},
stderr: {
on: () => {}
}
};
}
return {};
},
spawn: function() {
if (mocks.childProcess.spawn) {
mocks.childProcess.spawn.apply(this, arguments);
};
var rimraf = {};
rimraf.sync = function() {
if (mocks.rimraf.sync) {
mocks.rimraf.sync.apply(this, arguments);
}
return {
on: () => {},
stdout: {
on: () => {}
},
stderr: {
on: () => {}
}
};
}
};
var rimraf = {};
rimraf.sync = function() {
if (mocks.rimraf.sync) {
mocks.rimraf.sync.apply(this, arguments);
}
};
};
describe('cli', function() {
before(function() {
// create the mocks
mockery.enable({
@@ -5,6 +5,7 @@ describe('GenerateExecFile', function () {
var testFixture = require('../../globals'),
lua = require('../../../src/common/lua'),
path = testFixture.path,
assert = require('assert'),
SEED_DIR = path.join(testFixture.DF_SEED_DIR, 'devProject'),
gmeConfig = testFixture.getGmeConfig(),
expect = testFixture.expect,
@@ -139,19 +140,23 @@ describe('GenerateExecFile', function () {
expect(data).to.equal(saveData);
done();
});
torch.set('class', (name) => {
var cntr = context._G,
classes,
newClass = lua.newContext()._G;
torch.set('class', name => {
try {
var cntr = context._G,
classes,
newClass = lua.newContext()._G;
if (name.includes('.')) {
classes = name.split('.');
name = classes.pop();
for (var i = 0; i < classes.length; i++) {
cntr = cntr.get(classes[i]);
if (name.includes('.')) {
classes = name.split('.');
name = classes.pop();
for (var i = 0; i < classes.length; i++) {
cntr = cntr.get(classes[i]) || cntr;
}
}
cntr.set(name, newClass);
} catch(e) {
assert(!e, `Failed defining class ${name}: ${e}`);
}
cntr.set(name, newClass);
return newClass;
});
context._G.set('torch', torch);
@@ -0,0 +1,183 @@
/*jshint node:true, mocha:true*/
'use strict';
var testFixture = require('../../globals');
describe('ValidateArchitecture', function () {
var gmeConfig = testFixture.getGmeConfig(),
expect = testFixture.expect,
fs = require('fs'),
rm_rf = require('rimraf'),
mockery = require('mockery'),
logger = testFixture.logger.fork('ValidateArchitecture'),
PluginCliManager = testFixture.WebGME.PluginCliManager,
manager = new PluginCliManager(null, logger, gmeConfig),
projectName = 'testProject',
pluginName = 'ValidateArchitecture',
project,
gmeAuth,
storage,
commitHash;
before(function (done) {
testFixture.clearDBAndGetGMEAuth(gmeConfig, projectName)
.then(function (gmeAuth_) {
gmeAuth = gmeAuth_;
// This uses in memory storage. Use testFixture.getMongoStorage to persist test to database.
storage = testFixture.getMemoryStorage(logger, gmeConfig, gmeAuth);
return storage.openDatabase();
})
.then(function () {
var importParam = {
projectSeed: testFixture.path.join(testFixture.DF_SEED_DIR, 'devProject', 'devProject.webgmex'),
projectName: projectName,
branchName: 'master',
logger: logger,
gmeConfig: gmeConfig
};
return testFixture.importProject(storage, importParam);
})
.then(function (importResult) {
project = importResult.project;
commitHash = importResult.commitHash;
return project.createBranch('test', commitHash);
})
.nodeify(done);
});
after(function (done) {
storage.closeDatabase()
.then(function () {
return gmeAuth.unload();
})
.nodeify(done);
});
var plugin,
preparePlugin = function(done) {
var context = {
project: project,
commitHash: commitHash,
namespace: 'nn',
branchName: 'test',
activeNode: '/4/n' // "simple broken" architecture
};
return manager.initializePlugin(pluginName)
.then(plugin_ => {
plugin = plugin_;
plugin.setTorchInstalled(true);
return manager.configurePlugin(plugin, {}, context);
})
.nodeify(done);
};
// check that each layer is validated
describe('simple broken test case', function() {
beforeEach(preparePlugin);
it('should validate each layer', function(done) {
var validated = {};
plugin.validateLayer = id => {
validated[id] = true;
};
plugin.main(err => {
expect(err).to.equal(null);
expect(Object.keys(validated).length).to.equal(5);
done();
});
});
it('should make tmp dir', function(done) {
var oldMkdir = fs.mkdir;
fs.mkdir = (dir, cb) => {
expect(dir).to.equal(plugin._tmpFileId);
return oldMkdir(dir, cb);
};
plugin.main(() => {
fs.mkdir = oldMkdir;
done();
});
});
it('should rm tmp dir', function(done) {
mockery.enable({
warnOnReplace: false,
warnOnUnregistered: false
});
mockery.registerMock('rimraf', (dir, cb) => {
expect(dir).to.equal(plugin._tmpFileId);
return rm_rf(dir, cb);
});
plugin.main(() => {
mockery.disable();
done();
});
});
// check that errors are returned in the message
it('should return two error messages', function(done) {
plugin.validateLayer = (id, code) => {
if (code.indexOf('Linear()') === -1) {
return null;
} else { // error!
return {
id: id,
msg: 'invalid args'
};
}
};
plugin.main((err, result) => {
var invalidLayers = result.messages[0].message.errors.map(msg => msg.id);
expect(result.messages[0]).to.not.equal(undefined);
expect(invalidLayers.length).to.equal(2);
done();
});
});
describe('w/o torch support', function() {
before(function(done) {
preparePlugin(() => {
done();
});
});
it('should return "null" for messages', function(done) {
plugin.setTorchInstalled(false);
plugin.main((err, result) => {
var errors = result.messages[0].message.errors;
expect(errors).to.equal(null);
done();
});
});
});
});
describe('custom layer test case', function() {
beforeEach(done => {
var context = {
project: project,
commitHash: commitHash,
namespace: 'nn',
branchName: 'test',
activeNode: '/4/5' // "simple broken" architecture
};
return manager.initializePlugin(pluginName)
.then(plugin_ => {
plugin = plugin_;
return manager.configurePlugin(plugin, {}, context);
})
.nodeify(done);
});
it('should add custom layer def to test code', function(done) {
plugin.validateLayer = (id, code) => {
expect(code.indexOf('torch.class')).to.not.equal(-1);
return null;
};
plugin.main(done);
});
});
});
+4
Ver Arquivo
@@ -52,6 +52,10 @@
"UpdateLibrarySeed": {
"src": "src/plugins/UpdateLibrarySeed",
"test": "test/plugins/UpdateLibrarySeed"
},
"ValidateArchitecture": {
"src": "src/plugins/ValidateArchitecture",
"test": "test/plugins/ValidateArchitecture"
}
},
"layouts": {