Skip to content

Commit

Permalink
Merge pull request #75 from holochain/holochain-8d6c4c-update
Browse files Browse the repository at this point in the history
Update to holochain 8d6c4cd2 which allows setting UID
  • Loading branch information
zippy authored Apr 5, 2021
2 parents c9e900b + 4f5eac1 commit c3f0216
Show file tree
Hide file tree
Showing 14 changed files with 41 additions and 41 deletions.
12 changes: 6 additions & 6 deletions README-TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ If you need your conductor to be configured in a really specific way, fear not,

> 3. Conductors from different scenarios must remain independent and invisible to each other
To achieve the independence of conductors, Tryorama ensure that various values are unique. It uses UUIDs during DNA config as well as for Agent IDs to ensure unique values; it ensures that it automatically creates temp directories for file storage when necessary, adding the paths to the config. So how can we let Tryorama handle these concerns while still generating a custom config? The answer is in a key concept:
To achieve the independence of conductors, Tryorama ensure that various values are unique. It uses UIDs during DNA config as well as for Agent IDs to ensure unique values; it ensures that it automatically creates temp directories for file storage when necessary, adding the paths to the config. So how can we let Tryorama handle these concerns while still generating a custom config? The answer is in a key concept:

**Players are configured by giving them *functions* that generate their config**. For instance, when you call `Config.gen`, it's actually creating a function for you like this:

Expand All @@ -63,7 +63,7 @@ To achieve the independence of conductors, Tryorama ensure that various values a
const config = Config.gen({alice: dnaConfig})

// becomes this
const config = ({playerName, uuid, configDir, adminInterfacePort}) => {
const config = ({playerName, uid, configDir, adminInterfacePort}) => {
return {
environment_path: configDir,
network: {/* ... */},
Expand All @@ -80,7 +80,7 @@ Config seeds take an object as a parameter, with five values:

* `scenarioName`: the name of the current scenario, i.e. `registerScenario(scenarioName, ...)`
* `playerName`: the name of the player for this conductor, e.g. `"alice"`
* `uuid`: a UUID which is guaranteed to be the same within a scenario but unique between different scenarios
* `uid`: a UID which is guaranteed to be the same within a scenario but unique between different scenarios
* `configDir`: a temp dir created specifically for this conductor
* `adminInterfacePort`: a free port on the machine which is used for the admin Websocket interface

Expand All @@ -90,7 +90,7 @@ Under the hood, Tryorama generates unique and valid values for these parameters

* There must be an admin interface running over WebSockets at `adminInterfacePort` which includes all instances that are part of this test
* *All* agents within a scenario must have a unique name (even across different conductors!)
* You must incorporate the UUID or some other source of uniqueness into the DNA config's `uuid` field, to ensure that conductors in different tests do not attempt to connect to each other on the same network
* You must incorporate the UID or some other source of uniqueness into the DNA config's `uid` field, to ensure that conductors in different tests do not attempt to connect to each other on the same network

### Using seed functions in `Config.gen`

Expand All @@ -99,12 +99,12 @@ Since configuring a full config that properly uses these injected values is real
```js
Config.gen(
{alice: dnaConfig},
({playerName, uuid}) => {
({playerName, uid}) => {
return {
dpki: {
instance_id: 'my-instance',
init_params: JSON.stringify({
someValueThatNeedsToBeUnique: uuid,
someValueThatNeedsToBeUnique: uid,
someValueThatWantsToBeThePlayerName: playerName,
})
}
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ An end-to-end/scenario testing framework for Holochain applications, written in

Tryorama allows you to write test suites about the behavior of multiple Holochain nodes which are networked together, while ensuring that test nodes in different tests do not accidentally join a network together.

Note: this version of tryorama is tested against holochain rev a82372a62d46a503e48f345360d0fb18cc5822d1. Please see [testing Readme](test/README.md) for details on how to run tryorama's own tests.
Note: this version of tryorama is tested against holochain rev 8d6c4cd29bd17e8224aeffb87dc03eaf3ff33508. Please see [testing Readme](test/README.md) for details on how to run tryorama's own tests.

```bash
npm install @holochain/tryorama
Expand Down Expand Up @@ -100,7 +100,7 @@ orchestrator.registerScenario('proper zome call', async (s, t) => {
// or install a happ using
// - a previously generated key
// - and the hash of a dna that was previously registered with the same conductor
// (a dna can be registered either by installing a happ with that dna or by calling registerDna with an old dna's hash and a new UUID)
// (a dna can be registered either by installing a happ with that dna or by calling registerDna with an old dna's hash and a new UID)
const blogDnaHash = carol_test_happ.cells[0].dnaHash()
const derivedDnaHash = await carol.registerDna({hash: blogDnaHash}, "1234567890")
const carol_derived_happ_with_bobs_test_key = await carol.installHapp([derivedDnaHash], bob_blog_happ.agent)
Expand Down
2 changes: 1 addition & 1 deletion ci_scripts/install-holochain.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/bin/bash

REV=a82372a62d46a503e48f345360d0fb18cc5822d1
REV=8d6c4cd29bd17e8224aeffb87dc03eaf3ff33508
LAIR_REV=a01a40640574d3cfabae33dfe3f861de7bd7a57c

export CARGO_TARGET_DIR="$PWD/target"
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"type": "git",
"url": "https://github.com/holochain/tryorama"
},
"version": "0.4.1",
"version": "0.4.2",
"description": "test framework for holochain hApps",
"main": "lib/index.js",
"types": "lib/index.d.ts",
Expand All @@ -24,7 +24,7 @@
"author": "",
"license": "Apache-2.0",
"dependencies": {
"@holochain/conductor-api": "^0.0.1",
"@holochain/conductor-api": "^0.0.3",
"@holochain/hachiko": "^0.5.2",
"@iarna/toml": "^2.2.5",
"@msgpack/msgpack": "^2.1.0",
Expand Down
12 changes: 6 additions & 6 deletions src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,19 @@ export class ScenarioApi {

_localPlayers: Array<Player>
_trycpClients: Array<TrycpClient>
_uuid: string
_uid: string
_waiter: Waiter
_modifiers: Modifiers
_activityTimer: any
_conductorIndex: number

constructor(description: string, orchestratorData, uuid: string, modifiers: Modifiers = { singleConductor: false }) {
constructor(description: string, orchestratorData, uid: string, modifiers: Modifiers = { singleConductor: false }) {
this.description = description
this.fail = (reason) => { throw new Error(`s.fail: ${reason}`) }

this._localPlayers = []
this._trycpClients = []
this._uuid = uuid
this._uid = uid
this._waiter = new Waiter(FullSyncNetwork, undefined, orchestratorData.waiterConfig)
this._modifiers = modifiers
this._activityTimer = null
Expand Down Expand Up @@ -132,7 +132,7 @@ export class ScenarioApi {
await trycpClient.configurePlayer(playerName, configJson)
logger.debug('api.players: player config committed for %s', playerName)
return new Player({
scenarioUUID: this._uuid,
scenarioUID: this._uid,
name: playerName,
config: configJson,
spawnConductor: spawnRemote(trycpClient),
Expand Down Expand Up @@ -160,7 +160,7 @@ export class ScenarioApi {

logger.debug('api.players: player config committed for %s', playerName)
return new Player({
scenarioUUID: this._uuid,
scenarioUID: this._uid,
name: playerName,
config: configYaml,
spawnConductor: spawnLocal(configDir, adminInterfacePort, appInterfacePort),
Expand All @@ -175,7 +175,7 @@ export class ScenarioApi {
const configSeedArgs: T.ConfigSeedArgs = _.assign(partialConfigSeedArgs, {
scenarioName: this.description,
playerName,
uuid: this._uuid
uid: this._uid
})
logger.debug('api.players: seed args generated for %s = %j', playerName, configSeedArgs)
const configJson = configSeed(configSeedArgs)
Expand Down
23 changes: 12 additions & 11 deletions src/conductor.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const colors = require('colors/safe')
import { v4 as uuidGen } from 'uuid'
import { v4 as uidGen } from 'uuid'

import { KillFn } from "./types";
import { makeLogger } from "./logger";
Expand Down Expand Up @@ -139,7 +139,7 @@ export class Conductor {
}

// this function registers a DNA from a given source
registerDna = async (source: T.DnaSource, uuid?, properties?): Promise<HoloHash> => {
registerDna = async (source: T.DnaSource, uid?, properties?): Promise<HoloHash> => {
if ("path" in source && "saveDnaRemote" in this._backend) {
const contents = () => new Promise<Buffer>((resolve, reject) => {
fs.readFile((source as { path: string }).path, null, (err, data) => {
Expand All @@ -158,29 +158,30 @@ export class Conductor {
}
source = await this._backend.downloadDnaRemote((source as T.DnaUrl).url)
}
const registerDnaReq: RegisterDnaRequest = { ...source, uuid, properties }
const registerDnaReq: RegisterDnaRequest = { ...source, uid, properties }
return await this.adminClient!.registerDna(registerDnaReq)
}

// this function will install an app bundle as generated by hc app pack
installBundledHapp = async (bundleSource: AppBundleSource, agentPubKey?: AgentPubKey, installedAppId?: string): Promise<T.InstalledHapp> => {
installBundledHapp = async (bundleSource: AppBundleSource, agentPubKey?: AgentPubKey, installedAppId?: string, uid?: string): Promise<T.InstalledHapp> => {
if (!agentPubKey) {
agentPubKey = await this.adminClient!.generateAgentPubKey()
}

const bundleInstalledAppId = installedAppId || `app-${uuidGen()}`
const bundleInstalledAppId = installedAppId || `app-${uidGen()}`
const installAppBundleReq: InstallAppBundleRequest = {
...bundleSource,
installed_app_id: bundleInstalledAppId,
agent_key: agentPubKey,
membrane_proofs: {}
membrane_proofs: {},
uid
}
return await this._installBundledHapp(installAppBundleReq)
}

// install a hApp using the InstallAppBundleRequest struct from conductor-admin-api
// you must create your own app_id and bundle, this is useful also if you
// need to pass in uuid, properties or membrane-proof
// need to pass in uid, properties or membrane-proof
_installBundledHapp = async (installAppBundleReq: InstallAppBundleRequest): Promise<T.InstalledHapp> => {

const installedApp: InstalledApp = await this.adminClient!.installAppBundle(installAppBundleReq)
Expand All @@ -197,7 +198,7 @@ export class Conductor {
}
const dnaSources = agentHapp
const installAppReq: InstallAppRequest = {
installed_app_id: `app-${uuidGen()}`,
installed_app_id: `app-${uidGen()}`,
agent_key: agentPubKey,
dnas: await Promise.all(dnaSources.map(async (src, index) => {
let source: T.DnaSource
Expand All @@ -210,8 +211,8 @@ export class Conductor {
}

let dna = {
hash: await this.registerDna(source, this._player.scenarioUUID),
nick: `${index}${src}-${uuidGen()}`,
hash: await this.registerDna(source, this._player.scenarioUID),
nick: `${index}${src}-${uidGen()}`,
}
return dna
}))
Expand Down Expand Up @@ -266,7 +267,7 @@ export class Conductor {
}
const {port: appInterfacePort} = await this.adminClient!.attachAppInterface({ port: appPortNumber })
console.log("App Port spun up on port ", appInterfacePort);


switch (this._backend.type) {
case "local":
Expand Down
2 changes: 1 addition & 1 deletion src/config/gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const defaultCommonConfig = {
export const gen = ( commonConfig: T.CommonConfig = {} ): T.ConfigSeed => (
args: T.ConfigSeedArgs
): T.RawConductorConfig => {
const { configDir, adminInterfacePort, uuid } = args
const { configDir, adminInterfacePort, uid } = args
const keystorePath = path.join(configDir, 'keystore');

// don't put any keys on this object that you want to fall back to defaults
Expand Down
5 changes: 2 additions & 3 deletions src/orchestrator.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { v4 as uuidGen } from 'uuid'
import { v4 as uidGen } from 'uuid'
import * as _ from 'lodash'
import * as T from "./types";
import * as M from "./middleware";
Expand Down Expand Up @@ -161,11 +161,10 @@ export class Orchestrator<S> {
'_globalConfig',
'waiterConfig',
])
const api = new ScenarioApi(desc, orchestratorData, uuidGen())
const api = new ScenarioApi(desc, orchestratorData, uidGen())
const runner = scenario => scenario(api)
const execute = () => this._middleware(runner, scenario)
this._scenarios.push({ api, desc, execute, modifier })
}

}

8 changes: 4 additions & 4 deletions src/player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { TunneledAdminClient, TunneledAppClient } from './trycp';
const fs = require('fs').promises

type ConstructorArgs = {
scenarioUUID: string,
scenarioUID: string,
name: string,
config: RawConductorConfig,
adminInterfacePort?: number,
Expand All @@ -41,20 +41,20 @@ export class Player {
onLeave: () => void
onSignal: ((signal: any) => void) | null = null
onActivity: () => void
scenarioUUID: string
scenarioUID: string

_conductor: Conductor | null
_adminInterfacePort?: number
_spawnConductor: SpawnConductorFn

constructor({ scenarioUUID, name, config, adminInterfacePort, onJoin, onLeave, onActivity, spawnConductor }: ConstructorArgs) {
constructor({ scenarioUID, name, config, adminInterfacePort, onJoin, onLeave, onActivity, spawnConductor }: ConstructorArgs) {
this.name = name
this.logger = makeLogger(`player ${name}`)
this.onJoin = onJoin
this.onLeave = onLeave
this.onActivity = onActivity
this.config = config
this.scenarioUUID = scenarioUUID,
this.scenarioUID = scenarioUID,

this._conductor = null
this._adminInterfacePort = adminInterfacePort
Expand Down
2 changes: 1 addition & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export type CommonConfig = {
export type ConfigSeedArgs = PartialConfigSeedArgs & {
scenarioName: string,
playerName: string,
uuid: string,
uid: string,
}

// export type PlayerConfigs = ObjectS<PlayerConfig>
Expand Down
2 changes: 1 addition & 1 deletion test/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,6 @@ export const genConfigArgs: () => Promise<T.ConfigSeedArgs> = async () => ({
adminInterfacePort: 1000,
playerName: 'playerName',
scenarioName: 'scenarioName',
uuid: 'uuid',
uid: 'uid',
})
export const spawnConductor = (() => { }) as unknown as T.SpawnConductorFn
2 changes: 1 addition & 1 deletion test/e2e/fixture/dna.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
manifest_version: "1"
name: test-dna
uuid: 9a28aac8-337c-11eb-adc1-0Z02acw20115
uid: 9a28aac8-337c-11eb-adc1-0Z02acw20115
properties: ~
zomes:
- name: test
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/fixture/happ.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ slots:
dna:
bundled: ./test.dna
properties: ~
uuid: ~
uid: ~
version: ~
clone_limit: 0
2 changes: 1 addition & 1 deletion test/unit/test-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Orchestrator } from '../../src';

test('API complains if a non-function was used for config', async t => {
const orchestrator = new Orchestrator({ middleware: undefined })
const api = new ScenarioApi("description", orchestrator, "uuid")
const api = new ScenarioApi("description", orchestrator, "uid")
await t.rejects(
// @ts-ignore
api.players([{}]),
Expand Down

0 comments on commit c3f0216

Please sign in to comment.