mirror of
https://github.com/fluencelabs/fluence-js.git
synced 2024-12-05 02:10:18 +00:00
JS SDK: fix host functions in mocha tests (#1003)
This commit is contained in:
parent
f0b4c7a718
commit
b79f0920d4
6
package-lock.json
generated
6
package-lock.json
generated
@ -25,9 +25,9 @@
|
||||
}
|
||||
},
|
||||
"@fluencelabs/aquamarine-stepper": {
|
||||
"version": "0.0.16",
|
||||
"resolved": "https://registry.npmjs.org/@fluencelabs/aquamarine-stepper/-/aquamarine-stepper-0.0.16.tgz",
|
||||
"integrity": "sha512-yrRMH2ysrxkhOGUe599urPopx6bon44qHppyvE6RKdrE1qVgxYKONWU+BNM+ouzIZ3UW5hoT0gQZ7lmI3HS30g=="
|
||||
"version": "0.0.21",
|
||||
"resolved": "https://registry.npmjs.org/@fluencelabs/aquamarine-stepper/-/aquamarine-stepper-0.0.21.tgz",
|
||||
"integrity": "sha512-bw0tdC5+fihzw+BxA02TrNIzMp2reuV21RqPMlDUExh2tbSzHYKBXKOxGsIY10j3QYWpHQZK9N341VnA3nw6Sw=="
|
||||
},
|
||||
"@sinonjs/commons": {
|
||||
"version": "1.7.2",
|
||||
|
@ -5,8 +5,8 @@
|
||||
"main": "./dist/fluence.js",
|
||||
"typings": "./dist/fluence.d.ts",
|
||||
"scripts": {
|
||||
"test": "mocha -r esm -r ts-node/register src/**/*.spec.ts",
|
||||
"test-ts": "ts-mocha -r esm -p tsconfig.json src/**/*.spec.ts",
|
||||
"test": "mocha --timeout 10000 -r esm -r ts-node/register src/**/*.spec.ts",
|
||||
"test-ts": "ts-mocha --timeout 10000 -r esm -p tsconfig.json src/**/*.spec.ts",
|
||||
"package:build": "NODE_ENV=production webpack && npm run package",
|
||||
"package": "tsc && rsync -r src/aqua/*.js dist/aqua",
|
||||
"start": "webpack-dev-server -p",
|
||||
@ -16,7 +16,7 @@
|
||||
"author": "Fluence Labs",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@fluencelabs/aquamarine-stepper": "0.0.16",
|
||||
"@fluencelabs/aquamarine-stepper": "0.0.21",
|
||||
"async": "3.2.0",
|
||||
"base64-js": "1.3.1",
|
||||
"bs58": "4.0.1",
|
||||
|
7
src/aqua/index.d.ts
vendored
7
src/aqua/index.d.ts
vendored
@ -11,7 +11,8 @@
|
||||
*/
|
||||
export function invoke(wasm: any, init_user_id: string, aqua: string, prev_data: string, data: string, log_level: string): string;
|
||||
export function ast(wasm: any, script: string): string;
|
||||
export function return_current_peer_id(wasm: any, peerId: string, arg0: any): void;
|
||||
export function return_call_service_result(wasm: any, ret: string, arg0: any): void;
|
||||
export function getStringFromWasm0(wasm: any, arg1: any, arg2: any): string
|
||||
export function getInt32Memory0(wasm: any): number[]
|
||||
export function passStringToWasm0(wasm: any, arg: any, malloc: any, realloc: any): number
|
||||
export let WASM_VECTOR_LEN: number;
|
||||
export function free(wasm: any, ptr: any, len: any): void
|
||||
|
||||
|
@ -36,7 +36,6 @@ const encodeString = (typeof cachedTextEncoder.encodeInto === 'function'
|
||||
});
|
||||
|
||||
export function passStringToWasm0(wasm, arg, malloc, realloc) {
|
||||
|
||||
if (realloc === undefined) {
|
||||
const buf = cachedTextEncoder.encode(arg);
|
||||
const ptr = malloc(buf.length);
|
||||
@ -57,8 +56,8 @@ export function passStringToWasm0(wasm, arg, malloc, realloc) {
|
||||
if (code > 0x7F) break;
|
||||
mem[ptr + offset] = code;
|
||||
}
|
||||
|
||||
if (offset !== len) {
|
||||
|
||||
if (offset !== 0) {
|
||||
arg = arg.slice(offset);
|
||||
}
|
||||
@ -69,7 +68,9 @@ export function passStringToWasm0(wasm, arg, malloc, realloc) {
|
||||
offset += ret.written;
|
||||
}
|
||||
|
||||
|
||||
WASM_VECTOR_LEN = offset;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
@ -132,3 +133,22 @@ export function ast(wasm, script) {
|
||||
wasm.__wbindgen_free(r0, r1);
|
||||
}
|
||||
}
|
||||
|
||||
export function return_current_peer_id(wasm, peerId, arg0) {
|
||||
var ptr0 = passStringToWasm0(wasm, peerId, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
var len0 = WASM_VECTOR_LEN;
|
||||
getInt32Memory0(wasm)[arg0 / 4 + 1] = len0;
|
||||
getInt32Memory0(wasm)[arg0 / 4 + 0] = ptr0;
|
||||
}
|
||||
|
||||
export function return_call_service_result(wasm, ret, arg0) {
|
||||
var ptr1 = passStringToWasm0(wasm, ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
var len1 = WASM_VECTOR_LEN;
|
||||
getInt32Memory0(wasm)[arg0 / 4 + 1] = len1;
|
||||
getInt32Memory0(wasm)[arg0 / 4 + 0] = ptr1;
|
||||
|
||||
}
|
||||
|
||||
export function free(wasm, ptr, len) {
|
||||
wasm.__wbindgen_free(ptr, len);
|
||||
}
|
||||
|
@ -21,12 +21,7 @@ import * as PeerId from "peer-id";
|
||||
import Multiaddr from "multiaddr"
|
||||
import {FluenceConnection} from "./fluenceConnection";
|
||||
import {Subscriptions} from "./subscriptions";
|
||||
import {
|
||||
enqueueParticle,
|
||||
getCurrentParticleId,
|
||||
popParticle,
|
||||
setCurrentParticleId
|
||||
} from "./globalState";
|
||||
import {enqueueParticle, getCurrentParticleId, popParticle, setCurrentParticleId} from "./globalState";
|
||||
import {instantiateInterpreter, InterpreterInvoke} from "./stepper";
|
||||
import log from "loglevel";
|
||||
import {waitService} from "./helpers/waitService";
|
||||
@ -34,6 +29,8 @@ import {ModuleConfig} from "./moduleConfig";
|
||||
|
||||
const bs58 = require('bs58')
|
||||
|
||||
const INFO_LOG_LEVEL = 2
|
||||
|
||||
export class FluenceClient {
|
||||
readonly selfPeerId: PeerId;
|
||||
readonly selfPeerIdStr: string;
|
||||
@ -84,12 +81,21 @@ export class FluenceClient {
|
||||
let stepperOutcomeStr = this.interpreter(particle.init_peer_id, particle.script, JSON.stringify(prevData), JSON.stringify(particle.data))
|
||||
let stepperOutcome: StepperOutcome = JSON.parse(stepperOutcomeStr);
|
||||
|
||||
log.info("inner interpreter outcome:");
|
||||
log.info(stepperOutcome);
|
||||
if (log.getLevel() <= INFO_LOG_LEVEL) {
|
||||
log.info("inner interpreter outcome:");
|
||||
let so = {...stepperOutcome}
|
||||
try {
|
||||
so.data = JSON.parse(Buffer.from(so.data).toString("utf8"));
|
||||
log.info(so);
|
||||
} catch (e) {
|
||||
log.info("cannot parse StepperOutcome data as JSON: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
// update data after aquamarine execution
|
||||
let newParticle: Particle = {...particle};
|
||||
newParticle.data = JSON.parse(stepperOutcome.call_path)
|
||||
newParticle.data = stepperOutcome.data
|
||||
|
||||
this.subscriptions.update(newParticle)
|
||||
|
||||
// do nothing if there is no `next_peer_pks` or if client isn't connected to the network
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
import {toByteArray} from "base64-js";
|
||||
import * as aqua from "./aqua"
|
||||
import {getInt32Memory0, getStringFromWasm0, passStringToWasm0, WASM_VECTOR_LEN} from "./aqua"
|
||||
import {return_current_peer_id, return_call_service_result, getStringFromWasm0, free} from "./aqua"
|
||||
|
||||
import {service} from "./service";
|
||||
import PeerId from "peer-id";
|
||||
@ -25,13 +25,13 @@ import {wasmBs64} from "@fluencelabs/aquamarine-stepper";
|
||||
import Instance = WebAssembly.Instance;
|
||||
import Exports = WebAssembly.Exports;
|
||||
import ExportValue = WebAssembly.ExportValue;
|
||||
import Imports = WebAssembly.Imports;
|
||||
|
||||
export type InterpreterInvoke = (init_user_id: string, script: string, prev_data: string, data: string) => string
|
||||
type ImportObject = {
|
||||
"./aquamarine_client_bg.js": {
|
||||
__wbg_callserviceimpl_7d3cf77a2722659e: (arg0: any, arg1: any, arg2: any, arg3: any, arg4: any, arg5: any, arg6: any) => void;
|
||||
__wbg_getcurrentpeeridimpl_154ce1848a306ff5: (arg0: any) => void
|
||||
__wbg_getcurrentpeeridimpl_154ce1848a306ff5: (arg0: any) => void;
|
||||
__wbindgen_throw: (arg: any) => void;
|
||||
};
|
||||
host: LogImport
|
||||
};
|
||||
@ -89,7 +89,7 @@ function log_import(cfg: HostImportsConfig): LogImport {
|
||||
log_utf8_string: (level: any, target: any, offset: any, size: any) => {
|
||||
let wasm = cfg.exports;
|
||||
try {
|
||||
let str = getStringFromWasm0(wasm, offset, size)
|
||||
let str = getStringFromWasm0(wasm, offset, size);
|
||||
|
||||
switch (level) {
|
||||
case 1:
|
||||
@ -106,7 +106,7 @@ function log_import(cfg: HostImportsConfig): LogImport {
|
||||
break;
|
||||
case 5:
|
||||
// we don't want a trace in trace logs
|
||||
log.debug(str)
|
||||
log.debug(str)
|
||||
break;
|
||||
}
|
||||
} finally {
|
||||
@ -127,25 +127,22 @@ function newImportObject(cfg: HostImportsConfig, peerId: PeerId): ImportObject {
|
||||
let serviceId = getStringFromWasm0(wasm, arg1, arg2)
|
||||
let fnName = getStringFromWasm0(wasm, arg3, arg4)
|
||||
let args = getStringFromWasm0(wasm, arg5, arg6);
|
||||
var ret = service(serviceId, fnName, args);
|
||||
let retStr = JSON.stringify(ret)
|
||||
var ptr0 = passStringToWasm0(wasm, retStr, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
var len0 = WASM_VECTOR_LEN;
|
||||
getInt32Memory0(wasm)[arg0 / 4 + 1] = len0;
|
||||
getInt32Memory0(wasm)[arg0 / 4 + 0] = ptr0;
|
||||
let serviceResult = service(serviceId, fnName, args);
|
||||
let resultStr = JSON.stringify(serviceResult)
|
||||
return_call_service_result(wasm, resultStr, arg0);
|
||||
} finally {
|
||||
call_export(wasm.__wbindgen_free, arg1, arg2);
|
||||
call_export(wasm.__wbindgen_free, arg3, arg4);
|
||||
call_export(wasm.__wbindgen_free, arg5, arg6);
|
||||
free(wasm, arg1, arg2)
|
||||
free(wasm, arg3, arg4)
|
||||
free(wasm, arg5, arg6)
|
||||
}
|
||||
},
|
||||
__wbg_getcurrentpeeridimpl_154ce1848a306ff5: (arg0: any) => {
|
||||
let peerIdStr = peerId.toB58String();
|
||||
let wasm = cfg.exports;
|
||||
var ret = peerId.toB58String();
|
||||
var ptr0 = passStringToWasm0(wasm, ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
var len0 = WASM_VECTOR_LEN;
|
||||
getInt32Memory0(wasm)[arg0 / 4 + 1] = len0;
|
||||
getInt32Memory0(wasm)[arg0 / 4 + 0] = ptr0;
|
||||
return_current_peer_id(wasm, peerIdStr, arg0);
|
||||
},
|
||||
__wbindgen_throw: (arg: any) => {
|
||||
console.log(`wbindgen throw: ${JSON.stringify(arg)}`);
|
||||
}
|
||||
},
|
||||
host: log_import(cfg)
|
||||
@ -157,7 +154,8 @@ function newLogImport(cfg: HostImportsConfig): ImportObject {
|
||||
host: log_import(cfg),
|
||||
"./aquamarine_client_bg.js": {
|
||||
__wbg_callserviceimpl_7d3cf77a2722659e: _ => {},
|
||||
__wbg_getcurrentpeeridimpl_154ce1848a306ff5: _ => {}
|
||||
__wbg_getcurrentpeeridimpl_154ce1848a306ff5: _ => {},
|
||||
__wbindgen_throw: _ => {}
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -165,7 +163,9 @@ function newLogImport(cfg: HostImportsConfig): ImportObject {
|
||||
/// Instantiates AIR interpreter, and returns its `invoke` function as closure
|
||||
/// NOTE: an interpreter is also called a stepper from time to time
|
||||
export async function instantiateInterpreter(peerId: PeerId): Promise<InterpreterInvoke> {
|
||||
let cfg = new HostImportsConfig((cfg) => newImportObject(cfg, peerId))
|
||||
let cfg = new HostImportsConfig((cfg) => {
|
||||
return newImportObject(cfg, peerId);
|
||||
})
|
||||
let instance = await interpreterInstance(cfg);
|
||||
|
||||
return (init_user_id: string, script: string, prev_data: string, data: string) => {
|
||||
|
@ -16,6 +16,6 @@
|
||||
|
||||
export interface StepperOutcome {
|
||||
ret_code: number,
|
||||
call_path: string,
|
||||
data: number[],
|
||||
next_peer_pks: string[]
|
||||
}
|
||||
|
@ -1,27 +1,115 @@
|
||||
import 'mocha';
|
||||
import Fluence from "../fluence";
|
||||
import {build} from "../particle";
|
||||
import { ServiceMultiple } from "../service";
|
||||
import { registerService } from "../globalState";
|
||||
import {ServiceMultiple} from "../service";
|
||||
import {registerService} from "../globalState";
|
||||
import {expect} from "chai";
|
||||
|
||||
describe("AIR", () => {
|
||||
it("call local function", async function () {
|
||||
let service = new ServiceMultiple("console");
|
||||
registerService(service);
|
||||
service.registerFunction('log', (args: any[]) => {
|
||||
console.log(`log: ${args}`);
|
||||
function registerPromiseService<T>(serviceId: string, fnName: string, f: (args: any[]) => T): Promise<T> {
|
||||
let service = new ServiceMultiple(serviceId);
|
||||
registerService(service);
|
||||
|
||||
return {}
|
||||
return new Promise((resolve, reject) => {
|
||||
service.registerFunction(fnName, (args: any[]) => {
|
||||
resolve(f(args))
|
||||
|
||||
return {result: f(args)}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
describe("== AIR suite", () => {
|
||||
|
||||
it("check init_peer_id", async function () {
|
||||
let serviceId = "init_peer"
|
||||
let fnName = "id"
|
||||
let checkPromise = registerPromiseService(serviceId, fnName, (args) => args[0])
|
||||
|
||||
let client = await Fluence.local();
|
||||
|
||||
let script = `(call %init_peer_id% ("console" "log") ["hello"])`
|
||||
let script = `(call %init_peer_id% ("${serviceId}" "${fnName}") [%init_peer_id%])`
|
||||
|
||||
let particle = await build(client.selfPeerId, script, new Map())
|
||||
|
||||
await client.executeParticle(particle);
|
||||
|
||||
expect(await checkPromise).to.be.equal(client.selfPeerIdStr)
|
||||
})
|
||||
|
||||
it("call local function", async function () {
|
||||
let serviceId = "console"
|
||||
let fnName = "log"
|
||||
let checkPromise = registerPromiseService(serviceId, fnName, (args) => args[0])
|
||||
|
||||
let client = await Fluence.local();
|
||||
|
||||
let arg = "hello"
|
||||
let script = `(call %init_peer_id% ("${serviceId}" "${fnName}") ["${arg}"])`
|
||||
|
||||
// Wrap script into particle, so it can be executed by local WASM runtime
|
||||
let particle = await build(client.selfPeerId, script, new Map())
|
||||
|
||||
await client.executeParticle(particle);
|
||||
|
||||
expect(await checkPromise).to.be.equal(arg)
|
||||
})
|
||||
|
||||
it("check particle arguments", async function () {
|
||||
let serviceId = "check"
|
||||
let fnName = "args"
|
||||
let checkPromise = registerPromiseService(serviceId, fnName, (args) => args[0])
|
||||
|
||||
let client = await Fluence.local();
|
||||
|
||||
let arg = "arg1"
|
||||
let value = "hello"
|
||||
let script = `(call %init_peer_id% ("${serviceId}" "${fnName}") [${arg}])`
|
||||
|
||||
|
||||
let data = new Map()
|
||||
data.set("arg1", value)
|
||||
let particle = await build(client.selfPeerId, script, data)
|
||||
|
||||
await client.executeParticle(particle);
|
||||
|
||||
expect(await checkPromise).to.be.equal(value)
|
||||
})
|
||||
|
||||
it("check chain of services work properly", async function () {
|
||||
this.timeout(5000);
|
||||
let serviceId1 = "check1"
|
||||
let fnName1 = "fn1"
|
||||
let checkPromise1 = registerPromiseService(serviceId1, fnName1, (args) => args[0])
|
||||
|
||||
let serviceId2 = "check2"
|
||||
let fnName2 = "fn2"
|
||||
let checkPromise2 = registerPromiseService(serviceId2, fnName2, (args) => args[0])
|
||||
|
||||
let serviceId3 = "check3"
|
||||
let fnName3 = "fn3"
|
||||
let checkPromise3 = registerPromiseService(serviceId3, fnName3, (args) => args)
|
||||
|
||||
let client = await Fluence.local();
|
||||
|
||||
let arg1 = "arg1"
|
||||
let arg2 = "arg2"
|
||||
|
||||
// language=Clojure
|
||||
let script = `(seq
|
||||
(seq
|
||||
(call %init_peer_id% ("${serviceId1}" "${fnName1}") ["${arg1}"] result1)
|
||||
(call %init_peer_id% ("${serviceId2}" "${fnName2}") ["${arg2}"] result2))
|
||||
(call %init_peer_id% ("${serviceId3}" "${fnName3}") [result1 result2]))
|
||||
`
|
||||
|
||||
let particle = await build(client.selfPeerId, script, new Map())
|
||||
|
||||
await client.executeParticle(particle);
|
||||
|
||||
expect(await checkPromise1).to.be.equal(arg1)
|
||||
expect(await checkPromise2).to.be.equal(arg2)
|
||||
|
||||
expect(await checkPromise3).to.be.deep.equal([{result: arg1}, {result: arg2}])
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'mocha';
|
||||
import Fluence from "../fluence";
|
||||
|
||||
describe("AIR AST parsing suite", () => {
|
||||
describe("== AST parsing suite", () => {
|
||||
it("parse simple script and return ast", async function () {
|
||||
let ast = await Fluence.parseAIR(`
|
||||
(call node ("service" "function") [1 2 3 arg] output)
|
||||
|
Loading…
Reference in New Issue
Block a user