Holochain Forum

Try-o-rama troubles

Hi team. I’m trying to switch to try-o-rama but having some teething issues.
I get the following error:

Created DNA package file at "/home/simwilso/Code/RedGrid-Alpha/Holochain/signal_agent/dist/signal_agent.dna.json"
DNA hash: QmZkSgUvhcNiQ6hG1vMHngp7G4asF8CiB2t4gqdg5xjxNv
Running tests in test/index.js
> node test/index.js
23:20:39 [try-o-rama] debug: About to execute 1 tests
got an error for  messages are fetchable tapeExecutor middleware requires scenario functions to take 2 arguments, please check your scenario definitions.
23:20:39 [try-o-rama] debug: Done with test: messages are fetchable

Here’s my js:

const path = require('path')
const tape = require('tape')

const { Orchestrator, Config, tapeExecutor, singleConductor, combine  } = require('@holochain/try-o-rama')

process.on('unhandledRejection', error => {
  // Will print "unhandledRejection err is not defined"
  console.error('got unhandledRejection:', error);
});

const dnaPath = path.join(__dirname, "../dist/signal_agent.dna.json")

const orchestrator = new Orchestrator({
  middleware: combine(
    // squash all instances from all conductors down into a single conductor,
    // for in-memory testing purposes.
    // Remove this middleware for other "real" network types which can actually
    // send messages across conductors
    singleConductor,

    // use the tape harness to run the tests, injects the tape API into each scenario
    // as the second argument
    tapeExecutor(require('tape'))
  ),

  globalConfig: {
    logger: true,
    network: 'memory',  // must use singleConductor middleware if using in-memory network
  },

  // the following are optional:

  waiter: {
    softTimeout: 5000,
    hardTimeout: 10000,
  },
})

const conductorConfig = {
  instances: {
    signal_agent: Config.dna(dnaPath, 'scaffold-test')
  }
}

orchestrator.registerScenario('messages are fetchable', async s => {
  const { alice, bob } = await s.players({ alice: conductorConfig, bob: conductorConfig }, true)
  await alice.call('signal_agent', 'spot_signal', 'set_price', {
      price: 'you beauty it works',
  })
  await s.consistency() // wait long enough for network propagation to reach bob
  const result = await bob.call('signal_agent', 'spot_signal', 'get_price', {})
  assert(result.Ok[0] === 'you beauty it works')
})

orchestrator.run()

Any tips on what I’ve mucked up here?
:slight_smile:

The example on the Try-o-rama home page uses a more primitive executor — I forget what it does, but it doesn’t involve Tape. Because you’re using the Tape executor, the scenario callback function will need to take two arguments: a scenario handler object (s in your code) and a tape object (see example from Tape’s readme and all the following text; the tape object is called t in the examples). This tape object has assertions like t.equal(), t.ok(), flow control like t.plan() and t.end(), and logging stuff like t.comment(). Hope this helps!

You just need to alter the zome calls slightly.
From

const result = await bob.call('signal_agent', 'spot_signal', 'get_price', {})
const result = await bob.call('scaffold-test', 'signal_agent', 'spot_signal', 'get_price', {})
1 Like

Thankyou for that Paul. Worked a treat! :v:

ok having some troubles again here sorry folks. :frowning:

I’m sure this is something really simple so apologies in advance but would anyone have any ideas where this is breaking.

The updated test config tutorial in Hello Holo is great and seems to work but my own attempt here is failing.
I’m unable to get my simple test to pass (which will inserts a value and retrieve it)…

Here’s my response:

10:34:55 error: 
★★★ {{{CONDUCTOR combined}}}
★ 0: std::panicking::default_hook::{{closure}}
★    1: std::panicking::rust_panic_with_hook
★    2: std::panicking::continue_panic_fmt
★    3: rust_begin_unwind
★    4: core::panicking::panic_fmt
★    5: core::result::unwrap_failed
★    6: <holochain_core::instance::Instance as core::ops::drop::Drop>::drop
★    7: core::ptr::real_drop_in_place
★    8: alloc::sync::Arc<T>::drop_slow
★    9: core::ptr::real_drop_in_place.3142
★   10: holochain_conductor_lib::conductor::base::Conductor::shutdown
★   11: <holochain_conductor_lib::conductor::base::Conductor as core::ops::drop::Drop>::drop
★   12: core::ptr::real_drop_in_place
★   13: holochain::main
★   14: std::rt::lang_start::{{closure}}
★   15: main
★   16: __libc_start_main
★   17: _start
★ note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
★ 
10:34:55 [try-o-rama: player combined] info: conductor 'combined' exited with code 101

1..1
# tests 1
# pass  0
# fail  1

Error: command node test/index.js was not successful

I included the conductor error here as I’m thinking maybe that’s relevant.

Here’s my test config from ‘index.js’:

const path = require('path');
const tape = require('tape');

const {
  Config,
  Orchestrator,
  tapeExecutor,
  singleConductor,
  combine,
} = require('@holochain/try-o-rama');

process.on('unhandledRejection', error => {
  console.error('got unhandledRejection:', error);
});

const dnaPath = path.join(__dirname, "../dist/signal_agent.dna.json")

const orchestrator = new Orchestrator({
  middleware: combine(singleConductor, tapeExecutor(tape)),
  globalConfig: {
        logger: false,
        network: {
      type: 'sim2h',
      sim2h_url: 'wss://sim2h.holochain.org:9000',
    },
  },
});

const config = {
  instances: {
    signal_agent: Config.dna(dnaPath, 'signal_agent'),
  },
};
orchestrator.registerScenario('messages are fetchable', async (s, t) => {
  const { alice, bob } = await s.players({ alice: config, bob: config }, true)
  await alice.call('signal_agent', 'spot_signal', 'set_price', {"price": { "price" : "Alice" }});
  t.ok(create_result.Ok);
  const alice_person_address = create_result.Ok;
  await s.consistency() // wait long enough for network propagation to reach bob
  const retrieve_result = await alice.call('signal_agent', 'spot_signal', 'get_price', {"address": alice_person_address });
  t.ok(retrieve_result.Ok);//[0] === 'Alice')
  t.deepEqual(result, { Ok: { "price": "Alice" }})
})
orchestrator.run()

Here’s my Zome that compiles and runs no problem:

#![feature(proc_macro_hygiene)]
#[macro_use]
extern crate hdk;
extern crate hdk_proc_macros;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
#[macro_use]
extern crate holochain_json_derive;
use hdk::{
    entry_definition::ValidatingEntryType,
    error::ZomeApiResult,
};
use hdk::holochain_core_types::{
    entry::Entry,
    dna::entry_types::Sharing,
};

use hdk::holochain_json_api::{
    json::JsonString,
    error::JsonError,
};

  use hdk::holochain_persistence_api::{
    cas::content::Address
};
use hdk_proc_macros::zome;


// this is a struct for the current market price data.  This is updated every 5 minutes.
#[derive(Serialize, Deserialize, Debug, DefaultJson,Clone)]
pub struct PriceRange {
    price: String,
}

#[zome]
mod spot_signal {

    #[init]
    fn init() {
        Ok(())
    }

    #[validate_agent]
    pub fn validate_agent(validation_data: EntryValidationData<AgentId>) {
        Ok(())
    }

    #[entry_def]
    fn price_range_entry_def() -> ValidatingEntryType {
        entry!(
            name: "price",
            description: "this is the current price enum as a string",
            sharing: Sharing::Public,
            validation_package: || {
                hdk::ValidationPackageDefinition::Entry
            },
            validation: | _validation_data: hdk::EntryValidationData<PriceRange>| {
                Ok(())
            }
        )
    }
    // this function sets the spot price and is used by the device agents
    // function needs to be written to emit a signal when this changes
    // the signal emit is sent to interested agents who will update their connected device
    #[zome_fn("hc_public")]
    pub fn set_price(price: PriceRange) -> ZomeApiResult<Address> {
        let entry = Entry::App("price".into(), price.into());
        let address = hdk::commit_entry(&entry)?;
        Ok(address)
    }
    // this is the function that sets the spot price for each state every 5 minutes
    #[zome_fn("hc_public")]
    fn get_price(address: Address) -> ZomeApiResult<PriceRange> {
        hdk::utils::get_as_type(address)
    }

}

Thanks all. :slight_smile:

Hey @simwilso
Could you show me the test output that failed.
The first output where it says:

1..1
# tests 1
# pass  0
# fail  1

You should be able to scroll up and there will be a test that says something like “not ok …”
That should show what has gone wrong here.

Thanks @FreeSig. Searching for ‘not ok’ allowed me to find the issue and my tests all passed.
I had two problems in my orchestrator config:

1st I didnt define ‘create_result’ const:
const create_result = await alice.call('signal_agent', 'spot_signal', 'set_price', {"price": { "price" : "Alice" }});

2nd my deepequal statement wasn’t a match… it was:
t.deepEqual(retrieve_result, { Ok: ‘Alice’})
but had to change it too:
t.deepEqual(retrieve_result, { Ok: { price: ‘Alice’ } })

thanks! :slight_smile:

Oh cool, glad you found it. Yeh the test output’s a bit noisy and can be hard to see the failures. Might be worth looking into cleaning it up a bit or producing a summary at the end :thinking: