Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]

### Changed

* Удален `path` атрибут для макроса `#[picotest]`, передать путь до плагина теперь можно через переменную `PLUGIN_PATH`


## [3.2.3]

### Changed
Expand Down
43 changes: 4 additions & 39 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 10 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@
- [Использование `#[picotest]`](#использование-picotest)
- [Переменные окружения](#переменные-окружения)
- [`WAIT_VSHARD_DISCOVERY`](#wait_vshard_discovery)
- [`PICODATA_PATH`](#picodata_path)
- [`TOPOLOGY_PATH`](#topology_path)
- [`PLUGIN_PATH`](#plugin_path)
- [Логирование](#логирование)
- [Файлы логов кластера](#файлы-логов-кластера)
- [Совместимость с `rstest`](#совместимость-с-rstest)
- [Атрибуты макроса `#[picotest]`](#атрибуты-макроса-picotest)
- [Применение конфигурации плагина к запущенному кластеру Picodata](#применение-конфигурации-плагина-к-запущенному-кластеру-picodata)
- [Модульное тестирование](#модульное-тестирование)
- [Требования к конфигурации](#требования-к-конфигурации)
Expand Down Expand Up @@ -154,6 +156,12 @@ mod test_mod {
- **Допустимые значения**: абсолютный или относительный путь к файлу топологии
- **Значение по умолчанию**: topology.toml в корне плагина

#### 'PLUGIN_PATH'

- **Описание**: путь к корню плагина (директория с `Cargo.toml` / `topology.toml`). Если задан, используется вместо автопоиска вверх от `CARGO_MANIFEST_DIR`. Нужен в основном когда тесты запускаются не из workspace плагина.
- **Допустимые значения**: абсолютный или относительный путь к директории плагина
- **Значение по умолчанию**: автопоиск `topology.toml` от `CARGO_MANIFEST_DIR`

### Логирование

При старте кластера инициализируется [`env_logger`](https://docs.rs/env_logger), который читает переменную `RUST_LOG`.
Expand Down Expand Up @@ -220,12 +228,6 @@ mod test_mod {
}
```

### Атрибуты макроса `#[picotest]`

| Название | Описание | Значение по умолчанию |
|-----------|-------------|-----------------------|
| `path` | Путь до директории, содержащей файл топологии плагина ([topology.toml](https://github.com/picodata/pike?tab=readme-ov-file#topologytoml)) | Определяется автоматически |

### Применение конфигурации плагина к запущенному кластеру Picodata

Picotest позволяет менять конфигурацию сервисов плагина во время исполнения интеграционного теста.
Expand Down Expand Up @@ -522,7 +524,7 @@ pub struct ExampleResponse {
}

#[tokio::test]
#[picotest(path = "../tmp/test_plugin")]
#[picotest]
async fn test_rpc_handle() {
let user_to_send = User {
name: "Dodo".to_string(),
Expand Down
42 changes: 24 additions & 18 deletions picotest/src/internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const PLUGIN_TOPOLOGY_FILENAME: &str = "topology.toml";

const ENV_WAIT_VSHARD_DISCOVERY: &str = "WAIT_VSHARD_DISCOVERY";
const ENV_PICODATA_PATH: &str = "PICODATA_PATH";
const ENV_PLUGIN_PATH: &str = "PLUGIN_PATH";
const ENV_TOPOLOGY_PATH: &str = "TOPOLOGY_PATH";

pub fn plugin_profile_build_path(plugin_path: &Path) -> PathBuf {
Expand Down Expand Up @@ -62,25 +63,36 @@ pub fn plugin_topology_path(plugin_path: &Path) -> PathBuf {

/// Returns root directory of the plugin.
///
/// Resolution order:
/// 1. `PLUGIN_PATH` environment variable, if set and the path exists.
/// 2. Walk ancestors of `CARGO_MANIFEST_DIR` looking for `topology.toml`,
/// then take its parent directory.
///
/// Panics if it was not found.
///
/// Basically, it looks for topology.toml file and then
/// returns its parent directory.
pub fn plugin_root_dir() -> PathBuf {
let plugin_topology_path = find_plugin_topology_path()
.expect("Error occurred while searching for plugin topology configuration")
.expect("Plugin topology configuration is not found");

let plugin_root_dir = plugin_topology_path
.parent()
.expect("Failed to obtain parent directory of plugin topology file");
let plugin_root_dir = var(ENV_PLUGIN_PATH)
.map(PathBuf::from)
.ok()
.filter(|path| path.exists())
.unwrap_or_else(|| {
find_plugin_topology_path()
.expect("Error occurred while searching for plugin topology configuration")
.expect("Plugin topology configuration is not found")
.parent()
.expect("Failed to obtain parent directory of plugin topology file")
.to_path_buf()
});

assert!(
plugin_root_dir.join("Cargo.toml").exists(),
"broken plugin directory?"
"Plugin root directory does not contain Cargo.toml: {}",
plugin_root_dir.display()
);

plugin_root_dir.to_path_buf()
plugin_root_dir
}

/// Finds path to the plugin topology file.
Expand Down Expand Up @@ -183,18 +195,12 @@ pub fn verify_unit_test_output(output: &str) -> anyhow::Result<()> {
/// Creates new instance of Picodata [`Cluster`].
///
/// ### Arguments
/// - `plugin_path` - path to the plugin root directory.
/// If `None`, directory is identified automatically.
/// - `plugin_topology` - instance of `PluginTopology`.
/// If `None`, topology is parsed from default path.
///
pub fn create_cluster(
plugin_path: Option<PathBuf>,
plugin_topology: Option<PluginTopology>,
) -> Cluster {
// Look up plugin root directory automatically
// unless explicitly specified.
let plugin_path = plugin_path.unwrap_or_else(plugin_root_dir);
pub fn create_cluster(plugin_topology: Option<PluginTopology>) -> Cluster {
// Look up plugin root directory (see `plugin_root_dir`).
let plugin_path = plugin_root_dir();
// Use passed topology or go and parse original topology
// located in plugin root directory.
let plugin_topology = plugin_topology.map_or_else(
Expand Down
12 changes: 4 additions & 8 deletions picotest/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,16 @@ pub static SESSION_CLUSTER: OnceLock<Cluster> = OnceLock::new();
pub type PluginConfigMap = picotest_helpers::PluginConfigMap;

#[fixture]
pub fn cluster(#[default(None)] plugin_path: Option<&str>) -> &'static Cluster {
get_or_create_session_cluster(plugin_path, None)
pub fn cluster() -> &'static Cluster {
get_or_create_session_cluster(None)
}

pub fn get_or_create_session_cluster(
plugin_path: Option<&str>,
plugin_topology: Option<&PluginTopology>,
) -> &'static Cluster {
pub fn get_or_create_session_cluster(plugin_topology: Option<&PluginTopology>) -> &'static Cluster {
SESSION_CLUSTER.get_or_init(|| {
env_logger::init();
let plugin_path = plugin_path.map(PathBuf::from);
let plugin_topology = plugin_topology.cloned();

internal::create_cluster(plugin_path, plugin_topology)
internal::create_cluster(plugin_topology)
})
}

Expand Down
9 changes: 8 additions & 1 deletion picotest/tests/helpers.rs → picotest/tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,16 @@ pub fn create_test_plugin(remove_if_exists: bool) -> TestPlugin {
assert!(exit_status.success());
}

let plugin_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(PLUGIN_DIR);
let plugin_path = fs::canonicalize(&plugin_path).unwrap_or(plugin_path);

unsafe {
std::env::set_var("PLUGIN_PATH", &plugin_path);
}

TestPlugin {
name: PLUGIN_NAME.parse().unwrap(),
path: PathBuf::from(PLUGIN_DIR),
path: plugin_path,
service_name: PLUGIN_SERVICE_NAME.parse().unwrap(),
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
mod helpers;

use ctor::ctor;
use helpers::{plugin, TestPlugin};
use crate::common::{plugin, TestPlugin};
use picotest::*;
use picotest_helpers::{LUA_OUTPUT_HEADER, OUTPUT_FOOTER};
use serde::{Deserialize, Serialize};
Expand All @@ -10,12 +7,7 @@ use uuid::Uuid;

static GLOBAL_CLUSTER_UUID: OnceLock<Uuid> = OnceLock::new();

#[ctor]
unsafe fn init_plugin() {
plugin();
}

#[picotest(path = "../tmp/test_plugin")]
#[picotest]
fn test_func_install_plugin(plugin: &TestPlugin) {
let cluster_uuid = GLOBAL_CLUSTER_UUID.get_or_init(|| cluster.uuid);
assert_eq!(cluster_uuid, &cluster.uuid);
Expand All @@ -28,7 +20,7 @@ fn test_func_install_plugin(plugin: &TestPlugin) {
assert!(enabled.is_ok_and(|enabled| enabled.contains("true")));
}

#[picotest(path = "../tmp/test_plugin")]
#[picotest]
fn test_apply_config(plugin: &TestPlugin) {
let cluster_uuid = GLOBAL_CLUSTER_UUID.get_or_init(|| cluster.uuid);
assert_eq!(cluster_uuid, &cluster.uuid);
Expand Down Expand Up @@ -56,7 +48,7 @@ fn test_apply_config(plugin: &TestPlugin) {
assert!(service_properties.contains(must_be_overriden));
}

#[picotest(path = "../tmp/test_plugin")]
#[picotest]
fn test_get_instances() {
let cluster_uuid = GLOBAL_CLUSTER_UUID.get_or_init(|| cluster.uuid);
assert_eq!(cluster_uuid, &cluster.uuid);
Expand All @@ -65,7 +57,7 @@ fn test_get_instances() {
assert_eq!(cluster.main().pg_port, 5433)
}

#[picotest(path = "../tmp/test_plugin")]
#[picotest]
#[case(1, 1)]
#[case(2, 2)]
#[case(3, 3)]
Expand All @@ -75,7 +67,7 @@ fn test_function_with_case(#[case] input: i32, #[case] expected: i32) {
assert_eq!(input, expected);
}

#[picotest(path = "../tmp/test_plugin")]
#[picotest]
mod test_mod {
use crate::{plugin, TestPlugin};
use std::sync::OnceLock;
Expand Down Expand Up @@ -108,7 +100,7 @@ mod test_mod {
}
}

#[picotest(path = "../tmp/test_plugin")]
#[picotest]
fn test_select_from_missing_table() {
let result = cluster.run_query("SELECT * FROM table1");
assert!(result.is_err(), "result : {:?}", result);
Expand All @@ -125,7 +117,7 @@ pub struct ExampleResponse {
}

#[tokio::test]
#[picotest(path = "../tmp/test_plugin")]
#[picotest]
async fn test_rpc_handle(plugin: &TestPlugin) {
let user_to_send = User {
name: "Dodo".to_string(),
Expand All @@ -149,15 +141,15 @@ async fn test_rpc_handle(plugin: &TestPlugin) {
);
}

#[picotest(path = "../tmp/test_plugin")]
#[picotest]
fn test_run_lua_query(_plugin: &TestPlugin) {
let res = cluster.instances()[1].run_lua("return 1 + 1").unwrap();
assert!(res.contains("2"));
assert!(!res.contains(LUA_OUTPUT_HEADER));
assert!(!res.contains(OUTPUT_FOOTER));
}

#[picotest(path = "../tmp/test_plugin")]
#[picotest]
fn test_run_lua_select_and_serialize_output_from_yaml() {
// This test creates box and insert some values into it.
// Then tries to select those values through Lua query
Expand Down
13 changes: 13 additions & 0 deletions picotest/tests/integration_suite/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#[path = "../common/mod.rs"]
mod common;
mod integration;
mod pgproto;

use ctor::ctor;

pub use common::{plugin, TestPlugin};

#[ctor]
unsafe fn init_plugin() {
plugin();
}
Loading
Loading