diff --git a/forum-network/public/availability-test.html b/forum-network/public/availability-test.html
deleted file mode 100644
index 5f3db62..0000000
--- a/forum-network/public/availability-test.html
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
- Availability test
-
-
-
-
-
-
- {
- const index = members.length;
- const name = `Member${index + 1}`;
- const member = await new Member(name, scene).initialize();
- members.push(member);
- return member;
-};
-
-const member1 = await newMember();
-const member2 = await newMember();
-await newMember();
-const bench = window.bench = new Bench('Bench', scene);
-const forum = window.forum = new Forum(bench, 'Forum', scene);
-const availability = window.bench = new Availability(bench, 'Availability', scene);
-const business = window.business = new Business(bench, forum, availability, 'Business', scene);
-const requestor = window.requestor = new Public('Public', scene);
-
-const updateDisplayValues = async () => {
- member1.setValue('rep', bench.reputations.getTokens(member1.reputationPublicKey));
- member2.setValue('rep', bench.reputations.getTokens(member2.reputationPublicKey));
- bench.setValue('total rep', bench.getTotalReputation());
- await scene.renderSequenceDiagram();
-};
-
-const updateDisplayValuesAndDelay = async () => {
- await updateDisplayValues();
- await delay(DELAY_INTERVAL);
-};
-
-const getActiveWorker = async () => {
- let worker;
- let request;
- for (const member of members) {
- request = await member.getAssignedWork(availability, business);
- if (request) {
- worker = member;
- worker.actions.getAssignedWork.log(worker, availability);
- worker.activate();
- break;
- }
- }
- return { worker, request };
-};
-
-const voteForWorkEvidence = async (worker, pool) => {
- for (const member of members) {
- if (member !== worker) {
- await member.castVote(pool, { position: true, stake: 1, anonymous: false });
- }
- }
-};
-
-await updateDisplayValuesAndDelay();
-
-// Populate availability pool
-await member1.registerAvailability(availability, 1);
-await member2.registerAvailability(availability, 1);
-await updateDisplayValuesAndDelay();
-
-// Submit work request
-await requestor.submitRequest(business, { fee: 100 }, { please: 'do some work' });
-await updateDisplayValuesAndDelay();
-
-// Receive work request
-const { worker, request } = await getActiveWorker();
-
-// Submit work evidence
-const pool = await worker.submitWork(business, request.id, {
- here: 'is some evidence of work product',
-}, {
- tokenLossRatio: 1,
- duration: 1000,
-});
-worker.deactivate();
-await updateDisplayValuesAndDelay();
-
-// Vote on work evidence
-await voteForWorkEvidence(worker, pool);
-await updateDisplayValuesAndDelay();
-
-// Wait for validation pool duration to elapse
-await delay(1000);
-
-// Distribute reputation awards and fees
-await pool.evaluateWinningConditions();
-await updateDisplayValuesAndDelay();
diff --git a/forum-network/public/basic.html b/forum-network/public/basic.html
deleted file mode 100644
index f0a81f1..0000000
--- a/forum-network/public/basic.html
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
- Forum Network
-
-
-
-
-
-
diff --git a/forum-network/public/basic.js b/forum-network/public/basic.js
deleted file mode 100644
index 48e587d..0000000
--- a/forum-network/public/basic.js
+++ /dev/null
@@ -1,193 +0,0 @@
-import { Box } from './classes/box.js';
-import { Scene } from './classes/scene.js';
-
-const rootElement = document.getElementById('basic');
-const rootBox = new Box('rootBox', rootElement).flex();
-
-function randomDelay(min, max) {
- const delayMs = min + Math.random() * max;
- return delayMs;
-}
-
-function delay(min, max = min) {
- const delayMs = min + Math.random() * (max - min);
- return new Promise((resolve) => {
- setTimeout(resolve, delayMs);
- });
-}
-
-if (true) {
- const scene = new Scene('Scene 1', rootBox);
- const webClientStatus = scene.addDisplayValue('WebClient Status');
- const node1Status = scene.addDisplayValue('Node 1 Status');
- const blockchainStatus = scene.addDisplayValue('Blockchain Status');
-
- const webClient = scene.addActor('web client');
- const node1 = scene.addActor('node 1');
- const blockchain = scene.addActor('blockchain');
- const requestForumPage = scene.addAction('requestForumPage');
- const readBlockchainData = scene.addAction('readBlockchainData');
- const blockchainData = scene.addAction('blockchainData');
- const forumPage = scene.addAction('forumPage');
-
- webClientStatus.set('Initialized');
- node1Status.set('Idle');
- blockchainStatus.set('Idle');
-
- node1.on(requestForumPage, (src, detail) => {
- node1Status.set('Processing request');
- node1.on(blockchainData, (_src, data) => {
- node1Status.set('Processing response');
- setTimeout(() => {
- node1.send(src, forumPage, data);
- node1Status.set('Idle');
- }, randomDelay(500, 1000));
- });
- setTimeout(() => {
- node1.send(blockchain, readBlockchainData, detail);
- }, randomDelay(500, 1500));
- });
-
- blockchain.on(readBlockchainData, (src, _detail) => {
- blockchainStatus.set('Processing request');
- setTimeout(() => {
- blockchain.send(src, blockchainData, {});
- blockchainStatus.set('Idle');
- }, randomDelay(500, 1500));
- });
-
- webClient.on(forumPage, (_src, _detail) => {
- webClientStatus.set('Received forum page');
- });
-
- setInterval(() => {
- webClient.send(node1, requestForumPage);
- webClientStatus.set('Requested forum page');
- }, randomDelay(6000, 12000));
-}
-
-(async function run() {
- const scene = new Scene('Scene 2', rootBox);
-
- const webClient = scene.addActor('webClient');
-
- const nodes = [];
- const memories = [];
- const storages = [];
-
- function addNode() {
- const idx = nodes.length;
- const node = scene.addActor(`node${idx}`);
- const memory = scene.addActor(`memory${idx}`);
- const storage = scene.addActor(`storage${idx}`);
- node.memory = memory;
- node.storage = storage;
- nodes.push(node);
- memories.push(memory);
- storages.push(storage);
- return node;
- }
-
- function getPeer(node) {
- const peers = nodes.filter((peer) => peer !== node);
- const idx = Math.floor(Math.random() * peers.length);
- return peers[idx];
- }
-
- addNode();
- addNode();
-
- const [
- seekTruth,
- considerInfo,
- evaluateConfidence,
- chooseResponse,
- qualifiedOpinions,
- requestMemoryData,
- memoryData,
- requestStorageData,
- storageData,
- ] = [
- 'seek truth',
- 'consider available information',
- 'evaluate confidence',
- 'choose response',
- 'qualified opinions',
- 'request in-memory data',
- 'in-memory data',
- 'request storage data',
- 'storage data',
- ].map((name) => scene.addAction(name));
-
- memories.forEach((memory) => {
- memory.setStatus('Idle');
- memory.on(requestMemoryData, async (src, _detail) => {
- memory.setStatus('Retrieving data');
- await delay(1000);
- memory.send(src, memoryData, {});
- memory.setStatus('Idle');
- });
- });
-
- storages.forEach((storage) => {
- storage.setStatus('Idle');
- storage.on(requestStorageData, async (src, _detail) => {
- storage.setStatus('Retrieving data');
- await delay(1000);
- storage.send(src, storageData, {});
- storage.setStatus('Idle');
- });
- });
-
- nodes.forEach((node) => {
- node.setStatus('Idle');
- node.on(seekTruth, async (seeker, detail) => {
- node.setStatus('Processing request');
-
- node.on(chooseResponse, async (_src, _info) => {
- node.setStatus('Choosing response');
- await delay(1000);
- node.send(seeker, qualifiedOpinions, {});
- node.setStatus('Idle');
- });
-
- node.on(evaluateConfidence, async (_src, _info) => {
- node.setStatus('Evaluating confidence');
- await delay(1000);
- node.send(node, chooseResponse);
- });
-
- node.on(considerInfo, async (_src, _info) => {
- node.setStatus('Considering info');
- await delay(1000);
- node.send(node, evaluateConfidence);
- });
-
- node.on(memoryData, (_src, _data) => {
- node.on(storageData, (__src, __data) => {
- if (detail?.readConcern === 'single') {
- node.send(node, considerInfo, {});
- } else {
- const peer = getPeer(node);
- node.on(qualifiedOpinions, (___src, info) => {
- node.send(node, considerInfo, info);
- });
- node.send(peer, seekTruth, { readConcern: 'single' });
- }
- });
- node.send(node.storage, requestStorageData);
- });
-
- await delay(1000);
- node.send(node.memory, requestMemoryData);
- });
- });
-
- webClient.on(qualifiedOpinions, (_src, _detail) => {
- webClient.setStatus('Received opinions and qualifications');
- });
-
- await delay(1000);
- webClient.setStatus('Seek truth');
- webClient.send(nodes[0], seekTruth);
-}());
diff --git a/forum-network/public/debounce-test.html b/forum-network/public/debounce-test.html
deleted file mode 100644
index 028b237..0000000
--- a/forum-network/public/debounce-test.html
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
- Forum Graph: Debounce test
-
-
-
-
-
-
diff --git a/forum-network/public/debounce-test.js b/forum-network/public/debounce-test.js
deleted file mode 100644
index 278becf..0000000
--- a/forum-network/public/debounce-test.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import { Box } from './classes/box.js';
-import { Scene } from './classes/scene.js';
-import { debounce, delay } from './util.js';
-
-const rootElement = document.getElementById('debounce-test');
-const rootBox = new Box('rootBox', rootElement).flex();
-
-const scene = window.scene = new Scene('Debounce test', rootBox);
-
-const log = () => scene.log('event');
-debounce(log, 500);
-debounce(log, 500);
-await delay(500);
-debounce(log, 500);
-debounce(log, 500);
diff --git a/forum-network/public/forum-network-test.html b/forum-network/public/forum-network-test.html
deleted file mode 100644
index 21b7a39..0000000
--- a/forum-network/public/forum-network-test.html
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
- Forum Network test
-
-
-
-
-
-
diff --git a/forum-network/public/forum-network-test.js b/forum-network/public/forum-network-test.js
deleted file mode 100644
index c74e547..0000000
--- a/forum-network/public/forum-network-test.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import { Box } from './classes/box.js';
-import { Scene } from './classes/scene.js';
-import { PostContent } from './classes/post.js';
-import { Member } from './classes/member.js';
-import { ForumNode } from './classes/forum-node.js';
-import { ForumNetwork } from './classes/forum-network.js';
-import { delay } from './util.js';
-
-const rootElement = document.getElementById('forum-network');
-const rootBox = new Box('rootBox', rootElement).flex();
-
-window.scene = new Scene('Forum Network test', rootBox).log('sequenceDiagram');
-
-window.author1 = await new Member('author1', window.scene).initialize();
-window.author2 = await new Member('author2', window.scene).initialize();
-
-window.forumNetwork = new ForumNetwork();
-
-window.forumNode1 = await new ForumNode('node1', window.scene).initialize(window.forumNetwork);
-window.forumNode2 = await new ForumNode('node2', window.scene).initialize(window.forumNetwork);
-window.forumNode3 = await new ForumNode('node3', window.scene).initialize(window.forumNetwork);
-
-const processInterval = setInterval(async () => {
- await window.forumNode1.processNextMessage();
- await window.forumNode2.processNextMessage();
- await window.forumNode3.processNextMessage();
-
- await window.scene.renderSequenceDiagram();
-}, 100);
-
-// const blockchain = new Blockchain();
-
-window.post1 = new PostContent({ message: 'hi' });
-window.post2 = new PostContent({ message: 'hello' }).addCitation(window.post1.id, 1.0);
-
-await delay(1000);
-await window.author1.submitPost(window.forumNode1, window.post1, 50);
-await delay(1000);
-await window.author2.submitPost(window.forumNode2, window.post2, 100);
-
-await delay(1000);
-clearInterval(processInterval);
diff --git a/forum-network/public/graph-test.html b/forum-network/public/graph-test.html
deleted file mode 100644
index 2907cc2..0000000
--- a/forum-network/public/graph-test.html
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
- Forum Graph
-
-
-
-
-
-
diff --git a/forum-network/public/graph-test.js b/forum-network/public/graph-test.js
deleted file mode 100644
index 8c50aa3..0000000
--- a/forum-network/public/graph-test.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import { Box } from './classes/box.js';
-import { Scene } from './classes/scene.js';
-import { Graph } from './classes/graph.js';
-
-const rootElement = document.getElementById('graph-test');
-const rootBox = new Box('rootBox', rootElement).flex();
-
-window.scene = new Scene('Graph test', rootBox);
-
-window.graph = new Graph();
-
-window.v = [];
-function addVertex() {
- const vertex = window.graph.addVertex({ seq: window.v.length });
- window.v.push(vertex);
-}
-addVertex();
-addVertex();
-addVertex();
-addVertex();
-addVertex();
-
-window.graph.addEdge('e1', 0, 1);
diff --git a/forum-network/public/index.html b/forum-network/public/index.html
index b8a4ba0..77d5d26 100644
--- a/forum-network/public/index.html
+++ b/forum-network/public/index.html
@@ -1,16 +1,17 @@
Forum Network
-
+
+ Tests
diff --git a/forum-network/public/tests/availability.html b/forum-network/public/tests/availability.html
new file mode 100644
index 0000000..36cfd5b
--- /dev/null
+++ b/forum-network/public/tests/availability.html
@@ -0,0 +1,159 @@
+
+
+ Availability test
+
+
+
+
+
+
diff --git a/forum-network/public/tests/basic.html b/forum-network/public/tests/basic.html
new file mode 100644
index 0000000..de0e6e1
--- /dev/null
+++ b/forum-network/public/tests/basic.html
@@ -0,0 +1,203 @@
+
+
+ Forum Network
+
+
+
+
+
+
diff --git a/forum-network/public/tests/debounce.html b/forum-network/public/tests/debounce.html
new file mode 100644
index 0000000..86259ad
--- /dev/null
+++ b/forum-network/public/tests/debounce.html
@@ -0,0 +1,25 @@
+
+
+ Forum Graph: Debounce test
+
+
+
+
+
+
diff --git a/forum-network/public/tests/forum-network.html b/forum-network/public/tests/forum-network.html
new file mode 100644
index 0000000..0793bef
--- /dev/null
+++ b/forum-network/public/tests/forum-network.html
@@ -0,0 +1,63 @@
+
+
+ Forum Network test
+
+
+
+
+
+
diff --git a/forum-network/public/tests/graph.html b/forum-network/public/tests/graph.html
new file mode 100644
index 0000000..d905ce2
--- /dev/null
+++ b/forum-network/public/tests/graph.html
@@ -0,0 +1,33 @@
+
+
+ Forum Graph
+
+
+
+
+
+
diff --git a/forum-network/public/mermaid-test.html b/forum-network/public/tests/mermaid.html
similarity index 92%
rename from forum-network/public/mermaid-test.html
rename to forum-network/public/tests/mermaid.html
index f3b0ab4..2c9c87b 100644
--- a/forum-network/public/mermaid-test.html
+++ b/forum-network/public/tests/mermaid.html
@@ -1,7 +1,7 @@
Mermaid test
-
+
diff --git a/forum-network/public/validation-pool-test.html b/forum-network/public/validation-pool-test.html
deleted file mode 100644
index 7016a03..0000000
--- a/forum-network/public/validation-pool-test.html
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
- Validation Pool test
-
-
-
-
-
-
- {
- member1.setValue('rep', bench.reputations.getTokens(member1.reputationPublicKey));
- member2.setValue('rep', bench.reputations.getTokens(member2.reputationPublicKey));
- bench.setValue('total rep', bench.getTotalReputation());
- // With params.lockingTimeExponent = 0 and params.activeVoterThreshold = null,
- // these next 3 propetries are all equal to total rep
- // bench.setValue('available rep', bench.getTotalAvailableReputation());
- // bench.setValue('active rep', bench.getTotalActiveReputation());
- // bench.setValue('active available rep', bench.getTotalActiveAvailableReputation());
- await scene.renderSequenceDiagram();
-};
-
-updateDisplayValues();
-await delay(1000);
-
-// First member can self-approve
-{
- const pool = await member1.initiateValidationPool(bench, { fee: 7, duration: 1000, tokenLossRatio: 1 });
- await member1.revealIdentity(pool);
- await delay(1000);
- await pool.evaluateWinningConditions(); // Vote passes
- await updateDisplayValues();
- await delay(1000);
-}
-
-// Failure example: second member can not self-approve
-try {
- const pool = await member2.initiateValidationPool(bench, { fee: 1, duration: 1000, tokenLossRatio: 1 });
- await member2.revealIdentity(pool);
- await delay(1000);
- await pool.evaluateWinningConditions(); // Quorum not met!
- await updateDisplayValues();
- await delay(1000);
-} catch (e) {
- if (e.message.match(/Quorum is not met/)) {
- console.log('Caught expected error: Quorum not met');
- } else {
- console.error('Unexpected error');
- throw e;
- }
-}
-
-// Second member must be approved by first member
-{
- const pool = await member2.initiateValidationPool(bench, { fee: 1, duration: 1000, tokenLossRatio: 1 });
- await member1.castVote(pool, { position: true, stake: 4, lockingTime: 0 });
- await member1.revealIdentity(pool);
- await member2.revealIdentity(pool);
- await delay(1000);
- await pool.evaluateWinningConditions(); // Vote passes
- await updateDisplayValues();
- await delay(1000);
-}
-
-await updateDisplayValues();
-
-scene.deactivateAll();
-
-await updateDisplayValues();