From ccdfed3680da3619832346af83b6e8cd6c9a1a18 Mon Sep 17 00:00:00 2001 From: Pavel Murygin Date: Thu, 3 Jun 2021 17:14:05 +0300 Subject: [PATCH 01/10] implement additional builtins --- src/internal/CallServiceHandler.ts | 4 +- src/internal/ClientImpl.ts | 66 ++++++++++++++++++++++++++++-- 2 files changed, 64 insertions(+), 6 deletions(-) diff --git a/src/internal/CallServiceHandler.ts b/src/internal/CallServiceHandler.ts index 563147bb6..93c0e3cd0 100644 --- a/src/internal/CallServiceHandler.ts +++ b/src/internal/CallServiceHandler.ts @@ -21,7 +21,7 @@ interface ParticleContext { /** * Represents the information passed from AVM when a `call` air instruction is executed on the local peer */ -interface CallServiceData { +export interface CallServiceData { /** * Service ID as specified in `call` air instruction */ @@ -58,7 +58,7 @@ export type CallServiceResultType = object | boolean | number | string; /** * Represents the result of the `call` air instruction to be returned into AVM */ -interface CallServiceResult { +export interface CallServiceResult { /** * Return code to be returned to AVM */ diff --git a/src/internal/ClientImpl.ts b/src/internal/ClientImpl.ts index 7960b4ca0..535e3b67f 100644 --- a/src/internal/ClientImpl.ts +++ b/src/internal/ClientImpl.ts @@ -21,16 +21,74 @@ import { FluenceConnection, FluenceConnectionOptions } from './FluenceConnection import { PeerIdB58 } from './commonTypes'; import { FluenceClient } from '../FluenceClient'; import { RequestFlow } from './RequestFlow'; -import { CallServiceHandler, errorHandler, fnHandler } from './CallServiceHandler'; +import { + CallServiceData, + CallServiceHandler, + CallServiceResult, + CallServiceResultType, + errorHandler, + fnHandler, + Middleware, +} from './CallServiceHandler'; import { loadRelayFn, loadVariablesService } from './RequestFlowBuilder'; import { logParticle, Particle } from './particle'; import log from 'loglevel'; -import { AirInterpreter, CallServiceResult, ParticleHandler, SecurityTetraplet } from '@fluencelabs/avm'; +import { + AirInterpreter, + ParticleHandler, + SecurityTetraplet, + CallServiceResult as AvmCallServiceResult, +} from '@fluencelabs/avm'; const makeDefaultClientHandler = (): CallServiceHandler => { + const success = (resp: CallServiceResult, result: CallServiceResultType) => { + resp.retCode = 0; + resp.result = result; + }; + const error = (resp: CallServiceResult, errorMsg: string) => { + resp.retCode = 1; + resp.result = errorMsg; + }; + const mw: Middleware = (req: CallServiceData, resp: CallServiceResult, next: Function) => { + if (req.serviceId === 'op') { + switch (req.fnName) { + case 'noop': + success(resp, {}); + return; + + case 'array': + success(resp, req.args); + return; + + case 'identity': + if (req.args.length > 1) { + error(resp, `identity accepts up to 1 arguments, received ${req.args.length} arguments`); + } else { + success(resp, req.args); + } + return; + + case 'concat': + const incorrectArgIndices = req.args // + .map((x, i) => [Array.isArray(x), i]) + .filter(([isArray, index]) => isArray) + .map((_, index) => index); + + if (incorrectArgIndices.length > 0) { + const str = incorrectArgIndices.join(' '); + error(resp, `All arguments of 'concat' must be arrays: arguments ${str} are not`); + } else { + success(resp, [].concat.apply([], req.args)); + } + return; + } + } + + next(); + }; const res = new CallServiceHandler(); res.use(errorHandler); - res.use(fnHandler('op', 'identity', (args, _) => args)); + res.use(mw); return res; }; @@ -151,7 +209,7 @@ export class ClientImpl implements FluenceClient { fnName: string, args: any[], tetraplets: SecurityTetraplet[][], - ): CallServiceResult => { + ): AvmCallServiceResult => { if (this.currentRequestId === null) { throw Error('current request can`t be null here'); } From 4902cac598a22257aa119f4531833e427e586290 Mon Sep 17 00:00:00 2001 From: Pavel Murygin Date: Thu, 3 Jun 2021 17:41:35 +0300 Subject: [PATCH 02/10] some refactorings --- package-lock.json | 9 +++ package.json | 1 + src/__test__/unit/builtInHandler.spec.ts | 13 ++++ src/internal/ClientImpl.ts | 72 ++------------------- src/internal/defaultClientHandler.ts | 81 ++++++++++++++++++++++++ 5 files changed, 108 insertions(+), 68 deletions(-) create mode 100644 src/__test__/unit/builtInHandler.spec.ts create mode 100644 src/internal/defaultClientHandler.ts diff --git a/package-lock.json b/package-lock.json index eaa1e4f1c..7238fd06e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -842,6 +842,15 @@ "@types/node": "*" } }, + "@types/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-yfAgiWgVLjFCmRv8zAcOIHywYATEwiTVccTLnRp6UxTNavT55M9d/uhK3T03St/+8/z/wW+CRjGKUNmEqoHHCA==", + "dev": true, + "requires": { + "base-x": "^3.0.6" + } + }, "@types/graceful-fs": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", diff --git a/package.json b/package.json index 5d2506f8a..e4d380f73 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "uuid": "8.3.0" }, "devDependencies": { + "@types/bs58": "^4.0.1", "@types/jest": "^26.0.22", "jest": "^26.6.3", "ts-jest": "^26.5.4", diff --git a/src/__test__/unit/builtInHandler.spec.ts b/src/__test__/unit/builtInHandler.spec.ts new file mode 100644 index 000000000..457a304ec --- /dev/null +++ b/src/__test__/unit/builtInHandler.spec.ts @@ -0,0 +1,13 @@ +import { encode } from 'bs58'; +import { peerIdToSeed, seedToPeerId } from '../..'; + +describe('Handler for builtins', () => { + it('should create private key from seed and back', async function () { + // prettier-ignore + let seed = [46, 188, 245, 171, 145, 73, 40, 24, 52, 233, 215, 163, 54, 26, 31, 221, 159, 179, 126, 106, 27, 199, 189, 194, 80, 133, 235, 42, 42, 247, 80, 201]; + let seedStr = encode(seed); + + let pid = await seedToPeerId(seedStr); + expect(peerIdToSeed(pid)).toEqual(seedStr); + }); +}); diff --git a/src/internal/ClientImpl.ts b/src/internal/ClientImpl.ts index 535e3b67f..de24f83fc 100644 --- a/src/internal/ClientImpl.ts +++ b/src/internal/ClientImpl.ts @@ -21,76 +21,12 @@ import { FluenceConnection, FluenceConnectionOptions } from './FluenceConnection import { PeerIdB58 } from './commonTypes'; import { FluenceClient } from '../FluenceClient'; import { RequestFlow } from './RequestFlow'; -import { - CallServiceData, - CallServiceHandler, - CallServiceResult, - CallServiceResultType, - errorHandler, - fnHandler, - Middleware, -} from './CallServiceHandler'; +import { CallServiceHandler } from './CallServiceHandler'; import { loadRelayFn, loadVariablesService } from './RequestFlowBuilder'; import { logParticle, Particle } from './particle'; import log from 'loglevel'; -import { - AirInterpreter, - ParticleHandler, - SecurityTetraplet, - CallServiceResult as AvmCallServiceResult, -} from '@fluencelabs/avm'; - -const makeDefaultClientHandler = (): CallServiceHandler => { - const success = (resp: CallServiceResult, result: CallServiceResultType) => { - resp.retCode = 0; - resp.result = result; - }; - const error = (resp: CallServiceResult, errorMsg: string) => { - resp.retCode = 1; - resp.result = errorMsg; - }; - const mw: Middleware = (req: CallServiceData, resp: CallServiceResult, next: Function) => { - if (req.serviceId === 'op') { - switch (req.fnName) { - case 'noop': - success(resp, {}); - return; - - case 'array': - success(resp, req.args); - return; - - case 'identity': - if (req.args.length > 1) { - error(resp, `identity accepts up to 1 arguments, received ${req.args.length} arguments`); - } else { - success(resp, req.args); - } - return; - - case 'concat': - const incorrectArgIndices = req.args // - .map((x, i) => [Array.isArray(x), i]) - .filter(([isArray, index]) => isArray) - .map((_, index) => index); - - if (incorrectArgIndices.length > 0) { - const str = incorrectArgIndices.join(' '); - error(resp, `All arguments of 'concat' must be arrays: arguments ${str} are not`); - } else { - success(resp, [].concat.apply([], req.args)); - } - return; - } - } - - next(); - }; - const res = new CallServiceHandler(); - res.use(errorHandler); - res.use(mw); - return res; -}; +import { AirInterpreter, ParticleHandler, SecurityTetraplet, CallServiceResult } from '@fluencelabs/avm'; +import makeDefaultClientHandler from './defaultClientHandler'; export class ClientImpl implements FluenceClient { readonly selfPeerIdFull: PeerId; @@ -209,7 +145,7 @@ export class ClientImpl implements FluenceClient { fnName: string, args: any[], tetraplets: SecurityTetraplet[][], - ): AvmCallServiceResult => { + ): CallServiceResult => { if (this.currentRequestId === null) { throw Error('current request can`t be null here'); } diff --git a/src/internal/defaultClientHandler.ts b/src/internal/defaultClientHandler.ts new file mode 100644 index 000000000..bb731d43d --- /dev/null +++ b/src/internal/defaultClientHandler.ts @@ -0,0 +1,81 @@ +import { encode, decode } from 'bs58'; +import { + CallServiceData, + CallServiceHandler, + CallServiceResult, + CallServiceResultType, + errorHandler, + Middleware, +} from './CallServiceHandler'; + +const makeDefaultClientHandler = (): CallServiceHandler => { + const success = (resp: CallServiceResult, result: CallServiceResultType) => { + resp.retCode = 0; + resp.result = result; + }; + const error = (resp: CallServiceResult, errorMsg: string) => { + resp.retCode = 1; + resp.result = errorMsg; + }; + const mw: Middleware = (req: CallServiceData, resp: CallServiceResult, next: Function) => { + if (req.serviceId === 'op') { + switch (req.fnName) { + case 'noop': + success(resp, {}); + return; + + case 'array': + success(resp, req.args); + return; + + case 'identity': + if (req.args.length > 1) { + error(resp, `identity accepts up to 1 arguments, received ${req.args.length} arguments`); + } else { + success(resp, req.args); + } + return; + + case 'concat': + const incorrectArgIndices = req.args // + .map((x, i) => [Array.isArray(x), i]) + .filter(([isArray, index]) => isArray) + .map((_, index) => index); + + if (incorrectArgIndices.length > 0) { + const str = incorrectArgIndices.join(' '); + error(resp, `All arguments of 'concat' must be arrays: arguments ${str} are not`); + } else { + success(resp, [].concat.apply([], req.args)); + } + return; + + case 'string_to_b58': + return; + + case 'string_from_b58': + return; + + case 'bytes_to_b58': + success(resp, encode(req.args[0])); + return; + + case 'bytes_from_b58': + success(resp, decode(req.args[0])); + return; + + case 'sha256_string': + return; + } + + next(); + } + }; + + const res = new CallServiceHandler(); + res.use(errorHandler); + res.use(mw); + return res; +}; + +export default makeDefaultClientHandler; From a9a324d5410eb45a0ccee5df9cceec2bcfc69dee Mon Sep 17 00:00:00 2001 From: Pavel Murygin Date: Thu, 3 Jun 2021 17:56:24 +0300 Subject: [PATCH 03/10] implement some of builtins + tests --- src/__test__/unit/builtInHandler.spec.ts | 33 +++++++++++++++++++----- src/internal/defaultClientHandler.ts | 6 ++--- tsconfig.json | 1 - types/ipfs-only-hash/index.d.ts | 19 -------------- types/it-length-prefixed/index.d.ts | 20 -------------- 5 files changed, 30 insertions(+), 49 deletions(-) delete mode 100644 types/ipfs-only-hash/index.d.ts delete mode 100644 types/it-length-prefixed/index.d.ts diff --git a/src/__test__/unit/builtInHandler.spec.ts b/src/__test__/unit/builtInHandler.spec.ts index 457a304ec..419d10af0 100644 --- a/src/__test__/unit/builtInHandler.spec.ts +++ b/src/__test__/unit/builtInHandler.spec.ts @@ -1,13 +1,34 @@ import { encode } from 'bs58'; import { peerIdToSeed, seedToPeerId } from '../..'; +import { CallServiceData } from '../../internal/CallServiceHandler'; +import makeDefaultClientHandler from '../../internal/defaultClientHandler'; + +const handler = makeDefaultClientHandler(); + +const mkReq = (fnName: string, args: unknown[]) => { + return { + serviceId: 'Op', + fnName: fnName, + args: args, + tetraplets: [], + particleContext: { + particleId: 'some', + }, + }; +}; describe('Handler for builtins', () => { - it('should create private key from seed and back', async function () { - // prettier-ignore - let seed = [46, 188, 245, 171, 145, 73, 40, 24, 52, 233, 215, 163, 54, 26, 31, 221, 159, 179, 126, 106, 27, 199, 189, 194, 80, 133, 235, 42, 42, 247, 80, 201]; - let seedStr = encode(seed); + it('1', () => { + // arrange + const req: CallServiceData = mkReq('identity', []); + + // act + const res = handler.execute(req); - let pid = await seedToPeerId(seedStr); - expect(peerIdToSeed(pid)).toEqual(seedStr); + // assert + expect(res).toMatchObject({ + retCode: 0, + result: {}, + }); }); }); diff --git a/src/internal/defaultClientHandler.ts b/src/internal/defaultClientHandler.ts index bb731d43d..48f1f5e48 100644 --- a/src/internal/defaultClientHandler.ts +++ b/src/internal/defaultClientHandler.ts @@ -18,7 +18,7 @@ const makeDefaultClientHandler = (): CallServiceHandler => { resp.result = errorMsg; }; const mw: Middleware = (req: CallServiceData, resp: CallServiceResult, next: Function) => { - if (req.serviceId === 'op') { + if (req.serviceId === 'Op') { switch (req.fnName) { case 'noop': success(resp, {}); @@ -67,9 +67,9 @@ const makeDefaultClientHandler = (): CallServiceHandler => { case 'sha256_string': return; } - - next(); } + + next(); }; const res = new CallServiceHandler(); diff --git a/tsconfig.json b/tsconfig.json index c9d20ddc0..fd1098fc5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,7 +3,6 @@ "typeRoots": [ "./node_modules/@types", "./node_modules/libp2p-ts/types", - "./types" ], "outDir": "./dist/", "baseUrl": ".", diff --git a/types/ipfs-only-hash/index.d.ts b/types/ipfs-only-hash/index.d.ts deleted file mode 100644 index 99e49e009..000000000 --- a/types/ipfs-only-hash/index.d.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2020 Fluence Labs Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -declare module 'ipfs-only-hash' { - export function of(data: Buffer): Promise -} diff --git a/types/it-length-prefixed/index.d.ts b/types/it-length-prefixed/index.d.ts deleted file mode 100644 index 9da68a315..000000000 --- a/types/it-length-prefixed/index.d.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2020 Fluence Labs Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -declare module 'it-length-prefixed' { - export function decode(): any - export function encode(): any -} From 90a83c0feab845079c448c569b08702484cc70d1 Mon Sep 17 00:00:00 2001 From: Pavel Murygin Date: Thu, 3 Jun 2021 18:32:50 +0300 Subject: [PATCH 04/10] moar tests --- src/__test__/unit/builtInHandler.spec.ts | 116 +++++++++++++++++++++++ src/internal/defaultClientHandler.ts | 8 +- 2 files changed, 120 insertions(+), 4 deletions(-) diff --git a/src/__test__/unit/builtInHandler.spec.ts b/src/__test__/unit/builtInHandler.spec.ts index 419d10af0..de3098183 100644 --- a/src/__test__/unit/builtInHandler.spec.ts +++ b/src/__test__/unit/builtInHandler.spec.ts @@ -31,4 +31,120 @@ describe('Handler for builtins', () => { result: {}, }); }); + + it('2', () => { + // arrange + const req: CallServiceData = mkReq('identity', [1]); + + // act + const res = handler.execute(req); + + // assert + expect(res).toMatchObject({ + retCode: 0, + result: 1, + }); + }); + + it('3', () => { + // arrange + const req: CallServiceData = mkReq('identity', [1, 2]); + + // act + const res = handler.execute(req); + + // assert + expect(res).toMatchObject({ + retCode: 1, + result: 'identity accepts up to 1 arguments, received 2 arguments', + }); + }); + + it('5', () => { + // arrange + const req: CallServiceData = mkReq('noop', [1, 2]); + + // act + const res = handler.execute(req); + + // assert + expect(res).toMatchObject({ + retCode: 0, + result: {}, + }); + }); + + it('512', () => { + // arrange + const req: CallServiceData = mkReq('array', [1, 2, 3]); + + // act + const res = handler.execute(req); + + // assert + expect(res).toMatchObject({ + retCode: 0, + result: [1, 2, 3], + }); + }); + + it('51211', () => { + // arrange + const req: CallServiceData = mkReq('concat', [ + [1, 2], + [3, 4], + [5, 6], + ]); + + // act + const res = handler.execute(req); + + // assert + expect(res).toMatchObject({ + retCode: 0, + result: [1, 2, 3, 4, 5, 6], + }); + }); + + it('5121115125', () => { + // arrange + const req: CallServiceData = mkReq('concat', []); + + // act + const res = handler.execute(req); + + // assert + expect(res).toMatchObject({ + retCode: 0, + result: [], + }); + }); + + it('5121122', () => { + // arrange + const req: CallServiceData = mkReq('concat', [[1, 2]]); + + // act + const res = handler.execute(req); + + // assert + expect(res).toMatchObject({ + retCode: 0, + result: [1, 2], + }); + }); + + it('512112222', () => { + // arrange + const req: CallServiceData = mkReq('concat', [1, [1, 2], 1]); + + // act + const res = handler.execute(req); + + // assert + expect(res).toMatchObject({ + retCode: 1, + result: "All arguments of 'concat' must be arrays: arguments 0, 2 are not", + }); + }); }); diff --git a/src/internal/defaultClientHandler.ts b/src/internal/defaultClientHandler.ts index 48f1f5e48..14fbf2b43 100644 --- a/src/internal/defaultClientHandler.ts +++ b/src/internal/defaultClientHandler.ts @@ -32,18 +32,18 @@ const makeDefaultClientHandler = (): CallServiceHandler => { if (req.args.length > 1) { error(resp, `identity accepts up to 1 arguments, received ${req.args.length} arguments`); } else { - success(resp, req.args); + success(resp, req.args.length === 0 ? {} : req.args[0]); } return; case 'concat': const incorrectArgIndices = req.args // .map((x, i) => [Array.isArray(x), i]) - .filter(([isArray, index]) => isArray) - .map((_, index) => index); + .filter(([isArray, _]) => !isArray) + .map(([_, index]) => index); if (incorrectArgIndices.length > 0) { - const str = incorrectArgIndices.join(' '); + const str = incorrectArgIndices.join(', '); error(resp, `All arguments of 'concat' must be arrays: arguments ${str} are not`); } else { success(resp, [].concat.apply([], req.args)); From c38dadf71c40350f85ba27de989a3b8f29517f0f Mon Sep 17 00:00:00 2001 From: Pavel Murygin Date: Thu, 3 Jun 2021 19:00:28 +0300 Subject: [PATCH 05/10] implement bytes to b58 operations --- src/__test__/unit/builtInHandler.spec.ts | 56 ++++++++++++++++++++++++ src/internal/defaultClientHandler.ts | 12 ++--- 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/src/__test__/unit/builtInHandler.spec.ts b/src/__test__/unit/builtInHandler.spec.ts index de3098183..d98eb9c03 100644 --- a/src/__test__/unit/builtInHandler.spec.ts +++ b/src/__test__/unit/builtInHandler.spec.ts @@ -147,4 +147,60 @@ describe('Handler for builtins', () => { result: "All arguments of 'concat' must be arrays: arguments 0, 2 are not", }); }); + + it('qqq', () => { + // arrange + const req: CallServiceData = mkReq('string_to_b58', ['test']); + + // act + const res = handler.execute(req); + + // assert + expect(res).toMatchObject({ + retCode: 0, + result: '3yZe7d', + }); + }); + + it('qqq22', () => { + // arrange + const req: CallServiceData = mkReq('string_from_b58', ['3yZe7d']); + + // act + const res = handler.execute(req); + + // assert + expect(res).toMatchObject({ + retCode: 0, + result: 'test', + }); + }); + + it('qццццqq', () => { + // arrange + const req: CallServiceData = mkReq('bytes_to_b58', [[116, 101, 115, 116]]); + + // act + const res = handler.execute(req); + + // assert + expect(res).toMatchObject({ + retCode: 0, + result: '3yZe7d', + }); + }); + + it('qqцццq22', () => { + // arrange + const req: CallServiceData = mkReq('bytes_from_b58', ['3yZe7d']); + + // act + const res = handler.execute(req); + + // assert + expect(res).toMatchObject({ + retCode: 0, + result: [116, 101, 115, 116], + }); + }); }); diff --git a/src/internal/defaultClientHandler.ts b/src/internal/defaultClientHandler.ts index 14fbf2b43..ddc240eae 100644 --- a/src/internal/defaultClientHandler.ts +++ b/src/internal/defaultClientHandler.ts @@ -51,20 +51,22 @@ const makeDefaultClientHandler = (): CallServiceHandler => { return; case 'string_to_b58': + success(resp, encode(new TextEncoder().encode(req.args[0]))); return; case 'string_from_b58': + success(resp, new TextDecoder().decode(decode(req.args[0]))); return; case 'bytes_to_b58': - success(resp, encode(req.args[0])); + const array = req.args[0] as number[]; + success(resp, encode(new Uint8Array(array))); return; case 'bytes_from_b58': - success(resp, decode(req.args[0])); - return; - - case 'sha256_string': + const ba = decode(req.args[0]); + const x = Array.from(ba); + success(resp, x); return; } } From 56cca75adaf776f5142234e52087a018b9bbccce Mon Sep 17 00:00:00 2001 From: Pavel Murygin Date: Thu, 3 Jun 2021 19:30:02 +0300 Subject: [PATCH 06/10] tidy up tests --- package-lock.json | 118 ++++++++++- package.json | 1 + src/__test__/unit/builtInHandler.spec.ts | 249 +++++------------------ 3 files changed, 160 insertions(+), 208 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7238fd06e..cf957b507 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3509,16 +3509,105 @@ } }, "jest-each": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-26.6.2.tgz", - "integrity": "sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A==", + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.0.2.tgz", + "integrity": "sha512-OLMBZBZ6JkoXgUenDtseFRWA43wVl2BwmZYIWQws7eS7pqsIvePqj/jJmEnfq91ALk3LNphgwNK/PRFBYi7ITQ==", "dev": true, "requires": { - "@jest/types": "^26.6.2", + "@jest/types": "^27.0.2", "chalk": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-util": "^26.6.2", - "pretty-format": "^26.6.2" + "jest-get-type": "^27.0.1", + "jest-util": "^27.0.2", + "pretty-format": "^27.0.2" + }, + "dependencies": { + "@jest/types": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.2.tgz", + "integrity": "sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz", + "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + }, + "ci-info": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", + "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", + "dev": true + }, + "graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "dev": true + }, + "is-ci": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz", + "integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==", + "dev": true, + "requires": { + "ci-info": "^3.1.1" + } + }, + "jest-get-type": { + "version": "27.0.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.1.tgz", + "integrity": "sha512-9Tggo9zZbu0sHKebiAijyt1NM77Z0uO4tuWOxUCujAiSeXv30Vb5D4xVF4UR4YWNapcftj+PbByU54lKD7/xMg==", + "dev": true + }, + "jest-util": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.0.2.tgz", + "integrity": "sha512-1d9uH3a00OFGGWSibpNYr+jojZ6AckOMCXV2Z4K3YXDnzpkAaXQyIpY14FOJPiUmil7CD+A6Qs+lnnh6ctRbIA==", + "dev": true, + "requires": { + "@jest/types": "^27.0.2", + "@types/node": "*", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^3.0.0", + "picomatch": "^2.2.3" + } + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true + }, + "pretty-format": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.2.tgz", + "integrity": "sha512-mXKbbBPnYTG7Yra9qFBtqj+IXcsvxsvOBco3QHxtxTl+hHKq6QdzMZ+q0CtL4ORHZgwGImRr2XZUX2EWzORxig==", + "dev": true, + "requires": { + "@jest/types": "^27.0.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + } + } } }, "jest-environment-jsdom": { @@ -3610,6 +3699,21 @@ "jest-util": "^26.6.2", "pretty-format": "^26.6.2", "throat": "^5.0.0" + }, + "dependencies": { + "jest-each": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-26.6.2.tgz", + "integrity": "sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A==", + "dev": true, + "requires": { + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "jest-get-type": "^26.3.0", + "jest-util": "^26.6.2", + "pretty-format": "^26.6.2" + } + } } }, "jest-leak-detector": { diff --git a/package.json b/package.json index e4d380f73..8b345032a 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "@types/bs58": "^4.0.1", "@types/jest": "^26.0.22", "jest": "^26.6.3", + "jest-each": "^27.0.2", "ts-jest": "^26.5.4", "typescript": "^3.9.5" } diff --git a/src/__test__/unit/builtInHandler.spec.ts b/src/__test__/unit/builtInHandler.spec.ts index d98eb9c03..426bdb17e 100644 --- a/src/__test__/unit/builtInHandler.spec.ts +++ b/src/__test__/unit/builtInHandler.spec.ts @@ -1,206 +1,53 @@ -import { encode } from 'bs58'; -import { peerIdToSeed, seedToPeerId } from '../..'; +import each from 'jest-each'; import { CallServiceData } from '../../internal/CallServiceHandler'; import makeDefaultClientHandler from '../../internal/defaultClientHandler'; -const handler = makeDefaultClientHandler(); - -const mkReq = (fnName: string, args: unknown[]) => { - return { - serviceId: 'Op', - fnName: fnName, - args: args, - tetraplets: [], - particleContext: { - particleId: 'some', +describe('Tests for default handler', () => { + // prettier-ignore + each` + fnName | args | retCode | result + ${'identity'} | ${[]} | ${0} | ${{}} + ${'identity'} | ${[1]} | ${0} | ${1} + ${'identity'} | ${[1, 2]} | ${1} | ${'identity accepts up to 1 arguments, received 2 arguments'} + + ${'noop'} | ${[1, 2]} | ${0} | ${{}} + + ${'array'} | ${[1, 2, 3]} | ${0} | ${[1, 2, 3]} + + ${'concat'} | ${[[1, 2], [3, 4], [5, 6]]} | ${0} | ${[1, 2, 3, 4, 5, 6]} + ${'concat'} | ${[[1, 2]]} | ${0} | ${[1, 2]} + ${'concat'} | ${[]} | ${0} | ${[]} + ${'concat'} | ${[1, [1, 2], 1]} | ${1} | ${"All arguments of 'concat' must be arrays: arguments 0, 2 are not"} + + ${'string_to_b58'} | ${["test"]} | ${0} | ${"3yZe7d"} + ${'string_from_b58'} | ${["3yZe7d"]} | ${0} | ${"test"} + ${'bytes_to_b58'} | ${[[116, 101, 115, 116]]} | ${0} | ${"3yZe7d"} + ${'bytes_from_b58'} | ${["3yZe7d"]} | ${0} | ${[116, 101, 115, 116]} + +`.test( + // + '$fnName with $args expected retcode: $retCode and result: $retcode', + ({ fnName, args, retCode, result }) => { + // arrange + const req: CallServiceData = { + serviceId: 'Op', + fnName: fnName, + args: args, + tetraplets: [], + particleContext: { + particleId: 'some', + }, + }; + + // act + const res = makeDefaultClientHandler().execute(req); + + // assert + expect(res).toMatchObject({ + retCode: retCode, + result: result, + }); + const handler = makeDefaultClientHandler(); }, - }; -}; - -describe('Handler for builtins', () => { - it('1', () => { - // arrange - const req: CallServiceData = mkReq('identity', []); - - // act - const res = handler.execute(req); - - // assert - expect(res).toMatchObject({ - retCode: 0, - result: {}, - }); - }); - - it('2', () => { - // arrange - const req: CallServiceData = mkReq('identity', [1]); - - // act - const res = handler.execute(req); - - // assert - expect(res).toMatchObject({ - retCode: 0, - result: 1, - }); - }); - - it('3', () => { - // arrange - const req: CallServiceData = mkReq('identity', [1, 2]); - - // act - const res = handler.execute(req); - - // assert - expect(res).toMatchObject({ - retCode: 1, - result: 'identity accepts up to 1 arguments, received 2 arguments', - }); - }); - - it('5', () => { - // arrange - const req: CallServiceData = mkReq('noop', [1, 2]); - - // act - const res = handler.execute(req); - - // assert - expect(res).toMatchObject({ - retCode: 0, - result: {}, - }); - }); - - it('512', () => { - // arrange - const req: CallServiceData = mkReq('array', [1, 2, 3]); - - // act - const res = handler.execute(req); - - // assert - expect(res).toMatchObject({ - retCode: 0, - result: [1, 2, 3], - }); - }); - - it('51211', () => { - // arrange - const req: CallServiceData = mkReq('concat', [ - [1, 2], - [3, 4], - [5, 6], - ]); - - // act - const res = handler.execute(req); - - // assert - expect(res).toMatchObject({ - retCode: 0, - result: [1, 2, 3, 4, 5, 6], - }); - }); - - it('5121115125', () => { - // arrange - const req: CallServiceData = mkReq('concat', []); - - // act - const res = handler.execute(req); - - // assert - expect(res).toMatchObject({ - retCode: 0, - result: [], - }); - }); - - it('5121122', () => { - // arrange - const req: CallServiceData = mkReq('concat', [[1, 2]]); - - // act - const res = handler.execute(req); - - // assert - expect(res).toMatchObject({ - retCode: 0, - result: [1, 2], - }); - }); - - it('512112222', () => { - // arrange - const req: CallServiceData = mkReq('concat', [1, [1, 2], 1]); - - // act - const res = handler.execute(req); - - // assert - expect(res).toMatchObject({ - retCode: 1, - result: "All arguments of 'concat' must be arrays: arguments 0, 2 are not", - }); - }); - - it('qqq', () => { - // arrange - const req: CallServiceData = mkReq('string_to_b58', ['test']); - - // act - const res = handler.execute(req); - - // assert - expect(res).toMatchObject({ - retCode: 0, - result: '3yZe7d', - }); - }); - - it('qqq22', () => { - // arrange - const req: CallServiceData = mkReq('string_from_b58', ['3yZe7d']); - - // act - const res = handler.execute(req); - - // assert - expect(res).toMatchObject({ - retCode: 0, - result: 'test', - }); - }); - - it('qццццqq', () => { - // arrange - const req: CallServiceData = mkReq('bytes_to_b58', [[116, 101, 115, 116]]); - - // act - const res = handler.execute(req); - - // assert - expect(res).toMatchObject({ - retCode: 0, - result: '3yZe7d', - }); - }); - - it('qqцццq22', () => { - // arrange - const req: CallServiceData = mkReq('bytes_from_b58', ['3yZe7d']); - - // act - const res = handler.execute(req); - - // assert - expect(res).toMatchObject({ - retCode: 0, - result: [116, 101, 115, 116], - }); - }); + ); }); From e5beb786b7c53d442558d06199ba5b18d7987866 Mon Sep 17 00:00:00 2001 From: Pavel Murygin Date: Thu, 3 Jun 2021 19:38:02 +0300 Subject: [PATCH 07/10] fix identity usage --- src/FluenceClient.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/FluenceClient.ts b/src/FluenceClient.ts index ce1f8f728..638890122 100644 --- a/src/FluenceClient.ts +++ b/src/FluenceClient.ts @@ -133,14 +133,14 @@ export const checkConnection = async (client: FluenceClient, ttl?: number): Prom .withVariables({ msg, }) - .buildAsFetch<[[string]]>(callbackService, callbackFn); + .buildAsFetch<[string]>(callbackService, callbackFn); await client.initiateFlow(request); try { - const [[result]] = await promise; + const [result] = await promise; if (result != msg) { - log.warn("unexpected behavior. 'identity' must return arguments the passed arguments."); + log.warn("unexpected behavior. 'identity' must return the passed arguments."); } return true; } catch (e) { From 8d4253a46611367abf1d99bb98c534aa7527fe2a Mon Sep 17 00:00:00 2001 From: Pavel Murygin Date: Thu, 3 Jun 2021 19:39:59 +0300 Subject: [PATCH 08/10] fix comment issues --- src/internal/defaultClientHandler.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/internal/defaultClientHandler.ts b/src/internal/defaultClientHandler.ts index ddc240eae..ff90c24e5 100644 --- a/src/internal/defaultClientHandler.ts +++ b/src/internal/defaultClientHandler.ts @@ -59,14 +59,12 @@ const makeDefaultClientHandler = (): CallServiceHandler => { return; case 'bytes_to_b58': - const array = req.args[0] as number[]; - success(resp, encode(new Uint8Array(array))); + const argumentArray = req.args[0] as number[]; + success(resp, encode(new Uint8Array(argumentArray))); return; case 'bytes_from_b58': - const ba = decode(req.args[0]); - const x = Array.from(ba); - success(resp, x); + success(resp, Array.from(decode(req.args[0]))); return; } } From cd6d21285c0339f3bfa3b510264274ba58b78f43 Mon Sep 17 00:00:00 2001 From: Pavel Murygin Date: Thu, 3 Jun 2021 19:45:25 +0300 Subject: [PATCH 09/10] fix tests --- src/__test__/integration/client.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/__test__/integration/client.spec.ts b/src/__test__/integration/client.spec.ts index 70d486bb8..871bf63ec 100644 --- a/src/__test__/integration/client.spec.ts +++ b/src/__test__/integration/client.spec.ts @@ -26,11 +26,11 @@ describe('Typescript usage suite', () => { (call %init_peer_id% ("callback" "callback") [result]) )`, ) - .buildAsFetch<[[string]]>('callback', 'callback'); + .buildAsFetch<[string]>('callback', 'callback'); await client.initiateFlow(request); // assert - const [[result]] = await promise; + const [result] = await promise; expect(result).toBe('hello world!'); }); From 6fcdd28d4d72018f30e8e8b4878b3eeee67e028b Mon Sep 17 00:00:00 2001 From: Pavel Murygin Date: Thu, 3 Jun 2021 20:05:19 +0300 Subject: [PATCH 10/10] Add additional checks --- src/__test__/unit/builtInHandler.spec.ts | 9 +++++++- src/internal/defaultClientHandler.ts | 26 +++++++++++++++++++----- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/__test__/unit/builtInHandler.spec.ts b/src/__test__/unit/builtInHandler.spec.ts index 426bdb17e..2563a56ef 100644 --- a/src/__test__/unit/builtInHandler.spec.ts +++ b/src/__test__/unit/builtInHandler.spec.ts @@ -20,13 +20,20 @@ describe('Tests for default handler', () => { ${'concat'} | ${[1, [1, 2], 1]} | ${1} | ${"All arguments of 'concat' must be arrays: arguments 0, 2 are not"} ${'string_to_b58'} | ${["test"]} | ${0} | ${"3yZe7d"} + ${'string_to_b58'} | ${["test", 1]} | ${1} | ${"string_to_b58 accepts only one string argument"} + ${'string_from_b58'} | ${["3yZe7d"]} | ${0} | ${"test"} + ${'string_from_b58'} | ${["3yZe7d", 1]} | ${1} | ${"string_from_b58 accepts only one string argument"} + ${'bytes_to_b58'} | ${[[116, 101, 115, 116]]} | ${0} | ${"3yZe7d"} + ${'bytes_to_b58'} | ${[[116, 101, 115, 116], 1]} | ${1} | ${"bytes_to_b58 accepts only single argument: array of numbers"} + ${'bytes_from_b58'} | ${["3yZe7d"]} | ${0} | ${[116, 101, 115, 116]} + ${'bytes_from_b58'} | ${["3yZe7d", 1]} | ${1} | ${"bytes_from_b58 accepts only one string argument"} `.test( // - '$fnName with $args expected retcode: $retCode and result: $retcode', + '$fnName with $args expected retcode: $retCode and result: $result', ({ fnName, args, retCode, result }) => { // arrange const req: CallServiceData = { diff --git a/src/internal/defaultClientHandler.ts b/src/internal/defaultClientHandler.ts index ff90c24e5..046080856 100644 --- a/src/internal/defaultClientHandler.ts +++ b/src/internal/defaultClientHandler.ts @@ -51,20 +51,36 @@ const makeDefaultClientHandler = (): CallServiceHandler => { return; case 'string_to_b58': - success(resp, encode(new TextEncoder().encode(req.args[0]))); + if (req.args.length !== 1) { + error(resp, 'string_to_b58 accepts only one string argument'); + } else { + success(resp, encode(new TextEncoder().encode(req.args[0]))); + } return; case 'string_from_b58': - success(resp, new TextDecoder().decode(decode(req.args[0]))); + if (req.args.length !== 1) { + error(resp, 'string_from_b58 accepts only one string argument'); + } else { + success(resp, new TextDecoder().decode(decode(req.args[0]))); + } return; case 'bytes_to_b58': - const argumentArray = req.args[0] as number[]; - success(resp, encode(new Uint8Array(argumentArray))); + if (req.args.length !== 1 || !Array.isArray(req.args[0])) { + error(resp, 'bytes_to_b58 accepts only single argument: array of numbers'); + } else { + const argumentArray = req.args[0] as number[]; + success(resp, encode(new Uint8Array(argumentArray))); + } return; case 'bytes_from_b58': - success(resp, Array.from(decode(req.args[0]))); + if (req.args.length !== 1) { + error(resp, 'bytes_from_b58 accepts only one string argument'); + } else { + success(resp, Array.from(decode(req.args[0]))); + } return; } }