Skip to content

Commit a585a5b

Browse files
authored
Louis/command-tests (#88)
* Add commandExecuted test util function Function for testing whether a command has been executed by a node. * Add execute script tests for measure and simulator * Add inputId() and outputId() methods These methods can be used to easily retrieve the IDs of the first and last nodes. Updated the commandExecuted() function to reflect this change. * Fix multiple nodes of the same type being added * Remove assumed wires array Remove wires being put into an array in add() method. This causes complications if a node is connected to multiple other nodes. * Fix PythonShell tests not starting fresh * Add execute command tests Includes: - Bloch sphere - Circuit diagram - Classical register - Hadamard gate - Quantum circuit - Quantum register - Toffoli gate * Run Node.js CI workflow on test/ file * Revert "Fix PythonShell tests not starting fresh" This reverts commit 8f560f9. * Increase timeout limit * Add before hook to PythonShell constructor tests Stops the shell before running tests. * Fix done() being called multiple times * Add Toffoli gate command executed test * Add multi-controlled-u-gate test suite * Fix multiple done calls on error * Add ibm-quantum-system execute command test This command is disabled by default as it requires an API key to run. For this to run on the CI, GitHub secrets could be used. To run this locally, an API key should be assigned to the API_TOKEN constant. * Add more execute command tests Add tests for: - barrier_spec.js - cnot-gate_spec.js - controlled-u-gate_spec.js - identity-gate_spec.js - multi-controlled-u-gate_spec.js - not-gate_spec.js - phase-gate_spec.js - reset_spec.js - rotation-gate_spec.js - swap_spec.js - unitary-gate_spec.js
1 parent dfae02d commit a585a5b

26 files changed

+385
-48
lines changed

.github/workflows/node.js.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ on:
55
branches: [ master ]
66
paths:
77
- 'quantum/**'
8+
- 'test/**'
89
pull_request:
910
branches: [ master ]
1011
paths:
1112
- 'quantum/**'
13+
- 'test/**'
1214

1315
jobs:
1416
build:

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
"setup": "(npm run link && npm run venv) && echo Setup complete - run 'npm start' to open Node-RED",
3030
"link": "bash bin/link.sh || bin/link.sh",
3131
"venv": "bash bin/pyvenv.sh || bin/pyvenv.sh",
32-
"test": "mocha \"test/**/*_spec.js\"",
32+
"test": "mocha \"test/**/*_spec.js\" --timeout 10000",
3333
"clean": "rm -r venv/ & npm uninstall --prefix ~/.node-red/ node-red-contrib-quantum",
3434
"lint": "eslint --fix --ignore-path .gitignore .",
3535
"postinstall": "npm run venv"

test/flow-builder.js

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const NODES = {
1212
'identity-gate': require('../quantum/nodes/identity-gate/identity-gate.js'),
1313
'local-simulator': require('../quantum/nodes/local-simulator/local-simulator.js'),
1414
'measure': require('../quantum/nodes/measure/measure.js'),
15+
'multi-controlled-u-gate': require('../quantum/nodes/multi-controlled-u-gate/multi-controlled-u-gate.js'),
1516
'not-gate': require('../quantum/nodes/not-gate/not-gate.js'),
1617
'phase-gate': require('../quantum/nodes/phase-gate/phase-gate.js'),
1718
'quantum-circuit': require('../quantum/nodes/quantum-circuit/quantum-circuit.js'),
@@ -42,6 +43,24 @@ class FlowBuilder {
4243
return JSON.stringify(this.flow);
4344
}
4445

46+
/**
47+
* Return the ID of the first node.
48+
*
49+
* @return {string} The nodes ID string.
50+
*/
51+
get inputId() {
52+
return this.flow[0].id;
53+
}
54+
55+
/**
56+
* Return the ID of the last node.
57+
*
58+
* @return {string} The nodes ID string.
59+
*/
60+
get outputId() {
61+
return this.flow[this.flow.length - 1].id;
62+
}
63+
4564
/**
4665
* Add a quantum node to the flow.
4766
*
@@ -54,9 +73,11 @@ class FlowBuilder {
5473
if (!NODES.hasOwnProperty(name)) {
5574
throw new Error(`Failed to find node ${name}`);
5675
}
57-
let json = {id: id, wires: [wires], type: name, name: name.replace(/-/g, ' ')};
76+
let json = {id: id, wires: wires, type: name, name: name.replace(/-/g, ' ')};
5877
Object.assign(json, properties);
59-
this.nodes.push(NODES[name]);
78+
if (!this.nodes.includes(NODES[name])) {
79+
this.nodes.push(NODES[name]);
80+
}
6081
this.flow.push(json);
6182
}
6283

test/nodes/barrier_spec.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
const barrierNode = require('../../quantum/nodes/barrier/barrier.js');
1+
const util = require('util');
22
const testUtil = require('../test-util');
33
const nodeTestHelper = testUtil.nodeTestHelper;
4+
const {FlowBuilder} = require('../flow-builder');
5+
const barrierNode = require('../../quantum/nodes/barrier/barrier.js');
6+
const snippets = require('../../quantum/snippets.js');
47

58

69
describe('BarrierNode', function() {
@@ -16,4 +19,14 @@ describe('BarrierNode', function() {
1619
it('load node', function(done) {
1720
testUtil.isLoaded(barrierNode, 'barrier', done);
1821
});
22+
23+
it('execute command', function(done) {
24+
let command = util.format(snippets.BARRIER, '0, ');
25+
let flow = new FlowBuilder();
26+
flow.add('quantum-circuit', 'n0', [['n1']], {structure: 'qubits', outputs: '1', qbitsreg: '1', cbitsreg: '1'});
27+
flow.add('barrier', 'n1', [['n2']], {outputs: '1'});
28+
flow.addOutput('n2');
29+
30+
testUtil.commandExecuted(flow, command, done);
31+
});
1932
});

test/nodes/bloch-sphere_spec.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
const blochSphereNode = require('../../quantum/nodes/bloch-sphere/bloch-sphere.js');
21
const testUtil = require('../test-util');
32
const nodeTestHelper = testUtil.nodeTestHelper;
3+
const {FlowBuilder} = require('../flow-builder');
4+
const blochSphereNode = require('../../quantum/nodes/bloch-sphere/bloch-sphere.js');
5+
const snippets = require('../../quantum/snippets.js');
46

57

68
describe('BlochSphereNode', function() {
@@ -16,4 +18,19 @@ describe('BlochSphereNode', function() {
1618
it('load node', function(done) {
1719
testUtil.isLoaded(blochSphereNode, 'bloch-sphere', done);
1820
});
21+
22+
it('execute command', function(done) {
23+
let command = snippets.BLOCH_SPHERE + snippets.ENCODE_IMAGE;
24+
let flow = new FlowBuilder();
25+
flow.add('quantum-circuit', 'n0', [['n1'], ['n2'], ['n3']],
26+
{structure: 'qubits', outputs: '3', qbitsreg: '3', cbitsreg: '1'});
27+
flow.add('hadamard-gate', 'n1', [['n4']]);
28+
flow.add('hadamard-gate', 'n2', [['n4']]);
29+
flow.add('not-gate', 'n3', [['n4']]);
30+
flow.add('toffoli-gate', 'n4', [['n5'], ['n5'], ['n5']], {targetPosition: 'Middle'});
31+
flow.add('bloch-sphere', 'n5', [['n6']]);
32+
flow.addOutput('n6');
33+
34+
testUtil.commandExecuted(flow, command, done);
35+
});
1936
});

test/nodes/circuit-diagram_spec.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
const circuitDiagramNode = require('../../quantum/nodes/circuit-diagram/circuit-diagram.js');
21
const testUtil = require('../test-util');
32
const nodeTestHelper = testUtil.nodeTestHelper;
3+
const {FlowBuilder} = require('../flow-builder');
4+
const circuitDiagramNode = require('../../quantum/nodes/circuit-diagram/circuit-diagram.js');
5+
const snippets = require('../../quantum/snippets.js');
46

57

68
describe('CircuitDiagramNode', function() {
@@ -16,4 +18,16 @@ describe('CircuitDiagramNode', function() {
1618
it('load node', function(done) {
1719
testUtil.isLoaded(circuitDiagramNode, 'circuit-diagram', done);
1820
});
21+
22+
it('execute command', function(done) {
23+
let command = snippets.CIRCUIT_DIAGRAM + snippets.ENCODE_IMAGE;
24+
let flow = new FlowBuilder();
25+
flow.add('quantum-circuit', 'n0', [['n1']], {structure: 'qubits', outputs: '1', qbitsreg: '1', cbitsreg: '1'});
26+
flow.add('hadamard-gate', 'n1', [['n2']]);
27+
flow.add('measure', 'n2', [['n3']], {selectedBit: '0'});
28+
flow.add('circuit-diagram', 'n3', [['n4']]);
29+
flow.addOutput('n4');
30+
31+
testUtil.commandExecuted(flow, command, done);
32+
});
1933
});

test/nodes/classical-register_spec.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
const classicalRegisterNode = require('../../quantum/nodes/classical-register/classical-register.js');
1+
const util = require('util');
22
const testUtil = require('../test-util');
3+
const classicalRegisterNode = require('../../quantum/nodes/classical-register/classical-register.js');
4+
const {FlowBuilder} = require('../flow-builder');
35
const nodeTestHelper = testUtil.nodeTestHelper;
4-
6+
const snippets = require('../../quantum/snippets.js');
57

68
describe('ClassicalRegisterNode', function() {
79
beforeEach(function(done) {
@@ -16,4 +18,16 @@ describe('ClassicalRegisterNode', function() {
1618
it('load node', function(done) {
1719
testUtil.isLoaded(classicalRegisterNode, 'classical-register', done);
1820
});
21+
22+
it('execute command', function(done) {
23+
let command = util.format(snippets.CLASSICAL_REGISTER, '_test', '3, "test"');
24+
let flow = new FlowBuilder();
25+
flow.add('quantum-circuit', 'n0', [['n1'], ['n2']],
26+
{structure: 'registers', outputs: '2', qbitsreg: '1', cbitsreg: '1'});
27+
flow.add('quantum-register', 'n1', [['n3']], {outputs: '1'});
28+
flow.add('classical-register', 'n2', [], {classicalBits: '3', name: 'test'});
29+
flow.addOutput('n3');
30+
31+
testUtil.commandExecuted(flow, command, done);
32+
});
1933
});

test/nodes/cnot-gate_spec.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
const cnotGateNode = require('../../quantum/nodes/cnot-gate/cnot-gate.js');
1+
const util = require('util');
22
const testUtil = require('../test-util');
33
const nodeTestHelper = testUtil.nodeTestHelper;
4+
const {FlowBuilder} = require('../flow-builder');
5+
const cnotGateNode = require('../../quantum/nodes/cnot-gate/cnot-gate.js');
6+
const snippets = require('../../quantum/snippets.js');
47

58

69
describe('CnotGateNode', function() {
@@ -16,4 +19,15 @@ describe('CnotGateNode', function() {
1619
it('load node', function(done) {
1720
testUtil.isLoaded(cnotGateNode, 'cnot-gate', done);
1821
});
22+
23+
it('execute command', function(done) {
24+
let command = util.format(snippets.CNOT_GATE, '1', '0');
25+
let flow = new FlowBuilder();
26+
flow.add('quantum-circuit', 'n0', [['n1'], ['n1']],
27+
{structure: 'qubits', outputs: '2', qbitsreg: '2', cbitsreg: '1'});
28+
flow.add('cnot-gate', 'n1', [['n2']], {targetPosition: 'Upper'});
29+
flow.addOutput('n2');
30+
31+
testUtil.commandExecuted(flow, command, done);
32+
});
1933
});

test/nodes/controlled-u-gate_spec.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
const controlledUGateNode = require('../../quantum/nodes/controlled-u-gate/controlled-u-gate.js');
1+
const util = require('util');
22
const testUtil = require('../test-util');
33
const nodeTestHelper = testUtil.nodeTestHelper;
4+
const {FlowBuilder} = require('../flow-builder');
5+
const controlledUGateNode = require('../../quantum/nodes/controlled-u-gate/controlled-u-gate.js');
6+
const snippets = require('../../quantum/snippets.js');
47

58

69
describe('ControlledUGateNode', function() {
@@ -16,4 +19,16 @@ describe('ControlledUGateNode', function() {
1619
it('load node', function(done) {
1720
testUtil.isLoaded(controlledUGateNode, 'controlled-u-gate', done);
1821
});
22+
23+
it('execute command', function(done) {
24+
let command = util.format(snippets.CU_GATE, '0*pi', '0*pi', '0*pi', '0*pi', '1', '0');
25+
let flow = new FlowBuilder();
26+
flow.add('quantum-circuit', 'n0', [['n1'], ['n1']],
27+
{structure: 'qubits', outputs: '2', qbitsreg: '2', cbitsreg: '1'});
28+
flow.add('controlled-u-gate', 'n1', [['n2']],
29+
{targetPosition: 'Upper', theta: '0', phi: '0', lambda: '0', gamma: '0'});
30+
flow.addOutput('n2');
31+
32+
testUtil.commandExecuted(flow, command, done);
33+
});
1934
});

test/nodes/hadamard-gate_spec.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
const hadamardGateNode = require('../../quantum/nodes/hadamard-gate/hadamard-gate.js');
1+
const util = require('util');
22
const testUtil = require('../test-util');
33
const nodeTestHelper = testUtil.nodeTestHelper;
4+
const {FlowBuilder} = require('../flow-builder');
5+
const hadamardGateNode = require('../../quantum/nodes/hadamard-gate/hadamard-gate.js');
6+
const snippets = require('../../quantum/snippets.js');
47

58

69
describe('HadamardGateNode', function() {
@@ -16,4 +19,14 @@ describe('HadamardGateNode', function() {
1619
it('load node', function(done) {
1720
testUtil.isLoaded(hadamardGateNode, 'hadamard-gate', done);
1821
});
22+
23+
it('execute command', function(done) {
24+
let command = util.format(snippets.HADAMARD_GATE, '0');
25+
let flow = new FlowBuilder();
26+
flow.add('quantum-circuit', 'n0', [['n1']], {structure: 'qubits', outputs: '1', qbitsreg: '1', cbitsreg: '1'});
27+
flow.add('hadamard-gate', 'n1', [['n2']]);
28+
flow.addOutput('n2');
29+
30+
testUtil.commandExecuted(flow, command, done);
31+
});
1932
});

test/nodes/ibm-quantum-system_spec.js

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1-
const ibmQuantumSystemNode = require('../../quantum/nodes/ibm-quantum-system/ibm-quantum-system.js');
1+
const util = require('util');
22
const testUtil = require('../test-util');
33
const nodeTestHelper = testUtil.nodeTestHelper;
4+
const {FlowBuilder} = require('../flow-builder');
5+
const ibmQuantumSystemNode = require('../../quantum/nodes/ibm-quantum-system/ibm-quantum-system.js');
6+
const snippets = require('../../quantum/snippets.js');
47

8+
// DO NOT COMMIT YOUR API TOKEN!
9+
const API_TOKEN = '';
510

611
describe('IBMQuantumSystemNode', function() {
712
beforeEach(function(done) {
@@ -16,4 +21,18 @@ describe('IBMQuantumSystemNode', function() {
1621
it('load node', function(done) {
1722
testUtil.isLoaded(ibmQuantumSystemNode, 'ibm-quantum-system', done);
1823
});
24+
25+
xit('execute command', function(done) {
26+
// Disabled for now until we can use GitHub secrets to pass an API key to this test for CI.
27+
let command = util.format(snippets.IBMQ_SYSTEM_DEFAULT + snippets.IBMQ_SYSTEM_RESULT, API_TOKEN, '1');
28+
let flow = new FlowBuilder();
29+
flow.add('quantum-circuit', 'n0', [['n1']], {structure: 'qubits', outputs: '1', qbitsreg: '1', cbitsreg: '1'});
30+
flow.add('hadamard-gate', 'n1', [['n2']]);
31+
flow.add('measure', 'n2', [['n3']], {selectedBit: '0'});
32+
flow.add('ibm-quantum-system', 'n3', [['n4']], {api_token: API_TOKEN,
33+
preferred_backend: '', preferred_output: ' Results'});
34+
flow.addOutput('n4');
35+
36+
testUtil.commandExecuted(flow, command, done);
37+
}).timeout(180000); // Needs long timeout as it takes awhile for IBM server to respond
1938
});

test/nodes/identity-gate_spec.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
const identityGateNode = require('../../quantum/nodes/identity-gate/identity-gate.js');
1+
const util = require('util');
22
const testUtil = require('../test-util');
33
const nodeTestHelper = testUtil.nodeTestHelper;
4+
const {FlowBuilder} = require('../flow-builder');
5+
const identityGateNode = require('../../quantum/nodes/identity-gate/identity-gate.js');
6+
const snippets = require('../../quantum/snippets.js');
47

58

69
describe('IdentityGateNode', function() {
@@ -16,4 +19,14 @@ describe('IdentityGateNode', function() {
1619
it('load node', function(done) {
1720
testUtil.isLoaded(identityGateNode, 'identity-gate', done);
1821
});
22+
23+
it('execute command', function(done) {
24+
let command = util.format(snippets.IDENTITY, '0');
25+
let flow = new FlowBuilder();
26+
flow.add('quantum-circuit', 'n0', [['n1']], {structure: 'qubits', outputs: '1', qbitsreg: '1', cbitsreg: '1'});
27+
flow.add('identity-gate', 'n1', [['n2']]);
28+
flow.addOutput('n2');
29+
30+
testUtil.commandExecuted(flow, command, done);
31+
});
1932
});

test/nodes/local-simulator_spec.js

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
const util = require('util');
2-
const assert = require('chai').assert;
32
const testUtil = require('../test-util');
43
const nodeTestHelper = testUtil.nodeTestHelper;
54
const {FlowBuilder} = require('../flow-builder');
65
const localSimulatorNode = require('../../quantum/nodes/local-simulator/local-simulator.js');
7-
const shell = require('../../quantum/python.js').PythonShell;
86
const snippets = require('../../quantum/snippets.js');
97

108

@@ -14,7 +12,6 @@ describe('LocalSimulatorNode', function() {
1412
});
1513

1614
afterEach(function(done) {
17-
shell.stop();
1815
nodeTestHelper.unload();
1916
nodeTestHelper.stopServer(done);
2017
});
@@ -23,29 +20,15 @@ describe('LocalSimulatorNode', function() {
2320
testUtil.isLoaded(localSimulatorNode, 'local-simulator', done);
2421
});
2522

26-
it('execute script', function(done) {
27-
const flow = new FlowBuilder();
28-
flow.add('quantum-circuit', 'n0', ['n1'], {structure: 'qubits', outputs: '1', qbitsreg: '1', cbitsreg: '1'});
29-
flow.add('hadamard-gate', 'n1', ['n2']);
30-
flow.add('measure', 'n2', ['n3'], {selectedBit: '0'});
31-
flow.add('local-simulator', 'n3', ['n4'], {shots: '1'});
23+
it('execute command', function(done) {
24+
let command = util.format(snippets.LOCAL_SIMULATOR, '1');
25+
let flow = new FlowBuilder();
26+
flow.add('quantum-circuit', 'n0', [['n1']], {structure: 'qubits', outputs: '1', qbitsreg: '1', cbitsreg: '1'});
27+
flow.add('hadamard-gate', 'n1', [['n2']]);
28+
flow.add('measure', 'n2', [['n3']], {selectedBit: '0'});
29+
flow.add('local-simulator', 'n3', [['n4']], {shots: '1'});
3230
flow.addOutput('n4');
3331

34-
nodeTestHelper.load(flow.nodes, flow.flow, function() {
35-
let n0 = nodeTestHelper.getNode('n0');
36-
let n4 = nodeTestHelper.getNode('n4');
37-
38-
n4.on('input', function(msg) {
39-
try {
40-
let command = util.format(snippets.LOCAL_SIMULATOR, '1');
41-
assert.strictEqual(shell.lastCommand, command);
42-
done();
43-
} catch (err) {
44-
done(err);
45-
}
46-
});
47-
48-
n0.receive({payload: ''});
49-
});
32+
testUtil.commandExecuted(flow, command, done);
5033
});
5134
});

0 commit comments

Comments
 (0)