Update builtins to new version (#27)

* Update builtins to new version

* Running integration tests in docker container
This commit is contained in:
Pavel 2021-02-25 15:33:37 +03:00 committed by GitHub
parent d65153e6de
commit 619c8a6d6a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 137 additions and 173 deletions

View File

@ -64,7 +64,7 @@ Make a particle
const particle = new Particle(
`
(seq
(call myRelay ("op" "identify") [] result)
(call myRelay ("peer" "identify") [] result)
(call %init_peer_id% ("helloService" "helloFunction") [result])
)`,
{
@ -112,10 +112,34 @@ npm install
### Running tests
To run test execute
Tests are split into unit and integration categories. By default integration tests require a locally running Fluence node with 4310 port open for ws connections. The dependency can be started with docker
```bash
npm test
docker run --rm -e RUST_LOG="info" -p 1210:1210 -p 4310:4310 fluencelabs/fluence:freeze -t 1210 -w 4310 -k gKdiCSUr1TFGFEgu2t8Ch1XEUsrN5A2UfBLjSZvfci9SPR3NvZpACfcpPGC3eY4zma1pk7UvYv5zb1VjvPHwCjj
```
To run all tests in interactive mode
```bash
npm run test
```
To run only unit tests
```bash
npm run test:unit
```
To run only integration tests
```bash
npm run test:unit
```
To run all tests
```bash
npm run test:all
```
## Contributing

View File

@ -0,0 +1,35 @@
import { generatePeerId } from '..';
import { createClient } from '../api';
import { FluenceClientImpl } from '../internal/FluenceClientImpl';
// Uncomment to test on dev nodes
// export const nodes = [
// {
// multiaddr: '/dns4/dev.fluence.dev/tcp/19003/wss/p2p/12D3KooWBUJifCTgaxAUrcM9JysqCcS4CS8tiYH5hExbdWCAoNwb',
// peerId: '12D3KooWBUJifCTgaxAUrcM9JysqCcS4CS8tiYH5hExbdWCAoNwb',
// },
// {
// multiaddr: '/dns4/dev.fluence.dev/tcp/19004/wss/p2p/12D3KooWJbJFaZ3k5sNd8DjQgg3aERoKtBAnirEvPV8yp76kEXHB',
// peerId: '12D3KooWJbJFaZ3k5sNd8DjQgg3aERoKtBAnirEvPV8yp76kEXHB',
// },
// ];
// start docker container to run integration tests locally
// > docker run --rm -e RUST_LOG="info" -p 1210:1210 -p 4310:4310 fluencelabs/fluence:freeze -t 1210 -w 4310 -k gKdiCSUr1TFGFEgu2t8Ch1XEUsrN5A2UfBLjSZvfci9SPR3NvZpACfcpPGC3eY4zma1pk7UvYv5zb1VjvPHwCjj
export const nodes = [
{
multiaddr: '/ip4/127.0.0.1/tcp/4310/ws/p2p/12D3KooWKEprYXUXqoV5xSBeyqrWLpQLLH4PXfvVkDJtmcqmh5V3',
peerId: '12D3KooWKEprYXUXqoV5xSBeyqrWLpQLLH4PXfvVkDJtmcqmh5V3',
},
];
export const createLocalClient = async () => {
const peerId = await generatePeerId();
const client = new FluenceClientImpl(peerId);
await client.local();
return client;
};
export const createConnectedClient = async (node: string) => {
return (await createClient(node)) as FluenceClientImpl;
};

View File

@ -1,30 +1,25 @@
import {
addBlueprint,
addProvider,
addScript,
createService,
getBlueprints,
getInterfaces,
getModules,
getProviders,
removeScript,
uploadModule,
} from '../../internal/builtins';
import { ModuleConfig } from '../../internal/moduleConfig';
import { createConnectedClient } from '../util';
import { checkConnection } from '../../api';
import log from 'loglevel';
import { generatePeerId } from '../..';
import { FluenceClientImpl } from '../../internal/FluenceClientImpl';
const dev2multiaddr = '/dns4/dev.fluence.dev/tcp/19003/wss/p2p/12D3KooWBUJifCTgaxAUrcM9JysqCcS4CS8tiYH5hExbdWCAoNwb';
const dev3multiaddr = '/dns4/dev.fluence.dev/tcp/19004/wss/p2p/12D3KooWJbJFaZ3k5sNd8DjQgg3aERoKtBAnirEvPV8yp76kEXHB';
const dev2peerId = '12D3KooWEXNUbCXooUwHrHBbrmjsrpHXoEphPwbjQXEGyzbqKnE9';
import { createConnectedClient, nodes } from '../connection';
describe('Builtins usage suite', () => {
jest.setTimeout(10000);
it('get_modules', async function () {
const client = await createConnectedClient(dev2multiaddr);
const client = await createConnectedClient(nodes[0].multiaddr);
let modulesList = await getModules(client);
@ -32,7 +27,7 @@ describe('Builtins usage suite', () => {
});
it('get_interfaces', async function () {
const client = await createConnectedClient(dev2multiaddr);
const client = await createConnectedClient(nodes[0].multiaddr);
let interfaces = await getInterfaces(client);
@ -40,7 +35,7 @@ describe('Builtins usage suite', () => {
});
it('get_blueprints', async function () {
const client = await createConnectedClient(dev2multiaddr);
const client = await createConnectedClient(nodes[0].multiaddr);
let bpList = await getBlueprints(client);
@ -51,7 +46,7 @@ describe('Builtins usage suite', () => {
const peerId = await generatePeerId();
const client = new FluenceClientImpl(peerId);
await client.local();
await client.connect(dev2multiaddr);
await client.connect(nodes[0].multiaddr);
let isConnected = await checkConnection(client);
@ -59,7 +54,7 @@ describe('Builtins usage suite', () => {
});
it('upload_modules', async function () {
const client = await createConnectedClient(dev2multiaddr);
const client = await createConnectedClient(nodes[0].multiaddr);
console.log('peerid: ' + client.selfPeerId);
@ -81,7 +76,7 @@ describe('Builtins usage suite', () => {
});
it('add_blueprint', async function () {
const client = await createConnectedClient(dev2multiaddr);
const client = await createConnectedClient(nodes[0].multiaddr);
let bpId = 'some';
@ -92,7 +87,7 @@ describe('Builtins usage suite', () => {
// FIXME:: there is no error on broken blueprint from a node
it.skip('create_service', async function () {
const client = await createConnectedClient(dev2multiaddr);
const client = await createConnectedClient(nodes[0].multiaddr);
let serviceId = await createService(client, 'test_broken_blueprint');
@ -100,23 +95,8 @@ describe('Builtins usage suite', () => {
expect(serviceId).not.toBeUndefined;
});
it('add_provider', async function () {
const client = await createConnectedClient(dev2multiaddr);
let key = Math.random().toString(36).substring(7);
let buf = Buffer.from(key);
let r = Math.random().toString(36).substring(7);
await addProvider(client, buf, dev2peerId, r, undefined, 10000);
let pr = await getProviders(client, buf, undefined, 10000);
console.log(pr);
console.log(r);
expect(r).toEqual(pr[0][0].service_id);
});
it('add and remove script', async function () {
const client = await createConnectedClient(dev3multiaddr);
const client = await createConnectedClient(nodes[0].multiaddr);
console.log('peerid: ' + client.selfPeerId);

View File

@ -1,13 +1,10 @@
import { encode } from 'bs58';
import { generatePeerId, peerIdToSeed, seedToPeerId } from '../../internal/peerIdUtils';
import { FluenceClientImpl } from '../../internal/FluenceClientImpl';
import { createConnectedClient } from '../util';
import log from 'loglevel';
import { createClient } from '../../api';
import Multiaddr from 'multiaddr';
const devNodeAddress = '/dns4/dev.fluence.dev/tcp/19001/wss/p2p/12D3KooWEXNUbCXooUwHrHBbrmjsrpHXoEphPwbjQXEGyzbqKnE9';
const devNodePeerId = '12D3KooWEXNUbCXooUwHrHBbrmjsrpHXoEphPwbjQXEGyzbqKnE9';
import { createConnectedClient, nodes } from '../connection';
describe('Typescript usage suite', () => {
it('should create private key from seed and back', async function () {
@ -45,7 +42,7 @@ describe('Typescript usage suite', () => {
it('address as string', async function () {
// arrange
const addr = devNodeAddress;
const addr = nodes[0].multiaddr;
// act
const client = (await createClient(addr)) as FluenceClientImpl;
@ -57,7 +54,7 @@ describe('Typescript usage suite', () => {
it('address as multiaddr', async function () {
// arrange
const addr = new Multiaddr(devNodeAddress);
const addr = new Multiaddr(nodes[0].multiaddr);
// act
const client = (await createClient(addr)) as FluenceClientImpl;
@ -69,10 +66,7 @@ describe('Typescript usage suite', () => {
it('address as node', async function () {
// arrange
const addr = {
multiaddr: devNodeAddress,
peerId: devNodePeerId,
};
const addr = nodes[0];
// act
const client = (await createClient(addr)) as FluenceClientImpl;
@ -84,7 +78,7 @@ describe('Typescript usage suite', () => {
it('peerid as peer id', async function () {
// arrange
const addr = devNodeAddress;
const addr = nodes[0].multiaddr;
const pid = await generatePeerId();
// act
@ -97,7 +91,7 @@ describe('Typescript usage suite', () => {
it('peerid as seed', async function () {
// arrange
const addr = devNodeAddress;
const addr = nodes[0].multiaddr;
const pid = peerIdToSeed(await generatePeerId());
// act
@ -111,7 +105,7 @@ describe('Typescript usage suite', () => {
it('should make a call through the network', async function () {
// arrange
const client = await createConnectedClient(devNodeAddress);
const client = await createConnectedClient(nodes[0].multiaddr);
client.registerCallback('test', 'test', (args, _) => {
log.trace('should make a call through the network, called "test" "test" with args', args);
@ -151,7 +145,7 @@ describe('Typescript usage suite', () => {
it('fireAndForget should work', async function () {
// arrange
const client = await createConnectedClient(devNodeAddress);
const client = await createConnectedClient(nodes[0].multiaddr);
let resMakingPromise = new Promise((resolve) => {
client.registerCallback('test', 'reverse_args', (args, _) => {
@ -180,11 +174,11 @@ describe('Typescript usage suite', () => {
it('fetch should work', async function () {
// arrange
const client = await createConnectedClient(devNodeAddress);
const client = await createConnectedClient(nodes[0].multiaddr);
// act
let script = `
(call "${client.relayPeerId}" ("op" "identify") [] result)
(call "${client.relayPeerId}" ("peer" "identify") [] result)
`;
const data = new Map();
data.set('__relay', client.relayPeerId);
@ -197,8 +191,8 @@ describe('Typescript usage suite', () => {
it('two clients should work inside the same time browser', async function () {
// arrange
const client1 = await createConnectedClient(devNodeAddress);
const client2 = await createConnectedClient(devNodeAddress);
const client1 = await createConnectedClient(nodes[0].multiaddr);
const client2 = await createConnectedClient(nodes[0].multiaddr);
let resMakingPromise = new Promise((resolve) => {
client2.registerCallback('test', 'test', (args, _) => {
@ -225,32 +219,4 @@ describe('Typescript usage suite', () => {
let res = await resMakingPromise;
expect(res).toEqual(['some a', 'some b', 'some c', 'some d']);
});
it('event registration should work', async function () {
// arrange
const client1 = await createConnectedClient(devNodeAddress);
const client2 = await createConnectedClient(devNodeAddress);
client2.registerEvent('event_stream', 'test');
const resMakingPromise = new Promise((resolve) => {
client2.subscribe('event_stream', resolve);
});
// act
let script = `
(call "${client2.selfPeerId}" ("event_stream" "test") [hello])
`;
let data: Map<string, any> = new Map();
data.set('hello', 'world');
await client1.fireAndForget(script, data);
// assert
let res = await resMakingPromise;
expect(res).toEqual({
type: 'test',
args: ['world'],
});
});
});

View File

@ -1,4 +1,4 @@
import { createLocalClient } from '../util';
import { createLocalClient } from '../connection';
describe('== AIR suite', () => {
it('check init_peer_id', async function () {
@ -57,7 +57,7 @@ describe('== AIR suite', () => {
const script = `(call %init_peer_id% ("" "") [""])`;
await expect(client.sendScript(script, undefined, 1)).rejects.toContain("Particle expired");
await expect(client.sendScript(script, undefined, 1)).rejects.toContain('Particle expired');
});
it.skip('call broken script by fetch', async function () {

View File

@ -1,14 +0,0 @@
import { generatePeerId } from '..';
import { createClient } from '../api';
import { FluenceClientImpl } from '../internal/FluenceClientImpl';
export const createLocalClient = async () => {
const peerId = await generatePeerId();
const client = new FluenceClientImpl(peerId);
await client.local();
return client;
};
export const createConnectedClient = async (node: string) => {
return (await createClient(node)) as FluenceClientImpl;
};

View File

@ -79,15 +79,15 @@ export class ParticleProcessor {
async executeLocalParticle(particle: ParticleDto) {
this.strategy?.onLocalParticleRecieved(particle);
return new Promise((resolve, reject) => {
return new Promise<void>((resolve, reject) => {
const resolveCallback = function () {
resolve()
}
resolve();
};
const rejectCallback = function (err: any) {
reject(err)
}
reject(err);
};
// we check by callbacks that the script passed through the interpreter without errors
this.handleParticle(particle, resolveCallback, rejectCallback)
this.handleParticle(particle, resolveCallback, rejectCallback);
});
}
@ -169,7 +169,9 @@ export class ParticleProcessor {
let actualTtl = particle.timestamp + particle.ttl - now;
if (actualTtl <= 0) {
this.strategy?.onParticleTimeout(particle, now);
if (reject) reject(`Particle expired. Now: ${now}, ttl: ${particle.ttl}, ts: ${particle.timestamp}`)
if (reject) {
reject(`Particle expired. Now: ${now}, ttl: ${particle.ttl}, ts: ${particle.timestamp}`);
}
} else {
// if there is no subscription yet, previous data is empty
let prevData: Uint8Array = Buffer.from([]);
@ -204,14 +206,14 @@ export class ParticleProcessor {
if (stepperOutcome.ret_code == 0) {
if (resolve) {
resolve()
resolve();
}
} else {
const error = stepperOutcome.error_message;
if (reject) {
reject(error);
} else {
log.error("Unhandled error: ", error);
log.error('Unhandled error: ', error);
}
}
}
@ -219,7 +221,7 @@ export class ParticleProcessor {
if (reject) {
reject(e);
} else {
log.error("Unhandled error: ", e)
log.error('Unhandled error: ', e);
throw e;
}
} finally {

View File

@ -66,11 +66,11 @@ const requestResponse = async <T>(
* @returns { Array<string> } - list of available modules on the connected relay
*/
export const getModules = async (client: FluenceClient, ttl?: number): Promise<string[]> => {
let callbackFn = "getModules"
let callbackFn = 'getModules';
const particle = new Particle(
`
(seq
(call __relay ("dist" "get_modules") [] result)
(call __relay ("dist" "list_modules") [] result)
(call myPeerId ("_callback" "${callbackFn}") [result])
)
`,
@ -78,34 +78,46 @@ export const getModules = async (client: FluenceClient, ttl?: number): Promise<s
__relay: client.relayPeerId,
myPeerId: client.selfPeerId,
},
ttl
ttl,
);
return sendParticleAsFetch(client, particle, callbackFn);
};
/**
* Get all available modules hosted on a connected relay. @deprecated prefer using raw Particles instead
* Get all available interfaces hosted on a connected relay. @deprecated prefer using raw Particles instead
* @param { FluenceClient } client - The Fluence Client instance.
* @returns { Array<string> } - list of available modules on the connected relay
* @returns { Array<string> } - list of available interfaces on the connected relay
*/
export const getInterfaces = async (client: FluenceClient, ttl?: number): Promise<string[]> => {
let callbackFn = "getInterfaces"
let callbackFn = 'getInterfaces';
const particle = new Particle(
`
(seq
(call __relay ("srv" "get_interfaces") [] result)
(call myPeerId ("_callback" "${callbackFn}") [result])
)
`,
(seq
(seq
(seq
(call relay ("srv" "list") [] services)
(call relay ("op" "identity") [] interfaces[])
)
(fold services s
(seq
(call relay ("srv" "get_interface") [s.$.id!] interfaces[])
(next s)
)
)
)
(call myPeerId ("_callback" "${callbackFn}") [interfaces])
)
`,
{
__relay: client.relayPeerId,
relay: client.relayPeerId,
myPeerId: client.selfPeerId,
},
ttl
ttl,
);
return sendParticleAsFetch(client, particle, callbackFn);
const [res] = await sendParticleAsFetch<[string[]]>(client, particle, callbackFn);
return res;
};
/**
@ -149,7 +161,7 @@ export const uploadModule = async (
)
`;
return sendParticleAsFetch(client, new Particle(script, data, ttl), 'getModules', "_callback");
return sendParticleAsFetch(client, new Particle(script, data, ttl), 'getModules', '_callback');
};
/**
@ -230,7 +242,7 @@ export const createService = async (
*/
export const getBlueprints = async (client: FluenceClient, nodeId?: string, ttl?: number): Promise<string[]> => {
let returnValue = 'blueprints';
let call = (nodeId: string) => `(call "${nodeId}" ("dist" "get_blueprints") [] ${returnValue})`;
let call = (nodeId: string) => `(call "${nodeId}" ("dist" "list_blueprints") [] ${returnValue})`;
return requestResponse(
client,
@ -244,53 +256,6 @@ export const getBlueprints = async (client: FluenceClient, nodeId?: string, ttl?
);
};
/**
* Add a provider to DHT network to neighborhood around a key. @deprecated prefer using raw Particles instead
*/
export const addProvider = async (
client: FluenceClient,
key: Buffer,
providerPeer: string,
providerServiceId?: string,
nodeId?: string,
ttl?: number,
): Promise<void> => {
let call = (nodeId: string) => `(call "${nodeId}" ("dht" "add_provider") [key provider] void[])`;
key = bs58.encode(key) as any;
let provider = {
peer: providerPeer,
service_id: providerServiceId,
};
let data = new Map();
data.set('key', key);
data.set('provider', provider);
return requestResponse(client, 'addProvider', call, '', data, () => {}, nodeId, ttl);
};
/**
* Get a provider from DHT network from neighborhood around a key. @deprecated prefer using raw Particles instead
* @param { FluenceClient } client - The Fluence Client instance.
* @param {[buffer]} key - get provider by this key
* @param {[string]} nodeId - Optional node peer id to get providers from
* @param {[number]} ttl - Optional ttl for the particle which does the job
* @returns { Array<object> } - List of providers
*/
export const getProviders = async (client: FluenceClient, key: Buffer, nodeId?: string, ttl?: number): Promise<any> => {
key = bs58.encode(key) as any;
let returnValue = 'providers';
let call = (nodeId: string) => `(call "${nodeId}" ("dht" "get_providers") [key] providers[])`;
let data = new Map();
data.set('key', key);
return requestResponse(client, 'getProviders', call, returnValue, data, (args) => args[0], nodeId, ttl);
};
/**
* Get relays neighborhood. @deprecated prefer using raw Particles instead
* @param { FluenceClient } client - The Fluence Client instance.
@ -317,15 +282,21 @@ export const neighborhood = async (client: FluenceClient, nodeId?: string, ttl?:
* @param {[number]} ttl - Optional ttl for the particle which does the job
* @returns {[string]} - script id
*/
export const addScript = async (client: FluenceClient, script: string, period?: number, nodeId?: string, ttl?: number): Promise<string> => {
export const addScript = async (
client: FluenceClient,
script: string,
period?: number,
nodeId?: string,
ttl?: number,
): Promise<string> => {
let returnValue = 'id';
let periodV = ""
if (period) periodV = period.toString()
let periodV = '';
if (period) periodV = period.toString();
let call = (nodeId: string) => `(call "${nodeId}" ("script" "add") [script ${periodV}] ${returnValue})`;
let data = new Map();
data.set('script', script);
if (period) data.set('period', period)
if (period) data.set('period', period);
return requestResponse(client, 'addScript', call, returnValue, data, (args) => args[0] as string, nodeId, ttl);
};