mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-27 11:51:13 +01:00
add workspace/folder/environment commands and reorganize cli tests
This commit is contained in:
@@ -145,7 +145,7 @@ Existing behavior stays the same, just reorganized. Remove the `get` command.
|
||||
|
||||
### Phase 2: Add missing CRUD commands
|
||||
|
||||
Status: in progress (request `show` and `delete` implemented)
|
||||
Status: in progress (`show`/`create`/`delete` implemented for workspace, request, folder, environment; JSON update flow pending)
|
||||
|
||||
1. `workspace show <id>`
|
||||
2. `workspace create --name <name>` (and `--json`)
|
||||
|
||||
69
crates-cli/yaak-cli/README.md
Normal file
69
crates-cli/yaak-cli/README.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# yaak-cli
|
||||
|
||||
Command-line interface for Yaak.
|
||||
|
||||
## Command Overview
|
||||
|
||||
Current top-level commands:
|
||||
|
||||
```text
|
||||
yaakcli send <request_id>
|
||||
yaakcli workspace list
|
||||
yaakcli workspace show <workspace_id>
|
||||
yaakcli workspace create --name <name>
|
||||
yaakcli workspace delete <workspace_id> [--yes]
|
||||
yaakcli request list <workspace_id>
|
||||
yaakcli request show <request_id>
|
||||
yaakcli request send <request_id>
|
||||
yaakcli request create <workspace_id> --name <name> --url <url> [--method GET]
|
||||
yaakcli request delete <request_id> [--yes]
|
||||
yaakcli folder list <workspace_id>
|
||||
yaakcli folder show <folder_id>
|
||||
yaakcli folder create <workspace_id> --name <name>
|
||||
yaakcli folder delete <folder_id> [--yes]
|
||||
yaakcli environment list <workspace_id>
|
||||
yaakcli environment show <environment_id>
|
||||
yaakcli environment create <workspace_id> --name <name>
|
||||
yaakcli environment delete <environment_id> [--yes]
|
||||
```
|
||||
|
||||
Global options:
|
||||
|
||||
- `--data-dir <path>`: use a custom data directory
|
||||
- `-e, --environment <id>`: environment to use during request rendering/sending
|
||||
- `-v, --verbose`: verbose logging and send output
|
||||
|
||||
Notes:
|
||||
|
||||
- `send` is currently a shortcut for sending an HTTP request ID.
|
||||
- `delete` commands prompt for confirmation unless `--yes` is provided.
|
||||
- In non-interactive mode, `delete` commands require `--yes`.
|
||||
|
||||
## Examples
|
||||
|
||||
```bash
|
||||
yaakcli workspace list
|
||||
yaakcli workspace create --name "My Workspace"
|
||||
yaakcli workspace show wk_abc
|
||||
yaakcli request list wk_abc
|
||||
yaakcli request show rq_abc
|
||||
yaakcli request create wk_abc --name "Users" --url "https://api.example.com/users"
|
||||
yaakcli request send rq_abc -e ev_abc
|
||||
yaakcli request delete rq_abc --yes
|
||||
yaakcli folder create wk_abc --name "Auth"
|
||||
yaakcli environment create wk_abc --name "Production"
|
||||
```
|
||||
|
||||
## Roadmap
|
||||
|
||||
Planned command expansion (JSON create/update, request schema, and polymorphic send) is tracked in `PLAN.md`.
|
||||
|
||||
When command behavior changes, update this README and verify with:
|
||||
|
||||
```bash
|
||||
cargo run -q -p yaak-cli -- --help
|
||||
cargo run -q -p yaak-cli -- request --help
|
||||
cargo run -q -p yaak-cli -- workspace --help
|
||||
cargo run -q -p yaak-cli -- folder --help
|
||||
cargo run -q -p yaak-cli -- environment --help
|
||||
```
|
||||
@@ -32,12 +32,10 @@ pub enum Commands {
|
||||
/// Request commands
|
||||
Request(RequestArgs),
|
||||
|
||||
/// Folder commands (coming soon)
|
||||
#[command(hide = true)]
|
||||
/// Folder commands
|
||||
Folder(FolderArgs),
|
||||
|
||||
/// Environment commands (coming soon)
|
||||
#[command(hide = true)]
|
||||
/// Environment commands
|
||||
Environment(EnvironmentArgs),
|
||||
}
|
||||
|
||||
@@ -57,6 +55,29 @@ pub struct WorkspaceArgs {
|
||||
pub enum WorkspaceCommands {
|
||||
/// List all workspaces
|
||||
List,
|
||||
|
||||
/// Show a workspace as JSON
|
||||
Show {
|
||||
/// Workspace ID
|
||||
workspace_id: String,
|
||||
},
|
||||
|
||||
/// Create a workspace
|
||||
Create {
|
||||
/// Workspace name
|
||||
#[arg(short, long)]
|
||||
name: String,
|
||||
},
|
||||
|
||||
/// Delete a workspace
|
||||
Delete {
|
||||
/// Workspace ID
|
||||
workspace_id: String,
|
||||
|
||||
/// Skip confirmation prompt
|
||||
#[arg(short, long)]
|
||||
yes: bool,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
@@ -115,7 +136,83 @@ pub enum RequestCommands {
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
pub struct FolderArgs {}
|
||||
pub struct FolderArgs {
|
||||
#[command(subcommand)]
|
||||
pub command: FolderCommands,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum FolderCommands {
|
||||
/// List folders in a workspace
|
||||
List {
|
||||
/// Workspace ID
|
||||
workspace_id: String,
|
||||
},
|
||||
|
||||
/// Show a folder as JSON
|
||||
Show {
|
||||
/// Folder ID
|
||||
folder_id: String,
|
||||
},
|
||||
|
||||
/// Create a folder
|
||||
Create {
|
||||
/// Workspace ID
|
||||
workspace_id: String,
|
||||
|
||||
/// Folder name
|
||||
#[arg(short, long)]
|
||||
name: String,
|
||||
},
|
||||
|
||||
/// Delete a folder
|
||||
Delete {
|
||||
/// Folder ID
|
||||
folder_id: String,
|
||||
|
||||
/// Skip confirmation prompt
|
||||
#[arg(short, long)]
|
||||
yes: bool,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
pub struct EnvironmentArgs {}
|
||||
pub struct EnvironmentArgs {
|
||||
#[command(subcommand)]
|
||||
pub command: EnvironmentCommands,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum EnvironmentCommands {
|
||||
/// List environments in a workspace
|
||||
List {
|
||||
/// Workspace ID
|
||||
workspace_id: String,
|
||||
},
|
||||
|
||||
/// Show an environment as JSON
|
||||
Show {
|
||||
/// Environment ID
|
||||
environment_id: String,
|
||||
},
|
||||
|
||||
/// Create an environment
|
||||
Create {
|
||||
/// Workspace ID
|
||||
workspace_id: String,
|
||||
|
||||
/// Environment name
|
||||
#[arg(short, long)]
|
||||
name: String,
|
||||
},
|
||||
|
||||
/// Delete an environment
|
||||
Delete {
|
||||
/// Environment ID
|
||||
environment_id: String,
|
||||
|
||||
/// Skip confirmation prompt
|
||||
#[arg(short, long)]
|
||||
yes: bool,
|
||||
},
|
||||
}
|
||||
|
||||
16
crates-cli/yaak-cli/src/commands/confirm.rs
Normal file
16
crates-cli/yaak-cli/src/commands/confirm.rs
Normal file
@@ -0,0 +1,16 @@
|
||||
use std::io::{self, IsTerminal, Write};
|
||||
|
||||
pub fn confirm_delete(resource_name: &str, resource_id: &str) -> bool {
|
||||
if !io::stdin().is_terminal() {
|
||||
eprintln!("Refusing to delete in non-interactive mode without --yes");
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
print!("Delete {resource_name} {resource_id}? [y/N]: ");
|
||||
io::stdout().flush().expect("Failed to flush stdout");
|
||||
|
||||
let mut input = String::new();
|
||||
io::stdin().read_line(&mut input).expect("Failed to read confirmation");
|
||||
|
||||
matches!(input.trim().to_lowercase().as_str(), "y" | "yes")
|
||||
}
|
||||
64
crates-cli/yaak-cli/src/commands/environment.rs
Normal file
64
crates-cli/yaak-cli/src/commands/environment.rs
Normal file
@@ -0,0 +1,64 @@
|
||||
use crate::cli::{EnvironmentArgs, EnvironmentCommands};
|
||||
use crate::commands::confirm::confirm_delete;
|
||||
use crate::context::CliContext;
|
||||
use yaak_models::models::Environment;
|
||||
use yaak_models::util::UpdateSource;
|
||||
|
||||
pub fn run(ctx: &CliContext, args: EnvironmentArgs) {
|
||||
match args.command {
|
||||
EnvironmentCommands::List { workspace_id } => list(ctx, &workspace_id),
|
||||
EnvironmentCommands::Show { environment_id } => show(ctx, &environment_id),
|
||||
EnvironmentCommands::Create { workspace_id, name } => create(ctx, workspace_id, name),
|
||||
EnvironmentCommands::Delete { environment_id, yes } => delete(ctx, &environment_id, yes),
|
||||
}
|
||||
}
|
||||
|
||||
fn list(ctx: &CliContext, workspace_id: &str) {
|
||||
let environments =
|
||||
ctx.db().list_environments_ensure_base(workspace_id).expect("Failed to list environments");
|
||||
|
||||
if environments.is_empty() {
|
||||
println!("No environments found in workspace {}", workspace_id);
|
||||
} else {
|
||||
for environment in environments {
|
||||
println!("{} - {} ({})", environment.id, environment.name, environment.parent_model);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn show(ctx: &CliContext, environment_id: &str) {
|
||||
let environment = ctx.db().get_environment(environment_id).expect("Failed to get environment");
|
||||
let output =
|
||||
serde_json::to_string_pretty(&environment).expect("Failed to serialize environment");
|
||||
println!("{output}");
|
||||
}
|
||||
|
||||
fn create(ctx: &CliContext, workspace_id: String, name: String) {
|
||||
let environment = Environment {
|
||||
workspace_id,
|
||||
name,
|
||||
parent_model: "environment".to_string(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let created = ctx
|
||||
.db()
|
||||
.upsert_environment(&environment, &UpdateSource::Sync)
|
||||
.expect("Failed to create environment");
|
||||
|
||||
println!("Created environment: {}", created.id);
|
||||
}
|
||||
|
||||
fn delete(ctx: &CliContext, environment_id: &str, yes: bool) {
|
||||
if !yes && !confirm_delete("environment", environment_id) {
|
||||
println!("Aborted");
|
||||
return;
|
||||
}
|
||||
|
||||
let deleted = ctx
|
||||
.db()
|
||||
.delete_environment_by_id(environment_id, &UpdateSource::Sync)
|
||||
.expect("Failed to delete environment");
|
||||
|
||||
println!("Deleted environment: {}", deleted.id);
|
||||
}
|
||||
54
crates-cli/yaak-cli/src/commands/folder.rs
Normal file
54
crates-cli/yaak-cli/src/commands/folder.rs
Normal file
@@ -0,0 +1,54 @@
|
||||
use crate::cli::{FolderArgs, FolderCommands};
|
||||
use crate::commands::confirm::confirm_delete;
|
||||
use crate::context::CliContext;
|
||||
use yaak_models::models::Folder;
|
||||
use yaak_models::util::UpdateSource;
|
||||
|
||||
pub fn run(ctx: &CliContext, args: FolderArgs) {
|
||||
match args.command {
|
||||
FolderCommands::List { workspace_id } => list(ctx, &workspace_id),
|
||||
FolderCommands::Show { folder_id } => show(ctx, &folder_id),
|
||||
FolderCommands::Create { workspace_id, name } => create(ctx, workspace_id, name),
|
||||
FolderCommands::Delete { folder_id, yes } => delete(ctx, &folder_id, yes),
|
||||
}
|
||||
}
|
||||
|
||||
fn list(ctx: &CliContext, workspace_id: &str) {
|
||||
let folders = ctx.db().list_folders(workspace_id).expect("Failed to list folders");
|
||||
if folders.is_empty() {
|
||||
println!("No folders found in workspace {}", workspace_id);
|
||||
} else {
|
||||
for folder in folders {
|
||||
println!("{} - {}", folder.id, folder.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn show(ctx: &CliContext, folder_id: &str) {
|
||||
let folder = ctx.db().get_folder(folder_id).expect("Failed to get folder");
|
||||
let output = serde_json::to_string_pretty(&folder).expect("Failed to serialize folder");
|
||||
println!("{output}");
|
||||
}
|
||||
|
||||
fn create(ctx: &CliContext, workspace_id: String, name: String) {
|
||||
let folder = Folder { workspace_id, name, ..Default::default() };
|
||||
|
||||
let created =
|
||||
ctx.db().upsert_folder(&folder, &UpdateSource::Sync).expect("Failed to create folder");
|
||||
|
||||
println!("Created folder: {}", created.id);
|
||||
}
|
||||
|
||||
fn delete(ctx: &CliContext, folder_id: &str, yes: bool) {
|
||||
if !yes && !confirm_delete("folder", folder_id) {
|
||||
println!("Aborted");
|
||||
return;
|
||||
}
|
||||
|
||||
let deleted = ctx
|
||||
.db()
|
||||
.delete_folder_by_id(folder_id, &UpdateSource::Sync)
|
||||
.expect("Failed to delete folder");
|
||||
|
||||
println!("Deleted folder: {}", deleted.id);
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
pub mod confirm;
|
||||
pub mod environment;
|
||||
pub mod folder;
|
||||
pub mod request;
|
||||
pub mod send;
|
||||
pub mod workspace;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use crate::cli::{RequestArgs, RequestCommands};
|
||||
use crate::commands::confirm::confirm_delete;
|
||||
use crate::context::CliContext;
|
||||
use log::info;
|
||||
use serde_json::Value;
|
||||
use std::collections::BTreeMap;
|
||||
use std::io::{self, IsTerminal, Write};
|
||||
use tokio::sync::mpsc;
|
||||
use yaak_http::path_placeholders::apply_path_placeholders;
|
||||
use yaak_http::sender::{HttpSender, ReqwestSender};
|
||||
@@ -30,10 +30,7 @@ pub async fn run(ctx: &CliContext, args: RequestArgs, environment: Option<&str>,
|
||||
}
|
||||
|
||||
fn list(ctx: &CliContext, workspace_id: &str) {
|
||||
let requests = ctx
|
||||
.db()
|
||||
.list_http_requests(workspace_id)
|
||||
.expect("Failed to list requests");
|
||||
let requests = ctx.db().list_http_requests(workspace_id).expect("Failed to list requests");
|
||||
if requests.is_empty() {
|
||||
println!("No requests found in workspace {}", workspace_id);
|
||||
} else {
|
||||
@@ -61,16 +58,13 @@ fn create(ctx: &CliContext, workspace_id: String, name: String, method: String,
|
||||
}
|
||||
|
||||
fn show(ctx: &CliContext, request_id: &str) {
|
||||
let request = ctx
|
||||
.db()
|
||||
.get_http_request(request_id)
|
||||
.expect("Failed to get request");
|
||||
let request = ctx.db().get_http_request(request_id).expect("Failed to get request");
|
||||
let output = serde_json::to_string_pretty(&request).expect("Failed to serialize request");
|
||||
println!("{output}");
|
||||
}
|
||||
|
||||
fn delete(ctx: &CliContext, request_id: &str, yes: bool) {
|
||||
if !yes && !confirm_delete_request(request_id) {
|
||||
if !yes && !confirm_delete("request", request_id) {
|
||||
println!("Aborted");
|
||||
return;
|
||||
}
|
||||
@@ -82,21 +76,6 @@ fn delete(ctx: &CliContext, request_id: &str, yes: bool) {
|
||||
println!("Deleted request: {}", deleted.id);
|
||||
}
|
||||
|
||||
fn confirm_delete_request(request_id: &str) -> bool {
|
||||
if !io::stdin().is_terminal() {
|
||||
eprintln!("Refusing to delete in non-interactive mode without --yes");
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
print!("Delete request {request_id}? [y/N]: ");
|
||||
io::stdout().flush().expect("Failed to flush stdout");
|
||||
|
||||
let mut input = String::new();
|
||||
io::stdin().read_line(&mut input).expect("Failed to read confirmation");
|
||||
|
||||
matches!(input.trim().to_lowercase().as_str(), "y" | "yes")
|
||||
}
|
||||
|
||||
/// Send a request by ID and print response in the same format as legacy `send`.
|
||||
pub async fn send_request_by_id(
|
||||
ctx: &CliContext,
|
||||
@@ -104,18 +83,11 @@ pub async fn send_request_by_id(
|
||||
environment: Option<&str>,
|
||||
verbose: bool,
|
||||
) {
|
||||
let request = ctx
|
||||
.db()
|
||||
.get_http_request(request_id)
|
||||
.expect("Failed to get request");
|
||||
let request = ctx.db().get_http_request(request_id).expect("Failed to get request");
|
||||
|
||||
let environment_chain = ctx
|
||||
.db()
|
||||
.resolve_environments(
|
||||
&request.workspace_id,
|
||||
request.folder_id.as_deref(),
|
||||
environment,
|
||||
)
|
||||
.resolve_environments(&request.workspace_id, request.folder_id.as_deref(), environment)
|
||||
.unwrap_or_default();
|
||||
|
||||
let plugin_context = PluginContext::new(None, Some(request.workspace_id.clone()));
|
||||
@@ -169,11 +141,7 @@ pub async fn send_request_by_id(
|
||||
if verbose {
|
||||
println!();
|
||||
}
|
||||
println!(
|
||||
"HTTP {} {}",
|
||||
response.status,
|
||||
response.status_reason.as_deref().unwrap_or("")
|
||||
);
|
||||
println!("HTTP {} {}", response.status, response.status_reason.as_deref().unwrap_or(""));
|
||||
|
||||
if verbose {
|
||||
for (name, value) in &response.headers {
|
||||
@@ -267,12 +235,5 @@ async fn render_http_request(
|
||||
|
||||
let (url, url_parameters) = apply_path_placeholders(&url, &url_parameters);
|
||||
|
||||
Ok(HttpRequest {
|
||||
url,
|
||||
url_parameters,
|
||||
headers,
|
||||
body,
|
||||
authentication,
|
||||
..request.to_owned()
|
||||
})
|
||||
Ok(HttpRequest { url, url_parameters, headers, body, authentication, ..request.to_owned() })
|
||||
}
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
use crate::cli::{WorkspaceArgs, WorkspaceCommands};
|
||||
use crate::commands::confirm::confirm_delete;
|
||||
use crate::context::CliContext;
|
||||
use yaak_models::models::Workspace;
|
||||
use yaak_models::util::UpdateSource;
|
||||
|
||||
pub fn run(ctx: &CliContext, args: WorkspaceArgs) {
|
||||
match args.command {
|
||||
WorkspaceCommands::List => list(ctx),
|
||||
WorkspaceCommands::Show { workspace_id } => show(ctx, &workspace_id),
|
||||
WorkspaceCommands::Create { name } => create(ctx, name),
|
||||
WorkspaceCommands::Delete { workspace_id, yes } => delete(ctx, &workspace_id, yes),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,3 +23,31 @@ fn list(ctx: &CliContext) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn show(ctx: &CliContext, workspace_id: &str) {
|
||||
let workspace = ctx.db().get_workspace(workspace_id).expect("Failed to get workspace");
|
||||
let output = serde_json::to_string_pretty(&workspace).expect("Failed to serialize workspace");
|
||||
println!("{output}");
|
||||
}
|
||||
|
||||
fn create(ctx: &CliContext, name: String) {
|
||||
let workspace = Workspace { name, ..Default::default() };
|
||||
let created = ctx
|
||||
.db()
|
||||
.upsert_workspace(&workspace, &UpdateSource::Sync)
|
||||
.expect("Failed to create workspace");
|
||||
println!("Created workspace: {}", created.id);
|
||||
}
|
||||
|
||||
fn delete(ctx: &CliContext, workspace_id: &str, yes: bool) {
|
||||
if !yes && !confirm_delete("workspace", workspace_id) {
|
||||
println!("Aborted");
|
||||
return;
|
||||
}
|
||||
|
||||
let deleted = ctx
|
||||
.db()
|
||||
.delete_workspace_by_id(workspace_id, &UpdateSource::Sync)
|
||||
.expect("Failed to delete workspace");
|
||||
println!("Deleted workspace: {}", deleted.id);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,8 @@ impl CliContext {
|
||||
let blob_path = data_dir.join("blobs.sqlite");
|
||||
|
||||
let (query_manager, _blob_manager, _rx) =
|
||||
yaak_models::init_standalone(&db_path, &blob_path).expect("Failed to initialize database");
|
||||
yaak_models::init_standalone(&db_path, &blob_path)
|
||||
.expect("Failed to initialize database");
|
||||
|
||||
let encryption_manager = Arc::new(EncryptionManager::new(query_manager.clone(), app_id));
|
||||
|
||||
|
||||
@@ -16,8 +16,9 @@ async fn main() {
|
||||
|
||||
let app_id = if cfg!(debug_assertions) { "app.yaak.desktop.dev" } else { "app.yaak.desktop" };
|
||||
|
||||
let data_dir =
|
||||
data_dir.unwrap_or_else(|| dirs::data_dir().expect("Could not determine data directory").join(app_id));
|
||||
let data_dir = data_dir.unwrap_or_else(|| {
|
||||
dirs::data_dir().expect("Could not determine data directory").join(app_id)
|
||||
});
|
||||
|
||||
let context = CliContext::initialize(data_dir, app_id).await;
|
||||
|
||||
@@ -34,13 +35,13 @@ async fn main() {
|
||||
commands::request::run(&context, args, environment.as_deref(), verbose).await;
|
||||
0
|
||||
}
|
||||
Commands::Folder(_) => {
|
||||
eprintln!("Folder commands are not implemented yet");
|
||||
1
|
||||
Commands::Folder(args) => {
|
||||
commands::folder::run(&context, args);
|
||||
0
|
||||
}
|
||||
Commands::Environment(_) => {
|
||||
eprintln!("Environment commands are not implemented yet");
|
||||
1
|
||||
Commands::Environment(args) => {
|
||||
commands::environment::run(&context, args);
|
||||
0
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
60
crates-cli/yaak-cli/tests/common/mod.rs
Normal file
60
crates-cli/yaak-cli/tests/common/mod.rs
Normal file
@@ -0,0 +1,60 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use assert_cmd::Command;
|
||||
use assert_cmd::cargo::cargo_bin_cmd;
|
||||
use std::path::Path;
|
||||
use yaak_models::models::{HttpRequest, Workspace};
|
||||
use yaak_models::query_manager::QueryManager;
|
||||
use yaak_models::util::UpdateSource;
|
||||
|
||||
pub fn cli_cmd(data_dir: &Path) -> Command {
|
||||
let mut cmd = cargo_bin_cmd!("yaakcli");
|
||||
cmd.arg("--data-dir").arg(data_dir);
|
||||
cmd
|
||||
}
|
||||
|
||||
pub fn parse_created_id(stdout: &[u8], label: &str) -> String {
|
||||
String::from_utf8_lossy(stdout)
|
||||
.trim()
|
||||
.split_once(": ")
|
||||
.map(|(_, id)| id.to_string())
|
||||
.unwrap_or_else(|| panic!("Expected id in '{label}' output"))
|
||||
}
|
||||
|
||||
pub fn query_manager(data_dir: &Path) -> QueryManager {
|
||||
let db_path = data_dir.join("db.sqlite");
|
||||
let blob_path = data_dir.join("blobs.sqlite");
|
||||
let (query_manager, _blob_manager, _rx) =
|
||||
yaak_models::init_standalone(&db_path, &blob_path).expect("Failed to initialize DB");
|
||||
query_manager
|
||||
}
|
||||
|
||||
pub fn seed_workspace(data_dir: &Path, workspace_id: &str) {
|
||||
let workspace = Workspace {
|
||||
id: workspace_id.to_string(),
|
||||
name: "Seed Workspace".to_string(),
|
||||
description: "Seeded for integration tests".to_string(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
query_manager(data_dir)
|
||||
.connect()
|
||||
.upsert_workspace(&workspace, &UpdateSource::Sync)
|
||||
.expect("Failed to seed workspace");
|
||||
}
|
||||
|
||||
pub fn seed_request(data_dir: &Path, workspace_id: &str, request_id: &str) {
|
||||
let request = HttpRequest {
|
||||
id: request_id.to_string(),
|
||||
workspace_id: workspace_id.to_string(),
|
||||
name: "Seeded Request".to_string(),
|
||||
method: "GET".to_string(),
|
||||
url: "https://example.com".to_string(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
query_manager(data_dir)
|
||||
.connect()
|
||||
.upsert_http_request(&request, &UpdateSource::Sync)
|
||||
.expect("Failed to seed request");
|
||||
}
|
||||
50
crates-cli/yaak-cli/tests/environment_commands.rs
Normal file
50
crates-cli/yaak-cli/tests/environment_commands.rs
Normal file
@@ -0,0 +1,50 @@
|
||||
mod common;
|
||||
|
||||
use common::{cli_cmd, parse_created_id, query_manager, seed_workspace};
|
||||
use predicates::str::contains;
|
||||
use tempfile::TempDir;
|
||||
|
||||
#[test]
|
||||
fn create_list_show_delete_round_trip() {
|
||||
let temp_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
let data_dir = temp_dir.path();
|
||||
seed_workspace(data_dir, "wk_test");
|
||||
|
||||
cli_cmd(data_dir)
|
||||
.args(["environment", "list", "wk_test"])
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(contains("Global Variables"));
|
||||
|
||||
let create_assert = cli_cmd(data_dir)
|
||||
.args(["environment", "create", "wk_test", "--name", "Production"])
|
||||
.assert()
|
||||
.success();
|
||||
let environment_id =
|
||||
parse_created_id(&create_assert.get_output().stdout, "environment create");
|
||||
|
||||
cli_cmd(data_dir)
|
||||
.args(["environment", "list", "wk_test"])
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(contains(&environment_id))
|
||||
.stdout(contains("Production"));
|
||||
|
||||
cli_cmd(data_dir)
|
||||
.args(["environment", "show", &environment_id])
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(contains(format!("\"id\": \"{environment_id}\"")))
|
||||
.stdout(contains("\"parentModel\": \"environment\""));
|
||||
|
||||
cli_cmd(data_dir)
|
||||
.args(["environment", "delete", &environment_id, "--yes"])
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(contains(format!("Deleted environment: {environment_id}")));
|
||||
|
||||
assert!(query_manager(data_dir)
|
||||
.connect()
|
||||
.get_environment(&environment_id)
|
||||
.is_err());
|
||||
}
|
||||
40
crates-cli/yaak-cli/tests/folder_commands.rs
Normal file
40
crates-cli/yaak-cli/tests/folder_commands.rs
Normal file
@@ -0,0 +1,40 @@
|
||||
mod common;
|
||||
|
||||
use common::{cli_cmd, parse_created_id, query_manager, seed_workspace};
|
||||
use predicates::str::contains;
|
||||
use tempfile::TempDir;
|
||||
|
||||
#[test]
|
||||
fn create_list_show_delete_round_trip() {
|
||||
let temp_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
let data_dir = temp_dir.path();
|
||||
seed_workspace(data_dir, "wk_test");
|
||||
|
||||
let create_assert = cli_cmd(data_dir)
|
||||
.args(["folder", "create", "wk_test", "--name", "Auth"])
|
||||
.assert()
|
||||
.success();
|
||||
let folder_id = parse_created_id(&create_assert.get_output().stdout, "folder create");
|
||||
|
||||
cli_cmd(data_dir)
|
||||
.args(["folder", "list", "wk_test"])
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(contains(&folder_id))
|
||||
.stdout(contains("Auth"));
|
||||
|
||||
cli_cmd(data_dir)
|
||||
.args(["folder", "show", &folder_id])
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(contains(format!("\"id\": \"{folder_id}\"")))
|
||||
.stdout(contains("\"workspaceId\": \"wk_test\""));
|
||||
|
||||
cli_cmd(data_dir)
|
||||
.args(["folder", "delete", &folder_id, "--yes"])
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(contains(format!("Deleted folder: {folder_id}")));
|
||||
|
||||
assert!(query_manager(data_dir).connect().get_folder(&folder_id).is_err());
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
use assert_cmd::cargo::cargo_bin_cmd;
|
||||
use assert_cmd::Command;
|
||||
use predicates::str::contains;
|
||||
use std::path::Path;
|
||||
use tempfile::TempDir;
|
||||
use yaak_models::models::{HttpRequest, Workspace};
|
||||
use yaak_models::util::UpdateSource;
|
||||
|
||||
fn cli_cmd(data_dir: &Path) -> Command {
|
||||
let mut cmd = cargo_bin_cmd!("yaakcli");
|
||||
cmd.arg("--data-dir").arg(data_dir);
|
||||
cmd
|
||||
}
|
||||
|
||||
fn seed_workspace(data_dir: &Path, workspace_id: &str) {
|
||||
let db_path = data_dir.join("db.sqlite");
|
||||
let blob_path = data_dir.join("blobs.sqlite");
|
||||
let (query_manager, _blob_manager, _rx) =
|
||||
yaak_models::init_standalone(&db_path, &blob_path).expect("Failed to initialize DB");
|
||||
|
||||
let workspace = Workspace {
|
||||
id: workspace_id.to_string(),
|
||||
name: "Test Workspace".to_string(),
|
||||
description: "Integration test workspace".to_string(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
query_manager
|
||||
.connect()
|
||||
.upsert_workspace(&workspace, &UpdateSource::Sync)
|
||||
.expect("Failed to seed workspace");
|
||||
}
|
||||
|
||||
fn seed_request(data_dir: &Path, workspace_id: &str, request_id: &str) {
|
||||
let db_path = data_dir.join("db.sqlite");
|
||||
let blob_path = data_dir.join("blobs.sqlite");
|
||||
let (query_manager, _blob_manager, _rx) =
|
||||
yaak_models::init_standalone(&db_path, &blob_path).expect("Failed to initialize DB");
|
||||
|
||||
let request = HttpRequest {
|
||||
id: request_id.to_string(),
|
||||
workspace_id: workspace_id.to_string(),
|
||||
name: "Seeded Request".to_string(),
|
||||
method: "GET".to_string(),
|
||||
url: "https://example.com".to_string(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
query_manager
|
||||
.connect()
|
||||
.upsert_http_request(&request, &UpdateSource::Sync)
|
||||
.expect("Failed to seed request");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn request_show_and_delete_yes_round_trip() {
|
||||
let temp_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
let data_dir = temp_dir.path();
|
||||
seed_workspace(data_dir, "wk_test");
|
||||
|
||||
let create_assert = cli_cmd(data_dir)
|
||||
.args([
|
||||
"request",
|
||||
"create",
|
||||
"wk_test",
|
||||
"--name",
|
||||
"Smoke Test",
|
||||
"--url",
|
||||
"https://example.com",
|
||||
])
|
||||
.assert()
|
||||
.success();
|
||||
|
||||
let create_stdout = String::from_utf8_lossy(&create_assert.get_output().stdout).to_string();
|
||||
let request_id = create_stdout
|
||||
.trim()
|
||||
.split_once(": ")
|
||||
.map(|(_, id)| id.to_string())
|
||||
.expect("Expected request id in create output");
|
||||
|
||||
cli_cmd(data_dir)
|
||||
.args(["request", "show", &request_id])
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(contains(format!("\"id\": \"{request_id}\"")))
|
||||
.stdout(contains("\"workspaceId\": \"wk_test\""));
|
||||
|
||||
cli_cmd(data_dir)
|
||||
.args(["request", "delete", &request_id, "--yes"])
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(contains(format!("Deleted request: {request_id}")));
|
||||
|
||||
let db_path = data_dir.join("db.sqlite");
|
||||
let blob_path = data_dir.join("blobs.sqlite");
|
||||
let (query_manager, _blob_manager, _rx) =
|
||||
yaak_models::init_standalone(&db_path, &blob_path).expect("Failed to initialize DB");
|
||||
assert!(query_manager.connect().get_http_request(&request_id).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn request_delete_without_yes_fails_in_non_interactive_mode() {
|
||||
let temp_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
let data_dir = temp_dir.path();
|
||||
seed_workspace(data_dir, "wk_test");
|
||||
seed_request(data_dir, "wk_test", "rq_seed_delete_noninteractive");
|
||||
|
||||
cli_cmd(data_dir)
|
||||
.args(["request", "delete", "rq_seed_delete_noninteractive"])
|
||||
.assert()
|
||||
.failure()
|
||||
.code(1)
|
||||
.stderr(contains("Refusing to delete in non-interactive mode without --yes"));
|
||||
|
||||
let db_path = data_dir.join("db.sqlite");
|
||||
let blob_path = data_dir.join("blobs.sqlite");
|
||||
let (query_manager, _blob_manager, _rx) =
|
||||
yaak_models::init_standalone(&db_path, &blob_path).expect("Failed to initialize DB");
|
||||
assert!(query_manager.connect().get_http_request("rq_seed_delete_noninteractive").is_ok());
|
||||
}
|
||||
62
crates-cli/yaak-cli/tests/request_commands.rs
Normal file
62
crates-cli/yaak-cli/tests/request_commands.rs
Normal file
@@ -0,0 +1,62 @@
|
||||
mod common;
|
||||
|
||||
use common::{cli_cmd, parse_created_id, query_manager, seed_request, seed_workspace};
|
||||
use predicates::str::contains;
|
||||
use tempfile::TempDir;
|
||||
|
||||
#[test]
|
||||
fn show_and_delete_yes_round_trip() {
|
||||
let temp_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
let data_dir = temp_dir.path();
|
||||
seed_workspace(data_dir, "wk_test");
|
||||
|
||||
let create_assert = cli_cmd(data_dir)
|
||||
.args([
|
||||
"request",
|
||||
"create",
|
||||
"wk_test",
|
||||
"--name",
|
||||
"Smoke Test",
|
||||
"--url",
|
||||
"https://example.com",
|
||||
])
|
||||
.assert()
|
||||
.success();
|
||||
|
||||
let request_id = parse_created_id(&create_assert.get_output().stdout, "request create");
|
||||
|
||||
cli_cmd(data_dir)
|
||||
.args(["request", "show", &request_id])
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(contains(format!("\"id\": \"{request_id}\"")))
|
||||
.stdout(contains("\"workspaceId\": \"wk_test\""));
|
||||
|
||||
cli_cmd(data_dir)
|
||||
.args(["request", "delete", &request_id, "--yes"])
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(contains(format!("Deleted request: {request_id}")));
|
||||
|
||||
assert!(query_manager(data_dir).connect().get_http_request(&request_id).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn delete_without_yes_fails_in_non_interactive_mode() {
|
||||
let temp_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
let data_dir = temp_dir.path();
|
||||
seed_workspace(data_dir, "wk_test");
|
||||
seed_request(data_dir, "wk_test", "rq_seed_delete_noninteractive");
|
||||
|
||||
cli_cmd(data_dir)
|
||||
.args(["request", "delete", "rq_seed_delete_noninteractive"])
|
||||
.assert()
|
||||
.failure()
|
||||
.code(1)
|
||||
.stderr(contains("Refusing to delete in non-interactive mode without --yes"));
|
||||
|
||||
assert!(query_manager(data_dir)
|
||||
.connect()
|
||||
.get_http_request("rq_seed_delete_noninteractive")
|
||||
.is_ok());
|
||||
}
|
||||
35
crates-cli/yaak-cli/tests/workspace_commands.rs
Normal file
35
crates-cli/yaak-cli/tests/workspace_commands.rs
Normal file
@@ -0,0 +1,35 @@
|
||||
mod common;
|
||||
|
||||
use common::{cli_cmd, parse_created_id, query_manager};
|
||||
use predicates::str::contains;
|
||||
use tempfile::TempDir;
|
||||
|
||||
#[test]
|
||||
fn create_show_delete_round_trip() {
|
||||
let temp_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
let data_dir = temp_dir.path();
|
||||
|
||||
let create_assert = cli_cmd(data_dir)
|
||||
.args(["workspace", "create", "--name", "WS One"])
|
||||
.assert()
|
||||
.success();
|
||||
let workspace_id = parse_created_id(&create_assert.get_output().stdout, "workspace create");
|
||||
|
||||
cli_cmd(data_dir)
|
||||
.args(["workspace", "show", &workspace_id])
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(contains(format!("\"id\": \"{workspace_id}\"")))
|
||||
.stdout(contains("\"name\": \"WS One\""));
|
||||
|
||||
cli_cmd(data_dir)
|
||||
.args(["workspace", "delete", &workspace_id, "--yes"])
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(contains(format!("Deleted workspace: {workspace_id}")));
|
||||
|
||||
assert!(query_manager(data_dir)
|
||||
.connect()
|
||||
.get_workspace(&workspace_id)
|
||||
.is_err());
|
||||
}
|
||||
Reference in New Issue
Block a user