github.com/kaleido-io/firefly@v0.0.0-20210622132723-8b4b6aacb971/kat/src/test/common.ts (about) 1 // Copyright © 2021 Kaleido, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 import { EventEmitter } from 'events'; 16 import rimraf from 'rimraf'; 17 import nock from 'nock'; 18 import mock from 'mock-require'; 19 import { promises as fs } from 'fs'; 20 import path from 'path'; 21 import assert from 'assert'; 22 import request from 'supertest'; 23 import * as utils from '../lib/utils'; 24 import { IEventMemberRegistered } from "../lib/interfaces"; 25 export let app: Express.Application; 26 export let mockEventStreamWebSocket: EventEmitter; 27 export let mockDocExchangeSocketIO = new EventEmitter(); 28 29 let shutDown: () => void; 30 31 class MockWebSocket extends EventEmitter { 32 33 constructor(url: string) { 34 super(); 35 assert.strictEqual(url, 'ws://eventstreams.kaleido.io'); 36 mockEventStreamWebSocket = this; 37 } 38 39 send(message: string) { 40 mockEventStreamWebSocket.emit('send', message); 41 } 42 43 ping() { } 44 45 close() { } 46 47 }; 48 49 export const setUp = async (protocol: string) => { 50 await new Promise<void>((resolve, reject) => { 51 rimraf(path.join(__dirname, `../../test-resources/sandbox/${protocol}`), {}, (err) => { 52 if (err) { 53 reject() 54 } else { 55 resolve(); 56 } 57 }); 58 }); 59 60 const sandboxPath = path.join(__dirname, `../../test-resources/sandbox/${protocol}`); 61 await fs.mkdir(sandboxPath, { recursive: true }); 62 await fs.copyFile(path.join(__dirname, '../../test-resources/settings.json'), path.join(sandboxPath, 'settings.json')); 63 await fs.copyFile(path.join(__dirname, `../../test-resources/config-${protocol}.json`), path.join(sandboxPath, 'config.json')); 64 65 mock('ws', MockWebSocket); 66 mock('socket.io-client', { 67 connect: () => { 68 return mockDocExchangeSocketIO; 69 } 70 }); 71 // IPFS 72 nock('https://ipfs.kaleido.io') 73 .post('/api/v0/version') 74 .reply(200, { Version: 1 }); 75 76 // Doc exchange REST API 77 nock('https://docexchange.kaleido.io') 78 .get('/documents') 79 .reply(200, { entries: [] }); 80 81 nock('https://apigateway.kaleido.io') 82 .get('/subscriptions') 83 .reply(200, [{ 84 name: 'AssetInstanceCreated', 85 stream: 'es12345' 86 }]); 87 88 const nockSubscribe = (description: string, name: string) => { 89 if(protocol === 'ethereum') { 90 nock('https://apigateway.kaleido.io') 91 .post(`/${name}/Subscribe`, { 92 description, 93 name, 94 stream: 'es12345', 95 }) 96 .reply(200, {}); 97 } else { 98 nock('https://apigateway.kaleido.io') 99 .post(`/subscriptions`, { 100 name, 101 stream: 'es12345', 102 fromTime: null, 103 filter: { 104 stateType: name, 105 stateStatus: "unconsumed", 106 relevancyStatus: "all" 107 } 108 }) 109 .reply(200, {}); 110 } 111 }; 112 113 const nockEventStreamsWithRetry = () => { 114 // event stream and subscriptions 115 nock('https://apigateway.kaleido.io') 116 .get('/eventstreams') 117 .times(2) 118 .reply(200, []); 119 120 nock('https://apigateway.kaleido.io') 121 .post('/eventstreams', { 122 name: 'dev', 123 errorHandling: "block", 124 blockedReryDelaySec: 30, 125 batchTimeoutMS: 500, 126 batchSize: 50, 127 type: "websocket", 128 websocket: { 129 topic: 'dev', 130 } 131 }) 132 .reply(500); 133 134 nock('https://apigateway.kaleido.io') 135 .post('/eventstreams', { 136 name: 'dev', 137 errorHandling: "block", 138 blockedReryDelaySec: 30, 139 batchTimeoutMS: 500, 140 batchSize: 50, 141 type: "websocket", 142 websocket: { 143 topic: 'dev', 144 } 145 }) 146 .reply(200, { 147 id: 'es12345' 148 }); 149 } 150 151 const nockEventStreamsWithRetryCorda = () => { 152 // event stream and subscriptions 153 nock('https://apigateway.kaleido.io') 154 .get('/eventstreams') 155 .times(2) 156 .reply(200, []); 157 158 nock('https://apigateway.kaleido.io') 159 .post('/eventstreams', { 160 name: 'dev', 161 errorHandling: "block", 162 blockedRetryDelaySec: 30, 163 batchTimeoutMS: 500, 164 batchSize: 50, 165 type: "websocket", 166 websocket: { 167 topic: 'dev', 168 } 169 }) 170 .reply(500); 171 172 nock('https://apigateway.kaleido.io') 173 .post('/eventstreams', { 174 name: 'dev', 175 errorHandling: "block", 176 blockedRetryDelaySec: 30, 177 batchTimeoutMS: 500, 178 batchSize: 50, 179 type: "websocket", 180 websocket: { 181 topic: 'dev', 182 } 183 }) 184 .reply(200, { 185 id: 'es12345' 186 }); 187 } 188 if(protocol === 'ethereum') { 189 nockEventStreamsWithRetry(); 190 nockSubscribe('Asset instance created', 'AssetInstanceCreated'); 191 nockSubscribe('Asset instance batch created', 'AssetInstanceBatchCreated'); 192 nockSubscribe('Payment instance created', 'PaymentInstanceCreated'); 193 nockSubscribe('Payment definition created', 'PaymentDefinitionCreated'); 194 nockSubscribe('Asset definition created', 'AssetDefinitionCreated'); 195 nockSubscribe('Asset instance property set', 'AssetInstancePropertySet'); 196 nockSubscribe('Described payment instance created', 'DescribedPaymentInstanceCreated'); 197 nockSubscribe('Described asset instance created', 'DescribedAssetInstanceCreated'); 198 nockSubscribe('Described payment definition created', 'DescribedPaymentDefinitionCreated'); 199 nockSubscribe('Member registered', 'MemberRegistered'); 200 } else { 201 nockEventStreamsWithRetryCorda(); 202 nockSubscribe('Asset instance created', 'io.kaleido.kat.states.AssetInstanceCreated'); 203 nockSubscribe('Asset instance batch created', 'io.kaleido.kat.states.AssetInstanceBatchCreated'); 204 nockSubscribe('Asset instance property set', 'io.kaleido.kat.states.AssetInstancePropertySet'); 205 nockSubscribe('Described asset instance created', 'io.kaleido.kat.states.DescribedAssetInstanceCreated'); 206 } 207 208 const { promise } = require('../app'); 209 ({ app, shutDown } = await promise); 210 211 const eventPromise = new Promise<void>((resolve) => { 212 mockEventStreamWebSocket.once('send', message => { 213 assert.strictEqual(message, '{"type":"listen","topic":"dev"}'); 214 resolve(); 215 }) 216 }); 217 218 mockEventStreamWebSocket.emit('open'); 219 mockDocExchangeSocketIO.emit('connect'); 220 221 await eventPromise; 222 223 if (protocol === 'corda') { 224 await setupSampleMembersCorda(); 225 } else { 226 await setupSampleMembersEthereum(); 227 } 228 } 229 230 const setupSampleMembersCorda = async () => { 231 console.log('Setting up corda members'); 232 await request(app) 233 .put('/api/v1/members') 234 .send({ 235 address: 'CN=Node of node1 for env1, O=Kaleido, L=Raleigh, C=US', 236 name: 'Test Member 1', 237 assetTrailInstanceID: 'service-id_1', 238 app2appDestination: 'kld://app2app_1', 239 docExchangeDestination: 'kld://docexchange_1' 240 }); 241 242 await request(app) 243 .put('/api/v1/members') 244 .send({ 245 address: 'CN=Node of node2 for env1, O=Kaleido, L=Raleigh, C=US', 246 name: 'Test Member 2', 247 assetTrailInstanceID: 'service-id_2', 248 app2appDestination: 'kld://app2app_2', 249 docExchangeDestination: 'kld://docexchange_2' 250 }); 251 }; 252 253 const setupSampleMembersEthereum = async () => { 254 console.log('Setting up ethereum members'); 255 nock('https://apigateway.kaleido.io') 256 .post('/registerMember?kld-from=0x0000000000000000000000000000000000000001&kld-sync=true') 257 .reply(200); 258 await request(app) 259 .put('/api/v1/members') 260 .send({ 261 address: '0x0000000000000000000000000000000000000001', 262 name: 'Test Member 1', 263 app2appDestination: 'kld://app2app_1', 264 docExchangeDestination: 'kld://docexchange_1' 265 }) 266 const eventPromise = new Promise<void>((resolve) => { 267 mockEventStreamWebSocket.once('send', message => { 268 assert.strictEqual(message, '{"type":"ack","topic":"dev"}'); 269 resolve(); 270 }) 271 }); 272 const dataMember1: IEventMemberRegistered = { 273 member: '0x0000000000000000000000000000000000000001', 274 name: 'Test Member 1', 275 assetTrailInstanceID: 'service-instance', 276 app2appDestination: 'kld://app2app_1', 277 docExchangeDestination: 'kld://docexchange_1', 278 timestamp: utils.getTimestamp() 279 } 280 const dataMember2: IEventMemberRegistered = 281 { 282 member: '0x0000000000000000000000000000000000000002', 283 name: 'Test Member 2', 284 assetTrailInstanceID: 'service-instance', 285 app2appDestination: 'kld://app2app_2', 286 docExchangeDestination: 'kld://docexchange_2', 287 timestamp: utils.getTimestamp() 288 }; 289 mockEventStreamWebSocket.emit('message', JSON.stringify([{ 290 signature: utils.contractEventSignatures.MEMBER_REGISTERED, 291 data: dataMember1, 292 blockNumber: '123', 293 transactionHash: '0x0000000000000000000000000000000000000000000000000000000000000000' 294 }, { 295 signature: utils.contractEventSignatures.MEMBER_REGISTERED, 296 data: dataMember2, 297 blockNumber: '123', 298 transactionHash: '0x0000000000000000000000000000000000000000000000000000000000000000' 299 }])); 300 await eventPromise; 301 }; 302 303 export const closeDown = async () => { 304 shutDown(); 305 mock.stop('ws'); 306 mock.stop('socket.io-client'); 307 nock.restore(); 308 };