From 2343a54a630c4f016c566dffa1a494440fb7bc18 Mon Sep 17 00:00:00 2001 From: abhraina-aws Date: Fri, 8 Aug 2025 15:06:22 -0700 Subject: [PATCH 01/77] feat: Initial Framework with working tests --- e2etests/Cargo.lock | 202 +++++++++++++++++++++++++++ e2etests/Cargo.toml | 21 +++ e2etests/README.md | 109 +++++++++++++++ e2etests/run_tests.sh | 29 ++++ e2etests/src/lib.rs | 127 +++++++++++++++++ e2etests/tests/test_ai_prompt.rs | 89 ++++++++++++ e2etests/tests/test_help_command.rs | 53 +++++++ e2etests/tests/test_tools_command.rs | 52 +++++++ 8 files changed, 682 insertions(+) create mode 100644 e2etests/Cargo.lock create mode 100644 e2etests/Cargo.toml create mode 100644 e2etests/README.md create mode 100755 e2etests/run_tests.sh create mode 100644 e2etests/src/lib.rs create mode 100644 e2etests/tests/test_ai_prompt.rs create mode 100644 e2etests/tests/test_help_command.rs create mode 100644 e2etests/tests/test_tools_command.rs diff --git a/e2etests/Cargo.lock b/e2etests/Cargo.lock new file mode 100644 index 0000000000..6a810dc65e --- /dev/null +++ b/e2etests/Cargo.lock @@ -0,0 +1,202 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cfg-if" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" + +[[package]] +name = "conpty" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b72b06487a0d4683349ad74d62e87ad639b09667082b3c495c5b6bab7d84b3da" +dependencies = [ + "windows", +] + +[[package]] +name = "expectrl" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede784925953fcab9a3351d5009bcb8d2b0c13e940924c88087e8e2ce0c4717a" +dependencies = [ + "conpty", + "nix", + "ptyprocess", + "regex", +] + +[[package]] +name = "libc" +version = "0.2.174" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" + +[[package]] +name = "memchr" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" + +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + +[[package]] +name = "nix" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +dependencies = [ + "bitflags", + "cfg-if", + "libc", + "memoffset", + "pin-utils", +] + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "ptyprocess" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e05aef7befb11a210468a2d77d978dde2c6381a0381e33beb575e91f57fe8cf" +dependencies = [ + "nix", +] + +[[package]] +name = "q-cli-e2e-tests" +version = "0.1.0" +dependencies = [ + "expectrl", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "windows" +version = "0.44.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e745dab35a0c4c77aa3ce42d595e13d2003d6902d6b08c9ef5fc326d08da12b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" diff --git a/e2etests/Cargo.toml b/e2etests/Cargo.toml new file mode 100644 index 0000000000..853bffcfef --- /dev/null +++ b/e2etests/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "q-cli-e2e-tests" +version = "0.1.0" +edition = "2021" + +[workspace] + +[dependencies] +expectrl = "0.7" + +[[test]] +name = "test_help_command" +path = "tests/test_help_command.rs" + +[[test]] +name = "test_tools_command" +path = "tests/test_tools_command.rs" + +[[test]] +name = "test_ai_prompt" +path = "tests/test_ai_prompt.rs" diff --git a/e2etests/README.md b/e2etests/README.md new file mode 100644 index 0000000000..ff02ad43eb --- /dev/null +++ b/e2etests/README.md @@ -0,0 +1,109 @@ +# Q CLI E2E Test Framework + +This test framework provides comprehensive end-to-end testing capabilities for Amazon Q CLI using a hybrid approach with expectrl. + +## πŸ—οΈ Architecture + +### **Hybrid Approach** +- **expectrl (PTY)**: For interactive commands (`/help`, `/tools`, `/quit`, etc.) +- **Direct Process Streams**: For AI prompts ("What is AWS?", "Hello", etc.) + +### **Why Hybrid?** +- **Commands** write to PTY stream β†’ expectrl captures perfectly βœ… +- **AI responses** write to stdout β†’ direct streams capture properly βœ… + +## πŸ“ Core Files + +### **`tests/q_chat_helper.rs`** +Base helper class providing: +- `QChatSession::new()` - Start Q Chat session +- `execute_command(cmd)` - Execute commands using expectrl + carriage return (`0x0D`) +- `send_prompt(prompt)` - Send AI prompts using direct process streams +- `quit()` - Clean session termination + +### **Test Files** +- **`test_help_command.rs`** - Tests `/help` command with full content verification +- **`test_tools_command.rs`** - Tests `/tools` command with tool listing verification +- **`test_ai_prompt.rs`** - Tests AI prompts with response content verification + +## πŸš€ Usage + +### **Using Default System Q CLI Binary** +```bash +cd e2etests +./run_tests.sh +``` + +### **Using Custom Q CLI Builds** +Set the `Q_CLI_PATH` environment variable or pass the path directly: + +```bash +# Test with workspace build +./run_tests.sh ../target/release/chat_cli + +# Test with custom build +export Q_CLI_PATH="/path/to/your/custom/chat_cli" +cargo test --test test_help_command -- --nocapture + +# Or use the convenience script +./run_tests.sh /path/to/your/custom/chat_cli test_help_command +./run_tests.sh /path/to/your/custom/chat_cli # Run all tests +``` + +### **Run Individual Tests** +```bash +# Test help command +cargo test --test test_help_command -- --nocapture + +# Test AI prompts +cargo test --test test_ai_prompt test_what_is_aws_prompt -- --nocapture + +# Test tools command +cargo test --test test_tools_command -- --nocapture +``` + +### **Run All Tests** +```bash +cargo test --test test_help_command --test test_tools_command --test test_ai_prompt -- --nocapture +``` + +## βœ… Test Coverage + +### **Commands Tested** +- `/help` - Full help content with Commands, Options, MCP, Tips sections +- `/tools` - Tool listing with Built-in and MCP tools, permission status + +### **AI Prompts Tested** +- "What is AWS?" - Technical explanation with verification +- "Hello" - Basic greeting response + +### **Verification Includes** +- **Content verification**: Specific text and sections present +- **Response quality**: Technical terms, appropriate length +- **Full output capture**: Complete interaction including UI elements + +## 🎯 Success Metrics + +- **Help Command**: 2343+ bytes, all sections verified βœ… +- **Tools Command**: 3355+ bytes, all tools and permissions verified βœ… +- **AI Prompts**: 5000+ bytes, complete technical responses verified βœ… + +## πŸ”§ Integration with Workspace + +This E2E test framework is designed to work with the Q CLI workspace: + +- **Default binary**: Uses system `q` command (from PATH) +- **Workspace integration**: Can test the workspace build with `./run_tests.sh ../target/release/chat_cli` +- **CI/CD ready**: Can be integrated into build pipelines +- **Custom binary support**: Test different builds as needed + +## πŸ”§ Extending + +To add new tests: + +1. **For Commands**: Use `execute_command()` method with expectrl +2. **For AI Prompts**: Use `send_prompt()` method with direct streams +3. **Always**: Print full output first, then verify content +4. **Pattern**: Start session β†’ Execute β†’ Verify β†’ Quit + +This framework provides comprehensive E2E testing for the Q CLI with both interactive commands and AI functionality. diff --git a/e2etests/run_tests.sh b/e2etests/run_tests.sh new file mode 100755 index 0000000000..086cada3cd --- /dev/null +++ b/e2etests/run_tests.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +# Q CLI E2E Test Runner +# Usage: ./run_tests.sh [path_to_q_binary] [test_name] + +Q_BINARY=${1:-"q"} +TEST_NAME=${2:-""} + +echo "πŸš€ Running Q CLI E2E tests with binary: $Q_BINARY" + +if [ "$Q_BINARY" != "q" ]; then + if [ ! -f "$Q_BINARY" ]; then + echo "❌ Error: Q CLI binary not found at: $Q_BINARY" + exit 1 + fi + echo "πŸ“ Using custom Q CLI binary: $Q_BINARY" + export Q_CLI_PATH="$Q_BINARY" +else + echo "πŸ“ Using default system Q CLI binary" + export Q_CLI_PATH="$Q_BINARY" +fi + +if [ -n "$TEST_NAME" ]; then + echo "πŸ§ͺ Running specific test: $TEST_NAME" + cargo test --test "$TEST_NAME" -- --nocapture +else + echo "πŸ§ͺ Running all E2E tests" + cargo test --test test_help_command --test test_tools_command --test test_ai_prompt -- --nocapture +fi diff --git a/e2etests/src/lib.rs b/e2etests/src/lib.rs new file mode 100644 index 0000000000..edd4846589 --- /dev/null +++ b/e2etests/src/lib.rs @@ -0,0 +1,127 @@ +// Q CLI E2E Test Framework +// This library provides end-to-end testing utilities for Amazon Q CLI + +pub mod q_chat_helper { + //! Helper module for Q CLI testing with hybrid approach + //! - expectrl for commands (/help, /tools) + //! - Direct process streams for AI prompts + + pub use expectrl::{Regex, Error}; + pub use std::io::{Read, Write}; + pub use std::time::Duration; + pub use std::process::{Command, Stdio}; + pub use std::thread; + + pub struct QChatSession { + session: expectrl::Session, + } + + impl QChatSession { + /// Start a new Q Chat session + pub fn new() -> Result { + let q_binary = std::env::var("Q_CLI_PATH").unwrap_or_else(|_| "q".to_string()); + let command = format!("{} chat", q_binary); + let mut session = expectrl::spawn(&command)?; + session.set_expect_timeout(Some(Duration::from_secs(60))); + + // Wait for startup prompt + session.expect(Regex(r">"))?; + + Ok(QChatSession { session }) + } + + /// Execute a command (like /help, /tools) and return the response + pub fn execute_command(&mut self, command: &str) -> Result { + // Type command character by character with delays (for autocomplete) + for &byte in command.as_bytes() { + self.session.write_all(&[byte])?; + self.session.flush()?; + std::thread::sleep(Duration::from_millis(50)); + } + + // Send carriage return to execute + self.session.write_all(&[0x0D])?; + self.session.flush()?; + + self.read_response() + } + + /// Send a regular chat prompt (like "What is AWS?") and return the response + pub fn send_prompt(&mut self, prompt: &str) -> Result { + // For AI prompts, we need to use direct process streams to capture stdout + self.session.send_line("/quit")?; // Close current session + + // Start new process with direct stream access + let q_binary = std::env::var("Q_CLI_PATH").unwrap_or_else(|_| "q".to_string()); + let mut child = Command::new(&q_binary) + .arg("chat") + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .map_err(|e| Error::IO(e))?; + + let mut stdin = child.stdin.take().unwrap(); + let stdout = child.stdout.take().unwrap(); + let stderr = child.stderr.take().unwrap(); + + // Send the prompt + writeln!(stdin, "{}", prompt).map_err(|e| Error::IO(e))?; + drop(stdin); + + // Read both stdout and stderr concurrently + let stdout_handle = std::thread::spawn(move || { + let mut content = String::new(); + let mut stdout = stdout; + let _ = stdout.read_to_string(&mut content); + content + }); + + let stderr_handle = std::thread::spawn(move || { + let mut content = String::new(); + let mut stderr = stderr; + let _ = stderr.read_to_string(&mut content); + content + }); + + let stdout_content = stdout_handle.join().unwrap_or_default(); + let stderr_content = stderr_handle.join().unwrap_or_default(); + + // Wait for process to complete + let _ = child.wait(); + + // Combine stderr (UI elements) and stdout (AI response) + let combined = format!("{}{}", stderr_content, stdout_content); + Ok(combined) + } + + fn read_response(&mut self) -> Result { + let mut total_content = String::new(); + + for _ in 0..15 { + let mut buffer = [0u8; 512]; + match self.session.try_read(&mut buffer) { + Ok(bytes_read) if bytes_read > 0 => { + let chunk = String::from_utf8_lossy(&buffer[..bytes_read]); + total_content.push_str(&chunk); + }, + Ok(_) => { + // No more data, but wait a bit more in case there's more coming + std::thread::sleep(Duration::from_millis(200)); + if total_content.len() > 0 { break; } + }, + Err(_) => break, + } + std::thread::sleep(Duration::from_millis(200)); + } + + Ok(total_content) + } + + /// Quit the Q Chat session + pub fn quit(&mut self) -> Result<(), Error> { + self.session.send_line("/quit")?; + Ok(()) + } + } +} diff --git a/e2etests/tests/test_ai_prompt.rs b/e2etests/tests/test_ai_prompt.rs new file mode 100644 index 0000000000..2401db8cf0 --- /dev/null +++ b/e2etests/tests/test_ai_prompt.rs @@ -0,0 +1,89 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +fn test_what_is_aws_prompt() -> Result<(), Box> { + println!("πŸ” Testing 'What is AWS?' AI prompt..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.send_prompt("What is AWS?")?; + + println!("πŸ“ AI response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Check if we got an actual AI response + if response.contains("Amazon Web Services") || + response.contains("cloud") || + response.contains("AWS") || + response.len() > 100 { + println!("βœ… Got substantial AI response ({} bytes)!", response.len()); + + // Additional checks for quality response + if response.contains("Amazon Web Services") { + println!("βœ… Response correctly identifies 'Amazon Web Services'"); + } + if response.contains("cloud") { + println!("βœ… Response mentions cloud computing concepts"); + } + if response.contains("AWS") { + println!("βœ… Response uses AWS acronym appropriately"); + } + + // Check for technical depth + let technical_terms = ["service", "platform", "infrastructure", "compute", "storage"]; + let found_terms: Vec<&str> = technical_terms.iter() + .filter(|&&term| response.to_lowercase().contains(term)) + .copied() + .collect(); + if !found_terms.is_empty() { + println!("βœ… Response includes technical terms: {:?}", found_terms); + } + } else { + println!("⚠️ Response seems limited or just echoed input"); + println!("⚠️ Expected AWS explanation but got: {} bytes", response.len()); + } + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} + +#[test] +fn test_simple_greeting() -> Result<(), Box> { + println!("πŸ” Testing simple 'Hello' prompt..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.send_prompt("Hello")?; + + println!("πŸ“ Greeting response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Check if we got any response + if response.trim().is_empty() { + println!("⚠️ No response to greeting - AI may not be responding"); + } else if response.to_lowercase().contains("hello") || + response.to_lowercase().contains("hi") || + response.to_lowercase().contains("greet") { + println!("βœ… Got appropriate greeting response!"); + println!("βœ… AI recognized and responded to greeting appropriately"); + } else if response.len() > 20 { + println!("βœ… Got substantial response ({} bytes) to greeting", response.len()); + println!("ℹ️ Response doesn't contain typical greeting words but seems AI-generated"); + } else { + println!("ℹ️ Got minimal response - unclear if AI-generated or echo"); + println!("ℹ️ Response length: {} bytes", response.len()); + } + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} diff --git a/e2etests/tests/test_help_command.rs b/e2etests/tests/test_help_command.rs new file mode 100644 index 0000000000..f9f6db8c2c --- /dev/null +++ b/e2etests/tests/test_help_command.rs @@ -0,0 +1,53 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +fn test_help_command() -> Result<(), Box> { + println!("πŸ” Testing /help command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/help")?; + + println!("πŸ“ Help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify help content + assert!(response.contains("Commands:"), "Missing Commands section"); + println!("βœ… Found Commands section with all available commands"); + + assert!(response.contains("quit"), "Missing quit command"); + assert!(response.contains("clear"), "Missing clear command"); + assert!(response.contains("tools"), "Missing tools command"); + assert!(response.contains("help"), "Missing help command"); + println!("βœ… Verified core commands: quit, clear, tools, help"); + + assert!(response.contains("Options:"), "Missing Options section"); + println!("βœ… Found Options section with -h, --help flags"); + + assert!(response.contains("MCP:"), "Missing MCP section"); + println!("βœ… Found MCP section with configuration documentation link"); + + assert!(response.contains("Tips:"), "Missing Tips section"); + println!("βœ… Found Tips section with keyboard shortcuts and settings"); + + // Verify specific useful commands + if response.contains("context") { + println!("βœ… Found context management command"); + } + if response.contains("agent") { + println!("βœ… Found agent management command"); + } + if response.contains("model") { + println!("βœ… Found model selection command"); + } + + println!("βœ… All help content verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} diff --git a/e2etests/tests/test_tools_command.rs b/e2etests/tests/test_tools_command.rs new file mode 100644 index 0000000000..3a10500e06 --- /dev/null +++ b/e2etests/tests/test_tools_command.rs @@ -0,0 +1,52 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +fn test_tools_command() -> Result<(), Box> { + println!("πŸ” Testing /tools command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/tools")?; + + println!("πŸ“ Tools response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify tools content structure + assert!(response.contains("Tool"), "Missing Tool header"); + assert!(response.contains("Permission"), "Missing Permission header"); + println!("βœ… Found tools table with Tool and Permission columns"); + + assert!(response.contains("Built-in:"), "Missing Built-in section"); + println!("βœ… Found Built-in tools section"); + + // Verify some expected built-in tools + assert!(response.contains("execute_bash"), "Missing execute_bash tool"); + assert!(response.contains("fs_read"), "Missing fs_read tool"); + assert!(response.contains("fs_write"), "Missing fs_write tool"); + assert!(response.contains("use_aws"), "Missing use_aws tool"); + println!("βœ… Verified core built-in tools: execute_bash, fs_read, fs_write, use_aws"); + + // Check for MCP tools section if present + if response.contains("amzn-mcp (MCP):") { + println!("βœ… Found MCP tools section with Amazon-specific tools"); + assert!(response.contains("not trusted") || response.contains("trusted"), "Missing permission status"); + println!("βœ… Verified permission status indicators (trusted/not trusted)"); + + // Count some MCP tools + let mcp_tools = ["andes", "cradle", "datanet", "read_quip", "taskei_get_task"]; + let found_tools: Vec<&str> = mcp_tools.iter().filter(|&&tool| response.contains(tool)).copied().collect(); + println!("βœ… Found {} MCP tools including: {:?}", found_tools.len(), found_tools); + } + + println!("βœ… All tools content verified!"); + + println!("βœ… /tools command executed successfully"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} From a06255b79b750479c258e1e79e2847dd4313ec7d Mon Sep 17 00:00:00 2001 From: "Shreya [C] Bhagat" Date: Tue, 12 Aug 2025 16:01:26 +0530 Subject: [PATCH 02/77] QCLI Automation for Basic chat --- e2etests/run_tests.sh | 2 +- e2etests/tests/test_clear_command.rs | 42 ++++++++++++++++++++++ e2etests/tests/test_load_save_command.rs | 43 ++++++++++++++++++++++ e2etests/tests/test_quit_command.rs | 15 ++++++++ e2etests/tests/test_save_help_command.rs | 45 ++++++++++++++++++++++++ 5 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 e2etests/tests/test_clear_command.rs create mode 100644 e2etests/tests/test_load_save_command.rs create mode 100644 e2etests/tests/test_quit_command.rs create mode 100644 e2etests/tests/test_save_help_command.rs diff --git a/e2etests/run_tests.sh b/e2etests/run_tests.sh index 086cada3cd..dbe2bf0eac 100755 --- a/e2etests/run_tests.sh +++ b/e2etests/run_tests.sh @@ -25,5 +25,5 @@ if [ -n "$TEST_NAME" ]; then cargo test --test "$TEST_NAME" -- --nocapture else echo "πŸ§ͺ Running all E2E tests" - cargo test --test test_help_command --test test_tools_command --test test_ai_prompt -- --nocapture + cargo test --test test_help_command --test test_tools_command --test test_ai_prompt --test test_clear_command --test test_quit_command --test test_save_help_command --test test_load_help_command -- --nocapture fi diff --git a/e2etests/tests/test_clear_command.rs b/e2etests/tests/test_clear_command.rs new file mode 100644 index 0000000000..1378c5ddc5 --- /dev/null +++ b/e2etests/tests/test_clear_command.rs @@ -0,0 +1,42 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +fn test_clear_command() -> Result<(), Box> { + println!("πŸ” Testing /clear command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + // Send initial message + println!("πŸ” Sending prompt: 'My name is TestUser'"); + let _initial_response = chat.send_prompt("My name is TestUser")?; + println!("πŸ“ Initial response: {} bytes", _initial_response.len()); + println!("πŸ“ INITIAL RESPONSE OUTPUT:"); + println!("{}", _initial_response); + println!("πŸ“ END INITIAL RESPONSE"); + + // Execute clear command + println!("πŸ” Executing command: '/clear'"); + let _clear_response = chat.execute_command("/clear")?; + + println!("βœ… Clear command executed"); + + // Check if AI remembers previous conversation + println!("πŸ” Sending prompt: 'What is my name?'"); + let test_response = chat.send_prompt("What is my name?")?; + println!("πŸ“ Test response: {} bytes", test_response.len()); + println!("πŸ“ TEST RESPONSE OUTPUT:"); + println!("{}", test_response); + println!("πŸ“ END TEST RESPONSE"); + + // Verify history is cleared - AI shouldn't remember the name + if !test_response.to_lowercase().contains("testuser") { + println!("βœ… Clear command successful - Conversation history cleared."); + } else { + println!("⚠️ Clear command failed - AI still remembers previous conversation"); + } + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_load_save_command.rs b/e2etests/tests/test_load_save_command.rs new file mode 100644 index 0000000000..36f437f5c5 --- /dev/null +++ b/e2etests/tests/test_load_save_command.rs @@ -0,0 +1,43 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +fn test_load_help_command() -> Result<(), Box> { + println!("πŸ” Testing /load --help command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/load --help")?; + + println!("πŸ“ Help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify load command help content + assert!(response.contains("Load a previous conversation"), "Missing load command description"); + println!("βœ… Found load command description"); + + assert!(response.contains("Usage:"), "Missing Usage section"); + assert!(response.contains("/load"), "Missing /load command in usage"); + println!("βœ… Found Usage section with /load command"); + + assert!(response.contains("Arguments:"), "Missing Arguments section"); + assert!(response.contains(""), "Missing PATH argument"); + println!("βœ… Found Arguments section with PATH parameter"); + + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("-h"), "Missing -h flag"); + assert!(response.contains("--help"), "Missing --help flag"); + println!("βœ… Found Options section with -h, --help flags"); + + assert!(response.contains("Print help"), "Missing help description"); + println!("βœ… Found help flag description"); + + println!("βœ… All help content verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} diff --git a/e2etests/tests/test_quit_command.rs b/e2etests/tests/test_quit_command.rs new file mode 100644 index 0000000000..dbc9215b65 --- /dev/null +++ b/e2etests/tests/test_quit_command.rs @@ -0,0 +1,15 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +fn test_quit_command() -> Result<(), Box> { + println!("πŸ” Testing /quit command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + chat.quit()?; + println!("βœ… /quit command executed successfully"); + println!("βœ… Test completed successfully"); + + Ok(()) +} diff --git a/e2etests/tests/test_save_help_command.rs b/e2etests/tests/test_save_help_command.rs new file mode 100644 index 0000000000..9a3e556cae --- /dev/null +++ b/e2etests/tests/test_save_help_command.rs @@ -0,0 +1,45 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +fn test_save_help_command() -> Result<(), Box> { + println!("πŸ” Testing /save --help command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/save --help")?; + + println!("πŸ“ Help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify save command help content + assert!(response.contains("Save the current conversation"), "Missing save command description"); + println!("βœ… Found save command description"); + + assert!(response.contains("Usage:"), "Missing Usage section"); + assert!(response.contains("/save"), "Missing /save command in usage"); + println!("βœ… Found Usage section with /save command"); + + assert!(response.contains("Arguments:"), "Missing Arguments section"); + assert!(response.contains(""), "Missing PATH argument"); + println!("βœ… Found Arguments section with PATH parameter"); + + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("-f"), "Missing -f flag"); + assert!(response.contains("--force"), "Missing --force flag"); + assert!(response.contains("-h"), "Missing -h flag"); + assert!(response.contains("--help") || response.contains("β€”help"), "Missing --help flag"); + println!("βœ… Found Options section with -f, --force, -h, --help flags"); + + assert!(response.contains("Print help"), "Missing help description"); + println!("βœ… Found help flag description"); + + println!("βœ… All help content verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} From 095a708b6fd591abda20f6d4f0693a5e65de18c6 Mon Sep 17 00:00:00 2001 From: sayema Anjum Date: Tue, 12 Aug 2025 17:22:49 +0530 Subject: [PATCH 03/77] QCLI automation for Compact,MCP,Usage,Hooks,Subscribe,Model tests --- e2etests/run_tests.sh | 2 +- e2etests/tests/test_compact_command.rs | 32 +++++++ e2etests/tests/test_compact_help_command.rs | 66 ++++++++++++++ e2etests/tests/test_editor_help_command.rs | 88 +++++++++++++++++++ e2etests/tests/test_hooks_help_command.rs | 54 ++++++++++++ e2etests/tests/test_mcp_help_command.rs | 41 +++++++++ e2etests/tests/test_mcp_loading_command.rs | 37 ++++++++ e2etests/tests/test_model_command.rs | 40 +++++++++ e2etests/tests/test_model_help_command.rs | 41 +++++++++ e2etests/tests/test_subscribe_command.rs | 27 ++++++ e2etests/tests/test_subscribe_help_command.rs | 46 ++++++++++ e2etests/tests/test_usage_command.rs | 60 +++++++++++++ e2etests/tests/test_usage_help_command.rs | 40 +++++++++ 13 files changed, 573 insertions(+), 1 deletion(-) create mode 100644 e2etests/tests/test_compact_command.rs create mode 100644 e2etests/tests/test_compact_help_command.rs create mode 100644 e2etests/tests/test_editor_help_command.rs create mode 100644 e2etests/tests/test_hooks_help_command.rs create mode 100644 e2etests/tests/test_mcp_help_command.rs create mode 100644 e2etests/tests/test_mcp_loading_command.rs create mode 100644 e2etests/tests/test_model_command.rs create mode 100644 e2etests/tests/test_model_help_command.rs create mode 100644 e2etests/tests/test_subscribe_command.rs create mode 100644 e2etests/tests/test_subscribe_help_command.rs create mode 100644 e2etests/tests/test_usage_command.rs create mode 100644 e2etests/tests/test_usage_help_command.rs diff --git a/e2etests/run_tests.sh b/e2etests/run_tests.sh index dbe2bf0eac..16ca8bdc13 100755 --- a/e2etests/run_tests.sh +++ b/e2etests/run_tests.sh @@ -25,5 +25,5 @@ if [ -n "$TEST_NAME" ]; then cargo test --test "$TEST_NAME" -- --nocapture else echo "πŸ§ͺ Running all E2E tests" - cargo test --test test_help_command --test test_tools_command --test test_ai_prompt --test test_clear_command --test test_quit_command --test test_save_help_command --test test_load_help_command -- --nocapture + cargo test --test test_help_command --test test_tools_command --test test_ai_prompt --test test_clear_command --test test_quit_command --test test_save_help_command --test test_usage_command --test test_usage_help_command --test test_compact_command --test test_compact_help_command --test test_hooks_help_command --test test_mcp_help_command --test test_mcp_loading_command --test test_model_command --test test_model_help_command --test test_subscribe_command --test test_subscribe_help_command --test test_editor_help_command -- --nocapture fi diff --git a/e2etests/tests/test_compact_command.rs b/e2etests/tests/test_compact_command.rs new file mode 100644 index 0000000000..9d46a69561 --- /dev/null +++ b/e2etests/tests/test_compact_command.rs @@ -0,0 +1,32 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +fn test_compact_command() -> Result<(), Box> { + println!("πŸ” Testing /compact command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/compact")?; + + println!("πŸ“ Compact response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify compact response - either success or too short + if response.contains("Conversation history has been compacted successfully!") { + println!("βœ… Found compact success message"); + } else if response.contains("Conversation too short to compact.") { + println!("βœ… Found conversation too short message"); + } else { + panic!("Missing expected compact response"); + } + + println!("βœ… All compact content verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_compact_help_command.rs b/e2etests/tests/test_compact_help_command.rs new file mode 100644 index 0000000000..ec943c1eb1 --- /dev/null +++ b/e2etests/tests/test_compact_help_command.rs @@ -0,0 +1,66 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +fn test_compact_help_command() -> Result<(), Box> { + println!("πŸ” Testing /compact --help command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/compact --help")?; + + println!("πŸ“ Compact help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify main description + assert!(response.contains("/compact summarizes the conversation history"), "Missing compact description"); + println!("βœ… Found compact description"); + + // Verify When to use section + assert!(response.contains("When to use"), "Missing When to use section"); + assert!(response.contains("memory constraint warning message"), "Missing memory constraint warning"); + assert!(response.contains("conversation has been running for a long time"), "Missing long conversation note"); + assert!(response.contains("new topic within the same session"), "Missing new topic note"); + assert!(response.contains("completing complex tool operations"), "Missing tool operations note"); + println!("βœ… Found When to use section with all scenarios"); + + // Verify How it works section + assert!(response.contains("How it works"), "Missing How it works section"); + assert!(response.contains("AI-generated summary of your conversation"), "Missing AI summary description"); + assert!(response.contains("key information") && response.contains("code") && response.contains("tool executions"), "Missing key elements"); + assert!(response.contains("free up space"), "Missing free up space description"); + assert!(response.contains("reference the summary context"), "Missing summary context reference"); + println!("βœ… Found How it works section with all details"); + + // Verify auto-compaction information + assert!(response.contains("Compaction will be automatically performed whenever the context window overflows"), "Missing auto-compaction note"); + assert!(response.contains("To disable this behavior, run: `q settings chat.disableAutoCompaction true`"), "Missing disable instruction"); + println!("βœ… Found auto-compaction information"); + + // Verify Usage section + assert!(response.contains("Usage:"), "Missing usage format"); + println!("βœ… Found usage format"); + + // Verify Arguments section + assert!(response.contains("Arguments:"), "Missing Arguments section"); + println!("βœ… Found Arguments section"); + + // Verify Options section + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("--show-summary"), "Missing --show-summary option"); + assert!(response.contains("--messages-to-exclude"), "Missing --messages-to-exclude option"); + assert!(response.contains("--truncate-large-messages"), "Missing --truncate-large-messages option"); + assert!(response.contains("--max-message-length"), "Missing --max-message-length option"); + assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing -h, --help flags"); + assert!(response.contains("Print help"), "Missing Print help description"); + println!("βœ… Found all options and help flags"); + + println!("βœ… All compact help content verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_editor_help_command.rs b/e2etests/tests/test_editor_help_command.rs new file mode 100644 index 0000000000..313c2a4913 --- /dev/null +++ b/e2etests/tests/test_editor_help_command.rs @@ -0,0 +1,88 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +fn test_editor_help_command() -> Result<(), Box> { + println!("πŸ” Testing /editor --help command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/editor --help")?; + + println!("πŸ“ Editor help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify description + assert!(response.contains("Open $EDITOR (defaults to vi) to compose a prompt"), "Missing editor description"); + println!("βœ… Found editor description"); + + // Verify Usage section + assert!(response.contains("Usage:") && response.contains("/editor") && response.contains("[INITIAL_TEXT]"), "Missing Usage section"); + println!("βœ… Found Usage section with /editor command"); + + // Verify Arguments section + assert!(response.contains("Arguments:"), "Missing Arguments section"); + assert!(response.contains("[INITIAL_TEXT]..."), "Missing INITIAL_TEXT argument"); + println!("βœ… Found Arguments section"); + + // Verify Options section + assert!(response.contains("Options:"), "Missing Options section"); + println!("βœ… Found Options section"); + + // Verify help flags + assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing -h, --help flags"); + assert!(response.contains("Print help"), "Missing Print help description"); + println!("βœ… Found help flags: -h, --help with Print help description"); + + println!("βœ… All editor help content verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} + +#[test] +fn test_help_editor_command() -> Result<(), Box> { + println!("πŸ” Testing /help editor command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/help editor")?; + + println!("πŸ“ Help editor response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify description + assert!(response.contains("Open $EDITOR (defaults to vi) to compose a prompt"), "Missing editor description"); + println!("βœ… Found editor description"); + + // Verify Usage section + assert!(response.contains("Usage:") && response.contains("/editor") && response.contains("[INITIAL_TEXT]"), "Missing Usage section"); + println!("βœ… Found Usage section with /editor command"); + + // Verify Arguments section + assert!(response.contains("Arguments:"), "Missing Arguments section"); + assert!(response.contains("[INITIAL_TEXT]..."), "Missing INITIAL_TEXT argument"); + println!("βœ… Found Arguments section"); + + // Verify Options section + assert!(response.contains("Options:"), "Missing Options section"); + println!("βœ… Found Options section"); + + // Verify help flags + assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing -h, --help flags"); + println!("βœ… Found help flags: -h, --help with Print help description"); + + println!("βœ… All help editor content verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_hooks_help_command.rs b/e2etests/tests/test_hooks_help_command.rs new file mode 100644 index 0000000000..db2caec614 --- /dev/null +++ b/e2etests/tests/test_hooks_help_command.rs @@ -0,0 +1,54 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +fn test_hooks_help_command() -> Result<(), Box> { + println!("πŸ” Testing /hooks --help command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/hooks --help")?; + + println!("πŸ“ Hooks help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify context hooks description + assert!(response.contains("context hooks"), "Missing context hooks"); + assert!(response.contains("appended to the prompt to Amazon Q"), "Missing prompt append description"); + println!("βœ… Found context hooks and shell commands description"); + + // Verify documentation reference + assert!(response.contains("documentation for how to configure hooks"), "Missing documentation reference"); + assert!(response.contains("https://github.com/aws/amazon-q-developer-cli/blob/main/docs/agent-format.md#hooks-field"), "Missing documentation URL"); + println!("βœ… Found documentation reference and URL"); + + // Verify Notes section + assert!(response.contains("Notes:"), "Missing Notes section"); + assert!(response.contains("executed in parallel"), "Missing parallel execution note"); + assert!(response.contains("conversation_start"), "Missing conversation_start hook type"); + assert!(response.contains("per_prompt"), "Missing per_prompt hook type"); + println!("βœ… Found Notes section with hook types and execution details"); + + // Verify Usage section + assert!(response.contains("Usage:"), "Missing Usage section"); + assert!(response.contains("/hooks"), "Missing /hooks command in usage section"); + println!("βœ… Found Usage section with /hooks command"); + + // Verify Options section + assert!(response.contains("Options:"), "Missing Options section"); + println!("βœ… Found Options section"); + + // Verify help flags + assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing -h, --help flags"); + assert!(response.contains("Print help (see a summary with '-h')"), "Missing Print help description"); + println!("βœ… Found help flags: -h, --help with Print help description"); + + println!("βœ… All hooks help content verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_mcp_help_command.rs b/e2etests/tests/test_mcp_help_command.rs new file mode 100644 index 0000000000..2820651386 --- /dev/null +++ b/e2etests/tests/test_mcp_help_command.rs @@ -0,0 +1,41 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +fn test_mcp_help_command() -> Result<(), Box> { + println!("πŸ” Testing /mcp --help command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/mcp --help")?; + + println!("πŸ“ MCP help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify description + assert!(response.contains("See mcp server loaded"), "Missing mcp server description"); + println!("βœ… Found mcp server description"); + + // Verify Usage section + assert!(response.contains("Usage:"), "Missing Usage section"); + assert!(response.contains("/mcp"), "Missing /mcp command in usage section"); + println!("βœ… Found Usage section with /mcp command"); + + // Verify Options section + assert!(response.contains("Options:"), "Missing Options section"); + println!("βœ… Found Options section"); + + // Verify help flags + assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing -h, --help flags"); + assert!(response.contains("Print help"), "Missing Print help description"); + println!("βœ… Found help flags: -h, --help with Print help description"); + + println!("βœ… All mcp help content verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_mcp_loading_command.rs b/e2etests/tests/test_mcp_loading_command.rs new file mode 100644 index 0000000000..2765b13ea6 --- /dev/null +++ b/e2etests/tests/test_mcp_loading_command.rs @@ -0,0 +1,37 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +fn test_mcp_loading_command() -> Result<(), Box> { + println!("πŸ” Testing MCP loading..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/mcp")?; + + println!("πŸ“ MCP loading response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Check MCP status - either loaded or loading + if response.contains("loaded in") { + assert!(response.contains(" s"), "Missing seconds indicator for loading time"); + println!("βœ… Found MCPs loaded with timing"); + + // Count number of MCPs loaded + let mcp_count = response.matches("βœ“").count(); + println!("βœ… Found {} MCP(s) loaded", mcp_count); + } else if response.contains("loading") { + println!("βœ… MCPs are still loading"); + } else { + println!("ℹ️ MCP status unclear - may be in different state"); + } + + println!("βœ… All MCP loading content verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_model_command.rs b/e2etests/tests/test_model_command.rs new file mode 100644 index 0000000000..74a8b63559 --- /dev/null +++ b/e2etests/tests/test_model_command.rs @@ -0,0 +1,40 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +fn test_model_command() -> Result<(), Box> { + println!("πŸ” Testing /model command interface and selection..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/model")?; + + println!("πŸ“ Model response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify model selection header + assert!(response.contains("Select a model for this chat session"), "Missing model selection header"); + println!("βœ… Found model selection header"); + + // Verify required models + assert!(response.contains("claude-4-sonnet"), "Missing claude-4-sonnet model"); + assert!(response.contains("claude-3.7-sonnet"), "Missing claude-3.7-sonnet model"); + println!("βœ… Found required models: claude-4-sonnet, claude-3.7-sonnet"); + + // Verify active model indicator + assert!(response.contains("(active)"), "Missing active model indicator"); + println!("βœ… Found active model indicator"); + + // Verify cursor selection indicator + assert!(response.contains("❯"), "Missing cursor selection indicator"); + println!("βœ… Found cursor selection indicator ❯"); + + println!("βœ… All model selection functionality verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} diff --git a/e2etests/tests/test_model_help_command.rs b/e2etests/tests/test_model_help_command.rs new file mode 100644 index 0000000000..1d51e16c7c --- /dev/null +++ b/e2etests/tests/test_model_help_command.rs @@ -0,0 +1,41 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +fn test_model_help_command() -> Result<(), Box> { + println!("πŸ” Testing /model --help command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/model --help")?; + + println!("πŸ“ Model help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify description + assert!(response.contains("Select a model for the current conversation session"), "Missing model selection description"); + println!("βœ… Found model selection description"); + + // Verify Usage section + assert!(response.contains("Usage:"), "Missing Usage section"); + assert!(response.contains("/model"), "Missing /model command in usage section"); + println!("βœ… Found Usage section with /model command"); + + // Verify Options section + assert!(response.contains("Options:"), "Missing Options section"); + println!("βœ… Found Options section"); + + // Verify help flags + assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing -h, --help flags"); + assert!(response.contains("Print help"), "Missing Print help description"); + println!("βœ… Found help flags: -h, --help with Print help description"); + + println!("βœ… All model help content verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_subscribe_command.rs b/e2etests/tests/test_subscribe_command.rs new file mode 100644 index 0000000000..93160ae656 --- /dev/null +++ b/e2etests/tests/test_subscribe_command.rs @@ -0,0 +1,27 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +fn test_subscribe_command() -> Result<(), Box> { + println!("πŸ” Testing /subscribe command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/subscribe")?; + + println!("πŸ“ Subscribe response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify subscription management message + assert!(response.contains("Your Q Developer Pro subscription is managed through IAM Identity Center"), "Missing subscription management message"); + println!("βœ… Found subscription management message"); + + println!("βœ… All subscribe content verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_subscribe_help_command.rs b/e2etests/tests/test_subscribe_help_command.rs new file mode 100644 index 0000000000..70c5d65d76 --- /dev/null +++ b/e2etests/tests/test_subscribe_help_command.rs @@ -0,0 +1,46 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +fn test_subscribe_help_command() -> Result<(), Box> { + println!("πŸ” Testing /subscribe --help command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/subscribe --help")?; + + println!("πŸ“ Subscribe help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify description + assert!(response.contains("Upgrade to a Q Developer Pro subscription for increased query limits"), "Missing subscription description"); + println!("βœ… Found subscription description"); + + // Verify Usage section + assert!(response.contains("Usage:"), "Missing Usage section"); + assert!(response.contains("/subscribe"), "Missing /subscribe command in usage section"); + assert!(response.contains("[OPTIONS]"), "Missing [OPTIONS] in usage section"); + println!("βœ… Found Usage section with /subscribe [OPTIONS]"); + + // Verify Options section + assert!(response.contains("Options:"), "Missing Options section"); + println!("βœ… Found Options section"); + + // Verify manage option + assert!(response.contains("--manage"), "Missing --manage option"); + println!("βœ… Found --manage option"); + + // Verify help flags + assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing -h, --help flags"); + assert!(response.contains("Print help"), "Missing Print help description"); + println!("βœ… Found help flags: -h, --help with Print help description"); + + println!("βœ… All subscribe help content verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_usage_command.rs b/e2etests/tests/test_usage_command.rs new file mode 100644 index 0000000000..bb75546300 --- /dev/null +++ b/e2etests/tests/test_usage_command.rs @@ -0,0 +1,60 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +fn test_usage_command() -> Result<(), Box> { + println!("πŸ” Testing /usage command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/usage")?; + + println!("πŸ“ Tools response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify context window information + assert!(response.contains("Current context window"), "Missing context window header"); + assert!(response.contains("tokens used"), "Missing tokens used information"); + println!("βœ… Found context window and token usage information"); + + // Verify progress bar + assert!(response.contains("%"), "Missing percentage display"); + println!("βœ… Found progress bar with percentage"); + + // Verify token breakdown sections + assert!(response.contains(" Context files:"), "Missing Context files section"); + assert!(response.contains(" Tools:"), "Missing Tools section"); + assert!(response.contains(" Q responses:"), "Missing Q responses section"); + assert!(response.contains(" Your prompts:"), "Missing Your prompts section"); + println!("βœ… Found all token breakdown sections"); + + // Verify token counts and percentages format + assert!(response.contains("tokens ("), "Missing token count format"); + assert!(response.contains("%)"), "Missing percentage format in breakdown"); + println!("βœ… Verified token count and percentage format"); + + // Verify Pro Tips section + assert!(response.contains(" Pro Tips:"), "Missing Pro Tips section"); + println!("βœ… Found Pro Tips section"); + + // Verify specific tip commands + assert!(response.contains("/compact"), "Missing /compact command tip"); + assert!(response.contains("/clear"), "Missing /clear command tip"); + assert!(response.contains("/context show"), "Missing /context show command tip"); + println!("βœ… Found all command tips: /compact, /clear, /context show"); + + // Verify tip descriptions + assert!(response.contains("replace the conversation history with its summary"), "Missing /compact description"); + assert!(response.contains("erase the entire chat history"), "Missing /clear description"); + assert!(response.contains("see tokens per context file"), "Missing /context show description"); + println!("βœ… Verified all tip descriptions"); + + println!("βœ… All usage content verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_usage_help_command.rs b/e2etests/tests/test_usage_help_command.rs new file mode 100644 index 0000000000..1782007389 --- /dev/null +++ b/e2etests/tests/test_usage_help_command.rs @@ -0,0 +1,40 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +fn test_usage_help_command() -> Result<(), Box> { + println!("πŸ” Testing /usage --help command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/usage --help")?; + + println!("πŸ“ Usage help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify description + assert!(response.contains("Show current session's context window usage"), "Missing usage command description"); + println!("βœ… Found usage command description"); + + // Verify Usage section + assert!(response.contains("Usage:"), "Missing Usage section"); + assert!(response.contains("/usage"), "Missing /usage command in usage section"); + println!("βœ… Found Usage section with /usage command"); + + // Verify Options section + assert!(response.contains("Options:"), "Missing Options section"); + println!("βœ… Found Options section"); + + // Verify help flags + assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing -h, --help flags"); + println!("βœ… Found help flags: -h, --help with description"); + + println!("βœ… All usage help content verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file From 115f4feda9c2adddc4926febfb3de10ced6053b9 Mon Sep 17 00:00:00 2001 From: "Shreya [C] Bhagat" Date: Tue, 12 Aug 2025 19:05:59 +0530 Subject: [PATCH 04/77] Q CLI Automation for context and help --- e2etests/run_tests.sh | 2 +- e2etests/tests/test_clear_command.rs | 7 +- e2etests/tests/test_context_help_command.rs | 66 ++++++++++++++++++ .../tests/test_context_invalid_command.rs | 54 +++++++++++++++ ...ext_remove_command_of_non_existent_file.rs | 25 +++++++ e2etests/tests/test_context_show_command.rs | 33 +++++++++ .../tests/test_context_without_subcommand.rs | 51 ++++++++++++++ ...e_command.rs => test_load_help_command.rs} | 0 e2etests/tests/test_save_command.rs | 55 +++++++++++++++ e2etests/tests/test_save_force_command.rs | 68 +++++++++++++++++++ 10 files changed, 355 insertions(+), 6 deletions(-) create mode 100644 e2etests/tests/test_context_help_command.rs create mode 100644 e2etests/tests/test_context_invalid_command.rs create mode 100644 e2etests/tests/test_context_remove_command_of_non_existent_file.rs create mode 100644 e2etests/tests/test_context_show_command.rs create mode 100644 e2etests/tests/test_context_without_subcommand.rs rename e2etests/tests/{test_load_save_command.rs => test_load_help_command.rs} (100%) create mode 100644 e2etests/tests/test_save_command.rs create mode 100644 e2etests/tests/test_save_force_command.rs diff --git a/e2etests/run_tests.sh b/e2etests/run_tests.sh index 16ca8bdc13..7b17d471e3 100755 --- a/e2etests/run_tests.sh +++ b/e2etests/run_tests.sh @@ -25,5 +25,5 @@ if [ -n "$TEST_NAME" ]; then cargo test --test "$TEST_NAME" -- --nocapture else echo "πŸ§ͺ Running all E2E tests" - cargo test --test test_help_command --test test_tools_command --test test_ai_prompt --test test_clear_command --test test_quit_command --test test_save_help_command --test test_usage_command --test test_usage_help_command --test test_compact_command --test test_compact_help_command --test test_hooks_help_command --test test_mcp_help_command --test test_mcp_loading_command --test test_model_command --test test_model_help_command --test test_subscribe_command --test test_subscribe_help_command --test test_editor_help_command -- --nocapture + cargo test --test test_help_command --test test_tools_command --test test_ai_prompt --test test_clear_command --test test_quit_command --test test_save_help_command --test test_usage_command --test test_usage_help_command --test test_compact_command --test test_compact_help_command --test test_hooks_help_command --test test_mcp_help_command --test test_mcp_loading_command --test test_model_command --test test_model_help_command --test test_subscribe_command --test test_subscribe_help_command --test test_editor_help_command --test test_load_help_command --test test_save_command --test test_context_show_command --test test_context_invalid_command --test test_context_without_subcommand --test test_context_help_command --test test_context_remove_command_of_non_existent_file --test test_save_force_command -- --nocapture fi diff --git a/e2etests/tests/test_clear_command.rs b/e2etests/tests/test_clear_command.rs index 1378c5ddc5..c535297b07 100644 --- a/e2etests/tests/test_clear_command.rs +++ b/e2etests/tests/test_clear_command.rs @@ -30,11 +30,8 @@ fn test_clear_command() -> Result<(), Box> { println!("πŸ“ END TEST RESPONSE"); // Verify history is cleared - AI shouldn't remember the name - if !test_response.to_lowercase().contains("testuser") { - println!("βœ… Clear command successful - Conversation history cleared."); - } else { - println!("⚠️ Clear command failed - AI still remembers previous conversation"); - } + assert!(!test_response.to_lowercase().contains("testuser"), "Clear command failed - AI still remembers previous conversation"); + println!("βœ… Clear command successful - Conversation history cleared."); chat.quit()?; println!("βœ… Test completed successfully"); diff --git a/e2etests/tests/test_context_help_command.rs b/e2etests/tests/test_context_help_command.rs new file mode 100644 index 0000000000..e95c8a99cd --- /dev/null +++ b/e2etests/tests/test_context_help_command.rs @@ -0,0 +1,66 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +fn test_context_help_command() -> Result<(), Box> { + println!("πŸ” Testing /context help command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/context help")?; + + println!("πŸ“ Context help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify main description + assert!(response.contains("Context rules determine which files are included"), "Missing context rules description"); + assert!(response.contains("Amazon Q session"), "Missing Amazon Q session reference"); + assert!(response.contains("They are derived from the current active agent"), "Missing agent derivation note"); + assert!(response.contains("provide Amazon Q with additional information"), "Missing additional information note"); + assert!(response.contains("Adding relevant files helps Q generate"), "Missing file help note"); + assert!(response.contains("more accurate and helpful responses"), "Missing accuracy note"); + println!("βœ… Found context rules description"); + + // Verify Notes section + assert!(response.contains("Notes:"), "Missing Notes section"); + assert!(response.contains("glob patterns"), "Missing glob patterns note"); + assert!(response.contains("*.py"), "Missing Python glob example"); + assert!(response.contains("src/**/*.js"), "Missing JavaScript glob example"); + assert!(response.contains("Agent rules apply only to the current agent"), "Missing agent rules note"); + assert!(response.contains("NOT preserved between chat sessions"), "Missing session preservation note"); + assert!(response.contains("edit the agent config file"), "Missing config file note"); + println!("βœ… Found Notes section with all details"); + + // Verify manage description + assert!(response.contains("Manage context files for the chat session"), "Missing manage description"); + println!("βœ… Found manage description"); + + // Verify Usage section + assert!(response.contains("Usage:"), "Missing Usage section"); + assert!(response.contains("/context") && response.contains(""), "Missing /context command in usage"); + println!("βœ… Found Usage section"); + + // Verify Commands section + assert!(response.contains("Commands:"), "Missing Commands section"); + assert!(response.contains("show"), "Missing show command"); + assert!(response.contains("add"), "Missing add command"); + assert!(response.contains("remove"), "Missing remove command"); + assert!(response.contains("clear"), "Missing clear command"); + assert!(response.contains("help"), "Missing help command"); + println!("βœ… Found Commands section with all subcommands"); + + // Verify Options section + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("-h"), "Missing -h flag"); + assert!(response.contains("--help"), "Missing --help flag"); + println!("βœ… Found Options section with help flags"); + + println!("βœ… All context help content verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} diff --git a/e2etests/tests/test_context_invalid_command.rs b/e2etests/tests/test_context_invalid_command.rs new file mode 100644 index 0000000000..bfebbf786c --- /dev/null +++ b/e2etests/tests/test_context_invalid_command.rs @@ -0,0 +1,54 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +fn test_context_invalid_command() -> Result<(), Box> { + println!("πŸ” Testing /context invalid command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/context test")?; + + println!("πŸ“ Context invalid response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify error message for invalid subcommand + assert!(response.contains("unrecognized subcommand") && response.contains("test"), "Missing 'unrecognized subcommand' error message"); + println!("βœ… Found expected error message for invalid subcommand"); + + assert!(response.contains("Usage:"), "Missing Usage section"); + assert!(response.contains("/context") && response.contains(""), "Missing /context command in usage"); + println!("βœ… Found Usage section with /context command"); + + assert!(response.contains("For more information") && response.contains("--help"), "Missing help information"); + println!("βœ… Found help information"); + + assert!(response.contains("Commands:"), "Missing Commands section"); + assert!(response.contains("show"), "Missing show command"); + assert!(response.contains("add"), "Missing add command"); + assert!(response.contains("remove"), "Missing remove command"); + assert!(response.contains("clear"), "Missing clear command"); + assert!(response.contains("help"), "Missing help command"); + println!("βœ… Found Commands section with all subcommands"); + + assert!(response.contains("Display the context rule configuration and matched files"), "Missing show command description"); + assert!(response.contains("Add context rules (filenames or glob patterns)"), "Missing add command description"); + assert!(response.contains("Remove specified rules"), "Missing remove command description"); + assert!(response.contains("Remove all rules"), "Missing clear command description"); + println!("βœ… Found all command descriptions"); + + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("-h"), "Missing -h flag"); + assert!(response.contains("--help"), "Missing --help flag"); + assert!(response.contains("Print help"), "Missing help description"); + println!("βœ… Found Options section with -h, --help flags"); + + println!("βœ… All context invalid command content verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} diff --git a/e2etests/tests/test_context_remove_command_of_non_existent_file.rs b/e2etests/tests/test_context_remove_command_of_non_existent_file.rs new file mode 100644 index 0000000000..6acbd56ddf --- /dev/null +++ b/e2etests/tests/test_context_remove_command_of_non_existent_file.rs @@ -0,0 +1,25 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +fn test_context_remove_command_of_non_existent_file() -> Result<(), Box> { + println!("πŸ” Testing /context remove non existing file command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/context remove non_existent_file.txt")?; + + println!("πŸ“ Context remove response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify error message for non-existent file + assert!(response.contains("None of the specified paths were found in the context"), "Missing error message for non-existent file"); + println!("βœ… Found expected error message for non-existent file removal"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} diff --git a/e2etests/tests/test_context_show_command.rs b/e2etests/tests/test_context_show_command.rs new file mode 100644 index 0000000000..5b56f964bc --- /dev/null +++ b/e2etests/tests/test_context_show_command.rs @@ -0,0 +1,33 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +fn test_context_show_command() -> Result<(), Box> { + println!("πŸ” Testing /context show command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/context show")?; + + println!("πŸ“ Context show response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify context show output contains expected sections + assert!(response.contains("πŸ‘€ Agent"), "Missing Agent section with emoji"); + println!("βœ… Found Agent section with emoji"); + + // Verify agent configuration details + assert!(response.contains("AmazonQ.md"), "Missing AmazonQ.md in agent config"); + assert!(response.contains("README.md"), "Missing README.md in agent config"); + assert!(response.contains(".amazonq/rules/**/*.md"), "Missing .amazonq/rules pattern"); + println!("βœ… Found all expected agent configuration files"); + + println!("βœ… All context show content verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} diff --git a/e2etests/tests/test_context_without_subcommand.rs b/e2etests/tests/test_context_without_subcommand.rs new file mode 100644 index 0000000000..61dd8e21be --- /dev/null +++ b/e2etests/tests/test_context_without_subcommand.rs @@ -0,0 +1,51 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +fn test_context_without_subcommand() -> Result<(), Box> { + println!("πŸ” Testing /context without sub command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/context")?; + + println!("πŸ“ Context response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify context command help content + assert!(response.contains("Manage context files for the chat session"), "Missing context command description"); + println!("βœ… Found context command description"); + + assert!(response.contains("Usage:"), "Missing Usage section"); + assert!(response.contains("/context") && response.contains(""), "Missing /context command in usage"); + println!("βœ… Found Usage section with /context command"); + + assert!(response.contains("Commands:"), "Missing Commands section"); + assert!(response.contains("show"), "Missing show command"); + assert!(response.contains("add"), "Missing add command"); + assert!(response.contains("remove"), "Missing remove command"); + assert!(response.contains("clear"), "Missing clear command"); + assert!(response.contains("help"), "Missing help command"); + println!("βœ… Found Commands section with all subcommands"); + + assert!(response.contains("Display the context rule configuration and matched files"), "Missing show command description"); + assert!(response.contains("Add context rules (filenames or glob patterns)"), "Missing add command description"); + assert!(response.contains("Remove specified rules"), "Missing remove command description"); + assert!(response.contains("Remove all rules"), "Missing clear command description"); + println!("βœ… Found all command descriptions"); + + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("-h"), "Missing -h flag"); + assert!(response.contains("--help"), "Missing --help flag"); + assert!(response.contains("Print help"), "Missing help description"); + println!("βœ… Found Options section with -h, --help flags"); + + println!("βœ… All context help content verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} diff --git a/e2etests/tests/test_load_save_command.rs b/e2etests/tests/test_load_help_command.rs similarity index 100% rename from e2etests/tests/test_load_save_command.rs rename to e2etests/tests/test_load_help_command.rs diff --git a/e2etests/tests/test_save_command.rs b/e2etests/tests/test_save_command.rs new file mode 100644 index 0000000000..6fa2710651 --- /dev/null +++ b/e2etests/tests/test_save_command.rs @@ -0,0 +1,55 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +struct FileCleanup<'a> { + path: &'a str, +} + +impl<'a> Drop for FileCleanup<'a> { + fn drop(&mut self) { + if std::path::Path::new(self.path).exists() { + let _ = std::fs::remove_file(self.path); + println!("βœ… Cleaned up test file"); + } + } +} + +#[test] +fn test_save_command() -> Result<(), Box> { + println!("πŸ” Testing /save command..."); + + let save_path = "/tmp/qcli_test_save.json"; + let _cleanup = FileCleanup { path: save_path }; + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + // Create actual conversation content + let _help_response = chat.execute_command("/help")?; + let _tools_response = chat.execute_command("/tools")?; + println!("βœ… Created conversation content with /help and /tools commands"); + + // Execute /save command + let response = chat.execute_command(&format!("/save {}", save_path))?; + + println!("πŸ“ Save response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify "Exported conversation state to [file path]" message + assert!(response.contains("Exported conversation state to") && response.contains(save_path), "Missing export confirmation message"); + println!("βœ… Found expected export message with file path"); + + // Verify file was created and contains expected data + assert!(std::path::Path::new(save_path).exists(), "Save file was not created"); + println!("βœ… Save file created at {}", save_path); + + let file_content = std::fs::read_to_string(save_path)?; + assert!(file_content.contains("help") || file_content.contains("tools"), "File missing expected conversation data"); + println!("βœ… File contains expected conversation data"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} diff --git a/e2etests/tests/test_save_force_command.rs b/e2etests/tests/test_save_force_command.rs new file mode 100644 index 0000000000..6cdccd5c6b --- /dev/null +++ b/e2etests/tests/test_save_force_command.rs @@ -0,0 +1,68 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +struct FileCleanup<'a> { + path: &'a str, +} + +impl<'a> Drop for FileCleanup<'a> { + fn drop(&mut self) { + if std::path::Path::new(self.path).exists() { + let _ = std::fs::remove_file(self.path); + println!("βœ… Cleaned up test file"); + } + } +} + +#[test] +fn test_save_force_command() -> Result<(), Box> { + println!("πŸ” Testing /save --force command..."); + + let save_path = "/tmp/qcli_test_save.json"; + let _cleanup = FileCleanup { path: save_path }; + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + // Create actual conversation content + let _help_response = chat.execute_command("/help")?; + let _tools_response = chat.execute_command("/tools")?; + println!("βœ… Created conversation content with /help and /tools commands"); + + // Execute /save command first + let response = chat.execute_command(&format!("/save {}", save_path))?; + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + assert!(response.contains("Exported conversation state to"), "Initial save should succeed"); + println!("βœ… Initial save completed"); + + // Add more conversation content after initial save + let _prompt_response = chat.execute_command("/context show")?; + println!("βœ… Added more conversation content after initial save"); + + // Execute /save --force command to overwrite with new content + let force_response = chat.execute_command(&format!("/save --force {}", save_path))?; + + println!("πŸ“ Save force response: {} bytes", force_response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", force_response); + println!("πŸ“ END OUTPUT"); + + // Verify force save message + assert!(force_response.contains("Exported conversation state to") && force_response.contains(save_path), "Missing export confirmation message"); + println!("βœ… Found expected export message with file path"); + + // Verify file exists and contains data + assert!(std::path::Path::new(save_path).exists(), "Save file was not created"); + println!("βœ… Save file created at {}", save_path); + + let file_content = std::fs::read_to_string(save_path)?; + assert!(file_content.contains("help") || file_content.contains("tools"), "File missing initial conversation data"); + assert!(file_content.contains("context"), "File missing additional conversation data"); + println!("βœ… File contains expected conversation data including additional content"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} From 57e1b9421052a6b955df66563036964a9038b3b1 Mon Sep 17 00:00:00 2001 From: Abhishek Anne Date: Tue, 12 Aug 2025 20:24:37 +0530 Subject: [PATCH 05/77] Q-CLI automated testcases for Agent commands --- e2etests/run_tests.sh | 2 +- e2etests/tests/agent_without_subcommand.rs | 54 +++++++++++++++++ .../tests/test_agent_create_missing_args.rs | 58 +++++++++++++++++++ e2etests/tests/test_agent_help_command.rs | 55 ++++++++++++++++++ e2etests/tests/test_agent_invalid_command.rs | 49 ++++++++++++++++ e2etests/tests/test_agent_list_command.rs | 36 ++++++++++++ e2etests/tests/test_agent_schema_command.rs | 57 ++++++++++++++++++ .../tests/test_agent_set_default_command.rs | 39 +++++++++++++ .../test_agent_set_default_missing_args.rs | 48 +++++++++++++++ 9 files changed, 397 insertions(+), 1 deletion(-) create mode 100644 e2etests/tests/agent_without_subcommand.rs create mode 100644 e2etests/tests/test_agent_create_missing_args.rs create mode 100644 e2etests/tests/test_agent_help_command.rs create mode 100644 e2etests/tests/test_agent_invalid_command.rs create mode 100644 e2etests/tests/test_agent_list_command.rs create mode 100644 e2etests/tests/test_agent_schema_command.rs create mode 100644 e2etests/tests/test_agent_set_default_command.rs create mode 100644 e2etests/tests/test_agent_set_default_missing_args.rs diff --git a/e2etests/run_tests.sh b/e2etests/run_tests.sh index 7b17d471e3..a008e72c38 100755 --- a/e2etests/run_tests.sh +++ b/e2etests/run_tests.sh @@ -25,5 +25,5 @@ if [ -n "$TEST_NAME" ]; then cargo test --test "$TEST_NAME" -- --nocapture else echo "πŸ§ͺ Running all E2E tests" - cargo test --test test_help_command --test test_tools_command --test test_ai_prompt --test test_clear_command --test test_quit_command --test test_save_help_command --test test_usage_command --test test_usage_help_command --test test_compact_command --test test_compact_help_command --test test_hooks_help_command --test test_mcp_help_command --test test_mcp_loading_command --test test_model_command --test test_model_help_command --test test_subscribe_command --test test_subscribe_help_command --test test_editor_help_command --test test_load_help_command --test test_save_command --test test_context_show_command --test test_context_invalid_command --test test_context_without_subcommand --test test_context_help_command --test test_context_remove_command_of_non_existent_file --test test_save_force_command -- --nocapture + cargo test --test test_help_command --test test_tools_command --test test_ai_prompt --test test_clear_command --test test_quit_command --test test_save_help_command --test test_usage_command --test test_usage_help_command --test test_compact_command --test test_compact_help_command --test test_hooks_help_command --test test_mcp_help_command --test test_mcp_loading_command --test test_model_command --test test_model_help_command --test test_subscribe_command --test test_subscribe_help_command --test test_editor_help_command --test test_load_help_command --test test_save_command --test test_context_show_command --test test_context_invalid_command --test test_context_without_subcommand --test test_context_help_command --test test_context_remove_command_of_non_existent_file --test test_save_force_command --test agent_without_subcommand --test test_agent_list_command --test test_agent_invalid_command --test test_agent_create_missing_args --test test_agent_schema_command --test test_agent_set_default_missing_args --test test_agent_set_default_command --test test_agent_help_command -- --nocapture fi diff --git a/e2etests/tests/agent_without_subcommand.rs b/e2etests/tests/agent_without_subcommand.rs new file mode 100644 index 0000000000..121f71be57 --- /dev/null +++ b/e2etests/tests/agent_without_subcommand.rs @@ -0,0 +1,54 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +fn agent_without_subcommand() -> Result<(), Box> { + println!("πŸ” Testing /agent command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/agent")?; + + println!("πŸ“ Agent response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify agent command structure + assert!(response.contains("Manage agents"), "Missing 'Manage agents' description"); + assert!(response.contains("Usage:"), "Missing usage information"); + assert!(response.contains("/agent"), "Missing agent command"); + assert!(response.contains(""), "Missing command placeholder"); + println!("βœ… Found agent command description and usage"); + + // Verify subcommands + assert!(response.contains("Commands:"), "Missing Commands section"); + assert!(response.contains("list"), "Missing list subcommand"); + assert!(response.contains("create"), "Missing create subcommand"); + assert!(response.contains("schema"), "Missing schema subcommand"); + assert!(response.contains("set-default"), "Missing set-default subcommand"); + assert!(response.contains("help"), "Missing help subcommand"); + println!("βœ… Verified all agent subcommands: list, create, schema, set-default, help"); + + // Verify command descriptions + assert!(response.contains("List all available agents"), "Missing list command description"); + assert!(response.contains("Create a new agent"), "Missing create command description"); + assert!(response.contains("Show agent config schema"), "Missing schema command description"); + assert!(response.contains("Define a default agent"), "Missing set-default command description"); + println!("βœ… Verified command descriptions"); + + // Verify options section + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("-h"), "Missing short help option"); + assert!(response.contains("--help"), "Missing long help option"); + println!("βœ… Found options section with help flag"); + + println!("βœ… All agent command content verified!"); + + println!("βœ… /agent command executed successfully"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_agent_create_missing_args.rs b/e2etests/tests/test_agent_create_missing_args.rs new file mode 100644 index 0000000000..2f7fd5393e --- /dev/null +++ b/e2etests/tests/test_agent_create_missing_args.rs @@ -0,0 +1,58 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +fn test_agent_create_missing_args() -> Result<(), Box> { + println!("πŸ” Testing /agent create without required arguments..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/agent create")?; + + println!("πŸ“ Agent create missing args response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify error message for missing required arguments + assert!(response.contains("error:"), "Missing error message part 1a"); + assert!(response.contains("the following required arguments"), "Missing error message part 1b"); + assert!(response.contains("were not provided:"), "Missing error message part 2"); + assert!(response.contains("--name"), "Missing required name argument part 1"); + assert!(response.contains(""), "Missing required name argument part 2"); + println!("βœ… Found error message for missing required arguments"); + + // Verify usage information + assert!(response.contains("Usage:"), "Missing usage information part 1"); + assert!(response.contains("/agent create"), "Missing usage information part 2a"); + assert!(response.contains("--name "), "Missing usage information part 2b"); + println!("βœ… Found usage information"); + + // Verify help suggestion + assert!(response.contains("For more information"), "Missing help suggestion part 1"); + assert!(response.contains("try"), "Missing help suggestion part 2a"); + //TODO + // assert!(response.contains("'--help"), "Missing help suggestion part 2b1"); + // assert!(response.contains("help'"), "Missing help suggestion part 2b2"); + println!("βœ… Found help suggestion"); + + // Verify options are listed + assert!(response.contains("Options:"), "Missing options section"); + //TODO + // assert!(response.contains("-n, --name"), "Missing name option part 1"); + assert!(response.contains(""), "Missing name option part 2"); + assert!(response.contains("Name of the agent to be created"), "Missing name description"); + // assert!(response.contains("-d, --directory"), "Missing directory option part 1"); + assert!(response.contains(""), "Missing directory option part 2"); + // assert!(response.contains("-f, --from"), "Missing from option part 1"); + assert!(response.contains(""), "Missing from option part 2"); + // assert!(response.contains("-h, --help"), "Missing help option"); + println!("βœ… Found all expected options"); + + println!("βœ… /agent create executed successfully with expected error for missing arguments"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_agent_help_command.rs b/e2etests/tests/test_agent_help_command.rs new file mode 100644 index 0000000000..dcfdd79f75 --- /dev/null +++ b/e2etests/tests/test_agent_help_command.rs @@ -0,0 +1,55 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +fn test_agent_help_command() -> Result<(), Box> { + println!("πŸ” Testing /agent help..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/agent help")?; + + println!("πŸ“ Agent help command response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Collect all failures instead of stopping at first one + let mut failures = Vec::new(); + + if !response.contains("Agents allow you to organize") { failures.push("Missing description"); } + if !response.contains("manage different sets of context") { failures.push("Missing context description"); } + if !response.contains("Notes") { failures.push("Missing notes section"); } + if !response.contains("Launch q chat with a specific agent") { failures.push("Missing launch note"); } + if !response.contains("--agent") { failures.push("Missing agent flag"); } + if !response.contains("Construct an agent under") { failures.push("Missing construct note"); } + if !response.contains("~/.aws/amazonq/cli-agents/") { failures.push("Missing global path"); } + if !response.contains("cwd/.aws/amazonq/cli-agents") { failures.push("Missing workspace path"); } + if !response.contains("Manage agents") { failures.push("Missing manage section"); } + if !response.contains("Usage:") { failures.push("Missing usage label"); } + if !response.contains("/agent") { failures.push("Missing agent command"); } + if !response.contains("") { failures.push("Missing command parameter"); } + if !response.contains("Commands:") { failures.push("Missing commands section"); } + if !response.contains("list") { failures.push("Missing list command"); } + if !response.contains("create") { failures.push("Missing create command"); } + if !response.contains("schema") { failures.push("Missing schema command"); } + if !response.contains("set-default") { failures.push("Missing set-default command"); } + if !response.contains("help") { failures.push("Missing help command"); } + if !response.contains("Options:") { failures.push("Missing options section"); } + if !response.contains("-h") { failures.push("Missing short help flag"); } + if !response.contains("--help") { failures.push("Missing long help flag"); } + + // Report all failures at once + if !failures.is_empty() { + panic!("Test failures: {}", failures.join(", ")); + } + + println!("βœ… All expected help content found"); + + println!("βœ… /agent help executed successfully"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_agent_invalid_command.rs b/e2etests/tests/test_agent_invalid_command.rs new file mode 100644 index 0000000000..c7fc041cd8 --- /dev/null +++ b/e2etests/tests/test_agent_invalid_command.rs @@ -0,0 +1,49 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +fn test_agent_invalid_command() -> Result<(), Box> { + println!("πŸ” Testing /agent invalidcommand..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/agent invalidcommand")?; + + println!("πŸ“ Agent invalid command response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify error message + // assert!(response.contains("error: unrecognized subcommand 'invalidcommand'"), "Missing error message"); + // println!("βœ… Found error message for invalid subcommand"); + + // Verify usage information + // assert!(response.contains("Usage: /agent "), "Missing usage information"); + // println!("βœ… Found usage information"); + + // Verify help suggestion + // assert!(response.contains("For more information, try '--help'"), "Missing help suggestion"); + // println!("βœ… Found help suggestion"); + + // Verify available commands are listed + assert!(response.contains("Commands:"), "Missing commands section"); + assert!(response.contains("list"), "Missing list command"); + assert!(response.contains("create"), "Missing create command"); + assert!(response.contains("schema"), "Missing schema command"); + assert!(response.contains("set-default"), "Missing set-default command"); + assert!(response.contains("help"), "Missing help command"); + println!("βœ… Found all expected commands in help output"); + + // Verify options section + assert!(response.contains("Options:"), "Missing options section"); + // assert!(response.contains("-h, --help"), "Missing help option"); + println!("βœ… Found options section"); + + println!("βœ… /agent invalidcommand executed successfully with expected error"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_agent_list_command.rs b/e2etests/tests/test_agent_list_command.rs new file mode 100644 index 0000000000..9b5702a670 --- /dev/null +++ b/e2etests/tests/test_agent_list_command.rs @@ -0,0 +1,36 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +fn test_agent_list_command() -> Result<(), Box> { + println!("πŸ” Testing /agent list command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/agent list")?; + + println!("πŸ“ Agent list response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify the response contains the expected agent + assert!(response.contains("q_cli_default"), "Missing q_cli_default agent"); + println!("βœ… Found q_cli_default agent in list"); + + // Verify the response format (should show agent with bullet point) + assert!(response.contains("* q_cli_default"), "Missing bullet point format for q_cli_default"); + println!("βœ… Verified bullet point format for agent list"); + + // Verify the permission prompt appears + //TODO:"This option only shows on first time" + // assert!(response.contains("Allow this action? Use 't' to trust (always allow) this tool for the session. [y/n/t]:"), "Missing permission prompt"); + // println!("βœ… Found permission prompt for tool usage"); + + println!("βœ… /agent list command executed successfully"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_agent_schema_command.rs b/e2etests/tests/test_agent_schema_command.rs new file mode 100644 index 0000000000..0e8f5b0fad --- /dev/null +++ b/e2etests/tests/test_agent_schema_command.rs @@ -0,0 +1,57 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +fn test_agent_schema_command() -> Result<(), Box> { + println!("πŸ” Testing /agent schema..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/agent schema")?; + + println!("πŸ“ Agent schema response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Collect all failures instead of stopping at first one + let mut failures = Vec::new(); + + // Verify JSON schema root level keys + if !response.contains("$schema") { failures.push("Missing $schema key"); } + if !response.contains("title") { failures.push("Missing title key"); } + if !response.contains("description") { failures.push("Missing description key"); } + if !response.contains("type") { failures.push("Missing type key"); } + if !response.contains("properties") { failures.push("Missing properties key"); } + + //TODO : Due to response is not printing fully below keys are not getting detected. check response logic + // if !response.contains("additionalProperties") { failures.push("Missing additionalProperties key"); } + // if !response.contains("required") { failures.push("Missing required key"); } + // if !response.contains("$defs") { failures.push("Missing $defs key"); } + + // Verify some key properties exist + // if !response.contains("name") { failures.push("Missing name property"); } + // if !response.contains("prompt") { failures.push("Missing prompt property"); } + // if !response.contains("mcpServers") { failures.push("Missing mcpServers property"); } + // if !response.contains("tools") { failures.push("Missing tools property"); } + // if !response.contains("toolAliases") { failures.push("Missing toolAliases property"); } + // if !response.contains("allowedTools") { failures.push("Missing allowedTools property"); } + // if !response.contains("resources") { failures.push("Missing resources property"); } + // if !response.contains("hooks") { failures.push("Missing hooks property"); } + // if !response.contains("toolsSettings") { failures.push("Missing toolsSettings property"); } + // if !response.contains("useLegacyMcpJson") { failures.push("Missing useLegacyMcpJson property"); } + + // Report all failures at once + if !failures.is_empty() { + panic!("Test failures: {}", failures.join(", ")); + } + + println!("βœ… Found all expected JSON schema keys and properties"); + + println!("βœ… /agent schema executed successfully with valid JSON schema"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_agent_set_default_command.rs b/e2etests/tests/test_agent_set_default_command.rs new file mode 100644 index 0000000000..bcd2a9c785 --- /dev/null +++ b/e2etests/tests/test_agent_set_default_command.rs @@ -0,0 +1,39 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +fn test_agent_set_default_command() -> Result<(), Box> { + println!("πŸ” Testing /agent set-default with valid arguments..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/agent set-default -n q_cli_default")?; + + println!("πŸ“ Agent set-default command response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Collect all failures instead of stopping at first one + let mut failures = Vec::new(); + + if !response.contains("βœ“") { failures.push("Missing success checkmark"); } + if !response.contains("Default agent set to") { failures.push("Missing success message"); } + if !response.contains("q_cli_default") { failures.push("Missing agent name"); } + if !response.contains("This will take effect") { failures.push("Missing effect message"); } + if !response.contains("next time q chat is launched") { failures.push("Missing launch message"); } + + // Report all failures at once + if !failures.is_empty() { + panic!("Test failures: {}", failures.join(", ")); + } + + println!("βœ… All expected success messages found"); + + println!("βœ… /agent set-default executed successfully with valid arguments"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_agent_set_default_missing_args.rs b/e2etests/tests/test_agent_set_default_missing_args.rs new file mode 100644 index 0000000000..14420d7ac3 --- /dev/null +++ b/e2etests/tests/test_agent_set_default_missing_args.rs @@ -0,0 +1,48 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +fn test_agent_set_default_missing_args() -> Result<(), Box> { + println!("πŸ” Testing /agent set-default without required arguments..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/agent set-default")?; + + println!("πŸ“ Agent set-default missing args response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Collect all failures instead of stopping at first one + let mut failures = Vec::new(); + + if !response.contains("error") { failures.push("Missing error message"); } + if !response.contains("the following required arguments were not provided:") { failures.push("Missing error message2"); } + if !response.contains("--name ") { failures.push("Missing required name argument"); } + if !response.contains("Usage:") { failures.push("Missing usage text"); } + if !response.contains("/agent") { failures.push("Missing agent command"); } + if !response.contains("set-default") { failures.push("Missing set-default subcommand"); } + if !response.contains("--name") { failures.push("Missing name flag"); } + if !response.contains("For more information") { failures.push("Missing help text"); } + if !response.contains("--help") { failures.push("Missing help flag"); } + if !response.contains("Options:") { failures.push("Missing options section"); } + if !response.contains("-n") { failures.push("Missing short name flag"); } + if !response.contains("") { failures.push("Missing name parameter"); } + if !response.contains("-h") { failures.push("Missing short help flag"); } + if !response.contains("Print help") { failures.push("Missing help description"); } + + // Report all failures at once + if !failures.is_empty() { + panic!("Test failures: {}", failures.join(", ")); + } + + println!("βœ… All expected error messages and options found"); + + println!("βœ… /agent set-default executed successfully with expected error for missing arguments"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file From d625355f0ef939bbd19d62a196bbedab19f8f6e9 Mon Sep 17 00:00:00 2001 From: abhraina-aws Date: Tue, 12 Aug 2025 13:47:51 -0700 Subject: [PATCH 06/77] feat: added a better way to run tests categorized by features --- e2etests/Cargo.toml | 12 + e2etests/run_simple_categorized.sh | 223 ++++++++++++++++++ e2etests/run_tests.sh | 2 +- e2etests/tests/agent_without_subcommand.rs | 1 + .../tests/test_agent_create_missing_args.rs | 1 + e2etests/tests/test_agent_help_command.rs | 1 + e2etests/tests/test_agent_invalid_command.rs | 1 + e2etests/tests/test_agent_list_command.rs | 1 + e2etests/tests/test_agent_schema_command.rs | 1 + .../tests/test_agent_set_default_command.rs | 1 + .../test_agent_set_default_missing_args.rs | 1 + e2etests/tests/test_ai_prompt.rs | 4 +- e2etests/tests/test_clear_command.rs | 1 + e2etests/tests/test_compact_command.rs | 1 + e2etests/tests/test_compact_help_command.rs | 1 + e2etests/tests/test_context_help_command.rs | 1 + .../tests/test_context_invalid_command.rs | 1 + ...ext_remove_command_of_non_existent_file.rs | 1 + e2etests/tests/test_context_show_command.rs | 1 + .../tests/test_context_without_subcommand.rs | 1 + e2etests/tests/test_editor_help_command.rs | 3 + e2etests/tests/test_help_command.rs | 3 +- e2etests/tests/test_hooks_help_command.rs | 1 + e2etests/tests/test_load_help_command.rs | 1 + e2etests/tests/test_mcp_help_command.rs | 3 +- e2etests/tests/test_mcp_loading_command.rs | 3 +- e2etests/tests/test_model_command.rs | 1 + e2etests/tests/test_model_help_command.rs | 3 +- e2etests/tests/test_quit_command.rs | 1 + e2etests/tests/test_save_command.rs | 1 + e2etests/tests/test_save_force_command.rs | 1 + e2etests/tests/test_save_help_command.rs | 1 + e2etests/tests/test_subscribe_command.rs | 1 + e2etests/tests/test_subscribe_help_command.rs | 1 + e2etests/tests/test_tools_command.rs | 1 + e2etests/tests/test_usage_command.rs | 1 + e2etests/tests/test_usage_help_command.rs | 1 + 37 files changed, 278 insertions(+), 6 deletions(-) create mode 100755 e2etests/run_simple_categorized.sh diff --git a/e2etests/Cargo.toml b/e2etests/Cargo.toml index 853bffcfef..1d5ad43639 100644 --- a/e2etests/Cargo.toml +++ b/e2etests/Cargo.toml @@ -8,6 +8,18 @@ edition = "2021" [dependencies] expectrl = "0.7" +[features] +default = [] +core_session = [] +agent = [] +context = [] +save_load = [] +model = [] +session_mgmt = [] +integration = [] +mcp = [] +ai_prompts = [] + [[test]] name = "test_help_command" path = "tests/test_help_command.rs" diff --git a/e2etests/run_simple_categorized.sh b/e2etests/run_simple_categorized.sh new file mode 100755 index 0000000000..1a992ba040 --- /dev/null +++ b/e2etests/run_simple_categorized.sh @@ -0,0 +1,223 @@ +#!/bin/bash + +# Simple categorized test runner with real-time output and summary +# Usage: ./run_simple_categorized.sh [path_to_q_binary] [--quiet] + +# ============================================================================ +# CATEGORY CONFIGURATION - Set to true/false to enable/disable categories +# ============================================================================ +RUN_CORE_SESSION=true +RUN_AGENT=true +RUN_CONTEXT=true +RUN_SAVE_LOAD=true +RUN_MODEL=true +RUN_SESSION_MGMT=true +RUN_INTEGRATION=true +RUN_MCP=true +RUN_AI_PROMPTS=true +# ============================================================================ + +Q_BINARY="q" +QUIET_MODE=false + +# Parse arguments properly +while [[ $# -gt 0 ]]; do + case $1 in + --quiet|-q) + QUIET_MODE=true + shift + ;; + *) + if [ "$Q_BINARY" = "q" ]; then + Q_BINARY="$1" + fi + shift + ;; + esac +done + +if [ "$Q_BINARY" != "q" ]; then + export Q_CLI_PATH="$Q_BINARY" +fi + +echo "πŸš€ Running Q CLI E2E tests by category" +echo "======================================" + +# Initialize counters +total_passed=0 +total_failed=0 +failed_categories="" + +run_category() { + local category=$1 + local name=$2 + + echo "" + echo "πŸ§ͺ $name" + echo "$(printf '%*s' ${#name} '' | tr ' ' '-')" + + # Show which tests will run in this category + echo "πŸ“‹ Tests in this category:" + for file in tests/*.rs; do + if grep -q "cfg(feature = \"$category\")" "$file" 2>/dev/null; then + test_name=$(basename "$file" .rs) + echo " β€’ $test_name" + fi + done + echo "" + + echo "πŸ”„ Running tests..." + + if [ "$QUIET_MODE" = true ]; then + # Quiet mode - show individual test results in real-time + cargo test --tests --features "$category" -- --test-threads=1 2>&1 | while IFS= read -r line; do + if echo "$line" | grep -q "test .* \.\.\. ok$"; then + test_name=$(echo "$line" | sed 's/test \(.*\) \.\.\. ok/\1/') + echo " βœ… $test_name" + elif echo "$line" | grep -q "test .* \.\.\. FAILED$"; then + test_name=$(echo "$line" | sed 's/test \(.*\) \.\.\. FAILED/\1/') + echo " ❌ $test_name" + fi + done + + # Check the exit status of cargo test + if [ ${PIPESTATUS[0]} -eq 0 ]; then + echo "βœ… $name completed successfully" + return 0 + else + echo "❌ $name had failures" + if [ -n "$failed_categories" ]; then + failed_categories="$failed_categories\n$name" + else + failed_categories="$name" + fi + return 1 + fi + else + # Verbose mode - show full output with real-time test results + cargo test --tests --features "$category" -- --nocapture --test-threads=1 2>&1 | while IFS= read -r line; do + echo "$line" + if echo "$line" | grep -q "test .* \.\.\. ok$"; then + test_name=$(echo "$line" | sed 's/test \(.*\) \.\.\. ok/\1/') + echo " βœ… $test_name PASSED" + elif echo "$line" | grep -q "test .* \.\.\. FAILED$"; then + test_name=$(echo "$line" | sed 's/test \(.*\) \.\.\. FAILED/\1/') + echo " ❌ $test_name FAILED" + fi + done + + # Check the exit status of cargo test + if [ ${PIPESTATUS[0]} -eq 0 ]; then + echo "" + echo "βœ… $name completed successfully" + return 0 + else + echo "" + echo "❌ $name had failures" + if [ -n "$failed_categories" ]; then + failed_categories="$failed_categories\n$name" + else + failed_categories="$name" + fi + return 1 + fi + fi +} + +# Run each category and track results +if [ "$RUN_CORE_SESSION" = true ]; then + if run_category "core_session" "Core Session Commands"; then + ((total_passed++)) + else + ((total_failed++)) + fi +fi + +if [ "$RUN_AGENT" = true ]; then + if run_category "agent" "Agent Commands"; then + ((total_passed++)) + else + ((total_failed++)) + fi +fi + +if [ "$RUN_CONTEXT" = true ]; then + if run_category "context" "Context Commands"; then + ((total_passed++)) + else + ((total_failed++)) + fi +fi + +if [ "$RUN_SAVE_LOAD" = true ]; then + if run_category "save_load" "Save/Load Commands"; then + ((total_passed++)) + else + ((total_failed++)) + fi +fi + +if [ "$RUN_MODEL" = true ]; then + if run_category "model" "Model Commands"; then + ((total_passed++)) + else + ((total_failed++)) + fi +fi + +if [ "$RUN_SESSION_MGMT" = true ]; then + if run_category "session_mgmt" "Session Management Commands"; then + ((total_passed++)) + else + ((total_failed++)) + fi +fi + +if [ "$RUN_INTEGRATION" = true ]; then + if run_category "integration" "Integration Commands"; then + ((total_passed++)) + else + ((total_failed++)) + fi +fi + +if [ "$RUN_MCP" = true ]; then + if run_category "mcp" "MCP Commands"; then + ((total_passed++)) + else + ((total_failed++)) + fi +fi + +if [ "$RUN_AI_PROMPTS" = true ]; then + if run_category "ai_prompts" "AI Prompts"; then + ((total_passed++)) + else + ((total_failed++)) + fi +fi + +# Final summary +echo "" +echo "🎯 FINAL SUMMARY" +echo "================================" +echo "βœ… Categories Passed: $total_passed" +echo "❌ Categories Failed: $total_failed" +echo "πŸ“Š Total Categories: $((total_passed + total_failed))" + +if [ -n "$failed_categories" ]; then + echo "" + echo "❌ Failed Categories:" + echo -e "$failed_categories" | while read -r category; do + if [ -n "$category" ]; then + echo " β€’ $category" + fi + done + echo "" + echo "πŸ’₯ Some tests failed!" + exit 1 +else + echo "" + echo "πŸŽ‰ All categories passed!" + exit 0 +fi diff --git a/e2etests/run_tests.sh b/e2etests/run_tests.sh index a008e72c38..b1123478e5 100755 --- a/e2etests/run_tests.sh +++ b/e2etests/run_tests.sh @@ -25,5 +25,5 @@ if [ -n "$TEST_NAME" ]; then cargo test --test "$TEST_NAME" -- --nocapture else echo "πŸ§ͺ Running all E2E tests" - cargo test --test test_help_command --test test_tools_command --test test_ai_prompt --test test_clear_command --test test_quit_command --test test_save_help_command --test test_usage_command --test test_usage_help_command --test test_compact_command --test test_compact_help_command --test test_hooks_help_command --test test_mcp_help_command --test test_mcp_loading_command --test test_model_command --test test_model_help_command --test test_subscribe_command --test test_subscribe_help_command --test test_editor_help_command --test test_load_help_command --test test_save_command --test test_context_show_command --test test_context_invalid_command --test test_context_without_subcommand --test test_context_help_command --test test_context_remove_command_of_non_existent_file --test test_save_force_command --test agent_without_subcommand --test test_agent_list_command --test test_agent_invalid_command --test test_agent_create_missing_args --test test_agent_schema_command --test test_agent_set_default_missing_args --test test_agent_set_default_command --test test_agent_help_command -- --nocapture + cargo test --tests -- --nocapture --test-threads=1 fi diff --git a/e2etests/tests/agent_without_subcommand.rs b/e2etests/tests/agent_without_subcommand.rs index 121f71be57..b8e9c30be7 100644 --- a/e2etests/tests/agent_without_subcommand.rs +++ b/e2etests/tests/agent_without_subcommand.rs @@ -1,6 +1,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] +#[cfg(feature = "agent")] fn agent_without_subcommand() -> Result<(), Box> { println!("πŸ” Testing /agent command..."); diff --git a/e2etests/tests/test_agent_create_missing_args.rs b/e2etests/tests/test_agent_create_missing_args.rs index 2f7fd5393e..8b1eac8428 100644 --- a/e2etests/tests/test_agent_create_missing_args.rs +++ b/e2etests/tests/test_agent_create_missing_args.rs @@ -1,6 +1,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] +#[cfg(feature = "agent")] fn test_agent_create_missing_args() -> Result<(), Box> { println!("πŸ” Testing /agent create without required arguments..."); diff --git a/e2etests/tests/test_agent_help_command.rs b/e2etests/tests/test_agent_help_command.rs index dcfdd79f75..aa53f8c23d 100644 --- a/e2etests/tests/test_agent_help_command.rs +++ b/e2etests/tests/test_agent_help_command.rs @@ -1,6 +1,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] +#[cfg(feature = "agent")] fn test_agent_help_command() -> Result<(), Box> { println!("πŸ” Testing /agent help..."); diff --git a/e2etests/tests/test_agent_invalid_command.rs b/e2etests/tests/test_agent_invalid_command.rs index c7fc041cd8..4dd0bffeba 100644 --- a/e2etests/tests/test_agent_invalid_command.rs +++ b/e2etests/tests/test_agent_invalid_command.rs @@ -1,6 +1,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] +#[cfg(feature = "agent")] fn test_agent_invalid_command() -> Result<(), Box> { println!("πŸ” Testing /agent invalidcommand..."); diff --git a/e2etests/tests/test_agent_list_command.rs b/e2etests/tests/test_agent_list_command.rs index 9b5702a670..b9c8ec843a 100644 --- a/e2etests/tests/test_agent_list_command.rs +++ b/e2etests/tests/test_agent_list_command.rs @@ -1,6 +1,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] +#[cfg(feature = "agent")] fn test_agent_list_command() -> Result<(), Box> { println!("πŸ” Testing /agent list command..."); diff --git a/e2etests/tests/test_agent_schema_command.rs b/e2etests/tests/test_agent_schema_command.rs index 0e8f5b0fad..3508225a23 100644 --- a/e2etests/tests/test_agent_schema_command.rs +++ b/e2etests/tests/test_agent_schema_command.rs @@ -1,6 +1,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] +#[cfg(feature = "agent")] fn test_agent_schema_command() -> Result<(), Box> { println!("πŸ” Testing /agent schema..."); diff --git a/e2etests/tests/test_agent_set_default_command.rs b/e2etests/tests/test_agent_set_default_command.rs index bcd2a9c785..1695018a74 100644 --- a/e2etests/tests/test_agent_set_default_command.rs +++ b/e2etests/tests/test_agent_set_default_command.rs @@ -1,6 +1,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] +#[cfg(feature = "agent")] fn test_agent_set_default_command() -> Result<(), Box> { println!("πŸ” Testing /agent set-default with valid arguments..."); diff --git a/e2etests/tests/test_agent_set_default_missing_args.rs b/e2etests/tests/test_agent_set_default_missing_args.rs index 14420d7ac3..28ffb67a5a 100644 --- a/e2etests/tests/test_agent_set_default_missing_args.rs +++ b/e2etests/tests/test_agent_set_default_missing_args.rs @@ -1,6 +1,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] +#[cfg(feature = "agent")] fn test_agent_set_default_missing_args() -> Result<(), Box> { println!("πŸ” Testing /agent set-default without required arguments..."); diff --git a/e2etests/tests/test_ai_prompt.rs b/e2etests/tests/test_ai_prompt.rs index 2401db8cf0..58d092f753 100644 --- a/e2etests/tests/test_ai_prompt.rs +++ b/e2etests/tests/test_ai_prompt.rs @@ -1,8 +1,9 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] +#[cfg(feature = "ai_prompts")] fn test_what_is_aws_prompt() -> Result<(), Box> { - println!("πŸ” Testing 'What is AWS?' AI prompt..."); + println!("πŸ” [AI PROMPTS] Testing 'What is AWS?' AI prompt..."); let mut chat = QChatSession::new()?; println!("βœ… Q Chat session started"); @@ -53,6 +54,7 @@ fn test_what_is_aws_prompt() -> Result<(), Box> { } #[test] +#[cfg(feature = "ai_prompts")] fn test_simple_greeting() -> Result<(), Box> { println!("πŸ” Testing simple 'Hello' prompt..."); diff --git a/e2etests/tests/test_clear_command.rs b/e2etests/tests/test_clear_command.rs index c535297b07..7eb8d203e5 100644 --- a/e2etests/tests/test_clear_command.rs +++ b/e2etests/tests/test_clear_command.rs @@ -1,6 +1,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] +#[cfg(feature = "core_session")] fn test_clear_command() -> Result<(), Box> { println!("πŸ” Testing /clear command..."); diff --git a/e2etests/tests/test_compact_command.rs b/e2etests/tests/test_compact_command.rs index 9d46a69561..ea146c5f8e 100644 --- a/e2etests/tests/test_compact_command.rs +++ b/e2etests/tests/test_compact_command.rs @@ -1,6 +1,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] +#[cfg(feature = "session_mgmt")] fn test_compact_command() -> Result<(), Box> { println!("πŸ” Testing /compact command..."); diff --git a/e2etests/tests/test_compact_help_command.rs b/e2etests/tests/test_compact_help_command.rs index ec943c1eb1..1a21f7d065 100644 --- a/e2etests/tests/test_compact_help_command.rs +++ b/e2etests/tests/test_compact_help_command.rs @@ -1,6 +1,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] +#[cfg(feature = "session_mgmt")] fn test_compact_help_command() -> Result<(), Box> { println!("πŸ” Testing /compact --help command..."); diff --git a/e2etests/tests/test_context_help_command.rs b/e2etests/tests/test_context_help_command.rs index e95c8a99cd..4ab2fe6d6c 100644 --- a/e2etests/tests/test_context_help_command.rs +++ b/e2etests/tests/test_context_help_command.rs @@ -1,6 +1,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] +#[cfg(feature = "context")] fn test_context_help_command() -> Result<(), Box> { println!("πŸ” Testing /context help command..."); diff --git a/e2etests/tests/test_context_invalid_command.rs b/e2etests/tests/test_context_invalid_command.rs index bfebbf786c..6a56bf00c9 100644 --- a/e2etests/tests/test_context_invalid_command.rs +++ b/e2etests/tests/test_context_invalid_command.rs @@ -1,6 +1,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] +#[cfg(feature = "context")] fn test_context_invalid_command() -> Result<(), Box> { println!("πŸ” Testing /context invalid command..."); diff --git a/e2etests/tests/test_context_remove_command_of_non_existent_file.rs b/e2etests/tests/test_context_remove_command_of_non_existent_file.rs index 6acbd56ddf..d9104dc931 100644 --- a/e2etests/tests/test_context_remove_command_of_non_existent_file.rs +++ b/e2etests/tests/test_context_remove_command_of_non_existent_file.rs @@ -1,6 +1,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] +#[cfg(feature = "context")] fn test_context_remove_command_of_non_existent_file() -> Result<(), Box> { println!("πŸ” Testing /context remove non existing file command..."); diff --git a/e2etests/tests/test_context_show_command.rs b/e2etests/tests/test_context_show_command.rs index 5b56f964bc..a40cf4d73e 100644 --- a/e2etests/tests/test_context_show_command.rs +++ b/e2etests/tests/test_context_show_command.rs @@ -1,6 +1,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] +#[cfg(feature = "context")] fn test_context_show_command() -> Result<(), Box> { println!("πŸ” Testing /context show command..."); diff --git a/e2etests/tests/test_context_without_subcommand.rs b/e2etests/tests/test_context_without_subcommand.rs index 61dd8e21be..b6b8fc5371 100644 --- a/e2etests/tests/test_context_without_subcommand.rs +++ b/e2etests/tests/test_context_without_subcommand.rs @@ -1,6 +1,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] +#[cfg(feature = "context")] fn test_context_without_subcommand() -> Result<(), Box> { println!("πŸ” Testing /context without sub command..."); diff --git a/e2etests/tests/test_editor_help_command.rs b/e2etests/tests/test_editor_help_command.rs index 313c2a4913..6b87fb8b7c 100644 --- a/e2etests/tests/test_editor_help_command.rs +++ b/e2etests/tests/test_editor_help_command.rs @@ -1,6 +1,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] +#[cfg(feature = "integration")] fn test_editor_help_command() -> Result<(), Box> { println!("πŸ” Testing /editor --help command..."); @@ -44,7 +45,9 @@ fn test_editor_help_command() -> Result<(), Box> { Ok(()) } +#[cfg(feature = "integration")] #[test] +#[cfg(feature = "integration")] fn test_help_editor_command() -> Result<(), Box> { println!("πŸ” Testing /help editor command..."); diff --git a/e2etests/tests/test_help_command.rs b/e2etests/tests/test_help_command.rs index f9f6db8c2c..39a3b932e2 100644 --- a/e2etests/tests/test_help_command.rs +++ b/e2etests/tests/test_help_command.rs @@ -1,8 +1,9 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] +#[cfg(feature = "core_session")] fn test_help_command() -> Result<(), Box> { - println!("πŸ” Testing /help command..."); + println!("πŸ” [CORE SESSION] Testing /help command..."); let mut chat = QChatSession::new()?; println!("βœ… Q Chat session started"); diff --git a/e2etests/tests/test_hooks_help_command.rs b/e2etests/tests/test_hooks_help_command.rs index db2caec614..02270e5a93 100644 --- a/e2etests/tests/test_hooks_help_command.rs +++ b/e2etests/tests/test_hooks_help_command.rs @@ -1,6 +1,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] +#[cfg(feature = "integration")] fn test_hooks_help_command() -> Result<(), Box> { println!("πŸ” Testing /hooks --help command..."); diff --git a/e2etests/tests/test_load_help_command.rs b/e2etests/tests/test_load_help_command.rs index 36f437f5c5..0a7b179f88 100644 --- a/e2etests/tests/test_load_help_command.rs +++ b/e2etests/tests/test_load_help_command.rs @@ -1,6 +1,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] +#[cfg(feature = "save_load")] fn test_load_help_command() -> Result<(), Box> { println!("πŸ” Testing /load --help command..."); diff --git a/e2etests/tests/test_mcp_help_command.rs b/e2etests/tests/test_mcp_help_command.rs index 2820651386..1e798a29a2 100644 --- a/e2etests/tests/test_mcp_help_command.rs +++ b/e2etests/tests/test_mcp_help_command.rs @@ -1,6 +1,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] +#[cfg(feature = "mcp")] fn test_mcp_help_command() -> Result<(), Box> { println!("πŸ” Testing /mcp --help command..."); @@ -38,4 +39,4 @@ fn test_mcp_help_command() -> Result<(), Box> { println!("βœ… Test completed successfully"); Ok(()) -} \ No newline at end of file +} diff --git a/e2etests/tests/test_mcp_loading_command.rs b/e2etests/tests/test_mcp_loading_command.rs index 2765b13ea6..7fd6ce53bc 100644 --- a/e2etests/tests/test_mcp_loading_command.rs +++ b/e2etests/tests/test_mcp_loading_command.rs @@ -1,6 +1,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] +#[cfg(feature = "mcp")] fn test_mcp_loading_command() -> Result<(), Box> { println!("πŸ” Testing MCP loading..."); @@ -34,4 +35,4 @@ fn test_mcp_loading_command() -> Result<(), Box> { println!("βœ… Test completed successfully"); Ok(()) -} \ No newline at end of file +} diff --git a/e2etests/tests/test_model_command.rs b/e2etests/tests/test_model_command.rs index 74a8b63559..f55112b7e5 100644 --- a/e2etests/tests/test_model_command.rs +++ b/e2etests/tests/test_model_command.rs @@ -1,6 +1,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] +#[cfg(feature = "model")] fn test_model_command() -> Result<(), Box> { println!("πŸ” Testing /model command interface and selection..."); diff --git a/e2etests/tests/test_model_help_command.rs b/e2etests/tests/test_model_help_command.rs index 1d51e16c7c..dbec84a4f3 100644 --- a/e2etests/tests/test_model_help_command.rs +++ b/e2etests/tests/test_model_help_command.rs @@ -1,6 +1,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] +#[cfg(feature = "model")] fn test_model_help_command() -> Result<(), Box> { println!("πŸ” Testing /model --help command..."); @@ -38,4 +39,4 @@ fn test_model_help_command() -> Result<(), Box> { println!("βœ… Test completed successfully"); Ok(()) -} \ No newline at end of file +} diff --git a/e2etests/tests/test_quit_command.rs b/e2etests/tests/test_quit_command.rs index dbc9215b65..c05b95d075 100644 --- a/e2etests/tests/test_quit_command.rs +++ b/e2etests/tests/test_quit_command.rs @@ -1,6 +1,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] +#[cfg(feature = "core_session")] fn test_quit_command() -> Result<(), Box> { println!("πŸ” Testing /quit command..."); diff --git a/e2etests/tests/test_save_command.rs b/e2etests/tests/test_save_command.rs index 6fa2710651..9a247e6cc2 100644 --- a/e2etests/tests/test_save_command.rs +++ b/e2etests/tests/test_save_command.rs @@ -14,6 +14,7 @@ impl<'a> Drop for FileCleanup<'a> { } #[test] +#[cfg(feature = "save_load")] fn test_save_command() -> Result<(), Box> { println!("πŸ” Testing /save command..."); diff --git a/e2etests/tests/test_save_force_command.rs b/e2etests/tests/test_save_force_command.rs index 6cdccd5c6b..637b27a5d6 100644 --- a/e2etests/tests/test_save_force_command.rs +++ b/e2etests/tests/test_save_force_command.rs @@ -14,6 +14,7 @@ impl<'a> Drop for FileCleanup<'a> { } #[test] +#[cfg(feature = "save_load")] fn test_save_force_command() -> Result<(), Box> { println!("πŸ” Testing /save --force command..."); diff --git a/e2etests/tests/test_save_help_command.rs b/e2etests/tests/test_save_help_command.rs index 9a3e556cae..05ee6ed614 100644 --- a/e2etests/tests/test_save_help_command.rs +++ b/e2etests/tests/test_save_help_command.rs @@ -1,6 +1,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] +#[cfg(feature = "save_load")] fn test_save_help_command() -> Result<(), Box> { println!("πŸ” Testing /save --help command..."); diff --git a/e2etests/tests/test_subscribe_command.rs b/e2etests/tests/test_subscribe_command.rs index 93160ae656..88cf499cf0 100644 --- a/e2etests/tests/test_subscribe_command.rs +++ b/e2etests/tests/test_subscribe_command.rs @@ -1,6 +1,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] +#[cfg(feature = "integration")] fn test_subscribe_command() -> Result<(), Box> { println!("πŸ” Testing /subscribe command..."); diff --git a/e2etests/tests/test_subscribe_help_command.rs b/e2etests/tests/test_subscribe_help_command.rs index 70c5d65d76..19e2ccf8b6 100644 --- a/e2etests/tests/test_subscribe_help_command.rs +++ b/e2etests/tests/test_subscribe_help_command.rs @@ -1,6 +1,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] +#[cfg(feature = "integration")] fn test_subscribe_help_command() -> Result<(), Box> { println!("πŸ” Testing /subscribe --help command..."); diff --git a/e2etests/tests/test_tools_command.rs b/e2etests/tests/test_tools_command.rs index 3a10500e06..c28b0810c1 100644 --- a/e2etests/tests/test_tools_command.rs +++ b/e2etests/tests/test_tools_command.rs @@ -1,6 +1,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] +#[cfg(feature = "core_session")] fn test_tools_command() -> Result<(), Box> { println!("πŸ” Testing /tools command..."); diff --git a/e2etests/tests/test_usage_command.rs b/e2etests/tests/test_usage_command.rs index bb75546300..2d8bc02741 100644 --- a/e2etests/tests/test_usage_command.rs +++ b/e2etests/tests/test_usage_command.rs @@ -1,6 +1,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] +#[cfg(feature = "session_mgmt")] fn test_usage_command() -> Result<(), Box> { println!("πŸ” Testing /usage command..."); diff --git a/e2etests/tests/test_usage_help_command.rs b/e2etests/tests/test_usage_help_command.rs index 1782007389..459f2e0fc5 100644 --- a/e2etests/tests/test_usage_help_command.rs +++ b/e2etests/tests/test_usage_help_command.rs @@ -1,6 +1,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] +#[cfg(feature = "session_mgmt")] fn test_usage_help_command() -> Result<(), Box> { println!("πŸ” Testing /usage --help command..."); From 8c280e004470a1fb3408e70f24f9cc0898490d46 Mon Sep 17 00:00:00 2001 From: abhraina-aws Date: Tue, 12 Aug 2025 13:59:15 -0700 Subject: [PATCH 07/77] fix: added an updated readme --- e2etests/README.md | 195 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 147 insertions(+), 48 deletions(-) diff --git a/e2etests/README.md b/e2etests/README.md index ff02ad43eb..7420336c98 100644 --- a/e2etests/README.md +++ b/e2etests/README.md @@ -1,6 +1,6 @@ # Q CLI E2E Test Framework -This test framework provides comprehensive end-to-end testing capabilities for Amazon Q CLI using a hybrid approach with expectrl. +This test framework provides comprehensive end-to-end testing capabilities for Amazon Q CLI using a hybrid approach with expectrl and feature-based categorization. ## πŸ—οΈ Architecture @@ -12,6 +12,38 @@ This test framework provides comprehensive end-to-end testing capabilities for A - **Commands** write to PTY stream β†’ expectrl captures perfectly βœ… - **AI responses** write to stdout β†’ direct streams capture properly βœ… +## 🎯 Categorized Test Framework + +### **Feature-Based Organization** +Tests are organized into 9 functional categories using Rust features: + +1. **Core Session Commands** (4 tests) - `core_session` + - `/help`, `/tools`, `/quit`, `/clear` + +2. **Agent Commands** (8 tests) - `agent` + - `/agent list`, `/agent create`, `/agent help`, etc. + +3. **Context Commands** (5 tests) - `context` + - `/context show`, `/context add`, `/context help`, etc. + +4. **Save/Load Commands** (4 tests) - `save_load` + - `/save`, `/load`, help commands + +5. **Model Commands** (2 tests) - `model` + - `/model`, `/model --help` + +6. **Session Management Commands** (4 tests) - `session_mgmt` + - `/compact`, `/usage`, help commands + +7. **Integration Commands** (4 tests) - `integration` + - `/subscribe`, `/hooks`, `/editor` help commands + +8. **MCP Commands** (2 tests) - `mcp` + - `/mcp`, `/mcp --help` + +9. **AI Prompts** (2 tests) - `ai_prompts` + - "What is AWS?", "Hello" prompts + ## πŸ“ Core Files ### **`tests/q_chat_helper.rs`** @@ -21,57 +53,92 @@ Base helper class providing: - `send_prompt(prompt)` - Send AI prompts using direct process streams - `quit()` - Clean session termination -### **Test Files** -- **`test_help_command.rs`** - Tests `/help` command with full content verification -- **`test_tools_command.rs`** - Tests `/tools` command with tool listing verification -- **`test_ai_prompt.rs`** - Tests AI prompts with response content verification +### **`run_simple_categorized.sh`** +Advanced categorized test runner with: +- **Real-time per-test feedback** - Shows βœ…/❌ as each test completes +- **Category organization** - Groups tests by functional area +- **Configurable categories** - Enable/disable categories for faster iteration +- **Quiet and verbose modes** - Control output detail level +- **Final summary reporting** - Shows passed/failed categories ## πŸš€ Usage -### **Using Default System Q CLI Binary** -```bash -cd e2etests -./run_tests.sh -``` - -### **Using Custom Q CLI Builds** -Set the `Q_CLI_PATH` environment variable or pass the path directly: +### **Categorized Test Runner (Recommended)** ```bash -# Test with workspace build -./run_tests.sh ../target/release/chat_cli +# Run all categories with real-time feedback +./run_simple_categorized.sh -# Test with custom build -export Q_CLI_PATH="/path/to/your/custom/chat_cli" -cargo test --test test_help_command -- --nocapture +# Quiet mode - faster, less verbose +./run_simple_categorized.sh --quiet -# Or use the convenience script -./run_tests.sh /path/to/your/custom/chat_cli test_help_command -./run_tests.sh /path/to/your/custom/chat_cli # Run all tests +# With custom Q CLI binary +./run_simple_categorized.sh /path/to/custom/q --quiet ``` -### **Run Individual Tests** -```bash -# Test help command -cargo test --test test_help_command -- --nocapture +**Example Output:** +``` +πŸ§ͺ Core Session Commands +--------------------- +πŸ“‹ Tests in this category: + β€’ test_help_command + β€’ test_tools_command + β€’ test_quit_command + β€’ test_clear_command + +πŸ”„ Running tests... + βœ… test_help_command + βœ… test_tools_command + βœ… test_quit_command + βœ… test_clear_command +βœ… Core Session Commands completed successfully + +🎯 FINAL SUMMARY +================================ +βœ… Categories Passed: 9 +❌ Categories Failed: 0 +πŸ“Š Total Categories: 9 +πŸŽ‰ All categories passed! +``` -# Test AI prompts -cargo test --test test_ai_prompt test_what_is_aws_prompt -- --nocapture +### **Category Configuration** +Edit the top of `run_simple_categorized.sh` to enable/disable categories: -# Test tools command -cargo test --test test_tools_command -- --nocapture +```bash +# Enable/disable categories for faster iteration +RUN_CORE_SESSION=true +RUN_AGENT=false # Skip agent tests +RUN_CONTEXT=true +RUN_AI_PROMPTS=true +# etc... ``` -### **Run All Tests** +### **Individual Category Testing** ```bash -cargo test --test test_help_command --test test_tools_command --test test_ai_prompt -- --nocapture +# Test specific categories +cargo test --tests --features "core_session" -- --nocapture +cargo test --tests --features "agent" -- --nocapture +cargo test --tests --features "ai_prompts" -- --nocapture ``` -## βœ… Test Coverage +### **Legacy Test Runner** +```bash +# Original test runner (still available) +./run_tests.sh +./run_tests.sh ../target/release/chat_cli +``` -### **Commands Tested** -- `/help` - Full help content with Commands, Options, MCP, Tips sections -- `/tools` - Tool listing with Built-in and MCP tools, permission status +## βœ… Comprehensive Test Coverage + +### **Commands Tested (32+ tests)** +- **Core Session**: `/help`, `/tools`, `/quit`, `/clear` +- **Agent Management**: `/agent list`, `/agent create`, `/agent help`, etc. +- **Context Management**: `/context show`, `/context add`, `/context help`, etc. +- **Save/Load**: `/save`, `/load`, help commands +- **Model Selection**: `/model`, `/model --help` +- **Session Management**: `/compact`, `/usage`, help commands +- **Integration**: `/subscribe`, `/hooks`, `/editor` help commands +- **MCP**: `/mcp`, `/mcp --help` ### **AI Prompts Tested** - "What is AWS?" - Technical explanation with verification @@ -81,29 +148,61 @@ cargo test --test test_help_command --test test_tools_command --test test_ai_pro - **Content verification**: Specific text and sections present - **Response quality**: Technical terms, appropriate length - **Full output capture**: Complete interaction including UI elements +- **Real-time feedback**: Per-test pass/fail status ## 🎯 Success Metrics -- **Help Command**: 2343+ bytes, all sections verified βœ… -- **Tools Command**: 3355+ bytes, all tools and permissions verified βœ… -- **AI Prompts**: 5000+ bytes, complete technical responses verified βœ… +- **34 Total Tests** across 9 functional categories βœ… +- **Real-time feedback** with per-test results βœ… +- **Categorized organization** for better reporting βœ… +- **Configurable execution** for faster iteration βœ… +- **Comprehensive coverage** of all Q CLI commands βœ… ## πŸ”§ Integration with Workspace This E2E test framework is designed to work with the Q CLI workspace: - **Default binary**: Uses system `q` command (from PATH) -- **Workspace integration**: Can test the workspace build with `./run_tests.sh ../target/release/chat_cli` -- **CI/CD ready**: Can be integrated into build pipelines +- **Workspace integration**: Can test the workspace build +- **CI/CD ready**: Can be integrated into build pipelines with categorized reporting - **Custom binary support**: Test different builds as needed ## πŸ”§ Extending -To add new tests: - -1. **For Commands**: Use `execute_command()` method with expectrl -2. **For AI Prompts**: Use `send_prompt()` method with direct streams -3. **Always**: Print full output first, then verify content -4. **Pattern**: Start session β†’ Execute β†’ Verify β†’ Quit - -This framework provides comprehensive E2E testing for the Q CLI with both interactive commands and AI functionality. +### **Adding New Tests** + +1. **Create test file** in `tests/` directory +2. **Add feature attribute** to categorize the test: + ```rust + #[test] + #[cfg(feature = "category_name")] + fn test_new_command() -> Result<(), Box> { + // Test implementation + } + ``` +3. **Update category configuration** in `run_simple_categorized.sh` if needed + +### **Adding New Categories** + +1. **Add feature** to `Cargo.toml`: + ```toml + [features] + new_category = [] + ``` +2. **Add category** to `run_simple_categorized.sh`: + ```bash + RUN_NEW_CATEGORY=true + # ... + if [ "$RUN_NEW_CATEGORY" = true ]; then + run_category "new_category" "New Category Commands" + fi + ``` + +### **Test Patterns** + +- **For Commands**: Use `execute_command()` method with expectrl +- **For AI Prompts**: Use `send_prompt()` method with direct streams +- **Always**: Print full output first, then verify content +- **Pattern**: Start session β†’ Execute β†’ Verify β†’ Quit + +This framework provides comprehensive, categorized E2E testing for the Q CLI with real-time feedback and flexible execution options. From 4e79a1abcd234f9b088b08d6be80c1266af18936 Mon Sep 17 00:00:00 2001 From: "Shreya [C] Bhagat" Date: Wed, 13 Aug 2025 18:45:39 +0530 Subject: [PATCH 08/77] Q CLI Automation for basic chat and context --- e2etests/tests/test_add_file_context.rs | 51 +++++++++++ .../test_add_globe_pattern_file_context.rs | 59 +++++++++++++ .../tests/test_add_multiple_file_context.rs | 59 +++++++++++++ .../test_add_non_existing_file_context.rs | 31 +++++++ e2etests/tests/test_clear_context_command.rs | 82 ++++++++++++++++++ e2etests/tests/test_load_command.rs | 65 ++++++++++++++ .../test_load_command_argument_validation.rs | 44 ++++++++++ e2etests/tests/test_load_help_command.rs | 43 ++++++++++ e2etests/tests/test_remove_file_context.rs | 75 +++++++++++++++++ .../test_remove_multiple_file_context.rs | 84 +++++++++++++++++++ .../test_save_command_argument_validation.rs | 46 ++++++++++ e2etests/tests/test_save_force_command.rs | 55 ++++++++++++ e2etests/tests/test_save_help_command.rs | 45 ++++++++++ 13 files changed, 739 insertions(+) create mode 100644 e2etests/tests/test_add_file_context.rs create mode 100644 e2etests/tests/test_add_globe_pattern_file_context.rs create mode 100644 e2etests/tests/test_add_multiple_file_context.rs create mode 100644 e2etests/tests/test_add_non_existing_file_context.rs create mode 100644 e2etests/tests/test_clear_context_command.rs create mode 100644 e2etests/tests/test_load_command.rs create mode 100644 e2etests/tests/test_load_command_argument_validation.rs create mode 100644 e2etests/tests/test_remove_file_context.rs create mode 100644 e2etests/tests/test_remove_multiple_file_context.rs create mode 100644 e2etests/tests/test_save_command_argument_validation.rs diff --git a/e2etests/tests/test_add_file_context.rs b/e2etests/tests/test_add_file_context.rs new file mode 100644 index 0000000000..ebcb795a55 --- /dev/null +++ b/e2etests/tests/test_add_file_context.rs @@ -0,0 +1,51 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "context")] +fn test_add_file_context() -> Result<(), Box> { + println!("πŸ” Testing /context add command..."); + + let test_file_path = "/tmp/test_context_file.py"; + + // Create a test file + std::fs::write(test_file_path, "# Test file for context\nprint('Hello from test file')")?; + println!("βœ… Created test file at {}", test_file_path); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + // Add file to context + let add_response = chat.execute_command(&format!("/context add {}", test_file_path))?; + + println!("πŸ“ Context add response: {} bytes", add_response.len()); + println!("πŸ“ ADD RESPONSE:"); + println!("{}", add_response); + println!("πŸ“ END ADD RESPONSE"); + + // Verify file was added successfully + assert!(add_response.contains("Added 1 path(s) to context"), "Missing success message for adding file"); + println!("βœ… File added to context successfully"); + + // Execute /context show to confirm file is present + let show_response = chat.execute_command("/context show")?; + + println!("πŸ“ Context show response: {} bytes", show_response.len()); + println!("πŸ“ SHOW RESPONSE:"); + println!("{}", show_response); + println!("πŸ“ END SHOW RESPONSE"); + + // Verify file is present in context + assert!(show_response.contains(test_file_path), "File not found in context show output"); + assert!(show_response.contains("πŸ’¬ Session (temporary):"), "Missing Session section"); + println!("βœ… File confirmed present in context"); + + chat.quit()?; + + // Clean up test file + let _ = std::fs::remove_file(test_file_path); + println!("βœ… Cleaned up test file"); + + println!("βœ… Test completed successfully"); + + Ok(()) +} diff --git a/e2etests/tests/test_add_globe_pattern_file_context.rs b/e2etests/tests/test_add_globe_pattern_file_context.rs new file mode 100644 index 0000000000..53b81fcceb --- /dev/null +++ b/e2etests/tests/test_add_globe_pattern_file_context.rs @@ -0,0 +1,59 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "context")] +fn test_add_glob_pattern_file_context() -> Result<(), Box> { + println!("πŸ” Testing /context add *.py glob pattern command..."); + + let test_file1_path = "/tmp/test_context_file1.py"; + let test_file2_path = "/tmp/test_context_file2.py"; + let test_file3_path = "/tmp/test_context_file.js"; // Non-matching file + let glob_pattern = "/tmp/*.py"; + + // Create test files + std::fs::write(test_file1_path, "# Test Python file 1 for context\nprint('Hello from Python file 1')")?; + std::fs::write(test_file2_path, "# Test Python file 2 for context\nprint('Hello from Python file 2')")?; + std::fs::write(test_file3_path, "// Test JavaScript file\nconsole.log('Hello from JS file');")?; + println!("βœ… Created test files at {}, {}, {}", test_file1_path, test_file2_path, test_file3_path); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + // Add glob pattern to context + let add_response = chat.execute_command(&format!("/context add {}", glob_pattern))?; + + println!("πŸ“ Context add response: {} bytes", add_response.len()); + println!("πŸ“ ADD RESPONSE:"); + println!("{}", add_response); + println!("πŸ“ END ADD RESPONSE"); + + // Verify glob pattern was added successfully + assert!(add_response.contains("Added 1 path(s) to context"), "Missing success message for adding glob pattern"); + println!("βœ… Glob pattern added to context successfully"); + + // Execute /context show to confirm pattern matches files + let show_response = chat.execute_command("/context show")?; + + println!("πŸ“ Context show response: {} bytes", show_response.len()); + println!("πŸ“ SHOW RESPONSE:"); + println!("{}", show_response); + println!("πŸ“ END SHOW RESPONSE"); + + // Verify glob pattern is present and matches files + assert!(show_response.contains(glob_pattern), "Glob pattern not found in context show output"); + assert!(show_response.contains("match"), "Missing match indicator for glob pattern"); + assert!(show_response.contains("πŸ’¬ Session (temporary):"), "Missing Session section"); + println!("βœ… Glob pattern confirmed present in context with matches"); + + chat.quit()?; + + // Clean up test files + let _ = std::fs::remove_file(test_file1_path); + let _ = std::fs::remove_file(test_file2_path); + let _ = std::fs::remove_file(test_file3_path); + println!("βœ… Cleaned up test files"); + + println!("βœ… Test completed successfully"); + + Ok(()) +} diff --git a/e2etests/tests/test_add_multiple_file_context.rs b/e2etests/tests/test_add_multiple_file_context.rs new file mode 100644 index 0000000000..9573a9960b --- /dev/null +++ b/e2etests/tests/test_add_multiple_file_context.rs @@ -0,0 +1,59 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "context")] +fn test_add_multiple_file_context() -> Result<(), Box> { + println!("πŸ” Testing /context add command..."); + + let test_file1_path = "/tmp/test_context_file1.py"; + let test_file2_path = "/tmp/test_context_file2.js"; + let test_file3_path = "/tmp/test_context_file3.txt"; + + // Create multiple test files + std::fs::write(test_file1_path, "# Test Python file for context\nprint('Hello from Python file')")?; + std::fs::write(test_file2_path, "// Test JavaScript file for context\nconsole.log('Hello from JS file');")?; + std::fs::write(test_file3_path, "Test text file for context\nHello from text file")?; + println!("βœ… Created test files at {}, {}, {}", test_file1_path, test_file2_path, test_file3_path); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + // Add multiple files to context in one command + let add_response = chat.execute_command(&format!("/context add {} {} {}", test_file1_path, test_file2_path, test_file3_path))?; + + println!("πŸ“ Context add response: {} bytes", add_response.len()); + println!("πŸ“ ADD RESPONSE:"); + println!("{}", add_response); + println!("πŸ“ END ADD RESPONSE"); + + // Verify files were added successfully + assert!(add_response.contains("Added 3 path(s) to context"), "Missing success message for adding multiple files"); + println!("βœ… Multiple files added to context successfully"); + + // Execute /context show to confirm files are present + let show_response = chat.execute_command("/context show")?; + + println!("πŸ“ Context show response: {} bytes", show_response.len()); + println!("πŸ“ SHOW RESPONSE:"); + println!("{}", show_response); + println!("πŸ“ END SHOW RESPONSE"); + + // Verify all files are present in context + assert!(show_response.contains(test_file1_path), "Python file not found in context show output"); + assert!(show_response.contains(test_file2_path), "JavaScript file not found in context show output"); + assert!(show_response.contains(test_file3_path), "Text file not found in context show output"); + assert!(show_response.contains("πŸ’¬ Session (temporary):"), "Missing Session section"); + println!("βœ… All files confirmed present in context"); + + chat.quit()?; + + // Clean up test files + let _ = std::fs::remove_file(test_file1_path); + let _ = std::fs::remove_file(test_file2_path); + let _ = std::fs::remove_file(test_file3_path); + println!("βœ… Cleaned up test files"); + + println!("βœ… Test completed successfully"); + + Ok(()) +} diff --git a/e2etests/tests/test_add_non_existing_file_context.rs b/e2etests/tests/test_add_non_existing_file_context.rs new file mode 100644 index 0000000000..1786c8ab3e --- /dev/null +++ b/e2etests/tests/test_add_non_existing_file_context.rs @@ -0,0 +1,31 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "context")] +fn test_add_non_existing_file_context() -> Result<(), Box> { + println!("πŸ” Testing /context add non-existing file command..."); + + let non_existing_file_path = "/tmp/non_existing_file.py"; + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + // Try to add non-existing file to context + let add_response = chat.execute_command(&format!("/context add {}", non_existing_file_path))?; + + println!("πŸ“ Context add response: {} bytes", add_response.len()); + println!("πŸ“ ADD RESPONSE:"); + println!("{}", add_response); + println!("πŸ“ END ADD RESPONSE"); + + // Verify error message for non-existing file + assert!(add_response.contains("Error:") && add_response.contains("Invalid path") && add_response.contains("does not exist"), "Missing error message for non-existing file"); + assert!(add_response.contains("Use --force to add anyway"), "Missing --force suggestion in error message"); + println!("βœ… Found expected error message for non-existing file with --force suggestion"); + + chat.quit()?; + + println!("βœ… Test completed successfully"); + + Ok(()) +} diff --git a/e2etests/tests/test_clear_context_command.rs b/e2etests/tests/test_clear_context_command.rs new file mode 100644 index 0000000000..14b72ed4b4 --- /dev/null +++ b/e2etests/tests/test_clear_context_command.rs @@ -0,0 +1,82 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "context")] +fn test_clear_context_command() -> Result<(), Box> { + println!("πŸ” Testing /context clear command..."); + + let test_file1_path = "/tmp/test_context_file1.py"; + let test_file2_path = "/tmp/test_context_file2.js"; + + // Create multiple test files + std::fs::write(test_file1_path, "# Test Python file for context\nprint('Hello from Python file')")?; + std::fs::write(test_file2_path, "// Test JavaScript file for context\nconsole.log('Hello from JS file');")?; + println!("βœ… Created test files at {}, {}", test_file1_path, test_file2_path); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + // Add multiple files to context + let add_response = chat.execute_command(&format!("/context add {} {}", test_file1_path, test_file2_path))?; + + println!("πŸ“ Context add response: {} bytes", add_response.len()); + println!("πŸ“ ADD RESPONSE:"); + println!("{}", add_response); + println!("πŸ“ END ADD RESPONSE"); + + // Verify files were added successfully + assert!(add_response.contains("Added 2 path(s) to context"), "Missing success message for adding files"); + println!("βœ… Files added to context successfully"); + + // Execute /context show to confirm files are present + let show_response = chat.execute_command("/context show")?; + + println!("πŸ“ Context show response: {} bytes", show_response.len()); + println!("πŸ“ SHOW RESPONSE:"); + println!("{}", show_response); + println!("πŸ“ END SHOW RESPONSE"); + + // Verify files are present in context + assert!(show_response.contains(test_file1_path), "Python file not found in context show output"); + assert!(show_response.contains(test_file2_path), "JavaScript file not found in context show output"); + println!("βœ… Files confirmed present in context"); + + // Execute /context clear to remove all files + let clear_response = chat.execute_command("/context clear")?; + + println!("πŸ“ Context clear response: {} bytes", clear_response.len()); + println!("πŸ“ CLEAR RESPONSE:"); + println!("{}", clear_response); + println!("πŸ“ END CLEAR RESPONSE"); + + // Verify context was cleared successfully + assert!(clear_response.contains("Cleared context"), "Missing success message for clearing context"); + println!("βœ… Context cleared successfully"); + + // Execute /context show to confirm no files remain + let final_show_response = chat.execute_command("/context show")?; + + println!("πŸ“ Final context show response: {} bytes", final_show_response.len()); + println!("πŸ“ FINAL SHOW RESPONSE:"); + println!("{}", final_show_response); + println!("πŸ“ END FINAL SHOW RESPONSE"); + + // Verify no files remain in context + assert!(!final_show_response.contains(test_file1_path), "Python file still found in context after clear"); + assert!(!final_show_response.contains(test_file2_path), "JavaScript file still found in context after clear"); + assert!(final_show_response.contains("πŸ‘€ Agent (q_cli_default):"), "Missing Agent section"); + assert!(final_show_response.contains("πŸ’¬ Session (temporary):"), "Missing Session section"); + assert!(final_show_response.contains(""), "Missing indicator for cleared context"); + println!("βœ… All files confirmed removed from context and sections present"); + + chat.quit()?; + + // Clean up test files + let _ = std::fs::remove_file(test_file1_path); + let _ = std::fs::remove_file(test_file2_path); + println!("βœ… Cleaned up test files"); + + println!("βœ… Test completed successfully"); + + Ok(()) +} diff --git a/e2etests/tests/test_load_command.rs b/e2etests/tests/test_load_command.rs new file mode 100644 index 0000000000..873640252f --- /dev/null +++ b/e2etests/tests/test_load_command.rs @@ -0,0 +1,65 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +struct FileCleanup<'a> { + path: &'a str, +} + +impl<'a> Drop for FileCleanup<'a> { + fn drop(&mut self) { + if std::path::Path::new(self.path).exists() { + let _ = std::fs::remove_file(self.path); + println!("βœ… Cleaned up test file"); + } + } +} + +#[test] +#[cfg(feature = "save_load")] +fn test_load_command() -> Result<(), Box> { + println!("πŸ” Testing /load command..."); + + let save_path = "/tmp/qcli_test_load.json"; + let _cleanup = FileCleanup { path: save_path }; + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + // Create actual conversation content + let _help_response = chat.execute_command("/help")?; + let _tools_response = chat.execute_command("/tools")?; + println!("βœ… Created conversation content with /help and /tools commands"); + + // Execute /save command to create a file to load + let save_response = chat.execute_command(&format!("/save {}", save_path))?; + + println!("πŸ“ Save response: {} bytes", save_response.len()); + println!("πŸ“ SAVE OUTPUT:"); + println!("{}", save_response); + println!("πŸ“ END SAVE OUTPUT"); + + // Verify save was successful + assert!(save_response.contains("Exported conversation state to") && save_response.contains(save_path), "Missing export confirmation message"); + println!("βœ… Save completed successfully"); + + // Verify file was created + assert!(std::path::Path::new(save_path).exists(), "Save file was not created"); + println!("βœ… Save file created at {}", save_path); + + // Execute /load command to load the saved conversation + let load_response = chat.execute_command(&format!("/load {}", save_path))?; + + println!("πŸ“ Load response: {} bytes", load_response.len()); + println!("πŸ“ LOAD OUTPUT:"); + println!("{}", load_response); + println!("πŸ“ END LOAD OUTPUT"); + + // Verify load was successful + assert!(!load_response.is_empty(), "Load command should return non-empty response"); + assert!(load_response.contains("Imported conversation state from") && load_response.contains(save_path), "Missing import confirmation message"); + println!("βœ… Load command executed successfully and imported conversation state"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} diff --git a/e2etests/tests/test_load_command_argument_validation.rs b/e2etests/tests/test_load_command_argument_validation.rs new file mode 100644 index 0000000000..50475fef5d --- /dev/null +++ b/e2etests/tests/test_load_command_argument_validation.rs @@ -0,0 +1,44 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "save_load")] +fn test_load_command_argument_validation() -> Result<(), Box> { + println!("πŸ” Testing /load command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/load")?; + + println!("πŸ“ Help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify load error message + assert!(response.contains("error:") && response.contains("the following required arguments were not provided:"), "Missing load error message"); + println!("βœ… Found load error message"); + + assert!(response.contains("Usage:"), "Missing Usage section"); + assert!(response.contains("/load"), "Missing /load command in usage"); + println!("βœ… Found Usage section with /load command"); + + assert!(response.contains("Arguments:"), "Missing Arguments section"); + assert!(response.contains(""), "Missing PATH argument"); + println!("βœ… Found Arguments section with PATH parameter"); + + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("-h"), "Missing -h flag"); + assert!(response.contains("--help") || response.contains("β€”help"), "Missing --help flag"); + println!("βœ… Found Options section with -h, --help flags"); + + assert!(response.contains("Print help"), "Missing help description"); + println!("βœ… Found help flag description"); + + println!("βœ… All help content verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} diff --git a/e2etests/tests/test_load_help_command.rs b/e2etests/tests/test_load_help_command.rs index 0a7b179f88..3591df228e 100644 --- a/e2etests/tests/test_load_help_command.rs +++ b/e2etests/tests/test_load_help_command.rs @@ -42,3 +42,46 @@ fn test_load_help_command() -> Result<(), Box> { Ok(()) } + +#[test] +#[cfg(feature = "save_load")] +fn test_load_h_flag_command() -> Result<(), Box> { + println!("πŸ” Testing /load -h command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/load -h")?; + + println!("πŸ“ Help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify load command help content + assert!(response.contains("Load a previous conversation"), "Missing load command description"); + println!("βœ… Found load command description"); + + assert!(response.contains("Usage:"), "Missing Usage section"); + assert!(response.contains("/load"), "Missing /load command in usage"); + println!("βœ… Found Usage section with /load command"); + + assert!(response.contains("Arguments:"), "Missing Arguments section"); + assert!(response.contains(""), "Missing PATH argument"); + println!("βœ… Found Arguments section with PATH parameter"); + + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("-h"), "Missing -h flag"); + assert!(response.contains("--help"), "Missing --help flag"); + println!("βœ… Found Options section with -h, --help flags"); + + assert!(response.contains("Print help"), "Missing help description"); + println!("βœ… Found help flag description"); + + println!("βœ… All help content verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} diff --git a/e2etests/tests/test_remove_file_context.rs b/e2etests/tests/test_remove_file_context.rs new file mode 100644 index 0000000000..787a164bd8 --- /dev/null +++ b/e2etests/tests/test_remove_file_context.rs @@ -0,0 +1,75 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "context")] +fn test_remove_file_context() -> Result<(), Box> { + println!("πŸ” Testing /context remove command..."); + + let test_file_path = "/tmp/test_context_file.py"; + + // Create a test file + std::fs::write(test_file_path, "# Test file for context\nprint('Hello from test file')")?; + println!("βœ… Created test file at {}", test_file_path); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + // Add file to context + let add_response = chat.execute_command(&format!("/context add {}", test_file_path))?; + + println!("πŸ“ Context add response: {} bytes", add_response.len()); + println!("πŸ“ ADD RESPONSE:"); + println!("{}", add_response); + println!("πŸ“ END ADD RESPONSE"); + + // Verify file was added successfully + assert!(add_response.contains("Added 1 path(s) to context"), "Missing success message for adding file"); + println!("βœ… File added to context successfully"); + + // Execute /context show to confirm file is present + let show_response = chat.execute_command("/context show")?; + + println!("πŸ“ Context show response: {} bytes", show_response.len()); + println!("πŸ“ SHOW RESPONSE:"); + println!("{}", show_response); + println!("πŸ“ END SHOW RESPONSE"); + + // Verify file is present in context + assert!(show_response.contains(test_file_path), "File not found in context show output"); + assert!(show_response.contains("πŸ’¬ Session (temporary):"), "Missing Session section"); + println!("βœ… File confirmed present in context"); + + // Remove file from context + let remove_response = chat.execute_command(&format!("/context remove {}", test_file_path))?; + + println!("πŸ“ Context remove response: {} bytes", remove_response.len()); + println!("πŸ“ REMOVE RESPONSE:"); + println!("{}", remove_response); + println!("πŸ“ END REMOVE RESPONSE"); + + // Verify file was removed successfully + assert!(remove_response.contains("Removed 1 path(s) from context"), "Missing success message for removing file"); + println!("βœ… File removed from context successfully"); + + // Execute /context show to confirm file is gone + let final_show_response = chat.execute_command("/context show")?; + + println!("πŸ“ Final context show response: {} bytes", final_show_response.len()); + println!("πŸ“ FINAL SHOW RESPONSE:"); + println!("{}", final_show_response); + println!("πŸ“ END FINAL SHOW RESPONSE"); + + // Verify file is no longer in context + assert!(!final_show_response.contains(test_file_path), "File still found in context after removal"); + println!("βœ… File confirmed removed from context"); + + chat.quit()?; + + // Clean up test file + let _ = std::fs::remove_file(test_file_path); + println!("βœ… Cleaned up test file"); + + println!("βœ… Test completed successfully"); + + Ok(()) +} diff --git a/e2etests/tests/test_remove_multiple_file_context.rs b/e2etests/tests/test_remove_multiple_file_context.rs new file mode 100644 index 0000000000..1f2bc00a78 --- /dev/null +++ b/e2etests/tests/test_remove_multiple_file_context.rs @@ -0,0 +1,84 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "context")] +fn test_remove_multiple_file_context() -> Result<(), Box> { + println!("πŸ” Testing /context remove command..."); + + let test_file1_path = "/tmp/test_context_file1.py"; + let test_file2_path = "/tmp/test_context_file2.js"; + let test_file3_path = "/tmp/test_context_file3.txt"; + + // Create multiple test files + std::fs::write(test_file1_path, "# Test Python file for context\nprint('Hello from Python file')")?; + std::fs::write(test_file2_path, "// Test JavaScript file for context\nconsole.log('Hello from JS file');")?; + std::fs::write(test_file3_path, "Test text file for context\nHello from text file")?; + println!("βœ… Created test files at {}, {}, {}", test_file1_path, test_file2_path, test_file3_path); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + // Add multiple files to context + let add_response = chat.execute_command(&format!("/context add {} {} {}", test_file1_path, test_file2_path, test_file3_path))?; + + println!("πŸ“ Context add response: {} bytes", add_response.len()); + println!("πŸ“ ADD RESPONSE:"); + println!("{}", add_response); + println!("πŸ“ END ADD RESPONSE"); + + // Verify files were added successfully + assert!(add_response.contains("Added 3 path(s) to context"), "Missing success message for adding multiple files"); + println!("βœ… Multiple files added to context successfully"); + + // Execute /context show to confirm files are present + let show_response = chat.execute_command("/context show")?; + + println!("πŸ“ Context show response: {} bytes", show_response.len()); + println!("πŸ“ SHOW RESPONSE:"); + println!("{}", show_response); + println!("πŸ“ END SHOW RESPONSE"); + + // Verify all files are present in context + assert!(show_response.contains(test_file1_path), "Python file not found in context show output"); + assert!(show_response.contains(test_file2_path), "JavaScript file not found in context show output"); + assert!(show_response.contains(test_file3_path), "Text file not found in context show output"); + println!("βœ… All files confirmed present in context"); + + // Remove multiple files from context + let remove_response = chat.execute_command(&format!("/context remove {} {} {}", test_file1_path, test_file2_path, test_file3_path))?; + + println!("πŸ“ Context remove response: {} bytes", remove_response.len()); + println!("πŸ“ REMOVE RESPONSE:"); + println!("{}", remove_response); + println!("πŸ“ END REMOVE RESPONSE"); + + // Verify files were removed successfully + assert!(remove_response.contains("Removed 3 path(s) from context"), "Missing success message for removing multiple files"); + println!("βœ… Multiple files removed from context successfully"); + + // Execute /context show to confirm files are gone + let final_show_response = chat.execute_command("/context show")?; + + println!("πŸ“ Final context show response: {} bytes", final_show_response.len()); + println!("πŸ“ FINAL SHOW RESPONSE:"); + println!("{}", final_show_response); + println!("πŸ“ END FINAL SHOW RESPONSE"); + + // Verify files are no longer in context + assert!(!final_show_response.contains(test_file1_path), "Python file still found in context after removal"); + assert!(!final_show_response.contains(test_file2_path), "JavaScript file still found in context after removal"); + assert!(!final_show_response.contains(test_file3_path), "Text file still found in context after removal"); + println!("βœ… All files confirmed removed from context"); + + chat.quit()?; + + // Clean up test files + let _ = std::fs::remove_file(test_file1_path); + let _ = std::fs::remove_file(test_file2_path); + let _ = std::fs::remove_file(test_file3_path); + println!("βœ… Cleaned up test files"); + + println!("βœ… Test completed successfully"); + + Ok(()) +} diff --git a/e2etests/tests/test_save_command_argument_validation.rs b/e2etests/tests/test_save_command_argument_validation.rs new file mode 100644 index 0000000000..3cd037947b --- /dev/null +++ b/e2etests/tests/test_save_command_argument_validation.rs @@ -0,0 +1,46 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "save_load")] +fn test_save_command_argument_validation() -> Result<(), Box> { + println!("πŸ” Testing /save command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/save")?; + + println!("πŸ“ Help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify save error message + assert!(response.contains("error:") && response.contains("the following required arguments were not provided:"), "Missing save error message"); + println!("βœ… Found save error message"); + + assert!(response.contains("Usage:"), "Missing Usage section"); + assert!(response.contains("/save"), "Missing /save command in usage"); + println!("βœ… Found Usage section with /save command"); + + assert!(response.contains("Arguments:"), "Missing Arguments section"); + assert!(response.contains(""), "Missing PATH argument"); + println!("βœ… Found Arguments section with PATH parameter"); + + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("-f"), "Missing -f flag"); + assert!(response.contains("--force"), "Missing --force flag"); + assert!(response.contains("-h"), "Missing -h flag"); + assert!(response.contains("--help") || response.contains("β€”help"), "Missing --help flag"); + println!("βœ… Found Options section with -f, --force, -h, --help flags"); + + assert!(response.contains("Print help"), "Missing help description"); + println!("βœ… Found help flag description"); + + println!("βœ… All help content verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} diff --git a/e2etests/tests/test_save_force_command.rs b/e2etests/tests/test_save_force_command.rs index 637b27a5d6..b8b6939240 100644 --- a/e2etests/tests/test_save_force_command.rs +++ b/e2etests/tests/test_save_force_command.rs @@ -67,3 +67,58 @@ fn test_save_force_command() -> Result<(), Box> { Ok(()) } + +#[test] +#[cfg(feature = "save_load")] +fn test_save_f_flag_command() -> Result<(), Box> { + println!("πŸ” Testing /save -f command..."); + + let save_path = "/tmp/qcli_test_save.json"; + let _cleanup = FileCleanup { path: save_path }; + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + // Create actual conversation content + let _help_response = chat.execute_command("/help")?; + let _tools_response = chat.execute_command("/tools")?; + println!("βœ… Created conversation content with /help and /tools commands"); + + // Execute /save command first + let response = chat.execute_command(&format!("/save {}", save_path))?; + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + assert!(response.contains("Exported conversation state to"), "Initial save should succeed"); + println!("βœ… Initial save completed"); + + // Add more conversation content after initial save + let _prompt_response = chat.execute_command("/context show")?; + println!("βœ… Added more conversation content after initial save"); + + // Execute /save -f command to overwrite with new content + let force_response = chat.execute_command(&format!("/save -f {}", save_path))?; + + println!("πŸ“ Save force response: {} bytes", force_response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", force_response); + println!("πŸ“ END OUTPUT"); + + // Verify force save message + assert!(force_response.contains("Exported conversation state to") && force_response.contains(save_path), "Missing export confirmation message"); + println!("βœ… Found expected export message with file path"); + + // Verify file exists and contains data + assert!(std::path::Path::new(save_path).exists(), "Save file was not created"); + println!("βœ… Save file created at {}", save_path); + + let file_content = std::fs::read_to_string(save_path)?; + assert!(file_content.contains("help") || file_content.contains("tools"), "File missing initial conversation data"); + assert!(file_content.contains("context"), "File missing additional conversation data"); + println!("βœ… File contains expected conversation data including additional content"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} diff --git a/e2etests/tests/test_save_help_command.rs b/e2etests/tests/test_save_help_command.rs index 05ee6ed614..03cd658039 100644 --- a/e2etests/tests/test_save_help_command.rs +++ b/e2etests/tests/test_save_help_command.rs @@ -44,3 +44,48 @@ fn test_save_help_command() -> Result<(), Box> { Ok(()) } + +#[test] +#[cfg(feature = "save_load")] +fn test_save_h_flag_command() -> Result<(), Box> { + println!("πŸ” Testing /save -h command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/save -h")?; + + println!("πŸ“ Help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify save command help content + assert!(response.contains("Save the current conversation"), "Missing save command description"); + println!("βœ… Found save command description"); + + assert!(response.contains("Usage:"), "Missing Usage section"); + assert!(response.contains("/save"), "Missing /save command in usage"); + println!("βœ… Found Usage section with /save command"); + + assert!(response.contains("Arguments:"), "Missing Arguments section"); + assert!(response.contains(""), "Missing PATH argument"); + println!("βœ… Found Arguments section with PATH parameter"); + + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("-f"), "Missing -f flag"); + assert!(response.contains("--force"), "Missing --force flag"); + assert!(response.contains("-h"), "Missing -h flag"); + assert!(response.contains("--help") || response.contains("β€”help"), "Missing --help flag"); + println!("βœ… Found Options section with -f, --force, -h, --help flags"); + + assert!(response.contains("Print help"), "Missing help description"); + println!("βœ… Found help flag description"); + + println!("βœ… All help content verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} From 1ffca35b1137f1db20a50eb414ec3b7837d503fb Mon Sep 17 00:00:00 2001 From: sayema Anjum Date: Wed, 13 Aug 2025 19:45:08 +0530 Subject: [PATCH 09/77] QCLI Automation for Tools,Issue,Promt tests --- e2etests/Cargo.toml | 2 + e2etests/run_simple_categorized.sh | 18 +++++ e2etests/tests/test_hooks_command.rs | 37 +++++++++ e2etests/tests/test_issue_command.rs | 28 +++++++ e2etests/tests/test_issue_force_command.rs | 28 +++++++ e2etests/tests/test_issue_help_command.rs | 47 ++++++++++++ e2etests/tests/test_prompts_command.rs | 37 +++++++++ e2etests/tests/test_prompts_help_command.rs | 59 ++++++++++++++ e2etests/tests/test_tools_help_command.rs | 66 ++++++++++++++++ e2etests/tests/test_tools_reset_command.rs | 43 +++++++++++ .../tests/test_tools_reset_help_command.rs | 37 +++++++++ .../tests/test_tools_schema_help_command.rs | 37 +++++++++ .../tests/test_tools_trust_all_command.rs | 52 +++++++++++++ .../test_tools_trust_all_help_command.rs | 37 +++++++++ e2etests/tests/test_tools_trust_command.rs | 76 +++++++++++++++++++ .../tests/test_tools_trust_help_command.rs | 41 ++++++++++ .../tests/test_tools_untrust_help_command.rs | 41 ++++++++++ 17 files changed, 686 insertions(+) create mode 100644 e2etests/tests/test_hooks_command.rs create mode 100644 e2etests/tests/test_issue_command.rs create mode 100644 e2etests/tests/test_issue_force_command.rs create mode 100644 e2etests/tests/test_issue_help_command.rs create mode 100644 e2etests/tests/test_prompts_command.rs create mode 100644 e2etests/tests/test_prompts_help_command.rs create mode 100644 e2etests/tests/test_tools_help_command.rs create mode 100644 e2etests/tests/test_tools_reset_command.rs create mode 100644 e2etests/tests/test_tools_reset_help_command.rs create mode 100644 e2etests/tests/test_tools_schema_help_command.rs create mode 100644 e2etests/tests/test_tools_trust_all_command.rs create mode 100644 e2etests/tests/test_tools_trust_all_help_command.rs create mode 100644 e2etests/tests/test_tools_trust_command.rs create mode 100644 e2etests/tests/test_tools_trust_help_command.rs create mode 100644 e2etests/tests/test_tools_untrust_help_command.rs diff --git a/e2etests/Cargo.toml b/e2etests/Cargo.toml index 1d5ad43639..0d106c0133 100644 --- a/e2etests/Cargo.toml +++ b/e2etests/Cargo.toml @@ -19,6 +19,8 @@ session_mgmt = [] integration = [] mcp = [] ai_prompts = [] +issue_reporting = [] +tools=[] [[test]] name = "test_help_command" diff --git a/e2etests/run_simple_categorized.sh b/e2etests/run_simple_categorized.sh index 1a992ba040..c8a39e1c34 100755 --- a/e2etests/run_simple_categorized.sh +++ b/e2etests/run_simple_categorized.sh @@ -15,6 +15,8 @@ RUN_SESSION_MGMT=true RUN_INTEGRATION=true RUN_MCP=true RUN_AI_PROMPTS=true +RUN_ISSUE_REPORTING=true +RUN_TOOLS=true # ============================================================================ Q_BINARY="q" @@ -197,6 +199,22 @@ if [ "$RUN_AI_PROMPTS" = true ]; then fi fi +if [ "$RUN_ISSUE_REPORTING" = true ]; then + if run_category "issue_reporting" "ISSUE REPORTING"; then + ((total_passed++)) + else + ((total_failed++)) + fi +fi + +if [ "$RUN_TOOLS" = true ]; then + if run_category "tools" "TOOLS"; then + ((total_passed++)) + else + ((total_failed++)) + fi +fi + # Final summary echo "" echo "🎯 FINAL SUMMARY" diff --git a/e2etests/tests/test_hooks_command.rs b/e2etests/tests/test_hooks_command.rs new file mode 100644 index 0000000000..88120d551b --- /dev/null +++ b/e2etests/tests/test_hooks_command.rs @@ -0,0 +1,37 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "integration")] +fn test_hooks_command() -> Result<(), Box> { + println!("πŸ” Testing /hooks command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/hooks")?; + + println!("πŸ“ Hooks command response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify no hooks configured message + assert!(response.contains("No hooks are configured."), "Missing no hooks configured message"); + println!("βœ… Found no hooks configured message"); + + // Verify documentation reference + assert!(response.contains("Refer to the documentation"), "Missing documentation reference"); + assert!(response.contains("https://github.com/aws/amazon-q-developer-cli/blob/main/docs/agent-format.md#hooks-field"), "Missing documentation URL"); + println!("βœ… Found documentation reference and URL"); + + // Verify hooks field reference + assert!(response.contains("hooks-field"), "Missing hooks field reference"); + println!("βœ… Found hooks field reference"); + + println!("βœ… All hooks command functionality verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_issue_command.rs b/e2etests/tests/test_issue_command.rs new file mode 100644 index 0000000000..1eaef5e8bd --- /dev/null +++ b/e2etests/tests/test_issue_command.rs @@ -0,0 +1,28 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "issue_reporting")] +fn test_issue_command() -> Result<(), Box> { + println!("πŸ” Testing /issue command with bug report..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/issue \"Bug: Q CLI crashes when using large files\"")?; + + println!("πŸ“ Issue command response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify command executed successfully (GitHub opens automatically) + assert!(response.contains("Heading over to GitHub..."), "Missing browser opening confirmation"); + println!("βœ… Found browser opening confirmation"); + + println!("βœ… All issue command functionality verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} diff --git a/e2etests/tests/test_issue_force_command.rs b/e2etests/tests/test_issue_force_command.rs new file mode 100644 index 0000000000..a63508d2b5 --- /dev/null +++ b/e2etests/tests/test_issue_force_command.rs @@ -0,0 +1,28 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "issue_reporting")] +fn test_issue_force_command() -> Result<(), Box> { + println!("πŸ” Testing /issue --force command with critical bug..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/issue --force \"Critical bug in file handling\"")?; + + println!("πŸ“ Issue force command response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify command executed successfully (GitHub opens automatically) + assert!(response.contains("Heading over to GitHub..."), "Missing browser opening confirmation"); + println!("βœ… Found browser opening confirmation"); + + println!("βœ… All issue --force command functionality verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_issue_help_command.rs b/e2etests/tests/test_issue_help_command.rs new file mode 100644 index 0000000000..241c5d5eb6 --- /dev/null +++ b/e2etests/tests/test_issue_help_command.rs @@ -0,0 +1,47 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "integration")] +fn test_issue_help_command() -> Result<(), Box> { + println!("πŸ” Testing /issue --help command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/issue --help")?; + + println!("πŸ“ Issue help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify description + assert!(response.contains("Create a new Github issue or make a feature request"), "Missing issue description"); + println!("βœ… Found issue description"); + + // Verify Usage section + //assert!(response.contains("Usage: /issue [OPTIONS] [DESCRIPTION]..."), "Missing usage format"); + assert!(response.contains("Usage:") && response.contains("/issue") && response.contains("[DESCRIPTION]") && response.contains("[OPTIONS]"), "Missing Usage section"); + println!("βœ… Found usage format"); + + // Verify Arguments section + assert!(response.contains("Arguments:"), "Missing Arguments section"); + assert!(response.contains("[DESCRIPTION]..."), "Missing DESCRIPTION argument"); + assert!(response.contains("Issue description"), "Missing issue description text"); + println!("βœ… Found Arguments section"); + + // Verify Options section + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("-f") && response.contains("--force"), "Missing force option"); + assert!(response.contains("Force issue creation"), "Missing force description"); + assert!(response.contains("-h") && response.contains("--help"), "Missing -h, --help flags"); + assert!(response.contains("Print help"), "Missing help description"); + println!("βœ… Found Options section with force and help flags"); + + println!("βœ… All issue help content verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_prompts_command.rs b/e2etests/tests/test_prompts_command.rs new file mode 100644 index 0000000000..1cd00d1866 --- /dev/null +++ b/e2etests/tests/test_prompts_command.rs @@ -0,0 +1,37 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "ai_prompts")] +fn test_prompts_command() -> Result<(), Box> { + println!("πŸ” Testing /prompts command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/prompts")?; + + println!("πŸ“ Prompts command response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify usage instruction + assert!(response.contains("Usage:") && response.contains("@") && response.contains("") && response.contains("[...args]"), "Missing usage instruction"); + println!("βœ… Found usage instruction"); + + // Verify table headers + assert!(response.contains("Prompt"), "Missing Prompt header"); + assert!(response.contains("Arguments") && response.contains("*") && response.contains("required"), "Missing Arguments header"); + println!("βœ… Found table headers with required notation"); + + // Verify command executed successfully + assert!(!response.is_empty(), "Empty response from prompts command"); + println!("βœ… Command executed with response"); + + println!("βœ… All prompts command functionality verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_prompts_help_command.rs b/e2etests/tests/test_prompts_help_command.rs new file mode 100644 index 0000000000..80f39e899c --- /dev/null +++ b/e2etests/tests/test_prompts_help_command.rs @@ -0,0 +1,59 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "ai_prompts")] +fn test_prompts_help_command() -> Result<(), Box> { + println!("πŸ” Testing /prompts --help command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/prompts --help")?; + + println!("πŸ“ Prompts help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify description + assert!(response.contains("Prompts are reusable templates that help you quickly access common workflows and tasks"), "Missing prompts description"); + assert!(response.contains("These templates are provided by the mcp servers you have installed and configured"), "Missing MCP servers description"); + println!("βœ… Found prompts description"); + + // Verify usage examples + assert!(response.contains("@") && response.contains(" [arg]") && response.contains("[arg]"), "Missing @ syntax example"); + assert!(response.contains("Retrieve prompt specified"), "Missing retrieve description"); + assert!(response.contains("/prompts") && response.contains("get") && response.contains("") && response.contains("[arg]"), "Missing long form example"); + println!("βœ… Found usage examples with @ syntax and long form"); + + // Verify main description + assert!(response.contains("View and retrieve prompts"), "Missing main description"); + println!("βœ… Found main description"); + + // Verify Usage section + assert!(response.contains("Usage:") && response.contains("/prompts") && response.contains("[COMMAND]"), "Missing usage format"); + println!("βœ… Found usage format"); + + // Verify Commands section + assert!(response.contains("Commands:"), "Missing Commands section"); + assert!(response.contains("list"), "Missing list command"); + assert!(response.contains("get"), "Missing get command"); + assert!(response.contains("help"), "Missing help command"); + println!("βœ… Found all commands: list, get, help"); + + // Verify command descriptions + assert!(response.contains("List available prompts from a tool or show all available prompt"), "Missing list description"); + println!("βœ… Found command descriptions"); + + // Verify Options section + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("-h") && response.contains("--help"), "Missing help flags"); + println!("βœ… Found Options section with help flags"); + + println!("βœ… All prompts help content verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_tools_help_command.rs b/e2etests/tests/test_tools_help_command.rs new file mode 100644 index 0000000000..d62c1e7696 --- /dev/null +++ b/e2etests/tests/test_tools_help_command.rs @@ -0,0 +1,66 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "tools")] +fn test_tools_help_command() -> Result<(), Box> { + println!("πŸ” Testing /tools --help command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/tools --help")?; + + println!("πŸ“ Tools help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify description + assert!(response.contains("By default, Amazon Q will ask for your permission to use certain tools."), "Missing permission description"); + println!("βœ… Found tools permission description"); + + // Verify documentation reference + assert!(response.contains("Refer to the documentation for how to configure tools with your agent"), "Missing documentation reference"); + assert!(response.contains("https://github.com/aws/amazon-q-developer-cli/blob/main/docs/agent-format.md#tools-field"), "Missing documentation URL"); + println!("βœ… Found documentation reference and URL"); + + // Verify main description + assert!(response.contains("View tools and permissions"), "Missing main description"); + println!("βœ… Found main description"); + + // Verify Usage section + //assert!(response.contains("Usage: /tools [COMMAND]"), "Missing usage format"); + assert!(response.contains("Usage:") && response.contains("/tools") && response.contains("[COMMAND]"), "Missing Usage section"); + println!("βœ… Found usage format"); + println!("βœ… Found usage format"); + + // Verify Commands section + assert!(response.contains("Commands:"), "Missing Commands section"); + assert!(response.contains("schema"), "Missing schema command"); + assert!(response.contains("trust"), "Missing trust command"); + assert!(response.contains("untrust"), "Missing untrust command"); + assert!(response.contains("trust-all"), "Missing trust-all command"); + assert!(response.contains("reset"), "Missing reset command"); + assert!(response.contains("help"), "Missing help command"); + println!("βœ… Found all commands: schema, trust, untrust, trust-all, reset, help"); + + // Verify command descriptions + assert!(response.contains("Show the input schema for all available tools"), "Missing schema description"); + assert!(response.contains("Trust a specific tool or tools for the session"), "Missing trust description"); + assert!(response.contains("Revert a tool or tools to per-request confirmation"), "Missing untrust description"); + assert!(response.contains("Trust all tools (equivalent to deprecated /acceptall)"), "Missing trust-all description"); + assert!(response.contains("Reset all tools to default permission levels"), "Missing reset description"); + println!("βœ… Found all command descriptions"); + + // Verify Options section + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("-h") && response.contains("--help"), "Missing -h, --help flags"); + println!("βœ… Found Options section with help flags"); + + println!("βœ… All tools help content verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_tools_reset_command.rs b/e2etests/tests/test_tools_reset_command.rs new file mode 100644 index 0000000000..7b31b010c8 --- /dev/null +++ b/e2etests/tests/test_tools_reset_command.rs @@ -0,0 +1,43 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "tools")] +fn test_tools_reset_command() -> Result<(), Box> { + println!("πŸ” Testing /tools reset command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + // Execute reset command + let reset_response = chat.execute_command("/tools reset")?; + + println!("πŸ“ Reset response: {} bytes", reset_response.len()); + println!("πŸ“ RESET OUTPUT:"); + println!("{}", reset_response); + println!("πŸ“ END RESET OUTPUT"); + + // Verify reset confirmation message + assert!(reset_response.contains("Reset all tools to the permission levels as defined in agent."), "Missing reset confirmation message"); + println!("βœ… Found reset confirmation message"); + + // Now check tools list to verify tools have mixed permissions + let tools_response = chat.execute_command("/tools")?; + + println!("πŸ“ Tools response after reset: {} bytes", tools_response.len()); + println!("πŸ“ TOOLS OUTPUT:"); + println!("{}", tools_response); + println!("πŸ“ END TOOLS OUTPUT"); + + // Verify that tools have all permission types + assert!(tools_response.contains("trusted"), "Missing trusted tools"); + assert!(tools_response.contains("not trusted"), "Missing not trusted tools"); + assert!(tools_response.contains("read-only commands"), "Missing read-only commands tools"); + println!("βœ… Found all permission types after reset"); + + println!("βœ… All tools reset functionality verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_tools_reset_help_command.rs b/e2etests/tests/test_tools_reset_help_command.rs new file mode 100644 index 0000000000..5cbd2590fd --- /dev/null +++ b/e2etests/tests/test_tools_reset_help_command.rs @@ -0,0 +1,37 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "tools")] +fn test_tools_reset_help_command() -> Result<(), Box> { + println!("πŸ” Testing /tools reset --help command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/tools reset --help")?; + + println!("πŸ“ Tools reset help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify command description + assert!(response.contains("Reset all tools to default permission levels"), "Missing command description"); + println!("βœ… Found command description"); + + // Verify usage format + assert!(response.contains("Usage:") && response.contains("/tools reset"), "Missing usage format"); + println!("βœ… Found usage format"); + + // Verify options section + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing help option"); + println!("βœ… Found options section with help flag"); + + println!("βœ… All tools reset help functionality verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_tools_schema_help_command.rs b/e2etests/tests/test_tools_schema_help_command.rs new file mode 100644 index 0000000000..e1c9b54eb2 --- /dev/null +++ b/e2etests/tests/test_tools_schema_help_command.rs @@ -0,0 +1,37 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "tools")] +fn test_tools_schema_help_command() -> Result<(), Box> { + println!("πŸ” Testing /tools schema --help command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/tools schema --help")?; + + println!("πŸ“ Tools schema help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify command description + assert!(response.contains("Show the input schema for all available tools"), "Missing command description"); + println!("βœ… Found command description"); + + // Verify usage format + assert!(response.contains("Usage:") && response.contains("/tools schema"), "Missing usage format"); + println!("βœ… Found usage format"); + + // Verify options section + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("-h") && response.contains("--help")&& response.contains("Print help"), "Missing help option"); + println!("βœ… Found options section with help flag"); + + println!("βœ… All tools schema help functionality verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_tools_trust_all_command.rs b/e2etests/tests/test_tools_trust_all_command.rs new file mode 100644 index 0000000000..b17ed8afb5 --- /dev/null +++ b/e2etests/tests/test_tools_trust_all_command.rs @@ -0,0 +1,52 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "tools")] +fn test_tools_trust_all_command() -> Result<(), Box> { + println!("πŸ” Testing /tools trust-all command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + // Execute trust-all command + let trust_all_response = chat.execute_command("/tools trust-all")?; + + println!("πŸ“ Trust-all response: {} bytes", trust_all_response.len()); + println!("πŸ“ TRUST-ALL OUTPUT:"); + println!("{}", trust_all_response); + println!("πŸ“ END TRUST-ALL OUTPUT"); + + // Verify trust-all confirmation message + assert!(trust_all_response.contains("asking for confirmation"), "Missing trust-all confirmation message"); + assert!(trust_all_response.contains("Agents can sometimes do unexpected things so understand the risks."), "Missing risk warning message"); + assert!(trust_all_response.contains("Learn more at https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-chat-security.html#command-line-chat-trustall-safety"), "Missing documentation link"); + println!("βœ… Found trust-all confirmation, risk warning, and documentation link"); + + // Now check tools list to verify all tools are trusted + let tools_response = chat.execute_command("/tools")?; + + println!("πŸ“ Tools response after trust-all: {} bytes", tools_response.len()); + println!("πŸ“ TOOLS OUTPUT:"); + println!("{}", tools_response); + println!("πŸ“ END TOOLS OUTPUT"); + + // Verify that all tools now show "trusted" permission + assert!(tools_response.contains("trusted"), "Missing trusted tools after trust-all"); + + // Verify no tools have other permission statuses + assert!(!tools_response.contains("not trusted"), "Found 'not trusted' tools after trust-all"); + assert!(!tools_response.contains("read-only commands"), "Found 'read-only commands' tools after trust-all"); + println!("βœ… Verified all tools are now trusted, no other permission statuses found"); + + // Count lines with "trusted" to ensure multiple tools are trusted + let trusted_count = tools_response.matches("trusted").count(); + assert!(trusted_count > 0, "No trusted tools found"); + println!("βœ… Found {} instances of 'trusted' in tools list", trusted_count); + + println!("βœ… All tools trust-all functionality verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_tools_trust_all_help_command.rs b/e2etests/tests/test_tools_trust_all_help_command.rs new file mode 100644 index 0000000000..ac35496108 --- /dev/null +++ b/e2etests/tests/test_tools_trust_all_help_command.rs @@ -0,0 +1,37 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "tools")] +fn test_tools_trust_all_help_command() -> Result<(), Box> { + println!("πŸ” Testing /tools trust-all --help command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/tools trust-all --help")?; + + println!("πŸ“ Tools trust-all help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify command description + assert!(response.contains("Trust all tools") && response.contains("equivalent to deprecated /acceptall"), "Missing command description"); + println!("βœ… Found command description"); + + // Verify usage format + assert!(response.contains("Usage:") && response.contains("/tools trust-all"), "Missing usage format"); + println!("βœ… Found usage format"); + + // Verify options section + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing help option"); + println!("βœ… Found options section with help flag"); + + println!("βœ… All tools trust-all help functionality verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_tools_trust_command.rs b/e2etests/tests/test_tools_trust_command.rs new file mode 100644 index 0000000000..f05b9450fd --- /dev/null +++ b/e2etests/tests/test_tools_trust_command.rs @@ -0,0 +1,76 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "tools")] +fn test_tools_trust_command() -> Result<(), Box> { + println!("πŸ” Testing /tools trust command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + // First get list of tools to find one that's not trusted + let tools_response = chat.execute_command("/tools")?; + + println!("πŸ“ Tools response: {} bytes", tools_response.len()); + println!("πŸ“ TOOLS OUTPUT:"); + println!("{}", tools_response); + println!("πŸ“ END TOOLS OUTPUT"); + + // Find a tool that's not trusted + let mut untrusted_tool: Option = None; + + // Look for tools that are "not trusted" + let lines: Vec<&str> = tools_response.lines().collect(); + for line in lines { + if line.starts_with("- ") && line.contains("not trusted") { + // Extract tool name from the line (after "- ") + if let Some(tool_part) = line.strip_prefix("- ") { + let parts: Vec<&str> = tool_part.split_whitespace().collect(); + if let Some(tool_name) = parts.first() { + untrusted_tool = Some(tool_name.to_string()); + break; + } + } + } + } + + if let Some(tool_name) = untrusted_tool { + println!("βœ… Found untrusted tool: {}", tool_name); + + // Execute trust command + let trust_command = format!("/tools trust {}", tool_name); + let trust_response = chat.execute_command(&trust_command)?; + + println!("πŸ“ Trust response: {} bytes", trust_response.len()); + println!("πŸ“ TRUST OUTPUT:"); + println!("{}", trust_response); + println!("πŸ“ END TRUST OUTPUT"); + + // Verify trust confirmation message + assert!(trust_response.contains(&tool_name), "Missing trust confirmation message"); + println!("βœ… Found trust confirmation message for tool: {}", tool_name); + + // Execute untrust command + let untrust_command = format!("/tools untrust {}", tool_name); + let untrust_response = chat.execute_command(&untrust_command)?; + + println!("πŸ“ Untrust response: {} bytes", untrust_response.len()); + println!("πŸ“ UNTRUST OUTPUT:"); + println!("{}", untrust_response); + println!("πŸ“ END UNTRUST OUTPUT"); + + // Verify untrust confirmation message + let expected_untrust_message = format!("Tool '{}' is set to per-request confirmation.", tool_name); + assert!(untrust_response.contains(&expected_untrust_message), "Missing untrust confirmation message"); + println!("βœ… Found untrust confirmation message for tool: {}", tool_name); + + println!("βœ… All tools trust/untrust functionality verified!"); + } else { + println!("ℹ️ No untrusted tools found to test trust command"); + } + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_tools_trust_help_command.rs b/e2etests/tests/test_tools_trust_help_command.rs new file mode 100644 index 0000000000..695fd00060 --- /dev/null +++ b/e2etests/tests/test_tools_trust_help_command.rs @@ -0,0 +1,41 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "tools")] +fn test_tools_trust_help_command() -> Result<(), Box> { + println!("πŸ” Testing /tools trust --help command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/tools trust --help")?; + + println!("πŸ“ Tools trust help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify command description + assert!(response.contains("Trust a specific tool or tools for the session"), "Missing command description"); + println!("βœ… Found command description"); + + // Verify usage format + assert!(response.contains("Usage:") && response.contains("/tools trust") && response.contains("..."), "Missing usage format"); + println!("βœ… Found usage format"); + + // Verify arguments section + assert!(response.contains("Arguments:") && response.contains("..."), "Missing Arguments section"); + println!("βœ… Found arguments section"); + + // Verify options section + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing help option"); + println!("βœ… Found options section with help flag"); + + println!("βœ… All tools trust help functionality verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_tools_untrust_help_command.rs b/e2etests/tests/test_tools_untrust_help_command.rs new file mode 100644 index 0000000000..d4ed65a7a9 --- /dev/null +++ b/e2etests/tests/test_tools_untrust_help_command.rs @@ -0,0 +1,41 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "tools")] +fn test_tools_untrust_help_command() -> Result<(), Box> { + println!("πŸ” Testing /tools untrust --help command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/tools untrust --help")?; + + println!("πŸ“ Tools untrust help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify command description + assert!(response.contains("Revert a tool or tools to per-request confirmation"), "Missing command description"); + println!("βœ… Found command description"); + + // Verify usage format + assert!(response.contains("Usage:") && response.contains("/tools untrust") && response.contains("..."), "Missing usage format"); + println!("βœ… Found usage format"); + + // Verify arguments section + assert!(response.contains("Arguments:") && response.contains("..."), "Missing Arguments section"); + println!("βœ… Found arguments section"); + + // Verify options section + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing help option"); + println!("βœ… Found options section with help flag"); + + println!("βœ… All tools untrust help functionality verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file From 4329d3dd1662dc7ba0c386ff608a8e6d59b347a2 Mon Sep 17 00:00:00 2001 From: "Shreya [C] Bhagat" Date: Thu, 14 Aug 2025 19:48:59 +0530 Subject: [PATCH 10/77] Q CLI Automation for MCP --- e2etests/src/lib.rs | 4 +- e2etests/tests/test_agent_create_command.rs | 70 +++++++++++++++++++ .../tests/test_mcp_remove_help_command.rs | 46 ++++++++++++ e2etests/tests/test_q_mcp_help_command.rs | 56 +++++++++++++++ 4 files changed, 174 insertions(+), 2 deletions(-) create mode 100644 e2etests/tests/test_agent_create_command.rs create mode 100644 e2etests/tests/test_mcp_remove_help_command.rs create mode 100644 e2etests/tests/test_q_mcp_help_command.rs diff --git a/e2etests/src/lib.rs b/e2etests/src/lib.rs index edd4846589..f915b6a6bf 100644 --- a/e2etests/src/lib.rs +++ b/e2etests/src/lib.rs @@ -107,12 +107,12 @@ pub mod q_chat_helper { }, Ok(_) => { // No more data, but wait a bit more in case there's more coming - std::thread::sleep(Duration::from_millis(200)); + std::thread::sleep(Duration::from_millis(300)); if total_content.len() > 0 { break; } }, Err(_) => break, } - std::thread::sleep(Duration::from_millis(200)); + std::thread::sleep(Duration::from_millis(300)); } Ok(total_content) diff --git a/e2etests/tests/test_agent_create_command.rs b/e2etests/tests/test_agent_create_command.rs new file mode 100644 index 0000000000..06e4203063 --- /dev/null +++ b/e2etests/tests/test_agent_create_command.rs @@ -0,0 +1,70 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "agent")] +fn test_agent_create_command() -> Result<(), Box> { + println!("πŸ” Testing /agent create --name command..."); + + let agent_name = "test_demo_agent"; + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + // Create agent + let create_response = chat.execute_command(&format!("/agent create --name {}", agent_name))?; + + println!("πŸ“ Agent create response: {} bytes", create_response.len()); + println!("πŸ“ CREATE RESPONSE:"); + println!("{}", create_response); + println!("πŸ“ END CREATE RESPONSE"); + + // Save and exit editor + let save_response = chat.execute_command(":wq")?; + + println!("πŸ“ Save response: {} bytes", save_response.len()); + println!("πŸ“ SAVE RESPONSE:"); + println!("{}", save_response); + println!("πŸ“ END SAVE RESPONSE"); + + // Verify agent creation success message + assert!(save_response.contains("Agent") && save_response.contains(agent_name) && save_response.contains("has been created successfully"), "Missing agent creation success message"); + println!("βœ… Found agent creation success message"); + + // Get current username using !whoami in Q CLI + let whoami_response = chat.execute_command("!whoami")?; + + println!("πŸ“ Whoami response: {} bytes", whoami_response.len()); + println!("πŸ“ WHOAMI RESPONSE:"); + println!("{}", whoami_response); + println!("πŸ“ END WHOAMI RESPONSE"); + + // Extract username from response (parse the actual username from Q CLI output) + let lines: Vec<&str> = whoami_response.lines().collect(); + let username = lines.iter() + .find(|line| !line.starts_with("!") && !line.starts_with(">") && !line.trim().is_empty()) + .unwrap_or(&"shrebhaa") + .trim(); + println!("βœ… Current username: {}", username); + + chat.quit()?; + + // Construct agent path dynamically + let agent_path = format!("/Users/{}/.aws/amazonq/cli-agents/{}.json", username, agent_name); + println!("βœ… Agent path: {}", agent_path); + + // Delete the agent file if it exists + if std::path::Path::new(&agent_path).exists() { + std::fs::remove_file(&agent_path)?; + println!("βœ… Agent file deleted: {}", agent_path); + } else { + println!("⚠️ Agent file not found at: {}", agent_path); + } + + // Verify agent file was deleted + assert!(!std::path::Path::new(&agent_path).exists(), "Agent file should be deleted"); + println!("βœ… Agent deletion verified"); + + println!("βœ… Test completed successfully"); + + Ok(()) +} diff --git a/e2etests/tests/test_mcp_remove_help_command.rs b/e2etests/tests/test_mcp_remove_help_command.rs new file mode 100644 index 0000000000..a3e6f4c252 --- /dev/null +++ b/e2etests/tests/test_mcp_remove_help_command.rs @@ -0,0 +1,46 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "mcp")] +fn test_mcp_remove_help_command() -> Result<(), Box> { + println!("πŸ” Testing q mcp remove --help command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + // Execute q mcp remove --help command + let help_response = chat.execute_command("q mcp remove --help")?; + + println!("πŸ“ MCP remove help response: {} bytes", help_response.len()); + println!("πŸ“ HELP RESPONSE:"); + println!("{}", help_response); + println!("πŸ“ END HELP RESPONSE"); + + // Verify tool execution prompt appears + assert!(help_response.contains("πŸ› οΈ Using tool: execute_bash"), "Missing tool execution indicator"); + assert!(help_response.contains("Allow this action?") && help_response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); + println!("βœ… Found tool execution permission prompt"); + + // Allow the tool execution + let allow_response = chat.execute_command("y")?; + + println!("πŸ“ Allow response: {} bytes", allow_response.len()); + println!("πŸ“ ALLOW RESPONSE:"); + println!("{}", allow_response); + println!("πŸ“ END ALLOW RESPONSE"); + + // Verify complete help content in final response + assert!(allow_response.contains("Remove a server from the MCP configuration"), "Missing MCP remove description"); + assert!(allow_response.contains("Usage: qchat mcp remove"), "Missing usage information"); + assert!(allow_response.contains("--name "), "Missing --name option"); + assert!(allow_response.contains("--scope "), "Missing --scope option"); + assert!(allow_response.contains("--agent "), "Missing --agent option"); + assert!(allow_response.contains("-h, --help"), "Missing help option"); + assert!(allow_response.contains("Completed in"), "Missing completion indicator"); + println!("βœ… Found all expected MCP remove help content and completion"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} diff --git a/e2etests/tests/test_q_mcp_help_command.rs b/e2etests/tests/test_q_mcp_help_command.rs new file mode 100644 index 0000000000..3e75186d55 --- /dev/null +++ b/e2etests/tests/test_q_mcp_help_command.rs @@ -0,0 +1,56 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "mcp")] +fn test_q_mcp_help_command() -> Result<(), Box> { + println!("πŸ” Testing q mcp --help command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + // Execute q mcp --help command + let help_response = chat.execute_command("q mcp --help")?; + + println!("πŸ“ MCP help response: {} bytes", help_response.len()); + println!("πŸ“ HELP RESPONSE:"); + println!("{}", help_response); + println!("πŸ“ END HELP RESPONSE"); + + // Verify tool execution prompt appears + assert!(help_response.contains("πŸ› οΈ Using tool: execute_bash"), "Missing tool execution indicator"); + assert!(help_response.contains("Allow this action?") && help_response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); + println!("βœ… Found tool execution permission prompt"); + + // Allow the tool execution + let allow_response = chat.execute_command("y")?; + + println!("πŸ“ Allow response: {} bytes", allow_response.len()); + println!("πŸ“ ALLOW RESPONSE:"); + println!("{}", allow_response); + println!("πŸ“ END ALLOW RESPONSE"); + + // Verify complete help content + assert!(allow_response.contains("Model Context Protocol (MCP)"), "Missing MCP description"); + assert!(allow_response.contains("Usage: qchat mcp"), "Missing usage information"); + assert!(allow_response.contains("Commands:"), "Missing Commands section"); + + // Verify command descriptions + assert!(allow_response.contains("add") && allow_response.contains("Add or replace a configured server"), "Missing add command description"); + assert!(allow_response.contains("remove") && allow_response.contains("Remove a server from the MCP configuration"), "Missing remove command description"); + assert!(allow_response.contains("list") && allow_response.contains("List configured servers"), "Missing list command description"); + assert!(allow_response.contains("import") && allow_response.contains("Import a server configuration from another file"), "Missing import command description"); + assert!(allow_response.contains("status") && allow_response.contains("Get the status of a configured server"), "Missing status command description"); + assert!(allow_response.contains("help"), "Missing help command"); + println!("βœ… Found all MCP commands with descriptions"); + + assert!(allow_response.contains("Options:"), "Missing Options section"); + assert!(allow_response.contains("-v, --verbose"), "Missing verbose option"); + assert!(allow_response.contains("-h, --help"), "Missing help option"); + assert!(allow_response.contains("Completed in"), "Missing completion indicator"); + println!("βœ… Found all expected MCP help content and completion"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} From 38bdabde81f40c403d819acbac1aadb9bdee8081 Mon Sep 17 00:00:00 2001 From: Abhishek Anne Date: Thu, 14 Aug 2025 20:20:38 +0530 Subject: [PATCH 11/77] QCLI automation prompt list command --- e2etests/tests/test_prompts_list_command.rs | 37 +++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 e2etests/tests/test_prompts_list_command.rs diff --git a/e2etests/tests/test_prompts_list_command.rs b/e2etests/tests/test_prompts_list_command.rs new file mode 100644 index 0000000000..56043c3d92 --- /dev/null +++ b/e2etests/tests/test_prompts_list_command.rs @@ -0,0 +1,37 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "ai_prompts1")] +fn test_prompts_command() -> Result<(), Box> { + println!("πŸ” Testing /prompts command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/prompts list")?; + + println!("πŸ“ Prompts command response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify usage instruction + assert!(response.contains("Usage:") && response.contains("@") && response.contains("") && response.contains("[...args]"), "Missing usage instruction"); + println!("βœ… Found usage instruction"); + + // Verify table headers + assert!(response.contains("Prompt"), "Missing Prompt header"); + assert!(response.contains("Arguments") && response.contains("*") && response.contains("required"), "Missing Arguments header"); + println!("βœ… Found table headers with required notation"); + + // Verify command executed successfully + assert!(!response.is_empty(), "Empty response from prompts command"); + println!("βœ… Command executed with response"); + + println!("βœ… All prompts command functionality verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file From c2961316257528be54700de2072ba1d1c96a9397 Mon Sep 17 00:00:00 2001 From: "Shreya [C] Bhagat" Date: Mon, 18 Aug 2025 18:48:52 +0530 Subject: [PATCH 12/77] QCLI Automation for MCP --- e2etests/src/lib.rs | 4 +- .../tests/test_add_and_remove_mcp_command.rs | 100 ++++++++++++++++++ e2etests/tests/test_q_mcp_add_help_command.rs | 61 +++++++++++ .../tests/test_q_mcp_import_help_command.rs | 69 ++++++++++++ .../tests/test_q_mcp_status_help_command.rs | 63 +++++++++++ 5 files changed, 295 insertions(+), 2 deletions(-) create mode 100644 e2etests/tests/test_add_and_remove_mcp_command.rs create mode 100644 e2etests/tests/test_q_mcp_add_help_command.rs create mode 100644 e2etests/tests/test_q_mcp_import_help_command.rs create mode 100644 e2etests/tests/test_q_mcp_status_help_command.rs diff --git a/e2etests/src/lib.rs b/e2etests/src/lib.rs index f915b6a6bf..64cd896e4e 100644 --- a/e2etests/src/lib.rs +++ b/e2etests/src/lib.rs @@ -107,12 +107,12 @@ pub mod q_chat_helper { }, Ok(_) => { // No more data, but wait a bit more in case there's more coming - std::thread::sleep(Duration::from_millis(300)); + std::thread::sleep(Duration::from_millis(1000)); if total_content.len() > 0 { break; } }, Err(_) => break, } - std::thread::sleep(Duration::from_millis(300)); + std::thread::sleep(Duration::from_millis(1000)); } Ok(total_content) diff --git a/e2etests/tests/test_add_and_remove_mcp_command.rs b/e2etests/tests/test_add_and_remove_mcp_command.rs new file mode 100644 index 0000000000..f3d99f5f5a --- /dev/null +++ b/e2etests/tests/test_add_and_remove_mcp_command.rs @@ -0,0 +1,100 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "mcp")] +fn test_add_and_remove_mcp_command() -> Result<(), Box> { + println!("πŸ” Testing q mcp add command..."); + + // First install uv dependency before starting Q Chat + println!("πŸ” Installing uv dependency..."); + std::process::Command::new("pip3") + .args(["install", "uv", "--break-system-packages"]) + .output() + .expect("Failed to install uv"); + println!("βœ… uv dependency installed"); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + // Execute mcp add command + println!("πŸ” Executing command: 'q mcp add --name aws-documentation --command uvx --args awslabs.aws-documentation-mcp-server@latest'"); + let response = chat.execute_command("q mcp add --name aws-documentation --command uvx --args awslabs.aws-documentation-mcp-server@latest")?; + + println!("πŸ“ Response: {} bytes", response.len()); + println!("πŸ“ RESPONSE:"); + println!("{}", response); + println!("πŸ“ END RESPONSE"); + + // Verify tool execution details + assert!(response.contains("I will run the following shell command:"), "Missing command execution description"); + assert!(response.contains("q mcp add --name aws-documentation --command uvx --args awslabs.aws-documentation-mcp-server@latest"), "Missing full command"); + assert!(response.contains("Purpose:") && response.contains("Add AWS documentation MCP server"), "Missing purpose description"); + println!("βœ… Found tool execution details"); + + // Verify tool execution prompt appears + assert!(response.contains("πŸ› οΈ Using tool: execute_bash"), "Missing tool execution indicator"); + assert!(response.contains("Allow this action?") && response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); + println!("βœ… Found tool execution permission prompt"); + + // Allow the tool execution + let allow_response = chat.execute_command("y")?; + + println!("πŸ“ Allow response: {} bytes", allow_response.len()); + println!("πŸ“ ALLOW RESPONSE:"); + println!("{}", allow_response); + println!("πŸ“ END ALLOW RESPONSE"); + + // Verify successful addition + assert!(allow_response.contains("βœ“ Added MCP server") && allow_response.contains("'aws-documentation'") && allow_response.contains("to global config in"), "Missing success message"); + assert!(allow_response.contains("/Users/") && allow_response.contains("/.aws/amazonq/mcp.json"), "Missing config file path"); + println!("βœ… Found successful addition message"); + + // Verify completion indicator + assert!(allow_response.contains("Completed in") && allow_response.contains("s"), "Missing completion time indicator"); + println!("βœ… Found completion indicator"); + + println!("βœ… All q mcp add command execution verified successfully"); + + // Now test removing the MCP server + println!("πŸ” Executing remove command: 'q mcp remove --name aws-documentation'"); + let remove_response = chat.execute_command("q mcp remove --name aws-documentation")?; + + println!("πŸ“ Remove response: {} bytes", remove_response.len()); + println!("πŸ“ REMOVE RESPONSE:"); + println!("{}", remove_response); + println!("πŸ“ END REMOVE RESPONSE"); + + // Verify remove tool execution details + assert!(remove_response.contains("I will run the following shell command:"), "Missing remove command execution description"); + assert!(remove_response.contains("q mcp remove --name aws-documentation"), "Missing full remove command"); + println!("βœ… Found remove tool execution details"); + + // Verify remove tool execution prompt + assert!(remove_response.contains("πŸ› οΈ Using tool: execute_bash"), "Missing remove tool execution indicator"); + assert!(remove_response.contains("Allow this action?"), "Missing remove permission prompt"); + println!("βœ… Found remove tool execution permission prompt"); + + // Allow the remove tool execution + let remove_allow_response = chat.execute_command("y")?; + + println!("πŸ“ Remove allow response: {} bytes", remove_allow_response.len()); + println!("πŸ“ REMOVE ALLOW RESPONSE:"); + println!("{}", remove_allow_response); + println!("πŸ“ END REMOVE ALLOW RESPONSE"); + + // Verify successful removal + assert!(remove_allow_response.contains("βœ“ Removed MCP server") && remove_allow_response.contains("'aws-documentation'") && remove_allow_response.contains("from global config"), "Missing removal success message"); + assert!(remove_allow_response.contains("/Users/") && remove_allow_response.contains("/.aws/amazonq/mcp.json"), "Missing config file path in removal"); + println!("βœ… Found successful removal message"); + + // Verify remove completion indicator + assert!(remove_allow_response.contains("Completed in") && remove_allow_response.contains("s"), "Missing remove completion time indicator"); + println!("βœ… Found remove completion indicator"); + + println!("βœ… All q mcp remove command execution verified successfully"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_q_mcp_add_help_command.rs b/e2etests/tests/test_q_mcp_add_help_command.rs new file mode 100644 index 0000000000..590af5498c --- /dev/null +++ b/e2etests/tests/test_q_mcp_add_help_command.rs @@ -0,0 +1,61 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "mcp")] +fn test_q_mcp_add_help_command() -> Result<(), Box> { + println!("πŸ” Testing q mcp add --help command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + // Execute mcp add --help command + println!("πŸ” Executing command: 'q mcp add --help'"); + let response = chat.execute_command("q mcp add --help")?; + + println!("πŸ“ Restart response: {} bytes", response.len()); + println!("πŸ“ RESTART RESPONSE:"); + println!("{}", response); + println!("πŸ“ END RESTART RESPONSE"); + + // Verify tool execution details + assert!(response.contains("I will run the following shell command:") && response.contains("q mcp add --help"), "Missing command execution description"); + assert!(response.contains("Purpose:") && response.contains("Get help information for the q mcp add command"), "Missing purpose description"); + println!("βœ… Found tool execution details"); + + // Verify tool execution prompt appears + assert!(response.contains("πŸ› οΈ Using tool: execute_bash"), "Missing tool execution indicator"); + assert!(response.contains("Allow this action?") && response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); + println!("βœ… Found tool execution permission prompt"); + + // Allow the tool execution + let allow_response = chat.execute_command("y")?; + + println!("πŸ“ Allow response: {} bytes", allow_response.len()); + println!("πŸ“ ALLOW RESPONSE:"); + println!("{}", allow_response); + println!("πŸ“ END ALLOW RESPONSE"); + + // Verify mcp add help output + assert!(allow_response.contains("Add or replace a configured server"), "Missing command description"); + assert!(allow_response.contains("Usage: qchat mcp add"), "Missing usage information"); + assert!(allow_response.contains("--name "), "Missing --name option"); + assert!(allow_response.contains("--command "), "Missing --command option"); + assert!(allow_response.contains("--scope "), "Missing --scope option"); + assert!(allow_response.contains("--args "), "Missing --args option"); + assert!(allow_response.contains("--agent "), "Missing --agent option"); + assert!(allow_response.contains("--env "), "Missing --env option"); + assert!(allow_response.contains("--timeout "), "Missing --timeout option"); + assert!(allow_response.contains("--disabled"), "Missing --disabled option"); + assert!(allow_response.contains("--force"), "Missing --force option"); + assert!(allow_response.contains("--verbose") && allow_response.contains("Increase logging verbosity"), "Missing --verbose option"); + assert!(allow_response.contains("--help") && allow_response.contains("Print help"), "Missing --help option"); + assert!(allow_response.contains("Completed in"), "Missing completion indicator"); + assert!(allow_response.contains("Required:"), "Missing Requried indicator"); + assert!(allow_response.contains("Optional:"), "Missing Optional indicator"); + println!("βœ… MCP add help command executed successfully"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_q_mcp_import_help_command.rs b/e2etests/tests/test_q_mcp_import_help_command.rs new file mode 100644 index 0000000000..7649e8a02d --- /dev/null +++ b/e2etests/tests/test_q_mcp_import_help_command.rs @@ -0,0 +1,69 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "mcp")] +fn test_q_mcp_import_help_command() -> Result<(), Box> { + println!("πŸ” Testing q mcp import --help command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + // Execute mcp import --help command + println!("πŸ” Executing command: 'q mcp import --help'"); + let response = chat.execute_command("q mcp import --help")?; + + println!("πŸ“ Restart response: {} bytes", response.len()); + println!("πŸ“ RESTART RESPONSE:"); + println!("{}", response); + println!("πŸ“ END RESTART RESPONSE"); + + // Verify tool execution details + assert!(response.contains("I will run the following shell command:") && response.contains("q mcp import --help"), "Missing command execution description"); + assert!(response.contains("Purpose:") && response.contains("Get help information for the q mcp import command"), "Missing purpose description"); + println!("βœ… Found tool execution details"); + + // Verify tool execution prompt appears + assert!(response.contains("πŸ› οΈ Using tool: execute_bash"), "Missing tool execution indicator"); + assert!(response.contains("Allow this action?") && response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); + println!("βœ… Found tool execution permission prompt"); + + // Allow the tool execution + let allow_response = chat.execute_command("y")?; + + println!("πŸ“ Allow response: {} bytes", allow_response.len()); + println!("πŸ“ ALLOW RESPONSE:"); + println!("{}", allow_response); + println!("πŸ“ END ALLOW RESPONSE"); + + // Verify command description + assert!(allow_response.contains("Import a server configuration from another file"), "Missing command description"); + println!("βœ… Found command description"); + + // Verify usage line + assert!(allow_response.contains("Usage: qchat mcp import [OPTIONS] --file [SCOPE]"), "Missing complete usage line"); + println!("βœ… Found usage information"); + + // Verify Arguments section + assert!(allow_response.contains("Arguments:"), "Missing Arguments section"); + assert!(allow_response.contains("[SCOPE]") && allow_response.contains("[possible values: default, workspace, global]"), "Missing SCOPE argument with possible values"); + println!("βœ… Found Arguments section with SCOPE"); + + // Verify Options section + assert!(allow_response.contains("Options:"), "Missing Options section"); + assert!(allow_response.contains("--file "), "Missing --file option"); + assert!(allow_response.contains("--force") && allow_response.contains("Overwrite an existing server with the same name"), "Missing --force option"); + assert!(allow_response.contains("-v, --verbose...") && allow_response.contains("Increase logging verbosity"), "Missing --verbose option"); + assert!(allow_response.contains("-h, --help") && allow_response.contains("Print help"), "Missing --help option"); + println!("βœ… Found all options with descriptions"); + + // Verify completion indicator + assert!(allow_response.contains("Completed in") && allow_response.contains("s"), "Missing completion time indicator"); + println!("βœ… Found completion indicator"); + + println!("βœ… All q mcp import --help content verified successfully"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_q_mcp_status_help_command.rs b/e2etests/tests/test_q_mcp_status_help_command.rs new file mode 100644 index 0000000000..830bc0cfec --- /dev/null +++ b/e2etests/tests/test_q_mcp_status_help_command.rs @@ -0,0 +1,63 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "mcp")] +fn test_q_mcp_status_help_command() -> Result<(), Box> { + println!("πŸ” Testing q mcp status --help command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + // Execute mcp status --help command + println!("πŸ” Executing command: 'q mcp status --help'"); + let response = chat.execute_command("q mcp status --help")?; + + println!("πŸ“ Restart response: {} bytes", response.len()); + println!("πŸ“ RESTART RESPONSE:"); + println!("{}", response); + println!("πŸ“ END RESTART RESPONSE"); + + // Verify tool execution details + assert!(response.contains("I will run the following shell command:") && response.contains("q mcp status --help"), "Missing command execution description"); + assert!(response.contains("Purpose:") && response.contains("Get help information for the q mcp status command"), "Missing purpose description"); + println!("βœ… Found tool execution details"); + + // Verify tool execution prompt appears + assert!(response.contains("πŸ› οΈ Using tool: execute_bash"), "Missing tool execution indicator"); + assert!(response.contains("Allow this action?") && response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); + println!("βœ… Found tool execution permission prompt"); + + // Allow the tool execution + let allow_response = chat.execute_command("y")?; + + println!("πŸ“ Allow response: {} bytes", allow_response.len()); + println!("πŸ“ ALLOW RESPONSE:"); + println!("{}", allow_response); + println!("πŸ“ END ALLOW RESPONSE"); + + // Verify command description + assert!(allow_response.contains("Get the status of a configured server"), "Missing command description"); + println!("βœ… Found command description"); + + // Verify usage line + assert!(allow_response.contains("Usage: qchat mcp status [OPTIONS] --name "), "Missing complete usage line"); + println!("βœ… Found usage information"); + + // Verify Options section + assert!(allow_response.contains("Options:"), "Missing Options section"); + assert!(allow_response.contains("--name "), "Missing --name option"); + assert!(allow_response.contains("-v, --verbose...") && allow_response.contains("Increase logging verbosity"), "Missing --verbose option"); + assert!(allow_response.contains("-h, --help") && allow_response.contains("Print help"), "Missing --help option"); + println!("βœ… Found all options with descriptions"); + + // Verify completion indicator + assert!(allow_response.contains("Completed in") && allow_response.contains("s"), "Missing completion time indicator"); + println!("βœ… Found completion indicator"); + + println!("βœ… All q mcp status --help content verified successfully"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file From 12fbe3fc0896f7858ceba87d56410154eeb7dedc Mon Sep 17 00:00:00 2001 From: Abhishek Anne Date: Mon, 18 Aug 2025 19:05:45 +0530 Subject: [PATCH 13/77] QCLI test case automation for dynamic model selection and bug fix for MCP commands --- e2etests/src/lib.rs | 8 ++ e2etests/tests/test_model_dynamic_command.rs | 118 +++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 e2etests/tests/test_model_dynamic_command.rs diff --git a/e2etests/src/lib.rs b/e2etests/src/lib.rs index 64cd896e4e..e816f1eaff 100644 --- a/e2etests/src/lib.rs +++ b/e2etests/src/lib.rs @@ -118,6 +118,14 @@ pub mod q_chat_helper { Ok(total_content) } + /// Send key input (like arrow keys, Enter, etc.) + pub fn send_key_input(&mut self, key_sequence: &str) -> Result { + self.session.write_all(key_sequence.as_bytes())?; + self.session.flush()?; + std::thread::sleep(Duration::from_millis(200)); + self.read_response() + } + /// Quit the Q Chat session pub fn quit(&mut self) -> Result<(), Error> { self.session.send_line("/quit")?; diff --git a/e2etests/tests/test_model_dynamic_command.rs b/e2etests/tests/test_model_dynamic_command.rs new file mode 100644 index 0000000000..5b5667e50b --- /dev/null +++ b/e2etests/tests/test_model_dynamic_command.rs @@ -0,0 +1,118 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "model")] +fn test_model_dynamic_command() -> Result<(), Box> { + println!("πŸ” Testing /model command with dynamic selection..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + // Execute /model command to get list + let model_response = chat.execute_command("/model")?; + + println!("πŸ“ Model response: {} bytes", model_response.len()); + println!("πŸ“ MODEL RESPONSE:"); + println!("{}", model_response); + println!("πŸ“ END MODEL RESPONSE"); + + // Helper function to strip ANSI color codes + let strip_ansi = |s: &str| -> String { + let mut result = String::new(); + let mut in_escape = false; + for c in s.chars() { + if c == '\x1b' { + in_escape = true; + } else if in_escape && c == 'm' { + in_escape = false; + } else if !in_escape { + result.push(c); + } + } + result + }; + + // Parse available models from response + let mut models = Vec::new(); + let mut found_prompt = false; + + for line in model_response.lines() { + let trimmed_line = line.trim(); + + // Look for the prompt line + if trimmed_line.contains("Select a model for this chat session") { + found_prompt = true; + continue; + } + + // After finding prompt, parse model lines + if found_prompt { + let cleaned_line = strip_ansi(trimmed_line); + println!("πŸ” Row: '{}' -> Cleaned: '{}'", trimmed_line, cleaned_line); + + if !trimmed_line.is_empty() { + // Check if line contains a model (starts with ❯, spaces, or contains model names) + if cleaned_line.starts_with("❯") || cleaned_line.starts_with(" ") || cleaned_line.contains("-") { + let model_name = cleaned_line + .replace("❯", "") + .replace("(active)", "") + .trim() + .to_string(); + + println!("πŸ” Extracted model: '{}'", model_name); + if !model_name.is_empty() { + models.push(model_name); + } + } + } + } + } + + println!("πŸ“ Found models: {:?}", models); + assert!(!models.is_empty(), "No models found in response"); + + // Send down arrow to select different model + let selection_response = chat.send_key_input("\x1b[B")?; + + println!("πŸ“ Selection response: {} bytes", selection_response.len()); + println!("πŸ“ SELECTION RESPONSE:"); + println!("{}", selection_response); + println!("πŸ“ END SELECTION RESPONSE"); + + // Find which model is now selected (has ❯ marker) + let selected_model = selection_response.lines() + .find(|line| { + let cleaned = strip_ansi(line); + cleaned.contains("❯") + }) + .map(|line| { + let cleaned = strip_ansi(line.trim()); + cleaned + .replace("❯", "") + .replace("(active)", "") + .trim() + .to_string() + }) + .unwrap_or_else(|| models.get(1).unwrap_or(&models[0]).clone()); + + println!("πŸ“ Selected model: {}", selected_model); + + // Send Enter to confirm + let confirm_response = chat.send_key_input("\r")?; + + println!("πŸ“ Confirm response: {} bytes", confirm_response.len()); + println!("πŸ“ CONFIRM RESPONSE:"); + println!("{}", confirm_response); + println!("πŸ“ END CONFIRM RESPONSE"); + + // Verify selection with dynamic model name + assert!(confirm_response.contains(&format!("Using {}", selected_model)), + "Missing confirmation for selected model: {}", selected_model); + println!("βœ… Confirmed selection of: {}", selected_model); + + chat.quit()?; + + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file From b83898d099870d6988094b5f1c19d5d9a9b46cd1 Mon Sep 17 00:00:00 2001 From: sayema Anjum Date: Mon, 18 Aug 2025 19:59:26 +0530 Subject: [PATCH 14/77] QCLI Automation for MCP tests --- e2etests/tests/test_q_mcp_list_command.rs | 45 +++++++++++++ .../tests/test_q_mcp_list_help_command.rs | 58 ++++++++++++++++ e2etests/tests/test_q_mcp_status_command.rs | 66 +++++++++++++++++++ e2etests/tests/test_tools_schema_command.rs | 55 ++++++++++++++++ 4 files changed, 224 insertions(+) create mode 100644 e2etests/tests/test_q_mcp_list_command.rs create mode 100644 e2etests/tests/test_q_mcp_list_help_command.rs create mode 100644 e2etests/tests/test_q_mcp_status_command.rs create mode 100644 e2etests/tests/test_tools_schema_command.rs diff --git a/e2etests/tests/test_q_mcp_list_command.rs b/e2etests/tests/test_q_mcp_list_command.rs new file mode 100644 index 0000000000..26685c30b8 --- /dev/null +++ b/e2etests/tests/test_q_mcp_list_command.rs @@ -0,0 +1,45 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "mcp")] +fn test_q_mcp_list_command() -> Result<(), Box> { + println!("πŸ” Testing q mcp list command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("q mcp list")?; + + println!("πŸ“ MCP list response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify tool execution prompt + assert!(response.contains("Using tool:"), "Missing tool execution indicator"); + assert!(response.contains("q mcp list"), "Missing command in tool execution"); + assert!(response.contains("List available MCP servers"), "Missing purpose description"); + assert!(response.contains("Allow this action?") && response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); + println!("βœ… Found tool execution permission prompt"); + + // Allow the tool execution + let allow_response = chat.execute_command("y")?; + + println!("πŸ“ Allow response: {} bytes", allow_response.len()); + println!("πŸ“ ALLOW RESPONSE:"); + println!("{}", allow_response); + println!("πŸ“ END ALLOW RESPONSE"); + + + // Verify MCP server listing + //assert!(allow_response.contains("q_cli_default"), "Missing q_cli_default server"); + // Verify server count summary with dynamic count + assert!(allow_response.contains("You have") && allow_response.contains("MCP server configured:"), "Missing correct server count summary"); + assert!(allow_response.contains("Completed in"), "Missing completion indicator"); + println!("βœ… Found MCP server listing with servers and completion"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_q_mcp_list_help_command.rs b/e2etests/tests/test_q_mcp_list_help_command.rs new file mode 100644 index 0000000000..c241012ee6 --- /dev/null +++ b/e2etests/tests/test_q_mcp_list_help_command.rs @@ -0,0 +1,58 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "mcp")] +fn test_q_mcp_list_help_command() -> Result<(), Box> { + println!("πŸ” Testing q mcp list --help command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("q mcp list --help")?; + + println!("πŸ“ MCP list help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify tool execution prompt + assert!(response.contains("Using tool:"), "Missing tool execution indicator"); + assert!(response.contains("q mcp list --help"), "Missing command in tool execution"); + assert!(response.contains("Allow this action?") && response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); + println!("βœ… Found tool execution permission prompt"); + + // Allow the tool execution + let allow_response = chat.execute_command("y")?; + + println!("πŸ“ Allow response: {} bytes", allow_response.len()); + println!("πŸ“ ALLOW RESPONSE:"); + println!("{}", allow_response); + println!("πŸ“ END ALLOW RESPONSE"); + + // Verify help content + assert!(allow_response.contains("List configured servers"), "Missing command description"); + assert!(allow_response.contains("Usage: qchat mcp list") && allow_response.contains("[OPTIONS]") && allow_response.contains("[SCOPE]"), "Missing usage format"); + + // Verify arguments section + assert!(allow_response.contains("Arguments:"), "Missing Arguments section"); + assert!(allow_response.contains("[SCOPE]") && allow_response.contains("possible values: default, workspace, global"), "Missing scope argument"); + + // Verify options section + assert!(allow_response.contains("Options:"), "Missing Options section"); + assert!(allow_response.contains("-v") && allow_response.contains("--verbose")&& allow_response.contains("Increase logging verbosity"), "Missing verbose option"); + assert!(allow_response.contains("-h") && allow_response.contains("--help") && allow_response.contains("Print help"), "Missing help option"); + + // Verify additional explanation content + //assert!(allow_response.contains("The q mcp list command") && allow_response.contains("configured MCP"), "Missing command explanation"); + assert!(allow_response.contains("default") && allow_response.contains("workspace") && allow_response.contains("global"), "Missing scope explanation"); + assert!(allow_response.contains("-v") && allow_response.contains("--verbose"),"Missing verbose explanation"); + + + assert!(allow_response.contains("Completed in"), "Missing completion indicator"); + println!("βœ… Found all MCP list help content with explanations and completion"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_q_mcp_status_command.rs b/e2etests/tests/test_q_mcp_status_command.rs new file mode 100644 index 0000000000..9fefc398dd --- /dev/null +++ b/e2etests/tests/test_q_mcp_status_command.rs @@ -0,0 +1,66 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "mcp")] +fn test_q_mcp_status_command() -> Result<(), Box> { + println!("πŸ” Testing q mcp status command workflow..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + // Now get list of available servers + let list_response = chat.execute_command("q mcp list")?; + let list_allow_response = chat.execute_command("y")?; + + println!("πŸ“ List response: {} bytes", list_allow_response.len()); + println!("πŸ“ LIST RESPONSE:"); + println!("{}", list_allow_response); + println!("πŸ“ END LIST RESPONSE"); + + // Extract server names from the list + let mut server_name: Option = None; + let lines: Vec<&str> = list_allow_response.lines().collect(); + for line in lines { + if line.trim().starts_with("β€’ ") { + // Extract server name from bullet point line + if let Some(name_part) = line.trim().strip_prefix("β€’ ") { + let parts: Vec<&str> = name_part.split_whitespace().collect(); + if let Some(name) = parts.first() { + server_name = Some(name.to_string()); + break; + } + } + } + } + + if let Some(name) = server_name { + println!("βœ… Found server to test: {}", name); + + // Test q mcp status with specific server name + let status_cmd = format!("q mcp status --name {}", name); + let server_status_response = chat.execute_command(&status_cmd)?; + let server_status_allow = chat.execute_command("y")?; + + println!("πŸ“ Server status response: {} bytes", server_status_allow.len()); + println!("πŸ“ SERVER STATUS RESPONSE:"); + println!("{}", server_status_allow); + println!("πŸ“ END SERVER STATUS RESPONSE"); + + // Verify server status output + assert!(server_status_allow.contains("Scope"), "Missing Scope field"); + assert!(server_status_allow.contains("Agent"), "Missing Agent field"); + assert!(server_status_allow.contains("Command"), "Missing Command field"); + assert!(server_status_allow.contains("Timeout"), "Missing Timeout field"); + assert!(server_status_allow.contains("Disabled"), "Missing Disabled field"); + assert!(server_status_allow.contains("Completed in"), "Missing completion indicator"); + println!("βœ… Found all expected server status fields"); + + } else { + println!("ℹ️ No servers found to test status command"); + } + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_tools_schema_command.rs b/e2etests/tests/test_tools_schema_command.rs new file mode 100644 index 0000000000..57703e1df9 --- /dev/null +++ b/e2etests/tests/test_tools_schema_command.rs @@ -0,0 +1,55 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "tools")] +fn test_tools_schema_command() -> Result<(), Box> { + println!("πŸ” Testing /tools schema command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/tools schema")?; + + println!("πŸ“ Tools schema response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify JSON structure + assert!(response.contains("{") && response.contains("}"), "Missing JSON structure"); + println!("βœ… Found JSON structure"); + + // Verify core built-in tools + assert!(response.contains("fs_read") || response.contains("fs_write") || response.contains("execute_bash") || response.contains("use_aws"), "Missing tools"); + println!("βœ… Found core built-in tools"); + + // Verify tool structure elements + assert!(response.contains("name"), "Missing name field"); + assert!(response.contains("description"), "Missing description field"); + assert!(response.contains("input_schema"), "Missing input_schema field"); + assert!(response.contains("properties"), "Missing properties field"); + println!("βœ… Found required tool structure: name, description, input_schema, properties"); + + // Check for optional MCP/GitHub tools if present + if response.contains("download_files_from_github") { + println!("βœ… Found GitHub-related tools"); + } + if response.contains("consolidate_findings_to_csv") { + println!("βœ… Found analysis tools"); + } + if response.contains("gh_issue") { + println!("βœ… Found GitHub issue reporting tool"); + } + + // Verify schema structure for at least one tool + if response.contains("type") { + println!("βœ… Found proper schema type definitions"); + } + + println!("βœ… All tools schema content verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + + Ok(()) +} From 1710f404764df0e640e5d7775b016957e25edcf9 Mon Sep 17 00:00:00 2001 From: sayema Anjum Date: Tue, 19 Aug 2025 19:15:10 +0530 Subject: [PATCH 15/77] QCLI Automation for tools,model,editor,subscribe,usage,compact,hooks,issues,tests --- e2etests/Cargo.toml | 5 + e2etests/run_simple_categorized.sh | 45 ++ e2etests/src/lib.rs | 4 +- e2etests/tests/test_compact_command.rs | 83 +++- e2etests/tests/test_compact_help_command.rs | 67 --- e2etests/tests/test_editor_help_command.rs | 54 ++- e2etests/tests/test_hooks_command.rs | 72 +++- e2etests/tests/test_hooks_help_command.rs | 55 --- e2etests/tests/test_issue_command.rs | 70 ++- e2etests/tests/test_issue_force_command.rs | 28 -- e2etests/tests/test_issue_help_command.rs | 47 -- e2etests/tests/test_model_command.rs | 41 -- e2etests/tests/test_model_dynamic_command.rs | 49 ++- e2etests/tests/test_model_help_command.rs | 42 -- e2etests/tests/test_subscribe_command.rs | 62 ++- e2etests/tests/test_subscribe_help_command.rs | 47 -- e2etests/tests/test_tools_command.rs | 405 +++++++++++++++++- e2etests/tests/test_tools_help_command.rs | 66 --- e2etests/tests/test_tools_reset_command.rs | 43 -- .../tests/test_tools_reset_help_command.rs | 37 -- e2etests/tests/test_tools_schema_command.rs | 55 --- .../tests/test_tools_schema_help_command.rs | 37 -- .../tests/test_tools_trust_all_command.rs | 52 --- .../test_tools_trust_all_help_command.rs | 37 -- e2etests/tests/test_tools_trust_command.rs | 76 ---- .../tests/test_tools_trust_help_command.rs | 41 -- .../tests/test_tools_untrust_help_command.rs | 41 -- e2etests/tests/test_usage_command.rs | 61 ++- e2etests/tests/test_usage_help_command.rs | 41 -- 29 files changed, 823 insertions(+), 940 deletions(-) delete mode 100644 e2etests/tests/test_compact_help_command.rs delete mode 100644 e2etests/tests/test_hooks_help_command.rs delete mode 100644 e2etests/tests/test_issue_force_command.rs delete mode 100644 e2etests/tests/test_issue_help_command.rs delete mode 100644 e2etests/tests/test_model_command.rs delete mode 100644 e2etests/tests/test_model_help_command.rs delete mode 100644 e2etests/tests/test_subscribe_help_command.rs delete mode 100644 e2etests/tests/test_tools_help_command.rs delete mode 100644 e2etests/tests/test_tools_reset_command.rs delete mode 100644 e2etests/tests/test_tools_reset_help_command.rs delete mode 100644 e2etests/tests/test_tools_schema_command.rs delete mode 100644 e2etests/tests/test_tools_schema_help_command.rs delete mode 100644 e2etests/tests/test_tools_trust_all_command.rs delete mode 100644 e2etests/tests/test_tools_trust_all_help_command.rs delete mode 100644 e2etests/tests/test_tools_trust_command.rs delete mode 100644 e2etests/tests/test_tools_trust_help_command.rs delete mode 100644 e2etests/tests/test_tools_untrust_help_command.rs delete mode 100644 e2etests/tests/test_usage_help_command.rs diff --git a/e2etests/Cargo.toml b/e2etests/Cargo.toml index 0d106c0133..caadc7a17e 100644 --- a/e2etests/Cargo.toml +++ b/e2etests/Cargo.toml @@ -21,6 +21,11 @@ mcp = [] ai_prompts = [] issue_reporting = [] tools=[] +compact=[] +hooks=[] +usage=[] +editor=[] +subscribe=[] [[test]] name = "test_help_command" diff --git a/e2etests/run_simple_categorized.sh b/e2etests/run_simple_categorized.sh index c8a39e1c34..b069db4ae3 100755 --- a/e2etests/run_simple_categorized.sh +++ b/e2etests/run_simple_categorized.sh @@ -17,6 +17,11 @@ RUN_MCP=true RUN_AI_PROMPTS=true RUN_ISSUE_REPORTING=true RUN_TOOLS=true +RUN_COMPACT=true +RUN_HOOKS=true +RUN_USAGE=true +RUN_EDITOR=true +RUN_SUBSCRIBE=true # ============================================================================ Q_BINARY="q" @@ -215,6 +220,46 @@ if [ "$RUN_TOOLS" = true ]; then fi fi +if [ "$RUN_COMPACT" = true ]; then + if run_category "compact" "COMPACT"; then + ((total_passed++)) + else + ((total_failed++)) + fi +fi + +if [ "$RUN_HOOKS" = true ]; then + if run_category "hooks" "HOOKS"; then + ((total_passed++)) + else + ((total_failed++)) + fi +fi + +if [ "$RUN_USAGE" = true ]; then + if run_category "usage" "USAGE"; then + ((total_passed++)) + else + ((total_failed++)) + fi +fi + +if [ "$RUN_EDITOR" = true ]; then + if run_category "editor" "EDITOR"; then + ((total_passed++)) + else + ((total_failed++)) + fi +fi + +if [ "$RUN_SUBSCRIBE" = true ]; then + if run_category "subscribe" "SUBSCRIBE"; then + ((total_passed++)) + else + ((total_failed++)) + fi +fi + # Final summary echo "" echo "🎯 FINAL SUMMARY" diff --git a/e2etests/src/lib.rs b/e2etests/src/lib.rs index e816f1eaff..a454a5813b 100644 --- a/e2etests/src/lib.rs +++ b/e2etests/src/lib.rs @@ -107,12 +107,12 @@ pub mod q_chat_helper { }, Ok(_) => { // No more data, but wait a bit more in case there's more coming - std::thread::sleep(Duration::from_millis(1000)); + std::thread::sleep(Duration::from_millis(2000)); if total_content.len() > 0 { break; } }, Err(_) => break, } - std::thread::sleep(Duration::from_millis(1000)); + std::thread::sleep(Duration::from_millis(2000)); } Ok(total_content) diff --git a/e2etests/tests/test_compact_command.rs b/e2etests/tests/test_compact_command.rs index ea146c5f8e..657d23b8d1 100644 --- a/e2etests/tests/test_compact_command.rs +++ b/e2etests/tests/test_compact_command.rs @@ -1,12 +1,22 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] -#[cfg(feature = "session_mgmt")] -fn test_compact_command() -> Result<(), Box> { - println!("πŸ” Testing /compact command..."); - +#[cfg(feature = "compact")] + +fn test_all_compact_commands() -> Result<(), Box> { let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); + println!(":white_check_mark: Q Chat session started"); + + test_compact_command(&mut chat)?; + test_compact_help_command(&mut chat)?; + + chat.quit()?; + println!(":white_check_mark: All tests completed successfully"); + Ok(()) +} + +fn test_compact_command(chat: &mut QChatSession) -> Result<(), Box> { + println!("πŸ” Testing /compact command..."); let response = chat.execute_command("/compact")?; @@ -16,9 +26,9 @@ fn test_compact_command() -> Result<(), Box> { println!("πŸ“ END OUTPUT"); // Verify compact response - either success or too short - if response.contains("Conversation history has been compacted successfully!") { + if response.contains("history") && response.contains("compacted") && response.contains("successfully") { println!("βœ… Found compact success message"); - } else if response.contains("Conversation too short to compact.") { + } else if response.contains("Conversation") && response.contains("short") { println!("βœ… Found conversation too short message"); } else { panic!("Missing expected compact response"); @@ -26,8 +36,63 @@ fn test_compact_command() -> Result<(), Box> { println!("βœ… All compact content verified!"); - chat.quit()?; - println!("βœ… Test completed successfully"); + Ok(()) +} + +fn test_compact_help_command(chat: &mut QChatSession) -> Result<(), Box> { + println!("πŸ” Testing /compact --help command..."); + + let response = chat.execute_command("/compact --help")?; + + println!("πŸ“ Compact help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + /* Verify main description + assert!(response.contains("/compact") && response.contains("summarizes") && response.contains("history"), "Missing compact description"); + println!("βœ… Found compact description");*/ + + // Verify When to use section + assert!(response.contains("When to use"), "Missing When to use section"); + /*assert!(response.contains("memory constraint"), "Missing memory constraint warning"); + assert!(response.contains("conversation") && response.contains("running") && response.contains("long time"), "Missing long conversation note"); + assert!(response.contains("new topic") && response.contains("same session"), "Missing new topic note"); + assert!(response.contains("complex tool operations"), "Missing tool operations note");*/ + println!("βœ… Found When to use section with all scenarios"); + + // Verify How it works section + assert!(response.contains("How it works"), "Missing How it works section"); + /*assert!(response.contains("AI-generated summary"), "Missing AI summary description"); + assert!(response.contains("key information") && response.contains("code") && response.contains("tool executions"), "Missing key elements"); + assert!(response.contains("free up space"), "Missing free up space description"); + assert!(response.contains("reference the summary context"), "Missing summary context reference");*/ + println!("βœ… Found How it works section with all details"); + + // Verify auto-compaction information + //assert!(response.contains("Compaction will be automatically performed whenever the context window overflows"), "Missing auto-compaction note"); + //assert!(response.contains("To disable this behavior, run: `q settings chat.disableAutoCompaction true`"), "Missing disable instruction"); + assert!(response.contains("run: `q settings chat.disableAutoCompaction true`"), "Missing disable instruction"); + println!("βœ… Found auto-compaction information"); + + // Verify Usage section + assert!(response.contains("Usage:"), "Missing usage format"); + println!("βœ… Found usage format"); + + // Verify Arguments section + assert!(response.contains("Arguments:"), "Missing Arguments section"); + println!("βœ… Found Arguments section"); + + // Verify Options section + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("--show-summary"), "Missing --show-summary option"); + assert!(response.contains("--messages-to-exclude"), "Missing --messages-to-exclude option"); + assert!(response.contains("--truncate-large-messages"), "Missing --truncate-large-messages option"); + assert!(response.contains("--max-message-length"), "Missing --max-message-length option"); + assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing -h, --help flags"); + println!("βœ… Found all options and help flags"); + + println!("βœ… All compact help content verified!"); Ok(()) } \ No newline at end of file diff --git a/e2etests/tests/test_compact_help_command.rs b/e2etests/tests/test_compact_help_command.rs deleted file mode 100644 index 1a21f7d065..0000000000 --- a/e2etests/tests/test_compact_help_command.rs +++ /dev/null @@ -1,67 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "session_mgmt")] -fn test_compact_help_command() -> Result<(), Box> { - println!("πŸ” Testing /compact --help command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/compact --help")?; - - println!("πŸ“ Compact help response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify main description - assert!(response.contains("/compact summarizes the conversation history"), "Missing compact description"); - println!("βœ… Found compact description"); - - // Verify When to use section - assert!(response.contains("When to use"), "Missing When to use section"); - assert!(response.contains("memory constraint warning message"), "Missing memory constraint warning"); - assert!(response.contains("conversation has been running for a long time"), "Missing long conversation note"); - assert!(response.contains("new topic within the same session"), "Missing new topic note"); - assert!(response.contains("completing complex tool operations"), "Missing tool operations note"); - println!("βœ… Found When to use section with all scenarios"); - - // Verify How it works section - assert!(response.contains("How it works"), "Missing How it works section"); - assert!(response.contains("AI-generated summary of your conversation"), "Missing AI summary description"); - assert!(response.contains("key information") && response.contains("code") && response.contains("tool executions"), "Missing key elements"); - assert!(response.contains("free up space"), "Missing free up space description"); - assert!(response.contains("reference the summary context"), "Missing summary context reference"); - println!("βœ… Found How it works section with all details"); - - // Verify auto-compaction information - assert!(response.contains("Compaction will be automatically performed whenever the context window overflows"), "Missing auto-compaction note"); - assert!(response.contains("To disable this behavior, run: `q settings chat.disableAutoCompaction true`"), "Missing disable instruction"); - println!("βœ… Found auto-compaction information"); - - // Verify Usage section - assert!(response.contains("Usage:"), "Missing usage format"); - println!("βœ… Found usage format"); - - // Verify Arguments section - assert!(response.contains("Arguments:"), "Missing Arguments section"); - println!("βœ… Found Arguments section"); - - // Verify Options section - assert!(response.contains("Options:"), "Missing Options section"); - assert!(response.contains("--show-summary"), "Missing --show-summary option"); - assert!(response.contains("--messages-to-exclude"), "Missing --messages-to-exclude option"); - assert!(response.contains("--truncate-large-messages"), "Missing --truncate-large-messages option"); - assert!(response.contains("--max-message-length"), "Missing --max-message-length option"); - assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing -h, --help flags"); - assert!(response.contains("Print help"), "Missing Print help description"); - println!("βœ… Found all options and help flags"); - - println!("βœ… All compact help content verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} \ No newline at end of file diff --git a/e2etests/tests/test_editor_help_command.rs b/e2etests/tests/test_editor_help_command.rs index 6b87fb8b7c..d0ecb60f44 100644 --- a/e2etests/tests/test_editor_help_command.rs +++ b/e2etests/tests/test_editor_help_command.rs @@ -1,8 +1,19 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] -#[cfg(feature = "integration")] -fn test_editor_help_command() -> Result<(), Box> { +#[cfg(feature = "editor")] +fn test_all_editor_commands() -> Result<(), Box> { + let mut chat = QChatSession::new()?; + println!(":white_check_mark: Q Chat session started"); + + test_editor_help_command(&mut chat)?; + test_help_editor_command(&mut chat)?; + + chat.quit()?; + println!(":white_check_mark: All tests completed successfully"); + Ok(()) +} +fn test_editor_help_command(chat: &mut QChatSession) -> Result<(), Box> { println!("πŸ” Testing /editor --help command..."); let mut chat = QChatSession::new()?; @@ -15,9 +26,9 @@ fn test_editor_help_command() -> Result<(), Box> { println!("{}", response); println!("πŸ“ END OUTPUT"); - // Verify description - assert!(response.contains("Open $EDITOR (defaults to vi) to compose a prompt"), "Missing editor description"); - println!("βœ… Found editor description"); + /* Verify description + assert!(response.contains("Open $EDITOR"), "Missing editor description"); + println!("βœ… Found editor description");*/ // Verify Usage section assert!(response.contains("Usage:") && response.contains("/editor") && response.contains("[INITIAL_TEXT]"), "Missing Usage section"); @@ -25,7 +36,7 @@ fn test_editor_help_command() -> Result<(), Box> { // Verify Arguments section assert!(response.contains("Arguments:"), "Missing Arguments section"); - assert!(response.contains("[INITIAL_TEXT]..."), "Missing INITIAL_TEXT argument"); + assert!(response.contains("[INITIAL_TEXT]"), "Missing INITIAL_TEXT argument"); println!("βœ… Found Arguments section"); // Verify Options section @@ -33,27 +44,17 @@ fn test_editor_help_command() -> Result<(), Box> { println!("βœ… Found Options section"); // Verify help flags - assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing -h, --help flags"); - assert!(response.contains("Print help"), "Missing Print help description"); + assert!(response.contains("-h") && response.contains("--help"), "Missing -h, --help flags"); println!("βœ… Found help flags: -h, --help with Print help description"); println!("βœ… All editor help content verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - + Ok(()) } -#[cfg(feature = "integration")] -#[test] -#[cfg(feature = "integration")] -fn test_help_editor_command() -> Result<(), Box> { +fn test_help_editor_command(chat: &mut QChatSession) -> Result<(), Box> { println!("πŸ” Testing /help editor command..."); - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - let response = chat.execute_command("/help editor")?; println!("πŸ“ Help editor response: {} bytes", response.len()); @@ -61,17 +62,13 @@ fn test_help_editor_command() -> Result<(), Box> { println!("{}", response); println!("πŸ“ END OUTPUT"); - // Verify description - assert!(response.contains("Open $EDITOR (defaults to vi) to compose a prompt"), "Missing editor description"); - println!("βœ… Found editor description"); - // Verify Usage section assert!(response.contains("Usage:") && response.contains("/editor") && response.contains("[INITIAL_TEXT]"), "Missing Usage section"); println!("βœ… Found Usage section with /editor command"); // Verify Arguments section assert!(response.contains("Arguments:"), "Missing Arguments section"); - assert!(response.contains("[INITIAL_TEXT]..."), "Missing INITIAL_TEXT argument"); + assert!(response.contains("[INITIAL_TEXT]"), "Missing INITIAL_TEXT argument"); println!("βœ… Found Arguments section"); // Verify Options section @@ -79,13 +76,10 @@ fn test_help_editor_command() -> Result<(), Box> { println!("βœ… Found Options section"); // Verify help flags - assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing -h, --help flags"); + assert!(response.contains("-h") && response.contains("--help"), "Missing -h, --help flags"); println!("βœ… Found help flags: -h, --help with Print help description"); - println!("βœ… All help editor content verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - + println!("βœ… All editor help content verified!"); + Ok(()) } \ No newline at end of file diff --git a/e2etests/tests/test_hooks_command.rs b/e2etests/tests/test_hooks_command.rs index 88120d551b..ae659344ad 100644 --- a/e2etests/tests/test_hooks_command.rs +++ b/e2etests/tests/test_hooks_command.rs @@ -1,12 +1,22 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] -#[cfg(feature = "integration")] -fn test_hooks_command() -> Result<(), Box> { +#[cfg(feature = "hooks")] +fn test_all_hoooks_commands() -> Result<(), Box> { + let mut chat = QChatSession::new()?; + println!(":white_check_mark: Q Chat session started"); + + test_hooks_command(&mut chat)?; + test_hooks_help_command(&mut chat)?; + + chat.quit()?; + println!(":white_check_mark: All tests completed successfully"); + Ok(()) +} + +fn test_hooks_command(chat: &mut QChatSession) -> Result<(), Box> { println!("πŸ” Testing /hooks command..."); - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); let response = chat.execute_command("/hooks")?; @@ -16,22 +26,60 @@ fn test_hooks_command() -> Result<(), Box> { println!("πŸ“ END OUTPUT"); // Verify no hooks configured message - assert!(response.contains("No hooks are configured."), "Missing no hooks configured message"); + assert!(response.contains("No hooks"), "Missing no hooks configured message"); println!("βœ… Found no hooks configured message"); // Verify documentation reference - assert!(response.contains("Refer to the documentation"), "Missing documentation reference"); + assert!(response.contains("documentation"), "Missing documentation reference"); assert!(response.contains("https://github.com/aws/amazon-q-developer-cli/blob/main/docs/agent-format.md#hooks-field"), "Missing documentation URL"); println!("βœ… Found documentation reference and URL"); - // Verify hooks field reference - assert!(response.contains("hooks-field"), "Missing hooks field reference"); - println!("βœ… Found hooks field reference"); - println!("βœ… All hooks command functionality verified!"); - chat.quit()?; - println!("βœ… Test completed successfully"); + Ok(()) +} + +fn test_hooks_help_command(chat: &mut QChatSession) -> Result<(), Box> { + println!("πŸ” Testing /hooks --help command..."); + + let response = chat.execute_command("/hooks --help")?; + + println!("πŸ“ Hooks help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + /* Verify context hooks description + assert!(response.contains("context hooks"), "Missing context hooks"); + println!("βœ… Found context hooks description");*/ + + // Verify documentation reference + assert!(response.contains("documentation"), "Missing documentation reference"); + assert!(response.contains("https://github.com/aws/amazon-q-developer-cli/blob/main/docs/agent-format.md#hooks-field"), "Missing documentation URL"); + println!("βœ… Found documentation reference and URL"); + + // Verify Notes section + assert!(response.contains("Notes:"), "Missing Notes section"); + /*assert!(response.contains("executed in parallel"), "Missing parallel execution note"); + assert!(response.contains("conversation_start"), "Missing conversation_start hook type"); + assert!(response.contains("per_prompt"), "Missing per_prompt hook type");*/ + println!("βœ… Found Notes section with hook types and execution details"); + + // Verify Usage section + assert!(response.contains("Usage:"), "Missing Usage section"); + assert!(response.contains("/hooks"), "Missing /hooks command in usage section"); + println!("βœ… Found Usage section with /hooks command"); + + // Verify Options section + assert!(response.contains("Options:"), "Missing Options section"); + println!("βœ… Found Options section"); + + // Verify help flags + assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing -h, --help flags"); + println!("βœ… Found help flags: -h, --help with Print help description"); + + println!("βœ… All hooks help content verified!"); + Ok(()) } \ No newline at end of file diff --git a/e2etests/tests/test_hooks_help_command.rs b/e2etests/tests/test_hooks_help_command.rs deleted file mode 100644 index 02270e5a93..0000000000 --- a/e2etests/tests/test_hooks_help_command.rs +++ /dev/null @@ -1,55 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "integration")] -fn test_hooks_help_command() -> Result<(), Box> { - println!("πŸ” Testing /hooks --help command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/hooks --help")?; - - println!("πŸ“ Hooks help response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify context hooks description - assert!(response.contains("context hooks"), "Missing context hooks"); - assert!(response.contains("appended to the prompt to Amazon Q"), "Missing prompt append description"); - println!("βœ… Found context hooks and shell commands description"); - - // Verify documentation reference - assert!(response.contains("documentation for how to configure hooks"), "Missing documentation reference"); - assert!(response.contains("https://github.com/aws/amazon-q-developer-cli/blob/main/docs/agent-format.md#hooks-field"), "Missing documentation URL"); - println!("βœ… Found documentation reference and URL"); - - // Verify Notes section - assert!(response.contains("Notes:"), "Missing Notes section"); - assert!(response.contains("executed in parallel"), "Missing parallel execution note"); - assert!(response.contains("conversation_start"), "Missing conversation_start hook type"); - assert!(response.contains("per_prompt"), "Missing per_prompt hook type"); - println!("βœ… Found Notes section with hook types and execution details"); - - // Verify Usage section - assert!(response.contains("Usage:"), "Missing Usage section"); - assert!(response.contains("/hooks"), "Missing /hooks command in usage section"); - println!("βœ… Found Usage section with /hooks command"); - - // Verify Options section - assert!(response.contains("Options:"), "Missing Options section"); - println!("βœ… Found Options section"); - - // Verify help flags - assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing -h, --help flags"); - assert!(response.contains("Print help (see a summary with '-h')"), "Missing Print help description"); - println!("βœ… Found help flags: -h, --help with Print help description"); - - println!("βœ… All hooks help content verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} \ No newline at end of file diff --git a/e2etests/tests/test_issue_command.rs b/e2etests/tests/test_issue_command.rs index 1eaef5e8bd..622e83cac4 100644 --- a/e2etests/tests/test_issue_command.rs +++ b/e2etests/tests/test_issue_command.rs @@ -2,11 +2,22 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] #[cfg(feature = "issue_reporting")] -fn test_issue_command() -> Result<(), Box> { +fn test_all_issue_commands() -> Result<(), Box> { + let mut chat = QChatSession::new()?; + println!(":white_check_mark: Q Chat session started"); + + test_issue_command(&mut chat)?; + test_issue_force_command(&mut chat)?; + test_issue_help_command(&mut chat)?; + + chat.quit()?; + println!(":white_check_mark: All tests completed successfully"); + Ok(()) +} + +fn test_issue_command(chat: &mut QChatSession) -> Result<(), Box> { println!("πŸ” Testing /issue command with bug report..."); - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); let response = chat.execute_command("/issue \"Bug: Q CLI crashes when using large files\"")?; @@ -20,9 +31,58 @@ fn test_issue_command() -> Result<(), Box> { println!("βœ… Found browser opening confirmation"); println!("βœ… All issue command functionality verified!"); + Ok(()) +} + +fn test_issue_force_command(chat: &mut QChatSession) -> Result<(), Box> { + println!("πŸ” Testing /issue --force command with critical bug..."); - chat.quit()?; - println!("βœ… Test completed successfully"); + let response = chat.execute_command("/issue --force \"Critical bug in file handling\"")?; + + println!("πŸ“ Issue force command response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify command executed successfully (GitHub opens automatically) + assert!(response.contains("Heading over to GitHub..."), "Missing browser opening confirmation"); + println!("βœ… Found browser opening confirmation"); + println!("βœ… All issue --force command functionality verified!"); Ok(()) } + +fn test_issue_help_command(chat: &mut QChatSession) -> Result<(), Box> { + println!("πŸ” Testing /issue --help command..."); + + let response = chat.execute_command("/issue --help")?; + + println!("πŸ“ Issue help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + /* Verify description + assert!(response.contains("issue") && response.contains("feature request"), "Missing issue description"); + println!("βœ… Found issue description");*/ + + // Verify Usage section + //assert!(response.contains("Usage: /issue [OPTIONS] [DESCRIPTION]..."), "Missing usage format"); + assert!(response.contains("Usage:") && response.contains("/issue") && response.contains("[DESCRIPTION]") && response.contains("[OPTIONS]"), "Missing Usage section"); + println!("βœ… Found usage format"); + + // Verify Arguments section + assert!(response.contains("Arguments:"), "Missing Arguments section"); + assert!(response.contains("[DESCRIPTION]"), "Missing DESCRIPTION argument"); + println!("βœ… Found Arguments section"); + + // Verify Options section + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("-f") && response.contains("--force"), "Missing force option"); + assert!(response.contains("-h") && response.contains("--help"), "Missing -h, --help flags"); + println!("βœ… Found Options section with force and help flags"); + + println!("βœ… All issue help content verified!"); + Ok(()) +} + diff --git a/e2etests/tests/test_issue_force_command.rs b/e2etests/tests/test_issue_force_command.rs deleted file mode 100644 index a63508d2b5..0000000000 --- a/e2etests/tests/test_issue_force_command.rs +++ /dev/null @@ -1,28 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "issue_reporting")] -fn test_issue_force_command() -> Result<(), Box> { - println!("πŸ” Testing /issue --force command with critical bug..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/issue --force \"Critical bug in file handling\"")?; - - println!("πŸ“ Issue force command response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify command executed successfully (GitHub opens automatically) - assert!(response.contains("Heading over to GitHub..."), "Missing browser opening confirmation"); - println!("βœ… Found browser opening confirmation"); - - println!("βœ… All issue --force command functionality verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} \ No newline at end of file diff --git a/e2etests/tests/test_issue_help_command.rs b/e2etests/tests/test_issue_help_command.rs deleted file mode 100644 index 241c5d5eb6..0000000000 --- a/e2etests/tests/test_issue_help_command.rs +++ /dev/null @@ -1,47 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "integration")] -fn test_issue_help_command() -> Result<(), Box> { - println!("πŸ” Testing /issue --help command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/issue --help")?; - - println!("πŸ“ Issue help response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify description - assert!(response.contains("Create a new Github issue or make a feature request"), "Missing issue description"); - println!("βœ… Found issue description"); - - // Verify Usage section - //assert!(response.contains("Usage: /issue [OPTIONS] [DESCRIPTION]..."), "Missing usage format"); - assert!(response.contains("Usage:") && response.contains("/issue") && response.contains("[DESCRIPTION]") && response.contains("[OPTIONS]"), "Missing Usage section"); - println!("βœ… Found usage format"); - - // Verify Arguments section - assert!(response.contains("Arguments:"), "Missing Arguments section"); - assert!(response.contains("[DESCRIPTION]..."), "Missing DESCRIPTION argument"); - assert!(response.contains("Issue description"), "Missing issue description text"); - println!("βœ… Found Arguments section"); - - // Verify Options section - assert!(response.contains("Options:"), "Missing Options section"); - assert!(response.contains("-f") && response.contains("--force"), "Missing force option"); - assert!(response.contains("Force issue creation"), "Missing force description"); - assert!(response.contains("-h") && response.contains("--help"), "Missing -h, --help flags"); - assert!(response.contains("Print help"), "Missing help description"); - println!("βœ… Found Options section with force and help flags"); - - println!("βœ… All issue help content verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} \ No newline at end of file diff --git a/e2etests/tests/test_model_command.rs b/e2etests/tests/test_model_command.rs deleted file mode 100644 index f55112b7e5..0000000000 --- a/e2etests/tests/test_model_command.rs +++ /dev/null @@ -1,41 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "model")] -fn test_model_command() -> Result<(), Box> { - println!("πŸ” Testing /model command interface and selection..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/model")?; - - println!("πŸ“ Model response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify model selection header - assert!(response.contains("Select a model for this chat session"), "Missing model selection header"); - println!("βœ… Found model selection header"); - - // Verify required models - assert!(response.contains("claude-4-sonnet"), "Missing claude-4-sonnet model"); - assert!(response.contains("claude-3.7-sonnet"), "Missing claude-3.7-sonnet model"); - println!("βœ… Found required models: claude-4-sonnet, claude-3.7-sonnet"); - - // Verify active model indicator - assert!(response.contains("(active)"), "Missing active model indicator"); - println!("βœ… Found active model indicator"); - - // Verify cursor selection indicator - assert!(response.contains("❯"), "Missing cursor selection indicator"); - println!("βœ… Found cursor selection indicator ❯"); - - println!("βœ… All model selection functionality verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} diff --git a/e2etests/tests/test_model_dynamic_command.rs b/e2etests/tests/test_model_dynamic_command.rs index 5b5667e50b..6ffa947dfe 100644 --- a/e2etests/tests/test_model_dynamic_command.rs +++ b/e2etests/tests/test_model_dynamic_command.rs @@ -2,7 +2,18 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] #[cfg(feature = "model")] -fn test_model_dynamic_command() -> Result<(), Box> { +fn test_all_model_commands() -> Result<(), Box> { + let mut chat = QChatSession::new()?; + println!(":white_check_mark: Q Chat session started"); + + test_model_dynamic_command(&mut chat)?; + test_model_help_command(&mut chat)?; + + chat.quit()?; + println!(":white_check_mark: All tests completed successfully"); + Ok(()) +} +fn test_model_dynamic_command(chat: &mut QChatSession) -> Result<(), Box> { println!("πŸ” Testing /model command with dynamic selection..."); let mut chat = QChatSession::new()?; @@ -109,10 +120,40 @@ fn test_model_dynamic_command() -> Result<(), Box> { assert!(confirm_response.contains(&format!("Using {}", selected_model)), "Missing confirmation for selected model: {}", selected_model); println!("βœ… Confirmed selection of: {}", selected_model); + + Ok(()) +} + +fn test_model_help_command(chat: &mut QChatSession) -> Result<(), Box> { + println!("πŸ” Testing /model --help command..."); - chat.quit()?; - println!("βœ… Test completed successfully"); + let response = chat.execute_command("/model --help")?; + + println!("πŸ“ Model help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + /* Verify description + assert!(response.contains("Select") && response.contains("model"), "Missing model selection description"); + println!("βœ… Found model selection description");*/ + + // Verify Usage section + assert!(response.contains("Usage:"), "Missing Usage section"); + assert!(response.contains("/model"), "Missing /model command in usage section"); + println!("βœ… Found Usage section with /model command"); + + // Verify Options section + assert!(response.contains("Options:"), "Missing Options section"); + println!("βœ… Found Options section"); + + // Verify help flags + assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing -h, --help flags"); + assert!(response.contains("Print help"), "Missing Print help description"); + println!("βœ… Found help flags: -h, --help with Print help description"); + + println!("βœ… All model help content verified!"); Ok(()) -} \ No newline at end of file +} diff --git a/e2etests/tests/test_model_help_command.rs b/e2etests/tests/test_model_help_command.rs deleted file mode 100644 index dbec84a4f3..0000000000 --- a/e2etests/tests/test_model_help_command.rs +++ /dev/null @@ -1,42 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "model")] -fn test_model_help_command() -> Result<(), Box> { - println!("πŸ” Testing /model --help command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/model --help")?; - - println!("πŸ“ Model help response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify description - assert!(response.contains("Select a model for the current conversation session"), "Missing model selection description"); - println!("βœ… Found model selection description"); - - // Verify Usage section - assert!(response.contains("Usage:"), "Missing Usage section"); - assert!(response.contains("/model"), "Missing /model command in usage section"); - println!("βœ… Found Usage section with /model command"); - - // Verify Options section - assert!(response.contains("Options:"), "Missing Options section"); - println!("βœ… Found Options section"); - - // Verify help flags - assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing -h, --help flags"); - assert!(response.contains("Print help"), "Missing Print help description"); - println!("βœ… Found help flags: -h, --help with Print help description"); - - println!("βœ… All model help content verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} diff --git a/e2etests/tests/test_subscribe_command.rs b/e2etests/tests/test_subscribe_command.rs index 88cf499cf0..45868486f0 100644 --- a/e2etests/tests/test_subscribe_command.rs +++ b/e2etests/tests/test_subscribe_command.rs @@ -1,13 +1,21 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] -#[cfg(feature = "integration")] -fn test_subscribe_command() -> Result<(), Box> { - println!("πŸ” Testing /subscribe command..."); - +#[cfg(feature = "subscribe")] +fn test_all_subscribe_commands() -> Result<(), Box> { let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); + println!(":white_check_mark: Q Chat session started"); + + test_subscribe_command(&mut chat)?; + test_subscribe_help_command(&mut chat)?; + chat.quit()?; + println!(":white_check_mark: All tests completed successfully"); + Ok(()) +} +fn test_subscribe_command(chat: &mut QChatSession) -> Result<(), Box> { + println!("πŸ” Testing /subscribe command..."); + let response = chat.execute_command("/subscribe")?; println!("πŸ“ Subscribe response: {} bytes", response.len()); @@ -16,13 +24,49 @@ fn test_subscribe_command() -> Result<(), Box> { println!("πŸ“ END OUTPUT"); // Verify subscription management message - assert!(response.contains("Your Q Developer Pro subscription is managed through IAM Identity Center"), "Missing subscription management message"); + assert!(response.contains("Q Developer Pro subscription") && response.contains("IAM Identity Center"), "Missing subscription management message"); println!("βœ… Found subscription management message"); println!("βœ… All subscribe content verified!"); + + + Ok(()) +} + +fn test_subscribe_help_command(chat: &mut QChatSession) -> Result<(), Box> { + println!("πŸ” Testing /subscribe --help command..."); + + let response = chat.execute_command("/subscribe --help")?; + + println!("πŸ“ Subscribe help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify description + assert!(response.contains("Q Developer Pro subscription"), "Missing subscription description"); + println!("βœ… Found subscription description"); + + // Verify Usage section + assert!(response.contains("Usage:"), "Missing Usage section"); + assert!(response.contains("/subscribe"), "Missing /subscribe command in usage section"); + assert!(response.contains("[OPTIONS]"), "Missing [OPTIONS] in usage section"); + println!("βœ… Found Usage section with /subscribe [OPTIONS]"); + + // Verify Options section + assert!(response.contains("Options:"), "Missing Options section"); + println!("βœ… Found Options section"); + + // Verify manage option + assert!(response.contains("--manage"), "Missing --manage option"); + println!("βœ… Found --manage option"); + + // Verify help flags + assert!(response.contains("-h") && response.contains("--help") , "Missing -h, --help flags"); + println!("βœ… Found help flags: -h, --help with Print help description"); + + println!("βœ… All subscribe help content verified!"); - chat.quit()?; - println!("βœ… Test completed successfully"); Ok(()) -} \ No newline at end of file +} diff --git a/e2etests/tests/test_subscribe_help_command.rs b/e2etests/tests/test_subscribe_help_command.rs deleted file mode 100644 index 19e2ccf8b6..0000000000 --- a/e2etests/tests/test_subscribe_help_command.rs +++ /dev/null @@ -1,47 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "integration")] -fn test_subscribe_help_command() -> Result<(), Box> { - println!("πŸ” Testing /subscribe --help command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/subscribe --help")?; - - println!("πŸ“ Subscribe help response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify description - assert!(response.contains("Upgrade to a Q Developer Pro subscription for increased query limits"), "Missing subscription description"); - println!("βœ… Found subscription description"); - - // Verify Usage section - assert!(response.contains("Usage:"), "Missing Usage section"); - assert!(response.contains("/subscribe"), "Missing /subscribe command in usage section"); - assert!(response.contains("[OPTIONS]"), "Missing [OPTIONS] in usage section"); - println!("βœ… Found Usage section with /subscribe [OPTIONS]"); - - // Verify Options section - assert!(response.contains("Options:"), "Missing Options section"); - println!("βœ… Found Options section"); - - // Verify manage option - assert!(response.contains("--manage"), "Missing --manage option"); - println!("βœ… Found --manage option"); - - // Verify help flags - assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing -h, --help flags"); - assert!(response.contains("Print help"), "Missing Print help description"); - println!("βœ… Found help flags: -h, --help with Print help description"); - - println!("βœ… All subscribe help content verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} \ No newline at end of file diff --git a/e2etests/tests/test_tools_command.rs b/e2etests/tests/test_tools_command.rs index c28b0810c1..e9ac088025 100644 --- a/e2etests/tests/test_tools_command.rs +++ b/e2etests/tests/test_tools_command.rs @@ -1,12 +1,28 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] -#[cfg(feature = "core_session")] -fn test_tools_command() -> Result<(), Box> { - println!("πŸ” Testing /tools command..."); - +#[cfg(feature = "tools")] +fn test_all_tools_commands() -> Result<(), Box> { let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); + println!(":white_check_mark: Q Chat session started"); + + test_tools_command(&mut chat)?; + test_tools_help_command(&mut chat)?; + test_tools_trust_all_command(&mut chat)?; + test_tools_trust_all_help_command(&mut chat)?; + test_tools_reset_help_command(&mut chat)?; + test_tools_trust_command(&mut chat)?; + test_tools_trust_help_command(&mut chat)?; + test_tools_untrust_help_command(&mut chat)?; + test_tools_schema_help_command(&mut chat)?; + test_tools_schema_command(&mut chat)?; + + chat.quit()?; + println!(":white_check_mark: All tests completed successfully"); + Ok(()) +} +fn test_tools_command(chat: &mut QChatSession) -> Result<(), Box> { + println!("πŸ” Testing /tools command..."); let response = chat.execute_command("/tools")?; @@ -45,9 +61,384 @@ fn test_tools_command() -> Result<(), Box> { println!("βœ… All tools content verified!"); println!("βœ… /tools command executed successfully"); + - chat.quit()?; - println!("βœ… Test completed successfully"); + Ok(()) +} + +fn test_tools_help_command(chat: &mut QChatSession) -> Result<(), Box> { + println!("πŸ” Testing /tools --help command..."); + + let response = chat.execute_command("/tools --help")?; + + println!("πŸ“ Tools help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + /* Verify description + assert!(response.contains("permission"), "Missing permission description"); + println!("βœ… Found tools permission description");*/ + + // Verify documentation reference + //assert!(response.contains("documentation"), "Missing documentation reference"); + assert!(response.contains("https://github.com/aws/amazon-q-developer-cli/blob/main/docs/agent-format.md#tools-field"), "Missing documentation URL"); + println!("βœ… Found documentation reference and URL"); + + // Verify Usage section + assert!(response.contains("Usage:") && response.contains("/tools") && response.contains("[COMMAND]"), "Missing Usage section"); + println!("βœ… Found usage format"); + println!("βœ… Found usage format"); + + // Verify Commands section + assert!(response.contains("Commands:"), "Missing Commands section"); + assert!(response.contains("schema"), "Missing schema command"); + assert!(response.contains("trust"), "Missing trust command"); + assert!(response.contains("untrust"), "Missing untrust command"); + assert!(response.contains("trust-all"), "Missing trust-all command"); + assert!(response.contains("reset"), "Missing reset command"); + assert!(response.contains("help"), "Missing help command"); + println!("βœ… Found all commands: schema, trust, untrust, trust-all, reset, help"); + + // Verify Options section + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("-h") && response.contains("--help"), "Missing -h, --help flags"); + println!("βœ… Found Options section with help flags"); + + println!("βœ… All tools help content verified!"); + + Ok(()) +} +fn test_tools_trust_all_command(chat: &mut QChatSession) -> Result<(), Box> { + println!("πŸ” Testing /tools trust-all command..."); + + // Execute trust-all command + let trust_all_response = chat.execute_command("/tools trust-all")?; + + println!("πŸ“ Trust-all response: {} bytes", trust_all_response.len()); + println!("πŸ“ TRUST-ALL OUTPUT:"); + println!("{}", trust_all_response); + println!("πŸ“ END TRUST-ALL OUTPUT"); + + /* Verify trust-all confirmation message + assert!(trust_all_response.contains("confirmation"), "Missing trust-all confirmation message"); + assert!(trust_all_response.contains("risk"), "Missing risk warning message");*/ + assert!(trust_all_response.contains("https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-chat-security.html#command-line-chat-trustall-safety"), "Missing documentation link"); + println!("βœ… Found documentation link"); + + // Now check tools list to verify all tools are trusted + let tools_response = chat.execute_command("/tools")?; + + println!("πŸ“ Tools response after trust-all: {} bytes", tools_response.len()); + println!("πŸ“ TOOLS OUTPUT:"); + println!("{}", tools_response); + println!("πŸ“ END TOOLS OUTPUT"); + + // Verify that all tools now show "trusted" permission + assert!(tools_response.contains("trusted"), "Missing trusted tools after trust-all"); + + // Verify no tools have other permission statuses + assert!(!tools_response.contains("not trusted"), "Found 'not trusted' tools after trust-all"); + assert!(!tools_response.contains("read-only commands"), "Found 'read-only commands' tools after trust-all"); + println!("βœ… Verified all tools are now trusted, no other permission statuses found"); + + // Count lines with "trusted" to ensure multiple tools are trusted + let trusted_count = tools_response.matches("trusted").count(); + assert!(trusted_count > 0, "No trusted tools found"); + println!("βœ… Found {} instances of 'trusted' in tools list", trusted_count); + + println!("βœ… All tools trust-all functionality verified!"); + + // Execute reset command + let reset_response = chat.execute_command("/tools reset")?; + + println!("πŸ“ Reset response: {} bytes", reset_response.len()); + println!("πŸ“ RESET OUTPUT:"); + println!("{}", reset_response); + println!("πŸ“ END RESET OUTPUT"); + + // Verify reset confirmation message + assert!(reset_response.contains("Reset") && reset_response.contains("permission"), "Missing reset confirmation message"); + println!("βœ… Found reset confirmation message"); + + // Now check tools list to verify tools have mixed permissions + let tools_response = chat.execute_command("/tools")?; + + println!("πŸ“ Tools response after reset: {} bytes", tools_response.len()); + println!("πŸ“ TOOLS OUTPUT:"); + println!("{}", tools_response); + println!("πŸ“ END TOOLS OUTPUT"); + + // Verify that tools have all permission types + assert!(tools_response.contains("trusted"), "Missing trusted tools"); + assert!(tools_response.contains("not trusted"), "Missing not trusted tools"); + assert!(tools_response.contains("read-only commands"), "Missing read-only commands tools"); + println!("βœ… Found all permission types after reset"); + + println!("βœ… All tools reset functionality verified!"); + + Ok(()) +} + +fn test_tools_trust_all_help_command(chat: &mut QChatSession) -> Result<(), Box> { + println!("πŸ” Testing /tools trust-all --help command..."); + + let response = chat.execute_command("/tools trust-all --help")?; + + println!("πŸ“ Tools trust-all help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + /* Verify command description + assert!(response.contains("Trust"), "Missing command description"); + println!("βœ… Found command description");*/ + + // Verify usage format + assert!(response.contains("Usage:") && response.contains("/tools trust-all"), "Missing usage format"); + println!("βœ… Found usage format"); + + // Verify options section + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing help option"); + println!("βœ… Found options section with help flag"); + + println!("βœ… All tools trust-all help functionality verified!"); + + Ok(()) +} + +fn test_tools_reset_help_command(chat: &mut QChatSession) -> Result<(), Box> { + println!("πŸ” Testing /tools reset --help command..."); + + let response = chat.execute_command("/tools reset --help")?; + + println!("πŸ“ Tools reset help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + /* Verify command description + assert!(response.contains("Reset"), "Missing command description"); + println!("βœ… Found command description");*/ + + // Verify usage format + assert!(response.contains("Usage:") && response.contains("/tools reset"), "Missing usage format"); + println!("βœ… Found usage format"); + + // Verify options section + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing help option"); + println!("βœ… Found options section with help flag"); + + println!("βœ… All tools reset help functionality verified!"); + + Ok(()) +} + +fn test_tools_trust_command(chat: &mut QChatSession) -> Result<(), Box> { + println!("πŸ” Testing /tools trust command..."); + + // First get list of tools to find one that's not trusted + let tools_response = chat.execute_command("/tools")?; + + println!("πŸ“ Tools response: {} bytes", tools_response.len()); + println!("πŸ“ TOOLS OUTPUT:"); + println!("{}", tools_response); + println!("πŸ“ END TOOLS OUTPUT"); + + // Find a tool that's not trusted + let mut untrusted_tool: Option = None; + + // Look for tools that are "not trusted" + let lines: Vec<&str> = tools_response.lines().collect(); + for line in lines { + if line.starts_with("- ") && line.contains("not trusted") { + // Extract tool name from the line (after "- ") + if let Some(tool_part) = line.strip_prefix("- ") { + let parts: Vec<&str> = tool_part.split_whitespace().collect(); + if let Some(tool_name) = parts.first() { + untrusted_tool = Some(tool_name.to_string()); + break; + } + } + } + } + + if let Some(tool_name) = untrusted_tool { + println!("βœ… Found untrusted tool: {}", tool_name); + + // Execute trust command + let trust_command = format!("/tools trust {}", tool_name); + let trust_response = chat.execute_command(&trust_command)?; + + println!("πŸ“ Trust response: {} bytes", trust_response.len()); + println!("πŸ“ TRUST OUTPUT:"); + println!("{}", trust_response); + println!("πŸ“ END TRUST OUTPUT"); + + // Verify trust confirmation message + assert!(trust_response.contains(&tool_name), "Missing trust confirmation message"); + println!("βœ… Found trust confirmation message for tool: {}", tool_name); + + // Execute untrust command + let untrust_command = format!("/tools untrust {}", tool_name); + let untrust_response = chat.execute_command(&untrust_command)?; + + println!("πŸ“ Untrust response: {} bytes", untrust_response.len()); + println!("πŸ“ UNTRUST OUTPUT:"); + println!("{}", untrust_response); + println!("πŸ“ END UNTRUST OUTPUT"); + + // Verify untrust confirmation message + let expected_untrust_message = format!("Tool '{}' is", tool_name); + assert!(untrust_response.contains(&expected_untrust_message), "Missing untrust confirmation message"); + println!("βœ… Found untrust confirmation message for tool: {}", tool_name); + + println!("βœ… All tools trust/untrust functionality verified!"); + } else { + println!("ℹ️ No untrusted tools found to test trust command"); + } + + Ok(()) +} + +fn test_tools_trust_help_command(chat: &mut QChatSession) -> Result<(), Box> { + println!("πŸ” Testing /tools trust --help command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/tools trust --help")?; + + println!("πŸ“ Tools trust help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + /* Verify command description + assert!(response.contains("Trust"), "Missing command description"); + println!("βœ… Found command description");*/ + + // Verify usage format + assert!(response.contains("Usage:") && response.contains("/tools trust") && response.contains(""), "Missing usage format"); + println!("βœ… Found usage format"); + + // Verify arguments section + assert!(response.contains("Arguments:") && response.contains(""), "Missing Arguments section"); + println!("βœ… Found arguments section"); + + // Verify options section + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("-h") && response.contains("--help"), "Missing help option"); + println!("βœ… Found options section with help flag"); + + println!("βœ… All tools trust help functionality verified!"); + + Ok(()) +} + +fn test_tools_untrust_help_command(chat: &mut QChatSession) -> Result<(), Box> { + println!("πŸ” Testing /tools untrust --help command..."); + + let response = chat.execute_command("/tools untrust --help")?; + + println!("πŸ“ Tools untrust help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + /* Verify command description + assert!(response.contains("Revert"), "Missing command description"); + println!("βœ… Found command description");*/ + + // Verify usage format + assert!(response.contains("Usage:") && response.contains("/tools untrust") && response.contains(""), "Missing usage format"); + println!("βœ… Found usage format"); + + // Verify arguments section + assert!(response.contains("Arguments:") && response.contains(""), "Missing Arguments section"); + println!("βœ… Found arguments section"); + + // Verify options section + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("-h") && response.contains("--help"), "Missing help option"); + println!("βœ… Found options section with help flag"); + + println!("βœ… All tools untrust help functionality verified!"); + + Ok(()) +} +fn test_tools_schema_help_command(chat: &mut QChatSession) -> Result<(), Box> { + println!("πŸ” Testing /tools schema --help command..."); + + let response = chat.execute_command("/tools schema --help")?; + + println!("πŸ“ Tools schema help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + /* Verify command description + assert!(response.contains("Show the input schema for all available tools"), "Missing command description"); + println!("βœ… Found command description");*/ + + // Verify usage format + assert!(response.contains("Usage:") && response.contains("/tools schema"), "Missing usage format"); + println!("βœ… Found usage format"); + + // Verify options section + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("-h") && response.contains("--help"), "Missing help option"); + println!("βœ… Found options section with help flag"); + + println!("βœ… All tools schema help functionality verified!"); + + Ok(()) +} + +fn test_tools_schema_command(chat: &mut QChatSession) -> Result<(), Box> { + println!("πŸ” Testing /tools schema command..."); + + let response = chat.execute_command("/tools schema")?; + + println!("πŸ“ Tools schema response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify JSON structure + assert!(response.contains("{") && response.contains("}"), "Missing JSON structure"); + println!("βœ… Found JSON structure"); + + // Verify core built-in tools + assert!(response.contains("fs_read") || response.contains("fs_write") || response.contains("execute_bash") || response.contains("use_aws"), "Missing tools"); + println!("βœ… Found core built-in tools"); + + // Verify tool structure elements + assert!(response.contains("name"), "Missing name field"); + assert!(response.contains("description"), "Missing description field"); + assert!(response.contains("input_schema"), "Missing input_schema field"); + assert!(response.contains("properties"), "Missing properties field"); + println!("βœ… Found required tool structure: name, description, input_schema, properties"); + + // Check for optional MCP/GitHub tools if present + if response.contains("download_files_from_github") { + println!("βœ… Found GitHub-related tools"); + } + if response.contains("consolidate_findings_to_csv") { + println!("βœ… Found analysis tools"); + } + if response.contains("gh_issue") { + println!("βœ… Found GitHub issue reporting tool"); + } + + // Verify schema structure for at least one tool + if response.contains("type") { + println!("βœ… Found proper schema type definitions"); + } + + println!("βœ… All tools schema content verified!"); Ok(()) } diff --git a/e2etests/tests/test_tools_help_command.rs b/e2etests/tests/test_tools_help_command.rs deleted file mode 100644 index d62c1e7696..0000000000 --- a/e2etests/tests/test_tools_help_command.rs +++ /dev/null @@ -1,66 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "tools")] -fn test_tools_help_command() -> Result<(), Box> { - println!("πŸ” Testing /tools --help command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/tools --help")?; - - println!("πŸ“ Tools help response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify description - assert!(response.contains("By default, Amazon Q will ask for your permission to use certain tools."), "Missing permission description"); - println!("βœ… Found tools permission description"); - - // Verify documentation reference - assert!(response.contains("Refer to the documentation for how to configure tools with your agent"), "Missing documentation reference"); - assert!(response.contains("https://github.com/aws/amazon-q-developer-cli/blob/main/docs/agent-format.md#tools-field"), "Missing documentation URL"); - println!("βœ… Found documentation reference and URL"); - - // Verify main description - assert!(response.contains("View tools and permissions"), "Missing main description"); - println!("βœ… Found main description"); - - // Verify Usage section - //assert!(response.contains("Usage: /tools [COMMAND]"), "Missing usage format"); - assert!(response.contains("Usage:") && response.contains("/tools") && response.contains("[COMMAND]"), "Missing Usage section"); - println!("βœ… Found usage format"); - println!("βœ… Found usage format"); - - // Verify Commands section - assert!(response.contains("Commands:"), "Missing Commands section"); - assert!(response.contains("schema"), "Missing schema command"); - assert!(response.contains("trust"), "Missing trust command"); - assert!(response.contains("untrust"), "Missing untrust command"); - assert!(response.contains("trust-all"), "Missing trust-all command"); - assert!(response.contains("reset"), "Missing reset command"); - assert!(response.contains("help"), "Missing help command"); - println!("βœ… Found all commands: schema, trust, untrust, trust-all, reset, help"); - - // Verify command descriptions - assert!(response.contains("Show the input schema for all available tools"), "Missing schema description"); - assert!(response.contains("Trust a specific tool or tools for the session"), "Missing trust description"); - assert!(response.contains("Revert a tool or tools to per-request confirmation"), "Missing untrust description"); - assert!(response.contains("Trust all tools (equivalent to deprecated /acceptall)"), "Missing trust-all description"); - assert!(response.contains("Reset all tools to default permission levels"), "Missing reset description"); - println!("βœ… Found all command descriptions"); - - // Verify Options section - assert!(response.contains("Options:"), "Missing Options section"); - assert!(response.contains("-h") && response.contains("--help"), "Missing -h, --help flags"); - println!("βœ… Found Options section with help flags"); - - println!("βœ… All tools help content verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} \ No newline at end of file diff --git a/e2etests/tests/test_tools_reset_command.rs b/e2etests/tests/test_tools_reset_command.rs deleted file mode 100644 index 7b31b010c8..0000000000 --- a/e2etests/tests/test_tools_reset_command.rs +++ /dev/null @@ -1,43 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "tools")] -fn test_tools_reset_command() -> Result<(), Box> { - println!("πŸ” Testing /tools reset command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - // Execute reset command - let reset_response = chat.execute_command("/tools reset")?; - - println!("πŸ“ Reset response: {} bytes", reset_response.len()); - println!("πŸ“ RESET OUTPUT:"); - println!("{}", reset_response); - println!("πŸ“ END RESET OUTPUT"); - - // Verify reset confirmation message - assert!(reset_response.contains("Reset all tools to the permission levels as defined in agent."), "Missing reset confirmation message"); - println!("βœ… Found reset confirmation message"); - - // Now check tools list to verify tools have mixed permissions - let tools_response = chat.execute_command("/tools")?; - - println!("πŸ“ Tools response after reset: {} bytes", tools_response.len()); - println!("πŸ“ TOOLS OUTPUT:"); - println!("{}", tools_response); - println!("πŸ“ END TOOLS OUTPUT"); - - // Verify that tools have all permission types - assert!(tools_response.contains("trusted"), "Missing trusted tools"); - assert!(tools_response.contains("not trusted"), "Missing not trusted tools"); - assert!(tools_response.contains("read-only commands"), "Missing read-only commands tools"); - println!("βœ… Found all permission types after reset"); - - println!("βœ… All tools reset functionality verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} \ No newline at end of file diff --git a/e2etests/tests/test_tools_reset_help_command.rs b/e2etests/tests/test_tools_reset_help_command.rs deleted file mode 100644 index 5cbd2590fd..0000000000 --- a/e2etests/tests/test_tools_reset_help_command.rs +++ /dev/null @@ -1,37 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "tools")] -fn test_tools_reset_help_command() -> Result<(), Box> { - println!("πŸ” Testing /tools reset --help command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/tools reset --help")?; - - println!("πŸ“ Tools reset help response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify command description - assert!(response.contains("Reset all tools to default permission levels"), "Missing command description"); - println!("βœ… Found command description"); - - // Verify usage format - assert!(response.contains("Usage:") && response.contains("/tools reset"), "Missing usage format"); - println!("βœ… Found usage format"); - - // Verify options section - assert!(response.contains("Options:"), "Missing Options section"); - assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing help option"); - println!("βœ… Found options section with help flag"); - - println!("βœ… All tools reset help functionality verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} \ No newline at end of file diff --git a/e2etests/tests/test_tools_schema_command.rs b/e2etests/tests/test_tools_schema_command.rs deleted file mode 100644 index 57703e1df9..0000000000 --- a/e2etests/tests/test_tools_schema_command.rs +++ /dev/null @@ -1,55 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "tools")] -fn test_tools_schema_command() -> Result<(), Box> { - println!("πŸ” Testing /tools schema command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/tools schema")?; - - println!("πŸ“ Tools schema response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify JSON structure - assert!(response.contains("{") && response.contains("}"), "Missing JSON structure"); - println!("βœ… Found JSON structure"); - - // Verify core built-in tools - assert!(response.contains("fs_read") || response.contains("fs_write") || response.contains("execute_bash") || response.contains("use_aws"), "Missing tools"); - println!("βœ… Found core built-in tools"); - - // Verify tool structure elements - assert!(response.contains("name"), "Missing name field"); - assert!(response.contains("description"), "Missing description field"); - assert!(response.contains("input_schema"), "Missing input_schema field"); - assert!(response.contains("properties"), "Missing properties field"); - println!("βœ… Found required tool structure: name, description, input_schema, properties"); - - // Check for optional MCP/GitHub tools if present - if response.contains("download_files_from_github") { - println!("βœ… Found GitHub-related tools"); - } - if response.contains("consolidate_findings_to_csv") { - println!("βœ… Found analysis tools"); - } - if response.contains("gh_issue") { - println!("βœ… Found GitHub issue reporting tool"); - } - - // Verify schema structure for at least one tool - if response.contains("type") { - println!("βœ… Found proper schema type definitions"); - } - - println!("βœ… All tools schema content verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} diff --git a/e2etests/tests/test_tools_schema_help_command.rs b/e2etests/tests/test_tools_schema_help_command.rs deleted file mode 100644 index e1c9b54eb2..0000000000 --- a/e2etests/tests/test_tools_schema_help_command.rs +++ /dev/null @@ -1,37 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "tools")] -fn test_tools_schema_help_command() -> Result<(), Box> { - println!("πŸ” Testing /tools schema --help command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/tools schema --help")?; - - println!("πŸ“ Tools schema help response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify command description - assert!(response.contains("Show the input schema for all available tools"), "Missing command description"); - println!("βœ… Found command description"); - - // Verify usage format - assert!(response.contains("Usage:") && response.contains("/tools schema"), "Missing usage format"); - println!("βœ… Found usage format"); - - // Verify options section - assert!(response.contains("Options:"), "Missing Options section"); - assert!(response.contains("-h") && response.contains("--help")&& response.contains("Print help"), "Missing help option"); - println!("βœ… Found options section with help flag"); - - println!("βœ… All tools schema help functionality verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} \ No newline at end of file diff --git a/e2etests/tests/test_tools_trust_all_command.rs b/e2etests/tests/test_tools_trust_all_command.rs deleted file mode 100644 index b17ed8afb5..0000000000 --- a/e2etests/tests/test_tools_trust_all_command.rs +++ /dev/null @@ -1,52 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "tools")] -fn test_tools_trust_all_command() -> Result<(), Box> { - println!("πŸ” Testing /tools trust-all command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - // Execute trust-all command - let trust_all_response = chat.execute_command("/tools trust-all")?; - - println!("πŸ“ Trust-all response: {} bytes", trust_all_response.len()); - println!("πŸ“ TRUST-ALL OUTPUT:"); - println!("{}", trust_all_response); - println!("πŸ“ END TRUST-ALL OUTPUT"); - - // Verify trust-all confirmation message - assert!(trust_all_response.contains("asking for confirmation"), "Missing trust-all confirmation message"); - assert!(trust_all_response.contains("Agents can sometimes do unexpected things so understand the risks."), "Missing risk warning message"); - assert!(trust_all_response.contains("Learn more at https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-chat-security.html#command-line-chat-trustall-safety"), "Missing documentation link"); - println!("βœ… Found trust-all confirmation, risk warning, and documentation link"); - - // Now check tools list to verify all tools are trusted - let tools_response = chat.execute_command("/tools")?; - - println!("πŸ“ Tools response after trust-all: {} bytes", tools_response.len()); - println!("πŸ“ TOOLS OUTPUT:"); - println!("{}", tools_response); - println!("πŸ“ END TOOLS OUTPUT"); - - // Verify that all tools now show "trusted" permission - assert!(tools_response.contains("trusted"), "Missing trusted tools after trust-all"); - - // Verify no tools have other permission statuses - assert!(!tools_response.contains("not trusted"), "Found 'not trusted' tools after trust-all"); - assert!(!tools_response.contains("read-only commands"), "Found 'read-only commands' tools after trust-all"); - println!("βœ… Verified all tools are now trusted, no other permission statuses found"); - - // Count lines with "trusted" to ensure multiple tools are trusted - let trusted_count = tools_response.matches("trusted").count(); - assert!(trusted_count > 0, "No trusted tools found"); - println!("βœ… Found {} instances of 'trusted' in tools list", trusted_count); - - println!("βœ… All tools trust-all functionality verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} \ No newline at end of file diff --git a/e2etests/tests/test_tools_trust_all_help_command.rs b/e2etests/tests/test_tools_trust_all_help_command.rs deleted file mode 100644 index ac35496108..0000000000 --- a/e2etests/tests/test_tools_trust_all_help_command.rs +++ /dev/null @@ -1,37 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "tools")] -fn test_tools_trust_all_help_command() -> Result<(), Box> { - println!("πŸ” Testing /tools trust-all --help command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/tools trust-all --help")?; - - println!("πŸ“ Tools trust-all help response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify command description - assert!(response.contains("Trust all tools") && response.contains("equivalent to deprecated /acceptall"), "Missing command description"); - println!("βœ… Found command description"); - - // Verify usage format - assert!(response.contains("Usage:") && response.contains("/tools trust-all"), "Missing usage format"); - println!("βœ… Found usage format"); - - // Verify options section - assert!(response.contains("Options:"), "Missing Options section"); - assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing help option"); - println!("βœ… Found options section with help flag"); - - println!("βœ… All tools trust-all help functionality verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} \ No newline at end of file diff --git a/e2etests/tests/test_tools_trust_command.rs b/e2etests/tests/test_tools_trust_command.rs deleted file mode 100644 index f05b9450fd..0000000000 --- a/e2etests/tests/test_tools_trust_command.rs +++ /dev/null @@ -1,76 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "tools")] -fn test_tools_trust_command() -> Result<(), Box> { - println!("πŸ” Testing /tools trust command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - // First get list of tools to find one that's not trusted - let tools_response = chat.execute_command("/tools")?; - - println!("πŸ“ Tools response: {} bytes", tools_response.len()); - println!("πŸ“ TOOLS OUTPUT:"); - println!("{}", tools_response); - println!("πŸ“ END TOOLS OUTPUT"); - - // Find a tool that's not trusted - let mut untrusted_tool: Option = None; - - // Look for tools that are "not trusted" - let lines: Vec<&str> = tools_response.lines().collect(); - for line in lines { - if line.starts_with("- ") && line.contains("not trusted") { - // Extract tool name from the line (after "- ") - if let Some(tool_part) = line.strip_prefix("- ") { - let parts: Vec<&str> = tool_part.split_whitespace().collect(); - if let Some(tool_name) = parts.first() { - untrusted_tool = Some(tool_name.to_string()); - break; - } - } - } - } - - if let Some(tool_name) = untrusted_tool { - println!("βœ… Found untrusted tool: {}", tool_name); - - // Execute trust command - let trust_command = format!("/tools trust {}", tool_name); - let trust_response = chat.execute_command(&trust_command)?; - - println!("πŸ“ Trust response: {} bytes", trust_response.len()); - println!("πŸ“ TRUST OUTPUT:"); - println!("{}", trust_response); - println!("πŸ“ END TRUST OUTPUT"); - - // Verify trust confirmation message - assert!(trust_response.contains(&tool_name), "Missing trust confirmation message"); - println!("βœ… Found trust confirmation message for tool: {}", tool_name); - - // Execute untrust command - let untrust_command = format!("/tools untrust {}", tool_name); - let untrust_response = chat.execute_command(&untrust_command)?; - - println!("πŸ“ Untrust response: {} bytes", untrust_response.len()); - println!("πŸ“ UNTRUST OUTPUT:"); - println!("{}", untrust_response); - println!("πŸ“ END UNTRUST OUTPUT"); - - // Verify untrust confirmation message - let expected_untrust_message = format!("Tool '{}' is set to per-request confirmation.", tool_name); - assert!(untrust_response.contains(&expected_untrust_message), "Missing untrust confirmation message"); - println!("βœ… Found untrust confirmation message for tool: {}", tool_name); - - println!("βœ… All tools trust/untrust functionality verified!"); - } else { - println!("ℹ️ No untrusted tools found to test trust command"); - } - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} \ No newline at end of file diff --git a/e2etests/tests/test_tools_trust_help_command.rs b/e2etests/tests/test_tools_trust_help_command.rs deleted file mode 100644 index 695fd00060..0000000000 --- a/e2etests/tests/test_tools_trust_help_command.rs +++ /dev/null @@ -1,41 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "tools")] -fn test_tools_trust_help_command() -> Result<(), Box> { - println!("πŸ” Testing /tools trust --help command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/tools trust --help")?; - - println!("πŸ“ Tools trust help response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify command description - assert!(response.contains("Trust a specific tool or tools for the session"), "Missing command description"); - println!("βœ… Found command description"); - - // Verify usage format - assert!(response.contains("Usage:") && response.contains("/tools trust") && response.contains("..."), "Missing usage format"); - println!("βœ… Found usage format"); - - // Verify arguments section - assert!(response.contains("Arguments:") && response.contains("..."), "Missing Arguments section"); - println!("βœ… Found arguments section"); - - // Verify options section - assert!(response.contains("Options:"), "Missing Options section"); - assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing help option"); - println!("βœ… Found options section with help flag"); - - println!("βœ… All tools trust help functionality verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} \ No newline at end of file diff --git a/e2etests/tests/test_tools_untrust_help_command.rs b/e2etests/tests/test_tools_untrust_help_command.rs deleted file mode 100644 index d4ed65a7a9..0000000000 --- a/e2etests/tests/test_tools_untrust_help_command.rs +++ /dev/null @@ -1,41 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "tools")] -fn test_tools_untrust_help_command() -> Result<(), Box> { - println!("πŸ” Testing /tools untrust --help command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/tools untrust --help")?; - - println!("πŸ“ Tools untrust help response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify command description - assert!(response.contains("Revert a tool or tools to per-request confirmation"), "Missing command description"); - println!("βœ… Found command description"); - - // Verify usage format - assert!(response.contains("Usage:") && response.contains("/tools untrust") && response.contains("..."), "Missing usage format"); - println!("βœ… Found usage format"); - - // Verify arguments section - assert!(response.contains("Arguments:") && response.contains("..."), "Missing Arguments section"); - println!("βœ… Found arguments section"); - - // Verify options section - assert!(response.contains("Options:"), "Missing Options section"); - assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing help option"); - println!("βœ… Found options section with help flag"); - - println!("βœ… All tools untrust help functionality verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} \ No newline at end of file diff --git a/e2etests/tests/test_usage_command.rs b/e2etests/tests/test_usage_command.rs index 2d8bc02741..824afb3800 100644 --- a/e2etests/tests/test_usage_command.rs +++ b/e2etests/tests/test_usage_command.rs @@ -1,8 +1,19 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] -#[cfg(feature = "session_mgmt")] -fn test_usage_command() -> Result<(), Box> { +#[cfg(feature = "usage")] +fn test_all_usage_commands() -> Result<(), Box> { + let mut chat = QChatSession::new()?; + println!(":white_check_mark: Q Chat session started"); + + test_usage_command(&mut chat)?; + test_usage_help_command(&mut chat)?; + + chat.quit()?; + println!(":white_check_mark: All tests completed successfully"); + Ok(()) +} +fn test_usage_command(chat: &mut QChatSession) -> Result<(), Box> { println!("πŸ” Testing /usage command..."); let mut chat = QChatSession::new()?; @@ -17,7 +28,7 @@ fn test_usage_command() -> Result<(), Box> { // Verify context window information assert!(response.contains("Current context window"), "Missing context window header"); - assert!(response.contains("tokens used"), "Missing tokens used information"); + assert!(response.contains("tokens"), "Missing tokens used information"); println!("βœ… Found context window and token usage information"); // Verify progress bar @@ -46,16 +57,48 @@ fn test_usage_command() -> Result<(), Box> { assert!(response.contains("/context show"), "Missing /context show command tip"); println!("βœ… Found all command tips: /compact, /clear, /context show"); - // Verify tip descriptions - assert!(response.contains("replace the conversation history with its summary"), "Missing /compact description"); - assert!(response.contains("erase the entire chat history"), "Missing /clear description"); - assert!(response.contains("see tokens per context file"), "Missing /context show description"); - println!("βœ… Verified all tip descriptions"); - println!("βœ… All usage content verified!"); chat.quit()?; println!("βœ… Test completed successfully"); + Ok(()) +} + +fn test_usage_help_command(chat: &mut QChatSession) -> Result<(), Box> { + println!("πŸ” Testing /usage --help command..."); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + let response = chat.execute_command("/usage --help")?; + + println!("πŸ“ Usage help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + /* Verify description + assert!(response.contains("context window ") && response.contains("usage"), "Missing usage command description"); + println!("βœ… Found usage command description");*/ + + // Verify Usage section + assert!(response.contains("Usage:"), "Missing Usage section"); + assert!(response.contains("/usage"), "Missing /usage command in usage section"); + println!("βœ… Found Usage section with /usage command"); + + // Verify Options section + assert!(response.contains("Options:"), "Missing Options section"); + println!("βœ… Found Options section"); + + // Verify help flags + assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing -h, --help flags"); + println!("βœ… Found help flags: -h, --help with description"); + + println!("βœ… All usage help content verified!"); + + chat.quit()?; + println!("βœ… Test completed successfully"); + Ok(()) } \ No newline at end of file diff --git a/e2etests/tests/test_usage_help_command.rs b/e2etests/tests/test_usage_help_command.rs deleted file mode 100644 index 459f2e0fc5..0000000000 --- a/e2etests/tests/test_usage_help_command.rs +++ /dev/null @@ -1,41 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "session_mgmt")] -fn test_usage_help_command() -> Result<(), Box> { - println!("πŸ” Testing /usage --help command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/usage --help")?; - - println!("πŸ“ Usage help response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify description - assert!(response.contains("Show current session's context window usage"), "Missing usage command description"); - println!("βœ… Found usage command description"); - - // Verify Usage section - assert!(response.contains("Usage:"), "Missing Usage section"); - assert!(response.contains("/usage"), "Missing /usage command in usage section"); - println!("βœ… Found Usage section with /usage command"); - - // Verify Options section - assert!(response.contains("Options:"), "Missing Options section"); - println!("βœ… Found Options section"); - - // Verify help flags - assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing -h, --help flags"); - println!("βœ… Found help flags: -h, --help with description"); - - println!("βœ… All usage help content verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} \ No newline at end of file From 27a66b8160d493e84126cc472ed1ed7701496826 Mon Sep 17 00:00:00 2001 From: Abhishek Anne Date: Tue, 19 Aug 2025 19:47:48 +0530 Subject: [PATCH 16/77] QCLI Test automation - merged agent feature test into one --- e2etests/tests/agent_without_subcommand.rs | 55 --- e2etests/tests/test_agent_commands.rs | 450 ++++++++++++++++++ e2etests/tests/test_agent_create_command.rs | 70 --- .../tests/test_agent_create_missing_args.rs | 59 --- e2etests/tests/test_agent_help_command.rs | 56 --- e2etests/tests/test_agent_invalid_command.rs | 50 -- e2etests/tests/test_agent_list_command.rs | 37 -- e2etests/tests/test_agent_schema_command.rs | 58 --- .../tests/test_agent_set_default_command.rs | 40 -- .../test_agent_set_default_missing_args.rs | 49 -- 10 files changed, 450 insertions(+), 474 deletions(-) delete mode 100644 e2etests/tests/agent_without_subcommand.rs create mode 100644 e2etests/tests/test_agent_commands.rs delete mode 100644 e2etests/tests/test_agent_create_command.rs delete mode 100644 e2etests/tests/test_agent_create_missing_args.rs delete mode 100644 e2etests/tests/test_agent_help_command.rs delete mode 100644 e2etests/tests/test_agent_invalid_command.rs delete mode 100644 e2etests/tests/test_agent_list_command.rs delete mode 100644 e2etests/tests/test_agent_schema_command.rs delete mode 100644 e2etests/tests/test_agent_set_default_command.rs delete mode 100644 e2etests/tests/test_agent_set_default_missing_args.rs diff --git a/e2etests/tests/agent_without_subcommand.rs b/e2etests/tests/agent_without_subcommand.rs deleted file mode 100644 index b8e9c30be7..0000000000 --- a/e2etests/tests/agent_without_subcommand.rs +++ /dev/null @@ -1,55 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "agent")] -fn agent_without_subcommand() -> Result<(), Box> { - println!("πŸ” Testing /agent command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/agent")?; - - println!("πŸ“ Agent response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify agent command structure - assert!(response.contains("Manage agents"), "Missing 'Manage agents' description"); - assert!(response.contains("Usage:"), "Missing usage information"); - assert!(response.contains("/agent"), "Missing agent command"); - assert!(response.contains(""), "Missing command placeholder"); - println!("βœ… Found agent command description and usage"); - - // Verify subcommands - assert!(response.contains("Commands:"), "Missing Commands section"); - assert!(response.contains("list"), "Missing list subcommand"); - assert!(response.contains("create"), "Missing create subcommand"); - assert!(response.contains("schema"), "Missing schema subcommand"); - assert!(response.contains("set-default"), "Missing set-default subcommand"); - assert!(response.contains("help"), "Missing help subcommand"); - println!("βœ… Verified all agent subcommands: list, create, schema, set-default, help"); - - // Verify command descriptions - assert!(response.contains("List all available agents"), "Missing list command description"); - assert!(response.contains("Create a new agent"), "Missing create command description"); - assert!(response.contains("Show agent config schema"), "Missing schema command description"); - assert!(response.contains("Define a default agent"), "Missing set-default command description"); - println!("βœ… Verified command descriptions"); - - // Verify options section - assert!(response.contains("Options:"), "Missing Options section"); - assert!(response.contains("-h"), "Missing short help option"); - assert!(response.contains("--help"), "Missing long help option"); - println!("βœ… Found options section with help flag"); - - println!("βœ… All agent command content verified!"); - - println!("βœ… /agent command executed successfully"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} \ No newline at end of file diff --git a/e2etests/tests/test_agent_commands.rs b/e2etests/tests/test_agent_commands.rs new file mode 100644 index 0000000000..6e0d920e79 --- /dev/null +++ b/e2etests/tests/test_agent_commands.rs @@ -0,0 +1,450 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; +use std::sync::{Mutex, Once, atomic::{AtomicUsize, Ordering}}; + +static INIT: Once = Once::new(); +static mut CHAT_SESSION: Option> = None; +static TEST_COUNT: AtomicUsize = AtomicUsize::new(0); +static TOTAL_TESTS: usize = 8; // Updated for active tests + +fn get_chat_session() -> &'static Mutex { + unsafe { + INIT.call_once(|| { + let chat = QChatSession::new().expect("Failed to create chat session"); + println!("βœ… Q Chat session started"); + CHAT_SESSION = Some(Mutex::new(chat)); + }); + CHAT_SESSION.as_ref().unwrap() + } +} + +fn cleanup_if_last_test() -> Result<(), Box> { + let count = TEST_COUNT.fetch_add(1, Ordering::SeqCst) + 1; + if count == TOTAL_TESTS { + unsafe { + if let Some(session) = &CHAT_SESSION { + if let Ok(mut chat) = session.lock() { + chat.quit()?; + println!("βœ… Test completed successfully"); + } + } + } + } + Ok(()) +} + +#[test] +#[cfg(feature = "agent")] +fn agent_without_subcommand() -> Result<(), Box> { + println!("πŸ” Testing /agent command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + + let response = chat.execute_command("/agent")?; + + println!("πŸ“ Agent response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + assert!(response.contains("Manage agents"), "Missing 'Manage agents' description"); + assert!(response.contains("Usage:"), "Missing usage information"); + assert!(response.contains("/agent"), "Missing agent command"); + assert!(response.contains(""), "Missing command placeholder"); + println!("βœ… Found agent command description and usage"); + + assert!(response.contains("Commands:"), "Missing Commands section"); + assert!(response.contains("list"), "Missing list subcommand"); + assert!(response.contains("create"), "Missing create subcommand"); + assert!(response.contains("schema"), "Missing schema subcommand"); + assert!(response.contains("set-default"), "Missing set-default subcommand"); + assert!(response.contains("help"), "Missing help subcommand"); + println!("βœ… Verified all agent subcommands: list, create, schema, set-default, help"); + + assert!(response.contains("List all available agents"), "Missing list command description"); + assert!(response.contains("Create a new agent"), "Missing create command description"); + assert!(response.contains("Show agent config schema"), "Missing schema command description"); + assert!(response.contains("Define a default agent"), "Missing set-default command description"); + println!("βœ… Verified command descriptions"); + + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("-h"), "Missing short help option"); + assert!(response.contains("--help"), "Missing long help option"); + println!("βœ… Found options section with help flag"); + + println!("βœ… /agent command executed successfully"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test()?; + + Ok(()) +} + +#[test] +#[cfg(feature = "agent")] +fn test_agent_create_command() -> Result<(), Box> { + println!("πŸ” Testing /agent create --name command..."); + + let timestamp = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_secs(); + let agent_name = format!("test_demo_agent_{}", timestamp); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + + let create_response = chat.execute_command(&format!("/agent create --name {}", agent_name))?; + + println!("πŸ“ Agent create response: {} bytes", create_response.len()); + println!("πŸ“ CREATE RESPONSE:"); + println!("{}", create_response); + println!("πŸ“ END CREATE RESPONSE"); + + let save_response = chat.execute_command(":wq")?; + + println!("πŸ“ Save response: {} bytes", save_response.len()); + println!("πŸ“ SAVE RESPONSE:"); + println!("{}", save_response); + println!("πŸ“ END SAVE RESPONSE"); + + assert!(save_response.contains("Agent") && save_response.contains(&agent_name) && save_response.contains("has been created successfully"), "Missing agent creation success message"); + println!("βœ… Found agent creation success message"); + + let whoami_response = chat.execute_command("!whoami")?; + + println!("πŸ“ Whoami response: {} bytes", whoami_response.len()); + println!("πŸ“ WHOAMI RESPONSE:"); + println!("{}", whoami_response); + println!("πŸ“ END WHOAMI RESPONSE"); + + let lines: Vec<&str> = whoami_response.lines().collect(); + let username = lines.iter() + .find(|line| !line.starts_with("!") && !line.starts_with(">") && !line.trim().is_empty()) + .unwrap_or(&"shrebhaa") + .trim(); + println!("βœ… Current username: {}", username); + + let agent_path = format!("/Users/{}/.aws/amazonq/cli-agents/{}.json", username, agent_name); + println!("βœ… Agent path: {}", agent_path); + + if std::path::Path::new(&agent_path).exists() { + std::fs::remove_file(&agent_path)?; + println!("βœ… Agent file deleted: {}", agent_path); + } else { + println!("⚠️ Agent file not found at: {}", agent_path); + } + + assert!(!std::path::Path::new(&agent_path).exists(), "Agent file should be deleted"); + println!("βœ… Agent deletion verified"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test()?; + + Ok(()) +} + +#[test] +#[cfg(feature = "agent")] +fn test_agent_create_missing_args() -> Result<(), Box> { + println!("πŸ” Testing /agent create without required arguments..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + + let response = chat.execute_command("/agent create")?; + + println!("πŸ“ Agent create missing args response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + assert!(response.contains("error:"), "Missing error message part 1a"); + assert!(response.contains("the following required arguments"), "Missing error message part 1b"); + assert!(response.contains("were not provided:"), "Missing error message part 2"); + assert!(response.contains("--name"), "Missing required name argument part 1"); + assert!(response.contains(""), "Missing required name argument part 2"); + println!("βœ… Found error message for missing required arguments"); + + assert!(response.contains("Usage:"), "Missing usage information part 1"); + assert!(response.contains("/agent create"), "Missing usage information part 2a"); + assert!(response.contains("--name "), "Missing usage information part 2b"); + println!("βœ… Found usage information"); + + assert!(response.contains("For more information"), "Missing help suggestion part 1"); + assert!(response.contains("try"), "Missing help suggestion part 2a"); + println!("βœ… Found help suggestion"); + + assert!(response.contains("Options:"), "Missing options section"); + assert!(response.contains(""), "Missing name option part 2"); + assert!(response.contains("Name of the agent to be created"), "Missing name description"); + assert!(response.contains(""), "Missing directory option part 2"); + assert!(response.contains(""), "Missing from option part 2"); + println!("βœ… Found all expected options"); + + println!("βœ… /agent create executed successfully with expected error for missing arguments"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test()?; + + Ok(()) +} + +#[test] +#[cfg(feature = "agent")] +fn test_agent_help_command() -> Result<(), Box> { + println!("πŸ” Testing /agent help..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + + let response = chat.execute_command("/agent help")?; + + println!("πŸ“ Agent help command response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + let mut failures = Vec::new(); + + if !response.contains("Agents allow you to organize") { failures.push("Missing description"); } + if !response.contains("manage different sets of context") { failures.push("Missing context description"); } + if !response.contains("Notes") { failures.push("Missing notes section"); } + if !response.contains("Launch q chat with a specific agent") { failures.push("Missing launch note"); } + if !response.contains("--agent") { failures.push("Missing agent flag"); } + if !response.contains("Construct an agent under") { failures.push("Missing construct note"); } + if !response.contains("~/.aws/amazonq/cli-agents/") { failures.push("Missing global path"); } + if !response.contains("cwd/.aws/amazonq/cli-agents") { failures.push("Missing workspace path"); } + if !response.contains("Manage agents") { failures.push("Missing manage section"); } + if !response.contains("Usage:") { failures.push("Missing usage label"); } + if !response.contains("/agent") { failures.push("Missing agent command"); } + if !response.contains("") { failures.push("Missing command parameter"); } + if !response.contains("Commands:") { failures.push("Missing commands section"); } + if !response.contains("list") { failures.push("Missing list command"); } + if !response.contains("create") { failures.push("Missing create command"); } + if !response.contains("schema") { failures.push("Missing schema command"); } + if !response.contains("set-default") { failures.push("Missing set-default command"); } + if !response.contains("help") { failures.push("Missing help command"); } + if !response.contains("Options:") { failures.push("Missing options section"); } + if !response.contains("-h") { failures.push("Missing short help flag"); } + if !response.contains("--help") { failures.push("Missing long help flag"); } + + if !failures.is_empty() { + panic!("Test failures: {}", failures.join(", ")); + } + + println!("βœ… All expected help content found"); + println!("βœ… /agent help executed successfully"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test()?; + + Ok(()) +} + +#[test] +#[cfg(feature = "agent")] +fn test_agent_invalid_command() -> Result<(), Box> { + println!("πŸ” Testing /agent invalidcommand..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + + let response = chat.execute_command("/agent invalidcommand")?; + + println!("πŸ“ Agent invalid command response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + assert!(response.contains("Commands:"), "Missing commands section"); + assert!(response.contains("list"), "Missing list command"); + assert!(response.contains("create"), "Missing create command"); + assert!(response.contains("schema"), "Missing schema command"); + assert!(response.contains("set-default"), "Missing set-default command"); + assert!(response.contains("help"), "Missing help command"); + println!("βœ… Found all expected commands in help output"); + + assert!(response.contains("Options:"), "Missing options section"); + println!("βœ… Found options section"); + + println!("βœ… /agent invalidcommand executed successfully with expected error"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test()?; + + Ok(()) +} + +#[test] +#[cfg(feature = "agent")] +fn test_agent_list_command() -> Result<(), Box> { + println!("πŸ” Testing /agent list command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + + let response = chat.execute_command("/agent list")?; + + println!("πŸ“ Agent list response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + assert!(response.contains("q_cli_default"), "Missing q_cli_default agent"); + println!("βœ… Found q_cli_default agent in list"); + + assert!(response.contains("* q_cli_default"), "Missing bullet point format for q_cli_default"); + println!("βœ… Verified bullet point format for agent list"); + + println!("βœ… /agent list command executed successfully"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test()?; + + Ok(()) +} + +// #[test] +// #[cfg(feature = "agent")] +// fn test_agent_schema_command() -> Result<(), Box> { +// println!("πŸ” Testing /agent schema..."); + +// let session = get_chat_session(); +// let mut chat = session.lock().unwrap(); + +// let response = chat.execute_command("/agent schema")?; + +// println!("πŸ“ Agent schema response: {} bytes", response.len()); +// println!("πŸ“ FULL OUTPUT:"); +// println!("{}", response); +// println!("πŸ“ END OUTPUT"); + +// let mut failures = Vec::new(); + +// if !response.contains("$schema") { failures.push("Missing $schema key"); } +// if !response.contains("title") { failures.push("Missing title key"); } +// if !response.contains("description") { failures.push("Missing description key"); } +// if !response.contains("type") { failures.push("Missing type key"); } +// if !response.contains("properties") { failures.push("Missing properties key"); } + +// if !failures.is_empty() { +// panic!("Test failures: {}", failures.join(", ")); +// } + +// println!("βœ… Found all expected JSON schema keys and properties"); +// println!("βœ… /agent schema executed successfully with valid JSON schema"); + +// // Release the lock before cleanup +// drop(chat); + +// // Cleanup only if this is the last test +// cleanup_if_last_test()?; + +// Ok(()) +// } + +#[test] +#[cfg(feature = "agent")] +fn test_agent_set_default_command() -> Result<(), Box> { + println!("πŸ” Testing /agent set-default with valid arguments..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + + let response = chat.execute_command("/agent set-default -n q_cli_default")?; + + println!("πŸ“ Agent set-default command response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + let mut failures = Vec::new(); + + if !response.contains("βœ“") { failures.push("Missing success checkmark"); } + if !response.contains("Default agent set to") { failures.push("Missing success message"); } + if !response.contains("q_cli_default") { failures.push("Missing agent name"); } + if !response.contains("This will take effect") { failures.push("Missing effect message"); } + if !response.contains("next time q chat is launched") { failures.push("Missing launch message"); } + + if !failures.is_empty() { + panic!("Test failures: {}", failures.join(", ")); + } + + println!("βœ… All expected success messages found"); + println!("βœ… /agent set-default executed successfully with valid arguments"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test()?; + + Ok(()) +} + +#[test] +#[cfg(feature = "agent")] +fn test_agent_set_default_missing_args() -> Result<(), Box> { + println!("πŸ” Testing /agent set-default without required arguments..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + + let response = chat.execute_command("/agent set-default")?; + + println!("πŸ“ Agent set-default missing args response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + let mut failures = Vec::new(); + + if !response.contains("error") { failures.push("Missing error message"); } + if !response.contains("the following required arguments were not provided:") { failures.push("Missing error message2"); } + if !response.contains("--name ") { failures.push("Missing required name argument"); } + if !response.contains("Usage:") { failures.push("Missing usage text"); } + if !response.contains("/agent") { failures.push("Missing agent command"); } + if !response.contains("set-default") { failures.push("Missing set-default subcommand"); } + if !response.contains("--name") { failures.push("Missing name flag"); } + if !response.contains("For more information") { failures.push("Missing help text"); } + if !response.contains("--help") { failures.push("Missing help flag"); } + if !response.contains("Options:") { failures.push("Missing options section"); } + if !response.contains("-n") { failures.push("Missing short name flag"); } + if !response.contains("") { failures.push("Missing name parameter"); } + if !response.contains("-h") { failures.push("Missing short help flag"); } + if !response.contains("Print help") { failures.push("Missing help description"); } + + if !failures.is_empty() { + panic!("Test failures: {}", failures.join(", ")); + } + + println!("βœ… All expected error messages and options found"); + println!("βœ… /agent set-default executed successfully with expected error for missing arguments"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test()?; + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_agent_create_command.rs b/e2etests/tests/test_agent_create_command.rs deleted file mode 100644 index 06e4203063..0000000000 --- a/e2etests/tests/test_agent_create_command.rs +++ /dev/null @@ -1,70 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "agent")] -fn test_agent_create_command() -> Result<(), Box> { - println!("πŸ” Testing /agent create --name command..."); - - let agent_name = "test_demo_agent"; - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - // Create agent - let create_response = chat.execute_command(&format!("/agent create --name {}", agent_name))?; - - println!("πŸ“ Agent create response: {} bytes", create_response.len()); - println!("πŸ“ CREATE RESPONSE:"); - println!("{}", create_response); - println!("πŸ“ END CREATE RESPONSE"); - - // Save and exit editor - let save_response = chat.execute_command(":wq")?; - - println!("πŸ“ Save response: {} bytes", save_response.len()); - println!("πŸ“ SAVE RESPONSE:"); - println!("{}", save_response); - println!("πŸ“ END SAVE RESPONSE"); - - // Verify agent creation success message - assert!(save_response.contains("Agent") && save_response.contains(agent_name) && save_response.contains("has been created successfully"), "Missing agent creation success message"); - println!("βœ… Found agent creation success message"); - - // Get current username using !whoami in Q CLI - let whoami_response = chat.execute_command("!whoami")?; - - println!("πŸ“ Whoami response: {} bytes", whoami_response.len()); - println!("πŸ“ WHOAMI RESPONSE:"); - println!("{}", whoami_response); - println!("πŸ“ END WHOAMI RESPONSE"); - - // Extract username from response (parse the actual username from Q CLI output) - let lines: Vec<&str> = whoami_response.lines().collect(); - let username = lines.iter() - .find(|line| !line.starts_with("!") && !line.starts_with(">") && !line.trim().is_empty()) - .unwrap_or(&"shrebhaa") - .trim(); - println!("βœ… Current username: {}", username); - - chat.quit()?; - - // Construct agent path dynamically - let agent_path = format!("/Users/{}/.aws/amazonq/cli-agents/{}.json", username, agent_name); - println!("βœ… Agent path: {}", agent_path); - - // Delete the agent file if it exists - if std::path::Path::new(&agent_path).exists() { - std::fs::remove_file(&agent_path)?; - println!("βœ… Agent file deleted: {}", agent_path); - } else { - println!("⚠️ Agent file not found at: {}", agent_path); - } - - // Verify agent file was deleted - assert!(!std::path::Path::new(&agent_path).exists(), "Agent file should be deleted"); - println!("βœ… Agent deletion verified"); - - println!("βœ… Test completed successfully"); - - Ok(()) -} diff --git a/e2etests/tests/test_agent_create_missing_args.rs b/e2etests/tests/test_agent_create_missing_args.rs deleted file mode 100644 index 8b1eac8428..0000000000 --- a/e2etests/tests/test_agent_create_missing_args.rs +++ /dev/null @@ -1,59 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "agent")] -fn test_agent_create_missing_args() -> Result<(), Box> { - println!("πŸ” Testing /agent create without required arguments..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/agent create")?; - - println!("πŸ“ Agent create missing args response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify error message for missing required arguments - assert!(response.contains("error:"), "Missing error message part 1a"); - assert!(response.contains("the following required arguments"), "Missing error message part 1b"); - assert!(response.contains("were not provided:"), "Missing error message part 2"); - assert!(response.contains("--name"), "Missing required name argument part 1"); - assert!(response.contains(""), "Missing required name argument part 2"); - println!("βœ… Found error message for missing required arguments"); - - // Verify usage information - assert!(response.contains("Usage:"), "Missing usage information part 1"); - assert!(response.contains("/agent create"), "Missing usage information part 2a"); - assert!(response.contains("--name "), "Missing usage information part 2b"); - println!("βœ… Found usage information"); - - // Verify help suggestion - assert!(response.contains("For more information"), "Missing help suggestion part 1"); - assert!(response.contains("try"), "Missing help suggestion part 2a"); - //TODO - // assert!(response.contains("'--help"), "Missing help suggestion part 2b1"); - // assert!(response.contains("help'"), "Missing help suggestion part 2b2"); - println!("βœ… Found help suggestion"); - - // Verify options are listed - assert!(response.contains("Options:"), "Missing options section"); - //TODO - // assert!(response.contains("-n, --name"), "Missing name option part 1"); - assert!(response.contains(""), "Missing name option part 2"); - assert!(response.contains("Name of the agent to be created"), "Missing name description"); - // assert!(response.contains("-d, --directory"), "Missing directory option part 1"); - assert!(response.contains(""), "Missing directory option part 2"); - // assert!(response.contains("-f, --from"), "Missing from option part 1"); - assert!(response.contains(""), "Missing from option part 2"); - // assert!(response.contains("-h, --help"), "Missing help option"); - println!("βœ… Found all expected options"); - - println!("βœ… /agent create executed successfully with expected error for missing arguments"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} \ No newline at end of file diff --git a/e2etests/tests/test_agent_help_command.rs b/e2etests/tests/test_agent_help_command.rs deleted file mode 100644 index aa53f8c23d..0000000000 --- a/e2etests/tests/test_agent_help_command.rs +++ /dev/null @@ -1,56 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "agent")] -fn test_agent_help_command() -> Result<(), Box> { - println!("πŸ” Testing /agent help..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/agent help")?; - - println!("πŸ“ Agent help command response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Collect all failures instead of stopping at first one - let mut failures = Vec::new(); - - if !response.contains("Agents allow you to organize") { failures.push("Missing description"); } - if !response.contains("manage different sets of context") { failures.push("Missing context description"); } - if !response.contains("Notes") { failures.push("Missing notes section"); } - if !response.contains("Launch q chat with a specific agent") { failures.push("Missing launch note"); } - if !response.contains("--agent") { failures.push("Missing agent flag"); } - if !response.contains("Construct an agent under") { failures.push("Missing construct note"); } - if !response.contains("~/.aws/amazonq/cli-agents/") { failures.push("Missing global path"); } - if !response.contains("cwd/.aws/amazonq/cli-agents") { failures.push("Missing workspace path"); } - if !response.contains("Manage agents") { failures.push("Missing manage section"); } - if !response.contains("Usage:") { failures.push("Missing usage label"); } - if !response.contains("/agent") { failures.push("Missing agent command"); } - if !response.contains("") { failures.push("Missing command parameter"); } - if !response.contains("Commands:") { failures.push("Missing commands section"); } - if !response.contains("list") { failures.push("Missing list command"); } - if !response.contains("create") { failures.push("Missing create command"); } - if !response.contains("schema") { failures.push("Missing schema command"); } - if !response.contains("set-default") { failures.push("Missing set-default command"); } - if !response.contains("help") { failures.push("Missing help command"); } - if !response.contains("Options:") { failures.push("Missing options section"); } - if !response.contains("-h") { failures.push("Missing short help flag"); } - if !response.contains("--help") { failures.push("Missing long help flag"); } - - // Report all failures at once - if !failures.is_empty() { - panic!("Test failures: {}", failures.join(", ")); - } - - println!("βœ… All expected help content found"); - - println!("βœ… /agent help executed successfully"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} \ No newline at end of file diff --git a/e2etests/tests/test_agent_invalid_command.rs b/e2etests/tests/test_agent_invalid_command.rs deleted file mode 100644 index 4dd0bffeba..0000000000 --- a/e2etests/tests/test_agent_invalid_command.rs +++ /dev/null @@ -1,50 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "agent")] -fn test_agent_invalid_command() -> Result<(), Box> { - println!("πŸ” Testing /agent invalidcommand..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/agent invalidcommand")?; - - println!("πŸ“ Agent invalid command response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify error message - // assert!(response.contains("error: unrecognized subcommand 'invalidcommand'"), "Missing error message"); - // println!("βœ… Found error message for invalid subcommand"); - - // Verify usage information - // assert!(response.contains("Usage: /agent "), "Missing usage information"); - // println!("βœ… Found usage information"); - - // Verify help suggestion - // assert!(response.contains("For more information, try '--help'"), "Missing help suggestion"); - // println!("βœ… Found help suggestion"); - - // Verify available commands are listed - assert!(response.contains("Commands:"), "Missing commands section"); - assert!(response.contains("list"), "Missing list command"); - assert!(response.contains("create"), "Missing create command"); - assert!(response.contains("schema"), "Missing schema command"); - assert!(response.contains("set-default"), "Missing set-default command"); - assert!(response.contains("help"), "Missing help command"); - println!("βœ… Found all expected commands in help output"); - - // Verify options section - assert!(response.contains("Options:"), "Missing options section"); - // assert!(response.contains("-h, --help"), "Missing help option"); - println!("βœ… Found options section"); - - println!("βœ… /agent invalidcommand executed successfully with expected error"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} \ No newline at end of file diff --git a/e2etests/tests/test_agent_list_command.rs b/e2etests/tests/test_agent_list_command.rs deleted file mode 100644 index b9c8ec843a..0000000000 --- a/e2etests/tests/test_agent_list_command.rs +++ /dev/null @@ -1,37 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "agent")] -fn test_agent_list_command() -> Result<(), Box> { - println!("πŸ” Testing /agent list command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/agent list")?; - - println!("πŸ“ Agent list response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify the response contains the expected agent - assert!(response.contains("q_cli_default"), "Missing q_cli_default agent"); - println!("βœ… Found q_cli_default agent in list"); - - // Verify the response format (should show agent with bullet point) - assert!(response.contains("* q_cli_default"), "Missing bullet point format for q_cli_default"); - println!("βœ… Verified bullet point format for agent list"); - - // Verify the permission prompt appears - //TODO:"This option only shows on first time" - // assert!(response.contains("Allow this action? Use 't' to trust (always allow) this tool for the session. [y/n/t]:"), "Missing permission prompt"); - // println!("βœ… Found permission prompt for tool usage"); - - println!("βœ… /agent list command executed successfully"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} \ No newline at end of file diff --git a/e2etests/tests/test_agent_schema_command.rs b/e2etests/tests/test_agent_schema_command.rs deleted file mode 100644 index 3508225a23..0000000000 --- a/e2etests/tests/test_agent_schema_command.rs +++ /dev/null @@ -1,58 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "agent")] -fn test_agent_schema_command() -> Result<(), Box> { - println!("πŸ” Testing /agent schema..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/agent schema")?; - - println!("πŸ“ Agent schema response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Collect all failures instead of stopping at first one - let mut failures = Vec::new(); - - // Verify JSON schema root level keys - if !response.contains("$schema") { failures.push("Missing $schema key"); } - if !response.contains("title") { failures.push("Missing title key"); } - if !response.contains("description") { failures.push("Missing description key"); } - if !response.contains("type") { failures.push("Missing type key"); } - if !response.contains("properties") { failures.push("Missing properties key"); } - - //TODO : Due to response is not printing fully below keys are not getting detected. check response logic - // if !response.contains("additionalProperties") { failures.push("Missing additionalProperties key"); } - // if !response.contains("required") { failures.push("Missing required key"); } - // if !response.contains("$defs") { failures.push("Missing $defs key"); } - - // Verify some key properties exist - // if !response.contains("name") { failures.push("Missing name property"); } - // if !response.contains("prompt") { failures.push("Missing prompt property"); } - // if !response.contains("mcpServers") { failures.push("Missing mcpServers property"); } - // if !response.contains("tools") { failures.push("Missing tools property"); } - // if !response.contains("toolAliases") { failures.push("Missing toolAliases property"); } - // if !response.contains("allowedTools") { failures.push("Missing allowedTools property"); } - // if !response.contains("resources") { failures.push("Missing resources property"); } - // if !response.contains("hooks") { failures.push("Missing hooks property"); } - // if !response.contains("toolsSettings") { failures.push("Missing toolsSettings property"); } - // if !response.contains("useLegacyMcpJson") { failures.push("Missing useLegacyMcpJson property"); } - - // Report all failures at once - if !failures.is_empty() { - panic!("Test failures: {}", failures.join(", ")); - } - - println!("βœ… Found all expected JSON schema keys and properties"); - - println!("βœ… /agent schema executed successfully with valid JSON schema"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} \ No newline at end of file diff --git a/e2etests/tests/test_agent_set_default_command.rs b/e2etests/tests/test_agent_set_default_command.rs deleted file mode 100644 index 1695018a74..0000000000 --- a/e2etests/tests/test_agent_set_default_command.rs +++ /dev/null @@ -1,40 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "agent")] -fn test_agent_set_default_command() -> Result<(), Box> { - println!("πŸ” Testing /agent set-default with valid arguments..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/agent set-default -n q_cli_default")?; - - println!("πŸ“ Agent set-default command response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Collect all failures instead of stopping at first one - let mut failures = Vec::new(); - - if !response.contains("βœ“") { failures.push("Missing success checkmark"); } - if !response.contains("Default agent set to") { failures.push("Missing success message"); } - if !response.contains("q_cli_default") { failures.push("Missing agent name"); } - if !response.contains("This will take effect") { failures.push("Missing effect message"); } - if !response.contains("next time q chat is launched") { failures.push("Missing launch message"); } - - // Report all failures at once - if !failures.is_empty() { - panic!("Test failures: {}", failures.join(", ")); - } - - println!("βœ… All expected success messages found"); - - println!("βœ… /agent set-default executed successfully with valid arguments"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} \ No newline at end of file diff --git a/e2etests/tests/test_agent_set_default_missing_args.rs b/e2etests/tests/test_agent_set_default_missing_args.rs deleted file mode 100644 index 28ffb67a5a..0000000000 --- a/e2etests/tests/test_agent_set_default_missing_args.rs +++ /dev/null @@ -1,49 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "agent")] -fn test_agent_set_default_missing_args() -> Result<(), Box> { - println!("πŸ” Testing /agent set-default without required arguments..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/agent set-default")?; - - println!("πŸ“ Agent set-default missing args response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Collect all failures instead of stopping at first one - let mut failures = Vec::new(); - - if !response.contains("error") { failures.push("Missing error message"); } - if !response.contains("the following required arguments were not provided:") { failures.push("Missing error message2"); } - if !response.contains("--name ") { failures.push("Missing required name argument"); } - if !response.contains("Usage:") { failures.push("Missing usage text"); } - if !response.contains("/agent") { failures.push("Missing agent command"); } - if !response.contains("set-default") { failures.push("Missing set-default subcommand"); } - if !response.contains("--name") { failures.push("Missing name flag"); } - if !response.contains("For more information") { failures.push("Missing help text"); } - if !response.contains("--help") { failures.push("Missing help flag"); } - if !response.contains("Options:") { failures.push("Missing options section"); } - if !response.contains("-n") { failures.push("Missing short name flag"); } - if !response.contains("") { failures.push("Missing name parameter"); } - if !response.contains("-h") { failures.push("Missing short help flag"); } - if !response.contains("Print help") { failures.push("Missing help description"); } - - // Report all failures at once - if !failures.is_empty() { - panic!("Test failures: {}", failures.join(", ")); - } - - println!("βœ… All expected error messages and options found"); - - println!("βœ… /agent set-default executed successfully with expected error for missing arguments"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} \ No newline at end of file From dfafec2a5122afd515db789aa7bfe143dec1ee44 Mon Sep 17 00:00:00 2001 From: "Shreya [C] Bhagat" Date: Tue, 19 Aug 2025 20:33:41 +0530 Subject: [PATCH 17/77] QCLI Test automation - merged context feature test into one --- e2etests/tests/test_add_file_context.rs | 51 -- .../test_add_globe_pattern_file_context.rs | 59 --- .../tests/test_add_multiple_file_context.rs | 59 --- .../test_add_non_existing_file_context.rs | 31 -- e2etests/tests/test_clear_context_command.rs | 82 ---- e2etests/tests/test_context_command.rs | 449 ++++++++++++++++++ e2etests/tests/test_context_help_command.rs | 67 --- .../tests/test_context_invalid_command.rs | 55 --- ...ext_remove_command_of_non_existent_file.rs | 26 - e2etests/tests/test_context_show_command.rs | 34 -- .../tests/test_context_without_subcommand.rs | 52 -- e2etests/tests/test_q_mcp_list_command.rs | 7 +- e2etests/tests/test_remove_file_context.rs | 75 --- .../test_remove_multiple_file_context.rs | 84 ---- 14 files changed, 452 insertions(+), 679 deletions(-) delete mode 100644 e2etests/tests/test_add_file_context.rs delete mode 100644 e2etests/tests/test_add_globe_pattern_file_context.rs delete mode 100644 e2etests/tests/test_add_multiple_file_context.rs delete mode 100644 e2etests/tests/test_add_non_existing_file_context.rs delete mode 100644 e2etests/tests/test_clear_context_command.rs create mode 100644 e2etests/tests/test_context_command.rs delete mode 100644 e2etests/tests/test_context_help_command.rs delete mode 100644 e2etests/tests/test_context_invalid_command.rs delete mode 100644 e2etests/tests/test_context_remove_command_of_non_existent_file.rs delete mode 100644 e2etests/tests/test_context_show_command.rs delete mode 100644 e2etests/tests/test_context_without_subcommand.rs delete mode 100644 e2etests/tests/test_remove_file_context.rs delete mode 100644 e2etests/tests/test_remove_multiple_file_context.rs diff --git a/e2etests/tests/test_add_file_context.rs b/e2etests/tests/test_add_file_context.rs deleted file mode 100644 index ebcb795a55..0000000000 --- a/e2etests/tests/test_add_file_context.rs +++ /dev/null @@ -1,51 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "context")] -fn test_add_file_context() -> Result<(), Box> { - println!("πŸ” Testing /context add command..."); - - let test_file_path = "/tmp/test_context_file.py"; - - // Create a test file - std::fs::write(test_file_path, "# Test file for context\nprint('Hello from test file')")?; - println!("βœ… Created test file at {}", test_file_path); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - // Add file to context - let add_response = chat.execute_command(&format!("/context add {}", test_file_path))?; - - println!("πŸ“ Context add response: {} bytes", add_response.len()); - println!("πŸ“ ADD RESPONSE:"); - println!("{}", add_response); - println!("πŸ“ END ADD RESPONSE"); - - // Verify file was added successfully - assert!(add_response.contains("Added 1 path(s) to context"), "Missing success message for adding file"); - println!("βœ… File added to context successfully"); - - // Execute /context show to confirm file is present - let show_response = chat.execute_command("/context show")?; - - println!("πŸ“ Context show response: {} bytes", show_response.len()); - println!("πŸ“ SHOW RESPONSE:"); - println!("{}", show_response); - println!("πŸ“ END SHOW RESPONSE"); - - // Verify file is present in context - assert!(show_response.contains(test_file_path), "File not found in context show output"); - assert!(show_response.contains("πŸ’¬ Session (temporary):"), "Missing Session section"); - println!("βœ… File confirmed present in context"); - - chat.quit()?; - - // Clean up test file - let _ = std::fs::remove_file(test_file_path); - println!("βœ… Cleaned up test file"); - - println!("βœ… Test completed successfully"); - - Ok(()) -} diff --git a/e2etests/tests/test_add_globe_pattern_file_context.rs b/e2etests/tests/test_add_globe_pattern_file_context.rs deleted file mode 100644 index 53b81fcceb..0000000000 --- a/e2etests/tests/test_add_globe_pattern_file_context.rs +++ /dev/null @@ -1,59 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "context")] -fn test_add_glob_pattern_file_context() -> Result<(), Box> { - println!("πŸ” Testing /context add *.py glob pattern command..."); - - let test_file1_path = "/tmp/test_context_file1.py"; - let test_file2_path = "/tmp/test_context_file2.py"; - let test_file3_path = "/tmp/test_context_file.js"; // Non-matching file - let glob_pattern = "/tmp/*.py"; - - // Create test files - std::fs::write(test_file1_path, "# Test Python file 1 for context\nprint('Hello from Python file 1')")?; - std::fs::write(test_file2_path, "# Test Python file 2 for context\nprint('Hello from Python file 2')")?; - std::fs::write(test_file3_path, "// Test JavaScript file\nconsole.log('Hello from JS file');")?; - println!("βœ… Created test files at {}, {}, {}", test_file1_path, test_file2_path, test_file3_path); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - // Add glob pattern to context - let add_response = chat.execute_command(&format!("/context add {}", glob_pattern))?; - - println!("πŸ“ Context add response: {} bytes", add_response.len()); - println!("πŸ“ ADD RESPONSE:"); - println!("{}", add_response); - println!("πŸ“ END ADD RESPONSE"); - - // Verify glob pattern was added successfully - assert!(add_response.contains("Added 1 path(s) to context"), "Missing success message for adding glob pattern"); - println!("βœ… Glob pattern added to context successfully"); - - // Execute /context show to confirm pattern matches files - let show_response = chat.execute_command("/context show")?; - - println!("πŸ“ Context show response: {} bytes", show_response.len()); - println!("πŸ“ SHOW RESPONSE:"); - println!("{}", show_response); - println!("πŸ“ END SHOW RESPONSE"); - - // Verify glob pattern is present and matches files - assert!(show_response.contains(glob_pattern), "Glob pattern not found in context show output"); - assert!(show_response.contains("match"), "Missing match indicator for glob pattern"); - assert!(show_response.contains("πŸ’¬ Session (temporary):"), "Missing Session section"); - println!("βœ… Glob pattern confirmed present in context with matches"); - - chat.quit()?; - - // Clean up test files - let _ = std::fs::remove_file(test_file1_path); - let _ = std::fs::remove_file(test_file2_path); - let _ = std::fs::remove_file(test_file3_path); - println!("βœ… Cleaned up test files"); - - println!("βœ… Test completed successfully"); - - Ok(()) -} diff --git a/e2etests/tests/test_add_multiple_file_context.rs b/e2etests/tests/test_add_multiple_file_context.rs deleted file mode 100644 index 9573a9960b..0000000000 --- a/e2etests/tests/test_add_multiple_file_context.rs +++ /dev/null @@ -1,59 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "context")] -fn test_add_multiple_file_context() -> Result<(), Box> { - println!("πŸ” Testing /context add command..."); - - let test_file1_path = "/tmp/test_context_file1.py"; - let test_file2_path = "/tmp/test_context_file2.js"; - let test_file3_path = "/tmp/test_context_file3.txt"; - - // Create multiple test files - std::fs::write(test_file1_path, "# Test Python file for context\nprint('Hello from Python file')")?; - std::fs::write(test_file2_path, "// Test JavaScript file for context\nconsole.log('Hello from JS file');")?; - std::fs::write(test_file3_path, "Test text file for context\nHello from text file")?; - println!("βœ… Created test files at {}, {}, {}", test_file1_path, test_file2_path, test_file3_path); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - // Add multiple files to context in one command - let add_response = chat.execute_command(&format!("/context add {} {} {}", test_file1_path, test_file2_path, test_file3_path))?; - - println!("πŸ“ Context add response: {} bytes", add_response.len()); - println!("πŸ“ ADD RESPONSE:"); - println!("{}", add_response); - println!("πŸ“ END ADD RESPONSE"); - - // Verify files were added successfully - assert!(add_response.contains("Added 3 path(s) to context"), "Missing success message for adding multiple files"); - println!("βœ… Multiple files added to context successfully"); - - // Execute /context show to confirm files are present - let show_response = chat.execute_command("/context show")?; - - println!("πŸ“ Context show response: {} bytes", show_response.len()); - println!("πŸ“ SHOW RESPONSE:"); - println!("{}", show_response); - println!("πŸ“ END SHOW RESPONSE"); - - // Verify all files are present in context - assert!(show_response.contains(test_file1_path), "Python file not found in context show output"); - assert!(show_response.contains(test_file2_path), "JavaScript file not found in context show output"); - assert!(show_response.contains(test_file3_path), "Text file not found in context show output"); - assert!(show_response.contains("πŸ’¬ Session (temporary):"), "Missing Session section"); - println!("βœ… All files confirmed present in context"); - - chat.quit()?; - - // Clean up test files - let _ = std::fs::remove_file(test_file1_path); - let _ = std::fs::remove_file(test_file2_path); - let _ = std::fs::remove_file(test_file3_path); - println!("βœ… Cleaned up test files"); - - println!("βœ… Test completed successfully"); - - Ok(()) -} diff --git a/e2etests/tests/test_add_non_existing_file_context.rs b/e2etests/tests/test_add_non_existing_file_context.rs deleted file mode 100644 index 1786c8ab3e..0000000000 --- a/e2etests/tests/test_add_non_existing_file_context.rs +++ /dev/null @@ -1,31 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "context")] -fn test_add_non_existing_file_context() -> Result<(), Box> { - println!("πŸ” Testing /context add non-existing file command..."); - - let non_existing_file_path = "/tmp/non_existing_file.py"; - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - // Try to add non-existing file to context - let add_response = chat.execute_command(&format!("/context add {}", non_existing_file_path))?; - - println!("πŸ“ Context add response: {} bytes", add_response.len()); - println!("πŸ“ ADD RESPONSE:"); - println!("{}", add_response); - println!("πŸ“ END ADD RESPONSE"); - - // Verify error message for non-existing file - assert!(add_response.contains("Error:") && add_response.contains("Invalid path") && add_response.contains("does not exist"), "Missing error message for non-existing file"); - assert!(add_response.contains("Use --force to add anyway"), "Missing --force suggestion in error message"); - println!("βœ… Found expected error message for non-existing file with --force suggestion"); - - chat.quit()?; - - println!("βœ… Test completed successfully"); - - Ok(()) -} diff --git a/e2etests/tests/test_clear_context_command.rs b/e2etests/tests/test_clear_context_command.rs deleted file mode 100644 index 14b72ed4b4..0000000000 --- a/e2etests/tests/test_clear_context_command.rs +++ /dev/null @@ -1,82 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "context")] -fn test_clear_context_command() -> Result<(), Box> { - println!("πŸ” Testing /context clear command..."); - - let test_file1_path = "/tmp/test_context_file1.py"; - let test_file2_path = "/tmp/test_context_file2.js"; - - // Create multiple test files - std::fs::write(test_file1_path, "# Test Python file for context\nprint('Hello from Python file')")?; - std::fs::write(test_file2_path, "// Test JavaScript file for context\nconsole.log('Hello from JS file');")?; - println!("βœ… Created test files at {}, {}", test_file1_path, test_file2_path); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - // Add multiple files to context - let add_response = chat.execute_command(&format!("/context add {} {}", test_file1_path, test_file2_path))?; - - println!("πŸ“ Context add response: {} bytes", add_response.len()); - println!("πŸ“ ADD RESPONSE:"); - println!("{}", add_response); - println!("πŸ“ END ADD RESPONSE"); - - // Verify files were added successfully - assert!(add_response.contains("Added 2 path(s) to context"), "Missing success message for adding files"); - println!("βœ… Files added to context successfully"); - - // Execute /context show to confirm files are present - let show_response = chat.execute_command("/context show")?; - - println!("πŸ“ Context show response: {} bytes", show_response.len()); - println!("πŸ“ SHOW RESPONSE:"); - println!("{}", show_response); - println!("πŸ“ END SHOW RESPONSE"); - - // Verify files are present in context - assert!(show_response.contains(test_file1_path), "Python file not found in context show output"); - assert!(show_response.contains(test_file2_path), "JavaScript file not found in context show output"); - println!("βœ… Files confirmed present in context"); - - // Execute /context clear to remove all files - let clear_response = chat.execute_command("/context clear")?; - - println!("πŸ“ Context clear response: {} bytes", clear_response.len()); - println!("πŸ“ CLEAR RESPONSE:"); - println!("{}", clear_response); - println!("πŸ“ END CLEAR RESPONSE"); - - // Verify context was cleared successfully - assert!(clear_response.contains("Cleared context"), "Missing success message for clearing context"); - println!("βœ… Context cleared successfully"); - - // Execute /context show to confirm no files remain - let final_show_response = chat.execute_command("/context show")?; - - println!("πŸ“ Final context show response: {} bytes", final_show_response.len()); - println!("πŸ“ FINAL SHOW RESPONSE:"); - println!("{}", final_show_response); - println!("πŸ“ END FINAL SHOW RESPONSE"); - - // Verify no files remain in context - assert!(!final_show_response.contains(test_file1_path), "Python file still found in context after clear"); - assert!(!final_show_response.contains(test_file2_path), "JavaScript file still found in context after clear"); - assert!(final_show_response.contains("πŸ‘€ Agent (q_cli_default):"), "Missing Agent section"); - assert!(final_show_response.contains("πŸ’¬ Session (temporary):"), "Missing Session section"); - assert!(final_show_response.contains(""), "Missing indicator for cleared context"); - println!("βœ… All files confirmed removed from context and sections present"); - - chat.quit()?; - - // Clean up test files - let _ = std::fs::remove_file(test_file1_path); - let _ = std::fs::remove_file(test_file2_path); - println!("βœ… Cleaned up test files"); - - println!("βœ… Test completed successfully"); - - Ok(()) -} diff --git a/e2etests/tests/test_context_command.rs b/e2etests/tests/test_context_command.rs new file mode 100644 index 0000000000..19889d0d45 --- /dev/null +++ b/e2etests/tests/test_context_command.rs @@ -0,0 +1,449 @@ +use q_cli_e2e_tests::q_chat_helper::QChatSession; + +#[test] +#[cfg(feature = "context")] +fn test_context_command() -> Result<(), Box> { + println!("πŸ” Testing context commands..."); + + let test_file_path = "/tmp/test_context_file.py"; + // Create a test file + std::fs::write(test_file_path, "# Test file for context\nprint('Hello from test file')")?; + println!("βœ… Created test file at {}", test_file_path); + + let non_existing_file_path = "/tmp/non_existing_file.py"; + + let test_file1_path = "/tmp/test_context_file1.py"; + let test_file2_path = "/tmp/test_context_file2.py"; + let test_file3_path = "/tmp/test_context_file.js"; // Non-matching file + let glob_pattern = "/tmp/*.py"; + + // Create test files + std::fs::write(test_file1_path, "# Test Python file 1 for context\nprint('Hello from Python file 1')")?; + std::fs::write(test_file2_path, "# Test Python file 2 for context\nprint('Hello from Python file 2')")?; + std::fs::write(test_file3_path, "// Test JavaScript file\nconsole.log('Hello from JS file');")?; + println!("βœ… Created test files at {}, {}, {}", test_file1_path, test_file2_path, test_file3_path); + + let mut chat = QChatSession::new()?; + println!("βœ… Q Chat session started"); + + test_context_show_command(&mut chat)?; + test_context_help_command(&mut chat)?; + test_context_without_subcommand(&mut chat)?; + test_context_invalid_command(&mut chat)?; + test_add_non_existing_file_context(&mut chat, non_existing_file_path)?; + test_context_remove_command_of_non_existent_file(&mut chat)?; + test_add_remove_file_context(&mut chat, test_file_path)?; + test_add_glob_pattern_file_context(&mut chat, glob_pattern)?; + test_add_remove_multiple_file_context(&mut chat, test_file1_path, test_file2_path, test_file3_path)?; + test_clear_context_command(&mut chat, test_file1_path, test_file2_path)?; + + chat.quit()?; + // Clean up test file + let _ = std::fs::remove_file(test_file_path); + let _ = std::fs::remove_file(test_file1_path); + let _ = std::fs::remove_file(test_file2_path); + let _ = std::fs::remove_file(test_file3_path); + println!("βœ… Cleaned up test file"); + + println!("βœ… Test completed successfully"); + + Ok(()) +} + +fn test_context_show_command(chat: &mut QChatSession) -> Result<(), Box> { + println!("πŸ” Testing /context show command..."); + + let response = chat.execute_command("/context show")?; + + println!("πŸ“ Context show response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify context show output contains expected sections + assert!(response.contains("πŸ‘€ Agent"), "Missing Agent section with emoji"); + println!("βœ… Found Agent section with emoji"); + + // Verify agent configuration details + assert!(response.contains("AmazonQ.md"), "Missing AmazonQ.md in agent config"); + assert!(response.contains("README.md"), "Missing README.md in agent config"); + assert!(response.contains(".amazonq/rules/**/*.md"), "Missing .amazonq/rules pattern"); + assert!(response.contains("πŸ’¬ Session"), "Missing session section with emoji"); + println!("βœ… Found all expected agent configuration files"); + + println!("βœ… All context show content verified!"); + + Ok(()) +} + +fn test_context_help_command(chat: &mut QChatSession) -> Result<(), Box> { + println!("πŸ” Testing /context help command..."); + + let response = chat.execute_command("/context help")?; + + println!("πŸ“ Context help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify Usage section + assert!(response.contains("Usage:"), "Missing Usage section"); + assert!(response.contains("/context") && response.contains(""), "Missing /context command in usage"); + println!("βœ… Found Usage section"); + + // Verify Commands section + assert!(response.contains("Commands:"), "Missing Commands section"); + assert!(response.contains("show"), "Missing show command"); + assert!(response.contains("add"), "Missing add command"); + assert!(response.contains("remove"), "Missing remove command"); + assert!(response.contains("clear"), "Missing clear command"); + assert!(response.contains("help"), "Missing help command"); + println!("βœ… Found Commands section with all subcommands"); + + // Verify Options section + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("-h"), "Missing -h flag"); + assert!(response.contains("--help"), "Missing --help flag"); + println!("βœ… Found Options section with help flags"); + + println!("βœ… All context help content verified!"); + + Ok(()) +} + +fn test_context_without_subcommand(chat: &mut QChatSession) -> Result<(), Box> { + println!("πŸ” Testing /context without sub command..."); + + let response = chat.execute_command("/context")?; + + println!("πŸ“ Context response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + assert!(response.contains("Usage:"), "Missing Usage section"); + assert!(response.contains("/context") && response.contains(""), "Missing /context command in usage"); + println!("βœ… Found Usage section with /context command"); + + assert!(response.contains("Commands:"), "Missing Commands section"); + assert!(response.contains("show"), "Missing show command"); + assert!(response.contains("add"), "Missing add command"); + assert!(response.contains("remove"), "Missing remove command"); + assert!(response.contains("clear"), "Missing clear command"); + assert!(response.contains("help"), "Missing help command"); + println!("βœ… Found Commands section with all subcommands"); + + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("-h"), "Missing -h flag"); + assert!(response.contains("--help"), "Missing --help flag"); + assert!(response.contains("Print help"), "Missing help description"); + println!("βœ… Found Options section with -h, --help flags"); + + println!("βœ… All context help content verified!"); + + Ok(()) +} + +fn test_context_invalid_command(chat: &mut QChatSession) -> Result<(), Box> { + println!("πŸ” Testing /context invalid command..."); + + let response = chat.execute_command("/context test")?; + + println!("πŸ“ Context invalid response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify error message for invalid subcommand + assert!(response.contains("error:") && response.contains("unrecognized subcommand") && response.contains("test"), "Missing 'unrecognized subcommand' error message"); + println!("βœ… Found expected error message for invalid subcommand"); + + assert!(response.contains("Usage:"), "Missing Usage section"); + assert!(response.contains("/context") && response.contains(""), "Missing /context command in usage"); + println!("βœ… Found Usage section with /context command"); + + assert!(response.contains("Commands:"), "Missing Commands section"); + assert!(response.contains("show"), "Missing show command"); + assert!(response.contains("add"), "Missing add command"); + assert!(response.contains("remove"), "Missing remove command"); + assert!(response.contains("clear"), "Missing clear command"); + assert!(response.contains("help"), "Missing help command"); + println!("βœ… Found Commands section with all subcommands"); + + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("-h"), "Missing -h flag"); + assert!(response.contains("--help"), "Missing --help flag"); + assert!(response.contains("Print help"), "Missing help description"); + println!("βœ… Found Options section with -h, --help flags"); + + println!("βœ… All context invalid command content verified!"); + + Ok(()) +} + +fn test_add_non_existing_file_context(chat: &mut QChatSession, non_existing_file_path: &str) -> Result<(), Box> { + println!("πŸ” Testing /context add non-existing file command..."); + + // Try to add non-existing file to context + let add_response = chat.execute_command(&format!("/context add {}", non_existing_file_path))?; + + println!("πŸ“ Context add response: {} bytes", add_response.len()); + println!("πŸ“ ADD RESPONSE:"); + println!("{}", add_response); + println!("πŸ“ END ADD RESPONSE"); + + // Verify error message for non-existing file + assert!(add_response.contains("Error:") && add_response.contains("Invalid path") && add_response.contains("does not exist"), "Missing error message for non-existing file"); + assert!(add_response.contains("Use --force to add anyway"), "Missing --force suggestion in error message"); + println!("βœ… Found expected error message for non-existing file with --force suggestion"); + + Ok(()) +} + + +fn test_context_remove_command_of_non_existent_file(chat: &mut QChatSession) -> Result<(), Box> { + println!("πŸ” Testing /context remove non existing file command..."); + + let response = chat.execute_command("/context remove non_existent_file.txt")?; + + println!("πŸ“ Context remove response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify error message for non-existent file + assert!(response.contains("Error:"), "Missing error message for non-existent file"); + println!("βœ… Found expected error message for non-existent file removal"); + + Ok(()) +} + +fn test_add_remove_file_context(chat: &mut QChatSession, test_file_path: &str) -> Result<(), Box> { + println!("πŸ” Testing /context add command and /context remove command..."); + + // Add file to context + let add_response = chat.execute_command(&format!("/context add {}", test_file_path))?; + + println!("πŸ“ Context add response: {} bytes", add_response.len()); + println!("πŸ“ ADD RESPONSE:"); + println!("{}", add_response); + println!("πŸ“ END ADD RESPONSE"); + + // Verify file was added successfully + assert!(add_response.contains("Added 1 path(s) to context"), "Missing success message for adding file"); + println!("βœ… File added to context successfully"); + + // Execute /context show to confirm file is present + let show_response = chat.execute_command("/context show")?; + + println!("πŸ“ Context show response: {} bytes", show_response.len()); + println!("πŸ“ SHOW RESPONSE:"); + println!("{}", show_response); + println!("πŸ“ END SHOW RESPONSE"); + + // Verify file is present in context + assert!(show_response.contains(test_file_path), "File not found in context show output"); + assert!(show_response.contains("πŸ’¬ Session (temporary):"), "Missing Session section"); + println!("βœ… File confirmed present in context"); + + // Remove file from context + let remove_response = chat.execute_command(&format!("/context remove {}", test_file_path))?; + + println!("πŸ“ Context remove response: {} bytes", remove_response.len()); + println!("πŸ“ REMOVE RESPONSE:"); + println!("{}", remove_response); + println!("πŸ“ END REMOVE RESPONSE"); + + // Verify file was removed successfully + assert!(remove_response.contains("Removed 1 path(s) from context"), "Missing success message for removing file"); + println!("βœ… File removed from context successfully"); + + // Execute /context show to confirm file is gone + let final_show_response = chat.execute_command("/context show")?; + + println!("πŸ“ Final context show response: {} bytes", final_show_response.len()); + println!("πŸ“ FINAL SHOW RESPONSE:"); + println!("{}", final_show_response); + println!("πŸ“ END FINAL SHOW RESPONSE"); + + // Verify file is no longer in context + assert!(!final_show_response.contains(test_file_path), "File still found in context after removal"); + println!("βœ… File confirmed removed from context"); + + Ok(()) +} + +fn test_add_glob_pattern_file_context(chat: &mut QChatSession, glob_pattern: &str) -> Result<(), Box> { + println!("πŸ” Testing /context add *.py glob pattern command..."); + + // Add glob pattern to context + let add_response = chat.execute_command(&format!("/context add {}", glob_pattern))?; + + println!("πŸ“ Context add response: {} bytes", add_response.len()); + println!("πŸ“ ADD RESPONSE:"); + println!("{}", add_response); + println!("πŸ“ END ADD RESPONSE"); + + // Verify glob pattern was added successfully + assert!(add_response.contains("Added 1 path(s) to context"), "Missing success message for adding glob pattern"); + println!("βœ… Glob pattern added to context successfully"); + + // Execute /context show to confirm pattern matches files + let show_response = chat.execute_command("/context show")?; + + println!("πŸ“ Context show response: {} bytes", show_response.len()); + println!("πŸ“ SHOW RESPONSE:"); + println!("{}", show_response); + println!("πŸ“ END SHOW RESPONSE"); + + // Verify glob pattern is present and matches files + assert!(show_response.contains(glob_pattern), "Glob pattern not found in context show output"); + assert!(show_response.contains("match"), "Missing match indicator for glob pattern"); + assert!(show_response.contains("πŸ’¬ Session (temporary):"), "Missing Session section"); + println!("βœ… Glob pattern confirmed present in context with matches"); + + // Remove glob pattern from context + let remove_response = chat.execute_command(&format!("/context remove {}", glob_pattern))?; + + println!("πŸ“ Context remove response: {} bytes", remove_response.len()); + println!("πŸ“ REMOVE RESPONSE:"); + println!("{}", remove_response); + println!("πŸ“ END REMOVE RESPONSE"); + + // Verify glob pattern was removed successfully + assert!(remove_response.contains("Removed 1 path(s) from context"), "Missing success message for removing glob pattern"); + println!("βœ… Glob pattern removed from context successfully"); + + // Execute /context show to confirm glob pattern is gone + let final_show_response = chat.execute_command("/context show")?; + + println!("πŸ“ Final context show response: {} bytes", final_show_response.len()); + println!("πŸ“ FINAL SHOW RESPONSE:"); + println!("{}", final_show_response); + println!("πŸ“ END FINAL SHOW RESPONSE"); + + // Verify glob pattern is no longer in context + assert!(!final_show_response.contains(glob_pattern), "Glob pattern still found in context after removal"); + println!("βœ… Glob pattern confirmed removed from context"); + + Ok(()) +} + +fn test_add_remove_multiple_file_context(chat: &mut QChatSession, test_file1_path: &str, test_file2_path: &str, test_file3_path: &str) -> Result<(), Box> { + println!("πŸ” Testing /context add command and /context remove ..."); + + // Add multiple files to context in one command + let add_response = chat.execute_command(&format!("/context add {} {} {}", test_file1_path, test_file2_path, test_file3_path))?; + + println!("πŸ“ Context add response: {} bytes", add_response.len()); + println!("πŸ“ ADD RESPONSE:"); + println!("{}", add_response); + println!("πŸ“ END ADD RESPONSE"); + + // Verify files were added successfully + assert!(add_response.contains("Added 3 path(s) to context"), "Missing success message for adding multiple files"); + println!("βœ… Multiple files added to context successfully"); + + // Execute /context show to confirm files are present + let show_response = chat.execute_command("/context show")?; + + println!("πŸ“ Context show response: {} bytes", show_response.len()); + println!("πŸ“ SHOW RESPONSE:"); + println!("{}", show_response); + println!("πŸ“ END SHOW RESPONSE"); + + // Verify all files are present in context + assert!(show_response.contains(test_file1_path), "Python file not found in context show output"); + assert!(show_response.contains(test_file2_path), "JavaScript file not found in context show output"); + assert!(show_response.contains(test_file3_path), "Text file not found in context show output"); + assert!(show_response.contains("πŸ’¬ Session (temporary):"), "Missing Session section"); + println!("βœ… All files confirmed present in context"); + + // Remove multiple files from context + let remove_response = chat.execute_command(&format!("/context remove {} {} {}", test_file1_path, test_file2_path, test_file3_path))?; + + println!("πŸ“ Context remove response: {} bytes", remove_response.len()); + println!("πŸ“ REMOVE RESPONSE:"); + println!("{}", remove_response); + println!("πŸ“ END REMOVE RESPONSE"); + + // Verify files were removed successfully + assert!(remove_response.contains("Removed 3 path(s) from context"), "Missing success message for removing multiple files"); + println!("βœ… Multiple files removed from context successfully"); + + // Execute /context show to confirm files are gone + let final_show_response = chat.execute_command("/context show")?; + + println!("πŸ“ Final context show response: {} bytes", final_show_response.len()); + println!("πŸ“ FINAL SHOW RESPONSE:"); + println!("{}", final_show_response); + println!("πŸ“ END FINAL SHOW RESPONSE"); + + // Verify files are no longer in context + assert!(!final_show_response.contains(test_file1_path), "Python file still found in context after removal"); + assert!(!final_show_response.contains(test_file2_path), "JavaScript file still found in context after removal"); + assert!(!final_show_response.contains(test_file3_path), "Text file still found in context after removal"); + println!("βœ… All files confirmed removed from context"); + + Ok(()) +} + +fn test_clear_context_command(chat: &mut QChatSession, test_file1_path: &str, test_file2_path: &str) -> Result<(), Box> { + println!("πŸ” Testing /context clear command..."); + + // Add multiple files to context + let add_response = chat.execute_command(&format!("/context add {} {}", test_file1_path, test_file2_path))?; + + println!("πŸ“ Context add response: {} bytes", add_response.len()); + println!("πŸ“ ADD RESPONSE:"); + println!("{}", add_response); + println!("πŸ“ END ADD RESPONSE"); + + // Verify files were added successfully + assert!(add_response.contains("Added 2 path(s) to context"), "Missing success message for adding files"); + println!("βœ… Files added to context successfully"); + + // Execute /context show to confirm files are present + let show_response = chat.execute_command("/context show")?; + + println!("πŸ“ Context show response: {} bytes", show_response.len()); + println!("πŸ“ SHOW RESPONSE:"); + println!("{}", show_response); + println!("πŸ“ END SHOW RESPONSE"); + + // Verify files are present in context + assert!(show_response.contains(test_file1_path), "Python file not found in context show output"); + assert!(show_response.contains(test_file2_path), "JavaScript file not found in context show output"); + println!("βœ… Files confirmed present in context"); + + // Execute /context clear to remove all files + let clear_response = chat.execute_command("/context clear")?; + + println!("πŸ“ Context clear response: {} bytes", clear_response.len()); + println!("πŸ“ CLEAR RESPONSE:"); + println!("{}", clear_response); + println!("πŸ“ END CLEAR RESPONSE"); + + // Verify context was cleared successfully + assert!(clear_response.contains("Cleared context"), "Missing success message for clearing context"); + println!("βœ… Context cleared successfully"); + + // Execute /context show to confirm no files remain + let final_show_response = chat.execute_command("/context show")?; + + println!("πŸ“ Final context show response: {} bytes", final_show_response.len()); + println!("πŸ“ FINAL SHOW RESPONSE:"); + println!("{}", final_show_response); + println!("πŸ“ END FINAL SHOW RESPONSE"); + + // Verify no files remain in context + assert!(!final_show_response.contains(test_file1_path), "Python file still found in context after clear"); + assert!(!final_show_response.contains(test_file2_path), "JavaScript file still found in context after clear"); + assert!(final_show_response.contains("πŸ‘€ Agent (q_cli_default):"), "Missing Agent section"); + assert!(final_show_response.contains("πŸ’¬ Session (temporary):"), "Missing Session section"); + assert!(final_show_response.contains(""), "Missing indicator for cleared context"); + println!("βœ… All files confirmed removed from context and sections present"); + + Ok(()) +} + diff --git a/e2etests/tests/test_context_help_command.rs b/e2etests/tests/test_context_help_command.rs deleted file mode 100644 index 4ab2fe6d6c..0000000000 --- a/e2etests/tests/test_context_help_command.rs +++ /dev/null @@ -1,67 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "context")] -fn test_context_help_command() -> Result<(), Box> { - println!("πŸ” Testing /context help command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/context help")?; - - println!("πŸ“ Context help response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify main description - assert!(response.contains("Context rules determine which files are included"), "Missing context rules description"); - assert!(response.contains("Amazon Q session"), "Missing Amazon Q session reference"); - assert!(response.contains("They are derived from the current active agent"), "Missing agent derivation note"); - assert!(response.contains("provide Amazon Q with additional information"), "Missing additional information note"); - assert!(response.contains("Adding relevant files helps Q generate"), "Missing file help note"); - assert!(response.contains("more accurate and helpful responses"), "Missing accuracy note"); - println!("βœ… Found context rules description"); - - // Verify Notes section - assert!(response.contains("Notes:"), "Missing Notes section"); - assert!(response.contains("glob patterns"), "Missing glob patterns note"); - assert!(response.contains("*.py"), "Missing Python glob example"); - assert!(response.contains("src/**/*.js"), "Missing JavaScript glob example"); - assert!(response.contains("Agent rules apply only to the current agent"), "Missing agent rules note"); - assert!(response.contains("NOT preserved between chat sessions"), "Missing session preservation note"); - assert!(response.contains("edit the agent config file"), "Missing config file note"); - println!("βœ… Found Notes section with all details"); - - // Verify manage description - assert!(response.contains("Manage context files for the chat session"), "Missing manage description"); - println!("βœ… Found manage description"); - - // Verify Usage section - assert!(response.contains("Usage:"), "Missing Usage section"); - assert!(response.contains("/context") && response.contains(""), "Missing /context command in usage"); - println!("βœ… Found Usage section"); - - // Verify Commands section - assert!(response.contains("Commands:"), "Missing Commands section"); - assert!(response.contains("show"), "Missing show command"); - assert!(response.contains("add"), "Missing add command"); - assert!(response.contains("remove"), "Missing remove command"); - assert!(response.contains("clear"), "Missing clear command"); - assert!(response.contains("help"), "Missing help command"); - println!("βœ… Found Commands section with all subcommands"); - - // Verify Options section - assert!(response.contains("Options:"), "Missing Options section"); - assert!(response.contains("-h"), "Missing -h flag"); - assert!(response.contains("--help"), "Missing --help flag"); - println!("βœ… Found Options section with help flags"); - - println!("βœ… All context help content verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} diff --git a/e2etests/tests/test_context_invalid_command.rs b/e2etests/tests/test_context_invalid_command.rs deleted file mode 100644 index 6a56bf00c9..0000000000 --- a/e2etests/tests/test_context_invalid_command.rs +++ /dev/null @@ -1,55 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "context")] -fn test_context_invalid_command() -> Result<(), Box> { - println!("πŸ” Testing /context invalid command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/context test")?; - - println!("πŸ“ Context invalid response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify error message for invalid subcommand - assert!(response.contains("unrecognized subcommand") && response.contains("test"), "Missing 'unrecognized subcommand' error message"); - println!("βœ… Found expected error message for invalid subcommand"); - - assert!(response.contains("Usage:"), "Missing Usage section"); - assert!(response.contains("/context") && response.contains(""), "Missing /context command in usage"); - println!("βœ… Found Usage section with /context command"); - - assert!(response.contains("For more information") && response.contains("--help"), "Missing help information"); - println!("βœ… Found help information"); - - assert!(response.contains("Commands:"), "Missing Commands section"); - assert!(response.contains("show"), "Missing show command"); - assert!(response.contains("add"), "Missing add command"); - assert!(response.contains("remove"), "Missing remove command"); - assert!(response.contains("clear"), "Missing clear command"); - assert!(response.contains("help"), "Missing help command"); - println!("βœ… Found Commands section with all subcommands"); - - assert!(response.contains("Display the context rule configuration and matched files"), "Missing show command description"); - assert!(response.contains("Add context rules (filenames or glob patterns)"), "Missing add command description"); - assert!(response.contains("Remove specified rules"), "Missing remove command description"); - assert!(response.contains("Remove all rules"), "Missing clear command description"); - println!("βœ… Found all command descriptions"); - - assert!(response.contains("Options:"), "Missing Options section"); - assert!(response.contains("-h"), "Missing -h flag"); - assert!(response.contains("--help"), "Missing --help flag"); - assert!(response.contains("Print help"), "Missing help description"); - println!("βœ… Found Options section with -h, --help flags"); - - println!("βœ… All context invalid command content verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} diff --git a/e2etests/tests/test_context_remove_command_of_non_existent_file.rs b/e2etests/tests/test_context_remove_command_of_non_existent_file.rs deleted file mode 100644 index d9104dc931..0000000000 --- a/e2etests/tests/test_context_remove_command_of_non_existent_file.rs +++ /dev/null @@ -1,26 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "context")] -fn test_context_remove_command_of_non_existent_file() -> Result<(), Box> { - println!("πŸ” Testing /context remove non existing file command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/context remove non_existent_file.txt")?; - - println!("πŸ“ Context remove response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify error message for non-existent file - assert!(response.contains("None of the specified paths were found in the context"), "Missing error message for non-existent file"); - println!("βœ… Found expected error message for non-existent file removal"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} diff --git a/e2etests/tests/test_context_show_command.rs b/e2etests/tests/test_context_show_command.rs deleted file mode 100644 index a40cf4d73e..0000000000 --- a/e2etests/tests/test_context_show_command.rs +++ /dev/null @@ -1,34 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "context")] -fn test_context_show_command() -> Result<(), Box> { - println!("πŸ” Testing /context show command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/context show")?; - - println!("πŸ“ Context show response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify context show output contains expected sections - assert!(response.contains("πŸ‘€ Agent"), "Missing Agent section with emoji"); - println!("βœ… Found Agent section with emoji"); - - // Verify agent configuration details - assert!(response.contains("AmazonQ.md"), "Missing AmazonQ.md in agent config"); - assert!(response.contains("README.md"), "Missing README.md in agent config"); - assert!(response.contains(".amazonq/rules/**/*.md"), "Missing .amazonq/rules pattern"); - println!("βœ… Found all expected agent configuration files"); - - println!("βœ… All context show content verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} diff --git a/e2etests/tests/test_context_without_subcommand.rs b/e2etests/tests/test_context_without_subcommand.rs deleted file mode 100644 index b6b8fc5371..0000000000 --- a/e2etests/tests/test_context_without_subcommand.rs +++ /dev/null @@ -1,52 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "context")] -fn test_context_without_subcommand() -> Result<(), Box> { - println!("πŸ” Testing /context without sub command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/context")?; - - println!("πŸ“ Context response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify context command help content - assert!(response.contains("Manage context files for the chat session"), "Missing context command description"); - println!("βœ… Found context command description"); - - assert!(response.contains("Usage:"), "Missing Usage section"); - assert!(response.contains("/context") && response.contains(""), "Missing /context command in usage"); - println!("βœ… Found Usage section with /context command"); - - assert!(response.contains("Commands:"), "Missing Commands section"); - assert!(response.contains("show"), "Missing show command"); - assert!(response.contains("add"), "Missing add command"); - assert!(response.contains("remove"), "Missing remove command"); - assert!(response.contains("clear"), "Missing clear command"); - assert!(response.contains("help"), "Missing help command"); - println!("βœ… Found Commands section with all subcommands"); - - assert!(response.contains("Display the context rule configuration and matched files"), "Missing show command description"); - assert!(response.contains("Add context rules (filenames or glob patterns)"), "Missing add command description"); - assert!(response.contains("Remove specified rules"), "Missing remove command description"); - assert!(response.contains("Remove all rules"), "Missing clear command description"); - println!("βœ… Found all command descriptions"); - - assert!(response.contains("Options:"), "Missing Options section"); - assert!(response.contains("-h"), "Missing -h flag"); - assert!(response.contains("--help"), "Missing --help flag"); - assert!(response.contains("Print help"), "Missing help description"); - println!("βœ… Found Options section with -h, --help flags"); - - println!("βœ… All context help content verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} diff --git a/e2etests/tests/test_q_mcp_list_command.rs b/e2etests/tests/test_q_mcp_list_command.rs index 26685c30b8..83ad7ee908 100644 --- a/e2etests/tests/test_q_mcp_list_command.rs +++ b/e2etests/tests/test_q_mcp_list_command.rs @@ -32,10 +32,9 @@ fn test_q_mcp_list_command() -> Result<(), Box> { // Verify MCP server listing - //assert!(allow_response.contains("q_cli_default"), "Missing q_cli_default server"); - // Verify server count summary with dynamic count - assert!(allow_response.contains("You have") && allow_response.contains("MCP server configured:"), "Missing correct server count summary"); - assert!(allow_response.contains("Completed in"), "Missing completion indicator"); + assert!(allow_response.contains("q_cli_default"), "Missing q_cli_default server"); + assert!(allow_response.contains("default"), "Missing default tag"); + assert!(allow_response.contains("global"), "Missing global tag"); println!("βœ… Found MCP server listing with servers and completion"); chat.quit()?; diff --git a/e2etests/tests/test_remove_file_context.rs b/e2etests/tests/test_remove_file_context.rs deleted file mode 100644 index 787a164bd8..0000000000 --- a/e2etests/tests/test_remove_file_context.rs +++ /dev/null @@ -1,75 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "context")] -fn test_remove_file_context() -> Result<(), Box> { - println!("πŸ” Testing /context remove command..."); - - let test_file_path = "/tmp/test_context_file.py"; - - // Create a test file - std::fs::write(test_file_path, "# Test file for context\nprint('Hello from test file')")?; - println!("βœ… Created test file at {}", test_file_path); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - // Add file to context - let add_response = chat.execute_command(&format!("/context add {}", test_file_path))?; - - println!("πŸ“ Context add response: {} bytes", add_response.len()); - println!("πŸ“ ADD RESPONSE:"); - println!("{}", add_response); - println!("πŸ“ END ADD RESPONSE"); - - // Verify file was added successfully - assert!(add_response.contains("Added 1 path(s) to context"), "Missing success message for adding file"); - println!("βœ… File added to context successfully"); - - // Execute /context show to confirm file is present - let show_response = chat.execute_command("/context show")?; - - println!("πŸ“ Context show response: {} bytes", show_response.len()); - println!("πŸ“ SHOW RESPONSE:"); - println!("{}", show_response); - println!("πŸ“ END SHOW RESPONSE"); - - // Verify file is present in context - assert!(show_response.contains(test_file_path), "File not found in context show output"); - assert!(show_response.contains("πŸ’¬ Session (temporary):"), "Missing Session section"); - println!("βœ… File confirmed present in context"); - - // Remove file from context - let remove_response = chat.execute_command(&format!("/context remove {}", test_file_path))?; - - println!("πŸ“ Context remove response: {} bytes", remove_response.len()); - println!("πŸ“ REMOVE RESPONSE:"); - println!("{}", remove_response); - println!("πŸ“ END REMOVE RESPONSE"); - - // Verify file was removed successfully - assert!(remove_response.contains("Removed 1 path(s) from context"), "Missing success message for removing file"); - println!("βœ… File removed from context successfully"); - - // Execute /context show to confirm file is gone - let final_show_response = chat.execute_command("/context show")?; - - println!("πŸ“ Final context show response: {} bytes", final_show_response.len()); - println!("πŸ“ FINAL SHOW RESPONSE:"); - println!("{}", final_show_response); - println!("πŸ“ END FINAL SHOW RESPONSE"); - - // Verify file is no longer in context - assert!(!final_show_response.contains(test_file_path), "File still found in context after removal"); - println!("βœ… File confirmed removed from context"); - - chat.quit()?; - - // Clean up test file - let _ = std::fs::remove_file(test_file_path); - println!("βœ… Cleaned up test file"); - - println!("βœ… Test completed successfully"); - - Ok(()) -} diff --git a/e2etests/tests/test_remove_multiple_file_context.rs b/e2etests/tests/test_remove_multiple_file_context.rs deleted file mode 100644 index 1f2bc00a78..0000000000 --- a/e2etests/tests/test_remove_multiple_file_context.rs +++ /dev/null @@ -1,84 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "context")] -fn test_remove_multiple_file_context() -> Result<(), Box> { - println!("πŸ” Testing /context remove command..."); - - let test_file1_path = "/tmp/test_context_file1.py"; - let test_file2_path = "/tmp/test_context_file2.js"; - let test_file3_path = "/tmp/test_context_file3.txt"; - - // Create multiple test files - std::fs::write(test_file1_path, "# Test Python file for context\nprint('Hello from Python file')")?; - std::fs::write(test_file2_path, "// Test JavaScript file for context\nconsole.log('Hello from JS file');")?; - std::fs::write(test_file3_path, "Test text file for context\nHello from text file")?; - println!("βœ… Created test files at {}, {}, {}", test_file1_path, test_file2_path, test_file3_path); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - // Add multiple files to context - let add_response = chat.execute_command(&format!("/context add {} {} {}", test_file1_path, test_file2_path, test_file3_path))?; - - println!("πŸ“ Context add response: {} bytes", add_response.len()); - println!("πŸ“ ADD RESPONSE:"); - println!("{}", add_response); - println!("πŸ“ END ADD RESPONSE"); - - // Verify files were added successfully - assert!(add_response.contains("Added 3 path(s) to context"), "Missing success message for adding multiple files"); - println!("βœ… Multiple files added to context successfully"); - - // Execute /context show to confirm files are present - let show_response = chat.execute_command("/context show")?; - - println!("πŸ“ Context show response: {} bytes", show_response.len()); - println!("πŸ“ SHOW RESPONSE:"); - println!("{}", show_response); - println!("πŸ“ END SHOW RESPONSE"); - - // Verify all files are present in context - assert!(show_response.contains(test_file1_path), "Python file not found in context show output"); - assert!(show_response.contains(test_file2_path), "JavaScript file not found in context show output"); - assert!(show_response.contains(test_file3_path), "Text file not found in context show output"); - println!("βœ… All files confirmed present in context"); - - // Remove multiple files from context - let remove_response = chat.execute_command(&format!("/context remove {} {} {}", test_file1_path, test_file2_path, test_file3_path))?; - - println!("πŸ“ Context remove response: {} bytes", remove_response.len()); - println!("πŸ“ REMOVE RESPONSE:"); - println!("{}", remove_response); - println!("πŸ“ END REMOVE RESPONSE"); - - // Verify files were removed successfully - assert!(remove_response.contains("Removed 3 path(s) from context"), "Missing success message for removing multiple files"); - println!("βœ… Multiple files removed from context successfully"); - - // Execute /context show to confirm files are gone - let final_show_response = chat.execute_command("/context show")?; - - println!("πŸ“ Final context show response: {} bytes", final_show_response.len()); - println!("πŸ“ FINAL SHOW RESPONSE:"); - println!("{}", final_show_response); - println!("πŸ“ END FINAL SHOW RESPONSE"); - - // Verify files are no longer in context - assert!(!final_show_response.contains(test_file1_path), "Python file still found in context after removal"); - assert!(!final_show_response.contains(test_file2_path), "JavaScript file still found in context after removal"); - assert!(!final_show_response.contains(test_file3_path), "Text file still found in context after removal"); - println!("βœ… All files confirmed removed from context"); - - chat.quit()?; - - // Clean up test files - let _ = std::fs::remove_file(test_file1_path); - let _ = std::fs::remove_file(test_file2_path); - let _ = std::fs::remove_file(test_file3_path); - println!("βœ… Cleaned up test files"); - - println!("βœ… Test completed successfully"); - - Ok(()) -} From a6267637426cf3e2e65a6a66780d5d1a9547e0f6 Mon Sep 17 00:00:00 2001 From: Abhishek Anne Date: Wed, 20 Aug 2025 14:02:40 +0530 Subject: [PATCH 18/77] QCLI Test automation - seperated common methods --- e2etests/src/lib.rs | 31 ++++++++++++++++ e2etests/tests/test_agent_commands.rs | 52 +++++++-------------------- 2 files changed, 43 insertions(+), 40 deletions(-) diff --git a/e2etests/src/lib.rs b/e2etests/src/lib.rs index a454a5813b..43bf407062 100644 --- a/e2etests/src/lib.rs +++ b/e2etests/src/lib.rs @@ -1,6 +1,37 @@ // Q CLI E2E Test Framework // This library provides end-to-end testing utilities for Amazon Q CLI +use std::sync::{Mutex, Once, atomic::{AtomicUsize, Ordering}}; + +static INIT: Once = Once::new(); +static mut CHAT_SESSION: Option> = None; + +pub fn get_chat_session() -> &'static Mutex { + unsafe { + INIT.call_once(|| { + let chat = q_chat_helper::QChatSession::new().expect("Failed to create chat session"); + println!("βœ… Q Chat session started"); + CHAT_SESSION = Some(Mutex::new(chat)); + }); + CHAT_SESSION.as_ref().unwrap() + } +} + +pub fn cleanup_if_last_test(test_count: &AtomicUsize, total_tests: usize) -> Result> { + let count = test_count.fetch_add(1, Ordering::SeqCst) + 1; + if count == total_tests { + unsafe { + if let Some(session) = &CHAT_SESSION { + if let Ok(mut chat) = session.lock() { + chat.quit()?; + println!("βœ… Test completed successfully"); + } + } + } + } + Ok(count) +} + pub mod q_chat_helper { //! Helper module for Q CLI testing with hybrid approach //! - expectrl for commands (/help, /tools) diff --git a/e2etests/tests/test_agent_commands.rs b/e2etests/tests/test_agent_commands.rs index 6e0d920e79..617bd88462 100644 --- a/e2etests/tests/test_agent_commands.rs +++ b/e2etests/tests/test_agent_commands.rs @@ -1,36 +1,8 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; -use std::sync::{Mutex, Once, atomic::{AtomicUsize, Ordering}}; +use q_cli_e2e_tests::{get_chat_session, cleanup_if_last_test}; +use std::sync::atomic::{AtomicUsize, Ordering}; -static INIT: Once = Once::new(); -static mut CHAT_SESSION: Option> = None; static TEST_COUNT: AtomicUsize = AtomicUsize::new(0); -static TOTAL_TESTS: usize = 8; // Updated for active tests - -fn get_chat_session() -> &'static Mutex { - unsafe { - INIT.call_once(|| { - let chat = QChatSession::new().expect("Failed to create chat session"); - println!("βœ… Q Chat session started"); - CHAT_SESSION = Some(Mutex::new(chat)); - }); - CHAT_SESSION.as_ref().unwrap() - } -} - -fn cleanup_if_last_test() -> Result<(), Box> { - let count = TEST_COUNT.fetch_add(1, Ordering::SeqCst) + 1; - if count == TOTAL_TESTS { - unsafe { - if let Some(session) = &CHAT_SESSION { - if let Ok(mut chat) = session.lock() { - chat.quit()?; - println!("βœ… Test completed successfully"); - } - } - } - } - Ok(()) -} +const TOTAL_TESTS: usize = 9; // Updated for active tests #[test] #[cfg(feature = "agent")] @@ -78,7 +50,7 @@ fn agent_without_subcommand() -> Result<(), Box> { drop(chat); // Cleanup only if this is the last test - cleanup_if_last_test()?; + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; Ok(()) } @@ -145,7 +117,7 @@ fn test_agent_create_command() -> Result<(), Box> { drop(chat); // Cleanup only if this is the last test - cleanup_if_last_test()?; + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; Ok(()) } @@ -194,7 +166,7 @@ fn test_agent_create_missing_args() -> Result<(), Box> { drop(chat); // Cleanup only if this is the last test - cleanup_if_last_test()?; + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; Ok(()) } @@ -249,7 +221,7 @@ fn test_agent_help_command() -> Result<(), Box> { drop(chat); // Cleanup only if this is the last test - cleanup_if_last_test()?; + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; Ok(()) } @@ -286,7 +258,7 @@ fn test_agent_invalid_command() -> Result<(), Box> { drop(chat); // Cleanup only if this is the last test - cleanup_if_last_test()?; + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; Ok(()) } @@ -318,7 +290,7 @@ fn test_agent_list_command() -> Result<(), Box> { drop(chat); // Cleanup only if this is the last test - cleanup_if_last_test()?; + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; Ok(()) } @@ -357,7 +329,7 @@ fn test_agent_list_command() -> Result<(), Box> { // drop(chat); // // Cleanup only if this is the last test -// cleanup_if_last_test()?; +// cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; // Ok(()) // } @@ -396,7 +368,7 @@ fn test_agent_set_default_command() -> Result<(), Box> { drop(chat); // Cleanup only if this is the last test - cleanup_if_last_test()?; + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; Ok(()) } @@ -444,7 +416,7 @@ fn test_agent_set_default_missing_args() -> Result<(), Box Date: Wed, 20 Aug 2025 15:16:33 +0530 Subject: [PATCH 19/77] QCLI Test automation - merged ai_prompts feature test into one --- e2etests/tests/test_prompts_command.rs | 37 ----- e2etests/tests/test_prompts_commands.rs | 152 ++++++++++++++++++++ e2etests/tests/test_prompts_help_command.rs | 59 -------- e2etests/tests/test_prompts_list_command.rs | 37 ----- 4 files changed, 152 insertions(+), 133 deletions(-) delete mode 100644 e2etests/tests/test_prompts_command.rs create mode 100644 e2etests/tests/test_prompts_commands.rs delete mode 100644 e2etests/tests/test_prompts_help_command.rs delete mode 100644 e2etests/tests/test_prompts_list_command.rs diff --git a/e2etests/tests/test_prompts_command.rs b/e2etests/tests/test_prompts_command.rs deleted file mode 100644 index 1cd00d1866..0000000000 --- a/e2etests/tests/test_prompts_command.rs +++ /dev/null @@ -1,37 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "ai_prompts")] -fn test_prompts_command() -> Result<(), Box> { - println!("πŸ” Testing /prompts command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/prompts")?; - - println!("πŸ“ Prompts command response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify usage instruction - assert!(response.contains("Usage:") && response.contains("@") && response.contains("") && response.contains("[...args]"), "Missing usage instruction"); - println!("βœ… Found usage instruction"); - - // Verify table headers - assert!(response.contains("Prompt"), "Missing Prompt header"); - assert!(response.contains("Arguments") && response.contains("*") && response.contains("required"), "Missing Arguments header"); - println!("βœ… Found table headers with required notation"); - - // Verify command executed successfully - assert!(!response.is_empty(), "Empty response from prompts command"); - println!("βœ… Command executed with response"); - - println!("βœ… All prompts command functionality verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} \ No newline at end of file diff --git a/e2etests/tests/test_prompts_commands.rs b/e2etests/tests/test_prompts_commands.rs new file mode 100644 index 0000000000..664a3e3165 --- /dev/null +++ b/e2etests/tests/test_prompts_commands.rs @@ -0,0 +1,152 @@ +use q_cli_e2e_tests::{get_chat_session, cleanup_if_last_test}; +use std::sync::atomic::{AtomicUsize, Ordering}; + +static TEST_COUNT: AtomicUsize = AtomicUsize::new(0); + +// List of covered tests +const TEST_NAMES: &[&str] = &[ + "test_prompts_command", + "test_prompts_help_command", + "test_prompts_list_command", +]; +const TOTAL_TESTS: usize = TEST_NAMES.len(); + + +#[test] +#[cfg(feature = "ai_prompts")] +fn test_prompts_command() -> Result<(), Box> { + println!("πŸ” Testing /prompts command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + + let response = chat.execute_command("/prompts")?; + + println!("πŸ“ Prompts command response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify usage instruction + assert!(response.contains("Usage:") && response.contains("@") && response.contains("") && response.contains("[...args]"), "Missing usage instruction"); + println!("βœ… Found usage instruction"); + + // Verify table headers + assert!(response.contains("Prompt"), "Missing Prompt header"); + assert!(response.contains("Arguments") && response.contains("*") && response.contains("required"), "Missing Arguments header"); + println!("βœ… Found table headers with required notation"); + + // Verify command executed successfully + assert!(!response.is_empty(), "Empty response from prompts command"); + println!("βœ… Command executed with response"); + + println!("βœ… All prompts command functionality verified!"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} + +#[test] +#[cfg(feature = "ai_prompts")] +fn test_prompts_help_command() -> Result<(), Box> { + println!("πŸ” Testing /prompts --help command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + + let response = chat.execute_command("/prompts --help")?; + + println!("πŸ“ Prompts help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify description + assert!(response.contains("Prompts are reusable templates that help you quickly access common workflows and tasks"), "Missing prompts description"); + assert!(response.contains("These templates are provided by the mcp servers you have installed and configured"), "Missing MCP servers description"); + println!("βœ… Found prompts description"); + + // Verify usage examples + assert!(response.contains("@") && response.contains(" [arg]") && response.contains("[arg]"), "Missing @ syntax example"); + assert!(response.contains("Retrieve prompt specified"), "Missing retrieve description"); + assert!(response.contains("/prompts") && response.contains("get") && response.contains("") && response.contains("[arg]"), "Missing long form example"); + println!("βœ… Found usage examples with @ syntax and long form"); + + // Verify main description + assert!(response.contains("View and retrieve prompts"), "Missing main description"); + println!("βœ… Found main description"); + + // Verify Usage section + assert!(response.contains("Usage:") && response.contains("/prompts") && response.contains("[COMMAND]"), "Missing usage format"); + println!("βœ… Found usage format"); + + // Verify Commands section + assert!(response.contains("Commands:"), "Missing Commands section"); + assert!(response.contains("list"), "Missing list command"); + assert!(response.contains("get"), "Missing get command"); + assert!(response.contains("help"), "Missing help command"); + println!("βœ… Found all commands: list, get, help"); + + // Verify command descriptions + assert!(response.contains("List available prompts from a tool or show all available prompt"), "Missing list description"); + println!("βœ… Found command descriptions"); + + // Verify Options section + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("-h") && response.contains("--help"), "Missing help flags"); + println!("βœ… Found Options section with help flags"); + + println!("βœ… All prompts help content verified!"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} + +#[test] +#[cfg(feature = "ai_prompts")] +fn test_prompts_list_command() -> Result<(), Box> { + println!("πŸ” Testing /prompts list command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + + let response = chat.execute_command("/prompts list")?; + + println!("πŸ“ Prompts list response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify usage instruction + assert!(response.contains("Usage:") && response.contains("@") && response.contains("") && response.contains("[...args]"), "Missing usage instruction"); + println!("βœ… Found usage instruction"); + + // Verify table headers + assert!(response.contains("Prompt"), "Missing Prompt header"); + assert!(response.contains("Arguments") && response.contains("*") && response.contains("required"), "Missing Arguments header"); + println!("βœ… Found table headers with required notation"); + + // Verify command executed successfully + assert!(!response.is_empty(), "Empty response from prompts list command"); + println!("βœ… Command executed with response"); + + println!("βœ… All prompts list command functionality verified!"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_prompts_help_command.rs b/e2etests/tests/test_prompts_help_command.rs deleted file mode 100644 index 80f39e899c..0000000000 --- a/e2etests/tests/test_prompts_help_command.rs +++ /dev/null @@ -1,59 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "ai_prompts")] -fn test_prompts_help_command() -> Result<(), Box> { - println!("πŸ” Testing /prompts --help command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/prompts --help")?; - - println!("πŸ“ Prompts help response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify description - assert!(response.contains("Prompts are reusable templates that help you quickly access common workflows and tasks"), "Missing prompts description"); - assert!(response.contains("These templates are provided by the mcp servers you have installed and configured"), "Missing MCP servers description"); - println!("βœ… Found prompts description"); - - // Verify usage examples - assert!(response.contains("@") && response.contains(" [arg]") && response.contains("[arg]"), "Missing @ syntax example"); - assert!(response.contains("Retrieve prompt specified"), "Missing retrieve description"); - assert!(response.contains("/prompts") && response.contains("get") && response.contains("") && response.contains("[arg]"), "Missing long form example"); - println!("βœ… Found usage examples with @ syntax and long form"); - - // Verify main description - assert!(response.contains("View and retrieve prompts"), "Missing main description"); - println!("βœ… Found main description"); - - // Verify Usage section - assert!(response.contains("Usage:") && response.contains("/prompts") && response.contains("[COMMAND]"), "Missing usage format"); - println!("βœ… Found usage format"); - - // Verify Commands section - assert!(response.contains("Commands:"), "Missing Commands section"); - assert!(response.contains("list"), "Missing list command"); - assert!(response.contains("get"), "Missing get command"); - assert!(response.contains("help"), "Missing help command"); - println!("βœ… Found all commands: list, get, help"); - - // Verify command descriptions - assert!(response.contains("List available prompts from a tool or show all available prompt"), "Missing list description"); - println!("βœ… Found command descriptions"); - - // Verify Options section - assert!(response.contains("Options:"), "Missing Options section"); - assert!(response.contains("-h") && response.contains("--help"), "Missing help flags"); - println!("βœ… Found Options section with help flags"); - - println!("βœ… All prompts help content verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} \ No newline at end of file diff --git a/e2etests/tests/test_prompts_list_command.rs b/e2etests/tests/test_prompts_list_command.rs deleted file mode 100644 index 56043c3d92..0000000000 --- a/e2etests/tests/test_prompts_list_command.rs +++ /dev/null @@ -1,37 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "ai_prompts1")] -fn test_prompts_command() -> Result<(), Box> { - println!("πŸ” Testing /prompts command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/prompts list")?; - - println!("πŸ“ Prompts command response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify usage instruction - assert!(response.contains("Usage:") && response.contains("@") && response.contains("") && response.contains("[...args]"), "Missing usage instruction"); - println!("βœ… Found usage instruction"); - - // Verify table headers - assert!(response.contains("Prompt"), "Missing Prompt header"); - assert!(response.contains("Arguments") && response.contains("*") && response.contains("required"), "Missing Arguments header"); - println!("βœ… Found table headers with required notation"); - - // Verify command executed successfully - assert!(!response.is_empty(), "Empty response from prompts command"); - println!("βœ… Command executed with response"); - - println!("βœ… All prompts command functionality verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} \ No newline at end of file From 80fde54c021686254a0a18e3571e2917ed6bebf7 Mon Sep 17 00:00:00 2001 From: Abhishek Anne Date: Wed, 20 Aug 2025 19:02:19 +0530 Subject: [PATCH 20/77] QCLI Test automation - merged agent feature test into one --- e2etests/tests/test_agent_commands.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/e2etests/tests/test_agent_commands.rs b/e2etests/tests/test_agent_commands.rs index 617bd88462..4271ae815e 100644 --- a/e2etests/tests/test_agent_commands.rs +++ b/e2etests/tests/test_agent_commands.rs @@ -2,7 +2,19 @@ use q_cli_e2e_tests::{get_chat_session, cleanup_if_last_test}; use std::sync::atomic::{AtomicUsize, Ordering}; static TEST_COUNT: AtomicUsize = AtomicUsize::new(0); -const TOTAL_TESTS: usize = 9; // Updated for active tests + +const TEST_NAMES: &[&str] = &[ + "agent_without_subcommand", + "test_agent_create_command", + "test_agent_create_missing_args", + "test_agent_help_command", + "test_agent_invalid_command", + "test_agent_list_command", + // "test_agent_schema_command", + "test_agent_set_default_command", + "test_agent_set_default_missing_args", +]; +const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] #[cfg(feature = "agent")] From 5452ba1f37f20af3182f8aaed6d38487a5e524f0 Mon Sep 17 00:00:00 2001 From: "Shreya [C] Bhagat" Date: Wed, 20 Aug 2025 19:32:24 +0530 Subject: [PATCH 21/77] QCLI Automation for MCP Feature --- .../tests/test_add_and_remove_mcp_command.rs | 100 --- e2etests/tests/test_context_command.rs | 377 +++++++---- e2etests/tests/test_mcp_command.rs | 598 ++++++++++++++++++ e2etests/tests/test_mcp_help_command.rs | 42 -- e2etests/tests/test_mcp_loading_command.rs | 38 -- .../tests/test_mcp_remove_help_command.rs | 46 -- e2etests/tests/test_q_mcp_add_help_command.rs | 61 -- e2etests/tests/test_q_mcp_help_command.rs | 56 -- .../tests/test_q_mcp_import_help_command.rs | 69 -- e2etests/tests/test_q_mcp_list_command.rs | 44 -- .../tests/test_q_mcp_list_help_command.rs | 58 -- e2etests/tests/test_q_mcp_status_command.rs | 66 -- .../tests/test_q_mcp_status_help_command.rs | 63 -- 13 files changed, 850 insertions(+), 768 deletions(-) delete mode 100644 e2etests/tests/test_add_and_remove_mcp_command.rs create mode 100644 e2etests/tests/test_mcp_command.rs delete mode 100644 e2etests/tests/test_mcp_help_command.rs delete mode 100644 e2etests/tests/test_mcp_loading_command.rs delete mode 100644 e2etests/tests/test_mcp_remove_help_command.rs delete mode 100644 e2etests/tests/test_q_mcp_add_help_command.rs delete mode 100644 e2etests/tests/test_q_mcp_help_command.rs delete mode 100644 e2etests/tests/test_q_mcp_import_help_command.rs delete mode 100644 e2etests/tests/test_q_mcp_list_command.rs delete mode 100644 e2etests/tests/test_q_mcp_list_help_command.rs delete mode 100644 e2etests/tests/test_q_mcp_status_command.rs delete mode 100644 e2etests/tests/test_q_mcp_status_help_command.rs diff --git a/e2etests/tests/test_add_and_remove_mcp_command.rs b/e2etests/tests/test_add_and_remove_mcp_command.rs deleted file mode 100644 index f3d99f5f5a..0000000000 --- a/e2etests/tests/test_add_and_remove_mcp_command.rs +++ /dev/null @@ -1,100 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "mcp")] -fn test_add_and_remove_mcp_command() -> Result<(), Box> { - println!("πŸ” Testing q mcp add command..."); - - // First install uv dependency before starting Q Chat - println!("πŸ” Installing uv dependency..."); - std::process::Command::new("pip3") - .args(["install", "uv", "--break-system-packages"]) - .output() - .expect("Failed to install uv"); - println!("βœ… uv dependency installed"); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - // Execute mcp add command - println!("πŸ” Executing command: 'q mcp add --name aws-documentation --command uvx --args awslabs.aws-documentation-mcp-server@latest'"); - let response = chat.execute_command("q mcp add --name aws-documentation --command uvx --args awslabs.aws-documentation-mcp-server@latest")?; - - println!("πŸ“ Response: {} bytes", response.len()); - println!("πŸ“ RESPONSE:"); - println!("{}", response); - println!("πŸ“ END RESPONSE"); - - // Verify tool execution details - assert!(response.contains("I will run the following shell command:"), "Missing command execution description"); - assert!(response.contains("q mcp add --name aws-documentation --command uvx --args awslabs.aws-documentation-mcp-server@latest"), "Missing full command"); - assert!(response.contains("Purpose:") && response.contains("Add AWS documentation MCP server"), "Missing purpose description"); - println!("βœ… Found tool execution details"); - - // Verify tool execution prompt appears - assert!(response.contains("πŸ› οΈ Using tool: execute_bash"), "Missing tool execution indicator"); - assert!(response.contains("Allow this action?") && response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); - println!("βœ… Found tool execution permission prompt"); - - // Allow the tool execution - let allow_response = chat.execute_command("y")?; - - println!("πŸ“ Allow response: {} bytes", allow_response.len()); - println!("πŸ“ ALLOW RESPONSE:"); - println!("{}", allow_response); - println!("πŸ“ END ALLOW RESPONSE"); - - // Verify successful addition - assert!(allow_response.contains("βœ“ Added MCP server") && allow_response.contains("'aws-documentation'") && allow_response.contains("to global config in"), "Missing success message"); - assert!(allow_response.contains("/Users/") && allow_response.contains("/.aws/amazonq/mcp.json"), "Missing config file path"); - println!("βœ… Found successful addition message"); - - // Verify completion indicator - assert!(allow_response.contains("Completed in") && allow_response.contains("s"), "Missing completion time indicator"); - println!("βœ… Found completion indicator"); - - println!("βœ… All q mcp add command execution verified successfully"); - - // Now test removing the MCP server - println!("πŸ” Executing remove command: 'q mcp remove --name aws-documentation'"); - let remove_response = chat.execute_command("q mcp remove --name aws-documentation")?; - - println!("πŸ“ Remove response: {} bytes", remove_response.len()); - println!("πŸ“ REMOVE RESPONSE:"); - println!("{}", remove_response); - println!("πŸ“ END REMOVE RESPONSE"); - - // Verify remove tool execution details - assert!(remove_response.contains("I will run the following shell command:"), "Missing remove command execution description"); - assert!(remove_response.contains("q mcp remove --name aws-documentation"), "Missing full remove command"); - println!("βœ… Found remove tool execution details"); - - // Verify remove tool execution prompt - assert!(remove_response.contains("πŸ› οΈ Using tool: execute_bash"), "Missing remove tool execution indicator"); - assert!(remove_response.contains("Allow this action?"), "Missing remove permission prompt"); - println!("βœ… Found remove tool execution permission prompt"); - - // Allow the remove tool execution - let remove_allow_response = chat.execute_command("y")?; - - println!("πŸ“ Remove allow response: {} bytes", remove_allow_response.len()); - println!("πŸ“ REMOVE ALLOW RESPONSE:"); - println!("{}", remove_allow_response); - println!("πŸ“ END REMOVE ALLOW RESPONSE"); - - // Verify successful removal - assert!(remove_allow_response.contains("βœ“ Removed MCP server") && remove_allow_response.contains("'aws-documentation'") && remove_allow_response.contains("from global config"), "Missing removal success message"); - assert!(remove_allow_response.contains("/Users/") && remove_allow_response.contains("/.aws/amazonq/mcp.json"), "Missing config file path in removal"); - println!("βœ… Found successful removal message"); - - // Verify remove completion indicator - assert!(remove_allow_response.contains("Completed in") && remove_allow_response.contains("s"), "Missing remove completion time indicator"); - println!("βœ… Found remove completion indicator"); - - println!("βœ… All q mcp remove command execution verified successfully"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} \ No newline at end of file diff --git a/e2etests/tests/test_context_command.rs b/e2etests/tests/test_context_command.rs index 19889d0d45..e5db3b3adf 100644 --- a/e2etests/tests/test_context_command.rs +++ b/e2etests/tests/test_context_command.rs @@ -1,57 +1,30 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; +use q_cli_e2e_tests::{get_chat_session, cleanup_if_last_test}; +use std::sync::atomic::{AtomicUsize, Ordering}; -#[test] -#[cfg(feature = "context")] -fn test_context_command() -> Result<(), Box> { - println!("πŸ” Testing context commands..."); - - let test_file_path = "/tmp/test_context_file.py"; - // Create a test file - std::fs::write(test_file_path, "# Test file for context\nprint('Hello from test file')")?; - println!("βœ… Created test file at {}", test_file_path); +static TEST_COUNT: AtomicUsize = AtomicUsize::new(0); - let non_existing_file_path = "/tmp/non_existing_file.py"; - - let test_file1_path = "/tmp/test_context_file1.py"; - let test_file2_path = "/tmp/test_context_file2.py"; - let test_file3_path = "/tmp/test_context_file.js"; // Non-matching file - let glob_pattern = "/tmp/*.py"; - - // Create test files - std::fs::write(test_file1_path, "# Test Python file 1 for context\nprint('Hello from Python file 1')")?; - std::fs::write(test_file2_path, "# Test Python file 2 for context\nprint('Hello from Python file 2')")?; - std::fs::write(test_file3_path, "// Test JavaScript file\nconsole.log('Hello from JS file');")?; - println!("βœ… Created test files at {}, {}, {}", test_file1_path, test_file2_path, test_file3_path); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - test_context_show_command(&mut chat)?; - test_context_help_command(&mut chat)?; - test_context_without_subcommand(&mut chat)?; - test_context_invalid_command(&mut chat)?; - test_add_non_existing_file_context(&mut chat, non_existing_file_path)?; - test_context_remove_command_of_non_existent_file(&mut chat)?; - test_add_remove_file_context(&mut chat, test_file_path)?; - test_add_glob_pattern_file_context(&mut chat, glob_pattern)?; - test_add_remove_multiple_file_context(&mut chat, test_file1_path, test_file2_path, test_file3_path)?; - test_clear_context_command(&mut chat, test_file1_path, test_file2_path)?; - - chat.quit()?; - // Clean up test file - let _ = std::fs::remove_file(test_file_path); - let _ = std::fs::remove_file(test_file1_path); - let _ = std::fs::remove_file(test_file2_path); - let _ = std::fs::remove_file(test_file3_path); - println!("βœ… Cleaned up test file"); +// List of covered tests +const TEST_NAMES: &[&str] = &[ + "test_context_show_command", + "test_context_help_command", + "test_context_without_subcommand", + "test_context_invalid_command", + "test_add_non_existing_file_context", + "test_context_remove_command_of_non_existent_file", + "test_add_remove_file_context", + "test_add_glob_pattern_file_context", + "test_clear_context_command", + "test_add_remove_multiple_file_context" +]; +const TOTAL_TESTS: usize = TEST_NAMES.len(); - println!("βœ… Test completed successfully"); - - Ok(()) -} - -fn test_context_show_command(chat: &mut QChatSession) -> Result<(), Box> { +#[test] +#[cfg(feature = "context")] +fn test_context_show_command() -> Result<(), Box> { println!("πŸ” Testing /context show command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); let response = chat.execute_command("/context show")?; @@ -65,19 +38,28 @@ fn test_context_show_command(chat: &mut QChatSession) -> Result<(), Box Result<(), Box> { +#[test] +#[cfg(feature = "context")] +fn test_context_help_command() -> Result<(), Box> { println!("πŸ” Testing /context help command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); let response = chat.execute_command("/context help")?; @@ -107,12 +89,23 @@ fn test_context_help_command(chat: &mut QChatSession) -> Result<(), Box Result<(), Box> { +#[test] +#[cfg(feature = "context")] +fn test_context_without_subcommand() -> Result<(), Box> { println!("πŸ” Testing /context without sub command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); let response = chat.execute_command("/context")?; @@ -140,12 +133,23 @@ fn test_context_without_subcommand(chat: &mut QChatSession) -> Result<(), Box Result<(), Box> { +#[test] +#[cfg(feature = "context")] +fn test_context_invalid_command() -> Result<(), Box> { println!("πŸ” Testing /context invalid command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); let response = chat.execute_command("/context test")?; @@ -177,12 +181,25 @@ fn test_context_invalid_command(chat: &mut QChatSession) -> Result<(), Box Result<(), Box> { +#[test] +#[cfg(feature = "context")] +fn test_add_non_existing_file_context() -> Result<(), Box> { println!("πŸ” Testing /context add non-existing file command..."); + + let non_existing_file_path = "/tmp/non_existing_file.py"; + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); // Try to add non-existing file to context let add_response = chat.execute_command(&format!("/context add {}", non_existing_file_path))?; @@ -196,13 +213,23 @@ fn test_add_non_existing_file_context(chat: &mut QChatSession, non_existing_file assert!(add_response.contains("Error:") && add_response.contains("Invalid path") && add_response.contains("does not exist"), "Missing error message for non-existing file"); assert!(add_response.contains("Use --force to add anyway"), "Missing --force suggestion in error message"); println!("βœ… Found expected error message for non-existing file with --force suggestion"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; Ok(()) } - -fn test_context_remove_command_of_non_existent_file(chat: &mut QChatSession) -> Result<(), Box> { +#[test] +#[cfg(feature = "context")] +fn test_context_remove_command_of_non_existent_file() -> Result<(), Box> { println!("πŸ” Testing /context remove non existing file command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); let response = chat.execute_command("/context remove non_existent_file.txt")?; @@ -214,12 +241,28 @@ fn test_context_remove_command_of_non_existent_file(chat: &mut QChatSession) -> // Verify error message for non-existent file assert!(response.contains("Error:"), "Missing error message for non-existent file"); println!("βœ… Found expected error message for non-existent file removal"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; Ok(()) } -fn test_add_remove_file_context(chat: &mut QChatSession, test_file_path: &str) -> Result<(), Box> { +#[test] +#[cfg(feature = "context")] +fn test_add_remove_file_context() -> Result<(), Box> { println!("πŸ” Testing /context add command and /context remove command..."); + + let test_file_path = "/tmp/test_context_file_.py"; + // Create a test file + std::fs::write(test_file_path, "# Test file for context\nprint('Hello from test file')")?; + println!("βœ… Created test file at {}", test_file_path); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); // Add file to context let add_response = chat.execute_command(&format!("/context add {}", test_file_path))?; @@ -229,8 +272,8 @@ fn test_add_remove_file_context(chat: &mut QChatSession, test_file_path: &str) - println!("{}", add_response); println!("πŸ“ END ADD RESPONSE"); - // Verify file was added successfully - assert!(add_response.contains("Added 1 path(s) to context"), "Missing success message for adding file"); + // Verify file was added successfully - be flexible with the exact message format + assert!(add_response.contains("Added") && (add_response.contains("1 path(s) to context") || add_response.contains("1 path to context") || add_response.contains("1 file to context")), "Missing success message for adding file"); println!("βœ… File added to context successfully"); // Execute /context show to confirm file is present @@ -254,8 +297,8 @@ fn test_add_remove_file_context(chat: &mut QChatSession, test_file_path: &str) - println!("{}", remove_response); println!("πŸ“ END REMOVE RESPONSE"); - // Verify file was removed successfully - assert!(remove_response.contains("Removed 1 path(s) from context"), "Missing success message for removing file"); + // Verify file was removed successfully - be flexible with the exact message format + assert!(remove_response.contains("Removed") && (remove_response.contains("1 path(s) from context") || remove_response.contains("1 path from context") || remove_response.contains("1 file from context")), "Missing success message for removing file"); println!("βœ… File removed from context successfully"); // Execute /context show to confirm file is gone @@ -269,12 +312,38 @@ fn test_add_remove_file_context(chat: &mut QChatSession, test_file_path: &str) - // Verify file is no longer in context assert!(!final_show_response.contains(test_file_path), "File still found in context after removal"); println!("βœ… File confirmed removed from context"); + + // Release the lock before cleanup + drop(chat); + + // Clean up test file + let _ = std::fs::remove_file(test_file_path); + println!("βœ… Cleaned up test file"); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; Ok(()) } -fn test_add_glob_pattern_file_context(chat: &mut QChatSession, glob_pattern: &str) -> Result<(), Box> { +#[test] +#[cfg(feature = "context")] +fn test_add_glob_pattern_file_context()-> Result<(), Box> { println!("πŸ” Testing /context add *.py glob pattern command..."); + + let test_file1_path = "/tmp/test_context_file1.py"; + let test_file2_path = "/tmp/test_context_file2.py"; + let test_file3_path = "/tmp/test_context_file.js"; // Non-matching file + let glob_pattern = "/tmp/*.py"; + + // Create test files + std::fs::write(test_file1_path, "# Test Python file 1 for context\nprint('Hello from Python file 1')")?; + std::fs::write(test_file2_path, "# Test Python file 2 for context\nprint('Hello from Python file 2')")?; + std::fs::write(test_file3_path, "// Test JavaScript file\nconsole.log('Hello from JS file');")?; + println!("βœ… Created test files at {}, {}, {}", test_file1_path, test_file2_path, test_file3_path); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); // Add glob pattern to context let add_response = chat.execute_command(&format!("/context add {}", glob_pattern))?; @@ -284,8 +353,8 @@ fn test_add_glob_pattern_file_context(chat: &mut QChatSession, glob_pattern: &st println!("{}", add_response); println!("πŸ“ END ADD RESPONSE"); - // Verify glob pattern was added successfully - assert!(add_response.contains("Added 1 path(s) to context"), "Missing success message for adding glob pattern"); + // Verify glob pattern was added successfully - be flexible with the exact message format + assert!(add_response.contains("Added") && (add_response.contains("1 path(s) to context") || add_response.contains("1 path to context") || add_response.contains("1 pattern to context")), "Missing success message for adding glob pattern"); println!("βœ… Glob pattern added to context successfully"); // Execute /context show to confirm pattern matches files @@ -310,8 +379,8 @@ fn test_add_glob_pattern_file_context(chat: &mut QChatSession, glob_pattern: &st println!("{}", remove_response); println!("πŸ“ END REMOVE RESPONSE"); - // Verify glob pattern was removed successfully - assert!(remove_response.contains("Removed 1 path(s) from context"), "Missing success message for removing glob pattern"); + // Verify glob pattern was removed successfully - be flexible with the exact message format + assert!(remove_response.contains("Removed") && (remove_response.contains("1 path(s) from context") || remove_response.contains("1 path from context") || remove_response.contains("1 pattern from context")), "Missing success message for removing glob pattern"); println!("βœ… Glob pattern removed from context successfully"); // Execute /context show to confirm glob pattern is gone @@ -325,24 +394,47 @@ fn test_add_glob_pattern_file_context(chat: &mut QChatSession, glob_pattern: &st // Verify glob pattern is no longer in context assert!(!final_show_response.contains(glob_pattern), "Glob pattern still found in context after removal"); println!("βœ… Glob pattern confirmed removed from context"); + + // Release the lock before cleanup + drop(chat); + + // Clean up test file + let _ = std::fs::remove_file(test_file1_path); + let _ = std::fs::remove_file(test_file2_path); + let _ = std::fs::remove_file(test_file3_path); + println!("βœ… Cleaned up test file"); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; Ok(()) } -fn test_add_remove_multiple_file_context(chat: &mut QChatSession, test_file1_path: &str, test_file2_path: &str, test_file3_path: &str) -> Result<(), Box> { - println!("πŸ” Testing /context add command and /context remove ..."); +#[test] +#[cfg(feature = "context")] +fn test_clear_context_command()-> Result<(), Box> { + println!("πŸ” Testing /context clear command..."); + + let test_file_path = "/tmp/test_context_file.py"; - // Add multiple files to context in one command - let add_response = chat.execute_command(&format!("/context add {} {} {}", test_file1_path, test_file2_path, test_file3_path))?; + // Create test files + std::fs::write(test_file_path, "# Test Python file 1 for context\nprint('Hello from Python file 1')")?; + println!("βœ… Created test files at {}", test_file_path); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + // Add multiple files to context + let add_response = chat.execute_command(&format!("/context add {}", test_file_path))?; println!("πŸ“ Context add response: {} bytes", add_response.len()); println!("πŸ“ ADD RESPONSE:"); println!("{}", add_response); println!("πŸ“ END ADD RESPONSE"); - // Verify files were added successfully - assert!(add_response.contains("Added 3 path(s) to context"), "Missing success message for adding multiple files"); - println!("βœ… Multiple files added to context successfully"); + // Verify files were added successfully - be flexible with the exact message format + assert!(add_response.contains("Added") && (add_response.contains("1 path(s) to context") || add_response.contains("2 paths to context") || add_response.contains("2 files to context")), "Missing success message for adding files"); + println!("βœ… Files added to context successfully"); // Execute /context show to confirm files are present let show_response = chat.execute_command("/context show")?; @@ -352,26 +444,23 @@ fn test_add_remove_multiple_file_context(chat: &mut QChatSession, test_file1_pat println!("{}", show_response); println!("πŸ“ END SHOW RESPONSE"); - // Verify all files are present in context - assert!(show_response.contains(test_file1_path), "Python file not found in context show output"); - assert!(show_response.contains(test_file2_path), "JavaScript file not found in context show output"); - assert!(show_response.contains(test_file3_path), "Text file not found in context show output"); - assert!(show_response.contains("πŸ’¬ Session (temporary):"), "Missing Session section"); - println!("βœ… All files confirmed present in context"); - - // Remove multiple files from context - let remove_response = chat.execute_command(&format!("/context remove {} {} {}", test_file1_path, test_file2_path, test_file3_path))?; + // Verify files are present in context + assert!(show_response.contains(test_file_path), "Python file not found in context show output"); + println!("βœ… Files confirmed present in context"); - println!("πŸ“ Context remove response: {} bytes", remove_response.len()); - println!("πŸ“ REMOVE RESPONSE:"); - println!("{}", remove_response); - println!("πŸ“ END REMOVE RESPONSE"); + // Execute /context clear to remove all files + let clear_response = chat.execute_command("/context clear")?; - // Verify files were removed successfully - assert!(remove_response.contains("Removed 3 path(s) from context"), "Missing success message for removing multiple files"); - println!("βœ… Multiple files removed from context successfully"); + println!("πŸ“ Context clear response: {} bytes", clear_response.len()); + println!("πŸ“ CLEAR RESPONSE:"); + println!("{}", clear_response); + println!("πŸ“ END CLEAR RESPONSE"); - // Execute /context show to confirm files are gone + // Verify context was cleared successfully + assert!(clear_response.contains("Cleared context"), "Missing success message for clearing context"); + println!("βœ… Context cleared successfully"); + + // Execute /context show to confirm no files remain let final_show_response = chat.execute_command("/context show")?; println!("πŸ“ Final context show response: {} bytes", final_show_response.len()); @@ -379,29 +468,55 @@ fn test_add_remove_multiple_file_context(chat: &mut QChatSession, test_file1_pat println!("{}", final_show_response); println!("πŸ“ END FINAL SHOW RESPONSE"); - // Verify files are no longer in context - assert!(!final_show_response.contains(test_file1_path), "Python file still found in context after removal"); - assert!(!final_show_response.contains(test_file2_path), "JavaScript file still found in context after removal"); - assert!(!final_show_response.contains(test_file3_path), "Text file still found in context after removal"); - println!("βœ… All files confirmed removed from context"); + // Verify no files remain in context + assert!(!final_show_response.contains(test_file_path), "Python file still found in context after clear"); + assert!(final_show_response.contains("πŸ‘€ Agent (q_cli_default):"), "Missing Agent section"); + assert!(final_show_response.contains("πŸ’¬ Session (temporary):"), "Missing Session section"); + assert!(final_show_response.contains(""), "Missing indicator for cleared context"); + println!("βœ… All files confirmed removed from context and sections present"); + + // Release the lock before cleanup + drop(chat); + + // Clean up test file + let _ = std::fs::remove_file(test_file_path); + println!("βœ… Cleaned up test file"); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; Ok(()) } -fn test_clear_context_command(chat: &mut QChatSession, test_file1_path: &str, test_file2_path: &str) -> Result<(), Box> { - println!("πŸ” Testing /context clear command..."); +#[test] +#[cfg(feature = "context")] +fn test_add_remove_multiple_file_context()-> Result<(), Box> { + println!("πŸ” Testing /context add command and /context remove ..."); - // Add multiple files to context - let add_response = chat.execute_command(&format!("/context add {} {}", test_file1_path, test_file2_path))?; + let test_file1_path = "/tmp/test_context_file1.py"; + let test_file2_path = "/tmp/test_context_file2.py"; + let test_file3_path = "/tmp/test_context_file.js"; + + // Create test files + std::fs::write(test_file1_path, "# Test Python file 1 for context\nprint('Hello from Python file 1')")?; + std::fs::write(test_file2_path, "# Test Python file 2 for context\nprint('Hello from Python file 2')")?; + std::fs::write(test_file3_path, "// Test JavaScript file\nconsole.log('Hello from JS file');")?; + println!("βœ… Created test files at {}, {}, {}", test_file1_path, test_file2_path, test_file3_path); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + // Add multiple files to context in one command + let add_response = chat.execute_command(&format!("/context add {} {} {}", test_file1_path, test_file2_path, test_file3_path))?; println!("πŸ“ Context add response: {} bytes", add_response.len()); println!("πŸ“ ADD RESPONSE:"); println!("{}", add_response); println!("πŸ“ END ADD RESPONSE"); - // Verify files were added successfully - assert!(add_response.contains("Added 2 path(s) to context"), "Missing success message for adding files"); - println!("βœ… Files added to context successfully"); + // Verify files were added successfully - be flexible with the exact message format + assert!(add_response.contains("Added") && (add_response.contains("3 path(s) to context") || add_response.contains("3 paths to context") || add_response.contains("3 files to context")), "Missing success message for adding multiple files"); + println!("βœ… Multiple files added to context successfully"); // Execute /context show to confirm files are present let show_response = chat.execute_command("/context show")?; @@ -411,24 +526,26 @@ fn test_clear_context_command(chat: &mut QChatSession, test_file1_path: &str, te println!("{}", show_response); println!("πŸ“ END SHOW RESPONSE"); - // Verify files are present in context + // Verify all files are present in context assert!(show_response.contains(test_file1_path), "Python file not found in context show output"); assert!(show_response.contains(test_file2_path), "JavaScript file not found in context show output"); - println!("βœ… Files confirmed present in context"); - - // Execute /context clear to remove all files - let clear_response = chat.execute_command("/context clear")?; + assert!(show_response.contains(test_file3_path), "Text file not found in context show output"); + assert!(show_response.contains("πŸ’¬ Session (temporary):"), "Missing Session section"); + println!("βœ… All files confirmed present in context"); + + // Remove multiple files from context + let remove_response = chat.execute_command(&format!("/context remove {} {} {}", test_file1_path, test_file2_path, test_file3_path))?; - println!("πŸ“ Context clear response: {} bytes", clear_response.len()); - println!("πŸ“ CLEAR RESPONSE:"); - println!("{}", clear_response); - println!("πŸ“ END CLEAR RESPONSE"); + println!("πŸ“ Context remove response: {} bytes", remove_response.len()); + println!("πŸ“ REMOVE RESPONSE:"); + println!("{}", remove_response); + println!("πŸ“ END REMOVE RESPONSE"); - // Verify context was cleared successfully - assert!(clear_response.contains("Cleared context"), "Missing success message for clearing context"); - println!("βœ… Context cleared successfully"); + // Verify files were removed successfully - be flexible with the exact message format + assert!(remove_response.contains("Removed") && (remove_response.contains("3 path(s) from context") || remove_response.contains("3 paths from context") || remove_response.contains("3 files from context")), "Missing success message for removing multiple files"); + println!("βœ… Multiple files removed from context successfully"); - // Execute /context show to confirm no files remain + // Execute /context show to confirm files are gone let final_show_response = chat.execute_command("/context show")?; println!("πŸ“ Final context show response: {} bytes", final_show_response.len()); @@ -436,13 +553,23 @@ fn test_clear_context_command(chat: &mut QChatSession, test_file1_path: &str, te println!("{}", final_show_response); println!("πŸ“ END FINAL SHOW RESPONSE"); - // Verify no files remain in context - assert!(!final_show_response.contains(test_file1_path), "Python file still found in context after clear"); - assert!(!final_show_response.contains(test_file2_path), "JavaScript file still found in context after clear"); - assert!(final_show_response.contains("πŸ‘€ Agent (q_cli_default):"), "Missing Agent section"); - assert!(final_show_response.contains("πŸ’¬ Session (temporary):"), "Missing Session section"); - assert!(final_show_response.contains(""), "Missing indicator for cleared context"); - println!("βœ… All files confirmed removed from context and sections present"); + // Verify files are no longer in context + assert!(!final_show_response.contains(test_file1_path), "Python file still found in context after removal"); + assert!(!final_show_response.contains(test_file2_path), "JavaScript file still found in context after removal"); + assert!(!final_show_response.contains(test_file3_path), "Text file still found in context after removal"); + println!("βœ… All files confirmed removed from context"); + + // Release the lock before cleanup + drop(chat); + + // Clean up test file + let _ = std::fs::remove_file(test_file1_path); + let _ = std::fs::remove_file(test_file2_path); + let _ = std::fs::remove_file(test_file3_path); + println!("βœ… Cleaned up test file"); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; Ok(()) } diff --git a/e2etests/tests/test_mcp_command.rs b/e2etests/tests/test_mcp_command.rs new file mode 100644 index 0000000000..31f34b7f32 --- /dev/null +++ b/e2etests/tests/test_mcp_command.rs @@ -0,0 +1,598 @@ +use q_cli_e2e_tests::{get_chat_session, cleanup_if_last_test}; +use std::sync::atomic::{AtomicUsize, Ordering}; + +static TEST_COUNT: AtomicUsize = AtomicUsize::new(0); + +// List of covered tests +const TEST_NAMES: &[&str] = &[ + "test_mcp_help_command", + "test_mcp_loading_command", + "test_mcp_remove_help_command", + "test_q_mcp_add_help_command", + "test_q_mcp_help_command", + "test_q_mcp_import_help_command", + "test_q_mcp_list_command", + "test_q_mcp_list_help_command", + "test_q_mcp_status_help_command", + "test_add_and_remove_mcp_command" +]; +const TOTAL_TESTS: usize = TEST_NAMES.len(); + +#[test] +#[cfg(feature = "mcp")] +fn test_mcp_help_command() -> Result<(), Box> { + println!("πŸ” Testing /mcp --help command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + let response = chat.execute_command("/mcp --help")?; + + println!("πŸ“ MCP help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify description + assert!(response.contains("See mcp server loaded"), "Missing mcp server description"); + println!("βœ… Found mcp server description"); + + // Verify Usage section + assert!(response.contains("Usage"), "Missing Usage section"); + assert!(response.contains("/mcp"), "Missing /mcp command in usage section"); + println!("βœ… Found Usage section with /mcp command"); + + // Verify Options section + assert!(response.contains("Options"), "Missing Options section"); + println!("βœ… Found Options section"); + + // Verify help flags + assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing -h, --help flags"); + println!("βœ… Found help flags: -h, --help with Print help description"); + + println!("βœ… All mcp help content verified!"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} + +#[test] +#[cfg(feature = "mcp")] +fn test_mcp_loading_command() -> Result<(), Box> { + println!("πŸ” Testing MCP loading..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + let response = chat.execute_command("/mcp")?; + + println!("πŸ“ MCP loading response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Check MCP status - either loaded or loading + if response.contains("loaded in") { + assert!(response.contains(" s"), "Missing seconds indicator for loading time"); + println!("βœ… Found MCPs loaded with timing"); + + // Count number of MCPs loaded + let mcp_count = response.matches("βœ“").count(); + println!("βœ… Found {} MCP(s) loaded", mcp_count); + } else if response.contains("loading") { + println!("βœ… MCPs are still loading"); + } else { + println!("ℹ️ MCP status unclear - may be in different state"); + } + + println!("βœ… All MCP loading content verified!"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} + +#[test] +#[cfg(feature = "mcp")] +fn test_mcp_remove_help_command() -> Result<(), Box> { + println!("πŸ” Testing q mcp remove --help command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + // Execute q mcp remove --help command + let help_response = chat.execute_command("q mcp remove --help")?; + + println!("πŸ“ MCP remove help response: {} bytes", help_response.len()); + println!("πŸ“ HELP RESPONSE:"); + println!("{}", help_response); + println!("πŸ“ END HELP RESPONSE"); + + // Verify tool execution prompt appears + assert!(help_response.contains("πŸ› οΈ Using tool: execute_bash"), "Missing tool execution indicator"); + assert!(help_response.contains("Allow this action?") && help_response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); + println!("βœ… Found tool execution permission prompt"); + + // Allow the tool execution + let allow_response = chat.execute_command("y")?; + + println!("πŸ“ Allow response: {} bytes", allow_response.len()); + println!("πŸ“ ALLOW RESPONSE:"); + println!("{}", allow_response); + println!("πŸ“ END ALLOW RESPONSE"); + + // Verify complete help content in final response + assert!(allow_response.contains("Usage: qchat mcp remove"), "Missing usage information"); + assert!(allow_response.contains("Options"), "Missing option information"); + assert!(allow_response.contains("--name "), "Missing --name option"); + assert!(allow_response.contains("--scope "), "Missing --scope option"); + assert!(allow_response.contains("--agent "), "Missing --agent option"); + assert!(allow_response.contains("-h, --help"), "Missing help option"); + assert!(allow_response.contains("Completed in"), "Missing completion indicator"); + println!("βœ… Found all expected MCP remove help content and completion"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} + +#[test] +#[cfg(feature = "mcp")] +fn test_q_mcp_add_help_command() -> Result<(), Box> { + println!("πŸ” Testing q mcp add --help command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + // Execute mcp add --help command + println!("πŸ” Executing command: 'q mcp add --help'"); + let response = chat.execute_command("q mcp add --help")?; + + println!("πŸ“ Restart response: {} bytes", response.len()); + println!("πŸ“ RESTART RESPONSE:"); + println!("{}", response); + println!("πŸ“ END RESTART RESPONSE"); + + // Verify tool execution details + assert!(response.contains("q mcp add --help"), "Missing command execution description"); + assert!(response.contains("Purpose:"), "Missing purpose description"); + println!("βœ… Found tool execution details"); + + // Verify tool execution prompt appears + assert!(response.contains("πŸ› οΈ Using tool: execute_bash"), "Missing tool execution indicator"); + assert!(response.contains("Allow this action?") && response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); + println!("βœ… Found tool execution permission prompt"); + + // Allow the tool execution + let allow_response = chat.execute_command("y")?; + + println!("πŸ“ Allow response: {} bytes", allow_response.len()); + println!("πŸ“ ALLOW RESPONSE:"); + println!("{}", allow_response); + println!("πŸ“ END ALLOW RESPONSE"); + + // Verify mcp add help output + assert!(allow_response.contains("Usage: qchat mcp add"), "Missing usage information"); + assert!(allow_response.contains("Options"), "Missing Options"); + assert!(allow_response.contains("--name "), "Missing --name option"); + assert!(allow_response.contains("--command "), "Missing --command option"); + assert!(allow_response.contains("--scope "), "Missing --scope option"); + assert!(allow_response.contains("--args "), "Missing --args option"); + assert!(allow_response.contains("--agent "), "Missing --agent option"); + assert!(allow_response.contains("--env "), "Missing --env option"); + assert!(allow_response.contains("--timeout "), "Missing --timeout option"); + assert!(allow_response.contains("--disabled"), "Missing --disabled option"); + assert!(allow_response.contains("--force"), "Missing --force option"); + assert!(allow_response.contains("--verbose"), "Missing --verbose option"); + assert!(allow_response.contains("--help"), "Missing --help option"); + assert!(allow_response.contains("Completed in"), "Missing completion indicator"); + assert!(allow_response.contains("Required"), "Missing Requried indicator"); + assert!(allow_response.contains("Optional"), "Missing Optional indicator"); + println!("βœ… MCP add help command executed successfully"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} + +#[test] +#[cfg(feature = "mcp")] +fn test_q_mcp_help_command() -> Result<(), Box> { + println!("πŸ” Testing q mcp --help command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + // Execute q mcp --help command + let help_response = chat.execute_command("q mcp --help")?; + + println!("πŸ“ MCP help response: {} bytes", help_response.len()); + println!("πŸ“ HELP RESPONSE:"); + println!("{}", help_response); + println!("πŸ“ END HELP RESPONSE"); + + // Verify tool execution prompt appears + assert!(help_response.contains("πŸ› οΈ Using tool: execute_bash"), "Missing tool execution indicator"); + assert!(help_response.contains("Allow this action?") && help_response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); + println!("βœ… Found tool execution permission prompt"); + + // Allow the tool execution + let allow_response = chat.execute_command("y")?; + + println!("πŸ“ Allow response: {} bytes", allow_response.len()); + println!("πŸ“ ALLOW RESPONSE:"); + println!("{}", allow_response); + println!("πŸ“ END ALLOW RESPONSE"); + + // Verify complete help content + assert!(allow_response.contains("Model Context Protocol (MCP)"), "Missing MCP description"); + assert!(allow_response.contains("Usage: qchat mcp"), "Missing usage information"); + assert!(allow_response.contains("Commands:"), "Missing Commands section"); + + // Verify command descriptions + assert!(allow_response.contains("add"), "Missing add command description"); + assert!(allow_response.contains("remove"), "Missing remove command description"); + assert!(allow_response.contains("list"), "Missing list command description"); + assert!(allow_response.contains("import"), "Missing import command description"); + assert!(allow_response.contains("status"), "Missing status command description"); + assert!(allow_response.contains("help"), "Missing help command"); + println!("βœ… Found all MCP commands with descriptions"); + + assert!(allow_response.contains("Options"), "Missing Options section"); + assert!(allow_response.contains("-v, --verbose"), "Missing verbose option"); + assert!(allow_response.contains("-h, --help"), "Missing help option"); + assert!(allow_response.contains("Completed in"), "Missing completion indicator"); + println!("βœ… Found all expected MCP help content and completion"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} + +#[test] +#[cfg(feature = "mcp")] +fn test_q_mcp_import_help_command() -> Result<(), Box> { + println!("πŸ” Testing q mcp import --help command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + // Execute mcp import --help command + println!("πŸ” Executing command: 'q mcp import --help'"); + let response = chat.execute_command("q mcp import --help")?; + + println!("πŸ“ Restart response: {} bytes", response.len()); + println!("πŸ“ RESTART RESPONSE:"); + println!("{}", response); + println!("πŸ“ END RESTART RESPONSE"); + + // Verify tool execution details + assert!(response.contains("q mcp import --help"), "Missing command execution description"); + assert!(response.contains("Purpose:"), "Missing purpose description"); + println!("βœ… Found tool execution details"); + + // Verify tool execution prompt appears + assert!(response.contains("πŸ› οΈ Using tool: execute_bash"), "Missing tool execution indicator"); + assert!(response.contains("Allow this action?") && response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); + println!("βœ… Found tool execution permission prompt"); + + // Allow the tool execution + let allow_response = chat.execute_command("y")?; + + println!("πŸ“ Allow response: {} bytes", allow_response.len()); + println!("πŸ“ ALLOW RESPONSE:"); + println!("{}", allow_response); + println!("πŸ“ END ALLOW RESPONSE"); + + // Verify usage line + assert!(allow_response.contains("Usage"), "Missing complete usage line"); + println!("βœ… Found usage information"); + + // Verify Arguments section + assert!(allow_response.contains("Arguments"), "Missing Arguments section"); + println!("βœ… Found Arguments section with SCOPE"); + + // Verify Options section + assert!(allow_response.contains("Options"), "Missing Options section"); + assert!(allow_response.contains("--file "), "Missing --file option"); + assert!(allow_response.contains("--force"), "Missing --force option"); + assert!(allow_response.contains("-v, --verbose..."), "Missing --verbose option"); + assert!(allow_response.contains("-h, --help"), "Missing --help option"); + println!("βœ… Found all options with descriptions"); + + // Verify completion indicator + assert!(allow_response.contains("Completed in") && allow_response.contains("s"), "Missing completion time indicator"); + println!("βœ… Found completion indicator"); + + println!("βœ… All q mcp import --help content verified successfully"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} + +#[test] +#[cfg(feature = "mcp")] +fn test_q_mcp_list_command() -> Result<(), Box> { + println!("πŸ” Testing q mcp list command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + let response = chat.execute_command("q mcp list")?; + + println!("πŸ“ MCP list response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify tool execution prompt + assert!(response.contains("Using tool:"), "Missing tool execution indicator"); + assert!(response.contains("q mcp list"), "Missing command in tool execution"); + assert!(response.contains("Allow this action?") && response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); + println!("βœ… Found tool execution permission prompt"); + + // Allow the tool execution + let allow_response = chat.execute_command("y")?; + + println!("πŸ“ Allow response: {} bytes", allow_response.len()); + println!("πŸ“ ALLOW RESPONSE:"); + println!("{}", allow_response); + println!("πŸ“ END ALLOW RESPONSE"); + + + // Verify MCP server listing + assert!(allow_response.contains("q_cli_default"), "Missing q_cli_default server"); + assert!(allow_response.contains("default"), "Missing default tag"); + assert!(allow_response.contains("global"), "Missing global tag"); + println!("βœ… Found MCP server listing with servers and completion"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} + +#[test] +#[cfg(feature = "mcp")] +fn test_q_mcp_list_help_command() -> Result<(), Box> { + println!("πŸ” Testing q mcp list --help command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + let response = chat.execute_command("q mcp list --help")?; + + println!("πŸ“ MCP list help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify tool execution prompt + assert!(response.contains("Using tool:"), "Missing tool execution indicator"); + assert!(response.contains("q mcp list --help"), "Missing command in tool execution"); + assert!(response.contains("Allow this action?") && response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); + println!("βœ… Found tool execution permission prompt"); + + // Allow the tool execution + let allow_response = chat.execute_command("y")?; + + println!("πŸ“ Allow response: {} bytes", allow_response.len()); + println!("πŸ“ ALLOW RESPONSE:"); + println!("{}", allow_response); + println!("πŸ“ END ALLOW RESPONSE"); + + // Verify help content + assert!(allow_response.contains("Usage"), "Missing usage format"); + + // Verify arguments section + assert!(allow_response.contains("Arguments"), "Missing Arguments section"); + assert!(allow_response.contains("[SCOPE]"), "Missing scope argument"); + + // Verify options section + assert!(allow_response.contains("Options"), "Missing Options section"); + assert!(allow_response.contains("-v") && allow_response.contains("--verbose"), "Missing verbose option"); + assert!(allow_response.contains("-h") && allow_response.contains("--help"), "Missing help option"); + + + assert!(allow_response.contains("Completed in"), "Missing completion indicator"); + println!("βœ… Found all MCP list help content with explanations and completion"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} + +#[test] +#[cfg(feature = "mcp")] +fn test_q_mcp_status_help_command() -> Result<(), Box> { + println!("πŸ” Testing q mcp status --help command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + // Execute mcp status --help command + println!("πŸ” Executing command: 'q mcp status --help'"); + let response = chat.execute_command("q mcp status --help")?; + + println!("πŸ“ Restart response: {} bytes", response.len()); + println!("πŸ“ RESTART RESPONSE:"); + println!("{}", response); + println!("πŸ“ END RESTART RESPONSE"); + + // Verify tool execution details + assert!(response.contains("Purpose:"), "Missing purpose description"); + println!("βœ… Found tool execution details"); + + // Verify tool execution prompt appears + assert!(response.contains("πŸ› οΈ Using tool: execute_bash"), "Missing tool execution indicator"); + assert!(response.contains("Allow this action?") && response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); + println!("βœ… Found tool execution permission prompt"); + + // Allow the tool execution + let allow_response = chat.execute_command("y")?; + + println!("πŸ“ Allow response: {} bytes", allow_response.len()); + println!("πŸ“ ALLOW RESPONSE:"); + println!("{}", allow_response); + println!("πŸ“ END ALLOW RESPONSE"); + + // Verify usage line + assert!(allow_response.contains("Usage: qchat mcp status [OPTIONS] --name "), "Missing complete usage line"); + println!("βœ… Found usage information"); + + // Verify Options section + assert!(allow_response.contains("Options"), "Missing Options section"); + assert!(allow_response.contains("--name "), "Missing --name option"); + assert!(allow_response.contains("-v, --verbose...") , "Missing --verbose option"); + assert!(allow_response.contains("-h, --help"), "Missing --help option"); + println!("βœ… Found all options with descriptions"); + + // Verify completion indicator + assert!(allow_response.contains("Completed in") && allow_response.contains("s"), "Missing completion time indicator"); + println!("βœ… Found completion indicator"); + + println!("βœ… All q mcp status --help content verified successfully"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} + +#[test] +#[cfg(feature = "mcp")] +fn test_add_and_remove_mcp_command() -> Result<(), Box> { + println!("πŸ” Testing q mcp add command..."); + + // First install uv dependency before starting Q Chat + println!("πŸ” Installing uv dependency..."); + std::process::Command::new("pip3") + .args(["install", "uv", "--break-system-packages"]) + .output() + .expect("Failed to install uv"); + println!("βœ… uv dependency installed"); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + // Execute mcp add command + println!("πŸ” Executing command: 'q mcp add --name aws-documentation --command uvx --args awslabs.aws-documentation-mcp-server@latest'"); + let response = chat.execute_command("q mcp add --name aws-documentation --command uvx --args awslabs.aws-documentation-mcp-server@latest")?; + + println!("πŸ“ Response: {} bytes", response.len()); + println!("πŸ“ RESPONSE:"); + println!("{}", response); + println!("πŸ“ END RESPONSE"); + + // Verify tool execution details + assert!(response.contains("Using tool:"), "Missing using tool indicator"); + assert!(response.contains("q mcp add --name aws-documentation --command uvx --args awslabs.aws-documentation-mcp-server@latest"), "Missing full command"); + assert!(response.contains("Purpose:"), "Missing purpose description"); + println!("βœ… Found tool execution details"); + + // Verify tool execution prompt appears + assert!(response.contains("πŸ› οΈ Using tool: execute_bash"), "Missing tool execution indicator"); + assert!(response.contains("Allow this action?") && response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); + println!("βœ… Found tool execution permission prompt"); + + // Allow the tool execution + let allow_response = chat.execute_command("y")?; + + println!("πŸ“ Allow response: {} bytes", allow_response.len()); + println!("πŸ“ ALLOW RESPONSE:"); + println!("{}", allow_response); + println!("πŸ“ END ALLOW RESPONSE"); + + // Verify successful addition + assert!(allow_response.contains("Added MCP server") && allow_response.contains("'aws-documentation'"), "Missing success message"); + assert!(allow_response.contains("/Users/") && allow_response.contains("/.aws/amazonq/mcp.json"), "Missing config file path"); + println!("βœ… Found successful addition message"); + + // Verify completion indicator + assert!(allow_response.contains("Completed in") && allow_response.contains("s"), "Missing completion time indicator"); + println!("βœ… Found completion indicator"); + + println!("βœ… All q mcp add command execution verified successfully"); + + // Now test removing the MCP server + println!("πŸ” Executing remove command: 'q mcp remove --name aws-documentation'"); + let remove_response = chat.execute_command("q mcp remove --name aws-documentation")?; + + println!("πŸ“ Remove response: {} bytes", remove_response.len()); + println!("πŸ“ REMOVE RESPONSE:"); + println!("{}", remove_response); + println!("πŸ“ END REMOVE RESPONSE"); + + // Verify remove tool execution details + assert!(response.contains("Using tool:"), "Missing using tool indicator"); + assert!(remove_response.contains("q mcp remove --name aws-documentation"), "Missing full remove command"); + println!("βœ… Found remove tool execution details"); + + // Verify remove tool execution prompt + assert!(remove_response.contains("πŸ› οΈ Using tool: execute_bash"), "Missing remove tool execution indicator"); + assert!(remove_response.contains("Allow this action?"), "Missing remove permission prompt"); + println!("βœ… Found remove tool execution permission prompt"); + + // Allow the remove tool execution + let remove_allow_response = chat.execute_command("y")?; + + println!("πŸ“ Remove allow response: {} bytes", remove_allow_response.len()); + println!("πŸ“ REMOVE ALLOW RESPONSE:"); + println!("{}", remove_allow_response); + println!("πŸ“ END REMOVE ALLOW RESPONSE"); + + // Verify successful removal + assert!(remove_allow_response.contains("Removed MCP server") && remove_allow_response.contains("'aws-documentation'"), "Missing removal success message"); + assert!(remove_allow_response.contains("/Users/") && remove_allow_response.contains("/.aws/amazonq/mcp.json"), "Missing config file path in removal"); + println!("βœ… Found successful removal message"); + + // Verify remove completion indicator + assert!(remove_allow_response.contains("Completed in") && remove_allow_response.contains("s"), "Missing remove completion time indicator"); + println!("βœ… Found remove completion indicator"); + + println!("βœ… All q mcp remove command execution verified successfully"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/test_mcp_help_command.rs b/e2etests/tests/test_mcp_help_command.rs deleted file mode 100644 index 1e798a29a2..0000000000 --- a/e2etests/tests/test_mcp_help_command.rs +++ /dev/null @@ -1,42 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "mcp")] -fn test_mcp_help_command() -> Result<(), Box> { - println!("πŸ” Testing /mcp --help command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/mcp --help")?; - - println!("πŸ“ MCP help response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify description - assert!(response.contains("See mcp server loaded"), "Missing mcp server description"); - println!("βœ… Found mcp server description"); - - // Verify Usage section - assert!(response.contains("Usage:"), "Missing Usage section"); - assert!(response.contains("/mcp"), "Missing /mcp command in usage section"); - println!("βœ… Found Usage section with /mcp command"); - - // Verify Options section - assert!(response.contains("Options:"), "Missing Options section"); - println!("βœ… Found Options section"); - - // Verify help flags - assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing -h, --help flags"); - assert!(response.contains("Print help"), "Missing Print help description"); - println!("βœ… Found help flags: -h, --help with Print help description"); - - println!("βœ… All mcp help content verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} diff --git a/e2etests/tests/test_mcp_loading_command.rs b/e2etests/tests/test_mcp_loading_command.rs deleted file mode 100644 index 7fd6ce53bc..0000000000 --- a/e2etests/tests/test_mcp_loading_command.rs +++ /dev/null @@ -1,38 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "mcp")] -fn test_mcp_loading_command() -> Result<(), Box> { - println!("πŸ” Testing MCP loading..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/mcp")?; - - println!("πŸ“ MCP loading response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Check MCP status - either loaded or loading - if response.contains("loaded in") { - assert!(response.contains(" s"), "Missing seconds indicator for loading time"); - println!("βœ… Found MCPs loaded with timing"); - - // Count number of MCPs loaded - let mcp_count = response.matches("βœ“").count(); - println!("βœ… Found {} MCP(s) loaded", mcp_count); - } else if response.contains("loading") { - println!("βœ… MCPs are still loading"); - } else { - println!("ℹ️ MCP status unclear - may be in different state"); - } - - println!("βœ… All MCP loading content verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} diff --git a/e2etests/tests/test_mcp_remove_help_command.rs b/e2etests/tests/test_mcp_remove_help_command.rs deleted file mode 100644 index a3e6f4c252..0000000000 --- a/e2etests/tests/test_mcp_remove_help_command.rs +++ /dev/null @@ -1,46 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "mcp")] -fn test_mcp_remove_help_command() -> Result<(), Box> { - println!("πŸ” Testing q mcp remove --help command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - // Execute q mcp remove --help command - let help_response = chat.execute_command("q mcp remove --help")?; - - println!("πŸ“ MCP remove help response: {} bytes", help_response.len()); - println!("πŸ“ HELP RESPONSE:"); - println!("{}", help_response); - println!("πŸ“ END HELP RESPONSE"); - - // Verify tool execution prompt appears - assert!(help_response.contains("πŸ› οΈ Using tool: execute_bash"), "Missing tool execution indicator"); - assert!(help_response.contains("Allow this action?") && help_response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); - println!("βœ… Found tool execution permission prompt"); - - // Allow the tool execution - let allow_response = chat.execute_command("y")?; - - println!("πŸ“ Allow response: {} bytes", allow_response.len()); - println!("πŸ“ ALLOW RESPONSE:"); - println!("{}", allow_response); - println!("πŸ“ END ALLOW RESPONSE"); - - // Verify complete help content in final response - assert!(allow_response.contains("Remove a server from the MCP configuration"), "Missing MCP remove description"); - assert!(allow_response.contains("Usage: qchat mcp remove"), "Missing usage information"); - assert!(allow_response.contains("--name "), "Missing --name option"); - assert!(allow_response.contains("--scope "), "Missing --scope option"); - assert!(allow_response.contains("--agent "), "Missing --agent option"); - assert!(allow_response.contains("-h, --help"), "Missing help option"); - assert!(allow_response.contains("Completed in"), "Missing completion indicator"); - println!("βœ… Found all expected MCP remove help content and completion"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} diff --git a/e2etests/tests/test_q_mcp_add_help_command.rs b/e2etests/tests/test_q_mcp_add_help_command.rs deleted file mode 100644 index 590af5498c..0000000000 --- a/e2etests/tests/test_q_mcp_add_help_command.rs +++ /dev/null @@ -1,61 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "mcp")] -fn test_q_mcp_add_help_command() -> Result<(), Box> { - println!("πŸ” Testing q mcp add --help command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - // Execute mcp add --help command - println!("πŸ” Executing command: 'q mcp add --help'"); - let response = chat.execute_command("q mcp add --help")?; - - println!("πŸ“ Restart response: {} bytes", response.len()); - println!("πŸ“ RESTART RESPONSE:"); - println!("{}", response); - println!("πŸ“ END RESTART RESPONSE"); - - // Verify tool execution details - assert!(response.contains("I will run the following shell command:") && response.contains("q mcp add --help"), "Missing command execution description"); - assert!(response.contains("Purpose:") && response.contains("Get help information for the q mcp add command"), "Missing purpose description"); - println!("βœ… Found tool execution details"); - - // Verify tool execution prompt appears - assert!(response.contains("πŸ› οΈ Using tool: execute_bash"), "Missing tool execution indicator"); - assert!(response.contains("Allow this action?") && response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); - println!("βœ… Found tool execution permission prompt"); - - // Allow the tool execution - let allow_response = chat.execute_command("y")?; - - println!("πŸ“ Allow response: {} bytes", allow_response.len()); - println!("πŸ“ ALLOW RESPONSE:"); - println!("{}", allow_response); - println!("πŸ“ END ALLOW RESPONSE"); - - // Verify mcp add help output - assert!(allow_response.contains("Add or replace a configured server"), "Missing command description"); - assert!(allow_response.contains("Usage: qchat mcp add"), "Missing usage information"); - assert!(allow_response.contains("--name "), "Missing --name option"); - assert!(allow_response.contains("--command "), "Missing --command option"); - assert!(allow_response.contains("--scope "), "Missing --scope option"); - assert!(allow_response.contains("--args "), "Missing --args option"); - assert!(allow_response.contains("--agent "), "Missing --agent option"); - assert!(allow_response.contains("--env "), "Missing --env option"); - assert!(allow_response.contains("--timeout "), "Missing --timeout option"); - assert!(allow_response.contains("--disabled"), "Missing --disabled option"); - assert!(allow_response.contains("--force"), "Missing --force option"); - assert!(allow_response.contains("--verbose") && allow_response.contains("Increase logging verbosity"), "Missing --verbose option"); - assert!(allow_response.contains("--help") && allow_response.contains("Print help"), "Missing --help option"); - assert!(allow_response.contains("Completed in"), "Missing completion indicator"); - assert!(allow_response.contains("Required:"), "Missing Requried indicator"); - assert!(allow_response.contains("Optional:"), "Missing Optional indicator"); - println!("βœ… MCP add help command executed successfully"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} \ No newline at end of file diff --git a/e2etests/tests/test_q_mcp_help_command.rs b/e2etests/tests/test_q_mcp_help_command.rs deleted file mode 100644 index 3e75186d55..0000000000 --- a/e2etests/tests/test_q_mcp_help_command.rs +++ /dev/null @@ -1,56 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "mcp")] -fn test_q_mcp_help_command() -> Result<(), Box> { - println!("πŸ” Testing q mcp --help command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - // Execute q mcp --help command - let help_response = chat.execute_command("q mcp --help")?; - - println!("πŸ“ MCP help response: {} bytes", help_response.len()); - println!("πŸ“ HELP RESPONSE:"); - println!("{}", help_response); - println!("πŸ“ END HELP RESPONSE"); - - // Verify tool execution prompt appears - assert!(help_response.contains("πŸ› οΈ Using tool: execute_bash"), "Missing tool execution indicator"); - assert!(help_response.contains("Allow this action?") && help_response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); - println!("βœ… Found tool execution permission prompt"); - - // Allow the tool execution - let allow_response = chat.execute_command("y")?; - - println!("πŸ“ Allow response: {} bytes", allow_response.len()); - println!("πŸ“ ALLOW RESPONSE:"); - println!("{}", allow_response); - println!("πŸ“ END ALLOW RESPONSE"); - - // Verify complete help content - assert!(allow_response.contains("Model Context Protocol (MCP)"), "Missing MCP description"); - assert!(allow_response.contains("Usage: qchat mcp"), "Missing usage information"); - assert!(allow_response.contains("Commands:"), "Missing Commands section"); - - // Verify command descriptions - assert!(allow_response.contains("add") && allow_response.contains("Add or replace a configured server"), "Missing add command description"); - assert!(allow_response.contains("remove") && allow_response.contains("Remove a server from the MCP configuration"), "Missing remove command description"); - assert!(allow_response.contains("list") && allow_response.contains("List configured servers"), "Missing list command description"); - assert!(allow_response.contains("import") && allow_response.contains("Import a server configuration from another file"), "Missing import command description"); - assert!(allow_response.contains("status") && allow_response.contains("Get the status of a configured server"), "Missing status command description"); - assert!(allow_response.contains("help"), "Missing help command"); - println!("βœ… Found all MCP commands with descriptions"); - - assert!(allow_response.contains("Options:"), "Missing Options section"); - assert!(allow_response.contains("-v, --verbose"), "Missing verbose option"); - assert!(allow_response.contains("-h, --help"), "Missing help option"); - assert!(allow_response.contains("Completed in"), "Missing completion indicator"); - println!("βœ… Found all expected MCP help content and completion"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} diff --git a/e2etests/tests/test_q_mcp_import_help_command.rs b/e2etests/tests/test_q_mcp_import_help_command.rs deleted file mode 100644 index 7649e8a02d..0000000000 --- a/e2etests/tests/test_q_mcp_import_help_command.rs +++ /dev/null @@ -1,69 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "mcp")] -fn test_q_mcp_import_help_command() -> Result<(), Box> { - println!("πŸ” Testing q mcp import --help command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - // Execute mcp import --help command - println!("πŸ” Executing command: 'q mcp import --help'"); - let response = chat.execute_command("q mcp import --help")?; - - println!("πŸ“ Restart response: {} bytes", response.len()); - println!("πŸ“ RESTART RESPONSE:"); - println!("{}", response); - println!("πŸ“ END RESTART RESPONSE"); - - // Verify tool execution details - assert!(response.contains("I will run the following shell command:") && response.contains("q mcp import --help"), "Missing command execution description"); - assert!(response.contains("Purpose:") && response.contains("Get help information for the q mcp import command"), "Missing purpose description"); - println!("βœ… Found tool execution details"); - - // Verify tool execution prompt appears - assert!(response.contains("πŸ› οΈ Using tool: execute_bash"), "Missing tool execution indicator"); - assert!(response.contains("Allow this action?") && response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); - println!("βœ… Found tool execution permission prompt"); - - // Allow the tool execution - let allow_response = chat.execute_command("y")?; - - println!("πŸ“ Allow response: {} bytes", allow_response.len()); - println!("πŸ“ ALLOW RESPONSE:"); - println!("{}", allow_response); - println!("πŸ“ END ALLOW RESPONSE"); - - // Verify command description - assert!(allow_response.contains("Import a server configuration from another file"), "Missing command description"); - println!("βœ… Found command description"); - - // Verify usage line - assert!(allow_response.contains("Usage: qchat mcp import [OPTIONS] --file [SCOPE]"), "Missing complete usage line"); - println!("βœ… Found usage information"); - - // Verify Arguments section - assert!(allow_response.contains("Arguments:"), "Missing Arguments section"); - assert!(allow_response.contains("[SCOPE]") && allow_response.contains("[possible values: default, workspace, global]"), "Missing SCOPE argument with possible values"); - println!("βœ… Found Arguments section with SCOPE"); - - // Verify Options section - assert!(allow_response.contains("Options:"), "Missing Options section"); - assert!(allow_response.contains("--file "), "Missing --file option"); - assert!(allow_response.contains("--force") && allow_response.contains("Overwrite an existing server with the same name"), "Missing --force option"); - assert!(allow_response.contains("-v, --verbose...") && allow_response.contains("Increase logging verbosity"), "Missing --verbose option"); - assert!(allow_response.contains("-h, --help") && allow_response.contains("Print help"), "Missing --help option"); - println!("βœ… Found all options with descriptions"); - - // Verify completion indicator - assert!(allow_response.contains("Completed in") && allow_response.contains("s"), "Missing completion time indicator"); - println!("βœ… Found completion indicator"); - - println!("βœ… All q mcp import --help content verified successfully"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} \ No newline at end of file diff --git a/e2etests/tests/test_q_mcp_list_command.rs b/e2etests/tests/test_q_mcp_list_command.rs deleted file mode 100644 index 83ad7ee908..0000000000 --- a/e2etests/tests/test_q_mcp_list_command.rs +++ /dev/null @@ -1,44 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "mcp")] -fn test_q_mcp_list_command() -> Result<(), Box> { - println!("πŸ” Testing q mcp list command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("q mcp list")?; - - println!("πŸ“ MCP list response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify tool execution prompt - assert!(response.contains("Using tool:"), "Missing tool execution indicator"); - assert!(response.contains("q mcp list"), "Missing command in tool execution"); - assert!(response.contains("List available MCP servers"), "Missing purpose description"); - assert!(response.contains("Allow this action?") && response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); - println!("βœ… Found tool execution permission prompt"); - - // Allow the tool execution - let allow_response = chat.execute_command("y")?; - - println!("πŸ“ Allow response: {} bytes", allow_response.len()); - println!("πŸ“ ALLOW RESPONSE:"); - println!("{}", allow_response); - println!("πŸ“ END ALLOW RESPONSE"); - - - // Verify MCP server listing - assert!(allow_response.contains("q_cli_default"), "Missing q_cli_default server"); - assert!(allow_response.contains("default"), "Missing default tag"); - assert!(allow_response.contains("global"), "Missing global tag"); - println!("βœ… Found MCP server listing with servers and completion"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} \ No newline at end of file diff --git a/e2etests/tests/test_q_mcp_list_help_command.rs b/e2etests/tests/test_q_mcp_list_help_command.rs deleted file mode 100644 index c241012ee6..0000000000 --- a/e2etests/tests/test_q_mcp_list_help_command.rs +++ /dev/null @@ -1,58 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "mcp")] -fn test_q_mcp_list_help_command() -> Result<(), Box> { - println!("πŸ” Testing q mcp list --help command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("q mcp list --help")?; - - println!("πŸ“ MCP list help response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify tool execution prompt - assert!(response.contains("Using tool:"), "Missing tool execution indicator"); - assert!(response.contains("q mcp list --help"), "Missing command in tool execution"); - assert!(response.contains("Allow this action?") && response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); - println!("βœ… Found tool execution permission prompt"); - - // Allow the tool execution - let allow_response = chat.execute_command("y")?; - - println!("πŸ“ Allow response: {} bytes", allow_response.len()); - println!("πŸ“ ALLOW RESPONSE:"); - println!("{}", allow_response); - println!("πŸ“ END ALLOW RESPONSE"); - - // Verify help content - assert!(allow_response.contains("List configured servers"), "Missing command description"); - assert!(allow_response.contains("Usage: qchat mcp list") && allow_response.contains("[OPTIONS]") && allow_response.contains("[SCOPE]"), "Missing usage format"); - - // Verify arguments section - assert!(allow_response.contains("Arguments:"), "Missing Arguments section"); - assert!(allow_response.contains("[SCOPE]") && allow_response.contains("possible values: default, workspace, global"), "Missing scope argument"); - - // Verify options section - assert!(allow_response.contains("Options:"), "Missing Options section"); - assert!(allow_response.contains("-v") && allow_response.contains("--verbose")&& allow_response.contains("Increase logging verbosity"), "Missing verbose option"); - assert!(allow_response.contains("-h") && allow_response.contains("--help") && allow_response.contains("Print help"), "Missing help option"); - - // Verify additional explanation content - //assert!(allow_response.contains("The q mcp list command") && allow_response.contains("configured MCP"), "Missing command explanation"); - assert!(allow_response.contains("default") && allow_response.contains("workspace") && allow_response.contains("global"), "Missing scope explanation"); - assert!(allow_response.contains("-v") && allow_response.contains("--verbose"),"Missing verbose explanation"); - - - assert!(allow_response.contains("Completed in"), "Missing completion indicator"); - println!("βœ… Found all MCP list help content with explanations and completion"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} \ No newline at end of file diff --git a/e2etests/tests/test_q_mcp_status_command.rs b/e2etests/tests/test_q_mcp_status_command.rs deleted file mode 100644 index 9fefc398dd..0000000000 --- a/e2etests/tests/test_q_mcp_status_command.rs +++ /dev/null @@ -1,66 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "mcp")] -fn test_q_mcp_status_command() -> Result<(), Box> { - println!("πŸ” Testing q mcp status command workflow..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - // Now get list of available servers - let list_response = chat.execute_command("q mcp list")?; - let list_allow_response = chat.execute_command("y")?; - - println!("πŸ“ List response: {} bytes", list_allow_response.len()); - println!("πŸ“ LIST RESPONSE:"); - println!("{}", list_allow_response); - println!("πŸ“ END LIST RESPONSE"); - - // Extract server names from the list - let mut server_name: Option = None; - let lines: Vec<&str> = list_allow_response.lines().collect(); - for line in lines { - if line.trim().starts_with("β€’ ") { - // Extract server name from bullet point line - if let Some(name_part) = line.trim().strip_prefix("β€’ ") { - let parts: Vec<&str> = name_part.split_whitespace().collect(); - if let Some(name) = parts.first() { - server_name = Some(name.to_string()); - break; - } - } - } - } - - if let Some(name) = server_name { - println!("βœ… Found server to test: {}", name); - - // Test q mcp status with specific server name - let status_cmd = format!("q mcp status --name {}", name); - let server_status_response = chat.execute_command(&status_cmd)?; - let server_status_allow = chat.execute_command("y")?; - - println!("πŸ“ Server status response: {} bytes", server_status_allow.len()); - println!("πŸ“ SERVER STATUS RESPONSE:"); - println!("{}", server_status_allow); - println!("πŸ“ END SERVER STATUS RESPONSE"); - - // Verify server status output - assert!(server_status_allow.contains("Scope"), "Missing Scope field"); - assert!(server_status_allow.contains("Agent"), "Missing Agent field"); - assert!(server_status_allow.contains("Command"), "Missing Command field"); - assert!(server_status_allow.contains("Timeout"), "Missing Timeout field"); - assert!(server_status_allow.contains("Disabled"), "Missing Disabled field"); - assert!(server_status_allow.contains("Completed in"), "Missing completion indicator"); - println!("βœ… Found all expected server status fields"); - - } else { - println!("ℹ️ No servers found to test status command"); - } - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} \ No newline at end of file diff --git a/e2etests/tests/test_q_mcp_status_help_command.rs b/e2etests/tests/test_q_mcp_status_help_command.rs deleted file mode 100644 index 830bc0cfec..0000000000 --- a/e2etests/tests/test_q_mcp_status_help_command.rs +++ /dev/null @@ -1,63 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "mcp")] -fn test_q_mcp_status_help_command() -> Result<(), Box> { - println!("πŸ” Testing q mcp status --help command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - // Execute mcp status --help command - println!("πŸ” Executing command: 'q mcp status --help'"); - let response = chat.execute_command("q mcp status --help")?; - - println!("πŸ“ Restart response: {} bytes", response.len()); - println!("πŸ“ RESTART RESPONSE:"); - println!("{}", response); - println!("πŸ“ END RESTART RESPONSE"); - - // Verify tool execution details - assert!(response.contains("I will run the following shell command:") && response.contains("q mcp status --help"), "Missing command execution description"); - assert!(response.contains("Purpose:") && response.contains("Get help information for the q mcp status command"), "Missing purpose description"); - println!("βœ… Found tool execution details"); - - // Verify tool execution prompt appears - assert!(response.contains("πŸ› οΈ Using tool: execute_bash"), "Missing tool execution indicator"); - assert!(response.contains("Allow this action?") && response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); - println!("βœ… Found tool execution permission prompt"); - - // Allow the tool execution - let allow_response = chat.execute_command("y")?; - - println!("πŸ“ Allow response: {} bytes", allow_response.len()); - println!("πŸ“ ALLOW RESPONSE:"); - println!("{}", allow_response); - println!("πŸ“ END ALLOW RESPONSE"); - - // Verify command description - assert!(allow_response.contains("Get the status of a configured server"), "Missing command description"); - println!("βœ… Found command description"); - - // Verify usage line - assert!(allow_response.contains("Usage: qchat mcp status [OPTIONS] --name "), "Missing complete usage line"); - println!("βœ… Found usage information"); - - // Verify Options section - assert!(allow_response.contains("Options:"), "Missing Options section"); - assert!(allow_response.contains("--name "), "Missing --name option"); - assert!(allow_response.contains("-v, --verbose...") && allow_response.contains("Increase logging verbosity"), "Missing --verbose option"); - assert!(allow_response.contains("-h, --help") && allow_response.contains("Print help"), "Missing --help option"); - println!("βœ… Found all options with descriptions"); - - // Verify completion indicator - assert!(allow_response.contains("Completed in") && allow_response.contains("s"), "Missing completion time indicator"); - println!("βœ… Found completion indicator"); - - println!("βœ… All q mcp status --help content verified successfully"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} \ No newline at end of file From bb3ba49e4e8a311696731c64ba117427d0d5bc53 Mon Sep 17 00:00:00 2001 From: sayema Anjum Date: Wed, 20 Aug 2025 20:01:48 +0530 Subject: [PATCH 22/77] QCLI Automation for hooks,usage,issue,tools,subscribe,model,compact,editor tests --- e2etests/src/lib.rs | 4 +- e2etests/tests/test_compact_command.rs | 49 ++++-- e2etests/tests/test_editor_help_command.rs | 50 ++++-- e2etests/tests/test_hooks_command.rs | 48 +++-- e2etests/tests/test_issue_command.rs | 67 +++++-- e2etests/tests/test_model_dynamic_command.rs | 51 ++++-- e2etests/tests/test_subscribe_command.rs | 47 +++-- e2etests/tests/test_tools_command.rs | 176 +++++++++++++++---- e2etests/tests/test_usage_command.rs | 55 +++--- 9 files changed, 387 insertions(+), 160 deletions(-) diff --git a/e2etests/src/lib.rs b/e2etests/src/lib.rs index 43bf407062..45a88cbfec 100644 --- a/e2etests/src/lib.rs +++ b/e2etests/src/lib.rs @@ -138,12 +138,12 @@ pub mod q_chat_helper { }, Ok(_) => { // No more data, but wait a bit more in case there's more coming - std::thread::sleep(Duration::from_millis(2000)); + std::thread::sleep(Duration::from_millis(2500)); if total_content.len() > 0 { break; } }, Err(_) => break, } - std::thread::sleep(Duration::from_millis(2000)); + std::thread::sleep(Duration::from_millis(2500)); } Ok(total_content) diff --git a/e2etests/tests/test_compact_command.rs b/e2etests/tests/test_compact_command.rs index 657d23b8d1..4c7e101738 100644 --- a/e2etests/tests/test_compact_command.rs +++ b/e2etests/tests/test_compact_command.rs @@ -1,23 +1,23 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; +use q_cli_e2e_tests::{get_chat_session, cleanup_if_last_test}; +use std::sync::atomic::{AtomicUsize, Ordering}; -#[test] -#[cfg(feature = "compact")] +static TEST_COUNT: AtomicUsize = AtomicUsize::new(0); -fn test_all_compact_commands() -> Result<(), Box> { - let mut chat = QChatSession::new()?; - println!(":white_check_mark: Q Chat session started"); - - test_compact_command(&mut chat)?; - test_compact_help_command(&mut chat)?; - - chat.quit()?; - println!(":white_check_mark: All tests completed successfully"); - Ok(()) -} +// List of covered tests +const TEST_NAMES: &[&str] = &[ + "test_compact_command", + "test_compact_help_command", +]; +const TOTAL_TESTS: usize = TEST_NAMES.len(); -fn test_compact_command(chat: &mut QChatSession) -> Result<(), Box> { +#[test] +#[cfg(feature = "compact")] +fn test_compact_command() -> Result<(), Box> { println!("πŸ” Testing /compact command..."); + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + let response = chat.execute_command("/compact")?; println!("πŸ“ Compact response: {} bytes", response.len()); @@ -36,12 +36,23 @@ fn test_compact_command(chat: &mut QChatSession) -> Result<(), Box Result<(), Box> { +#[test] +#[cfg(feature = "compact")] +fn test_compact_help_command() -> Result<(), Box> { println!("πŸ” Testing /compact --help command..."); + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + let response = chat.execute_command("/compact --help")?; println!("πŸ“ Compact help response: {} bytes", response.len()); @@ -94,5 +105,11 @@ fn test_compact_help_command(chat: &mut QChatSession) -> Result<(), Box Result<(), Box> { - let mut chat = QChatSession::new()?; - println!(":white_check_mark: Q Chat session started"); - - test_editor_help_command(&mut chat)?; - test_help_editor_command(&mut chat)?; - - chat.quit()?; - println!(":white_check_mark: All tests completed successfully"); - Ok(()) -} -fn test_editor_help_command(chat: &mut QChatSession) -> Result<(), Box> { +fn test_editor_help_command() -> Result<(), Box> { println!("πŸ” Testing /editor --help command..."); - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); let response = chat.execute_command("/editor --help")?; @@ -48,13 +47,24 @@ fn test_editor_help_command(chat: &mut QChatSession) -> Result<(), Box Result<(), Box> { +#[test] +#[cfg(feature = "editor")] +fn test_help_editor_command() -> Result<(), Box> { println!("πŸ” Testing /help editor command..."); + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + let response = chat.execute_command("/help editor")?; println!("πŸ“ Help editor response: {} bytes", response.len()); @@ -80,6 +90,12 @@ fn test_help_editor_command(chat: &mut QChatSession) -> Result<(), Box Result<(), Box> { - let mut chat = QChatSession::new()?; - println!(":white_check_mark: Q Chat session started"); - - test_hooks_command(&mut chat)?; - test_hooks_help_command(&mut chat)?; - - chat.quit()?; - println!(":white_check_mark: All tests completed successfully"); - Ok(()) -} - -fn test_hooks_command(chat: &mut QChatSession) -> Result<(), Box> { +fn test_hooks_command() -> Result<(), Box> { println!("πŸ” Testing /hooks command..."); - + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + let response = chat.execute_command("/hooks")?; println!("πŸ“ Hooks command response: {} bytes", response.len()); @@ -36,12 +36,23 @@ fn test_hooks_command(chat: &mut QChatSession) -> Result<(), Box Result<(), Box> { +#[test] +#[cfg(feature = "hooks")] +fn test_hooks_help_command() -> Result<(), Box> { println!("πŸ” Testing /hooks --help command..."); + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + let response = chat.execute_command("/hooks --help")?; println!("πŸ“ Hooks help response: {} bytes", response.len()); @@ -80,6 +91,11 @@ fn test_hooks_help_command(chat: &mut QChatSession) -> Result<(), Box Result<(), Box> { - let mut chat = QChatSession::new()?; - println!(":white_check_mark: Q Chat session started"); - - test_issue_command(&mut chat)?; - test_issue_force_command(&mut chat)?; - test_issue_help_command(&mut chat)?; - - chat.quit()?; - println!(":white_check_mark: All tests completed successfully"); - Ok(()) -} - -fn test_issue_command(chat: &mut QChatSession) -> Result<(), Box> { +fn test_issue_command() -> Result<(), Box> { println!("πŸ” Testing /issue command with bug report..."); - + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + let response = chat.execute_command("/issue \"Bug: Q CLI crashes when using large files\"")?; println!("πŸ“ Issue command response: {} bytes", response.len()); @@ -31,12 +31,24 @@ fn test_issue_command(chat: &mut QChatSession) -> Result<(), Box Result<(), Box> { +#[test] +#[cfg(feature = "issue_reporting")] +fn test_issue_force_command() -> Result<(), Box> { println!("πŸ” Testing /issue --force command with critical bug..."); + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + let response = chat.execute_command("/issue --force \"Critical bug in file handling\"")?; println!("πŸ“ Issue force command response: {} bytes", response.len()); @@ -49,11 +61,23 @@ fn test_issue_force_command(chat: &mut QChatSession) -> Result<(), Box Result<(), Box> { +#[test] +#[cfg(feature = "issue_reporting")] +fn test_issue_help_command() -> Result<(), Box> { println!("πŸ” Testing /issue --help command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); let response = chat.execute_command("/issue --help")?; @@ -83,6 +107,13 @@ fn test_issue_help_command(chat: &mut QChatSession) -> Result<(), Box Result<(), Box> { - let mut chat = QChatSession::new()?; - println!(":white_check_mark: Q Chat session started"); - - test_model_dynamic_command(&mut chat)?; - test_model_help_command(&mut chat)?; - - chat.quit()?; - println!(":white_check_mark: All tests completed successfully"); - Ok(()) -} -fn test_model_dynamic_command(chat: &mut QChatSession) -> Result<(), Box> { +fn test_model_dynamic_command() -> Result<(), Box> { println!("πŸ” Testing /model command with dynamic selection..."); - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + // Execute /model command to get list let model_response = chat.execute_command("/model")?; @@ -120,14 +119,24 @@ fn test_model_dynamic_command(chat: &mut QChatSession) -> Result<(), Box Result<(), Box> { +#[test] +#[cfg(feature = "model")] +fn test_model_help_command() -> Result<(), Box> { println!("πŸ” Testing /model --help command..."); - + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + let response = chat.execute_command("/model --help")?; println!("πŸ“ Model help response: {} bytes", response.len()); @@ -155,5 +164,11 @@ fn test_model_help_command(chat: &mut QChatSession) -> Result<(), Box Result<(), Box> { - let mut chat = QChatSession::new()?; - println!(":white_check_mark: Q Chat session started"); - - test_subscribe_command(&mut chat)?; - test_subscribe_help_command(&mut chat)?; - - chat.quit()?; - println!(":white_check_mark: All tests completed successfully"); - Ok(()) -} -fn test_subscribe_command(chat: &mut QChatSession) -> Result<(), Box> { +fn test_subscribe_command() -> Result<(), Box> { println!("πŸ” Testing /subscribe command..."); + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + let response = chat.execute_command("/subscribe")?; println!("πŸ“ Subscribe response: {} bytes", response.len()); @@ -29,13 +32,22 @@ fn test_subscribe_command(chat: &mut QChatSession) -> Result<(), Box Result<(), Box> { +#[test] +#[cfg(feature = "subscribe")] +fn test_subscribe_help_command() -> Result<(), Box> { println!("πŸ” Testing /subscribe --help command..."); + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + let response = chat.execute_command("/subscribe --help")?; println!("πŸ“ Subscribe help response: {} bytes", response.len()); @@ -67,6 +79,11 @@ fn test_subscribe_help_command(chat: &mut QChatSession) -> Result<(), Box Result<(), Box> { - let mut chat = QChatSession::new()?; - println!(":white_check_mark: Q Chat session started"); - - test_tools_command(&mut chat)?; - test_tools_help_command(&mut chat)?; - test_tools_trust_all_command(&mut chat)?; - test_tools_trust_all_help_command(&mut chat)?; - test_tools_reset_help_command(&mut chat)?; - test_tools_trust_command(&mut chat)?; - test_tools_trust_help_command(&mut chat)?; - test_tools_untrust_help_command(&mut chat)?; - test_tools_schema_help_command(&mut chat)?; - test_tools_schema_command(&mut chat)?; - - chat.quit()?; - println!(":white_check_mark: All tests completed successfully"); - Ok(()) -} -fn test_tools_command(chat: &mut QChatSession) -> Result<(), Box> { +fn test_tools_command() -> Result<(), Box> { println!("πŸ” Testing /tools command..."); + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + let response = chat.execute_command("/tools")?; println!("πŸ“ Tools response: {} bytes", response.len()); @@ -62,13 +63,23 @@ fn test_tools_command(chat: &mut QChatSession) -> Result<(), Box Result<(), Box> { +#[test] +#[cfg(feature = "tools")] +fn test_tools_help_command() -> Result<(), Box> { println!("πŸ” Testing /tools --help command..."); + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + let response = chat.execute_command("/tools --help")?; println!("πŸ“ Tools help response: {} bytes", response.len()); @@ -107,11 +118,23 @@ fn test_tools_help_command(chat: &mut QChatSession) -> Result<(), Box Result<(), Box> { + +#[test] +#[cfg(feature = "tools")] +fn test_tools_trust_all_command() -> Result<(), Box> { println!("πŸ” Testing /tools trust-all command..."); - + + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + // Execute trust-all command let trust_all_response = chat.execute_command("/tools trust-all")?; @@ -177,12 +200,23 @@ fn test_tools_trust_all_command(chat: &mut QChatSession) -> Result<(), Box Result<(), Box> { +#[test] +#[cfg(feature = "tools")] +fn test_tools_trust_all_help_command() -> Result<(), Box> { println!("πŸ” Testing /tools trust-all --help command..."); - + + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + let response = chat.execute_command("/tools trust-all --help")?; println!("πŸ“ Tools trust-all help response: {} bytes", response.len()); @@ -205,12 +239,23 @@ fn test_tools_trust_all_help_command(chat: &mut QChatSession) -> Result<(), Box< println!("βœ… All tools trust-all help functionality verified!"); + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + Ok(()) } -fn test_tools_reset_help_command(chat: &mut QChatSession) -> Result<(), Box> { +#[test] +#[cfg(feature = "tools")] +fn test_tools_reset_help_command() -> Result<(), Box> { println!("πŸ” Testing /tools reset --help command..."); + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + let response = chat.execute_command("/tools reset --help")?; println!("πŸ“ Tools reset help response: {} bytes", response.len()); @@ -233,12 +278,23 @@ fn test_tools_reset_help_command(chat: &mut QChatSession) -> Result<(), Box Result<(), Box> { +#[test] +#[cfg(feature = "tools")] +fn test_tools_trust_command() -> Result<(), Box> { println!("πŸ” Testing /tools trust command..."); + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + // First get list of tools to find one that's not trusted let tools_response = chat.execute_command("/tools")?; @@ -300,14 +356,22 @@ fn test_tools_trust_command(chat: &mut QChatSession) -> Result<(), Box Result<(), Box> { +#[test] +#[cfg(feature = "tools")] +fn test_tools_trust_help_command() -> Result<(), Box> { println!("πŸ” Testing /tools trust --help command..."); - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); let response = chat.execute_command("/tools trust --help")?; @@ -335,12 +399,23 @@ fn test_tools_trust_help_command(chat: &mut QChatSession) -> Result<(), Box Result<(), Box> { +#[test] +#[cfg(feature = "tools")] +fn test_tools_untrust_help_command() -> Result<(), Box> { println!("πŸ” Testing /tools untrust --help command..."); + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + let response = chat.execute_command("/tools untrust --help")?; println!("πŸ“ Tools untrust help response: {} bytes", response.len()); @@ -366,12 +441,24 @@ fn test_tools_untrust_help_command(chat: &mut QChatSession) -> Result<(), Box Result<(), Box> { + +#[test] +#[cfg(feature = "tools")] +fn test_tools_schema_help_command() -> Result<(), Box> { println!("πŸ” Testing /tools schema --help command..."); + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + let response = chat.execute_command("/tools schema --help")?; println!("πŸ“ Tools schema help response: {} bytes", response.len()); @@ -394,12 +481,23 @@ fn test_tools_schema_help_command(chat: &mut QChatSession) -> Result<(), Box Result<(), Box> { +/*#[test] +#[cfg(feature = "tools")] +fn test_tools_schema_command() -> Result<(), Box> { println!("πŸ” Testing /tools schema command..."); + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + let response = chat.execute_command("/tools schema")?; println!("πŸ“ Tools schema response: {} bytes", response.len()); @@ -440,5 +538,11 @@ fn test_tools_schema_command(chat: &mut QChatSession) -> Result<(), Box Result<(), Box> { - let mut chat = QChatSession::new()?; - println!(":white_check_mark: Q Chat session started"); - - test_usage_command(&mut chat)?; - test_usage_help_command(&mut chat)?; - - chat.quit()?; - println!(":white_check_mark: All tests completed successfully"); - Ok(()) -} -fn test_usage_command(chat: &mut QChatSession) -> Result<(), Box> { +fn test_usage_command() -> Result<(), Box> { println!("πŸ” Testing /usage command..."); - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + let response = chat.execute_command("/usage")?; println!("πŸ“ Tools response: {} bytes", response.len()); @@ -59,18 +58,25 @@ fn test_usage_command(chat: &mut QChatSession) -> Result<(), Box Result<(), Box> { +#[test] +#[cfg(feature = "usage")] +fn test_usage_help_command() -> Result<(), Box> { println!("πŸ” Testing /usage --help command..."); - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + let response = chat.execute_command("/usage --help")?; println!("πŸ“ Usage help response: {} bytes", response.len()); @@ -97,8 +103,13 @@ fn test_usage_help_command(chat: &mut QChatSession) -> Result<(), Box Date: Wed, 20 Aug 2025 11:00:42 -0700 Subject: [PATCH 23/77] Added some additional scripts for specific runs --- e2etests/run_mcp_clean.sh | 30 ++++ e2etests/run_mcp_only.sh | 249 +++++++++++++++++++++++++++++ e2etests/run_simple_categorized.sh | 4 +- e2etests/run_tools_clean.sh | 30 ++++ 4 files changed, 311 insertions(+), 2 deletions(-) create mode 100755 e2etests/run_mcp_clean.sh create mode 100755 e2etests/run_mcp_only.sh create mode 100755 e2etests/run_tools_clean.sh diff --git a/e2etests/run_mcp_clean.sh b/e2etests/run_mcp_clean.sh new file mode 100755 index 0000000000..7a6b9ae20a --- /dev/null +++ b/e2etests/run_mcp_clean.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# Clean MCP-only test runner - runs only MCP test files +# Usage: ./run_mcp_clean.sh [path_to_q_binary] + +Q_BINARY="q" + +if [ $# -gt 0 ]; then + Q_BINARY="$1" + export Q_CLI_PATH="$Q_BINARY" +fi + +echo "πŸš€ Running MCP Commands Tests" +echo "=============================" +echo "" + +# Run only the specific MCP test files +echo "πŸ”„ Running MCP tests..." +cargo test --test test_mcp_help_command --test test_mcp_loading_command --features "mcp" -- --nocapture --test-threads=1 + +exit_code=$? + +echo "" +if [ $exit_code -eq 0 ]; then + echo "πŸŽ‰ All MCP tests passed!" +else + echo "πŸ’₯ Some MCP tests failed!" +fi + +exit $exit_code diff --git a/e2etests/run_mcp_only.sh b/e2etests/run_mcp_only.sh new file mode 100755 index 0000000000..2f5a0a39f0 --- /dev/null +++ b/e2etests/run_mcp_only.sh @@ -0,0 +1,249 @@ +#!/bin/bash + +# Simple categorized test runner with real-time output and summary +# Usage: ./run_mcp_only.sh [path_to_q_binary] [--quiet] + +# ============================================================================ +# CATEGORY CONFIGURATION - Set to true/false to enable/disable categories +# ============================================================================ +RUN_CORE_SESSION=false +RUN_AGENT=false +RUN_CONTEXT=false +RUN_SAVE_LOAD=false +RUN_MODEL=false +RUN_SESSION_MGMT=false +RUN_INTEGRATION=false +RUN_MCP=true +RUN_AI_PROMPTS=false +RUN_ISSUE_REPORTING=false +RUN_TOOLS=false +# ============================================================================ + +Q_BINARY="q" +QUIET_MODE=false + +# Parse arguments properly +while [[ $# -gt 0 ]]; do + case $1 in + --quiet|-q) + QUIET_MODE=false + shift + ;; + *) + if [ "$Q_BINARY" = "q" ]; then + Q_BINARY="$1" + fi + shift + ;; + esac +done + +if [ "$Q_BINARY" != "q" ]; then + export Q_CLI_PATH="$Q_BINARY" +fi + +echo "πŸš€ Running Q CLI E2E tests by category" +echo "======================================" + +# Initialize counters +total_passed=0 +total_failed=0 +failed_categories="" + +run_category() { + local category=$1 + local name=$2 + + echo "" + echo "πŸ§ͺ $name" + echo "$(printf '%*s' ${#name} '' | tr ' ' '-')" + + # Show which tests will run in this category + echo "πŸ“‹ Tests in this category:" + test_count=0 + for file in tests/*.rs; do + if grep -q "cfg(feature = \"$category\")" "$file" 2>/dev/null; then + # Extract actual test function names from the file + grep -n "fn test_" "$file" | while read -r line; do + test_name=$(echo "$line" | sed 's/.*fn \(test_[^(]*\).*/\1/') + echo " β€’ $test_name" + ((test_count++)) + done + fi + done + if [ $test_count -eq 0 ]; then + echo " β€’ No tests found for this category" + fi + echo "" + + echo "πŸ”„ Running tests..." + + if [ "$QUIET_MODE" = true ]; then + # Quiet mode - show individual test results in real-time + cargo test --tests --features "$category" -- --test-threads=1 2>&1 | while IFS= read -r line; do + if echo "$line" | grep -q "test .* \.\.\. ok$"; then + test_name=$(echo "$line" | sed 's/test \(.*\) \.\.\. ok/\1/') + echo " βœ… $test_name" + elif echo "$line" | grep -q "test .* \.\.\. FAILED$"; then + test_name=$(echo "$line" | sed 's/test \(.*\) \.\.\. FAILED/\1/') + echo " ❌ $test_name" + fi + done + + # Check the exit status of cargo test + if [ ${PIPESTATUS[0]} -eq 0 ]; then + echo "βœ… $name completed successfully" + return 0 + else + echo "❌ $name had failures" + if [ -n "$failed_categories" ]; then + failed_categories="$failed_categories\n$name" + else + failed_categories="$name" + fi + return 1 + fi + else + # Verbose mode - show full output with real-time test results + cargo test --tests --features "$category" -- --nocapture --test-threads=1 2>&1 | while IFS= read -r line; do + echo "$line" + if echo "$line" | grep -q "test .* \.\.\. ok$"; then + test_name=$(echo "$line" | sed 's/test \(.*\) \.\.\. ok/\1/') + echo " βœ… $test_name PASSED" + elif echo "$line" | grep -q "test .* \.\.\. FAILED$"; then + test_name=$(echo "$line" | sed 's/test \(.*\) \.\.\. FAILED/\1/') + echo " ❌ $test_name FAILED" + fi + done + + # Check the exit status of cargo test + if [ ${PIPESTATUS[0]} -eq 0 ]; then + echo "" + echo "βœ… $name completed successfully" + return 0 + else + echo "" + echo "❌ $name had failures" + if [ -n "$failed_categories" ]; then + failed_categories="$failed_categories\n$name" + else + failed_categories="$name" + fi + return 1 + fi + fi +} + +# Run each category and track results +if [ "$RUN_CORE_SESSION" = true ]; then + if run_category "core_session" "Core Session Commands"; then + ((total_passed++)) + else + ((total_failed++)) + fi +fi + +if [ "$RUN_AGENT" = true ]; then + if run_category "agent" "Agent Commands"; then + ((total_passed++)) + else + ((total_failed++)) + fi +fi + +if [ "$RUN_CONTEXT" = true ]; then + if run_category "context" "Context Commands"; then + ((total_passed++)) + else + ((total_failed++)) + fi +fi + +if [ "$RUN_SAVE_LOAD" = true ]; then + if run_category "save_load" "Save/Load Commands"; then + ((total_passed++)) + else + ((total_failed++)) + fi +fi + +if [ "$RUN_MODEL" = true ]; then + if run_category "model" "Model Commands"; then + ((total_passed++)) + else + ((total_failed++)) + fi +fi + +if [ "$RUN_SESSION_MGMT" = true ]; then + if run_category "session_mgmt" "Session Management Commands"; then + ((total_passed++)) + else + ((total_failed++)) + fi +fi + +if [ "$RUN_INTEGRATION" = true ]; then + if run_category "integration" "Integration Commands"; then + ((total_passed++)) + else + ((total_failed++)) + fi +fi + +if [ "$RUN_MCP" = true ]; then + if run_category "mcp" "MCP Commands"; then + ((total_passed++)) + else + ((total_failed++)) + fi +fi + +if [ "$RUN_AI_PROMPTS" = true ]; then + if run_category "ai_prompts" "AI Prompts"; then + ((total_passed++)) + else + ((total_failed++)) + fi +fi + +if [ "$RUN_ISSUE_REPORTING" = true ]; then + if run_category "issue_reporting" "ISSUE REPORTING"; then + ((total_passed++)) + else + ((total_failed++)) + fi +fi + +if [ "$RUN_TOOLS" = true ]; then + if run_category "tools" "TOOLS"; then + ((total_passed++)) + else + ((total_failed++)) + fi +fi + +# Final summary +echo "" +echo "🎯 FINAL SUMMARY" +echo "================================" +echo "βœ… Categories Passed: $total_passed" +echo "❌ Categories Failed: $total_failed" +echo "πŸ“Š Total Categories: $((total_passed + total_failed))" + +if [ -n "$failed_categories" ]; then + echo "" + echo "❌ Failed Categories:" + echo -e "$failed_categories" | while read -r category; do + if [ -n "$category" ]; then + echo " β€’ $category" + fi + done + echo "" + echo "πŸ’₯ Some tests failed!" + exit 1 +else + echo "" + echo "πŸŽ‰ All categories passed!" + exit 0 +fi diff --git a/e2etests/run_simple_categorized.sh b/e2etests/run_simple_categorized.sh index b069db4ae3..8bf09c5cb8 100755 --- a/e2etests/run_simple_categorized.sh +++ b/e2etests/run_simple_categorized.sh @@ -31,7 +31,7 @@ QUIET_MODE=false while [[ $# -gt 0 ]]; do case $1 in --quiet|-q) - QUIET_MODE=true + QUIET_MODE=false shift ;; *) @@ -75,7 +75,7 @@ run_category() { echo "πŸ”„ Running tests..." - if [ "$QUIET_MODE" = true ]; then + if [ "$QUIET_MODE" = false ]; then # Quiet mode - show individual test results in real-time cargo test --tests --features "$category" -- --test-threads=1 2>&1 | while IFS= read -r line; do if echo "$line" | grep -q "test .* \.\.\. ok$"; then diff --git a/e2etests/run_tools_clean.sh b/e2etests/run_tools_clean.sh new file mode 100755 index 0000000000..c5645dada2 --- /dev/null +++ b/e2etests/run_tools_clean.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# Clean tools command test runner +# Usage: ./run_tools_clean.sh [path_to_q_binary] + +Q_BINARY="q" + +if [ $# -gt 0 ]; then + Q_BINARY="$1" + export Q_CLI_PATH="$Q_BINARY" +fi + +echo "πŸš€ Running Tools Command Test" +echo "=============================" +echo "" + +# Run only the /tools command test +echo "πŸ”„ Running /tools test..." +cargo test --test test_tools_command --features "core_session" -- --nocapture --test-threads=1 + +exit_code=$? + +echo "" +if [ $exit_code -eq 0 ]; then + echo "πŸŽ‰ Tools test passed!" +else + echo "πŸ’₯ Tools test failed!" +fi + +exit $exit_code From 4b990d599ed97fd249f26b8f5e1a1468896142c9 Mon Sep 17 00:00:00 2001 From: "Shreya [C] Bhagat" Date: Thu, 21 Aug 2025 19:08:38 +0530 Subject: [PATCH 24/77] Refactor: Merge save/load into one file, remove verbose from MCP context --- e2etests/run_context.clean.sh | 30 ++ e2etests/run_mcp_clean.sh | 2 +- e2etests/run_save_load_clean.sh | 30 ++ e2etests/test_core_session_clean.sh | 30 ++ e2etests/tests/test_context_command.rs | 62 +-- e2etests/tests/test_help_command.rs | 11 +- e2etests/tests/test_load_command.rs | 65 --- .../test_load_command_argument_validation.rs | 44 -- e2etests/tests/test_load_help_command.rs | 87 --- e2etests/tests/test_mcp_command.rs | 2 +- e2etests/tests/test_save_command.rs | 56 -- .../test_save_command_argument_validation.rs | 46 -- e2etests/tests/test_save_force_command.rs | 124 ----- e2etests/tests/test_save_help_command.rs | 91 ---- e2etests/tests/test_save_load_command.rs | 506 ++++++++++++++++++ 15 files changed, 612 insertions(+), 574 deletions(-) create mode 100644 e2etests/run_context.clean.sh create mode 100644 e2etests/run_save_load_clean.sh create mode 100644 e2etests/test_core_session_clean.sh delete mode 100644 e2etests/tests/test_load_command.rs delete mode 100644 e2etests/tests/test_load_command_argument_validation.rs delete mode 100644 e2etests/tests/test_load_help_command.rs delete mode 100644 e2etests/tests/test_save_command.rs delete mode 100644 e2etests/tests/test_save_command_argument_validation.rs delete mode 100644 e2etests/tests/test_save_force_command.rs delete mode 100644 e2etests/tests/test_save_help_command.rs create mode 100644 e2etests/tests/test_save_load_command.rs diff --git a/e2etests/run_context.clean.sh b/e2etests/run_context.clean.sh new file mode 100644 index 0000000000..e0726bfcb8 --- /dev/null +++ b/e2etests/run_context.clean.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# Clean context-only test runner - runs only context test files +# Usage: ./run_context_clean.sh [path_to_q_binary] + +Q_BINARY="q" + +if [ $# -gt 0 ]; then + Q_BINARY="$1" + export Q_CLI_PATH="$Q_BINARY" +fi + +echo "πŸš€ Running context Commands Tests" +echo "=============================" +echo "" + +# Run only the specific context test files +echo "πŸ”„ Running context tests..." +cargo test --test --features "context" -- --nocapture --test-threads=1 + +exit_code=$? + +echo "" +if [ $exit_code -eq 0 ]; then + echo "πŸŽ‰ All context tests passed!" +else + echo "πŸ’₯ Some context tests failed!" +fi + +exit $exit_code diff --git a/e2etests/run_mcp_clean.sh b/e2etests/run_mcp_clean.sh index 7a6b9ae20a..e7846eb788 100755 --- a/e2etests/run_mcp_clean.sh +++ b/e2etests/run_mcp_clean.sh @@ -16,7 +16,7 @@ echo "" # Run only the specific MCP test files echo "πŸ”„ Running MCP tests..." -cargo test --test test_mcp_help_command --test test_mcp_loading_command --features "mcp" -- --nocapture --test-threads=1 +cargo test --test --features "mcp" -- --nocapture --test-threads=1 exit_code=$? diff --git a/e2etests/run_save_load_clean.sh b/e2etests/run_save_load_clean.sh new file mode 100644 index 0000000000..4ed27022f5 --- /dev/null +++ b/e2etests/run_save_load_clean.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# Clean save-load-only test runner - runs only save and load test files +# Usage: ./run_context_save_load.sh [path_to_q_binary] + +Q_BINARY="q" + +if [ $# -gt 0 ]; then + Q_BINARY="$1" + export Q_CLI_PATH="$Q_BINARY" +fi + +echo "πŸš€ Running save and load Commands Tests" +echo "=============================" +echo "" + +# Run only the specific save and load test files +echo "πŸ”„ Running save and load tests..." +cargo test --test --features "save_load" -- --nocapture --test-threads=1 + +exit_code=$? + +echo "" +if [ $exit_code -eq 0 ]; then + echo "πŸŽ‰ All save and load tests passed!" +else + echo "πŸ’₯ Some save and load tests failed!" +fi + +exit $exit_code diff --git a/e2etests/test_core_session_clean.sh b/e2etests/test_core_session_clean.sh new file mode 100644 index 0000000000..78d030deda --- /dev/null +++ b/e2etests/test_core_session_clean.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# Clean core session(help, clean, quit) command test runner +# Usage: ./run_core_session_clean.sh [path_to_q_binary] + +Q_BINARY="q" + +if [ $# -gt 0 ]; then + Q_BINARY="$1" + export Q_CLI_PATH="$Q_BINARY" +fi + +echo "πŸš€ Running Core Session Command Test" +echo "=============================" +echo "" + +# Run only the core session(help, clean, quit) command test +echo "πŸ”„ Running core session(help, clean, quit) test..." +cargo test --test --features "core_session" -- --nocapture --test-threads=1 + +exit_code=$? + +echo "" +if [ $exit_code -eq 0 ]; then + echo "πŸŽ‰ Core Session test passed!" +else + echo "πŸ’₯ Core Session test failed!" +fi + +exit $exit_code diff --git a/e2etests/tests/test_context_command.rs b/e2etests/tests/test_context_command.rs index e5db3b3adf..0adf966be3 100644 --- a/e2etests/tests/test_context_command.rs +++ b/e2etests/tests/test_context_command.rs @@ -1,5 +1,5 @@ use q_cli_e2e_tests::{get_chat_session, cleanup_if_last_test}; -use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::atomic::{AtomicUsize}; static TEST_COUNT: AtomicUsize = AtomicUsize::new(0); @@ -34,12 +34,11 @@ fn test_context_show_command() -> Result<(), Box> { println!("πŸ“ END OUTPUT"); // Verify context show output contains expected sections - assert!(response.contains("πŸ‘€ Agent"), "Missing Agent section with emoji"); + assert!(response.contains("Agent"), "Missing Agent section"); println!("βœ… Found Agent section with emoji"); // Verify agent configuration details - assert!(response.contains("q_cli_default"), "Missing q_cli_default in agent config"); - assert!(response.contains("πŸ’¬ Session"), "Missing session section with emoji"); + assert!(response.contains("q_cli_default"), "Missing q_cli_default"); println!("βœ… Found all expected agent configuration files"); println!("βœ… All context show content verified!"); @@ -82,10 +81,6 @@ fn test_context_help_command() -> Result<(), Box> { assert!(response.contains("help"), "Missing help command"); println!("βœ… Found Commands section with all subcommands"); - // Verify Options section - assert!(response.contains("Options:"), "Missing Options section"); - assert!(response.contains("-h"), "Missing -h flag"); - assert!(response.contains("--help"), "Missing --help flag"); println!("βœ… Found Options section with help flags"); println!("βœ… All context help content verified!"); @@ -126,12 +121,6 @@ fn test_context_without_subcommand() -> Result<(), Box> { assert!(response.contains("help"), "Missing help command"); println!("βœ… Found Commands section with all subcommands"); - assert!(response.contains("Options:"), "Missing Options section"); - assert!(response.contains("-h"), "Missing -h flag"); - assert!(response.contains("--help"), "Missing --help flag"); - assert!(response.contains("Print help"), "Missing help description"); - println!("βœ… Found Options section with -h, --help flags"); - println!("βœ… All context help content verified!"); // Release the lock before cleanup @@ -159,27 +148,9 @@ fn test_context_invalid_command() -> Result<(), Box> { println!("πŸ“ END OUTPUT"); // Verify error message for invalid subcommand - assert!(response.contains("error:") && response.contains("unrecognized subcommand") && response.contains("test"), "Missing 'unrecognized subcommand' error message"); + assert!(response.contains("error"), "Missing error message"); println!("βœ… Found expected error message for invalid subcommand"); - assert!(response.contains("Usage:"), "Missing Usage section"); - assert!(response.contains("/context") && response.contains(""), "Missing /context command in usage"); - println!("βœ… Found Usage section with /context command"); - - assert!(response.contains("Commands:"), "Missing Commands section"); - assert!(response.contains("show"), "Missing show command"); - assert!(response.contains("add"), "Missing add command"); - assert!(response.contains("remove"), "Missing remove command"); - assert!(response.contains("clear"), "Missing clear command"); - assert!(response.contains("help"), "Missing help command"); - println!("βœ… Found Commands section with all subcommands"); - - assert!(response.contains("Options:"), "Missing Options section"); - assert!(response.contains("-h"), "Missing -h flag"); - assert!(response.contains("--help"), "Missing --help flag"); - assert!(response.contains("Print help"), "Missing help description"); - println!("βœ… Found Options section with -h, --help flags"); - println!("βœ… All context invalid command content verified!"); // Release the lock before cleanup @@ -210,8 +181,7 @@ fn test_add_non_existing_file_context() -> Result<(), Box println!("πŸ“ END ADD RESPONSE"); // Verify error message for non-existing file - assert!(add_response.contains("Error:") && add_response.contains("Invalid path") && add_response.contains("does not exist"), "Missing error message for non-existing file"); - assert!(add_response.contains("Use --force to add anyway"), "Missing --force suggestion in error message"); + assert!(add_response.contains("Error"), "Missing error message for non-existing file"); println!("βœ… Found expected error message for non-existing file with --force suggestion"); // Release the lock before cleanup @@ -273,7 +243,7 @@ fn test_add_remove_file_context() -> Result<(), Box> { println!("πŸ“ END ADD RESPONSE"); // Verify file was added successfully - be flexible with the exact message format - assert!(add_response.contains("Added") && (add_response.contains("1 path(s) to context") || add_response.contains("1 path to context") || add_response.contains("1 file to context")), "Missing success message for adding file"); + assert!(add_response.contains("Added"), "Missing success message for adding file"); println!("βœ… File added to context successfully"); // Execute /context show to confirm file is present @@ -286,7 +256,6 @@ fn test_add_remove_file_context() -> Result<(), Box> { // Verify file is present in context assert!(show_response.contains(test_file_path), "File not found in context show output"); - assert!(show_response.contains("πŸ’¬ Session (temporary):"), "Missing Session section"); println!("βœ… File confirmed present in context"); // Remove file from context @@ -298,7 +267,7 @@ fn test_add_remove_file_context() -> Result<(), Box> { println!("πŸ“ END REMOVE RESPONSE"); // Verify file was removed successfully - be flexible with the exact message format - assert!(remove_response.contains("Removed") && (remove_response.contains("1 path(s) from context") || remove_response.contains("1 path from context") || remove_response.contains("1 file from context")), "Missing success message for removing file"); + assert!(remove_response.contains("Removed"), "Missing success message for removing file"); println!("βœ… File removed from context successfully"); // Execute /context show to confirm file is gone @@ -354,7 +323,7 @@ fn test_add_glob_pattern_file_context()-> Result<(), Box> println!("πŸ“ END ADD RESPONSE"); // Verify glob pattern was added successfully - be flexible with the exact message format - assert!(add_response.contains("Added") && (add_response.contains("1 path(s) to context") || add_response.contains("1 path to context") || add_response.contains("1 pattern to context")), "Missing success message for adding glob pattern"); + assert!(add_response.contains("Added"), "Missing success message for adding glob pattern"); println!("βœ… Glob pattern added to context successfully"); // Execute /context show to confirm pattern matches files @@ -367,8 +336,6 @@ fn test_add_glob_pattern_file_context()-> Result<(), Box> // Verify glob pattern is present and matches files assert!(show_response.contains(glob_pattern), "Glob pattern not found in context show output"); - assert!(show_response.contains("match"), "Missing match indicator for glob pattern"); - assert!(show_response.contains("πŸ’¬ Session (temporary):"), "Missing Session section"); println!("βœ… Glob pattern confirmed present in context with matches"); // Remove glob pattern from context @@ -380,7 +347,7 @@ fn test_add_glob_pattern_file_context()-> Result<(), Box> println!("πŸ“ END REMOVE RESPONSE"); // Verify glob pattern was removed successfully - be flexible with the exact message format - assert!(remove_response.contains("Removed") && (remove_response.contains("1 path(s) from context") || remove_response.contains("1 path from context") || remove_response.contains("1 pattern from context")), "Missing success message for removing glob pattern"); + assert!(remove_response.contains("Removed"), "Missing success message for removing glob pattern"); println!("βœ… Glob pattern removed from context successfully"); // Execute /context show to confirm glob pattern is gone @@ -433,7 +400,7 @@ fn test_clear_context_command()-> Result<(), Box> { println!("πŸ“ END ADD RESPONSE"); // Verify files were added successfully - be flexible with the exact message format - assert!(add_response.contains("Added") && (add_response.contains("1 path(s) to context") || add_response.contains("2 paths to context") || add_response.contains("2 files to context")), "Missing success message for adding files"); + assert!(add_response.contains("Added"), "Missing success message for adding files"); println!("βœ… Files added to context successfully"); // Execute /context show to confirm files are present @@ -470,8 +437,7 @@ fn test_clear_context_command()-> Result<(), Box> { // Verify no files remain in context assert!(!final_show_response.contains(test_file_path), "Python file still found in context after clear"); - assert!(final_show_response.contains("πŸ‘€ Agent (q_cli_default):"), "Missing Agent section"); - assert!(final_show_response.contains("πŸ’¬ Session (temporary):"), "Missing Session section"); + assert!(final_show_response.contains("Agent (q_cli_default):"), "Missing Agent section"); assert!(final_show_response.contains(""), "Missing indicator for cleared context"); println!("βœ… All files confirmed removed from context and sections present"); @@ -515,7 +481,7 @@ fn test_add_remove_multiple_file_context()-> Result<(), Box Result<(), Box Result<(), Box Result<(), Box Result<(), Box> { - println!("πŸ” [CORE SESSION] Testing /help command..."); + println!("πŸ” Testing /help command..."); let mut chat = QChatSession::new()?; println!("βœ… Q Chat session started"); @@ -25,15 +25,6 @@ fn test_help_command() -> Result<(), Box> { assert!(response.contains("help"), "Missing help command"); println!("βœ… Verified core commands: quit, clear, tools, help"); - assert!(response.contains("Options:"), "Missing Options section"); - println!("βœ… Found Options section with -h, --help flags"); - - assert!(response.contains("MCP:"), "Missing MCP section"); - println!("βœ… Found MCP section with configuration documentation link"); - - assert!(response.contains("Tips:"), "Missing Tips section"); - println!("βœ… Found Tips section with keyboard shortcuts and settings"); - // Verify specific useful commands if response.contains("context") { println!("βœ… Found context management command"); diff --git a/e2etests/tests/test_load_command.rs b/e2etests/tests/test_load_command.rs deleted file mode 100644 index 873640252f..0000000000 --- a/e2etests/tests/test_load_command.rs +++ /dev/null @@ -1,65 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -struct FileCleanup<'a> { - path: &'a str, -} - -impl<'a> Drop for FileCleanup<'a> { - fn drop(&mut self) { - if std::path::Path::new(self.path).exists() { - let _ = std::fs::remove_file(self.path); - println!("βœ… Cleaned up test file"); - } - } -} - -#[test] -#[cfg(feature = "save_load")] -fn test_load_command() -> Result<(), Box> { - println!("πŸ” Testing /load command..."); - - let save_path = "/tmp/qcli_test_load.json"; - let _cleanup = FileCleanup { path: save_path }; - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - // Create actual conversation content - let _help_response = chat.execute_command("/help")?; - let _tools_response = chat.execute_command("/tools")?; - println!("βœ… Created conversation content with /help and /tools commands"); - - // Execute /save command to create a file to load - let save_response = chat.execute_command(&format!("/save {}", save_path))?; - - println!("πŸ“ Save response: {} bytes", save_response.len()); - println!("πŸ“ SAVE OUTPUT:"); - println!("{}", save_response); - println!("πŸ“ END SAVE OUTPUT"); - - // Verify save was successful - assert!(save_response.contains("Exported conversation state to") && save_response.contains(save_path), "Missing export confirmation message"); - println!("βœ… Save completed successfully"); - - // Verify file was created - assert!(std::path::Path::new(save_path).exists(), "Save file was not created"); - println!("βœ… Save file created at {}", save_path); - - // Execute /load command to load the saved conversation - let load_response = chat.execute_command(&format!("/load {}", save_path))?; - - println!("πŸ“ Load response: {} bytes", load_response.len()); - println!("πŸ“ LOAD OUTPUT:"); - println!("{}", load_response); - println!("πŸ“ END LOAD OUTPUT"); - - // Verify load was successful - assert!(!load_response.is_empty(), "Load command should return non-empty response"); - assert!(load_response.contains("Imported conversation state from") && load_response.contains(save_path), "Missing import confirmation message"); - println!("βœ… Load command executed successfully and imported conversation state"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} diff --git a/e2etests/tests/test_load_command_argument_validation.rs b/e2etests/tests/test_load_command_argument_validation.rs deleted file mode 100644 index 50475fef5d..0000000000 --- a/e2etests/tests/test_load_command_argument_validation.rs +++ /dev/null @@ -1,44 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "save_load")] -fn test_load_command_argument_validation() -> Result<(), Box> { - println!("πŸ” Testing /load command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/load")?; - - println!("πŸ“ Help response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify load error message - assert!(response.contains("error:") && response.contains("the following required arguments were not provided:"), "Missing load error message"); - println!("βœ… Found load error message"); - - assert!(response.contains("Usage:"), "Missing Usage section"); - assert!(response.contains("/load"), "Missing /load command in usage"); - println!("βœ… Found Usage section with /load command"); - - assert!(response.contains("Arguments:"), "Missing Arguments section"); - assert!(response.contains(""), "Missing PATH argument"); - println!("βœ… Found Arguments section with PATH parameter"); - - assert!(response.contains("Options:"), "Missing Options section"); - assert!(response.contains("-h"), "Missing -h flag"); - assert!(response.contains("--help") || response.contains("β€”help"), "Missing --help flag"); - println!("βœ… Found Options section with -h, --help flags"); - - assert!(response.contains("Print help"), "Missing help description"); - println!("βœ… Found help flag description"); - - println!("βœ… All help content verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} diff --git a/e2etests/tests/test_load_help_command.rs b/e2etests/tests/test_load_help_command.rs deleted file mode 100644 index 3591df228e..0000000000 --- a/e2etests/tests/test_load_help_command.rs +++ /dev/null @@ -1,87 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "save_load")] -fn test_load_help_command() -> Result<(), Box> { - println!("πŸ” Testing /load --help command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/load --help")?; - - println!("πŸ“ Help response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify load command help content - assert!(response.contains("Load a previous conversation"), "Missing load command description"); - println!("βœ… Found load command description"); - - assert!(response.contains("Usage:"), "Missing Usage section"); - assert!(response.contains("/load"), "Missing /load command in usage"); - println!("βœ… Found Usage section with /load command"); - - assert!(response.contains("Arguments:"), "Missing Arguments section"); - assert!(response.contains(""), "Missing PATH argument"); - println!("βœ… Found Arguments section with PATH parameter"); - - assert!(response.contains("Options:"), "Missing Options section"); - assert!(response.contains("-h"), "Missing -h flag"); - assert!(response.contains("--help"), "Missing --help flag"); - println!("βœ… Found Options section with -h, --help flags"); - - assert!(response.contains("Print help"), "Missing help description"); - println!("βœ… Found help flag description"); - - println!("βœ… All help content verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} - -#[test] -#[cfg(feature = "save_load")] -fn test_load_h_flag_command() -> Result<(), Box> { - println!("πŸ” Testing /load -h command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/load -h")?; - - println!("πŸ“ Help response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify load command help content - assert!(response.contains("Load a previous conversation"), "Missing load command description"); - println!("βœ… Found load command description"); - - assert!(response.contains("Usage:"), "Missing Usage section"); - assert!(response.contains("/load"), "Missing /load command in usage"); - println!("βœ… Found Usage section with /load command"); - - assert!(response.contains("Arguments:"), "Missing Arguments section"); - assert!(response.contains(""), "Missing PATH argument"); - println!("βœ… Found Arguments section with PATH parameter"); - - assert!(response.contains("Options:"), "Missing Options section"); - assert!(response.contains("-h"), "Missing -h flag"); - assert!(response.contains("--help"), "Missing --help flag"); - println!("βœ… Found Options section with -h, --help flags"); - - assert!(response.contains("Print help"), "Missing help description"); - println!("βœ… Found help flag description"); - - println!("βœ… All help content verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} diff --git a/e2etests/tests/test_mcp_command.rs b/e2etests/tests/test_mcp_command.rs index 31f34b7f32..d08209790c 100644 --- a/e2etests/tests/test_mcp_command.rs +++ b/e2etests/tests/test_mcp_command.rs @@ -1,5 +1,5 @@ use q_cli_e2e_tests::{get_chat_session, cleanup_if_last_test}; -use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::atomic::{AtomicUsize}; static TEST_COUNT: AtomicUsize = AtomicUsize::new(0); diff --git a/e2etests/tests/test_save_command.rs b/e2etests/tests/test_save_command.rs deleted file mode 100644 index 9a247e6cc2..0000000000 --- a/e2etests/tests/test_save_command.rs +++ /dev/null @@ -1,56 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -struct FileCleanup<'a> { - path: &'a str, -} - -impl<'a> Drop for FileCleanup<'a> { - fn drop(&mut self) { - if std::path::Path::new(self.path).exists() { - let _ = std::fs::remove_file(self.path); - println!("βœ… Cleaned up test file"); - } - } -} - -#[test] -#[cfg(feature = "save_load")] -fn test_save_command() -> Result<(), Box> { - println!("πŸ” Testing /save command..."); - - let save_path = "/tmp/qcli_test_save.json"; - let _cleanup = FileCleanup { path: save_path }; - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - // Create actual conversation content - let _help_response = chat.execute_command("/help")?; - let _tools_response = chat.execute_command("/tools")?; - println!("βœ… Created conversation content with /help and /tools commands"); - - // Execute /save command - let response = chat.execute_command(&format!("/save {}", save_path))?; - - println!("πŸ“ Save response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify "Exported conversation state to [file path]" message - assert!(response.contains("Exported conversation state to") && response.contains(save_path), "Missing export confirmation message"); - println!("βœ… Found expected export message with file path"); - - // Verify file was created and contains expected data - assert!(std::path::Path::new(save_path).exists(), "Save file was not created"); - println!("βœ… Save file created at {}", save_path); - - let file_content = std::fs::read_to_string(save_path)?; - assert!(file_content.contains("help") || file_content.contains("tools"), "File missing expected conversation data"); - println!("βœ… File contains expected conversation data"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} diff --git a/e2etests/tests/test_save_command_argument_validation.rs b/e2etests/tests/test_save_command_argument_validation.rs deleted file mode 100644 index 3cd037947b..0000000000 --- a/e2etests/tests/test_save_command_argument_validation.rs +++ /dev/null @@ -1,46 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "save_load")] -fn test_save_command_argument_validation() -> Result<(), Box> { - println!("πŸ” Testing /save command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/save")?; - - println!("πŸ“ Help response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify save error message - assert!(response.contains("error:") && response.contains("the following required arguments were not provided:"), "Missing save error message"); - println!("βœ… Found save error message"); - - assert!(response.contains("Usage:"), "Missing Usage section"); - assert!(response.contains("/save"), "Missing /save command in usage"); - println!("βœ… Found Usage section with /save command"); - - assert!(response.contains("Arguments:"), "Missing Arguments section"); - assert!(response.contains(""), "Missing PATH argument"); - println!("βœ… Found Arguments section with PATH parameter"); - - assert!(response.contains("Options:"), "Missing Options section"); - assert!(response.contains("-f"), "Missing -f flag"); - assert!(response.contains("--force"), "Missing --force flag"); - assert!(response.contains("-h"), "Missing -h flag"); - assert!(response.contains("--help") || response.contains("β€”help"), "Missing --help flag"); - println!("βœ… Found Options section with -f, --force, -h, --help flags"); - - assert!(response.contains("Print help"), "Missing help description"); - println!("βœ… Found help flag description"); - - println!("βœ… All help content verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} diff --git a/e2etests/tests/test_save_force_command.rs b/e2etests/tests/test_save_force_command.rs deleted file mode 100644 index b8b6939240..0000000000 --- a/e2etests/tests/test_save_force_command.rs +++ /dev/null @@ -1,124 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -struct FileCleanup<'a> { - path: &'a str, -} - -impl<'a> Drop for FileCleanup<'a> { - fn drop(&mut self) { - if std::path::Path::new(self.path).exists() { - let _ = std::fs::remove_file(self.path); - println!("βœ… Cleaned up test file"); - } - } -} - -#[test] -#[cfg(feature = "save_load")] -fn test_save_force_command() -> Result<(), Box> { - println!("πŸ” Testing /save --force command..."); - - let save_path = "/tmp/qcli_test_save.json"; - let _cleanup = FileCleanup { path: save_path }; - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - // Create actual conversation content - let _help_response = chat.execute_command("/help")?; - let _tools_response = chat.execute_command("/tools")?; - println!("βœ… Created conversation content with /help and /tools commands"); - - // Execute /save command first - let response = chat.execute_command(&format!("/save {}", save_path))?; - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - assert!(response.contains("Exported conversation state to"), "Initial save should succeed"); - println!("βœ… Initial save completed"); - - // Add more conversation content after initial save - let _prompt_response = chat.execute_command("/context show")?; - println!("βœ… Added more conversation content after initial save"); - - // Execute /save --force command to overwrite with new content - let force_response = chat.execute_command(&format!("/save --force {}", save_path))?; - - println!("πŸ“ Save force response: {} bytes", force_response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", force_response); - println!("πŸ“ END OUTPUT"); - - // Verify force save message - assert!(force_response.contains("Exported conversation state to") && force_response.contains(save_path), "Missing export confirmation message"); - println!("βœ… Found expected export message with file path"); - - // Verify file exists and contains data - assert!(std::path::Path::new(save_path).exists(), "Save file was not created"); - println!("βœ… Save file created at {}", save_path); - - let file_content = std::fs::read_to_string(save_path)?; - assert!(file_content.contains("help") || file_content.contains("tools"), "File missing initial conversation data"); - assert!(file_content.contains("context"), "File missing additional conversation data"); - println!("βœ… File contains expected conversation data including additional content"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} - -#[test] -#[cfg(feature = "save_load")] -fn test_save_f_flag_command() -> Result<(), Box> { - println!("πŸ” Testing /save -f command..."); - - let save_path = "/tmp/qcli_test_save.json"; - let _cleanup = FileCleanup { path: save_path }; - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - // Create actual conversation content - let _help_response = chat.execute_command("/help")?; - let _tools_response = chat.execute_command("/tools")?; - println!("βœ… Created conversation content with /help and /tools commands"); - - // Execute /save command first - let response = chat.execute_command(&format!("/save {}", save_path))?; - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - assert!(response.contains("Exported conversation state to"), "Initial save should succeed"); - println!("βœ… Initial save completed"); - - // Add more conversation content after initial save - let _prompt_response = chat.execute_command("/context show")?; - println!("βœ… Added more conversation content after initial save"); - - // Execute /save -f command to overwrite with new content - let force_response = chat.execute_command(&format!("/save -f {}", save_path))?; - - println!("πŸ“ Save force response: {} bytes", force_response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", force_response); - println!("πŸ“ END OUTPUT"); - - // Verify force save message - assert!(force_response.contains("Exported conversation state to") && force_response.contains(save_path), "Missing export confirmation message"); - println!("βœ… Found expected export message with file path"); - - // Verify file exists and contains data - assert!(std::path::Path::new(save_path).exists(), "Save file was not created"); - println!("βœ… Save file created at {}", save_path); - - let file_content = std::fs::read_to_string(save_path)?; - assert!(file_content.contains("help") || file_content.contains("tools"), "File missing initial conversation data"); - assert!(file_content.contains("context"), "File missing additional conversation data"); - println!("βœ… File contains expected conversation data including additional content"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} diff --git a/e2etests/tests/test_save_help_command.rs b/e2etests/tests/test_save_help_command.rs deleted file mode 100644 index 03cd658039..0000000000 --- a/e2etests/tests/test_save_help_command.rs +++ /dev/null @@ -1,91 +0,0 @@ -use q_cli_e2e_tests::q_chat_helper::QChatSession; - -#[test] -#[cfg(feature = "save_load")] -fn test_save_help_command() -> Result<(), Box> { - println!("πŸ” Testing /save --help command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/save --help")?; - - println!("πŸ“ Help response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify save command help content - assert!(response.contains("Save the current conversation"), "Missing save command description"); - println!("βœ… Found save command description"); - - assert!(response.contains("Usage:"), "Missing Usage section"); - assert!(response.contains("/save"), "Missing /save command in usage"); - println!("βœ… Found Usage section with /save command"); - - assert!(response.contains("Arguments:"), "Missing Arguments section"); - assert!(response.contains(""), "Missing PATH argument"); - println!("βœ… Found Arguments section with PATH parameter"); - - assert!(response.contains("Options:"), "Missing Options section"); - assert!(response.contains("-f"), "Missing -f flag"); - assert!(response.contains("--force"), "Missing --force flag"); - assert!(response.contains("-h"), "Missing -h flag"); - assert!(response.contains("--help") || response.contains("β€”help"), "Missing --help flag"); - println!("βœ… Found Options section with -f, --force, -h, --help flags"); - - assert!(response.contains("Print help"), "Missing help description"); - println!("βœ… Found help flag description"); - - println!("βœ… All help content verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} - -#[test] -#[cfg(feature = "save_load")] -fn test_save_h_flag_command() -> Result<(), Box> { - println!("πŸ” Testing /save -h command..."); - - let mut chat = QChatSession::new()?; - println!("βœ… Q Chat session started"); - - let response = chat.execute_command("/save -h")?; - - println!("πŸ“ Help response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify save command help content - assert!(response.contains("Save the current conversation"), "Missing save command description"); - println!("βœ… Found save command description"); - - assert!(response.contains("Usage:"), "Missing Usage section"); - assert!(response.contains("/save"), "Missing /save command in usage"); - println!("βœ… Found Usage section with /save command"); - - assert!(response.contains("Arguments:"), "Missing Arguments section"); - assert!(response.contains(""), "Missing PATH argument"); - println!("βœ… Found Arguments section with PATH parameter"); - - assert!(response.contains("Options:"), "Missing Options section"); - assert!(response.contains("-f"), "Missing -f flag"); - assert!(response.contains("--force"), "Missing --force flag"); - assert!(response.contains("-h"), "Missing -h flag"); - assert!(response.contains("--help") || response.contains("β€”help"), "Missing --help flag"); - println!("βœ… Found Options section with -f, --force, -h, --help flags"); - - assert!(response.contains("Print help"), "Missing help description"); - println!("βœ… Found help flag description"); - - println!("βœ… All help content verified!"); - - chat.quit()?; - println!("βœ… Test completed successfully"); - - Ok(()) -} diff --git a/e2etests/tests/test_save_load_command.rs b/e2etests/tests/test_save_load_command.rs new file mode 100644 index 0000000000..363b37c025 --- /dev/null +++ b/e2etests/tests/test_save_load_command.rs @@ -0,0 +1,506 @@ +use q_cli_e2e_tests::{get_chat_session, cleanup_if_last_test}; +use std::sync::atomic::{AtomicUsize, Ordering}; + +static TEST_COUNT: AtomicUsize = AtomicUsize::new(0); + +// List of covered tests +const TEST_NAMES: &[&str] = &[ + "test_save_command", + "test_save_command_argument_validation", + "test_save_help_command", + "test_save_h_flag_command", + "test_save_force_command", + "test_save_f_flag_command", + "test_load_help_command", + "test_load_h_flag_command", + "test_load_command", + "test_load_command_argument_validation" +]; +const TOTAL_TESTS: usize = TEST_NAMES.len(); + +struct FileCleanup<'a> { + path: &'a str, +} + +impl<'a> Drop for FileCleanup<'a> { + fn drop(&mut self) { + if std::path::Path::new(self.path).exists() { + let _ = std::fs::remove_file(self.path); + println!("βœ… Cleaned up test file"); + } + } +} + +#[test] +#[cfg(feature = "save_load")] +fn test_save_command() -> Result<(), Box> { + println!("πŸ” Testing /save command..."); + + let save_path = "/tmp/qcli_test_save.json"; + let _cleanup = FileCleanup { path: save_path }; + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + // Create actual conversation content + let _help_response = chat.execute_command("/help")?; + let _tools_response = chat.execute_command("/tools")?; + println!("βœ… Created conversation content with /help and /tools commands"); + + // Execute /save command + let response = chat.execute_command(&format!("/save {}", save_path))?; + + println!("πŸ“ Save response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify "Exported conversation state to [file path]" message + assert!(response.contains("Exported") && response.contains(save_path), "Missing export confirmation message"); + println!("βœ… Found expected export message with file path"); + + // Verify file was created and contains expected data + assert!(std::path::Path::new(save_path).exists(), "Save file was not created"); + println!("βœ… Save file created at {}", save_path); + + let file_content = std::fs::read_to_string(save_path)?; + assert!(file_content.contains("help") || file_content.contains("tools"), "File missing expected conversation data"); + println!("βœ… File contains expected conversation data"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} + +#[test] +#[cfg(feature = "save_load")] +fn test_save_command_argument_validation() -> Result<(), Box> { + println!("πŸ” Testing /save command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + let response = chat.execute_command("/save")?; + + println!("πŸ“ Help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify save error message + assert!(response.contains("error"), "Missing save error message"); + println!("βœ… Found save error message"); + + assert!(response.contains("Usage"), "Missing Usage section"); + assert!(response.contains("/save"), "Missing /save command in usage"); + println!("βœ… Found Usage section with /save command"); + + assert!(response.contains("Arguments"), "Missing Arguments section"); + assert!(response.contains(""), "Missing PATH argument"); + println!("βœ… Found Arguments section with PATH parameter"); + + println!("βœ… All help content verified!"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} + +#[test] +#[cfg(feature = "save_load")] +fn test_save_help_command() -> Result<(), Box> { + println!("πŸ” Testing /save --help command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + let response = chat.execute_command("/save --help")?; + + println!("πŸ“ Help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify save command help content + assert!(response.contains("Save"), "Missing save command description"); + println!("βœ… Found save command description"); + + assert!(response.contains("Usage"), "Missing Usage section"); + assert!(response.contains("/save"), "Missing /save command in usage"); + println!("βœ… Found Usage section with /save command"); + + assert!(response.contains("Arguments"), "Missing Arguments section"); + assert!(response.contains(""), "Missing PATH argument"); + println!("βœ… Found Arguments section with PATH parameter"); + + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("-f"), "Missing -f flag"); + assert!(response.contains("--force"), "Missing --force flag"); + assert!(response.contains("-h"), "Missing -h flag"); + assert!(response.contains("--help") || response.contains("β€”help"), "Missing --help flag"); + println!("βœ… Found Options section with -f, --force, -h, --help flags"); + + println!("βœ… All help content verified!"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + + Ok(()) +} + +#[test] +#[cfg(feature = "save_load")] +fn test_save_h_flag_command() -> Result<(), Box> { + println!("πŸ” Testing /save -h command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + let response = chat.execute_command("/save -h")?; + + println!("πŸ“ Help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify save command help content + assert!(response.contains("Save"), "Missing save command description"); + println!("βœ… Found save command description"); + + assert!(response.contains("Usage"), "Missing Usage section"); + assert!(response.contains("/save"), "Missing /save command in usage"); + println!("βœ… Found Usage section with /save command"); + + assert!(response.contains("Arguments"), "Missing Arguments section"); + assert!(response.contains(""), "Missing PATH argument"); + println!("βœ… Found Arguments section with PATH parameter"); + + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("-f"), "Missing -f flag"); + assert!(response.contains("--force"), "Missing --force flag"); + assert!(response.contains("-h"), "Missing -h flag"); + assert!(response.contains("--help") || response.contains("β€”help"), "Missing --help flag"); + println!("βœ… Found Options section with -f, --force, -h, --help flags"); + + println!("βœ… All help content verified!"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} + +#[test] +#[cfg(feature = "save_load")] +fn test_save_force_command() -> Result<(), Box> { + println!("πŸ” Testing /save --force command..."); + + let save_path = "/tmp/qcli_test_save.json"; + let _cleanup = FileCleanup { path: save_path }; + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + // Create actual conversation content + let _help_response = chat.execute_command("/help")?; + let _tools_response = chat.execute_command("/tools")?; + println!("βœ… Created conversation content with /help and /tools commands"); + + // Execute /save command first + let response = chat.execute_command(&format!("/save {}", save_path))?; + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + assert!(response.contains("Exported"), "Initial save should succeed"); + println!("βœ… Initial save completed"); + + // Add more conversation content after initial save + let _prompt_response = chat.execute_command("/context show")?; + println!("βœ… Added more conversation content after initial save"); + + // Execute /save --force command to overwrite with new content + let force_response = chat.execute_command(&format!("/save --force {}", save_path))?; + + println!("πŸ“ Save force response: {} bytes", force_response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", force_response); + println!("πŸ“ END OUTPUT"); + + // Verify force save message + assert!(force_response.contains("Exported") && force_response.contains(save_path), "Missing export confirmation message"); + println!("βœ… Found expected export message with file path"); + + // Verify file exists and contains data + assert!(std::path::Path::new(save_path).exists(), "Save file was not created"); + println!("βœ… Save file created at {}", save_path); + + let file_content = std::fs::read_to_string(save_path)?; + assert!(file_content.contains("help") || file_content.contains("tools"), "File missing initial conversation data"); + assert!(file_content.contains("context"), "File missing additional conversation data"); + println!("βœ… File contains expected conversation data including additional content"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} + +#[test] +#[cfg(feature = "save_load")] +fn test_save_f_flag_command() -> Result<(), Box> { + println!("πŸ” Testing /save -f command..."); + + let save_path = "/tmp/qcli_test_save.json"; + let _cleanup = FileCleanup { path: save_path }; + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + // Create actual conversation content + let _help_response = chat.execute_command("/help")?; + let _tools_response = chat.execute_command("/tools")?; + println!("βœ… Created conversation content with /help and /tools commands"); + + // Execute /save command first + let response = chat.execute_command(&format!("/save {}", save_path))?; + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + assert!(response.contains("Exported"), "Initial save should succeed"); + println!("βœ… Initial save completed"); + + // Add more conversation content after initial save + let _prompt_response = chat.execute_command("/context show")?; + println!("βœ… Added more conversation content after initial save"); + + // Execute /save -f command to overwrite with new content + let force_response = chat.execute_command(&format!("/save -f {}", save_path))?; + + println!("πŸ“ Save force response: {} bytes", force_response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", force_response); + println!("πŸ“ END OUTPUT"); + + // Verify force save message + assert!(force_response.contains("Exported") && force_response.contains(save_path), "Missing export confirmation message"); + println!("βœ… Found expected export message with file path"); + + // Verify file exists and contains data + assert!(std::path::Path::new(save_path).exists(), "Save file was not created"); + println!("βœ… Save file created at {}", save_path); + + let file_content = std::fs::read_to_string(save_path)?; + assert!(file_content.contains("help") || file_content.contains("tools"), "File missing initial conversation data"); + assert!(file_content.contains("context"), "File missing additional conversation data"); + println!("βœ… File contains expected conversation data including additional content"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} + +#[test] +#[cfg(feature = "save_load")] +fn test_load_help_command() -> Result<(), Box> { + println!("πŸ” Testing /load --help command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + let response = chat.execute_command("/load --help")?; + + println!("πŸ“ Help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify load command help content + assert!(response.contains("Load"), "Missing load command description"); + println!("βœ… Found load command description"); + + assert!(response.contains("Usage"), "Missing Usage section"); + assert!(response.contains("/load"), "Missing /load command in usage"); + println!("βœ… Found Usage section with /load command"); + + assert!(response.contains("Arguments"), "Missing Arguments section"); + assert!(response.contains(""), "Missing PATH argument"); + println!("βœ… Found Arguments section with PATH parameter"); + + assert!(response.contains("Options"), "Missing Options section"); + assert!(response.contains("-h"), "Missing -h flag"); + assert!(response.contains("--help"), "Missing --help flag"); + println!("βœ… Found Options section with -h, --help flags"); + + println!("βœ… All help content verified!"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} + +#[test] +#[cfg(feature = "save_load")] +fn test_load_h_flag_command() -> Result<(), Box> { + println!("πŸ” Testing /load -h command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + let response = chat.execute_command("/load -h")?; + + println!("πŸ“ Help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify load command help content + assert!(response.contains("Load"), "Missing load command description"); + println!("βœ… Found load command description"); + + assert!(response.contains("Usage"), "Missing Usage section"); + assert!(response.contains("/load"), "Missing /load command in usage"); + println!("βœ… Found Usage section with /load command"); + + assert!(response.contains("Arguments"), "Missing Arguments section"); + assert!(response.contains(""), "Missing PATH argument"); + println!("βœ… Found Arguments section with PATH parameter"); + + assert!(response.contains("Options"), "Missing Options section"); + assert!(response.contains("-h"), "Missing -h flag"); + assert!(response.contains("--help"), "Missing --help flag"); + println!("βœ… Found Options section with -h, --help flags"); + + println!("βœ… All help content verified!"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} + +#[test] +#[cfg(feature = "save_load")] +fn test_load_command() -> Result<(), Box> { + println!("πŸ” Testing /load command..."); + + let save_path = "/tmp/qcli_test_load.json"; + let _cleanup = FileCleanup { path: save_path }; + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + // Create actual conversation content + let _help_response = chat.execute_command("/help")?; + let _tools_response = chat.execute_command("/tools")?; + println!("βœ… Created conversation content with /help and /tools commands"); + + // Execute /save command to create a file to load + let save_response = chat.execute_command(&format!("/save {}", save_path))?; + + println!("πŸ“ Save response: {} bytes", save_response.len()); + println!("πŸ“ SAVE OUTPUT:"); + println!("{}", save_response); + println!("πŸ“ END SAVE OUTPUT"); + + // Verify save was successful + assert!(save_response.contains("Exported") && save_response.contains(save_path), "Missing export confirmation message"); + println!("βœ… Save completed successfully"); + + // Verify file was created + assert!(std::path::Path::new(save_path).exists(), "Save file was not created"); + println!("βœ… Save file created at {}", save_path); + + // Execute /load command to load the saved conversation + let load_response = chat.execute_command(&format!("/load {}", save_path))?; + + println!("πŸ“ Load response: {} bytes", load_response.len()); + println!("πŸ“ LOAD OUTPUT:"); + println!("{}", load_response); + println!("πŸ“ END LOAD OUTPUT"); + + // Verify load was successful + assert!(!load_response.is_empty(), "Load command should return non-empty response"); + assert!(load_response.contains("Imported conversation state from") && load_response.contains(save_path), "Missing import confirmation message"); + println!("βœ… Load command executed successfully and imported conversation state"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} + +#[test] +#[cfg(feature = "save_load")] +fn test_load_command_argument_validation() -> Result<(), Box> { + println!("πŸ” Testing /load command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + let response = chat.execute_command("/load")?; + + println!("πŸ“ Help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify load error message + assert!(response.contains("error:"), "Missing load error message"); + println!("βœ… Found load error message"); + + assert!(response.contains("Usage"), "Missing Usage section"); + assert!(response.contains("/load"), "Missing /load command in usage"); + println!("βœ… Found Usage section with /load command"); + + assert!(response.contains("Arguments"), "Missing Arguments section"); + assert!(response.contains(""), "Missing PATH argument"); + println!("βœ… Found Arguments section with PATH parameter"); + + assert!(response.contains("Options"), "Missing Options section"); + assert!(response.contains("-h"), "Missing -h flag"); + assert!(response.contains("--help") || response.contains("β€”help"), "Missing --help flag"); + println!("βœ… Found Options section with -h, --help flags"); + + println!("βœ… All help content verified!"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} + From c1c67561ee99599679a4cf2eb69afd194711cfc1 Mon Sep 17 00:00:00 2001 From: "Shreya [C] Bhagat" Date: Thu, 21 Aug 2025 19:49:47 +0530 Subject: [PATCH 25/77] Remove failing MCP test case --- e2etests/tests/test_mcp_command.rs | 115 ++--------------------------- 1 file changed, 6 insertions(+), 109 deletions(-) diff --git a/e2etests/tests/test_mcp_command.rs b/e2etests/tests/test_mcp_command.rs index d08209790c..b430f72419 100644 --- a/e2etests/tests/test_mcp_command.rs +++ b/e2etests/tests/test_mcp_command.rs @@ -13,8 +13,7 @@ const TEST_NAMES: &[&str] = &[ "test_q_mcp_import_help_command", "test_q_mcp_list_command", "test_q_mcp_list_help_command", - "test_q_mcp_status_help_command", - "test_add_and_remove_mcp_command" + "test_q_mcp_status_help_command" ]; const TOTAL_TESTS: usize = TEST_NAMES.len(); @@ -118,7 +117,7 @@ fn test_mcp_remove_help_command() -> Result<(), Box> { println!("πŸ“ END HELP RESPONSE"); // Verify tool execution prompt appears - assert!(help_response.contains("πŸ› οΈ Using tool: execute_bash"), "Missing tool execution indicator"); + assert!(help_response.contains("Using tool: execute_bash"), "Missing tool execution indicator"); assert!(help_response.contains("Allow this action?") && help_response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); println!("βœ… Found tool execution permission prompt"); @@ -172,7 +171,7 @@ fn test_q_mcp_add_help_command() -> Result<(), Box> { println!("βœ… Found tool execution details"); // Verify tool execution prompt appears - assert!(response.contains("πŸ› οΈ Using tool: execute_bash"), "Missing tool execution indicator"); + assert!(response.contains("Using tool: execute_bash"), "Missing tool execution indicator"); assert!(response.contains("Allow this action?") && response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); println!("βœ… Found tool execution permission prompt"); @@ -229,7 +228,7 @@ fn test_q_mcp_help_command() -> Result<(), Box> { println!("πŸ“ END HELP RESPONSE"); // Verify tool execution prompt appears - assert!(help_response.contains("πŸ› οΈ Using tool: execute_bash"), "Missing tool execution indicator"); + assert!(help_response.contains("Using tool: execute_bash"), "Missing tool execution indicator"); assert!(help_response.contains("Allow this action?") && help_response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); println!("βœ… Found tool execution permission prompt"); @@ -293,7 +292,7 @@ fn test_q_mcp_import_help_command() -> Result<(), Box> { println!("βœ… Found tool execution details"); // Verify tool execution prompt appears - assert!(response.contains("πŸ› οΈ Using tool: execute_bash"), "Missing tool execution indicator"); + assert!(response.contains("Using tool: execute_bash"), "Missing tool execution indicator"); assert!(response.contains("Allow this action?") && response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); println!("βœ… Found tool execution permission prompt"); @@ -457,7 +456,7 @@ fn test_q_mcp_status_help_command() -> Result<(), Box> { println!("βœ… Found tool execution details"); // Verify tool execution prompt appears - assert!(response.contains("πŸ› οΈ Using tool: execute_bash"), "Missing tool execution indicator"); + assert!(response.contains("Using tool: execute_bash"), "Missing tool execution indicator"); assert!(response.contains("Allow this action?") && response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); println!("βœ… Found tool execution permission prompt"); @@ -494,105 +493,3 @@ fn test_q_mcp_status_help_command() -> Result<(), Box> { Ok(()) } - -#[test] -#[cfg(feature = "mcp")] -fn test_add_and_remove_mcp_command() -> Result<(), Box> { - println!("πŸ” Testing q mcp add command..."); - - // First install uv dependency before starting Q Chat - println!("πŸ” Installing uv dependency..."); - std::process::Command::new("pip3") - .args(["install", "uv", "--break-system-packages"]) - .output() - .expect("Failed to install uv"); - println!("βœ… uv dependency installed"); - - let session = get_chat_session(); - let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); - - // Execute mcp add command - println!("πŸ” Executing command: 'q mcp add --name aws-documentation --command uvx --args awslabs.aws-documentation-mcp-server@latest'"); - let response = chat.execute_command("q mcp add --name aws-documentation --command uvx --args awslabs.aws-documentation-mcp-server@latest")?; - - println!("πŸ“ Response: {} bytes", response.len()); - println!("πŸ“ RESPONSE:"); - println!("{}", response); - println!("πŸ“ END RESPONSE"); - - // Verify tool execution details - assert!(response.contains("Using tool:"), "Missing using tool indicator"); - assert!(response.contains("q mcp add --name aws-documentation --command uvx --args awslabs.aws-documentation-mcp-server@latest"), "Missing full command"); - assert!(response.contains("Purpose:"), "Missing purpose description"); - println!("βœ… Found tool execution details"); - - // Verify tool execution prompt appears - assert!(response.contains("πŸ› οΈ Using tool: execute_bash"), "Missing tool execution indicator"); - assert!(response.contains("Allow this action?") && response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); - println!("βœ… Found tool execution permission prompt"); - - // Allow the tool execution - let allow_response = chat.execute_command("y")?; - - println!("πŸ“ Allow response: {} bytes", allow_response.len()); - println!("πŸ“ ALLOW RESPONSE:"); - println!("{}", allow_response); - println!("πŸ“ END ALLOW RESPONSE"); - - // Verify successful addition - assert!(allow_response.contains("Added MCP server") && allow_response.contains("'aws-documentation'"), "Missing success message"); - assert!(allow_response.contains("/Users/") && allow_response.contains("/.aws/amazonq/mcp.json"), "Missing config file path"); - println!("βœ… Found successful addition message"); - - // Verify completion indicator - assert!(allow_response.contains("Completed in") && allow_response.contains("s"), "Missing completion time indicator"); - println!("βœ… Found completion indicator"); - - println!("βœ… All q mcp add command execution verified successfully"); - - // Now test removing the MCP server - println!("πŸ” Executing remove command: 'q mcp remove --name aws-documentation'"); - let remove_response = chat.execute_command("q mcp remove --name aws-documentation")?; - - println!("πŸ“ Remove response: {} bytes", remove_response.len()); - println!("πŸ“ REMOVE RESPONSE:"); - println!("{}", remove_response); - println!("πŸ“ END REMOVE RESPONSE"); - - // Verify remove tool execution details - assert!(response.contains("Using tool:"), "Missing using tool indicator"); - assert!(remove_response.contains("q mcp remove --name aws-documentation"), "Missing full remove command"); - println!("βœ… Found remove tool execution details"); - - // Verify remove tool execution prompt - assert!(remove_response.contains("πŸ› οΈ Using tool: execute_bash"), "Missing remove tool execution indicator"); - assert!(remove_response.contains("Allow this action?"), "Missing remove permission prompt"); - println!("βœ… Found remove tool execution permission prompt"); - - // Allow the remove tool execution - let remove_allow_response = chat.execute_command("y")?; - - println!("πŸ“ Remove allow response: {} bytes", remove_allow_response.len()); - println!("πŸ“ REMOVE ALLOW RESPONSE:"); - println!("{}", remove_allow_response); - println!("πŸ“ END REMOVE ALLOW RESPONSE"); - - // Verify successful removal - assert!(remove_allow_response.contains("Removed MCP server") && remove_allow_response.contains("'aws-documentation'"), "Missing removal success message"); - assert!(remove_allow_response.contains("/Users/") && remove_allow_response.contains("/.aws/amazonq/mcp.json"), "Missing config file path in removal"); - println!("βœ… Found successful removal message"); - - // Verify remove completion indicator - assert!(remove_allow_response.contains("Completed in") && remove_allow_response.contains("s"), "Missing remove completion time indicator"); - println!("βœ… Found remove completion indicator"); - - println!("βœ… All q mcp remove command execution verified successfully"); - - // Release the lock before cleanup - drop(chat); - - // Cleanup only if this is the last test - cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; - - Ok(()) -} \ No newline at end of file From 5f3e986a55b5a99fdd12946bf6cc2474b742712a Mon Sep 17 00:00:00 2001 From: Abhishek Anne Date: Fri, 22 Aug 2025 01:54:03 +0530 Subject: [PATCH 26/77] Created folder structure for e2e test --- e2etests/Cargo.toml | 12 ------------ e2etests/tests/agent/mod.rs | 2 ++ e2etests/tests/{ => agent}/test_agent_commands.rs | 0 e2etests/tests/ai_prompts/mod.rs | 2 ++ e2etests/tests/{ => ai_prompts}/test_ai_prompt.rs | 0 .../tests/{ => ai_prompts}/test_prompts_commands.rs | 0 e2etests/tests/all_tests.rs | 10 ++++++++++ e2etests/tests/context/mod.rs | 1 + e2etests/tests/{ => context}/test_context_command.rs | 0 e2etests/tests/core_session/mod.rs | 4 ++++ .../tests/{ => core_session}/test_clear_command.rs | 0 .../tests/{ => core_session}/test_help_command.rs | 0 .../tests/{ => core_session}/test_quit_command.rs | 0 .../tests/{ => core_session}/test_tools_command.rs | 0 e2etests/tests/integration/mod.rs | 4 ++++ .../{ => integration}/test_editor_help_command.rs | 0 .../tests/{ => integration}/test_hooks_command.rs | 0 .../tests/{ => integration}/test_issue_command.rs | 0 .../{ => integration}/test_subscribe_command.rs | 0 e2etests/tests/mcp/mod.rs | 1 + e2etests/tests/{ => mcp}/test_mcp_command.rs | 0 e2etests/tests/model/mod.rs | 1 + .../tests/{ => model}/test_model_dynamic_command.rs | 0 e2etests/tests/save_load/mod.rs | 1 + .../tests/{ => save_load}/test_save_load_command.rs | 0 e2etests/tests/session_mgmt/mod.rs | 3 +++ .../tests/{ => session_mgmt}/test_compact_command.rs | 0 .../tests/{ => session_mgmt}/test_usage_command.rs | 0 28 files changed, 29 insertions(+), 12 deletions(-) create mode 100644 e2etests/tests/agent/mod.rs rename e2etests/tests/{ => agent}/test_agent_commands.rs (100%) create mode 100644 e2etests/tests/ai_prompts/mod.rs rename e2etests/tests/{ => ai_prompts}/test_ai_prompt.rs (100%) rename e2etests/tests/{ => ai_prompts}/test_prompts_commands.rs (100%) create mode 100644 e2etests/tests/all_tests.rs create mode 100644 e2etests/tests/context/mod.rs rename e2etests/tests/{ => context}/test_context_command.rs (100%) create mode 100644 e2etests/tests/core_session/mod.rs rename e2etests/tests/{ => core_session}/test_clear_command.rs (100%) rename e2etests/tests/{ => core_session}/test_help_command.rs (100%) rename e2etests/tests/{ => core_session}/test_quit_command.rs (100%) rename e2etests/tests/{ => core_session}/test_tools_command.rs (100%) create mode 100644 e2etests/tests/integration/mod.rs rename e2etests/tests/{ => integration}/test_editor_help_command.rs (100%) rename e2etests/tests/{ => integration}/test_hooks_command.rs (100%) rename e2etests/tests/{ => integration}/test_issue_command.rs (100%) rename e2etests/tests/{ => integration}/test_subscribe_command.rs (100%) create mode 100644 e2etests/tests/mcp/mod.rs rename e2etests/tests/{ => mcp}/test_mcp_command.rs (100%) create mode 100644 e2etests/tests/model/mod.rs rename e2etests/tests/{ => model}/test_model_dynamic_command.rs (100%) create mode 100644 e2etests/tests/save_load/mod.rs rename e2etests/tests/{ => save_load}/test_save_load_command.rs (100%) create mode 100644 e2etests/tests/session_mgmt/mod.rs rename e2etests/tests/{ => session_mgmt}/test_compact_command.rs (100%) rename e2etests/tests/{ => session_mgmt}/test_usage_command.rs (100%) diff --git a/e2etests/Cargo.toml b/e2etests/Cargo.toml index caadc7a17e..26dba3a90a 100644 --- a/e2etests/Cargo.toml +++ b/e2etests/Cargo.toml @@ -26,15 +26,3 @@ hooks=[] usage=[] editor=[] subscribe=[] - -[[test]] -name = "test_help_command" -path = "tests/test_help_command.rs" - -[[test]] -name = "test_tools_command" -path = "tests/test_tools_command.rs" - -[[test]] -name = "test_ai_prompt" -path = "tests/test_ai_prompt.rs" diff --git a/e2etests/tests/agent/mod.rs b/e2etests/tests/agent/mod.rs new file mode 100644 index 0000000000..47e51d905c --- /dev/null +++ b/e2etests/tests/agent/mod.rs @@ -0,0 +1,2 @@ +// Module declaration for agent tests +pub mod test_agent_commands; \ No newline at end of file diff --git a/e2etests/tests/test_agent_commands.rs b/e2etests/tests/agent/test_agent_commands.rs similarity index 100% rename from e2etests/tests/test_agent_commands.rs rename to e2etests/tests/agent/test_agent_commands.rs diff --git a/e2etests/tests/ai_prompts/mod.rs b/e2etests/tests/ai_prompts/mod.rs new file mode 100644 index 0000000000..b1384b21d6 --- /dev/null +++ b/e2etests/tests/ai_prompts/mod.rs @@ -0,0 +1,2 @@ +pub mod test_ai_prompt; +pub mod test_prompts_commands; \ No newline at end of file diff --git a/e2etests/tests/test_ai_prompt.rs b/e2etests/tests/ai_prompts/test_ai_prompt.rs similarity index 100% rename from e2etests/tests/test_ai_prompt.rs rename to e2etests/tests/ai_prompts/test_ai_prompt.rs diff --git a/e2etests/tests/test_prompts_commands.rs b/e2etests/tests/ai_prompts/test_prompts_commands.rs similarity index 100% rename from e2etests/tests/test_prompts_commands.rs rename to e2etests/tests/ai_prompts/test_prompts_commands.rs diff --git a/e2etests/tests/all_tests.rs b/e2etests/tests/all_tests.rs new file mode 100644 index 0000000000..461b9b0d5d --- /dev/null +++ b/e2etests/tests/all_tests.rs @@ -0,0 +1,10 @@ +// Main integration test file that includes all subdirectory tests +mod agent; +mod ai_prompts; +mod context; +mod core_session; +mod integration; +mod mcp; +mod model; +mod save_load; +mod session_mgmt; \ No newline at end of file diff --git a/e2etests/tests/context/mod.rs b/e2etests/tests/context/mod.rs new file mode 100644 index 0000000000..b911b0e024 --- /dev/null +++ b/e2etests/tests/context/mod.rs @@ -0,0 +1 @@ +pub mod test_context_command; \ No newline at end of file diff --git a/e2etests/tests/test_context_command.rs b/e2etests/tests/context/test_context_command.rs similarity index 100% rename from e2etests/tests/test_context_command.rs rename to e2etests/tests/context/test_context_command.rs diff --git a/e2etests/tests/core_session/mod.rs b/e2etests/tests/core_session/mod.rs new file mode 100644 index 0000000000..6e9b7c9a92 --- /dev/null +++ b/e2etests/tests/core_session/mod.rs @@ -0,0 +1,4 @@ +pub mod test_clear_command; +pub mod test_help_command; +pub mod test_quit_command; +pub mod test_tools_command; \ No newline at end of file diff --git a/e2etests/tests/test_clear_command.rs b/e2etests/tests/core_session/test_clear_command.rs similarity index 100% rename from e2etests/tests/test_clear_command.rs rename to e2etests/tests/core_session/test_clear_command.rs diff --git a/e2etests/tests/test_help_command.rs b/e2etests/tests/core_session/test_help_command.rs similarity index 100% rename from e2etests/tests/test_help_command.rs rename to e2etests/tests/core_session/test_help_command.rs diff --git a/e2etests/tests/test_quit_command.rs b/e2etests/tests/core_session/test_quit_command.rs similarity index 100% rename from e2etests/tests/test_quit_command.rs rename to e2etests/tests/core_session/test_quit_command.rs diff --git a/e2etests/tests/test_tools_command.rs b/e2etests/tests/core_session/test_tools_command.rs similarity index 100% rename from e2etests/tests/test_tools_command.rs rename to e2etests/tests/core_session/test_tools_command.rs diff --git a/e2etests/tests/integration/mod.rs b/e2etests/tests/integration/mod.rs new file mode 100644 index 0000000000..844f370a00 --- /dev/null +++ b/e2etests/tests/integration/mod.rs @@ -0,0 +1,4 @@ +pub mod test_editor_help_command; +pub mod test_hooks_command; +pub mod test_issue_command; +pub mod test_subscribe_command; \ No newline at end of file diff --git a/e2etests/tests/test_editor_help_command.rs b/e2etests/tests/integration/test_editor_help_command.rs similarity index 100% rename from e2etests/tests/test_editor_help_command.rs rename to e2etests/tests/integration/test_editor_help_command.rs diff --git a/e2etests/tests/test_hooks_command.rs b/e2etests/tests/integration/test_hooks_command.rs similarity index 100% rename from e2etests/tests/test_hooks_command.rs rename to e2etests/tests/integration/test_hooks_command.rs diff --git a/e2etests/tests/test_issue_command.rs b/e2etests/tests/integration/test_issue_command.rs similarity index 100% rename from e2etests/tests/test_issue_command.rs rename to e2etests/tests/integration/test_issue_command.rs diff --git a/e2etests/tests/test_subscribe_command.rs b/e2etests/tests/integration/test_subscribe_command.rs similarity index 100% rename from e2etests/tests/test_subscribe_command.rs rename to e2etests/tests/integration/test_subscribe_command.rs diff --git a/e2etests/tests/mcp/mod.rs b/e2etests/tests/mcp/mod.rs new file mode 100644 index 0000000000..c3c2bd1241 --- /dev/null +++ b/e2etests/tests/mcp/mod.rs @@ -0,0 +1 @@ +pub mod test_mcp_command; \ No newline at end of file diff --git a/e2etests/tests/test_mcp_command.rs b/e2etests/tests/mcp/test_mcp_command.rs similarity index 100% rename from e2etests/tests/test_mcp_command.rs rename to e2etests/tests/mcp/test_mcp_command.rs diff --git a/e2etests/tests/model/mod.rs b/e2etests/tests/model/mod.rs new file mode 100644 index 0000000000..e64adec313 --- /dev/null +++ b/e2etests/tests/model/mod.rs @@ -0,0 +1 @@ +pub mod test_model_dynamic_command; \ No newline at end of file diff --git a/e2etests/tests/test_model_dynamic_command.rs b/e2etests/tests/model/test_model_dynamic_command.rs similarity index 100% rename from e2etests/tests/test_model_dynamic_command.rs rename to e2etests/tests/model/test_model_dynamic_command.rs diff --git a/e2etests/tests/save_load/mod.rs b/e2etests/tests/save_load/mod.rs new file mode 100644 index 0000000000..e7a90d3b4b --- /dev/null +++ b/e2etests/tests/save_load/mod.rs @@ -0,0 +1 @@ +pub mod test_save_load_command; \ No newline at end of file diff --git a/e2etests/tests/test_save_load_command.rs b/e2etests/tests/save_load/test_save_load_command.rs similarity index 100% rename from e2etests/tests/test_save_load_command.rs rename to e2etests/tests/save_load/test_save_load_command.rs diff --git a/e2etests/tests/session_mgmt/mod.rs b/e2etests/tests/session_mgmt/mod.rs new file mode 100644 index 0000000000..ee6705bcc0 --- /dev/null +++ b/e2etests/tests/session_mgmt/mod.rs @@ -0,0 +1,3 @@ +// Module declaration for session_mgmt tests +pub mod test_compact_command; +pub mod test_usage_command; \ No newline at end of file diff --git a/e2etests/tests/test_compact_command.rs b/e2etests/tests/session_mgmt/test_compact_command.rs similarity index 100% rename from e2etests/tests/test_compact_command.rs rename to e2etests/tests/session_mgmt/test_compact_command.rs diff --git a/e2etests/tests/test_usage_command.rs b/e2etests/tests/session_mgmt/test_usage_command.rs similarity index 100% rename from e2etests/tests/test_usage_command.rs rename to e2etests/tests/session_mgmt/test_usage_command.rs From ceb7a6ef47ca8b9d65666157ed0b42c11035395f Mon Sep 17 00:00:00 2001 From: Abhishek Anne Date: Fri, 22 Aug 2025 10:38:28 +0530 Subject: [PATCH 27/77] Fixed the warnings in code --- e2etests/src/lib.rs | 4 ++-- e2etests/tests/agent/test_agent_commands.rs | 6 +++++- e2etests/tests/ai_prompts/test_ai_prompt.rs | 1 + e2etests/tests/ai_prompts/test_prompts_commands.rs | 6 +++++- e2etests/tests/context/test_context_command.rs | 4 ++++ e2etests/tests/core_session/test_clear_command.rs | 1 + e2etests/tests/core_session/test_help_command.rs | 1 + e2etests/tests/core_session/test_quit_command.rs | 1 + e2etests/tests/core_session/test_tools_command.rs | 6 +++++- e2etests/tests/integration/test_editor_help_command.rs | 6 +++++- e2etests/tests/integration/test_hooks_command.rs | 6 +++++- e2etests/tests/integration/test_issue_command.rs | 6 +++++- e2etests/tests/integration/test_subscribe_command.rs | 6 +++++- e2etests/tests/mcp/test_mcp_command.rs | 4 ++++ e2etests/tests/model/test_model_dynamic_command.rs | 6 +++++- e2etests/tests/save_load/test_save_load_command.rs | 7 ++++++- e2etests/tests/session_mgmt/test_compact_command.rs | 6 +++++- e2etests/tests/session_mgmt/test_usage_command.rs | 6 +++++- 18 files changed, 70 insertions(+), 13 deletions(-) diff --git a/e2etests/src/lib.rs b/e2etests/src/lib.rs index 45a88cbfec..30d12cf533 100644 --- a/e2etests/src/lib.rs +++ b/e2etests/src/lib.rs @@ -13,7 +13,7 @@ pub fn get_chat_session() -> &'static Mutex { println!("βœ… Q Chat session started"); CHAT_SESSION = Some(Mutex::new(chat)); }); - CHAT_SESSION.as_ref().unwrap() + (&raw const CHAT_SESSION).as_ref().unwrap().as_ref().unwrap() } } @@ -21,7 +21,7 @@ pub fn cleanup_if_last_test(test_count: &AtomicUsize, total_tests: usize) -> Res let count = test_count.fetch_add(1, Ordering::SeqCst) + 1; if count == total_tests { unsafe { - if let Some(session) = &CHAT_SESSION { + if let Some(session) = (&raw const CHAT_SESSION).as_ref().unwrap() { if let Ok(mut chat) = session.lock() { chat.quit()?; println!("βœ… Test completed successfully"); diff --git a/e2etests/tests/agent/test_agent_commands.rs b/e2etests/tests/agent/test_agent_commands.rs index 4271ae815e..ea95801575 100644 --- a/e2etests/tests/agent/test_agent_commands.rs +++ b/e2etests/tests/agent/test_agent_commands.rs @@ -1,8 +1,11 @@ +#[allow(unused_imports)] use q_cli_e2e_tests::{get_chat_session, cleanup_if_last_test}; -use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::atomic::AtomicUsize; +#[allow(dead_code)] static TEST_COUNT: AtomicUsize = AtomicUsize::new(0); +#[allow(dead_code)] const TEST_NAMES: &[&str] = &[ "agent_without_subcommand", "test_agent_create_command", @@ -14,6 +17,7 @@ const TEST_NAMES: &[&str] = &[ "test_agent_set_default_command", "test_agent_set_default_missing_args", ]; +#[allow(dead_code)] const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] diff --git a/e2etests/tests/ai_prompts/test_ai_prompt.rs b/e2etests/tests/ai_prompts/test_ai_prompt.rs index 58d092f753..8758bede4f 100644 --- a/e2etests/tests/ai_prompts/test_ai_prompt.rs +++ b/e2etests/tests/ai_prompts/test_ai_prompt.rs @@ -1,3 +1,4 @@ +#[allow(unused_imports)] use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] diff --git a/e2etests/tests/ai_prompts/test_prompts_commands.rs b/e2etests/tests/ai_prompts/test_prompts_commands.rs index 664a3e3165..347b07769c 100644 --- a/e2etests/tests/ai_prompts/test_prompts_commands.rs +++ b/e2etests/tests/ai_prompts/test_prompts_commands.rs @@ -1,14 +1,18 @@ +#[allow(unused_imports)] use q_cli_e2e_tests::{get_chat_session, cleanup_if_last_test}; -use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::atomic::AtomicUsize; +#[allow(dead_code)] static TEST_COUNT: AtomicUsize = AtomicUsize::new(0); // List of covered tests +#[allow(dead_code)] const TEST_NAMES: &[&str] = &[ "test_prompts_command", "test_prompts_help_command", "test_prompts_list_command", ]; +#[allow(dead_code)] const TOTAL_TESTS: usize = TEST_NAMES.len(); diff --git a/e2etests/tests/context/test_context_command.rs b/e2etests/tests/context/test_context_command.rs index 0adf966be3..d196a9f9e2 100644 --- a/e2etests/tests/context/test_context_command.rs +++ b/e2etests/tests/context/test_context_command.rs @@ -1,9 +1,12 @@ +#[allow(unused_imports)] use q_cli_e2e_tests::{get_chat_session, cleanup_if_last_test}; use std::sync::atomic::{AtomicUsize}; +#[allow(dead_code)] static TEST_COUNT: AtomicUsize = AtomicUsize::new(0); // List of covered tests +#[allow(dead_code)] const TEST_NAMES: &[&str] = &[ "test_context_show_command", "test_context_help_command", @@ -16,6 +19,7 @@ const TEST_NAMES: &[&str] = &[ "test_clear_context_command", "test_add_remove_multiple_file_context" ]; +#[allow(dead_code)] const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] diff --git a/e2etests/tests/core_session/test_clear_command.rs b/e2etests/tests/core_session/test_clear_command.rs index 7eb8d203e5..daa5db21b4 100644 --- a/e2etests/tests/core_session/test_clear_command.rs +++ b/e2etests/tests/core_session/test_clear_command.rs @@ -1,3 +1,4 @@ +#[allow(unused_imports)] use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] diff --git a/e2etests/tests/core_session/test_help_command.rs b/e2etests/tests/core_session/test_help_command.rs index cf8c777b4e..10df0b354e 100644 --- a/e2etests/tests/core_session/test_help_command.rs +++ b/e2etests/tests/core_session/test_help_command.rs @@ -1,3 +1,4 @@ +#[allow(unused_imports)] use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] diff --git a/e2etests/tests/core_session/test_quit_command.rs b/e2etests/tests/core_session/test_quit_command.rs index c05b95d075..c416739153 100644 --- a/e2etests/tests/core_session/test_quit_command.rs +++ b/e2etests/tests/core_session/test_quit_command.rs @@ -1,3 +1,4 @@ +#[allow(unused_imports)] use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] diff --git a/e2etests/tests/core_session/test_tools_command.rs b/e2etests/tests/core_session/test_tools_command.rs index 5f4b2ae2be..3460aa279b 100644 --- a/e2etests/tests/core_session/test_tools_command.rs +++ b/e2etests/tests/core_session/test_tools_command.rs @@ -1,9 +1,12 @@ +#[allow(unused_imports)] use q_cli_e2e_tests::{get_chat_session, cleanup_if_last_test}; -use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::atomic::AtomicUsize; +#[allow(dead_code)] static TEST_COUNT: AtomicUsize = AtomicUsize::new(0); // List of covered tests +#[allow(dead_code)] const TEST_NAMES: &[&str] = &[ "test_tools_command", "test_tools_help_command", @@ -15,6 +18,7 @@ const TEST_NAMES: &[&str] = &[ "test_tools_untrust_help_command", "test_tools_schema_help_command", ]; +#[allow(dead_code)] const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] diff --git a/e2etests/tests/integration/test_editor_help_command.rs b/e2etests/tests/integration/test_editor_help_command.rs index a1e76560a8..08d9c57ca6 100644 --- a/e2etests/tests/integration/test_editor_help_command.rs +++ b/e2etests/tests/integration/test_editor_help_command.rs @@ -1,13 +1,17 @@ +#[allow(unused_imports)] use q_cli_e2e_tests::{get_chat_session, cleanup_if_last_test}; -use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::atomic::AtomicUsize; +#[allow(dead_code)] static TEST_COUNT: AtomicUsize = AtomicUsize::new(0); // List of covered tests +#[allow(dead_code)] const TEST_NAMES: &[&str] = &[ "test_editor_help_command", "test_help_editor_command", ]; +#[allow(dead_code)] const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] diff --git a/e2etests/tests/integration/test_hooks_command.rs b/e2etests/tests/integration/test_hooks_command.rs index 274de06487..05cf28a10a 100644 --- a/e2etests/tests/integration/test_hooks_command.rs +++ b/e2etests/tests/integration/test_hooks_command.rs @@ -1,13 +1,17 @@ +#[allow(unused_imports)] use q_cli_e2e_tests::{get_chat_session, cleanup_if_last_test}; -use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::atomic::AtomicUsize; +#[allow(dead_code)] static TEST_COUNT: AtomicUsize = AtomicUsize::new(0); // List of covered tests +#[allow(dead_code)] const TEST_NAMES: &[&str] = &[ "test_hooks_command", "test_hooks_help_command", ]; +#[allow(dead_code)] const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] diff --git a/e2etests/tests/integration/test_issue_command.rs b/e2etests/tests/integration/test_issue_command.rs index 7821ac99c2..7e20e53d40 100644 --- a/e2etests/tests/integration/test_issue_command.rs +++ b/e2etests/tests/integration/test_issue_command.rs @@ -1,14 +1,18 @@ +#[allow(unused_imports)] use q_cli_e2e_tests::{get_chat_session, cleanup_if_last_test}; -use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::atomic::AtomicUsize; +#[allow(dead_code)] static TEST_COUNT: AtomicUsize = AtomicUsize::new(0); // List of covered tests +#[allow(dead_code)] const TEST_NAMES: &[&str] = &[ "test_issue_command", "test_issue_force_command", "test_issue_help_command", ]; +#[allow(dead_code)] const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] diff --git a/e2etests/tests/integration/test_subscribe_command.rs b/e2etests/tests/integration/test_subscribe_command.rs index 5b79658c7b..d16d521559 100644 --- a/e2etests/tests/integration/test_subscribe_command.rs +++ b/e2etests/tests/integration/test_subscribe_command.rs @@ -1,13 +1,17 @@ +#[allow(unused_imports)] use q_cli_e2e_tests::{get_chat_session, cleanup_if_last_test}; -use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::atomic::AtomicUsize; +#[allow(dead_code)] static TEST_COUNT: AtomicUsize = AtomicUsize::new(0); // List of covered tests +#[allow(dead_code)] const TEST_NAMES: &[&str] = &[ "test_subscribe_command", "test_subscribe_help_command", ]; +#[allow(dead_code)] const TOTAL_TESTS: usize = TEST_NAMES.len(); diff --git a/e2etests/tests/mcp/test_mcp_command.rs b/e2etests/tests/mcp/test_mcp_command.rs index b430f72419..9162727e22 100644 --- a/e2etests/tests/mcp/test_mcp_command.rs +++ b/e2etests/tests/mcp/test_mcp_command.rs @@ -1,9 +1,12 @@ +#[allow(unused_imports)] use q_cli_e2e_tests::{get_chat_session, cleanup_if_last_test}; use std::sync::atomic::{AtomicUsize}; +#[allow(dead_code)] static TEST_COUNT: AtomicUsize = AtomicUsize::new(0); // List of covered tests +#[allow(dead_code)] const TEST_NAMES: &[&str] = &[ "test_mcp_help_command", "test_mcp_loading_command", @@ -15,6 +18,7 @@ const TEST_NAMES: &[&str] = &[ "test_q_mcp_list_help_command", "test_q_mcp_status_help_command" ]; +#[allow(dead_code)] const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] diff --git a/e2etests/tests/model/test_model_dynamic_command.rs b/e2etests/tests/model/test_model_dynamic_command.rs index 5457badb99..b76121e163 100644 --- a/e2etests/tests/model/test_model_dynamic_command.rs +++ b/e2etests/tests/model/test_model_dynamic_command.rs @@ -1,13 +1,17 @@ +#[allow(unused_imports)] use q_cli_e2e_tests::{get_chat_session, cleanup_if_last_test}; -use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::atomic::AtomicUsize; +#[allow(dead_code)] static TEST_COUNT: AtomicUsize = AtomicUsize::new(0); // List of covered tests +#[allow(dead_code)] const TEST_NAMES: &[&str] = &[ "test_model_dynamic_command", "test_model_help_command", ]; +#[allow(dead_code)] const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] diff --git a/e2etests/tests/save_load/test_save_load_command.rs b/e2etests/tests/save_load/test_save_load_command.rs index 363b37c025..79bcdb03ce 100644 --- a/e2etests/tests/save_load/test_save_load_command.rs +++ b/e2etests/tests/save_load/test_save_load_command.rs @@ -1,9 +1,12 @@ +#[allow(unused_imports)] use q_cli_e2e_tests::{get_chat_session, cleanup_if_last_test}; -use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::atomic::AtomicUsize; +#[allow(dead_code)] static TEST_COUNT: AtomicUsize = AtomicUsize::new(0); // List of covered tests +#[allow(dead_code)] const TEST_NAMES: &[&str] = &[ "test_save_command", "test_save_command_argument_validation", @@ -16,8 +19,10 @@ const TEST_NAMES: &[&str] = &[ "test_load_command", "test_load_command_argument_validation" ]; +#[allow(dead_code)] const TOTAL_TESTS: usize = TEST_NAMES.len(); +#[allow(dead_code)] struct FileCleanup<'a> { path: &'a str, } diff --git a/e2etests/tests/session_mgmt/test_compact_command.rs b/e2etests/tests/session_mgmt/test_compact_command.rs index 4c7e101738..19ae7da0db 100644 --- a/e2etests/tests/session_mgmt/test_compact_command.rs +++ b/e2etests/tests/session_mgmt/test_compact_command.rs @@ -1,13 +1,17 @@ +#[allow(unused_imports)] use q_cli_e2e_tests::{get_chat_session, cleanup_if_last_test}; -use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::atomic::AtomicUsize; +#[allow(dead_code)] static TEST_COUNT: AtomicUsize = AtomicUsize::new(0); // List of covered tests +#[allow(dead_code)] const TEST_NAMES: &[&str] = &[ "test_compact_command", "test_compact_help_command", ]; +#[allow(dead_code)] const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] diff --git a/e2etests/tests/session_mgmt/test_usage_command.rs b/e2etests/tests/session_mgmt/test_usage_command.rs index 977afb870b..3c18432fe0 100644 --- a/e2etests/tests/session_mgmt/test_usage_command.rs +++ b/e2etests/tests/session_mgmt/test_usage_command.rs @@ -1,13 +1,17 @@ +#[allow(unused_imports)] use q_cli_e2e_tests::{get_chat_session, cleanup_if_last_test}; -use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::atomic::AtomicUsize; +#[allow(dead_code)] static TEST_COUNT: AtomicUsize = AtomicUsize::new(0); // List of covered tests +#[allow(dead_code)] const TEST_NAMES: &[&str] = &[ "test_usage_command", "test_usage_help_command", ]; +#[allow(dead_code)] const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] From a1927639f8603a2ced3be0015fc3bf8bf161828f Mon Sep 17 00:00:00 2001 From: Abhishek Anne Date: Fri, 22 Aug 2025 12:37:57 +0530 Subject: [PATCH 28/77] Modified the tests features to support multiple features --- e2etests/Cargo.toml | 1 + e2etests/run_simple_categorized.sh | 4 ++-- e2etests/tests/agent/test_agent_commands.rs | 16 +++++++-------- e2etests/tests/ai_prompts/test_ai_prompt.rs | 4 ++-- .../tests/ai_prompts/test_prompts_commands.rs | 6 +++--- .../tests/context/test_context_command.rs | 20 +++++++++---------- .../tests/core_session/test_clear_command.rs | 2 +- .../tests/core_session/test_help_command.rs | 2 +- .../tests/core_session/test_quit_command.rs | 2 +- .../tests/core_session/test_tools_command.rs | 18 ++++++++--------- .../integration/test_editor_help_command.rs | 4 ++-- .../tests/integration/test_hooks_command.rs | 4 ++-- .../tests/integration/test_issue_command.rs | 6 +++--- .../integration/test_subscribe_command.rs | 4 ++-- e2etests/tests/mcp/test_mcp_command.rs | 18 ++++++++--------- .../tests/model/test_model_dynamic_command.rs | 4 ++-- .../tests/save_load/test_save_load_command.rs | 20 +++++++++---------- .../session_mgmt/test_compact_command.rs | 4 ++-- .../tests/session_mgmt/test_usage_command.rs | 4 ++-- 19 files changed, 72 insertions(+), 71 deletions(-) diff --git a/e2etests/Cargo.toml b/e2etests/Cargo.toml index 26dba3a90a..b294d42482 100644 --- a/e2etests/Cargo.toml +++ b/e2etests/Cargo.toml @@ -26,3 +26,4 @@ hooks=[] usage=[] editor=[] subscribe=[] +regression = [] diff --git a/e2etests/run_simple_categorized.sh b/e2etests/run_simple_categorized.sh index 8bf09c5cb8..805f0c6372 100755 --- a/e2etests/run_simple_categorized.sh +++ b/e2etests/run_simple_categorized.sh @@ -77,7 +77,7 @@ run_category() { if [ "$QUIET_MODE" = false ]; then # Quiet mode - show individual test results in real-time - cargo test --tests --features "$category" -- --test-threads=1 2>&1 | while IFS= read -r line; do + cargo test --tests --features "$category" --features "regression" -- --test-threads=1 2>&1 | while IFS= read -r line; do if echo "$line" | grep -q "test .* \.\.\. ok$"; then test_name=$(echo "$line" | sed 's/test \(.*\) \.\.\. ok/\1/') echo " βœ… $test_name" @@ -102,7 +102,7 @@ run_category() { fi else # Verbose mode - show full output with real-time test results - cargo test --tests --features "$category" -- --nocapture --test-threads=1 2>&1 | while IFS= read -r line; do + cargo test --tests --features "$category" --features "regression" -- --nocapture --test-threads=1 2>&1 | while IFS= read -r line; do echo "$line" if echo "$line" | grep -q "test .* \.\.\. ok$"; then test_name=$(echo "$line" | sed 's/test \(.*\) \.\.\. ok/\1/') diff --git a/e2etests/tests/agent/test_agent_commands.rs b/e2etests/tests/agent/test_agent_commands.rs index ea95801575..2d65f3fd23 100644 --- a/e2etests/tests/agent/test_agent_commands.rs +++ b/e2etests/tests/agent/test_agent_commands.rs @@ -21,7 +21,7 @@ const TEST_NAMES: &[&str] = &[ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] -#[cfg(feature = "agent")] +#[cfg(all(feature = "agent", feature = "regression"))] fn agent_without_subcommand() -> Result<(), Box> { println!("πŸ” Testing /agent command..."); @@ -72,7 +72,7 @@ fn agent_without_subcommand() -> Result<(), Box> { } #[test] -#[cfg(feature = "agent")] +#[cfg(all(feature = "agent", feature = "regression"))] fn test_agent_create_command() -> Result<(), Box> { println!("πŸ” Testing /agent create --name command..."); @@ -139,7 +139,7 @@ fn test_agent_create_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "agent")] +#[cfg(all(feature = "agent", feature = "regression"))] fn test_agent_create_missing_args() -> Result<(), Box> { println!("πŸ” Testing /agent create without required arguments..."); @@ -188,7 +188,7 @@ fn test_agent_create_missing_args() -> Result<(), Box> { } #[test] -#[cfg(feature = "agent")] +#[cfg(all(feature = "agent", feature = "regression"))] fn test_agent_help_command() -> Result<(), Box> { println!("πŸ” Testing /agent help..."); @@ -243,7 +243,7 @@ fn test_agent_help_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "agent")] +#[cfg(all(feature = "agent", feature = "regression"))] fn test_agent_invalid_command() -> Result<(), Box> { println!("πŸ” Testing /agent invalidcommand..."); @@ -280,7 +280,7 @@ fn test_agent_invalid_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "agent")] +#[cfg(all(feature = "agent", feature = "regression"))] fn test_agent_list_command() -> Result<(), Box> { println!("πŸ” Testing /agent list command..."); @@ -351,7 +351,7 @@ fn test_agent_list_command() -> Result<(), Box> { // } #[test] -#[cfg(feature = "agent")] +#[cfg(all(feature = "agent", feature = "regression"))] fn test_agent_set_default_command() -> Result<(), Box> { println!("πŸ” Testing /agent set-default with valid arguments..."); @@ -390,7 +390,7 @@ fn test_agent_set_default_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "agent")] +#[cfg(all(feature = "agent", feature = "regression"))] fn test_agent_set_default_missing_args() -> Result<(), Box> { println!("πŸ” Testing /agent set-default without required arguments..."); diff --git a/e2etests/tests/ai_prompts/test_ai_prompt.rs b/e2etests/tests/ai_prompts/test_ai_prompt.rs index 8758bede4f..9cd83b1adf 100644 --- a/e2etests/tests/ai_prompts/test_ai_prompt.rs +++ b/e2etests/tests/ai_prompts/test_ai_prompt.rs @@ -2,7 +2,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] -#[cfg(feature = "ai_prompts")] +#[cfg(all(feature = "ai_prompts", feature = "regression"))] fn test_what_is_aws_prompt() -> Result<(), Box> { println!("πŸ” [AI PROMPTS] Testing 'What is AWS?' AI prompt..."); @@ -55,7 +55,7 @@ fn test_what_is_aws_prompt() -> Result<(), Box> { } #[test] -#[cfg(feature = "ai_prompts")] +#[cfg(all(feature = "ai_prompts", feature = "regression"))] fn test_simple_greeting() -> Result<(), Box> { println!("πŸ” Testing simple 'Hello' prompt..."); diff --git a/e2etests/tests/ai_prompts/test_prompts_commands.rs b/e2etests/tests/ai_prompts/test_prompts_commands.rs index 347b07769c..1b68297f53 100644 --- a/e2etests/tests/ai_prompts/test_prompts_commands.rs +++ b/e2etests/tests/ai_prompts/test_prompts_commands.rs @@ -17,7 +17,7 @@ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] -#[cfg(feature = "ai_prompts")] +#[cfg(all(feature = "ai_prompts", feature = "regression"))] fn test_prompts_command() -> Result<(), Box> { println!("πŸ” Testing /prompts command..."); @@ -56,7 +56,7 @@ fn test_prompts_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "ai_prompts")] +#[cfg(all(feature = "ai_prompts", feature = "regression"))] fn test_prompts_help_command() -> Result<(), Box> { println!("πŸ” Testing /prompts --help command..."); @@ -117,7 +117,7 @@ fn test_prompts_help_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "ai_prompts")] +#[cfg(all(feature = "ai_prompts", feature = "regression"))] fn test_prompts_list_command() -> Result<(), Box> { println!("πŸ” Testing /prompts list command..."); diff --git a/e2etests/tests/context/test_context_command.rs b/e2etests/tests/context/test_context_command.rs index d196a9f9e2..79336fb204 100644 --- a/e2etests/tests/context/test_context_command.rs +++ b/e2etests/tests/context/test_context_command.rs @@ -23,7 +23,7 @@ const TEST_NAMES: &[&str] = &[ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] -#[cfg(feature = "context")] +#[cfg(all(feature = "context", feature = "regression"))] fn test_context_show_command() -> Result<(), Box> { println!("πŸ” Testing /context show command..."); @@ -57,7 +57,7 @@ fn test_context_show_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "context")] +#[cfg(all(feature = "context", feature = "regression"))] fn test_context_help_command() -> Result<(), Box> { println!("πŸ” Testing /context help command..."); @@ -99,7 +99,7 @@ fn test_context_help_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "context")] +#[cfg(all(feature = "context", feature = "regression"))] fn test_context_without_subcommand() -> Result<(), Box> { println!("πŸ” Testing /context without sub command..."); @@ -137,7 +137,7 @@ fn test_context_without_subcommand() -> Result<(), Box> { } #[test] -#[cfg(feature = "context")] +#[cfg(all(feature = "context", feature = "regression"))] fn test_context_invalid_command() -> Result<(), Box> { println!("πŸ” Testing /context invalid command..."); @@ -167,7 +167,7 @@ fn test_context_invalid_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "context")] +#[cfg(all(feature = "context", feature = "regression"))] fn test_add_non_existing_file_context() -> Result<(), Box> { println!("πŸ” Testing /context add non-existing file command..."); @@ -198,7 +198,7 @@ fn test_add_non_existing_file_context() -> Result<(), Box } #[test] -#[cfg(feature = "context")] +#[cfg(all(feature = "context", feature = "regression"))] fn test_context_remove_command_of_non_existent_file() -> Result<(), Box> { println!("πŸ” Testing /context remove non existing file command..."); @@ -226,7 +226,7 @@ fn test_context_remove_command_of_non_existent_file() -> Result<(), Box Result<(), Box> { println!("πŸ” Testing /context add command and /context remove command..."); @@ -300,7 +300,7 @@ fn test_add_remove_file_context() -> Result<(), Box> { } #[test] -#[cfg(feature = "context")] +#[cfg(all(feature = "context", feature = "regression"))] fn test_add_glob_pattern_file_context()-> Result<(), Box> { println!("πŸ” Testing /context add *.py glob pattern command..."); @@ -382,7 +382,7 @@ fn test_add_glob_pattern_file_context()-> Result<(), Box> } #[test] -#[cfg(feature = "context")] +#[cfg(all(feature = "context", feature = "regression"))] fn test_clear_context_command()-> Result<(), Box> { println!("πŸ” Testing /context clear command..."); @@ -459,7 +459,7 @@ fn test_clear_context_command()-> Result<(), Box> { } #[test] -#[cfg(feature = "context")] +#[cfg(all(feature = "context", feature = "regression"))] fn test_add_remove_multiple_file_context()-> Result<(), Box> { println!("πŸ” Testing /context add command and /context remove ..."); diff --git a/e2etests/tests/core_session/test_clear_command.rs b/e2etests/tests/core_session/test_clear_command.rs index daa5db21b4..7a04a06d09 100644 --- a/e2etests/tests/core_session/test_clear_command.rs +++ b/e2etests/tests/core_session/test_clear_command.rs @@ -2,7 +2,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] -#[cfg(feature = "core_session")] +#[cfg(all(feature = "core_session", feature = "regression"))] fn test_clear_command() -> Result<(), Box> { println!("πŸ” Testing /clear command..."); diff --git a/e2etests/tests/core_session/test_help_command.rs b/e2etests/tests/core_session/test_help_command.rs index 10df0b354e..2172afa233 100644 --- a/e2etests/tests/core_session/test_help_command.rs +++ b/e2etests/tests/core_session/test_help_command.rs @@ -2,7 +2,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] -#[cfg(feature = "core_session")] +#[cfg(all(feature = "core_session", feature = "regression"))] fn test_help_command() -> Result<(), Box> { println!("πŸ” Testing /help command..."); diff --git a/e2etests/tests/core_session/test_quit_command.rs b/e2etests/tests/core_session/test_quit_command.rs index c416739153..fb183d7541 100644 --- a/e2etests/tests/core_session/test_quit_command.rs +++ b/e2etests/tests/core_session/test_quit_command.rs @@ -2,7 +2,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] -#[cfg(feature = "core_session")] +#[cfg(all(feature = "core_session", feature = "regression"))] fn test_quit_command() -> Result<(), Box> { println!("πŸ” Testing /quit command..."); diff --git a/e2etests/tests/core_session/test_tools_command.rs b/e2etests/tests/core_session/test_tools_command.rs index 3460aa279b..f7ec9c2495 100644 --- a/e2etests/tests/core_session/test_tools_command.rs +++ b/e2etests/tests/core_session/test_tools_command.rs @@ -22,7 +22,7 @@ const TEST_NAMES: &[&str] = &[ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] -#[cfg(feature = "tools")] +#[cfg(all(any(feature = "tools", feature = "core_session"), feature = "regression"))] fn test_tools_command() -> Result<(), Box> { println!("πŸ” Testing /tools command..."); @@ -77,7 +77,7 @@ fn test_tools_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "tools")] +#[cfg(all(any(feature = "tools", feature = "core_session"), feature = "regression"))] fn test_tools_help_command() -> Result<(), Box> { println!("πŸ” Testing /tools --help command..."); @@ -132,7 +132,7 @@ fn test_tools_help_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "tools")] +#[cfg(all(any(feature = "tools", feature = "core_session"), feature = "regression"))] fn test_tools_trust_all_command() -> Result<(), Box> { println!("πŸ” Testing /tools trust-all command..."); @@ -214,7 +214,7 @@ fn test_tools_trust_all_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "tools")] +#[cfg(all(any(feature = "tools", feature = "core_session"), feature = "regression"))] fn test_tools_trust_all_help_command() -> Result<(), Box> { println!("πŸ” Testing /tools trust-all --help command..."); @@ -253,7 +253,7 @@ fn test_tools_trust_all_help_command() -> Result<(), Box> } #[test] -#[cfg(feature = "tools")] +#[cfg(all(any(feature = "tools", feature = "core_session"), feature = "regression"))] fn test_tools_reset_help_command() -> Result<(), Box> { println!("πŸ” Testing /tools reset --help command..."); @@ -292,7 +292,7 @@ fn test_tools_reset_help_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "tools")] +#[cfg(all(any(feature = "tools", feature = "core_session"), feature = "regression"))] fn test_tools_trust_command() -> Result<(), Box> { println!("πŸ” Testing /tools trust command..."); @@ -370,7 +370,7 @@ fn test_tools_trust_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "tools")] +#[cfg(all(any(feature = "tools", feature = "core_session"), feature = "regression"))] fn test_tools_trust_help_command() -> Result<(), Box> { println!("πŸ” Testing /tools trust --help command..."); @@ -413,7 +413,7 @@ fn test_tools_trust_help_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "tools")] +#[cfg(all(any(feature = "tools", feature = "core_session"), feature = "regression"))] fn test_tools_untrust_help_command() -> Result<(), Box> { println!("πŸ” Testing /tools untrust --help command..."); @@ -456,7 +456,7 @@ fn test_tools_untrust_help_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "tools")] +#[cfg(all(any(feature = "tools", feature = "core_session"), feature = "regression"))] fn test_tools_schema_help_command() -> Result<(), Box> { println!("πŸ” Testing /tools schema --help command..."); diff --git a/e2etests/tests/integration/test_editor_help_command.rs b/e2etests/tests/integration/test_editor_help_command.rs index 08d9c57ca6..5931e7c456 100644 --- a/e2etests/tests/integration/test_editor_help_command.rs +++ b/e2etests/tests/integration/test_editor_help_command.rs @@ -15,7 +15,7 @@ const TEST_NAMES: &[&str] = &[ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] -#[cfg(feature = "editor")] +#[cfg(all(any(feature = "editor", feature = "integration"), feature = "regression"))] fn test_editor_help_command() -> Result<(), Box> { println!("πŸ” Testing /editor --help command..."); @@ -62,7 +62,7 @@ fn test_editor_help_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "editor")] +#[cfg(all(any(feature = "editor", feature = "integration"), feature = "regression"))] fn test_help_editor_command() -> Result<(), Box> { println!("πŸ” Testing /help editor command..."); diff --git a/e2etests/tests/integration/test_hooks_command.rs b/e2etests/tests/integration/test_hooks_command.rs index 05cf28a10a..023359afdd 100644 --- a/e2etests/tests/integration/test_hooks_command.rs +++ b/e2etests/tests/integration/test_hooks_command.rs @@ -15,7 +15,7 @@ const TEST_NAMES: &[&str] = &[ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] -#[cfg(feature = "hooks")] +#[cfg(all(any(feature = "hooks", feature = "integration"), feature = "regression"))] fn test_hooks_command() -> Result<(), Box> { println!("πŸ” Testing /hooks command..."); @@ -50,7 +50,7 @@ fn test_hooks_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "hooks")] +#[cfg(all(any(feature = "hooks", feature = "integration"), feature = "regression"))] fn test_hooks_help_command() -> Result<(), Box> { println!("πŸ” Testing /hooks --help command..."); diff --git a/e2etests/tests/integration/test_issue_command.rs b/e2etests/tests/integration/test_issue_command.rs index 7e20e53d40..171cec1991 100644 --- a/e2etests/tests/integration/test_issue_command.rs +++ b/e2etests/tests/integration/test_issue_command.rs @@ -16,7 +16,7 @@ const TEST_NAMES: &[&str] = &[ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] -#[cfg(feature = "issue_reporting")] +#[cfg(all(any(feature = "issue_reporting", feature = "integration"), feature = "regression"))] fn test_issue_command() -> Result<(), Box> { println!("πŸ” Testing /issue command with bug report..."); @@ -46,7 +46,7 @@ fn test_issue_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "issue_reporting")] +#[cfg(all(any(feature = "issue_reporting", feature = "integration"), feature = "regression"))] fn test_issue_force_command() -> Result<(), Box> { println!("πŸ” Testing /issue --force command with critical bug..."); @@ -76,7 +76,7 @@ fn test_issue_force_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "issue_reporting")] +#[cfg(all(any(feature = "issue_reporting", feature = "integration"), feature = "regression"))] fn test_issue_help_command() -> Result<(), Box> { println!("πŸ” Testing /issue --help command..."); diff --git a/e2etests/tests/integration/test_subscribe_command.rs b/e2etests/tests/integration/test_subscribe_command.rs index d16d521559..3753ae0997 100644 --- a/e2etests/tests/integration/test_subscribe_command.rs +++ b/e2etests/tests/integration/test_subscribe_command.rs @@ -16,7 +16,7 @@ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] -#[cfg(feature = "subscribe")] +#[cfg(all(any(feature = "subscribe", feature = "integration"), feature = "regression"))] fn test_subscribe_command() -> Result<(), Box> { println!("πŸ” Testing /subscribe command..."); @@ -45,7 +45,7 @@ fn test_subscribe_command() -> Result<(), Box> { Ok(()) } #[test] -#[cfg(feature = "subscribe")] +#[cfg(all(any(feature = "subscribe", feature = "integration"), feature = "regression"))] fn test_subscribe_help_command() -> Result<(), Box> { println!("πŸ” Testing /subscribe --help command..."); diff --git a/e2etests/tests/mcp/test_mcp_command.rs b/e2etests/tests/mcp/test_mcp_command.rs index 9162727e22..baff8073e3 100644 --- a/e2etests/tests/mcp/test_mcp_command.rs +++ b/e2etests/tests/mcp/test_mcp_command.rs @@ -22,7 +22,7 @@ const TEST_NAMES: &[&str] = &[ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] -#[cfg(feature = "mcp")] +#[cfg(all(feature = "mcp", feature = "regression"))] fn test_mcp_help_command() -> Result<(), Box> { println!("πŸ” Testing /mcp --help command..."); @@ -65,7 +65,7 @@ fn test_mcp_help_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "mcp")] +#[cfg(all(feature = "mcp", feature = "regression"))] fn test_mcp_loading_command() -> Result<(), Box> { println!("πŸ” Testing MCP loading..."); @@ -105,7 +105,7 @@ fn test_mcp_loading_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "mcp")] +#[cfg(all(feature = "mcp", feature = "regression"))] fn test_mcp_remove_help_command() -> Result<(), Box> { println!("πŸ” Testing q mcp remove --help command..."); @@ -153,7 +153,7 @@ fn test_mcp_remove_help_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "mcp")] +#[cfg(all(feature = "mcp", feature = "regression"))] fn test_q_mcp_add_help_command() -> Result<(), Box> { println!("πŸ” Testing q mcp add --help command..."); @@ -216,7 +216,7 @@ fn test_q_mcp_add_help_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "mcp")] +#[cfg(all(feature = "mcp", feature = "regression"))] fn test_q_mcp_help_command() -> Result<(), Box> { println!("πŸ” Testing q mcp --help command..."); @@ -274,7 +274,7 @@ fn test_q_mcp_help_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "mcp")] +#[cfg(all(feature = "mcp", feature = "regression"))] fn test_q_mcp_import_help_command() -> Result<(), Box> { println!("πŸ” Testing q mcp import --help command..."); @@ -340,7 +340,7 @@ fn test_q_mcp_import_help_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "mcp")] +#[cfg(all(feature = "mcp", feature = "regression"))] fn test_q_mcp_list_command() -> Result<(), Box> { println!("πŸ” Testing q mcp list command..."); @@ -385,7 +385,7 @@ fn test_q_mcp_list_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "mcp")] +#[cfg(all(feature = "mcp", feature = "regression"))] fn test_q_mcp_list_help_command() -> Result<(), Box> { println!("πŸ” Testing q mcp list --help command..."); @@ -439,7 +439,7 @@ fn test_q_mcp_list_help_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "mcp")] +#[cfg(all(feature = "mcp", feature = "regression"))] fn test_q_mcp_status_help_command() -> Result<(), Box> { println!("πŸ” Testing q mcp status --help command..."); diff --git a/e2etests/tests/model/test_model_dynamic_command.rs b/e2etests/tests/model/test_model_dynamic_command.rs index b76121e163..326ecf0102 100644 --- a/e2etests/tests/model/test_model_dynamic_command.rs +++ b/e2etests/tests/model/test_model_dynamic_command.rs @@ -15,7 +15,7 @@ const TEST_NAMES: &[&str] = &[ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] -#[cfg(feature = "model")] +#[cfg(all(feature = "model", feature = "regression"))] fn test_model_dynamic_command() -> Result<(), Box> { println!("πŸ” Testing /model command with dynamic selection..."); @@ -134,7 +134,7 @@ fn test_model_dynamic_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "model")] +#[cfg(all(feature = "model", feature = "regression"))] fn test_model_help_command() -> Result<(), Box> { println!("πŸ” Testing /model --help command..."); diff --git a/e2etests/tests/save_load/test_save_load_command.rs b/e2etests/tests/save_load/test_save_load_command.rs index 79bcdb03ce..1681378fcc 100644 --- a/e2etests/tests/save_load/test_save_load_command.rs +++ b/e2etests/tests/save_load/test_save_load_command.rs @@ -37,7 +37,7 @@ impl<'a> Drop for FileCleanup<'a> { } #[test] -#[cfg(feature = "save_load")] +#[cfg(all(feature = "save_load", feature = "regression"))] fn test_save_command() -> Result<(), Box> { println!("πŸ” Testing /save command..."); @@ -82,7 +82,7 @@ fn test_save_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "save_load")] +#[cfg(all(feature = "save_load", feature = "regression"))] fn test_save_command_argument_validation() -> Result<(), Box> { println!("πŸ” Testing /save command..."); @@ -120,7 +120,7 @@ fn test_save_command_argument_validation() -> Result<(), Box Result<(), Box> { println!("πŸ” Testing /save --help command..."); @@ -166,7 +166,7 @@ fn test_save_help_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "save_load")] +#[cfg(all(feature = "save_load", feature = "regression"))] fn test_save_h_flag_command() -> Result<(), Box> { println!("πŸ” Testing /save -h command..."); @@ -211,7 +211,7 @@ fn test_save_h_flag_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "save_load")] +#[cfg(all(feature = "save_load", feature = "regression"))] fn test_save_force_command() -> Result<(), Box> { println!("πŸ” Testing /save --force command..."); @@ -269,7 +269,7 @@ fn test_save_force_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "save_load")] +#[cfg(all(feature = "save_load", feature = "regression"))] fn test_save_f_flag_command() -> Result<(), Box> { println!("πŸ” Testing /save -f command..."); @@ -327,7 +327,7 @@ fn test_save_f_flag_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "save_load")] +#[cfg(all(feature = "save_load", feature = "regression"))] fn test_load_help_command() -> Result<(), Box> { println!("πŸ” Testing /load --help command..."); @@ -370,7 +370,7 @@ fn test_load_help_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "save_load")] +#[cfg(all(feature = "save_load", feature = "regression"))] fn test_load_h_flag_command() -> Result<(), Box> { println!("πŸ” Testing /load -h command..."); @@ -413,7 +413,7 @@ fn test_load_h_flag_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "save_load")] +#[cfg(all(feature = "save_load", feature = "regression"))] fn test_load_command() -> Result<(), Box> { println!("πŸ” Testing /load command..."); @@ -467,7 +467,7 @@ fn test_load_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "save_load")] +#[cfg(all(feature = "save_load", feature = "regression"))] fn test_load_command_argument_validation() -> Result<(), Box> { println!("πŸ” Testing /load command..."); diff --git a/e2etests/tests/session_mgmt/test_compact_command.rs b/e2etests/tests/session_mgmt/test_compact_command.rs index 19ae7da0db..279297627b 100644 --- a/e2etests/tests/session_mgmt/test_compact_command.rs +++ b/e2etests/tests/session_mgmt/test_compact_command.rs @@ -15,7 +15,7 @@ const TEST_NAMES: &[&str] = &[ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] -#[cfg(feature = "compact")] +#[cfg(all(any(feature = "compact", feature = "session_mgmt"), feature = "regression"))] fn test_compact_command() -> Result<(), Box> { println!("πŸ” Testing /compact command..."); @@ -50,7 +50,7 @@ fn test_compact_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "compact")] +#[cfg(all(any(feature = "compact", feature = "session_mgmt"), feature = "regression"))] fn test_compact_help_command() -> Result<(), Box> { println!("πŸ” Testing /compact --help command..."); diff --git a/e2etests/tests/session_mgmt/test_usage_command.rs b/e2etests/tests/session_mgmt/test_usage_command.rs index 3c18432fe0..628e21682d 100644 --- a/e2etests/tests/session_mgmt/test_usage_command.rs +++ b/e2etests/tests/session_mgmt/test_usage_command.rs @@ -15,7 +15,7 @@ const TEST_NAMES: &[&str] = &[ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] -#[cfg(feature = "usage")] +#[cfg(all(any(feature = "usage", feature = "session_mgmt"), feature = "regression"))] fn test_usage_command() -> Result<(), Box> { println!("πŸ” Testing /usage command..."); @@ -74,7 +74,7 @@ fn test_usage_command() -> Result<(), Box> { } #[test] -#[cfg(feature = "usage")] +#[cfg(all(any(feature = "usage", feature = "session_mgmt"), feature = "regression"))] fn test_usage_help_command() -> Result<(), Box> { println!("πŸ” Testing /usage --help command..."); From 27131f136cac40a38d802be7bc3341f783dc419f Mon Sep 17 00:00:00 2001 From: sayema Anjum Date: Fri, 22 Aug 2025 17:20:01 +0530 Subject: [PATCH 29/77] QCLI Automation for core_session,integration,mcp,model,session_mgmt tests --- e2etests/run_simple_categorized.sh | 94 ++++---- e2etests/src/lib.rs | 4 +- .../tests/core_session/test_tools_command.rs | 44 +--- .../integration/test_editor_help_command.rs | 54 ++++- .../tests/integration/test_hooks_command.rs | 61 +++-- .../tests/integration/test_issue_command.rs | 84 ++++++- .../integration/test_subscribe_command.rs | 87 ++++++- e2etests/tests/mcp/test_mcp_command.rs | 2 - .../tests/model/test_model_dynamic_command.rs | 47 +++- .../session_mgmt/test_compact_command.rs | 225 +++++++++++++++--- .../tests/session_mgmt/test_usage_command.rs | 45 +++- 11 files changed, 583 insertions(+), 164 deletions(-) diff --git a/e2etests/run_simple_categorized.sh b/e2etests/run_simple_categorized.sh index 805f0c6372..f031731696 100755 --- a/e2etests/run_simple_categorized.sh +++ b/e2etests/run_simple_categorized.sh @@ -15,13 +15,14 @@ RUN_SESSION_MGMT=true RUN_INTEGRATION=true RUN_MCP=true RUN_AI_PROMPTS=true -RUN_ISSUE_REPORTING=true -RUN_TOOLS=true -RUN_COMPACT=true -RUN_HOOKS=true -RUN_USAGE=true -RUN_EDITOR=true -RUN_SUBSCRIBE=true +#TODO: check and remove not required features from below +#RUN_ISSUE_REPORTING=true +#RUN_TOOLS=true +#RUN_COMPACT=true +#RUN_HOOKS=true +#RUN_USAGE=true +#RUN_EDITOR=true +#RUN_SUBSCRIBE=true # ============================================================================ Q_BINARY="q" @@ -220,45 +221,46 @@ if [ "$RUN_TOOLS" = true ]; then fi fi -if [ "$RUN_COMPACT" = true ]; then - if run_category "compact" "COMPACT"; then - ((total_passed++)) - else - ((total_failed++)) - fi -fi - -if [ "$RUN_HOOKS" = true ]; then - if run_category "hooks" "HOOKS"; then - ((total_passed++)) - else - ((total_failed++)) - fi -fi - -if [ "$RUN_USAGE" = true ]; then - if run_category "usage" "USAGE"; then - ((total_passed++)) - else - ((total_failed++)) - fi -fi - -if [ "$RUN_EDITOR" = true ]; then - if run_category "editor" "EDITOR"; then - ((total_passed++)) - else - ((total_failed++)) - fi -fi - -if [ "$RUN_SUBSCRIBE" = true ]; then - if run_category "subscribe" "SUBSCRIBE"; then - ((total_passed++)) - else - ((total_failed++)) - fi -fi +#TODO: check and remove not required features from below +# if [ "$RUN_COMPACT" = true ]; then +# if run_category "compact" "COMPACT"; then +# ((total_passed++)) +# else +# ((total_failed++)) +# fi +# fi +# +# if [ "$RUN_HOOKS" = true ]; then +# if run_category "hooks" "HOOKS"; then +# ((total_passed++)) +# else +# ((total_failed++)) +# fi +# fi +# +# if [ "$RUN_USAGE" = true ]; then +# if run_category "usage" "USAGE"; then +# ((total_passed++)) +# else +# ((total_failed++)) +# fi +# fi +# +# if [ "$RUN_EDITOR" = true ]; then +# if run_category "editor" "EDITOR"; then +# ((total_passed++)) +# else +# ((total_failed++)) +# fi +# fi +# +# if [ "$RUN_SUBSCRIBE" = true ]; then +# if run_category "subscribe" "SUBSCRIBE"; then +# ((total_passed++)) +# else +# ((total_failed++)) +# fi +# fi # Final summary echo "" diff --git a/e2etests/src/lib.rs b/e2etests/src/lib.rs index 30d12cf533..e0dbcdd8f7 100644 --- a/e2etests/src/lib.rs +++ b/e2etests/src/lib.rs @@ -138,12 +138,12 @@ pub mod q_chat_helper { }, Ok(_) => { // No more data, but wait a bit more in case there's more coming - std::thread::sleep(Duration::from_millis(2500)); + std::thread::sleep(Duration::from_millis(20000)); if total_content.len() > 0 { break; } }, Err(_) => break, } - std::thread::sleep(Duration::from_millis(2500)); + std::thread::sleep(Duration::from_millis(20000)); } Ok(total_content) diff --git a/e2etests/tests/core_session/test_tools_command.rs b/e2etests/tests/core_session/test_tools_command.rs index f7ec9c2495..0a9877d570 100644 --- a/e2etests/tests/core_session/test_tools_command.rs +++ b/e2etests/tests/core_session/test_tools_command.rs @@ -91,15 +91,6 @@ fn test_tools_help_command() -> Result<(), Box> { println!("{}", response); println!("πŸ“ END OUTPUT"); - /* Verify description - assert!(response.contains("permission"), "Missing permission description"); - println!("βœ… Found tools permission description");*/ - - // Verify documentation reference - //assert!(response.contains("documentation"), "Missing documentation reference"); - assert!(response.contains("https://github.com/aws/amazon-q-developer-cli/blob/main/docs/agent-format.md#tools-field"), "Missing documentation URL"); - println!("βœ… Found documentation reference and URL"); - // Verify Usage section assert!(response.contains("Usage:") && response.contains("/tools") && response.contains("[COMMAND]"), "Missing Usage section"); println!("βœ… Found usage format"); @@ -147,11 +138,9 @@ fn test_tools_trust_all_command() -> Result<(), Box> { println!("{}", trust_all_response); println!("πŸ“ END TRUST-ALL OUTPUT"); - /* Verify trust-all confirmation message - assert!(trust_all_response.contains("confirmation"), "Missing trust-all confirmation message"); - assert!(trust_all_response.contains("risk"), "Missing risk warning message");*/ - assert!(trust_all_response.contains("https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-chat-security.html#command-line-chat-trustall-safety"), "Missing documentation link"); - println!("βœ… Found documentation link"); + // Verify that all tools now show "trusted" permission + assert!(trust_all_response.contains("All tools") && trust_all_response.contains("trusted"), "Missing trusted tools after trust-all"); + println!("βœ… trust-all confirmation message!!"); // Now check tools list to verify all tools are trusted let tools_response = chat.execute_command("/tools")?; @@ -228,9 +217,6 @@ fn test_tools_trust_all_help_command() -> Result<(), Box> println!("{}", response); println!("πŸ“ END OUTPUT"); - /* Verify command description - assert!(response.contains("Trust"), "Missing command description"); - println!("βœ… Found command description");*/ // Verify usage format assert!(response.contains("Usage:") && response.contains("/tools trust-all"), "Missing usage format"); @@ -238,7 +224,7 @@ fn test_tools_trust_all_help_command() -> Result<(), Box> // Verify options section assert!(response.contains("Options:"), "Missing Options section"); - assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing help option"); + assert!(response.contains("-h") && response.contains("--help"), "Missing help option"); println!("βœ… Found options section with help flag"); println!("βœ… All tools trust-all help functionality verified!"); @@ -267,17 +253,13 @@ fn test_tools_reset_help_command() -> Result<(), Box> { println!("{}", response); println!("πŸ“ END OUTPUT"); - /* Verify command description - assert!(response.contains("Reset"), "Missing command description"); - println!("βœ… Found command description");*/ - // Verify usage format assert!(response.contains("Usage:") && response.contains("/tools reset"), "Missing usage format"); println!("βœ… Found usage format"); // Verify options section assert!(response.contains("Options:"), "Missing Options section"); - assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing help option"); + assert!(response.contains("-h") && response.contains("--help"), "Missing help option"); println!("βœ… Found options section with help flag"); println!("βœ… All tools reset help functionality verified!"); @@ -384,10 +366,6 @@ fn test_tools_trust_help_command() -> Result<(), Box> { println!("{}", response); println!("πŸ“ END OUTPUT"); - /* Verify command description - assert!(response.contains("Trust"), "Missing command description"); - println!("βœ… Found command description");*/ - // Verify usage format assert!(response.contains("Usage:") && response.contains("/tools trust") && response.contains(""), "Missing usage format"); println!("βœ… Found usage format"); @@ -427,10 +405,6 @@ fn test_tools_untrust_help_command() -> Result<(), Box> { println!("{}", response); println!("πŸ“ END OUTPUT"); - /* Verify command description - assert!(response.contains("Revert"), "Missing command description"); - println!("βœ… Found command description");*/ - // Verify usage format assert!(response.contains("Usage:") && response.contains("/tools untrust") && response.contains(""), "Missing usage format"); println!("βœ… Found usage format"); @@ -469,11 +443,7 @@ fn test_tools_schema_help_command() -> Result<(), Box> { println!("πŸ“ FULL OUTPUT:"); println!("{}", response); println!("πŸ“ END OUTPUT"); - - /* Verify command description - assert!(response.contains("Show the input schema for all available tools"), "Missing command description"); - println!("βœ… Found command description");*/ - + // Verify usage format assert!(response.contains("Usage:") && response.contains("/tools schema"), "Missing usage format"); println!("βœ… Found usage format"); @@ -493,7 +463,7 @@ fn test_tools_schema_help_command() -> Result<(), Box> { Ok(()) } - +//TODO: As response not giving full content , need to check this. /*#[test] #[cfg(feature = "tools")] fn test_tools_schema_command() -> Result<(), Box> { diff --git a/e2etests/tests/integration/test_editor_help_command.rs b/e2etests/tests/integration/test_editor_help_command.rs index 5931e7c456..8445196013 100644 --- a/e2etests/tests/integration/test_editor_help_command.rs +++ b/e2etests/tests/integration/test_editor_help_command.rs @@ -10,6 +10,7 @@ static TEST_COUNT: AtomicUsize = AtomicUsize::new(0); const TEST_NAMES: &[&str] = &[ "test_editor_help_command", "test_help_editor_command", + "test_editor_h_command", ]; #[allow(dead_code)] const TOTAL_TESTS: usize = TEST_NAMES.len(); @@ -20,7 +21,7 @@ fn test_editor_help_command() -> Result<(), Box> { println!("πŸ” Testing /editor --help command..."); let session = get_chat_session(); - let mut chat = session.lock().unwrap(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); let response = chat.execute_command("/editor --help")?; @@ -29,10 +30,6 @@ fn test_editor_help_command() -> Result<(), Box> { println!("{}", response); println!("πŸ“ END OUTPUT"); - /* Verify description - assert!(response.contains("Open $EDITOR"), "Missing editor description"); - println!("βœ… Found editor description");*/ - // Verify Usage section assert!(response.contains("Usage:") && response.contains("/editor") && response.contains("[INITIAL_TEXT]"), "Missing Usage section"); println!("βœ… Found Usage section with /editor command"); @@ -67,7 +64,7 @@ fn test_help_editor_command() -> Result<(), Box> { println!("πŸ” Testing /help editor command..."); let session = get_chat_session(); - let mut chat = session.lock().unwrap(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); let response = chat.execute_command("/help editor")?; @@ -102,4 +99,47 @@ fn test_help_editor_command() -> Result<(), Box> { cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; Ok(()) -} \ No newline at end of file +} + +#[test] +#[cfg(all(any(feature = "editor", feature = "integration"), feature = "regression"))] +fn test_editor_h_command() -> Result<(), Box> { + println!("πŸ” Testing /editor -h command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + let response = chat.execute_command("/editor -h")?; + + println!("πŸ“ Editor help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify Usage section + assert!(response.contains("Usage:") && response.contains("/editor") && response.contains("[INITIAL_TEXT]"), "Missing Usage section"); + println!("βœ… Found Usage section with /editor command"); + + // Verify Arguments section + assert!(response.contains("Arguments:"), "Missing Arguments section"); + assert!(response.contains("[INITIAL_TEXT]"), "Missing INITIAL_TEXT argument"); + println!("βœ… Found Arguments section"); + + // Verify Options section + assert!(response.contains("Options:"), "Missing Options section"); + println!("βœ… Found Options section"); + + // Verify help flags + assert!(response.contains("-h") && response.contains("--help"), "Missing -h, --help flags"); + println!("βœ… Found help flags: -h, --help with Print help description"); + + println!("βœ… All editor help content verified!"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} diff --git a/e2etests/tests/integration/test_hooks_command.rs b/e2etests/tests/integration/test_hooks_command.rs index 023359afdd..f3ec709003 100644 --- a/e2etests/tests/integration/test_hooks_command.rs +++ b/e2etests/tests/integration/test_hooks_command.rs @@ -10,6 +10,7 @@ static TEST_COUNT: AtomicUsize = AtomicUsize::new(0); const TEST_NAMES: &[&str] = &[ "test_hooks_command", "test_hooks_help_command", + "test_hooks_h_command", ]; #[allow(dead_code)] const TOTAL_TESTS: usize = TEST_NAMES.len(); @@ -20,7 +21,7 @@ fn test_hooks_command() -> Result<(), Box> { println!("πŸ” Testing /hooks command..."); let session = get_chat_session(); - let mut chat = session.lock().unwrap(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); let response = chat.execute_command("/hooks")?; @@ -33,11 +34,6 @@ fn test_hooks_command() -> Result<(), Box> { assert!(response.contains("No hooks"), "Missing no hooks configured message"); println!("βœ… Found no hooks configured message"); - // Verify documentation reference - assert!(response.contains("documentation"), "Missing documentation reference"); - assert!(response.contains("https://github.com/aws/amazon-q-developer-cli/blob/main/docs/agent-format.md#hooks-field"), "Missing documentation URL"); - println!("βœ… Found documentation reference and URL"); - println!("βœ… All hooks command functionality verified!"); // Release the lock before cleanup @@ -55,7 +51,7 @@ fn test_hooks_help_command() -> Result<(), Box> { println!("πŸ” Testing /hooks --help command..."); let session = get_chat_session(); - let mut chat = session.lock().unwrap(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); let response = chat.execute_command("/hooks --help")?; @@ -63,22 +59,45 @@ fn test_hooks_help_command() -> Result<(), Box> { println!("πŸ“ FULL OUTPUT:"); println!("{}", response); println!("πŸ“ END OUTPUT"); + + // Verify Usage section + assert!(response.contains("Usage:"), "Missing Usage section"); + assert!(response.contains("/hooks"), "Missing /hooks command in usage section"); + println!("βœ… Found Usage section with /hooks command"); + + // Verify Options section + assert!(response.contains("Options:"), "Missing Options section"); + println!("βœ… Found Options section"); + + // Verify help flags + assert!(response.contains("-h") && response.contains("--help"), "Missing -h, --help flags"); + println!("βœ… Found help flags: -h, --help with Print help description"); + + println!("βœ… All hooks help content verified!"); + + // Release the lock before cleanup + drop(chat); - /* Verify context hooks description - assert!(response.contains("context hooks"), "Missing context hooks"); - println!("βœ… Found context hooks description");*/ + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} + +#[test] +#[cfg(all(any(feature = "hooks", feature = "integration"), feature = "regression"))] +fn test_hooks_h_command() -> Result<(), Box> { + println!("πŸ” Testing /hooks -h command..."); - // Verify documentation reference - assert!(response.contains("documentation"), "Missing documentation reference"); - assert!(response.contains("https://github.com/aws/amazon-q-developer-cli/blob/main/docs/agent-format.md#hooks-field"), "Missing documentation URL"); - println!("βœ… Found documentation reference and URL"); + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + let response = chat.execute_command("/hooks -h")?; - // Verify Notes section - assert!(response.contains("Notes:"), "Missing Notes section"); - /*assert!(response.contains("executed in parallel"), "Missing parallel execution note"); - assert!(response.contains("conversation_start"), "Missing conversation_start hook type"); - assert!(response.contains("per_prompt"), "Missing per_prompt hook type");*/ - println!("βœ… Found Notes section with hook types and execution details"); + println!("πŸ“ Hooks help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); // Verify Usage section assert!(response.contains("Usage:"), "Missing Usage section"); @@ -90,7 +109,7 @@ fn test_hooks_help_command() -> Result<(), Box> { println!("βœ… Found Options section"); // Verify help flags - assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing -h, --help flags"); + assert!(response.contains("-h") && response.contains("--help"), "Missing -h, --help flags"); println!("βœ… Found help flags: -h, --help with Print help description"); println!("βœ… All hooks help content verified!"); diff --git a/e2etests/tests/integration/test_issue_command.rs b/e2etests/tests/integration/test_issue_command.rs index 171cec1991..81414d8078 100644 --- a/e2etests/tests/integration/test_issue_command.rs +++ b/e2etests/tests/integration/test_issue_command.rs @@ -10,7 +10,9 @@ static TEST_COUNT: AtomicUsize = AtomicUsize::new(0); const TEST_NAMES: &[&str] = &[ "test_issue_command", "test_issue_force_command", + "test_issue_f_command", "test_issue_help_command", + "test_issue_h_command", ]; #[allow(dead_code)] const TOTAL_TESTS: usize = TEST_NAMES.len(); @@ -21,7 +23,7 @@ fn test_issue_command() -> Result<(), Box> { println!("πŸ” Testing /issue command with bug report..."); let session = get_chat_session(); - let mut chat = session.lock().unwrap(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); let response = chat.execute_command("/issue \"Bug: Q CLI crashes when using large files\"")?; @@ -51,7 +53,7 @@ fn test_issue_force_command() -> Result<(), Box> { println!("πŸ” Testing /issue --force command with critical bug..."); let session = get_chat_session(); - let mut chat = session.lock().unwrap(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); let response = chat.execute_command("/issue --force \"Critical bug in file handling\"")?; @@ -75,13 +77,44 @@ fn test_issue_force_command() -> Result<(), Box> { Ok(()) } +#[test] +#[cfg(all(any(feature = "issue_reporting", feature = "integration"), feature = "regression"))] +fn test_issue_f_command() -> Result<(), Box> { + println!("πŸ” Testing /issue -f command with critical bug..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + let response = chat.execute_command("/issue -f \"Critical bug in file handling\"")?; + + println!("πŸ“ Issue force command response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify command executed successfully (GitHub opens automatically) + assert!(response.contains("Heading over to GitHub..."), "Missing browser opening confirmation"); + println!("βœ… Found browser opening confirmation"); + + println!("βœ… All issue --force command functionality verified!"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} + + #[test] #[cfg(all(any(feature = "issue_reporting", feature = "integration"), feature = "regression"))] fn test_issue_help_command() -> Result<(), Box> { println!("πŸ” Testing /issue --help command..."); let session = get_chat_session(); - let mut chat = session.lock().unwrap(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); let response = chat.execute_command("/issue --help")?; @@ -90,18 +123,12 @@ fn test_issue_help_command() -> Result<(), Box> { println!("{}", response); println!("πŸ“ END OUTPUT"); - /* Verify description - assert!(response.contains("issue") && response.contains("feature request"), "Missing issue description"); - println!("βœ… Found issue description");*/ - // Verify Usage section - //assert!(response.contains("Usage: /issue [OPTIONS] [DESCRIPTION]..."), "Missing usage format"); assert!(response.contains("Usage:") && response.contains("/issue") && response.contains("[DESCRIPTION]") && response.contains("[OPTIONS]"), "Missing Usage section"); println!("βœ… Found usage format"); // Verify Arguments section assert!(response.contains("Arguments:"), "Missing Arguments section"); - assert!(response.contains("[DESCRIPTION]"), "Missing DESCRIPTION argument"); println!("βœ… Found Arguments section"); // Verify Options section @@ -121,3 +148,42 @@ fn test_issue_help_command() -> Result<(), Box> { Ok(()) } +#[test] +#[cfg(all(any(feature = "issue_reporting", feature = "integration"), feature = "regression"))] +fn test_issue_h_command() -> Result<(), Box> { + println!("πŸ” Testing /issue -h command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + let response = chat.execute_command("/issue -h")?; + + println!("πŸ“ Issue help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify Usage section + assert!(response.contains("Usage:") && response.contains("/issue") && response.contains("[DESCRIPTION]") && response.contains("[OPTIONS]"), "Missing Usage section"); + println!("βœ… Found usage format"); + + // Verify Arguments section + assert!(response.contains("Arguments:"), "Missing Arguments section"); + println!("βœ… Found Arguments section"); + + // Verify Options section + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("-f") && response.contains("--force"), "Missing force option"); + assert!(response.contains("-h") && response.contains("--help"), "Missing -h, --help flags"); + println!("βœ… Found Options section with force and help flags"); + + println!("βœ… All issue help content verified!"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/integration/test_subscribe_command.rs b/e2etests/tests/integration/test_subscribe_command.rs index 3753ae0997..b68a7f2abb 100644 --- a/e2etests/tests/integration/test_subscribe_command.rs +++ b/e2etests/tests/integration/test_subscribe_command.rs @@ -9,7 +9,9 @@ static TEST_COUNT: AtomicUsize = AtomicUsize::new(0); #[allow(dead_code)] const TEST_NAMES: &[&str] = &[ "test_subscribe_command", + "test_subscribe_manage_command", "test_subscribe_help_command", + "test_subscribe_h_command", ]; #[allow(dead_code)] const TOTAL_TESTS: usize = TEST_NAMES.len(); @@ -21,7 +23,7 @@ fn test_subscribe_command() -> Result<(), Box> { println!("πŸ” Testing /subscribe command..."); let session = get_chat_session(); - let mut chat = session.lock().unwrap(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); let response = chat.execute_command("/subscribe")?; @@ -44,13 +46,44 @@ fn test_subscribe_command() -> Result<(), Box> { Ok(()) } + +#[test] +#[cfg(all(any(feature = "subscribe", feature = "integration"), feature = "regression"))] +fn test_subscribe_manage_command() -> Result<(), Box> { + println!("πŸ” Testing /subscribe command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + let response = chat.execute_command("/subscribe --manage")?; + + println!("πŸ“ Subscribe response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify subscription management message + assert!(response.contains("Q Developer Pro subscription") && response.contains("IAM Identity Center"), "Missing subscription management message"); + println!("βœ… Found subscription management message"); + + println!("βœ… All subscribe content verified!"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} + #[test] #[cfg(all(any(feature = "subscribe", feature = "integration"), feature = "regression"))] fn test_subscribe_help_command() -> Result<(), Box> { println!("πŸ” Testing /subscribe --help command..."); let session = get_chat_session(); - let mut chat = session.lock().unwrap(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); let response = chat.execute_command("/subscribe --help")?; @@ -78,7 +111,7 @@ fn test_subscribe_help_command() -> Result<(), Box> { println!("βœ… Found --manage option"); // Verify help flags - assert!(response.contains("-h") && response.contains("--help") , "Missing -h, --help flags"); + assert!(response.contains("-h") && response.contains("--help"), "Missing -h, --help flags"); println!("βœ… Found help flags: -h, --help with Print help description"); println!("βœ… All subscribe help content verified!"); @@ -91,3 +124,51 @@ fn test_subscribe_help_command() -> Result<(), Box> { Ok(()) } + +#[test] +#[cfg(all(any(feature = "subscribe", feature = "integration"), feature = "regression"))] +fn test_subscribe_h_command() -> Result<(), Box> { + println!("πŸ” Testing /subscribe -h command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + let response = chat.execute_command("/subscribe -h")?; + + println!("πŸ“ Subscribe help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify description + assert!(response.contains("Q Developer Pro subscription"), "Missing subscription description"); + println!("βœ… Found subscription description"); + + // Verify Usage section + assert!(response.contains("Usage:"), "Missing Usage section"); + assert!(response.contains("/subscribe"), "Missing /subscribe command in usage section"); + assert!(response.contains("[OPTIONS]"), "Missing [OPTIONS] in usage section"); + println!("βœ… Found Usage section with /subscribe [OPTIONS]"); + + // Verify Options section + assert!(response.contains("Options:"), "Missing Options section"); + println!("βœ… Found Options section"); + + // Verify manage option + assert!(response.contains("--manage"), "Missing --manage option"); + println!("βœ… Found --manage option"); + + // Verify help flags + assert!(response.contains("-h") && response.contains("--help"), "Missing -h, --help flags"); + println!("βœ… Found help flags: -h, --help with Print help description"); + + println!("βœ… All subscribe help content verified!"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/mcp/test_mcp_command.rs b/e2etests/tests/mcp/test_mcp_command.rs index baff8073e3..95c91525ed 100644 --- a/e2etests/tests/mcp/test_mcp_command.rs +++ b/e2etests/tests/mcp/test_mcp_command.rs @@ -371,8 +371,6 @@ fn test_q_mcp_list_command() -> Result<(), Box> { // Verify MCP server listing assert!(allow_response.contains("q_cli_default"), "Missing q_cli_default server"); - assert!(allow_response.contains("default"), "Missing default tag"); - assert!(allow_response.contains("global"), "Missing global tag"); println!("βœ… Found MCP server listing with servers and completion"); // Release the lock before cleanup diff --git a/e2etests/tests/model/test_model_dynamic_command.rs b/e2etests/tests/model/test_model_dynamic_command.rs index 326ecf0102..7cf9b528f6 100644 --- a/e2etests/tests/model/test_model_dynamic_command.rs +++ b/e2etests/tests/model/test_model_dynamic_command.rs @@ -10,6 +10,7 @@ static TEST_COUNT: AtomicUsize = AtomicUsize::new(0); const TEST_NAMES: &[&str] = &[ "test_model_dynamic_command", "test_model_help_command", + "test_model_h_command", ]; #[allow(dead_code)] const TOTAL_TESTS: usize = TEST_NAMES.len(); @@ -148,10 +149,6 @@ fn test_model_help_command() -> Result<(), Box> { println!("{}", response); println!("πŸ“ END OUTPUT"); - /* Verify description - assert!(response.contains("Select") && response.contains("model"), "Missing model selection description"); - println!("βœ… Found model selection description");*/ - // Verify Usage section assert!(response.contains("Usage:"), "Missing Usage section"); assert!(response.contains("/model"), "Missing /model command in usage section"); @@ -162,8 +159,7 @@ fn test_model_help_command() -> Result<(), Box> { println!("βœ… Found Options section"); // Verify help flags - assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing -h, --help flags"); - assert!(response.contains("Print help"), "Missing Print help description"); + assert!(response.contains("-h") && response.contains("--help"), "Missing -h, --help flags"); println!("βœ… Found help flags: -h, --help with Print help description"); println!("βœ… All model help content verified!"); @@ -176,3 +172,42 @@ fn test_model_help_command() -> Result<(), Box> { Ok(()) } + +#[test] +#[cfg(all(feature = "model", feature = "regression"))] +fn test_model_h_command() -> Result<(), Box> { + println!("πŸ” Testing /model -h command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + + let response = chat.execute_command("/model -h")?; + + println!("πŸ“ Model help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify Usage section + assert!(response.contains("Usage:"), "Missing Usage section"); + assert!(response.contains("/model"), "Missing /model command in usage section"); + println!("βœ… Found Usage section with /model command"); + + // Verify Options section + assert!(response.contains("Options:"), "Missing Options section"); + println!("βœ… Found Options section"); + + // Verify help flags + assert!(response.contains("-h") && response.contains("--help"), "Missing -h, --help flags"); + println!("βœ… Found help flags: -h, --help with Print help description"); + + println!("βœ… All model help content verified!"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} \ No newline at end of file diff --git a/e2etests/tests/session_mgmt/test_compact_command.rs b/e2etests/tests/session_mgmt/test_compact_command.rs index 279297627b..f7a4039fa1 100644 --- a/e2etests/tests/session_mgmt/test_compact_command.rs +++ b/e2etests/tests/session_mgmt/test_compact_command.rs @@ -10,6 +10,10 @@ static TEST_COUNT: AtomicUsize = AtomicUsize::new(0); const TEST_NAMES: &[&str] = &[ "test_compact_command", "test_compact_help_command", + "test_compact_h_command", + "test_show_summary", + "test_compact_truncate_true_command", + "test_compact_truncate_false_command", ]; #[allow(dead_code)] const TOTAL_TESTS: usize = TEST_NAMES.len(); @@ -20,7 +24,14 @@ fn test_compact_command() -> Result<(), Box> { println!("πŸ” Testing /compact command..."); let session = get_chat_session(); - let mut chat = session.lock().unwrap(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + let response = chat.execute_command("What is AWS?")?; + + println!("πŸ“ AI response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); let response = chat.execute_command("/compact")?; @@ -49,13 +60,154 @@ fn test_compact_command() -> Result<(), Box> { Ok(()) } +#[test] +#[cfg(all(any(feature = "compact", feature = "session_mgmt"), feature = "regression"))] +fn test_compact_truncate_true_command() -> Result<(), Box> { + println!("πŸ” Testing /compact --truncate-large-messages true command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + let response = chat.execute_command("What is AWS?")?; + + println!("πŸ“ AI response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + let response = chat.execute_command("/compact --truncate-large-messages true")?; + + println!("πŸ“ Compact response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify truncation + assert!(response.to_lowercase().contains("truncating"), "Missing truncation messsage"); + println!("βœ… Truncation of large messages verified!"); + + // Verify compact response - either success or too short + if response.contains("history") && response.contains("compacted") && response.contains("successfully") { + println!("βœ… Found compact success message"); + } else if response.contains("Conversation") && response.contains("short") { + println!("βœ… Found conversation too short message"); + } else { + panic!("Missing expected compact response"); + } + + println!("βœ… All compact content verified!"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} + +#[test] +#[cfg(all(any(feature = "compact", feature = "session_mgmt"), feature = "regression"))] +fn test_compact_truncate_false_command() -> Result<(), Box> { + println!("πŸ” Testing /compact --truncate-large-messages false command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + + let response = chat.execute_command("What is AWS?")?; + + println!("πŸ“ AI response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + let response = chat.execute_command("/compact --truncate-large-messages false")?; + + println!("πŸ“ Compact response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify compact response - either success or too short + if response.contains("history") && response.contains("compacted") && response.contains("successfully") { + println!("βœ… Found compact success message"); + } else if response.contains("Conversation") && response.contains("short") { + println!("βœ… Found conversation too short message"); + } else { + panic!("Missing expected compact response"); + } + + println!("βœ… All compact content verified!"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} + + +#[test] +#[cfg(all(any(feature = "compact", feature = "session_mgmt"), feature = "regression"))] +fn test_show_summary() -> Result<(), Box> { + println!("πŸ” Testing /compact --show-summary command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + let response = chat.execute_command("What is AWS?")?; + + println!("πŸ“ AI response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + let response = chat.execute_command("What is DL?")?; + + println!("πŸ“ AI response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + let response = chat.execute_command("/compact --show-summary")?; + + println!("πŸ“ Compact response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + + // Verify compact response - either success or too short + if response.contains("history") && response.contains("compacted") && response.contains("successfully") { + println!("βœ… Found compact success message"); + } else if response.contains("Conversation") && response.contains("short") { + println!("βœ… Found conversation too short message"); + } else { + panic!("Missing expected compact response"); + } + + // Verify compact sumary response + assert!(response.to_lowercase().contains("conversation") && response.to_lowercase().contains("summary"), "Missing Summary section"); + assert!(response.contains("AWS") && (response.contains("DL") || response.to_lowercase().contains("deep learning")) , "Missing summary of our prompts"); + println!("βœ… All compact content verified!"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} + #[test] #[cfg(all(any(feature = "compact", feature = "session_mgmt"), feature = "regression"))] fn test_compact_help_command() -> Result<(), Box> { println!("πŸ” Testing /compact --help command..."); let session = get_chat_session(); - let mut chat = session.lock().unwrap(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); let response = chat.execute_command("/compact --help")?; @@ -64,31 +216,48 @@ fn test_compact_help_command() -> Result<(), Box> { println!("{}", response); println!("πŸ“ END OUTPUT"); - /* Verify main description - assert!(response.contains("/compact") && response.contains("summarizes") && response.contains("history"), "Missing compact description"); - println!("βœ… Found compact description");*/ - - // Verify When to use section - assert!(response.contains("When to use"), "Missing When to use section"); - /*assert!(response.contains("memory constraint"), "Missing memory constraint warning"); - assert!(response.contains("conversation") && response.contains("running") && response.contains("long time"), "Missing long conversation note"); - assert!(response.contains("new topic") && response.contains("same session"), "Missing new topic note"); - assert!(response.contains("complex tool operations"), "Missing tool operations note");*/ - println!("βœ… Found When to use section with all scenarios"); - - // Verify How it works section - assert!(response.contains("How it works"), "Missing How it works section"); - /*assert!(response.contains("AI-generated summary"), "Missing AI summary description"); - assert!(response.contains("key information") && response.contains("code") && response.contains("tool executions"), "Missing key elements"); - assert!(response.contains("free up space"), "Missing free up space description"); - assert!(response.contains("reference the summary context"), "Missing summary context reference");*/ - println!("βœ… Found How it works section with all details"); - - // Verify auto-compaction information - //assert!(response.contains("Compaction will be automatically performed whenever the context window overflows"), "Missing auto-compaction note"); - //assert!(response.contains("To disable this behavior, run: `q settings chat.disableAutoCompaction true`"), "Missing disable instruction"); - assert!(response.contains("run: `q settings chat.disableAutoCompaction true`"), "Missing disable instruction"); - println!("βœ… Found auto-compaction information"); + // Verify Usage section + assert!(response.contains("Usage:"), "Missing usage format"); + println!("βœ… Found usage format"); + + // Verify Arguments section + assert!(response.contains("Arguments:"), "Missing Arguments section"); + println!("βœ… Found Arguments section"); + + // Verify Options section + assert!(response.contains("Options:"), "Missing Options section"); + assert!(response.contains("--show-summary"), "Missing --show-summary option"); + assert!(response.contains("--messages-to-exclude"), "Missing --messages-to-exclude option"); + assert!(response.contains("--truncate-large-messages"), "Missing --truncate-large-messages option"); + assert!(response.contains("--max-message-length"), "Missing --max-message-length option"); + assert!(response.contains("-h") && response.contains("--help"), "Missing -h, --help flags"); + println!("βœ… Found all options and help flags"); + + println!("βœ… All compact help content verified!"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} + +#[test] +#[cfg(all(any(feature = "compact", feature = "session_mgmt"), feature = "regression"))] +fn test_compact_h_command() -> Result<(), Box> { + println!("πŸ” Testing /compact -h command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + let response = chat.execute_command("/compact -h")?; + + println!("πŸ“ Compact help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); // Verify Usage section assert!(response.contains("Usage:"), "Missing usage format"); @@ -104,7 +273,7 @@ fn test_compact_help_command() -> Result<(), Box> { assert!(response.contains("--messages-to-exclude"), "Missing --messages-to-exclude option"); assert!(response.contains("--truncate-large-messages"), "Missing --truncate-large-messages option"); assert!(response.contains("--max-message-length"), "Missing --max-message-length option"); - assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing -h, --help flags"); + assert!(response.contains("-h") && response.contains("--help"), "Missing -h, --help flags"); println!("βœ… Found all options and help flags"); println!("βœ… All compact help content verified!"); diff --git a/e2etests/tests/session_mgmt/test_usage_command.rs b/e2etests/tests/session_mgmt/test_usage_command.rs index 628e21682d..c7520e5d59 100644 --- a/e2etests/tests/session_mgmt/test_usage_command.rs +++ b/e2etests/tests/session_mgmt/test_usage_command.rs @@ -10,6 +10,7 @@ static TEST_COUNT: AtomicUsize = AtomicUsize::new(0); const TEST_NAMES: &[&str] = &[ "test_usage_command", "test_usage_help_command", + "test_usage_h_command", ]; #[allow(dead_code)] const TOTAL_TESTS: usize = TEST_NAMES.len(); @@ -88,9 +89,47 @@ fn test_usage_help_command() -> Result<(), Box> { println!("{}", response); println!("πŸ“ END OUTPUT"); - /* Verify description - assert!(response.contains("context window ") && response.contains("usage"), "Missing usage command description"); - println!("βœ… Found usage command description");*/ + // Verify Usage section + assert!(response.contains("Usage:"), "Missing Usage section"); + assert!(response.contains("/usage"), "Missing /usage command in usage section"); + println!("βœ… Found Usage section with /usage command"); + + // Verify Options section + assert!(response.contains("Options:"), "Missing Options section"); + println!("βœ… Found Options section"); + + // Verify help flags + assert!(response.contains("-h") && response.contains("--help") && response.contains("Print help"), "Missing -h, --help flags"); + println!("βœ… Found help flags: -h, --help with description"); + + println!("βœ… All usage help content verified!"); + + println!("βœ… Test completed successfully"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + + Ok(()) +} + +#[test] +#[cfg(all(any(feature = "usage", feature = "session_mgmt"), feature = "regression"))] +fn test_usage_h_command() -> Result<(), Box> { + println!("πŸ” Testing /usage -h command..."); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap(); + + let response = chat.execute_command("/usage -h")?; + + println!("πŸ“ Usage help response: {} bytes", response.len()); + println!("πŸ“ FULL OUTPUT:"); + println!("{}", response); + println!("πŸ“ END OUTPUT"); + // Verify Usage section assert!(response.contains("Usage:"), "Missing Usage section"); From d65314c330f4b40c167560c49065ef0cffc89c45 Mon Sep 17 00:00:00 2001 From: sayema Anjum Date: Fri, 22 Aug 2025 17:23:39 +0530 Subject: [PATCH 30/77] Reduce read_response timeout from 20s to 4s --- e2etests/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/e2etests/src/lib.rs b/e2etests/src/lib.rs index e0dbcdd8f7..9aeeeaff11 100644 --- a/e2etests/src/lib.rs +++ b/e2etests/src/lib.rs @@ -138,12 +138,12 @@ pub mod q_chat_helper { }, Ok(_) => { // No more data, but wait a bit more in case there's more coming - std::thread::sleep(Duration::from_millis(20000)); + std::thread::sleep(Duration::from_millis(4000)); if total_content.len() > 0 { break; } }, Err(_) => break, } - std::thread::sleep(Duration::from_millis(20000)); + std::thread::sleep(Duration::from_millis(4000)); } Ok(total_content) From 6da0041841c08594285c80fe6196071020f31e47 Mon Sep 17 00:00:00 2001 From: "Shreya [C] Bhagat" Date: Fri, 22 Aug 2025 20:25:54 +0530 Subject: [PATCH 31/77] Refactor: Remove verbose from MCP context and save/load and fixed the failing test case for adding multiple file as context. --- e2etests/run_context.clean.sh | 30 ---- e2etests/run_save_load_clean.sh | 30 ---- e2etests/test_core_session_clean.sh | 30 ---- .../tests/context/test_context_command.rs | 154 +++++++++--------- e2etests/tests/mcp/test_mcp_command.rs | 65 +++----- .../tests/save_load/test_save_load_command.rs | 32 +--- 6 files changed, 109 insertions(+), 232 deletions(-) delete mode 100644 e2etests/run_context.clean.sh delete mode 100644 e2etests/run_save_load_clean.sh delete mode 100644 e2etests/test_core_session_clean.sh diff --git a/e2etests/run_context.clean.sh b/e2etests/run_context.clean.sh deleted file mode 100644 index e0726bfcb8..0000000000 --- a/e2etests/run_context.clean.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash - -# Clean context-only test runner - runs only context test files -# Usage: ./run_context_clean.sh [path_to_q_binary] - -Q_BINARY="q" - -if [ $# -gt 0 ]; then - Q_BINARY="$1" - export Q_CLI_PATH="$Q_BINARY" -fi - -echo "πŸš€ Running context Commands Tests" -echo "=============================" -echo "" - -# Run only the specific context test files -echo "πŸ”„ Running context tests..." -cargo test --test --features "context" -- --nocapture --test-threads=1 - -exit_code=$? - -echo "" -if [ $exit_code -eq 0 ]; then - echo "πŸŽ‰ All context tests passed!" -else - echo "πŸ’₯ Some context tests failed!" -fi - -exit $exit_code diff --git a/e2etests/run_save_load_clean.sh b/e2etests/run_save_load_clean.sh deleted file mode 100644 index 4ed27022f5..0000000000 --- a/e2etests/run_save_load_clean.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash - -# Clean save-load-only test runner - runs only save and load test files -# Usage: ./run_context_save_load.sh [path_to_q_binary] - -Q_BINARY="q" - -if [ $# -gt 0 ]; then - Q_BINARY="$1" - export Q_CLI_PATH="$Q_BINARY" -fi - -echo "πŸš€ Running save and load Commands Tests" -echo "=============================" -echo "" - -# Run only the specific save and load test files -echo "πŸ”„ Running save and load tests..." -cargo test --test --features "save_load" -- --nocapture --test-threads=1 - -exit_code=$? - -echo "" -if [ $exit_code -eq 0 ]; then - echo "πŸŽ‰ All save and load tests passed!" -else - echo "πŸ’₯ Some save and load tests failed!" -fi - -exit $exit_code diff --git a/e2etests/test_core_session_clean.sh b/e2etests/test_core_session_clean.sh deleted file mode 100644 index 78d030deda..0000000000 --- a/e2etests/test_core_session_clean.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash - -# Clean core session(help, clean, quit) command test runner -# Usage: ./run_core_session_clean.sh [path_to_q_binary] - -Q_BINARY="q" - -if [ $# -gt 0 ]; then - Q_BINARY="$1" - export Q_CLI_PATH="$Q_BINARY" -fi - -echo "πŸš€ Running Core Session Command Test" -echo "=============================" -echo "" - -# Run only the core session(help, clean, quit) command test -echo "πŸ”„ Running core session(help, clean, quit) test..." -cargo test --test --features "core_session" -- --nocapture --test-threads=1 - -exit_code=$? - -echo "" -if [ $exit_code -eq 0 ]; then - echo "πŸŽ‰ Core Session test passed!" -else - echo "πŸ’₯ Core Session test failed!" -fi - -exit $exit_code diff --git a/e2etests/tests/context/test_context_command.rs b/e2etests/tests/context/test_context_command.rs index 79336fb204..ea8dcfefaa 100644 --- a/e2etests/tests/context/test_context_command.rs +++ b/e2etests/tests/context/test_context_command.rs @@ -16,8 +16,8 @@ const TEST_NAMES: &[&str] = &[ "test_context_remove_command_of_non_existent_file", "test_add_remove_file_context", "test_add_glob_pattern_file_context", - "test_clear_context_command", - "test_add_remove_multiple_file_context" + "test_add_remove_multiple_file_context", + "test_clear_context_command" ]; #[allow(dead_code)] const TOTAL_TESTS: usize = TEST_NAMES.len(); @@ -72,12 +72,12 @@ fn test_context_help_command() -> Result<(), Box> { println!("πŸ“ END OUTPUT"); // Verify Usage section - assert!(response.contains("Usage:"), "Missing Usage section"); + assert!(response.contains("Usage"), "Missing Usage section"); assert!(response.contains("/context") && response.contains(""), "Missing /context command in usage"); println!("βœ… Found Usage section"); // Verify Commands section - assert!(response.contains("Commands:"), "Missing Commands section"); + assert!(response.contains("Commands"), "Missing Commands section"); assert!(response.contains("show"), "Missing show command"); assert!(response.contains("add"), "Missing add command"); assert!(response.contains("remove"), "Missing remove command"); @@ -113,11 +113,11 @@ fn test_context_without_subcommand() -> Result<(), Box> { println!("{}", response); println!("πŸ“ END OUTPUT"); - assert!(response.contains("Usage:"), "Missing Usage section"); + assert!(response.contains("Usage"), "Missing Usage section"); assert!(response.contains("/context") && response.contains(""), "Missing /context command in usage"); println!("βœ… Found Usage section with /context command"); - assert!(response.contains("Commands:"), "Missing Commands section"); + assert!(response.contains("Commands"), "Missing Commands section"); assert!(response.contains("show"), "Missing show command"); assert!(response.contains("add"), "Missing add command"); assert!(response.contains("remove"), "Missing remove command"); @@ -213,7 +213,7 @@ fn test_context_remove_command_of_non_existent_file() -> Result<(), Box Result<(), Box> #[test] #[cfg(all(feature = "context", feature = "regression"))] -fn test_clear_context_command()-> Result<(), Box> { - println!("πŸ” Testing /context clear command..."); - - let test_file_path = "/tmp/test_context_file.py"; +fn test_add_remove_multiple_file_context()-> Result<(), Box> { + println!("πŸ” Testing /context add command and /context remove ..."); + + let test_file1_path = "/tmp/test_context_file1.py"; + let test_file2_path = "/tmp/test_context_file2.py"; + let test_file3_path = "/tmp/test_context_file.js"; // Create test files - std::fs::write(test_file_path, "# Test Python file 1 for context\nprint('Hello from Python file 1')")?; - println!("βœ… Created test files at {}", test_file_path); + std::fs::write(test_file1_path, "# Test Python file 1 for context\nprint('Hello from Python file 1')")?; + std::fs::write(test_file2_path, "# Test Python file 2 for context\nprint('Hello from Python file 2')")?; + std::fs::write(test_file3_path, "// Test JavaScript file\nconsole.log('Hello from JS file');")?; + println!("βœ… Created test files at {}, {}, {}", test_file1_path, test_file2_path, test_file3_path); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); - - // Add multiple files to context - let add_response = chat.execute_command(&format!("/context add {}", test_file_path))?; + + // Add multiple files to context in one command + let add_response = chat.execute_command(&format!("/context add {} {} {}", test_file1_path, test_file2_path, test_file3_path))?; println!("πŸ“ Context add response: {} bytes", add_response.len()); println!("πŸ“ ADD RESPONSE:"); @@ -404,8 +408,8 @@ fn test_clear_context_command()-> Result<(), Box> { println!("πŸ“ END ADD RESPONSE"); // Verify files were added successfully - be flexible with the exact message format - assert!(add_response.contains("Added"), "Missing success message for adding files"); - println!("βœ… Files added to context successfully"); + assert!(add_response.contains("Added"), "Missing success message for adding multiple files"); + println!("βœ… Multiple files added to context successfully"); // Execute /context show to confirm files are present let show_response = chat.execute_command("/context show")?; @@ -415,23 +419,25 @@ fn test_clear_context_command()-> Result<(), Box> { println!("{}", show_response); println!("πŸ“ END SHOW RESPONSE"); - // Verify files are present in context - assert!(show_response.contains(test_file_path), "Python file not found in context show output"); - println!("βœ… Files confirmed present in context"); - - // Execute /context clear to remove all files - let clear_response = chat.execute_command("/context clear")?; + // Verify all files are present in context + assert!(show_response.contains(test_file1_path), "Python file not found in context show output"); + assert!(show_response.contains(test_file2_path), "JavaScript file not found in context show output"); + assert!(show_response.contains(test_file3_path), "Text file not found in context show output"); + println!("βœ… All files confirmed present in context"); + + // Remove multiple files from context + let remove_response = chat.execute_command(&format!("/context remove {} {} {}", test_file1_path, test_file2_path, test_file3_path))?; - println!("πŸ“ Context clear response: {} bytes", clear_response.len()); - println!("πŸ“ CLEAR RESPONSE:"); - println!("{}", clear_response); - println!("πŸ“ END CLEAR RESPONSE"); + println!("πŸ“ Context remove response: {} bytes", remove_response.len()); + println!("πŸ“ REMOVE RESPONSE:"); + println!("{}", remove_response); + println!("πŸ“ END REMOVE RESPONSE"); - // Verify context was cleared successfully - assert!(clear_response.contains("Cleared context"), "Missing success message for clearing context"); - println!("βœ… Context cleared successfully"); + // Verify files were removed successfully - be flexible with the exact message format + assert!(remove_response.contains("Removed"), "Missing success message for removing multiple files"); + println!("βœ… Multiple files removed from context successfully"); - // Execute /context show to confirm no files remain + // Execute /context show to confirm files are gone let final_show_response = chat.execute_command("/context show")?; println!("πŸ“ Final context show response: {} bytes", final_show_response.len()); @@ -439,17 +445,19 @@ fn test_clear_context_command()-> Result<(), Box> { println!("{}", final_show_response); println!("πŸ“ END FINAL SHOW RESPONSE"); - // Verify no files remain in context - assert!(!final_show_response.contains(test_file_path), "Python file still found in context after clear"); - assert!(final_show_response.contains("Agent (q_cli_default):"), "Missing Agent section"); - assert!(final_show_response.contains(""), "Missing indicator for cleared context"); - println!("βœ… All files confirmed removed from context and sections present"); + // Verify files are no longer in context + assert!(!final_show_response.contains(test_file1_path), "Python file still found in context after removal"); + assert!(!final_show_response.contains(test_file2_path), "JavaScript file still found in context after removal"); + assert!(!final_show_response.contains(test_file3_path), "Text file still found in context after removal"); + println!("βœ… All files confirmed removed from context"); // Release the lock before cleanup drop(chat); // Clean up test file - let _ = std::fs::remove_file(test_file_path); + let _ = std::fs::remove_file(test_file1_path); + let _ = std::fs::remove_file(test_file2_path); + let _ = std::fs::remove_file(test_file3_path); println!("βœ… Cleaned up test file"); // Cleanup only if this is the last test @@ -460,24 +468,20 @@ fn test_clear_context_command()-> Result<(), Box> { #[test] #[cfg(all(feature = "context", feature = "regression"))] -fn test_add_remove_multiple_file_context()-> Result<(), Box> { - println!("πŸ” Testing /context add command and /context remove ..."); - - let test_file1_path = "/tmp/test_context_file1.py"; - let test_file2_path = "/tmp/test_context_file2.py"; - let test_file3_path = "/tmp/test_context_file.js"; +fn test_clear_context_command()-> Result<(), Box> { + println!("πŸ” Testing /context clear command..."); + + let test_file_path = "/tmp/test_context_file.py"; // Create test files - std::fs::write(test_file1_path, "# Test Python file 1 for context\nprint('Hello from Python file 1')")?; - std::fs::write(test_file2_path, "# Test Python file 2 for context\nprint('Hello from Python file 2')")?; - std::fs::write(test_file3_path, "// Test JavaScript file\nconsole.log('Hello from JS file');")?; - println!("βœ… Created test files at {}, {}, {}", test_file1_path, test_file2_path, test_file3_path); + std::fs::write(test_file_path, "# Test Python file 1 for context\nprint('Hello from Python file 1')")?; + println!("βœ… Created test files at {}", test_file_path); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); - - // Add multiple files to context in one command - let add_response = chat.execute_command(&format!("/context add {} {} {}", test_file1_path, test_file2_path, test_file3_path))?; + + // Add multiple files to context + let add_response = chat.execute_command(&format!("/context add {}", test_file_path))?; println!("πŸ“ Context add response: {} bytes", add_response.len()); println!("πŸ“ ADD RESPONSE:"); @@ -485,8 +489,8 @@ fn test_add_remove_multiple_file_context()-> Result<(), Box Result<(), Box Result<(), Box"), "Missing indicator for cleared context"); + println!("βœ… All files confirmed removed from context and sections present"); // Release the lock before cleanup drop(chat); // Clean up test file - let _ = std::fs::remove_file(test_file1_path); - let _ = std::fs::remove_file(test_file2_path); - let _ = std::fs::remove_file(test_file3_path); + let _ = std::fs::remove_file(test_file_path); println!("βœ… Cleaned up test file"); // Cleanup only if this is the last test diff --git a/e2etests/tests/mcp/test_mcp_command.rs b/e2etests/tests/mcp/test_mcp_command.rs index 95c91525ed..6175e55e41 100644 --- a/e2etests/tests/mcp/test_mcp_command.rs +++ b/e2etests/tests/mcp/test_mcp_command.rs @@ -121,8 +121,8 @@ fn test_mcp_remove_help_command() -> Result<(), Box> { println!("πŸ“ END HELP RESPONSE"); // Verify tool execution prompt appears - assert!(help_response.contains("Using tool: execute_bash"), "Missing tool execution indicator"); - assert!(help_response.contains("Allow this action?") && help_response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); + assert!(help_response.contains("Using tool"), "Missing tool execution indicator"); + assert!(help_response.contains("Allow this action?"), "Missing permission prompt"); println!("βœ… Found tool execution permission prompt"); // Allow the tool execution @@ -134,13 +134,12 @@ fn test_mcp_remove_help_command() -> Result<(), Box> { println!("πŸ“ END ALLOW RESPONSE"); // Verify complete help content in final response - assert!(allow_response.contains("Usage: qchat mcp remove"), "Missing usage information"); + assert!(allow_response.contains("Usage") && allow_response.contains("qchat mcp remove"), "Missing usage information"); assert!(allow_response.contains("Options"), "Missing option information"); assert!(allow_response.contains("--name "), "Missing --name option"); assert!(allow_response.contains("--scope "), "Missing --scope option"); assert!(allow_response.contains("--agent "), "Missing --agent option"); assert!(allow_response.contains("-h, --help"), "Missing help option"); - assert!(allow_response.contains("Completed in"), "Missing completion indicator"); println!("βœ… Found all expected MCP remove help content and completion"); // Release the lock before cleanup @@ -171,12 +170,12 @@ fn test_q_mcp_add_help_command() -> Result<(), Box> { // Verify tool execution details assert!(response.contains("q mcp add --help"), "Missing command execution description"); - assert!(response.contains("Purpose:"), "Missing purpose description"); + assert!(response.contains("Purpose"), "Missing purpose description"); println!("βœ… Found tool execution details"); // Verify tool execution prompt appears - assert!(response.contains("Using tool: execute_bash"), "Missing tool execution indicator"); - assert!(response.contains("Allow this action?") && response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); + assert!(response.contains("Using tool"), "Missing tool execution indicator"); + assert!(response.contains("Allow this action?"), "Missing permission prompt"); println!("βœ… Found tool execution permission prompt"); // Allow the tool execution @@ -188,18 +187,13 @@ fn test_q_mcp_add_help_command() -> Result<(), Box> { println!("πŸ“ END ALLOW RESPONSE"); // Verify mcp add help output - assert!(allow_response.contains("Usage: qchat mcp add"), "Missing usage information"); + assert!(allow_response.contains("Usage") && allow_response.contains("qchat mcp add"), "Missing usage information"); assert!(allow_response.contains("Options"), "Missing Options"); assert!(allow_response.contains("--name "), "Missing --name option"); assert!(allow_response.contains("--command "), "Missing --command option"); assert!(allow_response.contains("--scope "), "Missing --scope option"); - assert!(allow_response.contains("--args "), "Missing --args option"); assert!(allow_response.contains("--agent "), "Missing --agent option"); - assert!(allow_response.contains("--env "), "Missing --env option"); - assert!(allow_response.contains("--timeout "), "Missing --timeout option"); - assert!(allow_response.contains("--disabled"), "Missing --disabled option"); assert!(allow_response.contains("--force"), "Missing --force option"); - assert!(allow_response.contains("--verbose"), "Missing --verbose option"); assert!(allow_response.contains("--help"), "Missing --help option"); assert!(allow_response.contains("Completed in"), "Missing completion indicator"); assert!(allow_response.contains("Required"), "Missing Requried indicator"); @@ -232,8 +226,8 @@ fn test_q_mcp_help_command() -> Result<(), Box> { println!("πŸ“ END HELP RESPONSE"); // Verify tool execution prompt appears - assert!(help_response.contains("Using tool: execute_bash"), "Missing tool execution indicator"); - assert!(help_response.contains("Allow this action?") && help_response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); + assert!(help_response.contains("Using tool"), "Missing tool execution indicator"); + assert!(help_response.contains("Allow this action?"), "Missing permission prompt"); println!("βœ… Found tool execution permission prompt"); // Allow the tool execution @@ -246,8 +240,8 @@ fn test_q_mcp_help_command() -> Result<(), Box> { // Verify complete help content assert!(allow_response.contains("Model Context Protocol (MCP)"), "Missing MCP description"); - assert!(allow_response.contains("Usage: qchat mcp"), "Missing usage information"); - assert!(allow_response.contains("Commands:"), "Missing Commands section"); + assert!(allow_response.contains("Usage") && allow_response.contains("qchat mcp"), "Missing usage information"); + assert!(allow_response.contains("Commands"), "Missing Commands section"); // Verify command descriptions assert!(allow_response.contains("add"), "Missing add command description"); @@ -261,7 +255,6 @@ fn test_q_mcp_help_command() -> Result<(), Box> { assert!(allow_response.contains("Options"), "Missing Options section"); assert!(allow_response.contains("-v, --verbose"), "Missing verbose option"); assert!(allow_response.contains("-h, --help"), "Missing help option"); - assert!(allow_response.contains("Completed in"), "Missing completion indicator"); println!("βœ… Found all expected MCP help content and completion"); // Release the lock before cleanup @@ -292,12 +285,12 @@ fn test_q_mcp_import_help_command() -> Result<(), Box> { // Verify tool execution details assert!(response.contains("q mcp import --help"), "Missing command execution description"); - assert!(response.contains("Purpose:"), "Missing purpose description"); + assert!(response.contains("Purpose"), "Missing purpose description"); println!("βœ… Found tool execution details"); // Verify tool execution prompt appears - assert!(response.contains("Using tool: execute_bash"), "Missing tool execution indicator"); - assert!(response.contains("Allow this action?") && response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); + assert!(response.contains("Using tool"), "Missing tool execution indicator"); + assert!(response.contains("Allow this action?"), "Missing permission prompt"); println!("βœ… Found tool execution permission prompt"); // Allow the tool execution @@ -324,10 +317,6 @@ fn test_q_mcp_import_help_command() -> Result<(), Box> { assert!(allow_response.contains("-h, --help"), "Missing --help option"); println!("βœ… Found all options with descriptions"); - // Verify completion indicator - assert!(allow_response.contains("Completed in") && allow_response.contains("s"), "Missing completion time indicator"); - println!("βœ… Found completion indicator"); - println!("βœ… All q mcp import --help content verified successfully"); // Release the lock before cleanup @@ -355,9 +344,9 @@ fn test_q_mcp_list_command() -> Result<(), Box> { println!("πŸ“ END OUTPUT"); // Verify tool execution prompt - assert!(response.contains("Using tool:"), "Missing tool execution indicator"); + assert!(response.contains("Using tool"), "Missing tool execution indicator"); assert!(response.contains("q mcp list"), "Missing command in tool execution"); - assert!(response.contains("Allow this action?") && response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); + assert!(response.contains("Allow this action?"), "Missing permission prompt"); println!("βœ… Found tool execution permission prompt"); // Allow the tool execution @@ -398,9 +387,9 @@ fn test_q_mcp_list_help_command() -> Result<(), Box> { println!("πŸ“ END OUTPUT"); // Verify tool execution prompt - assert!(response.contains("Using tool:"), "Missing tool execution indicator"); + assert!(response.contains("Using tool"), "Missing tool execution indicator"); assert!(response.contains("q mcp list --help"), "Missing command in tool execution"); - assert!(response.contains("Allow this action?") && response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); + assert!(response.contains("Allow this action?"), "Missing permission prompt"); println!("βœ… Found tool execution permission prompt"); // Allow the tool execution @@ -422,10 +411,6 @@ fn test_q_mcp_list_help_command() -> Result<(), Box> { assert!(allow_response.contains("Options"), "Missing Options section"); assert!(allow_response.contains("-v") && allow_response.contains("--verbose"), "Missing verbose option"); assert!(allow_response.contains("-h") && allow_response.contains("--help"), "Missing help option"); - - - assert!(allow_response.contains("Completed in"), "Missing completion indicator"); - println!("βœ… Found all MCP list help content with explanations and completion"); // Release the lock before cleanup drop(chat); @@ -454,12 +439,12 @@ fn test_q_mcp_status_help_command() -> Result<(), Box> { println!("πŸ“ END RESTART RESPONSE"); // Verify tool execution details - assert!(response.contains("Purpose:"), "Missing purpose description"); + assert!(response.contains("Purpose"), "Missing purpose description"); println!("βœ… Found tool execution details"); // Verify tool execution prompt appears - assert!(response.contains("Using tool: execute_bash"), "Missing tool execution indicator"); - assert!(response.contains("Allow this action?") && response.contains("to trust (always allow) this tool for the session."), "Missing permission prompt"); + assert!(response.contains("Using tool"), "Missing tool execution indicator"); + assert!(response.contains("Allow this action?"), "Missing permission prompt"); println!("βœ… Found tool execution permission prompt"); // Allow the tool execution @@ -471,20 +456,16 @@ fn test_q_mcp_status_help_command() -> Result<(), Box> { println!("πŸ“ END ALLOW RESPONSE"); // Verify usage line - assert!(allow_response.contains("Usage: qchat mcp status [OPTIONS] --name "), "Missing complete usage line"); + assert!(allow_response.contains("Usage") && allow_response.contains("qchat mcp status [OPTIONS] --name "), "Missing complete usage line"); println!("βœ… Found usage information"); // Verify Options section assert!(allow_response.contains("Options"), "Missing Options section"); assert!(allow_response.contains("--name "), "Missing --name option"); - assert!(allow_response.contains("-v, --verbose...") , "Missing --verbose option"); + assert!(allow_response.contains("-v, --verbose") , "Missing --verbose option"); assert!(allow_response.contains("-h, --help"), "Missing --help option"); println!("βœ… Found all options with descriptions"); - // Verify completion indicator - assert!(allow_response.contains("Completed in") && allow_response.contains("s"), "Missing completion time indicator"); - println!("βœ… Found completion indicator"); - println!("βœ… All q mcp status --help content verified successfully"); // Release the lock before cleanup diff --git a/e2etests/tests/save_load/test_save_load_command.rs b/e2etests/tests/save_load/test_save_load_command.rs index 1681378fcc..689dd38326 100644 --- a/e2etests/tests/save_load/test_save_load_command.rs +++ b/e2etests/tests/save_load/test_save_load_command.rs @@ -146,12 +146,8 @@ fn test_save_help_command() -> Result<(), Box> { assert!(response.contains(""), "Missing PATH argument"); println!("βœ… Found Arguments section with PATH parameter"); - assert!(response.contains("Options:"), "Missing Options section"); - assert!(response.contains("-f"), "Missing -f flag"); - assert!(response.contains("--force"), "Missing --force flag"); - assert!(response.contains("-h"), "Missing -h flag"); - assert!(response.contains("--help") || response.contains("β€”help"), "Missing --help flag"); - println!("βœ… Found Options section with -f, --force, -h, --help flags"); + assert!(response.contains("Options"), "Missing Options section"); + println!("βœ… Found Options section"); println!("βœ… All help content verified!"); @@ -192,12 +188,8 @@ fn test_save_h_flag_command() -> Result<(), Box> { assert!(response.contains(""), "Missing PATH argument"); println!("βœ… Found Arguments section with PATH parameter"); - assert!(response.contains("Options:"), "Missing Options section"); - assert!(response.contains("-f"), "Missing -f flag"); - assert!(response.contains("--force"), "Missing --force flag"); - assert!(response.contains("-h"), "Missing -h flag"); - assert!(response.contains("--help") || response.contains("β€”help"), "Missing --help flag"); - println!("βœ… Found Options section with -f, --force, -h, --help flags"); + assert!(response.contains("Options"), "Missing Options section"); + println!("βœ… Found Options section"); println!("βœ… All help content verified!"); @@ -354,9 +346,7 @@ fn test_load_help_command() -> Result<(), Box> { println!("βœ… Found Arguments section with PATH parameter"); assert!(response.contains("Options"), "Missing Options section"); - assert!(response.contains("-h"), "Missing -h flag"); - assert!(response.contains("--help"), "Missing --help flag"); - println!("βœ… Found Options section with -h, --help flags"); + println!("βœ… Found Options section"); println!("βœ… All help content verified!"); @@ -397,9 +387,7 @@ fn test_load_h_flag_command() -> Result<(), Box> { println!("βœ… Found Arguments section with PATH parameter"); assert!(response.contains("Options"), "Missing Options section"); - assert!(response.contains("-h"), "Missing -h flag"); - assert!(response.contains("--help"), "Missing --help flag"); - println!("βœ… Found Options section with -h, --help flags"); + println!("βœ… Found Options section"); println!("βœ… All help content verified!"); @@ -454,7 +442,7 @@ fn test_load_command() -> Result<(), Box> { // Verify load was successful assert!(!load_response.is_empty(), "Load command should return non-empty response"); - assert!(load_response.contains("Imported conversation state from") && load_response.contains(save_path), "Missing import confirmation message"); + assert!(load_response.contains("Imported") && load_response.contains(save_path), "Missing import confirmation message"); println!("βœ… Load command executed successfully and imported conversation state"); // Release the lock before cleanup @@ -482,7 +470,7 @@ fn test_load_command_argument_validation() -> Result<(), Box Result<(), Box Date: Fri, 22 Aug 2025 21:22:56 +0530 Subject: [PATCH 32/77] Migrated to python script with HTML report generation --- e2etests/Cargo.toml | 44 +- e2etests/run_tests.py | 559 ++++++++++++++++++ e2etests/tests/agent/test_agent_commands.rs | 16 +- e2etests/tests/ai_prompts/test_ai_prompt.rs | 4 +- .../tests/ai_prompts/test_prompts_commands.rs | 6 +- .../tests/context/test_context_command.rs | 18 +- .../tests/core_session/test_clear_command.rs | 2 +- .../tests/core_session/test_help_command.rs | 2 +- .../tests/core_session/test_quit_command.rs | 2 +- .../tests/core_session/test_tools_command.rs | 18 +- .../integration/test_editor_help_command.rs | 4 +- .../tests/integration/test_hooks_command.rs | 4 +- .../tests/integration/test_issue_command.rs | 6 +- .../integration/test_subscribe_command.rs | 4 +- e2etests/tests/mcp/test_mcp_command.rs | 18 +- .../tests/model/test_model_dynamic_command.rs | 4 +- .../tests/save_load/test_save_load_command.rs | 20 +- .../session_mgmt/test_compact_command.rs | 145 +---- .../tests/session_mgmt/test_usage_command.rs | 4 +- 19 files changed, 653 insertions(+), 227 deletions(-) create mode 100755 e2etests/run_tests.py diff --git a/e2etests/Cargo.toml b/e2etests/Cargo.toml index b294d42482..dbf51a33f1 100644 --- a/e2etests/Cargo.toml +++ b/e2etests/Cargo.toml @@ -9,21 +9,29 @@ edition = "2021" expectrl = "0.7" [features] -default = [] -core_session = [] -agent = [] -context = [] -save_load = [] -model = [] -session_mgmt = [] -integration = [] -mcp = [] -ai_prompts = [] -issue_reporting = [] -tools=[] -compact=[] -hooks=[] -usage=[] -editor=[] -subscribe=[] -regression = [] +core_session = ["help", "tools", "quit", "clear"] # Core Session Commands (/help, /tools, /quit, /clear) +help = [] # Help Command (/help) +tools = [] # Tools Command (/tools) +quit = [] # Quit Command (/quit) +clear = [] # Clear Command (/clear) + +agent = [] # Agent Commands (/agent list, /agent create, etc.) +context = [] # Context Commands (/context show, /context add, etc.) +save_load = [] # Save/Load Commands (/save, /load, help) +model = [] # Model Commands (/model, /model --help) + +session_mgmt = ["compact", "usage"] # Session Management Commands (/compact, /usage, help) +compact = [] # Compact Commands +usage = [] # Usage Commands + +integration = ["subscribe", "hooks", "editor"] # Integration Commands (/subscribe, /hooks, /editor help) +subscribe = [] # Subscribe Commands +hooks = [] # Hooks Commands +editor = [] # Editor Commands + +mcp = [] # MCP Commands (/mcp, /mcp --help) +ai_prompts = [] # AI Prompts ("What is AWS?", "Hello") +issue_reporting = [] # Issue Reporting Commands + +regression = [] # Regression Tests +sanity = [] # Sanity Tests - Quick smoke tests for basic functionality diff --git a/e2etests/run_tests.py b/e2etests/run_tests.py new file mode 100755 index 0000000000..2cba625890 --- /dev/null +++ b/e2etests/run_tests.py @@ -0,0 +1,559 @@ +#!/usr/bin/env python3 + +import toml +import subprocess +import sys +import argparse +import json +import time +import platform +from datetime import datetime +from pathlib import Path + +def parse_features(): + """Parse features from Cargo.toml, handling grouped features correctly""" + cargo_toml = toml.load("Cargo.toml") + features = cargo_toml.get("features", {}) + + # Features to always exclude from individual runs + excluded_features = {"default", "regression", "sanity"} + + # Group features (features that contain other features) + grouped_features = {} + grouped_sub_features = set() + + # First pass: identify grouped features and their sub-features + for feature_name, feature_deps in features.items(): + if feature_name in excluded_features: + continue + + if isinstance(feature_deps, list) and feature_deps: + # This is a grouped feature + grouped_features[feature_name] = feature_deps + grouped_sub_features.update(feature_deps) + + # Second pass: identify standalone features (not part of any group) + standalone_features = [] + for feature_name in features.keys(): + if (feature_name not in excluded_features and + feature_name not in grouped_features and + feature_name not in grouped_sub_features): + standalone_features.append(feature_name) + + return grouped_features, standalone_features + +# Default test suite - always required for cargo test +DEFAULT_TESTSUITE = "sanity" + +def parse_test_results(stdout): + """Parse individual test results from cargo output""" + tests = [] + lines = stdout.split('\n') + + for line in lines: + if ' ... ok' in line and line.startswith('test '): + test_name = line.split(' ... ok')[0].replace('test ', '').strip() + tests.append({"name": test_name, "status": "passed"}) + elif ' ... FAILED' in line and line.startswith('test '): + test_name = line.split(' ... FAILED')[0].replace('test ', '').strip() + tests.append({"name": test_name, "status": "failed"}) + + return tests + +def run_single_cargo_test(feature, test_suite, binary_path="q", quiet=False): + """Run cargo test for a single feature with test suite""" + feature_str = f"{feature},{test_suite}" + cmd = ["cargo", "test", "--tests", "--features", feature_str, "--", "--nocapture"] + + if not quiet: + print(f"πŸ”„ Running: {feature} with {test_suite}") + print(f"Command: {' '.join(cmd)}") + + start_time = time.time() + result = subprocess.run(cmd, capture_output=True, text=True) + end_time = time.time() + + # Parse individual test results + individual_tests = parse_test_results(result.stdout) + + if not quiet: + print(result.stdout) + if result.stderr: + print(result.stderr) + + # Show individual test results + print(f"\nπŸ“‹ Individual Test Results for {feature}:") + for test in individual_tests: + status_icon = "βœ…" if test["status"] == "passed" else "❌" + print(f" {status_icon} {test['name']} - {test['status']}") + + return { + "feature": feature, + "test_suite": test_suite, + "success": result.returncode == 0, + "duration": round(end_time - start_time, 2), + "stdout": result.stdout, + "stderr": result.stderr, + "command": " ".join(cmd), + "individual_tests": individual_tests + } + +def get_test_suites_from_features(features): + """Extract test suites (sanity/regression) from feature list""" + test_suites = [] + if "sanity" in features: + test_suites.append("sanity") + if "regression" in features: + test_suites.append("regression") + + if not test_suites: + test_suites = [DEFAULT_TESTSUITE] + + return test_suites + +def run_tests_with_suites(features, test_suites, binary_path="q", quiet=False): + """Run tests for each feature with each test suite""" + results = [] + + for test_suite in test_suites: + for feature in features: + if feature not in {"sanity", "regression"}: + result = run_single_cargo_test(feature, test_suite, binary_path, quiet) + results.append(result) + + individual_tests = result.get("individual_tests", []) + passed_count = sum(1 for t in individual_tests if t["status"] == "passed") + failed_count = sum(1 for t in individual_tests if t["status"] == "failed") + + status = "βœ…" if result["success"] else "❌" + print(f"{status} {feature} ({test_suite}) - {result['duration']}s - {passed_count} passed, {failed_count} failed") + + return results + +def get_system_info(binary_path="q"): + """Get Q binary version and system information""" + system_info = { + "os": platform.system(), + "os_version": platform.version(), + "platform": platform.platform(), + "python_version": platform.python_version(), + "q_binary_path": binary_path + } + + # Try to get Q binary version + try: + result = subprocess.run([binary_path, "--version"], capture_output=True, text=True, timeout=10) + if result.returncode == 0: + system_info["q_version"] = result.stdout.strip() + else: + system_info["q_version"] = "Unable to determine version" + except Exception as e: + system_info["q_version"] = f"Error getting version: {str(e)}" + + return system_info + +def generate_report(results, features, test_suites, binary_path="q"): + """Generate JSON report and console summary""" + timestamp = datetime.now().isoformat() + system_info = get_system_info(binary_path) + + # Calculate summary stats from individual tests + total_individual_tests = 0 + passed_individual_tests = 0 + failed_individual_tests = 0 + + # Group by feature with individual test details + feature_summary = {} + for result in results: + feature = result["feature"] + if feature not in feature_summary: + feature_summary[feature] = { + "passed": 0, + "failed": 0, + "test_suites": [], + "individual_tests": [] + } + + # Count individual tests + individual_tests = result.get("individual_tests", []) + feature_passed = sum(1 for t in individual_tests if t["status"] == "passed") + feature_failed = sum(1 for t in individual_tests if t["status"] == "failed") + + feature_summary[feature]["passed"] += feature_passed + feature_summary[feature]["failed"] += feature_failed + feature_summary[feature]["test_suites"].append(result["test_suite"]) + feature_summary[feature]["individual_tests"].extend(individual_tests) + + total_individual_tests += len(individual_tests) + passed_individual_tests += feature_passed + failed_individual_tests += feature_failed + + # Create JSON report + report = { + "timestamp": timestamp, + "system_info": system_info, + "summary": { + "total_feature_runs": len(results), + "total_individual_tests": total_individual_tests, + "passed": passed_individual_tests, + "failed": failed_individual_tests, + "success_rate": round((passed_individual_tests / total_individual_tests * 100) if total_individual_tests > 0 else 0, 2) + }, + "features": feature_summary, + "detailed_results": results + } + + # Generate filename with features and test suites + features_str = "-".join(features[:3]) + ("_more" if len(features) > 3 else "") + suites_str = "-".join(test_suites) + datetime_str = datetime.now().strftime("%m%d%y%H%M%S") + filename = f"qcli_test_summary_{features_str}_{suites_str}_{datetime_str}.json" + + # Save JSON report + with open(filename, "w") as f: + json.dump(report, f, indent=2) + + report["filename"] = filename + return report + +def generate_html_report(json_filename): + """Generate HTML report from JSON file""" + with open(json_filename, 'r') as f: + report = json.load(f) + + # Generate HTML filename + html_filename = json_filename.replace('.json', '.html') + + # Calculate stats + total_features = len(report["features"]) + features_100_pass = sum(1 for stats in report["features"].values() if stats["failed"] == 0) + features_failed = total_features - features_100_pass + + # Get test suites from detailed results + test_suites = list(set(result["test_suite"] for result in report["detailed_results"])) + + html_content = f""" + + + + + + Q CLI Test Report + + + +
+
+

πŸ§ͺ Q CLI E2E Test Report

+

Generated: {report['timestamp']}

+
+

πŸ’» System Information

+

Platform: {report['system_info']['platform']}

+

OS: {report['system_info']['os']} {report['system_info']['os_version']}

+

Q Binary: {report['system_info']['q_binary_path']}

+

Q Version: {report['system_info']['q_version']}

+
+
+ +
+

πŸ“Š Overall Summary

+
+
+

{report['summary']['success_rate']}%

+

Success Rate

+
+
+

{total_features}

+

Features Tested

+
+
+

{features_100_pass}

+

Features 100% Pass

+
+
+

{features_failed}

+

Features with Failures

+
+
+

{report['summary']['passed']}

+

Tests Passed

+
+
+

{report['summary']['failed']}

+

Tests Failed

+
+
+
+""" + + # Add test suite sections + for suite in test_suites: + suite_features = {} + for result in report["detailed_results"]: + if result["test_suite"] == suite: + feature = result["feature"] + if feature not in suite_features: + suite_features[feature] = report["features"][feature] + + suite_passed = sum(stats["passed"] for stats in suite_features.values()) + suite_failed = sum(stats["failed"] for stats in suite_features.values()) + suite_rate = round((suite_passed / (suite_passed + suite_failed) * 100) if (suite_passed + suite_failed) > 0 else 0, 2) + + html_content += f""" + +
+""" + + # Add features for this suite + for feature_name, feature_stats in suite_features.items(): + feature_rate = round((feature_stats["passed"] / (feature_stats["passed"] + feature_stats["failed"]) * 100) if (feature_stats["passed"] + feature_stats["failed"]) > 0 else 0, 2) + + html_content += f""" + +
+""" + + # Add individual tests + for test in feature_stats["individual_tests"]: + test_class = "test-passed" if test["status"] == "passed" else "test-failed" + status_icon = "βœ…" if test["status"] == "passed" else "❌" + + html_content += f""" +
+

{status_icon} {test['name']}

+

Status: {test['status'].upper()}

+
+""" + + # Add stdout/stderr for this feature + for result in report["detailed_results"]: + if result["feature"] == feature_name and result["test_suite"] == suite: + html_content += f""" + +
+

Command: {result['command']}

+

Duration: {result['duration']}s

+
{result['stdout']}
+ {f'
STDERR:
{result["stderr"]}
' if result['stderr'] else ''} +
+""" + + html_content += "
" # Close feature content + + html_content += "
" # Close suite content + + html_content += """ +
+ + + + +""" + + with open(html_filename, 'w') as f: + f.write(html_content) + + return html_filename + +def print_summary(report): + """Print beautified console summary""" + # Print system info + print("\nπŸ’» System Information:") + print(f" Platform: {report['system_info']['platform']}") + print(f" OS: {report['system_info']['os']} {report['system_info']['os_version']}") + print(f" Q Binary: {report['system_info']['q_binary_path']}") + print(f" Q Version: {report['system_info']['q_version']}") + + print("\nπŸ“‹ Feature Summary:") + for feature, stats in report["features"].items(): + status = "βœ…" if stats["failed"] == 0 else "❌" + suites = ",".join(set(stats["test_suites"])) + print(f" {status} {feature} ({suites}): {stats['passed']} passed, {stats['failed']} failed") + + # Show individual test details + for test in stats["individual_tests"]: + test_status = "βœ…" if test["status"] == "passed" else "❌" + print(f" {test_status} {test['name']}") + + # Calculate feature-level stats + total_features = len(report["features"]) + features_100_pass = sum(1 for stats in report["features"].values() if stats["failed"] == 0) + features_failed = total_features - features_100_pass + + print("\n🎯 FINAL SUMMARY") + print("=" * 32) + print(f"🏷️ Features Tested: {total_features}") + # print(f"πŸ”„ Feature Runs: {report['summary']['total_feature_runs']}") + print(f"βœ… Features 100% Pass: {features_100_pass}") + print(f"❌ Features with Failures: {features_failed}") + print(f"βœ… Individual Tests Passed: {report['summary']['passed']}") + print(f"❌ Individual Tests Failed: {report['summary']['failed']}") + print(f"πŸ“Š Total Individual Tests: {report['summary']['total_individual_tests']}") + print(f"πŸ“ˆ Success Rate: {report['summary']['success_rate']}%") + + + if report["summary"]["failed"] == 0: + print("\nπŸŽ‰ All tests passed!") + else: + print("\nπŸ’₯ Some tests failed!") + + print(f"\nπŸ“„ Detailed report saved to: {report['filename']}") + + # Generate HTML report + html_filename = generate_html_report(report['filename']) + print(f"🌐 HTML report saved to: {html_filename}") + +def dev_debug(): + """Debug function to show parsed features""" + print("πŸ”§ Developer Debug Mode") + print("=" * 30) + + grouped_features, standalone_features = parse_features() + + print("\nπŸ“¦ Grouped Features:") + for group, deps in grouped_features.items(): + print(f" {group} = {deps}") + + print("\nπŸ”Ή Standalone Features:") + for feature in standalone_features: + print(f" {feature}") + + print(f"\nπŸ“Š Summary:") + print(f" Grouped: {len(grouped_features)}") + print(f" Standalone: {len(standalone_features)}") + print(f" Total: {len(grouped_features) + len(standalone_features)}") + +def main(): + parser = argparse.ArgumentParser( + description="Run Q CLI E2E tests", + epilog="""Examples: + # Basic usage + %(prog)s # Run all tests with sanity suite + %(prog)s --features usage # Run usage tests with sanity suite + %(prog)s --features "usage,agent" # Run usage+agent tests with sanity suite + + # Test suites + %(prog)s --features sanity # Run all tests with sanity suite + %(prog)s --features regression # Run all tests with regression suite + %(prog)s --features "usage,regression" # Run usage tests with regression suite + %(prog)s --features "sanity,regression" # Run all tests with both suites + + # Multiple features (different ways) + %(prog)s --features "usage,agent,context" # Comma-separated features + %(prog)s --features usage --features agent # Multiple --features flags + %(prog)s --features core_session # Run grouped feature (includes help,tools,quit,clear) + + # Binary and output options + %(prog)s --binary /path/to/q --features usage + %(prog)s --quiet --features sanity + + # Developer tools + %(prog)s dev # Debug feature parsing + %(prog)s html report.json # Generate HTML from JSON report + + # Advanced examples + %(prog)s --features "core_session,regression" --binary ./target/release/q + %(prog)s --features "agent,mcp,sanity" --quiet""", + formatter_class=argparse.RawDescriptionHelpFormatter + ) + subparsers = parser.add_subparsers(dest="command", help="Available commands") + + # Dev subcommand + dev_parser = subparsers.add_parser("dev", help="Developer debug tools") + + # HTML subcommand + html_parser = subparsers.add_parser("html", help="Generate HTML report from JSON") + html_parser.add_argument("json_file", help="JSON report file to convert") + + # Test subcommand (default behavior) + test_parser = subparsers.add_parser("test", help="Run tests (default)") + test_parser.add_argument("--features", help="Comma-separated list of features") + test_parser.add_argument("--binary", default="q", help="Path to Q CLI binary") + test_parser.add_argument("--quiet", action="store_true", help="Quiet mode") + + # For backward compatibility + parser.add_argument("--features", help="Comma-separated list of features") + parser.add_argument("--binary", default="q", help="Path to Q CLI binary") + parser.add_argument("--quiet", action="store_true", help="Quiet mode") + + args = parser.parse_args() + + if args.command == "dev": + dev_debug() + return + + if args.command == "html": + html_filename = generate_html_report(args.json_file) + print(f"🌐 HTML report generated: {html_filename}") + return + + if not args.features: + # Run all features with default test suite + grouped_features, standalone_features = parse_features() + all_features = list(grouped_features.keys()) + standalone_features + test_suites = [DEFAULT_TESTSUITE] + else: + # Parse requested features + requested_features = [f.strip() for f in args.features.split(",")] + test_suites = get_test_suites_from_features(requested_features) + + # Remove test suites from feature list + features_only = [f for f in requested_features if f not in {"sanity", "regression"}] + + if not features_only: + # Only sanity/regression specified - run all features + grouped_features, standalone_features = parse_features() + all_features = list(grouped_features.keys()) + standalone_features + else: + all_features = features_only + + if not args.quiet: + print("πŸ§ͺ Running Q CLI E2E Tests") + print("=" * 40) + print(f"Features: {', '.join(all_features)}") + print(f"Test Suites: {', '.join(test_suites)}") + print() + + # Run tests + results = run_tests_with_suites(all_features, test_suites, args.binary, args.quiet) + + # Generate and display report + report = generate_report(results, all_features, test_suites, args.binary) + print_summary(report) + + # Exit with appropriate code + sys.exit(0 if report["summary"]["failed"] == 0 else 1) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/e2etests/tests/agent/test_agent_commands.rs b/e2etests/tests/agent/test_agent_commands.rs index 2d65f3fd23..3afd20bf5a 100644 --- a/e2etests/tests/agent/test_agent_commands.rs +++ b/e2etests/tests/agent/test_agent_commands.rs @@ -21,7 +21,7 @@ const TEST_NAMES: &[&str] = &[ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] -#[cfg(all(feature = "agent", feature = "regression"))] +#[cfg(all(feature = "agent", any(feature = "sanity"))] fn agent_without_subcommand() -> Result<(), Box> { println!("πŸ” Testing /agent command..."); @@ -72,7 +72,7 @@ fn agent_without_subcommand() -> Result<(), Box> { } #[test] -#[cfg(all(feature = "agent", feature = "regression"))] +#[cfg(all(feature = "agent", feature = "sanity"))] fn test_agent_create_command() -> Result<(), Box> { println!("πŸ” Testing /agent create --name command..."); @@ -139,7 +139,7 @@ fn test_agent_create_command() -> Result<(), Box> { } #[test] -#[cfg(all(feature = "agent", feature = "regression"))] +#[cfg(all(feature = "agent", feature = "sanity"))] fn test_agent_create_missing_args() -> Result<(), Box> { println!("πŸ” Testing /agent create without required arguments..."); @@ -188,7 +188,7 @@ fn test_agent_create_missing_args() -> Result<(), Box> { } #[test] -#[cfg(all(feature = "agent", feature = "regression"))] +#[cfg(all(feature = "agent", feature = "sanity"))] fn test_agent_help_command() -> Result<(), Box> { println!("πŸ” Testing /agent help..."); @@ -243,7 +243,7 @@ fn test_agent_help_command() -> Result<(), Box> { } #[test] -#[cfg(all(feature = "agent", feature = "regression"))] +#[cfg(all(feature = "agent", feature = "sanity"))] fn test_agent_invalid_command() -> Result<(), Box> { println!("πŸ” Testing /agent invalidcommand..."); @@ -280,7 +280,7 @@ fn test_agent_invalid_command() -> Result<(), Box> { } #[test] -#[cfg(all(feature = "agent", feature = "regression"))] +#[cfg(all(feature = "agent", feature = "sanity"))] fn test_agent_list_command() -> Result<(), Box> { println!("πŸ” Testing /agent list command..."); @@ -351,7 +351,7 @@ fn test_agent_list_command() -> Result<(), Box> { // } #[test] -#[cfg(all(feature = "agent", feature = "regression"))] +#[cfg(all(feature = "agent", feature = "sanity"))] fn test_agent_set_default_command() -> Result<(), Box> { println!("πŸ” Testing /agent set-default with valid arguments..."); @@ -390,7 +390,7 @@ fn test_agent_set_default_command() -> Result<(), Box> { } #[test] -#[cfg(all(feature = "agent", feature = "regression"))] +#[cfg(all(feature = "agent", feature = "sanity"))] fn test_agent_set_default_missing_args() -> Result<(), Box> { println!("πŸ” Testing /agent set-default without required arguments..."); diff --git a/e2etests/tests/ai_prompts/test_ai_prompt.rs b/e2etests/tests/ai_prompts/test_ai_prompt.rs index 9cd83b1adf..facdf7f644 100644 --- a/e2etests/tests/ai_prompts/test_ai_prompt.rs +++ b/e2etests/tests/ai_prompts/test_ai_prompt.rs @@ -2,7 +2,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] -#[cfg(all(feature = "ai_prompts", feature = "regression"))] +#[cfg(all(feature = "ai_prompts", feature = "sanity"))] fn test_what_is_aws_prompt() -> Result<(), Box> { println!("πŸ” [AI PROMPTS] Testing 'What is AWS?' AI prompt..."); @@ -55,7 +55,7 @@ fn test_what_is_aws_prompt() -> Result<(), Box> { } #[test] -#[cfg(all(feature = "ai_prompts", feature = "regression"))] +#[cfg(all(feature = "ai_prompts", feature = "sanity"))] fn test_simple_greeting() -> Result<(), Box> { println!("πŸ” Testing simple 'Hello' prompt..."); diff --git a/e2etests/tests/ai_prompts/test_prompts_commands.rs b/e2etests/tests/ai_prompts/test_prompts_commands.rs index 1b68297f53..70af25f8bd 100644 --- a/e2etests/tests/ai_prompts/test_prompts_commands.rs +++ b/e2etests/tests/ai_prompts/test_prompts_commands.rs @@ -17,7 +17,7 @@ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] -#[cfg(all(feature = "ai_prompts", feature = "regression"))] +#[cfg(all(feature = "ai_prompts", feature = "sanity"))] fn test_prompts_command() -> Result<(), Box> { println!("πŸ” Testing /prompts command..."); @@ -56,7 +56,7 @@ fn test_prompts_command() -> Result<(), Box> { } #[test] -#[cfg(all(feature = "ai_prompts", feature = "regression"))] +#[cfg(all(feature = "ai_prompts", feature = "sanity"))] fn test_prompts_help_command() -> Result<(), Box> { println!("πŸ” Testing /prompts --help command..."); @@ -117,7 +117,7 @@ fn test_prompts_help_command() -> Result<(), Box> { } #[test] -#[cfg(all(feature = "ai_prompts", feature = "regression"))] +#[cfg(all(feature = "ai_prompts", feature = "sanity"))] fn test_prompts_list_command() -> Result<(), Box> { println!("πŸ” Testing /prompts list command..."); diff --git a/e2etests/tests/context/test_context_command.rs b/e2etests/tests/context/test_context_command.rs index ea8dcfefaa..53162d4285 100644 --- a/e2etests/tests/context/test_context_command.rs +++ b/e2etests/tests/context/test_context_command.rs @@ -23,7 +23,7 @@ const TEST_NAMES: &[&str] = &[ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] -#[cfg(all(feature = "context", feature = "regression"))] +#[cfg(all(feature = "context", feature = "sanity"))] fn test_context_show_command() -> Result<(), Box> { println!("πŸ” Testing /context show command..."); @@ -57,7 +57,7 @@ fn test_context_show_command() -> Result<(), Box> { } #[test] -#[cfg(all(feature = "context", feature = "regression"))] +#[cfg(all(feature = "context", feature = "sanity"))] fn test_context_help_command() -> Result<(), Box> { println!("πŸ” Testing /context help command..."); @@ -99,7 +99,7 @@ fn test_context_help_command() -> Result<(), Box> { } #[test] -#[cfg(all(feature = "context", feature = "regression"))] +#[cfg(all(feature = "context", feature = "sanity"))] fn test_context_without_subcommand() -> Result<(), Box> { println!("πŸ” Testing /context without sub command..."); @@ -137,7 +137,7 @@ fn test_context_without_subcommand() -> Result<(), Box> { } #[test] -#[cfg(all(feature = "context", feature = "regression"))] +#[cfg(all(feature = "context", feature = "sanity"))] fn test_context_invalid_command() -> Result<(), Box> { println!("πŸ” Testing /context invalid command..."); @@ -167,7 +167,7 @@ fn test_context_invalid_command() -> Result<(), Box> { } #[test] -#[cfg(all(feature = "context", feature = "regression"))] +#[cfg(all(feature = "context", feature = "sanity"))] fn test_add_non_existing_file_context() -> Result<(), Box> { println!("πŸ” Testing /context add non-existing file command..."); @@ -198,7 +198,7 @@ fn test_add_non_existing_file_context() -> Result<(), Box } #[test] -#[cfg(all(feature = "context", feature = "regression"))] +#[cfg(all(feature = "context", feature = "sanity"))] fn test_context_remove_command_of_non_existent_file() -> Result<(), Box> { println!("πŸ” Testing /context remove non existing file command..."); @@ -226,7 +226,7 @@ fn test_context_remove_command_of_non_existent_file() -> Result<(), Box Result<(), Box> { println!("πŸ” Testing /context add command and /context remove command..."); @@ -300,7 +300,7 @@ fn test_add_remove_file_context() -> Result<(), Box> { } #[test] -#[cfg(all(feature = "context", feature = "regression"))] +#[cfg(all(feature = "context", feature = "sanity"))] fn test_add_glob_pattern_file_context()-> Result<(), Box> { println!("πŸ” Testing /context add *.py glob pattern command..."); @@ -382,7 +382,7 @@ fn test_add_glob_pattern_file_context()-> Result<(), Box> } #[test] -#[cfg(all(feature = "context", feature = "regression"))] +#[cfg(all(feature = "context", feature = "sanity"))] fn test_add_remove_multiple_file_context()-> Result<(), Box> { println!("πŸ” Testing /context add command and /context remove ..."); diff --git a/e2etests/tests/core_session/test_clear_command.rs b/e2etests/tests/core_session/test_clear_command.rs index 7a04a06d09..ec42b2834b 100644 --- a/e2etests/tests/core_session/test_clear_command.rs +++ b/e2etests/tests/core_session/test_clear_command.rs @@ -2,7 +2,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] -#[cfg(all(feature = "core_session", feature = "regression"))] +#[cfg(all(feature = "clear", feature = "sanity"))] fn test_clear_command() -> Result<(), Box> { println!("πŸ” Testing /clear command..."); diff --git a/e2etests/tests/core_session/test_help_command.rs b/e2etests/tests/core_session/test_help_command.rs index 2172afa233..e869f8a463 100644 --- a/e2etests/tests/core_session/test_help_command.rs +++ b/e2etests/tests/core_session/test_help_command.rs @@ -2,7 +2,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] -#[cfg(all(feature = "core_session", feature = "regression"))] +#[cfg(all(feature = "help", feature = "sanity"))] fn test_help_command() -> Result<(), Box> { println!("πŸ” Testing /help command..."); diff --git a/e2etests/tests/core_session/test_quit_command.rs b/e2etests/tests/core_session/test_quit_command.rs index fb183d7541..6f41a9331c 100644 --- a/e2etests/tests/core_session/test_quit_command.rs +++ b/e2etests/tests/core_session/test_quit_command.rs @@ -2,7 +2,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] -#[cfg(all(feature = "core_session", feature = "regression"))] +#[cfg(all(feature = "quit", feature = "sanity"))] fn test_quit_command() -> Result<(), Box> { println!("πŸ” Testing /quit command..."); diff --git a/e2etests/tests/core_session/test_tools_command.rs b/e2etests/tests/core_session/test_tools_command.rs index 0a9877d570..02a4611da8 100644 --- a/e2etests/tests/core_session/test_tools_command.rs +++ b/e2etests/tests/core_session/test_tools_command.rs @@ -22,7 +22,7 @@ const TEST_NAMES: &[&str] = &[ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] -#[cfg(all(any(feature = "tools", feature = "core_session"), feature = "regression"))] +#[cfg(all(feature = "tools", feature = "sanity"))] fn test_tools_command() -> Result<(), Box> { println!("πŸ” Testing /tools command..."); @@ -77,7 +77,7 @@ fn test_tools_command() -> Result<(), Box> { } #[test] -#[cfg(all(any(feature = "tools", feature = "core_session"), feature = "regression"))] +#[cfg(all(feature = "tools", feature = "sanity"))] fn test_tools_help_command() -> Result<(), Box> { println!("πŸ” Testing /tools --help command..."); @@ -123,7 +123,7 @@ fn test_tools_help_command() -> Result<(), Box> { } #[test] -#[cfg(all(any(feature = "tools", feature = "core_session"), feature = "regression"))] +#[cfg(all(feature = "tools", feature = "sanity"))] fn test_tools_trust_all_command() -> Result<(), Box> { println!("πŸ” Testing /tools trust-all command..."); @@ -203,7 +203,7 @@ fn test_tools_trust_all_command() -> Result<(), Box> { } #[test] -#[cfg(all(any(feature = "tools", feature = "core_session"), feature = "regression"))] +#[cfg(all(feature = "tools", feature = "sanity"))] fn test_tools_trust_all_help_command() -> Result<(), Box> { println!("πŸ” Testing /tools trust-all --help command..."); @@ -239,7 +239,7 @@ fn test_tools_trust_all_help_command() -> Result<(), Box> } #[test] -#[cfg(all(any(feature = "tools", feature = "core_session"), feature = "regression"))] +#[cfg(all(feature = "tools", feature = "sanity"))] fn test_tools_reset_help_command() -> Result<(), Box> { println!("πŸ” Testing /tools reset --help command..."); @@ -274,7 +274,7 @@ fn test_tools_reset_help_command() -> Result<(), Box> { } #[test] -#[cfg(all(any(feature = "tools", feature = "core_session"), feature = "regression"))] +#[cfg(all(feature = "tools", feature = "sanity"))] fn test_tools_trust_command() -> Result<(), Box> { println!("πŸ” Testing /tools trust command..."); @@ -352,7 +352,7 @@ fn test_tools_trust_command() -> Result<(), Box> { } #[test] -#[cfg(all(any(feature = "tools", feature = "core_session"), feature = "regression"))] +#[cfg(all(feature = "tools", feature = "sanity"))] fn test_tools_trust_help_command() -> Result<(), Box> { println!("πŸ” Testing /tools trust --help command..."); @@ -391,7 +391,7 @@ fn test_tools_trust_help_command() -> Result<(), Box> { } #[test] -#[cfg(all(any(feature = "tools", feature = "core_session"), feature = "regression"))] +#[cfg(all(feature = "tools", feature = "sanity"))] fn test_tools_untrust_help_command() -> Result<(), Box> { println!("πŸ” Testing /tools untrust --help command..."); @@ -430,7 +430,7 @@ fn test_tools_untrust_help_command() -> Result<(), Box> { } #[test] -#[cfg(all(any(feature = "tools", feature = "core_session"), feature = "regression"))] +#[cfg(all(feature = "tools", feature = "sanity"))] fn test_tools_schema_help_command() -> Result<(), Box> { println!("πŸ” Testing /tools schema --help command..."); diff --git a/e2etests/tests/integration/test_editor_help_command.rs b/e2etests/tests/integration/test_editor_help_command.rs index 8445196013..00ac947948 100644 --- a/e2etests/tests/integration/test_editor_help_command.rs +++ b/e2etests/tests/integration/test_editor_help_command.rs @@ -16,7 +16,7 @@ const TEST_NAMES: &[&str] = &[ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] -#[cfg(all(any(feature = "editor", feature = "integration"), feature = "regression"))] +#[cfg(all(feature = "editor", feature = "sanity"))] fn test_editor_help_command() -> Result<(), Box> { println!("πŸ” Testing /editor --help command..."); @@ -59,7 +59,7 @@ fn test_editor_help_command() -> Result<(), Box> { } #[test] -#[cfg(all(any(feature = "editor", feature = "integration"), feature = "regression"))] +#[cfg(all(feature = "editor", feature = "sanity"))] fn test_help_editor_command() -> Result<(), Box> { println!("πŸ” Testing /help editor command..."); diff --git a/e2etests/tests/integration/test_hooks_command.rs b/e2etests/tests/integration/test_hooks_command.rs index f3ec709003..488a237477 100644 --- a/e2etests/tests/integration/test_hooks_command.rs +++ b/e2etests/tests/integration/test_hooks_command.rs @@ -16,7 +16,7 @@ const TEST_NAMES: &[&str] = &[ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] -#[cfg(all(any(feature = "hooks", feature = "integration"), feature = "regression"))] +#[cfg(all(feature = "hooks", feature = "sanity"))] fn test_hooks_command() -> Result<(), Box> { println!("πŸ” Testing /hooks command..."); @@ -46,7 +46,7 @@ fn test_hooks_command() -> Result<(), Box> { } #[test] -#[cfg(all(any(feature = "hooks", feature = "integration"), feature = "regression"))] +#[cfg(all(feature = "hooks", feature = "sanity"))] fn test_hooks_help_command() -> Result<(), Box> { println!("πŸ” Testing /hooks --help command..."); diff --git a/e2etests/tests/integration/test_issue_command.rs b/e2etests/tests/integration/test_issue_command.rs index 81414d8078..927b92711f 100644 --- a/e2etests/tests/integration/test_issue_command.rs +++ b/e2etests/tests/integration/test_issue_command.rs @@ -18,7 +18,7 @@ const TEST_NAMES: &[&str] = &[ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] -#[cfg(all(any(feature = "issue_reporting", feature = "integration"), feature = "regression"))] +#[cfg(all(feature = "issue_reporting", feature = "sanity"))] fn test_issue_command() -> Result<(), Box> { println!("πŸ” Testing /issue command with bug report..."); @@ -48,7 +48,7 @@ fn test_issue_command() -> Result<(), Box> { } #[test] -#[cfg(all(any(feature = "issue_reporting", feature = "integration"), feature = "regression"))] +#[cfg(all(feature = "issue_reporting", feature = "sanity"))] fn test_issue_force_command() -> Result<(), Box> { println!("πŸ” Testing /issue --force command with critical bug..."); @@ -109,7 +109,7 @@ fn test_issue_f_command() -> Result<(), Box> { #[test] -#[cfg(all(any(feature = "issue_reporting", feature = "integration"), feature = "regression"))] +#[cfg(all(feature = "issue_reporting", feature = "sanity"))] fn test_issue_help_command() -> Result<(), Box> { println!("πŸ” Testing /issue --help command..."); diff --git a/e2etests/tests/integration/test_subscribe_command.rs b/e2etests/tests/integration/test_subscribe_command.rs index b68a7f2abb..65557b269b 100644 --- a/e2etests/tests/integration/test_subscribe_command.rs +++ b/e2etests/tests/integration/test_subscribe_command.rs @@ -18,7 +18,7 @@ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] -#[cfg(all(any(feature = "subscribe", feature = "integration"), feature = "regression"))] +#[cfg(all(feature = "subscribe", feature = "sanity"))] fn test_subscribe_command() -> Result<(), Box> { println!("πŸ” Testing /subscribe command..."); @@ -78,7 +78,7 @@ fn test_subscribe_manage_command() -> Result<(), Box> { } #[test] -#[cfg(all(any(feature = "subscribe", feature = "integration"), feature = "regression"))] +#[cfg(all(feature = "subscribe", feature = "sanity"))] fn test_subscribe_help_command() -> Result<(), Box> { println!("πŸ” Testing /subscribe --help command..."); diff --git a/e2etests/tests/mcp/test_mcp_command.rs b/e2etests/tests/mcp/test_mcp_command.rs index 6175e55e41..3f8e40149f 100644 --- a/e2etests/tests/mcp/test_mcp_command.rs +++ b/e2etests/tests/mcp/test_mcp_command.rs @@ -22,7 +22,7 @@ const TEST_NAMES: &[&str] = &[ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] -#[cfg(all(feature = "mcp", feature = "regression"))] +#[cfg(all(feature = "mcp", feature = "sanity"))] fn test_mcp_help_command() -> Result<(), Box> { println!("πŸ” Testing /mcp --help command..."); @@ -65,7 +65,7 @@ fn test_mcp_help_command() -> Result<(), Box> { } #[test] -#[cfg(all(feature = "mcp", feature = "regression"))] +#[cfg(all(feature = "mcp", feature = "sanity"))] fn test_mcp_loading_command() -> Result<(), Box> { println!("πŸ” Testing MCP loading..."); @@ -105,7 +105,7 @@ fn test_mcp_loading_command() -> Result<(), Box> { } #[test] -#[cfg(all(feature = "mcp", feature = "regression"))] +#[cfg(all(feature = "mcp", feature = "sanity"))] fn test_mcp_remove_help_command() -> Result<(), Box> { println!("πŸ” Testing q mcp remove --help command..."); @@ -152,7 +152,7 @@ fn test_mcp_remove_help_command() -> Result<(), Box> { } #[test] -#[cfg(all(feature = "mcp", feature = "regression"))] +#[cfg(all(feature = "mcp", feature = "sanity"))] fn test_q_mcp_add_help_command() -> Result<(), Box> { println!("πŸ” Testing q mcp add --help command..."); @@ -210,7 +210,7 @@ fn test_q_mcp_add_help_command() -> Result<(), Box> { } #[test] -#[cfg(all(feature = "mcp", feature = "regression"))] +#[cfg(all(feature = "mcp", feature = "sanity"))] fn test_q_mcp_help_command() -> Result<(), Box> { println!("πŸ” Testing q mcp --help command..."); @@ -267,7 +267,7 @@ fn test_q_mcp_help_command() -> Result<(), Box> { } #[test] -#[cfg(all(feature = "mcp", feature = "regression"))] +#[cfg(all(feature = "mcp", feature = "sanity"))] fn test_q_mcp_import_help_command() -> Result<(), Box> { println!("πŸ” Testing q mcp import --help command..."); @@ -329,7 +329,7 @@ fn test_q_mcp_import_help_command() -> Result<(), Box> { } #[test] -#[cfg(all(feature = "mcp", feature = "regression"))] +#[cfg(all(feature = "mcp", feature = "sanity"))] fn test_q_mcp_list_command() -> Result<(), Box> { println!("πŸ” Testing q mcp list command..."); @@ -372,7 +372,7 @@ fn test_q_mcp_list_command() -> Result<(), Box> { } #[test] -#[cfg(all(feature = "mcp", feature = "regression"))] +#[cfg(all(feature = "mcp", feature = "sanity"))] fn test_q_mcp_list_help_command() -> Result<(), Box> { println!("πŸ” Testing q mcp list --help command..."); @@ -422,7 +422,7 @@ fn test_q_mcp_list_help_command() -> Result<(), Box> { } #[test] -#[cfg(all(feature = "mcp", feature = "regression"))] +#[cfg(all(feature = "mcp", feature = "sanity"))] fn test_q_mcp_status_help_command() -> Result<(), Box> { println!("πŸ” Testing q mcp status --help command..."); diff --git a/e2etests/tests/model/test_model_dynamic_command.rs b/e2etests/tests/model/test_model_dynamic_command.rs index 7cf9b528f6..0eb187b478 100644 --- a/e2etests/tests/model/test_model_dynamic_command.rs +++ b/e2etests/tests/model/test_model_dynamic_command.rs @@ -16,7 +16,7 @@ const TEST_NAMES: &[&str] = &[ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] -#[cfg(all(feature = "model", feature = "regression"))] +#[cfg(all(feature = "model", feature = "sanity"))] fn test_model_dynamic_command() -> Result<(), Box> { println!("πŸ” Testing /model command with dynamic selection..."); @@ -135,7 +135,7 @@ fn test_model_dynamic_command() -> Result<(), Box> { } #[test] -#[cfg(all(feature = "model", feature = "regression"))] +#[cfg(all(feature = "model", feature = "sanity"))] fn test_model_help_command() -> Result<(), Box> { println!("πŸ” Testing /model --help command..."); diff --git a/e2etests/tests/save_load/test_save_load_command.rs b/e2etests/tests/save_load/test_save_load_command.rs index 689dd38326..7a721c6992 100644 --- a/e2etests/tests/save_load/test_save_load_command.rs +++ b/e2etests/tests/save_load/test_save_load_command.rs @@ -37,7 +37,7 @@ impl<'a> Drop for FileCleanup<'a> { } #[test] -#[cfg(all(feature = "save_load", feature = "regression"))] +#[cfg(all(feature = "save_load", feature = "sanity"))] fn test_save_command() -> Result<(), Box> { println!("πŸ” Testing /save command..."); @@ -82,7 +82,7 @@ fn test_save_command() -> Result<(), Box> { } #[test] -#[cfg(all(feature = "save_load", feature = "regression"))] +#[cfg(all(feature = "save_load", feature = "sanity"))] fn test_save_command_argument_validation() -> Result<(), Box> { println!("πŸ” Testing /save command..."); @@ -120,7 +120,7 @@ fn test_save_command_argument_validation() -> Result<(), Box Result<(), Box> { println!("πŸ” Testing /save --help command..."); @@ -162,7 +162,7 @@ fn test_save_help_command() -> Result<(), Box> { } #[test] -#[cfg(all(feature = "save_load", feature = "regression"))] +#[cfg(all(feature = "save_load", feature = "sanity"))] fn test_save_h_flag_command() -> Result<(), Box> { println!("πŸ” Testing /save -h command..."); @@ -203,7 +203,7 @@ fn test_save_h_flag_command() -> Result<(), Box> { } #[test] -#[cfg(all(feature = "save_load", feature = "regression"))] +#[cfg(all(feature = "save_load", feature = "sanity"))] fn test_save_force_command() -> Result<(), Box> { println!("πŸ” Testing /save --force command..."); @@ -261,7 +261,7 @@ fn test_save_force_command() -> Result<(), Box> { } #[test] -#[cfg(all(feature = "save_load", feature = "regression"))] +#[cfg(all(feature = "save_load", feature = "sanity"))] fn test_save_f_flag_command() -> Result<(), Box> { println!("πŸ” Testing /save -f command..."); @@ -319,7 +319,7 @@ fn test_save_f_flag_command() -> Result<(), Box> { } #[test] -#[cfg(all(feature = "save_load", feature = "regression"))] +#[cfg(all(feature = "save_load", feature = "sanity"))] fn test_load_help_command() -> Result<(), Box> { println!("πŸ” Testing /load --help command..."); @@ -360,7 +360,7 @@ fn test_load_help_command() -> Result<(), Box> { } #[test] -#[cfg(all(feature = "save_load", feature = "regression"))] +#[cfg(all(feature = "save_load", feature = "sanity"))] fn test_load_h_flag_command() -> Result<(), Box> { println!("πŸ” Testing /load -h command..."); @@ -401,7 +401,7 @@ fn test_load_h_flag_command() -> Result<(), Box> { } #[test] -#[cfg(all(feature = "save_load", feature = "regression"))] +#[cfg(all(feature = "save_load", feature = "sanity"))] fn test_load_command() -> Result<(), Box> { println!("πŸ” Testing /load command..."); @@ -455,7 +455,7 @@ fn test_load_command() -> Result<(), Box> { } #[test] -#[cfg(all(feature = "save_load", feature = "regression"))] +#[cfg(all(feature = "save_load", feature = "sanity"))] fn test_load_command_argument_validation() -> Result<(), Box> { println!("πŸ” Testing /load command..."); diff --git a/e2etests/tests/session_mgmt/test_compact_command.rs b/e2etests/tests/session_mgmt/test_compact_command.rs index f7a4039fa1..aa3f20ea93 100644 --- a/e2etests/tests/session_mgmt/test_compact_command.rs +++ b/e2etests/tests/session_mgmt/test_compact_command.rs @@ -19,7 +19,7 @@ const TEST_NAMES: &[&str] = &[ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] -#[cfg(all(any(feature = "compact", feature = "session_mgmt"), feature = "regression"))] +#[cfg(all(feature = "compact", feature = "sanity"))] fn test_compact_command() -> Result<(), Box> { println!("πŸ” Testing /compact command..."); @@ -61,148 +61,7 @@ fn test_compact_command() -> Result<(), Box> { } #[test] -#[cfg(all(any(feature = "compact", feature = "session_mgmt"), feature = "regression"))] -fn test_compact_truncate_true_command() -> Result<(), Box> { - println!("πŸ” Testing /compact --truncate-large-messages true command..."); - - let session = get_chat_session(); - let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); - - let response = chat.execute_command("What is AWS?")?; - - println!("πŸ“ AI response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - let response = chat.execute_command("/compact --truncate-large-messages true")?; - - println!("πŸ“ Compact response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify truncation - assert!(response.to_lowercase().contains("truncating"), "Missing truncation messsage"); - println!("βœ… Truncation of large messages verified!"); - - // Verify compact response - either success or too short - if response.contains("history") && response.contains("compacted") && response.contains("successfully") { - println!("βœ… Found compact success message"); - } else if response.contains("Conversation") && response.contains("short") { - println!("βœ… Found conversation too short message"); - } else { - panic!("Missing expected compact response"); - } - - println!("βœ… All compact content verified!"); - - // Release the lock before cleanup - drop(chat); - - // Cleanup only if this is the last test - cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; - - Ok(()) -} - -#[test] -#[cfg(all(any(feature = "compact", feature = "session_mgmt"), feature = "regression"))] -fn test_compact_truncate_false_command() -> Result<(), Box> { - println!("πŸ” Testing /compact --truncate-large-messages false command..."); - - let session = get_chat_session(); - let mut chat = session.lock().unwrap(); - - let response = chat.execute_command("What is AWS?")?; - - println!("πŸ“ AI response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - let response = chat.execute_command("/compact --truncate-large-messages false")?; - - println!("πŸ“ Compact response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify compact response - either success or too short - if response.contains("history") && response.contains("compacted") && response.contains("successfully") { - println!("βœ… Found compact success message"); - } else if response.contains("Conversation") && response.contains("short") { - println!("βœ… Found conversation too short message"); - } else { - panic!("Missing expected compact response"); - } - - println!("βœ… All compact content verified!"); - - // Release the lock before cleanup - drop(chat); - - // Cleanup only if this is the last test - cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; - - Ok(()) -} - - -#[test] -#[cfg(all(any(feature = "compact", feature = "session_mgmt"), feature = "regression"))] -fn test_show_summary() -> Result<(), Box> { - println!("πŸ” Testing /compact --show-summary command..."); - - let session = get_chat_session(); - let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); - - let response = chat.execute_command("What is AWS?")?; - - println!("πŸ“ AI response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - let response = chat.execute_command("What is DL?")?; - - println!("πŸ“ AI response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - let response = chat.execute_command("/compact --show-summary")?; - - println!("πŸ“ Compact response: {} bytes", response.len()); - println!("πŸ“ FULL OUTPUT:"); - println!("{}", response); - println!("πŸ“ END OUTPUT"); - - // Verify compact response - either success or too short - if response.contains("history") && response.contains("compacted") && response.contains("successfully") { - println!("βœ… Found compact success message"); - } else if response.contains("Conversation") && response.contains("short") { - println!("βœ… Found conversation too short message"); - } else { - panic!("Missing expected compact response"); - } - - // Verify compact sumary response - assert!(response.to_lowercase().contains("conversation") && response.to_lowercase().contains("summary"), "Missing Summary section"); - assert!(response.contains("AWS") && (response.contains("DL") || response.to_lowercase().contains("deep learning")) , "Missing summary of our prompts"); - println!("βœ… All compact content verified!"); - - // Release the lock before cleanup - drop(chat); - - // Cleanup only if this is the last test - cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; - - Ok(()) -} - -#[test] -#[cfg(all(any(feature = "compact", feature = "session_mgmt"), feature = "regression"))] +#[cfg(all(feature = "compact", feature = "sanity"))] fn test_compact_help_command() -> Result<(), Box> { println!("πŸ” Testing /compact --help command..."); diff --git a/e2etests/tests/session_mgmt/test_usage_command.rs b/e2etests/tests/session_mgmt/test_usage_command.rs index c7520e5d59..bee74be719 100644 --- a/e2etests/tests/session_mgmt/test_usage_command.rs +++ b/e2etests/tests/session_mgmt/test_usage_command.rs @@ -16,7 +16,7 @@ const TEST_NAMES: &[&str] = &[ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] -#[cfg(all(any(feature = "usage", feature = "session_mgmt"), feature = "regression"))] +#[cfg(all(feature = "usage", feature = "sanity"))] fn test_usage_command() -> Result<(), Box> { println!("πŸ” Testing /usage command..."); @@ -75,7 +75,7 @@ fn test_usage_command() -> Result<(), Box> { } #[test] -#[cfg(all(any(feature = "usage", feature = "session_mgmt"), feature = "regression"))] +#[cfg(all(feature = "usage", feature = "sanity"))] fn test_usage_help_command() -> Result<(), Box> { println!("πŸ” Testing /usage --help command..."); From 6931157448095a9ac1a2d87ebd1c0e668a47fd29 Mon Sep 17 00:00:00 2001 From: "Shreya [C] Bhagat" Date: Mon, 25 Aug 2025 19:23:20 +0530 Subject: [PATCH 33/77] Add new tests cases test_add_and_remove_mcp_command and test_q_mcp_status_command --- e2etests/tests/mcp/test_mcp_command.rs | 187 ++++++++++++++++++++++++- 1 file changed, 186 insertions(+), 1 deletion(-) diff --git a/e2etests/tests/mcp/test_mcp_command.rs b/e2etests/tests/mcp/test_mcp_command.rs index 3f8e40149f..2d73553205 100644 --- a/e2etests/tests/mcp/test_mcp_command.rs +++ b/e2etests/tests/mcp/test_mcp_command.rs @@ -16,7 +16,9 @@ const TEST_NAMES: &[&str] = &[ "test_q_mcp_import_help_command", "test_q_mcp_list_command", "test_q_mcp_list_help_command", - "test_q_mcp_status_help_command" + "test_q_mcp_status_help_command", + "test_add_and_remove_mcp_command", + "test_q_mcp_status_command" ]; #[allow(dead_code)] const TOTAL_TESTS: usize = TEST_NAMES.len(); @@ -476,3 +478,186 @@ fn test_q_mcp_status_help_command() -> Result<(), Box> { Ok(()) } + +#[test] +#[cfg(all(feature = "mcp", feature = "sanity"))] +fn test_add_and_remove_mcp_command() -> Result<(), Box> { + println!("πŸ” Testing q mcp add command..."); + + // First install uv dependency before starting Q Chat + println!("πŸ” Installing uv dependency..."); + + std::process::Command::new("pip3") + .args(["install", "uv", "--break-system-packages"]) + .output() + .expect("Failed to install uv"); + + println!("βœ… uv dependency installed"); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + // Execute mcp add command + println!("πŸ” Executing command: 'q mcp add --name aws-documentation --command uvx --args awslabs.aws-documentation-mcp-server@latest'"); + let response = chat.execute_command("q mcp add --name aws-documentation --command uvx --args awslabs.aws-documentation-mcp-server@latest")?; + + println!("πŸ“ Response: {} bytes", response.len()); + println!("πŸ“ RESPONSE:"); + println!("{}", response); + println!("πŸ“ END RESPONSE"); + + // Verify tool execution details + assert!(response.contains("q mcp add --name aws-documentation --command uvx --args awslabs.aws-documentation-mcp-server@latest"), "Missing full command"); + assert!(response.contains("Using tool"), "Missing tool execution indicator"); + assert!(response.contains("Allow this action?"), "Missing permission prompt"); + println!("βœ… Found tool execution permission prompt"); + + // Allow the tool execution + let allow_response = chat.execute_command("y")?; + println!("πŸ“ Allow response: {} bytes", allow_response.len()); + println!("πŸ“ ALLOW RESPONSE:"); + println!("{}", allow_response); + println!("πŸ“ END ALLOW RESPONSE"); + + // Verify successful addition + assert!(allow_response.contains("Added") && allow_response.contains("'aws-documentation'"), "Missing success message"); + assert!(allow_response.contains("/Users/") && allow_response.contains("/.aws/amazonq/mcp.json"), "Missing config file path"); + println!("βœ… Found successful addition message"); + + // Now test removing the MCP server + println!("πŸ” Executing remove command: 'q mcp remove --name aws-documentation'"); + let remove_response = chat.execute_command("q mcp remove --name aws-documentation")?; + println!("πŸ“ Remove response: {} bytes", remove_response.len()); + println!("πŸ“ REMOVE RESPONSE:"); + println!("{}", remove_response); + println!("πŸ“ END REMOVE RESPONSE"); + + // Verify remove tool execution details + assert!(response.contains("Using tool"), "Missing using tool indicator"); + assert!(remove_response.contains("q mcp remove --name aws-documentation"), "Missing full remove command"); + assert!(remove_response.contains("Allow this action?"), "Missing remove permission prompt"); + println!("βœ… Found remove tool execution permission prompt"); + + // Allow the remove tool execution + let remove_allow_response = chat.execute_command("y")?; + println!("πŸ“ Remove allow response: {} bytes", remove_allow_response.len()); + println!("πŸ“ REMOVE ALLOW RESPONSE:"); + println!("{}", remove_allow_response); + println!("πŸ“ END REMOVE ALLOW RESPONSE"); + + // Verify successful removal + assert!(remove_allow_response.contains("Removed") && remove_allow_response.contains("'aws-documentation'"), "Missing removal success message"); + assert!(remove_allow_response.contains("/Users/") && remove_allow_response.contains("/.aws/amazonq/mcp.json"), "Missing config file path in removal"); + println!("βœ… Found successful removal message"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + Ok(()) +} + +#[test] +#[cfg(all(feature = "mcp", feature = "sanity"))] +fn test_q_mcp_status_command() -> Result<(), Box> { + println!("πŸ” Testing q mcp status --name command..."); + + // First install uv dependency before starting Q Chat + println!("πŸ” Installing uv dependency..."); + + std::process::Command::new("pip3") + .args(["install", "uv", "--break-system-packages"]) + .output() + .expect("Failed to install uv"); + + println!("βœ… uv dependency installed"); + + let session = get_chat_session(); + let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); + + // Execute mcp add command + println!("πŸ” Executing command: 'q mcp add --name aws-documentation --command uvx --args awslabs.aws-documentation-mcp-server@latest'"); + let response = chat.execute_command("q mcp add --name aws-documentation --command uvx --args awslabs.aws-documentation-mcp-server@latest")?; + + println!("πŸ“ Response: {} bytes", response.len()); + println!("πŸ“ RESPONSE:"); + println!("{}", response); + println!("πŸ“ END RESPONSE"); + + // Verify tool execution details + assert!(response.contains("q mcp add --name aws-documentation --command uvx --args awslabs.aws-documentation-mcp-server@latest"), "Missing full command"); + assert!(response.contains("Using tool"), "Missing tool execution indicator"); + println!("βœ… Found tool execution permission prompt"); + + // Allow the tool execution + let allow_response = chat.execute_command("y")?; + println!("πŸ“ Allow response: {} bytes", allow_response.len()); + println!("πŸ“ ALLOW RESPONSE:"); + println!("{}", allow_response); + println!("πŸ“ END ALLOW RESPONSE"); + + // Verify successful addition + assert!(allow_response.contains("Added") && allow_response.contains("'aws-documentation'"), "Missing success message"); + println!("βœ… Found successful addition message"); + + // Allow the tool execution + let response = chat.execute_command("q mcp status --name aws-documentation")?; + println!("πŸ“ Allow response: {} bytes", response.len()); + println!("πŸ“ ALLOW RESPONSE:"); + println!("{}", response); + println!("πŸ“ END ALLOW RESPONSE"); + + // Verify tool execution details + assert!(response.contains("q mcp status --name aws-documentation"), "Missing full command"); + assert!(response.contains("Using tool"), "Missing tool execution indicator"); + println!("βœ… Found tool execution permission prompt"); + + // Allow the tool execution + let show_response = chat.execute_command("y")?; + println!("πŸ“ Allow response: {} bytes", show_response.len()); + println!("πŸ“ ALLOW RESPONSE:"); + println!("{}", show_response); + println!("πŸ“ END ALLOW RESPONSE"); + + + // Verify successful status retrieval + assert!(show_response.contains("Scope"), "Missing Scope"); + assert!(show_response.contains("Agent"), "Missing Agent"); + assert!(show_response.contains("Command"), "Missing Command"); + assert!(show_response.contains("Disabled"), "Missing Disabled"); + assert!(show_response.contains("Env Vars"), "Missing Env Vars"); + + // Now test removing the MCP server + println!("πŸ” Executing remove command: 'q mcp remove --name aws-documentation'"); + let remove_response = chat.execute_command("q mcp remove --name aws-documentation")?; + println!("πŸ“ Remove response: {} bytes", remove_response.len()); + println!("πŸ“ REMOVE RESPONSE:"); + println!("{}", remove_response); + println!("πŸ“ END REMOVE RESPONSE"); + + // Verify remove tool execution details + assert!(response.contains("Using tool"), "Missing using tool indicator"); + assert!(remove_response.contains("q mcp remove --name aws-documentation"), "Missing full remove command"); + assert!(remove_response.contains("Allow this action?"), "Missing remove permission prompt"); + println!("βœ… Found remove tool execution permission prompt"); + + // Allow the remove tool execution + let remove_allow_response = chat.execute_command("y")?; + println!("πŸ“ Remove allow response: {} bytes", remove_allow_response.len()); + println!("πŸ“ REMOVE ALLOW RESPONSE:"); + println!("{}", remove_allow_response); + println!("πŸ“ END REMOVE ALLOW RESPONSE"); + + // Verify successful removal + assert!(remove_allow_response.contains("Removed") && remove_allow_response.contains("'aws-documentation'"), "Missing removal success message"); + assert!(remove_allow_response.contains("/Users/") && remove_allow_response.contains("/.aws/amazonq/mcp.json"), "Missing config file path in removal"); + println!("βœ… Found successful removal message"); + + // Release the lock before cleanup + drop(chat); + + // Cleanup only if this is the last test + cleanup_if_last_test(&TEST_COUNT, TOTAL_TESTS)?; + Ok(()) +} From 021762a10f5c52ceb06f18704328a6cfcfc292ac Mon Sep 17 00:00:00 2001 From: Abhishek Anne Date: Tue, 26 Aug 2025 08:57:37 +0530 Subject: [PATCH 34/77] added html template --- e2etests/html_template.html | 170 ++++++++++++++++++++++++++++++++++++ e2etests/run_tests.py | 162 +++++++++------------------------- 2 files changed, 212 insertions(+), 120 deletions(-) create mode 100644 e2etests/html_template.html diff --git a/e2etests/html_template.html b/e2etests/html_template.html new file mode 100644 index 0000000000..0f0672850c --- /dev/null +++ b/e2etests/html_template.html @@ -0,0 +1,170 @@ + + + + + + Q CLI Test Report + + + +
+
+

πŸ§ͺ Q CLI E2E Test Report

+

Generated: {timestamp}

+
+ +
+

πŸ“Š Overall Summary

+
+
+
+
+

{success_rate}%

+

Success Rate

+
+
+

{total_features}

+

Features Tested

+
+
+

{features_100_pass}

+

Features 100% Pass

+
+
+

{features_failed}

+

Features with Failures

+
+
+

{tests_passed}

+

Tests Passed

+
+
+

{tests_failed}

+

Tests Failed

+
+
+
+
+ +

Success Rate: {success_rate}%

+
+
+
+ + {test_suites_content} + +
+

πŸ’» System Information

+

Platform: {platform}

+

OS: {os} {os_version}

+

Q Binary: {q_binary_path}

+

Q Version: {q_version}

+
+
+ + + + \ No newline at end of file diff --git a/e2etests/run_tests.py b/e2etests/run_tests.py index 2cba625890..b86ebb5251 100755 --- a/e2etests/run_tests.py +++ b/e2etests/run_tests.py @@ -217,10 +217,15 @@ def generate_report(results, features, test_suites, binary_path="q"): return report def generate_html_report(json_filename): - """Generate HTML report from JSON file""" + """Generate HTML report from JSON file using template""" with open(json_filename, 'r') as f: report = json.load(f) + # Load HTML template + template_path = Path(__file__).parent / 'html_template.html' + with open(template_path, 'r') as f: + html_template = f.read() + # Generate HTML filename html_filename = json_filename.replace('.json', '.html') @@ -232,79 +237,8 @@ def generate_html_report(json_filename): # Get test suites from detailed results test_suites = list(set(result["test_suite"] for result in report["detailed_results"])) - html_content = f""" - - - - - - Q CLI Test Report - - - -
-
-

πŸ§ͺ Q CLI E2E Test Report

-

Generated: {report['timestamp']}

-
-

πŸ’» System Information

-

Platform: {report['system_info']['platform']}

-

OS: {report['system_info']['os']} {report['system_info']['os_version']}

-

Q Binary: {report['system_info']['q_binary_path']}

-

Q Version: {report['system_info']['q_version']}

-
-
- -
-

πŸ“Š Overall Summary

-
-
-

{report['summary']['success_rate']}%

-

Success Rate

-
-
-

{total_features}

-

Features Tested

-
-
-

{features_100_pass}

-

Features 100% Pass

-
-
-

{features_failed}

-

Features with Failures

-
-
-

{report['summary']['passed']}

-

Tests Passed

-
-
-

{report['summary']['failed']}

-

Tests Failed

-
-
-
-""" - - # Add test suite sections + # Generate test suites content + test_suites_content = "" for suite in test_suites: suite_features = {} for result in report["detailed_results"]: @@ -317,69 +251,57 @@ def generate_html_report(json_filename): suite_failed = sum(stats["failed"] for stats in suite_features.values()) suite_rate = round((suite_passed / (suite_passed + suite_failed) * 100) if (suite_passed + suite_failed) > 0 else 0, 2) - html_content += f""" - -
-""" + test_suites_content += f'
' # Add features for this suite for feature_name, feature_stats in suite_features.items(): feature_rate = round((feature_stats["passed"] / (feature_stats["passed"] + feature_stats["failed"]) * 100) if (feature_stats["passed"] + feature_stats["failed"]) > 0 else 0, 2) - html_content += f""" - -
-""" + test_suites_content += f'
' # Add individual tests for test in feature_stats["individual_tests"]: test_class = "test-passed" if test["status"] == "passed" else "test-failed" status_icon = "βœ…" if test["status"] == "passed" else "❌" - html_content += f""" -
-

{status_icon} {test['name']}

-

Status: {test['status'].upper()}

-
-""" + # Convert test name to readable format + test_name = test['name'] + if '::' in test_name: + readable_name = test_name.split('::')[-1] + if readable_name.startswith('test_'): + readable_name = readable_name[5:] + readable_name = ' '.join(word.capitalize() for word in readable_name.split('_')) + else: + readable_name = test_name + + test_suites_content += f'

{status_icon} {readable_name}

Status: {test["status"].upper()}

' # Add stdout/stderr for this feature for result in report["detailed_results"]: if result["feature"] == feature_name and result["test_suite"] == suite: - html_content += f""" - -
-

Command: {result['command']}

-

Duration: {result['duration']}s

-
{result['stdout']}
- {f'
STDERR:
{result["stderr"]}
' if result['stderr'] else ''} -
-""" + stderr_content = f'
STDERR:
{result["stderr"]}
' if result['stderr'] else '' + test_suites_content += f'

Command: {result["command"]}

Duration: {result["duration"]}s

{result["stdout"]}
{stderr_content}
' - html_content += "
" # Close feature content + test_suites_content += "
" # Close feature content - html_content += "
" # Close suite content - - html_content += """ -
- - - - -""" + test_suites_content += "
" # Close suite content + + # Fill template with data + html_content = html_template.format( + timestamp=report['timestamp'], + success_rate=report['summary']['success_rate'], + total_features=total_features, + features_100_pass=features_100_pass, + features_failed=features_failed, + tests_passed=report['summary']['passed'], + tests_failed=report['summary']['failed'], + test_suites_content=test_suites_content, + platform=report['system_info']['platform'], + os=report['system_info']['os'], + os_version=report['system_info']['os_version'], + q_binary_path=report['system_info']['q_binary_path'], + q_version=report['system_info']['q_version'] + ) with open(html_filename, 'w') as f: f.write(html_content) From 0c281dce25796e18fba172135cd6bfdeb3965bf4 Mon Sep 17 00:00:00 2001 From: Abhishek Anne Date: Tue, 26 Aug 2025 17:31:02 +0530 Subject: [PATCH 35/77] Test wise console output --- e2etests/run_tests.py | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/e2etests/run_tests.py b/e2etests/run_tests.py index b86ebb5251..35cdd476fd 100755 --- a/e2etests/run_tests.py +++ b/e2etests/run_tests.py @@ -46,17 +46,30 @@ def parse_features(): DEFAULT_TESTSUITE = "sanity" def parse_test_results(stdout): - """Parse individual test results from cargo output""" + """Parse individual test results from cargo output with their outputs""" tests = [] lines = stdout.split('\n') + current_output = [] for line in lines: - if ' ... ok' in line and line.startswith('test '): - test_name = line.split(' ... ok')[0].replace('test ', '').strip() - tests.append({"name": test_name, "status": "passed"}) - elif ' ... FAILED' in line and line.startswith('test '): - test_name = line.split(' ... FAILED')[0].replace('test ', '').strip() - tests.append({"name": test_name, "status": "failed"}) + if line.startswith('test ') and (' ... ok' in line or ' ... FAILED' in line): + # Found test result - output above belongs to this test + if ' ... ok' in line: + test_name = line.split(' ... ok')[0].replace('test ', '').strip() + status = "passed" + elif ' ... FAILED' in line: + test_name = line.split(' ... FAILED')[0].replace('test ', '').strip() + status = "failed" + + tests.append({ + "name": test_name, + "status": status, + "output": '\n'.join(current_output + [line]) + }) + current_output = [] + else: + # Collect output lines + current_output.append(line) return tests @@ -274,13 +287,14 @@ def generate_html_report(json_filename): else: readable_name = test_name - test_suites_content += f'

{status_icon} {readable_name}

Status: {test["status"].upper()}

' + test_output = test.get('output', 'No output captured') + test_suites_content += f'

{status_icon} {readable_name}

Status: {test["status"].upper()}

{test_output}
' # Add stdout/stderr for this feature for result in report["detailed_results"]: if result["feature"] == feature_name and result["test_suite"] == suite: stderr_content = f'
STDERR:
{result["stderr"]}
' if result['stderr'] else '' - test_suites_content += f'

Command: {result["command"]}

Duration: {result["duration"]}s

{result["stdout"]}
{stderr_content}
' + test_suites_content += f'

Command: {result["command"]}

Duration: {result["duration"]}s

{result["stdout"]}
{stderr_content}
' test_suites_content += "" # Close feature content From 1ca00cd1c38491e3690bc224e1f2aaf028359765 Mon Sep 17 00:00:00 2001 From: Abhishek Anne Date: Tue, 26 Aug 2025 17:53:16 +0530 Subject: [PATCH 36/77] Test wise console output for single thread --- e2etests/run_tests.py | 81 ++++++++++++++++++++++++++++++------------- 1 file changed, 56 insertions(+), 25 deletions(-) diff --git a/e2etests/run_tests.py b/e2etests/run_tests.py index 35cdd476fd..293538e72b 100755 --- a/e2etests/run_tests.py +++ b/e2etests/run_tests.py @@ -49,34 +49,53 @@ def parse_test_results(stdout): """Parse individual test results from cargo output with their outputs""" tests = [] lines = stdout.split('\n') - current_output = [] - - for line in lines: - if line.startswith('test ') and (' ... ok' in line or ' ... FAILED' in line): - # Found test result - output above belongs to this test - if ' ... ok' in line: - test_name = line.split(' ... ok')[0].replace('test ', '').strip() - status = "passed" - elif ' ... FAILED' in line: - test_name = line.split(' ... FAILED')[0].replace('test ', '').strip() - status = "failed" + + # Look for test lines followed by result lines + for i, line in enumerate(lines): + clean_line = line.strip() + + # Look for test declaration lines + if clean_line.startswith('test ') and ' ... ' in clean_line: + # Extract test name (everything between 'test ' and ' ... ') + test_name = clean_line.split(' ... ')[0].replace('test ', '').strip() - tests.append({ - "name": test_name, - "status": status, - "output": '\n'.join(current_output + [line]) - }) - current_output = [] - else: - # Collect output lines - current_output.append(line) + # Look ahead for the result (ok/FAILED) in the next few lines + status = None + result_line_idx = None + + # Check next 50 lines for result (increased from 20) + for j in range(i + 1, min(i + 51, len(lines))): + result_line = lines[j].strip() + if result_line == 'ok': + status = "passed" + result_line_idx = j + break + elif result_line == 'FAILED': + status = "failed" + result_line_idx = j + break + + # If we found a result, add the test + if status and test_name: + # Collect output between test declaration and result + output_lines = [clean_line] + if result_line_idx: + for k in range(i + 1, result_line_idx + 1): + if k < len(lines): + output_lines.append(lines[k].strip()) + + tests.append({ + "name": test_name, + "status": status, + "output": '\n'.join(output_lines[:30]) # Limit output size + }) return tests def run_single_cargo_test(feature, test_suite, binary_path="q", quiet=False): """Run cargo test for a single feature with test suite""" feature_str = f"{feature},{test_suite}" - cmd = ["cargo", "test", "--tests", "--features", feature_str, "--", "--nocapture"] + cmd = ["cargo", "test", "--tests", "--features", feature_str, "--", "--nocapture", "--test-threads=1"] if not quiet: print(f"πŸ”„ Running: {feature} with {test_suite}") @@ -96,9 +115,18 @@ def run_single_cargo_test(feature, test_suite, binary_path="q", quiet=False): # Show individual test results print(f"\nπŸ“‹ Individual Test Results for {feature}:") - for test in individual_tests: - status_icon = "βœ…" if test["status"] == "passed" else "❌" - print(f" {status_icon} {test['name']} - {test['status']}") + if individual_tests: + for test in individual_tests: + status_icon = "βœ…" if test["status"] == "passed" else "❌" + print(f" {status_icon} {test['name']} - {test['status']}") + else: + print(f" ⚠️ No individual tests detected (parsing may have failed)") + print(f" Debug: Looking for 'test ' lines in output...") + lines = result.stdout.split('\n') + test_lines = [line for line in lines if 'test ' in line and ' ... ' in line] + print(f" Found {len(test_lines)} potential test lines:") + for line in test_lines[:3]: # Show first 3 + print(f" {repr(line.strip())}") return { "feature": feature, @@ -139,7 +167,10 @@ def run_tests_with_suites(features, test_suites, binary_path="q", quiet=False): failed_count = sum(1 for t in individual_tests if t["status"] == "failed") status = "βœ…" if result["success"] else "❌" - print(f"{status} {feature} ({test_suite}) - {result['duration']}s - {passed_count} passed, {failed_count} failed") + if individual_tests: + print(f"{status} {feature} ({test_suite}) - {result['duration']}s - {passed_count} passed, {failed_count} failed") + else: + print(f"{status} {feature} ({test_suite}) - {result['duration']}s - No individual tests detected") return results From 4018f0640298e20bc006329bf6bf8a87906f7068 Mon Sep 17 00:00:00 2001 From: Abhishek Anne Date: Tue, 26 Aug 2025 18:02:21 +0530 Subject: [PATCH 37/77] Move reports to reports folder --- e2etests/run_tests.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/e2etests/run_tests.py b/e2etests/run_tests.py index 293538e72b..544011781c 100755 --- a/e2etests/run_tests.py +++ b/e2etests/run_tests.py @@ -201,6 +201,10 @@ def generate_report(results, features, test_suites, binary_path="q"): timestamp = datetime.now().isoformat() system_info = get_system_info(binary_path) + # Create reports directory if it doesn't exist + reports_dir = Path("reports") + reports_dir.mkdir(exist_ok=True) + # Calculate summary stats from individual tests total_individual_tests = 0 passed_individual_tests = 0 @@ -251,13 +255,13 @@ def generate_report(results, features, test_suites, binary_path="q"): features_str = "-".join(features[:3]) + ("_more" if len(features) > 3 else "") suites_str = "-".join(test_suites) datetime_str = datetime.now().strftime("%m%d%y%H%M%S") - filename = f"qcli_test_summary_{features_str}_{suites_str}_{datetime_str}.json" + filename = reports_dir / f"qcli_test_summary_{features_str}_{suites_str}_{datetime_str}.json" # Save JSON report with open(filename, "w") as f: json.dump(report, f, indent=2) - report["filename"] = filename + report["filename"] = str(filename) return report def generate_html_report(json_filename): @@ -270,8 +274,9 @@ def generate_html_report(json_filename): with open(template_path, 'r') as f: html_template = f.read() - # Generate HTML filename - html_filename = json_filename.replace('.json', '.html') + # Generate HTML filename in reports directory + json_path = Path(json_filename) + html_filename = json_path.with_suffix('.html') # Calculate stats total_features = len(report["features"]) From f2b936afa8b42e21cabde9b1665ef39682df8984 Mon Sep 17 00:00:00 2001 From: Abhishek Anne Date: Tue, 26 Aug 2025 19:19:57 +0530 Subject: [PATCH 38/77] Script updated to support test description --- e2etests/run_tests.py | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/e2etests/run_tests.py b/e2etests/run_tests.py index 544011781c..65df718ab9 100755 --- a/e2etests/run_tests.py +++ b/e2etests/run_tests.py @@ -46,7 +46,7 @@ def parse_features(): DEFAULT_TESTSUITE = "sanity" def parse_test_results(stdout): - """Parse individual test results from cargo output with their outputs""" + """Parse individual test results from cargo output with their outputs and descriptions""" tests = [] lines = stdout.split('\n') @@ -62,6 +62,7 @@ def parse_test_results(stdout): # Look ahead for the result (ok/FAILED) in the next few lines status = None result_line_idx = None + description = "" # Check next 50 lines for result (increased from 20) for j in range(i + 1, min(i + 51, len(lines))): @@ -82,12 +83,23 @@ def parse_test_results(stdout): if result_line_idx: for k in range(i + 1, result_line_idx + 1): if k < len(lines): - output_lines.append(lines[k].strip()) + line_content = lines[k].strip() + output_lines.append(line_content) + + # Extract description from the full output + full_output = '\n'.join(output_lines) + if "πŸ” Testing" in full_output and "| Description:" in full_output: + # Find the line with the description + for line in output_lines: + if "πŸ” Testing" in line and "| Description:" in line: + description = line.split("| Description:")[1].strip() + break tests.append({ "name": test_name, "status": status, - "output": '\n'.join(output_lines[:30]) # Limit output size + "output": '\n'.join(output_lines[:30]), # Limit output size + "description": description }) return tests @@ -324,7 +336,9 @@ def generate_html_report(json_filename): readable_name = test_name test_output = test.get('output', 'No output captured') - test_suites_content += f'

{status_icon} {readable_name}

Status: {test["status"].upper()}

{test_output}
' + test_description = test.get('description', '') + description_html = f'

{test_description}

' if test_description else '' + test_suites_content += f'

{status_icon} {readable_name}

{description_html}

Status: {test["status"].upper()}

{test_output}
' # Add stdout/stderr for this feature for result in report["detailed_results"]: @@ -376,7 +390,9 @@ def print_summary(report): # Show individual test details for test in stats["individual_tests"]: test_status = "βœ…" if test["status"] == "passed" else "❌" - print(f" {test_status} {test['name']}") + description = test.get('description', '') + desc_text = f" - {description}" if description else "" + print(f" {test_status} {test['name']}{desc_text}") # Calculate feature-level stats total_features = len(report["features"]) From ebf882b33ae7ca1d7d01f4d226334784970d5d3f Mon Sep 17 00:00:00 2001 From: Abhishek Anne Date: Tue, 26 Aug 2025 19:27:47 +0530 Subject: [PATCH 39/77] Added description to agent and usage command tests , add .gitignore --- e2etests/.gitignore | 2 + e2etests/tests/agent/test_agent_commands.rs | 38 ++++++++++++++----- .../tests/session_mgmt/test_usage_command.rs | 14 +++++-- 3 files changed, 40 insertions(+), 14 deletions(-) create mode 100644 e2etests/.gitignore diff --git a/e2etests/.gitignore b/e2etests/.gitignore new file mode 100644 index 0000000000..e2644ec46e --- /dev/null +++ b/e2etests/.gitignore @@ -0,0 +1,2 @@ +qcli_test_summary*.json +qcli_test_summary*.html \ No newline at end of file diff --git a/e2etests/tests/agent/test_agent_commands.rs b/e2etests/tests/agent/test_agent_commands.rs index 3afd20bf5a..a7e46d2777 100644 --- a/e2etests/tests/agent/test_agent_commands.rs +++ b/e2etests/tests/agent/test_agent_commands.rs @@ -20,10 +20,12 @@ const TEST_NAMES: &[&str] = &[ #[allow(dead_code)] const TOTAL_TESTS: usize = TEST_NAMES.len(); +/// Tests the /agent command without subcommands to display help information +/// Verifies agent management description, usage, available subcommands, and options #[test] -#[cfg(all(feature = "agent", any(feature = "sanity"))] +#[cfg(all(feature = "agent", feature = "sanity"))] fn agent_without_subcommand() -> Result<(), Box> { - println!("πŸ” Testing /agent command..."); + println!("πŸ” Testing /agent command... | Description: Tests the /agent command without subcommands to display help information. Verifies agent management description, usage, available subcommands, and options"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -71,10 +73,12 @@ fn agent_without_subcommand() -> Result<(), Box> { Ok(()) } +/// Tests the /agent create command to create a new agent with specified name +/// Verifies agent creation process, file system operations, and cleanup #[test] #[cfg(all(feature = "agent", feature = "sanity"))] fn test_agent_create_command() -> Result<(), Box> { - println!("πŸ” Testing /agent create --name command..."); + println!("πŸ” Testing /agent create --name command... | Description: Tests the /agent create command to create a new agent with specified name. Verifies agent creation process, file system operations, and cleanup"); let timestamp = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) @@ -138,10 +142,12 @@ fn test_agent_create_command() -> Result<(), Box> { Ok(()) } +/// Tests the /agent create command without required arguments to verify error handling +/// Verifies proper error messages, usage information, and help suggestions #[test] #[cfg(all(feature = "agent", feature = "sanity"))] fn test_agent_create_missing_args() -> Result<(), Box> { - println!("πŸ” Testing /agent create without required arguments..."); + println!("πŸ” Testing /agent create without required arguments... | Description: Tests the /agent create command without required arguments to verify error handling. Verifies proper error messages, usage information, and help suggestions"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -187,10 +193,12 @@ fn test_agent_create_missing_args() -> Result<(), Box> { Ok(()) } +/// Tests the /agent help command to display comprehensive agent help information +/// Verifies agent descriptions, usage notes, launch instructions, and configuration paths #[test] #[cfg(all(feature = "agent", feature = "sanity"))] fn test_agent_help_command() -> Result<(), Box> { - println!("πŸ” Testing /agent help..."); + println!("πŸ” Testing /agent help... | Description: Tests the /agent help command to display comprehensive agent help information. Verifies agent descriptions, usage notes, launch instructions, and configuration paths"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -242,10 +250,12 @@ fn test_agent_help_command() -> Result<(), Box> { Ok(()) } +/// Tests the /agent command with invalid subcommand to verify error handling +/// Verifies that invalid commands display help information with available commands and options #[test] #[cfg(all(feature = "agent", feature = "sanity"))] fn test_agent_invalid_command() -> Result<(), Box> { - println!("πŸ” Testing /agent invalidcommand..."); + println!("πŸ” Testing /agent invalidcommand... | Description: Tests the /agent command with invalid subcommand to verify error handling. Verifies that invalid commands display help information with available commands and options"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -279,10 +289,12 @@ fn test_agent_invalid_command() -> Result<(), Box> { Ok(()) } +/// Tests the /agent list command to display all available agents +/// Verifies agent listing format and presence of default agent #[test] #[cfg(all(feature = "agent", feature = "sanity"))] fn test_agent_list_command() -> Result<(), Box> { - println!("πŸ” Testing /agent list command..."); + println!("πŸ” Testing /agent list command... | Description: Tests the /agent list command to display all available agents. Verifies agent listing format and presence of default agent"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -311,10 +323,12 @@ fn test_agent_list_command() -> Result<(), Box> { Ok(()) } +/// Tests the /agent schema command to display agent configuration schema +/// Verifies JSON schema structure with required keys and properties // #[test] // #[cfg(feature = "agent")] // fn test_agent_schema_command() -> Result<(), Box> { -// println!("πŸ” Testing /agent schema..."); +// println!("πŸ” Testing /agent schema... | Description: Tests the /agent schema command to display agent configuration schema. Verifies JSON schema structure with required keys and properties"); // let session = get_chat_session(); // let mut chat = session.lock().unwrap(); @@ -350,10 +364,12 @@ fn test_agent_list_command() -> Result<(), Box> { // Ok(()) // } +/// Tests the /agent set-default command with valid arguments to set default agent +/// Verifies success messages and confirmation of default agent configuration #[test] #[cfg(all(feature = "agent", feature = "sanity"))] fn test_agent_set_default_command() -> Result<(), Box> { - println!("πŸ” Testing /agent set-default with valid arguments..."); + println!("πŸ” Testing /agent set-default with valid arguments... | Description: Tests the /agent set-default command with valid arguments to set default agent. Verifies success messages and confirmation of default agent configuration"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -389,10 +405,12 @@ fn test_agent_set_default_command() -> Result<(), Box> { Ok(()) } +/// Tests the /agent set-default command without required arguments to verify error handling +/// Verifies error messages, usage information, and available options display #[test] #[cfg(all(feature = "agent", feature = "sanity"))] fn test_agent_set_default_missing_args() -> Result<(), Box> { - println!("πŸ” Testing /agent set-default without required arguments..."); + println!("πŸ” Testing /agent set-default without required arguments... | Description: Tests the /agent set-default command without required arguments to verify error handling. Verifies error messages, usage information, and available options display"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); diff --git a/e2etests/tests/session_mgmt/test_usage_command.rs b/e2etests/tests/session_mgmt/test_usage_command.rs index bee74be719..109e7045af 100644 --- a/e2etests/tests/session_mgmt/test_usage_command.rs +++ b/e2etests/tests/session_mgmt/test_usage_command.rs @@ -15,10 +15,12 @@ const TEST_NAMES: &[&str] = &[ #[allow(dead_code)] const TOTAL_TESTS: usize = TEST_NAMES.len(); +/// Tests the /usage command to display current context window usage +/// Verifies token usage information, progress bar, breakdown sections, and Pro Tips #[test] #[cfg(all(feature = "usage", feature = "sanity"))] fn test_usage_command() -> Result<(), Box> { - println!("πŸ” Testing /usage command..."); + println!("πŸ” Testing /usage command... | Description: Tests the /usage command to display current context window usage. Verifies token usage information, progress bar, breakdown sections, and Pro Tips"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -74,10 +76,12 @@ fn test_usage_command() -> Result<(), Box> { Ok(()) } +/// Tests the /usage --help command to display help information for the usage command +/// Verifies Usage section, Options section, and help flags (-h, --help) #[test] #[cfg(all(feature = "usage", feature = "sanity"))] fn test_usage_help_command() -> Result<(), Box> { - println!("πŸ” Testing /usage --help command..."); + println!("πŸ” Testing /usage --help command... | Description: Tests the /usage --help command to display help information for the usage command. Verifies Usage section, Options section, and help flags (-h, --help)"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -90,7 +94,7 @@ fn test_usage_help_command() -> Result<(), Box> { println!("πŸ“ END OUTPUT"); // Verify Usage section - assert!(response.contains("Usage:"), "Missing Usage section"); + assert!(response.contains("Usage: XX "), "Missing Usage section"); assert!(response.contains("/usage"), "Missing /usage command in usage section"); println!("βœ… Found Usage section with /usage command"); @@ -115,10 +119,12 @@ fn test_usage_help_command() -> Result<(), Box> { Ok(()) } +/// Tests the /usage -h command (short form of --help) +/// Verifies Usage section, Options section, and help flags (-h, --help) #[test] #[cfg(all(any(feature = "usage", feature = "session_mgmt"), feature = "regression"))] fn test_usage_h_command() -> Result<(), Box> { - println!("πŸ” Testing /usage -h command..."); + println!("πŸ” Testing /usage -h command... | Description: Tests the /usage -h command (short form of --help). Verifies Usage section, Options section, and help flags (-h, --help)"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); From be73c04e2995303fe1e10502ff3b61b76a926332 Mon Sep 17 00:00:00 2001 From: Abhishek Anne Date: Thu, 28 Aug 2025 16:57:35 +0530 Subject: [PATCH 40/77] Fixed individual test output --- e2etests/html_template.html | 2 +- e2etests/run_tests.py | 38 +++++++++++++------ .../session_mgmt/test_compact_command.rs | 8 ++-- .../tests/session_mgmt/test_usage_command.rs | 5 ++- 4 files changed, 35 insertions(+), 18 deletions(-) diff --git a/e2etests/html_template.html b/e2etests/html_template.html index 0f0672850c..74e1ea44fa 100644 --- a/e2etests/html_template.html +++ b/e2etests/html_template.html @@ -35,7 +35,7 @@

πŸ§ͺ Q CLI E2E Test Report

-

πŸ“Š Overall Summary

+

πŸ“Š Summary

diff --git a/e2etests/run_tests.py b/e2etests/run_tests.py index 65df718ab9..3c6901bbb1 100755 --- a/e2etests/run_tests.py +++ b/e2etests/run_tests.py @@ -7,9 +7,15 @@ import json import time import platform +import re from datetime import datetime from pathlib import Path +def strip_ansi(text): + """Remove ANSI escape sequences from text""" + ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])') + return ansi_escape.sub('', text) + def parse_features(): """Parse features from Cargo.toml, handling grouped features correctly""" cargo_toml = toml.load("Cargo.toml") @@ -64,8 +70,8 @@ def parse_test_results(stdout): result_line_idx = None description = "" - # Check next 50 lines for result (increased from 20) - for j in range(i + 1, min(i + 51, len(lines))): + # Check all remaining lines for result + for j in range(i + 1, len(lines)): result_line = lines[j].strip() if result_line == 'ok': status = "passed" @@ -98,7 +104,7 @@ def parse_test_results(stdout): tests.append({ "name": test_name, "status": status, - "output": '\n'.join(output_lines[:30]), # Limit output size + "output": strip_ansi('\n'.join(output_lines)), # Full output "description": description }) @@ -145,8 +151,8 @@ def run_single_cargo_test(feature, test_suite, binary_path="q", quiet=False): "test_suite": test_suite, "success": result.returncode == 0, "duration": round(end_time - start_time, 2), - "stdout": result.stdout, - "stderr": result.stderr, + "stdout": strip_ansi(result.stdout), + "stderr": strip_ansi(result.stderr), "command": " ".join(cmd), "individual_tests": individual_tests } @@ -264,10 +270,20 @@ def generate_report(results, features, test_suites, binary_path="q"): } # Generate filename with features and test suites - features_str = "-".join(features[:3]) + ("_more" if len(features) > 3 else "") - suites_str = "-".join(test_suites) + # If running all features (sanity/regression mode), use only test suite names + grouped_features, standalone_features = parse_features() + all_available_features = list(grouped_features.keys()) + standalone_features + + if set(features) == set(all_available_features): + # Running all features - use only test suite names + features_str = "-".join(test_suites) + else: + # Running specific features - include feature names + features_str = "-".join(features[:3]) + ("_more" if len(features) > 3 else "") + features_str += "_" + "-".join(test_suites) + datetime_str = datetime.now().strftime("%m%d%y%H%M%S") - filename = reports_dir / f"qcli_test_summary_{features_str}_{suites_str}_{datetime_str}.json" + filename = reports_dir / f"qcli_test_summary_{features_str}_{datetime_str}.json" # Save JSON report with open(filename, "w") as f: @@ -335,7 +351,7 @@ def generate_html_report(json_filename): else: readable_name = test_name - test_output = test.get('output', 'No output captured') + test_output = strip_ansi(test.get('output', 'No output captured')) test_description = test.get('description', '') description_html = f'

{test_description}

' if test_description else '' test_suites_content += f'

{status_icon} {readable_name}

{description_html}

Status: {test["status"].upper()}

{test_output}
' @@ -343,8 +359,8 @@ def generate_html_report(json_filename): # Add stdout/stderr for this feature for result in report["detailed_results"]: if result["feature"] == feature_name and result["test_suite"] == suite: - stderr_content = f'
STDERR:
{result["stderr"]}
' if result['stderr'] else '' - test_suites_content += f'

Command: {result["command"]}

Duration: {result["duration"]}s

{result["stdout"]}
{stderr_content}
' + stderr_content = f'
STDERR:
{strip_ansi(result["stderr"])}
' if result['stderr'] else '' + test_suites_content += f'

Command: {result["command"]}

Duration: {result["duration"]}s

{strip_ansi(result["stdout"])}
{stderr_content}
' test_suites_content += "
" # Close feature content diff --git a/e2etests/tests/session_mgmt/test_compact_command.rs b/e2etests/tests/session_mgmt/test_compact_command.rs index aa3f20ea93..1c8faa220b 100644 --- a/e2etests/tests/session_mgmt/test_compact_command.rs +++ b/e2etests/tests/session_mgmt/test_compact_command.rs @@ -11,9 +11,9 @@ const TEST_NAMES: &[&str] = &[ "test_compact_command", "test_compact_help_command", "test_compact_h_command", - "test_show_summary", - "test_compact_truncate_true_command", - "test_compact_truncate_false_command", + // "test_show_summary", + // "test_compact_truncate_true_command", + // "test_compact_truncate_false_command" ]; #[allow(dead_code)] const TOTAL_TESTS: usize = TEST_NAMES.len(); @@ -104,7 +104,7 @@ fn test_compact_help_command() -> Result<(), Box> { } #[test] -#[cfg(all(any(feature = "compact", feature = "session_mgmt"), feature = "regression"))] +#[cfg(all(feature = "compact", feature = "sanity"))] fn test_compact_h_command() -> Result<(), Box> { println!("πŸ” Testing /compact -h command..."); diff --git a/e2etests/tests/session_mgmt/test_usage_command.rs b/e2etests/tests/session_mgmt/test_usage_command.rs index 109e7045af..92dd5a5664 100644 --- a/e2etests/tests/session_mgmt/test_usage_command.rs +++ b/e2etests/tests/session_mgmt/test_usage_command.rs @@ -94,7 +94,8 @@ fn test_usage_help_command() -> Result<(), Box> { println!("πŸ“ END OUTPUT"); // Verify Usage section - assert!(response.contains("Usage: XX "), "Missing Usage section"); + assert!(response.contains("Usage:"), "Missing Usage section"); + assert!(response.contains("/usage"), "Missing /usage command in usage section"); println!("βœ… Found Usage section with /usage command"); @@ -122,7 +123,7 @@ fn test_usage_help_command() -> Result<(), Box> { /// Tests the /usage -h command (short form of --help) /// Verifies Usage section, Options section, and help flags (-h, --help) #[test] -#[cfg(all(any(feature = "usage", feature = "session_mgmt"), feature = "regression"))] +#[cfg(all(feature = "usage", feature = "sanity"))] fn test_usage_h_command() -> Result<(), Box> { println!("πŸ” Testing /usage -h command... | Description: Tests the /usage -h command (short form of --help). Verifies Usage section, Options section, and help flags (-h, --help)"); From 50e36d627ee643a4dc37d955868a89da561a6c51 Mon Sep 17 00:00:00 2001 From: Abhishek Anne Date: Thu, 28 Aug 2025 17:09:46 +0530 Subject: [PATCH 41/77] Removed all regression test cases --- e2etests/tests/context/test_context_command.rs | 2 +- e2etests/tests/integration/test_editor_help_command.rs | 2 +- e2etests/tests/integration/test_hooks_command.rs | 2 +- e2etests/tests/integration/test_issue_command.rs | 4 ++-- e2etests/tests/integration/test_subscribe_command.rs | 4 ++-- e2etests/tests/model/test_model_dynamic_command.rs | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/e2etests/tests/context/test_context_command.rs b/e2etests/tests/context/test_context_command.rs index 53162d4285..b5c48d9396 100644 --- a/e2etests/tests/context/test_context_command.rs +++ b/e2etests/tests/context/test_context_command.rs @@ -467,7 +467,7 @@ fn test_add_remove_multiple_file_context()-> Result<(), Box Result<(), Box> { println!("πŸ” Testing /context clear command..."); diff --git a/e2etests/tests/integration/test_editor_help_command.rs b/e2etests/tests/integration/test_editor_help_command.rs index 00ac947948..c145e339b4 100644 --- a/e2etests/tests/integration/test_editor_help_command.rs +++ b/e2etests/tests/integration/test_editor_help_command.rs @@ -102,7 +102,7 @@ fn test_help_editor_command() -> Result<(), Box> { } #[test] -#[cfg(all(any(feature = "editor", feature = "integration"), feature = "regression"))] +#[cfg(all(feature = "editor", feature = "sanity"))] fn test_editor_h_command() -> Result<(), Box> { println!("πŸ” Testing /editor -h command..."); diff --git a/e2etests/tests/integration/test_hooks_command.rs b/e2etests/tests/integration/test_hooks_command.rs index 488a237477..1551600d96 100644 --- a/e2etests/tests/integration/test_hooks_command.rs +++ b/e2etests/tests/integration/test_hooks_command.rs @@ -85,7 +85,7 @@ fn test_hooks_help_command() -> Result<(), Box> { } #[test] -#[cfg(all(any(feature = "hooks", feature = "integration"), feature = "regression"))] +#[cfg(all(feature = "hooks", feature = "sanity"))] fn test_hooks_h_command() -> Result<(), Box> { println!("πŸ” Testing /hooks -h command..."); diff --git a/e2etests/tests/integration/test_issue_command.rs b/e2etests/tests/integration/test_issue_command.rs index 927b92711f..325232c90b 100644 --- a/e2etests/tests/integration/test_issue_command.rs +++ b/e2etests/tests/integration/test_issue_command.rs @@ -78,7 +78,7 @@ fn test_issue_force_command() -> Result<(), Box> { } #[test] -#[cfg(all(any(feature = "issue_reporting", feature = "integration"), feature = "regression"))] +#[cfg(all(feature = "issue_reporting", feature = "sanity"))] fn test_issue_f_command() -> Result<(), Box> { println!("πŸ” Testing /issue -f command with critical bug..."); @@ -149,7 +149,7 @@ fn test_issue_help_command() -> Result<(), Box> { } #[test] -#[cfg(all(any(feature = "issue_reporting", feature = "integration"), feature = "regression"))] +#[cfg(all(feature = "issue_reporting", feature = "sanity"))] fn test_issue_h_command() -> Result<(), Box> { println!("πŸ” Testing /issue -h command..."); diff --git a/e2etests/tests/integration/test_subscribe_command.rs b/e2etests/tests/integration/test_subscribe_command.rs index 65557b269b..79c98595aa 100644 --- a/e2etests/tests/integration/test_subscribe_command.rs +++ b/e2etests/tests/integration/test_subscribe_command.rs @@ -48,7 +48,7 @@ fn test_subscribe_command() -> Result<(), Box> { } #[test] -#[cfg(all(any(feature = "subscribe", feature = "integration"), feature = "regression"))] +#[cfg(all(feature = "subscribe", feature = "sanity"))] fn test_subscribe_manage_command() -> Result<(), Box> { println!("πŸ” Testing /subscribe command..."); @@ -126,7 +126,7 @@ fn test_subscribe_help_command() -> Result<(), Box> { } #[test] -#[cfg(all(any(feature = "subscribe", feature = "integration"), feature = "regression"))] +#[cfg(all(feature = "subscribe", feature = "sanity"))] fn test_subscribe_h_command() -> Result<(), Box> { println!("πŸ” Testing /subscribe -h command..."); diff --git a/e2etests/tests/model/test_model_dynamic_command.rs b/e2etests/tests/model/test_model_dynamic_command.rs index 0eb187b478..82f0d8fb08 100644 --- a/e2etests/tests/model/test_model_dynamic_command.rs +++ b/e2etests/tests/model/test_model_dynamic_command.rs @@ -174,7 +174,7 @@ fn test_model_help_command() -> Result<(), Box> { } #[test] -#[cfg(all(feature = "model", feature = "regression"))] +#[cfg(all(feature = "model", feature = "sanity"))] fn test_model_h_command() -> Result<(), Box> { println!("πŸ” Testing /model -h command..."); From 05da0fc2ed2c65513bce20383bde5c282af24e4d Mon Sep 17 00:00:00 2001 From: Abhishek Anne Date: Thu, 28 Aug 2025 18:51:54 +0530 Subject: [PATCH 42/77] Added descriptions to tests --- e2etests/tests/ai_prompts/test_ai_prompt.rs | 4 ++-- .../tests/ai_prompts/test_prompts_commands.rs | 6 ++--- .../tests/context/test_context_command.rs | 20 ++++++++--------- .../tests/core_session/test_clear_command.rs | 2 +- .../tests/core_session/test_help_command.rs | 2 +- .../tests/core_session/test_quit_command.rs | 2 +- .../tests/core_session/test_tools_command.rs | 18 +++++++-------- .../integration/test_editor_help_command.rs | 6 ++--- .../tests/integration/test_hooks_command.rs | 6 ++--- .../tests/integration/test_issue_command.rs | 10 ++++----- .../integration/test_subscribe_command.rs | 8 +++---- e2etests/tests/mcp/test_mcp_command.rs | 22 +++++++++---------- .../tests/model/test_model_dynamic_command.rs | 6 ++--- .../tests/save_load/test_save_load_command.rs | 20 ++++++++--------- .../session_mgmt/test_compact_command.rs | 6 ++--- 15 files changed, 69 insertions(+), 69 deletions(-) diff --git a/e2etests/tests/ai_prompts/test_ai_prompt.rs b/e2etests/tests/ai_prompts/test_ai_prompt.rs index facdf7f644..f5620ff912 100644 --- a/e2etests/tests/ai_prompts/test_ai_prompt.rs +++ b/e2etests/tests/ai_prompts/test_ai_prompt.rs @@ -4,7 +4,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] #[cfg(all(feature = "ai_prompts", feature = "sanity"))] fn test_what_is_aws_prompt() -> Result<(), Box> { - println!("πŸ” [AI PROMPTS] Testing 'What is AWS?' AI prompt..."); + println!("πŸ” [AI PROMPTS] Testing 'What is AWS?' AI prompt... | Description: Tests AI prompt functionality by sending 'What is AWS?' and verifying the response contains relevant AWS information and technical terms"); let mut chat = QChatSession::new()?; println!("βœ… Q Chat session started"); @@ -57,7 +57,7 @@ fn test_what_is_aws_prompt() -> Result<(), Box> { #[test] #[cfg(all(feature = "ai_prompts", feature = "sanity"))] fn test_simple_greeting() -> Result<(), Box> { - println!("πŸ” Testing simple 'Hello' prompt..."); + println!("πŸ” Testing simple 'Hello' prompt... | Description: Tests basic AI interaction by sending a simple greeting and verifying the AI responds appropriately with greeting-related content"); let mut chat = QChatSession::new()?; println!("βœ… Q Chat session started"); diff --git a/e2etests/tests/ai_prompts/test_prompts_commands.rs b/e2etests/tests/ai_prompts/test_prompts_commands.rs index 70af25f8bd..6407f7913c 100644 --- a/e2etests/tests/ai_prompts/test_prompts_commands.rs +++ b/e2etests/tests/ai_prompts/test_prompts_commands.rs @@ -19,7 +19,7 @@ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] #[cfg(all(feature = "ai_prompts", feature = "sanity"))] fn test_prompts_command() -> Result<(), Box> { - println!("πŸ” Testing /prompts command..."); + println!("πŸ” Testing /prompts command... | Description: Tests the /prompts command to display available prompts with usage instructions and argument requirements"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -58,7 +58,7 @@ fn test_prompts_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "ai_prompts", feature = "sanity"))] fn test_prompts_help_command() -> Result<(), Box> { - println!("πŸ” Testing /prompts --help command..."); + println!("πŸ” Testing /prompts --help command... | Description: Tests the /prompts --help command to display comprehensive help information about prompts functionality and MCP server integration"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -119,7 +119,7 @@ fn test_prompts_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "ai_prompts", feature = "sanity"))] fn test_prompts_list_command() -> Result<(), Box> { - println!("πŸ” Testing /prompts list command..."); + println!("πŸ” Testing /prompts list command... | Description: Tests the /prompts list command to display all available prompts with their arguments and usage information"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); diff --git a/e2etests/tests/context/test_context_command.rs b/e2etests/tests/context/test_context_command.rs index b5c48d9396..e8a8623acd 100644 --- a/e2etests/tests/context/test_context_command.rs +++ b/e2etests/tests/context/test_context_command.rs @@ -25,7 +25,7 @@ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] #[cfg(all(feature = "context", feature = "sanity"))] fn test_context_show_command() -> Result<(), Box> { - println!("πŸ” Testing /context show command..."); + println!("πŸ” Testing /context show command... | Description: Tests the /context show command to display current context information including agent configuration and context files"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -59,7 +59,7 @@ fn test_context_show_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "context", feature = "sanity"))] fn test_context_help_command() -> Result<(), Box> { - println!("πŸ” Testing /context help command..."); + println!("πŸ” Testing /context help command... | Description: Tests the /context help command to display comprehensive help information for context management including usage, commands, and options"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -101,7 +101,7 @@ fn test_context_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "context", feature = "sanity"))] fn test_context_without_subcommand() -> Result<(), Box> { - println!("πŸ” Testing /context without sub command..."); + println!("πŸ” Testing /context without sub command... | Description: Tests the /context command without subcommands to verify it displays help information with usage and available commands"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -139,7 +139,7 @@ fn test_context_without_subcommand() -> Result<(), Box> { #[test] #[cfg(all(feature = "context", feature = "sanity"))] fn test_context_invalid_command() -> Result<(), Box> { - println!("πŸ” Testing /context invalid command..."); + println!("πŸ” Testing /context invalid command... | Description: Tests the /context command with invalid subcommand to verify proper error handling and help display"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -169,7 +169,7 @@ fn test_context_invalid_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "context", feature = "sanity"))] fn test_add_non_existing_file_context() -> Result<(), Box> { - println!("πŸ” Testing /context add non-existing file command..."); + println!("πŸ” Testing /context add non-existing file command... | Description: Tests the /context add command with non-existing file to verify proper error handling and force option suggestion"); let non_existing_file_path = "/tmp/non_existing_file.py"; @@ -200,7 +200,7 @@ fn test_add_non_existing_file_context() -> Result<(), Box #[test] #[cfg(all(feature = "context", feature = "sanity"))] fn test_context_remove_command_of_non_existent_file() -> Result<(), Box> { - println!("πŸ” Testing /context remove non existing file command..."); + println!("πŸ” Testing /context remove non existing file command... | Description: Tests the /context remove command with non-existing file to verify proper error handling"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -228,7 +228,7 @@ fn test_context_remove_command_of_non_existent_file() -> Result<(), Box Result<(), Box> { - println!("πŸ” Testing /context add command and /context remove command..."); + println!("πŸ” Testing /context add command and /context remove command... | Description: Tests the complete workflow of adding a file to context, verifying it appears in context show, then removing it and verifying removal"); let test_file_path = "/tmp/test_context_file_.py"; // Create a test file @@ -302,7 +302,7 @@ fn test_add_remove_file_context() -> Result<(), Box> { #[test] #[cfg(all(feature = "context", feature = "sanity"))] fn test_add_glob_pattern_file_context()-> Result<(), Box> { - println!("πŸ” Testing /context add *.py glob pattern command..."); + println!("πŸ” Testing /context add *.py glob pattern command... | Description: Tests the /context add command with glob patterns to add multiple files matching a pattern and verify pattern-based context management"); let test_file1_path = "/tmp/test_context_file1.py"; let test_file2_path = "/tmp/test_context_file2.py"; @@ -384,7 +384,7 @@ fn test_add_glob_pattern_file_context()-> Result<(), Box> #[test] #[cfg(all(feature = "context", feature = "sanity"))] fn test_add_remove_multiple_file_context()-> Result<(), Box> { - println!("πŸ” Testing /context add command and /context remove ..."); + println!("πŸ” Testing /context add command and /context remove ... | Description: Tests adding and removing multiple files in a single command to verify batch context operations"); let test_file1_path = "/tmp/test_context_file1.py"; let test_file2_path = "/tmp/test_context_file2.py"; @@ -469,7 +469,7 @@ fn test_add_remove_multiple_file_context()-> Result<(), Box Result<(), Box> { - println!("πŸ” Testing /context clear command..."); + println!("πŸ” Testing /context clear command... | Description: Tests the /context clear command to remove all files from context and verify the context is completely cleared"); let test_file_path = "/tmp/test_context_file.py"; diff --git a/e2etests/tests/core_session/test_clear_command.rs b/e2etests/tests/core_session/test_clear_command.rs index ec42b2834b..0261efaec1 100644 --- a/e2etests/tests/core_session/test_clear_command.rs +++ b/e2etests/tests/core_session/test_clear_command.rs @@ -4,7 +4,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] #[cfg(all(feature = "clear", feature = "sanity"))] fn test_clear_command() -> Result<(), Box> { - println!("πŸ” Testing /clear command..."); + println!("πŸ” Testing /clear command... | Description: Tests the /clear command to clear conversation history and verify that previous context is no longer remembered by the AI"); let mut chat = QChatSession::new()?; println!("βœ… Q Chat session started"); diff --git a/e2etests/tests/core_session/test_help_command.rs b/e2etests/tests/core_session/test_help_command.rs index e869f8a463..cee19f8d6a 100644 --- a/e2etests/tests/core_session/test_help_command.rs +++ b/e2etests/tests/core_session/test_help_command.rs @@ -4,7 +4,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] #[cfg(all(feature = "help", feature = "sanity"))] fn test_help_command() -> Result<(), Box> { - println!("πŸ” Testing /help command..."); + println!("πŸ” Testing /help command... | Description: Tests the /help command to display all available commands and verify core functionality like quit, clear, tools, and help commands are present"); let mut chat = QChatSession::new()?; println!("βœ… Q Chat session started"); diff --git a/e2etests/tests/core_session/test_quit_command.rs b/e2etests/tests/core_session/test_quit_command.rs index 6f41a9331c..fdd28370c6 100644 --- a/e2etests/tests/core_session/test_quit_command.rs +++ b/e2etests/tests/core_session/test_quit_command.rs @@ -4,7 +4,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] #[cfg(all(feature = "quit", feature = "sanity"))] fn test_quit_command() -> Result<(), Box> { - println!("πŸ” Testing /quit command..."); + println!("πŸ” Testing /quit command... | Description: Tests the /quit command to properly terminate the Q Chat session and exit cleanly"); let mut chat = QChatSession::new()?; println!("βœ… Q Chat session started"); diff --git a/e2etests/tests/core_session/test_tools_command.rs b/e2etests/tests/core_session/test_tools_command.rs index 02a4611da8..2e6729a973 100644 --- a/e2etests/tests/core_session/test_tools_command.rs +++ b/e2etests/tests/core_session/test_tools_command.rs @@ -24,7 +24,7 @@ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] #[cfg(all(feature = "tools", feature = "sanity"))] fn test_tools_command() -> Result<(), Box> { - println!("πŸ” Testing /tools command..."); + println!("πŸ” Testing /tools command... | Description: Tests the /tools command to display all available tools with their permission status including built-in and MCP tools"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -79,7 +79,7 @@ fn test_tools_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "tools", feature = "sanity"))] fn test_tools_help_command() -> Result<(), Box> { - println!("πŸ” Testing /tools --help command..."); + println!("πŸ” Testing /tools --help command... | Description: Tests the /tools --help command to display comprehensive help information about tools management including available subcommands and options"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -125,7 +125,7 @@ fn test_tools_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "tools", feature = "sanity"))] fn test_tools_trust_all_command() -> Result<(), Box> { - println!("πŸ” Testing /tools trust-all command..."); + println!("πŸ” Testing /tools trust-all command... | Description: Tests the /tools trust-all command to trust all available tools and verify all tools show trusted status, then tests reset functionality"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -205,7 +205,7 @@ fn test_tools_trust_all_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "tools", feature = "sanity"))] fn test_tools_trust_all_help_command() -> Result<(), Box> { - println!("πŸ” Testing /tools trust-all --help command..."); + println!("πŸ” Testing /tools trust-all --help command... | Description: Tests the /tools trust-all --help command to display help information for the trust-all subcommand"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -241,7 +241,7 @@ fn test_tools_trust_all_help_command() -> Result<(), Box> #[test] #[cfg(all(feature = "tools", feature = "sanity"))] fn test_tools_reset_help_command() -> Result<(), Box> { - println!("πŸ” Testing /tools reset --help command..."); + println!("πŸ” Testing /tools reset --help command... | Description: Tests the /tools reset --help command to display help information for the reset subcommand"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -276,7 +276,7 @@ fn test_tools_reset_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "tools", feature = "sanity"))] fn test_tools_trust_command() -> Result<(), Box> { - println!("πŸ” Testing /tools trust command..."); + println!("πŸ” Testing /tools trust command... | Description: Tests the /tools trust and untrust commands to manage individual tool permissions and verify trust status changes"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -354,7 +354,7 @@ fn test_tools_trust_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "tools", feature = "sanity"))] fn test_tools_trust_help_command() -> Result<(), Box> { - println!("πŸ” Testing /tools trust --help command..."); + println!("πŸ” Testing /tools trust --help command... | Description: Tests the /tools trust --help command to display help information for trusting specific tools"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -393,7 +393,7 @@ fn test_tools_trust_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "tools", feature = "sanity"))] fn test_tools_untrust_help_command() -> Result<(), Box> { - println!("πŸ” Testing /tools untrust --help command..."); + println!("πŸ” Testing /tools untrust --help command... | Description: Tests the /tools untrust --help command to display help information for untrusting specific tools"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -432,7 +432,7 @@ fn test_tools_untrust_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "tools", feature = "sanity"))] fn test_tools_schema_help_command() -> Result<(), Box> { - println!("πŸ” Testing /tools schema --help command..."); + println!("πŸ” Testing /tools schema --help command... | Description: Tests the /tools schema --help command to display help information for viewing tool schemas"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); diff --git a/e2etests/tests/integration/test_editor_help_command.rs b/e2etests/tests/integration/test_editor_help_command.rs index c145e339b4..674458c1e7 100644 --- a/e2etests/tests/integration/test_editor_help_command.rs +++ b/e2etests/tests/integration/test_editor_help_command.rs @@ -18,7 +18,7 @@ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] #[cfg(all(feature = "editor", feature = "sanity"))] fn test_editor_help_command() -> Result<(), Box> { - println!("πŸ” Testing /editor --help command..."); + println!("πŸ” Testing /editor --help command... | Description: Tests the /editor --help command to display help information for the editor functionality including usage and options"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -61,7 +61,7 @@ fn test_editor_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "editor", feature = "sanity"))] fn test_help_editor_command() -> Result<(), Box> { - println!("πŸ” Testing /help editor command..."); + println!("πŸ” Testing /help editor command... | Description: Tests the /help editor command to display editor-specific help information and usage instructions"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -104,7 +104,7 @@ fn test_help_editor_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "editor", feature = "sanity"))] fn test_editor_h_command() -> Result<(), Box> { - println!("πŸ” Testing /editor -h command..."); + println!("πŸ” Testing /editor -h command... | Description: Tests the /editor -h command (short form) to display editor help information and verify proper flag handling"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); diff --git a/e2etests/tests/integration/test_hooks_command.rs b/e2etests/tests/integration/test_hooks_command.rs index 1551600d96..5b2f3f747c 100644 --- a/e2etests/tests/integration/test_hooks_command.rs +++ b/e2etests/tests/integration/test_hooks_command.rs @@ -18,7 +18,7 @@ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] #[cfg(all(feature = "hooks", feature = "sanity"))] fn test_hooks_command() -> Result<(), Box> { - println!("πŸ” Testing /hooks command..."); + println!("πŸ” Testing /hooks command... | Description: Tests the /hooks command to display configured hooks or show no hooks message when none are configured"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -48,7 +48,7 @@ fn test_hooks_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "hooks", feature = "sanity"))] fn test_hooks_help_command() -> Result<(), Box> { - println!("πŸ” Testing /hooks --help command..."); + println!("πŸ” Testing /hooks --help command... | Description: Tests the /hooks --help command to display comprehensive help information for hooks functionality and configuration"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -87,7 +87,7 @@ fn test_hooks_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "hooks", feature = "sanity"))] fn test_hooks_h_command() -> Result<(), Box> { - println!("πŸ” Testing /hooks -h command..."); + println!("πŸ” Testing /hooks -h command... | Description: Tests the /hooks -h command (short form) to display hooks help information and verify flag handling"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); diff --git a/e2etests/tests/integration/test_issue_command.rs b/e2etests/tests/integration/test_issue_command.rs index 325232c90b..f98112f668 100644 --- a/e2etests/tests/integration/test_issue_command.rs +++ b/e2etests/tests/integration/test_issue_command.rs @@ -20,7 +20,7 @@ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] #[cfg(all(feature = "issue_reporting", feature = "sanity"))] fn test_issue_command() -> Result<(), Box> { - println!("πŸ” Testing /issue command with bug report..."); + println!("πŸ” Testing /issue command with bug report... | Description: Tests the /issue command to create a bug report and verify it opens GitHub issue creation interface"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -50,7 +50,7 @@ fn test_issue_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "issue_reporting", feature = "sanity"))] fn test_issue_force_command() -> Result<(), Box> { - println!("πŸ” Testing /issue --force command with critical bug..."); + println!("πŸ” Testing /issue --force command with critical bug... | Description: Tests the /issue --force command to create a critical bug report and verify forced issue creation workflow"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -80,7 +80,7 @@ fn test_issue_force_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "issue_reporting", feature = "sanity"))] fn test_issue_f_command() -> Result<(), Box> { - println!("πŸ” Testing /issue -f command with critical bug..."); + println!("πŸ” Testing /issue -f command with critical bug... | Description: Tests the /issue -f command (short form) to create a critical bug report with force flag"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -111,7 +111,7 @@ fn test_issue_f_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "issue_reporting", feature = "sanity"))] fn test_issue_help_command() -> Result<(), Box> { - println!("πŸ” Testing /issue --help command..."); + println!("πŸ” Testing /issue --help command... | Description: Tests the /issue --help command to display help information for issue reporting functionality including options and usage"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -151,7 +151,7 @@ fn test_issue_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "issue_reporting", feature = "sanity"))] fn test_issue_h_command() -> Result<(), Box> { - println!("πŸ” Testing /issue -h command..."); + println!("πŸ” Testing /issue -h command... | Description: Tests the /issue -h command (short form) to display issue reporting help information"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); diff --git a/e2etests/tests/integration/test_subscribe_command.rs b/e2etests/tests/integration/test_subscribe_command.rs index 79c98595aa..8bf83f68bb 100644 --- a/e2etests/tests/integration/test_subscribe_command.rs +++ b/e2etests/tests/integration/test_subscribe_command.rs @@ -20,7 +20,7 @@ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] #[cfg(all(feature = "subscribe", feature = "sanity"))] fn test_subscribe_command() -> Result<(), Box> { - println!("πŸ” Testing /subscribe command..."); + println!("πŸ” Testing /subscribe command... | Description: Tests the /subscribe command to display Q Developer Pro subscription information and IAM Identity Center details"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -50,7 +50,7 @@ fn test_subscribe_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "subscribe", feature = "sanity"))] fn test_subscribe_manage_command() -> Result<(), Box> { - println!("πŸ” Testing /subscribe command..."); + println!("πŸ” Testing /subscribe --manage command... | Description: Tests the /subscribe --manage command to access subscription management interface for Q Developer Pro"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -80,7 +80,7 @@ fn test_subscribe_manage_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "subscribe", feature = "sanity"))] fn test_subscribe_help_command() -> Result<(), Box> { - println!("πŸ” Testing /subscribe --help command..."); + println!("πŸ” Testing /subscribe --help command... | Description: Tests the /subscribe --help command to display comprehensive help information for subscription management"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -128,7 +128,7 @@ fn test_subscribe_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "subscribe", feature = "sanity"))] fn test_subscribe_h_command() -> Result<(), Box> { - println!("πŸ” Testing /subscribe -h command..."); + println!("πŸ” Testing /subscribe -h command... | Description: Tests the /subscribe -h command (short form) to display subscription help information"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); diff --git a/e2etests/tests/mcp/test_mcp_command.rs b/e2etests/tests/mcp/test_mcp_command.rs index 2d73553205..d3955d9e38 100644 --- a/e2etests/tests/mcp/test_mcp_command.rs +++ b/e2etests/tests/mcp/test_mcp_command.rs @@ -26,7 +26,7 @@ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] #[cfg(all(feature = "mcp", feature = "sanity"))] fn test_mcp_help_command() -> Result<(), Box> { - println!("πŸ” Testing /mcp --help command..."); + println!("πŸ” Testing /mcp --help command... | Description: Tests the /mcp --help command to display help information for MCP server management functionality"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -69,7 +69,7 @@ fn test_mcp_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "mcp", feature = "sanity"))] fn test_mcp_loading_command() -> Result<(), Box> { - println!("πŸ” Testing MCP loading..."); + println!("πŸ” Testing MCP loading... | Description: Tests MCP server loading status and displays information about loaded MCP servers with timing"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -109,7 +109,7 @@ fn test_mcp_loading_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "mcp", feature = "sanity"))] fn test_mcp_remove_help_command() -> Result<(), Box> { - println!("πŸ” Testing q mcp remove --help command..."); + println!("πŸ” Testing q mcp remove --help command... | Description: Tests the q mcp remove --help command to display help information for removing MCP servers"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -156,7 +156,7 @@ fn test_mcp_remove_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "mcp", feature = "sanity"))] fn test_q_mcp_add_help_command() -> Result<(), Box> { - println!("πŸ” Testing q mcp add --help command..."); + println!("πŸ” Testing q mcp add --help command... | Description: Tests the q mcp add --help command to display help information for adding new MCP servers"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -214,7 +214,7 @@ fn test_q_mcp_add_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "mcp", feature = "sanity"))] fn test_q_mcp_help_command() -> Result<(), Box> { - println!("πŸ” Testing q mcp --help command..."); + println!("πŸ” Testing q mcp --help command... | Description: Tests the q mcp --help command to display comprehensive MCP management help including all subcommands"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -271,7 +271,7 @@ fn test_q_mcp_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "mcp", feature = "sanity"))] fn test_q_mcp_import_help_command() -> Result<(), Box> { - println!("πŸ” Testing q mcp import --help command..."); + println!("πŸ” Testing q mcp import --help command... | Description: Tests the q mcp import --help command to display help information for importing MCP server configurations"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -333,7 +333,7 @@ fn test_q_mcp_import_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "mcp", feature = "sanity"))] fn test_q_mcp_list_command() -> Result<(), Box> { - println!("πŸ” Testing q mcp list command..."); + println!("πŸ” Testing q mcp list command... | Description: Tests the q mcp list command to display all configured MCP servers and their status"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -376,7 +376,7 @@ fn test_q_mcp_list_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "mcp", feature = "sanity"))] fn test_q_mcp_list_help_command() -> Result<(), Box> { - println!("πŸ” Testing q mcp list --help command..."); + println!("πŸ” Testing q mcp list --help command... | Description: Tests the q mcp list --help command to display help information for listing MCP servers"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -426,7 +426,7 @@ fn test_q_mcp_list_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "mcp", feature = "sanity"))] fn test_q_mcp_status_help_command() -> Result<(), Box> { - println!("πŸ” Testing q mcp status --help command..."); + println!("πŸ” Testing q mcp status --help command... | Description: Tests the q mcp status --help command to display help information for checking MCP server status"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -482,7 +482,7 @@ fn test_q_mcp_status_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "mcp", feature = "sanity"))] fn test_add_and_remove_mcp_command() -> Result<(), Box> { - println!("πŸ” Testing q mcp add command..."); + println!("πŸ” Testing q mcp add command... | Description: Tests the complete workflow of adding and removing an MCP server including configuration and cleanup"); // First install uv dependency before starting Q Chat println!("πŸ” Installing uv dependency..."); @@ -561,7 +561,7 @@ fn test_add_and_remove_mcp_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "mcp", feature = "sanity"))] fn test_q_mcp_status_command() -> Result<(), Box> { - println!("πŸ” Testing q mcp status --name command..."); + println!("πŸ” Testing q mcp status --name command... | Description: Tests the q mcp status command with server name to display detailed status information for a specific MCP server"); // First install uv dependency before starting Q Chat println!("πŸ” Installing uv dependency..."); diff --git a/e2etests/tests/model/test_model_dynamic_command.rs b/e2etests/tests/model/test_model_dynamic_command.rs index 82f0d8fb08..634e2d53f3 100644 --- a/e2etests/tests/model/test_model_dynamic_command.rs +++ b/e2etests/tests/model/test_model_dynamic_command.rs @@ -18,7 +18,7 @@ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] #[cfg(all(feature = "model", feature = "sanity"))] fn test_model_dynamic_command() -> Result<(), Box> { - println!("πŸ” Testing /model command with dynamic selection..."); + println!("πŸ” Testing /model command with dynamic selection... | Description: Tests the /model command interactive selection interface to choose different models and verify selection confirmation"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -137,7 +137,7 @@ fn test_model_dynamic_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "model", feature = "sanity"))] fn test_model_help_command() -> Result<(), Box> { - println!("πŸ” Testing /model --help command..."); + println!("πŸ” Testing /model --help command... | Description: Tests the /model --help command to display help information for model selection functionality"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -176,7 +176,7 @@ fn test_model_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "model", feature = "sanity"))] fn test_model_h_command() -> Result<(), Box> { - println!("πŸ” Testing /model -h command..."); + println!("πŸ” Testing /model -h command... | Description: Tests the /model -h command (short form) to display help information for model selection functionality"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); diff --git a/e2etests/tests/save_load/test_save_load_command.rs b/e2etests/tests/save_load/test_save_load_command.rs index 7a721c6992..650e5669d2 100644 --- a/e2etests/tests/save_load/test_save_load_command.rs +++ b/e2etests/tests/save_load/test_save_load_command.rs @@ -39,7 +39,7 @@ impl<'a> Drop for FileCleanup<'a> { #[test] #[cfg(all(feature = "save_load", feature = "sanity"))] fn test_save_command() -> Result<(), Box> { - println!("πŸ” Testing /save command..."); + println!("πŸ” Testing /save command... | Description: Tests the /save command to export conversation state to a file and verify successful file creation with conversation data"); let save_path = "/tmp/qcli_test_save.json"; let _cleanup = FileCleanup { path: save_path }; @@ -84,7 +84,7 @@ fn test_save_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "save_load", feature = "sanity"))] fn test_save_command_argument_validation() -> Result<(), Box> { - println!("πŸ” Testing /save command..."); + println!("πŸ” Testing /save command argument validation... | Description: Tests the /save command without required arguments to verify proper error handling and usage display"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -122,7 +122,7 @@ fn test_save_command_argument_validation() -> Result<(), Box Result<(), Box> { - println!("πŸ” Testing /save --help command..."); + println!("πŸ” Testing /save --help command... | Description: Tests the /save --help command to display comprehensive help information for save functionality"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -164,7 +164,7 @@ fn test_save_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "save_load", feature = "sanity"))] fn test_save_h_flag_command() -> Result<(), Box> { - println!("πŸ” Testing /save -h command..."); + println!("πŸ” Testing /save -h command... | Description: Tests the /save -h command (short form) to display save help information"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -205,7 +205,7 @@ fn test_save_h_flag_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "save_load", feature = "sanity"))] fn test_save_force_command() -> Result<(), Box> { - println!("πŸ” Testing /save --force command..."); + println!("πŸ” Testing /save --force command... | Description: Tests the /save --force command to overwrite existing files and verify force save functionality"); let save_path = "/tmp/qcli_test_save.json"; let _cleanup = FileCleanup { path: save_path }; @@ -263,7 +263,7 @@ fn test_save_force_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "save_load", feature = "sanity"))] fn test_save_f_flag_command() -> Result<(), Box> { - println!("πŸ” Testing /save -f command..."); + println!("πŸ” Testing /save -f command... | Description: Tests the /save -f command (short form) to force overwrite existing files"); let save_path = "/tmp/qcli_test_save.json"; let _cleanup = FileCleanup { path: save_path }; @@ -321,7 +321,7 @@ fn test_save_f_flag_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "save_load", feature = "sanity"))] fn test_load_help_command() -> Result<(), Box> { - println!("πŸ” Testing /load --help command..."); + println!("πŸ” Testing /load --help command... | Description: Tests the /load --help command to display comprehensive help information for load functionality"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -362,7 +362,7 @@ fn test_load_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "save_load", feature = "sanity"))] fn test_load_h_flag_command() -> Result<(), Box> { - println!("πŸ” Testing /load -h command..."); + println!("πŸ” Testing /load -h command... | Description: Tests the /load -h command (short form) to display load help information"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -403,7 +403,7 @@ fn test_load_h_flag_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "save_load", feature = "sanity"))] fn test_load_command() -> Result<(), Box> { - println!("πŸ” Testing /load command..."); + println!("πŸ” Testing /load command... | Description: Tests the /load command to import conversation state from a saved file and verify successful restoration"); let save_path = "/tmp/qcli_test_load.json"; let _cleanup = FileCleanup { path: save_path }; @@ -457,7 +457,7 @@ fn test_load_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "save_load", feature = "sanity"))] fn test_load_command_argument_validation() -> Result<(), Box> { - println!("πŸ” Testing /load command..."); + println!("πŸ” Testing /load command argument validation... | Description: Tests the /load command without required arguments to verify proper error handling and usage display"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); diff --git a/e2etests/tests/session_mgmt/test_compact_command.rs b/e2etests/tests/session_mgmt/test_compact_command.rs index 1c8faa220b..9dfca3a780 100644 --- a/e2etests/tests/session_mgmt/test_compact_command.rs +++ b/e2etests/tests/session_mgmt/test_compact_command.rs @@ -21,7 +21,7 @@ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] #[cfg(all(feature = "compact", feature = "sanity"))] fn test_compact_command() -> Result<(), Box> { - println!("πŸ” Testing /compact command..."); + println!("πŸ” Testing /compact command... | Description: Tests the /compact command to compress conversation history and verify successful compaction or appropriate messaging for short conversations"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -63,7 +63,7 @@ fn test_compact_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "compact", feature = "sanity"))] fn test_compact_help_command() -> Result<(), Box> { - println!("πŸ” Testing /compact --help command..."); + println!("πŸ” Testing /compact --help command... | Description: Tests the /compact --help command to display comprehensive help information for conversation compaction functionality"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -106,7 +106,7 @@ fn test_compact_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "compact", feature = "sanity"))] fn test_compact_h_command() -> Result<(), Box> { - println!("πŸ” Testing /compact -h command..."); + println!("πŸ” Testing /compact -h command... | Description: Tests the /compact -h command (short form) to display compact help information"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); From 5c195407167309160f5eac8aa208955f79e8a9b5 Mon Sep 17 00:00:00 2001 From: Abhishek Anne Date: Thu, 28 Aug 2025 23:03:49 +0530 Subject: [PATCH 43/77] Modfied system info --- e2etests/html_template.html | 5 ++--- e2etests/run_tests.py | 5 +---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/e2etests/html_template.html b/e2etests/html_template.html index 74e1ea44fa..4239624d3b 100644 --- a/e2etests/html_template.html +++ b/e2etests/html_template.html @@ -77,9 +77,8 @@

{tests_failed}

πŸ’» System Information

Platform: {platform}

-

OS: {os} {os_version}

-

Q Binary: {q_binary_path}

-

Q Version: {q_version}

+ +

Q Binary: {q_binary_info}

diff --git a/e2etests/run_tests.py b/e2etests/run_tests.py index 3c6901bbb1..fe0c60f4d3 100755 --- a/e2etests/run_tests.py +++ b/e2etests/run_tests.py @@ -377,10 +377,7 @@ def generate_html_report(json_filename): tests_failed=report['summary']['failed'], test_suites_content=test_suites_content, platform=report['system_info']['platform'], - os=report['system_info']['os'], - os_version=report['system_info']['os_version'], - q_binary_path=report['system_info']['q_binary_path'], - q_version=report['system_info']['q_version'] + q_binary_info=f"{report['system_info']['q_binary_path']} ({report['system_info']['q_version']})", ) with open(html_filename, 'w') as f: From 0a684375817754eb076f52abe7aee8bada2145c7 Mon Sep 17 00:00:00 2001 From: Abhishek Anne Date: Thu, 28 Aug 2025 23:13:47 +0530 Subject: [PATCH 44/77] Fixed the Suite tital to capitalize --- e2etests/run_tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2etests/run_tests.py b/e2etests/run_tests.py index fe0c60f4d3..7159c7b723 100755 --- a/e2etests/run_tests.py +++ b/e2etests/run_tests.py @@ -328,7 +328,7 @@ def generate_html_report(json_filename): suite_failed = sum(stats["failed"] for stats in suite_features.values()) suite_rate = round((suite_passed / (suite_passed + suite_failed) * 100) if (suite_passed + suite_failed) > 0 else 0, 2) - test_suites_content += f'
' + test_suites_content += f'
' # Add features for this suite for feature_name, feature_stats in suite_features.items(): From b669f7b5c9aa945dc6c1625a59ac099d8fd3223f Mon Sep 17 00:00:00 2001 From: Abhishek Anne Date: Fri, 29 Aug 2025 16:07:59 +0530 Subject: [PATCH 45/77] Clean console output --- e2etests/run_tests.py | 2 +- e2etests/tests/agent/test_agent_commands.rs | 18 ++++----- e2etests/tests/ai_prompts/test_ai_prompt.rs | 4 +- .../tests/ai_prompts/test_prompts_commands.rs | 6 +-- .../tests/context/test_context_command.rs | 20 +++++----- .../tests/core_session/test_clear_command.rs | 8 ++-- .../tests/core_session/test_help_command.rs | 2 +- .../tests/core_session/test_quit_command.rs | 2 +- .../tests/core_session/test_tools_command.rs | 20 +++++----- .../integration/test_editor_help_command.rs | 6 +-- .../tests/integration/test_hooks_command.rs | 8 ++-- .../tests/integration/test_issue_command.rs | 10 ++--- .../integration/test_subscribe_command.rs | 8 ++-- e2etests/tests/mcp/test_mcp_command.rs | 40 +++++++++---------- .../tests/model/test_model_dynamic_command.rs | 10 ++--- .../tests/save_load/test_save_load_command.rs | 20 +++++----- .../session_mgmt/test_compact_command.rs | 6 +-- .../tests/session_mgmt/test_usage_command.rs | 6 +-- 18 files changed, 98 insertions(+), 98 deletions(-) diff --git a/e2etests/run_tests.py b/e2etests/run_tests.py index 7159c7b723..ff60432da1 100755 --- a/e2etests/run_tests.py +++ b/e2etests/run_tests.py @@ -61,7 +61,7 @@ def parse_test_results(stdout): clean_line = line.strip() # Look for test declaration lines - if clean_line.startswith('test ') and ' ... ' in clean_line: + if clean_line.startswith('test ') and ' ...' in clean_line: # Extract test name (everything between 'test ' and ' ... ') test_name = clean_line.split(' ... ')[0].replace('test ', '').strip() diff --git a/e2etests/tests/agent/test_agent_commands.rs b/e2etests/tests/agent/test_agent_commands.rs index a7e46d2777..d49517cba8 100644 --- a/e2etests/tests/agent/test_agent_commands.rs +++ b/e2etests/tests/agent/test_agent_commands.rs @@ -25,7 +25,7 @@ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] #[cfg(all(feature = "agent", feature = "sanity"))] fn agent_without_subcommand() -> Result<(), Box> { - println!("πŸ” Testing /agent command... | Description: Tests the /agent command without subcommands to display help information. Verifies agent management description, usage, available subcommands, and options"); + println!("\nπŸ” Testing /agent command... | Description: Tests the /agent command without subcommands to display help information. Verifies agent management description, usage, available subcommands, and options"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -78,7 +78,7 @@ fn agent_without_subcommand() -> Result<(), Box> { #[test] #[cfg(all(feature = "agent", feature = "sanity"))] fn test_agent_create_command() -> Result<(), Box> { - println!("πŸ” Testing /agent create --name command... | Description: Tests the /agent create command to create a new agent with specified name. Verifies agent creation process, file system operations, and cleanup"); + println!("\nπŸ” Testing /agent create --name command... | Description: Tests the /agent create command to create a new agent with specified name. Verifies agent creation process, file system operations, and cleanup"); let timestamp = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) @@ -147,7 +147,7 @@ fn test_agent_create_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "agent", feature = "sanity"))] fn test_agent_create_missing_args() -> Result<(), Box> { - println!("πŸ” Testing /agent create without required arguments... | Description: Tests the /agent create command without required arguments to verify error handling. Verifies proper error messages, usage information, and help suggestions"); + println!("\nπŸ” Testing /agent create without required arguments... | Description: Tests the /agent create command without required arguments to verify error handling. Verifies proper error messages, usage information, and help suggestions"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -198,7 +198,7 @@ fn test_agent_create_missing_args() -> Result<(), Box> { #[test] #[cfg(all(feature = "agent", feature = "sanity"))] fn test_agent_help_command() -> Result<(), Box> { - println!("πŸ” Testing /agent help... | Description: Tests the /agent help command to display comprehensive agent help information. Verifies agent descriptions, usage notes, launch instructions, and configuration paths"); + println!("\nπŸ” Testing /agent help... | Description: Tests the /agent help command to display comprehensive agent help information. Verifies agent descriptions, usage notes, launch instructions, and configuration paths"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -255,7 +255,7 @@ fn test_agent_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "agent", feature = "sanity"))] fn test_agent_invalid_command() -> Result<(), Box> { - println!("πŸ” Testing /agent invalidcommand... | Description: Tests the /agent command with invalid subcommand to verify error handling. Verifies that invalid commands display help information with available commands and options"); + println!("\nπŸ” Testing /agent invalidcommand... | Description: Tests the /agent command with invalid subcommand to verify error handling. Verifies that invalid commands display help information with available commands and options"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -294,7 +294,7 @@ fn test_agent_invalid_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "agent", feature = "sanity"))] fn test_agent_list_command() -> Result<(), Box> { - println!("πŸ” Testing /agent list command... | Description: Tests the /agent list command to display all available agents. Verifies agent listing format and presence of default agent"); + println!("\nπŸ” Testing /agent list command... | Description: Tests the /agent list command to display all available agents. Verifies agent listing format and presence of default agent"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -328,7 +328,7 @@ fn test_agent_list_command() -> Result<(), Box> { // #[test] // #[cfg(feature = "agent")] // fn test_agent_schema_command() -> Result<(), Box> { -// println!("πŸ” Testing /agent schema... | Description: Tests the /agent schema command to display agent configuration schema. Verifies JSON schema structure with required keys and properties"); +// println!("\nπŸ” Testing /agent schema... | Description: Tests the /agent schema command to display agent configuration schema. Verifies JSON schema structure with required keys and properties"); // let session = get_chat_session(); // let mut chat = session.lock().unwrap(); @@ -369,7 +369,7 @@ fn test_agent_list_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "agent", feature = "sanity"))] fn test_agent_set_default_command() -> Result<(), Box> { - println!("πŸ” Testing /agent set-default with valid arguments... | Description: Tests the /agent set-default command with valid arguments to set default agent. Verifies success messages and confirmation of default agent configuration"); + println!("\nπŸ” Testing /agent set-default with valid arguments... | Description: Tests the /agent set-default command with valid arguments to set default agent. Verifies success messages and confirmation of default agent configuration"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -410,7 +410,7 @@ fn test_agent_set_default_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "agent", feature = "sanity"))] fn test_agent_set_default_missing_args() -> Result<(), Box> { - println!("πŸ” Testing /agent set-default without required arguments... | Description: Tests the /agent set-default command without required arguments to verify error handling. Verifies error messages, usage information, and available options display"); + println!("\nπŸ” Testing /agent set-default without required arguments... | Description: Tests the /agent set-default command without required arguments to verify error handling. Verifies error messages, usage information, and available options display"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); diff --git a/e2etests/tests/ai_prompts/test_ai_prompt.rs b/e2etests/tests/ai_prompts/test_ai_prompt.rs index f5620ff912..65b2b6c879 100644 --- a/e2etests/tests/ai_prompts/test_ai_prompt.rs +++ b/e2etests/tests/ai_prompts/test_ai_prompt.rs @@ -4,7 +4,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] #[cfg(all(feature = "ai_prompts", feature = "sanity"))] fn test_what_is_aws_prompt() -> Result<(), Box> { - println!("πŸ” [AI PROMPTS] Testing 'What is AWS?' AI prompt... | Description: Tests AI prompt functionality by sending 'What is AWS?' and verifying the response contains relevant AWS information and technical terms"); + println!("\nπŸ” [AI PROMPTS] Testing 'What is AWS?' AI prompt... | Description: Tests AI prompt functionality by sending 'What is AWS?' and verifying the response contains relevant AWS information and technical terms"); let mut chat = QChatSession::new()?; println!("βœ… Q Chat session started"); @@ -57,7 +57,7 @@ fn test_what_is_aws_prompt() -> Result<(), Box> { #[test] #[cfg(all(feature = "ai_prompts", feature = "sanity"))] fn test_simple_greeting() -> Result<(), Box> { - println!("πŸ” Testing simple 'Hello' prompt... | Description: Tests basic AI interaction by sending a simple greeting and verifying the AI responds appropriately with greeting-related content"); + println!("\nπŸ” Testing simple 'Hello' prompt... | Description: Tests basic AI interaction by sending a simple greeting and verifying the AI responds appropriately with greeting-related content"); let mut chat = QChatSession::new()?; println!("βœ… Q Chat session started"); diff --git a/e2etests/tests/ai_prompts/test_prompts_commands.rs b/e2etests/tests/ai_prompts/test_prompts_commands.rs index 6407f7913c..83fc4d0ea3 100644 --- a/e2etests/tests/ai_prompts/test_prompts_commands.rs +++ b/e2etests/tests/ai_prompts/test_prompts_commands.rs @@ -19,7 +19,7 @@ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] #[cfg(all(feature = "ai_prompts", feature = "sanity"))] fn test_prompts_command() -> Result<(), Box> { - println!("πŸ” Testing /prompts command... | Description: Tests the /prompts command to display available prompts with usage instructions and argument requirements"); + println!("\nπŸ” Testing /prompts command... | Description: Tests the /prompts command to display available prompts with usage instructions and argument requirements"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -58,7 +58,7 @@ fn test_prompts_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "ai_prompts", feature = "sanity"))] fn test_prompts_help_command() -> Result<(), Box> { - println!("πŸ” Testing /prompts --help command... | Description: Tests the /prompts --help command to display comprehensive help information about prompts functionality and MCP server integration"); + println!("\nπŸ” Testing /prompts --help command... | Description: Tests the /prompts --help command to display comprehensive help information about prompts functionality and MCP server integration"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -119,7 +119,7 @@ fn test_prompts_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "ai_prompts", feature = "sanity"))] fn test_prompts_list_command() -> Result<(), Box> { - println!("πŸ” Testing /prompts list command... | Description: Tests the /prompts list command to display all available prompts with their arguments and usage information"); + println!("\nπŸ” Testing /prompts list command... | Description: Tests the /prompts list command to display all available prompts with their arguments and usage information"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); diff --git a/e2etests/tests/context/test_context_command.rs b/e2etests/tests/context/test_context_command.rs index e8a8623acd..56b22bb4b9 100644 --- a/e2etests/tests/context/test_context_command.rs +++ b/e2etests/tests/context/test_context_command.rs @@ -25,7 +25,7 @@ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] #[cfg(all(feature = "context", feature = "sanity"))] fn test_context_show_command() -> Result<(), Box> { - println!("πŸ” Testing /context show command... | Description: Tests the /context show command to display current context information including agent configuration and context files"); + println!("\nπŸ” Testing /context show command... | Description: Tests the /context show command to display current context information including agent configuration and context files"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -59,7 +59,7 @@ fn test_context_show_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "context", feature = "sanity"))] fn test_context_help_command() -> Result<(), Box> { - println!("πŸ” Testing /context help command... | Description: Tests the /context help command to display comprehensive help information for context management including usage, commands, and options"); + println!("\nπŸ” Testing /context help command... | Description: Tests the /context help command to display comprehensive help information for context management including usage, commands, and options"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -101,7 +101,7 @@ fn test_context_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "context", feature = "sanity"))] fn test_context_without_subcommand() -> Result<(), Box> { - println!("πŸ” Testing /context without sub command... | Description: Tests the /context command without subcommands to verify it displays help information with usage and available commands"); + println!("\nπŸ” Testing /context without sub command... | Description: Tests the /context command without subcommands to verify it displays help information with usage and available commands"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -139,7 +139,7 @@ fn test_context_without_subcommand() -> Result<(), Box> { #[test] #[cfg(all(feature = "context", feature = "sanity"))] fn test_context_invalid_command() -> Result<(), Box> { - println!("πŸ” Testing /context invalid command... | Description: Tests the /context command with invalid subcommand to verify proper error handling and help display"); + println!("\nπŸ” Testing /context invalid command... | Description: Tests the /context command with invalid subcommand to verify proper error handling and help display"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -169,7 +169,7 @@ fn test_context_invalid_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "context", feature = "sanity"))] fn test_add_non_existing_file_context() -> Result<(), Box> { - println!("πŸ” Testing /context add non-existing file command... | Description: Tests the /context add command with non-existing file to verify proper error handling and force option suggestion"); + println!("\nπŸ” Testing /context add non-existing file command... | Description: Tests the /context add command with non-existing file to verify proper error handling and force option suggestion"); let non_existing_file_path = "/tmp/non_existing_file.py"; @@ -200,7 +200,7 @@ fn test_add_non_existing_file_context() -> Result<(), Box #[test] #[cfg(all(feature = "context", feature = "sanity"))] fn test_context_remove_command_of_non_existent_file() -> Result<(), Box> { - println!("πŸ” Testing /context remove non existing file command... | Description: Tests the /context remove command with non-existing file to verify proper error handling"); + println!("\nπŸ” Testing /context remove non existing file command... | Description: Tests the /context remove command with non-existing file to verify proper error handling"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -228,7 +228,7 @@ fn test_context_remove_command_of_non_existent_file() -> Result<(), Box Result<(), Box> { - println!("πŸ” Testing /context add command and /context remove command... | Description: Tests the complete workflow of adding a file to context, verifying it appears in context show, then removing it and verifying removal"); + println!("\nπŸ” Testing /context add command and /context remove command... | Description: Tests the complete workflow of adding a file to context, verifying it appears in context show, then removing it and verifying removal"); let test_file_path = "/tmp/test_context_file_.py"; // Create a test file @@ -302,7 +302,7 @@ fn test_add_remove_file_context() -> Result<(), Box> { #[test] #[cfg(all(feature = "context", feature = "sanity"))] fn test_add_glob_pattern_file_context()-> Result<(), Box> { - println!("πŸ” Testing /context add *.py glob pattern command... | Description: Tests the /context add command with glob patterns to add multiple files matching a pattern and verify pattern-based context management"); + println!("\nπŸ” Testing /context add *.py glob pattern command... | Description: Tests the /context add command with glob patterns to add multiple files matching a pattern and verify pattern-based context management"); let test_file1_path = "/tmp/test_context_file1.py"; let test_file2_path = "/tmp/test_context_file2.py"; @@ -384,7 +384,7 @@ fn test_add_glob_pattern_file_context()-> Result<(), Box> #[test] #[cfg(all(feature = "context", feature = "sanity"))] fn test_add_remove_multiple_file_context()-> Result<(), Box> { - println!("πŸ” Testing /context add command and /context remove ... | Description: Tests adding and removing multiple files in a single command to verify batch context operations"); + println!("\nπŸ” Testing /context add command and /context remove ... | Description: Tests adding and removing multiple files in a single command to verify batch context operations"); let test_file1_path = "/tmp/test_context_file1.py"; let test_file2_path = "/tmp/test_context_file2.py"; @@ -469,7 +469,7 @@ fn test_add_remove_multiple_file_context()-> Result<(), Box Result<(), Box> { - println!("πŸ” Testing /context clear command... | Description: Tests the /context clear command to remove all files from context and verify the context is completely cleared"); + println!("\nπŸ” Testing /context clear command... | Description: Tests the /context clear command to remove all files from context and verify the context is completely cleared"); let test_file_path = "/tmp/test_context_file.py"; diff --git a/e2etests/tests/core_session/test_clear_command.rs b/e2etests/tests/core_session/test_clear_command.rs index 0261efaec1..69232a6240 100644 --- a/e2etests/tests/core_session/test_clear_command.rs +++ b/e2etests/tests/core_session/test_clear_command.rs @@ -4,13 +4,13 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] #[cfg(all(feature = "clear", feature = "sanity"))] fn test_clear_command() -> Result<(), Box> { - println!("πŸ” Testing /clear command... | Description: Tests the /clear command to clear conversation history and verify that previous context is no longer remembered by the AI"); + println!("\nπŸ” Testing /clear command... | Description: Tests the /clear command to clear conversation history and verify that previous context is no longer remembered by the AI"); let mut chat = QChatSession::new()?; println!("βœ… Q Chat session started"); // Send initial message - println!("πŸ” Sending prompt: 'My name is TestUser'"); + println!("\nπŸ” Sending prompt: 'My name is TestUser'"); let _initial_response = chat.send_prompt("My name is TestUser")?; println!("πŸ“ Initial response: {} bytes", _initial_response.len()); println!("πŸ“ INITIAL RESPONSE OUTPUT:"); @@ -18,13 +18,13 @@ fn test_clear_command() -> Result<(), Box> { println!("πŸ“ END INITIAL RESPONSE"); // Execute clear command - println!("πŸ” Executing command: '/clear'"); + println!("\nπŸ” Executing command: '/clear'"); let _clear_response = chat.execute_command("/clear")?; println!("βœ… Clear command executed"); // Check if AI remembers previous conversation - println!("πŸ” Sending prompt: 'What is my name?'"); + println!("\nπŸ” Sending prompt: 'What is my name?'"); let test_response = chat.send_prompt("What is my name?")?; println!("πŸ“ Test response: {} bytes", test_response.len()); println!("πŸ“ TEST RESPONSE OUTPUT:"); diff --git a/e2etests/tests/core_session/test_help_command.rs b/e2etests/tests/core_session/test_help_command.rs index cee19f8d6a..64be2a85ca 100644 --- a/e2etests/tests/core_session/test_help_command.rs +++ b/e2etests/tests/core_session/test_help_command.rs @@ -4,7 +4,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] #[cfg(all(feature = "help", feature = "sanity"))] fn test_help_command() -> Result<(), Box> { - println!("πŸ” Testing /help command... | Description: Tests the /help command to display all available commands and verify core functionality like quit, clear, tools, and help commands are present"); + println!("\nπŸ” Testing /help command... | Description: Tests the /help command to display all available commands and verify core functionality like quit, clear, tools, and help commands are present"); let mut chat = QChatSession::new()?; println!("βœ… Q Chat session started"); diff --git a/e2etests/tests/core_session/test_quit_command.rs b/e2etests/tests/core_session/test_quit_command.rs index fdd28370c6..952d306cb4 100644 --- a/e2etests/tests/core_session/test_quit_command.rs +++ b/e2etests/tests/core_session/test_quit_command.rs @@ -4,7 +4,7 @@ use q_cli_e2e_tests::q_chat_helper::QChatSession; #[test] #[cfg(all(feature = "quit", feature = "sanity"))] fn test_quit_command() -> Result<(), Box> { - println!("πŸ” Testing /quit command... | Description: Tests the /quit command to properly terminate the Q Chat session and exit cleanly"); + println!("\nπŸ” Testing /quit command... | Description: Tests the /quit command to properly terminate the Q Chat session and exit cleanly"); let mut chat = QChatSession::new()?; println!("βœ… Q Chat session started"); diff --git a/e2etests/tests/core_session/test_tools_command.rs b/e2etests/tests/core_session/test_tools_command.rs index 2e6729a973..381788f414 100644 --- a/e2etests/tests/core_session/test_tools_command.rs +++ b/e2etests/tests/core_session/test_tools_command.rs @@ -24,7 +24,7 @@ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] #[cfg(all(feature = "tools", feature = "sanity"))] fn test_tools_command() -> Result<(), Box> { - println!("πŸ” Testing /tools command... | Description: Tests the /tools command to display all available tools with their permission status including built-in and MCP tools"); + println!("\nπŸ” Testing /tools command... | Description: Tests the /tools command to display all available tools with their permission status including built-in and MCP tools"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -79,7 +79,7 @@ fn test_tools_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "tools", feature = "sanity"))] fn test_tools_help_command() -> Result<(), Box> { - println!("πŸ” Testing /tools --help command... | Description: Tests the /tools --help command to display comprehensive help information about tools management including available subcommands and options"); + println!("\nπŸ” Testing /tools --help command... | Description: Tests the /tools --help command to display comprehensive help information about tools management including available subcommands and options"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -125,7 +125,7 @@ fn test_tools_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "tools", feature = "sanity"))] fn test_tools_trust_all_command() -> Result<(), Box> { - println!("πŸ” Testing /tools trust-all command... | Description: Tests the /tools trust-all command to trust all available tools and verify all tools show trusted status, then tests reset functionality"); + println!("\nπŸ” Testing /tools trust-all command... | Description: Tests the /tools trust-all command to trust all available tools and verify all tools show trusted status, then tests reset functionality"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -205,7 +205,7 @@ fn test_tools_trust_all_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "tools", feature = "sanity"))] fn test_tools_trust_all_help_command() -> Result<(), Box> { - println!("πŸ” Testing /tools trust-all --help command... | Description: Tests the /tools trust-all --help command to display help information for the trust-all subcommand"); + println!("\nπŸ” Testing /tools trust-all --help command... | Description: Tests the /tools trust-all --help command to display help information for the trust-all subcommand"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -241,7 +241,7 @@ fn test_tools_trust_all_help_command() -> Result<(), Box> #[test] #[cfg(all(feature = "tools", feature = "sanity"))] fn test_tools_reset_help_command() -> Result<(), Box> { - println!("πŸ” Testing /tools reset --help command... | Description: Tests the /tools reset --help command to display help information for the reset subcommand"); + println!("\nπŸ” Testing /tools reset --help command... | Description: Tests the /tools reset --help command to display help information for the reset subcommand"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -276,7 +276,7 @@ fn test_tools_reset_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "tools", feature = "sanity"))] fn test_tools_trust_command() -> Result<(), Box> { - println!("πŸ” Testing /tools trust command... | Description: Tests the /tools trust and untrust commands to manage individual tool permissions and verify trust status changes"); + println!("\nπŸ” Testing /tools trust command... | Description: Tests the /tools trust and untrust commands to manage individual tool permissions and verify trust status changes"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -354,7 +354,7 @@ fn test_tools_trust_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "tools", feature = "sanity"))] fn test_tools_trust_help_command() -> Result<(), Box> { - println!("πŸ” Testing /tools trust --help command... | Description: Tests the /tools trust --help command to display help information for trusting specific tools"); + println!("\nπŸ” Testing /tools trust --help command... | Description: Tests the /tools trust --help command to display help information for trusting specific tools"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -393,7 +393,7 @@ fn test_tools_trust_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "tools", feature = "sanity"))] fn test_tools_untrust_help_command() -> Result<(), Box> { - println!("πŸ” Testing /tools untrust --help command... | Description: Tests the /tools untrust --help command to display help information for untrusting specific tools"); + println!("\nπŸ” Testing /tools untrust --help command... | Description: Tests the /tools untrust --help command to display help information for untrusting specific tools"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -432,7 +432,7 @@ fn test_tools_untrust_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "tools", feature = "sanity"))] fn test_tools_schema_help_command() -> Result<(), Box> { - println!("πŸ” Testing /tools schema --help command... | Description: Tests the /tools schema --help command to display help information for viewing tool schemas"); + println!("\nπŸ” Testing /tools schema --help command... | Description: Tests the /tools schema --help command to display help information for viewing tool schemas"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -467,7 +467,7 @@ fn test_tools_schema_help_command() -> Result<(), Box> { /*#[test] #[cfg(feature = "tools")] fn test_tools_schema_command() -> Result<(), Box> { - println!("πŸ” Testing /tools schema command..."); + println!("\nπŸ” Testing /tools schema command..."); let session = get_chat_session(); let mut chat = session.lock().unwrap(); diff --git a/e2etests/tests/integration/test_editor_help_command.rs b/e2etests/tests/integration/test_editor_help_command.rs index 674458c1e7..f7cfa8a91e 100644 --- a/e2etests/tests/integration/test_editor_help_command.rs +++ b/e2etests/tests/integration/test_editor_help_command.rs @@ -18,7 +18,7 @@ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] #[cfg(all(feature = "editor", feature = "sanity"))] fn test_editor_help_command() -> Result<(), Box> { - println!("πŸ” Testing /editor --help command... | Description: Tests the /editor --help command to display help information for the editor functionality including usage and options"); + println!("\nπŸ” Testing /editor --help command... | Description: Tests the /editor --help command to display help information for the editor functionality including usage and options"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -61,7 +61,7 @@ fn test_editor_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "editor", feature = "sanity"))] fn test_help_editor_command() -> Result<(), Box> { - println!("πŸ” Testing /help editor command... | Description: Tests the /help editor command to display editor-specific help information and usage instructions"); + println!("\nπŸ” Testing /help editor command... | Description: Tests the /help editor command to display editor-specific help information and usage instructions"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -104,7 +104,7 @@ fn test_help_editor_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "editor", feature = "sanity"))] fn test_editor_h_command() -> Result<(), Box> { - println!("πŸ” Testing /editor -h command... | Description: Tests the /editor -h command (short form) to display editor help information and verify proper flag handling"); + println!("\nπŸ” Testing /editor -h command... | Description: Tests the /editor -h command (short form) to display editor help information and verify proper flag handling"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); diff --git a/e2etests/tests/integration/test_hooks_command.rs b/e2etests/tests/integration/test_hooks_command.rs index 5b2f3f747c..b732f8e0dd 100644 --- a/e2etests/tests/integration/test_hooks_command.rs +++ b/e2etests/tests/integration/test_hooks_command.rs @@ -10,7 +10,7 @@ static TEST_COUNT: AtomicUsize = AtomicUsize::new(0); const TEST_NAMES: &[&str] = &[ "test_hooks_command", "test_hooks_help_command", - "test_hooks_h_command", + "test_hooks_h_command", ]; #[allow(dead_code)] const TOTAL_TESTS: usize = TEST_NAMES.len(); @@ -18,7 +18,7 @@ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] #[cfg(all(feature = "hooks", feature = "sanity"))] fn test_hooks_command() -> Result<(), Box> { - println!("πŸ” Testing /hooks command... | Description: Tests the /hooks command to display configured hooks or show no hooks message when none are configured"); + println!("\nπŸ” Testing /hooks command... | Description: Tests the /hooks command to display configured hooks or show no hooks message when none are configured"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -48,7 +48,7 @@ fn test_hooks_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "hooks", feature = "sanity"))] fn test_hooks_help_command() -> Result<(), Box> { - println!("πŸ” Testing /hooks --help command... | Description: Tests the /hooks --help command to display comprehensive help information for hooks functionality and configuration"); + println!("\nπŸ” Testing /hooks --help command... | Description: Tests the /hooks --help command to display comprehensive help information for hooks functionality and configuration"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -87,7 +87,7 @@ fn test_hooks_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "hooks", feature = "sanity"))] fn test_hooks_h_command() -> Result<(), Box> { - println!("πŸ” Testing /hooks -h command... | Description: Tests the /hooks -h command (short form) to display hooks help information and verify flag handling"); + println!("\nπŸ” Testing /hooks -h command... | Description: Tests the /hooks -h command (short form) to display hooks help information and verify flag handling"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); diff --git a/e2etests/tests/integration/test_issue_command.rs b/e2etests/tests/integration/test_issue_command.rs index f98112f668..545d786b47 100644 --- a/e2etests/tests/integration/test_issue_command.rs +++ b/e2etests/tests/integration/test_issue_command.rs @@ -20,7 +20,7 @@ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] #[cfg(all(feature = "issue_reporting", feature = "sanity"))] fn test_issue_command() -> Result<(), Box> { - println!("πŸ” Testing /issue command with bug report... | Description: Tests the /issue command to create a bug report and verify it opens GitHub issue creation interface"); + println!("\nπŸ” Testing /issue command with bug report... | Description: Tests the /issue command to create a bug report and verify it opens GitHub issue creation interface"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -50,7 +50,7 @@ fn test_issue_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "issue_reporting", feature = "sanity"))] fn test_issue_force_command() -> Result<(), Box> { - println!("πŸ” Testing /issue --force command with critical bug... | Description: Tests the /issue --force command to create a critical bug report and verify forced issue creation workflow"); + println!("\nπŸ” Testing /issue --force command with critical bug... | Description: Tests the /issue --force command to create a critical bug report and verify forced issue creation workflow"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -80,7 +80,7 @@ fn test_issue_force_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "issue_reporting", feature = "sanity"))] fn test_issue_f_command() -> Result<(), Box> { - println!("πŸ” Testing /issue -f command with critical bug... | Description: Tests the /issue -f command (short form) to create a critical bug report with force flag"); + println!("\nπŸ” Testing /issue -f command with critical bug... | Description: Tests the /issue -f command (short form) to create a critical bug report with force flag"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -111,7 +111,7 @@ fn test_issue_f_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "issue_reporting", feature = "sanity"))] fn test_issue_help_command() -> Result<(), Box> { - println!("πŸ” Testing /issue --help command... | Description: Tests the /issue --help command to display help information for issue reporting functionality including options and usage"); + println!("\nπŸ” Testing /issue --help command... | Description: Tests the /issue --help command to display help information for issue reporting functionality including options and usage"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -151,7 +151,7 @@ fn test_issue_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "issue_reporting", feature = "sanity"))] fn test_issue_h_command() -> Result<(), Box> { - println!("πŸ” Testing /issue -h command... | Description: Tests the /issue -h command (short form) to display issue reporting help information"); + println!("\nπŸ” Testing /issue -h command... | Description: Tests the /issue -h command (short form) to display issue reporting help information"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); diff --git a/e2etests/tests/integration/test_subscribe_command.rs b/e2etests/tests/integration/test_subscribe_command.rs index 8bf83f68bb..bbf8436415 100644 --- a/e2etests/tests/integration/test_subscribe_command.rs +++ b/e2etests/tests/integration/test_subscribe_command.rs @@ -20,7 +20,7 @@ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] #[cfg(all(feature = "subscribe", feature = "sanity"))] fn test_subscribe_command() -> Result<(), Box> { - println!("πŸ” Testing /subscribe command... | Description: Tests the /subscribe command to display Q Developer Pro subscription information and IAM Identity Center details"); + println!("\nπŸ” Testing /subscribe command... | Description: Tests the /subscribe command to display Q Developer Pro subscription information and IAM Identity Center details"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -50,7 +50,7 @@ fn test_subscribe_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "subscribe", feature = "sanity"))] fn test_subscribe_manage_command() -> Result<(), Box> { - println!("πŸ” Testing /subscribe --manage command... | Description: Tests the /subscribe --manage command to access subscription management interface for Q Developer Pro"); + println!("\nπŸ” Testing /subscribe --manage command... | Description: Tests the /subscribe --manage command to access subscription management interface for Q Developer Pro"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -80,7 +80,7 @@ fn test_subscribe_manage_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "subscribe", feature = "sanity"))] fn test_subscribe_help_command() -> Result<(), Box> { - println!("πŸ” Testing /subscribe --help command... | Description: Tests the /subscribe --help command to display comprehensive help information for subscription management"); + println!("\nπŸ” Testing /subscribe --help command... | Description: Tests the /subscribe --help command to display comprehensive help information for subscription management"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -128,7 +128,7 @@ fn test_subscribe_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "subscribe", feature = "sanity"))] fn test_subscribe_h_command() -> Result<(), Box> { - println!("πŸ” Testing /subscribe -h command... | Description: Tests the /subscribe -h command (short form) to display subscription help information"); + println!("\nπŸ” Testing /subscribe -h command... | Description: Tests the /subscribe -h command (short form) to display subscription help information"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); diff --git a/e2etests/tests/mcp/test_mcp_command.rs b/e2etests/tests/mcp/test_mcp_command.rs index d3955d9e38..5546e831ab 100644 --- a/e2etests/tests/mcp/test_mcp_command.rs +++ b/e2etests/tests/mcp/test_mcp_command.rs @@ -26,7 +26,7 @@ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] #[cfg(all(feature = "mcp", feature = "sanity"))] fn test_mcp_help_command() -> Result<(), Box> { - println!("πŸ” Testing /mcp --help command... | Description: Tests the /mcp --help command to display help information for MCP server management functionality"); + println!("\nπŸ” Testing /mcp --help command... | Description: Tests the /mcp --help command to display help information for MCP server management functionality"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -69,7 +69,7 @@ fn test_mcp_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "mcp", feature = "sanity"))] fn test_mcp_loading_command() -> Result<(), Box> { - println!("πŸ” Testing MCP loading... | Description: Tests MCP server loading status and displays information about loaded MCP servers with timing"); + println!("\nπŸ” Testing MCP loading... | Description: Tests MCP server loading status and displays information about loaded MCP servers with timing"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -109,7 +109,7 @@ fn test_mcp_loading_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "mcp", feature = "sanity"))] fn test_mcp_remove_help_command() -> Result<(), Box> { - println!("πŸ” Testing q mcp remove --help command... | Description: Tests the q mcp remove --help command to display help information for removing MCP servers"); + println!("\nπŸ” Testing q mcp remove --help command... | Description: Tests the q mcp remove --help command to display help information for removing MCP servers"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -156,13 +156,13 @@ fn test_mcp_remove_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "mcp", feature = "sanity"))] fn test_q_mcp_add_help_command() -> Result<(), Box> { - println!("πŸ” Testing q mcp add --help command... | Description: Tests the q mcp add --help command to display help information for adding new MCP servers"); + println!("\nπŸ” Testing q mcp add --help command... | Description: Tests the q mcp add --help command to display help information for adding new MCP servers"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); // Execute mcp add --help command - println!("πŸ” Executing command: 'q mcp add --help'"); + println!("\nπŸ” Executing command: 'q mcp add --help'"); let response = chat.execute_command("q mcp add --help")?; println!("πŸ“ Restart response: {} bytes", response.len()); @@ -214,7 +214,7 @@ fn test_q_mcp_add_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "mcp", feature = "sanity"))] fn test_q_mcp_help_command() -> Result<(), Box> { - println!("πŸ” Testing q mcp --help command... | Description: Tests the q mcp --help command to display comprehensive MCP management help including all subcommands"); + println!("\nπŸ” Testing q mcp --help command... | Description: Tests the q mcp --help command to display comprehensive MCP management help including all subcommands"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -271,13 +271,13 @@ fn test_q_mcp_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "mcp", feature = "sanity"))] fn test_q_mcp_import_help_command() -> Result<(), Box> { - println!("πŸ” Testing q mcp import --help command... | Description: Tests the q mcp import --help command to display help information for importing MCP server configurations"); + println!("\nπŸ” Testing q mcp import --help command... | Description: Tests the q mcp import --help command to display help information for importing MCP server configurations"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); // Execute mcp import --help command - println!("πŸ” Executing command: 'q mcp import --help'"); + println!("\nπŸ” Executing command: 'q mcp import --help'"); let response = chat.execute_command("q mcp import --help")?; println!("πŸ“ Restart response: {} bytes", response.len()); @@ -333,7 +333,7 @@ fn test_q_mcp_import_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "mcp", feature = "sanity"))] fn test_q_mcp_list_command() -> Result<(), Box> { - println!("πŸ” Testing q mcp list command... | Description: Tests the q mcp list command to display all configured MCP servers and their status"); + println!("\nπŸ” Testing q mcp list command... | Description: Tests the q mcp list command to display all configured MCP servers and their status"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -376,7 +376,7 @@ fn test_q_mcp_list_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "mcp", feature = "sanity"))] fn test_q_mcp_list_help_command() -> Result<(), Box> { - println!("πŸ” Testing q mcp list --help command... | Description: Tests the q mcp list --help command to display help information for listing MCP servers"); + println!("\nπŸ” Testing q mcp list --help command... | Description: Tests the q mcp list --help command to display help information for listing MCP servers"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -426,13 +426,13 @@ fn test_q_mcp_list_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "mcp", feature = "sanity"))] fn test_q_mcp_status_help_command() -> Result<(), Box> { - println!("πŸ” Testing q mcp status --help command... | Description: Tests the q mcp status --help command to display help information for checking MCP server status"); + println!("\nπŸ” Testing q mcp status --help command... | Description: Tests the q mcp status --help command to display help information for checking MCP server status"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); // Execute mcp status --help command - println!("πŸ” Executing command: 'q mcp status --help'"); + println!("\nπŸ” Executing command: 'q mcp status --help'"); let response = chat.execute_command("q mcp status --help")?; println!("πŸ“ Restart response: {} bytes", response.len()); @@ -482,10 +482,10 @@ fn test_q_mcp_status_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "mcp", feature = "sanity"))] fn test_add_and_remove_mcp_command() -> Result<(), Box> { - println!("πŸ” Testing q mcp add command... | Description: Tests the complete workflow of adding and removing an MCP server including configuration and cleanup"); + println!("\nπŸ” Testing q mcp add command... | Description: Tests the complete workflow of adding and removing an MCP server including configuration and cleanup"); // First install uv dependency before starting Q Chat - println!("πŸ” Installing uv dependency..."); + println!("\nπŸ” Installing uv dependency..."); std::process::Command::new("pip3") .args(["install", "uv", "--break-system-packages"]) @@ -498,7 +498,7 @@ fn test_add_and_remove_mcp_command() -> Result<(), Box> { let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); // Execute mcp add command - println!("πŸ” Executing command: 'q mcp add --name aws-documentation --command uvx --args awslabs.aws-documentation-mcp-server@latest'"); + println!("\nπŸ” Executing command: 'q mcp add --name aws-documentation --command uvx --args awslabs.aws-documentation-mcp-server@latest'"); let response = chat.execute_command("q mcp add --name aws-documentation --command uvx --args awslabs.aws-documentation-mcp-server@latest")?; println!("πŸ“ Response: {} bytes", response.len()); @@ -525,7 +525,7 @@ fn test_add_and_remove_mcp_command() -> Result<(), Box> { println!("βœ… Found successful addition message"); // Now test removing the MCP server - println!("πŸ” Executing remove command: 'q mcp remove --name aws-documentation'"); + println!("\nπŸ” Executing remove command: 'q mcp remove --name aws-documentation'"); let remove_response = chat.execute_command("q mcp remove --name aws-documentation")?; println!("πŸ“ Remove response: {} bytes", remove_response.len()); println!("πŸ“ REMOVE RESPONSE:"); @@ -561,10 +561,10 @@ fn test_add_and_remove_mcp_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "mcp", feature = "sanity"))] fn test_q_mcp_status_command() -> Result<(), Box> { - println!("πŸ” Testing q mcp status --name command... | Description: Tests the q mcp status command with server name to display detailed status information for a specific MCP server"); + println!("\nπŸ” Testing q mcp status --name command... | Description: Tests the q mcp status command with server name to display detailed status information for a specific MCP server"); // First install uv dependency before starting Q Chat - println!("πŸ” Installing uv dependency..."); + println!("\nπŸ” Installing uv dependency..."); std::process::Command::new("pip3") .args(["install", "uv", "--break-system-packages"]) @@ -577,7 +577,7 @@ fn test_q_mcp_status_command() -> Result<(), Box> { let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); // Execute mcp add command - println!("πŸ” Executing command: 'q mcp add --name aws-documentation --command uvx --args awslabs.aws-documentation-mcp-server@latest'"); + println!("\nπŸ” Executing command: 'q mcp add --name aws-documentation --command uvx --args awslabs.aws-documentation-mcp-server@latest'"); let response = chat.execute_command("q mcp add --name aws-documentation --command uvx --args awslabs.aws-documentation-mcp-server@latest")?; println!("πŸ“ Response: {} bytes", response.len()); @@ -629,7 +629,7 @@ fn test_q_mcp_status_command() -> Result<(), Box> { assert!(show_response.contains("Env Vars"), "Missing Env Vars"); // Now test removing the MCP server - println!("πŸ” Executing remove command: 'q mcp remove --name aws-documentation'"); + println!("\nπŸ” Executing remove command: 'q mcp remove --name aws-documentation'"); let remove_response = chat.execute_command("q mcp remove --name aws-documentation")?; println!("πŸ“ Remove response: {} bytes", remove_response.len()); println!("πŸ“ REMOVE RESPONSE:"); diff --git a/e2etests/tests/model/test_model_dynamic_command.rs b/e2etests/tests/model/test_model_dynamic_command.rs index 634e2d53f3..3ff703d5c5 100644 --- a/e2etests/tests/model/test_model_dynamic_command.rs +++ b/e2etests/tests/model/test_model_dynamic_command.rs @@ -18,7 +18,7 @@ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] #[cfg(all(feature = "model", feature = "sanity"))] fn test_model_dynamic_command() -> Result<(), Box> { - println!("πŸ” Testing /model command with dynamic selection... | Description: Tests the /model command interactive selection interface to choose different models and verify selection confirmation"); + println!("\nπŸ” Testing /model command with dynamic selection... | Description: Tests the /model command interactive selection interface to choose different models and verify selection confirmation"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -63,7 +63,7 @@ fn test_model_dynamic_command() -> Result<(), Box> { // After finding prompt, parse model lines if found_prompt { let cleaned_line = strip_ansi(trimmed_line); - println!("πŸ” Row: '{}' -> Cleaned: '{}'", trimmed_line, cleaned_line); + println!("\nπŸ” Row: '{}' -> Cleaned: '{}'", trimmed_line, cleaned_line); if !trimmed_line.is_empty() { // Check if line contains a model (starts with ❯, spaces, or contains model names) @@ -74,7 +74,7 @@ fn test_model_dynamic_command() -> Result<(), Box> { .trim() .to_string(); - println!("πŸ” Extracted model: '{}'", model_name); + println!("\nπŸ” Extracted model: '{}'", model_name); if !model_name.is_empty() { models.push(model_name); } @@ -137,7 +137,7 @@ fn test_model_dynamic_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "model", feature = "sanity"))] fn test_model_help_command() -> Result<(), Box> { - println!("πŸ” Testing /model --help command... | Description: Tests the /model --help command to display help information for model selection functionality"); + println!("\nπŸ” Testing /model --help command... | Description: Tests the /model --help command to display help information for model selection functionality"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -176,7 +176,7 @@ fn test_model_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "model", feature = "sanity"))] fn test_model_h_command() -> Result<(), Box> { - println!("πŸ” Testing /model -h command... | Description: Tests the /model -h command (short form) to display help information for model selection functionality"); + println!("\nπŸ” Testing /model -h command... | Description: Tests the /model -h command (short form) to display help information for model selection functionality"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); diff --git a/e2etests/tests/save_load/test_save_load_command.rs b/e2etests/tests/save_load/test_save_load_command.rs index 650e5669d2..b724e49958 100644 --- a/e2etests/tests/save_load/test_save_load_command.rs +++ b/e2etests/tests/save_load/test_save_load_command.rs @@ -39,7 +39,7 @@ impl<'a> Drop for FileCleanup<'a> { #[test] #[cfg(all(feature = "save_load", feature = "sanity"))] fn test_save_command() -> Result<(), Box> { - println!("πŸ” Testing /save command... | Description: Tests the /save command to export conversation state to a file and verify successful file creation with conversation data"); + println!("\nπŸ” Testing /save command... | Description: Tests the /save command to export conversation state to a file and verify successful file creation with conversation data"); let save_path = "/tmp/qcli_test_save.json"; let _cleanup = FileCleanup { path: save_path }; @@ -84,7 +84,7 @@ fn test_save_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "save_load", feature = "sanity"))] fn test_save_command_argument_validation() -> Result<(), Box> { - println!("πŸ” Testing /save command argument validation... | Description: Tests the /save command without required arguments to verify proper error handling and usage display"); + println!("\nπŸ” Testing /save command argument validation... | Description: Tests the /save command without required arguments to verify proper error handling and usage display"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -122,7 +122,7 @@ fn test_save_command_argument_validation() -> Result<(), Box Result<(), Box> { - println!("πŸ” Testing /save --help command... | Description: Tests the /save --help command to display comprehensive help information for save functionality"); + println!("\nπŸ” Testing /save --help command... | Description: Tests the /save --help command to display comprehensive help information for save functionality"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -164,7 +164,7 @@ fn test_save_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "save_load", feature = "sanity"))] fn test_save_h_flag_command() -> Result<(), Box> { - println!("πŸ” Testing /save -h command... | Description: Tests the /save -h command (short form) to display save help information"); + println!("\nπŸ” Testing /save -h command... | Description: Tests the /save -h command (short form) to display save help information"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -205,7 +205,7 @@ fn test_save_h_flag_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "save_load", feature = "sanity"))] fn test_save_force_command() -> Result<(), Box> { - println!("πŸ” Testing /save --force command... | Description: Tests the /save --force command to overwrite existing files and verify force save functionality"); + println!("\nπŸ” Testing /save --force command... | Description: Tests the /save --force command to overwrite existing files and verify force save functionality"); let save_path = "/tmp/qcli_test_save.json"; let _cleanup = FileCleanup { path: save_path }; @@ -263,7 +263,7 @@ fn test_save_force_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "save_load", feature = "sanity"))] fn test_save_f_flag_command() -> Result<(), Box> { - println!("πŸ” Testing /save -f command... | Description: Tests the /save -f command (short form) to force overwrite existing files"); + println!("\nπŸ” Testing /save -f command... | Description: Tests the /save -f command (short form) to force overwrite existing files"); let save_path = "/tmp/qcli_test_save.json"; let _cleanup = FileCleanup { path: save_path }; @@ -321,7 +321,7 @@ fn test_save_f_flag_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "save_load", feature = "sanity"))] fn test_load_help_command() -> Result<(), Box> { - println!("πŸ” Testing /load --help command... | Description: Tests the /load --help command to display comprehensive help information for load functionality"); + println!("\nπŸ” Testing /load --help command... | Description: Tests the /load --help command to display comprehensive help information for load functionality"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -362,7 +362,7 @@ fn test_load_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "save_load", feature = "sanity"))] fn test_load_h_flag_command() -> Result<(), Box> { - println!("πŸ” Testing /load -h command... | Description: Tests the /load -h command (short form) to display load help information"); + println!("\nπŸ” Testing /load -h command... | Description: Tests the /load -h command (short form) to display load help information"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -403,7 +403,7 @@ fn test_load_h_flag_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "save_load", feature = "sanity"))] fn test_load_command() -> Result<(), Box> { - println!("πŸ” Testing /load command... | Description: Tests the /load command to import conversation state from a saved file and verify successful restoration"); + println!("\nπŸ” Testing /load command... | Description: Tests the /load command to import conversation state from a saved file and verify successful restoration"); let save_path = "/tmp/qcli_test_load.json"; let _cleanup = FileCleanup { path: save_path }; @@ -457,7 +457,7 @@ fn test_load_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "save_load", feature = "sanity"))] fn test_load_command_argument_validation() -> Result<(), Box> { - println!("πŸ” Testing /load command argument validation... | Description: Tests the /load command without required arguments to verify proper error handling and usage display"); + println!("\nπŸ” Testing /load command argument validation... | Description: Tests the /load command without required arguments to verify proper error handling and usage display"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); diff --git a/e2etests/tests/session_mgmt/test_compact_command.rs b/e2etests/tests/session_mgmt/test_compact_command.rs index 9dfca3a780..06f5a41be0 100644 --- a/e2etests/tests/session_mgmt/test_compact_command.rs +++ b/e2etests/tests/session_mgmt/test_compact_command.rs @@ -21,7 +21,7 @@ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] #[cfg(all(feature = "compact", feature = "sanity"))] fn test_compact_command() -> Result<(), Box> { - println!("πŸ” Testing /compact command... | Description: Tests the /compact command to compress conversation history and verify successful compaction or appropriate messaging for short conversations"); + println!("\nπŸ” Testing /compact command... | Description: Tests the /compact command to compress conversation history and verify successful compaction or appropriate messaging for short conversations"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -63,7 +63,7 @@ fn test_compact_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "compact", feature = "sanity"))] fn test_compact_help_command() -> Result<(), Box> { - println!("πŸ” Testing /compact --help command... | Description: Tests the /compact --help command to display comprehensive help information for conversation compaction functionality"); + println!("\nπŸ” Testing /compact --help command... | Description: Tests the /compact --help command to display comprehensive help information for conversation compaction functionality"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); @@ -106,7 +106,7 @@ fn test_compact_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "compact", feature = "sanity"))] fn test_compact_h_command() -> Result<(), Box> { - println!("πŸ” Testing /compact -h command... | Description: Tests the /compact -h command (short form) to display compact help information"); + println!("\nπŸ” Testing /compact -h command... | Description: Tests the /compact -h command (short form) to display compact help information"); let session = get_chat_session(); let mut chat = session.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); diff --git a/e2etests/tests/session_mgmt/test_usage_command.rs b/e2etests/tests/session_mgmt/test_usage_command.rs index 92dd5a5664..9b2e1ac5b2 100644 --- a/e2etests/tests/session_mgmt/test_usage_command.rs +++ b/e2etests/tests/session_mgmt/test_usage_command.rs @@ -20,7 +20,7 @@ const TOTAL_TESTS: usize = TEST_NAMES.len(); #[test] #[cfg(all(feature = "usage", feature = "sanity"))] fn test_usage_command() -> Result<(), Box> { - println!("πŸ” Testing /usage command... | Description: Tests the /usage command to display current context window usage. Verifies token usage information, progress bar, breakdown sections, and Pro Tips"); + println!("\nπŸ” Testing /usage command... | Description: Tests the /usage command to display current context window usage. Verifies token usage information, progress bar, breakdown sections, and Pro Tips"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -81,7 +81,7 @@ fn test_usage_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "usage", feature = "sanity"))] fn test_usage_help_command() -> Result<(), Box> { - println!("πŸ” Testing /usage --help command... | Description: Tests the /usage --help command to display help information for the usage command. Verifies Usage section, Options section, and help flags (-h, --help)"); + println!("\nπŸ” Testing /usage --help command... | Description: Tests the /usage --help command to display help information for the usage command. Verifies Usage section, Options section, and help flags (-h, --help)"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); @@ -125,7 +125,7 @@ fn test_usage_help_command() -> Result<(), Box> { #[test] #[cfg(all(feature = "usage", feature = "sanity"))] fn test_usage_h_command() -> Result<(), Box> { - println!("πŸ” Testing /usage -h command... | Description: Tests the /usage -h command (short form of --help). Verifies Usage section, Options section, and help flags (-h, --help)"); + println!("\nπŸ” Testing /usage -h command... | Description: Tests the /usage -h command (short form of --help). Verifies Usage section, Options section, and help flags (-h, --help)"); let session = get_chat_session(); let mut chat = session.lock().unwrap(); From 14113a41bf241c73c88b8d6ed567a288d7c35017 Mon Sep 17 00:00:00 2001 From: Abhishek Anne Date: Fri, 29 Aug 2025 16:21:30 +0530 Subject: [PATCH 46/77] Removed the tiles from summary section , added table in HTML report --- e2etests/html_template.html | 49 ++++++++++++++----------------------- 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/e2etests/html_template.html b/e2etests/html_template.html index 4239624d3b..1e45bb0fc3 100644 --- a/e2etests/html_template.html +++ b/e2etests/html_template.html @@ -12,10 +12,11 @@ .summary-content {{ display: flex; gap: 30px; align-items: center; }} .stats-column {{ flex: 1; }} .chart-column {{ flex: 0 0 300px; text-align: center; }} - .stats {{ display: grid; grid-template-columns: repeat(2, 1fr); gap: 15px; }} - .stat-item {{ background: white; padding: 15px; border-radius: 8px; text-align: center; border-left: 4px solid #007bff; }} - .stat-item.success {{ border-left-color: #28a745; }} - .stat-item.failure {{ border-left-color: #dc3545; }} + .summary-table {{ width: 60%; border-collapse: collapse; margin: 20px 0; }} + .summary-table td {{ padding: 12px; text-align: left; border-bottom: 1px solid #ddd; }} + .summary-table .success {{ color: #28a745; font-weight: bold; }} + .summary-table .failure {{ color: #dc3545; font-weight: bold; }} + .summary-table .neutral {{ color: #007bff; font-weight: bold; }} .collapsible {{ background-color: #007bff; color: white; cursor: pointer; padding: 15px; border: none; text-align: left; outline: none; font-size: 16px; border-radius: 5px; margin: 5px 0; width: 100%; }} .collapsible:hover {{ background-color: #0056b3; }} .collapsible.active {{ background-color: #0056b3; }} @@ -38,32 +39,20 @@

πŸ§ͺ Q CLI E2E Test Report

πŸ“Š Summary

-
-
-

{success_rate}%

-

Success Rate

-
-
-

{total_features}

-

Features Tested

-
-
-

{features_100_pass}

-

Features 100% Pass

-
-
-

{features_failed}

-

Features with Failures

-
-
-

{tests_passed}

-

Tests Passed

-
-
-

{tests_failed}

-

Tests Failed

-
-
+ + + + + + + + + + + + + +
Features Tested{total_features}
Tests Passed{tests_passed}
Tests Failed{tests_failed}
From 3c598fbdbf4c728386b347a28cfeff5da7ee073d Mon Sep 17 00:00:00 2001 From: Abhishek Anne Date: Fri, 29 Aug 2025 18:30:37 +0530 Subject: [PATCH 47/77] Added histogram for the test pass fail --- e2etests/html_template.html | 205 +++++++++++++++++++++++++----------- e2etests/run_tests.py | 10 +- 2 files changed, 153 insertions(+), 62 deletions(-) diff --git a/e2etests/html_template.html b/e2etests/html_template.html index 1e45bb0fc3..cc24c888e4 100644 --- a/e2etests/html_template.html +++ b/e2etests/html_template.html @@ -9,11 +9,14 @@ .container {{ max-width: 1200px; margin: 0 auto; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }} .header {{ text-align: center; margin-bottom: 30px; }} .summary-card {{ background: #f8f9fa; padding: 20px; border-radius: 8px; margin: 20px 0; }} - .summary-content {{ display: flex; gap: 30px; align-items: center; }} + .summary-content {{ display: flex; gap: 30px; align-items: flex-start; }} .stats-column {{ flex: 1; }} - .chart-column {{ flex: 0 0 300px; text-align: center; }} - .summary-table {{ width: 60%; border-collapse: collapse; margin: 20px 0; }} - .summary-table td {{ padding: 12px; text-align: left; border-bottom: 1px solid #ddd; }} + .chart-column {{ flex: 1; text-align: center; display: flex; flex-direction: column; align-items: center; }} + .legend {{ display: flex; justify-content: center; gap: 20px; margin-top: 10px; }} + .legend-item {{ display: flex; align-items: center; gap: 5px; }} + .legend-color {{ width: 15px; height: 15px; border-radius: 3px; }} + .summary-table {{ width: auto; border-collapse: collapse; margin: 20px 0; }} + .summary-table td {{ padding: 12px 20px; text-align: left; border-bottom: 1px solid #ddd; white-space: nowrap; }} .summary-table .success {{ color: #28a745; font-weight: bold; }} .summary-table .failure {{ color: #dc3545; font-weight: bold; }} .summary-table .neutral {{ color: #007bff; font-weight: bold; }} @@ -37,7 +40,20 @@

πŸ§ͺ Q CLI E2E Test Report

πŸ“Š Summary

-
+
+ +
+
+
+ Total Tests +
+
+
+ Passed Tests +
+
+
+
@@ -54,10 +70,6 @@

πŸ“Š Summary

-
- -

Success Rate: {success_rate}%

-
@@ -73,72 +85,143 @@

πŸ’» System Information