Skip to content

Commit

Permalink
Identity warn when bound participant not found (Issue 3011) (hyperled…
Browse files Browse the repository at this point in the history
…ger-archives#3665)

* Identity warn no bound participant

Signed-off-by: awjh-ibm <[email protected]>

* Adding e2e tests

Signed-off-by: awjh-ibm <[email protected]>
  • Loading branch information
awjh-ibm authored and nklincoln committed Mar 23, 2018
1 parent 1f385c5 commit 2b6d0eb
Show file tree
Hide file tree
Showing 29 changed files with 1,164 additions and 148 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,4 @@
"author": "Hyperledger Composer",
"license": "Apache-2.0",
"dependencies": {}
}
}
35 changes: 32 additions & 3 deletions packages/composer-cli/lib/cmds/identity/lib/list.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,35 @@ class List {
let businessNetworkDefinition;
let cardName = argv.card;

let participants = new Map();

const spinner = ora('List all identities in the business network ');
spinner.start();

businessNetworkConnection = cmdUtil.createBusinessNetworkConnection();
return businessNetworkConnection.connect(cardName)

.then((result) => {
businessNetworkDefinition = result;
return businessNetworkConnection.getAllParticipantRegistries();
})
.then((participantRegistries) => {
return Promise.all(participantRegistries.map((registry) => {
return registry.getAll();
}));
})
.then((participantArrays) => {
return Promise.all(
participantArrays.reduce(
(accumulator, currentValue) => accumulator.concat(currentValue),
[]
));
})
.then((allParticipants) => {
return Promise.all(allParticipants.map((registryParticipant) => {
return participants.set(registryParticipant.getFullyQualifiedIdentifier(), registryParticipant);
}));
})
.then(() => {
return businessNetworkConnection.getIdentityRegistry();
})
.then((identityRegistry) => {
Expand All @@ -53,7 +74,16 @@ class List {
spinner.succeed();
const serializer = businessNetworkDefinition.getSerializer();
const json = identities.map((identity) => {
return serializer.toJSON(identity);
let jsonIdentity = serializer.toJSON(identity);
let fqi = jsonIdentity.participant.replace('resource:', '');

if (identity.participant.getType() !== 'NetworkAdmin' && jsonIdentity.state !== 'REVOKED') {
if (!participants.get(fqi)) {
jsonIdentity.state = 'BOUND PARTICIPANT NOT FOUND';
}
}

return jsonIdentity;
});
cmdUtil.log(Pretty.render(json,{
keysColor: 'blue',
Expand All @@ -67,7 +97,6 @@ class List {
throw error;
});
}

}

module.exports = List;
46 changes: 40 additions & 6 deletions packages/composer-cli/test/identity/list.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@

const Client = require('composer-client');
const BusinessNetworkConnection = Client.BusinessNetworkConnection;
const BusinessNetworkDefinition = require('composer-common').BusinessNetworkDefinition;
const Factory = require('composer-common').Factory;
const ParticipantRegistry = Client.ParticipantRegistry;
const IdentityRegistry = Client.IdentityRegistry;
const ModelManager = require('composer-common').ModelManager;
const Serializer = require('composer-common').Serializer;
const Common = require('composer-common');
const BusinessNetworkDefinition = Common.BusinessNetworkDefinition;
const Factory = Common.Factory;
const Resource = Common.Resource;
const ModelManager = Common.ModelManager;
const Serializer = Common.Serializer;

const CmdUtil = require('../../lib/cmds/utils/cmdutils.js');
const List = require('../../lib/cmds/identity/listCommand.js');
Expand Down Expand Up @@ -69,15 +72,38 @@ describe('composer identity list CLI unit tests', () => {
certificate: '',
participant: factory.newRelationship('org.hyperledger.composer.system', 'Participant', '[email protected]')
});
mockIdentityRegistry.getAll.resolves([identity1, identity2]);
const identity3 = factory.newResource('org.hyperledger.composer.system', 'Identity', 'bfb8c488c0cdec07d9beeef6d97c27a77965ed9a8e30b57e40ea1eb399d8a1bd');
Object.assign(identity3, {
name: 'admin',
issuer: 'ac3dbcbe135ba48b29f97665bb103f8260c38d3872473e584314392797c595f3',
state: 'ACTIVATED',
certificate: '',
participant: factory.newRelationship('org.hyperledger.composer.system', 'NetworkAdmin', 'admin')
});

const identity4 = factory.newResource('org.hyperledger.composer.system', 'Identity', 'd1fa10f09219c13aeecbbbc4823a391f769b64f17124f2c136a9c09d7fd3789f');
Object.assign(identity4, {
name: 'bob',
issuer: 'bfb8c488c0cdec07d9beeef6d97c27a77965ed9a8e30b57e40ea1eb399d8a1be',
state: 'REVOKED',
certificate: '',
participant: factory.newRelationship('org.hyperledger.composer.system', 'Participant', '[email protected]')
});
mockIdentityRegistry.getAll.resolves([identity1, identity2, identity3, identity4]);
sandbox.spy(console, 'log');
});

afterEach(() => {
sandbox.restore();
});

it('should list all identities in the business network using the specified profile', () => {
it('should list all identities in the business network using the specified profile marking those where the participant does not exist', () => {
let mockParticpantRegistry = sinon.createStubInstance(ParticipantRegistry);
let mockParticipant1 = sinon.createStubInstance(Resource);
mockParticipant1.getFullyQualifiedIdentifier.returns('org.hyperledger.composer.system.Participant#[email protected]');
mockParticpantRegistry.getAll.returns([mockParticipant1]);
mockBusinessNetworkConnection.getAllParticipantRegistries.returns(Promise.resolve([mockParticpantRegistry]));

let argv = {
card :'cardName',
participantId: 'org.doge.Doge#DOGE_1',
Expand All @@ -89,12 +115,20 @@ describe('composer identity list CLI unit tests', () => {
sinon.assert.calledOnce(mockBusinessNetworkConnection.connect);
sinon.assert.calledWith(mockBusinessNetworkConnection.connect, 'cardName');
sinon.assert.calledOnce(mockIdentityRegistry.getAll);
sinon.assert.calledOnce(mockBusinessNetworkConnection.getAllParticipantRegistries);
sinon.assert.calledWith(console.log, sinon.match(/identityId:.*eac9f8ff4e0a0df8017a40313c12bdfb9597928526d651e620598d17c9c875ca/));
sinon.assert.calledWith(console.log, sinon.match(/identityId:.*3b6cf18fe92474b6bc720401d5fb9590a3e2e3b67b1aa64ba7d3db85e746a3ba/));
sinon.assert.calledWith(console.log, sinon.match(/identityId:.*bfb8c488c0cdec07d9beeef6d97c27a77965ed9a8e30b57e40ea1eb399d8a1bd/));
sinon.assert.calledWith(console.log, sinon.match(/identityId:.*d1fa10f09219c13aeecbbbc4823a391f769b64f17124f2c136a9c09d7fd3789f/));
sinon.assert.calledWith(console.log, sinon.match(/state:.*ISSUED/));
sinon.assert.calledWith(console.log, sinon.match(/state:.*BOUND PARTICIPANT NOT FOUND/));
sinon.assert.calledWith(console.log, sinon.match(/state:.*ACTIVATED/));
sinon.assert.calledWith(console.log, sinon.match(/state:.*REVOKED/));
});
});

it('should error if the identities cannot be listed', () => {
mockBusinessNetworkConnection.getAllParticipantRegistries.returns(Promise.resolve([]));
mockIdentityRegistry.getAll.rejects(new Error('such error'));

let argv = {
Expand Down
Binary file not shown.
Binary file not shown.
2 changes: 1 addition & 1 deletion packages/composer-playground-api/routes/npm.js
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ module.exports = (app, testMode) => {


if (testMode) {
let readStream = fs.createReadStream(__dirname + '/../basic-sample-network-0.1.9.tgz');
let readStream = fs.createReadStream(__dirname + '/../basic-sample-network-0.2.2.tgz');

return downloadSample(readStream, res);
}
Expand Down
8 changes: 8 additions & 0 deletions packages/composer-playground/e2e/component/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@ export class Deploy {
return element(by.id('import-businessNetworkName')).sendKeys(name);
}

static selectDeployFile(filePath: string) {
this.retrieveBaseTileOptions()
.then(() => {
let inputFileElement = element(by.id('file-importer_input'));
return dragDropFile(inputFileElement, filePath);
});
}

// Deploy selected Tile option from Base tiles
static selectDeployBasisOption(importOption: string) {
// Wait for poplation of sample-network-list-item(s)
Expand Down
6 changes: 3 additions & 3 deletions packages/composer-playground/e2e/component/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@ export class Editor {
static makeFileActive(filename: string) {
return OperationsHelper.retrieveMatchingElementsByCSS('.side-bar-nav', '.flex-container', 0)
.then((elements) => {
for (var i = 0; i < elements.length; i++) {
for (let i = 0; i < elements.length; i++) {
let elm = elements[i];
browser.executeScript(scrollMe, elm);
OperationsHelper.retrieveTextFromElement(elm)
.then((text) => {
if(text.toString().split(/\r\n|\n/)[1] === filename) {
return OperationsHelper.click(elm)
if (text.toString().split(/\r\n|\n/)[1] === filename) {
return OperationsHelper.click(elm);
}
});
}
Expand Down
45 changes: 45 additions & 0 deletions packages/composer-playground/e2e/component/identity-issued.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { browser, element, by, protractor } from 'protractor';
import { ExpectedConditions } from 'protractor';

import { OperationsHelper } from '../utils/operations-helper';
import { Constants } from '../constants';

export class IdentityIssued {
static waitToAppear() {
return browser.wait(ExpectedConditions.visibilityOf(element(by.css('.issue-identity'))), Constants.shortWait);
}

static addToWallet(cardName) {
return OperationsHelper.click(element(by.id('option-1')))
.then(() => {
browser.wait(ExpectedConditions.visibilityOf(element(by.id('cardName'))), Constants.shortWait);
if (cardName) {
return element(by.id('cardName')).clear()
.then(() => {
return element(by.id('cardName')).sendKeys(cardName);
});
} else {
return;
}
})
.then(() => {
return element(by.id('option-1')).element(by.css('.primary'));
})
.then((button) => {
return OperationsHelper.click(button);
});
}
}
65 changes: 65 additions & 0 deletions packages/composer-playground/e2e/component/identity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { browser, element, by, protractor } from 'protractor';
import { ExpectedConditions } from 'protractor';

import { OperationsHelper } from '../utils/operations-helper';
import { dragDropFile } from '../utils/fileUtils';
import { Constants } from '../constants';

export class Identity {
static waitToAppear() {
return browser.wait(ExpectedConditions.visibilityOf(element(by.css('.identity-title'))), Constants.shortWait);
}

static getMyIds() {
return OperationsHelper.retrieveMatchingElementsByCSSFromParentByID('myIDs', '.identity', 0)
.then((values) => {
let promises = [];

for (let i = 0; i < values.length; i++) {
promises.push(OperationsHelper.retrieveTextFromElement(values[i]));
}

return protractor.promise.all(promises).then((texts) => {
let IDs = [];
texts.forEach((text) => {
text = text.split('\n');
IDs.push({id: text[0], status: text[1]});
});
return IDs;
});
});
}

static getAllIds() {
return OperationsHelper.retrieveMatchingElementsByCSSFromParentByID('allIDs', '.identity', 0)
.then((values) => {
let promises = [];

for (let i = 0; i < values.length; i++) {
promises.push(OperationsHelper.retrieveTextFromElement(values[i]));
}

return protractor.promise.all(promises).then((texts) => {
let IDs = [];
texts.forEach((text) => {
text = text.split('\n');
IDs.push({id: text[0], issued: text[1], status: text[2]});
});
return IDs;
});
});
}
}
60 changes: 60 additions & 0 deletions packages/composer-playground/e2e/component/issue-identity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { browser, element, by, protractor } from 'protractor';
import { ExpectedConditions } from 'protractor';

import { OperationsHelper } from '../utils/operations-helper';
import { Constants } from '../constants';

export class IssueIdentity {
static waitToAppear() {
return browser.wait(ExpectedConditions.visibilityOf(element(by.css('.issue-identity'))), Constants.shortWait);
}

static inputUserId(userId) {
return element(by.id('userID')).sendKeys(userId);
}

static inputParticipant(participant) {
return element(by.id('participantFQI')).sendKeys(participant);
}

static selectParticipantType(identifiedBy, type) {
return OperationsHelper.retrieveMatchingElementsByCSSFromParentByID('ngb-typeahead-0', '.dropdown-item', 0)
.then((items) => {
let promises = [];

for (let i = 0; i < items.length; i++) {
promises.push(OperationsHelper.retrieveTextFromElement(items[i]));
}

return protractor.promise.all(promises).then((texts) => {
let id = -1;
texts.forEach((text, index) => {
text = text.split(' ');
if (text[0] === identifiedBy && text[1] === type) {
id = index;
}
});
if (id === -1) {
throw new Error('Particpant not found: ' + identifiedBy + ', ' + type);
}
return items[id];
});
})
.then((el) => {
return OperationsHelper.click(el);
})
}
}
Loading

0 comments on commit 2b6d0eb

Please sign in to comment.