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  };