github.com/kaleido-io/firefly@v0.0.0-20210622132723-8b4b6aacb971/kat/src/test/ethereum/assets/authored/public/described-structured.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 assert from 'assert';
    16  import { createHash, randomBytes } from 'crypto';
    17  import nock from 'nock';
    18  import request from 'supertest';
    19  import { promisify } from 'util';
    20  import { IDBAssetDefinition, IDBAssetInstance, IEventAssetDefinitionCreated, IEventAssetInstanceBatchCreated } from '../../../../../lib/interfaces';
    21  import * as utils from '../../../../../lib/utils';
    22  import { app, mockEventStreamWebSocket } from '../../../../common';
    23  import { testContent, testDescription } from '../../../../samples';
    24  const delay = promisify(setTimeout);
    25  
    26  export const testAuthoredPublicDescribedStructured = () => {
    27  
    28  describe('Assets: authored - public - described - structured', async () => {
    29  
    30    let assetDefinitionID: string;
    31    const assetDefinitionName = 'authored - public - described - structured';
    32    const timestamp = utils.getTimestamp();
    33    const batchHashSha256 = '0x' + createHash('sha256').update(randomBytes(10)).digest().toString('hex');
    34    const batchHashIPFSMulti = utils.sha256ToIPFSHash(batchHashSha256);
    35  
    36    let batchMaxRecordsToRestore: number;
    37    beforeEach(() => {
    38      nock.cleanAll();
    39      // Force batches to close immediately
    40      batchMaxRecordsToRestore = utils.constants.BATCH_MAX_RECORDS;
    41      utils.constants.BATCH_MAX_RECORDS = 1;
    42    });
    43  
    44    afterEach(() => {
    45      assert.deepStrictEqual(nock.pendingMocks(), []);
    46      utils.constants.BATCH_MAX_RECORDS = batchMaxRecordsToRestore;
    47    });
    48  
    49    describe('Create asset definition', () => {
    50  
    51      it('Checks that the asset definition can be added', async () => {
    52  
    53        nock('https://apigateway.kaleido.io')
    54          .post('/createAssetDefinition?kld-from=0x0000000000000000000000000000000000000001&kld-sync=false')
    55          .reply(200, { id: 'my-receipt-id' });
    56  
    57        nock('https://ipfs.kaleido.io')
    58          .post('/api/v0/add')
    59          .reply(200, { Hash: 'QmPsTQxwhQjJsCFh3hBijCC4gGReQpEz5VjcCK7gu6sYXX' })
    60  
    61        const result = await request(app)
    62          .post('/api/v1/assets/definitions')
    63          .send({
    64            name: assetDefinitionName,
    65            author: '0x0000000000000000000000000000000000000001',
    66            isContentPrivate: false,
    67            isContentUnique: true,
    68            descriptionSchema: testDescription.schema.object,
    69            contentSchema: testContent.schema.object
    70          })
    71          .expect(200);
    72        assert.deepStrictEqual(result.body.status, 'submitted');
    73        assetDefinitionID = result.body.assetDefinitionID;
    74  
    75        const getAssetDefinitionsResponse = await request(app)
    76          .get('/api/v1/assets/definitions')
    77          .expect(200);
    78        const assetDefinition = getAssetDefinitionsResponse.body.find((assetDefinition: IDBAssetDefinition) => assetDefinition.name === 'authored - public - described - structured');
    79        assert.strictEqual(assetDefinition.assetDefinitionID, assetDefinitionID);
    80        assert.strictEqual(assetDefinition.author, '0x0000000000000000000000000000000000000001');
    81        assert.strictEqual(assetDefinition.isContentPrivate, false);
    82        assert.strictEqual(assetDefinition.isContentUnique, true);
    83        assert.deepStrictEqual(assetDefinition.descriptionSchema, testDescription.schema.object);
    84        assert.deepStrictEqual(assetDefinition.contentSchema, testContent.schema.object);
    85        assert.strictEqual(assetDefinition.name, 'authored - public - described - structured');
    86        assert.strictEqual(assetDefinition.receipt, 'my-receipt-id');
    87        assert.strictEqual(typeof assetDefinition.submitted, 'number');
    88      });
    89  
    90      it('Checks that the event stream notification for confirming the asset definition creation is handled', async () => {
    91        const eventPromise = new Promise<void>((resolve) => {
    92          mockEventStreamWebSocket.once('send', message => {
    93            assert.strictEqual(message, '{"type":"ack","topic":"dev"}');
    94            resolve();
    95          })
    96        });
    97        nock('https://ipfs.kaleido.io')
    98          .get('/ipfs/QmPsTQxwhQjJsCFh3hBijCC4gGReQpEz5VjcCK7gu6sYXX')
    99          .reply(200, {
   100            assetDefinitionID: assetDefinitionID,
   101            name: assetDefinitionName,
   102            isContentPrivate: false,
   103            isContentUnique: true,
   104            descriptionSchema: testDescription.schema.object,
   105            contentSchema: testContent.schema.object
   106          });
   107        const data: IEventAssetDefinitionCreated = {
   108          author: '0x0000000000000000000000000000000000000001',
   109          assetDefinitionHash: '0x16bfeb8bb4befe63cc90578fe6fa0f4ef56955c462cd57965279effc69df1ea6',
   110          timestamp: timestamp.toString()
   111        };
   112        mockEventStreamWebSocket.emit('message', JSON.stringify([{
   113          signature: utils.contractEventSignatures.ASSET_DEFINITION_CREATED,
   114          data,
   115          blockNumber: '123',
   116          transactionHash: '0x0000000000000000000000000000000000000000000000000000000000000000'
   117        }]));
   118        await eventPromise;
   119      });
   120  
   121      it('Checks that the asset definition is confirmed', async () => {
   122        const getAssetDefinitionsResponse = await request(app)
   123          .get('/api/v1/assets/definitions')
   124          .expect(200);
   125        const assetDefinition = getAssetDefinitionsResponse.body.find((assetDefinition: IDBAssetDefinition) => assetDefinition.name === 'authored - public - described - structured');
   126        assert.strictEqual(assetDefinition.assetDefinitionID, assetDefinitionID);
   127        assert.strictEqual(assetDefinition.author, '0x0000000000000000000000000000000000000001');
   128        assert.strictEqual(assetDefinition.isContentPrivate, false);
   129        assert.strictEqual(assetDefinition.isContentUnique, true);
   130        assert.deepStrictEqual(assetDefinition.descriptionSchema, testDescription.schema.object);
   131        assert.deepStrictEqual(assetDefinition.contentSchema, testContent.schema.object);
   132        assert.strictEqual(assetDefinition.name, 'authored - public - described - structured');
   133        assert.strictEqual(typeof assetDefinition.submitted, 'number');
   134        assert.strictEqual(assetDefinition.timestamp, timestamp);
   135        assert.strictEqual(assetDefinition.receipt, 'my-receipt-id');
   136        assert.strictEqual(assetDefinition.blockNumber, 123);
   137        assert.strictEqual(assetDefinition.transactionHash, '0x0000000000000000000000000000000000000000000000000000000000000000');
   138  
   139        const getAssetDefinitionResponse = await request(app)
   140          .get(`/api/v1/assets/definitions/${assetDefinitionID}`)
   141          .expect(200);
   142        assert.deepStrictEqual(assetDefinition, getAssetDefinitionResponse.body);
   143      });
   144  
   145    });
   146  
   147    describe('Asset instances', async () => {
   148  
   149      let assetInstanceID: string;
   150  
   151      it('Checks that an asset instance can be created', async () => {
   152  
   153        nock('https://apigateway.kaleido.io')
   154          .post('/createAssetInstanceBatch?kld-from=0x0000000000000000000000000000000000000001&kld-sync=false')
   155          .reply(200, { id: 'my-receipt-id' });
   156  
   157        nock('https://ipfs.kaleido.io')
   158          .post('/api/v0/add')
   159          .reply(200, { Hash: batchHashIPFSMulti })
   160  
   161        const result = await request(app)
   162          .post(`/api/v1/assets/${assetDefinitionID}`)
   163          .send({
   164            author: '0x0000000000000000000000000000000000000001',
   165            description: testDescription.sample.object,
   166            content: testContent.sample.object
   167          })
   168          .expect(200);
   169        assert.deepStrictEqual(result.body.status, 'submitted');
   170        assetInstanceID = result.body.assetInstanceID;
   171  
   172        const getAssetInstancesResponse = await request(app)
   173          .get(`/api/v1/assets/${assetDefinitionID}`)
   174          .expect(200);
   175        const assetInstance = getAssetInstancesResponse.body.find((assetInstance: IDBAssetInstance) => assetInstance.assetInstanceID === assetInstanceID);
   176        assert.strictEqual(assetInstance.author, '0x0000000000000000000000000000000000000001');
   177        assert.strictEqual(assetInstance.assetDefinitionID, assetDefinitionID);
   178        assert.strictEqual(assetInstance.descriptionHash, '0x' + utils.getSha256(JSON.stringify(testDescription.sample.object)));
   179        assert.deepStrictEqual(assetInstance.description, testDescription.sample.object);
   180        assert.strictEqual(assetInstance.contentHash,'0x' + utils.getSha256(JSON.stringify(testContent.sample.object)));
   181        assert.deepStrictEqual(assetInstance.content, testContent.sample.object);
   182        assert.strictEqual(assetInstance.receipt, undefined); // As this has been batched
   183        assert.strictEqual(typeof assetInstance.submitted, 'number');
   184        assert.strictEqual(typeof assetInstance.batchID, 'string');
   185  
   186        // Expect the batch to have been submitted
   187        let getBatchResponse: any;
   188        for (let i = 0; i < 10; i++) {
   189          getBatchResponse = await request(app)
   190            .get(`/api/v1/batches/${assetInstance.batchID}`)
   191            .expect(200);
   192          if (getBatchResponse.body.completed) break;
   193          await delay(1);
   194        }
   195        assert.strictEqual(typeof getBatchResponse.body.completed, 'number');
   196        assert.strictEqual(typeof getBatchResponse.body.batchHash, 'string');
   197        assert.strictEqual(getBatchResponse.body.receipt, 'my-receipt-id');
   198        assert.strictEqual(getBatchResponse.body.batchHash, batchHashSha256);
   199        // As this is a public asset, the full content will have been written to IPFS in the batch
   200        assert.deepStrictEqual(getBatchResponse.body.records[0].content, testContent.sample.object);
   201        // The full description payload should be in the batch data written to IPFS in the batch
   202        assert.deepStrictEqual(getBatchResponse.body.records[0].description, testDescription.sample.object);
   203  
   204        const getAssetInstanceResponse = await request(app)
   205          .get(`/api/v1/assets/${assetDefinitionID}/${assetInstanceID}`)
   206          .expect(200);
   207        assert.deepStrictEqual(assetInstance, getAssetInstanceResponse.body);
   208  
   209      });
   210  
   211      it('Checks that the event stream notification for confirming the asset instance creation is handled', async () => {
   212        const eventPromise = new Promise<void>((resolve) => {
   213          mockEventStreamWebSocket.once('send', message => {
   214            assert.strictEqual(message, '{"type":"ack","topic":"dev"}');
   215            resolve();
   216          })
   217        });
   218        const data: IEventAssetInstanceBatchCreated = {
   219          author: '0x0000000000000000000000000000000000000001',
   220          batchHash: batchHashSha256,
   221          timestamp: timestamp.toString()
   222        };
   223  
   224        mockEventStreamWebSocket.emit('message', JSON.stringify([{
   225          signature: utils.contractEventSignatures.ASSET_INSTANCE_BATCH_CREATED,
   226          data,
   227          blockNumber: '123',
   228          transactionHash: '0x0000000000000000000000000000000000000000000000000000000000000000'
   229        }]));
   230        await eventPromise;
   231      });
   232  
   233      it('Checks that the asset instance is confirmed', async () => {
   234        const getAssetInstancesResponse = await request(app)
   235          .get(`/api/v1/assets/${assetDefinitionID}`)
   236          .expect(200);
   237        const assetInstance = getAssetInstancesResponse.body.find((assetInstance: IDBAssetInstance) => assetInstance.assetInstanceID === assetInstanceID);
   238        assert.strictEqual(assetInstance.author, '0x0000000000000000000000000000000000000001');
   239        assert.strictEqual(assetInstance.assetDefinitionID, assetDefinitionID);
   240        assert.strictEqual(assetInstance.descriptionHash, '0x' + utils.getSha256(JSON.stringify(testDescription.sample.object)));
   241        assert.deepStrictEqual(assetInstance.description, testDescription.sample.object);
   242        assert.strictEqual(assetInstance.contentHash, '0x' + utils.getSha256(JSON.stringify(testContent.sample.object)));
   243        assert.deepStrictEqual(assetInstance.content, testContent.sample.object);
   244        assert.strictEqual(assetInstance.receipt, undefined); // the batch has the receipt
   245        assert.strictEqual(typeof assetInstance.timestamp, 'number');
   246        assert.strictEqual(assetInstance.timestamp, timestamp);
   247        assert.strictEqual(assetInstance.blockNumber, 123);
   248        assert.strictEqual(assetInstance.transactionHash, '0x0000000000000000000000000000000000000000000000000000000000000000');
   249  
   250        const getAssetInstanceResponse = await request(app)
   251          .get(`/api/v1/assets/${assetDefinitionID}/${assetInstanceID}`)
   252          .expect(200);
   253        assert.deepStrictEqual(assetInstance, getAssetInstanceResponse.body);
   254      });
   255  
   256    });
   257  
   258  });
   259  };