@fix(embark/core): Fix VM2 + Remap Imports + Monorepo + Tests

This PR introduces a large number of changes (for that, I am very sorry). Breaking this up in to smaller PR's was causing tests to fail, and the likelihood of them getting merged diminished. There a couple of PRs this PR closes, and as such, I have kep the original commits to preserve the history. The first two (of three) commits are the close PRs, and the last is the glue bringin it all together.

The main goal of this PR is to fix the fragility of the tests with EmbarkJS, however in doing so, a number of recent features have been updated:
Remapping of imports still had a few edge cases that needed to be ironed out, as well as have unit tests created for them. More details of the changes an be seen in the closed PR (below).
The main issue with VM2 was running the code generated EmbarkJS code inside the VM, and getting EmbarkJS contracts out of the VM and available to the tests. This fixed issues where ENS may not have been available to the tests. Notable additions include adding `EmbarkJS.Blockchain.connectTests` to the tests lifecycle, and ensuring `EmbarkJS` is only every required in the console module and not used or passed around elsewhere.
As mentioned above, the main issue with the tests in the context of a monorepo and with embark running as module inside the dapp’s `node_modules`, there were issues getting the correct contract state available inside of the tests. For some reason, this particular case was causing the tests to fail, with ENS never being available (assuming this to be an issue with `EmbarkJS.Blockchain.connect()` never being called). The main fix for this came with passing `web3` as an option in to `EmbarkJS.Blockchain.setProvider()`.
---
1. https://github.com/embark-framework/embark/pull/1286
2. https://github.com/embark-framework/embark/pull/1275
Go to bottom for details
---
There are few known issues with this PR. Instead of trying to fix all of them with this PR, I was hoping to get these issues tackled in separate PRs.
1. `deployIf` directive on contracts defined in the config are not working, however the tests are passing. The issue is that if `ContractA` has a `deployIf` set to `!!ContractB.options.address`, it means that it will not deploy if `ContractB` is not deployed. However, it appears that `ContractA` is attempted to be deployed prior to `ContractB` being deployed, and therefore `ContractA` fails to deploy. Instead, because `ContractA` depends on `ContractB`, `ContractB` should be deployed before `ContractA`.
2. `embark test --node embark` does not seem to be functioning for reasons unknown.
3. Remix tests: Currently there is support for adding contract tests that get process by `remix-tests`, however, there is an error that I believe is not due to embark, but due to the Assert library. For example, if we add a `test/remix_test.sol` to the `test_app` with the following content:
```
pragma solidity ^0.4.24;

import "remix_tests.sol";
import "../app/contracts/simple_storage.sol";

contract SimpleStorageTest {
  SimpleStorage simpleStorage;

  function beforeAll() public {
    simpleStorage = new SimpleStorage(100);
  }

  function initialValueShouldBeCorrect() public {
    return Assert.equal(
      100,
      simpleStorage.storedData,
      "stored data is not what I expected"
    );
  }
}
```
After compilation, we would get the error:
```
remix_test.sol:14:12: TypeError: Member "equal" not found or not visible after argument-dependent lookup in type(library Assert)
    return Assert.equal(
           ^—————^
```
---
This branch is based off of ()`refactor/embarkjs-in-monorepo`)[https://github.com/embark-framework/embark/tree/refactor/embarkjs-in-monorepo], which does not have passing tests due to the `EmbarkJS` ENS issue mentioned above. However, you should (hopefully) see the tests passing in this branch, meaning if both branches are merged, the tests should be passing.
Related PRs: https://github.com/embark-framework/embark-solc/pull/24

---

Changes include:
1. Add unit tests for recursively remapping imports
2. Handle plugin contracts correctly
3. Allow `prepareForCompilation` to be called from `File`, allowing for external compilers, like `embark-solc` to call this function before compilation.
4. Add flattened remappings to `File` that gets prepared for compilation (ie has it's imports remapped)
5. Return remapped contract content when file type is http. Previously this was broken, as always freshly downloaded (original) content was returned.
6. Handle additional cases for `custom` and http file types.

This PR was tested with:
- `embark` unit tests
- `embark` test_app
- `embark` test_app with `embark-solc` plugin
- `embark` test_app with `embark-flattener` plugin
- `Giveth/lpp-campaign`

Related change to get `embark-solc` up-to-date` with these changes: https://github.com/embark-framework/embark-solc/pull/24

When embark was running as module inside the dapp’s `node_modules`, the tests were failing due to several issues:
1. `web3` was not being set in the global namespace of vm2. `EmbarkJS.Blockchain.setProvider` was therefore failing because it relies on `global.web3` to be set. I guess somehow this works when the test app was running in a child tree of the executing program. maybe this is a security feature of vm2, but i’m not sure.
2. `embarkjs` provider code being injected to the vm twice. This really was the initial point of failure, as this piece of code is requiring embarkjs, so i’m assuming, but again not sure, that maybe it was getting a second instance of `EmbarkJS` which did not have it’s providers set up correctly (hence the error with `ENS provider not set`).

Fixes for those issues in this PR:
1. To circumvent the web3 issue, we are now setting `global.web3` for tests only (the global web3 accessible in the tests), and `web3` is now explicitly passed in to `EmbarkJS.Blockchain.setProvider`
2. To fix the `embarkjs` code being called twice, we are not re-injecting this code to the VM during test initialisations
This commit is contained in:
emizzle 2019-02-05 15:38:33 +11:00 committed by Iuri Matias
parent 2f354c9323
commit 129a35484f
21 changed files with 337 additions and 235 deletions

View File

@ -182,12 +182,7 @@ class Engine {
} }
codeRunnerService(_options) { codeRunnerService(_options) {
const CodeRunner = require('./modules/coderunner/codeRunner.js'); this.registerModule('codeRunner', {
this.codeRunner = new CodeRunner({
config: this.config,
plugins: this.plugins,
events: this.events,
logger: this.logger,
ipc: this.ipc ipc: this.ipc
}); });
} }

View File

@ -1,3 +1,4 @@
import {__} from "i18n";
import * as path from "path"; import * as path from "path";
import { ImportRemapping, prepareForCompilation } from "../utils/solidity/remapImports"; import { ImportRemapping, prepareForCompilation } from "../utils/solidity/remapImports";
@ -41,15 +42,15 @@ export class File {
} else if (this.type === Types.http) { } else if (this.type === Types.http) {
const external = utils.getExternalContractUrl(options.externalUrl, this.providerUrl); const external = utils.getExternalContractUrl(options.externalUrl, this.providerUrl);
this.externalUrl = external.url; this.externalUrl = external.url;
this.path = fs.dappPath(external.filePath); this.path = path.normalize(fs.dappPath(external.filePath));
} else { } else {
this.path = options.path.replace(/\\/g, "/"); this.path = path.normalize(options.path);
} }
} }
public async prepareForCompilation(isCoverage = false) { public async prepareForCompilation(isCoverage = false) {
if (!this.path.endsWith(".sol")) { if (!this.path.endsWith(".sol")) {
return Promise.reject("this method is only supported for Solidity files"); return Promise.reject(__("This method is only supported for Solidity files"));
} }
return prepareForCompilation(this, isCoverage); return prepareForCompilation(this, isCoverage);
} }

View File

@ -1,6 +1,7 @@
const utils = require('../utils/utils.js'); const utils = require('../utils/utils.js');
const constants = require('../constants'); const constants = require('../constants');
const fs = require('./fs.js'); const fs = require('./fs.js');
const deepEqual = require('deep-equal');
// TODO: pass other params like blockchainConfig, contract files, etc.. // TODO: pass other params like blockchainConfig, contract files, etc..
var Plugin = function(options) { var Plugin = function(options) {
@ -217,8 +218,13 @@ Plugin.prototype.registerUploadCommand = function(cmd, cb) {
}; };
Plugin.prototype.addCodeToEmbarkJS = function(code) { Plugin.prototype.addCodeToEmbarkJS = function(code) {
this.embarkjs_code.push(code);
this.addPluginType('embarkjsCode'); this.addPluginType('embarkjsCode');
if (!this.embarkjs_code.some((existingCode) => deepEqual(existingCode, code))) {
this.embarkjs_code.push(code);
this.events.request('blockchain:ready', () => {
this.events.emit('runcode:embarkjs-code:updated', code, () => {});
});
}
}; };
Plugin.prototype.addProviderInit = function(providerType, code, initCondition) { Plugin.prototype.addProviderInit = function(providerType, code, initCondition) {
@ -229,8 +235,14 @@ Plugin.prototype.addProviderInit = function(providerType, code, initCondition) {
Plugin.prototype.addConsoleProviderInit = function(providerType, code, initCondition) { Plugin.prototype.addConsoleProviderInit = function(providerType, code, initCondition) {
this.embarkjs_init_console_code[providerType] = this.embarkjs_init_console_code[providerType] || []; this.embarkjs_init_console_code[providerType] = this.embarkjs_init_console_code[providerType] || [];
this.embarkjs_init_console_code[providerType].push([code, initCondition]);
this.addPluginType('initConsoleCode'); this.addPluginType('initConsoleCode');
const toAdd = [code, initCondition];
if (!this.embarkjs_init_console_code[providerType].some((initConsoleCode) => deepEqual(initConsoleCode, toAdd))) {
this.embarkjs_init_console_code[providerType].push(toAdd);
this.events.request('blockchain:ready', () => {
this.events.emit('runcode:init-console-code:updated', code, () => {});
});
}
}; };
Plugin.prototype.registerImportFile = function(importName, importLocation) { Plugin.prototype.registerImportFile = function(importName, importLocation) {

View File

@ -45,6 +45,8 @@ class BlockchainConnector {
}); });
}); });
self.events.setCommandHandler("blockchain:ready", self.onReady.bind(this));
self.events.setCommandHandler("blockchain:web3:isReady", (cb) => { self.events.setCommandHandler("blockchain:web3:isReady", (cb) => {
cb(self.isWeb3Ready); cb(self.isWeb3Ready);
}); });
@ -68,7 +70,6 @@ class BlockchainConnector {
this.registerServiceCheck(); this.registerServiceCheck();
this.registerRequests(); this.registerRequests();
this.registerAPIRequests(); this.registerAPIRequests();
this.registerWeb3Object();
this.registerEvents(); this.registerEvents();
this.subscribeToPendingTransactions(); this.subscribeToPendingTransactions();
} }
@ -192,8 +193,9 @@ class BlockchainConnector {
_emitWeb3Ready() { _emitWeb3Ready() {
this.isWeb3Ready = true; this.isWeb3Ready = true;
this.events.emit(WEB3_READY); this.registerWeb3Object(() => {
this.registerWeb3Object(); this.events.emit(WEB3_READY);
});
this.subscribeToPendingTransactions(); this.subscribeToPendingTransactions();
} }
@ -690,10 +692,10 @@ class BlockchainConnector {
}); });
} }
registerWeb3Object() { registerWeb3Object(cb = () => {}) {
// doesn't feel quite right, should be a cmd or plugin method // doesn't feel quite right, should be a cmd or plugin method
// can just be a command without a callback // can just be a command without a callback
this.events.emit("runcode:register", "web3", this.web3, false); this.events.emit("runcode:register", "web3", this.web3, false, cb);
} }
subscribeToPendingTransactions() { subscribeToPendingTransactions() {

View File

@ -1,16 +1,25 @@
const VM = require('./vm'); const VM = require('./vm');
const fs = require('../../fs'); const fs = require('../../core/fs');
const deepEqual = require('deep-equal');
const EmbarkJS = require('embarkjs');
const IpfsApi = require("ipfs-api");
const Web3 = require('web3');
class CodeRunner { class CodeRunner {
constructor(options) { constructor(embark, options) {
this.ready = false; this.ready = false;
this.config = options.config; this.blockchainConnected = false;
this.plugins = options.plugins; this.config = embark.config;
this.logger = options.logger; this.plugins = embark.plugins;
this.events = options.events; this.logger = embark.logger;
this.events = embark.events;
this.ipc = options.ipc; this.ipc = options.ipc;
this.commands = [];
this.vm = new VM({ this.vm = new VM({
sandbox: {
IpfsApi,
Web3,
EmbarkJS
},
require: { require: {
mock: { mock: {
fs: { fs: {
@ -33,6 +42,8 @@ class CodeRunner {
} }
} }
}, this.logger); }, this.logger);
this.embark = embark;
this.commands = [];
this.registerIpcEvents(); this.registerIpcEvents();
this.IpcClientListen(); this.IpcClientListen();
@ -69,6 +80,28 @@ class CodeRunner {
registerEvents() { registerEvents() {
this.events.on("runcode:register", this.registerVar.bind(this)); this.events.on("runcode:register", this.registerVar.bind(this));
this.events.on("runcode:init-console-code:updated", (code, cb) => {
this.evalCode(code, (err, _result) => {
if(err) {
this.logger.error("Error running init console code: ", err);
}
else if(code.includes("EmbarkJS.Blockchain.setProvider")) {
this.events.emit('runcode:blockchain:connected');
this.blockchainConnected = true;
}
cb();
});
});
this.events.on("runcode:embarkjs-code:updated", (code, cb) => {
this.evalCode(code, (err, _result) => {
if(err) {
this.logger.error("Error running embarkjs code: ", err);
}
cb();
});
});
} }
registerCommands() { registerCommands() {
@ -82,28 +115,42 @@ class CodeRunner {
} }
this.events.once("runcode:ready", cb); this.events.once("runcode:ready", cb);
}); });
this.events.setCommandHandler('runcode:blockchain:connected', (cb) => {
if (this.blockchainConnected) {
return cb();
}
this.events.once("runcode:blockchain:connected", cb);
});
this.events.setCommandHandler('runcode:embarkjs:reset', this.resetEmbarkJS.bind(this)); this.events.setCommandHandler('runcode:embarkjs:reset', this.resetEmbarkJS.bind(this));
} }
resetEmbarkJS(cb) { resetEmbarkJS(cb) {
this.events.request('blockchain:get', (web3) => { this.events.request("code-generator:embarkjs:provider-code", (code) => {
this.events.emit("runcode:register", "web3", web3, false, () => { this.evalCode(code, (err) => {
this.events.request("code-generator:embarkjs:init-provider-code", async (code) => { if (err) {
await this.evalCode(code, cb, true); return cb(err);
}
this.events.request("code-generator:embarkjs:init-provider-code", (providerCode) => {
this.evalCode(providerCode, (err, _result) => {
cb(err);
}, false, true);
}); });
}); }, true);
}); });
} }
registerVar(varName, code, toRecord = true, cb = () => {}) { registerVar(varName, code, toRecord = true, cb = () => {}) {
if (this.ipc.isServer() && toRecord) { const command = {varName, code};
this.commands.push({varName, code}); if (toRecord && !this.commands.some(cmd => deepEqual(cmd, command))) {
this.ipc.broadcast("runcode:newCommand", {varName, code}); if (this.ipc.isServer()) {
this.commands.push(command);
this.ipc.broadcast("runcode:newCommand", command);
}
} }
this.vm.registerVar(varName, code, cb); this.vm.registerVar(varName, code, cb);
} }
async evalCode(code, cb, isNotUserInput = false, tolerateError = false) { evalCode(code, cb, isNotUserInput = false, tolerateError = false) {
cb = cb || function () {}; cb = cb || function () {};
if (!code) return cb(null, ''); if (!code) return cb(null, '');
@ -112,16 +159,15 @@ class CodeRunner {
if(err) { if(err) {
return cb(err); return cb(err);
} }
const command = {code};
if (isNotUserInput && this.ipc.isServer()) { if (isNotUserInput && this.ipc.isServer() && !this.commands.some(cmd => cmd.code === command.code)) {
this.commands.push({code}); this.commands.push(command);
this.ipc.broadcast("runcode:newCommand", {code}); this.ipc.broadcast("runcode:newCommand", command);
} }
cb(null, result); cb(null, result);
}); });
} }
} }
module.exports = CodeRunner; module.exports = CodeRunner;

View File

@ -2,12 +2,16 @@ import { each } from "async";
import { Callback, Logger } from "embark"; import { Callback, Logger } from "embark";
import { NodeVM, NodeVMOptions } from "vm2"; import { NodeVM, NodeVMOptions } from "vm2";
const fs = require("../../fs"); const fs = require("../../core/fs");
const { recursiveMerge, isEs6Module } = require("../../../utils/utils"); const { recursiveMerge, isEs6Module, compact } = require("../../utils/utils");
const Utils = require("../../../utils/utils");
const WEB3_INVALID_RESPONSE_ERROR: string = "Invalid JSON RPC response"; const WEB3_INVALID_RESPONSE_ERROR: string = "Invalid JSON RPC response";
interface Command {
varName: string;
code: any;
}
/** /**
* Wraps an instance of NodeVM from VM2 (https://github.com/patriksimek/vm2) and allows * Wraps an instance of NodeVM from VM2 (https://github.com/patriksimek/vm2) and allows
* code evaluations in the fully sandboxed NodeVM context. * code evaluations in the fully sandboxed NodeVM context.
@ -59,18 +63,18 @@ class VM {
* @returns Formatted code. * @returns Formatted code.
*/ */
private static formatCode(code: string) { private static formatCode(code: string) {
const instructions = Utils.compact(code.split(";")); const instructions = compact(code.split(";"));
const last = instructions.pop().trim(); const last = instructions.pop().trim();
const awaiting = code.indexOf("await") > -1; const awaiting = code.indexOf("await") > -1;
if (!(last.startsWith("return") || last.indexOf("=") > -1)) { if (!(last.includes("return") || last.includes("="))) {
instructions.push(`return ${last}`); instructions.push(`return ${last}`);
} else { } else {
instructions.push(last); instructions.push(last);
} }
code = instructions.join(";"); code = instructions.join(";");
return `module.exports = (${awaiting ? "async" : ""} () => {${code};})()`; return `module.exports = (${awaiting ? "async" : ""} function () {${code};})()`;
} }
/** /**
@ -89,10 +93,10 @@ class VM {
if (!tolerateError) { if (!tolerateError) {
this.logger.error(e.message); this.logger.error(e.message);
} }
return cb(null, e.message); return cb(e);
} }
try { try {
return cb(null, await result); result = await result;
} catch (error) { } catch (error) {
// Improve error message when there's no connection to node // Improve error message when there's no connection to node
if (error.message && error.message.indexOf(WEB3_INVALID_RESPONSE_ERROR) !== -1) { if (error.message && error.message.indexOf(WEB3_INVALID_RESPONSE_ERROR) !== -1) {
@ -101,6 +105,7 @@ class VM {
return cb(error); return cb(error);
} }
return cb(null, result);
} }
/** /**
@ -117,7 +122,7 @@ class VM {
code = code.default; code = code.default;
} }
this.updateState((_err) => { this.updateState(() => {
this.options.sandbox[varName] = code; this.options.sandbox[varName] = code;
this.setupNodeVm(cb); this.setupNodeVm(cb);
}); });
@ -128,7 +133,7 @@ class VM {
// update sandbox state from VM // update sandbox state from VM
each(Object.keys(this.options.sandbox), (sandboxVar: string, next: Callback<null>) => { each(Object.keys(this.options.sandbox), (sandboxVar: string, next: Callback<null>) => {
this.doEval(sandboxVar, false, (err, result) => { this.doEval(sandboxVar, false, (err?: Error | null, result?: any) => {
if (!err) { if (!err) {
this.options.sandbox[sandboxVar] = result; this.options.sandbox[sandboxVar] = result;
} }

View File

@ -1,12 +1,11 @@
/*globals __*/ /*globals __*/
const env = require("../../core/env"); const env = require("../../core/env");
const utils = require("../../utils/utils"); const utils = require("../../utils/utils");
const EmbarkJS = require("embarkjs"); import { Callback } from "embark";
const IpfsApi = require("ipfs-api");
const stringify = require("json-stringify-safe"); const stringify = require("json-stringify-safe");
import { waterfall } from "async";
import { Embark, Events } from "embark"; import { Embark, Events } from "embark";
import {__} from "i18n"; import {__} from "i18n";
import Web3 from "web3";
import Suggestions from "./suggestions"; import Suggestions from "./suggestions";
type MatchFunction = (cmd: string) => boolean; type MatchFunction = (cmd: string) => boolean;
@ -60,7 +59,13 @@ class Console {
} }
this.events.once("console:provider:done", cb); this.events.once("console:provider:done", cb);
}); });
this.registerEmbarkJs(); this.registerEmbarkJs((err?: Error | null) => {
if (err) {
return this.logger.error(err);
}
this.providerReady = true;
this.events.emit("console:provider:done");
});
this.registerConsoleCommands(); this.registerConsoleCommands();
this.registerApi(); this.registerApi();
@ -76,12 +81,12 @@ class Console {
plugin.registerAPICall("post", "/embark-api/command", (req: any, res: any) => { plugin.registerAPICall("post", "/embark-api/command", (req: any, res: any) => {
this.executeCmd(req.body.command, (err: any, result: any) => { this.executeCmd(req.body.command, (err: any, result: any) => {
if (err) { if (err) {
return res.send({result: err.message || err}); return res.send({ result: err.message || err });
} }
if (typeof result === "string") { if (typeof result === "string") {
return res.send({result}); return res.send({ result });
} }
res.send({result: stringify(result, utils.jsonFunctionReplacer, 2)}); res.send({ result: stringify(result, utils.jsonFunctionReplacer, 2) });
}); });
}); });
} }
@ -170,37 +175,41 @@ class Console {
} }
} }
private registerEmbarkJs() { private registerEmbarkJs(cb: Callback<null>) {
this.events.emit("runcode:register", "IpfsApi", IpfsApi, false); waterfall([
this.events.emit("runcode:register", "Web3", Web3, false); // wait for the VM to be setup
this.events.emit("runcode:register", "EmbarkJS", EmbarkJS, false); (next: any) => {
this.events.request("runcode:ready", next);
EmbarkJS.Blockchain.done = true; },
if (this.ipc.connected && !this.forceRegister) { (next: any) => {
return; const waitingForReady = setTimeout(() => {
} this.logger.warn(__("Waiting for the blockchain connector to be ready..."));
// TODO add docs link to how to install one
this.events.once("code-generator-ready", () => { this.logger.warn(__("If you did not install a blockchain connector, stop this process and install one"));
const waitingForReady = setTimeout(() => { }, 5000);
this.logger.warn(__("Waiting for the blockchain connector to be ready...")); this.events.once("blockchain:connector:ready", () => {
// TODO add docs link to how to install one clearTimeout(waitingForReady);
this.logger.warn(__("If you did not install a blockchain connector, stop this process and install one")); next();
}, 5000);
this.events.request("blockchain:connector:ready", () => {
clearTimeout(waitingForReady);
this.events.request("code-generator:embarkjs:provider-code", (providerCode: string) => {
const func = () => {
};
this.events.request("runcode:eval", providerCode, func, true);
this.events.request("code-generator:embarkjs:init-provider-code", (initCode: string) => {
this.events.request("runcode:eval", initCode, () => {
this.events.emit("console:provider:done");
this.providerReady = true;
}, true);
});
}); });
}); },
}); (next: any) => {
this.events.request("runcode:blockchain:connected", next);
},
// for every other case (including when asked for force), get the embarkjs
// provider code and eval it in the VM (either main running VM or console VM
// in the secondary process)
(next: any) => {
if (this.ipc.connected && !this.forceRegister) {
return next();
}
const connectCode = `EmbarkJS.Blockchain.connectConsole((err) => {
if(err) throw new Error("[VM]: Error connecting to blockchain. " + err);
});`;
this.events.request("runcode:eval", connectCode, (err: Error, _result: any) => {
cb(err);
});
},
], cb);
} }
private registerConsoleCommands() { private registerConsoleCommands() {
@ -229,16 +238,16 @@ class Console {
} }
private getHistory(historySize: any, callback: any) { private getHistory(historySize: any, callback: any) {
if (typeof historySize === "string") { if (typeof historySize === "string") {
historySize = parseInt(historySize, 10); historySize = parseInt(historySize, 10);
if (isNaN(historySize)) { return callback("Invalid argument. Please provide an integer."); } if (isNaN(historySize)) { return callback("Invalid argument. Please provide an integer."); }
} }
const length = historySize || this.cmdHistorySize(); const length = historySize || this.cmdHistorySize();
return callback(null, this.history return callback(null, this.history
.slice(Math.max(0, this.history.length - length)) .slice(Math.max(0, this.history.length - length))
.filter((line: string) => line.trim()) .filter((line: string) => line.trim())
.reverse() .reverse()
.join("\n")); .join("\n"));
} }
private saveHistory(cmd: string, fromIpcClient = false) { private saveHistory(cmd: string, fromIpcClient = false) {

View File

@ -340,10 +340,11 @@ class ContractDeployer {
self.events.request('code-generator:contract:custom', contract, (contractCode) => { self.events.request('code-generator:contract:custom', contract, (contractCode) => {
self.events.request('runcode:eval', contractCode, () => {}, true); self.events.request('runcode:eval', contractCode, () => {
self.plugins.runActionsForEvent('deploy:contract:deployed', {contract: contract}, () => { self.plugins.runActionsForEvent('deploy:contract:deployed', {contract: contract}, () => {
return next(null, receipt); return next(null, receipt);
}); });
}, true);
}); });
}, hash => { }, hash => {
self.logFunction(contract)(__("deploying") + " " + contract.className.bold.cyan + " " + __("with").green + " " + contract.gas + " " + __("gas at the price of").green + " " + contract.gasPrice + " " + __("Wei, estimated cost:").green + " " + estimatedCost + " Wei".green + " (txHash: " + hash.bold.cyan + ")"); self.logFunction(contract)(__("deploying") + " " + contract.className.bold.cyan + " " + __("with").green + " " + contract.gas + " " + __("gas at the price of").green + " " + contract.gasPrice + " " + __("Wei, estimated cost:").green + " " + estimatedCost + " Wei".green + " (txHash: " + hash.bold.cyan + ")");

View File

@ -16,7 +16,6 @@ class TestRunner {
this.fs = embark.fs; this.fs = embark.fs;
this.ipc = options.ipc; this.ipc = options.ipc;
this.runResults = []; this.runResults = [];
this.embarkjs = null;
this.events.setCommandHandler('tests:run', (options, callback) => { this.events.setCommandHandler('tests:run', (options, callback) => {
this.run(options, callback); this.run(options, callback);
@ -173,9 +172,6 @@ class TestRunner {
const Module = require('module'); const Module = require('module');
const originalRequire = require('module').prototype.require; const originalRequire = require('module').prototype.require;
Module.prototype.require = function (requireName) { Module.prototype.require = function (requireName) {
if (requireName.startsWith('Embark/EmbarkJS')) {
return self.embarkjs;
}
if (requireName.startsWith('Embark')) { if (requireName.startsWith('Embark')) {
return test.require(...arguments); return test.require(...arguments);
} }
@ -207,13 +203,7 @@ class TestRunner {
if (global.embark.needConfig) { if (global.embark.needConfig) {
global.config({}); global.config({});
} }
global.embark.onReady((err) => { global.embark.onReady(done);
if(err) return done(err);
self.events.request('runcode:eval', 'EmbarkJS', (err, embarkjs) => {
self.embarkjs = embarkjs;
done(err);
});
});
}); });
mocha.run(function (fails) { mocha.run(function (fails) {
mocha.suite.removeAllListeners(); mocha.suite.removeAllListeners();

View File

@ -68,7 +68,7 @@ class SolcTest extends Test {
async.series(fns, next); async.series(fns, next);
}, },
function resetEmbarkJs(file, next) { function resetEmbarkJs(file, next) {
self.resetEmbarkJS((err) => { self.events.request("runcode:embarkjs:reset", (err) => {
next(err, file); next(err, file);
}); });
} }
@ -120,11 +120,11 @@ class SolcTest extends Test {
methodIdentifiers: contract.functionHashes methodIdentifiers: contract.functionHashes
} }
}; };
this.getWeb3Contract(contract, web3, (err, web3contract) => { this.getEmbarkJSContract(contract, (err, embarkjsContract) => {
if(err) { if(err) {
return _callback(err); return _callback(err);
} }
remixTests.runTest(contract.className, web3contract, contractDetails, {accounts}, remixTests.runTest(contract.className, embarkjsContract, contractDetails, {accounts},
self._prettyPrint.bind(self), _callback); self._prettyPrint.bind(self), _callback);
}); });
}; };

View File

@ -5,7 +5,6 @@ const AccountParser = require('../../utils/accountParser');
const utils = require('../../utils/utils'); const utils = require('../../utils/utils');
const constants = require('../../constants'); const constants = require('../../constants');
const web3Utils = require('web3-utils'); const web3Utils = require('web3-utils');
const EmbarkJS = require('embarkjs');
const BALANCE_10_ETHER_IN_HEX = '0x8AC7230489E80000'; const BALANCE_10_ETHER_IN_HEX = '0x8AC7230489E80000';
@ -26,30 +25,42 @@ class Test {
this.needConfig = true; this.needConfig = true;
this.provider = null; this.provider = null;
this.accounts = []; this.accounts = [];
this.embarkjs = {};
} }
init(callback) { init(callback) {
this.events.request('runcode:ready', () => { async.waterfall([
this.gasLimit = constants.tests.gasLimit; (next) => {
this.events.request('deploy:setGasLimit', this.gasLimit); this.events.request('runcode:ready', next);
const waitingForReady = setTimeout(() => { },
this.logger.warn('Waiting for the blockchain connector to be ready...'); (next) => {
// TODO add docs link to how to install one this.initWeb3Provider(next);
this.logger.warn('If you did not install a blockchain connector, stop this process and install one'); },
}, 5000); (next) => {
this.events.request('blockchain:connector:ready', () => { const waitingForReady = setTimeout(() => {
clearTimeout(waitingForReady); this.logger.warn('Waiting for the blockchain connector to be ready...');
// TODO add docs link to how to install one
this.logger.warn('If you did not install a blockchain connector, stop this process and install one');
}, 5000);
this.events.request('blockchain:connector:ready', () => {
clearTimeout(waitingForReady);
next();
});
},
(next) => {
this.gasLimit = constants.tests.gasLimit;
this.events.request('deploy:setGasLimit', this.gasLimit);
if (this.options.node !== 'embark') { if (this.options.node !== 'embark') {
this.showNodeHttpWarning(); this.showNodeHttpWarning();
return callback(); return next();
} }
if (!this.ipc.connected) { if (!this.ipc.connected) {
this.logger.error("Could not connect to Embark's IPC. Is embark running?"); this.logger.error("Could not connect to Embark's IPC. Is embark running?");
if (!this.options.inProcess) process.exit(1); if (!this.options.inProcess) process.exit(1);
} }
this.connectToIpcNode(callback); return this.connectToIpcNode(next);
}); }
}); ], callback);
} }
connectToIpcNode(cb) { connectToIpcNode(cb) {
@ -174,7 +185,7 @@ class Test {
return callback(err); return callback(err);
} }
self.firstRunConfig = false; self.firstRunConfig = false;
callback(); self.events.request("runcode:embarkjs:reset", callback);
}); });
}); });
} }
@ -230,11 +241,6 @@ class Test {
self.error = false; self.error = false;
next(null, accounts); next(null, accounts);
}); });
},
function changeGlobalWeb3(accounts, next) {
self.resetEmbarkJS((err) => {
next(err, accounts);
});
} }
], (err, accounts) => { ], (err, accounts) => {
if (err) { if (err) {
@ -246,14 +252,6 @@ class Test {
}); });
} }
resetEmbarkJS(cb) {
this.events.request('blockchain:get', (web3) => {
// global web3 used in the tests, not in the vm
global.web3 = web3;
this.events.request("runcode:embarkjs:reset", cb);
});
}
async deploy(contract, deployArgs = {}, sendArgs = {}) { async deploy(contract, deployArgs = {}, sendArgs = {}) {
const instance = await contract.deploy(deployArgs).send(sendArgs); const instance = await contract.deploy(deployArgs).send(sendArgs);
this.events.emit("tests:manualDeploy", instance); this.events.emit("tests:manualDeploy", instance);
@ -297,13 +295,15 @@ class Test {
next(null, accounts); next(null, accounts);
}); });
}, },
function deploy(accounts, next) {
self.events.request('deploy:contracts:test', () => {
next(null, accounts);
});
},
function getWeb3Object(accounts, next) { function getWeb3Object(accounts, next) {
self.events.request('blockchain:get', (web3) => { self.events.request('blockchain:get', (web3) => {
// global web3 used in the tests, not in the vm
global.web3 = web3;
next(null, accounts, web3);
});
},
function deploy(accounts, web3, next) {
self.events.request('deploy:contracts:test', () => {
next(null, accounts, web3); next(null, accounts, web3);
}); });
}, },
@ -322,22 +322,31 @@ class Test {
const testContractFactoryPlugin = self.plugins.getPluginsFor('testContractFactory').slice(-1)[0]; const testContractFactoryPlugin = self.plugins.getPluginsFor('testContractFactory').slice(-1)[0];
if (!testContractFactoryPlugin) { if (testContractFactoryPlugin) {
return self.getWeb3Contract(contract, web3, (err, web3Contract) => { const newContract = testContractFactoryPlugin.testContractFactory(contract, web3);
Object.setPrototypeOf(self.contracts[contract.className], web3Contract); Object.setPrototypeOf(self.contracts[contract.className], newContract);
eachCb(); return eachCb();
});
} }
self.getEmbarkJSContract(contract, (err, vmContract) => {
const newContract = testContractFactoryPlugin.testContractFactory(contract, web3); if(err) {
Object.setPrototypeOf(self.contracts[contract.className], newContract); self.logger.error(`Erroring creating contract instance '${contract.className}' for import in to test. Error: ${err}`);
}
eachCb(); Object.setPrototypeOf(self.contracts[contract.className], vmContract || null);
eachCb();
});
}, (err) => { }, (err) => {
next(err, accounts); next(err, accounts);
}); });
}); });
},
function updateEmbarkJsRef(accounts, next) {
self.events.request("runcode:eval", "EmbarkJS", (err, embarkjs) => {
if (!err && embarkjs) {
Object.setPrototypeOf(self.embarkjs, embarkjs);
}
next(err, accounts);
}, true);
} }
], function (err, accounts) { ], function (err, accounts) {
if (err) { if (err) {
@ -349,30 +358,31 @@ class Test {
}); });
} }
getWeb3Contract(contract, web3, cb) { getEmbarkJSContract(contract, cb) {
const newContract = new EmbarkJS.Blockchain.Contract({ const codeToRun = `
abi: contract.abiDefinition, const newContract = new EmbarkJS.Blockchain.Contract({
address: contract.deployedAddress, abi: ${JSON.stringify(contract.abiDefinition)},
from: contract.deploymentAccount || web3.eth.defaultAccount, address: "${contract.deployedAddress || ""}" || undefined,
gas: constants.tests.gasLimit, from: "${contract.deploymentAccount || ""}" || web3.eth.defaultAccount,
web3: web3 gas: "${constants.tests.gasLimit}",
}); web3: web3
});
newContract.filename = contract.filename; newContract.filename = "${contract.filename}";
if (newContract.options) { if (newContract.options) {
newContract.options.from = contract.deploymentAccount || web3.eth.defaultAccount; newContract.options.from = "${contract.deploymentAccount || ""}" || web3.eth.defaultAccount;
newContract.options.data = contract.code; newContract.options.data = "${contract.code}";
if (!newContract.options.data.startsWith('0x')) { if (newContract.options.data && !newContract.options.data.startsWith('0x')) {
newContract.options.data = '0x' + newContract.options.data; newContract.options.data = '0x' + newContract.options.data;
}
newContract.options.gas = "${constants.tests.gasLimit}";
} }
newContract.options.gas = constants.tests.gasLimit; return newContract;`;
} this.events.request("runcode:eval", codeToRun, cb, false, true);
cb(null, newContract);
} }
require(path) { require(path) {
const contractsPrefix = 'Embark/contracts/'; const [contractsPrefix, embarkJSPrefix] = ['Embark/contracts/', 'Embark/EmbarkJS'];
// Contract require // Contract require
if (path.startsWith(contractsPrefix)) { if (path.startsWith(contractsPrefix)) {
@ -387,6 +397,11 @@ class Test {
return newContract; return newContract;
} }
// EmbarkJS require
if (path.startsWith(embarkJSPrefix)) {
return this.embarkjs;
}
throw new Error(__('Unknown module %s', path)); throw new Error(__('Unknown module %s', path));
} }
} }

View File

@ -36,12 +36,21 @@ const prepareInitialFile = async (file: File) => {
return await file.content; return await file.content;
} }
const destination = fs.dappPath(".embark", file.path); let to = file.path.includes(fs.dappPath(".embark")) ? file.path : fs.dappPath(".embark", file.path);
to = path.normalize(to);
if (file.type === Types.dappFile || file.type === Types.custom) { if (file.type === Types.dappFile || file.type === Types.custom) {
fs.copySync(fs.dappPath(file.path), destination); if (file.resolver) {
fs.mkdirpSync(path.dirname(to));
fs.writeFileSync(to, await file.content);
} else {
const from = file.path.includes(fs.dappPath()) ? file.path : fs.dappPath(file.path);
if (from !== to) {
fs.copySync(from, to);
}
}
} }
file.path = destination; file.path = to;
}; };
const buildNewFile = (file: File, importPath: string) => { const buildNewFile = (file: File, importPath: string) => {
@ -63,24 +72,30 @@ const buildNewFile = (file: File, importPath: string) => {
// imported from node_modules, ie import "@aragon/os/contracts/acl/ACL.sol" // imported from node_modules, ie import "@aragon/os/contracts/acl/ACL.sol"
if (isNodeModule(importPath)) { if (isNodeModule(importPath)) {
from = resolve(importPath); from = resolve(importPath);
to = fs.dappPath(".embark", "node_modules", importPath); to = importPath.includes(fs.dappPath(".embark")) ? importPath : fs.dappPath(".embark", "node_modules", importPath);
fs.copySync(from, to); to = path.normalize(to);
return new File({ path: to, type: Types.dappFile, originalPath: from }); if (from !== to) {
fs.copySync(from, to);
}
return new File({ path: to, type: Types.dappFile });
} }
// started with node_modules then further imports local paths in it's own repo/directory // started with node_modules then further imports local paths in it's own repo/directory
if (isEmbarkNodeModule(file.path)) { if (isEmbarkNodeModule(file.path)) {
from = path.join(path.dirname(file.path.replace(".embark", ".")), importPath); from = path.join(path.dirname(file.path.replace(".embark", ".")), importPath);
to = path.join(path.dirname(file.path), importPath); to = path.normalize(path.join(path.dirname(file.path), importPath));
fs.copySync(from, to); fs.copySync(from, to);
return new File({ path: to, type: Types.dappFile, originalPath: from }); return new File({ path: to, type: Types.dappFile, originalPath: from });
} }
// local import, ie import "../path/to/contract" or "./path/to/contract" // local import, ie import "../path/to/contract" or "./path/to/contract"
from = path.join(path.dirname(file.path.replace(".embark", ".")), importPath); from = path.join(path.dirname(file.path.replace(".embark", ".")), importPath);
to = path.join(path.dirname(file.path), importPath); if (importPath === "remix_tests.sol") {
to = path.normalize(fs.dappPath(".embark", "remix_tests.sol"));
fs.copySync(from, to); } else {
to = path.normalize(path.join(path.dirname(file.path), importPath));
fs.copySync(from, to);
}
return new File({ path: to, type: Types.dappFile, originalPath: from }); return new File({ path: to, type: Types.dappFile, originalPath: from });
}; };
@ -129,7 +144,7 @@ const replaceImports = (remapImports: RemapImport[]) => {
Object.keys(byPath).forEach((p) => { Object.keys(byPath).forEach((p) => {
let source = fs.readFileSync(p, "utf-8"); let source = fs.readFileSync(p, "utf-8");
byPath[p].forEach(({ remapping }) => { byPath[p].forEach(({ remapping }) => {
source = source.replace(`import "${remapping.prefix}"`, `import "${remapping.target}"`); source = source.replace(`import "${remapping.prefix}"`, `import "${remapping.target.replace(/\\/g, "/")}"`);
}); });
fs.writeFileSync(p, source); fs.writeFileSync(p, source);
}); });
@ -138,10 +153,10 @@ const replaceImports = (remapImports: RemapImport[]) => {
const addRemappingsToFile = (file: File, remapImports: RemapImport[]) => { const addRemappingsToFile = (file: File, remapImports: RemapImport[]) => {
const byPath: { [path: string]: [{ remapping: ImportRemapping }] } = groupBy(remapImports, "path"); const byPath: { [path: string]: [{ remapping: ImportRemapping }] } = groupBy(remapImports, "path");
const paths = Object.keys(byPath); const paths = Object.keys(byPath);
if (paths) { if (paths.length) {
file.importRemappings = []; // clear as we already have the first remapping added file.importRemappings = []; // clear as we already have the first remapping added
paths.forEach((p) => { paths.forEach((p) => {
const [...remappings] = byPath[p].map((importRemapping) => importRemapping.remapping); const remappings = byPath[p].map((importRemapping) => importRemapping.remapping);
file.importRemappings = file.importRemappings.concat(remappings); file.importRemappings = file.importRemappings.concat(remappings);
}); });
} }
@ -149,26 +164,21 @@ const addRemappingsToFile = (file: File, remapImports: RemapImport[]) => {
const resolve = (input: string) => { const resolve = (input: string) => {
try { try {
const result = require.resolve(input, { paths: [fs.dappPath("node_modules"), fs.embarkPath("node_modules")] }); return require.resolve(input, { paths: [fs.dappPath("node_modules"), fs.embarkPath("node_modules")] });
return result;
} catch (e) { } catch (e) {
return ""; return "";
} }
}; };
export const prepareForCompilation = async (file: File, isCoverage = false) => { export const prepareForCompilation = async (file: File, isCoverage = false) => {
if (!file.isPrepared) { await prepareInitialFile(file);
await prepareInitialFile(file); const remapImports = await rescursivelyFindRemapImports(file);
const remapImports = await rescursivelyFindRemapImports(file); replaceImports(remapImports);
replaceImports(remapImports); // add all remappings to top-level file
// add all remappings to top-level file addRemappingsToFile(file, remapImports);
addRemappingsToFile(file, remapImports);
// set flag to prevent copying, remapping, and changing of paths again
file.isPrepared = true;
}
let content; let content;
if (file.type === Types.http) { if (file.type === Types.http || file.type === Types.custom) {
content = (await fs.readFile(file.path)).toString(); content = (await fs.readFile(file.path)).toString();
} else { } else {
content = await file.content; content = await file.content;

View File

@ -29,6 +29,7 @@ describe('embark.CodeGenerator', function() {
} }
]; ];
const currentSolcVersion = require('../../package.json').dependencies.solc;
const TestEvents = { const TestEvents = {
request: (cmd, cb) => { request: (cmd, cb) => {
cb(currentSolcVersion); cb(currentSolcVersion);

View File

@ -191,13 +191,12 @@ describe('embark.Config', function () {
const expected = [ const expected = [
{ {
"type": "http", "type": "http",
"externalUrl": "https://raw.githubusercontent.com/embark-framework/embark/master/test_dapps/packages/test_app/app/contracts/simple_storage.sol", "externalUrl": "https://raw.githubusercontent.com/embark-framework/embark/master/test_dapps/test_app/app/contracts/simple_storage.sol",
"path": fs.dappPath(".embark/contracts/embark-framework/embark/master/test_dapps/packages/test_app/app/contracts/simple_storage.sol"), "path": fs.dappPath(".embark/contracts/embark-framework/embark/master/test_dapps/test_app/app/contracts/simple_storage.sol"),
"originalPath": ".embark/contracts/embark-framework/embark/master/test_dapps/packages/test_app/app/contracts/simple_storage.sol", "originalPath": ".embark/contracts/embark-framework/embark/master/test_dapps/test_app/app/contracts/simple_storage.sol",
"pluginPath": '', "pluginPath": '',
"basedir": "", "basedir": "",
"importRemappings": [], "importRemappings": [],
"isPrepared": false,
"resolver": undefined, "resolver": undefined,
"storageConfig": undefined, "storageConfig": undefined,
"providerUrl": "" "providerUrl": ""
@ -210,7 +209,6 @@ describe('embark.Config', function () {
"pluginPath": '', "pluginPath": '',
"basedir": "", "basedir": "",
"importRemappings": [], "importRemappings": [],
"isPrepared": false,
"resolver": undefined, "resolver": undefined,
"storageConfig": undefined, "storageConfig": undefined,
"providerUrl": "" "providerUrl": ""
@ -223,7 +221,6 @@ describe('embark.Config', function () {
"pluginPath": '', "pluginPath": '',
"basedir": "", "basedir": "",
"importRemappings": [], "importRemappings": [],
"isPrepared": false,
"resolver": undefined, "resolver": undefined,
"storageConfig": undefined, "storageConfig": undefined,
"providerUrl": "" "providerUrl": ""

View File

@ -7,7 +7,7 @@ let version = require('../../package.json').version;
describe('embark.Console', function() { describe('embark.Console', function() {
let ipc = new IPC({ipcRole: 'none'}); let ipc = new IPC({ipcRole: 'none'});
let events = {once: () => {}, setCommandHandler: () => {}, emit: () => {}, on: () => {}}; let events = {once: () => {}, setCommandHandler: () => {}, emit: () => {}, on: () => {}, request: () => {}};
let plugins = new Plugins({plugins: {}, events: events}); let plugins = new Plugins({plugins: {}, events: events});
let embarkObject = { let embarkObject = {
registerAPICall: () => {}, registerAPICall: () => {},

View File

@ -1,17 +1,17 @@
/*globals describe, it, before*/ /*globals describe, it*/
const {File, Types} = require("../lib/core/file"); const {File, Types} = require("../lib/core/file");
const path = require("path"); const path = require("path");
const {expect, assert} = require("chai"); const {expect} = require("chai");
const fs = require("../lib/core/fs"); const fs = require("../lib/core/fs");
const fsNode = require("fs"); const fsNode = require("fs");
describe('embark.File', function () { describe('embark.File', function () {
describe('Read file contents', function () { describe('Read file contents', function () {
it('should be able to download a file when type is "http"', async () => { it('should be able to download a file when type is "http"', async () => {
const file = new File({externalUrl: 'https://raw.githubusercontent.com/embark-framework/embark/master/test_apps/test_app/app/contracts/simple_storage.sol', type: Types.http}); const file = new File({externalUrl: 'https://raw.githubusercontent.com/embark-framework/embark/master/test_dapps/test_app/app/contracts/simple_storage.sol', type: Types.http});
const content = await file.content; const content = await file.content;
const contentFromFileSystem = fsNode.readFileSync(path.join(fs.embarkPath(), "../../", "test_dapps/packages/test_app/app/contracts/simple_storage.sol")).toString(); const contentFromFileSystem = fsNode.readFileSync(path.join(fs.embarkPath(), "../../", "test_dapps/test_app/app/contracts/simple_storage.sol")).toString();
expect(content).to.equal(contentFromFileSystem); expect(content).to.equal(contentFromFileSystem);
}); });

View File

@ -18,42 +18,42 @@ describe('embark.RemapImports', function () {
it("should find and add remappings for all recursive imports", (done) => { it("should find and add remappings for all recursive imports", (done) => {
expect(file.importRemappings[0]).to.deep.equal({ expect(file.importRemappings[0]).to.deep.equal({
prefix: "./recursive_test_1.sol", prefix: "./recursive_test_1.sol",
target: fs.dappPath(".embark/contracts/recursive_test_1.sol") target: path.normalize(fs.dappPath(".embark/contracts/recursive_test_1.sol"))
}); });
expect(file.importRemappings[1]).to.deep.equal({ expect(file.importRemappings[1]).to.deep.equal({
prefix: "./recursive_test_2.sol", prefix: "./recursive_test_2.sol",
target: fs.dappPath(".embark/contracts/recursive_test_2.sol") target: path.normalize(fs.dappPath(".embark/contracts/recursive_test_2.sol"))
}); });
expect(file.importRemappings[2]).to.deep.equal({ expect(file.importRemappings[2]).to.deep.equal({
prefix: "embark-test-contract-0/recursive_test_3.sol", prefix: "embark-test-contract-0/recursive_test_3.sol",
target: fs.dappPath(".embark/node_modules/embark-test-contract-0/recursive_test_3.sol") target: path.normalize(fs.dappPath(".embark/node_modules/embark-test-contract-0/recursive_test_3.sol"))
}); });
expect(file.importRemappings[3]).to.deep.equal({ expect(file.importRemappings[3]).to.deep.equal({
prefix: "embark-test-contract-1/recursive_test_4.sol", prefix: "embark-test-contract-1/recursive_test_4.sol",
target: fs.dappPath(".embark/node_modules/embark-test-contract-1/recursive_test_4.sol") target: path.normalize(fs.dappPath(".embark/node_modules/embark-test-contract-1/recursive_test_4.sol"))
}); });
done(); done();
}); });
it("should update the contract content to use the remapped imports", function (done) { it("should update the contract content to use the remapped imports", function (done) {
expect(content).to.not.contain("./recursive_test_1.sol"); expect(content).to.not.contain("./recursive_test_1.sol");
expect(content).to.contain(".embark/contracts/recursive_test_1.sol"); expect(content).to.contain(path.normalize(".embark/contracts/recursive_test_1.sol").replace(/\\/g, "/"));
let contractFromFilesystem = fsNode.readFileSync(fs.dappPath(".embark/contracts/recursive_test_0.sol")).toString(); let contractFromFilesystem = fsNode.readFileSync(fs.dappPath(".embark/contracts/recursive_test_0.sol")).toString();
expect(contractFromFilesystem).to.not.contain("./recursive_test_1.sol"); expect(contractFromFilesystem).to.not.contain("./recursive_test_1.sol");
expect(contractFromFilesystem).to.contain(".embark/contracts/recursive_test_1.sol"); expect(contractFromFilesystem).to.contain(path.normalize(".embark/contracts/recursive_test_1.sol").replace(/\\/g, "/"));
contractFromFilesystem = fsNode.readFileSync(fs.dappPath(".embark/contracts/recursive_test_1.sol")).toString(); contractFromFilesystem = fsNode.readFileSync(fs.dappPath(".embark/contracts/recursive_test_1.sol")).toString();
expect(contractFromFilesystem).to.not.contain("./recursive_test_2.sol"); expect(contractFromFilesystem).to.not.contain("./recursive_test_2.sol");
expect(contractFromFilesystem).to.contain(".embark/contracts/recursive_test_2.sol"); expect(contractFromFilesystem).to.contain(path.normalize(".embark/contracts/recursive_test_2.sol").replace(/\\/g, "/"));
contractFromFilesystem = fsNode.readFileSync(fs.dappPath(".embark/contracts/recursive_test_2.sol")).toString(); contractFromFilesystem = fsNode.readFileSync(fs.dappPath(".embark/contracts/recursive_test_2.sol")).toString();
expect(contractFromFilesystem).to.not.contain("import \"embark-test-contract-0/recursive_test_3.sol\""); expect(contractFromFilesystem).to.not.contain("import \"embark-test-contract-0/recursive_test_3.sol\"");
expect(contractFromFilesystem).to.contain(`import "${fs.dappPath(".embark/node_modules/embark-test-contract-0/recursive_test_3.sol")}"`); expect(contractFromFilesystem).to.contain(`import "${path.normalize(fs.dappPath(".embark/node_modules/embark-test-contract-0/recursive_test_3.sol")).replace(/\\/g, "/")}"`);
contractFromFilesystem = fsNode.readFileSync(fs.dappPath(".embark/node_modules/embark-test-contract-0/recursive_test_3.sol")).toString(); contractFromFilesystem = fsNode.readFileSync(fs.dappPath(".embark/node_modules/embark-test-contract-0/recursive_test_3.sol")).toString();
expect(contractFromFilesystem).to.not.contain("import \"embark-test-contract-1/recursive_test_4.sol\""); expect(contractFromFilesystem).to.not.contain("import \"embark-test-contract-1/recursive_test_4.sol\"");
expect(contractFromFilesystem).to.contain(`import "${fs.dappPath(".embark/node_modules/embark-test-contract-1/recursive_test_4.sol")}"`); expect(contractFromFilesystem).to.contain(`import "${path.normalize(fs.dappPath(".embark/node_modules/embark-test-contract-1/recursive_test_4.sol")).replace(/\\/g, "/")}"`);
done(); done();
}); });
@ -62,41 +62,41 @@ describe('embark.RemapImports', function () {
describe('Import remappings from external URL', function () { describe('Import remappings from external URL', function () {
before('do the external HTTP contract remappings', async () => { before('do the external HTTP contract remappings', async () => {
file = new File({externalUrl: 'https://github.com/embark-framework/embark/blob/master/src/test/contracts/recursive_test_0.sol', type: Types.http}); file = new File({externalUrl: 'https://github.com/embark-framework/embark/master/packages/embark/src/test/contracts/recursive_test_0.sol', type: Types.http});
content = await remapImports.prepareForCompilation(file); content = await remapImports.prepareForCompilation(file);
}); });
it("should find and add remappings for all recursive imports", (done) => { it("should find and add remappings for all recursive imports", (done) => {
expect(file.importRemappings[0]).to.deep.equal({ expect(file.importRemappings[0]).to.deep.equal({
prefix: "./recursive_test_1.sol", prefix: "./recursive_test_1.sol",
target: fs.dappPath(".embark/contracts/embark-framework/embark/master/src/test/contracts/recursive_test_1.sol") target: path.normalize(fs.dappPath(".embark/contracts/embark-framework/embark/master/packages/embark/src/test/contracts/recursive_test_1.sol"))
}); });
expect(file.importRemappings[1]).to.deep.equal({ expect(file.importRemappings[1]).to.deep.equal({
prefix: "./recursive_test_2.sol", prefix: "./recursive_test_2.sol",
target: fs.dappPath(".embark/contracts/embark-framework/embark/master/src/test/contracts/recursive_test_2.sol") target: path.normalize(fs.dappPath(".embark/contracts/embark-framework/embark/master/packages/embark/src/test/contracts/recursive_test_2.sol"))
}); });
expect(file.importRemappings[2]).to.deep.equal({ expect(file.importRemappings[2]).to.deep.equal({
prefix: "embark-test-contract-0/recursive_test_3.sol", prefix: "embark-test-contract-0/recursive_test_3.sol",
target: fs.dappPath(".embark/contracts/embark-framework/embark/master/src/test/contracts/embark-test-contract-0/recursive_test_3.sol") target: path.normalize(fs.dappPath(".embark/contracts/embark-framework/embark/master/packages/embark/src/test/contracts/embark-test-contract-0/recursive_test_3.sol"))
}); });
done(); done();
}); });
it("should update the contract content to use the remapped imports", function (done) { it("should update the contract content to use the remapped imports", function (done) {
expect(content).to.not.contain("./recursive_test_1.sol"); expect(content).to.not.contain("./recursive_test_1.sol");
expect(content).to.contain(".embark/contracts/embark-framework/embark/master/src/test/contracts/recursive_test_1.sol"); expect(content).to.contain(path.normalize(".embark/contracts/embark-framework/embark/master/packages/embark/src/test/contracts/recursive_test_1.sol").replace(/\\/g, "/"));
let contractFromFilesystem = fsNode.readFileSync(fs.dappPath(".embark/contracts/embark-framework/embark/master/src/test/contracts/recursive_test_0.sol")).toString(); let contractFromFilesystem = fsNode.readFileSync(fs.dappPath(".embark/contracts/embark-framework/embark/master/packages/embark/src/test/contracts/recursive_test_0.sol")).toString();
expect(contractFromFilesystem).to.not.contain("./recursive_test_1.sol"); expect(contractFromFilesystem).to.not.contain("./recursive_test_1.sol");
expect(contractFromFilesystem).to.contain(".embark/contracts/embark-framework/embark/master/src/test/contracts/recursive_test_1.sol"); expect(contractFromFilesystem).to.contain(path.normalize(".embark/contracts/embark-framework/embark/master/packages/embark/src/test/contracts/recursive_test_1.sol").replace(/\\/g, "/"));
contractFromFilesystem = fsNode.readFileSync(fs.dappPath(".embark/contracts/embark-framework/embark/master/src/test/contracts/recursive_test_1.sol")).toString(); contractFromFilesystem = fsNode.readFileSync(fs.dappPath(".embark/contracts/embark-framework/embark/master/packages/embark/src/test/contracts/recursive_test_1.sol")).toString();
expect(contractFromFilesystem).to.not.contain("./recursive_test_2.sol"); expect(contractFromFilesystem).to.not.contain("./recursive_test_2.sol");
expect(contractFromFilesystem).to.contain(".embark/contracts/embark-framework/embark/master/src/test/contracts/recursive_test_2.sol"); expect(contractFromFilesystem).to.contain(path.normalize(".embark/contracts/embark-framework/embark/master/packages/embark/src/test/contracts/recursive_test_2.sol").replace(/\\/g, "/"));
contractFromFilesystem = fsNode.readFileSync(fs.dappPath(".embark/contracts/embark-framework/embark/master/src/test/contracts/recursive_test_2.sol")).toString(); contractFromFilesystem = fsNode.readFileSync(fs.dappPath(".embark/contracts/embark-framework/embark/master/packages/embark/src/test/contracts/recursive_test_2.sol")).toString();
expect(contractFromFilesystem).to.not.contain("import \"embark-test-contract-0/recursive_test_3.sol\""); expect(contractFromFilesystem).to.not.contain("import \"embark-test-contract-0/recursive_test_3.sol\"");
expect(contractFromFilesystem).to.contain(`import "${fs.dappPath(".embark/contracts/embark-framework/embark/master/src/test/contracts/embark-test-contract-0/recursive_test_3.sol")}"`); expect(contractFromFilesystem).to.contain(`import "${path.normalize(fs.dappPath(".embark/contracts/embark-framework/embark/master/packages/embark/src/test/contracts/embark-test-contract-0/recursive_test_3.sol")).replace(/\\/g, "/")}"`);
done(); done();
}); });

View File

@ -1,6 +1,6 @@
/*globals describe, it*/ /*globals describe, it*/
const TestLogger = require('../lib/utils/test_logger'); const TestLogger = require('../lib/utils/test_logger');
const VM = require('../lib/core/modules/coderunner/vm'); const VM = require('../lib/modules/codeRunner/vm');
const {expect} = require('chai'); const {expect} = require('chai');
describe('embark.vm', function () { describe('embark.vm', function () {

View File

@ -47,6 +47,18 @@ Blockchain.connect = function(options, callback) {
return connect(options); return connect(options);
}; };
Blockchain.connectConsole = function(doneCb) {
this.doFirst((cb) => {
this.blockchainConnector.getAccounts((err, accounts) => {
if (accounts) {
this.blockchainConnector.setDefaultAccount(accounts[0]);
}
cb(err);
doneCb(err);
});
});
};
Blockchain.doFirst = function(todo) { Blockchain.doFirst = function(todo) {
todo((err) => { todo((err) => {
this.done = true; this.done = true;

View File

@ -29,12 +29,18 @@ function getWeb3Location(embark) {
} }
module.exports = async (embark) => { module.exports = async (embark) => {
let blockchainConnectorReady = false;
await whenRuncodeReady(embark); await whenRuncodeReady(embark);
const web3LocationPromise = getWeb3Location(embark); const web3LocationPromise = getWeb3Location(embark);
embark.events.setCommandHandler('blockchain:connector:ready', (cb) => { embark.events.setCommandHandler('blockchain:connector:ready', (cb) => {
if (blockchainConnectorReady) {
return cb();
}
web3LocationPromise.then((_web3Location) => { web3LocationPromise.then((_web3Location) => {
blockchainConnectorReady = true;
embark.events.emit('blockchain:connector:ready');
cb(); cb();
}); });
}); });
@ -54,11 +60,11 @@ module.exports = async (embark) => {
code += "\nEmbarkJS.Blockchain.registerProvider('web3', web3Connector);"; code += "\nEmbarkJS.Blockchain.registerProvider('web3', web3Connector);";
code += "\nEmbarkJS.Blockchain.setProvider('web3', {});"; code += "\nEmbarkJS.Blockchain.setProvider('web3', {web3});";
embark.addCodeToEmbarkJS(code); embark.addCodeToEmbarkJS(code);
code = "EmbarkJS.Blockchain.setProvider('web3', {});"; code = "EmbarkJS.Blockchain.setProvider('web3', {web3});";
const shouldInit = (_config) => { const shouldInit = (_config) => {
return true; return true;

View File

@ -1,7 +1,7 @@
/*global Web3*/ /*global Web3*/
const web3Connector = {}; const web3Connector = {};
web3Connector.init = function(_config) { web3Connector.init = function(config) {
global.web3 = config.web3 || global.web3; global.web3 = config.web3 || global.web3;
// Check if the global web3 object uses the old web3 (0.x) // Check if the global web3 object uses the old web3 (0.x)
if (global.web3 && typeof global.web3.version !== 'string') { if (global.web3 && typeof global.web3.version !== 'string') {