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