Skip to content
This repository has been archived by the owner on Sep 7, 2023. It is now read-only.

Commit

Permalink
Merge 9582339 into ccf6e3a
Browse files Browse the repository at this point in the history
  • Loading branch information
jeromesimeon committed Feb 3, 2019
2 parents ccf6e3a + 9582339 commit 0cdfff1
Show file tree
Hide file tree
Showing 14 changed files with 89 additions and 44 deletions.
4 changes: 4 additions & 0 deletions examples/startendtest/logic.ergo
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ define transaction Request {
}

define transaction TestResponse {
now: DateTime,
date: DateTime,
startOfDay: DateTime,
endOfDay: DateTime
}
Expand All @@ -32,6 +34,8 @@ contract StartEndTest over TemplateModel {
clause test(request : Request) : TestResponse {
let date : DateTime = request.date;
return TestResponse{
now: now(),
date: date,
startOfDay: startOf(date, "days"),
endOfDay: endOf(date, "days")
}
Expand Down
5 changes: 3 additions & 2 deletions packages/ergo-cli/bin/ergorun.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@
'use strict';

const Commands = require('../lib/commands');
const Moment = require('moment');
const Logger = require('@accordproject/ergo-compiler/lib/logger');

const argv =
require('yargs')
.demandOption(['contract', 'request', 'contractName'], 'Please provide at least contract, request and contractName')
.demandOption(['contract', 'request', 'contractName', 'currentTime'], 'Please provide at least contract, request and contractName')
.usage('Usage: $0 --contract [file] --state [file] --request [file] [ctos] [ergos]')
.option('contract', {
describe: 'path to the contract data'
Expand All @@ -39,7 +40,7 @@ const argv =
.option('currentTime', {
describe: 'the current time',
type: 'string',
default: null
default: Moment().format() // Defaults to now
})
.option('state', {
describe: 'path to the state data',
Expand Down
2 changes: 1 addition & 1 deletion packages/ergo-cli/lib/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class Commands {
const firstRequest = requestsJson[0];
let initResponse;
if (statePath === null) {
initResponse = ErgoEngine.init(ergoSources,ctoSources,'es6',contractJson,firstRequest,contractName);
initResponse = ErgoEngine.init(ergoSources,ctoSources,'es6',contractJson,firstRequest,contractName,currentTime);
} else {
const stateJson = JSON.parse(Fs.readFileSync(statePath, 'utf8'));
initResponse = ErgoEngine.execute(ergoSources,ctoSources,'es6',contractJson,firstRequest,stateJson,contractName,currentTime);
Expand Down
6 changes: 5 additions & 1 deletion packages/ergo-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@
"lint": "eslint .",
"postlint": "npm run licchk",
"licchk": "license-check",
"test:mocha": "mocha",
"test:cucumber": "cucumber-js test/features --require .cucumber.js --world-parameters '{\"rootdir\":\"./test\"}'",
"test": "mocha && npm run test:cucumber && nyc mocha"
"test:all": "npm run test:mocha && npm run test:cucumber",
"test:cov": "nyc npm run test:all",
"test": "npm run test:all && npm run test:cov"
},
"contributors": [
{
Expand All @@ -27,6 +30,7 @@
"dependencies": {
"@accordproject/ergo-compiler": "0.6.2",
"@accordproject/ergo-engine": "0.6.2",
"moment": "2.20.1",
"jsome": "2.5.0",
"winston": "^3.2.1",
"yargs": "9.0.1",
Expand Down
22 changes: 11 additions & 11 deletions packages/ergo-cli/test/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,15 @@ describe('ergo', () => {
const contractPath = Path.resolve(__dirname, 'data/helloworld', 'contract.json');
const requestPath = Path.resolve(__dirname, 'data/helloworld', 'request.json');
const statePath = Path.resolve(__dirname, 'data/helloworld', 'state.json');
const result = await Commands.execute([ergoPath], [ctoPath], contractPath, [requestPath], statePath, 'org.accordproject.helloworld.HelloWorld', null);
const result = await Commands.execute([ergoPath], [ctoPath], contractPath, [requestPath], statePath, 'org.accordproject.helloworld.HelloWorld', '1970-01-01T00:00:00Z');
result.response.output.should.equal('Hello Fred Blogs (Accord Project)');
});
it('should throw when executing a smart Ergo contract without its cto', async function () {
const ergoPath = Path.resolve(__dirname, 'data/helloworld', 'logic.ergo');
const contractPath = Path.resolve(__dirname, 'data/helloworld', 'contract.json');
const requestPath = Path.resolve(__dirname, 'data/helloworld', 'request.json');
const statePath = Path.resolve(__dirname, 'data/helloworld', 'state.json');
const result = await Commands.execute([ergoPath], undefined, contractPath, [requestPath], statePath, 'org.accordproject.helloworld.HelloWorld', null);
const result = await Commands.execute([ergoPath], undefined, contractPath, [requestPath], statePath, 'org.accordproject.helloworld.HelloWorld', '1970-01-01T00:00:00Z');
result.error.kind.should.equal('CompilationError');
result.error.message.should.equal('Cannot find type with name \'TemplateModel\'');
result.error.locstart.should.deep.equal({ 'line' : 16, 'character' : 25 });
Expand All @@ -53,7 +53,7 @@ describe('ergo', () => {
const contractPath = Path.resolve(__dirname, 'data/helloworld', 'contract.json');
const requestPath = Path.resolve(__dirname, 'data/helloworld', 'request.json');
const statePath = Path.resolve(__dirname, 'data/helloworld', 'state.json');
const result = await Commands.execute(undefined, [ctoPath], contractPath, [requestPath], statePath, 'org.accordproject.helloworld.HelloWorld', null);
const result = await Commands.execute(undefined, [ctoPath], contractPath, [requestPath], statePath, 'org.accordproject.helloworld.HelloWorld', '1970-01-01T00:00:00Z');
result.error.message.should.equal('No input ergo found');
});
});
Expand All @@ -64,7 +64,7 @@ describe('ergo', () => {
const contractPath = Path.resolve(__dirname, 'data/helloworldstate', 'contract.json');
const requestPath = Path.resolve(__dirname, 'data/helloworldstate', 'request.json');
const statePath = Path.resolve(__dirname, 'data/helloworldstate', 'state.json');
const result = await Commands.execute([ergoPath], [ctoPath], contractPath, [requestPath], statePath, 'org.accordproject.helloworldstate.HelloWorldState', null);
const result = await Commands.execute([ergoPath], [ctoPath], contractPath, [requestPath], statePath, 'org.accordproject.helloworldstate.HelloWorldState', '1970-01-01T00:00:00Z');
result.response.output.should.equal('Hello Fred Blogs (Accord Project) (1.0)');
});
it('should execute a smart Ergo contract with state thrice', async function () {
Expand All @@ -73,7 +73,7 @@ describe('ergo', () => {
const contractPath = Path.resolve(__dirname, 'data/helloworldstate', 'contract.json');
const requestPath = Path.resolve(__dirname, 'data/helloworldstate', 'request.json');
const statePath = Path.resolve(__dirname, 'data/helloworldstate', 'state.json');
const result = await Commands.execute([ergoPath], [ctoPath], contractPath, [requestPath,requestPath,requestPath], statePath, 'org.accordproject.helloworldstate.HelloWorldState', null);
const result = await Commands.execute([ergoPath], [ctoPath], contractPath, [requestPath,requestPath,requestPath], statePath, 'org.accordproject.helloworldstate.HelloWorldState', '1970-01-01T00:00:00Z');
result.response.output.should.equal('Hello Fred Blogs (Accord Project) (3.0)');
});
});
Expand All @@ -83,7 +83,7 @@ describe('ergo', () => {
const ctoPath = Path.resolve(__dirname, 'data/installment-sale', 'model.cto');
const contractPath = Path.resolve(__dirname, 'data/installment-sale', 'contract.json');
const requestInitPath = Path.resolve(__dirname, 'data/installment-sale', 'request-init.json');
const result = await Commands.execute([ergoPath], [ctoPath], contractPath, [requestInitPath], null, 'org.accordproject.installmentsale.InstallmentSale', null);
const result = await Commands.execute([ergoPath], [ctoPath], contractPath, [requestInitPath], null, 'org.accordproject.installmentsale.InstallmentSale', '1970-01-01T00:00:00Z');
result.state.balance_remaining.should.equal(10000.00);
});
it('should initialize a smart Ergo contract and execute one request', async function () {
Expand All @@ -92,7 +92,7 @@ describe('ergo', () => {
const contractPath = Path.resolve(__dirname, 'data/installment-sale', 'contract.json');
const requestInitPath = Path.resolve(__dirname, 'data/installment-sale', 'request-init.json');
const requestPath = Path.resolve(__dirname, 'data/installment-sale', 'request.json');
const result = await Commands.execute([ergoPath], [ctoPath], contractPath, [requestInitPath,requestPath], null, 'org.accordproject.installmentsale.InstallmentSale', null);
const result = await Commands.execute([ergoPath], [ctoPath], contractPath, [requestInitPath,requestPath], null, 'org.accordproject.installmentsale.InstallmentSale', '1970-01-01T00:00:00Z');
result.state.balance_remaining.should.equal(7612.499999999999);
});
});
Expand All @@ -104,7 +104,7 @@ describe('ergo', () => {
const contractPath = Path.resolve(__dirname, 'data/promissory-note', 'contract.json');
const requestPath = Path.resolve(__dirname, 'data/promissory-note', 'request.json');
const statePath = Path.resolve(__dirname, 'data/promissory-note', 'state.json');
const result = await Commands.execute([ergoPath], [ctoPath1, ctoPath2], contractPath, [requestPath], statePath, 'org.accordproject.promissorynote.PromissoryNote', null);
const result = await Commands.execute([ergoPath], [ctoPath1, ctoPath2], contractPath, [requestPath], statePath, 'org.accordproject.promissorynote.PromissoryNote', '1970-01-01T00:00:00Z');
result.response.outstandingBalance.should.equal(1425.4396822450633);
});
});
Expand All @@ -117,7 +117,7 @@ describe('ergo', () => {
const contractPath = Path.resolve(__dirname, 'data/promissory-note', 'contract.json');
const requestPath = Path.resolve(__dirname, 'data/promissory-note', 'request.json');
const statePath = Path.resolve(__dirname, 'data/promissory-note', 'state.json');
const result = await Commands.execute([ergoPath1, ergoPath2], [ctoPath1, ctoPath2], contractPath, [requestPath], statePath, 'org.accordproject.promissorynote.PromissoryNote', null);
const result = await Commands.execute([ergoPath1, ergoPath2], [ctoPath1, ctoPath2], contractPath, [requestPath], statePath, 'org.accordproject.promissorynote.PromissoryNote', '1970-01-01T00:00:00Z');
result.response.outstandingBalance.should.equal(1425.4396822450633);
});
});
Expand All @@ -128,7 +128,7 @@ describe('ergo', () => {
const contractPath = Path.resolve(__dirname, 'data/acceptance-of-delivery', 'contract.json');
const requestPath = Path.resolve(__dirname, 'data/acceptance-of-delivery', 'request.json');
const statePath = Path.resolve(__dirname, 'data/acceptance-of-delivery', 'state.json');
const result = await Commands.execute([ergoPath], [ctoPath], contractPath, [requestPath], statePath, 'org.accordproject.acceptanceofdelivery.AcceptanceOfDelivery', '20 Jan 2019 16:34:00 EST');
const result = await Commands.execute([ergoPath], [ctoPath], contractPath, [requestPath], statePath, 'org.accordproject.acceptanceofdelivery.AcceptanceOfDelivery', '2019-01-20T16:34:00-05:00');
result.response.status.should.equal('OUTSIDE_INSPECTION_PERIOD');
});
it('should execute a smart Ergo contract', async function () {
Expand All @@ -137,7 +137,7 @@ describe('ergo', () => {
const contractPath = Path.resolve(__dirname, 'data/acceptance-of-delivery', 'contract.json');
const requestPath = Path.resolve(__dirname, 'data/acceptance-of-delivery', 'request.json');
const statePath = Path.resolve(__dirname, 'data/acceptance-of-delivery', 'state.json');
const result = await Commands.execute([ergoPath], [ctoPath], contractPath, [requestPath], statePath, 'org.accordproject.acceptanceofdelivery.AcceptanceOfDelivery', '11 Jan 2019 16:34:00 EST');
const result = await Commands.execute([ergoPath], [ctoPath], contractPath, [requestPath], statePath, 'org.accordproject.acceptanceofdelivery.AcceptanceOfDelivery', '2019-01-11T16:34:00-05:00');
result.response.status.should.equal('PASSED_TESTING');
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ Feature: Acceptance of delivery Contract
Then the initial state should be the default state

Scenario: The contract gets initialized, with a current time
When the current time is "11 Jan 2019 16:34:00 EST"
When the current time is "2019-01-11T16:34:00-05:00"
Then the initial state should be the default state

Scenario: The contract should accept inspection if received within delivery period
When the current time is "11 Jan 2019 16:34:00 EST"
When the current time is "2019-01-11T16:34:00-05:00"
And it receives the request
"""
{
Expand Down
6 changes: 4 additions & 2 deletions packages/ergo-engine/lib/cucumber-steps.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,9 @@ async function init(rootdir, target,ergo,models,contractName,currentTime,contrac
} else {
actualTarget = defaultTarget;
}
const now = currentTime ? currentTime : '1970-01-01T00:00:00Z';
const requestJson = { '$class' : 'org.accordproject.cicero.runtime.Request' };
return ErgoEngine.init(ergoSources, ctoSources, actualTarget, contractJson, requestJson, contractName, currentTime);
return ErgoEngine.init(ergoSources, ctoSources, actualTarget, contractJson, requestJson, contractName, now);
}

/**
Expand Down Expand Up @@ -135,7 +136,8 @@ async function send(rootdir, target,ergo,models,contractName,currentTime,contrac
} else {
actualStateJson = defaultState;
}
return ErgoEngine.execute(ergoSources, ctoSources, actualTarget, contractJson, requestJson, actualStateJson, contractName, currentTime);
const now = currentTime ? currentTime : '1970-01-01T00:00:00Z';
return ErgoEngine.execute(ergoSources, ctoSources, actualTarget, contractJson, requestJson, actualStateJson, contractName, now);
}

Given('the target platform {string}', function (target) {
Expand Down
28 changes: 20 additions & 8 deletions packages/ergo-engine/lib/ergo-engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,24 @@ const {
* @class
*/
class ErgoEngine {
/**
* Ensures there is a proper current time
*
* @param {string} currentTime the definition of 'now'
* @returns {object} if valid, the moment object for the current time
*/
static initCurrentTime(currentTime) {
if (!currentTime) {
throw new Error('Calls to Ergo engine should provide a current time');
}
const now = Moment.parseZone(currentTime, 'YYYY-MM-DDTHH:mm:ssZ', true);
if (now.isValid()) {
return now;
} else {
throw new Error(`${currentTime} is not a valid moment in format 'YYYY-MM-DDTHH:mm:ssZ'`);
}
}

/**
* Execute Ergo code compiled to ES6
*
Expand All @@ -42,10 +60,7 @@ class ErgoEngine {
* @returns {object} Promise to the result of execution
*/
static executeErgoCode(ergoCode,codeKind,contractJson,requestJson,stateJson,contractName,currentTime) {
let now = Moment();
if (currentTime) {
now = Moment.parseZone(currentTime);
}
const now = this.initCurrentTime(currentTime);
const vm = new VM({
timeout: 1000,
sandbox: {
Expand Down Expand Up @@ -88,10 +103,7 @@ class ErgoEngine {
* @returns {object} Promise to the result of initialization
*/
static initErgoCode(ergoCode,codeKind,contractJson,requestJson,contractName,currentTime) {
let now = Moment();
if (currentTime) {
now = Moment.parseZone(currentTime);
}
const now = this.initCurrentTime(currentTime);
const vm = new VM({
timeout: 1000,
sandbox: {
Expand Down
5 changes: 3 additions & 2 deletions packages/ergo-engine/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@
"licchk": "license-check",
"test:mocha": "mocha",
"test:cucumber": "cucumber-js test/features --require lib/cucumber-steps.js --world-parameters '{\"rootdir\":\"./test\"}'",
"test:cov": "nyc cucumber-js test/features --require lib/cucumber-steps.js --world-parameters '{\"rootdir\":\"./test\"}'",
"test": "npm run test:mocha && npm run test:cucumber && npm run test:cov"
"test:all": "npm run test:mocha && npm run test:cucumber",
"test:cov": "nyc npm run test:all",
"test": "npm run test:all && npm run test:cov"
},
"contributors": [
{
Expand Down
19 changes: 17 additions & 2 deletions packages/ergo-engine/test/ergo-engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ describe('Execute ES6', () => {
const request = test.request;
const state = test.state;
const contractName = test.contractName;
const currentTime = test.currentTime;
const currentTime = test.currentTime ? test.currentTime : '1970-01-01T00:00:00Z';
const expected = test.expected;
let resultKind;
if (expected.hasOwnProperty('compilationerror') || expected.hasOwnProperty('error')) {
Expand Down Expand Up @@ -128,7 +128,7 @@ describe('Execute ES5', () => {
const request = test.request;
const state = test.state;
const contractName = test.contractName;
const currentTime = test.currentTime;
const currentTime = test.currentTime ? test.currentTime : '1970-01-01T00:00:00Z';
const expected = test.expected;
let resultKind;
if (expected.hasOwnProperty('compilationerror') || expected.hasOwnProperty('error')) {
Expand Down Expand Up @@ -165,3 +165,18 @@ describe('Execute ES5', () => {
});
}
});
describe('Initialize current time', () => {
it('Should succeed for a well-formed date/time', function () {
const currentTime = ErgoEngine.initCurrentTime('1970-01-01T00:00:00Z');
return currentTime.format().should.equal('1970-01-01T00:00:00Z');
});
it('Should fail for a non-well-formed date/time', function () {
return (() => ErgoEngine.initCurrentTime('1970-01-01').format()).should.throw('1970-01-01 is not a valid moment in format \'YYYY-MM-DDTHH:mm:ssZ\'');
});
it('Should fail when currentTime is null', function () {
return (() => ErgoEngine.initCurrentTime(null).format()).should.throw('Calls to Ergo engine should provide a current time');
});
it('Should fail when currentTime is undefined', function () {
return (() => ErgoEngine.initCurrentTime(undefined).format()).should.throw('Calls to Ergo engine should provide a current time');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ Feature: Acceptance of delivery Contract
Then the initial state should be the default state

Scenario: The contract gets initialized, with a current time
When the current time is "11 Jan 2019 16:34:00 EST"
When the current time is "2019-01-11T16:34:00-05:00"
Then the initial state should be the default state

Scenario: The contract should accept inspection if received within delivery period
When the current time is "11 Jan 2019 16:34:00 EST"
When the current time is "2019-01-11T16:34:00-05:00"
And it receives the request
"""
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Feature: Late delivery contract
Then the initial state should be the default state

Scenario: The contract should return an error if called before the expected delivery date
When the current time is "11 Jan 2019 16:34:00 EST"
When the current time is "2019-01-11T16:34:00-05:00"
And it receives the request
"""
{
Expand All @@ -53,7 +53,7 @@ Feature: Late delivery contract
"""

Scenario: The contract should return the penalty amount but not allow the buyer to terminate
When the current time is "11 Jan 2019 16:34:00 EST"
When the current time is "2019-01-11T16:34:00-05:00"
When it receives the request
"""
{
Expand All @@ -74,7 +74,7 @@ Feature: Late delivery contract
"""

Scenario: The contract should return the penalty amount and allow the buyer to terminate
When the current time is "11 Jan 2019 16:34:00 EST"
When the current time is "2019-01-11T16:34:00-05:00"
When it receives the request
"""
{
Expand Down

0 comments on commit 0cdfff1

Please sign in to comment.