Struct Cluster

Source
pub struct Cluster {
    pub uuid: Uuid,
    pub plugin_path: PathBuf,
    pub data_dir: PathBuf,
    pub timeout: Duration,
    /* private fields */
}

Fields§

§uuid: Uuid§plugin_path: PathBuf§data_dir: PathBuf§timeout: Duration

Implementations§

Source§

impl Cluster

Source

pub fn new( plugin_path: PathBuf, topology: Topology, timeout: Duration, ) -> Result<Cluster, Error>

Source

pub fn data_dir_path(&self) -> PathBuf

Source

pub fn stop(&self) -> Result<(), Error>

Source

pub fn apply_config<T>(&self, config: T) -> Result<(), Error>

Applies passed plugin config to the running cluster through the interface of command “pike config apply”.

§Arguments:
  • config - mapping of plugin services to their values. This structure should be able to deserialize into PluginConfigMap.
§Returns

Note: your cluster logs may contain messages related to status of config applying. E.g., if some fields are erroneously serialized, Picodata plugin environment will throw a descriptive error during config validation saying what went wrong.

Thus, this routine will raise an error if something goes wrong, but details of an error rather be found in cluster logs.

§Examples:
§Plugin with single service called router.

Assume plugin YAML configuration file has the following mapping:

router:
    rpc_endpoint: "/hello"
    max_rpc_message_size_bytes: 1024
    max_rpc_message_queue_size: 2048

Our integration test will override all fields of service configuration and apply new config through Cluster::apply_config routine.

There’re several approaches of assembling PluginConfigMap that is passed into the routine.

1. Using YAML formatted string.

Put desired config inside string and deserialize it using [serde_yaml::from_str]. Then attach it to a particular plugin service.

use rmpv::Value;
use std::collections::HashMap;
use serde_yaml::Value;
use picotest::*;

#[picotest]
fn test_apply_plugin_from_yaml_string() {
    // 1. Assemble YAML string.

    let plugin_config_yaml = r#"
        router:
            rpc_endpoint: "/test"
            max_rpc_message_size_bytes: 128
            max_rpc_message_queue_size: 32
        "#;

    let plugin_config: PluginConfigMap =
        serde_yaml::from_str(plugin_config_yaml).unwrap();

    // 2. Apply config to the running cluster instance.

    cluster // implicitly created variable by picotest magic
        .apply_config(plugin_config)
        .expect("Failed to apply config");

    // Callback Serivce::on_config_change should've been already
    // called at this point.
}

**2. Using HashMap.

Config can be assembled by means of std::collections::HashMap and [serde_yaml::to_str].

use rmpv::Value;
use std::collections::HashMap;
use serde_yaml::Value;
use picotest::*;

#[picotest]
fn test_apply_plugin_from_hashmap() {
    // 1. Override properties of the "router" service.

    let router_config = HashMap::from([
        ("rpc_endpoint".to_string(), Value::String("/test".into())),
        ("max_rpc_message_size_bytes".to_string(), Value::Number(128.into())),
        ("max_rpc_message_queue_size".to_string(), Value::Number(32.into())),
    ]);

    // 2. "Attach" overridden properties to the service "router".

    let plugin_config = HashMap::from([("router".into(), router_config)]);

    // 3. Apply config to the running cluster instance.

    cluster // implicitly created variable by picotest magic
        .apply_config(plugin_config)
        .expect("Failed to apply config");

    // Callback Serivce::on_config_change should've been already
    // called at this point.
}
§Plugin with single service called router, which has nested properties for RPC machinery.

Nested sections in config mapping are handled similarly. We just need to wrap nested map value into [serde_yaml::Value].

Assume plugin YAML configuration file has the following mapping:

router:
 rpc:
  endpoint: "/hello"
  max_message_size_bytes: 1024
  max_message_queue_size: 2048

Out integration test will look like:

use rmpv::Value;
use std::collections::HashMap;
use serde_yaml::Value;
use picotest::*;

#[picotest]
fn test_apply_plugin_nested_config() {
    // Override properties of the RPC machinery.
    let rpc_config = HashMap::from([
        ("endpoint".to_string(), Value::String("/test".into())),
        ("max_message_size_bytes".to_string(), Value::Number(128.into())),
        ("max_message_queue_size".to_string(), Value::Number(32.into())),
    ]);

    let router_config = HashMap::from([("rpc".to_string(), serde_yaml::to_value(rpc_config).unwrap())]);
    let plugin_config = HashMap::from([("router".to_string(), router_config)]);

    cluster // implicitly created variable by picotest magic
        .apply_config(plugin_config)
        .expect("Failed to apply config");
}
Source

pub fn run(self) -> Result<Cluster, Error>

Source

pub fn recreate(self) -> Result<Cluster, Error>

Source

pub fn run_query<T>(&self, query: T) -> Result<String, Error>
where T: AsRef<[u8]>,

Executes an SQL query through the picodata admin console.

§Workflow
  1. Establishes connection with the admin console (await_picodata_admin)
  2. Writes the query to the process’s stdin
  3. Reads the result from stdout, skipping the first 2 lines (typically headers)
  4. Terminates the process after receiving the result
§Arguments
  • query - SQL query as a byte slice or convertible type
§Return Value

Result<String, Error> where:

  • Ok(String) - query execution result
  • Err(Error) - I/O or execution error
§Examples
use picotest::*;

#[picotest]
fn run_sql_query() {
    let result = cluster.run_query("SELECT * FROM users").unwrap();
    println!("{}", result);
}
Source

pub fn run_lua<T>(&self, query: T) -> Result<String, Error>
where T: AsRef<[u8]>,

Executes Lua script through picodata’s query mechanism.

Prepends \lua\n to the query and passes it to run_query.

§Arguments
  • query - Lua code as a byte slice or convertible type
§Return Value

Result<String, Error> where:

  • Ok(String) - script execution result
  • Err(Error) - execution error (inherited from run_query)
§Examples
use picotest::*;

#[picotest]
fn test_run_lua_query() {
    let res = cluster.instances()[1].run_lua("return 1 + 1")?;
    assert!(res.contains("2"));
}
Source

pub fn main(&self) -> &PicotestInstance

Method returns first running cluster instance

Source

pub fn get_instances_by_tier(&self, tier_name: &str) -> Vec<&PicotestInstance>

Method returns all instances, which belong to certain tier

Source

pub fn instances(&self) -> &Vec<PicotestInstance>

Method returns all running instances of cluster

Trait Implementations§

Source§

impl Drop for Cluster

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> Any for T
where T: Any,