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