diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2decf987..80544e5d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,22 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
### Changed
### Fixed
+## [0.6.2]
+
+### Added
+- feat(common): add app and role id options to hApp installation
+- feat(common): add mem-proofs to installAgentsHapps (#139)
+- feat(trycp): add multiple clients by array of URLs
+- feat(trycp): add multiple clients/players
+
+### Fixed
+- fix(trycp): allow for multiple hosts in scenario (#136)
+
+## [0.6.1]
+
+### Changed
+- Fixture: split zome into integrity and coordinator zomes [PR \#143](https://github.com/holochain/tryorama/pull/143)
+
## [0.6.0]
### Changed
diff --git a/Cargo.lock b/Cargo.lock
index 762f9acc..a0d9cdbf 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -206,6 +206,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
+[[package]]
+name = "coordinator"
+version = "0.1.0"
+dependencies = [
+ "hdk",
+ "integrity",
+ "serde",
+]
+
[[package]]
name = "core-foundation"
version = "0.9.3"
@@ -345,14 +354,6 @@ dependencies = [
"once_cell",
]
-[[package]]
-name = "crud"
-version = "0.1.0"
-dependencies = [
- "hdk",
- "serde",
-]
-
[[package]]
name = "darling"
version = "0.13.4"
@@ -1006,6 +1007,14 @@ dependencies = [
"cfg-if 1.0.0",
]
+[[package]]
+name = "integrity"
+version = "0.1.0"
+dependencies = [
+ "holochain_deterministic_integrity",
+ "serde",
+]
+
[[package]]
name = "intervallum"
version = "1.4.0"
diff --git a/Cargo.toml b/Cargo.toml
index f135d080..978b995d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,7 +1,8 @@
[workspace]
members = [
"crates/trycp_server",
- "ts/test/fixture/zomes/entry"
+ "ts/test/fixture/zomes/coordinator",
+ "ts/test/fixture/zomes/integrity"
]
[profile.dev]
diff --git a/README.md b/README.md
index bd3f3953..61935301 100644
--- a/README.md
+++ b/README.md
@@ -55,7 +55,7 @@ test("Create 2 players and create and read an entry", async (t) => {
// The cells of the installed hApp are returned in the same order as the DNAs
// that were passed into the player creation.
const createEntryHash: ActionHash = await alice.cells[0].callZome({
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "create",
payload: content,
});
@@ -66,7 +66,7 @@ test("Create 2 players and create and read an entry", async (t) => {
// Using the same cell and zome as before, the second player reads the
// created entry.
const readContent: typeof content = await bob.cells[0].callZome({
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "read",
payload: createEntryHash,
});
@@ -100,7 +100,7 @@ test("Create 2 players and create and read an entry", async (t) => {
const content = "Hello Tryorama";
const createEntryHash: EntryHash = await alice.cells[0].callZome({
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "create",
payload: content,
});
@@ -108,7 +108,7 @@ test("Create 2 players and create and read an entry", async (t) => {
await pause(100);
const readContent: typeof content = await bob.cells[0].callZome({
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "read",
payload: createEntryHash,
});
@@ -184,7 +184,7 @@ Here is the above example that just uses a `Conductor` without a `Scenario`:
const entryContent = "test-content";
const createEntryHash: EntryHash = await aliceHapps.cells[0].callZome({
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "create",
payload: entryContent,
});
@@ -193,7 +193,7 @@ Here is the above example that just uses a `Conductor` without a `Scenario`:
const readEntryResponse: typeof entryContent =
await bobHapps.cells[0].callZome({
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "read",
payload: createEntryHash,
});
@@ -226,7 +226,7 @@ const [aliceHapps] = await conductor.installAgentsHapps({
const entryContent = "test-content";
const createEntryHash: EntryHash = await aliceHapps.cells[0].callZome({
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "create",
payload: entryContent,
});
@@ -248,12 +248,12 @@ const [aliceHapps] = await conductor.installAgentsHapps({
agentsDnas: [dnas],
});
const createEntryHash: EntryHash = await aliceHapps.cells[0].callZome({
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "create",
payload: entryContent,
});
const readEntryHash: string = await aliceHapps.cells[0].callZome({
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "read",
payload: createEntryHash,
});
@@ -265,12 +265,12 @@ the shorthand access to the Zome can be called
const [aliceHapps] = await conductor.installAgentsHapps({
agentsDnas: [dnas],
});
-const aliceCrudZomeCall = getZomeCaller(aliceHapps.cells[0], "crud");
-const entryHeaderHash: ActionHash = await crudZomeCall(
+const aliceCallCoordinatorZome = getZomeCaller(aliceHapps.cells[0], "coordinator");
+const entryHeaderHash: ActionHash = await aliceCallCoordinatorZome(
"create",
"test-entry"
);
-const readEntryHash: string = await crudZomeCall(
+const readEntryHash: string = await aliceCallCoordinatorZome(
"read",
entryHeaderHash
);
@@ -298,7 +298,7 @@ const alice = await scenario.addPlayerWithHapp(dna, signalHandler);
const signal = { value: "hello alice" };
alice.cells[0].callZome({
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "signal_loopback",
payload: signal,
});
diff --git a/docs/tryorama.agentdnas.agentpubkey.md b/docs/tryorama.agentdnas.agentpubkey.md
new file mode 100644
index 00000000..5f94f0d9
--- /dev/null
+++ b/docs/tryorama.agentdnas.agentpubkey.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [AgentDnas](./tryorama.agentdnas.md) > [agentPubKey](./tryorama.agentdnas.agentpubkey.md)
+
+## AgentDnas.agentPubKey property
+
+Signature:
+
+```typescript
+agentPubKey?: AgentPubKey;
+```
diff --git a/docs/tryorama.agentdnas.dnas.md b/docs/tryorama.agentdnas.dnas.md
new file mode 100644
index 00000000..bb640d58
--- /dev/null
+++ b/docs/tryorama.agentdnas.dnas.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [AgentDnas](./tryorama.agentdnas.md) > [dnas](./tryorama.agentdnas.dnas.md)
+
+## AgentDnas.dnas property
+
+Signature:
+
+```typescript
+dnas: Dna[];
+```
diff --git a/docs/tryorama.agentdnas.md b/docs/tryorama.agentdnas.md
new file mode 100644
index 00000000..8be965d2
--- /dev/null
+++ b/docs/tryorama.agentdnas.md
@@ -0,0 +1,21 @@
+
+
+[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [AgentDnas](./tryorama.agentdnas.md)
+
+## AgentDnas interface
+
+DNAs per agent. Optionally an agent pub key.
+
+Signature:
+
+```typescript
+export interface AgentDnas
+```
+
+## Properties
+
+| Property | Type | Description |
+| --- | --- | --- |
+| [agentPubKey?](./tryorama.agentdnas.agentpubkey.md) | AgentPubKey | (Optional) |
+| [dnas](./tryorama.agentdnas.dnas.md) | [Dna](./tryorama.dna.md)\[\] | |
+
diff --git a/docs/tryorama.agenthappoptions.md b/docs/tryorama.agenthappoptions.md
deleted file mode 100644
index eaad06c4..00000000
--- a/docs/tryorama.agenthappoptions.md
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [AgentHappOptions](./tryorama.agenthappoptions.md)
-
-## AgentHappOptions type
-
-A type that specifies either only the DNAs that the hApp to be installed consists of, or the DNAs and a signal handler to be registered.
-
-Signature:
-
-```typescript
-export declare type AgentHappOptions = DnaSource[] | {
- dnas: DnaSource[];
- signalHandler?: AppSignalCb;
- properties?: DnaProperties;
-};
-```
diff --git a/docs/tryorama.agentshappsoptions.md b/docs/tryorama.agentshappsoptions.md
new file mode 100644
index 00000000..93e17763
--- /dev/null
+++ b/docs/tryorama.agentshappsoptions.md
@@ -0,0 +1,19 @@
+
+
+[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [AgentsHappsOptions](./tryorama.agentshappsoptions.md)
+
+## AgentsHappsOptions type
+
+An array of DNA sources for each agent (2-dimensional array) or an array of DNAs and an optional agent pub key. Optionally a UID to be used for DNA installation.
+
+Signature:
+
+```typescript
+export declare type AgentsHappsOptions = DnaSource[][] | {
+ agentsDnas: AgentDnas[];
+ uid?: string;
+ installedAppId?: InstalledAppId;
+};
+```
+References: [AgentDnas](./tryorama.agentdnas.md)
+
diff --git a/docs/tryorama.cleanalltrycpconductors.md b/docs/tryorama.cleanalltrycpconductors.md
deleted file mode 100644
index 27fc4baf..00000000
--- a/docs/tryorama.cleanalltrycpconductors.md
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [cleanAllTryCpConductors](./tryorama.cleanalltrycpconductors.md)
-
-## cleanAllTryCpConductors variable
-
-Run the `reset` command on the TryCP server to delete all conductor data.
-
-Signature:
-
-```typescript
-cleanAllTryCpConductors: (serverUrl: URL) => Promise
-```
diff --git a/docs/tryorama.clientsplayersoptions.agentpubkeys.md b/docs/tryorama.clientsplayersoptions.agentpubkeys.md
new file mode 100644
index 00000000..a64ed540
--- /dev/null
+++ b/docs/tryorama.clientsplayersoptions.agentpubkeys.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [ClientsPlayersOptions](./tryorama.clientsplayersoptions.md) > [agentPubKeys](./tryorama.clientsplayersoptions.agentpubkeys.md)
+
+## ClientsPlayersOptions.agentPubKeys property
+
+A list of previously generated agent pub keys (optional).
+
+Signature:
+
+```typescript
+agentPubKeys?: AgentPubKey[];
+```
diff --git a/docs/tryorama.clientsplayersoptions.clienttimeout.md b/docs/tryorama.clientsplayersoptions.clienttimeout.md
new file mode 100644
index 00000000..db9db98d
--- /dev/null
+++ b/docs/tryorama.clientsplayersoptions.clienttimeout.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [ClientsPlayersOptions](./tryorama.clientsplayersoptions.md) > [clientTimeout](./tryorama.clientsplayersoptions.clienttimeout.md)
+
+## ClientsPlayersOptions.clientTimeout property
+
+A timeout for the web socket connection (optional).
+
+Signature:
+
+```typescript
+clientTimeout?: number;
+```
diff --git a/docs/tryorama.clientsplayersoptions.dnas.md b/docs/tryorama.clientsplayersoptions.dnas.md
new file mode 100644
index 00000000..239cc6ca
--- /dev/null
+++ b/docs/tryorama.clientsplayersoptions.dnas.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [ClientsPlayersOptions](./tryorama.clientsplayersoptions.md) > [dnas](./tryorama.clientsplayersoptions.dnas.md)
+
+## ClientsPlayersOptions.dnas property
+
+An array of DNAs that will be installed for each agent (optional).
+
+Signature:
+
+```typescript
+dnas?: Dna[];
+```
diff --git a/docs/tryorama.clientsplayersoptions.md b/docs/tryorama.clientsplayersoptions.md
new file mode 100644
index 00000000..809a29c2
--- /dev/null
+++ b/docs/tryorama.clientsplayersoptions.md
@@ -0,0 +1,24 @@
+
+
+[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [ClientsPlayersOptions](./tryorama.clientsplayersoptions.md)
+
+## ClientsPlayersOptions interface
+
+
+Signature:
+
+```typescript
+export interface ClientsPlayersOptions
+```
+
+## Properties
+
+| Property | Type | Description |
+| --- | --- | --- |
+| [agentPubKeys?](./tryorama.clientsplayersoptions.agentpubkeys.md) | AgentPubKey\[\] | (Optional) A list of previously generated agent pub keys (optional). |
+| [clientTimeout?](./tryorama.clientsplayersoptions.clienttimeout.md) | number | (Optional) A timeout for the web socket connection (optional). |
+| [dnas?](./tryorama.clientsplayersoptions.dnas.md) | [Dna](./tryorama.dna.md)\[\] | (Optional) An array of DNAs that will be installed for each agent (optional). |
+| [numberOfAgentsPerConductor?](./tryorama.clientsplayersoptions.numberofagentsperconductor.md) | number | (Optional) Number of agents per conductor. Defaults to 1. Requires dnas
to be specified. |
+| [numberOfConductorsPerClient?](./tryorama.clientsplayersoptions.numberofconductorsperclient.md) | number | (Optional) Number of conductors per client. Default to 1. |
+| [signalHandler?](./tryorama.clientsplayersoptions.signalhandler.md) | AppSignalCb | (Optional) A signal handler to be registered in conductors. |
+
diff --git a/docs/tryorama.clientsplayersoptions.numberofagentsperconductor.md b/docs/tryorama.clientsplayersoptions.numberofagentsperconductor.md
new file mode 100644
index 00000000..a2fe87bd
--- /dev/null
+++ b/docs/tryorama.clientsplayersoptions.numberofagentsperconductor.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [ClientsPlayersOptions](./tryorama.clientsplayersoptions.md) > [numberOfAgentsPerConductor](./tryorama.clientsplayersoptions.numberofagentsperconductor.md)
+
+## ClientsPlayersOptions.numberOfAgentsPerConductor property
+
+Number of agents per conductor. Defaults to 1. Requires `dnas` to be specified.
+
+Signature:
+
+```typescript
+numberOfAgentsPerConductor?: number;
+```
diff --git a/docs/tryorama.clientsplayersoptions.numberofconductorsperclient.md b/docs/tryorama.clientsplayersoptions.numberofconductorsperclient.md
new file mode 100644
index 00000000..ba19a03d
--- /dev/null
+++ b/docs/tryorama.clientsplayersoptions.numberofconductorsperclient.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [ClientsPlayersOptions](./tryorama.clientsplayersoptions.md) > [numberOfConductorsPerClient](./tryorama.clientsplayersoptions.numberofconductorsperclient.md)
+
+## ClientsPlayersOptions.numberOfConductorsPerClient property
+
+Number of conductors per client. Default to 1.
+
+Signature:
+
+```typescript
+numberOfConductorsPerClient?: number;
+```
diff --git a/docs/tryorama.clientsplayersoptions.signalhandler.md b/docs/tryorama.clientsplayersoptions.signalhandler.md
new file mode 100644
index 00000000..94e89dcc
--- /dev/null
+++ b/docs/tryorama.clientsplayersoptions.signalhandler.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [ClientsPlayersOptions](./tryorama.clientsplayersoptions.md) > [signalHandler](./tryorama.clientsplayersoptions.signalhandler.md)
+
+## ClientsPlayersOptions.signalHandler property
+
+A signal handler to be registered in conductors.
+
+Signature:
+
+```typescript
+signalHandler?: AppSignalCb;
+```
diff --git a/docs/tryorama.conductor.installagentshapps.md b/docs/tryorama.conductor.installagentshapps.md
index 2cd714df..80340194 100644
--- a/docs/tryorama.conductor.installagentshapps.md
+++ b/docs/tryorama.conductor.installagentshapps.md
@@ -9,18 +9,14 @@ Install a set of DNAs for multiple agents into the conductor.
Signature:
```typescript
-installAgentsHapps(options: {
- agentsDnas: DnaSource[][];
- uid?: string;
- properties?: DnaProperties;
- }): Promise;
+installAgentsHapps(options: AgentsHappsOptions): Promise;
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
-| options | { agentsDnas: DnaSource\[\]\[\]; uid?: string; properties?: DnaProperties; } | An array of DNAs for each agent, resulting in a 2-dimensional array, and a UID for the DNAs (optional). |
+| options | [AgentsHappsOptions](./tryorama.agentshappsoptions.md) | An array of DNAs for each agent, resulting in a 2-dimensional array, and a UID for the DNAs (optional). |
Returns:
diff --git a/docs/tryorama.createtrycpconductor.md b/docs/tryorama.createtrycpconductor.md
index cfe053a2..ca97bdb2 100644
--- a/docs/tryorama.createtrycpconductor.md
+++ b/docs/tryorama.createtrycpconductor.md
@@ -4,10 +4,10 @@
## createTryCpConductor variable
-The function to create a TryCP Conductor (aka "Player").
+The function to create a TryCP Conductor. By default configures and starts it.
Signature:
```typescript
-createTryCpConductor: (serverUrl: URL, options?: TryCpConductorOptions) => Promise
+createTryCpConductor: (tryCpClient: TryCpClient, options?: TryCpConductorOptions) => Promise
```
diff --git a/docs/tryorama.dna.md b/docs/tryorama.dna.md
new file mode 100644
index 00000000..68da2eb1
--- /dev/null
+++ b/docs/tryorama.dna.md
@@ -0,0 +1,23 @@
+
+
+[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [Dna](./tryorama.dna.md)
+
+## Dna interface
+
+DNA source and additional options.
+
+Signature:
+
+```typescript
+export interface Dna
+```
+
+## Properties
+
+| Property | Type | Description |
+| --- | --- | --- |
+| [membraneProof?](./tryorama.dna.membraneproof.md) | MembraneProof | (Optional) |
+| [properties?](./tryorama.dna.properties.md) | DnaProperties | (Optional) |
+| [roleId?](./tryorama.dna.roleid.md) | string | (Optional) |
+| [source](./tryorama.dna.source.md) | DnaSource | |
+
diff --git a/docs/tryorama.dna.membraneproof.md b/docs/tryorama.dna.membraneproof.md
new file mode 100644
index 00000000..71c4464a
--- /dev/null
+++ b/docs/tryorama.dna.membraneproof.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [Dna](./tryorama.dna.md) > [membraneProof](./tryorama.dna.membraneproof.md)
+
+## Dna.membraneProof property
+
+Signature:
+
+```typescript
+membraneProof?: MembraneProof;
+```
diff --git a/docs/tryorama.dna.properties.md b/docs/tryorama.dna.properties.md
new file mode 100644
index 00000000..2e43ecca
--- /dev/null
+++ b/docs/tryorama.dna.properties.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [Dna](./tryorama.dna.md) > [properties](./tryorama.dna.properties.md)
+
+## Dna.properties property
+
+Signature:
+
+```typescript
+properties?: DnaProperties;
+```
diff --git a/docs/tryorama.dna.roleid.md b/docs/tryorama.dna.roleid.md
new file mode 100644
index 00000000..81dd48c6
--- /dev/null
+++ b/docs/tryorama.dna.roleid.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [Dna](./tryorama.dna.md) > [roleId](./tryorama.dna.roleid.md)
+
+## Dna.roleId property
+
+Signature:
+
+```typescript
+roleId?: string;
+```
diff --git a/docs/tryorama.dna.source.md b/docs/tryorama.dna.source.md
new file mode 100644
index 00000000..8254df8f
--- /dev/null
+++ b/docs/tryorama.dna.source.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [Dna](./tryorama.dna.md) > [source](./tryorama.dna.source.md)
+
+## Dna.source property
+
+Signature:
+
+```typescript
+source: DnaSource;
+```
diff --git a/docs/tryorama.iconductor.installagentshapps.md b/docs/tryorama.iconductor.installagentshapps.md
index e021b616..3c2616cf 100644
--- a/docs/tryorama.iconductor.installagentshapps.md
+++ b/docs/tryorama.iconductor.installagentshapps.md
@@ -7,10 +7,5 @@
Signature:
```typescript
-installAgentsHapps: (options: {
- agentsDnas: DnaSource[][];
- uid?: string;
- properties?: DnaProperties;
- signalHandler?: AppSignalCb;
- }) => Promise;
+installAgentsHapps: (options: AgentsHappsOptions) => Promise;
```
diff --git a/docs/tryorama.iconductor.md b/docs/tryorama.iconductor.md
index 53ebf075..277f717e 100644
--- a/docs/tryorama.iconductor.md
+++ b/docs/tryorama.iconductor.md
@@ -18,7 +18,7 @@ export interface IConductor
| --- | --- | --- |
| [adminWs](./tryorama.iconductor.adminws.md) | () => Omit<AdminWebsocket, "\_requester" \| "client" \| "activateApp" \| "deactivateApp" \| "defaultTimeout" \| "listActiveApps"> | |
| [appWs](./tryorama.iconductor.appws.md) | () => Pick<AppWebsocket, "callZome" \| "appInfo"> | |
-| [installAgentsHapps](./tryorama.iconductor.installagentshapps.md) | (options: { agentsDnas: DnaSource\[\]\[\]; uid?: string; properties?: DnaProperties; signalHandler?: AppSignalCb; }) => Promise<[AgentHapp](./tryorama.agenthapp.md)\[\]> | |
+| [installAgentsHapps](./tryorama.iconductor.installagentshapps.md) | (options: [AgentsHappsOptions](./tryorama.agentshappsoptions.md)) => Promise<[AgentHapp](./tryorama.agenthapp.md)\[\]> | |
| [shutDown](./tryorama.iconductor.shutdown.md) | () => Promise<number \| null> | |
| [startUp](./tryorama.iconductor.startup.md) | () => Promise<void \| null> | |
diff --git a/docs/tryorama.iscenario.addconductor.md b/docs/tryorama.iscenario.addconductor.md
deleted file mode 100644
index b722a491..00000000
--- a/docs/tryorama.iscenario.addconductor.md
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [IScenario](./tryorama.iscenario.md) > [addConductor](./tryorama.iscenario.addconductor.md)
-
-## IScenario.addConductor() method
-
-Signature:
-
-```typescript
-addConductor(signalHandler?: AppSignalCb): Promise;
-```
-
-## Parameters
-
-| Parameter | Type | Description |
-| --- | --- | --- |
-| signalHandler | AppSignalCb | (Optional) |
-
-Returns:
-
-Promise<[IConductor](./tryorama.iconductor.md)>
-
diff --git a/docs/tryorama.iscenario.addplayerswithhappbundles.md b/docs/tryorama.iscenario.addplayerswithhappbundles.md
deleted file mode 100644
index 6645aef8..00000000
--- a/docs/tryorama.iscenario.addplayerswithhappbundles.md
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [IScenario](./tryorama.iscenario.md) > [addPlayersWithHappBundles](./tryorama.iscenario.addplayerswithhappbundles.md)
-
-## IScenario.addPlayersWithHappBundles() method
-
-Signature:
-
-```typescript
-addPlayersWithHappBundles(playersHappBundles: Array<{
- appBundleSource: AppBundleSource;
- options?: HappBundleOptions & {
- signalHandler?: AppSignalCb;
- };
- }>): Promise;
-```
-
-## Parameters
-
-| Parameter | Type | Description |
-| --- | --- | --- |
-| playersHappBundles | Array<{ appBundleSource: AppBundleSource; options?: [HappBundleOptions](./tryorama.happbundleoptions.md) & { signalHandler?: AppSignalCb; }; }> | |
-
-Returns:
-
-Promise<[IPlayer](./tryorama.iplayer.md)\[\]>
-
diff --git a/docs/tryorama.iscenario.addplayerswithhapps.md b/docs/tryorama.iscenario.addplayerswithhapps.md
deleted file mode 100644
index 8ebdb780..00000000
--- a/docs/tryorama.iscenario.addplayerswithhapps.md
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [IScenario](./tryorama.iscenario.md) > [addPlayersWithHapps](./tryorama.iscenario.addplayerswithhapps.md)
-
-## IScenario.addPlayersWithHapps() method
-
-Signature:
-
-```typescript
-addPlayersWithHapps(agentHappOptions: AgentHappOptions[]): Promise;
-```
-
-## Parameters
-
-| Parameter | Type | Description |
-| --- | --- | --- |
-| agentHappOptions | [AgentHappOptions](./tryorama.agenthappoptions.md)\[\] | |
-
-Returns:
-
-Promise<[IPlayer](./tryorama.iplayer.md)\[\]>
-
diff --git a/docs/tryorama.iscenario.addplayerwithhapp.md b/docs/tryorama.iscenario.addplayerwithhapp.md
deleted file mode 100644
index 3024a8ee..00000000
--- a/docs/tryorama.iscenario.addplayerwithhapp.md
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [IScenario](./tryorama.iscenario.md) > [addPlayerWithHapp](./tryorama.iscenario.addplayerwithhapp.md)
-
-## IScenario.addPlayerWithHapp() method
-
-Signature:
-
-```typescript
-addPlayerWithHapp(agentHappOptions: AgentHappOptions): Promise;
-```
-
-## Parameters
-
-| Parameter | Type | Description |
-| --- | --- | --- |
-| agentHappOptions | [AgentHappOptions](./tryorama.agenthappoptions.md) | |
-
-Returns:
-
-Promise<[IPlayer](./tryorama.iplayer.md)>
-
diff --git a/docs/tryorama.iscenario.addplayerwithhappbundle.md b/docs/tryorama.iscenario.addplayerwithhappbundle.md
deleted file mode 100644
index 902745a7..00000000
--- a/docs/tryorama.iscenario.addplayerwithhappbundle.md
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [IScenario](./tryorama.iscenario.md) > [addPlayerWithHappBundle](./tryorama.iscenario.addplayerwithhappbundle.md)
-
-## IScenario.addPlayerWithHappBundle() method
-
-Signature:
-
-```typescript
-addPlayerWithHappBundle(appBundleSource: AppBundleSource, options?: HappBundleOptions & {
- signalHandler?: AppSignalCb;
- }): Promise;
-```
-
-## Parameters
-
-| Parameter | Type | Description |
-| --- | --- | --- |
-| appBundleSource | AppBundleSource | |
-| options | [HappBundleOptions](./tryorama.happbundleoptions.md) & { signalHandler?: AppSignalCb; } | (Optional) |
-
-Returns:
-
-Promise<[IPlayer](./tryorama.iplayer.md)>
-
diff --git a/docs/tryorama.iscenario.md b/docs/tryorama.iscenario.md
deleted file mode 100644
index 238eb49d..00000000
--- a/docs/tryorama.iscenario.md
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [IScenario](./tryorama.iscenario.md)
-
-## IScenario interface
-
-Base interface of a Tryorama test scenario. Both [Scenario](./tryorama.scenario.md) and [TryCpScenario](./tryorama.trycpscenario.md) implement this interface.
-
-Signature:
-
-```typescript
-export interface IScenario
-```
-
-## Methods
-
-| Method | Description |
-| --- | --- |
-| [addConductor(signalHandler)](./tryorama.iscenario.addconductor.md) | |
-| [addPlayersWithHappBundles(playersHappBundles)](./tryorama.iscenario.addplayerswithhappbundles.md) | |
-| [addPlayersWithHapps(agentHappOptions)](./tryorama.iscenario.addplayerswithhapps.md) | |
-| [addPlayerWithHapp(agentHappOptions)](./tryorama.iscenario.addplayerwithhapp.md) | |
-| [addPlayerWithHappBundle(appBundleSource, options)](./tryorama.iscenario.addplayerwithhappbundle.md) | |
-| [cleanUp()](./tryorama.iscenario.cleanup.md) | |
-| [shareAllAgents(conductors)](./tryorama.iscenario.shareallagents.md) | |
-| [shutDown()](./tryorama.iscenario.shutdown.md) | |
-
diff --git a/docs/tryorama.iscenario.shareallagents.md b/docs/tryorama.iscenario.shareallagents.md
deleted file mode 100644
index c3d7bc16..00000000
--- a/docs/tryorama.iscenario.shareallagents.md
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [IScenario](./tryorama.iscenario.md) > [shareAllAgents](./tryorama.iscenario.shareallagents.md)
-
-## IScenario.shareAllAgents() method
-
-Signature:
-
-```typescript
-shareAllAgents(conductors: IConductor[]): Promise;
-```
-
-## Parameters
-
-| Parameter | Type | Description |
-| --- | --- | --- |
-| conductors | [IConductor](./tryorama.iconductor.md)\[\] | |
-
-Returns:
-
-Promise<void>
-
diff --git a/docs/tryorama.iscenario.shutdown.md b/docs/tryorama.iscenario.shutdown.md
deleted file mode 100644
index ed1c0d6c..00000000
--- a/docs/tryorama.iscenario.shutdown.md
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [IScenario](./tryorama.iscenario.md) > [shutDown](./tryorama.iscenario.shutdown.md)
-
-## IScenario.shutDown() method
-
-Signature:
-
-```typescript
-shutDown(): Promise;
-```
-Returns:
-
-Promise<void>
-
diff --git a/docs/tryorama.md b/docs/tryorama.md
index 88cac647..fcd33ef9 100644
--- a/docs/tryorama.md
+++ b/docs/tryorama.md
@@ -18,9 +18,9 @@ TryCP stands for Tryorama Control Protocol (TryCP) and is a protocol to enable r
| --- | --- |
| [Conductor](./tryorama.conductor.md) | A class to manage a conductor running on localhost. |
| [Scenario](./tryorama.scenario.md) | An abstraction of a test scenario to write tests against Holochain hApps, running on a local conductor. |
-| [TryCpClient](./tryorama.trycpclient.md) | A factory class to create client connections to a running TryCP server. |
+| [TryCpClient](./tryorama.trycpclient.md) | A factory class to create client connections to a running TryCP server.With a client, conductors on the server can ba configured, started and stopped. All valid Admin and App API commands can be sent to the server too. |
| [TryCpConductor](./tryorama.trycpconductor.md) | A class to manage a conductor running on a TryCP server. |
-| [TryCpScenario](./tryorama.trycpscenario.md) | An abstraction of a test scenario to write tests against Holochain hApps, running on a TryCp conductor. |
+| [TryCpScenario](./tryorama.trycpscenario.md) | A test scenario abstraction with convenience functions to manage TryCP clients and players (agent + conductor).Clients in turn help manage conductors on TryCP servers. Clients can be added to a scenario to keep track of all server connections. When finishing a test scenario, all conductors of all clients can be easily cleaned up and the client connections closed. |
| [TryCpServer](./tryorama.trycpserver.md) | A factory class to start and stop local instances of the TryCP server. |
## Enumerations
@@ -51,16 +51,18 @@ TryCP stands for Tryorama Control Protocol (TryCP) and is a protocol to enable r
| [AdminApiResponseDnasListed](./tryorama.adminapiresponsednaslisted.md) | |
| [AdminApiResponseFullStateDumped](./tryorama.adminapiresponsefullstatedumped.md) | |
| [AdminApiResponseStateDumped](./tryorama.adminapiresponsestatedumped.md) | |
+| [AgentDnas](./tryorama.agentdnas.md) | DNAs per agent. Optionally an agent pub key. |
| [AgentHapp](./tryorama.agenthapp.md) | Provides direct access to cells of a hApp and the agent key. |
| [ApiErrorResponse](./tryorama.apierrorresponse.md) | Error response from the Admin or App API. |
| [AppApiResponseAppInfo](./tryorama.appapiresponseappinfo.md) | |
| [AppApiResponseZomeCall](./tryorama.appapiresponsezomecall.md) | |
| [CallableCell](./tryorama.callablecell.md) | Extends an installed cell by a function to call a zome. |
+| [ClientsPlayersOptions](./tryorama.clientsplayersoptions.md) | |
| [ConductorOptions](./tryorama.conductoroptions.md) | |
+| [Dna](./tryorama.dna.md) | DNA source and additional options. |
| [HappBundleOptions](./tryorama.happbundleoptions.md) | Optional arguments when installing a hApp bundle. |
| [IConductor](./tryorama.iconductor.md) | Base interface of a Tryorama conductor. Both [Conductor](./tryorama.conductor.md) and [TryCpConductor](./tryorama.trycpconductor.md) implement this interface. |
| [IPlayer](./tryorama.iplayer.md) | Combines an agent hApp with the conductor they belong to. |
-| [IScenario](./tryorama.iscenario.md) | Base interface of a Tryorama test scenario. Both [Scenario](./tryorama.scenario.md) and [TryCpScenario](./tryorama.trycpscenario.md) implement this interface. |
| [Player](./tryorama.player.md) | A player tied to a [Conductor](./tryorama.conductor.md). |
| [RequestAdminInterfaceData](./tryorama.requestadmininterfacedata.md) | All possible calls to an admin interface. |
| [RequestAppInfo](./tryorama.requestappinfo.md) | Request app info from a conductor. |
@@ -86,9 +88,8 @@ TryCP stands for Tryorama Control Protocol (TryCP) and is a protocol to enable r
| --- | --- |
| [addAllAgentsToAllConductors](./tryorama.addallagentstoallconductors.md) | Add all agents of all conductors to each other. Shortcuts peer discovery through a bootstrap server or gossiping. |
| [cleanAllConductors](./tryorama.cleanallconductors.md) | Run the hc
command to delete all conductor data. |
-| [cleanAllTryCpConductors](./tryorama.cleanalltrycpconductors.md) | Run the reset
command on the TryCP server to delete all conductor data. |
| [createConductor](./tryorama.createconductor.md) | The function to create a conductor. It starts a sandbox conductor via the Holochain CLI. |
-| [createTryCpConductor](./tryorama.createtrycpconductor.md) | The function to create a TryCP Conductor (aka "Player"). |
+| [createTryCpConductor](./tryorama.createtrycpconductor.md) | The function to create a TryCP Conductor. By default configures and starts it. |
| [DEFAULT\_PARTIAL\_PLAYER\_CONFIG](./tryorama.default_partial_player_config.md) | The default partial config for a TryCP conductor. |
| [getZomeCaller](./tryorama.getzomecaller.md) | Get a shorthand function to call a cell's zome. |
| [pause](./tryorama.pause.md) | A utility function to wait the given amount of time. |
@@ -100,12 +101,13 @@ TryCP stands for Tryorama Control Protocol (TryCP) and is a protocol to enable r
| Type Alias | Description |
| --- | --- |
| [AdminApiResponse](./tryorama.adminapiresponse.md) | All possible responses from the Admin API. |
-| [AgentHappOptions](./tryorama.agenthappoptions.md) | A type that specifies either only the DNAs that the hApp to be installed consists of, or the DNAs and a signal handler to be registered. |
+| [AgentsHappsOptions](./tryorama.agentshappsoptions.md) | An array of DNA sources for each agent (2-dimensional array) or an array of DNAs and an optional agent pub key. Optionally a UID to be used for DNA installation. |
| [AppApiResponse](./tryorama.appapiresponse.md) | Possible responses from the App API. |
| [CallZomeFn](./tryorama.callzomefn.md) | The function for calling a zome from a specific cell. |
| [CellZomeCallRequest](./tryorama.cellzomecallrequest.md) | The zome request options adapted to a specific cell. |
| [ConductorId](./tryorama.conductorid.md) | |
| [CreateConductorOptions](./tryorama.createconductoroptions.md) | Options for using the conductor factory. |
+| [PlayerHappOptions](./tryorama.playerhappoptions.md) | Player installation options used in scenarios.Specifies either only the DNA sources that the hApp to be installed consists of, or the DNAs and a signal handler to be registered. |
| [RequestCallAppInterfaceMessage](./tryorama.requestcallappinterfacemessage.md) | All possible calls to an app interface. |
| [TryCpApiResponse](./tryorama.trycpapiresponse.md) | Possible responses from the Admin and App APIs. |
| [TryCpConductorLogLevel](./tryorama.trycpconductorloglevel.md) | Log level for a TryCP conductor. |
diff --git a/docs/tryorama.playerhappoptions.md b/docs/tryorama.playerhappoptions.md
new file mode 100644
index 00000000..5b656f04
--- /dev/null
+++ b/docs/tryorama.playerhappoptions.md
@@ -0,0 +1,20 @@
+
+
+[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [PlayerHappOptions](./tryorama.playerhappoptions.md)
+
+## PlayerHappOptions type
+
+Player installation options used in scenarios.
+
+Specifies either only the DNA sources that the hApp to be installed consists of, or the DNAs and a signal handler to be registered.
+
+Signature:
+
+```typescript
+export declare type PlayerHappOptions = DnaSource[] | {
+ dnas: Dna[];
+ signalHandler?: AppSignalCb;
+};
+```
+References: [Dna](./tryorama.dna.md)
+
diff --git a/docs/tryorama.scenario.addplayerswithhapps.md b/docs/tryorama.scenario.addplayerswithhapps.md
index bdd27445..73d7e65d 100644
--- a/docs/tryorama.scenario.addplayerswithhapps.md
+++ b/docs/tryorama.scenario.addplayerswithhapps.md
@@ -9,14 +9,14 @@ Create and add multiple players to the scenario, with a set of DNAs installed fo
Signature:
```typescript
-addPlayersWithHapps(agentHappOptions: AgentHappOptions[]): Promise;
+addPlayersWithHapps(agentHappOptions: PlayerHappOptions[]): Promise;
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
-| agentHappOptions | [AgentHappOptions](./tryorama.agenthappoptions.md)\[\] | [AgentHappOptions](./tryorama.agenthappoptions.md) for each player. |
+| agentHappOptions | [PlayerHappOptions](./tryorama.playerhappoptions.md)\[\] | [PlayerHappOptions](./tryorama.playerhappoptions.md) for each player. |
Returns:
diff --git a/docs/tryorama.scenario.addplayerwithhapp.md b/docs/tryorama.scenario.addplayerwithhapp.md
index 8a19f6cb..60344a5c 100644
--- a/docs/tryorama.scenario.addplayerwithhapp.md
+++ b/docs/tryorama.scenario.addplayerwithhapp.md
@@ -9,14 +9,14 @@ Create and add a single player to the scenario, with a set of DNAs installed.
Signature:
```typescript
-addPlayerWithHapp(agentHappOptions: AgentHappOptions): Promise;
+addPlayerWithHapp(playerHappOptions: PlayerHappOptions): Promise;
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
-| agentHappOptions | [AgentHappOptions](./tryorama.agenthappoptions.md) | [AgentHappOptions](./tryorama.agenthappoptions.md). |
+| playerHappOptions | [PlayerHappOptions](./tryorama.playerhappoptions.md) | [PlayerHappOptions](./tryorama.playerhappoptions.md). |
Returns:
diff --git a/docs/tryorama.scenario.md b/docs/tryorama.scenario.md
index 6c38ca0e..9844fb71 100644
--- a/docs/tryorama.scenario.md
+++ b/docs/tryorama.scenario.md
@@ -9,9 +9,8 @@ An abstraction of a test scenario to write tests against Holochain hApps, runnin
Signature:
```typescript
-export declare class Scenario implements IScenario
+export declare class Scenario
```
-Implements: [IScenario](./tryorama.iscenario.md)
## Constructors
@@ -33,7 +32,7 @@ export declare class Scenario implements IScenario
| [addConductor(signalHandler)](./tryorama.scenario.addconductor.md) | | Create and add a conductor to the scenario. |
| [addPlayersWithHappBundles(playersHappBundles)](./tryorama.scenario.addplayerswithhappbundles.md) | | Create and add multiple players to the scenario, with a hApp bundle installed for each player. |
| [addPlayersWithHapps(agentHappOptions)](./tryorama.scenario.addplayerswithhapps.md) | | Create and add multiple players to the scenario, with a set of DNAs installed for each player. |
-| [addPlayerWithHapp(agentHappOptions)](./tryorama.scenario.addplayerwithhapp.md) | | Create and add a single player to the scenario, with a set of DNAs installed. |
+| [addPlayerWithHapp(playerHappOptions)](./tryorama.scenario.addplayerwithhapp.md) | | Create and add a single player to the scenario, with a set of DNAs installed. |
| [addPlayerWithHappBundle(appBundleSource, options)](./tryorama.scenario.addplayerwithhappbundle.md) | | Create and add a single player to the scenario, with a hApp bundle installed. |
| [cleanUp()](./tryorama.scenario.cleanup.md) | | Shut down and delete all conductors in the scenario. |
| [shareAllAgents()](./tryorama.scenario.shareallagents.md) | | Register all agents of all passed in conductors to each other. This skips peer discovery through gossip and thus accelerates test runs. |
diff --git a/docs/tryorama.trycpscenario.addconductor.md b/docs/tryorama.trycpclient.addconductor.md
similarity index 71%
rename from docs/tryorama.trycpscenario.addconductor.md
rename to docs/tryorama.trycpclient.addconductor.md
index 0a0a3d38..64c1bda7 100644
--- a/docs/tryorama.trycpscenario.addconductor.md
+++ b/docs/tryorama.trycpclient.addconductor.md
@@ -1,10 +1,10 @@
-[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [TryCpScenario](./tryorama.trycpscenario.md) > [addConductor](./tryorama.trycpscenario.addconductor.md)
+[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [TryCpClient](./tryorama.trycpclient.md) > [addConductor](./tryorama.trycpclient.addconductor.md)
-## TryCpScenario.addConductor() method
+## TryCpClient.addConductor() method
-Create and add a conductor to the scenario.
+Create and add a conductor to the client.
Signature:
diff --git a/docs/tryorama.trycpclient.cleanallconductors.md b/docs/tryorama.trycpclient.cleanallconductors.md
new file mode 100644
index 00000000..689d9576
--- /dev/null
+++ b/docs/tryorama.trycpclient.cleanallconductors.md
@@ -0,0 +1,19 @@
+
+
+[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [TryCpClient](./tryorama.trycpclient.md) > [cleanAllConductors](./tryorama.trycpclient.cleanallconductors.md)
+
+## TryCpClient.cleanAllConductors() method
+
+Run the `reset` command on the TryCP server to delete all conductor data.
+
+Signature:
+
+```typescript
+cleanAllConductors(): Promise;
+```
+Returns:
+
+Promise<null>
+
+An empty success response.
+
diff --git a/docs/tryorama.iscenario.cleanup.md b/docs/tryorama.trycpclient.cleanup.md
similarity index 52%
rename from docs/tryorama.iscenario.cleanup.md
rename to docs/tryorama.trycpclient.cleanup.md
index 781170e9..89d2b8ea 100644
--- a/docs/tryorama.iscenario.cleanup.md
+++ b/docs/tryorama.trycpclient.cleanup.md
@@ -1,8 +1,10 @@
-[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [IScenario](./tryorama.iscenario.md) > [cleanUp](./tryorama.iscenario.cleanup.md)
+[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [TryCpClient](./tryorama.trycpclient.md) > [cleanUp](./tryorama.trycpclient.cleanup.md)
-## IScenario.cleanUp() method
+## TryCpClient.cleanUp() method
+
+Shut down all registered conductors and delete them, and close the client connection.
Signature:
diff --git a/docs/tryorama.trycpscenario.conductors.md b/docs/tryorama.trycpclient.conductors.md
similarity index 58%
rename from docs/tryorama.trycpscenario.conductors.md
rename to docs/tryorama.trycpclient.conductors.md
index 4d4b20de..0ed51e12 100644
--- a/docs/tryorama.trycpscenario.conductors.md
+++ b/docs/tryorama.trycpclient.conductors.md
@@ -1,8 +1,8 @@
-[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [TryCpScenario](./tryorama.trycpscenario.md) > [conductors](./tryorama.trycpscenario.conductors.md)
+[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [TryCpClient](./tryorama.trycpclient.md) > [conductors](./tryorama.trycpclient.conductors.md)
-## TryCpScenario.conductors property
+## TryCpClient.conductors property
Signature:
diff --git a/docs/tryorama.trycpclient.create.md b/docs/tryorama.trycpclient.create.md
index cc6a40a9..f60ecda5 100644
--- a/docs/tryorama.trycpclient.create.md
+++ b/docs/tryorama.trycpclient.create.md
@@ -23,5 +23,5 @@ static create(serverUrl: URL, timeout?: number): Promise;
Promise<[TryCpClient](./tryorama.trycpclient.md)>
-A client connection.
+The created client connection.
diff --git a/docs/tryorama.trycpclient.md b/docs/tryorama.trycpclient.md
index cd184e95..6b772c76 100644
--- a/docs/tryorama.trycpclient.md
+++ b/docs/tryorama.trycpclient.md
@@ -6,19 +6,31 @@
A factory class to create client connections to a running TryCP server.
+With a client, conductors on the server can ba configured, started and stopped. All valid Admin and App API commands can be sent to the server too.
+
Signature:
```typescript
export declare class TryCpClient
```
+## Properties
+
+| Property | Modifiers | Type | Description |
+| --- | --- | --- | --- |
+| [conductors](./tryorama.trycpclient.conductors.md) | | [TryCpConductor](./tryorama.trycpconductor.md)\[\] | |
+
## Methods
| Method | Modifiers | Description |
| --- | --- | --- |
+| [addConductor(signalHandler)](./tryorama.trycpclient.addconductor.md) | | Create and add a conductor to the client. |
| [call(request)](./tryorama.trycpclient.call.md) | | Send a call to the TryCP server. |
+| [cleanAllConductors()](./tryorama.trycpclient.cleanallconductors.md) | | Run the reset
command on the TryCP server to delete all conductor data. |
+| [cleanUp()](./tryorama.trycpclient.cleanup.md) | | Shut down all registered conductors and delete them, and close the client connection. |
| [close()](./tryorama.trycpclient.close.md) | | Closes the client connection. |
| [create(serverUrl, timeout)](./tryorama.trycpclient.create.md) | static
| Create a client connection to a running TryCP server. |
| [ping(data)](./tryorama.trycpclient.ping.md) | | Send a ping with data. |
| [setSignalHandler(port, signalHandler)](./tryorama.trycpclient.setsignalhandler.md) | | |
+| [shutDownConductors()](./tryorama.trycpclient.shutdownconductors.md) | | Shut down all conductors on the connected TryCP server and disconnect their app interfaces. |
diff --git a/docs/tryorama.trycpclient.shutdownconductors.md b/docs/tryorama.trycpclient.shutdownconductors.md
new file mode 100644
index 00000000..c870db03
--- /dev/null
+++ b/docs/tryorama.trycpclient.shutdownconductors.md
@@ -0,0 +1,17 @@
+
+
+[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [TryCpClient](./tryorama.trycpclient.md) > [shutDownConductors](./tryorama.trycpclient.shutdownconductors.md)
+
+## TryCpClient.shutDownConductors() method
+
+Shut down all conductors on the connected TryCP server and disconnect their app interfaces.
+
+Signature:
+
+```typescript
+shutDownConductors(): Promise;
+```
+Returns:
+
+Promise<void>
+
diff --git a/docs/tryorama.trycpconductor.id.md b/docs/tryorama.trycpconductor.id.md
new file mode 100644
index 00000000..d69f27b5
--- /dev/null
+++ b/docs/tryorama.trycpconductor.id.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [TryCpConductor](./tryorama.trycpconductor.md) > [id](./tryorama.trycpconductor.id.md)
+
+## TryCpConductor.id property
+
+Signature:
+
+```typescript
+readonly id: string;
+```
diff --git a/docs/tryorama.trycpconductor.installagentshapps.md b/docs/tryorama.trycpconductor.installagentshapps.md
index 9b599ba4..26c7fc11 100644
--- a/docs/tryorama.trycpconductor.installagentshapps.md
+++ b/docs/tryorama.trycpconductor.installagentshapps.md
@@ -9,19 +9,14 @@ Install a set of DNAs for multiple agents into the conductor.
Signature:
```typescript
-installAgentsHapps(options: {
- agentsDnas: DnaSource[][];
- signalHandler?: AppSignalCb;
- uid?: string;
- properties?: DnaProperties;
- }): Promise;
+installAgentsHapps(options: AgentsHappsOptions): Promise;
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
-| options | { agentsDnas: DnaSource\[\]\[\]; signalHandler?: AppSignalCb; uid?: string; properties?: DnaProperties; } | An array of DNAs for each agent, resulting in a 2-dimensional array, and a UID for the DNAs (optional). |
+| options | [AgentsHappsOptions](./tryorama.agentshappsoptions.md) | [AgentsHappsOptions](./tryorama.agentshappsoptions.md) |
Returns:
diff --git a/docs/tryorama.trycpconductor.installhappbundle.md b/docs/tryorama.trycpconductor.installhappbundle.md
index e90699cb..05fe9ff9 100644
--- a/docs/tryorama.trycpconductor.installhappbundle.md
+++ b/docs/tryorama.trycpconductor.installhappbundle.md
@@ -9,12 +9,7 @@ Install a hApp bundle into the conductor.
Signature:
```typescript
-installHappBundle(appBundleSource: AppBundleSource, options?: {
- agentPubKey?: AgentPubKey;
- installedAppId?: string;
- uid?: string;
- membraneProofs?: Record;
- }): Promise;
+installHappBundle(appBundleSource: AppBundleSource, options?: HappBundleOptions): Promise;
```
## Parameters
@@ -22,7 +17,7 @@ installHappBundle(appBundleSource: AppBundleSource, options?: {
| Parameter | Type | Description |
| --- | --- | --- |
| appBundleSource | AppBundleSource | The bundle or path to the bundle. |
-| options | { agentPubKey?: AgentPubKey; installedAppId?: string; uid?: string; membraneProofs?: Record<string, MembraneProof>; } | (Optional) [HappBundleOptions](./tryorama.happbundleoptions.md) for the hApp bundle (optional). |
+| options | [HappBundleOptions](./tryorama.happbundleoptions.md) | (Optional) [HappBundleOptions](./tryorama.happbundleoptions.md) for the hApp bundle (optional). |
Returns:
diff --git a/docs/tryorama.trycpconductor.md b/docs/tryorama.trycpconductor.md
index 6aef75d9..df9b0b33 100644
--- a/docs/tryorama.trycpconductor.md
+++ b/docs/tryorama.trycpconductor.md
@@ -19,6 +19,13 @@ export declare class TryCpConductor implements IConductor
| --- | --- | --- |
| [(constructor)(tryCpClient, id)](./tryorama.trycpconductor._constructor_.md) | | Constructs a new instance of the TryCpConductor
class |
+## Properties
+
+| Property | Modifiers | Type | Description |
+| --- | --- | --- | --- |
+| [id](./tryorama.trycpconductor.id.md) | | string | |
+| [tryCpClient](./tryorama.trycpconductor.trycpclient.md) | | [TryCpClient](./tryorama.trycpclient.md) | |
+
## Methods
| Method | Modifiers | Description |
@@ -33,6 +40,6 @@ export declare class TryCpConductor implements IConductor
| [installAgentsHapps(options)](./tryorama.trycpconductor.installagentshapps.md) | | Install a set of DNAs for multiple agents into the conductor. |
| [installHappBundle(appBundleSource, options)](./tryorama.trycpconductor.installhappbundle.md) | | Install a hApp bundle into the conductor. |
| [saveDna(dnaContent)](./tryorama.trycpconductor.savedna.md) | | Upload a DNA file from the local file system to the server. |
-| [shutDown()](./tryorama.trycpconductor.shutdown.md) | | Disconnect App interface and shut down the conductor. |
+| [shutDown()](./tryorama.trycpconductor.shutdown.md) | | Disconnect app interface and shut down the conductor. |
| [startUp(options)](./tryorama.trycpconductor.startup.md) | | Start a configured conductor. |
diff --git a/docs/tryorama.trycpconductor.shutdown.md b/docs/tryorama.trycpconductor.shutdown.md
index 4097a1fb..178635fa 100644
--- a/docs/tryorama.trycpconductor.shutdown.md
+++ b/docs/tryorama.trycpconductor.shutdown.md
@@ -4,7 +4,7 @@
## TryCpConductor.shutDown() method
-Disconnect App interface and shut down the conductor.
+Disconnect app interface and shut down the conductor.
Signature:
diff --git a/docs/tryorama.trycpconductor.trycpclient.md b/docs/tryorama.trycpconductor.trycpclient.md
new file mode 100644
index 00000000..1ca8581c
--- /dev/null
+++ b/docs/tryorama.trycpconductor.trycpclient.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [TryCpConductor](./tryorama.trycpconductor.md) > [tryCpClient](./tryorama.trycpconductor.trycpclient.md)
+
+## TryCpConductor.tryCpClient property
+
+Signature:
+
+```typescript
+readonly tryCpClient: TryCpClient;
+```
diff --git a/docs/tryorama.trycpconductoroptions.md b/docs/tryorama.trycpconductoroptions.md
index 8469ff3a..49c25cdd 100644
--- a/docs/tryorama.trycpconductoroptions.md
+++ b/docs/tryorama.trycpconductoroptions.md
@@ -19,5 +19,4 @@ export interface TryCpConductorOptions
| [logLevel?](./tryorama.trycpconductoroptions.loglevel.md) | [TryCpConductorLogLevel](./tryorama.trycpconductorloglevel.md) | (Optional) Log level of the conductor (optional).default: "info" |
| [partialConfig?](./tryorama.trycpconductoroptions.partialconfig.md) | string | (Optional) Configuration for the conductor (optional). |
| [startup?](./tryorama.trycpconductoroptions.startup.md) | boolean | (Optional) Start up conductor after creation.default: true |
-| [timeout?](./tryorama.trycpconductoroptions.timeout.md) | number | (Optional) Timeout for requests to Admin and App API. |
diff --git a/docs/tryorama.trycpconductoroptions.timeout.md b/docs/tryorama.trycpconductoroptions.timeout.md
deleted file mode 100644
index 9ede6f33..00000000
--- a/docs/tryorama.trycpconductoroptions.timeout.md
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [TryCpConductorOptions](./tryorama.trycpconductoroptions.md) > [timeout](./tryorama.trycpconductoroptions.timeout.md)
-
-## TryCpConductorOptions.timeout property
-
-Timeout for requests to Admin and App API.
-
-Signature:
-
-```typescript
-timeout?: number;
-```
diff --git a/docs/tryorama.trycpscenario._constructor_.md b/docs/tryorama.trycpscenario._constructor_.md
new file mode 100644
index 00000000..8179f109
--- /dev/null
+++ b/docs/tryorama.trycpscenario._constructor_.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [TryCpScenario](./tryorama.trycpscenario.md) > [(constructor)](./tryorama.trycpscenario._constructor_.md)
+
+## TryCpScenario.(constructor)
+
+Constructs a new instance of the `TryCpScenario` class
+
+Signature:
+
+```typescript
+constructor();
+```
diff --git a/docs/tryorama.trycpscenario.addclient.md b/docs/tryorama.trycpscenario.addclient.md
new file mode 100644
index 00000000..734ee896
--- /dev/null
+++ b/docs/tryorama.trycpscenario.addclient.md
@@ -0,0 +1,27 @@
+
+
+[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [TryCpScenario](./tryorama.trycpscenario.md) > [addClient](./tryorama.trycpscenario.addclient.md)
+
+## TryCpScenario.addClient() method
+
+Creates a TryCP client connection and add it to the scenario.
+
+Signature:
+
+```typescript
+addClient(serverUrl: URL, timeout?: number): Promise;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| serverUrl | URL | The TryCP server URL to connect to. |
+| timeout | number | (Optional) An optional timeout for the web socket connection. |
+
+Returns:
+
+Promise<[TryCpClient](./tryorama.trycpclient.md)>
+
+The created TryCP client.
+
diff --git a/docs/tryorama.trycpscenario.addclientsplayers.md b/docs/tryorama.trycpscenario.addclientsplayers.md
new file mode 100644
index 00000000..3062da06
--- /dev/null
+++ b/docs/tryorama.trycpscenario.addclientsplayers.md
@@ -0,0 +1,30 @@
+
+
+[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [TryCpScenario](./tryorama.trycpscenario.md) > [addClientsPlayers](./tryorama.trycpscenario.addclientsplayers.md)
+
+## TryCpScenario.addClientsPlayers() method
+
+Creates client connections for all passed in URLs and, depending on the options, creates multiple players with DNAs. Adds all clients to the scenario.
+
+Signature:
+
+```typescript
+addClientsPlayers(serverUrls: URL[], options?: ClientsPlayersOptions): Promise<{
+ client: TryCpClient;
+ players: TryCpPlayer[];
+ }[]>;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| serverUrls | URL\[\] | The TryCP server URLs to connect to. |
+| options | [ClientsPlayersOptions](./tryorama.clientsplayersoptions.md) | (Optional) [ClientsPlayersOptions](./tryorama.clientsplayersoptions.md) |
+
+Returns:
+
+Promise<{ client: [TryCpClient](./tryorama.trycpclient.md); players: [TryCpPlayer](./tryorama.trycpplayer.md)\[\]; }\[\]>
+
+The created TryCP clients and all conductors per client and all agents' hApps per conductor.
+
diff --git a/docs/tryorama.trycpscenario.addplayerswithhappbundles.md b/docs/tryorama.trycpscenario.addplayerswithhappbundles.md
index e4bc20cf..59a85ed8 100644
--- a/docs/tryorama.trycpscenario.addplayerswithhappbundles.md
+++ b/docs/tryorama.trycpscenario.addplayerswithhappbundles.md
@@ -4,12 +4,12 @@
## TryCpScenario.addPlayersWithHappBundles() method
-Create and add multiple players to the scenario, with a hApp bundle installed for each player.
+Creates and adds multiple players to the scenario, with a hApp bundle installed for each player.
Signature:
```typescript
-addPlayersWithHappBundles(playersHappBundles: Array<{
+addPlayersWithHappBundles(tryCpClient: TryCpClient, playersHappBundles: Array<{
appBundleSource: AppBundleSource;
options?: HappBundleOptions & {
signalHandler?: AppSignalCb;
@@ -27,10 +27,12 @@ addPlayersWithHappBundles(playersHappBundles: Array<{
| Parameter | Type | Description |
| --- | --- | --- |
+| tryCpClient | [TryCpClient](./tryorama.trycpclient.md) | The client connection to the TryCP server on which to create the player. |
| playersHappBundles | Array<{ appBundleSource: AppBundleSource; options?: [HappBundleOptions](./tryorama.happbundleoptions.md) & { signalHandler?: AppSignalCb; }; }> | An array with a hApp bundle for each player, and a signal handler (optional). |
Returns:
Promise<{ happId: string; agentPubKey: Uint8Array; cells: import("../../types.js").[CallableCell](./tryorama.callablecell.md)\[\]; namedCells: Map<string, import("../../types.js").[CallableCell](./tryorama.callablecell.md)>; conductor: [TryCpConductor](./tryorama.trycpconductor.md); }\[\]>
+An array of the added players.
diff --git a/docs/tryorama.trycpscenario.addplayerswithhapps.md b/docs/tryorama.trycpscenario.addplayerswithhapps.md
index 5472ae29..194dd9f4 100644
--- a/docs/tryorama.trycpscenario.addplayerswithhapps.md
+++ b/docs/tryorama.trycpscenario.addplayerswithhapps.md
@@ -4,23 +4,24 @@
## TryCpScenario.addPlayersWithHapps() method
-Create and add multiple players to the scenario, with a set of DNAs installed for each player.
+Creates and adds multiple players to the scenario, with a set of DNAs installed for each player.
Signature:
```typescript
-addPlayersWithHapps(agentHappOptions: AgentHappOptions[]): Promise;
+addPlayersWithHapps(tryCpClient: TryCpClient, agentHappOptions: PlayerHappOptions[]): Promise;
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
-| agentHappOptions | [AgentHappOptions](./tryorama.agenthappoptions.md)\[\] | [AgentHappOptions](./tryorama.agenthappoptions.md) for each player. |
+| tryCpClient | [TryCpClient](./tryorama.trycpclient.md) | The client connection to the TryCP server on which to create the player. |
+| agentHappOptions | [PlayerHappOptions](./tryorama.playerhappoptions.md)\[\] | [PlayerHappOptions](./tryorama.playerhappoptions.md) for each player. |
Returns:
Promise<[TryCpPlayer](./tryorama.trycpplayer.md)\[\]>
-An array with the added players.
+An array of the added players.
diff --git a/docs/tryorama.trycpscenario.addplayerwithhapp.md b/docs/tryorama.trycpscenario.addplayerwithhapp.md
index 64989b30..3ad2194f 100644
--- a/docs/tryorama.trycpscenario.addplayerwithhapp.md
+++ b/docs/tryorama.trycpscenario.addplayerwithhapp.md
@@ -4,23 +4,24 @@
## TryCpScenario.addPlayerWithHapp() method
-Create and add a single player to the scenario, with a set of DNAs installed.
+Creates and adds a single player to the scenario, with a set of DNAs installed.
Signature:
```typescript
-addPlayerWithHapp(agentHappOptions: AgentHappOptions): Promise;
+addPlayerWithHapp(tryCpClient: TryCpClient, playerHappOptions: PlayerHappOptions): Promise;
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
-| agentHappOptions | [AgentHappOptions](./tryorama.agenthappoptions.md) | [AgentHappOptions](./tryorama.agenthappoptions.md). |
+| tryCpClient | [TryCpClient](./tryorama.trycpclient.md) | The client connection to the TryCP server on which to create the player. |
+| playerHappOptions | [PlayerHappOptions](./tryorama.playerhappoptions.md) | [PlayerHappOptions](./tryorama.playerhappoptions.md). |
Returns:
Promise<[TryCpPlayer](./tryorama.trycpplayer.md)>
-A local player instance.
+The created player instance.
diff --git a/docs/tryorama.trycpscenario.addplayerwithhappbundle.md b/docs/tryorama.trycpscenario.addplayerwithhappbundle.md
index ba2f74fb..f4fdeb50 100644
--- a/docs/tryorama.trycpscenario.addplayerwithhappbundle.md
+++ b/docs/tryorama.trycpscenario.addplayerwithhappbundle.md
@@ -4,12 +4,12 @@
## TryCpScenario.addPlayerWithHappBundle() method
-Create and add a single player to the scenario, with a hApp bundle installed.
+Creates and adds a single player to the scenario, with a hApp bundle installed.
Signature:
```typescript
-addPlayerWithHappBundle(appBundleSource: AppBundleSource, options?: HappBundleOptions & {
+addPlayerWithHappBundle(tryCpClient: TryCpClient, appBundleSource: AppBundleSource, options?: HappBundleOptions & {
signalHandler?: AppSignalCb;
}): Promise<{
happId: string;
@@ -24,6 +24,7 @@ addPlayerWithHappBundle(appBundleSource: AppBundleSource, options?: HappBundleOp
| Parameter | Type | Description |
| --- | --- | --- |
+| tryCpClient | [TryCpClient](./tryorama.trycpclient.md) | The client connection to the TryCP server on which to create the player. |
| appBundleSource | AppBundleSource | The bundle or path to the bundle. |
| options | [HappBundleOptions](./tryorama.happbundleoptions.md) & { signalHandler?: AppSignalCb; } | (Optional) [HappBundleOptions](./tryorama.happbundleoptions.md) plus a signal handler (optional). |
@@ -31,5 +32,5 @@ addPlayerWithHappBundle(appBundleSource: AppBundleSource, options?: HappBundleOp
Promise<{ happId: string; agentPubKey: Uint8Array; cells: import("../../types.js").[CallableCell](./tryorama.callablecell.md)\[\]; namedCells: Map<string, import("../../types.js").[CallableCell](./tryorama.callablecell.md)>; conductor: [TryCpConductor](./tryorama.trycpconductor.md); }>
-A local player instance.
+The created player instance.
diff --git a/docs/tryorama.trycpscenario.cleanup.md b/docs/tryorama.trycpscenario.cleanup.md
index bc13a0e6..479f6ac8 100644
--- a/docs/tryorama.trycpscenario.cleanup.md
+++ b/docs/tryorama.trycpscenario.cleanup.md
@@ -4,7 +4,7 @@
## TryCpScenario.cleanUp() method
-Shut down and delete all conductors in the scenario, and stop the TryCP server.
+Shut down and delete all conductors and close all client connections in the scenario.
Signature:
diff --git a/docs/tryorama.trycpscenario.clients.md b/docs/tryorama.trycpscenario.clients.md
new file mode 100644
index 00000000..67716b96
--- /dev/null
+++ b/docs/tryorama.trycpscenario.clients.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [TryCpScenario](./tryorama.trycpscenario.md) > [clients](./tryorama.trycpscenario.clients.md)
+
+## TryCpScenario.clients property
+
+Signature:
+
+```typescript
+clients: TryCpClient[];
+```
diff --git a/docs/tryorama.trycpscenario.create.md b/docs/tryorama.trycpscenario.create.md
deleted file mode 100644
index e2ed266f..00000000
--- a/docs/tryorama.trycpscenario.create.md
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-[Home](./index.md) > [@holochain/tryorama](./tryorama.md) > [TryCpScenario](./tryorama.trycpscenario.md) > [create](./tryorama.trycpscenario.create.md)
-
-## TryCpScenario.create() method
-
-Factory method to create a new scenario.
-
-Signature:
-
-```typescript
-static create(serverUrl: URL): Promise;
-```
-
-## Parameters
-
-| Parameter | Type | Description |
-| --- | --- | --- |
-| serverUrl | URL | The URL of the TryCp server to connect to. |
-
-Returns:
-
-Promise<[TryCpScenario](./tryorama.trycpscenario.md)>
-
-A new scenario instance.
-
diff --git a/docs/tryorama.trycpscenario.md b/docs/tryorama.trycpscenario.md
index e83271df..83b19c6c 100644
--- a/docs/tryorama.trycpscenario.md
+++ b/docs/tryorama.trycpscenario.md
@@ -4,33 +4,40 @@
## TryCpScenario class
-An abstraction of a test scenario to write tests against Holochain hApps, running on a TryCp conductor.
+A test scenario abstraction with convenience functions to manage TryCP clients and players (agent + conductor).
+
+Clients in turn help manage conductors on TryCP servers. Clients can be added to a scenario to keep track of all server connections. When finishing a test scenario, all conductors of all clients can be easily cleaned up and the client connections closed.
Signature:
```typescript
-export declare class TryCpScenario implements IScenario
+export declare class TryCpScenario
```
-Implements: [IScenario](./tryorama.iscenario.md)
+
+## Constructors
+
+| Constructor | Modifiers | Description |
+| --- | --- | --- |
+| [(constructor)()](./tryorama.trycpscenario._constructor_.md) | | Constructs a new instance of the TryCpScenario
class |
## Properties
| Property | Modifiers | Type | Description |
| --- | --- | --- | --- |
-| [conductors](./tryorama.trycpscenario.conductors.md) | | [TryCpConductor](./tryorama.trycpconductor.md)\[\] | |
+| [clients](./tryorama.trycpscenario.clients.md) | | [TryCpClient](./tryorama.trycpclient.md)\[\] | |
| [uid](./tryorama.trycpscenario.uid.md) | | string | |
## Methods
| Method | Modifiers | Description |
| --- | --- | --- |
-| [addConductor(signalHandler)](./tryorama.trycpscenario.addconductor.md) | | Create and add a conductor to the scenario. |
-| [addPlayersWithHappBundles(playersHappBundles)](./tryorama.trycpscenario.addplayerswithhappbundles.md) | | Create and add multiple players to the scenario, with a hApp bundle installed for each player. |
-| [addPlayersWithHapps(agentHappOptions)](./tryorama.trycpscenario.addplayerswithhapps.md) | | Create and add multiple players to the scenario, with a set of DNAs installed for each player. |
-| [addPlayerWithHapp(agentHappOptions)](./tryorama.trycpscenario.addplayerwithhapp.md) | | Create and add a single player to the scenario, with a set of DNAs installed. |
-| [addPlayerWithHappBundle(appBundleSource, options)](./tryorama.trycpscenario.addplayerwithhappbundle.md) | | Create and add a single player to the scenario, with a hApp bundle installed. |
-| [cleanUp()](./tryorama.trycpscenario.cleanup.md) | | Shut down and delete all conductors in the scenario, and stop the TryCP server. |
-| [create(serverUrl)](./tryorama.trycpscenario.create.md) | static
| Factory method to create a new scenario. |
-| [shareAllAgents()](./tryorama.trycpscenario.shareallagents.md) | | Register all agents of all passed in conductors to each other. This skips peer discovery through gossip and thus accelerates test runs. |
-| [shutDown()](./tryorama.trycpscenario.shutdown.md) | | Shut down all conductors in the scenario. |
+| [addClient(serverUrl, timeout)](./tryorama.trycpscenario.addclient.md) | | Creates a TryCP client connection and add it to the scenario. |
+| [addClientsPlayers(serverUrls, options)](./tryorama.trycpscenario.addclientsplayers.md) | | Creates client connections for all passed in URLs and, depending on the options, creates multiple players with DNAs. Adds all clients to the scenario. |
+| [addPlayersWithHappBundles(tryCpClient, playersHappBundles)](./tryorama.trycpscenario.addplayerswithhappbundles.md) | | Creates and adds multiple players to the scenario, with a hApp bundle installed for each player. |
+| [addPlayersWithHapps(tryCpClient, agentHappOptions)](./tryorama.trycpscenario.addplayerswithhapps.md) | | Creates and adds multiple players to the scenario, with a set of DNAs installed for each player. |
+| [addPlayerWithHapp(tryCpClient, playerHappOptions)](./tryorama.trycpscenario.addplayerwithhapp.md) | | Creates and adds a single player to the scenario, with a set of DNAs installed. |
+| [addPlayerWithHappBundle(tryCpClient, appBundleSource, options)](./tryorama.trycpscenario.addplayerwithhappbundle.md) | | Creates and adds a single player to the scenario, with a hApp bundle installed. |
+| [cleanUp()](./tryorama.trycpscenario.cleanup.md) | | Shut down and delete all conductors and close all client connections in the scenario. |
+| [shareAllAgents()](./tryorama.trycpscenario.shareallagents.md) | | Registers all agents of all passed in conductors to each other. This skips peer discovery through gossip and thus accelerates test runs. |
+| [shutDown()](./tryorama.trycpscenario.shutdown.md) | | Shut down all conductors of all clients in the scenario. |
diff --git a/docs/tryorama.trycpscenario.shareallagents.md b/docs/tryorama.trycpscenario.shareallagents.md
index 009db1e5..7b868838 100644
--- a/docs/tryorama.trycpscenario.shareallagents.md
+++ b/docs/tryorama.trycpscenario.shareallagents.md
@@ -4,7 +4,7 @@
## TryCpScenario.shareAllAgents() method
-Register all agents of all passed in conductors to each other. This skips peer discovery through gossip and thus accelerates test runs.
+Registers all agents of all passed in conductors to each other. This skips peer discovery through gossip and thus accelerates test runs.
Signature:
diff --git a/docs/tryorama.trycpscenario.shutdown.md b/docs/tryorama.trycpscenario.shutdown.md
index 2c6e7a75..ab34d480 100644
--- a/docs/tryorama.trycpscenario.shutdown.md
+++ b/docs/tryorama.trycpscenario.shutdown.md
@@ -4,7 +4,7 @@
## TryCpScenario.shutDown() method
-Shut down all conductors in the scenario.
+Shut down all conductors of all clients in the scenario.
Signature:
diff --git a/package-lock.json b/package-lock.json
index 53a3590c..2ed3b209 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@holochain/tryorama",
- "version": "0.5.9",
+ "version": "0.6.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@holochain/tryorama",
- "version": "0.5.9",
+ "version": "0.6.1",
"license": "CAL-1.0",
"workspaces": [
"crates/trycp_server/test"
diff --git a/package.json b/package.json
index 4abe7ec7..b7279bf9 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "@holochain/tryorama",
"description": "Toolset to manage Holochain conductors and facilitate running test scenarios",
- "version": "0.6.0",
+ "version": "0.6.2",
"author": "Holochain Foundation",
"keywords": [
"holochain",
@@ -39,8 +39,8 @@
"test:local": "npm run test:local:conductor && npm run test:local:scenario",
"test:local:conductor": "node --loader ts-node/esm ts/test/local/conductor.ts",
"test:local:scenario": "node --loader ts-node/esm ts/test/local/scenario.ts",
- "test:trycp": "npm run test:trycp:server && npm run test:trycp:conductor && npm run test:trycp:scenario",
- "test:trycp:server": "node --loader ts-node/esm ts/test/trycp/server.ts",
+ "test:trycp": "npm run test:trycp:client && npm run test:trycp:conductor && npm run test:trycp:scenario",
+ "test:trycp:client": "node --loader ts-node/esm ts/test/trycp/client.ts",
"test:trycp:conductor": "node --loader ts-node/esm ts/test/trycp/conductor.ts",
"test:trycp:scenario": "node --loader ts-node/esm ts/test/trycp/scenario.ts"
},
diff --git a/run-test.sh b/run-test.sh
index b942b0e1..8caf133c 100755
--- a/run-test.sh
+++ b/run-test.sh
@@ -6,9 +6,11 @@ cargo build --release --target-dir target
cd ../..
# build test hApp
-cd ts/test/fixture/zomes/entry
+cd ts/test/fixture/zomes/integrity
cargo build --release --target wasm32-unknown-unknown
-cd ../../ # into fixtures
+cd ../coordinator
+cargo build --release --target wasm32-unknown-unknown
+cd ../.. # into fixtures
hc dna pack . -o entry.dna
hc app pack . -o entry.happ
cd ../../..
diff --git a/ts/src/local/conductor.ts b/ts/src/local/conductor.ts
index 00862567..5ab76bd7 100644
--- a/ts/src/local/conductor.ts
+++ b/ts/src/local/conductor.ts
@@ -4,8 +4,6 @@ import {
AppSignalCb,
AppWebsocket,
AttachAppInterfaceRequest,
- DnaSource,
- DnaProperties,
InstallAppBundleRequest,
InstallAppDnaPayload,
RegisterDnaRequest,
@@ -21,6 +19,7 @@ import { enableAndGetAgentHapp } from "../common.js";
import { makeLogger } from "../logger.js";
import {
AgentHapp,
+ AgentsHappsOptions,
HappBundleOptions,
IConductor,
_RegisterDnaReqOpts,
@@ -399,48 +398,57 @@ export class Conductor implements IConductor {
* 2-dimensional array, and a UID for the DNAs (optional).
* @returns An array with each agent's hApps.
*/
- async installAgentsHapps(options: {
- agentsDnas: DnaSource[][];
- uid?: string;
- properties?: DnaProperties;
- }) {
+ async installAgentsHapps(options: AgentsHappsOptions) {
const agentsHapps: AgentHapp[] = [];
+ const agentsDnas = Array.isArray(options) ? options : options.agentsDnas;
- for (const agent of options.agentsDnas) {
- const dnas: InstallAppDnaPayload[] = [];
- const agentPubKey = await this.adminWs().generateAgentPubKey();
- const appId = `app-${uuidv4()}`;
+ for (const agentDnas of agentsDnas) {
+ const dnasToInstall: InstallAppDnaPayload[] = [];
+ const appId =
+ ("installedAppId" in options && options.installedAppId) ||
+ `app-${uuidv4()}`;
+ const agentPubKey =
+ ("agentPubKey" in agentDnas && agentDnas.agentPubKey) ||
+ (await this.adminWs().generateAgentPubKey());
- for (const dna of agent) {
- let role_id: string;
+ const dnas = "dnas" in agentDnas ? agentDnas.dnas : agentDnas;
+ for (const dna of dnas) {
+ let roleId: string;
const registerDnaReqOpts: _RegisterDnaReqOpts = {
- uid: options.uid,
- properties: options.properties,
+ uid: ("uid" in options && options.uid) || undefined,
+ properties: ("properties" in dna && dna.properties) || undefined,
};
- if ("path" in dna) {
- registerDnaReqOpts["path"] = dna.path;
- role_id = `${dna.path}-${uuidv4()}`;
- } else if ("hash" in dna) {
- registerDnaReqOpts["hash"] = dna.hash;
- role_id = `dna-${uuidv4()}`;
+ const dnaSource = "source" in dna ? dna.source : dna;
+ if ("path" in dnaSource) {
+ registerDnaReqOpts.path = dnaSource.path;
+ roleId = `${dnaSource.path}-${uuidv4()}`;
+ } else if ("hash" in dnaSource) {
+ registerDnaReqOpts.hash = dnaSource.hash;
+ roleId = `dna-${uuidv4()}`;
} else {
- registerDnaReqOpts["bundle"] = dna.bundle;
- role_id = `${dna.bundle.manifest.name}-${uuidv4()}`;
+ registerDnaReqOpts.bundle = dnaSource.bundle;
+ roleId = `${dnaSource.bundle.manifest.name}-${uuidv4()}`;
}
const dnaHash = await this.adminWs().registerDna(
registerDnaReqOpts as RegisterDnaRequest
);
- dnas.push({ hash: dnaHash, role_id });
+ const membrane_proof =
+ "membraneProof" in dna ? dna.membraneProof : undefined;
+ dnasToInstall.push({
+ hash: dnaHash,
+ role_id: ("roleId" in dna && dna.roleId) || roleId,
+ membrane_proof,
+ });
}
const installedAppInfo = await this.adminWs().installApp({
installed_app_id: appId,
agent_key: agentPubKey,
- dnas,
+ dnas: dnasToInstall,
});
const agentHapp = await enableAndGetAgentHapp(
this,
diff --git a/ts/src/local/scenario.ts b/ts/src/local/scenario.ts
index c2379af2..41d0530b 100644
--- a/ts/src/local/scenario.ts
+++ b/ts/src/local/scenario.ts
@@ -1,13 +1,13 @@
+import { AppBundleSource, AppSignalCb } from "@holochain/client";
import { v4 as uuidv4 } from "uuid";
-import { AppBundleSource, AppSignalCb, DnaSource } from "@holochain/client";
-import { cleanAllConductors, createConductor, Conductor } from "./conductor.js";
+import { addAllAgentsToAllConductors } from "../common.js";
import {
- AgentHappOptions,
+ AgentDnas,
HappBundleOptions,
IPlayer,
- IScenario,
+ PlayerHappOptions,
} from "../types.js";
-import { addAllAgentsToAllConductors } from "../common.js";
+import { cleanAllConductors, Conductor, createConductor } from "./conductor.js";
/**
* A player tied to a {@link Conductor}.
@@ -34,7 +34,7 @@ export interface ScenarioOptions {
*
* @public
*/
-export class Scenario implements IScenario {
+export class Scenario {
private timeout: number | undefined;
uid: string;
conductors: Conductor[];
@@ -69,24 +69,26 @@ export class Scenario implements IScenario {
* Create and add a single player to the scenario, with a set of DNAs
* installed.
*
- * @param agentHappOptions - {@link AgentHappOptions}.
+ * @param playerHappOptions - {@link PlayerHappOptions}.
* @returns A local player instance.
*/
- async addPlayerWithHapp(agentHappOptions: AgentHappOptions): Promise {
- const signalHandler = Array.isArray(agentHappOptions)
- ? undefined
- : agentHappOptions.signalHandler;
- const properties = Array.isArray(agentHappOptions)
+ async addPlayerWithHapp(
+ playerHappOptions: PlayerHappOptions
+ ): Promise {
+ const signalHandler = Array.isArray(playerHappOptions)
? undefined
- : agentHappOptions.properties;
- const agentsDnas: DnaSource[][] = Array.isArray(agentHappOptions)
- ? [agentHappOptions]
- : [agentHappOptions.dnas];
+ : playerHappOptions.signalHandler;
+ const agentsDnas: AgentDnas[] = [
+ {
+ dnas: Array.isArray(playerHappOptions)
+ ? playerHappOptions.map((dnaSource) => ({ source: dnaSource }))
+ : playerHappOptions.dnas,
+ },
+ ];
const conductor = await this.addConductor(signalHandler);
const [agentHapp] = await conductor.installAgentsHapps({
agentsDnas,
uid: this.uid,
- properties,
});
return { conductor, ...agentHapp };
}
@@ -95,11 +97,11 @@ export class Scenario implements IScenario {
* Create and add multiple players to the scenario, with a set of DNAs
* installed for each player.
*
- * @param agentHappOptions - {@link AgentHappOptions} for each player.
+ * @param agentHappOptions - {@link PlayerHappOptions} for each player.
* @returns An array with the added players.
*/
async addPlayersWithHapps(
- agentHappOptions: AgentHappOptions[]
+ agentHappOptions: PlayerHappOptions[]
): Promise {
const players = await Promise.all(
agentHappOptions.map((options) => this.addPlayerWithHapp(options))
diff --git a/ts/src/trycp/conductor/conductor.ts b/ts/src/trycp/conductor/conductor.ts
index 30276e65..266d584b 100644
--- a/ts/src/trycp/conductor/conductor.ts
+++ b/ts/src/trycp/conductor/conductor.ts
@@ -9,7 +9,6 @@ import {
CreateCloneCellRequest,
DisableAppRequest,
DnaHash,
- DnaProperties,
DnaSource,
DumpFullStateRequest,
DumpStateRequest,
@@ -19,7 +18,6 @@ import {
InstallAppDnaPayload,
InstallAppRequest,
ListAppsRequest,
- MembraneProof,
RegisterDnaRequest,
RequestAgentInfoRequest,
StartAppRequest,
@@ -32,7 +30,13 @@ import { URL } from "node:url";
import { v4 as uuidv4 } from "uuid";
import { enableAndGetAgentHapp } from "../../common.js";
import { makeLogger } from "../../logger.js";
-import { AgentHapp, IConductor, _RegisterDnaReqOpts } from "../../types.js";
+import {
+ AgentHapp,
+ HappBundleOptions,
+ IConductor,
+ AgentsHappsOptions,
+ _RegisterDnaReqOpts,
+} from "../../types.js";
import { TryCpClient, TryCpConductorLogLevel } from "../index.js";
import {
RequestAdminInterfaceData,
@@ -86,27 +90,23 @@ export interface TryCpConductorOptions {
* default: "info"
*/
logLevel?: TryCpConductorLogLevel;
-
- /**
- * Timeout for requests to Admin and App API.
- */
- timeout?: number;
}
/**
- * The function to create a TryCP Conductor (aka "Player").
+ * The function to create a TryCP Conductor. By default configures and starts
+ * it.
*
- * @param serverUrl - The URL of the TryCP server to connect to.
- * @returns A configured Conductor instance.
+ * @param tryCpClient - The client connection to the TryCP server on which to
+ * create the conductor.
+ * @returns A conductor instance.
*
* @public
*/
export const createTryCpConductor = async (
- serverUrl: URL,
+ tryCpClient: TryCpClient,
options?: TryCpConductorOptions
) => {
- const client = await TryCpClient.create(serverUrl, options?.timeout);
- const conductor = new TryCpConductor(client, options?.id);
+ const conductor = new TryCpConductor(tryCpClient, options?.id);
if (options?.startup !== false) {
// configure and startup conductor by default
await conductor.configure(options?.partialConfig);
@@ -121,9 +121,9 @@ export const createTryCpConductor = async (
* @public
*/
export class TryCpConductor implements IConductor {
- private readonly id: string;
- private readonly tryCpClient: TryCpClient;
+ readonly id: string;
private appInterfacePort: undefined | number;
+ readonly tryCpClient: TryCpClient;
constructor(tryCpClient: TryCpClient, id?: ConductorId) {
this.tryCpClient = tryCpClient;
@@ -165,7 +165,7 @@ export class TryCpConductor implements IConductor {
}
/**
- * Disconnect App interface and shut down the conductor.
+ * Disconnect app interface and shut down the conductor.
*
* @returns An empty success response.
*
@@ -636,39 +636,41 @@ export class TryCpConductor implements IConductor {
/**
* Install a set of DNAs for multiple agents into the conductor.
*
- * @param options - An array of DNAs for each agent, resulting in a
- * 2-dimensional array, and a UID for the DNAs (optional).
+ * @param options - {@link AgentsHappsOptions}
* @returns An array with each agent's hApp.
*/
- async installAgentsHapps(options: {
- agentsDnas: DnaSource[][];
- signalHandler?: AppSignalCb;
- uid?: string;
- properties?: DnaProperties;
- }) {
+ async installAgentsHapps(options: AgentsHappsOptions) {
const agentsHapps: AgentHapp[] = [];
-
- for (const agentDnas of options.agentsDnas) {
- const dnas: InstallAppDnaPayload[] = [];
- const agentPubKey = await this.adminWs().generateAgentPubKey();
- const appId = `app-${uuidv4()}`;
+ const agentsDnas = Array.isArray(options) ? options : options.agentsDnas;
+
+ for (const agentDnas of agentsDnas) {
+ const dnasToInstall: InstallAppDnaPayload[] = [];
+ const appId =
+ ("installedAppId" in options && options.installedAppId) ||
+ `app-${uuidv4()}`;
+ const agentPubKey =
+ ("agentPubKey" in agentDnas && agentDnas.agentPubKey) ||
+ (await this.adminWs().generateAgentPubKey());
logger.debug(
`installing app with id ${appId} for agent ${Buffer.from(
agentPubKey
).toString("base64")}`
);
- for (const dna of agentDnas) {
- let role_id: string;
+ const dnas = "dnas" in agentDnas ? agentDnas.dnas : agentDnas;
+ for (const dna of dnas) {
+ let roleId: string;
const registerDnaReqOpts: _RegisterDnaReqOpts = {
- uid: options.uid,
- properties: options.properties,
+ uid: ("uid" in options && options.uid) || undefined,
+ properties: ("properties" in dna && dna.properties) || undefined,
};
- if ("path" in dna) {
+ const dnaSource = "source" in dna ? dna.source : dna;
+ if ("path" in dnaSource) {
+ const path = dnaSource.path;
const dnaContent = await new Promise((resolve, reject) => {
- fs.readFile(dna.path, null, (err, data) => {
+ fs.readFile(path, null, (err, data) => {
if (err) {
reject(err);
}
@@ -676,27 +678,33 @@ export class TryCpConductor implements IConductor {
});
});
const relativePath = await this.saveDna(dnaContent);
- registerDnaReqOpts["path"] = relativePath;
- role_id = `${dna.path}-${uuidv4()}`;
- } else if ("hash" in dna) {
- registerDnaReqOpts["hash"] = dna.hash;
- role_id = `dna-${uuidv4()}`;
+ registerDnaReqOpts.path = relativePath;
+ roleId = `${path}-${uuidv4()}`;
+ } else if ("hash" in dnaSource) {
+ registerDnaReqOpts.hash = dnaSource.hash;
+ roleId = `dna-${uuidv4()}`;
} else {
- registerDnaReqOpts["bundle"] = dna.bundle;
- role_id = `${dna.bundle.manifest.name}-${uuidv4()}`;
+ registerDnaReqOpts.bundle = dnaSource.bundle;
+ roleId = `${dnaSource.bundle.manifest.name}-${uuidv4()}`;
}
const dnaHash = await this.adminWs().registerDna(
registerDnaReqOpts as RegisterDnaRequest
);
- dnas.push({ hash: dnaHash, role_id });
+ const membrane_proof =
+ "membraneProof" in dna ? dna.membraneProof : undefined;
+ dnasToInstall.push({
+ hash: dnaHash,
+ role_id: ("roleId" in dna && dna.roleId) || roleId,
+ membrane_proof,
+ });
}
const installedAppInfo = await this.adminWs().installApp({
installed_app_id: appId,
agent_key: agentPubKey,
- dnas,
+ dnas: dnasToInstall,
});
const agentHapp = await enableAndGetAgentHapp(
@@ -719,12 +727,7 @@ export class TryCpConductor implements IConductor {
*/
async installHappBundle(
appBundleSource: AppBundleSource,
- options?: {
- agentPubKey?: AgentPubKey;
- installedAppId?: string;
- uid?: string;
- membraneProofs?: Record;
- }
+ options?: HappBundleOptions
) {
const agentPubKey =
options?.agentPubKey ?? (await this.adminWs().generateAgentPubKey());
@@ -749,19 +752,3 @@ export class TryCpConductor implements IConductor {
return agentHapp;
}
}
-
-/**
- * Run the `reset` command on the TryCP server to delete all conductor data.
- *
- * @param serverUrl - The TryCP server to connect to.
- * @returns An empty success response.
- *
- * @public
- */
-export const cleanAllTryCpConductors = async (serverUrl: URL) => {
- const client = await TryCpClient.create(serverUrl);
- const response = await client.call({ type: "reset" });
- assert(response === TRYCP_SUCCESS_RESPONSE);
- await client.close();
- return response;
-};
diff --git a/ts/src/trycp/conductor/scenario.ts b/ts/src/trycp/conductor/scenario.ts
index 3a234f61..4e5dcbe5 100644
--- a/ts/src/trycp/conductor/scenario.ts
+++ b/ts/src/trycp/conductor/scenario.ts
@@ -1,28 +1,52 @@
-import { AppBundleSource, AppSignalCb, DnaSource } from "@holochain/client";
+import { AgentPubKey, AppBundleSource, AppSignalCb } from "@holochain/client";
import { URL } from "url";
import { v4 as uuidv4 } from "uuid";
import { addAllAgentsToAllConductors as shareAllAgents } from "../../common.js";
import {
- AgentHappOptions,
+ AgentDnas,
+ Dna,
HappBundleOptions,
IPlayer,
- IScenario,
+ PlayerHappOptions,
} from "../../types.js";
-import { TryCpServer } from "../trycp-server.js";
-import {
- cleanAllTryCpConductors,
- createTryCpConductor,
- TryCpConductor,
-} from "./conductor.js";
-
-const partialConfig = `signing_service_uri: ~
-encryption_service_uri: ~
-decryption_service_uri: ~
-dpki: ~
-network:
- transport_pool:
- - type: quic
- network_type: quic_mdns`;
+import { TryCpClient } from "../trycp-client.js";
+import { TryCpConductor } from "./conductor.js";
+
+/**
+ * @public
+ */
+export interface ClientsPlayersOptions {
+ /**
+ * A timeout for the web socket connection (optional).
+ */
+ clientTimeout?: number;
+
+ /**
+ * An array of DNAs that will be installed for each agent (optional).
+ */
+ dnas?: Dna[];
+
+ /**
+ * A list of previously generated agent pub keys (optional).
+ */
+ agentPubKeys?: AgentPubKey[];
+
+ /**
+ * Number of conductors per client. Default to 1.
+ */
+ numberOfConductorsPerClient?: number;
+
+ /**
+ * Number of agents per conductor. Defaults to 1. Requires `dnas` to be
+ * specified.
+ */
+ numberOfAgentsPerConductor?: number;
+
+ /**
+ * A signal handler to be registered in conductors.
+ */
+ signalHandler?: AppSignalCb;
+}
/**
* A player tied to a {@link TryCpConductor}.
@@ -34,111 +58,175 @@ export interface TryCpPlayer extends IPlayer {
}
/**
- * An abstraction of a test scenario to write tests against Holochain hApps,
- * running on a TryCp conductor.
+ * A test scenario abstraction with convenience functions to manage TryCP
+ * clients and players (agent + conductor).
+ *
+ * Clients in turn help manage conductors on TryCP servers. Clients can be
+ * added to a scenario to keep track of all server connections. When finishing
+ * a test scenario, all conductors of all clients can be easily cleaned up and
+ * the client connections closed.
*
* @public
*/
-export class TryCpScenario implements IScenario {
+export class TryCpScenario {
uid: string;
- conductors: TryCpConductor[];
- private serverUrl: URL;
- private server: TryCpServer | undefined;
+ clients: TryCpClient[];
- private constructor(serverUrl: URL) {
+ constructor() {
this.uid = uuidv4();
- this.conductors = [];
- this.serverUrl = serverUrl;
- this.server = undefined;
+ this.clients = [];
}
/**
- * Factory method to create a new scenario.
+ * Creates a TryCP client connection and add it to the scenario.
*
- * @param serverUrl - The URL of the TryCp server to connect to.
- * @returns A new scenario instance.
+ * @param serverUrl - The TryCP server URL to connect to.
+ * @param timeout - An optional timeout for the web socket connection.
+ * @returns The created TryCP client.
*/
- static async create(serverUrl: URL) {
- const scenario = new TryCpScenario(serverUrl);
- scenario.server = await TryCpServer.start();
- return scenario;
+ async addClient(serverUrl: URL, timeout?: number) {
+ const client = await TryCpClient.create(serverUrl, timeout);
+ this.clients.push(client);
+ return client;
}
/**
- * Create and add a conductor to the scenario.
+ * Creates client connections for all passed in URLs and, depending on the
+ * options, creates multiple players with DNAs. Adds all clients to the
+ * scenario.
*
- * @param signalHandler - A callback function to handle signals.
- * @returns The newly added conductor instance.
+ * @param serverUrls - The TryCP server URLs to connect to.
+ * @param options - {@link ClientsPlayersOptions}
+ * @returns The created TryCP clients and all conductors per client and all
+ * agents' hApps per conductor.
*/
- async addConductor(signalHandler?: AppSignalCb) {
- const conductor = await createTryCpConductor(this.serverUrl, {
- partialConfig,
- });
- await conductor.adminWs().attachAppInterface();
- await conductor.connectAppInterface(signalHandler);
- this.conductors.push(conductor);
- return conductor;
+ async addClientsPlayers(serverUrls: URL[], options?: ClientsPlayersOptions) {
+ const clientsPlayers: Array<{
+ client: TryCpClient;
+ players: TryCpPlayer[];
+ }> = [];
+
+ // create client connections for specified URLs
+ for (const serverUrl of serverUrls) {
+ const client = await this.addClient(serverUrl, options?.clientTimeout);
+ const players: TryCpPlayer[] = [];
+ const numberOfConductorsPerClient =
+ options?.numberOfConductorsPerClient ?? 1;
+
+ // create conductors for each client
+ for (let i = 0; i < numberOfConductorsPerClient; i++) {
+ const conductor = await client.addConductor(options?.signalHandler);
+ const numberOfAgentsPerConductor =
+ options?.numberOfAgentsPerConductor ?? 1;
+
+ if (options?.numberOfAgentsPerConductor) {
+ // install agents hApps for each conductor
+ if (options.dnas === undefined) {
+ throw new Error("no DNAs specified to be installed for agents");
+ }
+
+ // TS fails to infer that options.dnas cannot be `undefined` here
+ const dnas = options.dnas;
+
+ let agentsDnas: AgentDnas[];
+ if (options.agentPubKeys) {
+ if (options.agentPubKeys.length !== options.dnas.length) {
+ throw new Error(
+ "number of agent pub keys doesn't match number of DNAs"
+ );
+ }
+ agentsDnas = options.agentPubKeys.map((agentPubKey) => ({
+ agentPubKey,
+ dnas,
+ }));
+ } else {
+ agentsDnas = [...Array(numberOfAgentsPerConductor)].map(() => ({
+ dnas,
+ }));
+ }
+
+ const installedAgentsHapps = await conductor.installAgentsHapps({
+ agentsDnas,
+ });
+ installedAgentsHapps.forEach((agentHapps) =>
+ players.push({ conductor, ...agentHapps })
+ );
+ }
+ }
+ clientsPlayers.push({ client, players });
+ }
+ return clientsPlayers;
}
/**
- * Create and add a single player to the scenario, with a set of DNAs
+ * Creates and adds a single player to the scenario, with a set of DNAs
* installed.
*
- * @param agentHappOptions - {@link AgentHappOptions}.
- * @returns A local player instance.
+ * @param tryCpClient - The client connection to the TryCP server on which to
+ * create the player.
+ * @param playerHappOptions - {@link PlayerHappOptions}.
+ * @returns The created player instance.
*/
async addPlayerWithHapp(
- agentHappOptions: AgentHappOptions
+ tryCpClient: TryCpClient,
+ playerHappOptions: PlayerHappOptions
): Promise {
- const signalHandler = Array.isArray(agentHappOptions)
- ? undefined
- : agentHappOptions.signalHandler;
- const properties = Array.isArray(agentHappOptions)
+ const signalHandler = Array.isArray(playerHappOptions)
? undefined
- : agentHappOptions.properties;
- const agentsDnas: DnaSource[][] = Array.isArray(agentHappOptions)
- ? [agentHappOptions]
- : [agentHappOptions.dnas];
- const conductor = await this.addConductor(signalHandler);
+ : playerHappOptions.signalHandler;
+ const agentsDnas: AgentDnas[] = [
+ {
+ dnas: Array.isArray(playerHappOptions)
+ ? playerHappOptions.map((dnaSource) => ({ source: dnaSource }))
+ : playerHappOptions.dnas,
+ },
+ ];
+ const conductor = await tryCpClient.addConductor(signalHandler);
const [agentHapp] = await conductor.installAgentsHapps({
agentsDnas,
uid: this.uid,
- properties,
- signalHandler,
});
return { conductor, ...agentHapp };
}
/**
- * Create and add multiple players to the scenario, with a set of DNAs
+ * Creates and adds multiple players to the scenario, with a set of DNAs
* installed for each player.
*
- * @param agentHappOptions - {@link AgentHappOptions} for each player.
- * @returns An array with the added players.
+ * @param tryCpClient - The client connection to the TryCP server on which to
+ * create the player.
+ * @param agentHappOptions - {@link PlayerHappOptions} for each player.
+ * @returns An array of the added players.
*/
async addPlayersWithHapps(
- agentHappOptions: AgentHappOptions[]
+ tryCpClient: TryCpClient,
+ agentHappOptions: PlayerHappOptions[]
): Promise {
const players = await Promise.all(
- agentHappOptions.map((options) => this.addPlayerWithHapp(options))
+ agentHappOptions.map((options) =>
+ this.addPlayerWithHapp(tryCpClient, options)
+ )
);
return players;
}
/**
- * Create and add a single player to the scenario, with a hApp bundle
+ * Creates and adds a single player to the scenario, with a hApp bundle
* installed.
*
+ * @param tryCpClient - The client connection to the TryCP server on which to
+ * create the player.
* @param appBundleSource - The bundle or path to the bundle.
* @param options - {@link HappBundleOptions} plus a signal handler
* (optional).
- * @returns A local player instance.
+ * @returns The created player instance.
*/
async addPlayerWithHappBundle(
+ tryCpClient: TryCpClient,
appBundleSource: AppBundleSource,
options?: HappBundleOptions & { signalHandler?: AppSignalCb }
) {
- const conductor = await this.addConductor(options?.signalHandler);
+ const conductor = await tryCpClient.addConductor(options?.signalHandler);
options = options
? Object.assign(options, { uid: options.uid ?? this.uid })
: { uid: this.uid };
@@ -146,19 +234,21 @@ export class TryCpScenario implements IScenario {
appBundleSource,
options
);
- this.conductors.push(conductor);
return { conductor, ...agentHapp };
}
/**
- * Create and add multiple players to the scenario, with a hApp bundle
+ * Creates and adds multiple players to the scenario, with a hApp bundle
* installed for each player.
*
+ * @param tryCpClient - The client connection to the TryCP server on which to
+ * create the player.
* @param playersHappBundles - An array with a hApp bundle for each player,
* and a signal handler (optional).
- * @returns
+ * @returns An array of the added players.
*/
async addPlayersWithHappBundles(
+ tryCpClient: TryCpClient,
playersHappBundles: Array<{
appBundleSource: AppBundleSource;
options?: HappBundleOptions & { signalHandler?: AppSignalCb };
@@ -167,6 +257,7 @@ export class TryCpScenario implements IScenario {
const players = await Promise.all(
playersHappBundles.map(async (playerHappBundle) =>
this.addPlayerWithHappBundle(
+ tryCpClient,
playerHappBundle.appBundleSource,
playerHappBundle.options
)
@@ -176,35 +267,30 @@ export class TryCpScenario implements IScenario {
}
/**
- * Register all agents of all passed in conductors to each other. This skips
+ * Registers all agents of all passed in conductors to each other. This skips
* peer discovery through gossip and thus accelerates test runs.
- *
- * @public
*/
async shareAllAgents() {
- return shareAllAgents(this.conductors);
+ return shareAllAgents(
+ this.clients.map((client) => client.conductors).flat()
+ );
}
/**
- * Shut down all conductors in the scenario.
+ * Shut down all conductors of all clients in the scenario.
*/
async shutDown() {
- await Promise.all(this.conductors.map((conductor) => conductor.shutDown()));
await Promise.all(
- this.conductors.map((conductor) => conductor.disconnectClient())
+ this.clients.map((client) => client.shutDownConductors())
);
}
/**
- * Shut down and delete all conductors in the scenario, and stop the TryCP
- * server.
- *
- * @public
+ * Shut down and delete all conductors and close all client connections in
+ * the scenario.
*/
async cleanUp() {
- await this.shutDown();
- await cleanAllTryCpConductors(this.serverUrl);
- this.conductors = [];
- await this.server?.stop();
+ await Promise.all(this.clients.map((client) => client.cleanUp()));
+ this.clients = [];
}
}
diff --git a/ts/src/trycp/trycp-client.ts b/ts/src/trycp/trycp-client.ts
index 96fc9bf8..34ec5237 100644
--- a/ts/src/trycp/trycp-client.ts
+++ b/ts/src/trycp/trycp-client.ts
@@ -1,9 +1,14 @@
import { AppSignalCb } from "@holochain/client";
import msgpack from "@msgpack/msgpack";
import cloneDeep from "lodash/cloneDeep.js";
+import assert from "node:assert";
import { URL } from "node:url";
import { WebSocket } from "ws";
import { makeLogger } from "../logger.js";
+import {
+ createTryCpConductor as createConductor,
+ TryCpConductor,
+} from "./conductor/conductor.js";
import {
TryCpApiResponse,
TryCpRequest,
@@ -22,9 +27,21 @@ import {
const logger = makeLogger("TryCP client");
let requestId = 0;
+const partialConfig = `signing_service_uri: ~
+encryption_service_uri: ~
+decryption_service_uri: ~
+dpki: ~
+network:
+ transport_pool:
+ - type: quic
+ network_type: quic_mdns`;
+
/**
* A factory class to create client connections to a running TryCP server.
*
+ * With a client, conductors on the server can ba configured, started and
+ * stopped. All valid Admin and App API commands can be sent to the server too.
+ *
* @public
*/
export class TryCpClient {
@@ -37,21 +54,20 @@ export class TryCpClient {
};
private signalHandlers: Record;
+ conductors: TryCpConductor[];
+
private constructor(serverUrl: URL, timeout = 15000) {
this.ws = new WebSocket(serverUrl, { timeout });
this.requestPromises = {};
this.signalHandlers = {};
- }
-
- setSignalHandler(port: number, signalHandler?: AppSignalCb) {
- this.signalHandlers[port] = signalHandler;
+ this.conductors = [];
}
/**
* Create a client connection to a running TryCP server.
*
* @param serverUrl - The URL of the TryCP server.
- * @returns A client connection.
+ * @returns The created client connection.
*/
static async create(serverUrl: URL, timeout?: number) {
const tryCpClient = new TryCpClient(serverUrl, timeout);
@@ -134,27 +150,8 @@ export class TryCpClient {
return connectPromise;
}
- private processSuccessResponse(response: _TryCpSuccessResponseSeralized) {
- if (response === TRYCP_SUCCESS_RESPONSE || typeof response === "string") {
- logger.debug(`response ${JSON.stringify(response, null, 4)}\n`);
- return response;
- }
-
- const deserializedApiResponse = deserializeApiResponse(response);
-
- // when the request fails, the response's type is "error"
- if (deserializedApiResponse.type === "error") {
- const errorMessage = `error response from Admin API\n${JSON.stringify(
- deserializedApiResponse.data,
- null,
- 4
- )}`;
- throw new Error(errorMessage);
- }
-
- logger.debug(this.getFormattedResponseLog(deserializedApiResponse));
-
- return deserializedApiResponse;
+ setSignalHandler(port: number, signalHandler?: AppSignalCb) {
+ this.signalHandlers[port] = signalHandler;
}
/**
@@ -238,6 +235,71 @@ export class TryCpClient {
return callPromise;
}
+ /**
+ * Create and add a conductor to the client.
+ *
+ * @param signalHandler - A callback function to handle signals.
+ * @returns The newly added conductor instance.
+ */
+ async addConductor(signalHandler?: AppSignalCb) {
+ const conductor = await createConductor(this, { partialConfig });
+ await conductor.adminWs().attachAppInterface();
+ await conductor.connectAppInterface(signalHandler);
+ this.conductors.push(conductor);
+ return conductor;
+ }
+
+ /**
+ * Shut down all conductors on the connected TryCP server and disconnect
+ * their app interfaces.
+ */
+ async shutDownConductors() {
+ await Promise.all(this.conductors.map((conductor) => conductor.shutDown()));
+ }
+
+ /**
+ * Run the `reset` command on the TryCP server to delete all conductor data.
+ *
+ * @returns An empty success response.
+ */
+ async cleanAllConductors() {
+ const response = await this.call({ type: "reset" });
+ assert(response === TRYCP_SUCCESS_RESPONSE);
+ return response;
+ }
+
+ /**
+ * Shut down all registered conductors and delete them, and close the client
+ * connection.
+ */
+ async cleanUp() {
+ await this.cleanAllConductors();
+ await this.close();
+ }
+
+ private processSuccessResponse(response: _TryCpSuccessResponseSeralized) {
+ if (response === TRYCP_SUCCESS_RESPONSE || typeof response === "string") {
+ logger.debug(`response ${JSON.stringify(response, null, 4)}\n`);
+ return response;
+ }
+
+ const deserializedApiResponse = deserializeApiResponse(response);
+
+ // when the request fails, the response's type is "error"
+ if (deserializedApiResponse.type === "error") {
+ const errorMessage = `error response from Admin API\n${JSON.stringify(
+ deserializedApiResponse.data,
+ null,
+ 4
+ )}`;
+ throw new Error(errorMessage);
+ }
+
+ logger.debug(this.getFormattedResponseLog(deserializedApiResponse));
+
+ return deserializedApiResponse;
+ }
+
private getFormattedResponseLog(response: TryCpApiResponse) {
let debugLog;
if (
diff --git a/ts/src/trycp/trycp-server.ts b/ts/src/trycp/trycp-server.ts
index f485c271..030c7f48 100644
--- a/ts/src/trycp/trycp-server.ts
+++ b/ts/src/trycp/trycp-server.ts
@@ -57,9 +57,7 @@ export class TryCpServer {
logger.error(data);
return;
}
- const regexServerStarted = new RegExp(
- `Listening on ${TRYCP_SERVER_HOST}:${TRYCP_SERVER_PORT}`
- );
+ const regexServerStarted = new RegExp("Listening on");
if (regexServerStarted.test(data)) {
logger.verbose(data);
resolve(tryCpServer);
diff --git a/ts/src/types.ts b/ts/src/types.ts
index 4494ddbf..b7b86444 100644
--- a/ts/src/types.ts
+++ b/ts/src/types.ts
@@ -1,7 +1,6 @@
import {
AdminWebsocket,
AgentPubKey,
- AppBundleSource,
AppSignalCb,
AppWebsocket,
CallZomeRequest,
@@ -14,6 +13,7 @@ import {
MembraneProof,
RoleId,
RegisterDnaRequest,
+ InstalledAppId,
} from "@holochain/client";
/**
@@ -94,6 +94,65 @@ export interface HappBundleOptions {
membraneProofs?: Record;
}
+/**
+ * DNA source and additional options.
+ *
+ * @public
+ */
+export interface Dna {
+ source: DnaSource;
+ membraneProof?: MembraneProof;
+ properties?: DnaProperties;
+ roleId?: string;
+}
+
+/**
+ * DNAs per agent. Optionally an agent pub key.
+ *
+ * @public
+ */
+export interface AgentDnas {
+ dnas: Dna[];
+ agentPubKey?: AgentPubKey;
+}
+
+/**
+ * An array of DNA sources for each agent (2-dimensional array) or an array of DNAs
+ * and an optional agent pub key. Optionally a UID to be used for DNA installation.
+ *
+ * @public
+ */
+export type AgentsHappsOptions =
+ | DnaSource[][]
+ | {
+ agentsDnas: AgentDnas[];
+
+ /**
+ * A unique ID for the DNAs (optional).
+ */
+ uid?: string;
+
+ /**
+ * A unique ID for the hApp (optional).
+ */
+ installedAppId?: InstalledAppId;
+ };
+
+/**
+ * Player installation options used in scenarios.
+ *
+ * Specifies either only the DNA sources that the hApp to be installed
+ * consists of, or the DNAs and a signal handler to be registered.
+ *
+ * @public
+ */
+export type PlayerHappOptions =
+ | DnaSource[]
+ | {
+ dnas: Dna[];
+ signalHandler?: AppSignalCb;
+ };
+
/**
* Base interface of a Tryorama conductor. Both {@link Conductor} and
* {@link TryCpConductor} implement this interface.
@@ -117,49 +176,5 @@ export interface IConductor {
>;
appWs: () => Pick;
- installAgentsHapps: (options: {
- agentsDnas: DnaSource[][];
- uid?: string;
- properties?: DnaProperties;
- signalHandler?: AppSignalCb;
- }) => Promise;
-}
-
-/**
- * A type that specifies either only the DNAs that the hApp to be installed
- * consists of, or the DNAs and a signal handler to be registered.
- *
- * @public
- */
-export type AgentHappOptions =
- | DnaSource[]
- | {
- dnas: DnaSource[];
- signalHandler?: AppSignalCb;
- properties?: DnaProperties;
- };
-
-/**
- * Base interface of a Tryorama test scenario. Both {@link Scenario} and
- * {@link TryCpScenario} implement this interface.
- *
- * @public
- */
-export interface IScenario {
- addConductor(signalHandler?: AppSignalCb): Promise;
- addPlayerWithHapp(agentHappOptions: AgentHappOptions): Promise;
- addPlayersWithHapps(agentHappOptions: AgentHappOptions[]): Promise;
- addPlayerWithHappBundle(
- appBundleSource: AppBundleSource,
- options?: HappBundleOptions & { signalHandler?: AppSignalCb }
- ): Promise;
- addPlayersWithHappBundles(
- playersHappBundles: Array<{
- appBundleSource: AppBundleSource;
- options?: HappBundleOptions & { signalHandler?: AppSignalCb };
- }>
- ): Promise;
- shareAllAgents(conductors: IConductor[]): Promise;
- shutDown(): Promise;
- cleanUp(): Promise;
+ installAgentsHapps: (options: AgentsHappsOptions) => Promise;
}
diff --git a/ts/test/fixture/dna.yaml b/ts/test/fixture/dna.yaml
index ac6af71f..0c7a6751 100644
--- a/ts/test/fixture/dna.yaml
+++ b/ts/test/fixture/dna.yaml
@@ -5,5 +5,9 @@ integrity:
uid: 9a28aac8-337c-11eb-adc1-0Z02acw20115
properties: ~
zomes:
- - name: crud
- bundled: "../../../target/wasm32-unknown-unknown/release/crud.wasm"
+ - name: integrity
+ bundled: "../../../target/wasm32-unknown-unknown/release/integrity.wasm"
+coordinator:
+ zomes:
+ - name: coordinator
+ bundled: "../../../target/wasm32-unknown-unknown/release/coordinator.wasm"
diff --git a/ts/test/fixture/zomes/entry/Cargo.toml b/ts/test/fixture/zomes/coordinator/Cargo.toml
similarity index 56%
rename from ts/test/fixture/zomes/entry/Cargo.toml
rename to ts/test/fixture/zomes/coordinator/Cargo.toml
index 39fa61bf..31cce80c 100644
--- a/ts/test/fixture/zomes/entry/Cargo.toml
+++ b/ts/test/fixture/zomes/coordinator/Cargo.toml
@@ -1,12 +1,13 @@
[package]
-name = "crud"
edition = "2021"
+name = "coordinator"
version = "0.1.0"
[lib]
crate-type = ["cdylib", "rlib"]
-name = "crud"
+name = "coordinator"
[dependencies]
hdk = "0.0.140"
-serde = "1"
\ No newline at end of file
+integrity = {path = "../integrity"}
+serde = "1"
diff --git a/ts/test/fixture/zomes/entry/src/lib.rs b/ts/test/fixture/zomes/coordinator/src/lib.rs
similarity index 82%
rename from ts/test/fixture/zomes/entry/src/lib.rs
rename to ts/test/fixture/zomes/coordinator/src/lib.rs
index d513046c..7b1e5082 100644
--- a/ts/test/fixture/zomes/entry/src/lib.rs
+++ b/ts/test/fixture/zomes/coordinator/src/lib.rs
@@ -1,19 +1,5 @@
use hdk::prelude::*;
-
-#[hdk_entry_helper]
-pub struct Content(String);
-
-#[hdk_entry_helper]
-pub struct UpdateInput {
- pub hash: ActionHash,
- pub content: String,
-}
-
-#[hdk_entry_defs]
-#[unit_enum(EntryTypesUnit)]
-pub enum EntryTypes {
- Content(Content),
-}
+use integrity::{Content, EntryTypes, UpdateInput};
#[hdk_extern]
pub fn create(input: Content) -> ExternResult {
diff --git a/ts/test/fixture/zomes/integrity/Cargo.toml b/ts/test/fixture/zomes/integrity/Cargo.toml
new file mode 100644
index 00000000..bd7302bf
--- /dev/null
+++ b/ts/test/fixture/zomes/integrity/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+edition = "2021"
+name = "integrity"
+version = "0.1.0"
+
+[lib]
+crate-type = ["cdylib", "rlib"]
+name = "integrity"
+
+[dependencies]
+holochain_deterministic_integrity = "0.0.12"
+serde = "1"
diff --git a/ts/test/fixture/zomes/integrity/src/lib.rs b/ts/test/fixture/zomes/integrity/src/lib.rs
new file mode 100644
index 00000000..89f8f98b
--- /dev/null
+++ b/ts/test/fixture/zomes/integrity/src/lib.rs
@@ -0,0 +1,16 @@
+use holochain_deterministic_integrity::prelude::*;
+
+#[hdk_entry_helper]
+pub struct Content(pub String);
+
+#[hdk_entry_helper]
+pub struct UpdateInput {
+ pub hash: ActionHash,
+ pub content: String,
+}
+
+#[hdk_entry_defs]
+#[unit_enum(EntryTypesUnit)]
+pub enum EntryTypes {
+ Content(Content),
+}
diff --git a/ts/test/local/conductor.ts b/ts/test/local/conductor.ts
index 94f86abd..c83c53d9 100644
--- a/ts/test/local/conductor.ts
+++ b/ts/test/local/conductor.ts
@@ -166,9 +166,9 @@ test("Local Conductor - Spawn a conductor and check for admin and app ws", async
test("Local Conductor - Get app info", async (t) => {
const conductor = await createConductor();
- const [aliceHapps] = await conductor.installAgentsHapps({
- agentsDnas: [[{ path: FIXTURE_DNA_URL.pathname }]],
- });
+ const [aliceHapps] = await conductor.installAgentsHapps([
+ [{ path: FIXTURE_DNA_URL.pathname }],
+ ]);
const appInfo = await conductor.appWs().appInfo({
installed_app_id: aliceHapps.happId,
});
@@ -187,14 +187,14 @@ test("Local Conductor - Install and call a hApp bundle", async (t) => {
const entryContent = "Bye bye, world";
const createEntryResponse: EntryHash =
await installedHappBundle.cells[0].callZome({
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "create",
payload: entryContent,
});
t.ok(createEntryResponse);
const readEntryResponse: typeof entryContent =
await installedHappBundle.cells[0].callZome({
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "read",
payload: createEntryResponse,
});
@@ -207,12 +207,16 @@ test("Local Conductor - Install and call a hApp bundle", async (t) => {
test("Local Conductor - Get a convenience function for zome calls", async (t) => {
const conductor = await createConductor();
const [aliceHapps] = await conductor.installAgentsHapps({
- agentsDnas: [[{ path: FIXTURE_DNA_URL.pathname }]],
+ agentsDnas: [{ dnas: [{ source: { path: FIXTURE_DNA_URL.pathname } }] }],
});
- const crudZomeCall = getZomeCaller(aliceHapps.cells[0], "crud");
- t.equal(typeof crudZomeCall, "function", "getZomeCaller returns a function");
+ const coordinatorZomeCall = getZomeCaller(aliceHapps.cells[0], "coordinator");
+ t.equal(
+ typeof coordinatorZomeCall,
+ "function",
+ "getZomeCaller returns a function"
+ );
- const entryHeaderHash: ActionHash = await crudZomeCall(
+ const entryHeaderHash: ActionHash = await coordinatorZomeCall(
"create",
"test-entry"
);
@@ -226,12 +230,10 @@ test("Local Conductor - Get a convenience function for zome calls", async (t) =>
test("Local Conductor - Install multiple agents and DNAs and get access to agents and cells", async (t) => {
const conductor = await createConductor();
- const [aliceHapps, bobHapps] = await conductor.installAgentsHapps({
- agentsDnas: [
- [{ path: FIXTURE_DNA_URL.pathname }, { path: FIXTURE_DNA_URL.pathname }],
- [{ path: FIXTURE_DNA_URL.pathname }, { path: FIXTURE_DNA_URL.pathname }],
- ],
- });
+ const [aliceHapps, bobHapps] = await conductor.installAgentsHapps([
+ [{ path: FIXTURE_DNA_URL.pathname }, { path: FIXTURE_DNA_URL.pathname }],
+ [{ path: FIXTURE_DNA_URL.pathname }, { path: FIXTURE_DNA_URL.pathname }],
+ ]);
aliceHapps.cells.forEach((cell) =>
t.deepEqual(cell.cell_id[1], aliceHapps.agentPubKey)
);
@@ -243,6 +245,28 @@ test("Local Conductor - Install multiple agents and DNAs and get access to agent
await cleanAllConductors();
});
+test("Local Conductor - Install a DNA with custom role id", async (t) => {
+ const conductor = await createConductor();
+ const expectedRoleId = "test-role-id";
+ const [aliceHapps] = await conductor.installAgentsHapps({
+ agentsDnas: [
+ {
+ dnas: [
+ {
+ source: { path: FIXTURE_DNA_URL.pathname },
+ roleId: expectedRoleId,
+ },
+ ],
+ },
+ ],
+ });
+ const actualRoleId = aliceHapps.cells[0].role_id;
+ t.equal(actualRoleId, expectedRoleId, "dna role id matches");
+
+ await conductor.shutDown();
+ await cleanAllConductors();
+});
+
test("Local Conductor - Install hApp bundle and access cells with role ids", async (t) => {
const conductor = await createConductor();
const aliceHapp = await conductor.installHappBundle({
@@ -262,7 +286,9 @@ test("Local Conductor - Zome call can time out before completion", async (t) =>
const cell = aliceHapp.namedCells.get("test");
assert(cell);
- await t.rejects(cell.callZome({ fn_name: "create", zome_name: "crud" }, 1));
+ await t.rejects(
+ cell.callZome({ fn_name: "create", zome_name: "coordinator" }, 1)
+ );
await conductor.shutDown();
await cleanAllConductors();
@@ -298,7 +324,7 @@ test("Local Conductor - Create and read an entry using the entry zome", async (t
const createEntryHash: EntryHash = await conductor.appWs().callZome({
cap_secret: null,
cell_id,
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "create",
provenance: agentPubKey,
payload: entryContent,
@@ -312,7 +338,7 @@ test("Local Conductor - Create and read an entry using the entry zome", async (t
.callZome({
cap_secret: null,
cell_id,
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "read",
provenance: agentPubKey,
payload: createEntryHash,
@@ -328,15 +354,16 @@ test("Local Conductor - Create and read an entry using the entry zome, 2 conduct
const conductor1 = await createConductor();
const conductor2 = await createConductor();
- const [aliceHapps, bobHapps] = await conductor1.installAgentsHapps({
- agentsDnas: [dnas, dnas],
- });
+ const [aliceHapps, bobHapps] = await conductor1.installAgentsHapps([
+ dnas,
+ dnas,
+ ]);
await addAllAgentsToAllConductors([conductor1, conductor2]);
const entryContent = "test-content";
const createEntryHash: EntryHash = await aliceHapps.cells[0].callZome({
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "create",
payload: entryContent,
});
@@ -348,7 +375,7 @@ test("Local Conductor - Create and read an entry using the entry zome, 2 conduct
const readEntryResponse: typeof entryContent =
await bobHapps.cells[0].callZome({
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "read",
payload: createEntryHash,
});
@@ -370,13 +397,11 @@ test("Local Conductor - Receive a signal", async (t) => {
});
const conductor = await createConductor({ signalHandler, timeout: 30000 });
- const [aliceHapps] = await conductor.installAgentsHapps({
- agentsDnas: [dnas],
- });
+ const [aliceHapps] = await conductor.installAgentsHapps([dnas]);
const aliceSignal = { value: "signal" };
aliceHapps.cells[0].callZome({
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "signal_loopback",
payload: aliceSignal,
});
diff --git a/ts/test/local/scenario.ts b/ts/test/local/scenario.ts
index acd8dbfe..ec95f34d 100644
--- a/ts/test/local/scenario.ts
+++ b/ts/test/local/scenario.ts
@@ -6,6 +6,7 @@ import {
} from "@holochain/client";
import test from "tape-promise/tape.js";
import { runScenario, Scenario } from "../../src/local/scenario.js";
+import { Dna } from "../../src/types.js";
import { pause } from "../../src/util.js";
import { FIXTURE_DNA_URL, FIXTURE_HAPP_URL } from "../fixture/index.js";
@@ -20,8 +21,8 @@ test("Local Scenario - runScenario - Install hApp bundle and access cells throug
test("Local Scenario - runScenario - Catch error when calling non-existent zome", async (t) => {
await runScenario(async (scenario: Scenario) => {
- const alice = await scenario.addPlayerWithHapp([
- { path: FIXTURE_DNA_URL.pathname },
+ const [alice] = await scenario.addPlayersWithHapps([
+ [{ path: FIXTURE_DNA_URL.pathname }],
]);
await t.rejects(
@@ -35,8 +36,8 @@ test("Local Scenario - runScenario - Catch error when calling non-existent zome"
test("Local Scenario - runScenario - Catch error when attaching a protected port", async (t) => {
await runScenario(async (scenario: Scenario) => {
- const alice = await scenario.addPlayerWithHapp([
- { path: FIXTURE_DNA_URL.pathname },
+ const [alice] = await scenario.addPlayersWithHapps([
+ [{ path: FIXTURE_DNA_URL.pathname }],
]);
await t.rejects(alice.conductor.attachAppInterface({ port: 300 }));
@@ -45,8 +46,8 @@ test("Local Scenario - runScenario - Catch error when attaching a protected port
test("Local Scenario - runScenario - Catch error when calling a zome of an undefined cell", async (t) => {
await runScenario(async (scenario: Scenario) => {
- const alice = await scenario.addPlayerWithHapp([
- { path: FIXTURE_DNA_URL.pathname },
+ const [alice] = await scenario.addPlayersWithHapps([
+ [{ path: FIXTURE_DNA_URL.pathname }],
]);
t.throws(() => alice.cells[2].callZome({ zome_name: "", fn_name: "" }));
@@ -64,14 +65,14 @@ test("Local Scenario - runScenario - Catch error that occurs in a signal handler
const [alice] = await scenario.addPlayersWithHapps([
{
- dnas: [{ path: FIXTURE_DNA_URL.pathname }],
+ dnas: [{ source: { path: FIXTURE_DNA_URL.pathname } }],
signalHandler: signalHandlerAlice,
},
]);
const signalAlice = { value: "hello alice" };
alice.cells[0].callZome({
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "signal_loopback",
payload: signalAlice,
});
@@ -114,7 +115,7 @@ test("Local Scenario - Create and read an entry, 2 conductors", async (t) => {
const content = "Hi dare";
const createEntryHash = await alice.cells[0].callZome({
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "create",
payload: content,
});
@@ -122,7 +123,7 @@ test("Local Scenario - Create and read an entry, 2 conductors", async (t) => {
await pause(100);
const readContent = await bob.cells[0].callZome({
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "read",
payload: createEntryHash,
});
@@ -142,7 +143,7 @@ test("Local Scenario - Conductor maintains data after shutdown and restart", asy
const content = "Before shutdown";
const createEntryHash = await alice.cells[0].callZome({
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "create",
payload: content,
});
@@ -150,7 +151,7 @@ test("Local Scenario - Conductor maintains data after shutdown and restart", asy
await pause(100);
const readContent = await bob.cells[0].callZome({
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "read",
payload: createEntryHash,
});
@@ -162,7 +163,7 @@ test("Local Scenario - Conductor maintains data after shutdown and restart", asy
await bob.conductor.startUp();
await bob.conductor.connectAppInterface();
const readContentAfterRestart = await bob.cells[0].callZome({
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "read",
payload: createEntryHash,
});
@@ -173,7 +174,7 @@ test("Local Scenario - Conductor maintains data after shutdown and restart", asy
test("Local Scenario - Receive signals with 2 conductors", async (t) => {
const scenario = new Scenario();
- const dnas: DnaSource[] = [{ path: FIXTURE_DNA_URL.pathname }];
+ const dnas: Dna[] = [{ source: { path: FIXTURE_DNA_URL.pathname } }];
let signalHandlerAlice: AppSignalCb | undefined;
const signalReceivedAlice = new Promise((resolve) => {
@@ -196,13 +197,13 @@ test("Local Scenario - Receive signals with 2 conductors", async (t) => {
const signalAlice = { value: "hello alice" };
alice.cells[0].callZome({
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "signal_loopback",
payload: signalAlice,
});
const signalBob = { value: "hello bob" };
bob.cells[0].callZome({
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "signal_loopback",
payload: signalBob,
});
diff --git a/ts/test/trycp/server.ts b/ts/test/trycp/client.ts
similarity index 78%
rename from ts/test/trycp/server.ts
rename to ts/test/trycp/client.ts
index 5e91ff22..b3746060 100644
--- a/ts/test/trycp/server.ts
+++ b/ts/test/trycp/client.ts
@@ -1,8 +1,7 @@
import { Buffer } from "node:buffer";
-import test from "tape-promise/tape.js";
import { URL } from "node:url";
+import test from "tape-promise/tape.js";
import {
- cleanAllTryCpConductors,
createTryCpConductor,
DEFAULT_PARTIAL_PLAYER_CONFIG,
} from "../../src/trycp/index.js";
@@ -30,7 +29,7 @@ test("TryCP Server - Ping", async (t) => {
await localTryCpServer.stop();
});
-test("TryCP Server - Non-existent call throws", async (t) => {
+test("TryCP Server - non-existent call throws", async (t) => {
const localTryCpServer = await TryCpServer.start();
const tryCpClient = await createTryCpClient();
@@ -47,7 +46,7 @@ test("TryCP Server - Non-existent call throws", async (t) => {
await localTryCpServer.stop();
});
-test("TryCP Server - Download DNA from web", async (t) => {
+test("TryCP Server - download DNA from web", async (t) => {
const localTryCpServer = await TryCpServer.start();
const tryCpClient = await createTryCpClient();
@@ -64,7 +63,7 @@ test("TryCP Server - Download DNA from web", async (t) => {
await localTryCpServer.stop();
});
-test("TryCP Server - Download DNA from file system", async (t) => {
+test("TryCP Server - download DNA from file system", async (t) => {
const localTryCpServer = await TryCpServer.start();
const tryCpClient = await createTryCpClient();
@@ -80,7 +79,7 @@ test("TryCP Server - Download DNA from file system", async (t) => {
await localTryCpServer.stop();
});
-test("TryCP Server - Save DNA to file system", async (t) => {
+test("TryCP Server - save DNA to file system", async (t) => {
const localTryCpServer = await TryCpServer.start();
const tryCpClient = await createTryCpClient();
@@ -96,7 +95,7 @@ test("TryCP Server - Save DNA to file system", async (t) => {
await localTryCpServer.stop();
});
-test("TryCP Server - Configure player", async (t) => {
+test("TryCP Server - configure player", async (t) => {
const localTryCpServer = await TryCpServer.start();
const tryCpClient = await createTryCpClient();
@@ -161,7 +160,7 @@ test("TryCP Server - 2 parallel calls from two clients return correct responses"
await localTryCpServer.stop();
});
-test("TryCP Server - Startup and shutdown", async (t) => {
+test("TryCP Server - startup and shutdown", async (t) => {
const localTryCpServer = await TryCpServer.start();
const tryCpClient = await createTryCpClient();
@@ -187,7 +186,7 @@ test("TryCP Server - Startup and shutdown", async (t) => {
await localTryCpServer.stop();
});
-test("TryCP Server - Reset", async (t) => {
+test("TryCP Server - reset", async (t) => {
const localTryCpServer = await TryCpServer.start();
const tryCpClient = await createTryCpClient();
@@ -216,16 +215,46 @@ test("TryCP Server - Reset", async (t) => {
await localTryCpServer.stop();
});
-test("TryCP Server - Clean all conductors", async (t) => {
+test("TryCP Server - clean all conductors", async (t) => {
const localTryCpServer = await TryCpServer.start();
- const actual = await cleanAllTryCpConductors(SERVER_URL);
+ const tryCpClient = await createTryCpClient();
+ const actual = await tryCpClient.cleanAllConductors();
t.equal(actual, TRYCP_SUCCESS_RESPONSE);
+ await tryCpClient.close();
await localTryCpServer.stop();
});
-test("TryCP Server - Admin API - Connect app interface", async (t) => {
+test("TryCP Client - shut down", async (t) => {
const localTryCpServer = await TryCpServer.start();
- const conductor = await createTryCpConductor(SERVER_URL);
+ const client = await createTryCpClient();
+ const conductor1 = await client.addConductor();
+ const conductor2 = await client.addConductor();
+ const conductor3 = await client.addConductor();
+ t.doesNotReject(
+ conductor1.adminWs().generateAgentPubKey,
+ "conductor 1 responds"
+ );
+ t.doesNotReject(
+ conductor2.adminWs().generateAgentPubKey,
+ "conductor 2 responds"
+ );
+ t.doesNotReject(
+ conductor3.adminWs().generateAgentPubKey,
+ "conductor 3 responds"
+ );
+ await client.shutDownConductors();
+ t.rejects(conductor1.adminWs().generateAgentPubKey, "conductor 1 is down");
+ t.rejects(conductor2.adminWs().generateAgentPubKey, "conductor 2 is down");
+ t.rejects(conductor3.adminWs().generateAgentPubKey, "conductor 3 is down");
+
+ await client.cleanUp();
+ await localTryCpServer.stop();
+});
+
+test("TryCP Server - Admin API - connect app interface", async (t) => {
+ const localTryCpServer = await TryCpServer.start();
+ const tryCpClient = await createTryCpClient();
+ const conductor = await createTryCpConductor(tryCpClient);
const { port } = await conductor.adminWs().attachAppInterface();
t.ok(typeof port === "number");
@@ -247,12 +276,13 @@ test("TryCP Server - Admin API - Connect app interface", async (t) => {
await localTryCpServer.stop();
});
-test("TryCP Server - App API - Get app info", async (t) => {
+test("TryCP Server - App API - get app info", async (t) => {
const localTryCpServer = await TryCpServer.start();
- const conductor = await createTryCpConductor(SERVER_URL);
- const [alice] = await conductor.installAgentsHapps({
- agentsDnas: [[{ path: FIXTURE_DNA_URL.pathname }]],
- });
+ const tryCpClient = await createTryCpClient();
+ const conductor = await createTryCpConductor(tryCpClient);
+ const [alice] = await conductor.installAgentsHapps([
+ [{ path: FIXTURE_DNA_URL.pathname }],
+ ]);
await conductor.adminWs().attachAppInterface();
await conductor.connectAppInterface();
diff --git a/ts/test/trycp/conductor.ts b/ts/test/trycp/conductor.ts
index 553ccc1c..784cd314 100644
--- a/ts/test/trycp/conductor.ts
+++ b/ts/test/trycp/conductor.ts
@@ -1,10 +1,10 @@
import { AppSignal, DnaSource, EntryHash } from "@holochain/client";
import { Buffer } from "node:buffer";
-import test from "tape-promise/tape.js";
import { URL } from "node:url";
+import test from "tape-promise/tape.js";
import { addAllAgentsToAllConductors } from "../../src/common.js";
+import { Dna, TryCpClient } from "../../src/index.js";
import {
- cleanAllTryCpConductors,
createTryCpConductor,
TryCpConductorOptions,
} from "../../src/trycp/conductor/index.js";
@@ -27,53 +27,81 @@ network:
- type: quic
network_type: quic_mdns`;
-const createTestTryCpConductor = (options?: TryCpConductorOptions) =>
- createTryCpConductor(SERVER_URL, {
+const createTestConductor = (
+ client: TryCpClient,
+ options?: TryCpConductorOptions
+) =>
+ createTryCpConductor(client, {
partialConfig: LOCAL_TEST_PARTIAL_CONFIG,
...options,
});
-test("TryCP Conductor - Stop and restart a conductor", async (t) => {
+test("TryCP Conductor - stop and restart a conductor", async (t) => {
const localTryCpServer = await TryCpServer.start();
- const conductor = await createTestTryCpConductor({ timeout: 30000 });
+ const client = await TryCpClient.create(SERVER_URL, 60000);
+ const conductor = await createTestConductor(client);
const agentPubKeyResponse = await conductor.adminWs().generateAgentPubKey();
- t.ok(agentPubKeyResponse);
+ t.ok(agentPubKeyResponse, "agent pub key generated before shutdown");
await conductor.shutDown();
- await t.rejects(conductor.adminWs().generateAgentPubKey);
+ await t.rejects(
+ conductor.adminWs().generateAgentPubKey,
+ "conductor rejects request after shutdown"
+ );
await conductor.startUp({});
const agentPubKeyResponse2 = await conductor.adminWs().generateAgentPubKey();
- t.ok(agentPubKeyResponse2);
+ t.ok(agentPubKeyResponse2, "agent pub key generated after restart");
- await conductor.shutDown();
- await conductor.disconnectClient();
- await cleanAllTryCpConductors(SERVER_URL);
+ await client.cleanUp();
await localTryCpServer.stop();
});
-test("TryCP Conductor - Install hApp bundle and access cells with role ids", async (t) => {
+test("TryCP Conductor - provide agent pub keys when installing hApp", async (t) => {
const localTryCpServer = await TryCpServer.start();
- const conductor = await createTestTryCpConductor();
+ const client = await TryCpClient.create(SERVER_URL, 60000);
+ const conductor = await createTestConductor(client);
+
+ const agentPubKey = await conductor.adminWs().generateAgentPubKey();
+ t.ok(agentPubKey, "agent pub key generated");
+
+ const [alice] = await conductor.installAgentsHapps({
+ agentsDnas: [
+ { dnas: [{ source: { path: FIXTURE_DNA_URL.pathname } }], agentPubKey },
+ ],
+ });
+ t.deepEqual(
+ alice.agentPubKey,
+ agentPubKey,
+ "alice's agent pub key matches provided key"
+ );
+
+ await client.cleanUp();
+ await localTryCpServer.stop();
+});
+
+test("TryCP Conductor - install hApp bundle and access cells with role ids", async (t) => {
+ const localTryCpServer = await TryCpServer.start();
+ const client = await TryCpClient.create(SERVER_URL, 60000);
+ const conductor = await createTestConductor(client);
const aliceHapp = await conductor.installHappBundle({
path: FIXTURE_HAPP_URL.pathname,
});
- t.ok(aliceHapp.namedCells.get("test"));
+ t.ok(aliceHapp.namedCells.get("test"), "named cell can be accessed");
- await conductor.shutDown();
- await conductor.disconnectClient();
- await cleanAllTryCpConductors(SERVER_URL);
+ await client.cleanUp();
await localTryCpServer.stop();
});
-test("TryCP Conductor - Install and call a hApp bundle", async (t) => {
+test("TryCP Conductor - install and call a hApp bundle", async (t) => {
const localTryCpServer = await TryCpServer.start();
- const conductor = await createTestTryCpConductor();
+ const client = await TryCpClient.create(SERVER_URL, 60000);
+ const conductor = await createTestConductor(client);
const installedHappBundle = await conductor.installHappBundle({
path: FIXTURE_HAPP_URL.pathname,
});
- t.ok(installedHappBundle.happId);
+ t.ok(installedHappBundle.happId, "installed hApp bundle has a hApp id");
await conductor.adminWs().attachAppInterface();
await conductor.connectAppInterface();
@@ -81,27 +109,32 @@ test("TryCP Conductor - Install and call a hApp bundle", async (t) => {
const entryContent = "Bye bye, world";
const createEntryResponse: EntryHash =
await installedHappBundle.cells[0].callZome({
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "create",
payload: entryContent,
});
- t.ok(createEntryResponse);
+ t.ok(createEntryResponse, "entry created successfully");
const readEntryResponse: typeof entryContent =
await installedHappBundle.cells[0].callZome({
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "read",
payload: createEntryResponse,
});
- t.equal(readEntryResponse, entryContent);
+ t.equal(
+ readEntryResponse,
+ entryContent,
+ "read entry content matches created entry content"
+ );
- await conductor.shutDown();
- await conductor.disconnectClient();
- await cleanAllTryCpConductors(SERVER_URL);
+ await client.cleanUp();
await localTryCpServer.stop();
});
-test("TryCP Conductor - Receive a signal", async (t) => {
+test("TryCP Conductor - receive a signal", async (t) => {
const localTryCpServer = await TryCpServer.start();
+ const client = await TryCpClient.create(SERVER_URL, 30000);
+ const conductor = await createTestConductor(client);
+
const testSignal = { value: "signal" };
let signalHandler;
@@ -111,7 +144,6 @@ test("TryCP Conductor - Receive a signal", async (t) => {
};
});
- const conductor = await createTestTryCpConductor({ timeout: 30000 });
const agentPubKey = await conductor.adminWs().generateAgentPubKey();
const installedAppBundle = await conductor.adminWs().installAppBundle({
agent_key: agentPubKey,
@@ -127,34 +159,37 @@ test("TryCP Conductor - Receive a signal", async (t) => {
conductor.appWs().callZome({
cap_secret: null,
cell_id: installedAppBundle.cell_data[0].cell_id,
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "signal_loopback",
provenance: agentPubKey,
payload: testSignal,
});
const actualSignal = await signalReceived;
- t.deepEqual(actualSignal.data.payload, testSignal);
+ t.deepEqual(
+ actualSignal.data.payload,
+ testSignal,
+ "received signal matches expected signal"
+ );
- await conductor.shutDown();
- await conductor.disconnectClient();
- await cleanAllTryCpConductors(SERVER_URL);
+ await client.cleanUp();
await localTryCpServer.stop();
});
-test("TryCP Conductor - Create and read an entry using the entry zome", async (t) => {
+test("TryCP Conductor - create and read an entry using the entry zome", async (t) => {
const localTryCpServer = await TryCpServer.start();
- const conductor = await createTestTryCpConductor();
+ const client = await TryCpClient.create(SERVER_URL, 60000);
+ const conductor = await createTestConductor(client);
const relativePath = await conductor.downloadDna(FIXTURE_DNA_URL);
const dnaHash = await conductor.adminWs().registerDna({ path: relativePath });
const dnaHashB64 = Buffer.from(dnaHash).toString("base64");
- t.equal(dnaHash.length, 39);
- t.ok(dnaHashB64.startsWith("hC0k"));
+ t.equal(dnaHash.length, 39, "DNA hash is 39 bytes long");
+ t.ok(dnaHashB64.startsWith("hC0k"), "DNA hash starts with hC0k");
const agentPubKey = await conductor.adminWs().generateAgentPubKey();
const agentPubKeyB64 = Buffer.from(agentPubKey).toString("base64");
- t.equal(agentPubKey.length, 39);
- t.ok(agentPubKeyB64.startsWith("hCAk"));
+ t.equal(agentPubKey.length, 39, "agent pub key is 39 bytes long");
+ t.ok(agentPubKeyB64.startsWith("hCAk"), "agent pub key starts with hCAk");
const appId = "entry-app";
const installedAppInfo = await conductor.adminWs().installApp({
@@ -163,81 +198,102 @@ test("TryCP Conductor - Create and read an entry using the entry zome", async (t
dnas: [{ hash: dnaHash, role_id: "entry-dna" }],
});
const { cell_id } = installedAppInfo.cell_data[0];
- t.ok(Buffer.from(cell_id[0]).toString("base64").startsWith("hC0k"));
- t.ok(Buffer.from(cell_id[1]).toString("base64").startsWith("hCAk"));
+ t.ok(
+ Buffer.from(cell_id[0]).toString("base64").startsWith("hC0k"),
+ "first part of cell id start with hC0k"
+ );
+ t.ok(
+ Buffer.from(cell_id[1]).toString("base64").startsWith("hCAk"),
+ "second part of cell id starts with hC0k"
+ );
const enabledAppResponse = await conductor.adminWs().enableApp({
installed_app_id: appId,
});
- t.deepEqual(enabledAppResponse.app.status, { running: null });
+ t.deepEqual(
+ enabledAppResponse.app.status,
+ { running: null },
+ "enabled app response matches 'running'"
+ );
await conductor.adminWs().attachAppInterface();
const connectAppInterfaceResponse = await conductor.connectAppInterface();
- t.equal(connectAppInterfaceResponse, TRYCP_SUCCESS_RESPONSE);
+ t.equal(
+ connectAppInterfaceResponse,
+ TRYCP_SUCCESS_RESPONSE,
+ "connected app interface responds with success"
+ );
const entryContent = "test-content";
const createEntryHash = await conductor.appWs().callZome({
cap_secret: null,
cell_id,
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "create",
provenance: agentPubKey,
payload: entryContent,
});
const createdEntryHashB64 = Buffer.from(createEntryHash).toString("base64");
- t.equal(createEntryHash.length, 39);
- t.ok(createdEntryHashB64.startsWith("hCkk"));
+ t.equal(createEntryHash.length, 39, "created entry hash is 39 bytes long");
+ t.ok(
+ createdEntryHashB64.startsWith("hCkk"),
+ "created entry hash starts with hCkk"
+ );
const readEntryResponse = await conductor
.appWs()
.callZome({
cap_secret: null,
cell_id,
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "read",
provenance: agentPubKey,
payload: createEntryHash,
});
- t.equal(readEntryResponse, entryContent);
+ t.equal(
+ readEntryResponse,
+ entryContent,
+ "read entry content matches created entry content"
+ );
const disconnectAppInterfaceResponse =
await conductor.disconnectAppInterface();
- t.equal(disconnectAppInterfaceResponse, TRYCP_SUCCESS_RESPONSE);
+ t.equal(
+ disconnectAppInterfaceResponse,
+ TRYCP_SUCCESS_RESPONSE,
+ "disconnect app interface responds with success"
+ );
- await conductor.shutDown();
- await conductor.disconnectClient();
- await cleanAllTryCpConductors(SERVER_URL);
+ await client.cleanUp();
await localTryCpServer.stop();
});
-test("TryCP Conductor - Reading a non-existent entry returns null", async (t) => {
+test("TryCP Conductor - reading a non-existent entry returns null", async (t) => {
const localTryCpServer = await TryCpServer.start();
- const conductor = await createTestTryCpConductor();
+ const client = await TryCpClient.create(SERVER_URL, 60000);
+ const conductor = await createTestConductor(client);
const dnas = [{ path: FIXTURE_DNA_URL.pathname }];
- const [alice_happs] = await conductor.installAgentsHapps({
- agentsDnas: [dnas],
- });
+ const [alice_happs] = await conductor.installAgentsHapps([dnas]);
await conductor.adminWs().attachAppInterface();
await conductor.connectAppInterface();
const actual = await alice_happs.cells[0].callZome({
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "read",
provenance: alice_happs.agentPubKey,
payload: Buffer.from("hCkk", "base64"),
});
- t.equal(actual, null);
+ t.equal(actual, null, "read a non-existing entry returns null");
- await conductor.shutDown();
- await conductor.disconnectClient();
- await cleanAllTryCpConductors(SERVER_URL);
+ await client.cleanUp();
await localTryCpServer.stop();
});
-test("TryCP Conductor - Create and read an entry using the entry zome, 1 conductor, 2 cells, 2 agents", async (t) => {
+test("TryCP Conductor - create and read an entry using the entry zome, 1 conductor, 2 cells, 2 agents", async (t) => {
const localTryCpServer = await TryCpServer.start();
- const conductor = await createTestTryCpConductor();
+ const client = await TryCpClient.create(SERVER_URL, 60000);
+ const conductor = await createTestConductor(client);
const relativePath = await conductor.downloadDna(FIXTURE_DNA_URL);
const dnaHash1 = await conductor
@@ -248,20 +304,20 @@ test("TryCP Conductor - Create and read an entry using the entry zome, 1 conduct
.registerDna({ path: relativePath });
const dnaHash1B64 = Buffer.from(dnaHash1).toString("base64");
const dnaHash2B64 = Buffer.from(dnaHash1).toString("base64");
- t.equal(dnaHash1.length, 39);
- t.ok(dnaHash1B64.startsWith("hC0k"));
- t.equal(dnaHash2.length, 39);
- t.ok(dnaHash2B64.startsWith("hC0k"));
+ t.equal(dnaHash1.length, 39, "DNA hash 1 is 39 bytes long");
+ t.ok(dnaHash1B64.startsWith("hC0k"), "DNA hash 1 starts with hC0k");
+ t.equal(dnaHash2.length, 39, "DNA hash 2 is 39 bytes long");
+ t.ok(dnaHash2B64.startsWith("hC0k"), "DNA hash 2 starts with hC0k");
const agent1PubKey = await conductor.adminWs().generateAgentPubKey();
const agent1PubKeyB64 = Buffer.from(agent1PubKey).toString("base64");
- t.equal(agent1PubKey.length, 39);
- t.ok(agent1PubKeyB64.startsWith("hCAk"));
+ t.equal(agent1PubKey.length, 39), "agent pub key 1 is 39 bytes long";
+ t.ok(agent1PubKeyB64.startsWith("hCAk"), "agent pub key 1 starts with hCAk");
const agent2PubKey = await conductor.adminWs().generateAgentPubKey();
const agent2PubKeyB64 = Buffer.from(agent1PubKey).toString("base64");
- t.equal(agent2PubKey.length, 39);
- t.ok(agent2PubKeyB64.startsWith("hCAk"));
+ t.equal(agent2PubKey.length, 39, "agent pub key 2 is 39 bytes long");
+ t.ok(agent2PubKeyB64.startsWith("hCAk"), "agent pub key 2 starts with hCAk");
const appId1 = "entry-app1";
const installedAppInfo1 = await conductor.adminWs().installApp({
@@ -270,8 +326,14 @@ test("TryCP Conductor - Create and read an entry using the entry zome, 1 conduct
dnas: [{ hash: dnaHash1, role_id: "entry-dna" }],
});
const cellId1 = installedAppInfo1.cell_data[0].cell_id;
- t.ok(Buffer.from(cellId1[0]).toString("base64").startsWith("hC0k"));
- t.ok(Buffer.from(cellId1[1]).toString("base64").startsWith("hCAk"));
+ t.ok(
+ Buffer.from(cellId1[0]).toString("base64").startsWith("hC0k"),
+ "first part of cell id 1 starts with hC0k"
+ );
+ t.ok(
+ Buffer.from(cellId1[1]).toString("base64").startsWith("hCAk"),
+ "second part of cell id 1 starts with hCAk"
+ );
const appId2 = "entry-app2";
const installedAppInfo2 = await conductor.adminWs().installApp({
@@ -280,83 +342,114 @@ test("TryCP Conductor - Create and read an entry using the entry zome, 1 conduct
dnas: [{ hash: dnaHash2, role_id: "entry-dna" }],
});
const cellId2 = installedAppInfo2.cell_data[0].cell_id;
- t.ok(Buffer.from(cellId2[0]).toString("base64").startsWith("hC0k"));
- t.ok(Buffer.from(cellId2[1]).toString("base64").startsWith("hCAk"));
- t.deepEqual(cellId1[0], cellId2[0]);
+ t.ok(
+ Buffer.from(cellId2[0]).toString("base64").startsWith("hC0k"),
+ "first part of cell id 2 starts with hC0k"
+ );
+ t.ok(
+ Buffer.from(cellId2[1]).toString("base64").startsWith("hCAk"),
+ "second part of cell id 2 starts with hCAk"
+ );
+ t.deepEqual(
+ cellId1[0],
+ cellId2[0],
+ "DNA hash of cell 1 matches DNA has of cell 2"
+ );
const enabledAppResponse1 = await conductor.adminWs().enableApp({
installed_app_id: appId1,
});
- t.deepEqual(enabledAppResponse1.app.status, { running: null });
+ t.deepEqual(
+ enabledAppResponse1.app.status,
+ { running: null },
+ "enabled app response 1 matches 'running'"
+ );
const enabledAppResponse2 = await conductor.adminWs().enableApp({
installed_app_id: appId2,
});
- t.deepEqual(enabledAppResponse2.app.status, { running: null });
+ t.deepEqual(
+ enabledAppResponse2.app.status,
+ { running: null },
+ "enabled app response 2 matches 'running'"
+ );
await conductor.adminWs().attachAppInterface();
const connectAppInterfaceResponse = await conductor.connectAppInterface();
- t.equal(connectAppInterfaceResponse, TRYCP_SUCCESS_RESPONSE);
+ t.equal(
+ connectAppInterfaceResponse,
+ TRYCP_SUCCESS_RESPONSE,
+ "connect app interface responds with success"
+ );
const entryContent = "test-content";
const createEntryHash = await conductor.appWs().callZome({
cap_secret: null,
cell_id: cellId1,
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "create",
provenance: agent1PubKey,
payload: entryContent,
});
const createdEntryHashB64 = Buffer.from(createEntryHash).toString("base64");
- t.equal(createEntryHash.length, 39);
- t.ok(createdEntryHashB64.startsWith("hCkk"));
+ t.equal(createEntryHash.length, 39, "created entry hash is 39 bytes long");
+ t.ok(
+ createdEntryHashB64.startsWith("hCkk"),
+ "created entry hash starts with hCkk"
+ );
const readEntryResponse = await conductor
.appWs()
.callZome({
cap_secret: null,
cell_id: cellId2,
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "read",
provenance: agent2PubKey,
payload: createEntryHash,
});
- t.equal(readEntryResponse, entryContent);
+ t.equal(
+ readEntryResponse,
+ entryContent,
+ "read entry content matches created entry content"
+ );
- await conductor.shutDown();
- await conductor.disconnectClient();
- await cleanAllTryCpConductors(SERVER_URL);
+ await client.cleanUp();
await localTryCpServer.stop();
});
-test("TryCP Conductor - Create and read an entry using the entry zome, 2 conductors, 2 cells, 2 agents", async (t) => {
+test("TryCP Conductor - create and read an entry using the entry zome, 2 conductors, 2 cells, 2 agents", async (t) => {
const localTryCpServer = await TryCpServer.start();
+ const client = await TryCpClient.create(SERVER_URL, 60000);
const dnas: DnaSource[] = [{ path: FIXTURE_DNA_URL.pathname }];
- const conductor1 = await createTestTryCpConductor();
- const [alice] = await conductor1.installAgentsHapps({ agentsDnas: [dnas] });
+ const conductor1 = await createTestConductor(client);
+ const [alice] = await conductor1.installAgentsHapps([dnas]);
await conductor1.adminWs().attachAppInterface();
await conductor1.connectAppInterface();
- const conductor2 = await createTestTryCpConductor();
- const [bob] = await conductor2.installAgentsHapps({ agentsDnas: [dnas] });
+ const conductor2 = await createTestConductor(client);
+ const [bob] = await conductor2.installAgentsHapps([dnas]);
await conductor2.adminWs().attachAppInterface();
await conductor2.connectAppInterface();
await addAllAgentsToAllConductors([conductor1, conductor2]);
const entryContent = "test-content";
- const createEntry1Hash = await conductor1.appWs().callZome({
+ const createEntryHash = await conductor1.appWs().callZome({
cap_secret: null,
cell_id: alice.cells[0].cell_id,
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "create",
provenance: alice.agentPubKey,
payload: entryContent,
});
- const createdEntry1HashB64 = Buffer.from(createEntry1Hash).toString("base64");
- t.equal(createEntry1Hash.length, 39);
- t.ok(createdEntry1HashB64.startsWith("hCkk"));
+ const createdEntryHashB64 = Buffer.from(createEntryHash).toString("base64");
+ t.equal(createEntryHash.length, 39, "create entry hash is 39 bytes long");
+ t.ok(
+ createdEntryHashB64.startsWith("hCkk"),
+ "create entry hash starts with hCkk"
+ );
await pause(2000);
@@ -365,17 +458,40 @@ test("TryCP Conductor - Create and read an entry using the entry zome, 2 conduct
.callZome({
cap_secret: null,
cell_id: bob.cells[0].cell_id,
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "read",
provenance: bob.agentPubKey,
- payload: createEntry1Hash,
+ payload: createEntryHash,
});
- t.equal(readEntryResponse, entryContent);
+ t.equal(
+ readEntryResponse,
+ entryContent,
+ "read entry content matches created entry content"
+ );
- await conductor1.shutDown();
- await conductor1.disconnectClient();
- await conductor2.shutDown();
- await conductor2.disconnectClient();
- await cleanAllTryCpConductors(SERVER_URL);
+ await client.cleanUp();
+ await localTryCpServer.stop();
+});
+
+test("TryCP Conductor - pass a custom application id to happ installation", async (t) => {
+ const localTryCpServer = await TryCpServer.start();
+ const client = await TryCpClient.create(SERVER_URL, 60000);
+
+ const dnas: Dna[] = [{ source: { path: FIXTURE_DNA_URL.pathname } }];
+
+ const conductor1 = await createTestConductor(client);
+ const expectedInstalledAppId = "test-app-id";
+ const [alice] = await conductor1.installAgentsHapps({
+ agentsDnas: [{ dnas }],
+ installedAppId: expectedInstalledAppId,
+ });
+ const actualInstalledAppId = alice.happId;
+ t.equal(
+ actualInstalledAppId,
+ expectedInstalledAppId,
+ "installed app id matches"
+ );
+
+ await client.cleanUp();
await localTryCpServer.stop();
});
diff --git a/ts/test/trycp/index.ts b/ts/test/trycp/index.ts
index 8a8bdf9a..aa5d025d 100644
--- a/ts/test/trycp/index.ts
+++ b/ts/test/trycp/index.ts
@@ -1,3 +1,3 @@
export * from "./conductor.js";
-export * from "./server.js";
+export * from "./client.js";
export * from "./scenario.js";
diff --git a/ts/test/trycp/scenario.ts b/ts/test/trycp/scenario.ts
index 9a3db37d..ed657f4b 100644
--- a/ts/test/trycp/scenario.ts
+++ b/ts/test/trycp/scenario.ts
@@ -1,13 +1,10 @@
-import {
- AppSignal,
- AppSignalCb,
- DnaSource,
- EntryHash,
-} from "@holochain/client";
+import { AppSignal, AppSignalCb, EntryHash } from "@holochain/client";
import test from "tape-promise/tape.js";
import { URL } from "node:url";
+import { Dna } from "../../src/types.js";
import { TryCpScenario } from "../../src/trycp/conductor/scenario.js";
import {
+ TryCpServer,
TRYCP_SERVER_HOST,
TRYCP_SERVER_PORT,
} from "../../src/trycp/trycp-server.js";
@@ -16,31 +13,122 @@ import { FIXTURE_DNA_URL } from "../fixture/index.js";
const SERVER_URL = new URL(`ws://${TRYCP_SERVER_HOST}:${TRYCP_SERVER_PORT}`);
-test("TryCP Scenario - List everything", async (t) => {
- const scenario = await TryCpScenario.create(SERVER_URL);
- const alice = await scenario.addPlayerWithHapp([
+test("TryCP Scenario - create a conductor", async (t) => {
+ const tryCpServer = await TryCpServer.start();
+
+ const scenario = new TryCpScenario();
+ const client = await scenario.addClient(SERVER_URL);
+ t.ok(client, "client set up");
+
+ const conductor = await client.addConductor();
+ t.ok(conductor.adminWs() && conductor.appWs(), "conductor set up");
+
+ await scenario.cleanUp();
+ await tryCpServer.stop();
+});
+
+test("TryCP Scenario - install a hApp to 1 conductor with 1 agent", async (t) => {
+ const tryCpServer = await TryCpServer.start();
+
+ const scenario = new TryCpScenario();
+ const client = await scenario.addClient(SERVER_URL);
+ t.ok(client, "client set up");
+
+ const alice = await scenario.addPlayerWithHapp(client, {
+ dnas: [{ source: { path: FIXTURE_DNA_URL.pathname } }],
+ });
+ t.ok(alice.conductor, "player alice is associated with a conductor");
+ t.equal(
+ alice.conductor.tryCpClient,
+ client,
+ "player alice's conductor is associated with the right client"
+ );
+
+ await scenario.cleanUp();
+ await tryCpServer.stop();
+});
+
+test("TryCP Scenario - install a hApp to 2 conductors with 1 agent each", async (t) => {
+ const serverPort1 = TRYCP_SERVER_PORT;
+ const serverPort2 = TRYCP_SERVER_PORT + 1;
+ const serverUrl1 = new URL(`ws://${TRYCP_SERVER_HOST}:${serverPort1}`);
+ const serverUrl2 = new URL(`ws://${TRYCP_SERVER_HOST}:${serverPort2}`);
+ const tryCpServer1 = await TryCpServer.start(serverPort1);
+ const tryCpServer2 = await TryCpServer.start(serverPort2);
+
+ const scenario = new TryCpScenario();
+ const client1 = await scenario.addClient(serverUrl1);
+ const client2 = await scenario.addClient(serverUrl2);
+ t.ok(client1, "client 1 set up");
+ t.ok(client2, "client 2 set up");
+
+ const alice = await scenario.addPlayerWithHapp(client1, {
+ dnas: [{ source: { path: FIXTURE_DNA_URL.pathname } }],
+ });
+ t.equal(
+ alice.conductor.tryCpClient,
+ client1,
+ "player alice's conductor is associated with client 1"
+ );
+ t.ok(
+ client1.conductors.find((conductor) => conductor === alice.conductor),
+ "client 1 conductors includes alice's conductor"
+ );
+
+ const bob = await scenario.addPlayerWithHapp(client2, {
+ dnas: [{ source: { path: FIXTURE_DNA_URL.pathname } }],
+ });
+ t.equal(
+ bob.conductor.tryCpClient,
+ client2,
+ "player bob's conductor is associated with client 2"
+ );
+ t.ok(
+ client2.conductors.find((conductor) => conductor === bob.conductor),
+ "client 2 conductors includes bob's conductor"
+ );
+
+ await scenario.cleanUp();
+ await tryCpServer1.stop();
+ await tryCpServer2.stop();
+});
+
+test("TryCP Scenario - list everything", async (t) => {
+ const tryCpServer = await TryCpServer.start();
+
+ const scenario = new TryCpScenario();
+ const client = await scenario.addClient(SERVER_URL);
+
+ const alice = await scenario.addPlayerWithHapp(client, [
{ path: FIXTURE_DNA_URL.pathname },
]);
const listedApps = await alice.conductor.adminWs().listApps({});
- t.equal(listedApps.length, 1);
+ t.ok(listedApps.length === 1, "alice's conductor lists 1 installed app");
const listedAppInterfaces = await alice.conductor
.adminWs()
.listAppInterfaces();
- t.equal(listedAppInterfaces.length, 1);
+ t.ok(
+ listedAppInterfaces.length === 1,
+ "alice's conductor lists 1 app interface"
+ );
const listCellIds = await alice.conductor.adminWs().listCellIds();
- t.equal(listCellIds.length, 1);
+ t.ok(listCellIds.length === 1, "alice's conductor lists 1 cell id");
const listedDnas = await alice.conductor.adminWs().listDnas();
- t.equal(listedDnas.length, 1);
+ t.ok(listedDnas.length === 1, "alice's conductor lists 1 DNA");
await scenario.cleanUp();
+ await tryCpServer.stop();
});
-test("TryCP Scenario - Receive signals with 2 conductors", async (t) => {
- const scenario = await TryCpScenario.create(SERVER_URL);
+test("TryCP Scenario - receive signals with 2 conductors", async (t) => {
+ const tryCpServer = await TryCpServer.start();
+
+ const scenario = new TryCpScenario();
+ const client = await scenario.addClient(SERVER_URL);
let signalHandlerAlice: AppSignalCb | undefined;
const signalReceivedAlice = new Promise((resolve) => {
@@ -54,21 +142,21 @@ test("TryCP Scenario - Receive signals with 2 conductors", async (t) => {
resolve(signal);
};
});
- const dnas: DnaSource[] = [{ path: FIXTURE_DNA_URL.pathname }];
- const [alice, bob] = await scenario.addPlayersWithHapps([
+ const dnas: Dna[] = [{ source: { path: FIXTURE_DNA_URL.pathname } }];
+ const [alice, bob] = await scenario.addPlayersWithHapps(client, [
{ dnas, signalHandler: signalHandlerAlice },
{ dnas, signalHandler: signalHandlerBob },
]);
const signalAlice = { value: "hello alice" };
alice.cells[0].callZome({
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "signal_loopback",
payload: signalAlice,
});
const signalBob = { value: "hello bob" };
bob.cells[0].callZome({
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "signal_loopback",
payload: signalBob,
});
@@ -77,17 +165,24 @@ test("TryCP Scenario - Receive signals with 2 conductors", async (t) => {
signalReceivedAlice,
signalReceivedBob,
]);
- t.deepEqual(actualSignalAlice.data.payload, signalAlice);
- t.deepEqual(actualSignalBob.data.payload, signalBob);
+ t.deepEqual(
+ actualSignalAlice.data.payload,
+ signalAlice,
+ "received alice's signal"
+ );
+ t.deepEqual(actualSignalBob.data.payload, signalBob, "received bob's signal");
await scenario.cleanUp();
+ await tryCpServer.stop();
});
-test("TryCp Scenario - Create and read an entry, 2 conductors", async (t) => {
- const scenario = await TryCpScenario.create(SERVER_URL);
- t.ok(scenario.uid);
+test("TryCp Scenario - create and read an entry, 2 conductors", async (t) => {
+ const tryCpServer = await TryCpServer.start();
+
+ const scenario = new TryCpScenario();
+ const client = await scenario.addClient(SERVER_URL);
- const [alice, bob] = await scenario.addPlayersWithHapps([
+ const [alice, bob] = await scenario.addPlayersWithHapps(client, [
[{ path: FIXTURE_DNA_URL.pathname }],
[{ path: FIXTURE_DNA_URL.pathname }],
]);
@@ -95,7 +190,7 @@ test("TryCp Scenario - Create and read an entry, 2 conductors", async (t) => {
const content = "Hi dare";
const createEntryHash = await alice.cells[0].callZome({
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "create",
payload: content,
});
@@ -103,46 +198,166 @@ test("TryCp Scenario - Create and read an entry, 2 conductors", async (t) => {
await pause(100);
const readContent = await bob.cells[0].callZome({
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "read",
payload: createEntryHash,
});
t.equal(readContent, content);
await scenario.cleanUp();
+ await tryCpServer.stop();
});
-test("TryCP Scenario - Conductor maintains data after shutdown and restart", async (t) => {
- const scenario = await TryCpScenario.create(SERVER_URL);
- const [alice, bob] = await scenario.addPlayersWithHapps([
+test("TryCP Scenario - conductor maintains data after shutdown and restart", async (t) => {
+ const tryCpServer = await TryCpServer.start();
+
+ const scenario = new TryCpScenario();
+ const client = await scenario.addClient(SERVER_URL);
+
+ const [alice, bob] = await scenario.addPlayersWithHapps(client, [
[{ path: FIXTURE_DNA_URL.pathname }],
[{ path: FIXTURE_DNA_URL.pathname }],
]);
await scenario.shareAllAgents();
+
const content = "Before shutdown";
const createEntryHash = await alice.cells[0].callZome({
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "create",
payload: content,
});
await pause(100);
const readContent = await bob.cells[0].callZome({
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "read",
payload: createEntryHash,
});
- t.equal(readContent, content);
+ t.equal(
+ readContent,
+ content,
+ "entry content read successfully before shutdown"
+ );
await bob.conductor.shutDown();
- await t.rejects(bob.conductor.adminWs().generateAgentPubKey);
+ await t.rejects(
+ bob.conductor.adminWs().generateAgentPubKey,
+ "conductor cannot be reached after shutdown"
+ );
await bob.conductor.startUp({});
await bob.conductor.connectAppInterface();
const readContentAfterRestart = await bob.cells[0].callZome({
- zome_name: "crud",
+ zome_name: "coordinator",
fn_name: "read",
payload: createEntryHash,
});
- t.equal(readContentAfterRestart, content);
+ t.equal(
+ readContentAfterRestart,
+ content,
+ "entry content read successfully after restart"
+ );
+
+ await scenario.cleanUp();
+ await tryCpServer.stop();
+});
+
+test("TryCP Scenario - connect to multiple clients by passing a list of URLs", async (t) => {
+ const numberOfServers = 2;
+ const tryCpServers: TryCpServer[] = [];
+ const serverUrls: URL[] = [];
+
+ for (let i = 0; i < numberOfServers; i++) {
+ const serverPort = TRYCP_SERVER_PORT + i;
+ const serverUrl = new URL(`ws://${TRYCP_SERVER_HOST}:${serverPort}`);
+ const tryCpServer = await TryCpServer.start(serverPort);
+ tryCpServers.push(tryCpServer);
+ serverUrls.push(serverUrl);
+ }
+
+ const scenario = new TryCpScenario();
+ await scenario.addClientsPlayers(serverUrls);
+ t.ok(
+ scenario.clients.length === numberOfServers,
+ "scenario has expected number of clients"
+ );
+
+ for (const [index, client] of scenario.clients.entries()) {
+ const PING_MESSAGE = "pingpong";
+ const pong = (await client.ping(PING_MESSAGE)).toString();
+ t.equal(pong, PING_MESSAGE, `client ${index + 1} is running`);
+ }
+
+ await scenario.cleanUp();
+ await Promise.all(tryCpServers.map((tryCpServer) => tryCpServer.stop()));
+});
+
+test("TryCP Scenario - create multiple conductors for multiple clients", async (t) => {
+ const numberOfServers = 2;
+ const numberOfConductorsPerClient = 3;
+ const tryCpServers: TryCpServer[] = [];
+ const serverUrls: URL[] = [];
+
+ for (let i = 0; i < numberOfServers; i++) {
+ const serverPort = TRYCP_SERVER_PORT + i;
+ const serverUrl = new URL(`ws://${TRYCP_SERVER_HOST}:${serverPort}`);
+ const tryCpServer = await TryCpServer.start(serverPort);
+ tryCpServers.push(tryCpServer);
+ serverUrls.push(serverUrl);
+ }
+
+ const scenario = new TryCpScenario();
+ await scenario.addClientsPlayers(serverUrls, {
+ numberOfConductorsPerClient,
+ });
+
+ for (const [i, client] of scenario.clients.entries()) {
+ t.ok(
+ client.conductors.length === numberOfConductorsPerClient,
+ `client ${i + 1} has expected number of conductors`
+ );
+ for (const [j, conductor] of client.conductors.entries()) {
+ const agentPubKey = await conductor.adminWs().generateAgentPubKey();
+ t.ok(
+ agentPubKey,
+ `conductor ${j + 1} of client ${i + 1} responds with success`
+ );
+ }
+ }
+
+ await scenario.cleanUp();
+ await Promise.all(tryCpServers.map((tryCpServer) => tryCpServer.stop()));
+});
+
+test("TryCP Scenario - create multiple agents for multiple conductors for multiple clients", async (t) => {
+ const numberOfServers = 2;
+ const numberOfConductorsPerClient = 2;
+ const numberOfAgentsPerConductor = 3;
+ const tryCpServers: TryCpServer[] = [];
+ const serverUrls: URL[] = [];
+
+ for (let i = 0; i < numberOfServers; i++) {
+ const serverPort = TRYCP_SERVER_PORT + i;
+ const serverUrl = new URL(`ws://${TRYCP_SERVER_HOST}:${serverPort}`);
+ const tryCpServer = await TryCpServer.start(serverPort);
+ tryCpServers.push(tryCpServer);
+ serverUrls.push(serverUrl);
+ }
+
+ const scenario = new TryCpScenario();
+ const clientsPlayers = await scenario.addClientsPlayers(serverUrls, {
+ numberOfConductorsPerClient,
+ numberOfAgentsPerConductor,
+ dnas: [{ source: { path: FIXTURE_DNA_URL.pathname } }],
+ });
+
+ for (const [i, clientPlayers] of clientsPlayers.entries()) {
+ t.ok(
+ clientPlayers.players.length ===
+ numberOfConductorsPerClient * numberOfAgentsPerConductor,
+ `client ${i + 1} has expected number of players`
+ );
+ }
+
await scenario.cleanUp();
+ await Promise.all(tryCpServers.map((tryCpServer) => tryCpServer.stop()));
});